diff --git a/memory.h b/memory.h index 52e7753..04cc457 100644 --- a/memory.h +++ b/memory.h @@ -4,7 +4,7 @@ #define SCRATCHLEN 1024 extern u_char* const scratchpad; // Starting address of scratchpad memory, i.e. the 1kB of data cache usable as fast RAM -#define PRIMBUFLEN 65536*4 // TODO: reduce this to what's needed for a typical scene +#define PRIMBUFLEN 65536*2 // TODO: reduce this to what's needed for a typical scene extern char *nextprim; extern char *primbuf_bounds; diff --git a/ps1bsp.h b/ps1bsp.h index e9583c5..d2eb4a0 100755 --- a/ps1bsp.h +++ b/ps1bsp.h @@ -90,7 +90,7 @@ typedef struct // High quality: Face -> polygons -> polygon vertex indices (index + UV + light) -> vertices // Low quality: Face -> face vertex indices (index + color) -> vertices -typedef struct +typedef struct ps1bsp_face_s { unsigned short planeId; unsigned char side; @@ -111,7 +111,8 @@ typedef struct SVECTOR center; // Run-time data - u_long drawFrame; // Which frame was this face last drawn on? Used to check if this face should be drawn. + const struct ps1bsp_face_s* nextFace; // For chaining faces in drawing order + u_long drawFrame; // Which frame was this face last drawn on? Used to check if this face should be drawn. } ps1bsp_face_t; typedef struct @@ -140,8 +141,7 @@ typedef struct ps1bsp_leaf_s u_short numLeafFaces; // Run-time data - struct ps1bsp_leaf_s *nextLeaf; // For chaining leafs in drawing order - u_short leafDepth; // At what depth the leaf's faces should be placed in the ordering table + const struct ps1bsp_leaf_s* nextLeaf; // For chaining leafs in drawing order } ps1bsp_leaf_t; // Pre-parsed and encoded entity data (this runs the risk of becoming too bloated) diff --git a/test.ps1bsp b/test.ps1bsp index 8d808f6..1ddc313 100755 Binary files a/test.ps1bsp and b/test.ps1bsp differ diff --git a/world.c b/world.c index 92eb2e7..c84c627 100644 --- a/world.c +++ b/world.c @@ -207,10 +207,7 @@ static void world_drawface_textured(const world_t *world, const ps1bsp_face_t *f curVert->pad = polyVertex->light; } - if (poly->numPolyVertices == 3) - draw_triangle_textured(verts, faceTexture->tpage, ot); - else - draw_quadstrip_textured(verts, poly->numPolyVertices, faceTexture->tpage, ot); + draw_quadstrip_textured(verts, poly->numPolyVertices, faceTexture->tpage, ot); } } } @@ -218,30 +215,40 @@ static void world_drawface_textured(const world_t *world, const ps1bsp_face_t *f static void (*world_drawface)(const world_t*, const ps1bsp_face_t*, u_long *ot) = &world_drawface_fast; static ps1bsp_leaf_t *firstLeaf = NULL; -static u_short leafDepth = 0; +static ps1bsp_face_t *firstFace = NULL; -static void world_drawLeafs(const world_t *world) +static void world_drawFaces(const world_t *world) +{ + // Draw the faces in front-to-back order. There are two advantages to this: + // 1) We don't need to do any depth calculations. The ordering table will be rendered in reverse order, i.e. back-to-front. + // 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) + { + world_drawface(world, face, curOT); + } +} + +static void world_sortFaces(const world_t *world) { u_long frameNum = time_getFrameNumber(); - // Draw each visible leaf's faces in front-to-back order - // This way if we run out of primitive buffer space, we will stop drawing at far-away faces + // Traverse leaves in back-to-front order + // This ensures that faces shared between adjacent leaves are drawn in the correct order, with the back leaf being drawn behind for (const ps1bsp_leaf_t *leaf = firstLeaf; leaf != NULL; leaf = leaf->nextLeaf) { - u_long *ot = curOT + leaf->leafDepth; - const u_short *leafFaces = &world->leafFaces[leaf->firstLeafFace]; for (u_short leafFaceIdx = 0; leafFaceIdx < leaf->numLeafFaces; ++leafFaceIdx) { ps1bsp_face_t *face = &world->faces[leafFaces[leafFaceIdx]]; - // Check if we've already drawn this face on the current frame - // NOTE: this can cause sorting issues when rendering front-to-back with leaf-based depth + // Ensure we draw each face only once per frame if (face->drawFrame == frameNum) continue; - world_drawface(world, face, ot); + // Sort the faces to draw in front-to-back order face->drawFrame = frameNum; + face->nextFace = firstFace; + firstFace = face; } } } @@ -263,7 +270,6 @@ static void world_sortLeafs(const world_t *world, short nodeIdx, u_char *pvs) // Since we're traversing the BSP tree front-to-back, adding each leaf at the start sorts the list in back-to-front order ps1bsp_leaf_t *leaf = (ps1bsp_leaf_t*)&world->leaves[leafIdx]; leaf->nextLeaf = firstLeaf; - leaf->leafDepth = leafDepth++; firstLeaf = leaf; return; } @@ -361,7 +367,9 @@ void world_draw(const world_t *world) world_drawface = &world_drawface_lit; firstLeaf = NULL; - leafDepth = 1; + firstFace = NULL; + world_sortLeafs(world, 0, pvs); - world_drawLeafs(world); + world_sortFaces(world); + world_drawFaces(world); }