root/trunk/src/shared/vmap/TreeNode.h @ 102

Revision 102, 9.5 kB (checked in by yumileroy, 17 years ago)

[svn] Fixed copyright notices to comply with GPL.

Original author: w12x
Date: 2008-10-23 03:29:52-05:00

Line 
1/*
2* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3*
4* Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
5*
6* This program is free software; you can redistribute it and/or modify
7* it under the terms of the GNU General Public License as published by
8* the Free Software Foundation; either version 2 of the License, or
9* (at your option) any later version.
10*
11* This program is distributed in the hope that it will be useful,
12* but WITHOUT ANY WARRANTY; without even the implied warranty of
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14* GNU General Public License for more details.
15*
16* You should have received a copy of the GNU General Public License
17* along with this program; if not, write to the Free Software
18* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21#ifndef _TREENODE_H
22#define _TREENODE_H
23
24#include "ShortVector.h"
25#include "ShortBox.h"
26#include "NodeValueAccess.h"
27#include "VMapTools.h"
28
29#include <G3D/Vector3.h>
30#include <G3D/AABox.h>
31
32namespace VMAP
33{
34    /**
35    This Class is mainly taken from G3D/AABSPTree.h and modified to match our data structure.
36    It is the node within our static BSP-Trees.
37    It does not use pointers but indexes to access the values and other nodes.
38    */
39
40    //=====================================================
41
42    class TreeNode
43    {
44    private:
45        /** Location along the specified axis */
46        float iSplitLocation;
47        // Offest or the clients
48        int iChilds[2];
49        //Position within the TriangleBox array
50        unsigned int iStartPosition;
51        G3D::Vector3::Axis iSplitAxis;
52        G3D::AABox iBounds;
53        unsigned short iNumberOfValues;
54    public:
55        TreeNode() {}
56        TreeNode(unsigned short pNValues, unsigned int pStartPosition)
57        {
58            iChilds[0] = -1;
59            iChilds[1] = -1;
60            iStartPosition = pStartPosition;
61            iNumberOfValues = pNValues;
62        }
63
64        bool hasChilds() const { return(iChilds[0] >= 0 || iChilds[1] >= 0); }
65
66        TreeNode const* getChild(TreeNode const* pValueArray, int pNo) const;
67        // pChildNo = 0 or 1
68        inline void setChildPos(int pChildNo, int pChildPosInTreeNodeArray) { iChilds[pChildNo] = pChildPosInTreeNodeArray; }
69
70        inline G3D::Vector3::Axis getSplitAxis() const { return(iSplitAxis); }
71
72        inline void setSplitAxis(G3D::Vector3::Axis a) { iSplitAxis = a; }
73        inline void setSplitLocation(float l) { iSplitLocation = l; }
74
75        inline void setBounds(const G3D::AABox& pBox) { iBounds = pBox; }
76
77        inline void setBounds(const G3D::Vector3& lo, const G3D::Vector3& hi) { iBounds.set(lo,hi); }
78
79        inline void getBounds(G3D::AABox& pBox) const { pBox.set(iBounds.low(),iBounds.high()); }
80
81        inline float getSplitLocation() const { return(iSplitLocation); }
82
83        inline unsigned short getNValues() const { return (iNumberOfValues); }
84
85        inline unsigned int getStartPosition() const { return(iStartPosition); }
86
87        inline bool operator==(const TreeNode& n) const
88        {
89            return ((iSplitLocation == n.iSplitLocation) &&
90                (iChilds[0] == n.iChilds[0]) && (iChilds[1] == n.iChilds[1]) &&
91                (iStartPosition == n.iStartPosition) &&
92                (iSplitAxis == n.iSplitAxis) &&
93                (iBounds == n.iBounds) &&
94                (iNumberOfValues == n.iNumberOfValues));
95        }
96
97        inline bool operator!=(const TreeNode& n) const
98        {
99            return !((iSplitLocation == n.iSplitLocation) &&
100                (iChilds[0] == n.iChilds[0]) && (iChilds[1] == n.iChilds[1]) &&
101                (iStartPosition == n.iStartPosition) &&
102                (iSplitAxis == n.iSplitAxis) &&
103                (iBounds == n.iBounds) &&
104                (iNumberOfValues == n.iNumberOfValues));
105        }
106
107        /** Returns true if the ray intersects this node */
108        bool intersects(const G3D::Ray& ray, float distance) const {
109            // See if the ray will ever hit this node or its children
110            G3D::Vector3 location;
111            bool alreadyInsideBounds = false;
112            bool rayWillHitBounds = 
113                MyCollisionDetection::collisionLocationForMovingPointFixedAABox(
114                ray.origin, ray.direction, iBounds, location, alreadyInsideBounds);
115
116            bool canHitThisNode = (alreadyInsideBounds ||               
117                (rayWillHitBounds && ((location - ray.origin).squaredLength() < (distance*distance))));
118
119            return canHitThisNode;
120        }
121
122        template<typename RayCallback, typename TNode, typename TValue>
123        void intersectRay(
124            const G3D::Ray& ray, 
125            RayCallback& intersectCallback, 
126            float& distance,
127            const NodeValueAccess<TNode, TValue>& pNodeValueAccess,
128            bool pStopAtFirstHit,
129            bool intersectCallbackIsFast) const {
130                float enterDistance = distance;
131                if (! intersects(ray, distance)) {
132                    // The ray doesn't hit this node, so it can't hit the children of the node.
133                    return;
134                }
135
136                // Test for intersection against every object at this node.
137                for (unsigned int v = iStartPosition; v < (iNumberOfValues+iStartPosition); ++v) {       
138                    const TValue& nodeValue = pNodeValueAccess.getValue(v);
139                    bool canHitThisObject = true;
140                    if (! intersectCallbackIsFast) {
141                        // See if
142                        G3D::Vector3 location;
143                        const G3D::AABox& bounds = nodeValue.getAABoxBounds();
144                        bool alreadyInsideBounds = false;
145                        bool rayWillHitBounds = 
146                            MyCollisionDetection::collisionLocationForMovingPointFixedAABox(
147                            ray.origin, ray.direction, bounds, location, alreadyInsideBounds);
148
149                        canHitThisObject = (alreadyInsideBounds ||               
150                            (rayWillHitBounds && ((location - ray.origin).squaredLength() < (distance*distance))));
151                    }
152
153                    if (canHitThisObject) {
154                        // It is possible that this ray hits this object.  Look for the intersection using the
155                        // callback.
156                        intersectCallback(ray, &nodeValue, pStopAtFirstHit, distance);
157                    }
158                    if(pStopAtFirstHit && distance < enterDistance)
159                        return;
160                }
161
162                // There are three cases to consider next:
163                //
164                //  1. the ray can start on one side of the splitting plane and never enter the other,
165                //  2. the ray can start on one side and enter the other, and
166                //  3. the ray can travel exactly down the splitting plane
167
168                enum {NONE = -1};
169                int firstChild = NONE;
170                int secondChild = NONE;
171
172                if (ray.origin[iSplitAxis] < iSplitLocation) {
173
174                    // The ray starts on the small side
175                    firstChild = 0;
176
177                    if (ray.direction[iSplitAxis] > 0) {
178                        // The ray will eventually reach the other side
179                        secondChild = 1;
180                    }
181
182                } else if (ray.origin[iSplitAxis] > iSplitLocation) {
183
184                    // The ray starts on the large side
185                    firstChild = 1;
186
187                    if (ray.direction[iSplitAxis] < 0) {
188                        secondChild = 0;
189                    }
190                } else {
191                    // The ray starts on the splitting plane
192                    if (ray.direction[iSplitAxis] < 0) {
193                        // ...and goes to the small side
194                        firstChild = 0;
195                    } else if (ray.direction[iSplitAxis] > 0) {
196                        // ...and goes to the large side
197                        firstChild = 1;
198                    }
199                }
200
201                // Test on the side closer to the ray origin.
202                if ((firstChild != NONE) && iChilds[firstChild]>0) {
203                    getChild(pNodeValueAccess.getNodePtr() , firstChild)->intersectRay(ray, intersectCallback, distance, pNodeValueAccess, pStopAtFirstHit,intersectCallbackIsFast);
204                    if(pStopAtFirstHit && distance < enterDistance)
205                        return;
206                }
207                if (ray.direction[iSplitAxis] != 0) {
208                    // See if there was an intersection before hitting the splitting plane. 
209                    // If so, there is no need to look on the far side and recursion terminates.
210                    float distanceToSplittingPlane = (iSplitLocation - ray.origin[iSplitAxis]) / ray.direction[iSplitAxis];
211                    if (distanceToSplittingPlane > distance) {
212                        // We aren't going to hit anything else before hitting the splitting plane,
213                        // so don't bother looking on the far side of the splitting plane at the other
214                        // child.
215                        return;
216                    }
217                }
218                // Test on the side farther from the ray origin.
219                if ((secondChild != NONE) && iChilds[secondChild]>0) {
220                    getChild(pNodeValueAccess.getNodePtr() , secondChild)->intersectRay(ray, intersectCallback, distance, pNodeValueAccess, pStopAtFirstHit,intersectCallbackIsFast);
221                }
222        }
223    };
224}
225#endif
Note: See TracBrowser for help on using the browser.