Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / pacs / primitive_world_image.cpp
blob22cf2cee2aad2f11b1c600fa049ff5682b360d3c
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
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.
8 //
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/>.
17 #include "stdpacs.h"
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;
28 namespace NLPACS
31 // ***************************************************************************
33 CPrimitiveWorldImage::CPrimitiveWorldImage()
35 // Set to NULL
36 for (uint i=0; i<4; i++)
37 _MoveElement[i]=NULL;
39 _DynamicFlags=0;
40 _BBXMin=-FLT_MAX;
41 _BBXMax=-FLT_MAX;
42 _BBYMin=-FLT_MAX;
43 _BBYMax=-FLT_MAX;
46 // ***************************************************************************
48 void CPrimitiveWorldImage::deleteIt (CMoveContainer &container, uint8 worldImage)
50 // Free the move elements
51 for (uint i=0; i<4; i++)
52 if (_MoveElement[i])
53 removeMoveElement (i, container, worldImage);
55 // ***************************************************************************
57 void CPrimitiveWorldImage::copy (const CPrimitiveWorldImage& source)
59 // Copy
60 this->operator=(source);
62 // Reset some flags
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++)
67 _MoveElement[i]=NULL;
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);
78 // Mask test
79 if (( (primitive.getCollisionMaskInternal() & otherPrimitive.getOcclusionMaskInternal()) == 0) &&
80 ( (primitive.getOcclusionMaskInternal() & otherPrimitive.getCollisionMaskInternal()) == 0))
81 return false;
83 // Test time
84 if ( (!primitive.checkTestTime (testTime, maxTestIteration)) || (!otherPrimitive.checkTestTime (testTime, maxTestIteration)) )
85 return false;
87 // Clear time min time max
88 firstContactTime=FLT_MAX;
89 lastContactTime=-FLT_MAX;
91 // Switch the good test
92 switch (primitive.getPrimitiveTypeInternal())
95 // Static box over...
96 case UMovePrimitive::_2DOrientedBox:
98 // Switch second type
99 switch (otherPrimitive.getPrimitiveTypeInternal())
102 // Static box over movable box
103 case UMovePrimitive::_2DOrientedBox:
104 // Make the test
105 return evalCollisionOBoverOB (other, desc, timeMin, timeMax, firstContactTime, lastContactTime, primitive, otherPrimitive);
107 // Static box over movable cylinder
108 case UMovePrimitive::_2DOrientedCylinder:
109 // Make the test
110 return evalCollisionOBoverOC (other, desc, timeMin, timeMax, firstContactTime, lastContactTime, primitive, otherPrimitive);
112 default:
113 // Should not go here
114 nlstop;
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:
128 // Make the test
129 bool collid=other.evalCollisionOBoverOC (*this, desc, timeMin, timeMax, firstContactTime, lastContactTime, otherPrimitive,
130 primitive);
131 if (collid)
132 desc.XChgContactNormals ();
133 return collid;
136 // Static box over movable cylinder
137 case UMovePrimitive::_2DOrientedCylinder:
138 // Make the test
139 return evalCollisionOCoverOC (other, desc, timeMin, timeMax, firstContactTime, lastContactTime, primitive, otherPrimitive);
141 default:
142 // Should not go here
143 nlstop;
147 default:
148 // Should not go here
149 nlstop;
152 return false;
155 // ***************************************************************************
157 const TCollisionSurfaceDescVector *CPrimitiveWorldImage::evalCollision (CGlobalRetriever &retriever, CCollisionSurfaceTemp& surfaceTemp,
158 uint32 testTime, uint32 maxTestIteration, CMovePrimitive& primitive)
160 // H_AUTO(PACS_PWI_evalCollision_short);
162 // Test time
163 if (!primitive.checkTestTime (testTime, maxTestIteration))
164 return NULL;
166 // Switch the good test
167 if (primitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox)
169 // Local I
170 CVector locI ((float)(_OBData.EdgeDirectionX[0]*primitive.getLength(0)/2.0), (float)(_OBData.EdgeDirectionY[0]*primitive.getLength(1)/2.0), 0);
172 // Local J
173 CVector locJ ((float)(_OBData.EdgeDirectionX[1]*primitive.getLength(0)/2.0), (float)(_OBData.EdgeDirectionY[1]*primitive.getLength(1)/2.0), 0);
175 // Test
176 return retriever.testBBoxMove (_Position.getGlobalPos (), _DeltaPosition, locI, locJ, surfaceTemp);
178 else
180 // Check
181 nlassert (primitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedCylinder);
183 // Test
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);
197 // Time to avance
198 double ratio;
199 if (finalMax!=originalMax)
200 ratio=(finalMax-_InitTime)/(originalMax-_InitTime);
201 else
202 ratio=1;
204 // Make the move
205 if (!keepZ)
207 _Position.setGlobalPos (retriever.doMove(_Position.getGlobalPos(), _DeltaPosition, (float)ratio, surfaceTemp, false), retriever);
209 else
211 _Position.setGlobalPosKeepZ(retriever.doMove(_Position.getGlobalPos(), _DeltaPosition, (float)ratio, surfaceTemp, false), retriever);
215 // Final position
216 _InitTime=finalMax;
219 // ***************************************************************************
221 void CPrimitiveWorldImage::doMove (double timeMax)
223 // H_AUTO(PACS_PWI_doMove_short);
225 // Make the move
226 _Position.setPos (_Position.getPos ()+_Speed*(timeMax-_InitTime));
228 // Final position
229 _InitTime=timeMax;
232 // ***************************************************************************
234 bool CPrimitiveWorldImage::evalCollisionOBoverOB (CPrimitiveWorldImage& other, CCollisionDesc& desc, double timeMin, double timeMax,
235 double &firstContactTime, double &lastContactTime, CMovePrimitive& primitive,
236 CMovePrimitive& otherPrimitive)
238 // Checks
239 nlassert (primitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox);
240 nlassert (otherPrimitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox);
242 // Find a collision
243 bool find=false;
245 // Best time
246 desc.ContactTime=FLT_MAX;
248 // Timemin
249 double _timeMax=-FLT_MAX;
251 // Check movable points over the edge
252 uint pt;
253 uint seg;
254 for (pt=0; pt<4; pt++)
255 for (seg=0; seg<4; seg++)
257 // Get collision time of the point over the segment
258 CCollisionDesc d;
259 if ( evalCollisionPoverS (other, d, pt, seg, primitive, otherPrimitive) )
261 // Find
262 find=true;
264 // Best time ?
265 if (d.ContactTime<desc.ContactTime)
267 // This is the new descriptor
268 desc=d;
271 // Best max time ?
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
285 CCollisionDesc d;
286 if (other.evalCollisionPoverS (*this, d, pt, seg, primitive, otherPrimitive))
288 // Find
289 find=true;
291 // Best time ?
292 if (d.ContactTime<desc.ContactTime)
294 // This is the new descriptor
295 desc=d;
298 // Best max time ?
299 if (d.ContactTime>_timeMax)
301 // This is the new max time
302 _timeMax=d.ContactTime;
307 if (find)
309 // First last contact time
310 firstContactTime=desc.ContactTime;
311 lastContactTime=_timeMax;
313 // Half time
314 //double halfTime = (_timeMax+desc.ContactTime)/2.0;
316 // Collision in the past ?
317 //if (timeMin > halfTime)
318 if (timeMin > _timeMax)
319 // yes, abort
320 return false;
322 // Collision not in the future ?
323 if (timeMax>desc.ContactTime)
325 // Clamp time
326 if (desc.ContactTime<timeMin)
327 desc.ContactTime=timeMin;
329 // yes, found it
330 return true;
334 // No collision found
335 return false;
338 // ***************************************************************************
340 bool CPrimitiveWorldImage::evalCollisionOBoverOC (CPrimitiveWorldImage& other, CCollisionDesc& desc, double timeMin, double timeMax,
341 double &firstContactTime, double &lastContactTime, CMovePrimitive& primitive,
342 CMovePrimitive& otherPrimitive)
344 // Checks
345 nlassert (primitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox);
346 nlassert (otherPrimitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedCylinder);
348 // Find a collision
349 bool find=false;
351 // Best time
352 desc.ContactTime=FLT_MAX;
354 // time min clip
355 double _timeMax = -FLT_MAX;
357 // Check movable points over the cylinder
358 uint pt;
359 for (pt=0; pt<4; pt++)
361 // Get collision time of the point over the segment
362 CCollisionDesc d;
363 double firstContactTime;
364 double lastContactTime;
365 if (evalCollisionPoverOC (other, d, pt, firstContactTime, lastContactTime, primitive, otherPrimitive))
367 // Found
368 find=true;
370 // Best time ?
371 if (firstContactTime<desc.ContactTime)
373 // This is the new descriptor
374 desc=d;
377 // Best max time ?
378 if (lastContactTime>_timeMax)
380 // New max time
381 _timeMax=lastContactTime;
386 // Check static points over the movable box
387 uint seg;
388 for (seg=0; seg<4; seg++)
390 // Get collision time of the point over the segment
391 CCollisionDesc d;
392 if (evalCollisionSoverOC (other, d, seg, primitive, otherPrimitive))
394 // Found
395 find=true;
397 // Best time ?
398 if (d.ContactTime<desc.ContactTime)
400 // This is the new descriptor
401 desc=d;
404 // Best max time ?
405 if (d.ContactTime>_timeMax)
407 // New max time
408 _timeMax=d.ContactTime;
413 if (find)
415 // First last contact time
416 firstContactTime=desc.ContactTime;
417 lastContactTime=_timeMax;
419 // Half time
420 //double halfTime = (_timeMax+desc.ContactTime)/2.0;
422 // Collision in the past ?
423 //if (timeMin > halfTime)
424 if (timeMin > _timeMax)
425 // yes, abort
426 return false;
428 // Collision not in the future ?
429 if (timeMax>desc.ContactTime)
431 // Clamp time
432 if (desc.ContactTime<timeMin)
433 desc.ContactTime=timeMin;
435 // yes, found it
436 return true;
440 // No collision found
441 return false;
444 // ***************************************************************************
446 bool CPrimitiveWorldImage::evalCollisionPoverS (CPrimitiveWorldImage& other, CCollisionDesc& desc, uint numPoint, uint numSeg,
447 CMovePrimitive& primitive, CMovePrimitive& otherPrimitive)
449 // Checks
450 nlassert (primitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox);
451 nlassert (otherPrimitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox);
453 // Some constants
454 const double normalSegX=other._OBData.EdgeDirectionY[numSeg];
455 const double normalSegY=-other._OBData.EdgeDirectionX[numSeg];
457 // Relative speed
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;
463 //if ( dotProd > 0 )
464 if ( dotProd != 0 )
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;
485 // Included ?
486 if ( ( length >= 0 ) && ( length <= otherPrimitive.getLength(numSeg&1) ) )
488 // 2d Collid checked... Now check height
490 // Pos Z
491 const double pointSegZ=other._3dInitPosition.z;
492 const double segPosZ= pointSegZ + other._Speed.z*time;
494 // Some constants
495 const double pointZ=_3dInitPosition.z;
496 const double ptPosZ= pointZ + _Speed.z*time;
498 // Included ?
499 if ( (ptPosZ <= segPosZ + otherPrimitive.getHeightInternal()) && (ptPosZ + primitive.getHeightInternal() >= segPosZ) )
501 // Ok Collision, fill the result
503 // Time
504 desc.ContactTime=time;
506 // Position
507 desc.ContactPosition.x=ptPosX;
508 desc.ContactPosition.y=ptPosY;
509 desc.ContactPosition.z=std::max (segPosZ, ptPosZ);
511 // Seg box normal
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;
519 // End
520 return true;
525 // No collision
526 return false;
529 // ***************************************************************************
531 inline uint secondDegree (double a, double b, double c, double& s0, double& s1)
533 double d=b*b-4.f*a*c;
534 if (d>0)
536 // sqrt d
537 d=(double)sqrt (d);
539 // 1 / 2a
540 a=0.5f/a;
542 // 2 solutions
543 s0 = (-b-d)*a;
544 s1 = (-b+d)*a;
546 return 2;
548 else if (d<0)
550 // No solution
551 return 0;
553 else
555 // 1 solution
556 s0 = -b/(2.f*a);
558 return 1;
562 // ***************************************************************************
564 bool CPrimitiveWorldImage::evalCollisionPoverOC (CPrimitiveWorldImage& other, CCollisionDesc& desc, uint numPoint,
565 double &firstContactTime, double &lastContactTime, CMovePrimitive& primitive,
566 CMovePrimitive& otherPrimitive)
568 // Checks
569 nlassert (primitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox);
570 nlassert (otherPrimitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedCylinder);
572 /* Point Equ:
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
583 * B = (v0 - v'0)
585 * Norm^2 (B)*t^2 + 2*(A.B)*t + Norm^2 (A) - R^2 = 0
587 * a = Norm^2 (B)
588 * b = 2*(A.B)
589 * c = Norm^2 (A) - R^2
591 * a*t^2 + b*t + c = 0
594 // Let's go
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;
600 // Eval system
601 double s0, s1;
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);
604 if (numSolution!=0)
606 // time
607 double time;
609 // Collision time
610 if (numSolution==1)
612 firstContactTime=s0;
613 lastContactTime=s0;
615 else
617 // First and last time
618 if (s0<s1)
620 firstContactTime=s0;
621 lastContactTime=s1;
623 else
625 firstContactTime=s1;
626 lastContactTime=s0;
629 time=firstContactTime;
631 // Pos Z
632 const double pointCylZ=other._3dInitPosition.z;
633 const double cylPosZ= pointCylZ + other._Speed.z*time;
635 // Some constants
636 const double pointZ=_3dInitPosition.z;
637 const double ptPosZ= pointZ + _Speed.z*time;
639 // Z Included ?
640 if ( (ptPosZ <= cylPosZ + otherPrimitive.getHeightInternal()) && (ptPosZ + primitive.getHeightInternal() >= cylPosZ) )
642 // Ok Collision, fill the result
644 // Time
645 desc.ContactTime=time;
647 // Point position
648 const double ptPosX= _OBData.PointPosX[numPoint] + _Speed.x*time;
649 const double ptPosY= _OBData.PointPosY[numPoint] + _Speed.y*time;
651 // Cylinder position
652 const double cylPosX= other._3dInitPosition.x + other._Speed.x*time;
653 const double cylPosY= other._3dInitPosition.y + other._Speed.y*time;
655 // Position
656 desc.ContactPosition.x=ptPosX;
657 desc.ContactPosition.y=ptPosY;
658 desc.ContactPosition.z=std::max (cylPosZ, ptPosZ);
660 // Cylinder normal
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;
669 // End
670 return true;
674 // No collision
675 return false;
678 // ***************************************************************************
680 bool CPrimitiveWorldImage::evalCollisionSoverOC (CPrimitiveWorldImage& other, CCollisionDesc& desc, uint numSeg, CMovePrimitive& primitive,
681 CMovePrimitive& otherPrimitive)
683 // Checks
684 nlassert (primitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedBox);
685 nlassert (otherPrimitive.getPrimitiveTypeInternal()==UMovePrimitive::_2DOrientedCylinder);
687 // Some constants
688 const double normalSegX=_OBData.EdgeDirectionY[numSeg];
689 const double normalSegY=-_OBData.EdgeDirectionX[numSeg];
691 // Relative speed
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;
697 //if ( dotProd < 0 )
698 if ( dotProd !=0 )
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;
723 // Included ?
724 if ( ( length >= 0 ) && ( length <= primitive.getLength (numSeg&1) ) )
726 // 2d Collid checked... Now check height
728 // Pos Z
729 const double segPosZ= _3dInitPosition.z + _Speed.z*time;
731 // Some constants
732 const double cylPosZ= other._3dInitPosition.z + other._Speed.z*time;
734 // Included ?
735 if ( (cylPosZ <= segPosZ + primitive.getHeightInternal() ) && (cylPosZ + otherPrimitive.getHeightInternal() >= segPosZ) )
737 // Ok Collision, fill the result
739 // Time
740 desc.ContactTime=time;
742 // Position
743 desc.ContactPosition.x=contactX;
744 desc.ContactPosition.y=contactY;
745 desc.ContactPosition.z=std::max (segPosZ, cylPosZ);
747 // Segment normal
748 desc.ContactNormal0.x=normalSegX;
749 desc.ContactNormal0.y=normalSegY;
750 desc.ContactNormal0.z=0;
752 // Seg box normal
753 desc.ContactNormal1.x=contactX-cylPosX;
754 desc.ContactNormal1.y=contactY-cylPosY;
755 desc.ContactNormal1.z=0;
756 desc.ContactNormal1.normalize ();
758 // End
759 return true;
764 // No collision
765 return false;
769 // ***************************************************************************
771 bool CPrimitiveWorldImage::evalCollisionOCoverOC (CPrimitiveWorldImage& other, CCollisionDesc& desc, double timeMin, double timeMax,
772 double &firstContactTime, double &lastContactTime, CMovePrimitive& primitive,
773 CMovePrimitive& otherPrimitive)
775 // Checks
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
791 * B = (v0 - v'0)
793 * Norm^2 (B)*t^2 + 2*(A.B)*t + Norm^2 (A) - (R + R')^2 = 0
795 * a = Norm^2 (B)
796 * b = 2*(A.B)
797 * c = Norm^2 (A) - (R + R')^2
799 * a*t^2 + b*t + c = 0
802 // Let's go
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;
808 // Eval system
809 double s0, s1;
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);
813 if (numSolution!=0)
815 // time
816 double _timeMin, _timeMax;
818 // Collision time
819 if (numSolution==1)
821 _timeMin=s0;
822 _timeMax=s0;
824 else
826 // Time min and max
827 if (s0>s1)
829 _timeMin=s1;
830 _timeMax=s0;
832 else
834 _timeMin=s0;
835 _timeMax=s1;
839 // half time
840 //const double halfTime=(_timeMin+_timeMax)/2.0;
842 // Conatct time
843 firstContactTime=_timeMin;
844 lastContactTime=_timeMax;
846 // Clip time
847 if ((timeMin<_timeMax)&&(_timeMin<timeMax))
849 // Some constants
850 const double cyl0Time= _timeMin;
851 const double pointCyl0Z=_3dInitPosition.z;
852 const double cyl0PosZ= pointCyl0Z + _Speed.z*cyl0Time;
854 // Pos Z
855 const double cyl1Time= _timeMin;
856 const double pointCyl1Z=other._3dInitPosition.z;
857 const double cyl1PosZ= pointCyl1Z + other._Speed.z * cyl1Time;
859 // Z Included ?
860 if ( (cyl0PosZ <= cyl1PosZ + otherPrimitive.getHeightInternal() ) && (cyl0PosZ + primitive.getHeightInternal() >= cyl1PosZ) )
862 // Ok Collision, fill the result
864 // Time
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 ();
881 // Contact position
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;
891 // End
892 return true;
897 // No collision
898 return false;
901 // ***************************************************************************
903 void CPrimitiveWorldImage::precalcPos (CMovePrimitive &primitive)
905 // Type of the primitive
906 uint type=primitive.getPrimitiveTypeInternal();
908 // Box ?
909 if (type==UMovePrimitive::_2DOrientedBox)
911 // Calc cosinus and sinus
912 double cosinus=(double)cos(_OBData.Orientation);
913 double sinus=(double)sin(_OBData.Orientation);
915 // Size
916 double halfWidth=primitive.getLength (0)/2;
917 double halfDepth=primitive.getLength (1)/2;
919 // First point
920 _OBData.PointPosX[0]=cosinus*(-halfWidth)-sinus*(-halfDepth)+_3dInitPosition.x;
921 _OBData.PointPosY[0]=sinus*(-halfWidth)+cosinus*(-halfDepth)+_3dInitPosition.y;
923 // Second point
924 _OBData.PointPosX[1]=cosinus*halfWidth-sinus*(-halfDepth)+_3dInitPosition.x;
925 _OBData.PointPosY[1]=sinus*halfWidth+cosinus*(-halfDepth)+_3dInitPosition.y;
927 // Third point
928 _OBData.PointPosX[2]=cosinus*halfWidth-sinus*halfDepth+_3dInitPosition.x;
929 _OBData.PointPosY[2]=sinus*halfWidth+cosinus*halfDepth+_3dInitPosition.y;
931 // Fourth point
932 _OBData.PointPosX[3]=cosinus*(-halfWidth)-sinus*halfDepth+_3dInitPosition.x;
933 _OBData.PointPosY[3]=sinus*(-halfWidth)+cosinus*halfDepth+_3dInitPosition.y;
935 // Direction
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 };
940 // Direction
941 uint i;
942 for (i=0; i<4; i++)
944 // Next index
945 uint next=(i+1)&3;
946 double oneOver=oneOverLength[i&1];
948 // New direction
949 _OBData.EdgeDirectionX[i]=(_OBData.PointPosX[next] - _OBData.PointPosX[i])*oneOver;
950 _OBData.EdgeDirectionY[i]=(_OBData.PointPosY[next] - _OBData.PointPosY[i])*oneOver;
953 else
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();
967 // Box ?
968 if (type==UMovePrimitive::_2DOrientedBox)
970 // Orientation index
971 sint orient= (sint)(256.f*_OBData.Orientation/(2.f*NLMISC::Pi));
972 orient&=0xff;
973 orient>>=6;
974 nlassert (orient>=0);
975 nlassert (orient<4);
977 // Compute coordinates
978 _BBXMin=FLT_MAX;
979 _BBYMin=FLT_MAX;
980 _BBXMax=-FLT_MAX;
981 _BBYMax=-FLT_MAX;
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);*/
1013 else
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)
1023 double tmp=_BBXMin;
1024 _BBXMin=_BBXMax;
1025 _BBXMax=tmp;
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)
1035 double tmp=_BBYMin;
1036 _BBYMin=_BBYMax;
1037 _BBYMax=tmp;
1039 _BBYMin-=primitive.getRadiusInternal();
1040 _BBYMax+=primitive.getRadiusInternal();
1043 // Delta position
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
1053 uint slot;
1054 for (slot=0; slot<4; slot++)
1056 // Empty ?
1057 if (_MoveElement[slot]==NULL)
1059 // Primitive center
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 ?
1069 if (cx<centerX)
1070 // In the left
1071 cell.linkFirstX (_MoveElement[slot]);
1072 else
1073 // In the right
1074 cell.linkLastX (_MoveElement[slot]);
1076 /*// Insert in left or right ?
1077 if (cy<centerY)
1078 // In the left
1079 cell.linkFirstY (_MoveElement[slot]);
1080 else
1081 // In the right
1082 cell.linkLastY (_MoveElement[slot]);*/
1084 // Move it
1085 cell.updateSortedLists (_MoveElement[slot], worldImage);
1087 // End
1088 break;
1093 // ***************************************************************************
1095 void CPrimitiveWorldImage::addMoveElementendOfList (CMoveCell& cell, uint16 x, uint16 y, CMovePrimitive *primitive,
1096 CMoveContainer &container)
1098 // Find a free place
1099 uint slot;
1100 for (slot=0; slot<4; slot++)
1102 // Empty ?
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;
1111 // In the right
1112 cell.linkLastX (_MoveElement[slot]);
1114 // End
1115 break;
1120 // ***************************************************************************
1122 void CPrimitiveWorldImage::removeMoveElement (uint i, CMoveContainer &container, uint8 worldImage)
1124 // Check
1125 nlassert (i<4);
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]);
1134 // Set to NULL
1135 _MoveElement[i]=NULL;
1138 // ***************************************************************************
1140 void CPrimitiveWorldImage::checkSortedList (uint8 worldImage)
1142 // For the 4 elements
1143 for (uint i=0; i<4; i++)
1145 // element here ?
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,
1161 bool secondConst)
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();
1169 // Overide collsion
1170 collision = collision && (primitive.isObstacle ()) && (otherPrimitive.isObstacle ());
1172 // Get the two mass
1173 float mass0 = primitive.getMass ();
1174 float mass1 = otherPrimitive.getMass ();
1176 // Energy sum
1177 double projSpeed0 = desc.ContactNormal1 * _Speed;
1178 double projSpeed1 = desc.ContactNormal0 * second._Speed;
1179 double energySum = (- mass0 * projSpeed0 - mass1 * projSpeed1 ) / 2.0;
1181 // Old position
1182 CVectorD collisionPosition=_3dInitPosition;
1183 collisionPosition+=_Speed*desc.ContactTime;
1185 // Calc new speed
1186 CVectorD newSpeed(0.0, 0.0, 0.0);
1188 // Obstacle ?
1189 if (collision)
1191 switch (firstReaction)
1193 case UMovePrimitive::Slide:
1194 // Remove projected speed
1195 newSpeed=_Speed - projSpeed0 * desc.ContactNormal1;
1197 // Reflexion speed
1198 newSpeed+=( primitive.getAttenuation()*energySum / mass0 ) * desc.ContactNormal1;
1199 break;
1200 case UMovePrimitive::Reflexion:
1201 // Remove projected speed
1202 newSpeed=_Speed - projSpeed0 * desc.ContactNormal1;
1204 // Reflexion speed
1205 newSpeed+=( primitive.getAttenuation()*energySum / mass0 ) * desc.ContactNormal1;
1206 break;
1207 case UMovePrimitive::Stop:
1208 newSpeed.set (0,0,0);
1209 break;
1210 case UMovePrimitive::DoNothing:
1211 newSpeed=_Speed;
1212 break;
1213 default: break;
1216 // Set new speed
1217 setSpeed (newSpeed, container, &primitive, worldImage);
1219 // New position at t=0
1220 if (retriever)
1222 // Make a domove in the Ben data
1223 double deltaDist= _DeltaPosition.norm();
1224 double deltaTime;
1225 if(deltaDist<0.000001)
1226 deltaTime= 0;
1227 else
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);
1238 // Position at t=0
1239 _3dInitPosition = _Position.getPos() - newSpeed * desc.ContactTime;
1241 // New init time
1242 _InitTime = desc.ContactTime;
1244 else
1246 // No retriever used
1247 _Position.setPos (collisionPosition);
1249 // Position at t=0
1250 _3dInitPosition = collisionPosition - newSpeed * desc.ContactTime;
1252 // New init time
1253 _InitTime = desc.ContactTime;
1256 // Dirt pos
1257 dirtPos (container, &primitive, worldImage);
1259 // ****** Second object
1261 // Is second object in a static world ?
1262 if (!secondConst)
1264 // Old position
1265 collisionPosition=second._3dInitPosition;
1266 collisionPosition+=second._Speed * desc.ContactTime;
1268 // Obstacle ?
1269 switch (secondReaction)
1271 case UMovePrimitive::Slide:
1272 // Remove projected speed
1273 newSpeed=second._Speed - projSpeed1 * desc.ContactNormal0;
1275 // Reflexion speed
1276 newSpeed+=( otherPrimitive.getAttenuation()*energySum / mass1 ) * desc.ContactNormal1;
1277 break;
1278 case UMovePrimitive::Reflexion:
1279 // Remove projected speed
1280 newSpeed=second._Speed - projSpeed1 * desc.ContactNormal0;
1282 // Reflexion speed
1283 newSpeed+=( otherPrimitive.getAttenuation()*energySum / mass1 ) * desc.ContactNormal0;
1284 break;
1285 case UMovePrimitive::Stop:
1286 newSpeed.set (0,0,0);
1287 break;
1288 case UMovePrimitive::DoNothing:
1289 newSpeed=second._Speed;
1290 break;
1291 default: break;
1294 // Set new speed
1295 second.setSpeed (newSpeed, container, &otherPrimitive, secondWorldImage);
1297 // New position at t=0
1298 if (retriever)
1300 // Make a domove in the Ben data
1301 double deltaDist= second._DeltaPosition.norm();
1302 double deltaTime;
1303 if(deltaDist==0)
1304 deltaTime= 0;
1305 else
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);
1315 // Position at t=0
1316 second._3dInitPosition = second._Position.getPos() - newSpeed * desc.ContactTime;
1318 // New init time
1319 second._InitTime = desc.ContactTime;
1321 else
1323 // No retriever used
1324 second._Position.setPos (collisionPosition);
1326 // Position at t=0
1327 second._3dInitPosition = collisionPosition - newSpeed * desc.ContactTime;
1329 // New init time
1330 second._InitTime = desc.ContactTime;
1333 // Dirt pos
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,
1343 uint8 worldImage)
1345 // H_AUTO(PACS_PWI_reaction_short);
1347 // Reaction type
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))
1356 // 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));
1363 // Reflexion ?
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));
1371 else
1373 // Stop ?
1374 if (type==UMovePrimitive::Stop)
1376 _Speed.set (0,0,0);
1380 // Contact time
1381 double contactTime=surfaceDesc.ContactTime;
1383 // Init position
1384 _3dInitPosition = _Position.getPos() - _Speed * contactTime;
1386 // Set contactTime
1387 _InitTime=contactTime;
1389 // Dirt pos
1390 dirtPos (&container, &primitive, worldImage);
1393 // ***************************************************************************
1395 void CPrimitiveWorldImage::setGlobalPosition (const UGlobalPosition& pos, CMoveContainer& container, CMovePrimitive &primitive, uint8 worldImage)
1397 // Cast type
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());
1405 // Get the pos
1406 _Position.setGlobalPos (pos, *cont->getGlobalRetriever());
1408 // Precalc some values
1409 _3dInitPosition = _Position.getPos ();
1410 _InitTime = 0;
1412 // Speed NULL
1413 _Speed=CVector::Null;
1415 // Dirt BB
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*/)
1423 // Cast type
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
1431 if (retriever)
1433 // Get a cvector
1434 // CVector vect=pos; // better with CVectorD
1436 // Get global position
1437 UGlobalPosition globalPosition=retriever->retrievePosition (pos, 1.0e10, type);
1439 if (keepZ)
1441 // Set the position
1442 _Position.setPos (pos);
1444 // Set global position
1445 _Position.setGlobalPosKeepZ (globalPosition, *retriever);
1447 else
1449 // Set global position
1450 _Position.setGlobalPos (globalPosition, *retriever);
1453 else
1455 // Set the position
1456 _Position.setPos (pos);
1459 // Precalc some values
1460 _3dInitPosition = _Position.getPos ();
1461 _InitTime = 0;
1463 // Speed NULL
1464 _Speed=CVector::Null;
1466 // Dirt BB
1467 dirtPos (&container, &primitive, worldImage);
1470 // ***************************************************************************
1472 void CPrimitiveWorldImage::move (const NLMISC::CVectorD& speed, CMoveContainer& container, CMovePrimitive &primitive, uint8 worldImage)
1474 // New speed
1475 setSpeed (speed, &container, &primitive, worldImage);
1477 // Set initial position
1478 _3dInitPosition = _Position.getPos ();
1480 // Set initial time
1481 _InitTime = 0;
1483 // Dirt BB
1484 dirtPos (&container, &primitive, worldImage);
1487 // ***************************************************************************
1490 } // NLPACS