diff options
Diffstat (limited to 'libraries/ode-0.9/ode/src/heightfield.cpp')
-rw-r--r-- | libraries/ode-0.9/ode/src/heightfield.cpp | 1812 |
1 files changed, 0 insertions, 1812 deletions
diff --git a/libraries/ode-0.9/ode/src/heightfield.cpp b/libraries/ode-0.9/ode/src/heightfield.cpp deleted file mode 100644 index 36755fc..0000000 --- a/libraries/ode-0.9/ode/src/heightfield.cpp +++ /dev/null | |||
@@ -1,1812 +0,0 @@ | |||
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 | |||
20 | |||
21 | #if dTRIMESH_ENABLED | ||
22 | #include "collision_trimesh_internal.h" | ||
23 | #endif // dTRIMESH_ENABLED | ||
24 | |||
25 | #define TERRAINTOL REAL(0.0) | ||
26 | |||
27 | #define dMIN(A,B) ((A)>(B) ? B : A) | ||
28 | #define dMAX(A,B) ((A)>(B) ? A : B) | ||
29 | |||
30 | |||
31 | // Three-way MIN and MAX | ||
32 | #define dMIN3(A,B,C) ( (A)<(B) ? dMIN((A),(C)) : dMIN((B),(C)) ) | ||
33 | #define dMAX3(A,B,C) ( (A)>(B) ? dMAX((A),(C)) : dMAX((B),(C)) ) | ||
34 | |||
35 | #define dOPESIGN(a, op1, op2,b) \ | ||
36 | (a)[0] op1 op2 ((b)[0]); \ | ||
37 | (a)[1] op1 op2 ((b)[1]); \ | ||
38 | (a)[2] op1 op2 ((b)[2]); | ||
39 | |||
40 | #define dGeomRaySetNoNormalize(myRay, MyPoint, MyVector) { \ | ||
41 | \ | ||
42 | dVector3Copy (MyPoint, myRay.final_posr->pos); \ | ||
43 | myRay.final_posr->R[2] = MyVector[0]; \ | ||
44 | myRay.final_posr->R[6] = MyVector[1]; \ | ||
45 | myRay.final_posr->R[10] = MyVector[2]; \ | ||
46 | dGeomMoved (&myRay); \ | ||
47 | } | ||
48 | |||
49 | #define dGeomPlaneSetNoNormalize(MyPlane, MyPlaneDef) { \ | ||
50 | \ | ||
51 | MyPlane->p[0] = MyPlaneDef[0]; \ | ||
52 | MyPlane->p[1] = MyPlaneDef[1]; \ | ||
53 | MyPlane->p[2] = MyPlaneDef[2]; \ | ||
54 | MyPlane->p[3] = MyPlaneDef[3]; \ | ||
55 | dGeomMoved (MyPlane); \ | ||
56 | } | ||
57 | //////// Local Build Option //////////////////////////////////////////////////// | ||
58 | |||
59 | // Uncomment this #define to use the (0,0) corner of the geom as the origin, | ||
60 | // rather than the center. This was the way the original heightfield worked, | ||
61 | // but as it does not match the way all other geometries work, so for constancy it | ||
62 | // was changed to work like this. | ||
63 | |||
64 | // #define DHEIGHTFIELD_CORNER_ORIGIN | ||
65 | |||
66 | |||
67 | // Uncomment this #define to add heightfield triangles edge colliding | ||
68 | // Code is not guaranteed and I didn't find the need to add that as | ||
69 | // colliding planes triangles and edge triangles seems enough. | ||
70 | // #define _HEIGHTFIELDEDGECOLLIDING | ||
71 | |||
72 | |||
73 | //////// dxHeightfieldData ///////////////////////////////////////////////////////////// | ||
74 | |||
75 | // dxHeightfieldData constructor | ||
76 | dxHeightfieldData::dxHeightfieldData() | ||
77 | { | ||
78 | // | ||
79 | } | ||
80 | |||
81 | |||
82 | // build Heightfield data | ||
83 | void dxHeightfieldData::SetData( int nWidthSamples, int nDepthSamples, | ||
84 | dReal fWidth, dReal fDepth, | ||
85 | dReal fScale, dReal fOffset, dReal fThickness, | ||
86 | int bWrapMode ) | ||
87 | { | ||
88 | dIASSERT( fWidth > REAL( 0.0 ) ); | ||
89 | dIASSERT( fDepth > REAL( 0.0 ) ); | ||
90 | dIASSERT( nWidthSamples > 0 ); | ||
91 | dIASSERT( nDepthSamples > 0 ); | ||
92 | |||
93 | // x,z bounds | ||
94 | m_fWidth = fWidth; | ||
95 | m_fDepth = fDepth; | ||
96 | |||
97 | // cache half x,z bounds | ||
98 | m_fHalfWidth = fWidth / REAL( 2.0 ); | ||
99 | m_fHalfDepth = fDepth / REAL( 2.0 ); | ||
100 | |||
101 | // scale and offset | ||
102 | m_fScale = fScale; | ||
103 | m_fOffset = fOffset; | ||
104 | |||
105 | // infinite min height bounds | ||
106 | m_fThickness = fThickness; | ||
107 | |||
108 | // number of vertices per side | ||
109 | m_nWidthSamples = nWidthSamples; | ||
110 | m_nDepthSamples = nDepthSamples; | ||
111 | |||
112 | m_fSampleWidth = m_fWidth / ( m_nWidthSamples - 1 ); | ||
113 | m_fSampleDepth = m_fDepth / ( m_nDepthSamples - 1 ); | ||
114 | |||
115 | m_fInvSampleWidth = 1 / m_fSampleWidth; | ||
116 | m_fInvSampleDepth = 1 / m_fSampleDepth; | ||
117 | |||
118 | // finite or repeated terrain? | ||
119 | m_bWrapMode = bWrapMode; | ||
120 | } | ||
121 | |||
122 | |||
123 | // recomputes heights bounds | ||
124 | void dxHeightfieldData::ComputeHeightBounds() | ||
125 | { | ||
126 | static int i; | ||
127 | static dReal h; | ||
128 | static unsigned char *data_byte; | ||
129 | static short *data_short; | ||
130 | static float *data_float; | ||
131 | static double *data_double; | ||
132 | |||
133 | switch ( m_nGetHeightMode ) | ||
134 | { | ||
135 | |||
136 | // callback | ||
137 | case 0: | ||
138 | // change nothing, keep using default or user specified bounds | ||
139 | return; | ||
140 | |||
141 | // byte | ||
142 | case 1: | ||
143 | data_byte = (unsigned char*)m_pHeightData; | ||
144 | m_fMinHeight = dInfinity; | ||
145 | m_fMaxHeight = -dInfinity; | ||
146 | |||
147 | for (i=0; i<m_nWidthSamples*m_nDepthSamples; i++) | ||
148 | { | ||
149 | h = data_byte[i]; | ||
150 | if (h < m_fMinHeight) m_fMinHeight = h; | ||
151 | if (h > m_fMaxHeight) m_fMaxHeight = h; | ||
152 | } | ||
153 | |||
154 | break; | ||
155 | |||
156 | // short | ||
157 | case 2: | ||
158 | data_short = (short*)m_pHeightData; | ||
159 | m_fMinHeight = dInfinity; | ||
160 | m_fMaxHeight = -dInfinity; | ||
161 | |||
162 | for (i=0; i<m_nWidthSamples*m_nDepthSamples; i++) | ||
163 | { | ||
164 | h = data_short[i]; | ||
165 | if (h < m_fMinHeight) m_fMinHeight = h; | ||
166 | if (h > m_fMaxHeight) m_fMaxHeight = h; | ||
167 | } | ||
168 | |||
169 | break; | ||
170 | |||
171 | // float | ||
172 | case 3: | ||
173 | data_float = (float*)m_pHeightData; | ||
174 | m_fMinHeight = dInfinity; | ||
175 | m_fMaxHeight = -dInfinity; | ||
176 | |||
177 | for (i=0; i<m_nWidthSamples*m_nDepthSamples; i++) | ||
178 | { | ||
179 | h = data_float[i]; | ||
180 | if (h < m_fMinHeight) m_fMinHeight = h; | ||
181 | if (h > m_fMaxHeight) m_fMaxHeight = h; | ||
182 | } | ||
183 | |||
184 | break; | ||
185 | |||
186 | // double | ||
187 | case 4: | ||
188 | data_double = (double*)m_pHeightData; | ||
189 | m_fMinHeight = dInfinity; | ||
190 | m_fMaxHeight = -dInfinity; | ||
191 | |||
192 | for (i=0; i<m_nWidthSamples*m_nDepthSamples; i++) | ||
193 | { | ||
194 | h = static_cast< dReal >( data_double[i] ); | ||
195 | if (h < m_fMinHeight) m_fMinHeight = h; | ||
196 | if (h > m_fMaxHeight) m_fMaxHeight = h; | ||
197 | } | ||
198 | |||
199 | break; | ||
200 | |||
201 | } | ||
202 | |||
203 | // scale and offset | ||
204 | m_fMinHeight *= m_fScale; | ||
205 | m_fMaxHeight *= m_fScale; | ||
206 | m_fMinHeight += m_fOffset; | ||
207 | m_fMaxHeight += m_fOffset; | ||
208 | |||
209 | // add thickness | ||
210 | m_fMinHeight -= m_fThickness; | ||
211 | } | ||
212 | |||
213 | |||
214 | // returns whether point is over terrain Cell triangle? | ||
215 | bool dxHeightfieldData::IsOnHeightfield ( const dReal * const CellOrigin, const dReal * const pos, const bool isABC) const | ||
216 | { | ||
217 | { | ||
218 | const dReal MaxX = CellOrigin[0] + m_fSampleWidth; | ||
219 | const dReal TolX = m_fSampleWidth * TERRAINTOL; | ||
220 | if ((pos[0]<CellOrigin[0]-TolX) || (pos[0]>MaxX+TolX)) | ||
221 | return false; | ||
222 | } | ||
223 | |||
224 | { | ||
225 | const dReal MaxZ = CellOrigin[2] + m_fSampleDepth; | ||
226 | const dReal TolZ = m_fSampleDepth * TERRAINTOL; | ||
227 | if ((pos[2]<CellOrigin[2]-TolZ) || (pos[2]>MaxZ+TolZ)) | ||
228 | return false; | ||
229 | } | ||
230 | |||
231 | // add X percentage position on cell and Z percentage position on cell | ||
232 | const dReal pctTotal = (pos[0] - CellOrigin[0]) * m_fInvSampleWidth | ||
233 | + (pos[2] - CellOrigin[2]) * m_fInvSampleDepth; | ||
234 | |||
235 | if (isABC) | ||
236 | { | ||
237 | if (pctTotal >= REAL(1.0) + TERRAINTOL) | ||
238 | return false; | ||
239 | else | ||
240 | return true; | ||
241 | } | ||
242 | else if (pctTotal <= REAL(1.0) - TERRAINTOL) | ||
243 | { | ||
244 | return false; | ||
245 | } | ||
246 | return true; | ||
247 | } | ||
248 | // returns whether point is over terrain Cell triangle? | ||
249 | bool dxHeightfieldData::IsOnHeightfield2 ( const dReal * const CellOrigin, const dReal * const pos, const bool isABC) const | ||
250 | { | ||
251 | dReal MaxX, MinX; | ||
252 | dReal MaxZ, MinZ; | ||
253 | if (isABC) | ||
254 | { | ||
255 | // point A | ||
256 | MinX = CellOrigin[0]; | ||
257 | MaxX = CellOrigin[0] + m_fSampleWidth; | ||
258 | |||
259 | MinZ = CellOrigin[2]; | ||
260 | MaxZ = CellOrigin[2] + m_fSampleDepth; | ||
261 | } | ||
262 | else | ||
263 | { | ||
264 | // point D | ||
265 | MinX = CellOrigin[0] - m_fSampleWidth; | ||
266 | MaxX = CellOrigin[0]; | ||
267 | |||
268 | MinZ = CellOrigin[2] - m_fSampleDepth; | ||
269 | MaxZ = CellOrigin[2]; | ||
270 | } | ||
271 | |||
272 | // check if inside CELL | ||
273 | { | ||
274 | const dReal TolX = m_fSampleWidth * TERRAINTOL; | ||
275 | if ((pos[0]<MinX-TolX) || (pos[0]>MaxX+TolX)) | ||
276 | return false; | ||
277 | } | ||
278 | |||
279 | { | ||
280 | const dReal TolZ = m_fSampleDepth * TERRAINTOL; | ||
281 | if ((pos[2]<MinZ-TolZ) || (pos[2]>MaxZ+TolZ)) | ||
282 | return false; | ||
283 | } | ||
284 | |||
285 | // Sum up X percentage position on cell and Z percentage position on cell | ||
286 | const dReal pctTotal = (pos[0] - MinX) * m_fInvSampleWidth | ||
287 | + (pos[2] - MinZ) * m_fInvSampleDepth; | ||
288 | |||
289 | // check if inside respective Triangle of Cell | ||
290 | if (isABC) | ||
291 | { | ||
292 | if (pctTotal >= REAL(1.0) + TERRAINTOL) | ||
293 | return false; | ||
294 | else | ||
295 | return true; | ||
296 | } | ||
297 | else if (pctTotal <= REAL(1.0) - TERRAINTOL) | ||
298 | { | ||
299 | return false; | ||
300 | } | ||
301 | return true; | ||
302 | } | ||
303 | |||
304 | |||
305 | // returns height at given sample coordinates | ||
306 | dReal dxHeightfieldData::GetHeight( int x, int z ) | ||
307 | { | ||
308 | static dReal h; | ||
309 | static unsigned char *data_byte; | ||
310 | static short *data_short; | ||
311 | static float *data_float; | ||
312 | static double *data_double; | ||
313 | |||
314 | if ( m_bWrapMode == 0 ) | ||
315 | { | ||
316 | // Finite | ||
317 | if ( x < 0 ) x = 0; | ||
318 | if ( z < 0 ) z = 0; | ||
319 | if ( x > m_nWidthSamples - 1 ) x = m_nWidthSamples - 1; | ||
320 | if ( z > m_nDepthSamples - 1 ) z = m_nDepthSamples - 1; | ||
321 | } | ||
322 | else | ||
323 | { | ||
324 | // Infinite | ||
325 | x %= m_nWidthSamples - 1; | ||
326 | z %= m_nDepthSamples - 1; | ||
327 | if ( x < 0 ) x += m_nWidthSamples - 1; | ||
328 | if ( z < 0 ) z += m_nDepthSamples - 1; | ||
329 | } | ||
330 | |||
331 | switch ( m_nGetHeightMode ) | ||
332 | { | ||
333 | |||
334 | // callback (dReal) | ||
335 | case 0: | ||
336 | h = (*m_pGetHeightCallback)(m_pUserData, x, z); | ||
337 | break; | ||
338 | |||
339 | // byte | ||
340 | case 1: | ||
341 | data_byte = (unsigned char*)m_pHeightData; | ||
342 | h = data_byte[x+(z * m_nWidthSamples)]; | ||
343 | break; | ||
344 | |||
345 | // short | ||
346 | case 2: | ||
347 | data_short = (short*)m_pHeightData; | ||
348 | h = data_short[x+(z * m_nWidthSamples)]; | ||
349 | break; | ||
350 | |||
351 | // float | ||
352 | case 3: | ||
353 | data_float = (float*)m_pHeightData; | ||
354 | h = data_float[x+(z * m_nWidthSamples)]; | ||
355 | break; | ||
356 | |||
357 | // double | ||
358 | case 4: | ||
359 | data_double = (double*)m_pHeightData; | ||
360 | h = static_cast< dReal >( data_double[x+(z * m_nWidthSamples)] ); | ||
361 | break; | ||
362 | } | ||
363 | |||
364 | return (h * m_fScale) + m_fOffset; | ||
365 | } | ||
366 | |||
367 | |||
368 | // returns height at given coordinates | ||
369 | dReal dxHeightfieldData::GetHeight( dReal x, dReal z ) | ||
370 | { | ||
371 | dReal dnX = dFloor( x * m_fInvSampleWidth ); | ||
372 | dReal dnZ = dFloor( z * m_fInvSampleDepth ); | ||
373 | |||
374 | dReal dx = ( x - ( dnX * m_fSampleWidth ) ) * m_fInvSampleWidth; | ||
375 | dReal dz = ( z - ( dnZ * m_fSampleDepth ) ) * m_fInvSampleDepth; | ||
376 | |||
377 | int nX = int( dnX ); | ||
378 | int nZ = int( dnZ ); | ||
379 | |||
380 | //dIASSERT( ( dx + dEpsilon >= 0.0f ) && ( dx - dEpsilon <= 1.0f ) ); | ||
381 | //dIASSERT( ( dz + dEpsilon >= 0.0f ) && ( dz - dEpsilon <= 1.0f ) ); | ||
382 | |||
383 | dReal y, y0; | ||
384 | |||
385 | if ( dx + dz < REAL( 1.0 ) ) | ||
386 | { | ||
387 | y0 = GetHeight( nX, nZ ); | ||
388 | |||
389 | y = y0 + ( GetHeight( nX + 1, nZ ) - y0 ) * dx | ||
390 | + ( GetHeight( nX, nZ + 1 ) - y0 ) * dz; | ||
391 | } | ||
392 | else | ||
393 | { | ||
394 | y0 = GetHeight( nX + 1, nZ + 1 ); | ||
395 | |||
396 | y = y0 + ( GetHeight( nX + 1, nZ ) - y0 ) * ( REAL(1.0) - dz ) + | ||
397 | ( GetHeight( nX, nZ + 1 ) - y0 ) * ( REAL(1.0) - dx ); | ||
398 | } | ||
399 | |||
400 | return y; | ||
401 | } | ||
402 | |||
403 | |||
404 | // dxHeightfieldData destructor | ||
405 | dxHeightfieldData::~dxHeightfieldData() | ||
406 | { | ||
407 | static unsigned char *data_byte; | ||
408 | static short *data_short; | ||
409 | static float *data_float; | ||
410 | static double *data_double; | ||
411 | |||
412 | dIASSERT( m_pHeightData ); | ||
413 | |||
414 | if ( m_bCopyHeightData ) | ||
415 | { | ||
416 | switch ( m_nGetHeightMode ) | ||
417 | { | ||
418 | |||
419 | // callback | ||
420 | case 0: | ||
421 | // do nothing | ||
422 | break; | ||
423 | |||
424 | // byte | ||
425 | case 1: | ||
426 | data_byte = (unsigned char*)m_pHeightData; | ||
427 | delete [] data_byte; | ||
428 | break; | ||
429 | |||
430 | // short | ||
431 | case 2: | ||
432 | data_short = (short*)m_pHeightData; | ||
433 | delete [] data_short; | ||
434 | break; | ||
435 | |||
436 | // float | ||
437 | case 3: | ||
438 | data_float = (float*)m_pHeightData; | ||
439 | delete [] data_float; | ||
440 | break; | ||
441 | |||
442 | // double | ||
443 | case 4: | ||
444 | data_double = (double*)m_pHeightData; | ||
445 | delete [] data_double; | ||
446 | break; | ||
447 | |||
448 | } | ||
449 | } | ||
450 | } | ||
451 | |||
452 | |||
453 | //////// dxHeightfield ///////////////////////////////////////////////////////////////// | ||
454 | |||
455 | |||
456 | // dxHeightfield constructor | ||
457 | dxHeightfield::dxHeightfield( dSpaceID space, | ||
458 | dHeightfieldDataID data, | ||
459 | int bPlaceable ) : | ||
460 | dxGeom( space, bPlaceable ), | ||
461 | tempPlaneBuffer(0), | ||
462 | tempPlaneInstances(0), | ||
463 | tempPlaneBufferSize(0), | ||
464 | tempTriangleBuffer(0), | ||
465 | tempTriangleBufferSize(0), | ||
466 | tempHeightBuffer(0), | ||
467 | tempHeightInstances(0), | ||
468 | tempHeightBufferSizeX(0), | ||
469 | tempHeightBufferSizeZ(0) | ||
470 | { | ||
471 | type = dHeightfieldClass; | ||
472 | this->m_p_data = data; | ||
473 | } | ||
474 | |||
475 | |||
476 | // compute axis aligned bounding box | ||
477 | void dxHeightfield::computeAABB() | ||
478 | { | ||
479 | const dxHeightfieldData *d = m_p_data; | ||
480 | |||
481 | if ( d->m_bWrapMode == 0 ) | ||
482 | { | ||
483 | // Finite | ||
484 | if ( gflags & GEOM_PLACEABLE ) | ||
485 | { | ||
486 | dReal dx[6], dy[6], dz[6]; | ||
487 | |||
488 | // Y-axis | ||
489 | dy[0] = ( final_posr->R[ 1] * d->m_fMinHeight ); | ||
490 | dy[1] = ( final_posr->R[ 5] * d->m_fMinHeight ); | ||
491 | dy[2] = ( final_posr->R[ 9] * d->m_fMinHeight ); | ||
492 | dy[3] = ( final_posr->R[ 1] * d->m_fMaxHeight ); | ||
493 | dy[4] = ( final_posr->R[ 5] * d->m_fMaxHeight ); | ||
494 | dy[5] = ( final_posr->R[ 9] * d->m_fMaxHeight ); | ||
495 | |||
496 | #ifdef DHEIGHTFIELD_CORNER_ORIGIN | ||
497 | |||
498 | // X-axis | ||
499 | dx[0] = 0; dx[3] = ( final_posr->R[ 0] * d->m_fWidth ); | ||
500 | dx[1] = 0; dx[4] = ( final_posr->R[ 4] * d->m_fWidth ); | ||
501 | dx[2] = 0; dx[5] = ( final_posr->R[ 8] * d->m_fWidth ); | ||
502 | |||
503 | // Z-axis | ||
504 | dz[0] = 0; dz[3] = ( final_posr->R[ 2] * d->m_fDepth ); | ||
505 | dz[1] = 0; dz[4] = ( final_posr->R[ 6] * d->m_fDepth ); | ||
506 | dz[2] = 0; dz[5] = ( final_posr->R[10] * d->m_fDepth ); | ||
507 | |||
508 | #else // DHEIGHTFIELD_CORNER_ORIGIN | ||
509 | |||
510 | // X-axis | ||
511 | dx[0] = ( final_posr->R[ 0] * -d->m_fHalfWidth ); | ||
512 | dx[1] = ( final_posr->R[ 4] * -d->m_fHalfWidth ); | ||
513 | dx[2] = ( final_posr->R[ 8] * -d->m_fHalfWidth ); | ||
514 | dx[3] = ( final_posr->R[ 0] * d->m_fHalfWidth ); | ||
515 | dx[4] = ( final_posr->R[ 4] * d->m_fHalfWidth ); | ||
516 | dx[5] = ( final_posr->R[ 8] * d->m_fHalfWidth ); | ||
517 | |||
518 | // Z-axis | ||
519 | dz[0] = ( final_posr->R[ 2] * -d->m_fHalfDepth ); | ||
520 | dz[1] = ( final_posr->R[ 6] * -d->m_fHalfDepth ); | ||
521 | dz[2] = ( final_posr->R[10] * -d->m_fHalfDepth ); | ||
522 | dz[3] = ( final_posr->R[ 2] * d->m_fHalfDepth ); | ||
523 | dz[4] = ( final_posr->R[ 6] * d->m_fHalfDepth ); | ||
524 | dz[5] = ( final_posr->R[10] * d->m_fHalfDepth ); | ||
525 | |||
526 | #endif // DHEIGHTFIELD_CORNER_ORIGIN | ||
527 | |||
528 | // X extents | ||
529 | aabb[0] = final_posr->pos[0] + | ||
530 | dMIN3( dMIN( dx[0], dx[3] ), dMIN( dy[0], dy[3] ), dMIN( dz[0], dz[3] ) ); | ||
531 | aabb[1] = final_posr->pos[0] + | ||
532 | dMAX3( dMAX( dx[0], dx[3] ), dMAX( dy[0], dy[3] ), dMAX( dz[0], dz[3] ) ); | ||
533 | |||
534 | // Y extents | ||
535 | aabb[2] = final_posr->pos[1] + | ||
536 | dMIN3( dMIN( dx[1], dx[4] ), dMIN( dy[1], dy[4] ), dMIN( dz[1], dz[4] ) ); | ||
537 | aabb[3] = final_posr->pos[1] + | ||
538 | dMAX3( dMAX( dx[1], dx[4] ), dMAX( dy[1], dy[4] ), dMAX( dz[1], dz[4] ) ); | ||
539 | |||
540 | // Z extents | ||
541 | aabb[4] = final_posr->pos[2] + | ||
542 | dMIN3( dMIN( dx[2], dx[5] ), dMIN( dy[2], dy[5] ), dMIN( dz[2], dz[5] ) ); | ||
543 | aabb[5] = final_posr->pos[2] + | ||
544 | dMAX3( dMAX( dx[2], dx[5] ), dMAX( dy[2], dy[5] ), dMAX( dz[2], dz[5] ) ); | ||
545 | } | ||
546 | else | ||
547 | { | ||
548 | |||
549 | #ifdef DHEIGHTFIELD_CORNER_ORIGIN | ||
550 | |||
551 | aabb[0] = 0; aabb[1] = d->m_fWidth; | ||
552 | aabb[2] = d->m_fMinHeight; aabb[3] = d->m_fMaxHeight; | ||
553 | aabb[4] = 0; aabb[5] = d->m_fDepth; | ||
554 | |||
555 | #else // DHEIGHTFIELD_CORNER_ORIGIN | ||
556 | |||
557 | aabb[0] = -d->m_fHalfWidth; aabb[1] = +d->m_fHalfWidth; | ||
558 | aabb[2] = d->m_fMinHeight; aabb[3] = d->m_fMaxHeight; | ||
559 | aabb[4] = -d->m_fHalfDepth; aabb[5] = +d->m_fHalfDepth; | ||
560 | |||
561 | #endif // DHEIGHTFIELD_CORNER_ORIGIN | ||
562 | |||
563 | } | ||
564 | } | ||
565 | else | ||
566 | { | ||
567 | // Infinite | ||
568 | if ( gflags & GEOM_PLACEABLE ) | ||
569 | { | ||
570 | aabb[0] = -dInfinity; aabb[1] = +dInfinity; | ||
571 | aabb[2] = -dInfinity; aabb[3] = +dInfinity; | ||
572 | aabb[4] = -dInfinity; aabb[5] = +dInfinity; | ||
573 | } | ||
574 | else | ||
575 | { | ||
576 | aabb[0] = -dInfinity; aabb[1] = +dInfinity; | ||
577 | aabb[2] = d->m_fMinHeight; aabb[3] = d->m_fMaxHeight; | ||
578 | aabb[4] = -dInfinity; aabb[5] = +dInfinity; | ||
579 | } | ||
580 | } | ||
581 | |||
582 | } | ||
583 | |||
584 | |||
585 | // dxHeightfield destructor | ||
586 | dxHeightfield::~dxHeightfield() | ||
587 | { | ||
588 | resetTriangleBuffer(); | ||
589 | resetPlaneBuffer(); | ||
590 | resetHeightBuffer(); | ||
591 | } | ||
592 | |||
593 | void dxHeightfield::allocateTriangleBuffer(size_t numTri) | ||
594 | { | ||
595 | size_t alignedNumTri = AlignBufferSize(numTri, TEMP_TRIANGLE_BUFFER_ELEMENT_COUNT_ALIGNMENT); | ||
596 | tempTriangleBufferSize = alignedNumTri; | ||
597 | tempTriangleBuffer = new HeightFieldTriangle[alignedNumTri]; | ||
598 | } | ||
599 | |||
600 | void dxHeightfield::resetTriangleBuffer() | ||
601 | { | ||
602 | delete[] tempTriangleBuffer; | ||
603 | } | ||
604 | |||
605 | void dxHeightfield::allocatePlaneBuffer(size_t numTri) | ||
606 | { | ||
607 | size_t alignedNumTri = AlignBufferSize(numTri, TEMP_PLANE_BUFFER_ELEMENT_COUNT_ALIGNMENT); | ||
608 | tempPlaneBufferSize = alignedNumTri; | ||
609 | tempPlaneBuffer = new HeightFieldPlane *[alignedNumTri]; | ||
610 | tempPlaneInstances = new HeightFieldPlane[alignedNumTri]; | ||
611 | |||
612 | HeightFieldPlane *ptrPlaneMatrix = tempPlaneInstances; | ||
613 | for (size_t indexTri = 0; indexTri != alignedNumTri; indexTri++) | ||
614 | { | ||
615 | tempPlaneBuffer[indexTri] = ptrPlaneMatrix; | ||
616 | ptrPlaneMatrix += 1; | ||
617 | } | ||
618 | } | ||
619 | |||
620 | void dxHeightfield::resetPlaneBuffer() | ||
621 | { | ||
622 | delete[] tempPlaneInstances; | ||
623 | delete[] tempPlaneBuffer; | ||
624 | } | ||
625 | |||
626 | void dxHeightfield::allocateHeightBuffer(size_t numX, size_t numZ) | ||
627 | { | ||
628 | size_t alignedNumX = AlignBufferSize(numX, TEMP_HEIGHT_BUFFER_ELEMENT_COUNT_ALIGNMENT_X); | ||
629 | size_t alignedNumZ = AlignBufferSize(numZ, TEMP_HEIGHT_BUFFER_ELEMENT_COUNT_ALIGNMENT_Z); | ||
630 | tempHeightBufferSizeX = alignedNumX; | ||
631 | tempHeightBufferSizeZ = alignedNumZ; | ||
632 | tempHeightBuffer = new HeightFieldVertex *[alignedNumX]; | ||
633 | size_t numCells = alignedNumX * alignedNumZ; | ||
634 | tempHeightInstances = new HeightFieldVertex [numCells]; | ||
635 | |||
636 | HeightFieldVertex *ptrHeightMatrix = tempHeightInstances; | ||
637 | for (size_t indexX = 0; indexX != alignedNumX; indexX++) | ||
638 | { | ||
639 | tempHeightBuffer[indexX] = ptrHeightMatrix; | ||
640 | ptrHeightMatrix += alignedNumZ; | ||
641 | } | ||
642 | } | ||
643 | |||
644 | void dxHeightfield::resetHeightBuffer() | ||
645 | { | ||
646 | delete[] tempHeightInstances; | ||
647 | delete[] tempHeightBuffer; | ||
648 | } | ||
649 | //////// Heightfield data interface //////////////////////////////////////////////////// | ||
650 | |||
651 | |||
652 | dHeightfieldDataID dGeomHeightfieldDataCreate() | ||
653 | { | ||
654 | return new dxHeightfieldData(); | ||
655 | } | ||
656 | |||
657 | |||
658 | void dGeomHeightfieldDataBuildCallback( dHeightfieldDataID d, | ||
659 | void* pUserData, dHeightfieldGetHeight* pCallback, | ||
660 | dReal width, dReal depth, int widthSamples, int depthSamples, | ||
661 | dReal scale, dReal offset, dReal thickness, int bWrap ) | ||
662 | { | ||
663 | dUASSERT( d, "argument not Heightfield data" ); | ||
664 | dIASSERT( pCallback ); | ||
665 | dIASSERT( widthSamples >= 2 ); // Ensure we're making something with at least one cell. | ||
666 | dIASSERT( depthSamples >= 2 ); | ||
667 | |||
668 | // callback | ||
669 | d->m_nGetHeightMode = 0; | ||
670 | d->m_pUserData = pUserData; | ||
671 | d->m_pGetHeightCallback = pCallback; | ||
672 | |||
673 | // set info | ||
674 | d->SetData( widthSamples, depthSamples, width, depth, scale, offset, thickness, bWrap ); | ||
675 | |||
676 | // default bounds | ||
677 | d->m_fMinHeight = -dInfinity; | ||
678 | d->m_fMaxHeight = dInfinity; | ||
679 | } | ||
680 | |||
681 | |||
682 | void dGeomHeightfieldDataBuildByte( dHeightfieldDataID d, | ||
683 | const unsigned char *pHeightData, int bCopyHeightData, | ||
684 | dReal width, dReal depth, int widthSamples, int depthSamples, | ||
685 | dReal scale, dReal offset, dReal thickness, int bWrap ) | ||
686 | { | ||
687 | dUASSERT( d, "Argument not Heightfield data" ); | ||
688 | dIASSERT( pHeightData ); | ||
689 | dIASSERT( widthSamples >= 2 ); // Ensure we're making something with at least one cell. | ||
690 | dIASSERT( depthSamples >= 2 ); | ||
691 | |||
692 | // set info | ||
693 | d->SetData( widthSamples, depthSamples, width, depth, scale, offset, thickness, bWrap ); | ||
694 | d->m_nGetHeightMode = 1; | ||
695 | d->m_bCopyHeightData = bCopyHeightData; | ||
696 | |||
697 | if ( d->m_bCopyHeightData == 0 ) | ||
698 | { | ||
699 | // Data is referenced only. | ||
700 | d->m_pHeightData = pHeightData; | ||
701 | } | ||
702 | else | ||
703 | { | ||
704 | // We own the height data, allocate storage | ||
705 | d->m_pHeightData = new unsigned char[ d->m_nWidthSamples * d->m_nDepthSamples ]; | ||
706 | dIASSERT( d->m_pHeightData ); | ||
707 | |||
708 | // Copy data. | ||
709 | memcpy( (void*)d->m_pHeightData, pHeightData, | ||
710 | sizeof( unsigned char ) * d->m_nWidthSamples * d->m_nDepthSamples ); | ||
711 | } | ||
712 | |||
713 | // Find height bounds | ||
714 | d->ComputeHeightBounds(); | ||
715 | } | ||
716 | |||
717 | |||
718 | void dGeomHeightfieldDataBuildShort( dHeightfieldDataID d, | ||
719 | const short* pHeightData, int bCopyHeightData, | ||
720 | dReal width, dReal depth, int widthSamples, int depthSamples, | ||
721 | dReal scale, dReal offset, dReal thickness, int bWrap ) | ||
722 | { | ||
723 | dUASSERT( d, "Argument not Heightfield data" ); | ||
724 | dIASSERT( pHeightData ); | ||
725 | dIASSERT( widthSamples >= 2 ); // Ensure we're making something with at least one cell. | ||
726 | dIASSERT( depthSamples >= 2 ); | ||
727 | |||
728 | // set info | ||
729 | d->SetData( widthSamples, depthSamples, width, depth, scale, offset, thickness, bWrap ); | ||
730 | d->m_nGetHeightMode = 2; | ||
731 | d->m_bCopyHeightData = bCopyHeightData; | ||
732 | |||
733 | if ( d->m_bCopyHeightData == 0 ) | ||
734 | { | ||
735 | // Data is referenced only. | ||
736 | d->m_pHeightData = pHeightData; | ||
737 | } | ||
738 | else | ||
739 | { | ||
740 | // We own the height data, allocate storage | ||
741 | d->m_pHeightData = new short[ d->m_nWidthSamples * d->m_nDepthSamples ]; | ||
742 | dIASSERT( d->m_pHeightData ); | ||
743 | |||
744 | // Copy data. | ||
745 | memcpy( (void*)d->m_pHeightData, pHeightData, | ||
746 | sizeof( short ) * d->m_nWidthSamples * d->m_nDepthSamples ); | ||
747 | } | ||
748 | |||
749 | // Find height bounds | ||
750 | d->ComputeHeightBounds(); | ||
751 | } | ||
752 | |||
753 | |||
754 | void dGeomHeightfieldDataBuildSingle( dHeightfieldDataID d, | ||
755 | const float *pHeightData, int bCopyHeightData, | ||
756 | dReal width, dReal depth, int widthSamples, int depthSamples, | ||
757 | dReal scale, dReal offset, dReal thickness, int bWrap ) | ||
758 | { | ||
759 | dUASSERT( d, "Argument not Heightfield data" ); | ||
760 | dIASSERT( pHeightData ); | ||
761 | dIASSERT( widthSamples >= 2 ); // Ensure we're making something with at least one cell. | ||
762 | dIASSERT( depthSamples >= 2 ); | ||
763 | |||
764 | // set info | ||
765 | d->SetData( widthSamples, depthSamples, width, depth, scale, offset, thickness, bWrap ); | ||
766 | d->m_nGetHeightMode = 3; | ||
767 | d->m_bCopyHeightData = bCopyHeightData; | ||
768 | |||
769 | if ( d->m_bCopyHeightData == 0 ) | ||
770 | { | ||
771 | // Data is referenced only. | ||
772 | d->m_pHeightData = pHeightData; | ||
773 | } | ||
774 | else | ||
775 | { | ||
776 | // We own the height data, allocate storage | ||
777 | d->m_pHeightData = new float[ d->m_nWidthSamples * d->m_nDepthSamples ]; | ||
778 | dIASSERT( d->m_pHeightData ); | ||
779 | |||
780 | // Copy data. | ||
781 | memcpy( (void*)d->m_pHeightData, pHeightData, | ||
782 | sizeof( float ) * d->m_nWidthSamples * d->m_nDepthSamples ); | ||
783 | } | ||
784 | |||
785 | // Find height bounds | ||
786 | d->ComputeHeightBounds(); | ||
787 | } | ||
788 | |||
789 | void dGeomHeightfieldDataBuildDouble( dHeightfieldDataID d, | ||
790 | const double *pHeightData, int bCopyHeightData, | ||
791 | dReal width, dReal depth, int widthSamples, int depthSamples, | ||
792 | dReal scale, dReal offset, dReal thickness, int bWrap ) | ||
793 | { | ||
794 | dUASSERT( d, "Argument not Heightfield data" ); | ||
795 | dIASSERT( pHeightData ); | ||
796 | dIASSERT( widthSamples >= 2 ); // Ensure we're making something with at least one cell. | ||
797 | dIASSERT( depthSamples >= 2 ); | ||
798 | |||
799 | // set info | ||
800 | d->SetData( widthSamples, depthSamples, width, depth, scale, offset, thickness, bWrap ); | ||
801 | d->m_nGetHeightMode = 4; | ||
802 | d->m_bCopyHeightData = bCopyHeightData; | ||
803 | |||
804 | if ( d->m_bCopyHeightData == 0 ) | ||
805 | { | ||
806 | // Data is referenced only. | ||
807 | d->m_pHeightData = pHeightData; | ||
808 | } | ||
809 | else | ||
810 | { | ||
811 | // We own the height data, allocate storage | ||
812 | d->m_pHeightData = new double[ d->m_nWidthSamples * d->m_nDepthSamples ]; | ||
813 | dIASSERT( d->m_pHeightData ); | ||
814 | |||
815 | // Copy data. | ||
816 | memcpy( (void*)d->m_pHeightData, pHeightData, | ||
817 | sizeof( double ) * d->m_nWidthSamples * d->m_nDepthSamples ); | ||
818 | } | ||
819 | |||
820 | // Find height bounds | ||
821 | d->ComputeHeightBounds(); | ||
822 | } | ||
823 | |||
824 | |||
825 | |||
826 | |||
827 | void dGeomHeightfieldDataSetBounds( dHeightfieldDataID d, dReal minHeight, dReal maxHeight ) | ||
828 | { | ||
829 | dUASSERT(d, "Argument not Heightfield data"); | ||
830 | d->m_fMinHeight = ( minHeight * d->m_fScale ) + d->m_fOffset - d->m_fThickness; | ||
831 | d->m_fMaxHeight = ( maxHeight * d->m_fScale ) + d->m_fOffset; | ||
832 | } | ||
833 | |||
834 | |||
835 | void dGeomHeightfieldDataDestroy( dHeightfieldDataID d ) | ||
836 | { | ||
837 | dUASSERT(d, "argument not Heightfield data"); | ||
838 | delete d; | ||
839 | } | ||
840 | |||
841 | |||
842 | //////// Heightfield geom interface //////////////////////////////////////////////////// | ||
843 | |||
844 | |||
845 | dGeomID dCreateHeightfield( dSpaceID space, dHeightfieldDataID data, int bPlaceable ) | ||
846 | { | ||
847 | return new dxHeightfield( space, data, bPlaceable ); | ||
848 | } | ||
849 | |||
850 | |||
851 | void dGeomHeightfieldSetHeightfieldData( dGeomID g, dHeightfieldDataID d ) | ||
852 | { | ||
853 | dxHeightfield* geom = (dxHeightfield*) g; | ||
854 | geom->data = d; | ||
855 | } | ||
856 | |||
857 | |||
858 | dHeightfieldDataID dGeomHeightfieldGetHeightfieldData( dGeomID g ) | ||
859 | { | ||
860 | dxHeightfield* geom = (dxHeightfield*) g; | ||
861 | return geom->m_p_data; | ||
862 | } | ||
863 | |||
864 | //////// dxHeightfield ///////////////////////////////////////////////////////////////// | ||
865 | |||
866 | |||
867 | // Typedef for generic 'get point depth' function | ||
868 | typedef dReal dGetDepthFn( dGeomID g, dReal x, dReal y, dReal z ); | ||
869 | |||
870 | |||
871 | #define DMESS(A) \ | ||
872 | dMessage(0,"Contact Plane (%d %d %d) %.5e %.5e (%.5e %.5e %.5e)(%.5e %.5e %.5e)).", \ | ||
873 | x,z,A, \ | ||
874 | pContact->depth, \ | ||
875 | dGeomSphereGetRadius(o2), \ | ||
876 | pContact->pos[0], \ | ||
877 | pContact->pos[1], \ | ||
878 | pContact->pos[2], \ | ||
879 | pContact->normal[0], \ | ||
880 | pContact->normal[1], \ | ||
881 | pContact->normal[2]); | ||
882 | |||
883 | static inline bool DescendingTriangleSort(const HeightFieldTriangle * const A, const HeightFieldTriangle * const B) | ||
884 | { | ||
885 | return ((A->maxAAAB - B->maxAAAB) > dEpsilon); | ||
886 | } | ||
887 | static inline bool DescendingPlaneSort(const HeightFieldPlane * const A, const HeightFieldPlane * const B) | ||
888 | { | ||
889 | return ((A->maxAAAB - B->maxAAAB) > dEpsilon); | ||
890 | } | ||
891 | |||
892 | void dxHeightfield::sortPlanes(const size_t numPlanes) | ||
893 | { | ||
894 | bool has_swapped = true; | ||
895 | do | ||
896 | { | ||
897 | has_swapped = false;//reset flag | ||
898 | for (size_t i = 0; i < numPlanes - 1; i++) | ||
899 | { | ||
900 | //if they are in the wrong order | ||
901 | if (DescendingPlaneSort(tempPlaneBuffer[i], tempPlaneBuffer[i + 1])) | ||
902 | { | ||
903 | //exchange them | ||
904 | HeightFieldPlane * tempPlane = tempPlaneBuffer[i]; | ||
905 | tempPlaneBuffer[i] = tempPlaneBuffer[i + 1]; | ||
906 | tempPlaneBuffer[i + 1] = tempPlane; | ||
907 | |||
908 | //we have swapped at least once, list may not be sorted yet | ||
909 | has_swapped = true; | ||
910 | } | ||
911 | } | ||
912 | } //if no swaps were made during this pass, the list has been sorted | ||
913 | while (has_swapped); | ||
914 | } | ||
915 | |||
916 | static inline dReal DistancePointToLine(const dVector3 &_point, | ||
917 | const dVector3 &_pt0, | ||
918 | const dVector3 &_Edge, | ||
919 | const dReal _Edgelength) | ||
920 | { | ||
921 | dVector3 v; | ||
922 | dVector3Subtract(_point, _pt0, v); | ||
923 | dVector3 s; | ||
924 | dVector3Copy (_Edge, s); | ||
925 | const dReal dot = dVector3Dot(v, _Edge) / _Edgelength; | ||
926 | dVector3Scale(s, dot); | ||
927 | dVector3Subtract(v, s, v); | ||
928 | return dVector3Length(v); | ||
929 | } | ||
930 | |||
931 | |||
932 | |||
933 | |||
934 | int dxHeightfield::dCollideHeightfieldZone( const int minX, const int maxX, const int minZ, const int maxZ, | ||
935 | dxGeom* o2, const int numMaxContactsPossible, | ||
936 | int flags, dContactGeom* contact, | ||
937 | int skip ) | ||
938 | { | ||
939 | dContactGeom *pContact = 0; | ||
940 | int x, z; | ||
941 | // check if not above or inside terrain first | ||
942 | // while filling a heightmap partial temporary buffer | ||
943 | const unsigned int numX = (maxX - minX) + 1; | ||
944 | const unsigned int numZ = (maxZ - minZ) + 1; | ||
945 | const dReal minO2Height = o2->aabb[2]; | ||
946 | const dReal maxO2Height = o2->aabb[3]; | ||
947 | unsigned int x_local, z_local; | ||
948 | dReal maxY = - dInfinity; | ||
949 | dReal minY = dInfinity; | ||
950 | // localize and const for faster access | ||
951 | const dReal cfSampleWidth = m_p_data->m_fSampleWidth; | ||
952 | const dReal cfSampleDepth = m_p_data->m_fSampleDepth; | ||
953 | { | ||
954 | if (tempHeightBufferSizeX < numX || tempHeightBufferSizeZ < numZ) | ||
955 | { | ||
956 | resetHeightBuffer(); | ||
957 | allocateHeightBuffer(numX, numZ); | ||
958 | } | ||
959 | |||
960 | dReal Xpos, Ypos; | ||
961 | Xpos = minX * cfSampleWidth; | ||
962 | |||
963 | |||
964 | for ( x = minX, x_local = 0; x_local < numX; x++, x_local++) | ||
965 | { | ||
966 | const dReal c_Xpos = Xpos; | ||
967 | HeightFieldVertex *HeightFieldRow = tempHeightBuffer[x_local]; | ||
968 | Ypos = minZ * cfSampleDepth; | ||
969 | for ( z = minZ, z_local = 0; z_local < numZ; z++, z_local++) | ||
970 | { | ||
971 | const dReal h = m_p_data->GetHeight(x, z); | ||
972 | HeightFieldRow[z_local].vertex[0] = c_Xpos; | ||
973 | HeightFieldRow[z_local].vertex[1] = h; | ||
974 | HeightFieldRow[z_local].vertex[2] = Ypos; | ||
975 | |||
976 | |||
977 | maxY = dMAX(maxY, h); | ||
978 | minY = dMIN(minY, h); | ||
979 | |||
980 | |||
981 | Ypos += cfSampleDepth; | ||
982 | } | ||
983 | Xpos += cfSampleWidth; | ||
984 | } | ||
985 | if (minO2Height - maxY > -dEpsilon ) | ||
986 | { | ||
987 | //totally above heightfield | ||
988 | return 0; | ||
989 | } | ||
990 | if (minY - maxO2Height > -dEpsilon ) | ||
991 | { | ||
992 | // totally under heightfield | ||
993 | pContact = CONTACT(contact, 0); | ||
994 | |||
995 | pContact->pos[0] = o2->final_posr->pos[0]; | ||
996 | pContact->pos[1] = minY; | ||
997 | pContact->pos[2] = o2->final_posr->pos[2]; | ||
998 | |||
999 | pContact->normal[0] = 0; | ||
1000 | pContact->normal[1] = - 1; | ||
1001 | pContact->normal[2] = 0; | ||
1002 | |||
1003 | pContact->depth = minY - maxO2Height; | ||
1004 | |||
1005 | return 1; | ||
1006 | } | ||
1007 | } | ||
1008 | // get All Planes that could collide against. | ||
1009 | dColliderFn *geomRayNCollider; | ||
1010 | dColliderFn *geomNPlaneCollider; | ||
1011 | dGetDepthFn *geomNDepthGetter; | ||
1012 | |||
1013 | // int max_collisionContact = numMaxContactsPossible; -- not used | ||
1014 | switch (o2->type) | ||
1015 | { | ||
1016 | case dRayClass: | ||
1017 | geomRayNCollider = NULL; | ||
1018 | geomNPlaneCollider = dCollideRayPlane; | ||
1019 | geomNDepthGetter = NULL; | ||
1020 | //max_collisionContact = 1; | ||
1021 | break; | ||
1022 | |||
1023 | case dSphereClass: | ||
1024 | geomRayNCollider = dCollideRaySphere; | ||
1025 | geomNPlaneCollider = dCollideSpherePlane; | ||
1026 | geomNDepthGetter = dGeomSpherePointDepth; | ||
1027 | //max_collisionContact = 3; | ||
1028 | break; | ||
1029 | |||
1030 | case dBoxClass: | ||
1031 | geomRayNCollider = dCollideRayBox; | ||
1032 | geomNPlaneCollider = dCollideBoxPlane; | ||
1033 | geomNDepthGetter = dGeomBoxPointDepth; | ||
1034 | //max_collisionContact = 8; | ||
1035 | break; | ||
1036 | |||
1037 | case dCapsuleClass: | ||
1038 | geomRayNCollider = dCollideRayCapsule; | ||
1039 | geomNPlaneCollider = dCollideCapsulePlane; | ||
1040 | geomNDepthGetter = dGeomCapsulePointDepth; | ||
1041 | // max_collisionContact = 3; | ||
1042 | break; | ||
1043 | |||
1044 | case dCylinderClass: | ||
1045 | geomRayNCollider = dCollideRayCylinder; | ||
1046 | geomNPlaneCollider = dCollideCylinderPlane; | ||
1047 | geomNDepthGetter = NULL;// TODO: dGeomCCylinderPointDepth | ||
1048 | //max_collisionContact = 3; | ||
1049 | break; | ||
1050 | |||
1051 | case dConvexClass: | ||
1052 | geomRayNCollider = dCollideRayConvex; | ||
1053 | geomNPlaneCollider = dCollideConvexPlane; | ||
1054 | geomNDepthGetter = NULL;// TODO: dGeomConvexPointDepth; | ||
1055 | //max_collisionContact = 3; | ||
1056 | break; | ||
1057 | |||
1058 | #if dTRIMESH_ENABLED | ||
1059 | |||
1060 | case dTriMeshClass: | ||
1061 | geomRayNCollider = dCollideRayTrimesh; | ||
1062 | geomNPlaneCollider = dCollideTrimeshPlane; | ||
1063 | geomNDepthGetter = NULL;// TODO: dGeomTrimeshPointDepth; | ||
1064 | //max_collisionContact = 3; | ||
1065 | break; | ||
1066 | |||
1067 | #endif // dTRIMESH_ENABLED | ||
1068 | |||
1069 | default: | ||
1070 | dIASSERT(0); // Shouldn't ever get here. | ||
1071 | break; | ||
1072 | |||
1073 | } | ||
1074 | |||
1075 | dxPlane myplane(0,0,0,0,0); | ||
1076 | dxPlane* sliding_plane = &myplane; | ||
1077 | dReal triplane[4]; | ||
1078 | int i; | ||
1079 | |||
1080 | // check some trivial case. | ||
1081 | // Vector Up plane | ||
1082 | if (maxY - minY < dEpsilon) | ||
1083 | { | ||
1084 | // it's a single plane. | ||
1085 | triplane[0] = 0; | ||
1086 | triplane[1] = 1; | ||
1087 | triplane[2] = 0; | ||
1088 | triplane[3] = minY; | ||
1089 | dGeomPlaneSetNoNormalize (sliding_plane, triplane); | ||
1090 | // find collision and compute contact points | ||
1091 | const int numTerrainContacts = geomNPlaneCollider (o2, sliding_plane, flags, contact, skip); | ||
1092 | dIASSERT(numTerrainContacts <= numMaxContactsPossible); | ||
1093 | for (i = 0; i < numTerrainContacts; i++) | ||
1094 | { | ||
1095 | pContact = CONTACT(contact, i*skip); | ||
1096 | dOPESIGN(pContact->normal, =, -, triplane); | ||
1097 | } | ||
1098 | return numTerrainContacts; | ||
1099 | } | ||
1100 | // unique plane | ||
1101 | { | ||
1102 | // check for very simple plane heightfield | ||
1103 | dReal minXHeightDelta = dInfinity, maxXHeightDelta = - dInfinity; | ||
1104 | dReal minZHeightDelta = dInfinity, maxZHeightDelta = - dInfinity; | ||
1105 | |||
1106 | |||
1107 | dReal lastXHeight = tempHeightBuffer[0][0].vertex[1]; | ||
1108 | for ( x_local = 1; x_local < numX; x_local++) | ||
1109 | { | ||
1110 | HeightFieldVertex *HeightFieldRow = tempHeightBuffer[x_local]; | ||
1111 | |||
1112 | const dReal deltaX = HeightFieldRow[0].vertex[1] - lastXHeight; | ||
1113 | |||
1114 | maxXHeightDelta = dMAX (maxXHeightDelta, deltaX); | ||
1115 | minXHeightDelta = dMIN (minXHeightDelta, deltaX); | ||
1116 | |||
1117 | dReal lastZHeight = HeightFieldRow[0].vertex[1]; | ||
1118 | for ( z_local = 1; z_local < numZ; z_local++) | ||
1119 | { | ||
1120 | const dReal deltaZ = (HeightFieldRow[z_local].vertex[1] - lastZHeight); | ||
1121 | |||
1122 | maxZHeightDelta = dMAX (maxZHeightDelta, deltaZ); | ||
1123 | minZHeightDelta = dMIN (minZHeightDelta, deltaZ); | ||
1124 | |||
1125 | } | ||
1126 | } | ||
1127 | |||
1128 | if (maxZHeightDelta - minZHeightDelta < dEpsilon && | ||
1129 | maxXHeightDelta - minXHeightDelta < dEpsilon ) | ||
1130 | { | ||
1131 | // it's a single plane. | ||
1132 | const dVector3 &A = tempHeightBuffer[0][0].vertex; | ||
1133 | const dVector3 &B = tempHeightBuffer[1][0].vertex; | ||
1134 | const dVector3 &C = tempHeightBuffer[0][1].vertex; | ||
1135 | |||
1136 | // define 2 edges and a point that will define collision plane | ||
1137 | { | ||
1138 | dVector3 Edge1, Edge2; | ||
1139 | dVector3Subtract(C, A, Edge1); | ||
1140 | dVector3Subtract(B, A, Edge2); | ||
1141 | dVector3Cross(Edge1, Edge2, triplane); | ||
1142 | } | ||
1143 | |||
1144 | // Define Plane | ||
1145 | // Normalize plane normal | ||
1146 | const dReal dinvlength = REAL(1.0) / dVector3Length(triplane); | ||
1147 | triplane[0] *= dinvlength; | ||
1148 | triplane[1] *= dinvlength; | ||
1149 | triplane[2] *= dinvlength; | ||
1150 | // get distance to origin from plane | ||
1151 | triplane[3] = dVector3Dot(triplane, A); | ||
1152 | |||
1153 | dGeomPlaneSetNoNormalize (sliding_plane, triplane); | ||
1154 | // find collision and compute contact points | ||
1155 | const int numTerrainContacts = geomNPlaneCollider (o2, sliding_plane, flags, contact, skip); | ||
1156 | dIASSERT(numTerrainContacts <= numMaxContactsPossible); | ||
1157 | for (i = 0; i < numTerrainContacts; i++) | ||
1158 | { | ||
1159 | pContact = CONTACT(contact, i*skip); | ||
1160 | dOPESIGN(pContact->normal, =, -, triplane); | ||
1161 | } | ||
1162 | return numTerrainContacts; | ||
1163 | } | ||
1164 | } | ||
1165 | |||
1166 | |||
1167 | int numTerrainContacts = 0; | ||
1168 | dContactGeom *PlaneContact = m_p_data->m_contacts; | ||
1169 | |||
1170 | const unsigned int numTriMax = (maxX - minX) * (maxZ - minZ) * 2; | ||
1171 | if (tempTriangleBufferSize < numTriMax) | ||
1172 | { | ||
1173 | resetTriangleBuffer(); | ||
1174 | allocateTriangleBuffer(numTriMax); | ||
1175 | } | ||
1176 | |||
1177 | // Sorting triangle/plane resulting from heightfield zone | ||
1178 | // Perhaps that would be necessary in case of too much limited | ||
1179 | // maximum contact point... | ||
1180 | // or in complex mesh case (trimesh and convex) | ||
1181 | // need some test or insights on this before enabling this. | ||
1182 | const bool isContactNumPointsLimited = | ||
1183 | true; | ||
1184 | // (numMaxContacts < 8) | ||
1185 | // || o2->type == dConvexClass | ||
1186 | // || o2->type == dTriMeshClass | ||
1187 | // || (numMaxContacts < (int)numTriMax) | ||
1188 | |||
1189 | |||
1190 | |||
1191 | // if small heightfield triangle related to O2 colliding | ||
1192 | // or no Triangle colliding at all. | ||
1193 | bool needFurtherPasses = (o2->type == dTriMeshClass); | ||
1194 | //compute Ratio between Triangle size and O2 aabb size | ||
1195 | // no FurtherPasses are needed in ray class | ||
1196 | if (o2->type != dRayClass && needFurtherPasses == false) | ||
1197 | { | ||
1198 | const dReal xratio = (o2->aabb[1] - o2->aabb[0]) * m_p_data->m_fInvSampleWidth; | ||
1199 | if (xratio > REAL(1.5)) | ||
1200 | needFurtherPasses = true; | ||
1201 | else | ||
1202 | { | ||
1203 | const dReal zratio = (o2->aabb[5] - o2->aabb[4]) * m_p_data->m_fInvSampleDepth; | ||
1204 | if (zratio > REAL(1.5)) | ||
1205 | needFurtherPasses = true; | ||
1206 | } | ||
1207 | |||
1208 | } | ||
1209 | |||
1210 | unsigned int numTri = 0; | ||
1211 | HeightFieldVertex *A, *B, *C, *D; | ||
1212 | /* (y is up) | ||
1213 | A--------B-...x | ||
1214 | | /| | ||
1215 | | / | | ||
1216 | | / | | ||
1217 | | / | | ||
1218 | | / | | ||
1219 | | / | | ||
1220 | | / | | ||
1221 | |/ | | ||
1222 | C--------D | ||
1223 | . | ||
1224 | . | ||
1225 | . | ||
1226 | z | ||
1227 | */ | ||
1228 | // keep only triangle that does intersect geom | ||
1229 | for ( x = minX, x_local = 0; x < maxX; x++, x_local++) | ||
1230 | { | ||
1231 | HeightFieldVertex *HeightFieldRow = tempHeightBuffer[x_local]; | ||
1232 | HeightFieldVertex *HeightFieldNextRow = tempHeightBuffer[x_local + 1]; | ||
1233 | |||
1234 | // First A | ||
1235 | C = &HeightFieldRow [0]; | ||
1236 | // First B | ||
1237 | D = &HeightFieldNextRow[0]; | ||
1238 | for ( z = minZ, z_local = 0; z < maxZ; z++, z_local++) | ||
1239 | { | ||
1240 | A = C; | ||
1241 | B = D; | ||
1242 | |||
1243 | C = &HeightFieldRow [z_local + 1]; | ||
1244 | D = &HeightFieldNextRow[z_local + 1]; | ||
1245 | |||
1246 | const dReal AHeight = A->vertex[1]; | ||
1247 | const dReal BHeight = B->vertex[1]; | ||
1248 | const dReal CHeight = C->vertex[1]; | ||
1249 | const dReal DHeight = D->vertex[1]; | ||
1250 | |||
1251 | const bool isACollide = 0 < AHeight - minO2Height; | ||
1252 | const bool isBCollide = 0 < BHeight - minO2Height; | ||
1253 | const bool isCCollide = 0 < CHeight - minO2Height; | ||
1254 | const bool isDCollide = 0 < DHeight - minO2Height; | ||
1255 | |||
1256 | A->state = !(isACollide); | ||
1257 | B->state = !(isBCollide); | ||
1258 | C->state = !(isCCollide); | ||
1259 | D->state = !(isCCollide); | ||
1260 | |||
1261 | if (isACollide || isBCollide || isCCollide) | ||
1262 | { | ||
1263 | HeightFieldTriangle * const CurrTriUp = &tempTriangleBuffer[numTri++]; | ||
1264 | |||
1265 | CurrTriUp->state = false; | ||
1266 | |||
1267 | // changing point order here implies to change it in isOnHeightField | ||
1268 | CurrTriUp->vertices[0] = A; | ||
1269 | CurrTriUp->vertices[1] = B; | ||
1270 | CurrTriUp->vertices[2] = C; | ||
1271 | |||
1272 | if (isContactNumPointsLimited) | ||
1273 | CurrTriUp->setMinMax(); | ||
1274 | CurrTriUp->isUp = true; | ||
1275 | } | ||
1276 | |||
1277 | if (isBCollide || isCCollide || isDCollide) | ||
1278 | { | ||
1279 | HeightFieldTriangle * const CurrTriDown = &tempTriangleBuffer[numTri++]; | ||
1280 | |||
1281 | CurrTriDown->state = false; | ||
1282 | // changing point order here implies to change it in isOnHeightField | ||
1283 | |||
1284 | CurrTriDown->vertices[0] = D; | ||
1285 | CurrTriDown->vertices[1] = B; | ||
1286 | CurrTriDown->vertices[2] = C; | ||
1287 | |||
1288 | |||
1289 | if (isContactNumPointsLimited) | ||
1290 | CurrTriDown->setMinMax(); | ||
1291 | CurrTriDown->isUp = false; | ||
1292 | } | ||
1293 | |||
1294 | |||
1295 | if (needFurtherPasses && | ||
1296 | (isBCollide || isCCollide) | ||
1297 | && | ||
1298 | (AHeight - CHeight > 0 && | ||
1299 | AHeight - BHeight > 0 && | ||
1300 | DHeight - CHeight > 0 && | ||
1301 | DHeight - BHeight > 0)) | ||
1302 | { | ||
1303 | // That means Edge BC is concave, therefore | ||
1304 | // BC Edge and B and C vertices cannot collide | ||
1305 | |||
1306 | B->state = true; | ||
1307 | C->state = true; | ||
1308 | } | ||
1309 | // should find a way to check other edges (AB, BD, CD) too for concavity | ||
1310 | } | ||
1311 | } | ||
1312 | |||
1313 | // at least on triangle should intersect geom | ||
1314 | dIASSERT (numTri != 0); | ||
1315 | // pass1: VS triangle as Planes | ||
1316 | // Group Triangle by same plane definition | ||
1317 | // as Terrain often has many triangles using same plane definition | ||
1318 | // then collide against that list of triangles. | ||
1319 | { | ||
1320 | |||
1321 | dVector3 Edge1, Edge2; | ||
1322 | //compute all triangles normals. | ||
1323 | for (unsigned int k = 0; k < numTri; k++) | ||
1324 | { | ||
1325 | HeightFieldTriangle * const itTriangle = &tempTriangleBuffer[k]; | ||
1326 | |||
1327 | // define 2 edges and a point that will define collision plane | ||
1328 | dVector3Subtract(itTriangle->vertices[2]->vertex, itTriangle->vertices[0]->vertex, Edge1); | ||
1329 | dVector3Subtract(itTriangle->vertices[1]->vertex, itTriangle->vertices[0]->vertex, Edge2); | ||
1330 | |||
1331 | // find a perpendicular vector to the triangle | ||
1332 | if (itTriangle->isUp) | ||
1333 | dVector3Cross(Edge1, Edge2, triplane); | ||
1334 | else | ||
1335 | dVector3Cross(Edge2, Edge1, triplane); | ||
1336 | |||
1337 | // Define Plane | ||
1338 | // Normalize plane normal | ||
1339 | const dReal dinvlength = REAL(1.0) / dVector3Length(triplane); | ||
1340 | triplane[0] *= dinvlength; | ||
1341 | triplane[1] *= dinvlength; | ||
1342 | triplane[2] *= dinvlength; | ||
1343 | // get distance to origin from plane | ||
1344 | triplane[3] = dVector3Dot(triplane, itTriangle->vertices[0]->vertex); | ||
1345 | |||
1346 | // saves normal for collision check (planes, triangles, vertices and edges.) | ||
1347 | dVector3Copy(triplane, itTriangle->planeDef); | ||
1348 | // saves distance for collision check (planes, triangles, vertices and edges.) | ||
1349 | itTriangle->planeDef[3] = triplane[3]; | ||
1350 | } | ||
1351 | |||
1352 | // group by Triangles by Planes sharing shame plane definition | ||
1353 | if (tempPlaneBufferSize < numTri) | ||
1354 | { | ||
1355 | resetPlaneBuffer(); | ||
1356 | allocatePlaneBuffer(numTri); | ||
1357 | } | ||
1358 | unsigned int numPlanes = 0; | ||
1359 | for (unsigned int k = 0; k < numTri; k++) | ||
1360 | { | ||
1361 | HeightFieldTriangle * const tri_base = &tempTriangleBuffer[k]; | ||
1362 | |||
1363 | if (tri_base->state == true) | ||
1364 | continue;// already tested or added to plane list. | ||
1365 | |||
1366 | HeightFieldPlane * const currPlane = tempPlaneBuffer[numPlanes]; | ||
1367 | currPlane->resetTriangleListSize(numTri - k); | ||
1368 | currPlane->addTriangle(tri_base); | ||
1369 | // saves normal for collision check (planes, triangles, vertices and edges.) | ||
1370 | dVector3Copy(tri_base->planeDef, currPlane->planeDef); | ||
1371 | // saves distance for collision check (planes, triangles, vertices and edges.) | ||
1372 | currPlane->planeDef[3]= tri_base->planeDef[3]; | ||
1373 | |||
1374 | const dReal normx = tri_base->planeDef[0]; | ||
1375 | const dReal normy = tri_base->planeDef[1]; | ||
1376 | const dReal normz = tri_base->planeDef[2]; | ||
1377 | const dReal dist = tri_base->planeDef[3]; | ||
1378 | |||
1379 | for (unsigned int m = k + 1; m < numTri; m++) | ||
1380 | { | ||
1381 | |||
1382 | HeightFieldTriangle * const tri_test = &tempTriangleBuffer[m]; | ||
1383 | if (tri_test->state == true) | ||
1384 | continue;// already tested or added to plane list. | ||
1385 | |||
1386 | // normals and distance are the same. | ||
1387 | if ( | ||
1388 | dFabs(normy - tri_test->planeDef[1]) < dEpsilon && | ||
1389 | dFabs(dist - tri_test->planeDef[3]) < dEpsilon && | ||
1390 | dFabs(normx - tri_test->planeDef[0]) < dEpsilon && | ||
1391 | dFabs(normz - tri_test->planeDef[2]) < dEpsilon | ||
1392 | ) | ||
1393 | { | ||
1394 | currPlane->addTriangle (tri_test); | ||
1395 | tri_test->state = true; | ||
1396 | } | ||
1397 | } | ||
1398 | |||
1399 | tri_base->state = true; | ||
1400 | if (isContactNumPointsLimited) | ||
1401 | currPlane->setMinMax(); | ||
1402 | |||
1403 | numPlanes++; | ||
1404 | } | ||
1405 | |||
1406 | // sort planes | ||
1407 | if (isContactNumPointsLimited) | ||
1408 | sortPlanes(numPlanes); | ||
1409 | |||
1410 | #if !defined(NO_CONTACT_CULLING_BY_ISONHEIGHTFIELD2) | ||
1411 | /* | ||
1412 | Note by Oleh_Derevenko: | ||
1413 | It seems to be incorrect to limit contact count by some particular value | ||
1414 | since some of them (and even all of them) may be culled in following condition. | ||
1415 | However I do not see an easy way to fix this. | ||
1416 | If not that culling the flags modification should be changed here and | ||
1417 | additionally repeated after some contacts have been generated (in "if (didCollide)"). | ||
1418 | The maximum of contacts in flags would then be set to minimum of contacts | ||
1419 | remaining and HEIGHTFIELDMAXCONTACTPERCELL. | ||
1420 | */ | ||
1421 | int planeTestFlags = (flags & ~NUMC_MASK) | HEIGHTFIELDMAXCONTACTPERCELL; | ||
1422 | dIASSERT((HEIGHTFIELDMAXCONTACTPERCELL & ~NUMC_MASK) == 0); | ||
1423 | #else // if defined(NO_CONTACT_CULLING_BY_ISONHEIGHTFIELD2) | ||
1424 | int numMaxContactsPerPlane = dMIN(numMaxContactsPossible - numTerrainContacts, HEIGHTFIELDMAXCONTACTPERCELL); | ||
1425 | int planeTestFlags = (flags & ~NUMC_MASK) | numMaxContactsPerPlane; | ||
1426 | dIASSERT((HEIGHTFIELDMAXCONTACTPERCELL & ~NUMC_MASK) == 0); | ||
1427 | #endif | ||
1428 | |||
1429 | for (unsigned int k = 0; k < numPlanes; k++) | ||
1430 | { | ||
1431 | HeightFieldPlane * const itPlane = tempPlaneBuffer[k]; | ||
1432 | |||
1433 | //set Geom | ||
1434 | dGeomPlaneSetNoNormalize (sliding_plane, itPlane->planeDef); | ||
1435 | //dGeomPlaneSetParams (sliding_plane, triangle_Plane[0], triangle_Plane[1], triangle_Plane[2], triangle_Plane[3]); | ||
1436 | // find collision and compute contact points | ||
1437 | bool didCollide = false; | ||
1438 | const int numPlaneContacts = geomNPlaneCollider (o2, sliding_plane, planeTestFlags, PlaneContact, sizeof(dContactGeom)); | ||
1439 | const size_t planeTriListSize = itPlane->trianglelistCurrentSize; | ||
1440 | for (i = 0; i < numPlaneContacts; i++) | ||
1441 | { | ||
1442 | // Check if contact point found in plane is inside Triangle. | ||
1443 | const dVector3 &pCPos = PlaneContact[i].pos; | ||
1444 | for (size_t b = 0; planeTriListSize > b; b++) | ||
1445 | { | ||
1446 | if (m_p_data->IsOnHeightfield2 (itPlane->trianglelist[b]->vertices[0]->vertex, | ||
1447 | pCPos, | ||
1448 | itPlane->trianglelist[b]->isUp)) | ||
1449 | { | ||
1450 | pContact = CONTACT(contact, numTerrainContacts*skip); | ||
1451 | dVector3Copy(pCPos, pContact->pos); | ||
1452 | dOPESIGN(pContact->normal, =, -, itPlane->planeDef); | ||
1453 | pContact->depth = PlaneContact[i].depth; | ||
1454 | numTerrainContacts++; | ||
1455 | if ( numTerrainContacts == numMaxContactsPossible ) | ||
1456 | return numTerrainContacts; | ||
1457 | |||
1458 | didCollide = true; | ||
1459 | break; | ||
1460 | } | ||
1461 | } | ||
1462 | } | ||
1463 | if (didCollide) | ||
1464 | { | ||
1465 | #if defined(NO_CONTACT_CULLING_BY_ISONHEIGHTFIELD2) | ||
1466 | /* Note by Oleh_Derevenko: | ||
1467 | This code is not used - see another note above | ||
1468 | */ | ||
1469 | numMaxContactsPerPlane = dMIN(numMaxContactsPossible - numTerrainContacts, HEIGHTFIELDMAXCONTACTPERCELL); | ||
1470 | planeTestFlags = (flags & ~NUMC_MASK) | numMaxContactsPerPlane; | ||
1471 | dIASSERT((HEIGHTFIELDMAXCONTACTPERCELL & ~NUMC_MASK) == 0); | ||
1472 | #endif | ||
1473 | for (size_t b = 0; planeTriListSize > b; b++) | ||
1474 | { | ||
1475 | // flag Triangles Vertices as collided | ||
1476 | // to prevent any collision test of those | ||
1477 | for (i = 0; i < 3; i++) | ||
1478 | itPlane->trianglelist[b]->vertices[i]->state = true; | ||
1479 | } | ||
1480 | } | ||
1481 | else | ||
1482 | { | ||
1483 | // flag triangle as not collided so that Vertices or Edge | ||
1484 | // of that triangles will be checked. | ||
1485 | for (size_t b = 0; planeTriListSize > b; b++) | ||
1486 | { | ||
1487 | itPlane->trianglelist[b]->state = false; | ||
1488 | } | ||
1489 | } | ||
1490 | } | ||
1491 | } | ||
1492 | |||
1493 | |||
1494 | |||
1495 | // pass2: VS triangle vertices | ||
1496 | if (needFurtherPasses) | ||
1497 | { | ||
1498 | dxRay tempRay(0, 1); | ||
1499 | dReal depth; | ||
1500 | bool vertexCollided; | ||
1501 | |||
1502 | // Only one contact is necessary for ray test | ||
1503 | int rayTestFlags = (flags & ~NUMC_MASK) | 1; | ||
1504 | dIASSERT((1 & ~NUMC_MASK) == 0); | ||
1505 | // | ||
1506 | // Find Contact Penetration Depth of each vertices | ||
1507 | // | ||
1508 | for (unsigned int k = 0; k < numTri; k++) | ||
1509 | { | ||
1510 | const HeightFieldTriangle * const itTriangle = &tempTriangleBuffer[k]; | ||
1511 | if (itTriangle->state == true) | ||
1512 | continue;// plane triangle did already collide. | ||
1513 | |||
1514 | for (size_t i = 0; i < 3; i++) | ||
1515 | { | ||
1516 | HeightFieldVertex *vertex = itTriangle->vertices[i]; | ||
1517 | if (vertex->state == true) | ||
1518 | continue;// vertice did already collide. | ||
1519 | |||
1520 | vertexCollided = false; | ||
1521 | const dVector3 &triVertex = vertex->vertex; | ||
1522 | if ( geomNDepthGetter ) | ||
1523 | { | ||
1524 | depth = geomNDepthGetter( o2, | ||
1525 | triVertex[0], triVertex[1], triVertex[2] ); | ||
1526 | if (depth + dEpsilon < 0) | ||
1527 | vertexCollided = true; | ||
1528 | } | ||
1529 | else | ||
1530 | { | ||
1531 | // We don't have a GetDepth function, so do a ray cast instead. | ||
1532 | // NOTE: This isn't ideal, and a GetDepth function should be | ||
1533 | // written for all geom classes. | ||
1534 | tempRay.length = (minO2Height - triVertex[1]) * REAL(1000.0); | ||
1535 | |||
1536 | //dGeomRaySet( &tempRay, pContact->pos[0], pContact->pos[1], pContact->pos[2], | ||
1537 | // - itTriangle->Normal[0], - itTriangle->Normal[1], - itTriangle->Normal[2] ); | ||
1538 | dGeomRaySetNoNormalize(tempRay, triVertex, itTriangle->planeDef); | ||
1539 | |||
1540 | if ( geomRayNCollider( &tempRay, o2, rayTestFlags, PlaneContact, sizeof( dContactGeom ) ) ) | ||
1541 | { | ||
1542 | depth = PlaneContact[0].depth; | ||
1543 | vertexCollided = true; | ||
1544 | } | ||
1545 | } | ||
1546 | if (vertexCollided) | ||
1547 | { | ||
1548 | pContact = CONTACT(contact, numTerrainContacts*skip); | ||
1549 | //create contact using vertices | ||
1550 | dVector3Copy (triVertex, pContact->pos); | ||
1551 | //create contact using Plane Normal | ||
1552 | dOPESIGN(pContact->normal, =, -, itTriangle->planeDef); | ||
1553 | |||
1554 | pContact->depth = depth; | ||
1555 | |||
1556 | numTerrainContacts++; | ||
1557 | if ( numTerrainContacts == numMaxContactsPossible ) | ||
1558 | return numTerrainContacts; | ||
1559 | |||
1560 | vertex->state = true; | ||
1561 | } | ||
1562 | } | ||
1563 | } | ||
1564 | } | ||
1565 | |||
1566 | #ifdef _HEIGHTFIELDEDGECOLLIDING | ||
1567 | // pass3: VS triangle Edges | ||
1568 | if (needFurtherPasses) | ||
1569 | { | ||
1570 | dVector3 Edge; | ||
1571 | dxRay edgeRay(0, 1); | ||
1572 | |||
1573 | int numMaxContactsPerTri = dMIN(numMaxContactsPossible - numTerrainContacts, HEIGHTFIELDMAXCONTACTPERCELL); | ||
1574 | int triTestFlags = (flags & ~NUMC_MASK) | numMaxContactsPerTri; | ||
1575 | dIASSERT((HEIGHTFIELDMAXCONTACTPERCELL & ~NUMC_MASK) == 0); | ||
1576 | |||
1577 | for (unsigned int k = 0; k < numTri; k++) | ||
1578 | { | ||
1579 | const HeightFieldTriangle * const itTriangle = &tempTriangleBuffer[k]; | ||
1580 | |||
1581 | if (itTriangle->state == true) | ||
1582 | continue;// plane did already collide. | ||
1583 | |||
1584 | for (size_t m = 0; m < 3; m++) | ||
1585 | { | ||
1586 | const size_t next = (m + 1) % 3; | ||
1587 | HeightFieldVertex *vertex0 = itTriangle->vertices[m]; | ||
1588 | HeightFieldVertex *vertex1 = itTriangle->vertices[next]; | ||
1589 | |||
1590 | // not concave or under the AABB | ||
1591 | // nor triangle already collided against vertices | ||
1592 | if (vertex0->state == true && vertex1->state == true) | ||
1593 | continue;// plane did already collide. | ||
1594 | |||
1595 | dVector3Subtract(vertex1->vertex, vertex0->vertex, Edge); | ||
1596 | edgeRay.length = dVector3Length (Edge); | ||
1597 | dGeomRaySetNoNormalize(edgeRay, vertex1->vertex, Edge); | ||
1598 | int prevTerrainContacts = numTerrainContacts; | ||
1599 | pContact = CONTACT(contact, prevTerrainContacts*skip); | ||
1600 | const int numCollision = geomRayNCollider(&edgeRay,o2,triTestFlags,pContact,skip); | ||
1601 | dIASSERT(numCollision <= numMaxContactsPerTri); | ||
1602 | |||
1603 | if (numCollision) | ||
1604 | { | ||
1605 | numTerrainContacts += numCollision; | ||
1606 | |||
1607 | do | ||
1608 | { | ||
1609 | pContact = CONTACT(contact, prevTerrainContacts*skip); | ||
1610 | |||
1611 | //create contact using Plane Normal | ||
1612 | dOPESIGN(pContact->normal, =, -, itTriangle->planeDef); | ||
1613 | |||
1614 | pContact->depth = DistancePointToLine(pContact->pos, vertex1->vertex, Edge, edgeRay.length); | ||
1615 | } | ||
1616 | while (++prevTerrainContacts != numTerrainContacts); | ||
1617 | |||
1618 | if ( numTerrainContacts == numMaxContactsPossible ) | ||
1619 | return numTerrainContacts; | ||
1620 | |||
1621 | numMaxContactsPerTri = dMIN(numMaxContactsPossible - numTerrainContacts, HEIGHTFIELDMAXCONTACTPERCELL); | ||
1622 | triTestFlags = (flags & ~NUMC_MASK) | numMaxContactsPerTri; | ||
1623 | dIASSERT((HEIGHTFIELDMAXCONTACTPERCELL & ~NUMC_MASK) == 0); | ||
1624 | } | ||
1625 | } | ||
1626 | |||
1627 | itTriangle->vertices[0]->state = true; | ||
1628 | itTriangle->vertices[1]->state = true; | ||
1629 | itTriangle->vertices[2]->state = true; | ||
1630 | } | ||
1631 | } | ||
1632 | #endif // _HEIGHTFIELDEDGECOLLIDING | ||
1633 | return numTerrainContacts; | ||
1634 | } | ||
1635 | |||
1636 | int dCollideHeightfield( dxGeom *o1, dxGeom *o2, int flags, dContactGeom* contact, int skip ) | ||
1637 | { | ||
1638 | dIASSERT( skip >= (int)sizeof(dContactGeom) ); | ||
1639 | dIASSERT( o1->type == dHeightfieldClass ); | ||
1640 | dIASSERT((flags & NUMC_MASK) >= 1); | ||
1641 | |||
1642 | int i; | ||
1643 | |||
1644 | // if ((flags & NUMC_MASK) == 0) -- An assertion check is made on entry | ||
1645 | // { flags = (flags & ~NUMC_MASK) | 1; dIASSERT((1 & ~NUMC_MASK) == 0); } | ||
1646 | |||
1647 | int numMaxTerrainContacts = (flags & NUMC_MASK); | ||
1648 | |||
1649 | dxHeightfield *terrain = (dxHeightfield*) o1; | ||
1650 | |||
1651 | dVector3 posbak; | ||
1652 | dMatrix3 Rbak; | ||
1653 | dReal aabbbak[6]; | ||
1654 | int gflagsbak; | ||
1655 | dVector3 pos0,pos1; | ||
1656 | dMatrix3 R1; | ||
1657 | |||
1658 | int numTerrainContacts = 0; | ||
1659 | |||
1660 | //@@ Should find a way to set reComputeAABB to false in default case | ||
1661 | // aka DHEIGHTFIELD_CORNER_ORIGIN not defined and terrain not PLACEABLE | ||
1662 | // so that we can free some memory and speed up things a bit | ||
1663 | // while saving some precision loss | ||
1664 | #ifndef DHEIGHTFIELD_CORNER_ORIGIN | ||
1665 | const bool reComputeAABB = true; | ||
1666 | #else | ||
1667 | const bool reComputeAABB = ( terrain->gflags & GEOM_PLACEABLE ) ? true : false; | ||
1668 | #endif //DHEIGHTFIELD_CORNER_ORIGIN | ||
1669 | |||
1670 | // | ||
1671 | // Transform O2 into Heightfield Space | ||
1672 | // | ||
1673 | if (reComputeAABB) | ||
1674 | { | ||
1675 | // Backup original o2 position, rotation and AABB. | ||
1676 | dVector3Copy( o2->final_posr->pos, posbak ); | ||
1677 | dMatrix3Copy( o2->final_posr->R, Rbak ); | ||
1678 | memcpy( aabbbak, o2->aabb, sizeof( dReal ) * 6 ); | ||
1679 | gflagsbak = o2->gflags; | ||
1680 | } | ||
1681 | |||
1682 | if ( terrain->gflags & GEOM_PLACEABLE ) | ||
1683 | { | ||
1684 | // Transform o2 into heightfield space. | ||
1685 | dOP( pos0, -, o2->final_posr->pos, terrain->final_posr->pos ); | ||
1686 | dMULTIPLY1_331( pos1, terrain->final_posr->R, pos0 ); | ||
1687 | dMULTIPLY1_333( R1, terrain->final_posr->R, o2->final_posr->R ); | ||
1688 | |||
1689 | // Update o2 with transformed position and rotation. | ||
1690 | dVector3Copy( pos1, o2->final_posr->pos ); | ||
1691 | dMatrix3Copy( R1, o2->final_posr->R ); | ||
1692 | } | ||
1693 | |||
1694 | #ifndef DHEIGHTFIELD_CORNER_ORIGIN | ||
1695 | o2->final_posr->pos[ 0 ] += terrain->m_p_data->m_fHalfWidth; | ||
1696 | o2->final_posr->pos[ 2 ] += terrain->m_p_data->m_fHalfDepth; | ||
1697 | #endif // DHEIGHTFIELD_CORNER_ORIGIN | ||
1698 | |||
1699 | // Rebuild AABB for O2 | ||
1700 | if (reComputeAABB) | ||
1701 | o2->computeAABB(); | ||
1702 | |||
1703 | // | ||
1704 | // Collide | ||
1705 | // | ||
1706 | |||
1707 | //check if inside boundaries | ||
1708 | // using O2 aabb | ||
1709 | // aabb[6] is (minx, maxx, miny, maxy, minz, maxz) | ||
1710 | const bool wrapped = terrain->m_p_data->m_bWrapMode != 0; | ||
1711 | |||
1712 | int nMinX; | ||
1713 | int nMaxX; | ||
1714 | int nMinZ; | ||
1715 | int nMaxZ; | ||
1716 | |||
1717 | if ( !wrapped ) | ||
1718 | { | ||
1719 | if ( o2->aabb[0] > terrain->m_p_data->m_fWidth //MinX | ||
1720 | && o2->aabb[4] > terrain->m_p_data->m_fDepth)//MinZ | ||
1721 | goto dCollideHeightfieldExit; | ||
1722 | |||
1723 | if ( o2->aabb[1] < 0 //MaxX | ||
1724 | && o2->aabb[5] < 0) //MaxZ | ||
1725 | goto dCollideHeightfieldExit; | ||
1726 | |||
1727 | } | ||
1728 | |||
1729 | nMinX = int(dFloor(o2->aabb[0] * terrain->m_p_data->m_fInvSampleWidth)); | ||
1730 | nMaxX = int(dFloor(o2->aabb[1] * terrain->m_p_data->m_fInvSampleWidth)) + 1; | ||
1731 | nMinZ = int(dFloor(o2->aabb[4] * terrain->m_p_data->m_fInvSampleDepth)); | ||
1732 | nMaxZ = int(dFloor(o2->aabb[5] * terrain->m_p_data->m_fInvSampleDepth)) + 1; | ||
1733 | |||
1734 | if ( !wrapped ) | ||
1735 | { | ||
1736 | nMinX = dMAX( nMinX, 0 ); | ||
1737 | nMaxX = dMIN( nMaxX, terrain->m_p_data->m_nWidthSamples - 1 ); | ||
1738 | nMinZ = dMAX( nMinZ, 0 ); | ||
1739 | nMaxZ = dMIN( nMaxZ, terrain->m_p_data->m_nDepthSamples - 1 ); | ||
1740 | |||
1741 | dIASSERT ((nMinX < nMaxX) || (nMinZ < nMaxZ)) | ||
1742 | } | ||
1743 | |||
1744 | |||
1745 | |||
1746 | numTerrainContacts += terrain->dCollideHeightfieldZone( | ||
1747 | nMinX,nMaxX,nMinZ,nMaxZ,o2,numMaxTerrainContacts - numTerrainContacts, | ||
1748 | flags,CONTACT(contact,numTerrainContacts*skip),skip ); | ||
1749 | |||
1750 | dIASSERT( numTerrainContacts <= numMaxTerrainContacts ); | ||
1751 | |||
1752 | dContactGeom *pContact; | ||
1753 | for ( i = 0; i < numTerrainContacts; ++i ) | ||
1754 | { | ||
1755 | pContact = CONTACT(contact,i*skip); | ||
1756 | pContact->g1 = o1; | ||
1757 | pContact->g2 = o2; | ||
1758 | } | ||
1759 | |||
1760 | |||
1761 | //------------------------------------------------------------------------------ | ||
1762 | |||
1763 | dCollideHeightfieldExit: | ||
1764 | |||
1765 | if (reComputeAABB) | ||
1766 | { | ||
1767 | // Restore o2 position, rotation and AABB | ||
1768 | dVector3Copy( posbak, o2->final_posr->pos ); | ||
1769 | dMatrix3Copy( Rbak, o2->final_posr->R ); | ||
1770 | memcpy( o2->aabb, aabbbak, sizeof(dReal)*6 ); | ||
1771 | o2->gflags = gflagsbak; | ||
1772 | |||
1773 | // | ||
1774 | // Transform Contacts to World Space | ||
1775 | // | ||
1776 | if ( terrain->gflags & GEOM_PLACEABLE ) | ||
1777 | { | ||
1778 | for ( i = 0; i < numTerrainContacts; ++i ) | ||
1779 | { | ||
1780 | pContact = CONTACT(contact,i*skip); | ||
1781 | dOPE( pos0, =, pContact->pos ); | ||
1782 | |||
1783 | #ifndef DHEIGHTFIELD_CORNER_ORIGIN | ||
1784 | pos0[ 0 ] -= terrain->m_p_data->m_fHalfWidth; | ||
1785 | pos0[ 2 ] -= terrain->m_p_data->m_fHalfDepth; | ||
1786 | #endif // !DHEIGHTFIELD_CORNER_ORIGIN | ||
1787 | |||
1788 | dMULTIPLY0_331( pContact->pos, terrain->final_posr->R, pos0 ); | ||
1789 | |||
1790 | dOP( pContact->pos, +, pContact->pos, terrain->final_posr->pos ); | ||
1791 | dOPE( pos0, =, pContact->normal ); | ||
1792 | |||
1793 | dMULTIPLY0_331( pContact->normal, terrain->final_posr->R, pos0 ); | ||
1794 | } | ||
1795 | } | ||
1796 | #ifndef DHEIGHTFIELD_CORNER_ORIGIN | ||
1797 | else | ||
1798 | { | ||
1799 | for ( i = 0; i < numTerrainContacts; ++i ) | ||
1800 | { | ||
1801 | pContact = CONTACT(contact,i*skip); | ||
1802 | pContact->pos[ 0 ] -= terrain->m_p_data->m_fHalfWidth; | ||
1803 | pContact->pos[ 2 ] -= terrain->m_p_data->m_fHalfDepth; | ||
1804 | } | ||
1805 | } | ||
1806 | #endif // !DHEIGHTFIELD_CORNER_ORIGIN | ||
1807 | } | ||
1808 | // Return contact count. | ||
1809 | return numTerrainContacts; | ||
1810 | } | ||
1811 | |||
1812 | |||