|
|
|
@ -7,18 +7,18 @@ |
|
|
|
|
|
|
|
static P_COLOR colors[] = |
|
|
|
{ |
|
|
|
{ (255 << 16), 0 }, |
|
|
|
{ (255 << 8), 0 }, |
|
|
|
{ (255 << 0), 0 }, |
|
|
|
{ (255 << 16) | (255 << 8), 0 }, |
|
|
|
{ (255 << 16) | (255 << 0), 0 }, |
|
|
|
{ (255 << 8) | (255 << 0), 0 }, |
|
|
|
{ (128 << 8) | (255 << 8), 0 }, |
|
|
|
{ (255 << 16) | (128 << 8), 0 }, |
|
|
|
{ (128 << 16) | (255 << 0), 0 }, |
|
|
|
{ (255 << 16) | (128 << 0), 0 }, |
|
|
|
{ (128 << 8) | (255 << 0), 0 }, |
|
|
|
{ (128 << 8) | (128 << 0), 0 }, |
|
|
|
{ (255 << 0), 0 }, // Red |
|
|
|
{ (255 << 8), 0 }, // Green |
|
|
|
{ (255 << 16), 0 }, // Blue |
|
|
|
{ (255 << 0) | (255 << 8), 0 }, |
|
|
|
{ (255 << 0) | (255 << 16), 0 }, |
|
|
|
{ (255 << 8) | (255 << 16), 0 }, |
|
|
|
{ (128 << 8) | (255 << 8), 0 }, |
|
|
|
{ (255 << 0) | (128 << 8), 0 }, |
|
|
|
{ (128 << 0) | (255 << 16), 0 }, |
|
|
|
{ (255 << 0) | (128 << 16), 0 }, |
|
|
|
{ (128 << 8) | (255 << 16), 0 }, |
|
|
|
{ (128 << 8) | (128 << 16), 0 }, |
|
|
|
}; |
|
|
|
static const int numColors = sizeof(colors) / sizeof(P_COLOR); |
|
|
|
|
|
|
|
@ -73,7 +73,7 @@ static INLINE short world_planeDot(const SVECTOR *dir, const ps1bsp_plane_t *pla |
|
|
|
return (short)m_dot12(dir, &plane->normal); |
|
|
|
} |
|
|
|
|
|
|
|
static INLINE char world_cull_backface(const world_t *world, const ps1bsp_face_t *face, short *dot) |
|
|
|
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 |
|
|
|
@ -84,9 +84,9 @@ static INLINE char world_cull_backface(const world_t *world, const ps1bsp_face_t |
|
|
|
|
|
|
|
// Check if the face's plane points towards the camera |
|
|
|
const ps1bsp_plane_t *plane = &world->planes[face->planeId]; |
|
|
|
*dot = world_planeDot(&cam_vec, plane); |
|
|
|
if ((*dot >= 0) ^ face->side) |
|
|
|
return 1; |
|
|
|
int planeDot = world_planeDot(&cam_vec, plane); |
|
|
|
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 |
|
|
|
@ -104,10 +104,34 @@ static INLINE char world_cull_backface(const world_t *world, const ps1bsp_face_t |
|
|
|
|
|
|
|
// 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. |
|
|
|
if (m_dot12(&cam_vec, &cam_dir) >= 0) |
|
|
|
int camDot = m_dot12(&cam_vec, &cam_dir); |
|
|
|
if (camDot < 0) |
|
|
|
return 0; |
|
|
|
|
|
|
|
return 1; |
|
|
|
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; |
|
|
|
} |
|
|
|
|
|
|
|
static u_short world_leafAtPoint(const world_t *world, const VECTOR *point) |
|
|
|
{ |
|
|
|
short nodeIdx = 0; |
|
|
|
while (nodeIdx >= 0) |
|
|
|
{ |
|
|
|
const ps1bsp_node_t *node = &world->nodes[nodeIdx]; |
|
|
|
const ps1bsp_plane_t *plane = &world->planes[node->planeId]; |
|
|
|
|
|
|
|
short dist = world_pointPlaneDist(point, plane); |
|
|
|
nodeIdx = node->children[(dist > 0) ^ 1]; |
|
|
|
} |
|
|
|
|
|
|
|
return ~nodeIdx; |
|
|
|
} |
|
|
|
|
|
|
|
static void world_drawface_flat(const world_t *world, const ps1bsp_face_t *face, P_COLOR *color, u_long *ot) |
|
|
|
@ -141,6 +165,13 @@ static void world_drawface_textured(const world_t *world, const ps1bsp_face_t *f |
|
|
|
const ps1bsp_texture_t *texture = &world->textures[face->textureId]; |
|
|
|
const ps1bsp_polygon_t* poly = &world->polygons[face->firstPolygon]; |
|
|
|
|
|
|
|
u_char tess = face->flags & 3; |
|
|
|
if (tess) |
|
|
|
{ |
|
|
|
world_drawface_flat(world, face, &colors[tess - 1], ot); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (face->flags & SURF_DRAWLIQUID) |
|
|
|
{ |
|
|
|
for (u_char polyIdx = 0; polyIdx < face->numPolygons; ++polyIdx, ++poly) |
|
|
|
@ -206,10 +237,18 @@ static ps1bsp_face_t *world_sortFaces(const world_t *world, const ps1bsp_leaf_t |
|
|
|
|
|
|
|
// 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; |
|
|
|
if (world_cull_backface(world, face, &dot)) |
|
|
|
short dot = world_cull_backface(world, face); |
|
|
|
if (!dot) |
|
|
|
continue; |
|
|
|
|
|
|
|
face->flags &= ~3; |
|
|
|
if (dot < 64) |
|
|
|
face->flags |= 1; |
|
|
|
else if (dot < 128) |
|
|
|
face->flags |= 2; |
|
|
|
else if (dot < 256) |
|
|
|
face->flags |= 3; |
|
|
|
|
|
|
|
// Sort the faces to draw in front-to-back order |
|
|
|
face->nextFace = firstFace; |
|
|
|
firstFace = face; |
|
|
|
|