diff --git a/main.cpp b/main.cpp index 9461681..b13066e 100644 --- a/main.cpp +++ b/main.cpp @@ -89,6 +89,7 @@ int process_faces(const world_t* world, const TextureList& textures) // Traverse the list of face edges to collect all of the face's vertices Vec3 vertexSum; + std::vector faceVertices; for (int edgeListIdx = 0; edgeListIdx < face->ledge_num; ++edgeListIdx) { int edgeIdx = world->edgeList[face->ledge_id + edgeListIdx]; @@ -97,8 +98,10 @@ int process_faces(const world_t* world, const TextureList& textures) world->edges[edgeIdx].vertex0 : world->edges[-edgeIdx].vertex1; + // TODO: some faces have redundant/degenerate vertices. We could optimize those by passing their polygons through GPC. const vertex_t* vertex = &world->vertices[vertIndex]; Vec3 vertexPoint = vertex->toVec(); + faceVertices.push_back(vertexPoint); // Calculate bounding boxes of this face Vec3 texturePoint = bounds.textureTransform.TransformPoint(vertexPoint); @@ -117,6 +120,30 @@ int process_faces(const world_t* world, const TextureList& textures) //if (face->ledge_num >= 10) // export_lightmap(world, face, bounds, faceIdx); + // Determine the face's bounding rectangle in world space (only four vertices, on the face's plane) + switch (faceVertices.size()) + { + case 3: // Special case: a triangle + for (int i = 0; i < 3; ++i) + outFace.bounds[i] = (unsigned short)tesselator.addVertex(faceVertices[i]); + + outFace.bounds[3] = outFace.bounds[2]; + break; + case 4: // Special case: a quad + for (int i = 0; i < 4; ++i) + outFace.bounds[i] = (unsigned short)tesselator.addVertex(faceVertices[i]); + + break; + default: + // TODO: this is far from optimal. We don't need a bounding rectangle, but a minimal bounding quad of any shape. Solve this problem: https://mathoverflow.net/questions/11580/minimum-area-bounding-quadrilateral-algorithm + bounds.textureTransform.Invert(); + outFace.bounds[0] = (unsigned short)tesselator.addVertex(bounds.textureTransform.TransformPoint(Vec3(bounds.textureBounds.min.x, bounds.textureBounds.min.y, 0.0f))); + outFace.bounds[1] = (unsigned short)tesselator.addVertex(bounds.textureTransform.TransformPoint(Vec3(bounds.textureBounds.min.x, bounds.textureBounds.max.y, 0.0f))); + outFace.bounds[2] = (unsigned short)tesselator.addVertex(bounds.textureTransform.TransformPoint(Vec3(bounds.textureBounds.max.x, bounds.textureBounds.max.y, 0.0f))); + outFace.bounds[3] = (unsigned short)tesselator.addVertex(bounds.textureTransform.TransformPoint(Vec3(bounds.textureBounds.max.x, bounds.textureBounds.min.y, 0.0f))); + break; + } + outFace.numFaceVertices = (unsigned char)(outFaceVertices.size() - outFace.firstFaceVertex); outFace.center = (vertexSum / face->ledge_num).convertWorldPosition(); double area = face_computeArea(world, face); @@ -124,7 +151,7 @@ int process_faces(const world_t* world, const TextureList& textures) outFaces.push_back(outFace); } - printf("Tesselating faces...\n"); + printf("Tessellating faces...\n"); std::vector outPolyVertices; std::vector outPolygons; @@ -248,7 +275,7 @@ int process_faces(const world_t* world, const TextureList& textures) outPoly.numPolyVertices = (unsigned short)(outPolyVertices.size() - outPoly.firstPolyVertex); outPolygons.push_back(outPoly); - outFace->totalQuads += (outPoly.numPolyVertices - 1) / 2; + outFace->totalPrimitives += (outPoly.numPolyVertices - 1) / 2; } outFace->numPolygons = (unsigned char)(outPolygons.size() - outFace->firstPolygon); diff --git a/ps1bsp.h b/ps1bsp.h index c87932a..ab0f07d 100644 --- a/ps1bsp.h +++ b/ps1bsp.h @@ -106,10 +106,14 @@ typedef struct ps1bsp_face_s unsigned short planeId; unsigned char side; + // TODO: not sure if we should make separate lists for triangles and non-triangle polygons here + // Could potentially improve drawing performance but at the cost of more memory use per face + // Used for high-quality tesselated textured drawing unsigned short firstPolygon; unsigned char numPolygons; - unsigned char totalQuads; + + unsigned char totalPrimitives; // Used for early primitive buffer checks // Used for low-quality untextured vertex colored drawing unsigned short firstFaceVertex; @@ -120,6 +124,7 @@ typedef struct ps1bsp_face_s // Used for backface culling SVECTOR center; + unsigned short bounds[4]; // Run-time data const struct ps1bsp_face_s* nextFace; // For chaining faces in drawing order