Browse Source

Added an extra face sorting step so we can draw faces in front-to-back order:

- Nodes are traversed front-to-back, leafs are sorted back-to-front
- Leaf faces are collected back-to-front to ensure faces shared between leaves are drawn in the correct order
- Faces to be drawn are then sorted front-to-back and drawn in that order
- This obsoletes the need for any kind of depth calculations, and makes the primitive buffer cutoff work as intended
unrollquadloop
Nico de Poel 3 years ago
parent
commit
4d138b4199
  1. 2
      memory.h
  2. 8
      ps1bsp.h
  3. BIN
      test.ps1bsp
  4. 40
      world.c

2
memory.h

@ -4,7 +4,7 @@
#define SCRATCHLEN 1024 #define SCRATCHLEN 1024
extern u_char* const scratchpad; // Starting address of scratchpad memory, i.e. the 1kB of data cache usable as fast RAM 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 *nextprim;
extern char *primbuf_bounds; extern char *primbuf_bounds;

8
ps1bsp.h

@ -90,7 +90,7 @@ typedef struct
// High quality: Face -> polygons -> polygon vertex indices (index + UV + light) -> vertices // High quality: Face -> polygons -> polygon vertex indices (index + UV + light) -> vertices
// Low quality: Face -> face vertex indices (index + color) -> vertices // Low quality: Face -> face vertex indices (index + color) -> vertices
typedef struct
typedef struct ps1bsp_face_s
{ {
unsigned short planeId; unsigned short planeId;
unsigned char side; unsigned char side;
@ -111,7 +111,8 @@ typedef struct
SVECTOR center; SVECTOR center;
// Run-time data // 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; } ps1bsp_face_t;
typedef struct typedef struct
@ -140,8 +141,7 @@ typedef struct ps1bsp_leaf_s
u_short numLeafFaces; u_short numLeafFaces;
// Run-time data // 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; } ps1bsp_leaf_t;
// Pre-parsed and encoded entity data (this runs the risk of becoming too bloated) // Pre-parsed and encoded entity data (this runs the risk of becoming too bloated)

BIN
test.ps1bsp

40
world.c

@ -207,10 +207,7 @@ static void world_drawface_textured(const world_t *world, const ps1bsp_face_t *f
curVert->pad = polyVertex->light; 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 void (*world_drawface)(const world_t*, const ps1bsp_face_t*, u_long *ot) = &world_drawface_fast;
static ps1bsp_leaf_t *firstLeaf = NULL; 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(); 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) 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]; const u_short *leafFaces = &world->leafFaces[leaf->firstLeafFace];
for (u_short leafFaceIdx = 0; leafFaceIdx < leaf->numLeafFaces; ++leafFaceIdx) for (u_short leafFaceIdx = 0; leafFaceIdx < leaf->numLeafFaces; ++leafFaceIdx)
{ {
ps1bsp_face_t *face = &world->faces[leafFaces[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) if (face->drawFrame == frameNum)
continue; continue;
world_drawface(world, face, ot);
// Sort the faces to draw in front-to-back order
face->drawFrame = frameNum; 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 // 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]; ps1bsp_leaf_t *leaf = (ps1bsp_leaf_t*)&world->leaves[leafIdx];
leaf->nextLeaf = firstLeaf; leaf->nextLeaf = firstLeaf;
leaf->leafDepth = leafDepth++;
firstLeaf = leaf; firstLeaf = leaf;
return; return;
} }
@ -361,7 +367,9 @@ void world_draw(const world_t *world)
world_drawface = &world_drawface_lit; world_drawface = &world_drawface_lit;
firstLeaf = NULL; firstLeaf = NULL;
leafDepth = 1;
firstFace = NULL;
world_sortLeafs(world, 0, pvs); world_sortLeafs(world, 0, pvs);
world_drawLeafs(world);
world_sortFaces(world);
world_drawFaces(world);
} }
Loading…
Cancel
Save