bsputil: start a --compare feature for helping with qbsp testing

This commit is contained in:
Eric Wasylishen 2019-01-10 02:58:37 -07:00
parent 4a360989f3
commit 8a47233bbf
3 changed files with 171 additions and 8 deletions

View File

@ -32,6 +32,7 @@
#include <set>
#include <list>
#include <algorithm> // std::sort
#include <light/light.hh>
/* FIXME - share header with qbsp, etc. */
typedef struct {
@ -453,6 +454,49 @@ CheckBSPFile(const mbsp_t *bsp)
bsp->dmodels[0].maxs[2]);
}
static void
CompareBSPFiles(const mbsp_t *refBsp, const mbsp_t *bsp)
{
printf("comparing %d with %d faces\n", refBsp->numfaces, bsp->numfaces);
const dmodel_t *world = BSP_GetWorldModel(bsp);
const dmodel_t *refWorld = BSP_GetWorldModel(refBsp);
// iterate through the refBsp world faces
for (int i=0; i<refWorld->numfaces; i++) {
auto* refFace = BSP_GetFace(refBsp, refWorld->firstface + i);
qvec3f refFaceCentroid = Face_Centroid(refBsp, refFace);
// FIXME:
vec3_t wantedPoint;
glm_to_vec3_t(refFaceCentroid, wantedPoint);
vec3_t wantedNormal;
Face_Normal(refBsp, refFace, wantedNormal);
// Search for a face in bsp touching refFaceCentroid.
auto* matchedFace = BSP_FindFaceAtPoint(bsp, world, wantedPoint, wantedNormal);
if (matchedFace == nullptr) {
printf("couldn't find a face at %f %f %f normal %f %f %f\n",
wantedPoint[0], wantedPoint[1], wantedPoint[2],
wantedNormal[0], wantedNormal[1], wantedNormal[2]);
}
// TODO: run on some more complex maps
// auto* refFaceSelfCheck = BSP_FindFaceAtPoint(refBsp, refWorld, wantedPoint, wantedNormal);
// if (refFaceSelfCheck == refFace) {
// matches ++;
// } else {
// printf("not match at %f %f %f wanted %p got %p\n", wantedPoint[0], wantedPoint[1], wantedPoint[2], refFace, refFaceSelfCheck);
// Face_DebugPrint(refBsp, refFace);
// Face_DebugPrint(refBsp, refFaceSelfCheck);
// notmat++;
// }
}
}
int
main(int argc, char **argv)
{
@ -465,7 +509,7 @@ main(int argc, char **argv)
printf("---- bsputil / ericw-tools " stringify(ERICWTOOLS_VERSION) " ----\n");
if (argc == 1) {
printf("usage: bsputil [--extract-entities] [--extract-textures] [--convert bsp29|bsp2|bsp2rmq|q2bsp] [--check] [--modelinfo]"
"[--check] bspfile\n");
"[--check] [--compare otherbsp] bspfile\n");
exit(1);
}
@ -479,7 +523,27 @@ main(int argc, char **argv)
ConvertBSPFormat(GENERIC_BSP, &bspdata);
for (i = 0; i < argc - 1; i++) {
if (!strcmp(argv[i], "--convert")) {
if (!strcmp(argv[i], "--compare")) {
i++;
if (i == argc - 1) {
Error("--compare requires two arguments");
}
// Load the reference BSP
char refbspname[1024];
bspdata_t refbspdata;
strcpy(refbspname, argv[i]);
DefaultExtension(refbspname, ".bsp");
LoadBSPFile(refbspname, &refbspdata);
ConvertBSPFormat(GENERIC_BSP, &refbspdata);
printf("comparing reference bsp %s with test bsp %s\n", refbspname, source);
CompareBSPFiles(&refbspdata.data.mbsp,
&bspdata.data.mbsp);
break;
} else if (!strcmp(argv[i], "--convert")) {
i++;
if (!(i < argc - 1)) {
Error("--convert requires an argument");

View File

@ -47,6 +47,20 @@ const bsp2_dnode_t *BSP_GetNode(const mbsp_t *bsp, int nodenum)
return &bsp->dnodes[nodenum];
}
const mleaf_t* BSP_GetLeaf(const mbsp_t *bsp, int leafnum)
{
if (leafnum < 0 || leafnum >= bsp->numleafs) {
Error("Corrupt BSP: leaf %d is out of bounds (bsp->numleafs = %d)", leafnum, bsp->numleafs);
}
return &bsp->dleafs[leafnum];
}
const mleaf_t* BSP_GetLeafFromNodeNum(const mbsp_t *bsp, int nodenum)
{
const int leafnum = (-1 - nodenum);
return BSP_GetLeaf(bsp, leafnum);
}
const dplane_t *BSP_GetPlane(const mbsp_t *bsp, int planenum)
{
Q_assert(planenum >= 0 && planenum < bsp->numplanes);
@ -248,12 +262,7 @@ vec_t Plane_Dist(const vec3_t point, const dplane_t *plane)
static bool Light_PointInSolid_r(const mbsp_t *bsp, const int nodenum, const vec3_t point)
{
if (nodenum < 0) {
// FIXME: Factor out into bounds-checked getter
const int leafnum = (-1 - nodenum);
if (leafnum < 0 || leafnum >= bsp->numleafs) {
Error("Corrupt BSP: leaf %d is out of bounds (bsp->numleafs = %d)", leafnum, bsp->numleafs);
}
mleaf_t *leaf = &bsp->dleafs[leafnum];
const mleaf_t *leaf = BSP_GetLeafFromNodeNum(bsp, nodenum);
return (bsp->loadversion == Q2_BSPVERSION ? leaf->contents & Q2_CONTENTS_SOLID : (leaf->contents == CONTENTS_SOLID || leaf->contents == CONTENTS_SKY)); //mxd
}
@ -282,6 +291,63 @@ bool Light_PointInWorld(const mbsp_t *bsp, const vec3_t point)
return Light_PointInSolid(bsp, &bsp->dmodels[0], point);
}
static const bsp2_dface_t *BSP_FindFaceAtPoint_r(const mbsp_t *bsp, const int nodenum, const vec3_t point, const vec3_t wantedNormal)
{
if (nodenum < 0) {
// we're only interested in nodes, since faces are owned by nodes.
return nullptr;
}
const bsp2_dnode_t *node = &bsp->dnodes[nodenum];
const vec_t dist = Plane_Dist(point, &bsp->dplanes[node->planenum]);
if (dist > 0.1)
return BSP_FindFaceAtPoint_r(bsp, node->children[0], point, wantedNormal);
if (dist < -0.1)
return BSP_FindFaceAtPoint_r(bsp, node->children[1], point, wantedNormal);
// Point is close to this node plane. Check all faces on the plane.
for (int i=0; i<node->numfaces; i++) {
const bsp2_dface_t *face = BSP_GetFace(bsp, node->firstface + i);
// First check if it's facing the right way
vec3_t faceNormal;
Face_Normal(bsp, face, faceNormal);
if (DotProduct(faceNormal, wantedNormal) < 0) {
// Opposite, so not the right face.
continue;
}
// Next test if it's within the boundaries of the face
plane_t *edgeplanes = Face_AllocInwardFacingEdgePlanes(bsp, face);
const bool insideFace = EdgePlanes_PointInside(face, edgeplanes, point);
free(edgeplanes);
// Found a match?
if (insideFace) {
return face;
}
}
// No match found on this plane. Check both sides of the tree.
const bsp2_dface_t *side0Match = BSP_FindFaceAtPoint_r(bsp, node->children[0], point, wantedNormal);
if (side0Match != nullptr) {
return side0Match;
} else {
return BSP_FindFaceAtPoint_r(bsp, node->children[1], point, wantedNormal);
}
}
const bsp2_dface_t * BSP_FindFaceAtPoint(const mbsp_t *bsp, const dmodel_t *model, const vec3_t point, const vec3_t wantedNormal)
{
return BSP_FindFaceAtPoint_r(bsp, model->headnode[0], point, wantedNormal);
}
const bsp2_dface_t * BSP_FindFaceAtPoint_InWorld(const mbsp_t *bsp, const vec3_t point, const vec3_t wantedNormal)
{
return BSP_FindFaceAtPoint(bsp, &bsp->dmodels[0], point, wantedNormal);
}
plane_t *
Face_AllocInwardFacingEdgePlanes(const mbsp_t *bsp, const bsp2_dface_t *face)
{
@ -360,3 +426,26 @@ qvec3f Face_Centroid(const mbsp_t *bsp, const bsp2_dface_t *face)
// FIXME: GLM_PolyCentroid has a assertion that there are >= 3 points
return GLM_PolyCentroid(GLM_FacePoints(bsp, face));
}
void Face_DebugPrint(const mbsp_t *bsp, const bsp2_dface_t *face)
{
const gtexinfo_t *tex = &bsp->texinfo[face->texinfo];
const char *texname = Face_TextureName(bsp, face);
logprint("face %d, texture '%s', %d edges...\n"
" vectors (%3.3f, %3.3f, %3.3f) (%3.3f)\n"
" (%3.3f, %3.3f, %3.3f) (%3.3f)\n",
(int)(face - bsp->dfaces), texname, face->numedges,
tex->vecs[0][0], tex->vecs[0][1], tex->vecs[0][2], tex->vecs[0][3],
tex->vecs[1][0], tex->vecs[1][1], tex->vecs[1][2], tex->vecs[1][3]);
for (int i = 0; i < face->numedges; i++) {
int edge = bsp->dsurfedges[face->firstedge + i];
int vert = Face_VertexAtIndex(bsp, face, i);
const vec_t *point = GetSurfaceVertexPoint(bsp, face, i);
logprint("%s %3d (%3.3f, %3.3f, %3.3f) :: edge %d\n",
i ? " " : " verts ", vert,
point[0], point[1], point[2],
edge);
}
}

View File

@ -31,6 +31,8 @@ int Face_GetNum(const mbsp_t *bsp, const bsp2_dface_t *f);
// bounds-checked array access (assertion failure on out-of-bounds)
const bsp2_dnode_t *BSP_GetNode(const mbsp_t *bsp, int nodenum);
const mleaf_t* BSP_GetLeaf(const mbsp_t *bsp, int leafnum);
const mleaf_t* BSP_GetLeafFromNodeNum(const mbsp_t *bsp, int nodenum);
const dplane_t *BSP_GetPlane(const mbsp_t *bsp, int planenum);
const bsp2_dface_t *BSP_GetFace(const mbsp_t *bsp, int fnum);
bsp2_dface_t *BSP_GetFace(mbsp_t *bsp, int fnum);
@ -52,6 +54,13 @@ const dmodel_t *BSP_DModelForModelString(const mbsp_t *bsp, const std::string &s
vec_t Plane_Dist(const vec3_t point, const dplane_t *plane);
bool Light_PointInSolid(const mbsp_t *bsp, const dmodel_t *model, const vec3_t point);
bool Light_PointInWorld(const mbsp_t *bsp, const vec3_t point);
/**
* Searches for a face touching a point and facing a certain way.
* Sometimes (water, sky?) there will be 2 overlapping candidates facing opposite ways, the provided normal
* is used to disambiguate these.
*/
const bsp2_dface_t *BSP_FindFaceAtPoint(const mbsp_t *bsp, const dmodel_t *model, const vec3_t point, const vec3_t wantedNormal);
const bsp2_dface_t *BSP_FindFaceAtPoint_InWorld(const mbsp_t *bsp, const vec3_t point, const vec3_t wantedNormal);
plane_t *Face_AllocInwardFacingEdgePlanes(const mbsp_t *bsp, const bsp2_dface_t *face);
bool EdgePlanes_PointInside(const bsp2_dface_t *face, const plane_t *edgeplanes, const vec3_t point);
@ -61,5 +70,6 @@ qvec3f Vertex_GetPos_E(const mbsp_t *bsp, int num);
qvec3f Face_Normal_E(const mbsp_t *bsp, const bsp2_dface_t *f);
std::vector<qvec3f> GLM_FacePoints(const mbsp_t *bsp, const bsp2_dface_t *face);
qvec3f Face_Centroid(const mbsp_t *bsp, const bsp2_dface_t *face);
void Face_DebugPrint(const mbsp_t *bsp, const bsp2_dface_t *face);
#endif /* __COMMON_BSPUTILS_HH__ */