2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4 (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org/
7 Copyright (c) 2000-2006 Torus Knot Software Ltd
8 Copyright (c) 2006 Matthias Fink, netAllied GmbH <matthias.fink@web.de>
9 Also see acknowledgements in Readme.html
11 This program is free software; you can redistribute it and/or modify it under
12 the terms of the GNU Lesser General Public License as published by the Free Software
13 Foundation; either version 2 of the License, or (at your option) any later
16 This program is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public License along with
21 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
23 http://www.gnu.org/copyleft/lesser.txt.
25 You may alternatively use this source under the terms of a specific version of
26 the OGRE Unrestricted License provided you have obtained such a license from
27 Torus Knot Software Ltd.
28 -----------------------------------------------------------------------------
30 #include "OgreStableHeaders.h"
31 #include "OgreConvexBody.h"
32 #include "OgreException.h"
33 #include "OgreVector3.h"
34 #include <OgreLogManager.h>
36 #include <OgreFrustum.h>
37 #include <OgreAxisAlignedBox.h>
44 //-----------------------------------------------------------------------
46 //-----------------------------------------------------------------------
47 ConvexBody::PolygonList
ConvexBody::msFreePolygons
;
48 #if OGRE_THREAD_SUPPORT
49 boost::recursive_mutex
ConvexBody::msFreePolygonsMutex
;
51 //-----------------------------------------------------------------------
52 void ConvexBody::_initialisePool()
54 OGRE_LOCK_MUTEX(msFreePolygonsMutex
)
56 if (msFreePolygons
.empty())
58 const size_t initialSize
= 30;
60 // Initialise polygon pool with 30 polys
61 msFreePolygons
.resize(initialSize
);
62 for (size_t i
= 0; i
< initialSize
; ++i
)
64 msFreePolygons
[i
] = OGRE_NEW_T(Polygon
, MEMCATEGORY_SCENE_CONTROL
)();
68 //-----------------------------------------------------------------------
69 void ConvexBody::_destroyPool()
71 OGRE_LOCK_MUTEX(msFreePolygonsMutex
)
73 for (PolygonList::iterator i
= msFreePolygons
.begin();
74 i
!= msFreePolygons
.end(); ++i
)
76 OGRE_DELETE_T(*i
, Polygon
, MEMCATEGORY_SCENE_CONTROL
);
78 msFreePolygons
.clear();
80 //-----------------------------------------------------------------------
81 Polygon
* ConvexBody::allocatePolygon()
83 OGRE_LOCK_MUTEX(msFreePolygonsMutex
)
85 if (msFreePolygons
.empty())
87 // if we ran out of polys to use, create a new one
88 // hopefully this one will return to the pool in due course
89 return OGRE_NEW_T(Polygon
, MEMCATEGORY_SCENE_CONTROL
)();
93 Polygon
* ret
= msFreePolygons
.back();
96 msFreePolygons
.pop_back();
102 //-----------------------------------------------------------------------
103 void ConvexBody::freePolygon(Polygon
* poly
)
105 OGRE_LOCK_MUTEX(msFreePolygonsMutex
)
106 msFreePolygons
.push_back(poly
);
108 //-----------------------------------------------------------------------
109 //-----------------------------------------------------------------------
110 ConvexBody::ConvexBody()
112 // Reserve space for 8 polys, normally 6 faces plus a couple of clips
113 mPolygons
.reserve(8);
116 //-----------------------------------------------------------------------
117 ConvexBody::~ConvexBody()
121 //-----------------------------------------------------------------------
122 ConvexBody::ConvexBody( const ConvexBody
& cpy
)
124 for ( size_t i
= 0; i
< cpy
.getPolygonCount(); ++i
)
126 Polygon
*p
= allocatePolygon();
127 *p
= cpy
.getPolygon( i
);
128 mPolygons
.push_back( p
);
131 //-----------------------------------------------------------------------
132 void ConvexBody::define(const Frustum
& frustum
)
134 // ordering of the points:
135 // near (0-3), far (4-7); each (top-right, top-left, bottom-left, bottom-right)
145 const Vector3
*pts
= frustum
.getWorldSpaceCorners();
150 /// update vertices: near, far, left, right, bottom, top; fill in ccw
154 poly
= allocatePolygon();
155 poly
->insertVertex( pts
[0] );
156 poly
->insertVertex( pts
[1] );
157 poly
->insertVertex( pts
[2] );
158 poly
->insertVertex( pts
[3] );
159 mPolygons
.push_back( poly
);
162 poly
= allocatePolygon();
163 poly
->insertVertex( pts
[5] );
164 poly
->insertVertex( pts
[4] );
165 poly
->insertVertex( pts
[7] );
166 poly
->insertVertex( pts
[6] );
167 mPolygons
.push_back( poly
);
170 poly
= allocatePolygon();
171 poly
->insertVertex( pts
[5] );
172 poly
->insertVertex( pts
[6] );
173 poly
->insertVertex( pts
[2] );
174 poly
->insertVertex( pts
[1] );
175 mPolygons
.push_back( poly
);
178 poly
= allocatePolygon();
179 poly
->insertVertex( pts
[4] );
180 poly
->insertVertex( pts
[0] );
181 poly
->insertVertex( pts
[3] );
182 poly
->insertVertex( pts
[7] );
183 mPolygons
.push_back( poly
);
186 poly
= allocatePolygon();
187 poly
->insertVertex( pts
[6] );
188 poly
->insertVertex( pts
[7] );
189 poly
->insertVertex( pts
[3] );
190 poly
->insertVertex( pts
[2] );
191 mPolygons
.push_back( poly
);
194 poly
= allocatePolygon();
195 poly
->insertVertex( pts
[4] );
196 poly
->insertVertex( pts
[5] );
197 poly
->insertVertex( pts
[1] );
198 poly
->insertVertex( pts
[0] );
199 mPolygons
.push_back( poly
);
201 //-----------------------------------------------------------------------
202 void ConvexBody::define(const AxisAlignedBox
& aab
)
204 // ordering of the AAB points:
214 const Vector3
& min
= aab
.getMinimum();
215 const Vector3
& max
= aab
.getMaximum();
217 Vector3 currentVertex
= min
;
225 poly
= allocatePolygon();
226 poly
->insertVertex( currentVertex
); // 0
227 currentVertex
.y
= max
.y
;
228 poly
->insertVertex( currentVertex
); // 1
229 currentVertex
.x
= max
.x
;
230 poly
->insertVertex( currentVertex
); // 2
231 currentVertex
.y
= min
.y
;
232 poly
->insertVertex( currentVertex
); // 3
233 insertPolygon( poly
);
236 poly
= allocatePolygon();
237 poly
->insertVertex( currentVertex
); // 3
238 currentVertex
.y
= max
.y
;
239 poly
->insertVertex( currentVertex
); // 2
240 currentVertex
.z
= max
.z
;
241 poly
->insertVertex( currentVertex
); // 4
242 currentVertex
.y
= min
.y
;
243 poly
->insertVertex( currentVertex
); // 7
244 insertPolygon( poly
);
247 poly
= allocatePolygon();
248 poly
->insertVertex( currentVertex
); // 7
249 currentVertex
.y
= max
.y
;
250 poly
->insertVertex( currentVertex
); // 4
251 currentVertex
.x
= min
.x
;
252 poly
->insertVertex( currentVertex
); // 5
253 currentVertex
.y
= min
.y
;
254 poly
->insertVertex( currentVertex
); // 6
255 insertPolygon( poly
);
258 poly
= allocatePolygon();
259 poly
->insertVertex( currentVertex
); // 6
260 currentVertex
.y
= max
.y
;
261 poly
->insertVertex( currentVertex
); // 5
262 currentVertex
.z
= min
.z
;
263 poly
->insertVertex( currentVertex
); // 1
264 currentVertex
.y
= min
.y
;
265 poly
->insertVertex( currentVertex
); // 0
266 insertPolygon( poly
);
269 poly
= allocatePolygon();
270 poly
->insertVertex( currentVertex
); // 0
271 currentVertex
.x
= max
.x
;
272 poly
->insertVertex( currentVertex
); // 3
273 currentVertex
.z
= max
.z
;
274 poly
->insertVertex( currentVertex
); // 7
275 currentVertex
.x
= min
.x
;
276 poly
->insertVertex( currentVertex
); // 6
277 insertPolygon( poly
);
280 poly
= allocatePolygon();
282 poly
->insertVertex( currentVertex
); // 4
283 currentVertex
.z
= min
.z
;
284 poly
->insertVertex( currentVertex
); // 2
285 currentVertex
.x
= min
.x
;
286 poly
->insertVertex( currentVertex
); // 1
287 currentVertex
.z
= max
.z
;
288 poly
->insertVertex( currentVertex
); // 5
289 insertPolygon( poly
);
292 //-----------------------------------------------------------------------
293 void ConvexBody::clip(const AxisAlignedBox
& aab
)
295 // ordering of the AAB points:
305 const Vector3
& min
= aab
.getMinimum();
306 const Vector3
& max
= aab
.getMaximum();
308 // clip object for each plane of the AAB
313 p
.redefine(Vector3::UNIT_Z
, max
);
317 p
.redefine(Vector3::NEGATIVE_UNIT_Z
, min
);
321 p
.redefine(Vector3::NEGATIVE_UNIT_X
, min
);
325 p
.redefine(Vector3::UNIT_X
, max
);
329 p
.redefine(Vector3::NEGATIVE_UNIT_Y
, min
);
333 p
.redefine(Vector3::UNIT_Y
, max
);
337 //-----------------------------------------------------------------------
338 void ConvexBody::clip(const Frustum
& fr
)
340 // clip the body with each plane
341 for ( unsigned short i
= 0; i
< 6; ++i
)
343 // clip, but keep positive space this time since frustum planes are
344 // the opposite to other cases (facing inwards rather than outwards)
345 clip(fr
.getFrustumPlane(i
), false);
348 //-----------------------------------------------------------------------
349 void ConvexBody::clip(const ConvexBody
& body
)
354 // for each polygon; clip 'this' with each plane of 'body'
355 // front vertex representation is ccw
359 for ( size_t iPoly
= 0; iPoly
< body
.getPolygonCount(); ++iPoly
)
361 const Polygon
& p
= body
.getPolygon( iPoly
);
363 OgreAssert( p
.getVertexCount() >= 3, "A valid polygon must contain at least three vertices." );
365 // set up plane with first three vertices of the polygon (a polygon is always planar)
366 pl
.redefine( p
.getVertex( 0 ), p
.getVertex( 1 ), p
.getVertex( 2 ) );
371 //-----------------------------------------------------------------------
372 void ConvexBody::extend(const Vector3
& pt
)
374 // Erase all polygons facing towards the point. For all edges that
375 // are not removed twice (once in AB and once BA direction) build a
376 // convex polygon (triangle) with the point.
377 Polygon::EdgeMap edgeMap
;
379 for ( size_t i
= 0; i
< getPolygonCount(); ++i
)
381 const Vector3
& normal
= getNormal( i
);
382 // direction of the point in regard to the polygon
383 // the polygon is planar so we can take an arbitrary vertex
384 Vector3 ptDir
= pt
- getVertex( i
, 0 );
387 // remove polygon if dot product is greater or equals null.
388 if ( normal
.dotProduct( ptDir
) >= 0 )
390 // store edges (copy them because if the polygon is deleted
391 // its vertices are also deleted)
392 storeEdgesOfPolygon( i
, &edgeMap
);
397 // decrement iterator because of deleted polygon
402 // point is already a part of the hull (point lies inside)
403 if ( edgeMap
.empty() )
406 // remove the edges that are twice in the list (once from each side: AB,BA)
408 Polygon::EdgeMap::iterator it
;
409 // iterate from first to the element before the last one
410 for (Polygon::EdgeMap::iterator itStart
= edgeMap
.begin();
411 itStart
!= edgeMap
.end(); )
413 // compare with iterator + 1 to end
414 // don't need to skip last entry in itStart since omitted in inner loop
419 // iterate from itStart+1 to the element before the last one
420 for ( ; it
!= edgeMap
.end(); ++it
)
422 if (itStart
->first
.positionEquals(it
->second
) &&
423 itStart
->second
.positionEquals(it
->first
))
426 // increment itStart before deletion (iterator invalidation)
427 Polygon::EdgeMap::iterator delistart
= itStart
++;
428 edgeMap
.erase(delistart
);
431 break; // found and erased
434 // increment itStart if we didn't do it when erasing
440 // use the remaining edges to build triangles with the point
441 // the vertices of the edges are in ccw order (edgePtA-edgePtB-point
442 // to form a ccw polygon)
443 while ( !edgeMap
.empty() )
445 Polygon::EdgeMap::iterator it
= edgeMap
.begin();
447 // build polygon it.first, it.second, point
448 Polygon
*p
= allocatePolygon();
450 p
->insertVertex(it
->first
);
451 p
->insertVertex(it
->second
);
453 p
->insertVertex( pt
);
454 // attach polygon to body
457 // erase the vertices from the list
458 // pointers are now held by the polygon
462 //-----------------------------------------------------------------------
463 void ConvexBody::reset( void )
465 for (PolygonList::iterator it
= mPolygons
.begin();
466 it
!= mPolygons
.end(); ++it
)
472 //-----------------------------------------------------------------------
473 size_t ConvexBody::getPolygonCount( void ) const
475 return mPolygons
.size();
477 //-----------------------------------------------------------------------
478 size_t ConvexBody::getVertexCount( size_t poly
) const
480 OgreAssert(poly
< getPolygonCount(), "Search position out of range" );
482 return mPolygons
[ poly
]->getVertexCount();
484 //-----------------------------------------------------------------------
485 bool ConvexBody::hasClosedHull( void ) const
487 // if this map is returned empty, the body is closed
488 Polygon::EdgeMap edgeMap
= getSingleEdges();
490 return edgeMap
.empty();
492 //-----------------------------------------------------------------------
493 void ConvexBody::mergePolygons( void )
495 // Merge all polygons that lay in the same plane as one big polygon.
496 // A convex body does not have two seperate regions (seperated by polygons
497 // with different normals) where the same normal occurs, so we can simply
498 // search all similar normals of a polygon. Two different options are
499 // possible when the normals fit:
500 // - the two polygons are neighbors
501 // - the two polygons aren't neighbors (but a third, fourth,.. polygon lays
504 // Signals if the body holds polygons which aren't neighbors but have the same
505 // normal. That means another step has to be processed.
508 for ( size_t iPolyA
= 0; iPolyA
< getPolygonCount(); ++iPolyA
)
511 OgreAssert( iPolyA
>= 0, "strange..." );
513 for ( size_t iPolyB
= iPolyA
+1; iPolyB
< getPolygonCount(); ++iPolyB
)
515 const Vector3
& n1
= getNormal( iPolyA
);
516 const Vector3
& n2
= getNormal( iPolyB
);
518 // if the normals point into the same direction
519 if ( n1
.directionEquals( n2
, Radian( Degree( 0.00001 ) ) ) )
521 // indicates if a neighbor has been found and joined
524 // search the two fitting vertices (if there are any) for the common edge
525 const size_t numVerticesA
= getVertexCount( iPolyA
);
526 for ( size_t iVertexA
= 0; iVertexA
< numVerticesA
; ++iVertexA
)
528 const size_t numVerticesB
= getVertexCount( iPolyB
);
529 for ( size_t iVertexB
= 0; iVertexB
< numVerticesB
; ++iVertexB
)
531 const Vector3
& aCurrent
= getVertex( iPolyA
, iVertexA
);
532 const Vector3
& aNext
= getVertex( iPolyA
, (iVertexA
+ 1) % getVertexCount( iPolyA
) );
533 const Vector3
& bCurrent
= getVertex( iPolyB
, iVertexB
);
534 const Vector3
& bNext
= getVertex( iPolyB
, (iVertexB
+ 1) % getVertexCount( iPolyB
) );
536 // if the edge is the same the current vertex of A has to be equal to the next of B and the other
538 if ( aCurrent
.positionEquals(bNext
) &&
539 bCurrent
.positionEquals(aNext
))
541 // polygons are neighbors, assemble new one
542 Polygon
*pNew
= allocatePolygon();
544 // insert all vertices of A up to the join (including the common vertex, ignoring
545 // whether the first vertex of A may be a shared vertex)
546 for ( size_t i
= 0; i
<= iVertexA
; ++i
)
548 pNew
->insertVertex( getVertex( iPolyA
, i
%numVerticesA
) );
551 // insert all vertices of B _after_ the join to the end
552 for ( size_t i
= iVertexB
+ 2; i
< numVerticesB
; ++i
)
554 pNew
->insertVertex( getVertex( iPolyB
, i
) );
557 // insert all vertices of B from the beginning up to the join (including the common vertex
558 // and excluding the first vertex if the first is part of the shared edge)
559 for ( size_t i
= 0; i
<= iVertexB
; ++i
)
561 pNew
->insertVertex( getVertex( iPolyB
, i
%numVerticesB
) );
564 // insert all vertices of A _after_ the join to the end
565 for ( size_t i
= iVertexA
+ 2; i
< numVerticesA
; ++i
)
567 pNew
->insertVertex( getVertex( iPolyA
, i
) );
570 // in case there are double vertices (in special cases), remove them
571 for ( size_t i
= 0; i
< pNew
->getVertexCount(); ++i
)
573 const Vector3
& a
= pNew
->getVertex( i
);
574 const Vector3
& b
= pNew
->getVertex( (i
+ 1) % pNew
->getVertexCount() );
576 // if the two vertices are the same...
577 if (a
.positionEquals(b
))
580 pNew
->deleteVertex( i
);
587 // delete the two old ones
588 OgreAssert( iPolyA
!= iPolyB
, "PolyA and polyB are the same!" );
590 // polyB is always higher than polyA, so delete polyB first
591 deletePolygon( iPolyB
);
592 deletePolygon( iPolyA
);
594 // continue with next (current is deleted, so don't jump to the next after the next)
598 // insert new polygon
599 insertPolygon( pNew
);
612 if ( bFound
== false )
614 // there are two polygons available with the same normal direction, but they
615 // could not be merged into one single because of no shared edge
623 // recursion to merge the previous non-neighbors
629 //-----------------------------------------------------------------------
630 const Vector3
& ConvexBody::getNormal( size_t poly
)
632 OgreAssert( poly
>= 0 && poly
< getPolygonCount(), "Search position out of range" );
634 return mPolygons
[ poly
]->getNormal();
636 //-----------------------------------------------------------------------
637 AxisAlignedBox
ConvexBody::getAABB( void ) const
641 for ( size_t i
= 0; i
< getPolygonCount(); ++i
)
643 for ( size_t j
= 0; j
< getVertexCount( i
); ++j
)
645 aab
.merge( getVertex( i
, j
) );
651 //-----------------------------------------------------------------------
652 bool ConvexBody::operator == ( const ConvexBody
& rhs
) const
654 if ( getPolygonCount() != rhs
.getPolygonCount() )
657 // Compare the polygons. They may not be in correct order.
658 // A correct convex body does not have identical polygons in its body.
659 bool *bChecked
= OGRE_ALLOC_T(bool, getPolygonCount(), MEMCATEGORY_SCENE_CONTROL
);
660 for ( size_t i
=0; i
<getPolygonCount(); ++i
)
662 bChecked
[ i
] = false;
665 for ( size_t i
=0; i
<getPolygonCount(); ++i
)
669 for ( size_t j
=0; j
<getPolygonCount(); ++j
)
671 const Polygon
& pA
= getPolygon( i
);
672 const Polygon
& pB
= rhs
.getPolygon( j
);
677 bChecked
[ i
] = true;
682 if ( bFound
== false )
684 OGRE_FREE(bChecked
, MEMCATEGORY_SCENE_CONTROL
);
690 for ( size_t i
=0; i
<getPolygonCount(); ++i
)
692 if ( bChecked
[ i
] != true )
694 OGRE_FREE(bChecked
, MEMCATEGORY_SCENE_CONTROL
);
700 OGRE_FREE(bChecked
, MEMCATEGORY_SCENE_CONTROL
);
704 //-----------------------------------------------------------------------
705 std::ostream
& operator<< ( std::ostream
& strm
, const ConvexBody
& body
)
707 strm
<< "POLYGON INFO (" << body
.getPolygonCount() << ")" << std::endl
;
709 for ( size_t i
= 0; i
< body
.getPolygonCount(); ++i
)
711 strm
<< "POLYGON " << i
<< ", ";
712 strm
<< body
.getPolygon( i
);
717 //-----------------------------------------------------------------------
718 void ConvexBody::insertPolygon(Polygon
* pdata
, size_t poly
)
720 OgreAssert(poly
<= getPolygonCount(), "Insert position out of range" );
721 OgreAssert( pdata
!= NULL
, "Polygon is NULL" );
723 PolygonList::iterator it
= mPolygons
.begin();
724 std::advance(it
, poly
);
726 mPolygons
.insert( it
, pdata
);
729 //-----------------------------------------------------------------------
730 void ConvexBody::insertPolygon(Polygon
* pdata
)
732 OgreAssert( pdata
!= NULL
, "Polygon is NULL" );
734 mPolygons
.push_back( pdata
);
737 //-----------------------------------------------------------------------
738 void ConvexBody::insertVertex(size_t poly
, const Vector3
& vdata
, size_t vertex
)
740 OgreAssert(poly
< getPolygonCount(), "Search position (polygon) out of range" );
742 mPolygons
[poly
]->insertVertex(vdata
, vertex
);
744 //-----------------------------------------------------------------------
745 void ConvexBody::insertVertex(size_t poly
, const Vector3
& vdata
)
747 OgreAssert(poly
< getPolygonCount(), "Search position (polygon) out of range" );
749 mPolygons
[poly
]->insertVertex(vdata
);
751 //-----------------------------------------------------------------------
752 void ConvexBody::deletePolygon(size_t poly
)
754 OgreAssert(poly
< getPolygonCount(), "Search position out of range" );
756 PolygonList::iterator it
= mPolygons
.begin();
757 std::advance(it
, poly
);
762 //-----------------------------------------------------------------------
763 Polygon
* ConvexBody::unlinkPolygon(size_t poly
)
765 OgreAssert( poly
>= 0 && poly
< getPolygonCount(), "Search position out of range" );
767 PolygonList::iterator it
= mPolygons
.begin();
768 std::advance(it
, poly
);
776 // return polygon pointer
780 //-----------------------------------------------------------------------
781 void ConvexBody::moveDataFromBody(ConvexBody
& body
)
783 body
.mPolygons
.swap(this->mPolygons
);
785 //-----------------------------------------------------------------------
786 void ConvexBody::deleteVertex(size_t poly
, size_t vertex
)
788 OgreAssert(poly
< getPolygonCount(), "Search position out of range" );
790 mPolygons
[poly
]->deleteVertex(vertex
);
792 //-----------------------------------------------------------------------
793 const Polygon
& ConvexBody::getPolygon(size_t poly
) const
795 OgreAssert(poly
< getPolygonCount(), "Search position out of range");
797 return *mPolygons
[poly
];
799 //-----------------------------------------------------------------------
800 void ConvexBody::setPolygon(Polygon
* pdata
, size_t poly
)
802 OgreAssert(poly
< getPolygonCount(), "Search position out of range" );
803 OgreAssert(pdata
!= NULL
, "Polygon is NULL" );
805 if (pdata
!= mPolygons
[poly
])
807 // delete old polygon
808 freePolygon(mPolygons
[ poly
]);
811 mPolygons
[poly
] = pdata
;
814 //-----------------------------------------------------------------------
815 const Vector3
& ConvexBody::getVertex(size_t poly
, size_t vertex
) const
817 OgreAssert( poly
>= 0 && poly
< getPolygonCount(), "Search position out of range" );
819 return mPolygons
[poly
]->getVertex(vertex
);
821 //-----------------------------------------------------------------------
822 void ConvexBody::setVertex(size_t poly
, const Vector3
& vdata
, size_t vertex
)
824 OgreAssert(poly
< getPolygonCount(), "Search position out of range");
826 mPolygons
[poly
]->setVertex(vdata
, vertex
);
828 //-----------------------------------------------------------------------
829 void ConvexBody::storeEdgesOfPolygon(size_t poly
, Polygon::EdgeMap
*edgeMap
) const
831 OgreAssert(poly
<= getPolygonCount(), "Search position out of range" );
832 OgreAssert( edgeMap
!= NULL
, "TEdgeMap ptr is NULL" );
834 mPolygons
[poly
]->storeEdges(edgeMap
);
836 //-----------------------------------------------------------------------
837 Polygon::EdgeMap
ConvexBody::getSingleEdges() const
839 Polygon::EdgeMap edgeMap
;
841 // put all edges of all polygons into a list every edge has to be
842 // walked in each direction once
843 for ( size_t i
= 0; i
< getPolygonCount(); ++i
)
845 const Polygon
& p
= getPolygon( i
);
847 for ( size_t j
= 0; j
< p
.getVertexCount(); ++j
)
849 const Vector3
& a
= p
.getVertex( j
);
850 const Vector3
& b
= p
.getVertex( ( j
+ 1 ) % p
.getVertexCount() );
852 edgeMap
.insert( Polygon::Edge( a
, b
) );
856 // search corresponding parts
857 Polygon::EdgeMap::iterator it
;
858 Polygon::EdgeMap::iterator itStart
;
859 Polygon::EdgeMap::const_iterator itEnd
;
860 while( !edgeMap
.empty() )
862 it
= edgeMap
.begin(); ++it
; // start one element after itStart
863 itStart
= edgeMap
.begin(); // the element to be compared with the others
864 itEnd
= edgeMap
.end(); // beyond the last element
868 for ( ; it
!= itEnd
; ++it
)
870 if (itStart
->first
.positionEquals(it
->second
) &&
871 itStart
->second
.positionEquals(it
->first
))
873 // erase itStart and it
875 edgeMap
.erase( itStart
);
883 if ( bFound
== false )
885 break; // not all edges could be matched
886 // body is not closed
892 //-----------------------------------------------------------------------
893 void ConvexBody::allocateSpace( size_t numPolygons
, size_t numVertices
)
897 // allocate numPolygons polygons with each numVertices vertices
898 for ( size_t iPoly
= 0; iPoly
< numPolygons
; ++iPoly
)
900 Polygon
*poly
= allocatePolygon();
902 for ( size_t iVertex
= 0; iVertex
< numVertices
; ++iVertex
)
904 poly
->insertVertex( Vector3::ZERO
);
907 mPolygons
.push_back( poly
);
910 //-----------------------------------------------------------------------
911 void ConvexBody::clip( const Plane
& pl
, bool keepNegative
)
913 if ( getPolygonCount() == 0 )
916 // current will be used as the reference body
918 current
.moveDataFromBody(*this);
920 OgreAssert( this->getPolygonCount() == 0, "Body not empty!" );
921 OgreAssert( current
.getPolygonCount() != 0, "Body empty!" );
923 // holds all intersection edges for the different polygons
924 Polygon::EdgeMap intersectionEdges
;
926 // clip all polygons by the intersection plane
927 // add only valid or intersected polygons to *this
928 for ( size_t iPoly
= 0; iPoly
< current
.getPolygonCount(); ++iPoly
)
931 // fetch vertex count and ignore polygons with less than three vertices
932 // the polygon is not valid and won't be added
933 const size_t vertexCount
= current
.getVertexCount( iPoly
);
934 if ( vertexCount
< 3 )
938 const Polygon
& p
= current
.getPolygon( iPoly
);
940 // the polygon to assemble
941 Polygon
*pNew
= allocatePolygon();
943 // the intersection polygon (indeed it's an edge or it's empty)
944 Polygon
*pIntersect
= allocatePolygon();
946 // check if polygons lie inside or outside (or on the plane)
947 // for each vertex check where it is situated in regard to the plane
948 // three possibilities appear:
949 Plane::Side clipSide
= keepNegative
? Plane::POSITIVE_SIDE
: Plane::NEGATIVE_SIDE
;
950 // - side is clipSide: vertex will be clipped
951 // - side is !clipSide: vertex will be untouched
952 // - side is NOSIDE: vertex will be untouched
953 Plane::Side
*side
= OGRE_ALLOC_T(Plane::Side
, vertexCount
, MEMCATEGORY_SCENE_CONTROL
);
954 for ( size_t iVertex
= 0; iVertex
< vertexCount
; ++iVertex
)
956 side
[ iVertex
] = pl
.getSide( p
.getVertex( iVertex
) );
959 // now we check the side combinations for the current and the next vertex
960 // four different combinations exist:
961 // - both points inside (or on the plane): keep the second (add it to the body)
962 // - both points outside: discard both (don't add them to the body)
963 // - first vertex is inside, second is outside: add the intersection point
964 // - first vertex is outside, second is inside: add the intersection point, then the second
965 for ( size_t iVertex
= 0; iVertex
< vertexCount
; ++iVertex
)
967 // determine the next vertex
968 size_t iNextVertex
= ( iVertex
+ 1 ) % vertexCount
;
970 const Vector3
& vCurrent
= p
.getVertex( iVertex
);
971 const Vector3
& vNext
= p
.getVertex( iNextVertex
);
973 // case 1: both points inside (store next)
974 if ( side
[ iVertex
] != clipSide
&& // NEGATIVE or NONE
975 side
[ iNextVertex
] != clipSide
) // NEGATIVE or NONE
978 pNew
->insertVertex( vNext
);
981 // case 3: inside -> outside (store intersection)
982 else if ( side
[ iVertex
] != clipSide
&&
983 side
[ iNextVertex
] == clipSide
)
985 // Do an intersection with the plane. We use a ray with a start point and a direction.
986 // The ray is forced to hit the plane with any option available (eigher current or next
987 // is the starting point)
989 // intersect from the outside vertex towards the inside one
990 Vector3 vDirection
= vCurrent
- vNext
;
991 vDirection
.normalise();
992 Ray
ray( vNext
, vDirection
);
993 std::pair
< bool, Real
> intersect
= ray
.intersects( pl
);
995 // store intersection
996 if ( intersect
.first
)
998 // convert distance to vector
999 Vector3 vIntersect
= ray
.getPoint( intersect
.second
);
1001 // store intersection
1002 pNew
->insertVertex( vIntersect
);
1003 pIntersect
->insertVertex( vIntersect
);
1007 // case 4: outside -> inside (store intersection, store next)
1008 else if ( side
[ iVertex
] == clipSide
&&
1009 side
[ iNextVertex
] != clipSide
)
1011 // Do an intersection with the plane. We use a ray with a start point and a direction.
1012 // The ray is forced to hit the plane with any option available (eigher current or next
1013 // is the starting point)
1015 // intersect from the outside vertex towards the inside one
1016 Vector3 vDirection
= vNext
- vCurrent
;
1017 vDirection
.normalise();
1018 Ray
ray( vCurrent
, vDirection
);
1019 std::pair
< bool, Real
> intersect
= ray
.intersects( pl
);
1021 // store intersection
1022 if ( intersect
.first
)
1024 // convert distance to vector
1025 Vector3 vIntersect
= ray
.getPoint( intersect
.second
);
1027 // store intersection
1028 pNew
->insertVertex( vIntersect
);
1029 pIntersect
->insertVertex( vIntersect
);
1032 pNew
->insertVertex( vNext
);
1036 // case 2: both outside (do nothing)
1040 // insert the polygon only, if at least three vertices are present
1041 if ( pNew
->getVertexCount() >= 3 )
1043 // in case there are double vertices, remove them
1044 pNew
->removeDuplicates();
1046 // in case there are still at least three vertices, insert the polygon
1047 if ( pNew
->getVertexCount() >= 3 )
1049 this->insertPolygon( pNew
);
1053 // delete pNew because it's empty or invalid
1060 // delete pNew because it's empty or invalid
1065 // insert intersection polygon only, if there are two vertices present
1066 if ( pIntersect
->getVertexCount() == 2 )
1068 intersectionEdges
.insert( Polygon::Edge( pIntersect
->getVertex( 0 ),
1069 pIntersect
->getVertex( 1 ) ) );
1072 // delete intersection polygon
1073 // vertices were copied (if there were any)
1074 freePolygon(pIntersect
);
1078 OGRE_FREE(side
, MEMCATEGORY_SCENE_CONTROL
);
1082 // if the polygon was partially clipped, close it
1083 // at least three edges are needed for a polygon
1084 if ( intersectionEdges
.size() >= 3 )
1086 Polygon
*pClosing
= allocatePolygon();
1088 // Analyze the intersection list and insert the intersection points in ccw order
1089 // Each point is twice in the list because of the fact that we have a convex body
1090 // with convex polygons. All we have to do is order the edges (an even-odd pair)
1091 // in a ccw order. The plane normal shows us the direction.
1092 Polygon::EdgeMap::iterator it
= intersectionEdges
.begin();
1094 // check the cross product of the first two edges
1095 Vector3 vFirst
= it
->first
;
1096 Vector3 vSecond
= it
->second
;
1098 // remove inserted edge
1099 intersectionEdges
.erase( it
);
1104 if (findAndEraseEdgePair(vSecond
, intersectionEdges
, vNext
))
1106 // detect the orientation
1107 // the polygon must have the same normal direction as the plane and then n
1108 Vector3 vCross
= ( vFirst
- vSecond
).crossProduct( vNext
- vSecond
);
1109 bool frontside
= ( pl
.normal
).directionEquals( vCross
, Degree( 1 ) );
1111 // first inserted vertex
1112 Vector3 firstVertex
;
1113 // currently inserted vertex
1114 Vector3 currentVertex
;
1115 // direction equals -> front side (walk ccw)
1118 // start with next as first vertex, then second, then first and continue with first to walk ccw
1119 pClosing
->insertVertex( vNext
);
1120 pClosing
->insertVertex( vSecond
);
1121 pClosing
->insertVertex( vFirst
);
1122 firstVertex
= vNext
;
1123 currentVertex
= vFirst
;
1125 #ifdef _DEBUG_INTERSECTION_LIST
1126 std::cout
<< "Plane: n=" << pl
.normal
<< ", d=" << pl
.d
<< std::endl
;
1127 std::cout
<< "First inserted vertex: " << *next
<< std::endl
;
1128 std::cout
<< "Second inserted vertex: " << *vSecond
<< std::endl
;
1129 std::cout
<< "Third inserted vertex: " << *vFirst
<< std::endl
;
1132 // direction does not equal -> back side (walk cw)
1135 // start with first as first vertex, then second, then next and continue with next to walk ccw
1136 pClosing
->insertVertex( vFirst
);
1137 pClosing
->insertVertex( vSecond
);
1138 pClosing
->insertVertex( vNext
);
1139 firstVertex
= vFirst
;
1140 currentVertex
= vNext
;
1142 #ifdef _DEBUG_INTERSECTION_LIST
1143 std::cout
<< "Plane: n=" << pl
.normal
<< ", d=" << pl
.d
<< std::endl
;
1144 std::cout
<< "First inserted vertex: " << *vFirst
<< std::endl
;
1145 std::cout
<< "Second inserted vertex: " << *vSecond
<< std::endl
;
1146 std::cout
<< "Third inserted vertex: " << *next
<< std::endl
;
1150 // search mating edges that have a point in common
1151 // continue this operation as long as edges are present
1152 while ( !intersectionEdges
.empty() )
1155 if (findAndEraseEdgePair(currentVertex
, intersectionEdges
, vNext
))
1157 // insert only if it's not the last (which equals the first) vertex
1158 if ( !intersectionEdges
.empty() )
1160 currentVertex
= vNext
;
1161 pClosing
->insertVertex( vNext
);
1170 } // while intersectionEdges not empty
1172 // insert polygon (may be degenerated!)
1173 this->insertPolygon( pClosing
);
1176 // mating intersection edge NOT found!
1179 freePolygon(pClosing
);
1182 } // if intersectionEdges contains more than three elements
1184 //-----------------------------------------------------------------------
1185 bool ConvexBody::findAndEraseEdgePair(const Vector3
& vec
,
1186 Polygon::EdgeMap
& intersectionEdges
, Vector3
& vNext
) const
1188 Polygon::EdgeMap::iterator it
= intersectionEdges
.begin();
1190 for (Polygon::EdgeMap::iterator it
= intersectionEdges
.begin();
1191 it
!= intersectionEdges
.end(); ++it
)
1193 if (it
->first
.positionEquals(vec
))
1198 intersectionEdges
.erase( it
);
1200 return true; // found!
1202 else if (it
->second
.positionEquals(vec
))
1207 intersectionEdges
.erase( it
);
1209 return true; // found!
1213 return false; // not found!
1215 //-----------------------------------------------------------------------
1216 void ConvexBody::logInfo( void ) const
1218 StringUtil::StrStreamType
ssOut( std::stringstream::out
);
1221 Ogre::LogManager::getSingleton().logMessage( Ogre::LML_NORMAL
, ssOut
.str() );