diff --git a/draw.h b/draw.h new file mode 100644 index 0000000..a0317b8 --- /dev/null +++ b/draw.h @@ -0,0 +1,226 @@ +#ifndef __DRAW_H__ +#define __DRAW_H__ + +#include "common.h" +#include "display.h" +#include + +static INLINE void draw_triangle_fan(SVECTOR *verts, u_char numVerts) +{ + int p; + + if (!mem_checkprim(sizeof(POLY_G3), numVerts - 2)) + return; + + // Draw the face as a triangle fan + u_char maxVert = numVerts - 1; + for (int vertIdx = 1; vertIdx < maxVert; ++vertIdx) + { + const SVECTOR *v0 = &verts[0]; + const SVECTOR *v1 = &verts[vertIdx]; + const SVECTOR *v2 = &verts[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 + + // Average Z for depth sorting and culling + gte_avsz3(); + gte_stotz(&p); + 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)); + 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); + ++polyCount; + } +} + +static INLINE void draw_triangle_strip(SVECTOR *verts, u_char numVerts) +{ + int p; + + u_char numTris = numVerts - 2; + if (!mem_checkprim(sizeof(POLY_G3), numTris)) + return; + + // Draw the face as a triangle strip + const SVECTOR *v0, *v1, *v2; + const SVECTOR *head = verts; + const SVECTOR *tail = verts + numVerts; + u_char reverse = 0; + + v2 = head++; // Initialize first vertex to index 0 and set head to index 1 + + for (u_char triIdx = 0; triIdx < numTris; ++triIdx) + { + if (reverse ^= 1) + { + v0 = v2; + v1 = head; + v2 = --tail; + } + else + { + v0 = v1; + v1 = ++head; + v2 = tail; + } + + // Naively draw the triangle with GTE, nothing special or optimized about this + gte_ldv3(v0, v1, v2); + gte_rtpt(); // Rotation, translation, perspective projection + + // Average Z for depth sorting and culling + gte_avsz3(); + gte_stotz(&p); + 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)); + 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); + ++polyCount; + } +} + +static INLINE void draw_quad_strip(SVECTOR *verts, u_char numVerts) +{ + int p; + + u_char numQuads = (numVerts - 1) / 2; + if (!mem_checkprim(sizeof(POLY_G4), numQuads)) + return; + + // Draw the face as a quad strip + const SVECTOR *v0, *v1, *v2, *v3; + const SVECTOR *head = verts; + const SVECTOR *tail = verts + numVerts; + + // Initialize the first two vertices + v2 = --tail; + v3 = head++; + + // Normally a quad strip would have (N-2)/2 quads, but we might end up with a sole triangle at the end which will be drawn as a collapsed quad + for (u_char quadIdx = 0; quadIdx < numQuads; ++quadIdx) + { + v0 = v2; + v1 = v3; + v2 = --tail; + v3 = head++; + + // Naively draw the quad with GTE, nothing special or optimized about this + gte_ldv3(v0, v1, v2); + gte_rtpt(); // Rotation, translation, perspective projection + + // Average Z for depth sorting and culling + gte_avsz3(); + gte_stotz(&p); + short depth = p >> 2; + if (depth <= 0 || depth >= OTLEN) + continue; + + // Draw a flat-shaded untextured colored quad + POLY_G4 *poly = (POLY_G4*)mem_prim(sizeof(POLY_G4)); + setPolyG4(poly); + gte_stsxy0(&poly->x0); + gte_stsxy1(&poly->x1); + gte_stsxy2(&poly->x2); + + // Transform the fourth vertex to complete the quad + gte_ldv0(v3); + gte_rtps(); + gte_stsxy(&poly->x3); + + 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; + poly->r3 = poly->g3 = poly->b3 = (uint8_t)v3->pad; + + addPrim(curOT + depth, poly); + ++polyCount; + } +} + +static INLINE void draw_quad_strip_tex(STVECTOR *verts, u_char numVerts, u_short tpage) +{ + int p; + + // Normally a quad strip would have (N-2)/2 quads, but we might end up with a sole triangle at the end which will be drawn as a collapsed quad + u_char numQuads = (numVerts - 1) / 2; + if (!mem_checkprim(sizeof(POLY_GT4), numQuads)) + return; + + // Draw the face as a quad strip + const STVECTOR *v0, *v1, *v2, *v3; + const STVECTOR *head = verts; + const STVECTOR *tail = verts + numVerts; + + // Initialize the first two vertices + v2 = --tail; + v3 = head++; + + for (u_char quadIdx = 0; quadIdx < numQuads; ++quadIdx) + { + v0 = v2; + v1 = v3; + v2 = --tail; + v3 = head++; + + // Naively draw the quad with GTE, nothing special or optimized about this + gte_ldv3(v0, v1, v2); + gte_rtpt(); // Rotation, translation, perspective projection + + // Average Z for depth sorting and culling + gte_avsz3(); + gte_stotz(&p); + short depth = p >> 2; + if (depth <= 0 || depth >= OTLEN) + continue; + + // Draw a flat-shaded untextured colored quad + POLY_GT4 *poly = (POLY_GT4*)mem_prim(sizeof(POLY_GT4)); + setPolyGT4(poly); + gte_stsxy0(&poly->x0); + gte_stsxy1(&poly->x1); + gte_stsxy2(&poly->x2); + + // Transform the fourth vertex to complete the quad + gte_ldv0(v3); + gte_rtps(); + gte_stsxy(&poly->x3); + + // Texture UVs + setUV4(poly, v0->u, v0->v, v1->u, v1->v, v2->u, v2->v, v3->u, v3->v); + poly->clut = quake_clut; + poly->tpage = tpage; + + // Vertex color lighting + 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; + poly->r3 = poly->g3 = poly->b3 = (uint8_t)v3->pad; + + addPrim(curOT + depth, poly); + ++polyCount; + } +} + +#endif // __DRAW_H__ diff --git a/world.c b/world.c index 065d6a9..29b6c45 100644 --- a/world.c +++ b/world.c @@ -2,8 +2,7 @@ #include "world.h" #include "display.h" #include "time.h" - -#include +#include "draw.h" static CVECTOR colors[] = { @@ -52,224 +51,6 @@ void world_load(const u_long *data, world_t *world) LOAD_CHUNK(u_char, world->visData, world->numVisData, bytes, header->visData); } -static INLINE void draw_triangle_fan(SVECTOR *verts, u_char numVerts) -{ - int p; - - if (!mem_checkprim(sizeof(POLY_G3), numVerts - 2)) - return; - - // Draw the face as a triangle fan - u_char maxVert = numVerts - 1; - for (int vertIdx = 1; vertIdx < maxVert; ++vertIdx) - { - const SVECTOR *v0 = &verts[0]; - const SVECTOR *v1 = &verts[vertIdx]; - const SVECTOR *v2 = &verts[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 - - // Average Z for depth sorting and culling - gte_avsz3(); - gte_stotz(&p); - 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)); - 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); - ++polyCount; - } -} - -static INLINE void draw_triangle_strip(SVECTOR *verts, u_char numVerts) -{ - int p; - - u_char numTris = numVerts - 2; - if (!mem_checkprim(sizeof(POLY_G3), numTris)) - return; - - // Draw the face as a triangle strip - const SVECTOR *v0, *v1, *v2; - const SVECTOR *head = verts; - const SVECTOR *tail = verts + numVerts; - u_char reverse = 0; - - v2 = head++; // Initialize first vertex to index 0 and set head to index 1 - - for (u_char triIdx = 0; triIdx < numTris; ++triIdx) - { - if (reverse ^= 1) - { - v0 = v2; - v1 = head; - v2 = --tail; - } - else - { - v0 = v1; - v1 = ++head; - v2 = tail; - } - - // Naively draw the triangle with GTE, nothing special or optimized about this - gte_ldv3(v0, v1, v2); - gte_rtpt(); // Rotation, translation, perspective projection - - // Average Z for depth sorting and culling - gte_avsz3(); - gte_stotz(&p); - 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)); - 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); - ++polyCount; - } -} - -static INLINE void draw_quad_strip(SVECTOR *verts, u_char numVerts) -{ - int p; - - u_char numQuads = (numVerts - 1) / 2; - if (!mem_checkprim(sizeof(POLY_G4), numQuads)) - return; - - // Draw the face as a quad strip - const SVECTOR *v0, *v1, *v2, *v3; - const SVECTOR *head = verts; - const SVECTOR *tail = verts + numVerts; - - // Initialize the first two vertices - v2 = --tail; - v3 = head++; - - // Normally a quad strip would have (N-2)/2 quads, but we might end up with a sole triangle at the end which will be drawn as a collapsed quad - for (u_char quadIdx = 0; quadIdx < numQuads; ++quadIdx) - { - v0 = v2; - v1 = v3; - v2 = --tail; - v3 = head++; - - // Naively draw the quad with GTE, nothing special or optimized about this - gte_ldv3(v0, v1, v2); - gte_rtpt(); // Rotation, translation, perspective projection - - // Average Z for depth sorting and culling - gte_avsz3(); - gte_stotz(&p); - short depth = p >> 2; - if (depth <= 0 || depth >= OTLEN) - continue; - - // Draw a flat-shaded untextured colored quad - POLY_G4 *poly = (POLY_G4*)mem_prim(sizeof(POLY_G4)); - setPolyG4(poly); - gte_stsxy0(&poly->x0); - gte_stsxy1(&poly->x1); - gte_stsxy2(&poly->x2); - - // Transform the fourth vertex to complete the quad - gte_ldv0(v3); - gte_rtps(); - gte_stsxy(&poly->x3); - - 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; - poly->r3 = poly->g3 = poly->b3 = (uint8_t)v3->pad; - - addPrim(curOT + depth, poly); - ++polyCount; - } -} - -static INLINE void draw_quad_strip_tex(STVECTOR *verts, u_char numVerts, u_short tpage) -{ - int p; - - // Normally a quad strip would have (N-2)/2 quads, but we might end up with a sole triangle at the end which will be drawn as a collapsed quad - u_char numQuads = (numVerts - 1) / 2; - if (!mem_checkprim(sizeof(POLY_GT4), numQuads)) - return; - - // Draw the face as a quad strip - const STVECTOR *v0, *v1, *v2, *v3; - const STVECTOR *head = verts; - const STVECTOR *tail = verts + numVerts; - - // Initialize the first two vertices - v2 = --tail; - v3 = head++; - - for (u_char quadIdx = 0; quadIdx < numQuads; ++quadIdx) - { - v0 = v2; - v1 = v3; - v2 = --tail; - v3 = head++; - - // Naively draw the quad with GTE, nothing special or optimized about this - gte_ldv3(v0, v1, v2); - gte_rtpt(); // Rotation, translation, perspective projection - - // Average Z for depth sorting and culling - gte_avsz3(); - gte_stotz(&p); - short depth = p >> 2; - if (depth <= 0 || depth >= OTLEN) - continue; - - // Draw a flat-shaded untextured colored quad - POLY_GT4 *poly = (POLY_GT4*)mem_prim(sizeof(POLY_GT4)); - setPolyGT4(poly); - gte_stsxy0(&poly->x0); - gte_stsxy1(&poly->x1); - gte_stsxy2(&poly->x2); - - // Transform the fourth vertex to complete the quad - gte_ldv0(v3); - gte_rtps(); - gte_stsxy(&poly->x3); - - // Texture UVs - setUV4(poly, v0->u, v0->v, v1->u, v1->v, v2->u, v2->v, v3->u, v3->v); - poly->clut = quake_clut; - poly->tpage = tpage; - - // Vertex color lighting - 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; - poly->r3 = poly->g3 = poly->b3 = (uint8_t)v3->pad; - - addPrim(curOT + depth, poly); - ++polyCount; - } -} - static INLINE short world_pointPlaneDist(const VECTOR *point, const ps1bsp_plane_t *plane) { // Make use of axis-aligned planes to skip the need for a dot product