Browse Source

Faces now have a vertex index list, which is more space-efficient and allows easy rewrites of polygon topology.

Also works quite well with the scratchpad RAM setup.
tess_experiment
Nico de Poel 3 years ago
parent
commit
f8a4d171a3
  1. 9
      ps1bsp.h
  2. BIN
      test.ps1bsp
  3. 39
      world.c
  4. 2
      world.h

9
ps1bsp.h

@ -22,7 +22,7 @@ Probable rendering process:
typedef struct typedef struct
{ {
unsigned short numVertices; unsigned short numVertices;
unsigned short numTriangles;
unsigned short numFaceVertIndices;
unsigned short numFaces; unsigned short numFaces;
} ps1bsp_header_t; } ps1bsp_header_t;
@ -62,11 +62,8 @@ typedef struct
typedef struct typedef struct
{ {
unsigned short firstTriangleId; // TODO: could also just do first-index, num-indices here. No real need for a triangle_t struct.
unsigned short numTriangles;
unsigned short firstQuadId; // For if/when we decide to add quads to the mix
unsigned short numQuads;
unsigned short firstVertexIndex;
unsigned short numVertices;
} ps1bsp_face_t; } ps1bsp_face_t;
// Pre-parsed and encoded entity data (this runs the risk of becoming too bloated) // Pre-parsed and encoded entity data (this runs the risk of becoming too bloated)

BIN
test.ps1bsp

39
world.c

@ -31,8 +31,8 @@ void world_load(const u_long *data, world_t *world)
world->vertices = (ps1bsp_vertex_t*)bytes; world->vertices = (ps1bsp_vertex_t*)bytes;
bytes += sizeof(ps1bsp_vertex_t) * world->header->numVertices; bytes += sizeof(ps1bsp_vertex_t) * world->header->numVertices;
world->triangles = (ps1bsp_triangle_t*)bytes;
bytes += sizeof(ps1bsp_triangle_t) * world->header->numTriangles;
world->faceVertIndices = (unsigned short*)bytes;
bytes += sizeof(unsigned short) * world->header->numFaceVertIndices;
world->faces = (ps1bsp_face_t*)bytes; world->faces = (ps1bsp_face_t*)bytes;
bytes += sizeof(ps1bsp_face_t) * world->header->numFaces; bytes += sizeof(ps1bsp_face_t) * world->header->numFaces;
@ -46,35 +46,26 @@ void world_draw(const world_t *world)
gte_SetRotMatrix(&vp_matrix); gte_SetRotMatrix(&vp_matrix);
gte_SetTransMatrix(&vp_matrix); gte_SetTransMatrix(&vp_matrix);
char *scratch = scratchpad;
SVECTOR *vecs = (SVECTOR*)mem_scratch(&scratch, sizeof(SVECTOR) * 3);
for (int faceIdx = 0; faceIdx < world->header->numFaces; ++faceIdx) for (int faceIdx = 0; faceIdx < world->header->numFaces; ++faceIdx)
{ {
const ps1bsp_face_t *face = &world->faces[faceIdx]; const ps1bsp_face_t *face = &world->faces[faceIdx];
const CVECTOR *col = &colors[faceIdx % numColors]; const CVECTOR *col = &colors[faceIdx % numColors];
const ps1bsp_triangle_t *tri = &world->triangles[face->firstTriangleId];
for (int triangleIdx = 0; triangleIdx < face->numTriangles; ++triangleIdx, ++tri)
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)
{ {
// 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);
vecs[vertIdx] = *((SVECTOR*)&world->vertices[*faceVertIndex]);
}
// Draw the face as a triangle fan
for (int vertIdx = 1; vertIdx < face->numVertices - 1; ++vertIdx)
{
// Naively draw the triangle with GTE, nothing special or optimized about this
gte_ldv3(&vecs[0], &vecs[vertIdx], &vecs[vertIdx + 1]);
gte_rtpt(); // Rotation, translation, perspective projection gte_rtpt(); // Rotation, translation, perspective projection
// Normal clipping for backface culling // Normal clipping for backface culling

2
world.h

@ -7,7 +7,7 @@ typedef struct
{ {
ps1bsp_header_t *header; ps1bsp_header_t *header;
ps1bsp_vertex_t *vertices; ps1bsp_vertex_t *vertices;
ps1bsp_triangle_t *triangles;
unsigned short *faceVertIndices;
ps1bsp_face_t *faces; ps1bsp_face_t *faces;
} world_t; } world_t;

Loading…
Cancel
Save