mirror of
https://github.com/Nexoniarz/Fry3DX.git
synced 2026-11-03 04:24:26 +00:00
Fuzz test (tests/fuzz_test.cpp): random shapes through random edits and combines, broken scene and model files; in check and CI. Fixed what it found: Manifold given repeated or non-finite points (crash; the BSP takes those now), a damaged file's non-finite numbers (now 0), extruding both sides of a plane (NaN)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
b95e436d10
commit
9918d9a770
13 changed files with 294 additions and 6 deletions
|
|
@ -343,11 +343,18 @@ std::optional<Mesh> combineManifold(const Mesh& a, const Mesh& b, Combine op) {
|
|||
manifold::MeshGL g;
|
||||
g.numProp = 3;
|
||||
g.vertProperties.reserve(m.verts.size() * 3);
|
||||
for (const glm::vec3& v : m.verts) g.vertProperties.insert(g.vertProperties.end(), {v.x, v.y, v.z});
|
||||
for (const glm::vec3& v : m.verts) {
|
||||
if (!std::isfinite(v.x) || !std::isfinite(v.y) || !std::isfinite(v.z)) return std::nullopt; // (it can't take those)
|
||||
g.vertProperties.insert(g.vertProperties.end(), {v.x, v.y, v.z});
|
||||
}
|
||||
for (size_t f = 0; f < m.faces.size(); ++f) {
|
||||
if (m.faces[f].size() < 3) return std::nullopt; // (a line: not a solid)
|
||||
const auto& fv = m.faces[f];
|
||||
if (fv.size() < 3) return std::nullopt; // (a line: not a solid)
|
||||
for (size_t i = 0; i < fv.size(); ++i) // (a point twice round a face, or one that isn't there: it can't take that either)
|
||||
if (fv[i] < 0 || size_t(fv[i]) >= m.verts.size() || std::find(fv.begin() + long(i) + 1, fv.end(), fv[i]) != fv.end()) return std::nullopt;
|
||||
for (const auto& t : triangulate(m, int(f)))
|
||||
g.triVerts.insert(g.triVerts.end(), {uint32_t(t[0]), uint32_t(t[1]), uint32_t(t[2])}), g.faceID.push_back(firstFace + uint32_t(f));
|
||||
if (t[0] == t[1] || t[1] == t[2] || t[0] == t[2]) return std::nullopt;
|
||||
else g.triVerts.insert(g.triVerts.end(), {uint32_t(t[0]), uint32_t(t[1]), uint32_t(t[2])}), g.faceID.push_back(firstFace + uint32_t(f));
|
||||
}
|
||||
if (g.triVerts.empty()) return std::nullopt;
|
||||
g.runOriginalID = {manifold::Manifold::ReserveIDs(1)}; // (so it keeps the faces given, not its own numbering)
|
||||
|
|
|
|||
|
|
@ -289,13 +289,14 @@ std::vector<int> extrudeFaces(Mesh& m, const std::set<int>& faces, float distanc
|
|||
}
|
||||
}
|
||||
// One flat piece moves as one, along its normal; a bent one, each point along its own.
|
||||
region = glm::length(region) > 1e-12f ? glm::normalize(region) : glm::vec3(0, 0, 1);
|
||||
// (faces facing opposite ways, a plane's two sides: theirs cancel out; the first one's way)
|
||||
region = glm::length(region) > 1e-12f ? glm::normalize(region) : faces.empty() ? glm::vec3(0, 0, 1) : faceNormal(m, *faces.begin());
|
||||
bool flat = true;
|
||||
for (int f : faces) flat &= glm::dot(faceNormal(m, f), region) > 0.99f;
|
||||
std::map<int, int> moved;
|
||||
std::vector<int> made;
|
||||
for (auto& [v, n] : along) {
|
||||
const glm::vec3 dir = flat ? region : glm::normalize(n);
|
||||
const glm::vec3 dir = flat || glm::length(n) < 1e-9f ? region : glm::normalize(n);
|
||||
moved[v] = int(m.verts.size());
|
||||
made.push_back(moved[v]);
|
||||
m.verts.push_back(m.verts[size_t(v)] + dir * distance);
|
||||
|
|
|
|||
|
|
@ -423,6 +423,18 @@ std::optional<Scene> parseScene(std::istream& in, const std::string& path, std::
|
|||
p = std::find_if(s.folders.begin(), s.folders.end(), [&](const Folder& g) { return g.id == p; })->parent;
|
||||
}
|
||||
for (Object& o : s.objects) o.folder = idAt(o.folder);
|
||||
// A number that isn't one (a file damaged, or edited by hand: "1e999", "nan"): nothing there.
|
||||
auto finite = [](glm::vec3& v, glm::vec3 instead) {
|
||||
if (!std::isfinite(v.x) || !std::isfinite(v.y) || !std::isfinite(v.z)) v = instead;
|
||||
};
|
||||
for (Object& o : s.objects) {
|
||||
for (glm::vec3& v : o.mesh.verts) finite(v, glm::vec3(0.0f));
|
||||
finite(o.position, glm::vec3(0.0f)), finite(o.scale, glm::vec3(1.0f));
|
||||
if (!std::isfinite(o.rotation.w) || !std::isfinite(o.rotation.x) || !std::isfinite(o.rotation.y) || !std::isfinite(o.rotation.z) || glm::length(o.rotation) < 1e-6f)
|
||||
o.rotation = glm::quat(1, 0, 0, 0);
|
||||
else
|
||||
o.rotation = glm::normalize(o.rotation);
|
||||
}
|
||||
for (Object& o : s.objects) o.cuts = o.cuts >= 1 && o.cuts <= s.objects.size() && &s.objects[o.cuts - 1] != &o ? s.objects[o.cuts - 1].id : 0u;
|
||||
return s;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue