|
|
@ -164,6 +164,52 @@ static void leaf_zone(const dleaf_t* leaf, short zone[3]) |
|
|
zone[2] = midZ & mask; |
|
|
zone[2] = midZ & mask; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static unsigned char sample_lightmap(const world_t* world, const face_t *face, const BoundBox& bounds, const Vec3& point) |
|
|
|
|
|
{ |
|
|
|
|
|
if (face->lightmap < 0) |
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
|
|
const unsigned char* lightmap = &world->lightmap[face->lightmap]; |
|
|
|
|
|
const plane_t* plane = &world->planes[face->plane_id]; |
|
|
|
|
|
|
|
|
|
|
|
float w, h, u, v; |
|
|
|
|
|
switch (plane->type) |
|
|
|
|
|
{ |
|
|
|
|
|
case 0: |
|
|
|
|
|
case 3: |
|
|
|
|
|
// Towards X
|
|
|
|
|
|
w = bounds.max.y - bounds.min.y; |
|
|
|
|
|
h = bounds.max.z - bounds.min.z; |
|
|
|
|
|
u = (point.y - bounds.min.y) / w; |
|
|
|
|
|
v = (point.z - bounds.min.z) / h; |
|
|
|
|
|
break; |
|
|
|
|
|
case 1: |
|
|
|
|
|
case 4: |
|
|
|
|
|
// Towards Y
|
|
|
|
|
|
w = bounds.max.x - bounds.min.x; |
|
|
|
|
|
h = bounds.max.z - bounds.min.z; |
|
|
|
|
|
u = (point.x - bounds.min.x) / w; |
|
|
|
|
|
v = (point.z - bounds.min.z) / h; |
|
|
|
|
|
break; |
|
|
|
|
|
case 2: |
|
|
|
|
|
case 5: |
|
|
|
|
|
// Towards Z
|
|
|
|
|
|
w = bounds.max.x - bounds.min.x; |
|
|
|
|
|
h = bounds.max.y - bounds.min.y; |
|
|
|
|
|
u = (point.x - bounds.min.x) / w; |
|
|
|
|
|
v = (point.y - bounds.min.y) / h; |
|
|
|
|
|
break; |
|
|
|
|
|
default: |
|
|
|
|
|
printf("Error: unknown plane type %d\n", plane->type); |
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int width = (int)(w / 16); |
|
|
|
|
|
int height = (int)(h / 16); |
|
|
|
|
|
|
|
|
|
|
|
return lightmap[(int)((height * v + u) * width)]; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
int process_faces(const world_t* world) |
|
|
int process_faces(const world_t* world) |
|
|
{ |
|
|
{ |
|
|
// Write some data to a file
|
|
|
// Write some data to a file
|
|
|
@ -185,10 +231,18 @@ int process_faces(const world_t* world) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Write vertex data to a file (no vertex splitting yet)
|
|
|
// Write vertex data to a file (no vertex splitting yet)
|
|
|
|
|
|
BoundBox bounds; |
|
|
|
|
|
std::vector<ps1bsp_vertex_t> outVertices; |
|
|
for (unsigned short i = 0; i < world->numVertices; ++i) |
|
|
for (unsigned short i = 0; i < world->numVertices; ++i) |
|
|
{ |
|
|
{ |
|
|
// TODO: we should respect the ordering from vertexRef->index here but meh, problem for later
|
|
|
// TODO: we should respect the ordering from vertexRef->index here but meh, problem for later
|
|
|
vertex_t* inVertex = &world->vertices[i]; |
|
|
vertex_t* inVertex = &world->vertices[i]; |
|
|
|
|
|
|
|
|
|
|
|
if (i == 0) |
|
|
|
|
|
bounds.init(inVertex->toVec()); |
|
|
|
|
|
else |
|
|
|
|
|
bounds.includePoint(inVertex->toVec()); |
|
|
|
|
|
|
|
|
ps1bsp_vertex_t outVertex = { 0 }; |
|
|
ps1bsp_vertex_t outVertex = { 0 }; |
|
|
// Ensure we don't overflow 16-bit short values. Most Quake maps will stay within these bounds so it *should* be fine (for now).
|
|
|
// Ensure we don't overflow 16-bit short values. Most Quake maps will stay within these bounds so it *should* be fine (for now).
|
|
|
if (inVertex->X > -8192 && inVertex->X < 8192 && inVertex->Y > -8192 && inVertex->Y < 8192 && inVertex->Z > -8192 && inVertex->Z < 8192) |
|
|
if (inVertex->X > -8192 && inVertex->X < 8192 && inVertex->Y > -8192 && inVertex->Y < 8192 && inVertex->Z > -8192 && inVertex->Z < 8192) |
|
|
@ -197,10 +251,11 @@ int process_faces(const world_t* world) |
|
|
outVertex.y = (short)(inVertex->Y * 4); |
|
|
outVertex.y = (short)(inVertex->Y * 4); |
|
|
outVertex.z = (short)(inVertex->Z * 4); |
|
|
outVertex.z = (short)(inVertex->Z * 4); |
|
|
} |
|
|
} |
|
|
outVertex.baseLight = 128; |
|
|
|
|
|
outVertex.finalLight = 128; |
|
|
|
|
|
|
|
|
outVertex.baseLight = 0; |
|
|
|
|
|
outVertex.finalLight = 0; |
|
|
|
|
|
outVertex.r = 0; |
|
|
|
|
|
|
|
|
fwrite(&outVertex, sizeof(ps1bsp_vertex_t), 1, fbsp); |
|
|
|
|
|
|
|
|
outVertices.push_back(outVertex); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
std::vector<ps1bsp_triangle_t> outTriangles; |
|
|
std::vector<ps1bsp_triangle_t> outTriangles; |
|
|
@ -224,32 +279,38 @@ int process_faces(const world_t* world) |
|
|
world->edges[-edgeIdx].vertex1; |
|
|
world->edges[-edgeIdx].vertex1; |
|
|
|
|
|
|
|
|
faceVertIndices.push_back(vertIndex); |
|
|
faceVertIndices.push_back(vertIndex); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//printf("Face %d: %d vertices\n", faceIdx, faceVerts.size());
|
|
|
|
|
|
|
|
|
|
|
|
// Triangulate face into polygons (triangle fan, the naive method)
|
|
|
|
|
|
// TODO better method: generate a quad strip topology
|
|
|
|
|
|
ps1bsp_triangle_t outTriangle; |
|
|
|
|
|
outTriangle.vertex0 = faceVertIndices[0]; |
|
|
|
|
|
for (int faceVertIdx = 1; faceVertIdx < faceVertIndices.size() - 1; ++faceVertIdx) |
|
|
|
|
|
|
|
|
unsigned char light = sample_lightmap(world, face, bounds, world->vertices[vertIndex].toVec()); |
|
|
|
|
|
if (light > 0) |
|
|
{ |
|
|
{ |
|
|
outTriangle.vertex1 = faceVertIndices[faceVertIdx]; |
|
|
|
|
|
outTriangle.vertex2 = faceVertIndices[faceVertIdx + 1]; |
|
|
|
|
|
|
|
|
|
|
|
outTriangles.push_back(outTriangle); |
|
|
|
|
|
|
|
|
*(unsigned short*)(&outVertices[vertIndex].baseLight) += light; |
|
|
|
|
|
outVertices[vertIndex].r++; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
outFace.numVertices = faceVertIndices.size() - outFace.firstVertexIndex; |
|
|
outFace.numVertices = faceVertIndices.size() - outFace.firstVertexIndex; |
|
|
outFaces.push_back(outFace); |
|
|
outFaces.push_back(outFace); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Average the lightmap values for this vertex
|
|
|
|
|
|
for (auto iter = outVertices.begin(); iter != outVertices.end(); ++iter) |
|
|
|
|
|
{ |
|
|
|
|
|
unsigned char count = (*iter).r; |
|
|
|
|
|
if (count == 0) |
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
unsigned short accumulate = *(unsigned short*)(&(*iter).baseLight); |
|
|
|
|
|
(*iter).baseLight = accumulate / count; |
|
|
|
|
|
(*iter).r = 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// Write triangle and face data to file
|
|
|
// 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(faceVertIndices.data(), sizeof(unsigned short), faceVertIndices.size(), fbsp); |
|
|
fwrite(outFaces.data(), sizeof(ps1bsp_face_t), outFaces.size(), fbsp); |
|
|
fwrite(outFaces.data(), sizeof(ps1bsp_face_t), outFaces.size(), fbsp); |
|
|
|
|
|
|
|
|
// Update header information
|
|
|
// Update header information
|
|
|
outHeader.numVertices = world->numVertices; |
|
|
|
|
|
|
|
|
outHeader.numVertices = outVertices.size(); |
|
|
outHeader.numFaceVertIndices = faceVertIndices.size(); |
|
|
outHeader.numFaceVertIndices = faceVertIndices.size(); |
|
|
outHeader.numFaces = outFaces.size(); |
|
|
outHeader.numFaces = outFaces.size(); |
|
|
|
|
|
|
|
|
@ -440,6 +501,15 @@ int load_bsp(const char* bspname, world_t* world) |
|
|
fseek(f, header->leaves.offset, SEEK_SET); |
|
|
fseek(f, header->leaves.offset, SEEK_SET); |
|
|
fread(world->leaves, sizeof(dleaf_t), world->numLeaves, f); |
|
|
fread(world->leaves, sizeof(dleaf_t), world->numLeaves, f); |
|
|
|
|
|
|
|
|
|
|
|
// Load lightmaps
|
|
|
|
|
|
world->lightmapLength = header->lightmaps.size / sizeof(unsigned char); |
|
|
|
|
|
world->lightmap = (unsigned char*)malloc(header->lightmaps.size); |
|
|
|
|
|
if (world->lightmap == NULL) |
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
|
|
fseek(f, header->lightmaps.offset, SEEK_SET); |
|
|
|
|
|
fread(world->lightmap, sizeof(unsigned char), world->lightmapLength, f); |
|
|
|
|
|
|
|
|
fclose(f); |
|
|
fclose(f); |
|
|
return 1; |
|
|
return 1; |
|
|
} |
|
|
} |
|
|
|