Browse Source

First test with GPC to cut faces into multiple polygons, based on a grid of texture boundaries. Reconstruct the texture space (s,t) coordinates back into world space. Store vertices and indices while avoiding duplicate vertices.

master
Nico de Poel 3 years ago
parent
commit
f413e8c47f
  1. 23
      common.h
  2. 102
      main.cpp

23
common.h

@ -82,6 +82,29 @@ typedef struct Vec3 // Vector or Position
} }
} vec3_t; } vec3_t;
template<> struct std::hash<Vec3>
{
std::uint64_t operator()(const Vec3& vec) const
{
int x = (int)(vec.x * 100);
int y = (int)(vec.y * 100);
int z = (int)(vec.z * 100);
return
(*((uint64_t*)&x) << 40) |
(*((uint64_t*)&y) << 20) |
(*((uint64_t*)&z) << 0);
}
};
static bool operator==(const Vec3& lhs, const Vec3& rhs)
{
return
fabs(rhs.x - lhs.x) < 0.001 &&
fabs(rhs.y - lhs.y) < 0.001 &&
fabs(rhs.z - lhs.z) < 0.001;
}
static float halton(int32_t index, int32_t base) static float halton(int32_t index, int32_t base)
{ {
float f = 1.0f, result = 0.0f; float f = 1.0f, result = 0.0f;

102
main.cpp

@ -4,9 +4,12 @@
#include "ps1bsp.h" #include "ps1bsp.h"
#include "lighting.h" #include "lighting.h"
#include "texture.h" #include "texture.h"
#include "gpc.h"
static char path[_MAX_PATH]; static char path[_MAX_PATH];
void gpc_test(const world_t* world, const face_t* face);
template<class TData> size_t writeMapData(const std::vector<TData>& data, ps1bsp_dentry_t& dentry, FILE* f) template<class TData> size_t writeMapData(const std::vector<TData>& data, ps1bsp_dentry_t& dentry, FILE* f)
{ {
dentry.offset = (unsigned int)ftell(f); dentry.offset = (unsigned int)ftell(f);
@ -204,6 +207,8 @@ int process_faces(const world_t* world, const std::vector<ps1bsp_texture_t>& tex
float area = computeFaceArea(world, face); float area = computeFaceArea(world, face);
outFace.center.pad = (short)(sqrt(area)); outFace.center.pad = (short)(sqrt(area));
outFaces.push_back(outFace); outFaces.push_back(outFace);
gpc_test(world, face);
} }
// Iterate over all faces again; now that we know the bounds of each face, we can calculate lighting for all of them // Iterate over all faces again; now that we know the bounds of each face, we can calculate lighting for all of them
@ -218,7 +223,7 @@ int process_faces(const world_t* world, const std::vector<ps1bsp_texture_t>& tex
ps1bsp_facevertex_t& faceVertex = outFaceVertices[outFace.firstFaceVertex + faceVertIdx]; ps1bsp_facevertex_t& faceVertex = outFaceVertices[outFace.firstFaceVertex + faceVertIdx];
const vertex_t* vertex = &world->vertices[faceVertex.index]; const vertex_t* vertex = &world->vertices[faceVertex.index];
faceVertex.light = compute_faceVertex_light5(world, face, faceBounds, vertex->toVec()); faceVertex.light = compute_faceVertex_light5(world, face, faceBounds, vertex->toVec());
faceVertex.light = (short)((float)faceVertex.light * 1.5f);
faceVertex.light = (short)((float)faceVertex.light * 1.5f); // Compromise between overbright and non-overbright lighting. Looks good in practice.
if (faceVertex.light > 255) if (faceVertex.light > 255)
faceVertex.light = 255; faceVertex.light = 255;
} }
@ -298,6 +303,101 @@ int process_faces(const world_t* world, const std::vector<ps1bsp_texture_t>& tex
return 1; return 1;
} }
void gpc_test(const world_t* world, const face_t* face)
{
const texinfo_t* texinfo = &world->texInfos[face->texinfo_id];
const miptex_t* miptex = &world->miptexes[texinfo->texture_id];
const plane_t* plane = &world->planes[face->plane_id];
double minS = DBL_MAX, minT = DBL_MAX;
double maxS = DBL_MIN, maxT = DBL_MIN;
gpc_polygon polygon = { 0 };
gpc_vertex_list contour;
contour.num_vertices = face->ledge_num;
contour.vertex = (gpc_vertex*)malloc(contour.num_vertices * sizeof(gpc_vertex));
if (contour.vertex == NULL)
return;
std::vector<Vec3> originalVecs;
for (int edgeListIdx = 0; edgeListIdx < face->ledge_num; ++edgeListIdx)
{
int edgeIdx = world->edgeList[face->ledge_id + edgeListIdx];
unsigned short vertIndex = edgeIdx > 0 ?
world->edges[edgeIdx].vertex0 :
world->edges[-edgeIdx].vertex1;
const vertex_t* vertex = &world->vertices[vertIndex];
Vec3 vertexPoint = vertex->toVec();
originalVecs.push_back(vertexPoint);
// Calculate texture UV bounds
double s = (vertexPoint.dotProduct(texinfo->vectorS) + texinfo->distS) / miptex->width;
double t = (vertexPoint.dotProduct(texinfo->vectorT) + texinfo->distT) / miptex->height;
if (s > maxS) maxS = s; if (s < minS) minS = s;
if (t > maxT) maxT = t; if (t < minT) minT = t;
contour.vertex[edgeListIdx] = gpc_vertex{ s, t };
}
gpc_add_contour(&polygon, &contour, 0);
std::vector<Vec3> vertices;
std::unordered_map<Vec3, size_t> vertexIndices;
// Create a virtual grid at the texture bounds and iterate over each cell to break up the face into repeating tiles
for (double y = floor(minT); y <= ceil(maxT); y += 1.0)
{
for (double x = floor(minS); x <= ceil(maxS); x += 1.0)
{
// Create a square polygon that covers the entire cell
gpc_polygon cell = { 0 };
gpc_vertex_list cell_bounds;
cell_bounds.num_vertices = 4;
cell_bounds.vertex = (gpc_vertex*)malloc(4 * sizeof(gpc_vertex));
cell_bounds.vertex[0] = gpc_vertex{ x, y };
cell_bounds.vertex[1] = gpc_vertex{ x + 1.0, y };
cell_bounds.vertex[2] = gpc_vertex{ x + 1.0, y + 1.0 };
cell_bounds.vertex[3] = gpc_vertex{ x, y + 1.0 };
gpc_add_contour(&cell, &cell_bounds, 0);
// Take the intersection to get the chunk of the face that's inside this cell
gpc_polygon result;
gpc_polygon_clip(GPC_INT, &polygon, &cell, &result);
// We should get a polygon with exactly one contour as a result; if not, the face was not on this grid cell
if (result.num_contours <= 0)
continue;
// Reconstruct the polygon's vertices in world space
for (int v = 0; v < result.contour[0].num_vertices; ++v)
{
const auto vert = &result.contour[0].vertex[v];
Vec3 newVert =
plane->normal * plane->dist +
texinfo->vectorS * (float)(vert->x * miptex->width - texinfo->distS) +
texinfo->vectorT * (float)(vert->y * miptex->height - texinfo->distT);
// Make sure we don't store duplicate vertices
auto vertIter = vertexIndices.find(newVert);
if (vertIter == vertexIndices.end())
{
vertexIndices[newVert] = vertices.size();
vertices.push_back(newVert);
}
// Store the relevant (S, T) coordinates for each vertex-texinfo pair
}
gpc_free_polygon(&result);
gpc_free_polygon(&cell);
}
}
gpc_free_polygon(&polygon);
}
int process_bsp(const world_t *world) int process_bsp(const world_t *world)
{ {
// Test exporting texture data // Test exporting texture data

Loading…
Cancel
Save