diff --git a/draw.h b/draw.h index 82bac0d..e67a031 100644 --- a/draw.h +++ b/draw.h @@ -331,6 +331,195 @@ static INLINE void draw_quadstrip_textured(const ps1bsp_vertex_t *vertices, cons } } +typedef struct _TMPVERT +{ + int16_t vx, vy, vz, vpad; + uint8_t r, g, b, cpad; + uint8_t u, v; + uint16_t pad; +} TMPVERT; + +#define copyVertFast(dst, pv, v) \ + setColorFast(&(dst)->r, &(pv)->r); \ + setColorFast(&(dst)->vx, &(v)->vx); \ + setColorFast(&(dst)->vz, &(v)->vz); \ + setUVFast(&(dst)->u, &(pv)->u); + +#define lerpVert(dst, src0, src1) \ + (dst)->vx = (int16_t)(((int32_t)(src0)->vx + (int32_t)(src1)->vx) >> 1); \ + (dst)->vy = (int16_t)(((int32_t)(src0)->vy + (int32_t)(src1)->vy) >> 1); \ + (dst)->vz = (int16_t)(((int32_t)(src0)->vz + (int32_t)(src1)->vz) >> 1); \ + (dst)->r = (uint8_t)(((uint16_t)(src0)->r + (uint16_t)(src1)->r) >> 1); \ + (dst)->g = (uint8_t)(((uint16_t)(src0)->g + (uint16_t)(src1)->g) >> 1); \ + (dst)->b = (uint8_t)(((uint16_t)(src0)->b + (uint16_t)(src1)->b) >> 1); \ + (dst)->u = (uint8_t)(((uint16_t)(src0)->u + (uint16_t)(src1)->u) >> 1); \ + (dst)->v = (uint8_t)(((uint16_t)(src0)->v + (uint16_t)(src1)->v) >> 1); + +#define blitVert(dst, src) \ + setColorFast(&(dst)->x, &(src)->vx); \ + setColorFast(&(dst)->r, &(src)->r); \ + setUVFast(&(dst)->u, &(src)->u); + +static INLINE void draw_quadstrip_tess2(const ps1bsp_vertex_t *vertices, const ps1bsp_polyvertex_t *polyVerts, u_char numVerts, u_short tpage, u_long *ot) +{ + const ps1bsp_polyvertex_t *pv0, *pv1, *pv2, *pv3; + const ps1bsp_vertex_t *v0, *v1, *v2, *v3; + u_char i0, i1, i2, i3; + u_char head = 0; + u_char tail = numVerts; + + // Initialize the first two vertices + i2 = --tail; + i3 = head++; + + TMPVERT *tmp = (TMPVERT*)(scratchpad); + + // 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 + // NOTE: testing has shown that the PS1 is faster just rendering quads and accepting the odd collapsed quad, rather than being clever with pointer comparisons and drawing a single triangle at the end. + u_char numQuads = (numVerts - 1) >> 1; + for (u_char quadIdx = 0; quadIdx < numQuads; ++quadIdx) + { + i0 = i2; + i1 = i3; + i2 = --tail; + i3 = head++; + + pv0 = &polyVerts[i0]; + pv1 = &polyVerts[i1]; + pv2 = &polyVerts[i2]; + pv3 = &polyVerts[i3]; + + v0 = &vertices[pv0->index]; + v1 = &vertices[pv1->index]; + v2 = &vertices[pv2->index]; + v3 = &vertices[pv3->index]; + + copyVertFast(&tmp[0], pv0, v0); + copyVertFast(&tmp[2], pv1, v1); + copyVertFast(&tmp[6], pv2, v2); + copyVertFast(&tmp[8], pv3, v3); + + lerpVert(&tmp[1], &tmp[0], &tmp[2]); + lerpVert(&tmp[3], &tmp[0], &tmp[6]); + lerpVert(&tmp[5], &tmp[2], &tmp[8]); + lerpVert(&tmp[7], &tmp[6], &tmp[8]); + lerpVert(&tmp[4], &tmp[3], &tmp[5]); + + // Transform the vertices in groups of three + gte_ldv3(&tmp[0], &tmp[1], &tmp[2]); + gte_rtpt(); + gte_stsxy0(&tmp[0].vx); + gte_stsxy1(&tmp[1].vx); + gte_stsxy2(&tmp[2].vx); + + gte_ldv3(&tmp[3], &tmp[4], &tmp[5]); + gte_rtpt(); + gte_stsxy0(&tmp[3].vx); + gte_stsxy1(&tmp[4].vx); + gte_stsxy2(&tmp[5].vx); + + gte_ldv3(&tmp[6], &tmp[7], &tmp[8]); + gte_rtpt(); + gte_stsxy0(&tmp[6].vx); + gte_stsxy1(&tmp[7].vx); + gte_stsxy2(&tmp[8].vx); + + // Draw the first quad + POLY_GT4 *poly = (POLY_GT4*)mem_prim(sizeof(POLY_GT4)); + setColorFast(&poly->x0, &tmp[0].vx); + setColorFast(&poly->r0, &tmp[0].r); + setUVFast(&poly->u0, &tmp[0].u); + poly->clut = quake_clut; + + setColorFast(&poly->x1, &tmp[3].vx); + setColorFast(&poly->r1, &tmp[3].r); + setUVFast(&poly->u1, &tmp[3].u); + poly->tpage = tpage; + + setColorFast(&poly->x2, &tmp[1].vx); + setColorFast(&poly->r2, &tmp[1].r); + setUVFast(&poly->u2, &tmp[1].u); + + setColorFast(&poly->x3, &tmp[4].vx); + setColorFast(&poly->r3, &tmp[4].r); + setUVFast(&poly->u3, &tmp[4].u); + + setPolyGT4(poly); + addPrim(ot, poly); + + // Second quad + poly = (POLY_GT4*)mem_prim(sizeof(POLY_GT4)); + setColorFast(&poly->x0, &tmp[1].vx); + setColorFast(&poly->r0, &tmp[1].r); + setUVFast(&poly->u0, &tmp[1].u); + poly->clut = quake_clut; + + setColorFast(&poly->x1, &tmp[4].vx); + setColorFast(&poly->r1, &tmp[4].r); + setUVFast(&poly->u1, &tmp[4].u); + poly->tpage = tpage; + + setColorFast(&poly->x2, &tmp[2].vx); + setColorFast(&poly->r2, &tmp[2].r); + setUVFast(&poly->u2, &tmp[2].u); + + setColorFast(&poly->x3, &tmp[5].vx); + setColorFast(&poly->r3, &tmp[5].r); + setUVFast(&poly->u3, &tmp[5].u); + + setPolyGT4(poly); + addPrim(ot, poly); + + // Third quad + poly = (POLY_GT4*)mem_prim(sizeof(POLY_GT4)); + setColorFast(&poly->x0, &tmp[3].vx); + setColorFast(&poly->r0, &tmp[3].r); + setUVFast(&poly->u0, &tmp[3].u); + poly->clut = quake_clut; + + setColorFast(&poly->x1, &tmp[6].vx); + setColorFast(&poly->r1, &tmp[6].r); + setUVFast(&poly->u1, &tmp[6].u); + poly->tpage = tpage; + + setColorFast(&poly->x2, &tmp[4].vx); + setColorFast(&poly->r2, &tmp[4].r); + setUVFast(&poly->u2, &tmp[4].u); + + setColorFast(&poly->x3, &tmp[7].vx); + setColorFast(&poly->r3, &tmp[7].r); + setUVFast(&poly->u3, &tmp[7].u); + + setPolyGT4(poly); + addPrim(ot, poly); + + // Fourth quad + poly = (POLY_GT4*)mem_prim(sizeof(POLY_GT4)); + setColorFast(&poly->x0, &tmp[4].vx); + setColorFast(&poly->r0, &tmp[4].r); + setUVFast(&poly->u0, &tmp[4].u); + poly->clut = quake_clut; + + setColorFast(&poly->x1, &tmp[7].vx); + setColorFast(&poly->r1, &tmp[7].r); + setUVFast(&poly->u1, &tmp[7].u); + poly->tpage = tpage; + + setColorFast(&poly->x2, &tmp[5].vx); + setColorFast(&poly->r2, &tmp[5].r); + setUVFast(&poly->u2, &tmp[5].u); + + setColorFast(&poly->x3, &tmp[8].vx); + setColorFast(&poly->r3, &tmp[8].r); + setUVFast(&poly->u3, &tmp[8].u); + + setPolyGT4(poly); + addPrim(ot, poly); + + polyCount += 4; + } +} + static INLINE void draw_quadstrip_water(const ps1bsp_vertex_t *vertices, const ps1bsp_polyvertex_t *polyVerts, u_char numVerts, u_short tpage, u_char semiTrans, u_long *ot) { // Draw the face as a quad strip diff --git a/n64e1m1.ps1bsp b/n64e1m1.ps1bsp index b47a0e2..1136465 100755 Binary files a/n64e1m1.ps1bsp and b/n64e1m1.ps1bsp differ diff --git a/n64start.ps1bsp b/n64start.ps1bsp index 98a07e5..4691da5 100755 Binary files a/n64start.ps1bsp and b/n64start.ps1bsp differ diff --git a/ps1bsp.h b/ps1bsp.h index e9adef3..5a0ebf1 100755 --- a/ps1bsp.h +++ b/ps1bsp.h @@ -63,7 +63,7 @@ typedef struct // This matches the SVECTOR data type; we can use the extra padding to store some more data. typedef struct { - short x, y, z; + short vx, vy, vz; short pad; } ps1bsp_vertex_t; diff --git a/world.c b/world.c index f329c90..0b75cf9 100644 --- a/world.c +++ b/world.c @@ -144,7 +144,7 @@ static void world_drawface_textured(const world_t *world, const ps1bsp_face_t *f const ps1bsp_texture_t *texture = &world->textures[face->textureId]; const ps1bsp_polygon_t* poly = &world->polygons[face->firstPolygon]; - // u_char tess = face->flags & 3; + u_char tess = face->flags & 3; // if (tess) // { // world_drawface_flat(world, face, &colors[tess - 1], ot); @@ -170,7 +170,10 @@ static void world_drawface_textured(const world_t *world, const ps1bsp_face_t *f draw_triangle_textured(world->vertices, polyVertices, texture->tpage, ot); break; default: - draw_quadstrip_textured(world->vertices, polyVertices, poly->numPolyVertices, texture->tpage, ot); + if (tess) + draw_quadstrip_tess2(world->vertices, polyVertices, poly->numPolyVertices, texture->tpage, ot); + else + draw_quadstrip_textured(world->vertices, polyVertices, poly->numPolyVertices, texture->tpage, ot); break; } }