Skip to content

Commit

Permalink
WIP BSP Tree for 3D Layer Sorting
Browse files Browse the repository at this point in the history
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
  • Loading branch information
thildebr@chromium.org committed Jul 30, 2014
1 parent e3a62a3 commit 80fae1e
Show file tree
Hide file tree
Showing 7 changed files with 646 additions and 1 deletion.
5 changes: 4 additions & 1 deletion cc/cc.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
1 change: 1 addition & 0 deletions cc/cc_tests.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
121 changes: 121 additions & 0 deletions cc/output/bsp_tree.cc
Original file line number Diff line number Diff line change
@@ -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
115 changes: 115 additions & 0 deletions cc/output/bsp_tree.h
Original file line number Diff line number Diff line change
@@ -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_
Loading

0 comments on commit 80fae1e

Please sign in to comment.