ode/src/heightfield.cpp
changeset 0 2f259fa3e83a
equal deleted inserted replaced
-1:000000000000 0:2f259fa3e83a
       
     1 // dHeightfield Collider
       
     2 //  Paul Cheyrou-Lagreze aka Tuan Kuranes 2006 Speed enhancements http://www.pop-3d.com
       
     3 //  Martijn Buijs 2006 http://home.planet.nl/~buijs512/
       
     4 // Based on Terrain & Cone contrib by:
       
     5 //  Benoit CHAPEROT 2003-2004 http://www.jstarlab.com
       
     6 //  Some code inspired by Magic Software
       
     7 
       
     8 
       
     9 #include <ode/common.h>
       
    10 #include <ode/collision.h>
       
    11 #include <ode/matrix.h>
       
    12 #include <ode/rotation.h>
       
    13 #include <ode/odemath.h>
       
    14 #include "collision_kernel.h"
       
    15 #include "collision_std.h"
       
    16 #include "collision_util.h"
       
    17 #include "heightfield.h"
       
    18 
       
    19 #define TERRAINTOL REAL(0.0f)
       
    20 
       
    21 #define dMIN(A,B)  ((A)>(B) ? B : A)
       
    22 #define dMAX(A,B)  ((A)>(B) ? A : B)
       
    23 
       
    24 
       
    25 // Three-way MIN and MAX
       
    26 #define dMIN3(A,B,C)	( (A)<(B) ? dMIN((A),(C)) : dMIN((B),(C)) )
       
    27 #define dMAX3(A,B,C)	( (A)>(B) ? dMAX((A),(C)) : dMAX((B),(C)) )
       
    28 
       
    29 #define dOPESIGN(a, op1, op2,b) \
       
    30     (a)[0] op1 op2 ((b)[0]); \
       
    31     (a)[1] op1 op2 ((b)[1]); \
       
    32     (a)[2] op1 op2 ((b)[2]);
       
    33 
       
    34 #define dGeomRaySetNoNormalize(myRay, MyPoint, MyVector) {  \
       
    35     \
       
    36     dVector3Copy (MyPoint, myRay.final_posr->pos);   \
       
    37     myRay.final_posr->R[2] = MyVector[0];       \
       
    38     myRay.final_posr->R[6] = MyVector[1];       \
       
    39     myRay.final_posr->R[10] = MyVector[2];      \
       
    40     dGeomMoved (&myRay);                        \
       
    41             }
       
    42 
       
    43 #define dGeomPlaneSetNoNormalize(MyPlane, MyPlaneDef) { \
       
    44     \
       
    45     MyPlane->p[0] = MyPlaneDef[0];  \
       
    46     MyPlane->p[1] = MyPlaneDef[1];  \
       
    47     MyPlane->p[2] = MyPlaneDef[2];  \
       
    48     MyPlane->p[3] = MyPlaneDef[3];  \
       
    49     dGeomMoved (MyPlane);           \
       
    50                     }
       
    51 //////// dxHeightfieldData /////////////////////////////////////////////////////////////
       
    52 
       
    53 // dxHeightfieldData constructor
       
    54 dxHeightfieldData::dxHeightfieldData()
       
    55 {
       
    56     //
       
    57 }
       
    58 
       
    59 
       
    60 // build Heightfield data
       
    61 void dxHeightfieldData::SetData( int nWidthSamples, int nDepthSamples,
       
    62                                 dReal fWidth, dReal fDepth,
       
    63                                 dReal fScale, dReal fOffset, dReal fThickness,
       
    64                                 int bWrapMode )
       
    65 {
       
    66 
       
    67 
       
    68     // x,z bounds
       
    69     m_fWidth = fWidth;
       
    70     m_fDepth = fDepth;
       
    71 
       
    72     // cache half x,z bounds
       
    73     m_fHalfWidth = dDIV(fWidth,REAL( 2.0 ));
       
    74     m_fHalfDepth = dDIV(fDepth,REAL( 2.0 ));
       
    75 
       
    76     // scale and offset
       
    77     m_fScale = fScale;
       
    78     m_fOffset = fOffset;
       
    79 
       
    80     // infinite min height bounds
       
    81     m_fThickness = fThickness;
       
    82 
       
    83     // number of vertices per side
       
    84     m_nWidthSamples = nWidthSamples;
       
    85     m_nDepthSamples = nDepthSamples;
       
    86 
       
    87     m_fSampleWidth = m_fWidth / ( m_nWidthSamples - 1 );
       
    88     m_fSampleDepth = m_fDepth / ( m_nDepthSamples - 1 );
       
    89 
       
    90     m_fInvSampleWidth = dDIV(REAL(1.0),m_fSampleWidth);
       
    91     m_fInvSampleDepth = dDIV(REAL(1.0),m_fSampleDepth);
       
    92 
       
    93     // finite or repeated terrain?
       
    94     m_bWrapMode = bWrapMode;
       
    95 }
       
    96 
       
    97 
       
    98 // recomputes heights bounds
       
    99 void dxHeightfieldData::ComputeHeightBounds()
       
   100 {
       
   101     static int i;
       
   102     static dReal h;
       
   103     static dReal *data_float;
       
   104 
       
   105     data_float = (dReal*)m_pHeightData;
       
   106     m_fMinHeight = dInfinity;
       
   107     m_fMaxHeight = -dInfinity;
       
   108 
       
   109     for (i=0; i<m_nWidthSamples*m_nDepthSamples; i++)
       
   110     {
       
   111        h = data_float[i];
       
   112        if (h < m_fMinHeight)	m_fMinHeight = h;
       
   113        if (h > m_fMaxHeight)	m_fMaxHeight = h;
       
   114     }
       
   115 
       
   116     // scale and offset
       
   117     m_fMinHeight = dMUL(m_fMinHeight,m_fScale);
       
   118     m_fMaxHeight = dMUL(m_fMaxHeight,m_fScale);
       
   119     m_fMinHeight += m_fOffset;
       
   120     m_fMaxHeight += m_fOffset;
       
   121 
       
   122     // add thickness
       
   123     m_fMinHeight -= m_fThickness;
       
   124 }
       
   125 
       
   126 
       
   127 // returns whether point is over terrain Cell triangle?
       
   128 bool dxHeightfieldData::IsOnHeightfield  ( const dReal * const CellOrigin, const dReal * const pos,  const bool isABC) const
       
   129 {
       
   130     {
       
   131         const dReal MaxX = CellOrigin[0] + m_fSampleWidth;
       
   132         const dReal TolX = dMUL(m_fSampleWidth,TERRAINTOL);
       
   133         if ((pos[0]<CellOrigin[0]-TolX) || (pos[0]>MaxX+TolX))	
       
   134             return false;
       
   135     }
       
   136 
       
   137     {
       
   138         const dReal MaxZ = CellOrigin[2] + m_fSampleDepth;
       
   139         const dReal TolZ = dMUL(m_fSampleDepth,TERRAINTOL);
       
   140         if ((pos[2]<CellOrigin[2]-TolZ) || (pos[2]>MaxZ+TolZ))	
       
   141             return false;
       
   142     }
       
   143 
       
   144     // add X percentage position on cell and Z percentage position on cell
       
   145     const dReal pctTotal = dMUL((pos[0] - CellOrigin[0]),m_fInvSampleWidth )
       
   146         + dMUL((pos[2] - CellOrigin[2]),m_fInvSampleDepth);
       
   147 
       
   148     if (isABC)
       
   149     {
       
   150         if (pctTotal >= REAL(1.0) + TERRAINTOL)	
       
   151             return false;
       
   152         else	
       
   153             return true;
       
   154     }
       
   155     else if (pctTotal <= REAL(1.0) - TERRAINTOL)	
       
   156     {
       
   157         return false;
       
   158     }
       
   159     return true;
       
   160 }
       
   161 // returns whether point is over terrain Cell triangle?
       
   162 bool dxHeightfieldData::IsOnHeightfield2  ( const dReal * const CellOrigin, const dReal * const pos,  const bool isABC) const
       
   163 {
       
   164     dReal MaxX, MinX;
       
   165     dReal MaxZ, MinZ;
       
   166     if (isABC)
       
   167     {
       
   168         // point A
       
   169         MinX = CellOrigin[0];
       
   170         MaxX = CellOrigin[0] + m_fSampleWidth;
       
   171 
       
   172         MinZ = CellOrigin[2];
       
   173         MaxZ = CellOrigin[2] + m_fSampleDepth;
       
   174     }
       
   175     else
       
   176     {
       
   177         // point D
       
   178         MinX = CellOrigin[0] - m_fSampleWidth;
       
   179         MaxX = CellOrigin[0];
       
   180 
       
   181         MinZ = CellOrigin[2] - m_fSampleDepth;
       
   182         MaxZ = CellOrigin[2];
       
   183     }
       
   184 
       
   185     // check if inside CELL
       
   186     {
       
   187         const dReal TolX = dMUL(m_fSampleWidth,TERRAINTOL);
       
   188         if ((pos[0]<MinX-TolX) || (pos[0]>MaxX+TolX))	
       
   189             return false;
       
   190     }
       
   191 
       
   192     {
       
   193         const dReal TolZ = dMUL(m_fSampleDepth,TERRAINTOL);
       
   194         if ((pos[2]<MinZ-TolZ) || (pos[2]>MaxZ+TolZ))	
       
   195             return false;
       
   196     }
       
   197 
       
   198     // Sum up X percentage position on cell and Z percentage position on cell
       
   199     const dReal pctTotal = dMUL((pos[0] - MinX),m_fInvSampleWidth) 
       
   200         + dMUL((pos[2] - MinZ),m_fInvSampleDepth);
       
   201 
       
   202     // check if inside respective Triangle of Cell
       
   203     if (isABC)	
       
   204     {
       
   205         if (pctTotal >= REAL(1.0) + TERRAINTOL)	
       
   206             return false;
       
   207         else	
       
   208             return true;
       
   209     }
       
   210     else if (pctTotal <= REAL(1.0) - TERRAINTOL)	
       
   211     {
       
   212         return false;
       
   213     }
       
   214     return true;
       
   215 }
       
   216 
       
   217 
       
   218 // returns height at given sample coordinates
       
   219 dReal dxHeightfieldData::GetHeight( int x, int z )
       
   220 {
       
   221     static dReal h;
       
   222     static dReal *data_float;
       
   223 
       
   224     if ( m_bWrapMode == 0 )
       
   225     {
       
   226         // Finite
       
   227         if ( x < 0 ) x = 0;
       
   228         if ( z < 0 ) z = 0;
       
   229         if ( x > m_nWidthSamples - 1 ) x = m_nWidthSamples - 1;
       
   230         if ( z > m_nDepthSamples - 1 ) z = m_nDepthSamples - 1;
       
   231     }
       
   232     else
       
   233     {
       
   234         // Infinite
       
   235         x %= m_nWidthSamples - 1;
       
   236         z %= m_nDepthSamples - 1;
       
   237         if ( x < 0 ) x += m_nWidthSamples - 1;
       
   238         if ( z < 0 ) z += m_nDepthSamples - 1;
       
   239     }
       
   240 
       
   241     data_float = (dReal*)m_pHeightData;
       
   242     h = data_float[x+(z * m_nWidthSamples)];
       
   243 
       
   244     return dMUL(h,m_fScale) + m_fOffset;
       
   245 }
       
   246 
       
   247 
       
   248 // returns height at given coordinates
       
   249 dReal dxHeightfieldData::GetHeight( dReal x, dReal z )
       
   250 {
       
   251     int nX	= dMUL( x,m_fInvSampleWidth )>>QFACTOR;
       
   252     int nZ	= dMUL( z,m_fInvSampleDepth )>>QFACTOR;
       
   253 
       
   254     dReal dx = dMUL(( x - ( nX * m_fSampleWidth ) ),m_fInvSampleWidth);
       
   255     dReal dz = dMUL(( z - ( nZ * m_fSampleDepth ) ),m_fInvSampleDepth);
       
   256 
       
   257 
       
   258 
       
   259     dReal y, y0;
       
   260 
       
   261     if ( dx + dz < REAL( 1.0 ) )
       
   262     {
       
   263         y0 = GetHeight( nX, nZ );
       
   264 
       
   265         y = y0 + dMUL(( GetHeight( nX + 1, nZ ) - y0 ),dx)
       
   266             + dMUL(( GetHeight( nX, nZ + 1 ) - y0 ),dz);
       
   267     }
       
   268     else
       
   269     {
       
   270         y0 = GetHeight( nX + 1, nZ + 1 );
       
   271 
       
   272         y = y0	+ dMUL(( GetHeight( nX + 1, nZ ) - y0 ),( REAL(1.0f) - dz )) +
       
   273             dMUL(( GetHeight( nX, nZ + 1 ) - y0 ),( REAL(1.0f) - dx ));
       
   274     }
       
   275 
       
   276     return y;
       
   277 }
       
   278 
       
   279 
       
   280 // dxHeightfieldData destructor
       
   281 dxHeightfieldData::~dxHeightfieldData()
       
   282 {
       
   283     static dReal *data_float;
       
   284 
       
   285 
       
   286     if ( m_bCopyHeightData )
       
   287     {
       
   288         data_float = (dReal*)m_pHeightData;
       
   289         delete [] data_float;     
       
   290     }
       
   291 }
       
   292 
       
   293 
       
   294 //////// dxHeightfield /////////////////////////////////////////////////////////////////
       
   295 
       
   296 
       
   297 // dxHeightfield constructor
       
   298 dxHeightfield::dxHeightfield( dSpaceID space,
       
   299                              dHeightfieldDataID data,
       
   300                              int bPlaceable )			:
       
   301     dxGeom( space, bPlaceable ),
       
   302     tempPlaneBuffer(0),
       
   303     tempPlaneBufferSize(0),
       
   304     tempTriangleBuffer(0),
       
   305     tempTriangleBufferSize(0),
       
   306     tempHeightBuffer(0),
       
   307     tempHeightBufferSizeX(0),
       
   308     tempHeightBufferSizeZ(0)
       
   309 {
       
   310     type = dHeightfieldClass;
       
   311     this->m_p_data = data;
       
   312 }
       
   313 
       
   314 
       
   315 // compute axis aligned bounding box
       
   316 void dxHeightfield::computeAABB()
       
   317 {
       
   318     const dxHeightfieldData *d = m_p_data;
       
   319 
       
   320     if ( d->m_bWrapMode == 0 )
       
   321     {
       
   322         // Finite
       
   323         if ( gflags & GEOM_PLACEABLE )
       
   324         {
       
   325             dReal dx[6], dy[6], dz[6];
       
   326 
       
   327             // Y-axis
       
   328             dy[0] = dMUL( final_posr->R[ 1],d->m_fMinHeight );
       
   329             dy[1] = dMUL( final_posr->R[ 5],d->m_fMinHeight );
       
   330             dy[2] = dMUL( final_posr->R[ 9],d->m_fMinHeight );
       
   331             dy[3] = dMUL( final_posr->R[ 1],d->m_fMaxHeight );
       
   332             dy[4] = dMUL( final_posr->R[ 5],d->m_fMaxHeight );
       
   333             dy[5] = dMUL( final_posr->R[ 9],d->m_fMaxHeight );
       
   334 
       
   335 
       
   336             // X-axis
       
   337             dx[0] = dMUL( final_posr->R[ 0],-d->m_fHalfWidth );
       
   338             dx[1] = dMUL( final_posr->R[ 4],-d->m_fHalfWidth );
       
   339             dx[2] = dMUL( final_posr->R[ 8],-d->m_fHalfWidth );
       
   340             dx[3] = dMUL( final_posr->R[ 0],d->m_fHalfWidth );
       
   341             dx[4] = dMUL( final_posr->R[ 4],d->m_fHalfWidth );
       
   342             dx[5] = dMUL( final_posr->R[ 8],d->m_fHalfWidth );
       
   343 
       
   344             // Z-axis
       
   345             dz[0] = dMUL( final_posr->R[ 2],-d->m_fHalfDepth );
       
   346             dz[1] = dMUL( final_posr->R[ 6],-d->m_fHalfDepth );
       
   347             dz[2] = dMUL( final_posr->R[10],-d->m_fHalfDepth );
       
   348             dz[3] = dMUL( final_posr->R[ 2],d->m_fHalfDepth );
       
   349             dz[4] = dMUL( final_posr->R[ 6],d->m_fHalfDepth );
       
   350             dz[5] = dMUL( final_posr->R[10],d->m_fHalfDepth );
       
   351 
       
   352 
       
   353             // X extents
       
   354             aabb[0] = final_posr->pos[0] +
       
   355                 dMIN3( dMIN( dx[0], dx[3] ), dMIN( dy[0], dy[3] ), dMIN( dz[0], dz[3] ) );
       
   356             aabb[1] = final_posr->pos[0] +
       
   357                 dMAX3( dMAX( dx[0], dx[3] ), dMAX( dy[0], dy[3] ), dMAX( dz[0], dz[3] ) );
       
   358 
       
   359             // Y extents
       
   360             aabb[2] = final_posr->pos[1] +
       
   361                 dMIN3( dMIN( dx[1], dx[4] ), dMIN( dy[1], dy[4] ), dMIN( dz[1], dz[4] ) );
       
   362             aabb[3] = final_posr->pos[1] +
       
   363                 dMAX3( dMAX( dx[1], dx[4] ), dMAX( dy[1], dy[4] ), dMAX( dz[1], dz[4] ) );
       
   364 
       
   365             // Z extents
       
   366             aabb[4] = final_posr->pos[2] +
       
   367                 dMIN3( dMIN( dx[2], dx[5] ), dMIN( dy[2], dy[5] ), dMIN( dz[2], dz[5] ) );
       
   368             aabb[5] = final_posr->pos[2] +
       
   369                 dMAX3( dMAX( dx[2], dx[5] ), dMAX( dy[2], dy[5] ), dMAX( dz[2], dz[5] ) );
       
   370         }
       
   371         else
       
   372         {
       
   373 
       
   374             aabb[0] = -d->m_fHalfWidth;		aabb[1] = +d->m_fHalfWidth;
       
   375             aabb[2] = d->m_fMinHeight;		aabb[3] = d->m_fMaxHeight;
       
   376             aabb[4] = -d->m_fHalfDepth;		aabb[5] = +d->m_fHalfDepth;
       
   377 
       
   378 
       
   379         }
       
   380     }
       
   381     else
       
   382     {
       
   383         // Infinite
       
   384         if ( gflags & GEOM_PLACEABLE )
       
   385         {
       
   386             aabb[0] = -dInfinity;			aabb[1] = +dInfinity;
       
   387             aabb[2] = -dInfinity;			aabb[3] = +dInfinity;
       
   388             aabb[4] = -dInfinity;			aabb[5] = +dInfinity;
       
   389         }
       
   390         else
       
   391         {
       
   392             aabb[0] = -dInfinity;			aabb[1] = +dInfinity;
       
   393             aabb[2] = d->m_fMinHeight;		aabb[3] = d->m_fMaxHeight;
       
   394             aabb[4] = -dInfinity;			aabb[5] = +dInfinity;
       
   395         }
       
   396     }
       
   397 
       
   398 }
       
   399 
       
   400 
       
   401 // dxHeightfield destructor
       
   402 dxHeightfield::~dxHeightfield()
       
   403 {
       
   404     delete [] tempTriangleBuffer;
       
   405 
       
   406     for (unsigned int k = 0; k < tempPlaneBufferSize; k++)
       
   407     {
       
   408         delete tempPlaneBuffer[k];
       
   409     }
       
   410     delete [] tempPlaneBuffer;
       
   411 
       
   412     resetHeightBuffer();
       
   413 }
       
   414 
       
   415 void dxHeightfield::resetHeightBuffer()
       
   416 {
       
   417     const size_t xSize = tempHeightBufferSizeX;
       
   418     for (size_t x = 0; xSize < x; x++)
       
   419     {
       
   420         delete [] tempHeightBuffer[x];
       
   421     }
       
   422     delete [] tempHeightBuffer;
       
   423 }
       
   424 //////// Heightfield data interface ////////////////////////////////////////////////////
       
   425 
       
   426 
       
   427 EXPORT_C dHeightfieldDataID dGeomHeightfieldDataCreate()
       
   428 {
       
   429     return new dxHeightfieldData();
       
   430 }
       
   431 
       
   432 
       
   433 EXPORT_C void dGeomHeightfieldDataBuildCallback( dHeightfieldDataID d,
       
   434                                        void* pUserData, dHeightfieldGetHeight* pCallback,
       
   435                                        dReal width, dReal depth, int widthSamples, int depthSamples,
       
   436                                        dReal scale, dReal offset, dReal thickness, int bWrap )
       
   437 {
       
   438 
       
   439 
       
   440     // callback
       
   441     d->m_nGetHeightMode = 0;
       
   442     d->m_pUserData = pUserData;
       
   443     d->m_pGetHeightCallback = pCallback;
       
   444 
       
   445     // set info
       
   446     d->SetData( widthSamples, depthSamples, width, depth, scale, offset, thickness, bWrap );
       
   447 
       
   448     // default bounds
       
   449     d->m_fMinHeight = -dInfinity;
       
   450     d->m_fMaxHeight = dInfinity;
       
   451 }
       
   452 
       
   453 EXPORT_C void dGeomHeightfieldDataBuildSingle( dHeightfieldDataID d,
       
   454                                      const float *pHeightData, int bCopyHeightData,
       
   455                                      dReal width, dReal depth, int widthSamples, int depthSamples,
       
   456                                      dReal scale, dReal offset, dReal thickness, int bWrap )
       
   457 {
       
   458 
       
   459 
       
   460     // set info
       
   461     d->SetData( widthSamples, depthSamples, width, depth, scale, offset, thickness, bWrap );
       
   462     d->m_nGetHeightMode = 3;
       
   463     d->m_bCopyHeightData = bCopyHeightData;
       
   464 
       
   465     if ( d->m_bCopyHeightData == 0 )
       
   466     {
       
   467         // Data is referenced only.
       
   468         d->m_pHeightData = pHeightData;
       
   469     }
       
   470     else
       
   471     {
       
   472         // We own the height data, allocate storage
       
   473         d->m_pHeightData = new dReal[ d->m_nWidthSamples * d->m_nDepthSamples ];
       
   474 
       
   475 
       
   476         // Copy data.
       
   477         memcpy( (void*)d->m_pHeightData, pHeightData,
       
   478             sizeof( dReal ) * d->m_nWidthSamples * d->m_nDepthSamples );
       
   479     }
       
   480 
       
   481     // Find height bounds
       
   482     d->ComputeHeightBounds();
       
   483 }
       
   484 
       
   485 
       
   486 EXPORT_C void dGeomHeightfieldDataSetBounds( dHeightfieldDataID d, dReal minHeight, dReal maxHeight )
       
   487 {
       
   488 
       
   489     d->m_fMinHeight = dMUL( minHeight,d->m_fScale ) + d->m_fOffset - d->m_fThickness;
       
   490     d->m_fMaxHeight = dMUL( maxHeight,d->m_fScale ) + d->m_fOffset;
       
   491 }
       
   492 
       
   493 
       
   494 EXPORT_C void dGeomHeightfieldDataDestroy( dHeightfieldDataID d )
       
   495 {
       
   496     delete d;
       
   497 }
       
   498 
       
   499 
       
   500 //////// Heightfield geom interface ////////////////////////////////////////////////////
       
   501 
       
   502 
       
   503 EXPORT_C dGeomID dCreateHeightfield( dSpaceID space, dHeightfieldDataID data, int bPlaceable )
       
   504 {
       
   505     return new dxHeightfield( space, data, bPlaceable );
       
   506 }
       
   507 
       
   508 
       
   509 EXPORT_C void dGeomHeightfieldSetHeightfieldData( dGeomID g, dHeightfieldDataID d )
       
   510 {
       
   511     dxHeightfield* geom = (dxHeightfield*) g;
       
   512     geom->data = d;
       
   513 }
       
   514 
       
   515 
       
   516 EXPORT_C dHeightfieldDataID dGeomHeightfieldGetHeightfieldData( dGeomID g )
       
   517 {
       
   518     dxHeightfield* geom = (dxHeightfield*) g;
       
   519     return geom->m_p_data;
       
   520 }
       
   521 
       
   522 //////// dxHeightfield /////////////////////////////////////////////////////////////////
       
   523 
       
   524 
       
   525 // Typedef for generic 'get point depth' function
       
   526 typedef dReal dGetDepthFn( dGeomID g, dReal x, dReal y, dReal z );
       
   527 
       
   528 
       
   529 
       
   530 static inline bool DescendingPlaneSort(const HeightFieldPlane * const A, const HeightFieldPlane * const B)
       
   531 {
       
   532     return ((A->maxAAAB - B->maxAAAB) > dEpsilon);
       
   533 }
       
   534 
       
   535 void dxHeightfield::sortPlanes(const size_t numPlanes)
       
   536 {
       
   537     bool has_swapped = true;
       
   538     do
       
   539     {
       
   540         has_swapped = false;//reset flag
       
   541         for (size_t i = 0; i < numPlanes - 1; i++)
       
   542         {
       
   543             //if they are in the wrong order
       
   544             if (DescendingPlaneSort(tempPlaneBuffer[i], tempPlaneBuffer[i + 1]))
       
   545             { 
       
   546                 //exchange them
       
   547                 HeightFieldPlane * tempPlane = tempPlaneBuffer[i];
       
   548                 tempPlaneBuffer[i] = tempPlaneBuffer[i + 1];
       
   549                 tempPlaneBuffer[i + 1] = tempPlane;
       
   550 
       
   551                 //we have swapped at least once, list may not be sorted yet
       
   552                 has_swapped = true;
       
   553             }
       
   554         }
       
   555     }    //if no swaps were made during this pass, the list has been sorted
       
   556     while (has_swapped);
       
   557 }
       
   558 
       
   559 int dxHeightfield::dCollideHeightfieldZone( const int minX, const int maxX, const int minZ, const int maxZ, 
       
   560                                            dxGeom* o2, const int numMaxContactsPossible,
       
   561                                            int flags, dContactGeom* contact, 
       
   562                                            int skip )
       
   563 {
       
   564 	dContactGeom *pContact = 0;
       
   565     int  x, z;
       
   566     // check if not above or inside terrain first
       
   567     // while filling a heightmap partial temporary buffer
       
   568     const unsigned int numX = (maxX - minX) + 1;
       
   569     const unsigned int numZ = (maxZ - minZ) + 1;
       
   570     const dReal minO2Height = o2->aabb[2];
       
   571     const dReal maxO2Height = o2->aabb[3];
       
   572     unsigned int x_local, z_local;
       
   573     dReal maxY = - dInfinity;
       
   574     dReal minY = dInfinity;
       
   575     // localize and const for faster access
       
   576     const dReal cfSampleWidth = m_p_data->m_fSampleWidth;
       
   577     const dReal cfSampleDepth = m_p_data->m_fSampleDepth;
       
   578     {
       
   579         if (tempHeightBufferSizeX < numX || tempHeightBufferSizeZ < numZ)
       
   580         {
       
   581             resetHeightBuffer();
       
   582             tempHeightBufferSizeX = numX;
       
   583             tempHeightBufferSizeZ = numZ;
       
   584             tempHeightBuffer = new HeightFieldVertex *[numX];
       
   585             for ( x_local = 0; x_local < numX; x_local++)
       
   586             {
       
   587                 tempHeightBuffer[x_local] = new HeightFieldVertex [numZ];     
       
   588             }
       
   589         }
       
   590 
       
   591         dReal Xpos, Ypos;
       
   592         Xpos = minX*cfSampleWidth;
       
   593 
       
   594 
       
   595         for ( x = minX, x_local = 0; x_local < numX; x++, x_local++)
       
   596         {
       
   597             const dReal c_Xpos = Xpos;
       
   598             HeightFieldVertex *HeightFieldRow = tempHeightBuffer[x_local];
       
   599             Ypos = minZ * cfSampleDepth;
       
   600             for ( z = minZ, z_local = 0; z_local < numZ; z++, z_local++)
       
   601             {
       
   602                 const dReal h = m_p_data->GetHeight(x, z);
       
   603                 HeightFieldRow[z_local].vertex[0] = c_Xpos;
       
   604                 HeightFieldRow[z_local].vertex[1] = h;
       
   605                 HeightFieldRow[z_local].vertex[2] = Ypos;
       
   606                 
       
   607 
       
   608                 maxY = dMAX(maxY, h);
       
   609                 minY = dMIN(minY, h);
       
   610 
       
   611 
       
   612                 Ypos += cfSampleDepth;
       
   613             }
       
   614             Xpos += cfSampleWidth;
       
   615         }
       
   616         if (minO2Height - maxY > -dEpsilon )
       
   617         {
       
   618 			//totally above heightfield
       
   619             return 0;
       
   620         }
       
   621 		if (minY - maxO2Height > -dEpsilon )
       
   622 		{
       
   623 			// totally under heightfield
       
   624 			pContact = CONTACT(contact, 0);
       
   625 
       
   626 			pContact->pos[0] = o2->final_posr->pos[0];
       
   627 			pContact->pos[1] = minY;
       
   628 			pContact->pos[2] = o2->final_posr->pos[2];
       
   629 
       
   630 			pContact->normal[0] = 0;
       
   631 			pContact->normal[1] = REAL(-1.0);
       
   632 			pContact->normal[2] = 0;
       
   633 
       
   634 			pContact->depth =  minY - maxO2Height;
       
   635 
       
   636 			return 1;
       
   637 		}
       
   638     }
       
   639     int numTerrainContacts = 0;
       
   640     // get All Planes that could collide against.
       
   641     dColliderFn *geomRayNCollider = 0;
       
   642     dColliderFn *geomNPlaneCollider = 0;
       
   643     dGetDepthFn *geomNDepthGetter = 0;
       
   644 
       
   645     int max_collisionContact = numMaxContactsPossible;
       
   646     switch (o2->type)
       
   647     {
       
   648     case dRayClass:
       
   649         geomRayNCollider		= NULL;
       
   650         geomNPlaneCollider	    = dCollideRayPlane;
       
   651         geomNDepthGetter		= NULL;
       
   652         //max_collisionContact    = 1;
       
   653         break;
       
   654 
       
   655     case dSphereClass:
       
   656         geomRayNCollider		= dCollideRaySphere;
       
   657         geomNPlaneCollider  	= dCollideSpherePlane;
       
   658         geomNDepthGetter		= dGeomSpherePointDepth;
       
   659         //max_collisionContact    = 3;
       
   660         break;
       
   661 
       
   662     case dBoxClass:
       
   663         geomRayNCollider		= dCollideRayBox;
       
   664         geomNPlaneCollider	    = dCollideBoxPlane;
       
   665         geomNDepthGetter		= dGeomBoxPointDepth;
       
   666         //max_collisionContact    = 8;
       
   667         break;
       
   668 
       
   669     case dCapsuleClass:
       
   670         geomRayNCollider		= dCollideRayCapsule;
       
   671         geomNPlaneCollider  	= dCollideCapsulePlane;
       
   672         geomNDepthGetter		= dGeomCapsulePointDepth;
       
   673         // max_collisionContact    = 3;
       
   674         break;
       
   675 
       
   676     case dCylinderClass:
       
   677         geomRayNCollider		= dCollideRayCylinder;
       
   678         geomNPlaneCollider	    = dCollideCylinderPlane;
       
   679         geomNDepthGetter		= NULL;// TODO: dGeomCCylinderPointDepth
       
   680         //max_collisionContact    = 3;
       
   681         break;
       
   682 
       
   683     case dConvexClass:
       
   684         geomRayNCollider		= dCollideRayConvex;
       
   685         geomNPlaneCollider  	= dCollideConvexPlane;
       
   686         geomNDepthGetter		= NULL;// TODO: dGeomConvexPointDepth;
       
   687         //max_collisionContact    = 3;
       
   688         break;
       
   689 
       
   690     default:
       
   691         	// Shouldn't ever get here.
       
   692         break;
       
   693 
       
   694     }
       
   695 
       
   696 
       
   697     const int numMaxContacts = dMIN (max_collisionContact, HEIGHTFIELDMAXCONTACTPERCELL);
       
   698     
       
   699     dxPlane myplane(0,0,0,0,0);
       
   700     dxPlane* sliding_plane = &myplane;
       
   701     dContactGeom *PlaneContact = m_p_data->m_contacts;    
       
   702     flags = (flags & 0xffff0000) | HEIGHTFIELDMAXCONTACTPERCELL;
       
   703     dReal triplane[4];
       
   704     int i;
       
   705 
       
   706     // check some trivial case.
       
   707     // Vector Up plane
       
   708     if (maxY - minY < dEpsilon)
       
   709     {
       
   710         // it's a single plane.
       
   711         triplane[0] = 0;
       
   712         triplane[1] = REAL(1.0);
       
   713         triplane[2] = 0;
       
   714         triplane[3] =  minY;
       
   715         dGeomPlaneSetNoNormalize (sliding_plane, triplane);
       
   716         // find collision and compute contact points
       
   717         const int numPlaneContacts = geomNPlaneCollider (o2, sliding_plane, flags, PlaneContact, sizeof(dContactGeom));
       
   718         for (i = 0; i < numPlaneContacts; i++)
       
   719         {
       
   720             pContact = CONTACT(contact, numTerrainContacts*skip);
       
   721             const dVector3 &pCPos = PlaneContact[i].pos;
       
   722             dVector3Copy (pCPos, pContact->pos);
       
   723             dOPESIGN(pContact->normal, =, -, triplane);
       
   724 
       
   725             pContact->depth = PlaneContact[i].depth;
       
   726             numTerrainContacts++;
       
   727             if (numTerrainContacts > numMaxContactsPossible)
       
   728                 break;
       
   729         }
       
   730         return numTerrainContacts;
       
   731     }
       
   732     // unique plane
       
   733     {
       
   734         // check for very simple plane heightfield
       
   735         dReal minXHeightDelta = dInfinity, maxXHeightDelta = - dInfinity;
       
   736         dReal minZHeightDelta = dInfinity, maxZHeightDelta = - dInfinity;
       
   737 
       
   738 
       
   739         dReal lastXHeight = tempHeightBuffer[0][0].vertex[1];
       
   740         for ( x_local = 1; x_local < numX; x_local++)
       
   741         {
       
   742             HeightFieldVertex *HeightFieldRow = tempHeightBuffer[x_local];
       
   743 
       
   744             const dReal deltaX = HeightFieldRow[0].vertex[1] - lastXHeight;
       
   745 
       
   746             maxXHeightDelta = dMAX (maxXHeightDelta,  deltaX);
       
   747             minXHeightDelta = dMIN (minXHeightDelta,  deltaX);
       
   748 
       
   749             dReal lastZHeight = HeightFieldRow[0].vertex[1];
       
   750             for ( z_local = 1; z_local < numZ; z_local++)
       
   751             {
       
   752                 const dReal deltaZ = (HeightFieldRow[z_local].vertex[1] - lastZHeight);
       
   753 
       
   754                 maxZHeightDelta = dMAX (maxZHeightDelta,  deltaZ);
       
   755                 minZHeightDelta = dMIN (minZHeightDelta,  deltaZ);
       
   756 
       
   757             }
       
   758         }
       
   759 
       
   760         if (maxZHeightDelta - minZHeightDelta < dEpsilon && 
       
   761             maxXHeightDelta - minXHeightDelta < dEpsilon )
       
   762         {
       
   763             // it's a single plane.
       
   764             const dVector3 &A = tempHeightBuffer[0][0].vertex;
       
   765             const dVector3 &B = tempHeightBuffer[1][0].vertex;
       
   766             const dVector3 &C = tempHeightBuffer[0][1].vertex;
       
   767 
       
   768             // define 2 edges and a point that will define collision plane
       
   769             {
       
   770                 dVector3 Edge1, Edge2; 
       
   771                 dVector3Subtract(C, A, Edge1);
       
   772                 dVector3Subtract(B, A, Edge2);
       
   773                 dVector3Cross(Edge1, Edge2, triplane);
       
   774             }
       
   775 
       
   776             // Define Plane
       
   777             // Normalize plane normal
       
   778             const dReal dinvlength = dDIV(REAL(1.0),dVector3Length(triplane));
       
   779             triplane[0] = dMUL(triplane[0],dinvlength);
       
   780             triplane[1] = dMUL(triplane[1],dinvlength);
       
   781             triplane[2] = dMUL(triplane[2],dinvlength);
       
   782             // get distance to origin from plane 
       
   783             triplane[3] = dVector3Dot(triplane, A);
       
   784 
       
   785             dGeomPlaneSetNoNormalize (sliding_plane, triplane);
       
   786             // find collision and compute contact points
       
   787             const int numPlaneContacts = geomNPlaneCollider (o2, sliding_plane, flags, PlaneContact, sizeof(dContactGeom));
       
   788             for (i = 0; i < numPlaneContacts; i++)
       
   789             {
       
   790                 pContact = CONTACT(contact, numTerrainContacts*skip);
       
   791                 const dVector3 &pCPos = PlaneContact[i].pos;
       
   792                 dVector3Copy (pCPos, pContact->pos);
       
   793                 dOPESIGN(pContact->normal, =, -, triplane);
       
   794 
       
   795                 pContact->depth = PlaneContact[i].depth;
       
   796                 numTerrainContacts++;
       
   797                 if (numTerrainContacts > numMaxContactsPossible)
       
   798                     break;
       
   799             }
       
   800             return numTerrainContacts;
       
   801         }
       
   802     }
       
   803 
       
   804 
       
   805     const unsigned int numTriMax = (maxX - minX) * (maxZ - minZ) * 2;
       
   806     if (tempTriangleBufferSize < numTriMax)
       
   807     {
       
   808         delete [] tempTriangleBuffer;
       
   809         tempTriangleBufferSize = numTriMax;
       
   810         tempTriangleBuffer = new HeightFieldTriangle[numTriMax];
       
   811     }
       
   812     
       
   813     // Sorting triangle/plane  resulting from heightfield zone
       
   814     // Perhaps that would be necessary in case of too much limited
       
   815     // maximum contact point...
       
   816     // or in complex mesh case (trimesh and convex)
       
   817     // need some test or insights on this before enabling this.
       
   818     const bool isContactNumPointsLimited = 
       
   819         true;
       
   820     // (numMaxContacts < 8)
       
   821     //    || o2->type == dConvexClass
       
   822     //    || o2->type == dTriMeshClass
       
   823     //    || (numMaxContacts < (int)numTriMax)       
       
   824         
       
   825 
       
   826 
       
   827     // if small heightfield triangle related to O2 colliding
       
   828     // or no Triangle colliding at all.
       
   829     bool needFurtherPasses = (o2->type == dTriMeshClass);
       
   830     //compute Ratio between Triangle size and O2 aabb size
       
   831 	// no FurtherPasses are needed in ray class
       
   832     if (o2->type != dRayClass  && needFurtherPasses == false)
       
   833     {
       
   834         const dReal xratio = dMUL((o2->aabb[1] - o2->aabb[0]),m_p_data->m_fInvSampleWidth);
       
   835         if (xratio > REAL(1.5))
       
   836             needFurtherPasses = true;
       
   837         else
       
   838         {
       
   839             const dReal zratio = dMUL((o2->aabb[5] - o2->aabb[4]),m_p_data->m_fInvSampleDepth);
       
   840             if (zratio > REAL(1.5))
       
   841                 needFurtherPasses = true;
       
   842         }
       
   843 
       
   844     }
       
   845 
       
   846     unsigned int numTri = 0;
       
   847     HeightFieldVertex *A, *B, *C, *D;
       
   848     /*    (y is up)
       
   849          A--------B-...x
       
   850          |       /|
       
   851          |      / |
       
   852          |     /  |
       
   853          |    /   |
       
   854          |   /    |
       
   855          |  /     |
       
   856          | /      |
       
   857          |/       |
       
   858          C--------D   
       
   859          .
       
   860          .
       
   861          .
       
   862          z
       
   863     */  
       
   864     // keep only triangle that does intersect geom
       
   865     for ( x = minX, x_local = 0; x < maxX; x++, x_local++)
       
   866     {
       
   867         HeightFieldVertex *HeightFieldRow      = tempHeightBuffer[x_local];
       
   868         HeightFieldVertex *HeightFieldNextRow  = tempHeightBuffer[x_local + 1];
       
   869 
       
   870         // First A
       
   871         C = &HeightFieldRow    [0];
       
   872         // First B
       
   873         D = &HeightFieldNextRow[0];
       
   874         for ( z = minZ, z_local = 0; z < maxZ; z++, z_local++)
       
   875         {
       
   876             A = C;
       
   877             B = D;
       
   878 
       
   879             C = &HeightFieldRow    [z_local + 1];
       
   880             D = &HeightFieldNextRow[z_local + 1];
       
   881 
       
   882             const dReal AHeight = A->vertex[1];
       
   883             const dReal BHeight = B->vertex[1];
       
   884             const dReal CHeight = C->vertex[1];
       
   885             const dReal DHeight = D->vertex[1];
       
   886 
       
   887             const bool isACollide = 0 < AHeight - minO2Height;
       
   888             const bool isBCollide = 0 < BHeight - minO2Height;
       
   889             const bool isCCollide = 0 < CHeight - minO2Height;
       
   890             const bool isDCollide = 0 < DHeight - minO2Height;
       
   891 
       
   892             A->state = !(isACollide);
       
   893             B->state = !(isBCollide);
       
   894             C->state = !(isCCollide);
       
   895             D->state = !(isCCollide);
       
   896 
       
   897             if (isACollide || isBCollide || isCCollide)
       
   898             {
       
   899                 HeightFieldTriangle * const CurrTriUp = &tempTriangleBuffer[numTri++];
       
   900 
       
   901                 CurrTriUp->state = false;
       
   902 
       
   903                 // changing point order here implies to change it in isOnHeightField
       
   904                 CurrTriUp->vertices[0] = A;
       
   905                 CurrTriUp->vertices[1] = B;
       
   906                 CurrTriUp->vertices[2] = C;
       
   907 
       
   908                 if (isContactNumPointsLimited)
       
   909                     CurrTriUp->setMinMax();
       
   910                 CurrTriUp->isUp = true;
       
   911             }
       
   912 
       
   913             if (isBCollide || isCCollide || isDCollide)
       
   914             {
       
   915                 HeightFieldTriangle * const CurrTriDown = &tempTriangleBuffer[numTri++];
       
   916 
       
   917                 CurrTriDown->state = false;
       
   918                 // changing point order here implies to change it in isOnHeightField
       
   919 
       
   920                 CurrTriDown->vertices[0] = D;
       
   921                 CurrTriDown->vertices[1] = B;
       
   922                 CurrTriDown->vertices[2] = C;
       
   923 
       
   924 
       
   925                 if (isContactNumPointsLimited)
       
   926                     CurrTriDown->setMinMax();
       
   927                 CurrTriDown->isUp = false;
       
   928             }
       
   929 
       
   930 
       
   931             if (needFurtherPasses &&
       
   932                 (isBCollide || isCCollide)
       
   933                 &&
       
   934                 (AHeight - CHeight > 0 &&
       
   935                  AHeight - BHeight > 0 &&
       
   936                  DHeight - CHeight > 0 &&
       
   937                  DHeight - BHeight > 0))
       
   938             {
       
   939                 // That means Edge BC is concave, therefore
       
   940                 // BC Edge and B and C vertices cannot collide
       
   941 
       
   942                 B->state = true;
       
   943                 C->state = true;
       
   944             }
       
   945             // should find a way to check other edges (AB, BD, CD) too for concavity
       
   946         }
       
   947     }
       
   948 
       
   949     // at least on triangle should intersect geom
       
   950 
       
   951     // pass1: VS triangle as Planes
       
   952     // Group Triangle by same plane definition
       
   953     // as Terrain often has many triangles using same plane definition
       
   954     // then collide against that list of triangles.
       
   955     {
       
   956 
       
   957         dVector3 Edge1, Edge2;
       
   958         //compute all triangles normals.
       
   959         for (unsigned int k = 0; k < numTri; k++)
       
   960         {
       
   961             HeightFieldTriangle * const itTriangle = &tempTriangleBuffer[k];
       
   962 
       
   963             // define 2 edges and a point that will define collision plane
       
   964             dVector3Subtract(itTriangle->vertices[2]->vertex, itTriangle->vertices[0]->vertex, Edge1);
       
   965             dVector3Subtract(itTriangle->vertices[1]->vertex, itTriangle->vertices[0]->vertex, Edge2);
       
   966 
       
   967             // find a perpendicular vector to the triangle
       
   968             if  (itTriangle->isUp)
       
   969                 dVector3Cross(Edge1, Edge2, triplane);
       
   970             else
       
   971                 dVector3Cross(Edge2, Edge1, triplane);
       
   972 
       
   973             // Define Plane
       
   974             // Normalize plane normal
       
   975             const dReal dinvlength = dDIV(1,dVector3Length(triplane));
       
   976             triplane[0] = dMUL(triplane[0],dinvlength);
       
   977             triplane[1] = dMUL(triplane[1],dinvlength);
       
   978             triplane[2] = dMUL(triplane[2],dinvlength);
       
   979             // get distance to origin from plane 
       
   980             triplane[3] = dVector3Dot(triplane, itTriangle->vertices[0]->vertex);
       
   981 
       
   982             // saves normal for collision check (planes, triangles, vertices and edges.)
       
   983             dVector3Copy(triplane, itTriangle->planeDef);
       
   984             // saves distance for collision check (planes, triangles, vertices and edges.)
       
   985             itTriangle->planeDef[3] = triplane[3];
       
   986         }
       
   987 
       
   988         // group by Triangles by Planes sharing shame plane definition
       
   989         if (tempPlaneBufferSize  < numTri)
       
   990         {
       
   991             delete [] tempPlaneBuffer;
       
   992             tempPlaneBufferSize = numTri;
       
   993             tempPlaneBuffer = new HeightFieldPlane *[numTri];
       
   994 
       
   995             for (unsigned int k = 0; k < tempPlaneBufferSize; k++)
       
   996             {
       
   997                 tempPlaneBuffer[k] = new HeightFieldPlane();
       
   998             }
       
   999         }
       
  1000         unsigned int numPlanes = 0;
       
  1001         for (unsigned int k = 0; k < numTri; k++)
       
  1002         {
       
  1003             HeightFieldTriangle * const tri_base = &tempTriangleBuffer[k];
       
  1004 
       
  1005             if (tri_base->state == true)
       
  1006                 continue;// already tested or added to plane list.
       
  1007 
       
  1008             HeightFieldPlane * const currPlane = tempPlaneBuffer[numPlanes];
       
  1009             currPlane->resetTriangleListSize(numTri - k);
       
  1010             currPlane->addTriangle(tri_base);
       
  1011             // saves normal for collision check (planes, triangles, vertices and edges.)
       
  1012             dVector3Copy(tri_base->planeDef, currPlane->planeDef);
       
  1013             // saves distance for collision check (planes, triangles, vertices and edges.)
       
  1014             currPlane->planeDef[3]= tri_base->planeDef[3];
       
  1015 
       
  1016             const dReal normx = tri_base->planeDef[0];
       
  1017             const dReal normy = tri_base->planeDef[1];
       
  1018             const dReal normz = tri_base->planeDef[2];
       
  1019             const dReal dist = tri_base->planeDef[3];
       
  1020 
       
  1021             for (unsigned int m = k + 1; m < numTri; m++)
       
  1022             {
       
  1023 
       
  1024                 HeightFieldTriangle * const tri_test = &tempTriangleBuffer[m];
       
  1025                 if (tri_test->state == true)
       
  1026                     continue;// already tested or added to plane list.
       
  1027 
       
  1028                 // normals and distance are the same.
       
  1029                 if (
       
  1030                     dFabs(normy - tri_test->planeDef[1]) < dEpsilon &&  
       
  1031                     dFabs(dist  - tri_test->planeDef[3]) < dEpsilon &&
       
  1032                     dFabs(normx - tri_test->planeDef[0]) < dEpsilon && 
       
  1033                     dFabs(normz - tri_test->planeDef[2]) < dEpsilon
       
  1034                     )
       
  1035                 {
       
  1036                     currPlane->addTriangle (tri_test);
       
  1037                     tri_test->state = true;
       
  1038                 }
       
  1039             }
       
  1040 
       
  1041             tri_base->state = true;
       
  1042             if (isContactNumPointsLimited)
       
  1043                 currPlane->setMinMax();
       
  1044 
       
  1045             numPlanes++;
       
  1046         }
       
  1047 
       
  1048         // sort planes
       
  1049         if (isContactNumPointsLimited)
       
  1050             sortPlanes(numPlanes);
       
  1051 
       
  1052         for (unsigned int k = 0; k < numPlanes; k++)
       
  1053         {
       
  1054             HeightFieldPlane * const itPlane = tempPlaneBuffer[k];
       
  1055 
       
  1056             //set Geom
       
  1057             dGeomPlaneSetNoNormalize (sliding_plane,  itPlane->planeDef);
       
  1058             //dGeomPlaneSetParams (sliding_plane, triangle_Plane[0], triangle_Plane[1], triangle_Plane[2], triangle_Plane[3]);
       
  1059             // find collision and compute contact points
       
  1060             bool didCollide = false;
       
  1061             const int numPlaneContacts = geomNPlaneCollider (o2, sliding_plane, flags, PlaneContact, sizeof(dContactGeom));
       
  1062             const size_t planeTriListSize = itPlane->trianglelistCurrentSize;
       
  1063             for (i = 0; i < numPlaneContacts; i++)
       
  1064             {
       
  1065                 // Check if contact point found in plane is inside Triangle.
       
  1066                 const dVector3 &pCPos = PlaneContact[i].pos;
       
  1067                 bool isOnOneOfTrianglePlane = false;
       
  1068                 for (size_t b = 0; planeTriListSize > b; b++)
       
  1069                 {  
       
  1070                     if (m_p_data->IsOnHeightfield2 (itPlane->trianglelist[b]->vertices[0]->vertex, 
       
  1071                                                     pCPos, 
       
  1072                                                     itPlane->trianglelist[b]->isUp))
       
  1073                     {
       
  1074                         isOnOneOfTrianglePlane = true;
       
  1075                         break;
       
  1076                     }
       
  1077                 }
       
  1078                 if ( isOnOneOfTrianglePlane)
       
  1079                 {
       
  1080                     pContact = CONTACT(contact, numTerrainContacts*skip);
       
  1081                     dVector3Copy(pCPos, pContact->pos);
       
  1082                     dOPESIGN(pContact->normal, =, -, itPlane->planeDef);
       
  1083                     pContact->depth = PlaneContact[i].depth;
       
  1084                     didCollide = true;
       
  1085                     numTerrainContacts++;
       
  1086                     if ( numTerrainContacts == numMaxContacts ) 
       
  1087                         return numTerrainContacts;
       
  1088                 }
       
  1089             }
       
  1090             if (didCollide)
       
  1091             {
       
  1092                 for (size_t b = 0; planeTriListSize > b; b++)
       
  1093                 {                      
       
  1094                     // flag Triangles Vertices as collided 
       
  1095                     // to prevent any collision test of those
       
  1096                     for (i = 0; i < 3; i++)
       
  1097                         itPlane->trianglelist[b]->vertices[i]->state = true;
       
  1098                 }
       
  1099             }
       
  1100             else 
       
  1101             {
       
  1102                 // flag triangle as not collided so that Vertices or Edge
       
  1103                 // of that triangles will be checked.
       
  1104                 for (size_t b = 0; planeTriListSize > b; b++)
       
  1105                 { 
       
  1106                     itPlane->trianglelist[b]->state = false;
       
  1107                 }
       
  1108             }
       
  1109         }
       
  1110     }
       
  1111     
       
  1112 
       
  1113    
       
  1114     // pass2: VS triangle vertices
       
  1115     if (needFurtherPasses)
       
  1116     {
       
  1117         dxRay tempRay(0, 1); 
       
  1118         dReal depth;
       
  1119         bool vertexCollided;
       
  1120         //
       
  1121         // Find Contact Penetration Depth of each vertices
       
  1122         //
       
  1123         for (unsigned int k = 0; k < numTri; k++)
       
  1124         {
       
  1125             const HeightFieldTriangle * const itTriangle = &tempTriangleBuffer[k];
       
  1126             if (itTriangle->state == true)
       
  1127                 continue;// plane triangle did already collide.
       
  1128 
       
  1129             for (size_t i = 0; i < 3; i++)
       
  1130             {
       
  1131                 HeightFieldVertex *vertex = itTriangle->vertices[i];
       
  1132                 if (vertex->state == true)
       
  1133                     continue;// vertice did already collide.
       
  1134 
       
  1135                 vertexCollided = false;
       
  1136                 const dVector3 &triVertex = vertex->vertex;
       
  1137                 if ( geomNDepthGetter )
       
  1138                 {
       
  1139                     depth = geomNDepthGetter( o2,
       
  1140                         triVertex[0], triVertex[1], triVertex[2] );
       
  1141                     if (depth + dEpsilon < 0)
       
  1142                         vertexCollided = true;
       
  1143                 }
       
  1144                 else
       
  1145                 {
       
  1146                     // We don't have a GetDepth function, so do a ray cast instead.
       
  1147                     // NOTE: This isn't ideal, and a GetDepth function should be
       
  1148                     // written for all geom classes.
       
  1149                     tempRay.length = (minO2Height - triVertex[1]) * REAL(1000.f);
       
  1150 
       
  1151                     //dGeomRaySet( &tempRay, pContact->pos[0], pContact->pos[1], pContact->pos[2],
       
  1152                     //    - itTriangle->Normal[0], - itTriangle->Normal[1], - itTriangle->Normal[2] );
       
  1153                     dGeomRaySetNoNormalize(tempRay, triVertex, itTriangle->planeDef);
       
  1154 
       
  1155                     if ( geomRayNCollider( &tempRay, o2, flags, PlaneContact, sizeof( dContactGeom ) ) )
       
  1156                     {
       
  1157                         depth = PlaneContact[0].depth;
       
  1158                         vertexCollided = true;
       
  1159                     }
       
  1160                 }
       
  1161                 if (vertexCollided)
       
  1162                 {
       
  1163                     pContact = CONTACT(contact, numTerrainContacts*skip);
       
  1164                     //create contact using vertices
       
  1165                     dVector3Copy (triVertex, pContact->pos);
       
  1166                     //create contact using Plane Normal
       
  1167                     dOPESIGN(pContact->normal, =, -, itTriangle->planeDef);
       
  1168 
       
  1169                     pContact->depth = depth;
       
  1170 
       
  1171                     numTerrainContacts++;
       
  1172                     if ( numTerrainContacts == numMaxContacts ) 
       
  1173                         return numTerrainContacts;
       
  1174 
       
  1175                     vertex->state = true;
       
  1176                 }
       
  1177             }
       
  1178         }
       
  1179     }
       
  1180 
       
  1181     return numTerrainContacts;
       
  1182 }
       
  1183 
       
  1184 int dCollideHeightfield( dxGeom *o1, dxGeom *o2, int flags, dContactGeom* contact, int skip )
       
  1185 {
       
  1186 
       
  1187     int i;
       
  1188 
       
  1189     if ((flags & 0xffff) == 0)
       
  1190         flags = (flags & 0xffff0000) | 1;
       
  1191 
       
  1192     int numMaxTerrainContacts = (flags & 0xffff);
       
  1193     dxHeightfield *terrain = (dxHeightfield*) o1;
       
  1194 
       
  1195     dVector3 posbak;
       
  1196     dMatrix3 Rbak;
       
  1197     dReal aabbbak[6];
       
  1198     int gflagsbak;
       
  1199     dVector3 pos0,pos1;
       
  1200     dMatrix3 R1;
       
  1201 
       
  1202     int numTerrainContacts = 0;
       
  1203 
       
  1204     //@@ Should find a way to set reComputeAABB to false in default case
       
  1205     // aka DHEIGHTFIELD_CORNER_ORIGIN not defined and terrain not PLACEABLE
       
  1206     // so that we can free some memory and speed up things a bit
       
  1207     // while saving some precision loss 
       
  1208 
       
  1209     const bool reComputeAABB = true;
       
  1210 
       
  1211     //
       
  1212     // Transform O2 into Heightfield Space
       
  1213     //
       
  1214     if (reComputeAABB)
       
  1215     {
       
  1216         // Backup original o2 position, rotation and AABB.
       
  1217         dVector3Copy( o2->final_posr->pos, posbak );
       
  1218         dMatrix3Copy( o2->final_posr->R, Rbak );
       
  1219         memcpy( aabbbak, o2->aabb, sizeof( dReal ) * 6 );
       
  1220         gflagsbak = o2->gflags;
       
  1221     }
       
  1222 
       
  1223     if ( terrain->gflags & GEOM_PLACEABLE )
       
  1224     {
       
  1225         // Transform o2 into heightfield space.
       
  1226         dOP( pos0, -, o2->final_posr->pos, terrain->final_posr->pos );
       
  1227         dMULTIPLY1_331( pos1, terrain->final_posr->R, pos0 );
       
  1228         dMULTIPLY1_333( R1, terrain->final_posr->R, o2->final_posr->R );
       
  1229 
       
  1230         // Update o2 with transformed position and rotation.
       
  1231         dVector3Copy( pos1, o2->final_posr->pos );
       
  1232         dMatrix3Copy( R1, o2->final_posr->R );
       
  1233     }
       
  1234 
       
  1235 
       
  1236     o2->final_posr->pos[ 0 ] += terrain->m_p_data->m_fHalfWidth;
       
  1237     o2->final_posr->pos[ 2 ] += terrain->m_p_data->m_fHalfDepth;
       
  1238 
       
  1239     // Rebuild AABB for O2
       
  1240     if (reComputeAABB)
       
  1241         o2->computeAABB();
       
  1242 
       
  1243     //
       
  1244     // Collide
       
  1245     //
       
  1246 
       
  1247     //check if inside boundaries
       
  1248     // using O2 aabb
       
  1249     //  aabb[6] is (minx, maxx, miny, maxy, minz, maxz) 
       
  1250     const bool notWrapped = terrain->m_p_data->m_bWrapMode == 0;
       
  1251 
       
  1252     int nMinX;
       
  1253     int nMaxX;
       
  1254     int nMinZ;
       
  1255     int nMaxZ;
       
  1256 
       
  1257     if ( notWrapped )
       
  1258     {
       
  1259         if (    o2->aabb[0] > terrain->m_p_data->m_fWidth //MinX
       
  1260             &&  o2->aabb[4] > terrain->m_p_data->m_fDepth)//MinZ
       
  1261             goto dCollideHeightfieldExit;
       
  1262 
       
  1263         if (    o2->aabb[1] < 0 //MaxX
       
  1264             &&  o2->aabb[5] < 0) //MaxZ
       
  1265             goto dCollideHeightfieldExit;
       
  1266 
       
  1267     }
       
  1268 
       
  1269     nMinX = dMUL(o2->aabb[0],terrain->m_p_data->m_fInvSampleWidth)>>QFACTOR;
       
  1270     nMaxX = dMUL(o2->aabb[1],terrain->m_p_data->m_fInvSampleWidth)>>QFACTOR + 1;
       
  1271     nMinZ = dMUL(o2->aabb[4],terrain->m_p_data->m_fInvSampleDepth)>>QFACTOR;
       
  1272     nMaxZ = dMUL(o2->aabb[5],terrain->m_p_data->m_fInvSampleDepth)>>QFACTOR + 1;
       
  1273 
       
  1274     if ( notWrapped )
       
  1275     {
       
  1276         nMinX = dMAX( nMinX, 0 );
       
  1277         nMaxX = dMIN( nMaxX, terrain->m_p_data->m_nWidthSamples - 1 );
       
  1278         nMinZ = dMAX( nMinZ, 0 );
       
  1279         nMaxZ = dMIN( nMaxZ, terrain->m_p_data->m_nDepthSamples - 1 );
       
  1280 	
       
  1281     }
       
  1282 
       
  1283 
       
  1284 
       
  1285     numTerrainContacts  = terrain->dCollideHeightfieldZone(
       
  1286         nMinX,nMaxX,nMinZ,nMaxZ,o2,numMaxTerrainContacts - numTerrainContacts,
       
  1287         flags,CONTACT(contact,numTerrainContacts*skip),skip	);
       
  1288 
       
  1289 
       
  1290         dContactGeom *pContact;
       
  1291         for ( i = 0; i < numTerrainContacts; ++i )
       
  1292         {
       
  1293             pContact = CONTACT(contact,i*skip);
       
  1294             pContact->g1 = o1;
       
  1295             pContact->g2 = o2;
       
  1296         }
       
  1297 
       
  1298 
       
  1299         //------------------------------------------------------------------------------
       
  1300 
       
  1301 dCollideHeightfieldExit:
       
  1302 
       
  1303         if (reComputeAABB)
       
  1304         {
       
  1305             // Restore o2 position, rotation and AABB
       
  1306             dVector3Copy( posbak, o2->final_posr->pos );
       
  1307             dMatrix3Copy( Rbak, o2->final_posr->R );
       
  1308             memcpy( o2->aabb, aabbbak, sizeof(dReal)*6 );
       
  1309             o2->gflags = gflagsbak;
       
  1310 
       
  1311             //
       
  1312             // Transform Contacts to World Space
       
  1313             //
       
  1314             if ( terrain->gflags & GEOM_PLACEABLE )
       
  1315             {
       
  1316                 for ( i = 0; i < numTerrainContacts; ++i )
       
  1317                 {
       
  1318                     pContact = CONTACT(contact,i*skip);
       
  1319                     dOPE( pos0, =, pContact->pos );
       
  1320 
       
  1321 
       
  1322                     pos0[ 0 ] -= terrain->m_p_data->m_fHalfWidth;
       
  1323                     pos0[ 2 ] -= terrain->m_p_data->m_fHalfDepth;
       
  1324 
       
  1325 
       
  1326                     dMULTIPLY0_331( pContact->pos, terrain->final_posr->R, pos0 );
       
  1327 
       
  1328                     dOP( pContact->pos, +, pContact->pos, terrain->final_posr->pos );
       
  1329                     dOPE( pos0, =, pContact->normal );
       
  1330 
       
  1331                     dMULTIPLY0_331( pContact->normal, terrain->final_posr->R, pos0 );
       
  1332                 }
       
  1333             }
       
  1334 
       
  1335             else
       
  1336             {
       
  1337                 for ( i = 0; i < numTerrainContacts; ++i )
       
  1338                 {
       
  1339                     pContact = CONTACT(contact,i*skip);
       
  1340                     pContact->pos[ 0 ] -= terrain->m_p_data->m_fHalfWidth;
       
  1341                     pContact->pos[ 2 ] -= terrain->m_p_data->m_fHalfDepth;
       
  1342                 }
       
  1343             }
       
  1344 
       
  1345         }
       
  1346         // Return contact count.
       
  1347         return numTerrainContacts;
       
  1348 }
       
  1349 
       
  1350