root/cafu/trunk/CaWE/OrthoBspTree.hpp

Revision 457, 8.7 KB (checked in by Carsten, 4 months ago)

Using UltraEdit's multi-line search-and-replace-in-files feature, replaced


^#ifndef _(CAFU|CF|CFS|CA)_(.*)_$
^#define _\1_\2_$

with

#ifndef CAFU_\2_INCLUDED
#define CAFU_\2_INCLUDED

and


^#ifndef _(.*)_HPP_$
^#define _\1_HPP_$

with

#ifndef CAFU_\1_HPP_INCLUDED
#define CAFU_\1_HPP_INCLUDED

Closes #91.

Line 
1/*
2=================================================================================
3This file is part of Cafu, the open-source game engine and graphics engine
4for multiplayer, cross-platform, real-time 3D action.
5Copyright (C) 2002-2012 Carsten Fuchs Software.
6
7Cafu is free software: you can redistribute it and/or modify it under the terms
8of the GNU General Public License as published by the Free Software Foundation,
9either version 3 of the License, or (at your option) any later version.
10
11Cafu is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
12without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13PURPOSE. See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with Cafu. If not, see <http://www.gnu.org/licenses/>.
17
18For support and more information about Cafu, visit us at <http://www.cafu.de>.
19=================================================================================
20*/
21
22#ifndef CAFU_ORTHO_BSP_TREE_HPP_INCLUDED
23#define CAFU_ORTHO_BSP_TREE_HPP_INCLUDED
24
25#include "Math3D/BoundingBox.hpp"
26
27
28class MapElementT;
29
30
31/// This class represents an orthogonal BSP tree (axis-aligned split planes) that spatially organizes MapElementT instances.
32///
33/// A map element is generally linked in each leaf that it intersects, or instead whenever possible in the node closest to the
34/// root where the element intersects *all* children.
35/// Note that the latter is an optional feature that yields a tree that is logically equivalent to the pure "store all contents
36/// in leaves" strategy (where nodes generally remain empty and store no contents at all), but in comparison saves some storage.
37/// Also note the subtle difference to storing some contents in nodes (the elements that intersect a split plane) and some (the
38/// rest) in leaves, like ancient version of our CaBSP: Keeping some contents in nodes like this would make it impossible to
39/// determine the contents (the set of all map elements) that are inside a given node, because the set would be grossly oversized.
40/// Our "extended leaves-only" approach saves both storage and is able to produce for each node the exact set of map elements
41/// (required e.g. for view frustum tests).
42///
43/// Another feature of this implementation is that the bounding-box of a node is usually *not* the tight bounding-box over its
44/// contents, but typically larger:
45/// The bounding-box of the root node is the maximum bounds of the world, the bounding-box of its children is determined by
46/// subdividing it along the split plane, etc. As such, the bounding-boxes in the tree only depend on the split planes, but not
47/// directly on the contents of the nodes (and thus the BB member of the NodeT class is const).
48///
49/// Finally, note how these larger bounding-boxes affect the tree structure and size. There are two important differences:
50/// 1. Where we would not have node planes at the outmost brush faces with a "tight" starting box, our approach definitively
51///    comes up with these outmost walls as split planes sooner or later. This enlarges the tree, but these extra nodes are
52///    fortunately not completely useless: When the user extends the map spatially, the extra nodes come in just handy.
53/// 2. The center of our larger boxes is often different from the center of the tight bounding-boxes, as the tight boxes are
54///    usually not symmetric to the origin. This causes different split planes to be chosen when the tree is built.
55///    As with issue 1. though, this difference is not a principal or serious problem.
56class OrthoBspTreeT
57{
58    public:
59
60    class NodeT
61    {
62        public:
63
64        /// As the nodes of the tree are not subdivided by arbitrary planes, but only by planes that are parallel
65        /// to the major axes, we do not store a full Plane3T<> member with the nodes, but only a "compacted" representation:
66        /// The type expresses which axes the plane is parallel to, the distance is the offset from the origin.
67        enum PlaneTypeE
68        {
69            NONE=-1,    ///< No plane at all. Used for nodes that are actually leaves.
70            ALONG_X,    ///< A plane with normal vector (1, 0, 0), parallel to the y- and z-axis.
71            ALONG_Y,    ///< A plane with normal vector (0, 1, 0), parallel to the x- and z-axis.
72            ALONG_Z     ///< A plane with normal vector (0, 0, 1), parallel to the x- and y-axis.
73        };
74
75
76        /// The constructor.
77        /// @param BB   The bounding box of this node (one "half" of the box of the parent).
78        NodeT(const BoundingBox3fT& BB);
79
80        /// The destructor.
81        ~NodeT();
82
83        PlaneTypeE                  GetPlaneType() const { return m_PlaneType; }
84        float                       GetPlaneDist() const { return m_PlaneDist; }
85        const NodeT*                GetChild(unsigned int ChildNr) const { return m_Children[ChildNr]; }
86        const ArrayT<MapElementT*>& GetElems() const { return m_Elems; }
87        const BoundingBox3fT&       GetBB() const { return m_BB; }
88
89        /// Returns the number of nodes in the (sub-)tree at and below this node.
90        unsigned long GetNumNodes() const;
91
92        /// Determines an axis-aligned split plane for further BSP partitioning of the contents of this node.
93        /// For choosing the split plane, the method considers the bounding-box planes of all objects (polygons, brushes, terrains)
94        /// of this node and all its ancestors, provided that they are wholly or partially in BB.
95        /// When a split plane was found, the m_PlaneType and m_PlaneDist members are appropriately set and true is returned,
96        /// otherwise they are initialized with NONE and 0, respectively, and the return value is false.
97        /// @returns whether a split plane has successfully been determined.
98        bool DetermineSplitPlane();
99
100        /// Determines whether the given BB intersects (is partly inside) each child of this node.
101        /// @param BB   The bounding box that is tested for intersection.
102        bool IntersectsAllChildren(const BoundingBox3fT& BB) const;
103
104        /// Finds any map elements in the (sub-)tree whose spatial position disagrees with their position in the tree.
105        void FindMismatches(ArrayT<MapElementT*>& Mismatches) const;
106
107        /// Recursively inserts the given element into the (sub-)tree at and below this node.
108        void Insert(MapElementT* Elem);
109
110        /// Removes the given element from the (sub-)tree at and below this node (the structure of the tree remains unchanged).
111        void Remove(MapElementT* Elem);
112
113
114        private:
115
116        friend class OrthoBspTreeT;
117
118        NodeT(const NodeT&);                ///< Use of the Copy    Constructor is not allowed.
119        void operator = (const NodeT&);     ///< Use of the Assignment Operator is not allowed.
120
121        PlaneTypeE           m_PlaneType;   ///< The type of the plane that subdivides this node (no plane at all, normal vector along the x-, y- or z-axis).
122        float                m_PlaneDist;   ///< The distance of the plane to the origin. Corresponds to the Plane3fT::Dist member in a full plane.
123        NodeT*               m_Parent;      ///< The parent of this node, NULL if this is the root node.
124        NodeT*               m_Children[2]; ///< The children of this node at each side of the plane (NULL if there is no plane / the node is a leaf).
125        ArrayT<MapElementT*> m_Elems;       ///< The list of map elements in this node.
126        const BoundingBox3fT m_BB;          ///< The bounding-box of this node.
127    };
128
129
130    /// The constructor.
131    OrthoBspTreeT(const ArrayT<MapElementT*>& Elems, const BoundingBox3fT& BB);
132
133    /// The destructor.
134    ~OrthoBspTreeT();
135
136    /// Returns the BSP trees root node.
137    const NodeT* GetRootNode() const { return m_RootNode; }
138
139    /// Inserts the given element into the tree (the structure of the tree remains unchanged).
140    void Insert(MapElementT* Elem) { m_RootNode->Insert(Elem); }
141
142    /// Removes the given element from the tree (the structure of the tree remains unchanged).
143    void Remove(MapElementT* Elem) { m_RootNode->Remove(Elem); }
144
145    /// Removes and re-inserts map elements from and into the tree whose bounding-box changed so that it disagrees with the tree structure.
146    /// This method is called once per "document frame" in ChildFrameT::OnIdle().
147    /// @returns the number of map elements that have been updated.
148    unsigned long Update();
149
150
151    private:
152
153    OrthoBspTreeT(const OrthoBspTreeT&);    ///< Use of the Copy    Constructor is not allowed.
154    void operator = (const OrthoBspTreeT&); ///< Use of the Assignment Operator is not allowed.
155
156    void BuildTree(NodeT* node);
157
158    NodeT* m_RootNode;
159};
160
161#endif
Note: See TracBrowser for help on using the browser.