[216] | 1 | //Benoit CHAPEROT 2003-2004 www.jstarlab.com |
---|
| 2 | //some code inspired by Magic Software |
---|
| 3 | #include <ode/common.h> |
---|
| 4 | #include <ode/collision.h> |
---|
| 5 | #include <ode/matrix.h> |
---|
| 6 | #include <ode/rotation.h> |
---|
| 7 | #include <ode/odemath.h> |
---|
| 8 | #include "collision_kernel.h" |
---|
| 9 | #include "collision_std.h" |
---|
| 10 | #include "collision_std_internal.h" |
---|
| 11 | #include "collision_util.h" |
---|
| 12 | //#include <drawstuff/drawstuff.h> |
---|
| 13 | #include "windows.h" |
---|
| 14 | #include "ode\ode.h" |
---|
| 15 | |
---|
| 16 | #define CONTACT(p,skip) ((dContactGeom*) (((char*)p) + (skip))) |
---|
| 17 | #define MAXCONTACT 10 |
---|
| 18 | #define TERRAINTOL 0.0f |
---|
| 19 | |
---|
| 20 | static bool IsAPowerOfTwo(int f) |
---|
| 21 | { |
---|
| 22 | dAASSERT(f!=0); |
---|
| 23 | while ((f&1) != 1) |
---|
| 24 | f >>= 1; |
---|
| 25 | |
---|
| 26 | return (f == 1); |
---|
| 27 | } |
---|
| 28 | |
---|
| 29 | static int GetPowerOfTwo(int f) |
---|
| 30 | { |
---|
| 31 | dAASSERT(f!=0); |
---|
| 32 | int n = 0; |
---|
| 33 | while ((f&1) != 1) |
---|
| 34 | { |
---|
| 35 | n++; |
---|
| 36 | f >>= 1; |
---|
| 37 | } |
---|
| 38 | |
---|
| 39 | return n; |
---|
| 40 | } |
---|
| 41 | |
---|
| 42 | dxTerrainY::dxTerrainY (dSpaceID space, dReal *pHeights,dReal vLength,int nNumNodesPerSide, int bFinite, int bPlaceable) : |
---|
| 43 | dxGeom (space,bPlaceable) |
---|
| 44 | { |
---|
| 45 | dIASSERT(IsAPowerOfTwo(nNumNodesPerSide)); |
---|
| 46 | dIASSERT(pHeights); |
---|
| 47 | dIASSERT(vLength > 0.f); |
---|
| 48 | dIASSERT(nNumNodesPerSide > 0); |
---|
| 49 | type = dTerrainYClass; |
---|
| 50 | m_vLength = vLength; |
---|
| 51 | m_pHeights = new dReal[nNumNodesPerSide * nNumNodesPerSide]; |
---|
| 52 | dIASSERT(m_pHeights); |
---|
| 53 | m_nNumNodesPerSide = nNumNodesPerSide; |
---|
| 54 | m_vNodeLength = m_vLength / m_nNumNodesPerSide; |
---|
| 55 | m_nNumNodesPerSideShift = GetPowerOfTwo(m_nNumNodesPerSide); |
---|
| 56 | m_nNumNodesPerSideMask = m_nNumNodesPerSide - 1; |
---|
| 57 | m_vMinHeight = dInfinity; |
---|
| 58 | m_vMaxHeight = -dInfinity; |
---|
| 59 | m_bFinite = bFinite; |
---|
| 60 | |
---|
| 61 | for (int i=0;i<nNumNodesPerSide * nNumNodesPerSide;i++) |
---|
| 62 | { |
---|
| 63 | m_pHeights[i] = pHeights[i]; |
---|
| 64 | if (m_pHeights[i] < m_vMinHeight) m_vMinHeight = m_pHeights[i]; |
---|
| 65 | if (m_pHeights[i] > m_vMaxHeight) m_vMaxHeight = m_pHeights[i]; |
---|
| 66 | } |
---|
| 67 | } |
---|
| 68 | |
---|
| 69 | dxTerrainY::~dxTerrainY() |
---|
| 70 | { |
---|
| 71 | dIASSERT(m_pHeights); |
---|
| 72 | delete [] m_pHeights; |
---|
| 73 | } |
---|
| 74 | |
---|
| 75 | void dxTerrainY::computeAABB() |
---|
| 76 | { |
---|
| 77 | if (m_bFinite) |
---|
| 78 | { |
---|
| 79 | if (gflags & GEOM_PLACEABLE) |
---|
| 80 | { |
---|
| 81 | dReal dx[6],dy[6],dz[6]; |
---|
| 82 | dx[0] = 0; |
---|
| 83 | dx[1] = final_posr->R[0] * m_vLength; |
---|
| 84 | dx[2] = final_posr->R[1] * m_vMinHeight; |
---|
| 85 | dx[3] = final_posr->R[1] * m_vMaxHeight; |
---|
| 86 | dx[4] = 0; |
---|
| 87 | dx[5] = final_posr->R[2] * m_vLength; |
---|
| 88 | |
---|
| 89 | dy[0] = 0; |
---|
| 90 | dy[1] = final_posr->R[4] * m_vLength; |
---|
| 91 | dy[2] = final_posr->R[5] * m_vMinHeight; |
---|
| 92 | dy[3] = final_posr->R[5] * m_vMaxHeight; |
---|
| 93 | dy[4] = 0; |
---|
| 94 | dy[5] = final_posr->R[6] * m_vLength; |
---|
| 95 | |
---|
| 96 | dz[0] = 0; |
---|
| 97 | dz[1] = final_posr->R[8] * m_vLength; |
---|
| 98 | dz[2] = final_posr->R[9] * m_vMinHeight; |
---|
| 99 | dz[3] = final_posr->R[9] * m_vMaxHeight; |
---|
| 100 | dz[4] = 0; |
---|
| 101 | dz[5] = final_posr->R[10] * m_vLength; |
---|
| 102 | |
---|
| 103 | aabb[0] = final_posr->pos[0] + MIN(dx[0],dx[1]) + MIN(dx[2],dx[3]) + MIN(dx[4],dx[5]); |
---|
| 104 | aabb[1] = final_posr->pos[0] + MAX(dx[0],dx[1]) + MAX(dx[2],dx[3]) + MAX(dx[4],dx[5]); |
---|
| 105 | aabb[2] = final_posr->pos[1] + MIN(dy[0],dy[1]) + MIN(dy[2],dy[3]) + MIN(dy[4],dy[5]); |
---|
| 106 | aabb[3] = final_posr->pos[1] + MAX(dy[0],dy[1]) + MAX(dy[2],dy[3]) + MAX(dy[4],dy[5]); |
---|
| 107 | aabb[4] = final_posr->pos[2] + MIN(dz[0],dz[1]) + MIN(dz[2],dz[3]) + MIN(dz[4],dz[5]); |
---|
| 108 | aabb[5] = final_posr->pos[2] + MAX(dz[0],dz[1]) + MAX(dz[2],dz[3]) + MAX(dz[4],dz[5]); |
---|
| 109 | } |
---|
| 110 | else |
---|
| 111 | { |
---|
| 112 | aabb[0] = 0; |
---|
| 113 | aabb[1] = m_vLength; |
---|
| 114 | aabb[2] = m_vMinHeight; |
---|
| 115 | aabb[3] = m_vMaxHeight; |
---|
| 116 | aabb[4] = 0; |
---|
| 117 | aabb[5] = m_vLength; |
---|
| 118 | } |
---|
| 119 | } |
---|
| 120 | else |
---|
| 121 | { |
---|
| 122 | if (gflags & GEOM_PLACEABLE) |
---|
| 123 | { |
---|
| 124 | aabb[0] = -dInfinity; |
---|
| 125 | aabb[1] = dInfinity; |
---|
| 126 | aabb[2] = -dInfinity; |
---|
| 127 | aabb[3] = dInfinity; |
---|
| 128 | aabb[4] = -dInfinity; |
---|
| 129 | aabb[5] = dInfinity; |
---|
| 130 | } |
---|
| 131 | else |
---|
| 132 | { |
---|
| 133 | aabb[0] = -dInfinity; |
---|
| 134 | aabb[1] = dInfinity; |
---|
| 135 | aabb[2] = m_vMinHeight; |
---|
| 136 | aabb[3] = m_vMaxHeight; |
---|
| 137 | aabb[4] = -dInfinity; |
---|
| 138 | aabb[5] = dInfinity; |
---|
| 139 | } |
---|
| 140 | } |
---|
| 141 | } |
---|
| 142 | |
---|
| 143 | dReal dxTerrainY::GetHeight(int x,int z) |
---|
| 144 | { |
---|
| 145 | return m_pHeights[ (((unsigned int)(z) & m_nNumNodesPerSideMask) << m_nNumNodesPerSideShift) |
---|
| 146 | + ((unsigned int)(x) & m_nNumNodesPerSideMask)]; |
---|
| 147 | } |
---|
| 148 | |
---|
| 149 | dReal dxTerrainY::GetHeight(dReal x,dReal z) |
---|
| 150 | { |
---|
| 151 | int nX = int(floor(x / m_vNodeLength)); |
---|
| 152 | int nZ = int(floor(z / m_vNodeLength)); |
---|
| 153 | dReal dx = (x - (dReal(nX) * m_vNodeLength)) / m_vNodeLength; |
---|
| 154 | dReal dz = (z - (dReal(nZ) * m_vNodeLength)) / m_vNodeLength; |
---|
| 155 | dIASSERT((dx >= 0.f) && (dx <= 1.f)); |
---|
| 156 | dIASSERT((dz >= 0.f) && (dz <= 1.f)); |
---|
| 157 | |
---|
| 158 | dReal y,y0; |
---|
| 159 | |
---|
| 160 | if (dx + dz < 1.f) |
---|
| 161 | { |
---|
| 162 | y0 = GetHeight(nX,nZ); |
---|
| 163 | y = y0 |
---|
| 164 | + (GetHeight(nX+1,nZ) - y0) * dx |
---|
| 165 | + (GetHeight(nX,nZ+1) - y0) * dz; |
---|
| 166 | } |
---|
| 167 | else |
---|
| 168 | { |
---|
| 169 | y0 = GetHeight(nX+1,nZ+1); |
---|
| 170 | y = y0 |
---|
| 171 | + (GetHeight(nX+1,nZ) - y0) * (1.f - dz) |
---|
| 172 | + (GetHeight(nX,nZ+1) - y0) * (1.f - dx); |
---|
| 173 | } |
---|
| 174 | |
---|
| 175 | return y; |
---|
| 176 | } |
---|
| 177 | |
---|
| 178 | bool dxTerrainY::IsOnTerrain(int nx,int nz,int w,dReal *pos) |
---|
| 179 | { |
---|
| 180 | dVector3 Min,Max; |
---|
| 181 | Min[0] = nx * m_vNodeLength; |
---|
| 182 | Min[2] = nz * m_vNodeLength; |
---|
| 183 | Max[0] = (nx+1) * m_vNodeLength; |
---|
| 184 | Max[2] = (nz+1) * m_vNodeLength; |
---|
| 185 | dReal Tol = m_vNodeLength * TERRAINTOL; |
---|
| 186 | |
---|
| 187 | if ((pos[0]<Min[0]-Tol) || (pos[0]>Max[0]+Tol)) |
---|
| 188 | return false; |
---|
| 189 | |
---|
| 190 | if ((pos[2]<Min[2]-Tol) || (pos[2]>Max[2]+Tol)) |
---|
| 191 | return false; |
---|
| 192 | |
---|
| 193 | dReal dx = (pos[0] - (dReal(nx) * m_vNodeLength)) / m_vNodeLength; |
---|
| 194 | dReal dz = (pos[2] - (dReal(nz) * m_vNodeLength)) / m_vNodeLength; |
---|
| 195 | |
---|
| 196 | if ((w == 0) && (dx + dz > 1.f+TERRAINTOL)) |
---|
| 197 | return false; |
---|
| 198 | |
---|
| 199 | if ((w == 1) && (dx + dz < 1.f-TERRAINTOL)) |
---|
| 200 | return false; |
---|
| 201 | |
---|
| 202 | return true; |
---|
| 203 | } |
---|
| 204 | |
---|
| 205 | dGeomID dCreateTerrainY(dSpaceID space, dReal *pHeights,dReal vLength,int nNumNodesPerSide, int bFinite, int bPlaceable) |
---|
| 206 | { |
---|
| 207 | return new dxTerrainY(space, pHeights,vLength,nNumNodesPerSide,bFinite,bPlaceable); |
---|
| 208 | } |
---|
| 209 | |
---|
| 210 | dReal dGeomTerrainYPointDepth (dGeomID g, dReal x, dReal y, dReal z) |
---|
| 211 | { |
---|
| 212 | dUASSERT (g && g->type == dTerrainYClass,"argument not a terrain"); |
---|
| 213 | g->recomputePosr(); |
---|
| 214 | dxTerrainY *t = (dxTerrainY*) g; |
---|
| 215 | return t->GetHeight(x,z) - y; |
---|
| 216 | } |
---|
| 217 | |
---|
| 218 | typedef dReal dGetDepthFn(dGeomID g, dReal x, dReal y, dReal z); |
---|
| 219 | #define RECOMPUTE_RAYNORMAL |
---|
| 220 | //#define DO_RAYDEPTH |
---|
| 221 | |
---|
| 222 | #define DMESS(A) \ |
---|
| 223 | dMessage(0,"Contact Plane (%d %d %d) %.5e %.5e (%.5e %.5e %.5e)(%.5e %.5e %.5e)).", \ |
---|
| 224 | x,z,A, \ |
---|
| 225 | pContact->depth, \ |
---|
| 226 | dGeomSphereGetRadius(o2), \ |
---|
| 227 | pContact->pos[0], \ |
---|
| 228 | pContact->pos[1], \ |
---|
| 229 | pContact->pos[2], \ |
---|
| 230 | pContact->normal[0], \ |
---|
| 231 | pContact->normal[1], \ |
---|
| 232 | pContact->normal[2]); |
---|
| 233 | /* |
---|
| 234 | (y is up) |
---|
| 235 | |
---|
| 236 | A-B-E.x |
---|
| 237 | |/| |
---|
| 238 | C-D |
---|
| 239 | | |
---|
| 240 | F |
---|
| 241 | . |
---|
| 242 | z |
---|
| 243 | */ |
---|
| 244 | int dxTerrainY::dCollideTerrainUnit( |
---|
| 245 | int x,int z,dxGeom *o2,int numMaxContacts, |
---|
| 246 | int flags,dContactGeom *contact, int skip) |
---|
| 247 | { |
---|
| 248 | dColliderFn *CollideRayN; |
---|
| 249 | dColliderFn *CollideNPlane; |
---|
| 250 | dGetDepthFn *GetDepth; |
---|
| 251 | int numContacts = 0; |
---|
| 252 | int numPlaneContacts = 0; |
---|
| 253 | int i; |
---|
| 254 | |
---|
| 255 | if (numContacts == numMaxContacts) |
---|
| 256 | return numContacts; |
---|
| 257 | |
---|
| 258 | dContactGeom PlaneContact[MAXCONTACT]; |
---|
| 259 | flags = (flags & 0xffff0000) | MAXCONTACT; |
---|
| 260 | |
---|
| 261 | switch (o2->type) |
---|
| 262 | { |
---|
| 263 | case dSphereClass: |
---|
| 264 | CollideRayN = dCollideRaySphere; |
---|
| 265 | CollideNPlane = dCollideSpherePlane; |
---|
| 266 | GetDepth = dGeomSpherePointDepth; |
---|
| 267 | break; |
---|
| 268 | case dBoxClass: |
---|
| 269 | CollideRayN = dCollideRayBox; |
---|
| 270 | CollideNPlane = dCollideBoxPlane; |
---|
| 271 | GetDepth = dGeomBoxPointDepth; |
---|
| 272 | break; |
---|
| 273 | case dCCylinderClass: |
---|
| 274 | CollideRayN = dCollideRayCCylinder; |
---|
| 275 | CollideNPlane = dCollideCCylinderPlane; |
---|
| 276 | GetDepth = dGeomCCylinderPointDepth; |
---|
| 277 | break; |
---|
| 278 | case dRayClass: |
---|
| 279 | CollideRayN = NULL; |
---|
| 280 | CollideNPlane = dCollideRayPlane; |
---|
| 281 | GetDepth = NULL; |
---|
| 282 | break; |
---|
| 283 | case dConeClass: |
---|
| 284 | CollideRayN = dCollideRayCone; |
---|
| 285 | CollideNPlane = dCollideConePlane; |
---|
| 286 | GetDepth = dGeomConePointDepth; |
---|
| 287 | break; |
---|
| 288 | default: |
---|
| 289 | dIASSERT(0); |
---|
| 290 | } |
---|
| 291 | |
---|
| 292 | dReal Plane[4],lBD,lCD,lBC; |
---|
| 293 | dVector3 A,B,C,D,BD,CD,BC,AB,AC; |
---|
| 294 | A[0] = x * m_vNodeLength; |
---|
| 295 | A[2] = z* m_vNodeLength; |
---|
| 296 | A[1] = GetHeight(x,z); |
---|
| 297 | B[0] = (x+1) * m_vNodeLength; |
---|
| 298 | B[2] = z * m_vNodeLength; |
---|
| 299 | B[1] = GetHeight(x+1,z); |
---|
| 300 | C[0] = x * m_vNodeLength; |
---|
| 301 | C[2] = (z+1) * m_vNodeLength; |
---|
| 302 | C[1] = GetHeight(x,z+1); |
---|
| 303 | D[0] = (x+1) * m_vNodeLength; |
---|
| 304 | D[2] = (z+1) * m_vNodeLength; |
---|
| 305 | D[1] = GetHeight(x+1,z+1); |
---|
| 306 | |
---|
| 307 | dOP(BC,-,C,B); |
---|
| 308 | lBC = dLENGTH(BC); |
---|
| 309 | dOPEC(BC,/=,lBC); |
---|
| 310 | |
---|
| 311 | dOP(BD,-,D,B); |
---|
| 312 | lBD = dLENGTH(BD); |
---|
| 313 | dOPEC(BD,/=,lBD); |
---|
| 314 | |
---|
| 315 | dOP(CD,-,D,C); |
---|
| 316 | lCD = dLENGTH(CD); |
---|
| 317 | dOPEC(CD,/=,lCD); |
---|
| 318 | |
---|
| 319 | dOP(AB,-,B,A); |
---|
| 320 | dNormalize3(AB); |
---|
| 321 | |
---|
| 322 | dOP(AC,-,C,A); |
---|
| 323 | dNormalize3(AC); |
---|
| 324 | |
---|
| 325 | if (CollideRayN) |
---|
| 326 | { |
---|
| 327 | #ifdef RECOMPUTE_RAYNORMAL |
---|
| 328 | dVector3 E,F; |
---|
| 329 | dVector3 CE,FB,AD; |
---|
| 330 | dVector3 Normal[3]; |
---|
| 331 | E[0] = (x+2) * m_vNodeLength; |
---|
| 332 | E[2] = z * m_vNodeLength; |
---|
| 333 | E[1] = GetHeight(x+2,z); |
---|
| 334 | F[0] = x * m_vNodeLength; |
---|
| 335 | F[2] = (z+2) * m_vNodeLength; |
---|
| 336 | F[1] = GetHeight(x,z+2); |
---|
| 337 | dOP(AD,-,D,A); |
---|
| 338 | dNormalize3(AD); |
---|
| 339 | dOP(CE,-,E,C); |
---|
| 340 | dNormalize3(CE); |
---|
| 341 | dOP(FB,-,B,F); |
---|
| 342 | dNormalize3(FB); |
---|
| 343 | |
---|
| 344 | //BC |
---|
| 345 | dCROSS(Normal[0],=,BC,AD); |
---|
| 346 | dNormalize3(Normal[0]); |
---|
| 347 | |
---|
| 348 | //BD |
---|
| 349 | dCROSS(Normal[1],=,BD,CE); |
---|
| 350 | dNormalize3(Normal[1]); |
---|
| 351 | |
---|
| 352 | //CD |
---|
| 353 | dCROSS(Normal[2],=,CD,FB); |
---|
| 354 | dNormalize3(Normal[2]); |
---|
| 355 | #endif |
---|
| 356 | int nA[3],nB[3]; |
---|
| 357 | dContactGeom ContactA[3],ContactB[3]; |
---|
| 358 | dxRay rayBC(0,lBC); |
---|
| 359 | dGeomRaySet(&rayBC, B[0], B[1], B[2], BC[0], BC[1], BC[2]); |
---|
| 360 | nA[0] = CollideRayN(&rayBC,o2,flags,&ContactA[0],sizeof(dContactGeom)); |
---|
| 361 | dGeomRaySet(&rayBC, C[0], C[1], C[2], -BC[0], -BC[1], -BC[2]); |
---|
| 362 | nB[0] = CollideRayN(&rayBC,o2,flags,&ContactB[0],sizeof(dContactGeom)); |
---|
| 363 | |
---|
| 364 | dxRay rayBD(0,lBD); |
---|
| 365 | dGeomRaySet(&rayBD, B[0], B[1], B[2], BD[0], BD[1], BD[2]); |
---|
| 366 | nA[1] = CollideRayN(&rayBD,o2,flags,&ContactA[1],sizeof(dContactGeom)); |
---|
| 367 | dGeomRaySet(&rayBD, D[0], D[1], D[2], -BD[0], -BD[1], -BD[2]); |
---|
| 368 | nB[1] = CollideRayN(&rayBD,o2,flags,&ContactB[1],sizeof(dContactGeom)); |
---|
| 369 | |
---|
| 370 | dxRay rayCD(0,lCD); |
---|
| 371 | dGeomRaySet(&rayCD, C[0], C[1], C[2], CD[0], CD[1], CD[2]); |
---|
| 372 | nA[2] = CollideRayN(&rayCD,o2,flags,&ContactA[2],sizeof(dContactGeom)); |
---|
| 373 | dGeomRaySet(&rayCD, D[0], D[1], D[2], -CD[0], -CD[1], -CD[2]); |
---|
| 374 | nB[2] = CollideRayN(&rayCD,o2,flags,&ContactB[2],sizeof(dContactGeom)); |
---|
| 375 | |
---|
| 376 | for (i=0;i<3;i++) |
---|
| 377 | { |
---|
| 378 | if (nA[i] & nB[i]) |
---|
| 379 | { |
---|
| 380 | dContactGeom *pContact = CONTACT(contact,numContacts*skip); |
---|
| 381 | pContact->pos[0] = (ContactA[i].pos[0] + ContactB[i].pos[0])/2; |
---|
| 382 | pContact->pos[1] = (ContactA[i].pos[1] + ContactB[i].pos[1])/2; |
---|
| 383 | pContact->pos[2] = (ContactA[i].pos[2] + ContactB[i].pos[2])/2; |
---|
| 384 | #ifdef RECOMPUTE_RAYNORMAL |
---|
| 385 | pContact->normal[0] = -Normal[i][0]; |
---|
| 386 | pContact->normal[1] = -Normal[i][1]; |
---|
| 387 | pContact->normal[2] = -Normal[i][2]; |
---|
| 388 | #else |
---|
| 389 | pContact->normal[0] = (ContactA[i].normal[0] + ContactB[i].normal[0])/2; //0.f; |
---|
| 390 | pContact->normal[1] = (ContactA[i].normal[1] + ContactB[i].normal[1])/2; //0.f; |
---|
| 391 | pContact->normal[2] = (ContactA[i].normal[2] + ContactB[i].normal[2])/2; //-1.f; |
---|
| 392 | dNormalize3(pContact->normal); |
---|
| 393 | #endif |
---|
| 394 | #ifdef DO_RAYDEPTH |
---|
| 395 | dxRay rayV(0,1000.f); |
---|
| 396 | dGeomRaySet(&rayV, pContact->pos[0], |
---|
| 397 | pContact->pos[1], |
---|
| 398 | pContact->pos[2], |
---|
| 399 | -pContact->normal[0], |
---|
| 400 | -pContact->normal[1], |
---|
| 401 | -pContact->normal[2]); |
---|
| 402 | |
---|
| 403 | dContactGeom ContactV; |
---|
| 404 | if (CollideRayN(&rayV,o2,flags,&ContactV,sizeof(dContactGeom))) |
---|
| 405 | { |
---|
| 406 | pContact->depth = ContactV.depth; |
---|
| 407 | numContacts++; |
---|
| 408 | } |
---|
| 409 | #else |
---|
| 410 | |
---|
| 411 | if (GetDepth == NULL) |
---|
| 412 | { |
---|
| 413 | dxRay rayV(0,1000.f); |
---|
| 414 | dGeomRaySet(&rayV, pContact->pos[0], |
---|
| 415 | pContact->pos[1], |
---|
| 416 | pContact->pos[2], |
---|
| 417 | -pContact->normal[0], |
---|
| 418 | -pContact->normal[1], |
---|
| 419 | -pContact->normal[2]); |
---|
| 420 | |
---|
| 421 | dContactGeom ContactV; |
---|
| 422 | |
---|
| 423 | if (CollideRayN(&rayV,o2,flags,&ContactV,sizeof(dContactGeom))) |
---|
| 424 | { |
---|
| 425 | pContact->depth = ContactV.depth; |
---|
| 426 | numContacts++; |
---|
| 427 | } |
---|
| 428 | } |
---|
| 429 | else |
---|
| 430 | { |
---|
| 431 | pContact->depth = GetDepth(o2, |
---|
| 432 | pContact->pos[0], |
---|
| 433 | pContact->pos[1], |
---|
| 434 | pContact->pos[2]); |
---|
| 435 | numContacts++; |
---|
| 436 | } |
---|
| 437 | |
---|
| 438 | #endif |
---|
| 439 | if (numContacts == numMaxContacts) |
---|
| 440 | return numContacts; |
---|
| 441 | |
---|
| 442 | } |
---|
| 443 | } |
---|
| 444 | } |
---|
| 445 | |
---|
| 446 | dCROSS(Plane,=,AC,AB); |
---|
| 447 | dNormalize3(Plane); |
---|
| 448 | Plane[3] = Plane[0] * A[0] + Plane[1] * A[1] + Plane[2] * A[2]; |
---|
| 449 | dxPlane planeABC(0,Plane[0],Plane[1],Plane[2],Plane[3]); |
---|
| 450 | numPlaneContacts = CollideNPlane(o2,&planeABC,flags,PlaneContact,sizeof(dContactGeom)); |
---|
| 451 | |
---|
| 452 | for (i=0;i<numPlaneContacts;i++) |
---|
| 453 | { |
---|
| 454 | if (IsOnTerrain(x,z,0,PlaneContact[i].pos)) |
---|
| 455 | { |
---|
| 456 | dContactGeom *pContact = CONTACT(contact,numContacts*skip); |
---|
| 457 | pContact->pos[0] = PlaneContact[i].pos[0]; |
---|
| 458 | pContact->pos[1] = PlaneContact[i].pos[1]; |
---|
| 459 | pContact->pos[2] = PlaneContact[i].pos[2]; |
---|
| 460 | pContact->normal[0] = -PlaneContact[i].normal[0]; |
---|
| 461 | pContact->normal[1] = -PlaneContact[i].normal[1]; |
---|
| 462 | pContact->normal[2] = -PlaneContact[i].normal[2]; |
---|
| 463 | pContact->depth = PlaneContact[i].depth; |
---|
| 464 | |
---|
| 465 | //DMESS(0); |
---|
| 466 | numContacts++; |
---|
| 467 | |
---|
| 468 | if (numContacts == numMaxContacts) |
---|
| 469 | return numContacts; |
---|
| 470 | } |
---|
| 471 | } |
---|
| 472 | |
---|
| 473 | dCROSS(Plane,=,BD,CD); |
---|
| 474 | dNormalize3(Plane); |
---|
| 475 | Plane[3] = Plane[0] * D[0] + Plane[1] * D[1] + Plane[2] * D[2]; |
---|
| 476 | dxPlane planeDCB(0,Plane[0],Plane[1],Plane[2],Plane[3]); |
---|
| 477 | numPlaneContacts = CollideNPlane(o2,&planeDCB,flags,PlaneContact,sizeof(dContactGeom)); |
---|
| 478 | |
---|
| 479 | for (i=0;i<numPlaneContacts;i++) |
---|
| 480 | { |
---|
| 481 | if (IsOnTerrain(x,z,1,PlaneContact[i].pos)) |
---|
| 482 | { |
---|
| 483 | dContactGeom *pContact = CONTACT(contact,numContacts*skip); |
---|
| 484 | pContact->pos[0] = PlaneContact[i].pos[0]; |
---|
| 485 | pContact->pos[1] = PlaneContact[i].pos[1]; |
---|
| 486 | pContact->pos[2] = PlaneContact[i].pos[2]; |
---|
| 487 | pContact->normal[0] = -PlaneContact[i].normal[0]; |
---|
| 488 | pContact->normal[1] = -PlaneContact[i].normal[1]; |
---|
| 489 | pContact->normal[2] = -PlaneContact[i].normal[2]; |
---|
| 490 | pContact->depth = PlaneContact[i].depth; |
---|
| 491 | //DMESS(1); |
---|
| 492 | numContacts++; |
---|
| 493 | |
---|
| 494 | if (numContacts == numMaxContacts) |
---|
| 495 | return numContacts; |
---|
| 496 | } |
---|
| 497 | } |
---|
| 498 | |
---|
| 499 | return numContacts; |
---|
| 500 | } |
---|
| 501 | |
---|
| 502 | int dCollideTerrainY(dxGeom *o1, dxGeom *o2, int flags,dContactGeom *contact, int skip) |
---|
| 503 | { |
---|
| 504 | dIASSERT (skip >= (int)sizeof(dContactGeom)); |
---|
| 505 | dIASSERT (o1->type == dTerrainYClass); |
---|
| 506 | int i,j; |
---|
| 507 | |
---|
| 508 | if ((flags & 0xffff) == 0) |
---|
| 509 | flags = (flags & 0xffff0000) | 1; |
---|
| 510 | |
---|
| 511 | int numMaxTerrainContacts = (flags & 0xffff); |
---|
| 512 | dxTerrainY *terrain = (dxTerrainY*) o1; |
---|
| 513 | |
---|
| 514 | dReal aabbbak[6]; |
---|
| 515 | int gflagsbak; |
---|
| 516 | |
---|
| 517 | dVector3 pos0; |
---|
| 518 | int numTerrainContacts = 0; |
---|
| 519 | |
---|
| 520 | dxPosR *bak; |
---|
| 521 | dxPosR X1; |
---|
| 522 | |
---|
| 523 | if (terrain->gflags & GEOM_PLACEABLE) |
---|
| 524 | { |
---|
| 525 | dOP(pos0,-,o2->final_posr->pos,terrain->final_posr->pos); |
---|
| 526 | dMULTIPLY1_331(X1.pos,terrain->final_posr->R,pos0); |
---|
| 527 | dMULTIPLY1_333(X1.R,terrain->final_posr->R,o2->final_posr->R); |
---|
| 528 | bak = o2->final_posr; |
---|
| 529 | o2->final_posr = &X1; |
---|
| 530 | memcpy(aabbbak,o2->aabb,sizeof(dReal)*6); |
---|
| 531 | gflagsbak = o2->gflags; |
---|
| 532 | o2->computeAABB(); |
---|
| 533 | } |
---|
| 534 | |
---|
| 535 | int nMinX = int(floor(o2->aabb[0] / terrain->m_vNodeLength)); |
---|
| 536 | int nMaxX = int(floor(o2->aabb[1] / terrain->m_vNodeLength)) + 1; |
---|
| 537 | int nMinZ = int(floor(o2->aabb[4] / terrain->m_vNodeLength)); |
---|
| 538 | int nMaxZ = int(floor(o2->aabb[5] / terrain->m_vNodeLength)) + 1; |
---|
| 539 | |
---|
| 540 | if (terrain->m_bFinite) |
---|
| 541 | { |
---|
| 542 | nMinX = MAX(nMinX,0); |
---|
| 543 | nMaxX = MIN(nMaxX,terrain->m_nNumNodesPerSide); |
---|
| 544 | nMinZ = MAX(nMinZ,0); |
---|
| 545 | nMaxZ = MIN(nMaxZ,terrain->m_nNumNodesPerSide); |
---|
| 546 | |
---|
| 547 | if ((nMinX >= nMaxX) || (nMinZ >= nMaxZ)) |
---|
| 548 | goto dCollideTerrainYExit; |
---|
| 549 | } |
---|
| 550 | |
---|
| 551 | dVector3 AabbTop; |
---|
| 552 | AabbTop[0] = (o2->aabb[0]+o2->aabb[1]) / 2; |
---|
| 553 | AabbTop[2] = (o2->aabb[4]+o2->aabb[5]) / 2; |
---|
| 554 | AabbTop[1] = o2->aabb[3]; |
---|
| 555 | if (o2->type != dRayClass) |
---|
| 556 | { |
---|
| 557 | dReal AabbTopDepth = terrain->GetHeight(AabbTop[0],AabbTop[2]) - AabbTop[1]; |
---|
| 558 | if (AabbTopDepth > 0.f) |
---|
| 559 | { |
---|
| 560 | contact->depth = AabbTopDepth; |
---|
| 561 | dReal MaxDepth = (o2->aabb[3]-o2->aabb[2]) / 2; |
---|
| 562 | if (contact->depth > MaxDepth) |
---|
| 563 | contact->depth = MaxDepth; |
---|
| 564 | contact->g1 = o1; |
---|
| 565 | contact->g2 = o2; |
---|
| 566 | dOPE(contact->pos,=,AabbTop); |
---|
| 567 | contact->normal[0] = 0.f; |
---|
| 568 | contact->normal[1] = -1.f; |
---|
| 569 | contact->normal[2] = 0.f; |
---|
| 570 | |
---|
| 571 | numTerrainContacts = 1; |
---|
| 572 | goto dCollideTerrainYExit; |
---|
| 573 | } |
---|
| 574 | } |
---|
| 575 | |
---|
| 576 | for (i=nMinX;i<nMaxX;i++) |
---|
| 577 | { |
---|
| 578 | for (j=nMinZ;j<nMaxZ;j++) |
---|
| 579 | { |
---|
| 580 | numTerrainContacts += terrain->dCollideTerrainUnit( |
---|
| 581 | i,j,o2,numMaxTerrainContacts - numTerrainContacts, |
---|
| 582 | flags,CONTACT(contact,numTerrainContacts*skip),skip ); |
---|
| 583 | } |
---|
| 584 | } |
---|
| 585 | |
---|
| 586 | dIASSERT(numTerrainContacts <= numMaxTerrainContacts); |
---|
| 587 | |
---|
| 588 | for (i=0; i<numTerrainContacts; i++) |
---|
| 589 | { |
---|
| 590 | CONTACT(contact,i*skip)->g1 = o1; |
---|
| 591 | CONTACT(contact,i*skip)->g2 = o2; |
---|
| 592 | } |
---|
| 593 | |
---|
| 594 | dCollideTerrainYExit: |
---|
| 595 | |
---|
| 596 | if (terrain->gflags & GEOM_PLACEABLE) |
---|
| 597 | { |
---|
| 598 | o2->final_posr = bak; |
---|
| 599 | memcpy(o2->aabb,aabbbak,sizeof(dReal)*6); |
---|
| 600 | o2->gflags = gflagsbak; |
---|
| 601 | |
---|
| 602 | for (i=0; i<numTerrainContacts; i++) |
---|
| 603 | { |
---|
| 604 | dOPE(pos0,=,CONTACT(contact,i*skip)->pos); |
---|
| 605 | dMULTIPLY0_331(CONTACT(contact,i*skip)->pos,terrain->final_posr->R,pos0); |
---|
| 606 | dOP(CONTACT(contact,i*skip)->pos,+,CONTACT(contact,i*skip)->pos,terrain->final_posr->pos); |
---|
| 607 | |
---|
| 608 | dOPE(pos0,=,CONTACT(contact,i*skip)->normal); |
---|
| 609 | dMULTIPLY0_331(CONTACT(contact,i*skip)->normal,terrain->final_posr->R,pos0); |
---|
| 610 | } |
---|
| 611 | } |
---|
| 612 | |
---|
| 613 | return numTerrainContacts; |
---|
| 614 | } |
---|
| 615 | /* |
---|
| 616 | void dsDrawTerrainY(int x,int z,float vLength,float vNodeLength,int nNumNodesPerSide,float *pHeights,const float *pR,const float *ppos) |
---|
| 617 | { |
---|
| 618 | float A[3],B[3],C[3],D[3]; |
---|
| 619 | float R[12]; |
---|
| 620 | float pos[3]; |
---|
| 621 | if (pR) |
---|
| 622 | memcpy(R,pR,sizeof(R)); |
---|
| 623 | else |
---|
| 624 | { |
---|
| 625 | memset(R,0,sizeof(R)); |
---|
| 626 | R[0] = 1.f; |
---|
| 627 | R[5] = 1.f; |
---|
| 628 | R[10] = 1.f; |
---|
| 629 | } |
---|
| 630 | |
---|
| 631 | if (ppos) |
---|
| 632 | memcpy(pos,ppos,sizeof(pos)); |
---|
| 633 | else |
---|
| 634 | memset(pos,0,sizeof(pos)); |
---|
| 635 | |
---|
| 636 | float vx,vz; |
---|
| 637 | vx = vLength * x; |
---|
| 638 | vz = vLength * z; |
---|
| 639 | |
---|
| 640 | int i; |
---|
| 641 | for (i=0;i<nNumNodesPerSide;i++) |
---|
| 642 | { |
---|
| 643 | for (int j=0;j<nNumNodesPerSide;j++) |
---|
| 644 | { |
---|
| 645 | A[0] = i * vNodeLength + vx; |
---|
| 646 | A[2] = j * vNodeLength + vz; |
---|
| 647 | A[1] = GetHeight(i,j,nNumNodesPerSide,pHeights); |
---|
| 648 | B[0] = (i+1) * vNodeLength + vx; |
---|
| 649 | B[2] = j * vNodeLength + vz; |
---|
| 650 | B[1] = GetHeight(i+1,j,nNumNodesPerSide,pHeights); |
---|
| 651 | C[0] = i * vNodeLength + vx; |
---|
| 652 | C[2] = (j+1) * vNodeLength + vz; |
---|
| 653 | C[1] = GetHeight(i,j+1,nNumNodesPerSide,pHeights); |
---|
| 654 | D[0] = (i+1) * vNodeLength + vx; |
---|
| 655 | D[2] = (j+1) * vNodeLength + vz; |
---|
| 656 | D[1] = GetHeight(i+1,j+1,nNumNodesPerSide,pHeights); |
---|
| 657 | dsDrawTriangle(pos,R,C,B,A,1); |
---|
| 658 | dsDrawTriangle(pos,R,D,B,C,1); |
---|
| 659 | } |
---|
| 660 | } |
---|
| 661 | } |
---|
| 662 | */ |
---|