From f596c008d7b34cf90ed363ab4c568169c5b2becb Mon Sep 17 00:00:00 2001 From: Nico de Poel Date: Mon, 16 Jan 2023 15:17:21 +0100 Subject: [PATCH] Store sampled light data per face vertex, so we can individually light each face without having to average lighting values. Keeping averaged light per vertex intact for now, as sampling isn't quite perfect yet and I like to have some options. --- main.cpp | 57 ++++++++++++++++++++++++++++---------------------------- ps1bsp.h | 15 ++++++--------- 2 files changed, 35 insertions(+), 37 deletions(-) diff --git a/main.cpp b/main.cpp index d61f768..545b7e3 100644 --- a/main.cpp +++ b/main.cpp @@ -225,20 +225,20 @@ static void export_lightmap(const world_t* world, const face_t* face, const Boun case 0: case 3: // Towards X - width = ceil(bounds.max.y / 16) - floor(bounds.min.y / 16); - height = ceil(bounds.max.z / 16) - floor(bounds.min.z / 16); + width = (int)(ceil(bounds.max.y / 16) - floor(bounds.min.y / 16)); + height = (int)(ceil(bounds.max.z / 16) - floor(bounds.min.z / 16)); break; case 1: case 4: // Towards Y - width = ceil(bounds.max.x / 16) - floor(bounds.min.x / 16); - height = ceil(bounds.max.z / 16) - floor(bounds.min.z / 16); + width = (int)(ceil(bounds.max.x / 16) - floor(bounds.min.x / 16)); + height = (int)(ceil(bounds.max.z / 16) - floor(bounds.min.z / 16)); break; case 2: case 5: // Towards Z - width = ceil(bounds.max.x / 16) - floor(bounds.min.x / 16); - height = ceil(bounds.max.y / 16) - floor(bounds.min.y / 16); + width = (int)(ceil(bounds.max.x / 16) - floor(bounds.min.x / 16)); + height = (int)(ceil(bounds.max.y / 16) - floor(bounds.min.y / 16)); break; default: printf("Error: unknown plane type %d\n", plane->type); @@ -297,23 +297,18 @@ int process_faces(const world_t* world) outVertex.y = (short)(inVertex->Y * 4); outVertex.z = (short)(inVertex->Z * 4); } - outVertex.baseLight = 0; - outVertex.finalLight = 0; - outVertex.r = 0; outVertices.push_back(outVertex); } - std::vector outTriangles; std::vector outFaces; - - std::vector faceVertIndices; + std::vector outFaceVertices; for (int faceIdx = 0; faceIdx < world->numFaces; ++faceIdx) { face_t* face = &world->faces[faceIdx]; ps1bsp_face_t outFace = { 0 }; - outFace.firstVertexIndex = faceVertIndices.size(); + outFace.firstFaceVertex = (unsigned short)outFaceVertices.size(); // Traverse the list of face edges to collect all of the face's vertices BoundBox bounds; @@ -325,7 +320,10 @@ int process_faces(const world_t* world) world->edges[edgeIdx].vertex0 : world->edges[-edgeIdx].vertex1; - faceVertIndices.push_back(vertIndex); + ps1bsp_facevertex_t faceVertex; + faceVertex.index = vertIndex; + faceVertex.light = 0; + outFaceVertices.push_back(faceVertex); // Calculate bounding box of this face const vertex_t* vertex = &world->vertices[vertIndex]; @@ -335,15 +333,18 @@ int process_faces(const world_t* world) bounds.includePoint(vertex->toVec()); } - // Accumulate lightmap contribution of this face on each vertex - if (face->lightmap >= 0) + // Sample lightmap contribution of this face on each vertex + for (size_t faceVertIdx = outFace.firstFaceVertex; faceVertIdx < outFaceVertices.size(); ++faceVertIdx) { - for (int indexIdx = outFace.firstVertexIndex; indexIdx < faceVertIndices.size(); ++indexIdx) + ps1bsp_facevertex_t& faceVertex = outFaceVertices[faceVertIdx]; + unsigned char lightmap = sample_lightmap(world, face, bounds, world->vertices[faceVertex.index].toVec()); + faceVertex.light = lightmap + (0xFF - face->baselight); + + if (face->lightmap >= 0) { - int vertIndex = faceVertIndices[indexIdx]; - unsigned char light = sample_lightmap(world, face, bounds, world->vertices[vertIndex].toVec()); - *(unsigned short*)(&outVertices[vertIndex].baseLight) += light + (0xFF - face->baselight); - outVertices[vertIndex].r++; + ps1bsp_vertex_t& vertex = outVertices[faceVertex.index]; + *(unsigned short*)(&vertex.baseLight) += faceVertex.light; + vertex.r++; } } @@ -351,11 +352,11 @@ int process_faces(const world_t* world) //if (face->ledge_num >= 10) // export_lightmap(world, face, bounds, faceIdx); - outFace.numVertices = faceVertIndices.size() - outFace.firstVertexIndex; + outFace.numFaceVertices = (unsigned short)(outFaceVertices.size() - outFace.firstFaceVertex); outFaces.push_back(outFace); } - // Average the lightmap values for this vertex + // Average the lightmap values for each vertex for (auto iter = outVertices.begin(); iter != outVertices.end(); ++iter) { unsigned char count = (*iter).r; @@ -369,20 +370,20 @@ int process_faces(const world_t* world) // Write triangle and face data to file fwrite(outVertices.data(), sizeof(ps1bsp_vertex_t), outVertices.size(), fbsp); - fwrite(faceVertIndices.data(), sizeof(unsigned short), faceVertIndices.size(), fbsp); + fwrite(outFaceVertices.data(), sizeof(ps1bsp_facevertex_t), outFaceVertices.size(), fbsp); fwrite(outFaces.data(), sizeof(ps1bsp_face_t), outFaces.size(), fbsp); // Update header information - outHeader.numVertices = outVertices.size(); - outHeader.numFaceVertIndices = faceVertIndices.size(); - outHeader.numFaces = outFaces.size(); + outHeader.numVertices = (unsigned short)outVertices.size(); + outHeader.numFaceVertices = (unsigned short)outFaceVertices.size(); + outHeader.numFaces = (unsigned short)outFaces.size(); // Write final header fseek(fbsp, 0, SEEK_SET); fwrite(&outHeader, sizeof(ps1bsp_header_t), 1, fbsp); fclose(fbsp); - printf("PS1BSP: wrote %d vertices, %d indices, %d faces\n", outHeader.numVertices, outHeader.numFaceVertIndices, outHeader.numFaces); + printf("PS1BSP: wrote %d vertices, %d indices, %d faces\n", outHeader.numVertices, outHeader.numFaceVertices, outHeader.numFaces); return 1; } diff --git a/ps1bsp.h b/ps1bsp.h index eafbc55..b1e27d3 100644 --- a/ps1bsp.h +++ b/ps1bsp.h @@ -22,7 +22,7 @@ Probable rendering process: typedef struct { unsigned short numVertices; - unsigned short numFaceVertIndices; + unsigned short numFaceVertices; unsigned short numFaces; } ps1bsp_header_t; @@ -51,19 +51,16 @@ typedef struct unsigned char b : 5; } ps1bsp_vertex_t; -// Instead of edges as in the original BSP format, we store triangles for easy consumption by the PS1 -// Note: it may actually be more efficient to render quads for faces with 4+ vertices typedef struct { - unsigned short vertex0; - unsigned short vertex1; - unsigned short vertex2; -} ps1bsp_triangle_t; + unsigned short index; + unsigned char light; +} ps1bsp_facevertex_t; typedef struct { - unsigned short firstVertexIndex; - unsigned short numVertices; + unsigned short firstFaceVertex; + unsigned short numFaceVertices; } ps1bsp_face_t; // Pre-parsed and encoded entity data (this runs the risk of becoming too bloated)