qbsp: add failing tests for healing invalid texture projections
This commit is contained in:
parent
5a90667738
commit
23b25a0a0e
|
|
@ -106,6 +106,10 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const qvec<N,T> &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
T operator[](const int idx) const {
|
||||
assert(idx >= 0 && idx < N);
|
||||
return v[idx];
|
||||
|
|
|
|||
|
|
@ -195,4 +195,7 @@ void ExportObj_Surfaces(const surface_t *surfaces);
|
|||
|
||||
void WriteBspBrushMap(const char *name, const std::vector<const brush_t *> &list);
|
||||
|
||||
bool IsValidTextureProjection(const qvec3f &faceNormal, const qvec3f &s_vec, const qvec3f &t_vec);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
20
qbsp/map.cc
20
qbsp/map.cc
|
|
@ -1394,6 +1394,26 @@ void mapface_t::set_texvecs(const std::array<qvec4f, 2> &vecs)
|
|||
this->texinfo = FindTexinfo( &texInfoNew, texInfoNew.flags );
|
||||
}
|
||||
|
||||
bool
|
||||
IsValidTextureProjection(const qvec3f &faceNormal, const qvec3f &s_vec, const qvec3f &t_vec)
|
||||
{
|
||||
// TODO: This doesn't match how light does it (TexSpaceToWorld)
|
||||
|
||||
const qvec3f tex_normal = qv::normalize(qv::cross(s_vec, t_vec));
|
||||
|
||||
for (int i=0;i<3;i++)
|
||||
if (std::isnan(tex_normal[i]))
|
||||
return false;
|
||||
|
||||
const float cosangle = qv::dot(tex_normal, faceNormal);
|
||||
if (std::isnan(cosangle))
|
||||
return false;
|
||||
if (fabs(cosangle) < ZERO_EPSILON)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::unique_ptr<mapface_t>
|
||||
ParseBrushFace(parser_t *parser, const mapbrush_t *brush, const mapentity_t *entity)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -307,6 +307,94 @@ TEST(qbsp, MemLeaks) {
|
|||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Test that this skip face gets auto-corrected.
|
||||
*/
|
||||
TEST(qbsp, InvalidTextureProjection) {
|
||||
const char *map = R"(
|
||||
// entity 0
|
||||
{
|
||||
"classname" "worldspawn"
|
||||
// brush 0
|
||||
{
|
||||
( -64 -64 -16 ) ( -64 -63 -16 ) ( -64 -64 -15 ) +2butn [ 0 -1 0 0 ] [ 0 0 -1 0 ] 0 1 1
|
||||
( 64 64 16 ) ( 64 64 17 ) ( 64 65 16 ) +2butn [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1
|
||||
( -64 -64 -16 ) ( -64 -64 -15 ) ( -63 -64 -16 ) +2butn [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
|
||||
( 64 64 16 ) ( 65 64 16 ) ( 64 64 17 ) +2butn [ -1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
|
||||
( 64 64 64 ) ( 64 65 64 ) ( 65 64 64 ) +2butn [ 1 0 0 -0 ] [ 0 -1 0 -0 ] -0 1 1
|
||||
( -64 -64 -0 ) ( -63 -64 -0 ) ( -64 -63 -0 ) skip [ 0 0 0 0 ] [ 0 0 0 0 ] -0 1 1
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
mapentity_t worldspawn = LoadMap(map);
|
||||
Q_assert(1 == worldspawn.nummapbrushes);
|
||||
|
||||
const mapface_t *face = &worldspawn.mapbrush(0).face(5);
|
||||
ASSERT_EQ("skip", face->texname);
|
||||
const auto texvecs = face->get_texvecs();
|
||||
EXPECT_TRUE(IsValidTextureProjection(vec3_t_to_glm(face->plane.normal), texvecs.at(0), texvecs.at(1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as above but the texture scales are 0
|
||||
*/
|
||||
TEST(qbsp, InvalidTextureProjection2) {
|
||||
const char *map = R"(
|
||||
// entity 0
|
||||
{
|
||||
"classname" "worldspawn"
|
||||
// brush 0
|
||||
{
|
||||
( -64 -64 -16 ) ( -64 -63 -16 ) ( -64 -64 -15 ) +2butn [ 0 -1 0 0 ] [ 0 0 -1 0 ] 0 1 1
|
||||
( 64 64 16 ) ( 64 64 17 ) ( 64 65 16 ) +2butn [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1
|
||||
( -64 -64 -16 ) ( -64 -64 -15 ) ( -63 -64 -16 ) +2butn [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
|
||||
( 64 64 16 ) ( 65 64 16 ) ( 64 64 17 ) +2butn [ -1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1
|
||||
( 64 64 64 ) ( 64 65 64 ) ( 65 64 64 ) +2butn [ 1 0 0 -0 ] [ 0 -1 0 -0 ] -0 1 1
|
||||
( -64 -64 -0 ) ( -63 -64 -0 ) ( -64 -63 -0 ) skip [ 0 0 0 0 ] [ 0 0 0 0 ] -0 0 0
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
mapentity_t worldspawn = LoadMap(map);
|
||||
Q_assert(1 == worldspawn.nummapbrushes);
|
||||
|
||||
const mapface_t *face = &worldspawn.mapbrush(0).face(5);
|
||||
ASSERT_EQ("skip", face->texname);
|
||||
const auto texvecs = face->get_texvecs();
|
||||
EXPECT_TRUE(IsValidTextureProjection(vec3_t_to_glm(face->plane.normal), texvecs.at(0), texvecs.at(1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* More realistic: *lava1 has tex vecs perpendicular to face
|
||||
*/
|
||||
TEST(qbsp, InvalidTextureProjection3) {
|
||||
const char *map = R"(
|
||||
// entity 0
|
||||
{
|
||||
"classname" "worldspawn"
|
||||
"wad" "Q.wad"
|
||||
// brush 0
|
||||
{
|
||||
( 512 512 64 ) ( 512 512 -0 ) ( 512 448 64 ) *04mwat1 [ 0 1 0 0 ] [ 0 0 -1 0 ] -0 1 1
|
||||
( -0 448 -0 ) ( -0 512 -0 ) ( -0 448 64 ) *04mwat1 [ 0 -1 0 0 ] [ -0 -0 -1 0 ] -0 1 1
|
||||
( 512 512 64 ) ( -0 512 64 ) ( 512 512 -0 ) *04mwat1 [ -1 0 0 0 ] [ 0 0 -1 0 ] -0 1 1
|
||||
( -0 448 -0 ) ( -0 448 64 ) ( 512 448 -0 ) *lava1 [ 0 1 0 0 ] [ 0 0 -1 0 ] -0 1 1
|
||||
( 512 512 64 ) ( 512 448 64 ) ( -0 512 64 ) *04mwat1 [ 1 0 0 0 ] [ 0 -1 0 0 ] -0 1 1
|
||||
( -0 448 -0 ) ( 512 448 -0 ) ( -0 512 -0 ) *04mwat1 [ -1 0 0 0 ] [ -0 -1 -0 -0 ] -0 1 1
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
mapentity_t worldspawn = LoadMap(map);
|
||||
Q_assert(1 == worldspawn.nummapbrushes);
|
||||
|
||||
const mapface_t *face = &worldspawn.mapbrush(0).face(3);
|
||||
ASSERT_EQ("*lava1", face->texname);
|
||||
const auto texvecs = face->get_texvecs();
|
||||
EXPECT_TRUE(IsValidTextureProjection(vec3_t_to_glm(face->plane.normal), texvecs.at(0), texvecs.at(1)));
|
||||
}
|
||||
|
||||
TEST(mathlib, WindingArea) {
|
||||
winding_t w;
|
||||
w.numpoints = 5;
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ AllocMem(int Type, int cElements, bool fZero)
|
|||
if (Type == FACE && cElements == 1)
|
||||
((face_t *)pTemp)->planenum = -1;
|
||||
if (Type == WINDING) {
|
||||
// FIXME: Remove this! Causing UBSan warnings
|
||||
*(int *)pTemp = cSize;
|
||||
pTemp = (char *)pTemp + sizeof(int);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue