Browse Source

Made the texture space transform available outside of Tessellator and used it to generate some more Face bounds data for later use.

master
Nico de Poel 3 years ago
parent
commit
c6a8abbb7b
  1. 22
      lighting.cpp
  2. 23
      lighting.h
  3. 16
      main.cpp
  4. 22
      tesselate.cpp
  5. 3
      tesselate.h

22
lighting.cpp

@ -1,7 +1,7 @@
#include "common.h"
#include "lighting.h"
bool sample_lightmap(const world_t* world, const face_t* face, const BoundBox& bounds, const Vec3& point, unsigned char* outSample)
bool sample_lightmap(const world_t* world, const face_t* face, const FaceBound& bounds, const Vec3& point, unsigned char* outSample)
{
if (face->lightmap < 0)
return false;
@ -9,8 +9,8 @@ bool sample_lightmap(const world_t* world, const face_t* face, const BoundBox& b
const unsigned char* lightmap = &world->lightmap[face->lightmap];
const plane_t* plane = &world->planes[face->plane_id];
Vec3 minBounds = (bounds.min / 16).floor() * 16.f;
Vec3 maxBounds = (bounds.max / 16).ceil() * 16.f;
Vec3 minBounds = (bounds.worldBounds.min / 16).floor() * 16.f;
Vec3 maxBounds = (bounds.worldBounds.max / 16).ceil() * 16.f;
int width, height;
int u, v;
@ -52,7 +52,7 @@ bool sample_lightmap(const world_t* world, const face_t* face, const BoundBox& b
return true;
}
unsigned char sample_lightmap(const world_t* world, const face_t* face, const BoundBox& bounds, const Vec3& point)
unsigned char sample_lightmap(const world_t* world, const face_t* face, const FaceBound& bounds, const Vec3& point)
{
unsigned char sample;
if (!sample_lightmap(world, face, bounds, point, &sample))
@ -61,7 +61,7 @@ unsigned char sample_lightmap(const world_t* world, const face_t* face, const Bo
return sample;
}
void export_lightmap(const world_t* world, const face_t* face, const BoundBox& bounds, int faceIdx)
void export_lightmap(const world_t* world, const face_t* face, const FaceBound& bounds, int faceIdx)
{
if (face->lightmap < 0)
return;
@ -75,20 +75,20 @@ void export_lightmap(const world_t* world, const face_t* face, const BoundBox& b
case 0:
case 3:
// Towards X
width = (int)(ceil(bounds.max.y / 16) - floor(bounds.min.y / 16));
height = (int)(ceil(bounds.max.z / 16) - floor(bounds.min.z / 16));
width = (int)(ceil(bounds.worldBounds.max.y / 16) - floor(bounds.worldBounds.min.y / 16));
height = (int)(ceil(bounds.worldBounds.max.z / 16) - floor(bounds.worldBounds.min.z / 16));
break;
case 1:
case 4:
// Towards Y
width = (int)(ceil(bounds.max.x / 16) - floor(bounds.min.x / 16));
height = (int)(ceil(bounds.max.z / 16) - floor(bounds.min.z / 16));
width = (int)(ceil(bounds.worldBounds.max.x / 16) - floor(bounds.worldBounds.min.x / 16));
height = (int)(ceil(bounds.worldBounds.max.z / 16) - floor(bounds.worldBounds.min.z / 16));
break;
case 2:
case 5:
// Towards Z
width = (int)(ceil(bounds.max.x / 16) - floor(bounds.min.x / 16));
height = (int)(ceil(bounds.max.y / 16) - floor(bounds.min.y / 16));
width = (int)(ceil(bounds.worldBounds.max.x / 16) - floor(bounds.worldBounds.min.x / 16));
height = (int)(ceil(bounds.worldBounds.max.y / 16) - floor(bounds.worldBounds.min.y / 16));
break;
default:
printf("Error: unknown plane type %d\n", plane->type);

23
lighting.h

@ -15,13 +15,28 @@ struct Surface
std::unordered_set<const face_t*> faces;
};
typedef std::unordered_map<const face_t*, BoundBox> FaceBounds;
struct FaceBound
{
BoundBox worldBounds;
double minS = DBL_MAX, minT = DBL_MAX;
double maxS = DBL_MIN, maxT = DBL_MIN;
void addTexturePoint(double s, double t)
{
if (s < minS) minS = s;
if (s > maxS) maxS = s;
if (t < minT) minT = t;
if (t > maxT) maxT = t;
}
};
typedef std::unordered_map<const face_t*, FaceBound> FaceBounds;
typedef std::unordered_map<const vertex_t*, std::unordered_set<const face_t*>> VertexFaces;
typedef std::vector<Surface> SurfaceList;
bool sample_lightmap(const world_t* world, const face_t* face, const BoundBox& bounds, const Vec3& point, unsigned char* outSample);
unsigned char sample_lightmap(const world_t* world, const face_t* face, const BoundBox& bounds, const Vec3& point);
void export_lightmap(const world_t* world, const face_t* face, const BoundBox& bounds, int faceIdx);
bool sample_lightmap(const world_t* world, const face_t* face, const FaceBound& bounds, const Vec3& point, unsigned char* outSample);
unsigned char sample_lightmap(const world_t* world, const face_t* face, const FaceBound& bounds, const Vec3& point);
void export_lightmap(const world_t* world, const face_t* face, const FaceBound& bounds, int faceIdx);
std::unordered_map<const edge_t*, EdgeData> analyze_edges(const world_t* world);
unsigned char compute_faceVertex_light(const world_t* world, const face_t* face, unsigned short vertexIndex, const FaceBounds& faceBounds, const std::unordered_map<const edge_t*, EdgeData>& edgeData);

16
main.cpp

@ -68,6 +68,8 @@ int process_faces(const world_t* world, const std::vector<ps1bsp_texture_t>& tex
{
const face_t* face = &world->faces[faceIdx];
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];
ps1bsp_face_t outFace = { 0 };
outFace.planeId = face->plane_id;
@ -75,9 +77,11 @@ int process_faces(const world_t* world, const std::vector<ps1bsp_texture_t>& tex
outFace.firstFaceVertex = (unsigned short)outFaceVertices.size();
outFace.textureId = (unsigned char)texinfo->texture_id;
Matrix4x4 textureTrsf = tesselator.buildTextureSpaceTransform(texinfo, miptex, plane);
// Traverse the list of face edges to collect all of the face's vertices
Vec3 vertexSum;
BoundBox bounds;
FaceBound bounds;
for (int edgeListIdx = 0; edgeListIdx < face->ledge_num; ++edgeListIdx)
{
int edgeIdx = world->edgeList[face->ledge_id + edgeListIdx];
@ -91,9 +95,12 @@ int process_faces(const world_t* world, const std::vector<ps1bsp_texture_t>& tex
// Calculate bounding box of this face
if (edgeListIdx == 0)
bounds.init(vertexPoint);
bounds.worldBounds.init(vertexPoint);
else
bounds.includePoint(vertexPoint);
bounds.worldBounds.includePoint(vertexPoint);
Vec3 texturePoint = textureTrsf.TransformPoint(vertexPoint);
bounds.addTexturePoint(texturePoint.x, texturePoint.y);
// Sum all vertices to calculate an average center point
vertexSum = vertexSum + vertexPoint;
@ -163,13 +170,12 @@ int process_faces(const world_t* world, const std::vector<ps1bsp_texture_t>& tex
size_t vertIndex = polyVertIter->vertexIndex;
Vec3 normalizedUV = polyVertIter->normalizedUV;
Vec3 vertex = tesselator.getVertices()[vertIndex];
ps1bsp_polyvertex_t polyVert = { 0 };
polyVert.index = (unsigned short)vertIndex;
polyVert.u = (unsigned char)(normalizedUV.x * (ps1tex.w - 1)) + ps1tex.uoffs;
polyVert.v = (unsigned char)(normalizedUV.y * (ps1tex.h - 1)) + ps1tex.voffs;
Vec3 vertex = tesselator.getVertices()[vertIndex];
int light = compute_faceVertex_light5(world, face, faceBounds, vertex);
light = (int)((float)light * 1.5f); // Compromise between overbright and non-overbright lighting. Looks good in practice.
if (light > 255)

22
tesselate.cpp

@ -22,14 +22,7 @@ std::vector<Tesselator::Polygon> Tesselator::tesselateFace(const face_t* face)
double minS = DBL_MAX, minT = DBL_MAX;
double maxS = DBL_MIN, maxT = DBL_MIN;
// vectorS and vectorT are normally perpendicular (dot product is 0), magnitude isn't always 1 but that's fine.
// Means we can construct a coordinate space from them (plane normal for the third vector) and transform the vertices to texture space.
// And we can create an inverse transform, meaning we can transform vertices from 2D texture space back to 3D world space.
Matrix4x4 textureTrsf;
textureTrsf.SetAxis(0, texinfo->vectorS / (float)miptex->width);
textureTrsf.SetAxis(1, texinfo->vectorT / (float)miptex->height);
textureTrsf.SetAxis(2, plane->normal);
textureTrsf.SetTranslation(Vec3(texinfo->distS / miptex->width, texinfo->distT / miptex->height, -plane->dist));
Matrix4x4 textureTrsf = buildTextureSpaceTransform(texinfo, miptex, plane);
// Build a polygon in normalized 2D texture space from the original face data
std::vector<Vec3> faceVertices;
@ -112,3 +105,16 @@ std::vector<Tesselator::Polygon> Tesselator::tesselateFace(const face_t* face)
gpc_free_polygon(&facePolygon);
return polygons;
}
Matrix4x4 Tesselator::buildTextureSpaceTransform(const texinfo_t* texinfo, const miptex_t* miptex, const plane_t* plane)
{
// vectorS and vectorT are normally perpendicular (dot product is 0), magnitude isn't always 1 but that's fine.
// Means we can construct a coordinate space from them (plane normal for the third vector) and transform the vertices to texture space.
// And we can create an inverse transform, meaning we can transform vertices from 2D texture space back to 3D world space.
Matrix4x4 matrix;
matrix.SetAxis(0, texinfo->vectorS / (float)miptex->width);
matrix.SetAxis(1, texinfo->vectorT / (float)miptex->height);
matrix.SetAxis(2, plane->normal);
matrix.SetTranslation(Vec3(texinfo->distS / miptex->width, texinfo->distT / miptex->height, -plane->dist));
return matrix;
}

3
tesselate.h

@ -1,4 +1,5 @@
#pragma once
#include "matrix.h"
class Tesselator
{
@ -46,6 +47,8 @@ public:
std::vector<Polygon> tesselateFace(const face_t* face);
static Matrix4x4 buildTextureSpaceTransform(const texinfo_t* texinfo, const miptex_t* miptex, const plane_t* plane);
private:
const world_t* world;

Loading…
Cancel
Save