00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <conio.h>
00012
00013 #include "Common/Assert.h"
00014 #include "Common/Error.h"
00015 #include "Common/Console.h"
00016 #include "Common/Directory.h"
00017 #include "Common/Plane.h"
00018
00019 #include "Common/Vertex.h"
00020 #include "Physics/PhysicsCollision.h"
00021
00022 #include "Bsp/BezierPatch.h"
00023
00024 #include "Bsp/Bsp.h"
00025
00026 #define EPSILON 0.03125f // 1/32 float
00027
00028
00029 KBsp::KBsp()
00030 : KBspLoader()
00031 {
00032 m_pBezierPatches = 0;
00033 m_pComputedVertices = NULL;
00034 }
00035
00036
00037 KBsp::~KBsp()
00038 {
00039 }
00040
00041
00042 s32 KBsp::LoadBSP( const char* pFileName )
00043 {
00044
00045 s32 Result;
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 g_Console << "Loading map [" << (char*)pFileName << "]...";
00056
00057 Result = KBspLoader::LoadBSP( pFileName );
00058
00059 switch( Result )
00060 {
00061 case BSP_OK:
00062 g_Console << "OK" << KENDL;
00063 g_Console << "Nb Vertices : " << (int)m_nVertices << KENDL;
00064 g_Console << "Nb Faces : " << (int)m_nFaces << KENDL;
00065 g_Console << "Nb Shaders : " << (int)m_nShaders << KENDL;
00066 g_Console << "Nb Lightmaps : " << (int)m_nLightMaps << KENDL;
00067 break;
00068 case BSP_ERROR_OPENFILE:
00069 g_Console << "Cannot open file." << KENDL;
00070 return Result;
00071 case BSP_ERROR_BADVERSION:
00072 g_Console << "Bad version." << KENDL;
00073 return Result;
00074 }
00075
00076 m_pBezierPatches = new KBezierPatch[m_nFaces];
00077 m_pComputedVertices = new KLVertex2[m_nVertices];
00078
00079 ComputeVertices();
00080 ComputeBezier();
00081
00082 return BSP_OK;
00083 }
00084
00085
00086 s32 KBsp::CloseBSP()
00087 {
00088 if( m_pBezierPatches )
00089 Deletev( m_pBezierPatches );
00090
00091 if( m_pComputedVertices )
00092 Deletev( m_pComputedVertices );
00093
00094 return KBspLoader::CloseBSP();
00095 }
00096
00097
00098 u32 KBsp::FindLeaf( u32 NodeId, KVector& Position )
00099 {
00100 if( KVector::DotProduct( m_pPlanes[m_pNodes[NodeId].m_PlaneId].m_Normal, Position ) - m_pPlanes[m_pNodes[NodeId].m_PlaneId].m_Distance >= 0 )
00101 {
00102
00103 if( m_pNodes[NodeId].m_Front & 0x8000 )
00104 {
00105
00106 return (u16)-( m_pNodes[NodeId].m_Front + 1);
00107 }
00108 else
00109 return FindLeaf( m_pNodes[NodeId].m_Front, Position );
00110 }
00111
00112
00113 if( m_pNodes[NodeId].m_Back & 0x8000 )
00114 {
00115
00116 return (u16)-( m_pNodes[NodeId].m_Back + 1);
00117 }
00118 else
00119 return FindLeaf( m_pNodes[NodeId].m_Back, Position );
00120 }
00121
00122
00123 void KBsp::ComputeVertices()
00124 {
00125 u32 v;
00126
00127 for( v = 0; v < m_nVertices; v ++ )
00128 {
00129 KRgba Color = KRgba( 255, 255, 255, 255 );
00130
00131
00132
00133
00134
00135
00136
00137
00138 m_pComputedVertices[v].Position = m_pVertices[v].m_Position;
00139 m_pComputedVertices[v].Color = KRGBA2INT( Color );
00140 m_pComputedVertices[v].tu1 = m_pVertices[v].m_UV[0].x;
00141 m_pComputedVertices[v].tv1 = m_pVertices[v].m_UV[0].y;
00142 m_pComputedVertices[v].tu2 = m_pVertices[v].m_UV[1].x;
00143 m_pComputedVertices[v].tv2 = m_pVertices[v].m_UV[1].y;
00144 }
00145 }
00146
00147
00148 void KBsp::ComputeBezier()
00149 {
00150 KASSERT( m_pBezierPatches );
00151
00152 for( u32 i = 0; i < m_nFaces; i ++ )
00153 {
00154 if( m_pFaces[i].m_Type == KBFT_PATCH )
00155 {
00156 m_pBezierPatches[i].GenerateVertices( &m_pComputedVertices[m_pFaces[i].m_FirstVertexId], KPt( m_pFaces[i].m_Size ) );
00157 }
00158 }
00159 }
00160
00161
00162
00163
00164 void KBsp::CheckSphereCollision( u32 NodeId, KPhysicsCollisionData* pData )
00165 {
00166 float Radius;
00167
00168 Radius = MAX( MAX( pData->m_eRadius.x, pData->m_eRadius.y ), pData->m_eRadius.z );
00169 Radius += pData->m_R3Velocity.Magnitude();
00170
00171 float fDist = KVector::DotProduct( m_pPlanes[m_pNodes[NodeId].m_PlaneId].m_Normal, pData->m_R3Position ) - m_pPlanes[m_pNodes[NodeId].m_PlaneId].m_Distance;
00172
00173 if( fDist >= -Radius )
00174 {
00175
00176 if( m_pNodes[NodeId].m_Front & 0x8000 )
00177 {
00178
00179 CheckLeafSphereCollision( (u16)-( m_pNodes[NodeId].m_Front + 1), pData );
00180 }
00181 else
00182 CheckSphereCollision( m_pNodes[NodeId].m_Front, pData );
00183 }
00184
00185 if( fDist <= Radius )
00186 {
00187
00188 if( m_pNodes[NodeId].m_Back & 0x8000 )
00189 {
00190
00191 CheckLeafSphereCollision( (u16)-( m_pNodes[NodeId].m_Back + 1), pData );
00192 }
00193 else
00194 CheckSphereCollision( m_pNodes[NodeId].m_Back, pData );
00195 }
00196 }
00197
00198
00199 bool KBsp::CheckLeafSphereCollision( u32 LeafId, KPhysicsCollisionData* pData )
00200 {
00201 s32 FaceId;
00202 u32 Face;
00203 s32 MeshVertId;
00204 KVector pVertex[3];
00205
00206 if( !LeafId )
00207 return false;
00208
00209
00210
00211 for( FaceId = m_pLeaves[LeafId].m_FirstFaceId;
00212 FaceId < m_pLeaves[LeafId].m_FirstFaceId + m_pLeaves[LeafId].m_NumFaces;
00213 FaceId ++ )
00214
00215 {
00216 Face = m_pFaceList[FaceId].m_Face;
00217
00218
00219
00220
00221 if( m_pFaces[Face].m_Type == KBFT_POLYGON )
00222 {
00223 for( MeshVertId = m_pFaces[Face].m_FirstMeshVert;
00224 MeshVertId < m_pFaces[Face].m_FirstMeshVert + m_pFaces[Face].m_NumMeshVerts;
00225 MeshVertId += 3 )
00226 {
00227 pVertex[0] = m_pVertices[m_pFaces[Face].m_FirstVertexId + m_pMeshVerts[MeshVertId + 0].m_FirstVertexId].m_Position;
00228 pVertex[1] = m_pVertices[m_pFaces[Face].m_FirstVertexId + m_pMeshVerts[MeshVertId + 2].m_FirstVertexId].m_Position;
00229 pVertex[2] = m_pVertices[m_pFaces[Face].m_FirstVertexId + m_pMeshVerts[MeshVertId + 1].m_FirstVertexId].m_Position;
00230
00231 #if _DEBUG
00232 m_DebugCollFace ++;
00233 #endif _DEBUG
00234 KPhysicsCollision::CheckSphereCollision( pData, pVertex[0], pVertex[1], pVertex[2] );
00235 }
00236 }
00237
00238
00239
00240
00241
00242 if( m_pFaces[Face].m_Type == KBFT_MESH )
00243 {
00244 for( MeshVertId = m_pFaces[Face].m_FirstMeshVert;
00245 MeshVertId < m_pFaces[Face].m_FirstMeshVert + m_pFaces[Face].m_NumMeshVerts;
00246 MeshVertId += 3 )
00247 {
00248 pVertex[0] = m_pVertices[m_pFaces[Face].m_FirstVertexId + m_pMeshVerts[MeshVertId + 0].m_FirstVertexId].m_Position;
00249 pVertex[1] = m_pVertices[m_pFaces[Face].m_FirstVertexId + m_pMeshVerts[MeshVertId + 2].m_FirstVertexId].m_Position;
00250 pVertex[2] = m_pVertices[m_pFaces[Face].m_FirstVertexId + m_pMeshVerts[MeshVertId + 1].m_FirstVertexId].m_Position;
00251
00252 #if _DEBUG
00253 m_DebugCollFace ++;
00254 #endif _DEBUG
00255 KPhysicsCollision::CheckSphereCollision( pData, pVertex[0], pVertex[1], pVertex[2] );
00256 }
00257 }
00258
00259
00260
00261
00262 if( m_pFaces[Face].m_Type == KBFT_PATCH )
00263 {
00264 for( MeshVertId = 0;
00265 MeshVertId < m_pBezierPatches[Face].GetnIndices();
00266 MeshVertId += 3 )
00267 {
00268 pVertex[0] = m_pBezierPatches[Face].GetpVertices()[m_pBezierPatches[Face].GetpIndices()[MeshVertId + 0]].Position;
00269 pVertex[1] = m_pBezierPatches[Face].GetpVertices()[m_pBezierPatches[Face].GetpIndices()[MeshVertId + 2]].Position;
00270 pVertex[2] = m_pBezierPatches[Face].GetpVertices()[m_pBezierPatches[Face].GetpIndices()[MeshVertId + 1]].Position;
00271
00272 #if _DEBUG
00273 m_DebugCollFace ++;
00274 #endif _DEBUG
00275 KPhysicsCollision::CheckSphereCollision( pData, pVertex[0], pVertex[1], pVertex[2] );
00276 }
00277 }
00278 }
00279
00280 return true;
00281 }
00282
00284
00285
00286
00287
00288
00289
00290 KBspCollisionData KBsp::CheckRayMove( KVector& vStart, KVector& vEnd )
00291 {
00292 KBspCollisionData CollisionData;
00293
00294
00295 CollisionData.m_StartOut = true;
00296 CollisionData.m_AllSolid = false;
00297 CollisionData.m_Fraction = 1.0f;
00298
00299 CollisionData.m_Start = vStart;
00300 CollisionData.m_End = vEnd;
00301 CollisionData.m_ObjectType = BSP_COLL_RAY;
00302 CollisionData.m_MoveOffset = 0.0f;
00303
00304
00305 CheckMoveByNode( 0, 0.0f, 1.0f, vStart, vEnd, CollisionData );
00306
00307 if( CollisionData.m_Fraction == 1.0f)
00308 {
00309 CollisionData.m_EndPoint = vEnd;
00310 }
00311 else
00312 {
00313 CollisionData.m_EndPoint = vStart + ( vEnd - vStart ) * CollisionData.m_Fraction;
00314 }
00315 return CollisionData;
00316 }
00317
00319
00320
00321
00322 KBspCollisionData KBsp::CheckSphereMove( KVector& vStart, KVector& vEnd, float Radius )
00323 {
00324 KBspCollisionData CollisionData;
00325
00326
00327 CollisionData.m_StartOut = true;
00328 CollisionData.m_AllSolid = false;
00329 CollisionData.m_Fraction = 1.0f;
00330
00331 CollisionData.m_Start = vStart;
00332 CollisionData.m_End = vEnd;
00333 CollisionData.m_ObjectType = BSP_COLL_SPHERE;
00334 CollisionData.m_MoveOffset = Radius;
00335
00336
00337 CheckMoveByNode( 0, 0.0f, 1.0f, vStart, vEnd, CollisionData );
00338
00339 if( CollisionData.m_Fraction == 1.0f )
00340 {
00341 CollisionData.m_EndPoint = vEnd;
00342 }
00343 else
00344 {
00345 CollisionData.m_EndPoint = vStart + ( vEnd - vStart ) * CollisionData.m_Fraction;
00346 }
00347 return CollisionData;
00348 }
00349
00350
00351
00352 void KBsp::CheckMoveByNode( s32 NodeId, float StartFraction, float EndFraction, KVector& vStart, KVector vEnd, KBspCollisionData& CollisionData )
00353 {
00354
00355 if( CollisionData.m_Fraction <= StartFraction)
00356 return;
00357
00358 if( NodeId < 0 )
00359 {
00360 KBspLeaf* pLeaf = &m_pLeaves[~NodeId];
00361
00362
00363
00364 for( s32 i = 0; i < pLeaf->m_NumBrushes; i++ )
00365 {
00366
00367 KBspBrush* pBrush = &m_pBrushes[m_pBrushList[pLeaf->m_FirstBrushId + i].m_Brush];
00368
00369
00370 if( pBrush->m_NumBrushSides > 0 && ( m_pShaders[pBrush->m_TextureId].m_Contents & 1 ) )
00371 {
00372 CheckTouchBrush( pBrush, CollisionData );
00373 }
00374 }
00375
00376
00377 return;
00378 }
00379
00380
00381
00382 KBspNode* pNode = &m_pNodes[NodeId];
00383 KBspPlane* pPlane = &m_pPlanes[pNode->m_PlaneId];
00384
00385
00386 float StartDistance = pPlane->m_Normal.x * vStart.x +
00387 pPlane->m_Normal.y * vStart.y +
00388 pPlane->m_Normal.z * vStart.z -
00389 pPlane->m_Distance;
00390 float EndDistance = pPlane->m_Normal.x * vEnd.x +
00391 pPlane->m_Normal.y * vEnd.y +
00392 pPlane->m_Normal.z * vEnd.z -
00393 pPlane->m_Distance;
00394
00395
00396
00397
00398 if( ( StartDistance >= CollisionData.m_MoveOffset ) && ( EndDistance >= CollisionData.m_MoveOffset ) )
00399 {
00400 CheckMoveByNode( pNode->m_Front, StartFraction, EndFraction, vStart, vEnd, CollisionData );
00401 }
00402
00403
00404
00405
00406 else if( ( StartDistance < -CollisionData.m_MoveOffset ) && ( EndDistance < -CollisionData.m_MoveOffset ) )
00407 {
00408 CheckMoveByNode( pNode->m_Back, StartFraction, EndFraction, vStart, vEnd, CollisionData );
00409 }
00410
00411 else
00412 {
00413 s32 Side1, Side2;
00414 float Fraction1, Fraction2;
00415 KVector vMiddle;
00416
00417
00418
00419
00420
00421 if( StartDistance < EndDistance )
00422 {
00423 Side1 = pNode->m_Back;
00424 Side2 = pNode->m_Front;
00425 float InverseDistance = 1.0f / ( StartDistance - EndDistance );
00426 Fraction1 = ( StartDistance - EPSILON - CollisionData.m_MoveOffset ) * InverseDistance;
00427 Fraction2 = ( StartDistance + EPSILON + CollisionData.m_MoveOffset ) * InverseDistance;
00428 }
00429
00430 else if ( EndDistance < StartDistance )
00431 {
00432 Side1 = pNode->m_Front;
00433 Side2 = pNode->m_Back;
00434 float InverseDistance = 1.0f / ( StartDistance - EndDistance );
00435 Fraction1 = ( StartDistance + EPSILON + CollisionData.m_MoveOffset ) * InverseDistance;
00436 Fraction2 = ( StartDistance - EPSILON - CollisionData.m_MoveOffset ) * InverseDistance;
00437 }
00438 else
00439 {
00440 Side1 = pNode->m_Front;
00441 Side2 = pNode->m_Back;
00442 Fraction1 = 1.0f;
00443 Fraction2 = 0.0f;
00444 }
00445
00446
00447 if( Fraction1 < 0.0f ) Fraction1 = 0.0f;
00448 else if ( Fraction1 > 1.0f ) Fraction1 = 1.0f;
00449 if ( Fraction2 < 0.0f ) Fraction2 = 0.0f;
00450 else if ( Fraction2 > 1.0f ) Fraction2 = 1.0f;
00451
00452
00453 vMiddle = vStart + ( vEnd - vStart ) * Fraction1;
00454
00455
00456 float MiddleFraction = StartFraction + ( EndFraction - StartFraction) * Fraction1;
00457
00458
00459 CheckMoveByNode( Side1, StartFraction, MiddleFraction, vStart, vMiddle, CollisionData );
00460
00461
00462 vMiddle = vStart + ( vEnd - vStart ) * Fraction2;
00463
00464
00465 MiddleFraction = StartFraction + ( EndFraction - StartFraction ) * Fraction2;
00466
00467
00468 CheckMoveByNode( Side2, MiddleFraction, EndFraction, vMiddle, vEnd, CollisionData );
00469 }
00470 }
00471
00472
00473 void KBsp::CheckTouchBrush( KBspBrush* pBrush, KBspCollisionData& CollisionData )
00474 {
00475 float StartFraction = -1.0f;
00476 float EndFraction = 1.0f;
00477 bool StartsOut = false;
00478 bool EndsOut = false;
00479
00480 KVector CandidateToHitNormal;
00481
00482
00483 for( s32 i = 0; i < pBrush->m_NumBrushSides; i ++ )
00484 {
00485
00486 KBspBrushSide* pBrushSide = &m_pBrushSides[pBrush->m_FirstBrushSideId + i];
00487 KBspPlane* pPlane = &m_pPlanes[pBrushSide->m_PlaneId];
00488
00489
00490 float StartDistance = pPlane->m_Normal.x * CollisionData.m_Start.x +
00491 pPlane->m_Normal.y * CollisionData.m_Start.y +
00492 pPlane->m_Normal.z * CollisionData.m_Start.z -
00493 pPlane->m_Distance - CollisionData.m_MoveOffset;
00494 float EndDistance = pPlane->m_Normal.x * CollisionData.m_End.x +
00495 pPlane->m_Normal.y * CollisionData.m_End.y +
00496 pPlane->m_Normal.z * CollisionData.m_End.z -
00497 pPlane->m_Distance - CollisionData.m_MoveOffset;
00498
00499
00500 if( StartDistance > 0 )
00501 StartsOut = true;
00502
00503
00504 if( EndDistance > 0 )
00505 EndsOut = true;
00506
00507
00508 if( StartDistance > 0 && EndDistance > 0 )
00509 {
00510 return;
00511 }
00512
00513 if( StartDistance <= 0 && EndDistance <= 0 )
00514 {
00515 continue;
00516 }
00517
00518
00519
00520
00521
00522
00523 if( StartDistance > EndDistance )
00524 {
00525 float Fraction = ( StartDistance - EPSILON ) / ( StartDistance - EndDistance );
00526 if( Fraction > StartFraction)
00527 {
00528 StartFraction = Fraction;
00529 CandidateToHitNormal = pPlane->m_Normal;
00530 }
00531 }
00532 else
00533
00534
00535
00536 {
00537 float Fraction = ( StartDistance + EPSILON ) / ( StartDistance - EndDistance );
00538 if( Fraction < EndFraction )
00539 EndFraction = Fraction;
00540 }
00541 }
00542
00543
00544
00545 if( StartsOut == false )
00546 {
00547 CollisionData.m_StartOut = false;
00548
00549
00550 if( EndsOut == false )
00551 CollisionData.m_AllSolid = true;
00552 return;
00553 }
00554
00555
00556 if( StartFraction < EndFraction )
00557 {
00558
00559
00560 if( StartFraction > -1 && StartFraction < CollisionData.m_Fraction )
00561 {
00562
00563
00564 if( StartFraction < 0 )
00565 StartFraction = 0;
00566
00567 CollisionData.m_Fraction = StartFraction;
00568 CollisionData.m_CollisionNormal = CandidateToHitNormal;
00569 }
00570 }
00571 }