diff --git a/common/mathlib.cc b/common/mathlib.cc index e6c4964f..6f6ae34e 100644 --- a/common/mathlib.cc +++ b/common/mathlib.cc @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -482,3 +483,58 @@ std::pair GLM_InterpolateNormal(const std::vector &p return make_pair(false, vec3(0)); } + +static winding_t *glm_to_winding(const std::vector &poly) +{ + const int N = poly.size(); + winding_t *winding = AllocWinding(N); + for (int i=0; ip[i]); + } + winding->numpoints = N; + return winding; +} + +static std::vector winding_to_glm(const winding_t *w) +{ + if (w == nullptr) + return {}; + std::vector res; + for (int i=0; inumpoints; i++) { + res.push_back(vec3_t_to_glm(w->p[i])); + } + return res; +} + +/// Returns (front part, back part) +std::pair,std::vector> GLM_ClipPoly(const std::vector &poly, const glm::vec4 &plane) +{ + vec3_t normal; + winding_t *front = nullptr; + winding_t *back = nullptr; + + if (poly.empty()) + return make_pair(vector(),vector()); + + winding_t *w = glm_to_winding(poly); + glm_to_vec3_t(vec3(plane), normal); + ClipWinding(w, normal, plane.w, &front, &back); + + const auto res = make_pair(winding_to_glm(front), winding_to_glm(back)); + free(front); + free(back); + return res; +} + +std::vector GLM_ShrinkPoly(const std::vector &poly, const float amount) { + const vector edgeplanes = GLM_MakeInwardFacingEdgePlanes(poly); + + vector clipped = poly; + + for (const vec4 &edge : edgeplanes) { + const vec4 shrunkEdgePlane(vec3(edge), edge.w + 1); + clipped = GLM_ClipPoly(clipped, shrunkEdgePlane).first; + } + + return clipped; +} diff --git a/include/common/mathlib.hh b/include/common/mathlib.hh index 7ce4a6ac..152bb9bf 100644 --- a/include/common/mathlib.hh +++ b/include/common/mathlib.hh @@ -332,4 +332,8 @@ std::pair GLM_ClosestPointOnPolyBoundary(const std::vector GLM_InterpolateNormal(const std::vector &points, const std::vector &normals, const glm::vec3 &point); +std::vector GLM_ShrinkPoly(const std::vector &poly, const float amount); +/// Returns (front part, back part) +std::pair,std::vector> GLM_ClipPoly(const std::vector &poly, const glm::vec4 &plane); + #endif /* __COMMON_MATHLIB_H__ */ diff --git a/light/test_light.cc b/light/test_light.cc index 3b84c776..dc6fa696 100644 --- a/light/test_light.cc +++ b/light/test_light.cc @@ -411,3 +411,83 @@ TEST(mathlib, InterpolateNormals) { // Outside poly EXPECT_FALSE(GLM_InterpolateNormal(poly, normals, vec3(-0.1, 0, 0)).first); } + +static bool pointsEqualEpsilon(const vec3 &a, const vec3 &b) { + return all(epsilonEqual(a, b, vec3(POINT_EQUAL_EPSILON))); +} + +static bool polysEqual(const vector &p1, const vector &p2) { + if (p1.size() != p2.size()) + return false; + for (int i=0; i poly { + { 0,0,0 }, + { 0,64,0 }, + { 64,64,0 }, + { 64,0,0 } + }; + + const vector frontRes { + { 0,0,0 }, + { 0,64,0 }, + { 32,64,0 }, + { 32,0,0 } + }; + + const vector backRes { + { 32,64,0 }, + { 64,64,0 }, + { 64,0,0 }, + { 32,0,0 } + }; + + auto clipRes = GLM_ClipPoly(poly, vec4(-1,0,0,-32)); + + EXPECT_TRUE(polysEqual(frontRes, clipRes.first)); + EXPECT_TRUE(polysEqual(backRes, clipRes.second)); +} + +TEST(mathlib, ShrinkPoly1) { + const vector poly { + { 0,0,0 }, + { 0,64,0 }, + { 64,64,0 }, + { 64,0,0 } + }; + + const vector shrunkPoly { + { 1,1,0 }, + { 1,63,0 }, + { 63,63,0 }, + { 63,1,0 } + }; + + const auto actualShrunk = GLM_ShrinkPoly(poly, 1.0f); + + EXPECT_TRUE(polysEqual(shrunkPoly, actualShrunk)); +} + +TEST(mathlib, ShrinkPoly2) { + const vector poly { + { 0,0,0 }, + { 64,64,0 }, + { 64,0,0 } + }; + + const vector shrunkPoly { + { 1.0f + sqrtf(2.0f), 1.0f, 0.0f }, + { 63.0f, 63.0f - sqrtf(2.0f), 0.0f }, + { 63,1,0 }, + }; + + const auto actualShrunk = GLM_ShrinkPoly(poly, 1.0f); + + EXPECT_TRUE(polysEqual(shrunkPoly, actualShrunk)); +}