// Copyright 2021 Benjamin Barenblat // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. #include "src/mesh.h" #include #include #include #include #include #include "src/util.h" #include "third_party/abseil/absl/strings/substitute.h" namespace glplanet { namespace { using Coordinates = ::glplanet::UvSphere::Coordinates; using ::testing::ElementsAre; using ::testing::ExplainMatchResult; using ::testing::Field; using ::testing::FloatNear; using ::testing::UnorderedElementsAre; struct Triangle { uint32_t a, b, c; std::string DebugString() const noexcept { return absl::Substitute("Triangle{$0, $1, $2}", a, b, c); } }; std::ostream& operator<<(std::ostream& out, const Triangle& t) noexcept { return out << t.DebugString(); } std::vector TrianglesIn(const std::vector& elements) { DCHECK(elements.size() % 3 == 0); std::vector result; for (int i = 0; i < elements.size(); i += 3) { result.push_back(Triangle{elements[i], elements[i + 1], elements[i + 2]}); } return result; } MATCHER_P5(CoordinatesAre, xv, yv, zv, uv, vv, absl::Substitute("is an object whose fields (x, y, z, u, v) are " "approximately ($0, $1, $2, $3, $4)", xv, yv, zv, uv, vv)) { return ExplainMatchResult( AllOf(Field("x", &Coordinates::x, FloatNear(xv, 1e-15)), Field("y", &Coordinates::y, FloatNear(yv, 1e-15)), Field("z", &Coordinates::z, FloatNear(zv, 1e-15)), Field("u", &Coordinates::u, FloatNear(uv, 1e-15)), Field("v", &Coordinates::v, FloatNear(vv, 1e-15))), arg, result_listener); } MATCHER_P3(TriangleIs, av, bv, cv, absl::Substitute("is the triangle ($0, $1, $2)", av, bv, cv)) { return arg.a == av && arg.b == bv && arg.c == cv; } TEST(MeshTest, SmallVertices) { // This test is overconstrained. In particular, we check the returned // coordinates with ElementsAre, rather than UnorderedElementsAre, and the u // coordinates are exact, rather than being normalized to [0, 1]. This allows // us to verify that the u coordinates increase monotonically as we travel // east around the sphere, which is important to prevent discontinuities in // texture mapping. UvSphere s(4, 2); EXPECT_THAT(s.vertices, ElementsAre(CoordinatesAre(0, 0, -1, 0, 1), // CoordinatesAre(0, 0, -1, 0.25, 1), // CoordinatesAre(0, 0, -1, 0.5, 1), // CoordinatesAre(0, 0, -1, 0.75, 1), // CoordinatesAre(0, 0, -1, 1, 1), CoordinatesAre(-1, 0, 0, 0, 0.5), // CoordinatesAre(0, -1, 0, 0.25, 0.5), // CoordinatesAre(1, 0, 0, 0.5, 0.5), // CoordinatesAre(0, 1, 0, 0.75, 0.5), // CoordinatesAre(-1, 0, 0, 1, 0.5), CoordinatesAre(0, 0, 1, 0, 0), // CoordinatesAre(0, 0, 1, 0.25, 0), // CoordinatesAre(0, 0, 1, 0.5, 0), // CoordinatesAre(0, 0, 1, 0.75, 0), // CoordinatesAre(0, 0, 1, 1, 0))); } TEST(MeshTest, SmallElements) { UvSphere s(4, 2); ASSERT_THAT(s.vertices, ElementsAre(CoordinatesAre(0, 0, -1, 0, 1), // CoordinatesAre(0, 0, -1, 0.25, 1), // CoordinatesAre(0, 0, -1, 0.5, 1), // CoordinatesAre(0, 0, -1, 0.75, 1), // CoordinatesAre(0, 0, -1, 1, 1), CoordinatesAre(-1, 0, 0, 0, 0.5), // CoordinatesAre(0, -1, 0, 0.25, 0.5), // CoordinatesAre(1, 0, 0, 0.5, 0.5), // CoordinatesAre(0, 1, 0, 0.75, 0.5), // CoordinatesAre(-1, 0, 0, 1, 0.5), CoordinatesAre(0, 0, 1, 0, 0), // CoordinatesAre(0, 0, 1, 0.25, 0), // CoordinatesAre(0, 0, 1, 0.5, 0), // CoordinatesAre(0, 0, 1, 0.75, 0), // CoordinatesAre(0, 0, 1, 1, 0))); EXPECT_THAT( TrianglesIn(s.elements), UnorderedElementsAre(TriangleIs(0, 6, 5), TriangleIs(1, 6, 0), // TriangleIs(1, 7, 6), TriangleIs(2, 7, 1), // TriangleIs(2, 8, 7), TriangleIs(3, 8, 2), // TriangleIs(3, 9, 8), TriangleIs(4, 9, 3), TriangleIs(5, 11, 10), TriangleIs(6, 11, 5), // TriangleIs(6, 12, 11), TriangleIs(7, 12, 6), // TriangleIs(7, 13, 12), TriangleIs(8, 13, 7), // TriangleIs(8, 14, 13), TriangleIs(9, 14, 8))); } } // namespace } // namespace glplanet