| Index: cc/output/bsp_tree_unittest.cc
|
| diff --git a/cc/output/bsp_tree_unittest.cc b/cc/output/bsp_tree_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f07c5e6caff429b0837f26ac64e3bb06932220f1
|
| --- /dev/null
|
| +++ b/cc/output/bsp_tree_unittest.cc
|
| @@ -0,0 +1,354 @@
|
| +// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "base/macros.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "cc/base/scoped_ptr_vector.h"
|
| +#include "cc/output/bsp_controller.h"
|
| +#include "cc/output/bsp_tree.h"
|
| +#include "cc/output/bsp_walk_action.h"
|
| +#include "cc/quads/draw_polygon.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace cc {
|
| +namespace {
|
| +
|
| +class TestBspController : public BspController {
|
| + public:
|
| + TestBspController() : BspController() {}
|
| + // Since the weights of polygons affect what order they're placed in the tree,
|
| + // it's important that we don't break unit tests if the heuristic is ever
|
| + // changed. By simply forcing all the weights to be 0, the polygons will all
|
| + // be put into the tree in the same order as they're given, and the unit tests
|
| + // won't be affected by changing heuristics.
|
| + virtual float SplitWeight(const DrawPolygon& poly) OVERRIDE { return 0.0f; }
|
| +};
|
| +
|
| +#define EXPECT_SORTED_LISTS_EQ(polygon_list, compare_list) \
|
| + do { \
|
| + EXPECT_EQ(polygon_list.size(), compare_list.size()); \
|
| + for (unsigned int i = 0; i < polygon_list.size(); i++) { \
|
| + EXPECT_EQ(polygon_list[i]->order_index, compare_list[i]); \
|
| + } \
|
| + } while (false);
|
| +
|
| +#define INT_VECTOR_FROM_ARRAY(array) \
|
| + std::vector<int>(array, array + arraysize(array))
|
| +
|
| +class BspTreeTest {
|
| + public:
|
| + static void RunTest(ScopedPtrVector<DrawPolygon>* test_polygons,
|
| + const std::vector<int>& compare_list) {
|
| + TestBspController bsp_controller;
|
| + BspTree bsp_tree(&bsp_controller, test_polygons);
|
| +
|
| + std::vector<DrawPolygon*> sorted_list;
|
| + BspWalkActionToVector action_handler(&sorted_list);
|
| + bsp_tree.TraverseWithActionHandler(&action_handler);
|
| +
|
| + EXPECT_SORTED_LISTS_EQ(sorted_list, compare_list);
|
| + EXPECT_TRUE(VerifySidedness(bsp_tree.root()));
|
| + }
|
| +
|
| + static bool VerifySidedness(const scoped_ptr<BspNode>& node) {
|
| + // We check if both the front and back child nodes have geometry that is
|
| + // completely on the expected side of the current node.
|
| + bool front_ok = true;
|
| + bool back_ok = true;
|
| + if (node->back_child) {
|
| + // Make sure the back child lies entirely behind this node.
|
| + if (!GeometrySide(node, node->back_child->node_data.get(), BSP_BACK)) {
|
| + return false;
|
| + }
|
| + back_ok = VerifySidedness(node->back_child);
|
| + }
|
| + // Make sure the front child lies entirely in front of this node.
|
| + if (node->front_child) {
|
| + if (!GeometrySide(node, node->front_child->node_data.get(), BSP_FRONT)) {
|
| + return false;
|
| + }
|
| + front_ok = VerifySidedness(node->front_child);
|
| + }
|
| + if (!back_ok || !front_ok) {
|
| + return false;
|
| + }
|
| +
|
| + // Now we need to make sure our coplanar geometry is all actually coplanar.
|
| + for (unsigned int i = 0; i < node->coplanars_front.size(); i++) {
|
| + if (!GeometrySide(node, node->coplanars_front[i], BSP_COPLANAR)) {
|
| + return false;
|
| + }
|
| + }
|
| + for (unsigned int i = 0; i < node->coplanars_back.size(); i++) {
|
| + if (!GeometrySide(node, node->coplanars_back[i], BSP_COPLANAR)) {
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| + }
|
| +
|
| + static bool GeometrySide(const scoped_ptr<BspNode>& parent,
|
| + DrawPolygon* child_data,
|
| + BspCompareResult side) {
|
| + for (unsigned int i = 0; i < child_data->points.size(); i++) {
|
| + float p_distance =
|
| + parent->node_data->SignedPointDistance(child_data->points[i]);
|
| + switch (side) {
|
| + case BSP_BACK:
|
| + if (p_distance > BspController::compare_threshold) {
|
| + return false;
|
| + }
|
| + break;
|
| + case BSP_FRONT:
|
| + if (p_distance < -BspController::compare_threshold) {
|
| + return false;
|
| + }
|
| + break;
|
| + case BSP_COPLANAR:
|
| + if (std::abs(p_distance) > BspController::compare_threshold) {
|
| + return false;
|
| + }
|
| + break;
|
| + default:
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| + }
|
| + return true;
|
| + }
|
| +};
|
| +
|
| +// Simple standing quads all parallel with each other, causing no splits.
|
| +TEST(BspTreeTest, NoSplit) {
|
| + gfx::Point3F vertices_a[4];
|
| + vertices_a[0] = gfx::Point3F(0.0f, 10.0f, 0.0f);
|
| + vertices_a[1] = gfx::Point3F(0.0f, 0.0f, 0.0f);
|
| + vertices_a[2] = gfx::Point3F(10.0f, 0.0f, 0.0f);
|
| + vertices_a[3] = gfx::Point3F(10.0f, 10.0f, 0.0f);
|
| + gfx::Point3F vertices_b[4];
|
| + vertices_b[0] = gfx::Point3F(0.0f, 10.0f, -5.0f);
|
| + vertices_b[1] = gfx::Point3F(0.0f, 0.0f, -5.0f);
|
| + vertices_b[2] = gfx::Point3F(10.0f, 0.0f, -5.0f);
|
| + vertices_b[3] = gfx::Point3F(10.0f, 10.0f, -5.0f);
|
| + gfx::Point3F vertices_c[4];
|
| + vertices_c[0] = gfx::Point3F(0.0f, 10.0f, 5.0f);
|
| + vertices_c[1] = gfx::Point3F(0.0f, 0.0f, 5.0f);
|
| + vertices_c[2] = gfx::Point3F(10.0f, 0.0f, 5.0f);
|
| + vertices_c[3] = gfx::Point3F(10.0f, 10.0f, 5.0f);
|
| +
|
| + scoped_ptr<DrawPolygon> polygon_a(
|
| + new DrawPolygon(NULL, vertices_a, 4, 0, true));
|
| + scoped_ptr<DrawPolygon> polygon_b(
|
| + new DrawPolygon(NULL, vertices_b, 4, 1, true));
|
| + scoped_ptr<DrawPolygon> polygon_c(
|
| + new DrawPolygon(NULL, vertices_c, 4, 2, true));
|
| + ScopedPtrVector<DrawPolygon> polygon_list;
|
| + polygon_list.push_back(polygon_a.Pass());
|
| + polygon_list.push_back(polygon_b.Pass());
|
| + polygon_list.push_back(polygon_c.Pass());
|
| +
|
| + int compare_ids[] = {1, 0, 2};
|
| + std::vector<int> compare_list = INT_VECTOR_FROM_ARRAY(compare_ids);
|
| + BspTreeTest::RunTest(&polygon_list, compare_list);
|
| +}
|
| +
|
| +// Basic two polygon split, can be viewed as a + from above.
|
| +TEST(BspTreeTest, BasicSplit) {
|
| + gfx::Point3F vertices_a[4];
|
| + vertices_a[0] = gfx::Point3F(-5.0f, 5.0f, 0.0f);
|
| + vertices_a[1] = gfx::Point3F(-5.0f, -5.0f, 0.0f);
|
| + vertices_a[2] = gfx::Point3F(5.0f, -5.0f, 0.0f);
|
| + vertices_a[3] = gfx::Point3F(5.0f, 5.0f, 0.0f);
|
| + gfx::Point3F vertices_b[4];
|
| + vertices_b[0] = gfx::Point3F(0.0f, 5.0f, -5.0f);
|
| + vertices_b[1] = gfx::Point3F(0.0f, -5.0f, -5.0f);
|
| + vertices_b[2] = gfx::Point3F(0.0f, -5.0f, 5.0f);
|
| + vertices_b[3] = gfx::Point3F(0.0f, 5.0f, 5.0f);
|
| +
|
| + scoped_ptr<DrawPolygon> polygon_a(
|
| + new DrawPolygon(NULL, vertices_a, 4, 0, true));
|
| + scoped_ptr<DrawPolygon> polygon_b(
|
| + new DrawPolygon(NULL, vertices_b, 4, 1, true));
|
| + ScopedPtrVector<DrawPolygon> polygon_list;
|
| + polygon_list.push_back(polygon_a.Pass());
|
| + polygon_list.push_back(polygon_b.Pass());
|
| +
|
| + int compare_ids[] = {1, 0, 1};
|
| + std::vector<int> compare_list = INT_VECTOR_FROM_ARRAY(compare_ids);
|
| + BspTreeTest::RunTest(&polygon_list, compare_list);
|
| +}
|
| +
|
| +// Same as above with the second quad offset so it doesn't intersect. One quad
|
| +// should be very clearly on one side of the other, and no splitting should
|
| +// occur.
|
| +TEST(BspTreeTest, QuadOffset) {
|
| + gfx::Point3F vertices_a[4];
|
| + vertices_a[0] = gfx::Point3F(-5.0f, 5.0f, 0.0f);
|
| + vertices_a[1] = gfx::Point3F(-5.0f, -5.0f, 0.0f);
|
| + vertices_a[2] = gfx::Point3F(5.0f, -5.0f, 0.0f);
|
| + vertices_a[3] = gfx::Point3F(5.0f, 5.0f, 0.0f);
|
| + gfx::Point3F vertices_b[4];
|
| + vertices_b[0] = gfx::Point3F(0.0f, 5.0f, -15.0f);
|
| + vertices_b[1] = gfx::Point3F(0.0f, -5.0f, -15.0f);
|
| + vertices_b[2] = gfx::Point3F(0.0f, -5.0f, -10.0f);
|
| + vertices_b[3] = gfx::Point3F(0.0f, 5.0f, -10.0f);
|
| +
|
| + scoped_ptr<DrawPolygon> polygon_a(
|
| + new DrawPolygon(NULL, vertices_a, 4, 0, true));
|
| + scoped_ptr<DrawPolygon> polygon_b(
|
| + new DrawPolygon(NULL, vertices_b, 4, 1, true));
|
| + ScopedPtrVector<DrawPolygon> polygon_list;
|
| + polygon_list.push_back(polygon_a.Pass());
|
| + polygon_list.push_back(polygon_b.Pass());
|
| +
|
| + int compare_ids[] = {1, 0};
|
| + std::vector<int> compare_list = INT_VECTOR_FROM_ARRAY(compare_ids);
|
| + BspTreeTest::RunTest(&polygon_list, compare_list);
|
| +}
|
| +
|
| +// Same as above, but this time we change the order in which the quads are
|
| +// inserted into the tree, causing one to actually cross the plane of the other
|
| +// and cause a split.
|
| +TEST(BspTreeTest, QuadOffsetSplit) {
|
| + gfx::Point3F vertices_a[4];
|
| + vertices_a[0] = gfx::Point3F(-5.0f, 5.0f, 0.0f);
|
| + vertices_a[1] = gfx::Point3F(-5.0f, -5.0f, 0.0f);
|
| + vertices_a[2] = gfx::Point3F(5.0f, -5.0f, 0.0f);
|
| + vertices_a[3] = gfx::Point3F(5.0f, 5.0f, 0.0f);
|
| + gfx::Point3F vertices_b[4];
|
| + vertices_b[0] = gfx::Point3F(0.0f, 5.0f, -15.0f);
|
| + vertices_b[1] = gfx::Point3F(0.0f, -5.0f, -15.0f);
|
| + vertices_b[2] = gfx::Point3F(0.0f, -5.0f, -10.0f);
|
| + vertices_b[3] = gfx::Point3F(0.0f, 5.0f, -10.0f);
|
| +
|
| + scoped_ptr<DrawPolygon> polygon_a(
|
| + new DrawPolygon(NULL, vertices_a, 4, 0, true));
|
| + scoped_ptr<DrawPolygon> polygon_b(
|
| + new DrawPolygon(NULL, vertices_b, 4, 1, true));
|
| + ScopedPtrVector<DrawPolygon> polygon_list;
|
| + polygon_list.push_back(polygon_b.Pass());
|
| + polygon_list.push_back(polygon_a.Pass());
|
| +
|
| + int compare_ids[] = {0, 1, 0};
|
| + std::vector<int> compare_list = INT_VECTOR_FROM_ARRAY(compare_ids);
|
| + BspTreeTest::RunTest(&polygon_list, compare_list);
|
| +}
|
| +
|
| +// In addition to what can be viewed as a + from above, another piece of
|
| +// geometry is inserted to cut these pieces right in the middle, viewed as
|
| +// a quad from overhead.
|
| +TEST(BspTreeTest, ThreeWaySplit) {
|
| + gfx::Point3F vertices_a[4];
|
| + vertices_a[0] = gfx::Point3F(-5.0f, 5.0f, 0.0f);
|
| + vertices_a[1] = gfx::Point3F(-5.0f, -5.0f, 0.0f);
|
| + vertices_a[2] = gfx::Point3F(5.0f, -5.0f, 0.0f);
|
| + vertices_a[3] = gfx::Point3F(5.0f, 5.0f, 0.0f);
|
| + gfx::Point3F vertices_b[4];
|
| + vertices_b[0] = gfx::Point3F(0.0f, 5.0f, -5.0f);
|
| + vertices_b[1] = gfx::Point3F(0.0f, -5.0f, -5.0f);
|
| + vertices_b[2] = gfx::Point3F(0.0f, -5.0f, 5.0f);
|
| + vertices_b[3] = gfx::Point3F(0.0f, 5.0f, 5.0f);
|
| + gfx::Point3F vertices_c[4];
|
| + vertices_c[0] = gfx::Point3F(-5.0f, 0.0f, 5.0f);
|
| + vertices_c[1] = gfx::Point3F(-5.0f, 0.0f, -5.0f);
|
| + vertices_c[2] = gfx::Point3F(5.0f, 0.0f, -5.0f);
|
| + vertices_c[3] = gfx::Point3F(5.0f, 0.0f, 5.0f);
|
| +
|
| + scoped_ptr<DrawPolygon> polygon_a(
|
| + new DrawPolygon(NULL, vertices_a, 4, 0, true));
|
| + scoped_ptr<DrawPolygon> polygon_b(
|
| + new DrawPolygon(NULL, vertices_b, 4, 1, true));
|
| + scoped_ptr<DrawPolygon> polygon_c(
|
| + new DrawPolygon(NULL, vertices_c, 4, 2, true));
|
| + ScopedPtrVector<DrawPolygon> polygon_list;
|
| + polygon_list.push_back(polygon_a.Pass());
|
| + polygon_list.push_back(polygon_b.Pass());
|
| + polygon_list.push_back(polygon_c.Pass());
|
| +
|
| + int compare_ids[] = {2, 1, 2, 0, 2, 1, 2};
|
| + std::vector<int> compare_list = INT_VECTOR_FROM_ARRAY(compare_ids);
|
| + BspTreeTest::RunTest(&polygon_list, compare_list);
|
| +}
|
| +
|
| +// This test checks whether coplanar geometry, when inserted into the tree in
|
| +// order, comes back in the same order as it should.
|
| +TEST(BspTreeTest, Coplanar) {
|
| + gfx::Point3F vertices_a[4];
|
| + vertices_a[0] = gfx::Point3F(-5.0f, 5.0f, 0.0f);
|
| + vertices_a[1] = gfx::Point3F(-5.0f, -5.0f, 0.0f);
|
| + vertices_a[2] = gfx::Point3F(5.0f, -5.0f, 0.0f);
|
| + vertices_a[3] = gfx::Point3F(5.0f, 5.0f, 0.0f);
|
| + gfx::Point3F vertices_b[4];
|
| + vertices_b[0] = gfx::Point3F(-4.0f, 4.0f, 0.0f);
|
| + vertices_b[1] = gfx::Point3F(-4.0f, -4.0f, 0.0f);
|
| + vertices_b[2] = gfx::Point3F(4.0f, -4.0f, 0.0f);
|
| + vertices_b[3] = gfx::Point3F(4.0f, 4.0f, 0.0f);
|
| + gfx::Point3F vertices_c[4];
|
| + vertices_c[0] = gfx::Point3F(-3.0f, 3.0f, 0.0f);
|
| + vertices_c[1] = gfx::Point3F(-3.0f, -3.0f, 0.0f);
|
| + vertices_c[2] = gfx::Point3F(3.0f, -3.0f, 0.0f);
|
| + vertices_c[3] = gfx::Point3F(3.0f, 3.0f, 0.0f);
|
| +
|
| + scoped_ptr<DrawPolygon> polygon_a(
|
| + new DrawPolygon(NULL, vertices_a, 4, 0, true));
|
| + scoped_ptr<DrawPolygon> polygon_b(
|
| + new DrawPolygon(NULL, vertices_b, 4, 1, true));
|
| + scoped_ptr<DrawPolygon> polygon_c(
|
| + new DrawPolygon(NULL, vertices_c, 4, 2, true));
|
| + ScopedPtrVector<DrawPolygon> polygon_list;
|
| + polygon_list.push_back(polygon_a.Pass());
|
| + polygon_list.push_back(polygon_b.Pass());
|
| + polygon_list.push_back(polygon_c.Pass());
|
| +
|
| + int compare_ids[] = {0, 1, 2};
|
| + std::vector<int> compare_list = INT_VECTOR_FROM_ARRAY(compare_ids);
|
| + BspTreeTest::RunTest(&polygon_list, compare_list);
|
| +}
|
| +
|
| +// A bunch of coplanar geometry should end up sharing a single node, and
|
| +// result in the final piece of geometry splitting into just two pieces on
|
| +// either side of the shared plane.
|
| +TEST(BspTreeTest, CoplanarSplit) {
|
| + gfx::Point3F vertices_a[4];
|
| + vertices_a[0] = gfx::Point3F(-5.0f, 5.0f, 0.0f);
|
| + vertices_a[1] = gfx::Point3F(-5.0f, -5.0f, 0.0f);
|
| + vertices_a[2] = gfx::Point3F(5.0f, -5.0f, 0.0f);
|
| + vertices_a[3] = gfx::Point3F(5.0f, 5.0f, 0.0f);
|
| + gfx::Point3F vertices_b[4];
|
| + vertices_b[0] = gfx::Point3F(-4.0f, 4.0f, 0.0f);
|
| + vertices_b[1] = gfx::Point3F(-4.0f, -4.0f, 0.0f);
|
| + vertices_b[2] = gfx::Point3F(4.0f, -4.0f, 0.0f);
|
| + vertices_b[3] = gfx::Point3F(4.0f, 4.0f, 0.0f);
|
| + gfx::Point3F vertices_c[4];
|
| + vertices_c[0] = gfx::Point3F(-3.0f, 3.0f, 0.0f);
|
| + vertices_c[1] = gfx::Point3F(-3.0f, -3.0f, 0.0f);
|
| + vertices_c[2] = gfx::Point3F(3.0f, -3.0f, 0.0f);
|
| + vertices_c[3] = gfx::Point3F(3.0f, 3.0f, 0.0f);
|
| + gfx::Point3F vertices_d[4];
|
| + vertices_d[0] = gfx::Point3F(0.0f, 15.0f, -15.0f);
|
| + vertices_d[1] = gfx::Point3F(0.0f, -15.0f, -15.0f);
|
| + vertices_d[2] = gfx::Point3F(0.0f, -15.0f, 15.0f);
|
| + vertices_d[3] = gfx::Point3F(0.0f, 15.0f, 15.0f);
|
| +
|
| + scoped_ptr<DrawPolygon> polygon_a(
|
| + new DrawPolygon(NULL, vertices_a, 4, 0, true));
|
| + scoped_ptr<DrawPolygon> polygon_b(
|
| + new DrawPolygon(NULL, vertices_b, 4, 1, true));
|
| + scoped_ptr<DrawPolygon> polygon_c(
|
| + new DrawPolygon(NULL, vertices_c, 4, 2, true));
|
| + scoped_ptr<DrawPolygon> polygon_d(
|
| + new DrawPolygon(NULL, vertices_d, 4, 3, true));
|
| + ScopedPtrVector<DrawPolygon> polygon_list;
|
| + polygon_list.push_back(polygon_a.Pass());
|
| + polygon_list.push_back(polygon_b.Pass());
|
| + polygon_list.push_back(polygon_c.Pass());
|
| + polygon_list.push_back(polygon_d.Pass());
|
| +
|
| + int compare_ids[] = {3, 0, 1, 2, 3};
|
| + std::vector<int> compare_list = INT_VECTOR_FROM_ARRAY(compare_ids);
|
| + BspTreeTest::RunTest(&polygon_list, compare_list);
|
| +}
|
| +
|
| +} // namespace
|
| +} // namespace cc
|
|
|