|
|
|
@ -48,6 +48,9 @@ void world_load(const u_long *data, world_t *world) |
|
|
|
|
|
|
|
world->leafFaces = (u_short*)(bytes + header->leafFaces.offset); |
|
|
|
world->numLeafFaces = header->leafFaces.size / sizeof(u_short); |
|
|
|
|
|
|
|
world->visData = (u_char*)(bytes + header->visData.offset); |
|
|
|
world->numVisData = header->visData.size / sizeof(u_char); |
|
|
|
} |
|
|
|
|
|
|
|
static INLINE void drawface_triangle_fan(const ps1bsp_face_t *face, SVECTOR *vecs) |
|
|
|
@ -75,7 +78,7 @@ static INLINE void drawface_triangle_fan(const ps1bsp_face_t *face, SVECTOR *vec |
|
|
|
// Average Z for depth sorting and culling |
|
|
|
gte_avsz3(); |
|
|
|
gte_stotz(&p); |
|
|
|
unsigned short depth = p >> 2; |
|
|
|
short depth = p >> 2; |
|
|
|
if (depth <= 0 || depth >= OTLEN) |
|
|
|
continue; |
|
|
|
|
|
|
|
@ -137,7 +140,7 @@ static INLINE void drawface_triangle_strip(const ps1bsp_face_t *face, SVECTOR *v |
|
|
|
// Average Z for depth sorting and culling |
|
|
|
gte_avsz3(); |
|
|
|
gte_stotz(&p); |
|
|
|
unsigned short depth = p >> 2; |
|
|
|
short depth = p >> 2; |
|
|
|
if (depth <= 0 || depth >= OTLEN) |
|
|
|
continue; |
|
|
|
|
|
|
|
@ -193,7 +196,7 @@ static INLINE void drawface_quad_strip(const ps1bsp_face_t *face, SVECTOR *vecs) |
|
|
|
// Average Z for depth sorting and culling |
|
|
|
gte_avsz3(); |
|
|
|
gte_stotz(&p); |
|
|
|
unsigned short depth = p >> 2; |
|
|
|
short depth = p >> 2; |
|
|
|
if (depth <= 0 || depth >= OTLEN) |
|
|
|
continue; |
|
|
|
|
|
|
|
@ -222,13 +225,15 @@ static INLINE void drawface_quad_strip(const ps1bsp_face_t *face, SVECTOR *vecs) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void world_drawface(const world_t *world, const ps1bsp_face_t *face, char *scratchptr) |
|
|
|
static void world_drawface(const world_t *world, const ps1bsp_face_t *face, u_char *scratchptr) |
|
|
|
{ |
|
|
|
const CVECTOR *col = &colors[(u_long)face % numColors]; |
|
|
|
|
|
|
|
SVECTOR *vecs = (SVECTOR*)mem_scratch(&scratchptr, sizeof(SVECTOR) * face->numFaceVertices); |
|
|
|
SVECTOR *vecs = (SVECTOR*)scratchptr; |
|
|
|
// scratchptr += sizeof(SVECTOR) * face->numFaceVertices; // No need to move the scratchpad pointer right now |
|
|
|
|
|
|
|
// Copy this face's vertices into scratch RAM for fast reuse |
|
|
|
// TODO: this is the main performance bottleneck right now! |
|
|
|
ps1bsp_facevertex_t *faceVertex = &world->faceVertices[face->firstFaceVertex]; |
|
|
|
for (int vertIdx = 0; vertIdx < face->numFaceVertices; ++vertIdx, ++faceVertex) |
|
|
|
{ |
|
|
|
@ -243,12 +248,17 @@ static void world_drawface(const world_t *world, const ps1bsp_face_t *face, char |
|
|
|
drawface_quad_strip(face, vecs); |
|
|
|
} |
|
|
|
|
|
|
|
static void world_drawnode(const world_t *world, short nodeIdx, char *scratchptr) |
|
|
|
static void world_drawnode(const world_t *world, short nodeIdx, u_char *pvs, u_char *scratchptr) |
|
|
|
{ |
|
|
|
u_long frameNum = time_getFrameNumber(); |
|
|
|
|
|
|
|
if (nodeIdx < 0) // Leaf node |
|
|
|
{ |
|
|
|
// Check if this leaf is visible from the current camera position |
|
|
|
u_short test = ~nodeIdx - 1; |
|
|
|
if ((pvs[test >> 3] & (1 << (test & 0x7))) == 0) |
|
|
|
return; |
|
|
|
|
|
|
|
const ps1bsp_leaf_t *leaf = &world->leaves[~nodeIdx]; |
|
|
|
const u_short *leafFace = &world->leafFaces[leaf->firstLeafFace]; |
|
|
|
|
|
|
|
@ -281,8 +291,52 @@ static void world_drawnode(const world_t *world, short nodeIdx, char *scratchpt |
|
|
|
// face->drawFrame = frameNum; |
|
|
|
// } |
|
|
|
|
|
|
|
world_drawnode(world, node->front, scratchptr); |
|
|
|
world_drawnode(world, node->back, scratchptr); |
|
|
|
const ps1bsp_plane_t *plane = &world->planes[node->planeId]; |
|
|
|
short dist = m_pointPlaneDist2(&cam_pos, &plane->normal, plane->dist); |
|
|
|
|
|
|
|
// Draw child nodes in front-to-back order; adding faces to the OT will reverse the drawing order |
|
|
|
if (dist > 0) |
|
|
|
{ |
|
|
|
world_drawnode(world, node->front, pvs, scratchptr); |
|
|
|
world_drawnode(world, node->back, pvs, scratchptr); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
world_drawnode(world, node->back, pvs, scratchptr); |
|
|
|
world_drawnode(world, node->front, pvs, scratchptr); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Decompress PVS data for the given leaf ID and store it in scratch RAM at the given scratch pointer location. |
|
|
|
// Returns the memory location of decompressed PVS data, and moves the scratch pointer forward. |
|
|
|
static u_char *world_loadVisData(const world_t *world, u_short leafIdx, u_char **scratchptr) |
|
|
|
{ |
|
|
|
u_char *head = *scratchptr; |
|
|
|
u_char *tail = head; |
|
|
|
|
|
|
|
const ps1bsp_leaf_t *leaf = &world->leaves[leafIdx]; |
|
|
|
|
|
|
|
const u_char *v = &world->visData[leaf->vislist]; |
|
|
|
for (int l = 1; l < world->numLeaves; ) |
|
|
|
{ |
|
|
|
u_char bits = *v++; |
|
|
|
if (bits) |
|
|
|
{ |
|
|
|
*tail++ = bits; |
|
|
|
l += 8; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
u_char skip = *v++; |
|
|
|
for (u_char i = 0; i < skip; ++i, l += 8) |
|
|
|
{ |
|
|
|
*tail++ = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
*scratchptr = tail; |
|
|
|
return head; |
|
|
|
} |
|
|
|
|
|
|
|
static u_short world_leafAtPoint(const world_t *world, const VECTOR *point) |
|
|
|
@ -294,9 +348,9 @@ static u_short world_leafAtPoint(const world_t *world, const VECTOR *point) |
|
|
|
const ps1bsp_plane_t *plane = &world->planes[node->planeId]; |
|
|
|
|
|
|
|
// TODO: can be optimized for axis-aligned planes, no need for a dot product there |
|
|
|
short dist = m_pointPlaneDist4(point, &plane->normal, plane->dist); |
|
|
|
short dist = m_pointPlaneDist2(point, &plane->normal, plane->dist); |
|
|
|
|
|
|
|
nodeIdx = dist < 0 ? node->back : node->front; // TODO: this can be done branchless with (dist < 0)^1 |
|
|
|
nodeIdx = dist > 0 ? node->front : node->back; // TODO: this can be done branchless with (dist < 0)^1 |
|
|
|
} |
|
|
|
|
|
|
|
return ~nodeIdx; |
|
|
|
@ -312,5 +366,8 @@ void world_draw(const world_t *world) |
|
|
|
|
|
|
|
cam_leaf = world_leafAtPoint(world, &cam_pos); |
|
|
|
|
|
|
|
world_drawnode(world, 0, scratchpad); |
|
|
|
u_char *scratchptr = scratchpad_root; |
|
|
|
u_char *pvs = world_loadVisData(world, cam_leaf, &scratchptr); |
|
|
|
|
|
|
|
world_drawnode(world, 0, pvs, scratchptr); |
|
|
|
} |