Browse Source

Perform backface culling early to save on a bunch of needless linked list iterations.

Moved primitive buffer check and generalized it. It's fine to only check for the worst case scenario.
unrollquadloop
Nico de Poel 3 years ago
parent
commit
520e62922c
  1. 3
      display.h
  2. 60
      world.c

3
display.h

@ -5,7 +5,8 @@
#define SCREENHEIGHT_NTSC 240 #define SCREENHEIGHT_NTSC 240
#define SCREENHEIGHT_PAL 256 #define SCREENHEIGHT_PAL 256
#define OTLEN 1024
#define OTLEN 1 // We don't require the ordering table for depth sorting BSP faces
// TODO: create separate OT's for batched rendering: single item per BSP batch, larger sub-OT's for drawing alias models
extern MATRIX vp_matrix; extern MATRIX vp_matrix;
extern u_long *curOT; extern u_long *curOT;

60
world.c

@ -89,20 +89,27 @@ static INLINE char world_cull_backface(const world_t *world, const ps1bsp_face_t
// Check if the face is behind the camera // 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: 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... // TODO: or, just check against all corners of the face...
short camDot = m_dot12(cam_vec, cam_dir);
return camDot < 0;
// 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;
// }
// 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)
return 0;
return 1;
} }
static void world_drawface_fast(const world_t *world, const ps1bsp_face_t *face, u_long *ot) static void world_drawface_fast(const world_t *world, const ps1bsp_face_t *face, u_long *ot)
{ {
// Early primitive buffer check
if (!mem_checkprim(sizeof(POLY_G4), face->totalQuads))
return;
short dot;
if (world_cull_backface(world, face, &dot))
return;
// Draw untextured, vertex colored faces, skipping the entire polygon tessellation step // Draw untextured, vertex colored faces, skipping the entire polygon tessellation step
const ps1bsp_facevertex_t *faceVertices = &world->faceVertices[face->firstFaceVertex]; const ps1bsp_facevertex_t *faceVertices = &world->faceVertices[face->firstFaceVertex];
draw_quadstrip_colored(world->vertices, faceVertices, face->numFaceVertices, ot); draw_quadstrip_colored(world->vertices, faceVertices, face->numFaceVertices, ot);
@ -110,14 +117,6 @@ static void world_drawface_fast(const world_t *world, const ps1bsp_face_t *face,
static void world_drawface_lit(const world_t *world, const ps1bsp_face_t *face, u_long *ot) static void world_drawface_lit(const world_t *world, const ps1bsp_face_t *face, u_long *ot)
{ {
// Early primitive buffer check
if (!mem_checkprim(sizeof(POLY_G4), face->totalQuads))
return;
short dot;
if (world_cull_backface(world, face, &dot))
return;
// Draw untextured, vertex colored polygons // Draw untextured, vertex colored polygons
const ps1bsp_polygon_t* poly = &world->polygons[face->firstPolygon]; const ps1bsp_polygon_t* poly = &world->polygons[face->firstPolygon];
for (u_char polyIdx = 0; polyIdx < face->numPolygons; ++polyIdx, ++poly) for (u_char polyIdx = 0; polyIdx < face->numPolygons; ++polyIdx, ++poly)
@ -129,16 +128,6 @@ static void world_drawface_lit(const world_t *world, const ps1bsp_face_t *face,
static void world_drawface_textured(const world_t *world, const ps1bsp_face_t *face, u_long *ot) static void world_drawface_textured(const world_t *world, const ps1bsp_face_t *face, u_long *ot)
{ {
// Early primitive buffer check
if (!mem_checkprim(sizeof(POLY_GT4), face->totalQuads))
return;
// 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))
return;
// Draw textured, vertex colored polygons // Draw textured, vertex colored polygons
const ps1bsp_texture_t *texture = &world->textures[face->textureId]; const ps1bsp_texture_t *texture = &world->textures[face->textureId];
const ps1bsp_polygon_t* poly = &world->polygons[face->firstPolygon]; const ps1bsp_polygon_t* poly = &world->polygons[face->firstPolygon];
@ -170,6 +159,10 @@ static void world_drawFaces(const world_t *world, const ps1bsp_face_t *firstFace
// 2) If we need to stop drawing because the primitive buffer is full, we'll only be culling distant faces. // 2) If we need to stop drawing because the primitive buffer is full, we'll only be culling distant faces.
for (const ps1bsp_face_t *face = firstFace; face != NULL; face = face->nextFace) for (const ps1bsp_face_t *face = firstFace; face != NULL; face = face->nextFace)
{ {
// Early primitive buffer check
if (!mem_checkprim(sizeof(POLY_GT4), face->totalQuads))
break;
world_drawface(world, face, curOT); world_drawface(world, face, curOT);
} }
} }
@ -188,12 +181,19 @@ static ps1bsp_face_t *world_sortFaces(const world_t *world, const ps1bsp_leaf_t
{ {
ps1bsp_face_t *face = &world->faces[leafFaces[leafFaceIdx]]; ps1bsp_face_t *face = &world->faces[leafFaces[leafFaceIdx]];
// Ensure we draw each face only once per frame
// Make sure we draw each face only once per frame
if (face->drawFrame == frameNum) if (face->drawFrame == frameNum)
continue; continue;
// Sort the faces to draw in front-to-back order
face->drawFrame = frameNum; 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;
if (world_cull_backface(world, face, &dot))
continue;
// Sort the faces to draw in front-to-back order
face->nextFace = firstFace; face->nextFace = firstFace;
firstFace = face; firstFace = face;
} }

Loading…
Cancel
Save