diff --git a/bsp.h b/bsp.h index be9ff20..1cd6978 100644 --- a/bsp.h +++ b/bsp.h @@ -172,7 +172,7 @@ typedef struct unsigned char sndlava; // } dleaf_t; -typedef struct +typedef struct World { const char* name; dheader_t header; @@ -214,4 +214,62 @@ typedef struct int lightmapLength; unsigned char* lightmap; + // Find the list of all faces that contain the given point, i.e. the point lies on the face's plane and is contained within its polygon bounds + std::vector facesWithPoint(const Vec3& point) const + { + std::vector outFaces; + for (int faceIdx = 0; faceIdx < numFaces; ++faceIdx) + { + const face_t* face = &faces[faceIdx]; + const plane_t* plane = &planes[face->plane_id]; + + // Check if the point lies on the face's plane (it's not strictly necessary to do this, but this check makes the whole function a lot faster) + double pointPlaneDist = ((double)point.x * plane->normal.x + (double)point.y * plane->normal.y + (double)point.z * plane->normal.z) - plane->dist; + if (fabs(pointPlaneDist) > 0.0001) + continue; + + // Check if the point is contained within the face's polygon + double angleSum = 0; + for (int edgeListIdx = 0; edgeListIdx < face->ledge_num; ++edgeListIdx) + { + int edgeIdx = edgeList[face->ledge_id + edgeListIdx]; + + Vec3 v0, v1; + if (edgeIdx > 0) + { + const edge_t* edge = &edges[edgeIdx]; + v0 = vertices[edge->vertex0].toVec(); + v1 = vertices[edge->vertex1].toVec(); + } + else + { + const edge_t* edge = &edges[-edgeIdx]; + v0 = vertices[edge->vertex1].toVec(); + v1 = vertices[edge->vertex0].toVec(); + } + + Vec3 p0 = v0 - point; + Vec3 p1 = v1 - point; + double m0 = p0.magnitude(); + double m1 = p1.magnitude(); + + if ((m0 * m1) <= 0.0001) + { + // Point is on one of the vertices + outFaces.push_back(face); + break; + } + + double dot = p0.dotProduct(p1) / (m0 * m1); + angleSum += acos(dot); + } + + // If the point is inside the polygon, then the sum of all the above angles will be exactly 360 degrees + if (fabs(2 * M_PI - angleSum) <= 0.0001) + outFaces.push_back(face); + } + + return outFaces; + } + } world_t; diff --git a/lighting.cpp b/lighting.cpp index 3444a68..0d3544e 100644 --- a/lighting.cpp +++ b/lighting.cpp @@ -325,139 +325,9 @@ SurfaceList group_surfaces(const world_t* world, const VertexFaces& vertexFaces) return surfaces; } -// To sample lightmap at any arbitrary world position: -// - Find the surface that the face belongs to -// - Select all faces from the surface where the position lies in its plane and is inside polygon boundaries -// - Sample those faces at the specified position (sample_lightmap) and average -std::vector find_facesWithPoint(const world_t* world, const face_t* refFace, const SurfaceList& surfaces, Vec3 point) -{ - std::vector faces; - - // Find the surface that the face belongs to - for (auto surfIter = surfaces.begin(); surfIter != surfaces.end(); ++surfIter) - { - if (surfIter->faces.find(refFace) == surfIter->faces.end()) - continue; - - // Select all faces from the surface where the point lies in its plane and is inside polygon boundaries - for (auto faceIter = surfIter->faces.begin(); faceIter != surfIter->faces.end(); ++faceIter) - { - const face_t* face = *faceIter; - const plane_t* plane = &world->planes[face->plane_id]; - - // Check if the point lies on the face's plane - float pointPlaneDist = (point.x * plane->normal.x + point.y * plane->normal.y + point.z * plane->normal.z) - plane->dist; - if (fabs(pointPlaneDist) > FLT_EPSILON) - continue; - - // Simple case first: check if this point lies on one of the face's edges - bool onEdge = false; - for (int edgeListIdx = 0; edgeListIdx < face->ledge_num; ++edgeListIdx) - { - int edgeIdx = world->edgeList[face->ledge_id + edgeListIdx]; - const edge_t* edge = &world->edges[abs(edgeIdx)]; - - Vec3 vert0 = world->vertices[edge->vertex0].toVec(); - Vec3 vert1 = world->vertices[edge->vertex1].toVec(); - - Vec3 dir0 = vert1 - vert0; - Vec3 dir1 = point - vert0; - float mag0 = dir0.magnitude(); - float mag1 = dir1.magnitude(); - - if (mag1 / mag0 <= 1.0f + FLT_EPSILON && dir0.dotProduct(dir1) >= (mag0 - FLT_EPSILON) * (mag1 - FLT_EPSILON)) - onEdge = true; - } - - if (onEdge) - faces.push_back(face); - } - - break; - } - - return faces; -} - -// Further improvements: -// - Reconstruct connected surfaces through vertices and edges, so we can fully sample all adjacent lightmaps. -// Right now we don't properly detect when one face has vertices halfway along the edge of an adjacent face. -// - Sample more lightmap points around each vertex to obtain a more representative average value -unsigned char compute_faceVertex_light3(const world_t* world, const face_t* refFace, const SurfaceList& surfaces, const FaceBounds& faceBounds, Vec3 point) -{ - auto faces = find_facesWithPoint(world, refFace, surfaces, point); - if (faces.empty()) - return 0; - - unsigned int light = 0; - for (auto faceIter = faces.begin(); faceIter != faces.end(); ++faceIter) - { - const face_t* face = *faceIter; - light += sample_lightmap(world, face, faceBounds.find(face)->second, point) + (0xFF - face->baselight); - } - - return (unsigned char)(light / faces.size()); -} - -// Find the list of all faces that contain the given point, i.e. the point lies on the face's plane and is contained within its polygon bounds -std::vector world_facesWithPoint(const world_t* world, Vec3 point) -{ - std::vector faces; - for (int faceIdx = 0; faceIdx < world->numFaces; ++faceIdx) - { - const face_t* face = &world->faces[faceIdx]; - const plane_t* plane = &world->planes[face->plane_id]; - - // Check if the point lies on the face's plane (it's not strictly necessary to do this, but this check makes the whole function a lot faster) - double pointPlaneDist = ((double)point.x * plane->normal.x + (double)point.y * plane->normal.y + (double)point.z * plane->normal.z) - plane->dist; - if (fabs(pointPlaneDist) > 0.0001) - continue; - - // Check if the point is contained within the face's polygon - double angleSum = 0; - for (int edgeListIdx = 0; edgeListIdx < face->ledge_num; ++edgeListIdx) - { - int edgeIdx = world->edgeList[face->ledge_id + edgeListIdx]; - - Vec3 v0, v1; - if (edgeIdx > 0) - { - const edge_t* edge = &world->edges[edgeIdx]; - v0 = world->vertices[edge->vertex0].toVec(); - v1 = world->vertices[edge->vertex1].toVec(); - } - else - { - const edge_t* edge = &world->edges[-edgeIdx]; - v0 = world->vertices[edge->vertex1].toVec(); - v1 = world->vertices[edge->vertex0].toVec(); - } - - Vec3 p0 = v0 - point; - Vec3 p1 = v1 - point; - double m0 = p0.magnitude(); - double m1 = p1.magnitude(); - - if ((m0 * m1) <= 0.0001) - { - faces.push_back(face); - break; - } - - double dot = p0.dotProduct(p1) / (m0 * m1); - angleSum += acos(dot); - } - - if (fabs(2 * M_PI - angleSum) <= 0.0001) - faces.push_back(face); - } - - return faces; -} - unsigned char compute_faceVertex_light4(const world_t* world, const face_t* refFace, const FaceBounds& faceBounds, Vec3 point) { - auto faces = world_facesWithPoint(world, point); + auto faces = world->facesWithPoint(point); if (faces.empty()) return 0; diff --git a/lighting.h b/lighting.h index bfabc7f..066813a 100644 --- a/lighting.h +++ b/lighting.h @@ -27,6 +27,4 @@ unsigned char compute_faceVertex_light(const world_t* world, const face_t* face, unsigned char compute_faceVertex_light2(const world_t* world, const face_t* face, unsigned short vertexIndex, const FaceBounds& faceBounds, const VertexFaces& vertexFaces); SurfaceList group_surfaces(const world_t* world, const VertexFaces& vertexFaces); -unsigned char compute_faceVertex_light3(const world_t* world, const face_t* refFace, const SurfaceList& surfaces, const FaceBounds& faceBounds, Vec3 point); - unsigned char compute_faceVertex_light4(const world_t* world, const face_t* refFace, const FaceBounds& faceBounds, Vec3 point);