#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->triangles = (ps1bsp_triangle_t*)bytes; bytes += sizeof(ps1bsp_triangle_t) * world->header->numTriangles; 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); mem_scratch_reset(); SVECTOR *vecs = mem_scratch(sizeof(SVECTOR) * 3); for (int faceIdx = 0; faceIdx < world->header->numFaces; ++faceIdx) { const ps1bsp_face_t *face = &world->faces[faceIdx]; const CVECTOR *col = &colors[faceIdx % numColors]; const ps1bsp_triangle_t *tri = &world->triangles[face->firstTriangleId]; for (int triangleIdx = 0; triangleIdx < face->numTriangles; ++triangleIdx, ++tri) { // Naively draw the triangle with GTE, nothing special or optimized about this const ps1bsp_vertex_t *v0 = &world->vertices[tri->vertex0]; const ps1bsp_vertex_t *v1 = &world->vertices[tri->vertex1]; const ps1bsp_vertex_t *v2 = &world->vertices[tri->vertex2]; vecs[0].vx = v0->x; vecs[0].vy = v0->y; vecs[0].vz = v0->z; vecs[1].vx = v1->x; vecs[1].vy = v1->y; vecs[1].vz = v1->z; vecs[2].vx = v2->x; vecs[2].vy = v2->y; vecs[2].vz = v2->z; gte_ldv3c(vecs); // This method *should* work but it doesn't on real hardware, for some reason. // Perhaps the PS1 doesn't like loading data from random far-off memory locations directly into GTE registers? // We probably want to use the scratchpad memory to prepare the vertex data for the GTE anyway. // SVECTOR *v0 = (SVECTOR*)&world->vertices[tri->vertex0]; // SVECTOR *v1 = (SVECTOR*)&world->vertices[tri->vertex1]; // SVECTOR *v2 = (SVECTOR*)&world->vertices[tri->vertex2]; // 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_F3 *poly = (POLY_F3*)mem_prim(sizeof(POLY_F3)); if (poly == NULL) break; setPolyF3(poly); gte_stsxy3_f3(poly); poly->r0 = col->r; poly->g0 = col->g; poly->b0 = col->b; addPrim(curOT + depth, poly); } } }