Main Page | Alphabetical List | Compound List | File List | Compound Members | File Members

Trace.c

Go to the documentation of this file.
00001 /****************************************************************************************/
00002 /*  Trace.c                                                                             */
00003 /*                                                                                      */
00004 /*  Author: John Pollard                                                                */
00005 /*  Description: BSP collision detection code                                           */
00006 /*                                                                                      */
00007 /*  The contents of this file are subject to the Genesis3D Public License               */
00008 /*  Version 1.01 (the "License"); you may not use this file except in                   */
00009 /*  compliance with the License. You may obtain a copy of the License at                */
00010 /*  http://www.genesis3d.com                                                            */
00011 /*                                                                                      */
00012 /*  Software distributed under the License is distributed on an "AS IS"                 */
00013 /*  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See                */
00014 /*  the License for the specific language governing rights and limitations              */
00015 /*  under the License.                                                                  */
00016 /*                                                                                      */
00017 /*  The Original Code is Genesis3D, released March 25, 1999.                            */
00018 /*Genesis3D Version 1.1 released November 15, 1999                            */
00019 /*  Copyright (C) 1999 WildTangent, Inc. All Rights Reserved           */
00020 /*                                                                                      */
00021 /****************************************************************************************/
00022 #include <Assert.h>
00023  
00024 #include "XForm3d.h"
00025 #include "BaseType.h"
00026 #include "GBSPFile.h"
00027 #include "World.h"
00028 #include "System.h"
00029 #include "Plane.h"
00030 #include "Trace.h"
00031 #include "ExtBox.h"
00032 #include "Actor.h"
00033 
00034 #define ON_EPSILON      (0.1f)
00035 
00036 //=====================================================================================
00037 //      Local Static Globals
00038 //=====================================================================================
00039 
00040 // Globals returned in the bsp subdivision code
00041 static  int32                   GPlaneNum;
00042 static  GFX_Plane               GlobalPlane;
00043 static  int32                   GlobalNode;
00044 static  int32                   GlobalSide;
00045 static  geVec3d                 GlobalI;
00046 static  geFloat                 GRatio;
00047 static  int32                   GlobalLeaf;
00048 static  int32                   GlobalLeaf;
00049 
00050 static  GBSP_BSPData    *BSPData;
00051 
00052 // Globals passed to the bsp subdivision code
00053 static  uint32                  gContents;                      // Contents that we should collide with for the current collision tests...
00054 
00055 static  BOOL                    UseMinsMaxs;            // If MiscCollision should use mins maxs...
00056 
00057 static  BOOL                    HitSet;
00058 static  int32                   GlobalNNode[2]={0x696C6345,0x21657370};
00059 
00060 int32   NumExactCast;
00061 int32   NumBBoxCast;
00062 int32   NumGetContents;
00063 
00064 //=====================================================================================
00065 //      Local Static Function Prototypes
00066 //=====================================================================================
00067 static geBoolean BSPIntersect(geVec3d *Front, geVec3d *Back, int32 Node);
00068 
00069 
00070 
00071 static geActor *Trace_ActorCollide(geWorld *World,
00072                                                                    const geVec3d *Mins, const geVec3d *Maxs,
00073                                                                    const geVec3d *Front,const geVec3d *Back, 
00074                                                                    geVec3d *CollisionPoint,GFX_Plane *BestPlane,
00075                                                                    uint32 UserFlags, GE_CollisionCB *CollisionCB, void *Context, geFloat *BestD  )
00076 {
00077         int i,Count;
00078         World_Actor *WA;
00079         geVec3d RayDirection;
00080         geFloat RayLength;
00081         geFloat Dist;
00082         geActor *BestActor = NULL;
00083         geVec3d FakeMins = {-1.0f, -1.0f, -1.0f};
00084         geVec3d FakeMaxs = { 1.0f,  1.0f,  1.0f};
00085         int32   k;
00086         geVec3d OMins, OMaxs;
00087         
00088         if (!Mins)
00089                 Mins = &FakeMins;
00090         
00091         if (!Maxs)
00092                 Maxs = &FakeMaxs;
00093 
00094         geVec3d_Subtract(Back,Front,&RayDirection);
00095         RayLength = geVec3d_Normalize(&RayDirection);
00096 
00097         Count = World->ActorCount;
00098         WA = &(World->ActorArray[0]);
00099 
00100         Trace_GetMoveBox(Mins, Maxs, Front, Back, &OMins, &OMaxs);
00101 
00102         for (i=0; i<Count; i++, WA++)
00103         {
00104                 geExtBox B;
00105                 geVec3d Normal;
00106                 
00107                 // Reject if not active or if userflags don't accept...
00108                 if (!(WA->Flags & GE_ACTOR_COLLIDE) || !(WA->UserFlags & UserFlags) )
00109                         continue;
00110 
00111                 if (CollisionCB && !CollisionCB(NULL, WA->Actor, Context))
00112                         continue;
00113 
00114                 if (!geActor_GetExtBox(WA->Actor, &B))
00115                         continue;
00116                                                         
00117                 for (k=0; k<3; k++)
00118                 {
00119                         if (geVec3d_GetElement(&OMaxs, k) < geVec3d_GetElement(&B.Min, k))
00120                                 break;
00121 
00122                         if (geVec3d_GetElement(&OMins, k) > geVec3d_GetElement(&B.Max, k))
00123                                 break;
00124                 }
00125                 
00126                 if (k != 3)
00127                         continue;
00128                 
00129                 geVec3d_Subtract(&B.Min, Maxs, &B.Min);
00130                 geVec3d_Subtract(&B.Max, Mins, &B.Max);
00131                                                         
00132                 if (!geExtBox_RayCollision( &B, Front, Back, &Dist, &Normal ))
00133                         continue;
00134 
00135                 //Dist -= 0.01f;
00136                 if (Dist < 0.0f)
00137                         Dist = 0.0f;
00138                 if (Dist > 1.0f)
00139                         Dist = 1.0f;
00140 
00141                 Dist *= RayLength;
00142 
00143                 if (Dist < *BestD)
00144                 {
00145                         BestActor = WA->Actor;
00146                         *BestD = Dist;
00147                         BestPlane->Normal = Normal;
00148                                                                                         
00149                         geVec3d_AddScaled(Front,&RayDirection,Dist,CollisionPoint);
00150                         BestPlane->Dist = geVec3d_DotProduct(CollisionPoint,&Normal);
00151                                                                                         
00152                         BestPlane->Type = PLANE_ANY;
00153                 }
00154         }
00155 
00156         return BestActor;
00157 }
00158 
00159 
00160 
00161 //=====================================================================================
00162 //      Trace_GEWorldCollision
00163 //      Function specially designed for GE UI...
00164 //=====================================================================================
00165 geBoolean Trace_GEWorldCollision(geWorld *World, const geVec3d *Mins, const geVec3d *Maxs, const geVec3d *Front, const geVec3d *Back, uint32 Contents, uint32 CollideFlags, uint32 UserFlags, GE_CollisionCB *CollisionCB, void *Context, GE_Collision *Col)
00166 {
00167         geVec3d         I;
00168         GFX_Plane       Plane;
00169         geWorld_Model   *Model;
00170         Mesh_RenderQ    *Mesh;
00171         geActor     *Actor;
00172 
00173         assert(World != NULL);
00174         assert(World->CurrentBSP != NULL);
00175         assert(Front != NULL);
00176         assert(Back!= NULL);
00177         assert(Contents);                       // It does not make sense to collide with nothing!!!
00178         
00179         // Set the global contents to collide with
00180         gContents = Contents;
00181 
00182         BSPData = &World->CurrentBSP->BSPData;
00183 
00184         // Reset all the collision feedback pointers
00185         Model = NULL;
00186         Mesh = NULL;
00187         Actor = NULL;
00188 
00189         Col->Model = NULL;
00190         Col->Mesh = NULL;
00191         Col->Actor = NULL;
00192 
00193         if (Mins && Maxs)
00194         {
00195                 NumBBoxCast++;
00196                 if (Trace_WorldCollisionBBox(World, Mins, Maxs, Front, Back, CollideFlags, &I, &Plane, &Model, &Mesh, &Actor, UserFlags, CollisionCB, Context))
00197                 {
00198                         
00199                         Col->Impact = I;
00200                         Col->Plane.Normal =     Plane.Normal;
00201                         Col->Plane.Dist = Plane.Dist;
00202                         
00203                         Col->Model = Model;
00204                         Col->Mesh = (geMesh*)Mesh;
00205                         Col->Actor = Actor;
00206 
00207                         Col->Ratio = GRatio;
00208                         return GE_TRUE;
00209                 }
00210         }
00211         else 
00212         {
00213                 NumExactCast++;
00214 
00215                 if (Trace_WorldCollisionExact(World, Front, Back, CollideFlags, &I, &Plane, &Model, &Mesh, &Actor, UserFlags, CollisionCB, Context))
00216                 {
00217                         Col->Impact = I;
00218                         Col->Plane.Normal = Plane.Normal;
00219                         Col->Plane.Dist = Plane.Dist;
00220 
00221                         Col->Model = Model;
00222                         Col->Mesh = (geMesh*)Mesh;
00223                         Col->Actor = Actor;
00224 
00225                         Col->Ratio = GRatio;
00226 
00227                         return GE_TRUE;
00228                 }
00229         }
00230         return GE_FALSE;
00231 }
00232 
00233 //=====================================================================================
00234 //      Trace_WorldCollisionExact
00235 //=====================================================================================
00236 geBoolean Trace_WorldCollisionExact(geWorld *World, 
00237                                                                         const geVec3d *Front, 
00238                                                                         const geVec3d *Back, 
00239                                                                         uint32 Flags,
00240                                                                         geVec3d *Impact,
00241                                                                         GFX_Plane *Plane,
00242                                                                         geWorld_Model **Model,
00243                                                                         Mesh_RenderQ **Mesh, 
00244                                                                         geActor **Actor,
00245                                                                         uint32 UserFlags,
00246                                                                         GE_CollisionCB *CollisionCB,
00247                                                                         void *Context)
00248 {
00249         int32                   i, b;
00250         geVec3d                 NewFront1, NewBack1;
00251         geVec3d                 NewFront2, NewBack2;
00252         geWorld_Model   *Models, *BestModel;
00253         GFX_Plane               BestPlane, Plane2;
00254         Mesh_RenderQ    *BestMesh=NULL;
00255         geActor                 *BestActor=NULL;
00256         geVec3d                 OMins, OMaxs, Vect, Impact2, BestI;
00257         static geVec3d  MMins = {-1.0f, -1.0f, -1.0f};
00258         static geVec3d  MMaxs = { 1.0f,  1.0f,  1.0f};
00259         geBoolean               Hit;
00260         geFloat                 Dist, BestD;
00261 
00262         assert(World != NULL);
00263         assert(World->CurrentBSP != NULL);
00264         assert(Front != NULL);
00265         assert(Back!= NULL);
00266         
00267         BSPData = &World->CurrentBSP->BSPData;
00268         Models = World->CurrentBSP->Models;
00269         
00270         // Clear mesh/model collision pointers
00271         if (Model)
00272                 *Model = NULL;
00273         if (Mesh)
00274                 *Mesh = NULL;
00275         if (Actor)
00276                 *Actor = NULL;
00277 
00278         BestD = 99999.0f;
00279         BestModel = NULL;
00280         BestMesh = NULL;
00281         Hit = GE_FALSE;
00282 
00283         if (Flags & GE_COLLIDE_ACTORS)
00284         {
00285                 BestActor = Trace_ActorCollide(World,NULL, NULL, Front,Back,&Impact2, &Plane2, UserFlags, CollisionCB, Context, &BestD);
00286                 if (BestActor != NULL)
00287                 {
00288                         BestI = Impact2;
00289                         BestPlane = Plane2;
00290                         Hit = GE_TRUE;
00291                 }
00292         }
00293 
00294         if (!(Flags & GE_COLLIDE_MODELS))
00295                 goto NoModels;
00296 
00297         Trace_GetMoveBox(&MMins, &MMaxs, Front, Back, &OMins, &OMaxs);
00298 
00299         for (i = 0; i < BSPData->NumGFXModels; i++, Models++)
00300         {
00301                 // First, give the caller a chance to reject the model
00302                 if (CollisionCB && !CollisionCB(Models, NULL, Context))
00303                         continue;
00304 
00305                 for (b=0; b<3; b++)
00306                 {
00307                         if (VectorToSUB(OMaxs, b) < VectorToSUB(Models->TMins, b))
00308                                 break;
00309                         if (VectorToSUB(OMins, b) > VectorToSUB(Models->TMaxs, b))
00310                                 break;
00311                 }
00312 
00313                 if (b != 3)
00314                         continue;
00315 
00316                 // Move to models center of rotation
00317                 geVec3d_Subtract(Front, &Models->Pivot, &NewFront1);
00318                 geVec3d_Subtract(Back , &Models->Pivot, &NewBack1);
00319 
00320                 // InverseTransform the point about models center of rotation
00321                 geXForm3d_TransposeTransform(&Models->XForm, &NewFront1, &NewFront2);
00322                 geXForm3d_TransposeTransform(&Models->XForm, &NewBack1 , &NewBack2);
00323 
00324                 // push back into world
00325                 geVec3d_Add(&NewFront2, &Models->Pivot, &NewFront1);
00326                 geVec3d_Add(&NewBack2 , &Models->Pivot, &NewBack1);
00327                 
00328                 HitSet = FALSE;
00329 
00330                 if (BSPIntersect(&NewFront1, &NewBack1, BSPData->GFXModels[i].RootNode[0]))
00331                 {
00332                         // Rotate the impact plane
00333                         geXForm3d_Rotate(&Models->XForm, &GlobalPlane.Normal, &GlobalPlane.Normal);
00334                         
00335                         // Rotate the impact point
00336                         geVec3d_Subtract(&GlobalI, &Models->Pivot, &GlobalI);
00337                         geXForm3d_Transform(&Models->XForm, &GlobalI, &GlobalI);
00338                         geVec3d_Add(&GlobalI, &Models->Pivot, &GlobalI);
00339                         
00340                         // Find the new plane distance based on the new impact point with the new plane
00341                         GlobalPlane.Dist = geVec3d_DotProduct(&GlobalPlane.Normal, &GlobalI);
00342 
00343                         geVec3d_Subtract(&GlobalI, Front, &Vect);
00344                         Dist = geVec3d_Length(&Vect);
00345 
00346                         if (Dist < BestD)
00347                         {
00348                                 BestD = Dist;
00349                                 BestI = GlobalI;
00350                         
00351                                 BestPlane = GlobalPlane;
00352                                 if (GlobalSide)
00353                                 {
00354                                         geVec3d_Inverse(&BestPlane.Normal);
00355                                         BestPlane.Dist = -BestPlane.Dist;
00356                                         BestPlane.Type = PLANE_ANY;
00357                                 }
00358 
00359                                 BestMesh = NULL;                // Clear hit mesh
00360                                 BestActor = NULL;
00361                                 BestModel = Models;
00362                                 Hit = GE_TRUE;
00363                         }
00364                 }
00365 
00366                 if ((Flags & GE_COLLIDE_NO_SUB_MODELS))
00367                         goto NoModels;
00368         }
00369 
00370         NoModels:
00371 
00372         if (Hit)
00373         {
00374                 if (Impact)
00375                         *Impact = BestI;
00376                 if (Plane)
00377                         *Plane = BestPlane;
00378                 if (Model)
00379                         *Model = BestModel;
00380                 if (Mesh)
00381                         *Mesh = BestMesh;
00382                 if (Actor)
00383                         *Actor = BestActor;
00384                 return GE_TRUE;
00385         }
00386 
00387         return GE_FALSE;
00388 }
00389 
00390 //=====================================================================================
00391 //      Trace_WorldCollisionExact2
00392 //      Internal only/ does not chek meshes/ returns index numbers into bsp structures for models
00393 //      FIXME:  This can be replaced by callinf Trace_WorldCollisionExact with the GE_COLLIDE_MODELS
00394 //      flag only...
00395 //=====================================================================================
00396 geBoolean Trace_WorldCollisionExact2(   geWorld *World, 
00397                                                                                 const geVec3d *Front, 
00398                                                                                 const geVec3d *Back, 
00399                                                                                 geVec3d *Impact,
00400                                                                                 int32 *Node,
00401                                                                                 int32 *Plane,
00402                                                                                 int32 *Side)
00403 {
00404         int32                   i;
00405         geVec3d                 NewFront1, NewBack1;
00406         geVec3d                 NewFront2, NewBack2;
00407         geWorld_Model           *Models;
00408 
00409         assert(World != NULL);
00410         assert(World->CurrentBSP != NULL);
00411         assert(Front != NULL);
00412         assert(Back!= NULL);
00413         
00414         BSPData = &World->CurrentBSP->BSPData;
00415         Models = World->CurrentBSP->Models;
00416         
00417         GPlaneNum = -1;
00418 
00419         gContents = GE_CONTENTS_SOLID_CLIP;
00420 
00421         for (i = 0; i < BSPData->NumGFXModels; i++)
00422         {
00423                 
00424                 // Move to models center of rotation
00425                 geVec3d_Subtract(Front, &Models[i].Pivot, &NewFront1);
00426                 geVec3d_Subtract(Back , &Models[i].Pivot, &NewBack1);
00427 
00428                 // InverseTransform the point about models center of rotation
00429                 geXForm3d_TransposeTransform(&Models[i].XForm, &NewFront1, &NewFront2);
00430                 geXForm3d_TransposeTransform(&Models[i].XForm, &NewBack1 , &NewBack2);
00431 
00432                 // push back into world
00433                 geVec3d_Add(&NewFront2, &Models[i].Pivot, &NewFront1);
00434                 geVec3d_Add(&NewBack2 , &Models[i].Pivot, &NewBack1);
00435                 
00436                 HitSet = FALSE;
00437                 
00438                 if (BSPIntersect(&NewFront1, &NewBack1, BSPData->GFXModels[i].RootNode[0]))
00439                 {
00440                         if (GPlaneNum == -1)
00441                                 return FALSE;
00442 
00443                         if (Impact) *Impact = GlobalI;
00444                         if (Node) *Node = GlobalNode;
00445                         if (Plane) *Plane = GPlaneNum;
00446                         if (Side) *Side = GlobalSide;
00447 
00448                         return GE_TRUE;
00449                 }
00450         }
00451 
00452         return GE_FALSE;
00453 }
00454 
00455 //=====================================================================================
00456 //      Local static support functions
00457 //=====================================================================================
00458 
00459 //=====================================================================================
00460 //      BSPIntersect
00461 //      Shoot a ray through the tree finding out what solid leafs it passed through
00462 //=====================================================================================
00463 static geBoolean BSPIntersect(geVec3d *Front, geVec3d *Back, int32 Node)
00464 {
00465     geFloat             Fd, Bd, Dist;
00466     int32               Side;
00467     geVec3d             I;
00468         GFX_Plane       *Plane;
00469         int32           Contents;
00470 
00471         if (Node < 0)
00472         {
00473                 Contents = BSPData->GFXLeafs[-(Node+1)].Contents;
00474 
00475                 if (Contents & gContents)
00476                     return GE_TRUE;                                             // Ray collided with solid space
00477 
00478                 return GE_FALSE;
00479         }
00480 
00481         Plane = &BSPData->GFXPlanes[BSPData->GFXNodes[Node].PlaneNum];
00482 
00483     Fd = Plane_PlaneDistanceFast(Plane, Front);
00484     Bd = Plane_PlaneDistanceFast(Plane, Back);
00485 
00486     if (Fd >= 0 && Bd >= 0) 
00487         return(BSPIntersect(Front, Back, BSPData->GFXNodes[Node].Children[0]));
00488     if (Fd < 0 && Bd < 0)
00489         return(BSPIntersect(Front, Back, BSPData->GFXNodes[Node].Children[1]));
00490 
00491     Side = Fd < 0;
00492     Dist = Fd / (Fd - Bd);
00493 
00494     I.X = Front->X + Dist * (Back->X - Front->X);
00495     I.Y = Front->Y + Dist * (Back->Y - Front->Y);
00496     I.Z = Front->Z + Dist * (Back->Z - Front->Z);
00497 
00498     // Work our way to the front, from the back side.  As soon as there
00499         // is no more collisions, we can assume that we have the front portion of the
00500         // ray that is in empty space.  Once we find this, and see that the back half is in
00501         // solid space, then we found the front intersection point...
00502         if (BSPIntersect(Front, &I, BSPData->GFXNodes[Node].Children[Side]))
00503         return GE_TRUE;
00504     else if (BSPIntersect(&I, Back, BSPData->GFXNodes[Node].Children[!Side]))
00505         {
00506                 if (!HitSet)
00507                 {
00508                         GPlaneNum = BSPData->GFXNodes[Node].PlaneNum;
00509                         GlobalPlane = BSPData->GFXPlanes[GPlaneNum];
00510                         GlobalSide = Side;
00511                         GlobalI = I;
00512                         GlobalNode = Node;
00513                         GRatio = Dist;
00514                         HitSet = TRUE;
00515                 }
00516                 return GE_TRUE;
00517         }
00518 
00519         return GE_FALSE;
00520 }
00521 
00522 //=====================================================================================
00523 //      BSPIntersectMesh
00524 //=====================================================================================
00525 static GFX_BNode                *MiscBNodes;
00526 static GFX_Node                 *MiscNodes;
00527 static GFX_Plane                *MiscPlanes;
00528 static GFX_Leaf                 *MiscLeafs;
00529 static GFX_LeafSide             *MiscSides;
00530 
00531 static geVec3d                  GMins1, GMaxs1;
00532 static geVec3d                  GMins2, GMaxs2;
00533 static geVec3d                  GFront, GBack;
00534 static BOOL                             LeafHit;
00535 static geFloat                  BestDist;
00536 
00537 static geBoolean BSPIntersectMisc(geVec3d *Front, geVec3d *Back, int32 Node)
00538 {
00539     geFloat             Fd, Bd, Dist;
00540     uint8               Side;
00541         GFX_Plane       Plane;
00542     geVec3d             I;
00543 
00544         if (Node == BSP_CONTENTS_SOLID)
00545         return GE_TRUE;                                 // Ray collided with solid space
00546     if (Node < 0)                                               
00547         return GE_FALSE;                                // Ray collided with empty space
00548 
00549         Plane = MiscPlanes[MiscBNodes[Node].PlaneNum];
00550         Plane.Type = PLANE_ANY;
00551         
00552         if (UseMinsMaxs)
00553         {
00554                 if (Plane.Normal.X > 0)
00555                         Plane.Dist -= Plane.Normal.X * GMins1.X;
00556                 else     
00557                         Plane.Dist -= Plane.Normal.X * GMaxs1.X;
00558         
00559                 if (Plane.Normal.Y > 0)
00560                         Plane.Dist -= Plane.Normal.Y * GMins1.Y;
00561                 else
00562                         Plane.Dist -= Plane.Normal.Y * GMaxs1.Y;
00563 
00564                 if (Plane.Normal.Z > 0)
00565                         Plane.Dist -= Plane.Normal.Z * GMins1.Z;
00566                 else                                                     
00567                         Plane.Dist -= Plane.Normal.Z * GMaxs1.Z;
00568         }
00569 
00570     Fd = Plane_PlaneDistanceFast(&Plane, Front);
00571     Bd = Plane_PlaneDistanceFast(&Plane, Back);
00572 
00573     if (Fd >= 0 && Bd >= 0) 
00574         return(BSPIntersectMisc(Front, Back, MiscBNodes[Node].Children[0]));
00575     if (Fd < 0 && Bd < 0)
00576         return(BSPIntersectMisc(Front, Back, MiscBNodes[Node].Children[1]));
00577 
00578     Side = Fd < 0;
00579     Dist = Fd / (Fd - Bd);
00580 
00581     I.X = Front->X + Dist * (Back->X - Front->X);
00582     I.Y = Front->Y + Dist * (Back->Y - Front->Y);
00583     I.Z = Front->Z + Dist * (Back->Z - Front->Z);
00584 
00585     // Work our way to the front, from the back side.  As soon as there
00586         // is no more collisions, we can assume that we have the front portion of the
00587         // ray that is in empty space.  Once we find this, and see that the back half is in
00588         // solid space, then we found the front intersection point...
00589         if (BSPIntersectMisc(Front, &I, MiscBNodes[Node].Children[Side]))
00590         return TRUE;
00591     else if (BSPIntersectMisc(&I, Back, MiscBNodes[Node].Children[!Side]))
00592         {
00593                 if (!HitSet)
00594                 {
00595                         GPlaneNum = MiscBNodes[Node].PlaneNum;
00596                         GlobalPlane = Plane;
00597                         GlobalSide = Side;
00598                         GlobalI = I;
00599                         GRatio = Dist;
00600                         HitSet = TRUE;
00601                 }
00602                 return GE_TRUE;
00603         }
00604 
00605         return GE_FALSE;
00606 }
00607 
00608 //=====================================================================================
00609 //      Trace_MiscCollision
00610 //      Does a collision with a given tree, ray and transform
00611 //      (The tree will be rotated by the transform, well actually the
00612 //       ray will be inverse rotated)
00613 //=====================================================================================
00614 geBoolean Trace_MiscCollision(GFX_BNode *BNodes, GFX_Plane *Planes, const geVec3d *Mins, const geVec3d *Maxs, const geVec3d *Front, const geVec3d *Back, geXForm3d *XForm, geVec3d *I, GFX_Plane *P)
00615 {
00616         geVec3d NewFront, NewBack;
00617         geVec3d Trans;
00618 
00619         GPlaneNum       =       -1;             //Safeguard to prevent a bad index 
00620 
00621         // Set Global misc vars
00622         MiscBNodes = BNodes;
00623         MiscPlanes = Planes;
00624 
00625         if (Mins && Maxs)
00626         {
00627                 GMins1 = *Mins;
00628                 GMaxs1 = *Maxs;
00629                 UseMinsMaxs = TRUE;
00630         }
00631         else
00632                 UseMinsMaxs = FALSE;
00633         
00634         // Move ray into tree space
00635         Trans.X = XForm->Translation.X;
00636         Trans.Y = XForm->Translation.Y;
00637         Trans.Z = XForm->Translation.Z;
00638 
00639         geVec3d_Subtract(Front, &Trans, &NewFront);
00640         geVec3d_Subtract(Back, &Trans, &NewBack);
00641         
00642         HitSet = FALSE;
00643         
00644         if (BSPIntersectMisc(&NewFront, &NewBack, 0))
00645         {
00646                 if (!HitSet)                                    // Was in solid, but did not cross any planes...
00647                         return GE_FALSE;                        // So just return false...
00648 
00649                 geVec3d_Add(&GlobalI, &Trans, &GlobalI);
00650 
00651                 if (I) *I = GlobalI;                    // Set the intersection point
00652                 if (P)
00653                 { 
00654                         *P = GlobalPlane;
00655                         // Adjust so plane is at impact point
00656                         P->Dist += geVec3d_DotProduct(&Trans, &P->Normal);
00657                 }
00658 
00659                 return GE_TRUE;
00660         }
00661 
00662         return GE_FALSE;
00663 }
00664 
00665 //=====================================================================================
00666 //      BSPIntersectMisc2
00667 //=====================================================================================
00668 static geBoolean BSPIntersectMisc2(const geVec3d *Front, const geVec3d *Back, int32 Node)
00669 {
00670     geFloat             Fd, Bd, Dist;
00671     uint8               Side;
00672         GFX_Plane       Plane;
00673     geVec3d             I;
00674 
00675         if (Node == BSP_CONTENTS_SOLID)
00676         return GE_TRUE;                                 // Ray collided with solid space
00677     if (Node < 0)                                               
00678         return GE_FALSE;                                // Ray collided with empty space
00679 
00680         Plane = MiscPlanes[MiscBNodes[Node].PlaneNum];
00681         Plane.Type = PLANE_ANY;
00682         
00683     Fd = Plane_PlaneDistanceFast(&Plane, Front);
00684     Bd = Plane_PlaneDistanceFast(&Plane, Back);
00685 
00686     if (Fd >= 0 && Bd >= 0) 
00687         return(BSPIntersectMisc2(Front, Back, MiscBNodes[Node].Children[0]));
00688     if (Fd < 0 && Bd < 0)
00689         return(BSPIntersectMisc2(Front, Back, MiscBNodes[Node].Children[1]));
00690 
00691     Side = Fd < 0;
00692     Dist = Fd / (Fd - Bd);
00693 
00694     I.X = Front->X + Dist * (Back->X - Front->X);
00695     I.Y = Front->Y + Dist * (Back->Y - Front->Y);
00696     I.Z = Front->Z + Dist * (Back->Z - Front->Z);
00697 
00698     // Work our way to the front, from the back side.  As soon as there
00699         // is no more collisions, we can assume that we have the front portion of the
00700         // ray that is in empty space.  Once we find this, and see that the back half is in
00701         // solid space, then we found the front intersection point...
00702         if (BSPIntersectMisc2(Front, &I, MiscBNodes[Node].Children[Side]))
00703         return TRUE;
00704     else if (BSPIntersectMisc2(&I, Back, MiscBNodes[Node].Children[!Side]))
00705         {
00706                 if (!HitSet)
00707                 {
00708                         GPlaneNum = MiscBNodes[Node].PlaneNum;
00709                         GlobalPlane = Plane;
00710                         GlobalSide = Side;
00711                         GlobalI = I;
00712                         GRatio = Dist;
00713                         HitSet = TRUE;
00714                 }
00715                 return GE_TRUE;
00716         }
00717 
00718         return GE_FALSE;
00719 }
00720 
00721 //=====================================================================================
00722 //      Trace_MiscCollision2
00723 //=====================================================================================
00724 geBoolean Trace_MiscCollision2(GFX_BNode *BNodes, GFX_Plane *Planes, const geVec3d *Front, const geVec3d *Back, geVec3d *I, int32 *P)
00725 {
00726         GPlaneNum       =       -1;             //Safeguard to prevent a bad index 
00727 
00728         // Set Global misc vars
00729         MiscBNodes = BNodes;
00730         MiscPlanes = Planes;
00731 
00732         HitSet = FALSE;
00733         
00734         if (BSPIntersectMisc2(Front, Back, 0))
00735         {
00736                 if (!HitSet || GPlaneNum == -1) // Was in solid, but did not cross any planes...
00737                         return GE_FALSE;                        // So just return false...
00738 
00739                 if (I) 
00740                         *I = GlobalI;                           // Set the intersection point
00741                 if (P)
00742                         *P = GPlaneNum;
00743 
00744                 return GE_TRUE;
00745         }
00746 
00747         return GE_FALSE;
00748 }
00749 
00750 //=====================================================================================
00751 //      Trace_BoxOnPlaneSide
00752 //      
00753 //      Returns PSIDE_FRONT, PSIDE_BACK, or PSIDE_BOTH
00754 //=====================================================================================
00755 int32 Trace_BoxOnPlaneSide(const geVec3d *Mins, const geVec3d *Maxs, GFX_Plane *Plane)
00756 {
00757         int32   Side;
00758         int32   i;
00759         geVec3d Corners[2];
00760         geFloat Dist1, Dist2;
00761 
00762         // Axial planes are easy
00763         if (Plane->Type < PLANE_ANYX)
00764         {
00765                 Side = 0;
00766                 if (VectorToSUB(*Maxs, Plane->Type) >= Plane->Dist)
00767                         Side |= PSIDE_FRONT;
00768                 if (VectorToSUB(*Mins, Plane->Type) < Plane->Dist)
00769                         Side |= PSIDE_BACK;
00770                 return Side;
00771         }
00772 
00773         // Create the proper leading and trailing verts for the box
00774         for (i=0 ; i<3 ; i++)
00775         {
00776                 if (VectorToSUB(Plane->Normal, i) < 0)
00777                 {
00778                         VectorToSUB(Corners[0], i) = VectorToSUB(*Mins, i);
00779                         VectorToSUB(Corners[1], i) = VectorToSUB(*Maxs, i);
00780                 }
00781                 else
00782                 {
00783                         VectorToSUB(Corners[1], i) = VectorToSUB(*Mins, i);
00784                         VectorToSUB(Corners[0], i) = VectorToSUB(*Maxs, i);
00785                 }
00786         }
00787 
00788         Dist1 = geVec3d_DotProduct(&Plane->Normal, &Corners[0]) - Plane->Dist;
00789         Dist2 = geVec3d_DotProduct(&Plane->Normal, &Corners[1]) - Plane->Dist;
00790         
00791         Side = 0;
00792         if (Dist1 >= 0)
00793                 Side = PSIDE_FRONT;
00794         if (Dist2 < 0)
00795                 Side |= PSIDE_BACK;
00796 
00797         return Side;
00798 }
00799 
00800 //=====================================================================================
00801 //      Trace_ExpandPlaneForBox
00802 //      Pushes a plan out by the side of the box it is looking at
00803 //=====================================================================================
00804 void Trace_ExpandPlaneForBox(GFX_Plane *Plane, geVec3d *Mins, geVec3d *Maxs)
00805 {
00806         geVec3d         *Normal;
00807 
00808         Normal = &Plane->Normal;
00809         
00810         if (Normal->X > 0)
00811                 Plane->Dist -= Normal->X * Mins->X;
00812         else     
00813                 Plane->Dist -= Normal->X * Maxs->X;
00814         
00815         if (Normal->Y > 0)
00816                 Plane->Dist -= Normal->Y * Mins->Y;
00817         else
00818                 Plane->Dist -= Normal->Y * Maxs->Y;
00819 
00820         if (Normal->Z > 0)
00821                 Plane->Dist -= Normal->Z * Mins->Z;
00822         else                                                     
00823                 Plane->Dist -= Normal->Z * Maxs->Z;
00824 }
00825 
00826 //=====================================================================================
00827 //      IntersectLeafSides
00828 //=====================================================================================
00829 static geBoolean PointInLeafSides(const geVec3d *Pos, const GFX_Leaf *Leaf)
00830 {
00831         int32           i, f;
00832         GFX_Plane       Plane;
00833         geFloat         Dist;
00834 
00835         f = Leaf->FirstSide;
00836 
00837         for (i=0; i< Leaf->NumSides; i++)
00838         {
00839                 Plane = MiscPlanes[MiscSides[i+f].PlaneNum];
00840                 Plane.Type = PLANE_ANY;
00841         
00842                 if (MiscSides[i+f].PlaneSide)
00843                 {
00844                         geVec3d_Inverse(&Plane.Normal);
00845                         Plane.Dist = -Plane.Dist;
00846                 }
00847 
00848                 // Simulate the point having a box, by pushing the plane out by the box size
00849                 Trace_ExpandPlaneForBox(&Plane, &GMins1, &GMaxs1);
00850 
00851                 Dist = Plane_PlaneDistanceFast(&Plane, Pos);
00852                 
00853                 if (Dist >= 0.0f)
00854                         return GE_FALSE;                // Since leafs are convex, it must be outside...
00855         }
00856 
00857         return GE_TRUE;
00858 }
00859 
00860 //=====================================================================================
00861 //      IntersectLeafSides
00862 //=====================================================================================
00863 BOOL IntersectLeafSides_r(geVec3d *Front, geVec3d *Back, int32 Leaf, int32 Side, int32 PSide)
00864 {
00865         geFloat         Fd, Bd, Dist;
00866         GFX_Plane       Plane;
00867         int32           RSide, Side2;
00868         geVec3d         I, Vec;
00869 
00870         if (!PSide)
00871                 return FALSE;
00872 
00873         if (Side >= MiscLeafs[Leaf].NumSides)
00874                 return TRUE;            // if it lands behind all planes, it is inside
00875 
00876         RSide = MiscLeafs[Leaf].FirstSide + Side;
00877 
00878         Plane = MiscPlanes[MiscSides[RSide].PlaneNum];
00879         Plane.Type = PLANE_ANY;
00880         
00881         if (MiscSides[RSide].PlaneSide)
00882         {
00883                 geVec3d_Inverse(&Plane.Normal);
00884                 Plane.Dist = -Plane.Dist;
00885         }
00886         
00887         // Simulate the point having a box, by pushing the plane out by the box size
00888         Trace_ExpandPlaneForBox(&Plane, &GMins1, &GMaxs1);
00889 
00890         Fd = Plane_PlaneDistanceFast(&Plane, Front);
00891         Bd = Plane_PlaneDistanceFast(&Plane, Back);
00892 
00893 #if 1
00894         if (Fd >= 0 && Bd >= 0) // Leaf sides are convex hulls, so front side is totally outside
00895                 return IntersectLeafSides_r(Front, Back, Leaf, Side+1, 0);
00896 
00897         if (Fd < 0 && Bd < 0)
00898                 return IntersectLeafSides_r(Front, Back, Leaf, Side+1, 1);
00899 #else
00900         if ((Fd >= ON_EPSILON && Bd >= ON_EPSILON) || (Bd > Fd && Fd >= 0) )
00901                 return IntersectLeafSides_r(Front, Back, Leaf, Side+1, 0);
00902 
00903         if ((Fd < -ON_EPSILON && Bd < -ON_EPSILON) || (Bd < Fd && Fd <= 0))
00904                 return IntersectLeafSides_r(Front, Back, Leaf, Side+1, 1);
00905 #endif
00906 
00907         // We have an intersection
00908 
00909         //Dist = Fd / (Fd - Bd);
00910 
00911     Side2 = Fd < 0;
00912         
00913         if (Fd < 0)
00914                 Dist = (Fd + ON_EPSILON)/(Fd-Bd);
00915         else
00916                 Dist = (Fd - ON_EPSILON)/(Fd-Bd);
00917 
00918         if (Dist < 0.0f)
00919                 Dist = 0.0f;
00920         
00921         if (Dist > 1.0f)
00922                 Dist = 1.0f;
00923 
00924     I.X = Front->X + Dist * (Back->X - Front->X);
00925     I.Y = Front->Y + Dist * (Back->Y - Front->Y);
00926     I.Z = Front->Z + Dist * (Back->Z - Front->Z);
00927 
00928         // Only go down the back side, since the front side is empty in a convex tree
00929         if (IntersectLeafSides_r(Front, &I, Leaf, Side+1, Side2))
00930         {
00931                 LeafHit = TRUE;
00932                 return TRUE;
00933         }
00934         else if (IntersectLeafSides_r(&I, Back, Leaf, Side+1, !Side2))
00935         {
00936                 geVec3d_Subtract(&I, &GFront, &Vec);
00937                 Dist = geVec3d_Length(&Vec);
00938 
00939                 // Record the intersection closest to the start of ray
00940                 if (Dist < BestDist && !HitSet)
00941                 {
00942                         GlobalI = I;
00943                         GlobalLeaf = Leaf;
00944                         BestDist = Dist;
00945                         GlobalPlane = Plane;
00946                         GRatio = Dist;
00947                         HitSet = TRUE;
00948                 }
00949                 LeafHit = TRUE;
00950                 return TRUE;
00951         }
00952         
00953         return FALSE;   
00954 }
00955 
00956 //=====================================================================================
00957 //      IntersectLeafSides2
00958 //=====================================================================================
00959 BOOL IntersectLeafSides2(geVec3d *Pos, int32 Leaf)
00960 {
00961         GFX_Plane       Plane;
00962         int32           i;
00963         geFloat         Dist;
00964 
00965         for (i=0; i< MiscLeafs[Leaf].NumSides; i++)
00966         {
00967                 Plane = MiscPlanes[MiscSides[MiscLeafs[Leaf].FirstSide+i].PlaneNum];
00968                 
00969                 if (!MiscSides[MiscLeafs[Leaf].FirstSide+i].PlaneSide)
00970                 {
00971                         geVec3d_Inverse(&Plane.Normal);
00972                         Plane.Dist = -Plane.Dist;
00973                 }
00974 
00975                 Dist = geVec3d_DotProduct(&Plane.Normal, Pos) - Plane.Dist;
00976 
00977                 if (Dist >= 25.0f)
00978                         return FALSE;
00979         }
00980 
00981         LeafHit = TRUE;
00982         return TRUE;
00983 }
00984 
00985 //=====================================================================================
00986 //      FindClosestLeafIntersection_r
00987 //=====================================================================================
00988 static  void FindClosestLeafIntersection_r(int32 Node)
00989 {
00990         int32           Leaf, Side, Contents;
00991 
00992         if (Node < 0)
00993         {
00994                 Leaf = -(Node+1);
00995                 Contents = MiscLeafs[Leaf].Contents;
00996 
00997                 //if (Contents != BSP_CONTENTS_SOLID && Contents != BSP_CONTENTS_WINDOW)
00998                 if (!(Contents & gContents))
00999                         return;         // Only solid leafs contain side info...
01000 
01001                 HitSet = FALSE;
01002                 
01003                 if (!MiscLeafs[Leaf].NumSides)
01004                         return;
01005 
01006                 IntersectLeafSides_r(&GFront, &GBack, Leaf, 0, 1);
01007                 //IntersectLeafSides2(&GBack, Leaf);
01008 
01009                 return;
01010         }
01011 
01012         Side = Trace_BoxOnPlaneSide(&GMins2, &GMaxs2, &MiscPlanes[MiscNodes[Node].PlaneNum]);
01013 
01014         // Go down the sides that the box lands in
01015         if (Side & PSIDE_FRONT)
01016                 FindClosestLeafIntersection_r(MiscNodes[Node].Children[0]);
01017 
01018         if (Side & PSIDE_BACK)
01019                 FindClosestLeafIntersection_r(MiscNodes[Node].Children[1]);
01020 }
01021 
01022 #define SIDE_SPACE              0.1f
01023 //=====================================================================================
01024 //      Trace_WorldCollisionBBox
01025 //      Shoots a ray through the world, using the expandable leaf hull
01026 //  The hull is expanded by the input BBox to simulate the points having volume...
01027 //=====================================================================================
01028 geBoolean Trace_WorldCollisionBBox(     geWorld *World,
01029                                                                         const   geVec3d *Mins, const geVec3d *Maxs, 
01030                                                                         const   geVec3d *Front, const geVec3d *Back,
01031                                                                         uint32  Flags,
01032                                                                         geVec3d *I, GFX_Plane *P,
01033                                                                         geWorld_Model **Model,
01034                                                                         Mesh_RenderQ **Mesh,
01035                                                                         geActor **Actor,
01036                                                                         uint32 UserFlags,
01037                                                                         GE_CollisionCB *CollisionCB,
01038                                                                         void *Context)
01039 {
01040         geWorld_Model   *Models;
01041         geVec3d                 NewFront, NewBack, OMins, OMaxs, BestI, Vect;
01042         geVec3d                 Impact;
01043         int32                   i, b;
01044         geFloat                 Dist, BestD;
01045         Mesh_RenderQ    *BestMesh;
01046         #ifdef MESHES
01047         Mesh_RenderQ    *Mesh2;
01048         #endif
01049         geActor                 *BestActor;
01050         geWorld_Model   *BestModel;
01051         GFX_Plane               BestPlane, Plane2;
01052         geBoolean               Hit;
01053 
01054         if (Model)
01055                 *Model = NULL;
01056         if (Mesh)
01057                 *Mesh = NULL;
01058         if (Actor)
01059                 *Actor = NULL;
01060 
01061         BestD = 99999.0f;
01062         BestMesh = NULL;
01063         BestModel = NULL;
01064         BestActor = NULL;
01065         Hit = GE_FALSE;                         // Have not hit nothing yet...
01066         
01067         // Test meshes first... (record the closest collision)
01068         if (Flags & GE_COLLIDE_MESHES)
01069         {
01070 #ifdef  MESHES
01071                 if (Mesh_MeshCollisionAll(World, Mins, Maxs, Front, Back, &Impact, &Plane2, &Mesh2, UserFlags))
01072                 {
01073                         geVec3d_Subtract(&Impact, Front, &Vect);
01074                         Dist = geVec3d_Length(&Vect);
01075                         if (Dist < BestD)
01076                         {
01077                                 BestD = Dist;
01078                                 BestI = Impact;
01079                                 BestMesh = Mesh2;
01080                                 BestPlane = Plane2;
01081                                 Hit = GE_TRUE;                  // We hit somthing
01082                         }
01083                 }
01084 #endif
01085         }
01086 
01087         
01088         if (Flags & GE_COLLIDE_ACTORS)
01089                 {
01090                         BestActor = Trace_ActorCollide(World, Mins,Maxs, Front,Back,&Impact,&Plane2,UserFlags, CollisionCB, Context, &BestD);
01091                         if (BestActor != NULL)
01092                                 {
01093                                         BestI = Impact;
01094                                         BestPlane = Plane2;
01095                                         Hit = GE_TRUE;
01096                                 }
01097                 }
01098 
01099         
01100         // GMins1/GMaxs1 is what is used to exapand the plane out with
01101         GMins1 = *Mins;
01102         GMaxs1 = *Maxs;
01103         
01104         GFront = *Front;
01105         GBack = *Back;
01106 
01107         BSPData = &World->CurrentBSP->BSPData;
01108         Models = World->CurrentBSP->Models;
01109 
01110         MiscNodes = BSPData->GFXNodes;
01111         MiscPlanes = BSPData->GFXPlanes;
01112         MiscLeafs = BSPData->GFXLeafs;
01113         MiscSides = BSPData->GFXLeafSides;
01114 
01115         assert(MiscNodes != NULL);
01116         assert(MiscPlanes != NULL);
01117         assert(MiscLeafs != NULL);
01118         assert(MiscSides != NULL);
01119 
01120         if (!(Flags & GE_COLLIDE_MODELS))
01121                 goto NoModels;
01122         
01123         Trace_GetMoveBox(Mins, Maxs, Front, Back, &OMins, &OMaxs);
01124 
01125         // Then test the world bsp(all models are the world bsp)
01126         // Go through each model, and find out what leafs we hit, keeping the closest intersection
01127         for (i = 0; i < BSPData->NumGFXModels; i++, Models++)
01128         {
01129                 
01130                 // First, see if the user wants to reject it...
01131                 if (CollisionCB && !CollisionCB(Models, NULL, Context))
01132                         continue;
01133 
01134                 for (b=0; b<3; b++)
01135                 {
01136                         if (VectorToSUB(OMaxs, b) < VectorToSUB(Models->TMins, b))
01137                                 break;
01138                         if (VectorToSUB(OMins, b) > VectorToSUB(Models->TMaxs, b))
01139                                 break;
01140                 }
01141 
01142                 if (b != 3)
01143                         continue;
01144                 
01145 
01146                 // Reset flags
01147                 BestDist = 9999.0f;
01148                 LeafHit = FALSE;
01149                 
01150                 geVec3d_Subtract(Front, &Models->Pivot, &GFront);
01151                 geVec3d_Subtract(Back , &Models->Pivot, &GBack);
01152 
01153                 // InverseTransform the point about models center of rotation
01154                 geXForm3d_TransposeTransform(&Models->XForm, &GFront, &NewFront);
01155                 geXForm3d_TransposeTransform(&Models->XForm, &GBack , &NewBack);
01156 
01157                 // push back into world
01158                 geVec3d_Add(&NewFront, &Models->Pivot, &GFront);
01159                 geVec3d_Add(&NewBack , &Models->Pivot, &GBack);
01160                 
01161                 // Make out box out of this move so we only check the leafs it intersected with...
01162 
01163                 Trace_GetMoveBox(Mins, Maxs, &GFront, &GBack, &GMins2, &GMaxs2);
01164 
01165                 FindClosestLeafIntersection_r(BSPData->GFXModels[i].RootNode[0]);
01166 
01167                 if (LeafHit)
01168                 {
01169                         
01170                         // Rotate the impact plane
01171                         geXForm3d_Rotate(&Models->XForm, &GlobalPlane.Normal, &GlobalPlane.Normal);
01172                         
01173                         // Rotate the impact point
01174                         geVec3d_Subtract(&GlobalI, &Models->Pivot, &GlobalI);
01175                         geXForm3d_Transform(&Models->XForm, &GlobalI, &NewFront);
01176                         //geXForm3d_Rotate(&Models->XForm, &GlobalI, &NewFront);
01177                         geVec3d_Add(&NewFront, &Models->Pivot, &GlobalI);
01178                         
01179                         // Find the new plane distance based on the new impact point with the new plane
01180                         GlobalPlane.Dist = geVec3d_DotProduct(&GlobalPlane.Normal, &GlobalI);
01181 
01182                         geVec3d_Subtract(&GlobalI, Front, &Vect);
01183 
01184                         Dist = geVec3d_Length(&Vect);
01185                         if (Dist < BestD)
01186                         {
01187                                 BestD = Dist;
01188                                 BestI = GlobalI;
01189                                 BestPlane = GlobalPlane;
01190                                 BestModel = Models;
01191                                 BestMesh = NULL;                        // Reset the mesh flag...
01192                                 BestActor = NULL;
01193                                 Hit = GE_TRUE;
01194                         }
01195                 }
01196 
01197                 if ((Flags & GE_COLLIDE_NO_SUB_MODELS))
01198                         goto NoModels;
01199 
01200         }
01201 
01202         NoModels:
01203 
01204         if (Hit)
01205         {
01206                 if (I) 
01207                         *I = BestI;
01208                 if (P) 
01209                         *P = BestPlane;
01210                 if (Mesh) 
01211                         *Mesh = BestMesh;
01212                 if (Model) 
01213                         *Model = BestModel;
01214                 if (Actor)
01215                         *Actor = BestActor;
01216                 return GE_TRUE;
01217         }
01218 
01219         return GE_FALSE;
01220 }
01221 
01222 //=====================================================================================
01223 //      Trace_TestModelMove
01224 //=====================================================================================
01225 geBoolean Trace_TestModelMove(  geWorld                 *World, 
01226                                                                 geWorld_Model   *Model, 
01227                                                                 const geXForm3d *DXForm, 
01228                                                                 const geVec3d   *Mins, const geVec3d *Maxs,
01229                                                                 const geVec3d   *In, geVec3d *Out)
01230 {
01231         geVec3d         NewFront, NewBack, Original;
01232 
01233         assert(World != NULL);
01234         assert(Model != NULL);
01235 
01236         BSPData = &World->CurrentBSP->BSPData;
01237 
01238         MiscNodes = BSPData->GFXNodes;
01239         MiscPlanes = BSPData->GFXPlanes;
01240         MiscLeafs = BSPData->GFXLeafs;
01241         MiscSides = BSPData->GFXLeafSides;
01242 
01243         assert(MiscNodes != NULL);
01244         assert(MiscPlanes != NULL);
01245         assert(MiscLeafs != NULL);
01246         assert(MiscSides != NULL);
01247 
01248         Original = *In;         // Save original
01249 
01250         GMins1 = *Mins;
01251         GMaxs1 = *Maxs;
01252         
01253         // Put point about models origin
01254         geVec3d_Subtract(In, &Model->Pivot, &GFront);
01255         GBack = GFront;
01256 
01257         // InverseTransform the points about models center of rotation
01258         geXForm3d_TransposeTransform(&Model->XForm, &GFront, &NewFront);
01259         // The back gets applied by the dest XForm
01260         geXForm3d_TransposeTransform(DXForm, &GBack, &NewBack);
01261 
01262         // push back into world
01263         geVec3d_Add(&NewFront, &Model->Pivot, &GFront);
01264         geVec3d_Add(&NewBack , &Model->Pivot, &GBack);
01265 
01266         // Make out box out of this move so we only check the leafs it intersected with...
01267         Trace_GetMoveBox(Mins, Maxs, &GFront, &GBack, &GMins2, &GMaxs2);
01268         
01269         BestDist = 9999.0f;
01270         LeafHit = FALSE;
01271 
01272         FindClosestLeafIntersection_r(BSPData->GFXModels[Model->GFXModelNum].RootNode[0]);
01273 
01274         if (LeafHit)
01275         {
01276                 GE_Collision    Collision;
01277 
01278                 // Rotate the impact plane
01279                 geXForm3d_Rotate(DXForm, &GlobalPlane.Normal, &GlobalPlane.Normal);
01280                         
01281                 // Rotate the impact point
01282                 geVec3d_Subtract(&GlobalI, &Model->Pivot, &NewFront);
01283                 geXForm3d_Transform(DXForm, &NewFront, &GlobalI);
01284                 geVec3d_Add(&GlobalI, &Model->Pivot, &NewFront);
01285                 GlobalI = NewFront;
01286 
01287                 // Find the new plane distance based on the new impact point with the new plane
01288                 GlobalPlane.Dist = geVec3d_DotProduct(&GlobalPlane.Normal, &GlobalI);
01289 
01290                 geVec3d_MA(&GlobalI, ON_EPSILON, &GlobalPlane.Normal, &GlobalI);
01291                 
01292                 // If the point gets pushed into the world as a result of the move, then cancel it out...
01293                 if (Trace_GEWorldCollision(World, Mins, Maxs, In, &GlobalI, GE_CONTENTS_SOLID_CLIP, GE_COLLIDE_ALL, 0xffffffff, NULL, NULL, &Collision))
01294                 {
01295                         *Out = Original;
01296                         return GE_FALSE;
01297                 }
01298 
01299                 *Out = GlobalI;
01300 
01301                 return GE_TRUE;
01302         }
01303 
01304         *Out = Original;
01305 
01306         return GE_TRUE;
01307 }
01308 
01309 //=====================================================================================
01310 // Trace_ModelCollisionBBox
01311 //=====================================================================================
01312 static
01313 geBoolean Trace_ModelCollisionBBox(geWorld *World, 
01314                                                                    geWorld_Model *Model, 
01315                                                                    const geXForm3d *DXForm, 
01316                                                                    const geVec3d *Mins, const geVec3d *Maxs,
01317                                                                    const geVec3d *In,
01318                                                                    geVec3d *ImpactPoint)
01319 {
01320         //MRB BEGIN
01321         // geVec3d NewFront, NewBack, Original;
01322         geVec3d NewFront, NewBack;
01323         //MRB END
01324         assert(World != NULL);
01325         assert(Model != NULL);
01326         BSPData = &World->CurrentBSP->BSPData;
01327         MiscNodes = BSPData->GFXNodes;
01328         MiscPlanes = BSPData->GFXPlanes;
01329         MiscLeafs = BSPData->GFXLeafs;
01330         MiscSides = BSPData->GFXLeafSides;
01331         assert(MiscNodes != NULL);
01332         assert(MiscPlanes != NULL);
01333         assert(MiscLeafs != NULL);
01334         assert(MiscSides != NULL);
01335         //MRB BEGIN
01336         // Original = *In; // Save original
01337         //MRB END
01338         GMins1 = *Mins;
01339         GMaxs1 = *Maxs;
01340         
01341         // Put point about models origin
01342         geVec3d_Subtract(In, &Model->Pivot, &GFront);
01343         GBack = GFront;
01344         // InverseTransform the points about models center of rotation
01345         geXForm3d_TransposeTransform(&Model->XForm, &GFront, &NewFront);
01346         // The back gets applied by the dest XForm
01347         geXForm3d_TransposeTransform(DXForm, &GBack, &NewBack);
01348         // push back into world
01349         geVec3d_Add(&NewFront, &Model->Pivot, &GFront);
01350         geVec3d_Add(&NewBack , &Model->Pivot, &GBack);
01351         // Make out box out of this move so we only check the leafs it intersected with...
01352         Trace_GetMoveBox(Mins, Maxs, &GFront, &GBack, &GMins2, &GMaxs2);
01353         
01354         BestDist = 9999.0f;
01355         LeafHit = FALSE;
01356         FindClosestLeafIntersection_r(BSPData->GFXModels[Model->GFXModelNum].RootNode[0]);
01357         if (LeafHit)
01358         {
01359                 // Rotate the impact plane
01360                 geXForm3d_Rotate(DXForm, &GlobalPlane.Normal, &GlobalPlane.Normal);
01361                 
01362                 // Rotate the impact point
01363                 //MRB BEGIN
01364                 // geVec3d_Subtract(&GlobalI, &Model->Pivot, &NewFront);
01365                 // geXForm3d_Transform(DXForm, &NewFront, &GlobalI);
01366                 // geVec3d_Add(&GlobalI, &Model->Pivot, &NewFront);
01367                 // GlobalI = NewFront;
01368                 geVec3d_Subtract(&GlobalI, &Model->Pivot, &GlobalI);
01369                 geXForm3d_Transform(DXForm, &GlobalI, &NewFront);
01370                 geVec3d_Add(&NewFront, &Model->Pivot, &GlobalI);
01371                 //MRB END
01372                 // Find the new plane distance based on the new impact point with the new plane
01373                 GlobalPlane.Dist = geVec3d_DotProduct(&GlobalPlane.Normal, &GlobalI);
01374                 geVec3d_MA(&GlobalI, ON_EPSILON, &GlobalPlane.Normal, &GlobalI);
01375                 *ImpactPoint = GlobalI;
01376                 return GE_TRUE;
01377         }
01378         return GE_FALSE;
01379 }
01380 //=====================================================================================
01381 // Trace_ModelCollision
01382 //=====================================================================================
01383 geBoolean Trace_ModelCollision(geWorld *World, 
01384                                                            geWorld_Model *Model, 
01385                                                            const geXForm3d *DXForm,
01386                                                            GE_Collision *Collision,
01387                                                            geVec3d *ImpactPoint)
01388 {
01389         geExtBox ExtBox;
01390         geVec3d Pos;
01391         geXForm3d myXForm;
01392 #ifdef MESHES
01393         Mesh_RenderQ * CollidableMesh;
01394         Mesh_CollidableMeshIterator Iter;
01395 #endif
01396   gContents = GE_CONTENTS_SOLID_CLIP;           // eaa3 from G3D BBS posting 01/29/2001
01397         memset(Collision, 0, sizeof(GE_Collision));
01398         // Fixed bug that mike pointed out. I was using 0, instead of 0xffffffff
01399 #ifdef MESHES
01400         CollidableMesh = Mesh_FirstCollidableMesh(World, &Iter, 0xffffffff);
01401         while (CollidableMesh)
01402         {
01403                 Mesh_MeshGetBox(World, CollidableMesh->MeshDef, &Mins, &Maxs);
01404                 Mesh_MeshGetPosition(CollidableMesh, &Pos);
01405                 if (Trace_ModelCollisionBBox(World, Model, DXForm, &Mins, &Maxs, &Pos, ImpactPoint))
01406                 {
01407                         Collision->Mesh = (geMesh *)CollidableMesh;
01408                         return GE_TRUE;
01409                 }
01410                 CollidableMesh = Mesh_NextCollidableMesh(&Iter, 0xffffffff);
01411         }
01412 #endif
01413         {
01414                 int i,Count;
01415                 World_Actor *WA;
01416                 //MRB BEGIN
01417                 geActor *BestActor;
01418                 geFloat BestActorDist;
01419                 geVec3d PossibleImpactPoint;
01420                 BestActor = NULL;
01421                 BestActorDist = 9999.0f;
01422                 //MRB END
01423                 
01424                 Count = World->ActorCount;
01425                 WA = &(World->ActorArray[0]);
01426                 for (i=0; i < Count; i++, WA++)
01427                 {
01428                         // if it's active (ignore userflags?)
01429                         if ( (WA->Flags & GE_ACTOR_COLLIDE) ) 
01430                         {
01431                                 //MRB BEGIN
01432                                 // if (geActor_GetExtBox(WA->Actor,&ExtBox)!=GE_FALSE)
01433                                 // {
01434                                 geActor_GetNonWorldExtBox(WA->Actor,&ExtBox);
01435                                 geActor_GetPosition(WA->Actor, &Pos);
01436                                 // eaa3 from posting on G3D message board 01/29/2001
01437                                 geActor_GetBoneTransform(WA->Actor, NULL, &myXForm);
01438                                 geVec3d_Copy(&myXForm.Translation, &Pos);
01439                                 geVec3d_Subtract(&ExtBox.Min, &Pos, &ExtBox.Min);
01440                                 geVec3d_Subtract(&ExtBox.Max, &Pos, &ExtBox.Max);
01441                                 // end eaa3 01/29/2001
01442                                 // if (Trace_ModelCollisionBBox(World, Model, DXForm, &(ExtBox.Min), &(ExtBox.Max), &Pos, ImpactPoint))
01443                                 if (Trace_ModelCollisionBBox(World, Model, DXForm, &(ExtBox.Min), &(ExtBox.Max), &Pos, &PossibleImpactPoint))
01444                                 {
01445                                         // Collision->Actor = WA->Actor;
01446                                         if (GlobalPlane.Dist < BestActorDist)
01447                                         {
01448                                                 BestActorDist = GlobalPlane.Dist;
01449                                                 BestActor = WA->Actor;
01450                                                 (*ImpactPoint) = PossibleImpactPoint;
01451                                                 Collision->Plane.Normal = GlobalPlane.Normal;
01452                                                 Collision->Plane.Dist = GlobalPlane.Dist;
01453                                                 Collision->Ratio = geVec3d_DistanceBetween(&DXForm->Translation, &Model->XForm.Translation);
01454                                         }
01455                                         // return GE_TRUE;
01456                                 }
01457                                 // }
01458                                 //MRB END
01459                         }
01460                 }
01461                 //MRB BEGIN
01462                 if (BestActor) {
01463                         Collision->Actor = BestActor;
01464                         return GE_TRUE;
01465                 }
01466                 //MRB END
01467         }
01468         return GE_FALSE;
01469 }
01470 
01471 
01472 //=====================================================================================
01473 //      MoveBox
01474 //      Creates a box around the entire move
01475 //=====================================================================================
01476 void Trace_GetMoveBox(const geVec3d *Mins, const geVec3d *Maxs, const geVec3d *Front, const geVec3d *Back, geVec3d *OMins, geVec3d *OMaxs)
01477 {
01478         int32           i;
01479 
01480         assert(Mins);
01481         assert(Maxs);
01482         assert(Front);
01483         assert(Back);
01484         
01485         for (i=0 ; i<3 ; i++)
01486         {
01487                 if (VectorToSUB(*Back, i) > VectorToSUB(*Front, i))
01488                 {
01489                         VectorToSUB(*OMins, i) = VectorToSUB(*Front, i) + VectorToSUB(*Mins, i) - 1.0f;
01490                         VectorToSUB(*OMaxs, i) = VectorToSUB(*Back, i) + VectorToSUB(*Maxs, i) + 1.0f;
01491                 }
01492                 else
01493                 {
01494                         VectorToSUB(*OMins, i) = VectorToSUB(*Back, i) + VectorToSUB(*Mins, i) - 1.0f;
01495                         VectorToSUB(*OMaxs, i) = VectorToSUB(*Front, i) + VectorToSUB(*Maxs, i) + 1.0f;
01496                 }
01497         }
01498 }
01499 
01500 
01501 static geBoolean        VisibleLeaf;
01502 //=====================================================================================
01503 //      BBoxInVisibleLeaf_r
01504 //=====================================================================================
01505 static void BBoxInVisibleLeaf_r(geWorld *World, geVec3d *Mins, geVec3d *Maxs, int32 Node)
01506 {
01507         int32           Leaf, Side;
01508 
01509         if (VisibleLeaf)
01510                 return;
01511         
01512         if (Node < 0)           // At a leaf, see if it's visible
01513         {
01514                 Leaf = -(Node+1);
01515 
01516                 if (World->CurrentBSP->LeafData[Leaf].VisFrame == World->CurFrameStatic)
01517                         VisibleLeaf = TRUE;
01518                 
01519                 return;
01520         }
01521 
01522         Side = Trace_BoxOnPlaneSide(Mins, Maxs, &MiscPlanes[MiscNodes[Node].PlaneNum]);
01523 
01524         // Go down the sides that the box lands in
01525         if (Side & PSIDE_FRONT)
01526                 BBoxInVisibleLeaf_r(World, Mins, Maxs, MiscNodes[Node].Children[0]);
01527 
01528         if (Side & PSIDE_BACK)
01529                 BBoxInVisibleLeaf_r(World, Mins, Maxs, MiscNodes[Node].Children[1]);
01530 }
01531 
01532 geBoolean Trace_BBoxInVisibleLeaf(geWorld *World, geVec3d *Mins, geVec3d *Maxs)
01533 {
01534         VisibleLeaf = FALSE;
01535 
01536         MiscNodes = World->CurrentBSP->BSPData.GFXNodes;
01537         MiscPlanes = World->CurrentBSP->BSPData.GFXPlanes;
01538         
01539         BBoxInVisibleLeaf_r(World, Mins, Maxs, 0);
01540 
01541         return VisibleLeaf;
01542 }
01543 
01544 //===================================================================================
01545 //      Trace_InverseTreeFromBox
01546 //      Builds am inside out collision tree from a box
01547 //===================================================================================
01548 geBoolean Trace_InverseTreeFromBox(geVec3d *Mins, geVec3d *Maxs, GFX_BNode *BNodes, GFX_Plane *Planes)
01549 {
01550         int32           i,j,n;
01551         geFloat         Bounds[2][3];
01552         GFX_Plane       *Plane;
01553 
01554         for (i=0; i< 3; i++)
01555         {
01556                 Bounds[0][i] = VectorToSUB(*Mins, i);
01557                 Bounds[1][i] = VectorToSUB(*Maxs, i);
01558         }
01559 
01560         // Build the boxs planes
01561         for (i=0; i< 3; i++)
01562         {
01563                 for (j=0; j< 2; j++)
01564                 {
01565                         n = j*3 + i;
01566                         
01567                         Plane = &Planes[n];
01568 
01569                         memset(Plane, 0, sizeof(GFX_Plane));
01570 
01571                         if (!j)         // Inside out
01572                         {
01573                                 VectorToSUB(Plane->Normal, i) = 1.0f;
01574                                 Plane->Dist = Bounds[j][i];
01575                         }
01576                         else
01577                         {
01578                                 VectorToSUB(Plane->Normal, i) = -1.0f;
01579                                 Plane->Dist = -Bounds[j][i];
01580                         }
01581 
01582                         Plane->Type = PLANE_ANY;
01583 
01584                         //
01585                         // Build the tree
01586                         //
01587                         BNodes[n].PlaneNum = n;
01588 
01589                         BNodes[n].Children[1] = BSP_CONTENTS_SOLID;
01590                         
01591                         if (n == 5)             
01592                                 BNodes[n].Children[0] = BSP_CONTENTS_EMPTY;
01593                         else            
01594                                 BNodes[n].Children[0] = n+1;
01595                 }
01596         }
01597         
01598         return GE_TRUE;
01599 }
01600 
01601 //=====================================================================================
01602 //      Trace_FindBNodeContents
01603 //      BNodes are special.  Instead of having a negative index to a leaf, the negative
01604 //  node number represents the contents of the leaf...
01605 //=====================================================================================
01606 int32 Plane_FindBNodeContents(  const GFX_BNode *Nodes, 
01607                                                                 const GFX_Plane *Planes, 
01608                                                                 int32 Node, 
01609                                                                 const geVec3d *POV)
01610 {
01611     geFloat             Dist;
01612 
01613     while (Node >= 0)           // < 0 == leaf with contents
01614         {
01615                 Dist = Plane_PlaneDistanceFast(&Planes[Nodes[Node].PlaneNum], POV);
01616         
01617                 if (Dist < 0) 
01618             Node = Nodes[Node].Children[1];
01619                 else
01620             Node = Nodes[Node].Children[0];
01621     }
01622         
01623         return Node;            // Return the contents
01624 }
01625 
01626 //=====================================================================================
01627 //      FillContents_r
01628 //      Traverses the leafs and or's all the contents together
01629 //=====================================================================================
01630 static void FillContents_r(int32 Node, const geVec3d *Pos, uint32 *Contents)
01631 {
01632         int32           Side;
01633 
01634         if (Node < 0)           // At a leaf, fill contens and return
01635         {
01636                 int32           Leaf;
01637 
01638                 Leaf = -(Node+1);
01639                 if (PointInLeafSides(Pos, &MiscLeafs[Leaf]))
01640                         *Contents |= MiscLeafs[Leaf].Contents;
01641                 return;
01642         }
01643 
01644         Side = Trace_BoxOnPlaneSide(&GMins2, &GMaxs2, &MiscPlanes[MiscNodes[Node].PlaneNum]);
01645 
01646         // Go down the sides that the box lands in
01647         if (Side & PSIDE_FRONT)
01648                 FillContents_r(MiscNodes[Node].Children[0], Pos, Contents);
01649 
01650         if (Side & PSIDE_BACK)
01651                 FillContents_r(MiscNodes[Node].Children[1], Pos, Contents);
01652 }
01653 
01654 //===================================================================================
01655 //      Trace_GetContents
01656 //      Fills a Contents structure with data and returns GE_TRUE if somthing was occupied
01657 //      Otherwise, it returns GE_FALSE and nothing is assumed to be occupied
01658 //===================================================================================
01659 geBoolean Trace_GetContents(geWorld *World, const geVec3d *Pos, const geVec3d *Mins, const geVec3d *Maxs, uint32 Flags, uint32 UserFlags, GE_CollisionCB *CollisionCB, void *Context, GE_Contents *Contents)
01660 {
01661         Mesh_RenderQ                            *MeshHit;
01662         geActor                                         *ActorHit;
01663         geExtBox                                        MeshExtBox;
01664         geVec3d                                         TMins, TMaxs;
01665         geBoolean                                       Hit;
01666         int32                                           i, k;
01667         uint32                                          NewContents, FinalContents;
01668         geWorld_Model                           *Models, *ModelHit;
01669         GFX_Model                                       *GFXModels;
01670 
01671         assert(World);
01672         assert(Contents);
01673         
01674         MeshHit = NULL;
01675         ModelHit = NULL;
01676         FinalContents = 0;
01677         Hit = GE_FALSE;
01678 
01679         BSPData = &World->CurrentBSP->BSPData;
01680 
01681         // Get the translated box from the input pos...
01682         geVec3d_Add(Mins, Pos, &TMins);
01683         geVec3d_Add(Maxs, Pos, &TMaxs);
01684 
01685         NumGetContents++;
01686 
01687         if (Flags & GE_COLLIDE_ACTORS)
01688         {
01689                 int32 Count;
01690                 World_Actor *WA;
01691                         
01692                 Count = World->ActorCount;
01693                 WA = &(World->ActorArray[0]);
01694 
01695                 for (i=0; i<Count; i++, WA++)
01696                 {
01697                                 
01698                         // Reject if not active or if userflags don't accept...
01699                         if (!(WA->Flags & GE_ACTOR_COLLIDE) || !(WA->UserFlags & UserFlags) )
01700                                 continue;
01701 
01702                         if (CollisionCB && !CollisionCB(NULL, WA->Actor, Context))
01703                                 continue;
01704 
01705                                 
01706                         if (geActor_GetExtBox(WA->Actor,&MeshExtBox)==GE_FALSE)
01707                                 continue;
01708 
01709                         for (k=0; k<3; k++)
01710                         {
01711                                 if (geVec3d_GetElement(&TMaxs,k) < geVec3d_GetElement(&(MeshExtBox.Min),k)-1)
01712                                         break;
01713                                 if (geVec3d_GetElement(&TMins,k) > geVec3d_GetElement(&(MeshExtBox.Max),k)+1)
01714                                         break;
01715                         }
01716                                 
01717                         if (k != 3)
01718                                 continue;
01719 
01720                         ActorHit = WA->Actor;
01721                         Hit = GE_TRUE;
01722                         break;                          // Just return the first actor
01723                 }
01724         }
01725 
01726         if (!(Flags & GE_COLLIDE_MODELS))
01727                 goto NoModels;
01728         
01729         MiscNodes = World->CurrentBSP->BSPData.GFXNodes;
01730         MiscPlanes = World->CurrentBSP->BSPData.GFXPlanes;
01731         MiscLeafs = World->CurrentBSP->BSPData.GFXLeafs;
01732         MiscSides = BSPData->GFXLeafSides;
01733 
01734         Models = World->CurrentBSP->Models;
01735         GFXModels = World->CurrentBSP->BSPData.GFXModels;
01736 
01737         GMins1 = *Mins;
01738         GMaxs1 = *Maxs;
01739 
01740         GMins2 = TMins;
01741         GMaxs2 = TMaxs;
01742 
01743         for (i = 0; i < BSPData->NumGFXModels; i++, Models++, GFXModels++)
01744         {
01745                 geVec3d TPos;
01746 
01747                 if (CollisionCB && !CollisionCB(Models, NULL, Context))
01748                         continue;
01749 
01750                 if (i > 0)              // Ignore model 0 box (main world, we should always try to collide with world)
01751                 {
01752                         for (k=0; k<3; k++)
01753                         {
01754                                 if (VectorToSUB(TMaxs, k) < VectorToSUB(Models->TMins, k))
01755                                         break;
01756                                 if (VectorToSUB(TMins, k) > VectorToSUB(Models->TMaxs, k))
01757                                         break;
01758                         }
01759 
01760                         if (k != 3)                     // Couldn't possibly hit if box's don't hit...
01761                                 continue;
01762                 }
01763 
01764                 geVec3d_Subtract(Pos, &Models->RealCenter, &TPos);
01765 
01766                 // InverseTransform the point about models center of rotation
01767                 geXForm3d_TransposeTransform(&Models->XForm, &TPos, &TPos);
01768 
01769                 // push back into world
01770 
01771                 geVec3d_Add(&TPos, &Models->RealCenter, &TPos);
01772 
01773                 // Reset contents
01774                 NewContents = 0;
01775 
01776                 FillContents_r(GFXModels->RootNode[0], &TPos, &NewContents);
01777 
01778                 if (NewContents && !ModelHit)
01779                 {
01780                         ModelHit = Models;                                              // First model hit for any arbritrary contents
01781                         Hit = GE_TRUE;
01782                 }
01783 
01784                 if (NewContents & GE_CONTENTS_SOLID_CLIP)       // Solid has precedence
01785                 {
01786                         ModelHit = Models;
01787                 }
01788 
01789                 // Or final contents with this new contents
01790                 FinalContents |= NewContents;
01791 
01792                 if ((Flags & GE_COLLIDE_NO_SUB_MODELS))
01793                         goto NoModels;
01794         }
01795 
01796         NoModels:
01797 
01798         if (Hit)
01799         {
01800                 Contents->Contents = FinalContents;
01801                 Contents->Mesh = (geMesh*)MeshHit;
01802                 Contents->Model = ModelHit;
01803                 Contents->Actor = ActorHit;
01804                 return GE_TRUE;
01805         }
01806 
01807         // If nothing occupied, then make sure the return structure is cleared for cleanness
01808         memset(Contents, 0, sizeof(GE_Contents));
01809 
01810         return GE_FALSE;
01811 }
01812 
01813 
01814 
01815 //=====================================================================================
01816 //      Trace_SetupIntersect
01817 //=====================================================================================
01818 static  GFX_Plane       *TreePlanes;
01819 static  GFX_Node        *TreeNodes;
01820 static  GFX_Leaf        *TreeLeafs;
01821 
01822 void Trace_SetupIntersect(geWorld *World)
01823 {
01824         BSPData = &World->CurrentBSP->BSPData;
01825 
01826         TreePlanes = BSPData->GFXPlanes;
01827         TreeNodes = BSPData->GFXNodes;
01828         TreeLeafs = BSPData->GFXLeafs;
01829 }
01830 
01831 //=====================================================================================
01832 //      Trace_IntersectWorldBSP
01833 //      Shoot a ray through the tree finding out what solid leafs it passed through
01834 //=====================================================================================
01835 geBoolean Trace_IntersectWorldBSP(geVec3d *Front, geVec3d *Back, int32 Node)
01836 {
01837     geFloat             Fd, Bd, Dist;
01838     int32               Side;
01839     geVec3d             I;
01840         GFX_Plane       *Plane;
01841         int32           Contents;
01842 
01843         gContents = GE_CONTENTS_SOLID_CLIP;
01844 
01845         if (Node < 0)
01846         {
01847                 Contents = TreeLeafs[-(Node+1)].Contents;
01848 
01849                 if (Contents & gContents)
01850                     return GE_TRUE;                                             // Ray collided with solid space
01851                 return GE_FALSE;
01852         }
01853 
01854         Plane = &TreePlanes[TreeNodes[Node].PlaneNum];
01855 
01856     Fd = Plane_PlaneDistanceFast(Plane, Front);
01857     Bd = Plane_PlaneDistanceFast(Plane, Back);
01858 
01859     if (Fd >= 0 && Bd >= 0) 
01860         return(BSPIntersect(Front, Back, TreeNodes[Node].Children[0]));
01861     if (Fd < 0 && Bd < 0)
01862         return(BSPIntersect(Front, Back, TreeNodes[Node].Children[1]));
01863 
01864     Side = Fd < 0;
01865     Dist = Fd / (Fd - Bd);
01866 
01867     I.X = Front->X + Dist * (Back->X - Front->X);
01868     I.Y = Front->Y + Dist * (Back->Y - Front->Y);
01869     I.Z = Front->Z + Dist * (Back->Z - Front->Z);
01870 
01871     // Work our way to the front, from the back side.  As soon as there
01872         // is no more collisions, we can assume that we have the front portion of the
01873         // ray that is in empty space.  Once we find this, and see that the back half is in
01874         // solid space, then we found the front intersection point...
01875         if (BSPIntersect(Front, &I, TreeNodes[Node].Children[Side]))
01876         return GE_TRUE;
01877     else if (BSPIntersect(&I, Back, TreeNodes[Node].Children[!Side]))
01878         {
01879                 return GE_TRUE;
01880         }
01881 
01882         return GE_FALSE;
01883 }
01884 
01885 static  geVec3d         gStart, gEnd;
01886 static  GFX_Plane       gPlane;
01887 
01888 geBoolean Trace_CollideBeam(int32 Node, geVec3d *s, geVec3d *e, geFloat Radius)
01889 {
01890         geFloat         dd, sDist, eDist;
01891         geVec3d         tempVec, tempVec2;
01892         geBoolean       FrontLeaf, BackLeaf;
01893         GFX_Plane       *Plane;
01894 
01895         if(Node < 0)
01896         {
01897                 //leaf found, check contents
01898                 return  !(!(BSPData->GFXLeafs[-(Node+1)].Contents & gContents));
01899         }
01900         Plane   =&BSPData->GFXPlanes[BSPData->GFXNodes[Node].PlaneNum];
01901 
01902         //startpoint and endpoint plane distances
01903         sDist   =Plane_PlaneDistanceFast(Plane, s);
01904         eDist   =Plane_PlaneDistanceFast(Plane, e);
01905 
01906         //check sides for start and end...
01907         if(*((uint32 *)&sDist) & 0x80000000)    //if sdist < 0
01908         {
01909                 if(sDist < -Radius)
01910                 {
01911                         if(*((uint32 *)&eDist) & 0x80000000)    //if edist < 0
01912                         {
01913                                 if(eDist < -Radius)
01914                                 {
01915                                         //nothing to front, all to back
01916                                         BackLeaf        =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, e, Radius);
01917                                 }
01918                                 else
01919                                 {
01920                                         //impact to e to front, all back
01921                                         //find spot where dist==-Radius along motionVec
01922                                         //make this the front s
01923                                         dd=(sDist+Radius)/((sDist+Radius)-(eDist+Radius));
01924 
01925                                         //cap the push back factor (don't allow negative)
01926                                         if(*((uint32 *)&dd) & 0x80000000)       //is dd negative?
01927                                         {
01928                                                 dd      =0.0f;
01929                                         }
01930 
01931                                         geVec3d_Subtract(e, s, &tempVec);
01932                                         geVec3d_Scale(&tempVec, dd, &tempVec2);
01933                                         geVec3d_Add(s, &tempVec2, &tempVec);
01934 
01935                                         //send new piece to front
01936                                         FrontLeaf       =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], &tempVec, e, Radius);
01937                                         BackLeaf        =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, e, Radius);
01938                                 }
01939                         }
01940                         else
01941                         {
01942                                 if(eDist > Radius)
01943                                 {
01944                                         //impact to e to front, sdist to impact to back
01945                                         //find spot where dist==-Radius along motionVec
01946                                         //make this the front s
01947                                         dd=(sDist+Radius)/((sDist+Radius)-(eDist+Radius));
01948 
01949                                         geVec3d_Subtract(e, s, &tempVec);
01950                                         geVec3d_Scale(&tempVec, dd, &tempVec2);
01951                                         geVec3d_Add(s, &tempVec2, &tempVec);
01952 
01953                                         //send new piece to front
01954                                         FrontLeaf       =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], &tempVec, e, Radius);
01955 
01956                                         //find spot where dist==Radius along motionVec
01957                                         //make this the back e
01958                                         dd=(sDist-Radius)/((sDist-Radius)-(eDist-Radius));
01959 
01960                                         //cap the push back factor (don't allow negative)
01961                                         if(*((uint32 *)&dd) & 0x80000000)       //is dd negative?
01962                                         {
01963                                                 dd      =0.0f;
01964                                         }
01965 
01966                                         geVec3d_Subtract(e, s, &tempVec);
01967                                         geVec3d_Scale(&tempVec, dd, &tempVec2);
01968                                         geVec3d_Add(e, &tempVec2, &tempVec);
01969 
01970                                         //send new piece to back
01971                                         BackLeaf        =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, &tempVec, Radius);
01972                                 }
01973                                 else
01974                                 {
01975                                         //impact to edist to front, all to back
01976                                         //find spot where dist==-Radius along motionVec
01977                                         //make this the front s
01978                                         dd=(sDist+Radius)/((sDist+Radius)-(eDist+Radius));
01979 
01980                                         //cap the push back factor (don't allow negative)
01981                                         if(*((uint32 *)&dd) & 0x80000000)       //is dd negative?
01982                                         {
01983                                                 dd      =0.0f;
01984                                         }
01985 
01986                                         geVec3d_Subtract(e, s, &tempVec);
01987                                         geVec3d_Scale(&tempVec, dd, &tempVec2);
01988                                         geVec3d_Add(s, &tempVec2, &tempVec);
01989 
01990                                         //send new piece to front
01991                                         FrontLeaf       =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], &tempVec, e, Radius);
01992                                         BackLeaf        =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, e, Radius);
01993                                 }
01994                         }
01995                 }
01996                 else
01997                 {
01998                         if(*((uint32 *)&eDist) & 0x80000000)    //if edist < 0
01999                         {
02000                                 if(eDist < -Radius)
02001                                 {
02002                                         //sdist to impact to front, all back
02003                                         //find spot where dist==-Radius along motionVec
02004                                         //make this the front e
02005                                         dd=(sDist+Radius)/((sDist+Radius)-(eDist+Radius));
02006 
02007                                         //cap the push back factor (don't allow negative)
02008                                         if(*((uint32 *)&dd) & 0x80000000)       //is dd negative?
02009                                         {
02010                                                 dd      =0.0f;
02011                                         }
02012 
02013                                         geVec3d_Subtract(e, s, &tempVec);
02014                                         geVec3d_Scale(&tempVec, dd, &tempVec2);
02015                                         geVec3d_Add(e, &tempVec2, &tempVec);
02016 
02017                                         //send new piece to front
02018                                         FrontLeaf       =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, &tempVec, Radius);
02019                                         BackLeaf        =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, e, Radius);
02020                                 }
02021                                 else
02022                                 {
02023                                         //all to front, all to back
02024                                         FrontLeaf       =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, e, Radius);
02025                                         BackLeaf        =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, e, Radius);
02026                                 }
02027                         }
02028                         else
02029                         {
02030                                 if(eDist > Radius)
02031                                 {
02032                                         //all to front, sdist to impact to back
02033                                         FrontLeaf       =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, e, Radius);
02034 
02035                                         //find the spot where dist==Radius along motionVec
02036                                         //make this the back e
02037                                         dd=(sDist-Radius)/((sDist-Radius)-(eDist-Radius));
02038 
02039                                         //cap the push back factor (don't allow negative)
02040                                         if(*((uint32 *)&dd) & 0x80000000)       //is dd negative?
02041                                         {
02042                                                 dd      =0.0f;
02043                                         }
02044 
02045                                         geVec3d_Subtract(e, s, &tempVec);
02046                                         geVec3d_Scale(&tempVec, dd, &tempVec2);
02047                                         geVec3d_Add(e, &tempVec2, &tempVec);
02048 
02049                                         //send new piece to back
02050                                         BackLeaf        =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, &tempVec, Radius);
02051                                 }
02052                                 else
02053                                 {
02054                                         //all to front, all to back
02055                                         FrontLeaf       =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, e, Radius);
02056                                         BackLeaf        =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, e, Radius);
02057                                 }
02058                         }
02059                 }
02060         }
02061         else
02062         {
02063                 if(sDist > Radius)
02064                 {
02065                         if(!(*((uint32 *)&eDist) & 0x80000000)) //if edist > 0
02066                         {
02067                                 if(eDist > Radius)
02068                                 {
02069                                         //all to front, none to back
02070                                         FrontLeaf       =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, e, Radius);
02071                                 }
02072                                 else
02073                                 {
02074                                         //all to front, impact to edist to back
02075                                         FrontLeaf       =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, e, Radius);
02076 
02077                                         //find spot where dist==Radius along motionVec
02078                                         //make this the back s
02079                                         dd=(sDist-Radius)/((sDist-Radius)-(eDist-Radius));
02080 
02081                                         //cap the push back factor (don't allow negative)
02082                                         if(*((uint32 *)&dd) & 0x80000000)       //is dd negative?
02083                                         {
02084                                                 dd      =0.0f;
02085                                         }
02086 
02087                                         geVec3d_Subtract(e, s, &tempVec);
02088                                         geVec3d_Scale(&tempVec, dd, &tempVec2);
02089                                         geVec3d_Add(e, &tempVec2, &tempVec);
02090 
02091                                         //send new piece to back
02092                                         BackLeaf        =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], &tempVec, e, Radius);
02093                                 }
02094                         }
02095                         else
02096                         {
02097                                 if(eDist < -Radius)
02098                                 {
02099                                         //sdist to impact to front, impact to edist to back
02100                                         //find spot where dist==-Radius along motionVec
02101                                         //make this the front e
02102                                         dd=(sDist+Radius)/((sDist+Radius)-(eDist+Radius));
02103 
02104                                         geVec3d_Subtract(e, s, &tempVec);
02105                                         geVec3d_Scale(&tempVec, dd, &tempVec2);
02106                                         geVec3d_Add(e, &tempVec2, &tempVec);
02107 
02108                                         //send new piece to front
02109                                         FrontLeaf       =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, &tempVec, Radius);
02110 
02111                                         //find spot where dist==Radius along motionVec
02112                                         //make this the back s
02113                                         dd=(sDist-Radius)/((sDist-Radius)-(eDist-Radius));
02114 
02115                                         //cap the push back factor (don't allow negative)
02116                                         if(*((uint32 *)&dd) & 0x80000000)       //is dd negative?
02117                                         {
02118                                                 dd      =0.0f;
02119                                         }
02120 
02121                                         geVec3d_Subtract(e, s, &tempVec);
02122                                         geVec3d_Scale(&tempVec, dd, &tempVec2);
02123                                         geVec3d_Add(s, &tempVec2, &tempVec);
02124 
02125                                         //send new piece to back
02126                                         BackLeaf        =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], &tempVec, e, Radius);
02127                                 }
02128                                 else
02129                                 {
02130                                         //all to front, impact to edist to back
02131                                         FrontLeaf       =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, e, Radius);
02132 
02133                                         //find spot where dist==Radius along motionVec
02134                                         //make this the back s
02135                                         dd=(sDist-Radius)/((sDist-Radius)-(eDist-Radius));
02136 
02137                                         //cap the push back factor (don't allow negative)
02138                                         if(*((uint32 *)&dd) & 0x80000000)       //is dd negative?
02139                                         {
02140                                                 dd      =0.0f;
02141                                         }
02142 
02143                                         geVec3d_Subtract(e, s, &tempVec);
02144                                         geVec3d_Scale(&tempVec, dd, &tempVec2);
02145                                         geVec3d_Add(s, &tempVec2, &tempVec);
02146 
02147                                         //send new piece to back
02148                                         BackLeaf        =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], &tempVec, e, Radius);
02149                                 }
02150                         }
02151                 }
02152                 else
02153                 {
02154                         if(!(*((uint32 *)&eDist) & 0x80000000)) //if edist > 0
02155                         {
02156                                 if(eDist > Radius)
02157                                 {
02158                                         //all to front, sdist to impact to back
02159                                         FrontLeaf       =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, e, Radius);
02160 
02161                                         //find the spot where dist==Radius along motionVec
02162                                         //make this the back e
02163                                         dd=(sDist-Radius)/((sDist-Radius)-(eDist-Radius));
02164 
02165                                         //cap the push back factor (don't allow negative)
02166                                         if(*((uint32 *)&dd) & 0x80000000)       //is dd negative?
02167                                         {
02168                                                 dd      =0.0f;
02169                                         }
02170 
02171                                         geVec3d_Subtract(e, s, &tempVec);
02172                                         geVec3d_Scale(&tempVec, dd, &tempVec2);
02173                                         geVec3d_Add(e, &tempVec2, &tempVec);
02174 
02175                                         //send new piece to back
02176                                         BackLeaf        =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, &tempVec, Radius);
02177                                 }
02178                                 else
02179                                 {
02180                                         //all to front, all to back
02181                                         FrontLeaf       =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, e, Radius);
02182                                         BackLeaf        =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, e, Radius);
02183                                 }
02184                         }
02185                         else
02186                         {
02187                                 if(eDist < -Radius)
02188                                 {
02189                                         //sdist to impact to front, all to back
02190                                         //find spot where dist==-Radius along motionVec
02191                                         //make this the front e
02192                                         dd=(sDist+Radius)/((sDist+Radius)-(eDist+Radius));
02193 
02194                                         //cap the push back factor (don't allow negative)
02195                                         if(*((uint32 *)&dd) & 0x80000000)       //is dd negative?
02196                                         {
02197                                                 dd      =0.0f;
02198                                         }
02199 
02200                                         geVec3d_Subtract(e, s, &tempVec);
02201                                         geVec3d_Scale(&tempVec, dd, &tempVec2);
02202                                         geVec3d_Add(e, &tempVec2, &tempVec);
02203 
02204                                         //send new piece to front
02205                                         FrontLeaf       =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, &tempVec, Radius);
02206                                         BackLeaf        =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, e, Radius);
02207                                 }
02208                                 else
02209                                 {
02210                                         //all to front, all to back
02211                                         FrontLeaf       =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[0], s, e, Radius);
02212                                         BackLeaf        =Trace_CollideBeam(BSPData->GFXNodes[Node].Children[1], s, e, Radius);
02213                                 }
02214                         }
02215                 }
02216         }
02217 
02218         //bsp ordering makes the magic happen
02219         //stack based can early out methinks, but it's way too ugly
02220         if(BackLeaf && !FrontLeaf)
02221         {
02222                 gStart  =*s;
02223                 gEnd    =*e;
02224                 gPlane  =*Plane;
02225         }
02226 
02227         //this will nullify farther collisions
02228         return  GE_FALSE;
02229 }
02230 
02231 // changed texture name
02232 
02233 
02234 //=====================================================================================
02235 //      FillContents_tr
02236 //      Traverses the leafs and or's all the contents together
02237 //=====================================================================================
02238 static void FillContents_tr(geWorld *World, int32 Node, const geVec3d *Pos, char *texname)
02239 {
02240         int32           Side;
02241 
02242         if (Node < 0)           // At a leaf, fill contens and return
02243         {
02244                 int32           Leaf;
02245 
02246                 Leaf = -(Node+1);
02247                 if (PointInLeafSides(Pos, &MiscLeafs[Leaf]))
02248                 {
02249                         //gePoly *Poly = World->CurrentBSP->LeafData[Leaf].PolyList;
02250                         //if(Poly)
02251                         {
02252                                 //const geBitmap *Bitmap = Poly->Bitmap;
02253                                 //char *name = geWBitmap_Pool_GetWNameByBitmap(World->CurrentBSP->WBitmapPool, Bitmap);
02254                                 char str[100];
02255                                 sprintf(str,"Leaf : %d\n",Leaf);
02256                                 OutputDebugString(str);
02257                                 //if(name)
02258                                 //{
02259                                 //      strcpy(str, name);
02260                                 //      OutputDebugString(str); OutputDebugString("\n");
02261                                 //}
02262                         }
02263                 }
02264                 return;
02265         }
02266 
02267         Side = Trace_BoxOnPlaneSide(&GMins2, &GMaxs2, &MiscPlanes[MiscNodes[Node].PlaneNum]);
02268 
02269         // Go down the sides that the box lands in
02270         if (Side & PSIDE_FRONT)
02271                 FillContents_tr(World, MiscNodes[Node].Children[0], Pos, texname);
02272 
02273         if (Side & PSIDE_BACK)
02274                 FillContents_tr(World, MiscNodes[Node].Children[1], Pos, texname);
02275 }
02276 
02277 //===================================================================================
02278 //      Trace_GetexureName
02279 //      Get texture name and returns GE_TRUE if somthing was occupied
02280 //      Otherwise, it returns GE_FALSE and nothing is assumed to be occupied
02281 //===================================================================================
02282 geBoolean Trace_GetTexureName(geWorld *World, const geVec3d *Pos, const geVec3d *Mins, const geVec3d *Maxs, char *TexName)
02283 {
02284         geVec3d                                         TMins, TMaxs;
02285         geBoolean                                       Hit;
02286         int32                                           i, k;
02287         geWorld_Model                           *Models, *ModelHit;
02288         GFX_Model                                       *GFXModels;
02289 
02290         assert(World);
02291         
02292         ModelHit = NULL;
02293         Hit = GE_FALSE;
02294 
02295         BSPData = &World->CurrentBSP->BSPData;
02296 
02297         // Get the translated box from the input pos...
02298         geVec3d_Add(Mins, Pos, &TMins);
02299         geVec3d_Add(Maxs, Pos, &TMaxs);
02300 
02301         MiscNodes = World->CurrentBSP->BSPData.GFXNodes;
02302         MiscPlanes = World->CurrentBSP->BSPData.GFXPlanes;
02303         MiscLeafs = World->CurrentBSP->BSPData.GFXLeafs;
02304         MiscSides = BSPData->GFXLeafSides;
02305 
02306         Models = World->CurrentBSP->Models;
02307         GFXModels = World->CurrentBSP->BSPData.GFXModels;
02308 
02309         GMins1 = *Mins;
02310         GMaxs1 = *Maxs;
02311 
02312         GMins2 = TMins;
02313         GMaxs2 = TMaxs;
02314 
02315         for (i = 0; i < BSPData->NumGFXModels; i++, Models++, GFXModels++)
02316         {
02317                 geVec3d TPos;
02318 
02319                 if (i > 0)              // Ignore model 0 box (main world, we should always try to collide with world)
02320                 {
02321                         for (k=0; k<3; k++)
02322                         {
02323                                 if (VectorToSUB(TMaxs, k) < VectorToSUB(Models->TMins, k))
02324                                         break;
02325                                 if (VectorToSUB(TMins, k) > VectorToSUB(Models->TMaxs, k))
02326                                         break;
02327                         }
02328 
02329                         if (k != 3)                     // Couldn't possibly hit if box's don't hit...
02330                                 continue;
02331                 }
02332 
02333                 geVec3d_Subtract(Pos, &Models->RealCenter, &TPos);
02334 
02335                 // InverseTransform the point about models center of rotation
02336                 geXForm3d_TransposeTransform(&Models->XForm, &TPos, &TPos);
02337 
02338                 // push back into world
02339 
02340                 geVec3d_Add(&TPos, &Models->RealCenter, &TPos);
02341 
02342                 FillContents_tr(World, GFXModels->RootNode[0], &TPos, TexName);
02343 
02344                 if (!ModelHit)
02345                 {
02346                         ModelHit = Models;                                              // First model hit for any arbritrary contents
02347                         Hit = GE_TRUE;
02348                 }
02349         }
02350 
02351         if (Hit)
02352         {
02353                 return GE_TRUE;
02354         }
02355 
02356         return GE_FALSE;
02357 }
02358 
02359 // end change texture name

Generated on Tue Sep 30 12:36:33 2003 for GTestAndEngine by doxygen 1.3.2