1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "nel/misc/hierarchical_timer.h"
21 #include "nel/pacs/primitive_world_image.h"
22 #include "nel/pacs/move_primitive.h"
23 #include "nel/pacs/move_element.h"
25 using namespace NLMISC
;
31 // ***************************************************************************
33 CPrimitiveWorldImage::CPrimitiveWorldImage()
36 for (uint i
=0; i
<4; i
++)
46 // ***************************************************************************
48 void CPrimitiveWorldImage::deleteIt (CMoveContainer
&container
, uint8 worldImage
)
50 // Free the move elements
51 for (uint i
=0; i
<4; i
++)
53 removeMoveElement (i
, container
, worldImage
);
55 // ***************************************************************************
57 void CPrimitiveWorldImage::copy (const CPrimitiveWorldImage
& source
)
60 this->operator=(source
);
63 _DynamicFlags
&=~InModifiedListFlag
;
65 // Pointer into the 4 possibles sorted lists of movable primitives. Must be NULL
66 for (uint i
=0; i
<4; i
++)
70 // ***************************************************************************
72 bool CPrimitiveWorldImage::evalCollision (CPrimitiveWorldImage
& other
, CCollisionDesc
& desc
, double timeMin
, double timeMax
, uint32 testTime
,
73 uint32 maxTestIteration
, double &firstContactTime
, double &lastContactTime
, CMovePrimitive
& primitive
,
74 CMovePrimitive
& otherPrimitive
)
76 // H_AUTO(PACS_PWI_evalCollision_long);
79 if (( (primitive
.getCollisionMaskInternal() & otherPrimitive
.getOcclusionMaskInternal()) == 0) &&
80 ( (primitive
.getOcclusionMaskInternal() & otherPrimitive
.getCollisionMaskInternal()) == 0))
84 if ( (!primitive
.checkTestTime (testTime
, maxTestIteration
)) || (!otherPrimitive
.checkTestTime (testTime
, maxTestIteration
)) )
87 // Clear time min time max
88 firstContactTime
=FLT_MAX
;
89 lastContactTime
=-FLT_MAX
;
91 // Switch the good test
92 switch (primitive
.getPrimitiveTypeInternal())
96 case UMovePrimitive::_2DOrientedBox
:
99 switch (otherPrimitive
.getPrimitiveTypeInternal())
102 // Static box over movable box
103 case UMovePrimitive::_2DOrientedBox
:
105 return evalCollisionOBoverOB (other
, desc
, timeMin
, timeMax
, firstContactTime
, lastContactTime
, primitive
, otherPrimitive
);
107 // Static box over movable cylinder
108 case UMovePrimitive::_2DOrientedCylinder
:
110 return evalCollisionOBoverOC (other
, desc
, timeMin
, timeMax
, firstContactTime
, lastContactTime
, primitive
, otherPrimitive
);
113 // Should not go here
118 // Static box over...
119 case UMovePrimitive::_2DOrientedCylinder
:
121 // Switch second type
122 switch (otherPrimitive
.getPrimitiveTypeInternal())
125 // Static box over movable box
126 case UMovePrimitive::_2DOrientedBox
:
129 bool collid
=other
.evalCollisionOBoverOC (*this, desc
, timeMin
, timeMax
, firstContactTime
, lastContactTime
, otherPrimitive
,
132 desc
.XChgContactNormals ();
136 // Static box over movable cylinder
137 case UMovePrimitive::_2DOrientedCylinder
:
139 return evalCollisionOCoverOC (other
, desc
, timeMin
, timeMax
, firstContactTime
, lastContactTime
, primitive
, otherPrimitive
);
142 // Should not go here
148 // Should not go here
155 // ***************************************************************************
157 const TCollisionSurfaceDescVector
*CPrimitiveWorldImage::evalCollision (CGlobalRetriever
&retriever
, CCollisionSurfaceTemp
& surfaceTemp
,
158 uint32 testTime
, uint32 maxTestIteration
, CMovePrimitive
& primitive
)
160 // H_AUTO(PACS_PWI_evalCollision_short);
163 if (!primitive
.checkTestTime (testTime
, maxTestIteration
))
166 // Switch the good test
167 if (primitive
.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox
)
170 CVector
locI ((float)(_OBData
.EdgeDirectionX
[0]*primitive
.getLength(0)/2.0), (float)(_OBData
.EdgeDirectionY
[0]*primitive
.getLength(1)/2.0), 0);
173 CVector
locJ ((float)(_OBData
.EdgeDirectionX
[1]*primitive
.getLength(0)/2.0), (float)(_OBData
.EdgeDirectionY
[1]*primitive
.getLength(1)/2.0), 0);
176 return retriever
.testBBoxMove (_Position
.getGlobalPos (), _DeltaPosition
, locI
, locJ
, surfaceTemp
);
181 nlassert (primitive
.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedCylinder
);
184 //nlinfo ("1) %f %f %f\n", _DeltaPosition.x, _DeltaPosition.y, _DeltaPosition.z);
186 return retriever
.testCylinderMove (_Position
.getGlobalPos (), _DeltaPosition
, primitive
.getRadiusInternal(), surfaceTemp
);
190 // ***************************************************************************
192 void CPrimitiveWorldImage::doMove (CGlobalRetriever
&retriever
, CCollisionSurfaceTemp
& surfaceTemp
, double originalMax
, double finalMax
, bool keepZ
/*= false*/)
194 H_AUTO(NLPACS_PWI_Do_Move
);
199 if (finalMax
!=originalMax
)
200 ratio
=(finalMax
-_InitTime
)/(originalMax
-_InitTime
);
207 _Position
.setGlobalPos (retriever
.doMove(_Position
.getGlobalPos(), _DeltaPosition
, (float)ratio
, surfaceTemp
, false), retriever
);
211 _Position
.setGlobalPosKeepZ(retriever
.doMove(_Position
.getGlobalPos(), _DeltaPosition
, (float)ratio
, surfaceTemp
, false), retriever
);
219 // ***************************************************************************
221 void CPrimitiveWorldImage::doMove (double timeMax
)
223 // H_AUTO(PACS_PWI_doMove_short);
226 _Position
.setPos (_Position
.getPos ()+_Speed
*(timeMax
-_InitTime
));
232 // ***************************************************************************
234 bool CPrimitiveWorldImage::evalCollisionOBoverOB (CPrimitiveWorldImage
& other
, CCollisionDesc
& desc
, double timeMin
, double timeMax
,
235 double &firstContactTime
, double &lastContactTime
, CMovePrimitive
& primitive
,
236 CMovePrimitive
& otherPrimitive
)
239 nlassert (primitive
.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox
);
240 nlassert (otherPrimitive
.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox
);
246 desc
.ContactTime
=FLT_MAX
;
249 double _timeMax
=-FLT_MAX
;
251 // Check movable points over the edge
254 for (pt
=0; pt
<4; pt
++)
255 for (seg
=0; seg
<4; seg
++)
257 // Get collision time of the point over the segment
259 if ( evalCollisionPoverS (other
, d
, pt
, seg
, primitive
, otherPrimitive
) )
265 if (d
.ContactTime
<desc
.ContactTime
)
267 // This is the new descriptor
272 if (d
.ContactTime
>_timeMax
)
274 // This is the new max time
275 _timeMax
=d
.ContactTime
;
280 // Check static points over the movable box
281 for (pt
=0; pt
<4; pt
++)
282 for (seg
=0; seg
<4; seg
++)
284 // Get collision time of the point over the segment
286 if (other
.evalCollisionPoverS (*this, d
, pt
, seg
, primitive
, otherPrimitive
))
292 if (d
.ContactTime
<desc
.ContactTime
)
294 // This is the new descriptor
299 if (d
.ContactTime
>_timeMax
)
301 // This is the new max time
302 _timeMax
=d
.ContactTime
;
309 // First last contact time
310 firstContactTime
=desc
.ContactTime
;
311 lastContactTime
=_timeMax
;
314 //double halfTime = (_timeMax+desc.ContactTime)/2.0;
316 // Collision in the past ?
317 //if (timeMin > halfTime)
318 if (timeMin
> _timeMax
)
322 // Collision not in the future ?
323 if (timeMax
>desc
.ContactTime
)
326 if (desc
.ContactTime
<timeMin
)
327 desc
.ContactTime
=timeMin
;
334 // No collision found
338 // ***************************************************************************
340 bool CPrimitiveWorldImage::evalCollisionOBoverOC (CPrimitiveWorldImage
& other
, CCollisionDesc
& desc
, double timeMin
, double timeMax
,
341 double &firstContactTime
, double &lastContactTime
, CMovePrimitive
& primitive
,
342 CMovePrimitive
& otherPrimitive
)
345 nlassert (primitive
.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox
);
346 nlassert (otherPrimitive
.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedCylinder
);
352 desc
.ContactTime
=FLT_MAX
;
355 double _timeMax
= -FLT_MAX
;
357 // Check movable points over the cylinder
359 for (pt
=0; pt
<4; pt
++)
361 // Get collision time of the point over the segment
363 double firstContactTime
;
364 double lastContactTime
;
365 if (evalCollisionPoverOC (other
, d
, pt
, firstContactTime
, lastContactTime
, primitive
, otherPrimitive
))
371 if (firstContactTime
<desc
.ContactTime
)
373 // This is the new descriptor
378 if (lastContactTime
>_timeMax
)
381 _timeMax
=lastContactTime
;
386 // Check static points over the movable box
388 for (seg
=0; seg
<4; seg
++)
390 // Get collision time of the point over the segment
392 if (evalCollisionSoverOC (other
, d
, seg
, primitive
, otherPrimitive
))
398 if (d
.ContactTime
<desc
.ContactTime
)
400 // This is the new descriptor
405 if (d
.ContactTime
>_timeMax
)
408 _timeMax
=d
.ContactTime
;
415 // First last contact time
416 firstContactTime
=desc
.ContactTime
;
417 lastContactTime
=_timeMax
;
420 //double halfTime = (_timeMax+desc.ContactTime)/2.0;
422 // Collision in the past ?
423 //if (timeMin > halfTime)
424 if (timeMin
> _timeMax
)
428 // Collision not in the future ?
429 if (timeMax
>desc
.ContactTime
)
432 if (desc
.ContactTime
<timeMin
)
433 desc
.ContactTime
=timeMin
;
440 // No collision found
444 // ***************************************************************************
446 bool CPrimitiveWorldImage::evalCollisionPoverS (CPrimitiveWorldImage
& other
, CCollisionDesc
& desc
, uint numPoint
, uint numSeg
,
447 CMovePrimitive
& primitive
, CMovePrimitive
& otherPrimitive
)
450 nlassert (primitive
.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox
);
451 nlassert (otherPrimitive
.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox
);
454 const double normalSegX
=other
._OBData
.EdgeDirectionY
[numSeg
];
455 const double normalSegY
=-other
._OBData
.EdgeDirectionX
[numSeg
];
458 const double speedX
=other
._Speed
.x
-_Speed
.x
;
459 const double speedY
=other
._Speed
.y
-_Speed
.y
;
461 // Dot product with the plan tangeante
462 double dotProd
= speedX
*normalSegX
+ speedY
*normalSegY
;
466 // Time of the collision
467 double time
= (normalSegX
*(_OBData
.PointPosX
[numPoint
] - other
._OBData
.PointPosX
[numSeg
]) +
468 normalSegY
*(_OBData
.PointPosY
[numPoint
] - other
._OBData
.PointPosY
[numSeg
])) / dotProd
;
470 // Position of segment point at collision time
471 const double segPosX
= other
._OBData
.PointPosX
[numSeg
] + other
._Speed
.x
*time
;
472 const double segPosY
= other
._OBData
.PointPosY
[numSeg
] + other
._Speed
.y
*time
;
474 // Position of the point at collision time
475 const double ptPosX
= _OBData
.PointPosX
[numPoint
] + _Speed
.x
*time
;
476 const double ptPosY
= _OBData
.PointPosY
[numPoint
] + _Speed
.y
*time
;
478 // Direction of the collision on the segment
479 const double dirX
= ptPosX
- segPosX
;
480 const double dirY
= ptPosY
- segPosY
;
482 // Length of this vector
483 const double length
= dirY
*normalSegX
- dirX
*normalSegY
;
486 if ( ( length
>= 0 ) && ( length
<= otherPrimitive
.getLength(numSeg
&1) ) )
488 // 2d Collid checked... Now check height
491 const double pointSegZ
=other
._3dInitPosition
.z
;
492 const double segPosZ
= pointSegZ
+ other
._Speed
.z
*time
;
495 const double pointZ
=_3dInitPosition
.z
;
496 const double ptPosZ
= pointZ
+ _Speed
.z
*time
;
499 if ( (ptPosZ
<= segPosZ
+ otherPrimitive
.getHeightInternal()) && (ptPosZ
+ primitive
.getHeightInternal() >= segPosZ
) )
501 // Ok Collision, fill the result
504 desc
.ContactTime
=time
;
507 desc
.ContactPosition
.x
=ptPosX
;
508 desc
.ContactPosition
.y
=ptPosY
;
509 desc
.ContactPosition
.z
=std::max (segPosZ
, ptPosZ
);
512 desc
.ContactNormal1
.x
=normalSegX
;
513 desc
.ContactNormal1
.y
=normalSegY
;
514 desc
.ContactNormal1
.z
=0;
515 desc
.ContactNormal0
.x
=-desc
.ContactNormal1
.x
;
516 desc
.ContactNormal0
.y
=-desc
.ContactNormal1
.y
;
517 desc
.ContactNormal0
.z
=0;
529 // ***************************************************************************
531 inline uint
secondDegree (double a
, double b
, double c
, double& s0
, double& s1
)
533 double d
=b
*b
-4.f
*a
*c
;
562 // ***************************************************************************
564 bool CPrimitiveWorldImage::evalCollisionPoverOC (CPrimitiveWorldImage
& other
, CCollisionDesc
& desc
, uint numPoint
,
565 double &firstContactTime
, double &lastContactTime
, CMovePrimitive
& primitive
,
566 CMovePrimitive
& otherPrimitive
)
569 nlassert (primitive
.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox
);
570 nlassert (otherPrimitive
.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedCylinder
);
573 * p(t) = p0 + v0*(t - t0)
575 * Cylinder center Equ:
576 * p'(t) = p'0 + v'0*(t - t'0)
578 * Find t for this equation:
579 * R^2 = Norm^2 (p(t) - p'(t))
580 * R^2 = Norm^2 ( p0 + v0 ( t - t0 ) - p'0 - v'0 ( t - t'0 ) )
582 * A = p0 - v0*t0 - p'0 + v'0*t'0
585 * Norm^2 (B)*t^2 + 2*(A.B)*t + Norm^2 (A) - R^2 = 0
589 * c = Norm^2 (A) - R^2
591 * a*t^2 + b*t + c = 0
595 const double _Ax
= _OBData
.PointPosX
[numPoint
] - other
._3dInitPosition
.x
;
596 const double _Ay
= _OBData
.PointPosY
[numPoint
] - other
._3dInitPosition
.y
;
597 const double _Bx
= _Speed
.x
- other
._Speed
.x
;
598 const double _By
= _Speed
.y
- other
._Speed
.y
;
602 double squareRadius
=otherPrimitive
.getRadiusInternal()*otherPrimitive
.getRadiusInternal();
603 uint numSolution
=secondDegree (_Bx
*_Bx
+_By
*_By
, 2.f
*(_Ax
*_Bx
+_Ay
*_By
), _Ax
*_Ax
+_Ay
*_Ay
-squareRadius
, s0
, s1
);
617 // First and last time
629 time
=firstContactTime
;
632 const double pointCylZ
=other
._3dInitPosition
.z
;
633 const double cylPosZ
= pointCylZ
+ other
._Speed
.z
*time
;
636 const double pointZ
=_3dInitPosition
.z
;
637 const double ptPosZ
= pointZ
+ _Speed
.z
*time
;
640 if ( (ptPosZ
<= cylPosZ
+ otherPrimitive
.getHeightInternal()) && (ptPosZ
+ primitive
.getHeightInternal() >= cylPosZ
) )
642 // Ok Collision, fill the result
645 desc
.ContactTime
=time
;
648 const double ptPosX
= _OBData
.PointPosX
[numPoint
] + _Speed
.x
*time
;
649 const double ptPosY
= _OBData
.PointPosY
[numPoint
] + _Speed
.y
*time
;
652 const double cylPosX
= other
._3dInitPosition
.x
+ other
._Speed
.x
*time
;
653 const double cylPosY
= other
._3dInitPosition
.y
+ other
._Speed
.y
*time
;
656 desc
.ContactPosition
.x
=ptPosX
;
657 desc
.ContactPosition
.y
=ptPosY
;
658 desc
.ContactPosition
.z
=std::max (cylPosZ
, ptPosZ
);
661 desc
.ContactNormal1
.x
=ptPosX
-cylPosX
;
662 desc
.ContactNormal1
.y
=ptPosY
-cylPosY
;
663 desc
.ContactNormal1
.z
=0;
664 desc
.ContactNormal1
.normalize ();
665 desc
.ContactNormal0
.x
=-desc
.ContactNormal1
.x
;
666 desc
.ContactNormal0
.y
=-desc
.ContactNormal1
.y
;
667 desc
.ContactNormal0
.z
=0;
678 // ***************************************************************************
680 bool CPrimitiveWorldImage::evalCollisionSoverOC (CPrimitiveWorldImage
& other
, CCollisionDesc
& desc
, uint numSeg
, CMovePrimitive
& primitive
,
681 CMovePrimitive
& otherPrimitive
)
684 nlassert (primitive
.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox
);
685 nlassert (otherPrimitive
.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedCylinder
);
688 const double normalSegX
=_OBData
.EdgeDirectionY
[numSeg
];
689 const double normalSegY
=-_OBData
.EdgeDirectionX
[numSeg
];
692 const double speedX
=other
._Speed
.x
-_Speed
.x
;
693 const double speedY
=other
._Speed
.y
-_Speed
.y
;
695 // Dot product with the plan tangeante
696 double dotProd
= speedX
*normalSegX
+ speedY
*normalSegY
;
700 // Time of the collision
701 double time
= (otherPrimitive
.getRadiusInternal() + normalSegX
*(_OBData
.PointPosX
[numSeg
] - other
._3dInitPosition
.x
) +
702 normalSegY
*(_OBData
.PointPosY
[numSeg
] - other
._3dInitPosition
.y
) ) / dotProd
;
704 // Position of segment point at collision time
705 const double segPosX
= _OBData
.PointPosX
[numSeg
] + _Speed
.x
*time
;
706 const double segPosY
= _OBData
.PointPosY
[numSeg
] + _Speed
.y
*time
;
708 // Position of the cylinder at collision time
709 const double cylPosX
= other
._3dInitPosition
.x
+ _Speed
.x
*time
;
710 const double cylPosY
= other
._3dInitPosition
.y
+ _Speed
.y
*time
;
712 // Position de contact
713 const double contactX
= cylPosX
- normalSegX
*otherPrimitive
.getRadiusInternal();
714 const double contactY
= cylPosY
- normalSegY
*otherPrimitive
.getRadiusInternal();
716 // Direction of the collision on the segment
717 const double dirX
= contactX
- segPosX
;
718 const double dirY
= contactY
- segPosY
;
720 // Length of this vector
721 const double length
= dirY
*normalSegX
- dirX
*normalSegY
;
724 if ( ( length
>= 0 ) && ( length
<= primitive
.getLength (numSeg
&1) ) )
726 // 2d Collid checked... Now check height
729 const double segPosZ
= _3dInitPosition
.z
+ _Speed
.z
*time
;
732 const double cylPosZ
= other
._3dInitPosition
.z
+ other
._Speed
.z
*time
;
735 if ( (cylPosZ
<= segPosZ
+ primitive
.getHeightInternal() ) && (cylPosZ
+ otherPrimitive
.getHeightInternal() >= segPosZ
) )
737 // Ok Collision, fill the result
740 desc
.ContactTime
=time
;
743 desc
.ContactPosition
.x
=contactX
;
744 desc
.ContactPosition
.y
=contactY
;
745 desc
.ContactPosition
.z
=std::max (segPosZ
, cylPosZ
);
748 desc
.ContactNormal0
.x
=normalSegX
;
749 desc
.ContactNormal0
.y
=normalSegY
;
750 desc
.ContactNormal0
.z
=0;
753 desc
.ContactNormal1
.x
=contactX
-cylPosX
;
754 desc
.ContactNormal1
.y
=contactY
-cylPosY
;
755 desc
.ContactNormal1
.z
=0;
756 desc
.ContactNormal1
.normalize ();
769 // ***************************************************************************
771 bool CPrimitiveWorldImage::evalCollisionOCoverOC (CPrimitiveWorldImage
& other
, CCollisionDesc
& desc
, double timeMin
, double timeMax
,
772 double &firstContactTime
, double &lastContactTime
, CMovePrimitive
& primitive
,
773 CMovePrimitive
& otherPrimitive
)
776 nlassert (primitive
.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedCylinder
);
777 nlassert (otherPrimitive
.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedCylinder
);
780 /* Cylinder0 center equ:
781 * p(t) = p0 + v0*(t - t0)
783 * Cylinder1 center equ:
784 * p'(t) = p'0 + v'0*(t - t'0)
786 * Find t for this equation:
787 * (R + R')^2 = Norm^2 (p(t) - p'(t))
788 * (R + R')^2 = Norm^2 ( p0 + v0 ( t - t0 ) - p'0 - v'0 ( t - t'0 ) )
790 * A = p0 - v0*t0 - p'0 + v'0*t'0
793 * Norm^2 (B)*t^2 + 2*(A.B)*t + Norm^2 (A) - (R + R')^2 = 0
797 * c = Norm^2 (A) - (R + R')^2
799 * a*t^2 + b*t + c = 0
803 const double _Ax
= _3dInitPosition
.x
- other
._3dInitPosition
.x
;
804 const double _Ay
= _3dInitPosition
.y
- other
._3dInitPosition
.y
;
805 const double _Bx
= _Speed
.x
- other
._Speed
.x
;
806 const double _By
= _Speed
.y
- other
._Speed
.y
;
810 double radiusSquare
=primitive
.getRadiusInternal()+otherPrimitive
.getRadiusInternal();
811 radiusSquare
*=radiusSquare
;
812 uint numSolution
=secondDegree (_Bx
*_Bx
+_By
*_By
, 2.f
*(_Ax
*_Bx
+_Ay
*_By
), _Ax
*_Ax
+_Ay
*_Ay
-radiusSquare
, s0
, s1
);
816 double _timeMin
, _timeMax
;
840 //const double halfTime=(_timeMin+_timeMax)/2.0;
843 firstContactTime
=_timeMin
;
844 lastContactTime
=_timeMax
;
847 if ((timeMin
<_timeMax
)&&(_timeMin
<timeMax
))
850 const double cyl0Time
= _timeMin
;
851 const double pointCyl0Z
=_3dInitPosition
.z
;
852 const double cyl0PosZ
= pointCyl0Z
+ _Speed
.z
*cyl0Time
;
855 const double cyl1Time
= _timeMin
;
856 const double pointCyl1Z
=other
._3dInitPosition
.z
;
857 const double cyl1PosZ
= pointCyl1Z
+ other
._Speed
.z
* cyl1Time
;
860 if ( (cyl0PosZ
<= cyl1PosZ
+ otherPrimitive
.getHeightInternal() ) && (cyl0PosZ
+ primitive
.getHeightInternal() >= cyl1PosZ
) )
862 // Ok Collision, fill the result
865 desc
.ContactTime
=std::max (_timeMin
, timeMin
);
867 // Cylinder 0 position
868 const double cyl0PosX
= _3dInitPosition
.x
+ _Speed
.x
*cyl0Time
;
869 const double cyl0PosY
= _3dInitPosition
.y
+ _Speed
.y
*cyl0Time
;
871 // Cylinder 1 position
872 const double cyl1PosX
= other
._3dInitPosition
.x
+ other
._Speed
.x
*cyl1Time
;
873 const double cyl1PosY
= other
._3dInitPosition
.y
+ other
._Speed
.y
*cyl1Time
;
875 // First cylinder normal
876 desc
.ContactNormal0
.x
= cyl1PosX
- cyl0PosX
;
877 desc
.ContactNormal0
.y
= cyl1PosY
- cyl0PosY
;
878 desc
.ContactNormal0
.z
= 0;
879 desc
.ContactNormal0
.normalize ();
882 desc
.ContactPosition
.x
= desc
.ContactNormal0
.x
*primitive
.getRadiusInternal() + cyl0PosX
;
883 desc
.ContactPosition
.y
= desc
.ContactNormal0
.y
*primitive
.getRadiusInternal() + cyl0PosY
;
884 desc
.ContactPosition
.z
= std::max (cyl0PosZ
, cyl1PosZ
);
886 // Second cylinder normal
887 desc
.ContactNormal1
.x
= -desc
.ContactNormal0
.x
;
888 desc
.ContactNormal1
.y
= -desc
.ContactNormal0
.y
;
889 desc
.ContactNormal1
.z
= 0;
901 // ***************************************************************************
903 void CPrimitiveWorldImage::precalcPos (CMovePrimitive
&primitive
)
905 // Type of the primitive
906 uint type
=primitive
.getPrimitiveTypeInternal();
909 if (type
==UMovePrimitive::_2DOrientedBox
)
911 // Calc cosinus and sinus
912 double cosinus
=(double)cos(_OBData
.Orientation
);
913 double sinus
=(double)sin(_OBData
.Orientation
);
916 double halfWidth
=primitive
.getLength (0)/2;
917 double halfDepth
=primitive
.getLength (1)/2;
920 _OBData
.PointPosX
[0]=cosinus
*(-halfWidth
)-sinus
*(-halfDepth
)+_3dInitPosition
.x
;
921 _OBData
.PointPosY
[0]=sinus
*(-halfWidth
)+cosinus
*(-halfDepth
)+_3dInitPosition
.y
;
924 _OBData
.PointPosX
[1]=cosinus
*halfWidth
-sinus
*(-halfDepth
)+_3dInitPosition
.x
;
925 _OBData
.PointPosY
[1]=sinus
*halfWidth
+cosinus
*(-halfDepth
)+_3dInitPosition
.y
;
928 _OBData
.PointPosX
[2]=cosinus
*halfWidth
-sinus
*halfDepth
+_3dInitPosition
.x
;
929 _OBData
.PointPosY
[2]=sinus
*halfWidth
+cosinus
*halfDepth
+_3dInitPosition
.y
;
932 _OBData
.PointPosX
[3]=cosinus
*(-halfWidth
)-sinus
*halfDepth
+_3dInitPosition
.x
;
933 _OBData
.PointPosY
[3]=sinus
*(-halfWidth
)+cosinus
*halfDepth
+_3dInitPosition
.y
;
936 double length0
= (primitive
.getLength(0)==0)? 0.001 : primitive
.getLength(0);
937 double length1
= (primitive
.getLength(1)==0)? 0.001 : primitive
.getLength(1);
938 double oneOverLength
[2]= { 1 / length0
, 1 / length1
};
946 double oneOver
=oneOverLength
[i
&1];
949 _OBData
.EdgeDirectionX
[i
]=(_OBData
.PointPosX
[next
] - _OBData
.PointPosX
[i
])*oneOver
;
950 _OBData
.EdgeDirectionY
[i
]=(_OBData
.PointPosY
[next
] - _OBData
.PointPosY
[i
])*oneOver
;
955 // Should be a cylinder
956 nlassert (type
==UMovePrimitive::_2DOrientedCylinder
);
960 // ***************************************************************************
962 void CPrimitiveWorldImage::precalcBB (double beginTime
, double endTime
, CMovePrimitive
&primitive
)
964 // Type of the primitive
965 uint type
=primitive
.getPrimitiveTypeInternal();
968 if (type
==UMovePrimitive::_2DOrientedBox
)
971 sint orient
= (sint
)(256.f
*_OBData
.Orientation
/(2.f
*NLMISC::Pi
));
974 nlassert (orient
>=0);
977 // Compute coordinates
983 for (uint i
=0; i
<4; i
++)
985 if (_OBData
.PointPosX
[i
]<_BBXMin
)
986 _BBXMin
=_OBData
.PointPosX
[i
];
987 if (_OBData
.PointPosX
[i
]>_BBXMax
)
988 _BBXMax
=_OBData
.PointPosX
[i
];
989 if (_OBData
.PointPosY
[i
]<_BBYMin
)
990 _BBYMin
=_OBData
.PointPosY
[i
];
991 if (_OBData
.PointPosY
[i
]>_BBYMax
)
992 _BBYMax
=_OBData
.PointPosY
[i
];
994 _BBXMin
=std::min (std::min (_BBXMin
, _BBXMin
+endTime
*_Speed
.x
), _BBXMin
+beginTime
*_Speed
.x
);
995 _BBXMax
=std::max (std::max (_BBXMax
, _BBXMax
+endTime
*_Speed
.x
), _BBXMax
+beginTime
*_Speed
.x
);
996 _BBYMin
=std::min (std::min (_BBYMin
, _BBYMin
+endTime
*_Speed
.y
), _BBYMin
+beginTime
*_Speed
.y
);
997 _BBYMax
=std::max (std::max (_BBYMax
, _BBYMax
+endTime
*_Speed
.y
), _BBYMax
+beginTime
*_Speed
.y
);
1000 // This code is faster but buggy..
1001 _BBXMin= _OBData.PointPosX[minX[orient]] + _Speed.x*beginTime;
1002 _BBXMin= std::min (_BBXMin, _OBData.PointPosX[minX[orient]] + _Speed.x*endTime);
1004 _BBYMin= _OBData.PointPosY[minY[orient]] + _Speed.y*beginTime;
1005 _BBYMin= std::min (_BBYMin, _OBData.PointPosY[minY[orient]] + _Speed.y*endTime);
1007 _BBXMax= _OBData.PointPosX[maxX[orient]] + _Speed.x*beginTime;
1008 _BBXMax= std::max (_BBXMax, _OBData.PointPosX[maxX[orient]] + _Speed.x*endTime);
1010 _BBYMax= _OBData.PointPosY[maxY[orient]] + _Speed.y*beginTime;
1011 _BBYMax= std::max (_BBYMax, _OBData.PointPosY[maxY[orient]] + _Speed.y*endTime);*/
1015 // Should be a cylinder
1016 nlassert (type
==UMovePrimitive::_2DOrientedCylinder
);
1018 // Compute X coordinates
1019 _BBXMin
= _3dInitPosition
.x
+ _Speed
.x
*beginTime
;
1020 _BBXMax
= _3dInitPosition
.x
+ _Speed
.x
*endTime
;
1021 if (_BBXMin
>_BBXMax
)
1027 _BBXMin
-=primitive
.getRadiusInternal();
1028 _BBXMax
+=primitive
.getRadiusInternal();
1030 // Compute Y coordinates
1031 _BBYMin
= _3dInitPosition
.y
+ _Speed
.y
*beginTime
;
1032 _BBYMax
= _3dInitPosition
.y
+ _Speed
.y
*endTime
;
1033 if (_BBYMin
>_BBYMax
)
1039 _BBYMin
-=primitive
.getRadiusInternal();
1040 _BBYMax
+=primitive
.getRadiusInternal();
1044 _DeltaPosition
=_Speed
*(endTime
-beginTime
);
1047 // ***************************************************************************
1049 void CPrimitiveWorldImage::addMoveElement (CMoveCell
& cell
, uint16 x
, uint16 y
, double centerX
, double /* centerY */, CMovePrimitive
*primitive
,
1050 CMoveContainer
&container
, uint8 worldImage
)
1052 // Find a free place
1054 for (slot
=0; slot
<4; slot
++)
1057 if (_MoveElement
[slot
]==NULL
)
1060 double cx
=(_BBXMin
+_BBXMax
)/2.f
;
1062 // Allocate move element
1063 _MoveElement
[slot
]=container
.allocateMoveElement ();
1064 _MoveElement
[slot
]->Primitive
=primitive
;
1065 _MoveElement
[slot
]->X
=x
;
1066 _MoveElement
[slot
]->Y
=y
;
1068 // Insert in left or right ?
1071 cell
.linkFirstX (_MoveElement
[slot
]);
1074 cell
.linkLastX (_MoveElement
[slot
]);
1076 /*// Insert in left or right ?
1079 cell.linkFirstY (_MoveElement[slot]);
1082 cell.linkLastY (_MoveElement[slot]);*/
1085 cell
.updateSortedLists (_MoveElement
[slot
], worldImage
);
1093 // ***************************************************************************
1095 void CPrimitiveWorldImage::addMoveElementendOfList (CMoveCell
& cell
, uint16 x
, uint16 y
, CMovePrimitive
*primitive
,
1096 CMoveContainer
&container
)
1098 // Find a free place
1100 for (slot
=0; slot
<4; slot
++)
1103 if (_MoveElement
[slot
]==NULL
)
1105 // Allocate move element
1106 _MoveElement
[slot
]=container
.allocateMoveElement ();
1107 _MoveElement
[slot
]->Primitive
=primitive
;
1108 _MoveElement
[slot
]->X
=x
;
1109 _MoveElement
[slot
]->Y
=y
;
1112 cell
.linkLastX (_MoveElement
[slot
]);
1120 // ***************************************************************************
1122 void CPrimitiveWorldImage::removeMoveElement (uint i
, CMoveContainer
&container
, uint8 worldImage
)
1126 nlassert (_MoveElement
[i
]!=NULL
);
1128 // Unlink the element
1129 container
.unlinkMoveElement (_MoveElement
[i
], worldImage
);
1131 // Free the move element
1132 container
.freeMoveElement (_MoveElement
[i
]);
1135 _MoveElement
[i
]=NULL
;
1138 // ***************************************************************************
1140 void CPrimitiveWorldImage::checkSortedList (uint8 worldImage
)
1142 // For the 4 elements
1143 for (uint i
=0; i
<4; i
++)
1146 if (_MoveElement
[i
])
1148 if (_MoveElement
[i
]->PreviousX
)
1149 nlassertonce (_MoveElement
[i
]->PreviousX
->Primitive
->getWorldImage(worldImage
)->_BBXMin
<= _BBXMin
);
1150 if (_MoveElement
[i
]->NextX
)
1151 nlassertonce (_BBXMin
<= _MoveElement
[i
]->NextX
->Primitive
->getWorldImage(worldImage
)->_BBXMin
);
1156 // ***************************************************************************
1158 void CPrimitiveWorldImage::reaction (CPrimitiveWorldImage
& second
, const CCollisionDesc
& desc
, CGlobalRetriever
* retriever
,
1159 CCollisionSurfaceTemp
& surfaceTemp
, bool collision
, CMovePrimitive
&primitive
,
1160 CMovePrimitive
&otherPrimitive
, CMoveContainer
*container
, uint8 worldImage
, uint8 secondWorldImage
,
1163 // H_AUTO(PACS_PWI_reaction_long);
1165 // Get the two reaction codes
1166 UMovePrimitive::TReaction firstReaction
=primitive
.getReactionTypeInternal();
1167 UMovePrimitive::TReaction secondReaction
=otherPrimitive
.getReactionTypeInternal();
1170 collision
= collision
&& (primitive
.isObstacle ()) && (otherPrimitive
.isObstacle ());
1173 float mass0
= primitive
.getMass ();
1174 float mass1
= otherPrimitive
.getMass ();
1177 double projSpeed0
= desc
.ContactNormal1
* _Speed
;
1178 double projSpeed1
= desc
.ContactNormal0
* second
._Speed
;
1179 double energySum
= (- mass0
* projSpeed0
- mass1
* projSpeed1
) / 2.0;
1182 CVectorD collisionPosition
=_3dInitPosition
;
1183 collisionPosition
+=_Speed
*desc
.ContactTime
;
1186 CVectorD
newSpeed(0.0, 0.0, 0.0);
1191 switch (firstReaction
)
1193 case UMovePrimitive::Slide
:
1194 // Remove projected speed
1195 newSpeed
=_Speed
- projSpeed0
* desc
.ContactNormal1
;
1198 newSpeed
+=( primitive
.getAttenuation()*energySum
/ mass0
) * desc
.ContactNormal1
;
1200 case UMovePrimitive::Reflexion
:
1201 // Remove projected speed
1202 newSpeed
=_Speed
- projSpeed0
* desc
.ContactNormal1
;
1205 newSpeed
+=( primitive
.getAttenuation()*energySum
/ mass0
) * desc
.ContactNormal1
;
1207 case UMovePrimitive::Stop
:
1208 newSpeed
.set (0,0,0);
1210 case UMovePrimitive::DoNothing
:
1217 setSpeed (newSpeed
, container
, &primitive
, worldImage
);
1219 // New position at t=0
1222 // Make a domove in the Ben data
1223 double deltaDist
= _DeltaPosition
.norm();
1225 if(deltaDist
<0.000001)
1228 deltaTime
=(collisionPosition
-_Position
.getPos ()).norm()/deltaDist
;
1229 nlassert (deltaTime
>=0);
1230 nlassert (deltaTime
<=1);
1232 UGlobalPosition newPosition
= retriever
->doMove (_Position
.getGlobalPos (), _DeltaPosition
,
1233 (float)deltaTime
, surfaceTemp
, true);
1235 // Set the new position
1236 _Position
.setGlobalPos (newPosition
, *retriever
);
1239 _3dInitPosition
= _Position
.getPos() - newSpeed
* desc
.ContactTime
;
1242 _InitTime
= desc
.ContactTime
;
1246 // No retriever used
1247 _Position
.setPos (collisionPosition
);
1250 _3dInitPosition
= collisionPosition
- newSpeed
* desc
.ContactTime
;
1253 _InitTime
= desc
.ContactTime
;
1257 dirtPos (container
, &primitive
, worldImage
);
1259 // ****** Second object
1261 // Is second object in a static world ?
1265 collisionPosition
=second
._3dInitPosition
;
1266 collisionPosition
+=second
._Speed
* desc
.ContactTime
;
1269 switch (secondReaction
)
1271 case UMovePrimitive::Slide
:
1272 // Remove projected speed
1273 newSpeed
=second
._Speed
- projSpeed1
* desc
.ContactNormal0
;
1276 newSpeed
+=( otherPrimitive
.getAttenuation()*energySum
/ mass1
) * desc
.ContactNormal1
;
1278 case UMovePrimitive::Reflexion
:
1279 // Remove projected speed
1280 newSpeed
=second
._Speed
- projSpeed1
* desc
.ContactNormal0
;
1283 newSpeed
+=( otherPrimitive
.getAttenuation()*energySum
/ mass1
) * desc
.ContactNormal0
;
1285 case UMovePrimitive::Stop
:
1286 newSpeed
.set (0,0,0);
1288 case UMovePrimitive::DoNothing
:
1289 newSpeed
=second
._Speed
;
1295 second
.setSpeed (newSpeed
, container
, &otherPrimitive
, secondWorldImage
);
1297 // New position at t=0
1300 // Make a domove in the Ben data
1301 double deltaDist
= second
._DeltaPosition
.norm();
1306 deltaTime
=(collisionPosition
-second
._Position
.getPos ()).norm()/deltaDist
;
1307 clamp (deltaTime
, 0.0, 1.0);
1309 UGlobalPosition newPosition
= retriever
->doMove (second
._Position
.getGlobalPos (), second
._DeltaPosition
,
1310 (float)deltaTime
, surfaceTemp
, true);
1312 // Set the new position
1313 second
._Position
.setGlobalPos (newPosition
, *retriever
);
1316 second
._3dInitPosition
= second
._Position
.getPos() - newSpeed
* desc
.ContactTime
;
1319 second
._InitTime
= desc
.ContactTime
;
1323 // No retriever used
1324 second
._Position
.setPos (collisionPosition
);
1327 second
._3dInitPosition
= collisionPosition
- newSpeed
* desc
.ContactTime
;
1330 second
._InitTime
= desc
.ContactTime
;
1334 second
.dirtPos (container
, &otherPrimitive
, secondWorldImage
);
1339 // ***************************************************************************
1341 void CPrimitiveWorldImage::reaction (const CCollisionSurfaceDesc
& surfaceDesc
, const UGlobalPosition
& globalPosition
,
1342 CGlobalRetriever
& retriever
, double /* ratio */, double dt
, CMovePrimitive
&primitive
, CMoveContainer
&container
,
1345 // H_AUTO(PACS_PWI_reaction_short);
1348 uint32 type
=primitive
.getReactionTypeInternal();
1350 // Reaction to the collision: copy the CGlobalRetriever::CGlobalPosition
1351 _Position
.setGlobalPos (globalPosition
, retriever
);
1353 // Relfexion or slide ?
1354 if ((type
==UMovePrimitive::Reflexion
)||(type
==UMovePrimitive::Slide
))
1357 if (type
==UMovePrimitive::Slide
)
1359 // Project last delta on plane of collision.
1360 _Speed
-= surfaceDesc
.ContactNormal
*(surfaceDesc
.ContactNormal
*_Speed
-NELPACS_DIST_BACK
/(dt
-surfaceDesc
.ContactTime
));
1364 if (type
==UMovePrimitive::Reflexion
)
1366 // Project last delta on plane of collision.
1367 double speedProj
=surfaceDesc
.ContactNormal
*_Speed
;
1368 _Speed
-=surfaceDesc
.ContactNormal
*(speedProj
+speedProj
*primitive
.getAttenuation()-NELPACS_DIST_BACK
/(dt
-surfaceDesc
.ContactTime
));
1374 if (type
==UMovePrimitive::Stop
)
1381 double contactTime
=surfaceDesc
.ContactTime
;
1384 _3dInitPosition
= _Position
.getPos() - _Speed
* contactTime
;
1387 _InitTime
=contactTime
;
1390 dirtPos (&container
, &primitive
, worldImage
);
1393 // ***************************************************************************
1395 void CPrimitiveWorldImage::setGlobalPosition (const UGlobalPosition
& pos
, CMoveContainer
& container
, CMovePrimitive
&primitive
, uint8 worldImage
)
1398 nlassert (dynamic_cast<const CMoveContainer
*>(&container
) != NULL
);
1399 const CMoveContainer
*cont
=(const CMoveContainer
*)&container
;
1401 if (!cont
->getGlobalRetriever()) return;
1402 // Use the global retriever ?
1403 nlassert (cont
->getGlobalRetriever());
1406 _Position
.setGlobalPos (pos
, *cont
->getGlobalRetriever());
1408 // Precalc some values
1409 _3dInitPosition
= _Position
.getPos ();
1413 _Speed
=CVector::Null
;
1416 dirtPos (&container
, &primitive
, worldImage
);
1419 // ***************************************************************************
1421 void CPrimitiveWorldImage::setGlobalPosition (const NLMISC::CVectorD
& pos
, CMoveContainer
& container
, CMovePrimitive
&primitive
, uint8 worldImage
, bool keepZ
/*= false*/, UGlobalPosition::TType type
/* =UGlobalPosition::Unspecified*/)
1424 nlassert (dynamic_cast<const CMoveContainer
*>(&container
) != NULL
);
1425 const CMoveContainer
*cont
=(const CMoveContainer
*)&container
;
1427 // Get the retriever
1428 CGlobalRetriever
*retriever
=cont
->getGlobalRetriever();
1430 // Use a global retriever
1434 // CVector vect=pos; // better with CVectorD
1436 // Get global position
1437 UGlobalPosition globalPosition
=retriever
->retrievePosition (pos
, 1.0e10
, type
);
1442 _Position
.setPos (pos
);
1444 // Set global position
1445 _Position
.setGlobalPosKeepZ (globalPosition
, *retriever
);
1449 // Set global position
1450 _Position
.setGlobalPos (globalPosition
, *retriever
);
1456 _Position
.setPos (pos
);
1459 // Precalc some values
1460 _3dInitPosition
= _Position
.getPos ();
1464 _Speed
=CVector::Null
;
1467 dirtPos (&container
, &primitive
, worldImage
);
1470 // ***************************************************************************
1472 void CPrimitiveWorldImage::move (const NLMISC::CVectorD
& speed
, CMoveContainer
& container
, CMovePrimitive
&primitive
, uint8 worldImage
)
1475 setSpeed (speed
, &container
, &primitive
, worldImage
);
1477 // Set initial position
1478 _3dInitPosition
= _Position
.getPos ();
1484 dirtPos (&container
, &primitive
, worldImage
);
1487 // ***************************************************************************