|
|
|
@ -64,59 +64,38 @@ static INLINE short world_pointPlaneDist(const VECTOR *point, const ps1bsp_plane |
|
|
|
return (short)m_pointPlaneDist2(point, &plane->normal, plane->dist); |
|
|
|
} |
|
|
|
|
|
|
|
static INLINE short world_planeDot(const SVECTOR *dir, const ps1bsp_plane_t *plane) |
|
|
|
{ |
|
|
|
// Make use of axis-aligned planes to skip the need for a dot product |
|
|
|
if (plane->type < 3) |
|
|
|
return ((short*)dir)[plane->type]; |
|
|
|
|
|
|
|
return (short)m_dot12(dir, &plane->normal); |
|
|
|
} |
|
|
|
|
|
|
|
static INLINE short world_cull_backface(const world_t *world, const ps1bsp_face_t *face) |
|
|
|
{ |
|
|
|
// Backface culling using the face's plane and center point |
|
|
|
// This eliminates the need for normal clipping per polygon |
|
|
|
SVECTOR cam_vec; |
|
|
|
cam_vec.vx = face->center.vx - cam_pos.vx; |
|
|
|
cam_vec.vy = face->center.vy - cam_pos.vy; |
|
|
|
cam_vec.vz = face->center.vz - cam_pos.vz; |
|
|
|
VECTOR cam_vec; |
|
|
|
cam_vec.vx = (int)face->center.vx - cam_pos.vx; |
|
|
|
cam_vec.vy = (int)face->center.vy - cam_pos.vy; |
|
|
|
cam_vec.vz = (int)face->center.vz - cam_pos.vz; |
|
|
|
|
|
|
|
// Check if the face's plane points towards the camera |
|
|
|
const ps1bsp_plane_t *plane = &world->planes[face->planeId]; |
|
|
|
int planeDot = world_planeDot(&cam_vec, plane); |
|
|
|
int planeDot = m_dot12(&cam_vec, &plane->normal); |
|
|
|
if ((planeDot >= 0) ^ face->side) |
|
|
|
return 0; |
|
|
|
|
|
|
|
// Check if the face is behind the camera |
|
|
|
// TODO: this may cull faces close to the camera, use VectorNormalS to normalize and check for angles < -60 degrees |
|
|
|
// TODO: or, just check against all corners of the face... |
|
|
|
// const ps1bsp_facevertex_t *faceVertices = &world->faceVertices[face->firstFaceVertex]; |
|
|
|
// for (int vertIdx = 0; vertIdx < face->numFaceVertices; ++vertIdx) |
|
|
|
// { |
|
|
|
// const ps1bsp_vertex_t *vert = &world->vertices[faceVertices[vertIdx].index]; |
|
|
|
// cam_vec.vx = vert->x - cam_pos.vx; |
|
|
|
// cam_vec.vy = vert->y - cam_pos.vy; |
|
|
|
// cam_vec.vz = vert->z - cam_pos.vz; |
|
|
|
// if (m_dot12(cam_vec, cam_dir) >= 0) |
|
|
|
// return 0; |
|
|
|
// } |
|
|
|
|
|
|
|
// Check if the face is behind the camera |
|
|
|
// NOTE: disabling the behind-the-camera check does *not* actually solve the problem of polygons disappearing when too close to the camera! |
|
|
|
// This means that the GPU probably already clips polygons that stretch too far outside the drawing area. Tessellation should solve this. |
|
|
|
int camDot = m_dot12(&cam_vec, &cam_dir); |
|
|
|
if (camDot < 0) |
|
|
|
return 0; |
|
|
|
|
|
|
|
int vecLenSqr = m_dot12(&cam_vec, &cam_vec); |
|
|
|
|
|
|
|
// Flip angle for faces that are on the opposite side of their plane |
|
|
|
char flip = 2 * face->side - 1; |
|
|
|
planeDot = planeDot * flip; |
|
|
|
|
|
|
|
int foo = (planeDot * vecLenSqr) / (camDot + 1); |
|
|
|
// TODO: include face area |
|
|
|
return (short)foo; |
|
|
|
// Calculate an LOD value for this face, based on camera position & direction, face normal & area and distance. |
|
|
|
// This is used to determine how many tessellation subdivisions are necessary to prevent texture warping. |
|
|
|
int vecLenSqr = m_dot12(&cam_vec, &cam_vec); |
|
|
|
int lod = (planeDot * vecLenSqr) / (camDot + 1); |
|
|
|
lod = (lod << 6) / (face->center.pad + 1); |
|
|
|
return (short)lod; |
|
|
|
} |
|
|
|
|
|
|
|
static u_short world_leafAtPoint(const world_t *world, const VECTOR *point) |
|
|
|
@ -235,19 +214,19 @@ static ps1bsp_face_t *world_sortFaces(const world_t *world, const ps1bsp_leaf_t |
|
|
|
|
|
|
|
face->drawFrame = frameNum; |
|
|
|
|
|
|
|
// NOTE: this value could be REALLY useful for determining the tessellation subdivisions. It has camera distance *and* angle in it. |
|
|
|
// Just include the face size/area for an approximate screen size. Maybe also separate x/y/z for angle-dependent tessellation. |
|
|
|
short dot = world_cull_backface(world, face); |
|
|
|
if (!dot) |
|
|
|
// Cull faces that are facing away from the camera |
|
|
|
// This also returns an LOD value used to determine tessellation level |
|
|
|
short lod = world_cull_backface(world, face); |
|
|
|
if (!lod) |
|
|
|
continue; |
|
|
|
|
|
|
|
face->flags &= ~3; |
|
|
|
if (dot < 64) |
|
|
|
if (lod < 64) |
|
|
|
face->flags |= 1; |
|
|
|
else if (dot < 128) |
|
|
|
else if (lod < 128) |
|
|
|
face->flags |= 2; |
|
|
|
else if (dot < 256) |
|
|
|
face->flags |= 3; |
|
|
|
// else if (lod < 256) |
|
|
|
// face->flags |= 3; |
|
|
|
|
|
|
|
// Sort the faces to draw in front-to-back order |
|
|
|
face->nextFace = firstFace; |
|
|
|
|