diff options
author | thildebr@chromium.org <thildebr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-30 12:50:20 +0000 |
---|---|---|
committer | thildebr@chromium.org <thildebr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-30 12:50:20 +0000 |
commit | 80fae1ef974518320a0c16cd25c510a5abcfcbb5 (patch) | |
tree | bc4355bfb934fd30569f2861839188b9ae319c08 | |
parent | e3a62a3b4f5114fb198518fba848d88418567a5b (diff) | |
download | chromium_src-80fae1ef974518320a0c16cd25c510a5abcfcbb5.zip chromium_src-80fae1ef974518320a0c16cd25c510a5abcfcbb5.tar.gz chromium_src-80fae1ef974518320a0c16cd25c510a5abcfcbb5.tar.bz2 |
WIP BSP Tree for 3D Layer Sorting
Still adding test scenarios as I come up with them.
Review URL: https://codereview.chromium.org/384083002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@286499 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | cc/cc.gyp | 5 | ||||
-rw-r--r-- | cc/cc_tests.gyp | 1 | ||||
-rw-r--r-- | cc/output/bsp_tree.cc | 121 | ||||
-rw-r--r-- | cc/output/bsp_tree.h | 115 | ||||
-rw-r--r-- | cc/output/bsp_tree_unittest.cc | 348 | ||||
-rw-r--r-- | cc/output/bsp_walk_action.cc | 23 | ||||
-rw-r--r-- | cc/output/bsp_walk_action.h | 34 |
7 files changed, 646 insertions, 1 deletions
@@ -244,7 +244,10 @@ 'layers/video_layer_impl.h', 'output/begin_frame_args.cc', 'output/begin_frame_args.h', - 'output/bsp_compare_result.h', + 'output/bsp_tree.cc', + 'output/bsp_tree.h', + 'output/bsp_walk_action.cc', + 'output/bsp_walk_action.h', 'output/compositor_frame.cc', 'output/compositor_frame.h', 'output/compositor_frame_ack.cc', diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp index d29413d..18d38f9 100644 --- a/cc/cc_tests.gyp +++ b/cc/cc_tests.gyp @@ -58,6 +58,7 @@ 'layers/ui_resource_layer_unittest.cc', 'layers/video_layer_impl_unittest.cc', 'output/begin_frame_args_unittest.cc', + 'output/bsp_tree_unittest.cc', 'output/delegating_renderer_unittest.cc', 'output/filter_operations_unittest.cc', 'output/gl_renderer_unittest.cc', diff --git a/cc/output/bsp_tree.cc b/cc/output/bsp_tree.cc new file mode 100644 index 0000000..2755c0b --- /dev/null +++ b/cc/output/bsp_tree.cc @@ -0,0 +1,121 @@ +// 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 "cc/output/bsp_tree.h" + +#include <list> +#include <vector> + +#include "base/memory/scoped_ptr.h" +#include "cc/base/scoped_ptr_deque.h" +#include "cc/base/scoped_ptr_vector.h" +#include "cc/output/bsp_compare_result.h" +#include "cc/quads/draw_polygon.h" + +namespace cc { + +BspNode::BspNode(scoped_ptr<DrawPolygon> data) : node_data(data.Pass()) { +} + +BspNode::~BspNode() { +} + +BspTree::BspTree(ScopedPtrDeque<DrawPolygon>* list) { + if (list->size() == 0) + return; + + root_ = scoped_ptr<BspNode>(new BspNode(list->take_front())); + BuildTree(root_.get(), list); +} + +// The idea behind using a deque for BuildTree's input is that we want to be +// able to place polygons that we've decided aren't splitting plane candidates +// at the back of the queue while moving the candidate splitting planes to the +// front when the heuristic decides that they're a better choice. This way we +// can always simply just take from the front of the deque for our node's +// data. +void BspTree::BuildTree(BspNode* node, + ScopedPtrDeque<DrawPolygon>* polygon_list) { + ScopedPtrDeque<DrawPolygon> front_list; + ScopedPtrDeque<DrawPolygon> back_list; + + // We take in a list of polygons at this level of the tree, and have to + // find a splitting plane, then classify polygons as either in front of + // or behind that splitting plane. + while (polygon_list->size() > 0) { + // Is this particular polygon in front of or behind our splitting polygon. + BspCompareResult comparer_result = + GetNodePositionRelative(*polygon_list->front(), *(node->node_data)); + + // If it's clearly behind or in front of the splitting plane, we use the + // heuristic to decide whether or not we should put it at the back + // or front of the list. + switch (comparer_result) { + case BSP_FRONT: + front_list.push_back(polygon_list->take_front().Pass()); + break; + case BSP_BACK: + back_list.push_back(polygon_list->take_front().Pass()); + break; + case BSP_SPLIT: + { + scoped_ptr<DrawPolygon> polygon; + scoped_ptr<DrawPolygon> new_front; + scoped_ptr<DrawPolygon> new_back; + bool split_result = false; + // Time to split this geometry, *it needs to be split by node_data. + polygon = polygon_list->take_front(); + split_result = + polygon->Split(*(node->node_data), &new_front, &new_back); + DCHECK(split_result); + if (!split_result) { + break; + } + front_list.push_back(new_front.Pass()); + back_list.push_back(new_back.Pass()); + break; + } + case BSP_COPLANAR_FRONT: + node->coplanars_front.push_back(polygon_list->take_front()); + break; + case BSP_COPLANAR_BACK: + node->coplanars_back.push_back(polygon_list->take_front()); + break; + default: + NOTREACHED(); + break; + } + } + + // Build the back subtree using the front of the back_list as our splitter. + if (back_list.size() > 0) { + node->back_child = scoped_ptr<BspNode>(new BspNode(back_list.take_front())); + BuildTree(node->back_child.get(), &back_list); + } + + // Build the front subtree using the front of the front_list as our splitter. + if (front_list.size() > 0) { + node->front_child = + scoped_ptr<BspNode>(new BspNode(front_list.take_front())); + BuildTree(node->front_child.get(), &front_list); + } +} + +BspCompareResult BspTree::GetNodePositionRelative(const DrawPolygon& node_a, + const DrawPolygon& node_b) { + return DrawPolygon::SideCompare(node_a, node_b); +} + +// The base comparer with 0,0,0 as camera position facing forward +BspCompareResult BspTree::GetCameraPositionRelative(const DrawPolygon& node) { + if (node.normal().z() > 0.0f) { + return BSP_FRONT; + } + return BSP_BACK; +} + +BspTree::~BspTree() { +} + +} // namespace cc diff --git a/cc/output/bsp_tree.h b/cc/output/bsp_tree.h new file mode 100644 index 0000000..6e7f66b --- /dev/null +++ b/cc/output/bsp_tree.h @@ -0,0 +1,115 @@ +// 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. + +#ifndef CC_OUTPUT_BSP_TREE_H_ +#define CC_OUTPUT_BSP_TREE_H_ + +#include <list> +#include <vector> + +#include "base/memory/scoped_ptr.h" +#include "cc/base/scoped_ptr_deque.h" +#include "cc/base/scoped_ptr_vector.h" +#include "cc/output/bsp_compare_result.h" +#include "cc/quads/draw_polygon.h" + +namespace cc { + +struct BspNode { + // This represents the splitting plane. + scoped_ptr<DrawPolygon> node_data; + // This represents any coplanar geometry we found while building the BSP. + ScopedPtrVector<DrawPolygon> coplanars_front; + ScopedPtrVector<DrawPolygon> coplanars_back; + + scoped_ptr<BspNode> back_child; + scoped_ptr<BspNode> front_child; + + explicit BspNode(scoped_ptr<DrawPolygon> data); + ~BspNode(); +}; + +class CC_EXPORT BspTree { + public: + explicit BspTree(ScopedPtrDeque<DrawPolygon>* list); + scoped_ptr<BspNode>& root() { return root_; } + + template <typename ActionHandlerType> + void TraverseWithActionHandler(ActionHandlerType* action_handler) const { + if (root_) { + WalkInOrderRecursion<ActionHandlerType>(action_handler, root_.get()); + } + } + + ~BspTree(); + + private: + scoped_ptr<BspNode> root_; + + void FromList(ScopedPtrVector<DrawPolygon>* list); + void BuildTree(BspNode* node, ScopedPtrDeque<DrawPolygon>* data); + + template <typename ActionHandlerType> + void WalkInOrderAction(ActionHandlerType* action_handler, + DrawPolygon* item) const { + (*action_handler)(item); + } + + template <typename ActionHandlerType> + void WalkInOrderVisitNodes( + ActionHandlerType* action_handler, + const BspNode* node, + const BspNode* first_child, + const BspNode* second_child, + const ScopedPtrVector<DrawPolygon>& first_coplanars, + const ScopedPtrVector<DrawPolygon>& second_coplanars) const { + if (first_child) { + WalkInOrderRecursion(action_handler, first_child); + } + for (size_t i = 0; i < first_coplanars.size(); i++) { + WalkInOrderAction(action_handler, first_coplanars[i]); + } + WalkInOrderAction(action_handler, node->node_data.get()); + for (size_t i = 0; i < second_coplanars.size(); i++) { + WalkInOrderAction(action_handler, second_coplanars[i]); + } + if (second_child) { + WalkInOrderRecursion(action_handler, second_child); + } + } + + template <typename ActionHandlerType> + void WalkInOrderRecursion(ActionHandlerType* action_handler, + const BspNode* node) const { + // If our view is in front of the the polygon + // in this node then walk back then front. + if (GetCameraPositionRelative(*(node->node_data)) == BSP_FRONT) { + WalkInOrderVisitNodes<ActionHandlerType>(action_handler, + node, + node->back_child.get(), + node->front_child.get(), + node->coplanars_front, + node->coplanars_back); + } else { + WalkInOrderVisitNodes<ActionHandlerType>(action_handler, + node, + node->front_child.get(), + node->back_child.get(), + node->coplanars_back, + node->coplanars_front); + } + } + + // Returns whether or not nodeA is on one or the other side of nodeB, + // coplanar, or whether it crosses nodeB's plane and needs to be split + static BspCompareResult GetNodePositionRelative(const DrawPolygon& node_a, + const DrawPolygon& node_b); + // Returns whether or not our viewer is in front of or behind the plane + // defined by this polygon/node + static BspCompareResult GetCameraPositionRelative(const DrawPolygon& node); +}; + +} // namespace cc + +#endif // CC_OUTPUT_BSP_TREE_H_ diff --git a/cc/output/bsp_tree_unittest.cc b/cc/output/bsp_tree_unittest.cc new file mode 100644 index 0000000..100bc91 --- /dev/null +++ b/cc/output/bsp_tree_unittest.cc @@ -0,0 +1,348 @@ +// 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_deque.h" +#include "cc/base/scoped_ptr_vector.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 { + +#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)) + +#define CREATE_DRAW_POLYGON(vertex_vector, normal, polygon_id) \ + new DrawPolygon(NULL, vertex_vector, normal, polygon_id) + +class BspTreeTest { + public: + static void RunTest(ScopedPtrDeque<DrawPolygon>* test_polygons, + const std::vector<int>& compare_list) { + BspTree bsp_tree(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. + BspCompareResult result = DrawPolygon::SideCompare( + *(node->back_child->node_data), *(node->node_data)); + if (result != 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) { + BspCompareResult result = DrawPolygon::SideCompare( + *(node->front_child->node_data), *(node->node_data)); + if (result != 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 (size_t i = 0; i < node->coplanars_front.size(); i++) { + BspCompareResult result = DrawPolygon::SideCompare( + *(node->coplanars_front[i]), *(node->node_data)); + if (result != BSP_COPLANAR_FRONT) { + return false; + } + } + for (size_t i = 0; i < node->coplanars_back.size(); i++) { + BspCompareResult result = DrawPolygon::SideCompare( + *(node->coplanars_back[i]), *(node->node_data)); + if (result != BSP_COPLANAR_BACK) { + return false; + } + } + return true; + } +}; + +// Simple standing quads all parallel with each other, causing no splits. +TEST(BspTreeTest, NoSplit) { + std::vector<gfx::Point3F> vertices_a; + vertices_a.push_back(gfx::Point3F(0.0f, 10.0f, 0.0f)); + vertices_a.push_back(gfx::Point3F(0.0f, 0.0f, 0.0f)); + vertices_a.push_back(gfx::Point3F(10.0f, 0.0f, 0.0f)); + vertices_a.push_back(gfx::Point3F(10.0f, 10.0f, 0.0f)); + std::vector<gfx::Point3F> vertices_b; + vertices_b.push_back(gfx::Point3F(0.0f, 10.0f, -5.0f)); + vertices_b.push_back(gfx::Point3F(0.0f, 0.0f, -5.0f)); + vertices_b.push_back(gfx::Point3F(10.0f, 0.0f, -5.0f)); + vertices_b.push_back(gfx::Point3F(10.0f, 10.0f, -5.0f)); + std::vector<gfx::Point3F> vertices_c; + vertices_c.push_back(gfx::Point3F(0.0f, 10.0f, 5.0f)); + vertices_c.push_back(gfx::Point3F(0.0f, 0.0f, 5.0f)); + vertices_c.push_back(gfx::Point3F(10.0f, 0.0f, 5.0f)); + vertices_c.push_back(gfx::Point3F(10.0f, 10.0f, 5.0f)); + + scoped_ptr<DrawPolygon> polygon_a( + CREATE_DRAW_POLYGON(vertices_a, gfx::Vector3dF(0.0f, 0.0f, 1.0f), 0)); + scoped_ptr<DrawPolygon> polygon_b( + CREATE_DRAW_POLYGON(vertices_b, gfx::Vector3dF(0.0f, 0.0f, 1.0f), 1)); + scoped_ptr<DrawPolygon> polygon_c( + CREATE_DRAW_POLYGON(vertices_c, gfx::Vector3dF(0.0f, 0.0f, 1.0f), 2)); + + ScopedPtrDeque<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) { + std::vector<gfx::Point3F> vertices_a; + vertices_a.push_back(gfx::Point3F(-5.0f, -5.0f, 0.0f)); + vertices_a.push_back(gfx::Point3F(-5.0f, 5.0f, 0.0f)); + vertices_a.push_back(gfx::Point3F(5.0f, 5.0f, 0.0f)); + vertices_a.push_back(gfx::Point3F(5.0f, -5.0f, 0.0f)); + std::vector<gfx::Point3F> vertices_b; + vertices_b.push_back(gfx::Point3F(0.0f, -5.0f, -5.0f)); + vertices_b.push_back(gfx::Point3F(0.0f, 5.0f, -5.0f)); + vertices_b.push_back(gfx::Point3F(0.0f, 5.0f, 5.0f)); + vertices_b.push_back(gfx::Point3F(0.0f, -5.0f, 5.0f)); + + scoped_ptr<DrawPolygon> polygon_a( + CREATE_DRAW_POLYGON(vertices_a, gfx::Vector3dF(0.0f, 0.0f, 1.0f), 0)); + scoped_ptr<DrawPolygon> polygon_b( + CREATE_DRAW_POLYGON(vertices_b, gfx::Vector3dF(-1.0f, 0.0f, 0.0f), 1)); + + ScopedPtrDeque<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) { + std::vector<gfx::Point3F> vertices_a; + vertices_a.push_back(gfx::Point3F(-5.0f, -5.0f, 0.0f)); + vertices_a.push_back(gfx::Point3F(-5.0f, 5.0f, 0.0f)); + vertices_a.push_back(gfx::Point3F(5.0f, 5.0f, 0.0f)); + vertices_a.push_back(gfx::Point3F(5.0f, -5.0f, 0.0f)); + std::vector<gfx::Point3F> vertices_b; + vertices_b.push_back(gfx::Point3F(0.0f, 5.0f, -15.0f)); + vertices_b.push_back(gfx::Point3F(0.0f, -5.0f, -15.0f)); + vertices_b.push_back(gfx::Point3F(0.0f, -5.0f, -10.0f)); + vertices_b.push_back(gfx::Point3F(0.0f, 5.0f, -10.0f)); + + scoped_ptr<DrawPolygon> polygon_a( + CREATE_DRAW_POLYGON(vertices_a, gfx::Vector3dF(0.0f, 0.0f, 1.0f), 0)); + scoped_ptr<DrawPolygon> polygon_b( + CREATE_DRAW_POLYGON(vertices_b, gfx::Vector3dF(-1.0f, 0.0f, 0.0f), 1)); + + ScopedPtrDeque<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) { + std::vector<gfx::Point3F> vertices_a; + vertices_a.push_back(gfx::Point3F(-5.0f, -5.0f, 0.0f)); + vertices_a.push_back(gfx::Point3F(-5.0f, 5.0f, 0.0f)); + vertices_a.push_back(gfx::Point3F(5.0f, 5.0f, 0.0f)); + vertices_a.push_back(gfx::Point3F(5.0f, -5.0f, 0.0f)); + std::vector<gfx::Point3F> vertices_b; + vertices_b.push_back(gfx::Point3F(0.0f, -5.0f, -15.0f)); + vertices_b.push_back(gfx::Point3F(0.0f, 5.0f, -15.0f)); + vertices_b.push_back(gfx::Point3F(0.0f, 5.0f, -10.0f)); + vertices_b.push_back(gfx::Point3F(0.0f, -5.0f, -10.0f)); + + scoped_ptr<DrawPolygon> polygon_a( + CREATE_DRAW_POLYGON(vertices_a, gfx::Vector3dF(0.0f, 0.0f, 1.0f), 0)); + scoped_ptr<DrawPolygon> polygon_b( + CREATE_DRAW_POLYGON(vertices_b, gfx::Vector3dF(-1.0f, 0.0f, 0.0f), 1)); + + ScopedPtrDeque<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) { + std::vector<gfx::Point3F> vertices_a; + vertices_a.push_back(gfx::Point3F(-5.0f, -5.0f, 0.0f)); + vertices_a.push_back(gfx::Point3F(-5.0f, 5.0f, 0.0f)); + vertices_a.push_back(gfx::Point3F(5.0f, 5.0f, 0.0f)); + vertices_a.push_back(gfx::Point3F(5.0f, -5.0f, 0.0f)); + std::vector<gfx::Point3F> vertices_b; + vertices_b.push_back(gfx::Point3F(0.0f, -5.0f, -5.0f)); + vertices_b.push_back(gfx::Point3F(0.0f, 5.0f, -5.0f)); + vertices_b.push_back(gfx::Point3F(0.0f, 5.0f, 5.0f)); + vertices_b.push_back(gfx::Point3F(0.0f, -5.0f, 5.0f)); + std::vector<gfx::Point3F> vertices_c; + vertices_c.push_back(gfx::Point3F(-5.0f, 0.0f, -5.0f)); + vertices_c.push_back(gfx::Point3F(-5.0f, 0.0f, 5.0f)); + vertices_c.push_back(gfx::Point3F(5.0f, 0.0f, 5.0f)); + vertices_c.push_back(gfx::Point3F(5.0f, 0.0f, -5.0f)); + + scoped_ptr<DrawPolygon> polygon_a( + CREATE_DRAW_POLYGON(vertices_a, gfx::Vector3dF(0.0f, 0.0f, 1.0f), 0)); + scoped_ptr<DrawPolygon> polygon_b( + CREATE_DRAW_POLYGON(vertices_b, gfx::Vector3dF(-1.0f, 0.0f, 0.0f), 1)); + scoped_ptr<DrawPolygon> polygon_c( + CREATE_DRAW_POLYGON(vertices_c, gfx::Vector3dF(0.0f, 1.0f, 0.0f), 2)); + + ScopedPtrDeque<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) { + std::vector<gfx::Point3F> vertices_a; + vertices_a.push_back(gfx::Point3F(-5.0f, -5.0f, 0.0f)); + vertices_a.push_back(gfx::Point3F(-5.0f, 5.0f, 0.0f)); + vertices_a.push_back(gfx::Point3F(5.0f, 5.0f, 0.0f)); + vertices_a.push_back(gfx::Point3F(5.0f, -5.0f, 0.0f)); + std::vector<gfx::Point3F> vertices_b; + vertices_b.push_back(gfx::Point3F(-4.0f, -4.0f, 0.0f)); + vertices_b.push_back(gfx::Point3F(-4.0f, 4.0f, 0.0f)); + vertices_b.push_back(gfx::Point3F(4.0f, 4.0f, 0.0f)); + vertices_b.push_back(gfx::Point3F(4.0f, -4.0f, 0.0f)); + std::vector<gfx::Point3F> vertices_c; + vertices_c.push_back(gfx::Point3F(-3.0f, -3.0f, 0.0f)); + vertices_c.push_back(gfx::Point3F(-3.0f, 3.0f, 0.0f)); + vertices_c.push_back(gfx::Point3F(3.0f, 3.0f, 0.0f)); + vertices_c.push_back(gfx::Point3F(3.0f, -3.0f, 0.0f)); + + scoped_ptr<DrawPolygon> polygon_a( + CREATE_DRAW_POLYGON(vertices_a, gfx::Vector3dF(0.0f, 0.0f, 1.0f), 0)); + scoped_ptr<DrawPolygon> polygon_b( + CREATE_DRAW_POLYGON(vertices_b, gfx::Vector3dF(0.0f, 0.0f, 1.0f), 1)); + scoped_ptr<DrawPolygon> polygon_c( + CREATE_DRAW_POLYGON(vertices_c, gfx::Vector3dF(0.0f, 0.0f, 1.0f), 2)); + + scoped_ptr<DrawPolygon> polygon_d = polygon_a->CreateCopy(); + scoped_ptr<DrawPolygon> polygon_e = polygon_b->CreateCopy(); + scoped_ptr<DrawPolygon> polygon_f = polygon_c->CreateCopy(); + + { + ScopedPtrDeque<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); + } + + // Now check a different order and ensure we get that back as well + { + ScopedPtrDeque<DrawPolygon> polygon_list; + polygon_list.push_back(polygon_f.Pass()); + polygon_list.push_back(polygon_d.Pass()); + polygon_list.push_back(polygon_e.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) { + std::vector<gfx::Point3F> vertices_a; + vertices_a.push_back(gfx::Point3F(-5.0f, -5.0f, 0.0f)); + vertices_a.push_back(gfx::Point3F(-5.0f, 5.0f, 0.0f)); + vertices_a.push_back(gfx::Point3F(5.0f, 5.0f, 0.0f)); + vertices_a.push_back(gfx::Point3F(5.0f, -5.0f, 0.0f)); + std::vector<gfx::Point3F> vertices_b; + vertices_b.push_back(gfx::Point3F(-4.0f, -4.0f, 0.0f)); + vertices_b.push_back(gfx::Point3F(-4.0f, 4.0f, 0.0f)); + vertices_b.push_back(gfx::Point3F(4.0f, 4.0f, 0.0f)); + vertices_b.push_back(gfx::Point3F(4.0f, -4.0f, 0.0f)); + std::vector<gfx::Point3F> vertices_c; + vertices_c.push_back(gfx::Point3F(-3.0f, -3.0f, 0.0f)); + vertices_c.push_back(gfx::Point3F(-3.0f, 3.0f, 0.0f)); + vertices_c.push_back(gfx::Point3F(3.0f, 3.0f, 0.0f)); + vertices_c.push_back(gfx::Point3F(3.0f, -3.0f, 0.0f)); + std::vector<gfx::Point3F> vertices_d; + vertices_d.push_back(gfx::Point3F(0.0f, -15.0f, -15.0f)); + vertices_d.push_back(gfx::Point3F(0.0f, 15.0f, -15.0f)); + vertices_d.push_back(gfx::Point3F(0.0f, 15.0f, 15.0f)); + vertices_d.push_back(gfx::Point3F(0.0f, -15.0f, 15.0f)); + + scoped_ptr<DrawPolygon> polygon_a( + CREATE_DRAW_POLYGON(vertices_a, gfx::Vector3dF(0.0f, 0.0f, 1.0f), 0)); + scoped_ptr<DrawPolygon> polygon_b( + CREATE_DRAW_POLYGON(vertices_b, gfx::Vector3dF(0.0f, 0.0f, 1.0f), 1)); + scoped_ptr<DrawPolygon> polygon_c( + CREATE_DRAW_POLYGON(vertices_c, gfx::Vector3dF(0.0f, 0.0f, 1.0f), 2)); + scoped_ptr<DrawPolygon> polygon_d( + CREATE_DRAW_POLYGON(vertices_d, gfx::Vector3dF(-1.0f, 0.0f, 0.0f), 3)); + + ScopedPtrDeque<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 diff --git a/cc/output/bsp_walk_action.cc b/cc/output/bsp_walk_action.cc new file mode 100644 index 0000000..da5ada5 --- /dev/null +++ b/cc/output/bsp_walk_action.cc @@ -0,0 +1,23 @@ +// 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 "cc/output/bsp_walk_action.h" + +#include <vector> + +#include "base/memory/scoped_ptr.h" +#include "cc/output/direct_renderer.h" +#include "cc/quads/draw_polygon.h" + +namespace cc { + +void BspWalkActionToVector::operator()(DrawPolygon* item) { + list_->push_back(item); +} + +BspWalkActionToVector::BspWalkActionToVector(std::vector<DrawPolygon*>* in_list) + : list_(in_list) { +} + +} // namespace cc diff --git a/cc/output/bsp_walk_action.h b/cc/output/bsp_walk_action.h new file mode 100644 index 0000000..bb31865 --- /dev/null +++ b/cc/output/bsp_walk_action.h @@ -0,0 +1,34 @@ +// 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. + +#ifndef CC_OUTPUT_BSP_WALK_ACTION_H_ +#define CC_OUTPUT_BSP_WALK_ACTION_H_ + +#include <vector> + +#include "base/memory/scoped_ptr.h" +#include "cc/output/direct_renderer.h" +#include "cc/quads/draw_polygon.h" + +namespace cc { + +class CC_EXPORT BspWalkAction { + public: + virtual void operator()(DrawPolygon* item) = 0; +}; + +// The BspTree class takes ownership of all the DrawPolygons returned in list_ +// so the BspTree must be preserved while elements in that vector are in use. +class CC_EXPORT BspWalkActionToVector : public BspWalkAction { + public: + explicit BspWalkActionToVector(std::vector<DrawPolygon*>* in_list); + virtual void operator()(DrawPolygon* item) OVERRIDE; + + private: + std::vector<DrawPolygon*>* list_; +}; + +} // namespace cc + +#endif // CC_OUTPUT_BSP_WALK_ACTION_H_ |