Browse Source

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.
master
Nico de Poel 3 years ago
parent
commit
f596c008d7
  1. 57
      main.cpp
  2. 15
      ps1bsp.h

57
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<ps1bsp_triangle_t> outTriangles;
std::vector<ps1bsp_face_t> outFaces;
std::vector<unsigned short> faceVertIndices;
std::vector<ps1bsp_facevertex_t> 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;
}

15
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)

Loading…
Cancel
Save