Browse Source

First implementation of near-camera polygon tessellation, which surprisingly actually worked on the first try!

Currently still rather inefficient, making no use of GTE for interpolation yet. Still only one tessellation level too.
master
Nico de Poel 3 years ago
parent
commit
02b19a67dc
  1. 189
      draw.h
  2. BIN
      n64e1m1.ps1bsp
  3. BIN
      n64start.ps1bsp
  4. 2
      ps1bsp.h
  5. 7
      world.c

189
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) 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 // Draw the face as a quad strip

BIN
n64e1m1.ps1bsp

BIN
n64start.ps1bsp

2
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. // This matches the SVECTOR data type; we can use the extra padding to store some more data.
typedef struct typedef struct
{ {
short x, y, z;
short vx, vy, vz;
short pad; short pad;
} ps1bsp_vertex_t; } ps1bsp_vertex_t;

7
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_texture_t *texture = &world->textures[face->textureId];
const ps1bsp_polygon_t* poly = &world->polygons[face->firstPolygon]; const ps1bsp_polygon_t* poly = &world->polygons[face->firstPolygon];
// u_char tess = face->flags & 3;
u_char tess = face->flags & 3;
// if (tess) // if (tess)
// { // {
// world_drawface_flat(world, face, &colors[tess - 1], ot); // 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); draw_triangle_textured(world->vertices, polyVertices, texture->tpage, ot);
break; break;
default: 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; break;
} }
} }

Loading…
Cancel
Save