diff --git a/world.c b/world.c index 2db1471..b320055 100644 --- a/world.c +++ b/world.c @@ -202,39 +202,54 @@ static ps1bsp_face_t *world_sortFaces(const world_t *world, const ps1bsp_leaf_t return firstFace; } -static void world_sortLeafs(const world_t *world, short nodeIdx, u_char *pvs, ps1bsp_leaf_t **firstLeaf) +static ps1bsp_leaf_t *world_sortLeafs(const world_t *world, short startNode, u_char *pvs) { - if (nodeIdx < 0) // Leaf node + short *nodeStack = (short*)(scratchpad + 256); // Place the node stack in fast RAM after the PVS data + u_char stackPtr = 0; + + // Push the start node onto the stack + nodeStack[stackPtr++] = startNode; + + ps1bsp_leaf_t *firstLeaf = NULL; + while (stackPtr > 0) { - u_short leafIdx = ~nodeIdx; - if (leafIdx == 0) // Leaf 0 should not be drawn - return; - - // PVS culling - u_short test = leafIdx - 1; - if ((pvs[test >> 3] & (1 << (test & 0x7))) == 0) - return; - - // Add the leaf to the sorted linked list - // 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; - *firstLeaf = leaf; - return; - } + // Pop a node off the stack + short nodeIdx = nodeStack[--stackPtr]; - // Perform frustum culling - const ps1bsp_node_t *node = &world->nodes[nodeIdx]; - if (!frustum_sphereInside(&node->boundingSphere)) - return; + if (nodeIdx < 0) // Leaf node + { + u_short leafIdx = ~nodeIdx; + if (leafIdx == 0) // Leaf 0 should not be drawn + continue; - const ps1bsp_plane_t *plane = &world->planes[node->planeId]; - short dist = world_pointPlaneDist(&cam_pos, plane); - - // Traverse the BSP tree in front-to-back order - char order = dist < 0; - world_sortLeafs(world, node->children[order], pvs, firstLeaf); - world_sortLeafs(world, node->children[order ^ 1], pvs, firstLeaf); + // PVS culling + u_short test = leafIdx - 1; + if ((pvs[test >> 3] & (1 << (test & 0x7))) == 0) + continue; + + // Add the leaf to the sorted linked list + // 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; + firstLeaf = leaf; + continue; + } + + // Perform frustum culling + const ps1bsp_node_t *node = &world->nodes[nodeIdx]; + if (!frustum_sphereInside(&node->boundingSphere)) + continue; + + const ps1bsp_plane_t *plane = &world->planes[node->planeId]; + short dist = world_pointPlaneDist(&cam_pos, plane); + + // Traverse the BSP tree in front-to-back order + char order = dist < 0; + nodeStack[stackPtr++] = node->children[order ^ 1]; + nodeStack[stackPtr++] = node->children[order]; + } + + return firstLeaf; } // Decompress PVS data for the given leaf ID and store it in RAM at the given buffer pointer location. @@ -315,8 +330,7 @@ void world_draw(const world_t *world) else world_drawface = &world_drawface_lit; - ps1bsp_leaf_t *firstLeaf = NULL; - world_sortLeafs(world, 0, pvs, &firstLeaf); + ps1bsp_leaf_t *firstLeaf = world_sortLeafs(world, 0, pvs); ps1bsp_face_t *firstFace = world_sortFaces(world, firstLeaf); world_drawFaces(world, firstFace); }