#include "common.h" #include "world.h" #include "display.h" #include static CVECTOR colors[] = { { 255, 0, 0 }, { 0, 255, 0 }, { 0, 0, 255 }, { 255, 255, 0 }, { 255, 0, 255 }, { 0, 255, 255 }, { 128, 255, 0 }, { 255, 128, 0 }, { 128, 0, 255 }, { 255, 0, 128 }, { 0, 128, 255 }, { 0, 255, 128 }, }; static const int numColors = sizeof(colors) / sizeof(CVECTOR); void world_load(const u_long *data, world_t *world) { const char *bytes = (const char*)data; world->header = (ps1bsp_header_t*)bytes; bytes += sizeof(ps1bsp_header_t); world->vertices = (ps1bsp_vertex_t*)bytes; bytes += sizeof(ps1bsp_vertex_t) * world->header->numVertices; world->faceVertIndices = (unsigned short*)bytes; bytes += sizeof(unsigned short) * world->header->numFaceVertIndices; world->faces = (ps1bsp_face_t*)bytes; bytes += sizeof(ps1bsp_face_t) * world->header->numFaces; } void world_draw(const world_t *world) { int p; // The world doesn't move, so we just set the camera view-projection matrix gte_SetRotMatrix(&vp_matrix); gte_SetTransMatrix(&vp_matrix); for (int faceIdx = 0; faceIdx < world->header->numFaces; ++faceIdx) { const ps1bsp_face_t *face = &world->faces[faceIdx]; const CVECTOR *col = &colors[faceIdx % numColors]; char *scratch = scratchpad; SVECTOR *vecs = (SVECTOR*)mem_scratch(&scratch, sizeof(SVECTOR) * face->numVertices); // Copy this face's vertices into scratch RAM for fast reuse unsigned short *faceVertIndex = &world->faceVertIndices[face->firstVertexIndex]; for (int vertIdx = 0; vertIdx < face->numVertices; ++vertIdx, ++faceVertIndex) { const ps1bsp_vertex_t *vert = &world->vertices[*faceVertIndex]; vecs[vertIdx] = *((SVECTOR*)vert); vecs[vertIdx].pad = vert->baseLight; } // Draw the face as a triangle fan for (int vertIdx = 1; vertIdx < face->numVertices - 1; ++vertIdx) { const SVECTOR *v0 = &vecs[0]; const SVECTOR *v1 = &vecs[vertIdx]; const SVECTOR *v2 = &vecs[vertIdx + 1]; // Naively draw the triangle with GTE, nothing special or optimized about this gte_ldv3(v0, v1, v2); gte_rtpt(); // Rotation, translation, perspective projection // Normal clipping for backface culling gte_nclip(); gte_stopz(&p); if (p < 0) continue; // Average Z for depth sorting and culling gte_avsz3(); gte_stotz(&p); unsigned short depth = p >> 2; if (depth <= 0 || depth >= OTLEN) continue; // Draw a flat-shaded untextured colored triangle POLY_G3 *poly = (POLY_G3*)mem_prim(sizeof(POLY_G3)); if (poly == NULL) break; setPolyG3(poly); gte_stsxy3_g3(poly); poly->r0 = poly->g0 = poly->b0 = (uint8_t)v0->pad; poly->r1 = poly->g1 = poly->b1 = (uint8_t)v1->pad; poly->r2 = poly->g2 = poly->b2 = (uint8_t)v2->pad; addPrim(curOT + depth, poly); } } }