diff --git a/display.h b/display.h index 809fb92..5e72c31 100644 --- a/display.h +++ b/display.h @@ -5,7 +5,8 @@ #define SCREENHEIGHT_NTSC 240 #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 u_long *curOT; diff --git a/world.c b/world.c index f784672..2db1471 100644 --- a/world.c +++ b/world.c @@ -85,24 +85,31 @@ static INLINE char world_cull_backface(const world_t *world, const ps1bsp_face_t *dot = world_planeDot(&cam_vec, plane); if ((*dot >= 0) ^ face->side) return 1; - + // 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... - 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) { - // 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 const ps1bsp_facevertex_t *faceVertices = &world->faceVertices[face->firstFaceVertex]; 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) { - // 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 const ps1bsp_polygon_t* poly = &world->polygons[face->firstPolygon]; 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) { - // 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 const ps1bsp_texture_t *texture = &world->textures[face->textureId]; 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. 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); } } @@ -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]]; - // Ensure we draw each face only once per frame + // Make sure we draw each face only once per frame if (face->drawFrame == frameNum) continue; - // Sort the faces to draw in front-to-back order 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; firstFace = face; }