| [216] | 1 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 2 | /* | 
|---|
 | 3 |  *      OPCODE - Optimized Collision Detection | 
|---|
 | 4 |  *      Copyright (C) 2001 Pierre Terdiman | 
|---|
 | 5 |  *      Homepage: http://www.codercorner.com/Opcode.htm | 
|---|
 | 6 |  */ | 
|---|
 | 7 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 8 |  | 
|---|
 | 9 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 10 | /** | 
|---|
 | 11 |  *      Contains code to perform "picking". | 
|---|
 | 12 |  *      \file           OPC_Picking.cpp | 
|---|
 | 13 |  *      \author         Pierre Terdiman | 
|---|
 | 14 |  *      \date           March, 20, 2001 | 
|---|
 | 15 |  */ | 
|---|
 | 16 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 17 |  | 
|---|
 | 18 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 19 | // Precompiled Header | 
|---|
 | 20 | #include "Stdafx.h" | 
|---|
 | 21 |  | 
|---|
 | 22 | using namespace Opcode; | 
|---|
 | 23 |  | 
|---|
 | 24 | #ifdef OPC_RAYHIT_CALLBACK | 
|---|
 | 25 |  | 
|---|
 | 26 | /* | 
|---|
 | 27 |         Possible RayCollider usages: | 
|---|
 | 28 |         - boolean query (shadow feeler) | 
|---|
 | 29 |         - closest hit | 
|---|
 | 30 |         - all hits | 
|---|
 | 31 |         - number of intersection (boolean) | 
|---|
 | 32 |  | 
|---|
 | 33 | */ | 
|---|
 | 34 |  | 
|---|
 | 35 | bool Opcode::SetupAllHits(RayCollider& collider, CollisionFaces& contacts) | 
|---|
 | 36 | { | 
|---|
 | 37 |         struct Local | 
|---|
 | 38 |         { | 
|---|
 | 39 |                 static void AllContacts(const CollisionFace& hit, void* user_data) | 
|---|
 | 40 |                 { | 
|---|
 | 41 |                         CollisionFaces* CF = (CollisionFaces*)user_data; | 
|---|
 | 42 |                         CF->AddFace(hit); | 
|---|
 | 43 |                 } | 
|---|
 | 44 |         }; | 
|---|
 | 45 |  | 
|---|
 | 46 |         collider.SetFirstContact(false); | 
|---|
 | 47 |         collider.SetHitCallback(Local::AllContacts); | 
|---|
 | 48 |         collider.SetUserData(&contacts); | 
|---|
 | 49 |         return true; | 
|---|
 | 50 | } | 
|---|
 | 51 |  | 
|---|
 | 52 | bool Opcode::SetupClosestHit(RayCollider& collider, CollisionFace& closest_contact) | 
|---|
 | 53 | { | 
|---|
 | 54 |         struct Local | 
|---|
 | 55 |         { | 
|---|
 | 56 |                 static void ClosestContact(const CollisionFace& hit, void* user_data) | 
|---|
 | 57 |                 { | 
|---|
 | 58 |                         CollisionFace* CF = (CollisionFace*)user_data; | 
|---|
 | 59 |                         if(hit.mDistance<CF->mDistance) *CF = hit; | 
|---|
 | 60 |                 } | 
|---|
 | 61 |         }; | 
|---|
 | 62 |  | 
|---|
 | 63 |         collider.SetFirstContact(false); | 
|---|
 | 64 |         collider.SetHitCallback(Local::ClosestContact); | 
|---|
 | 65 |         collider.SetUserData(&closest_contact); | 
|---|
 | 66 |         closest_contact.mDistance = MAX_FLOAT; | 
|---|
 | 67 |         return true; | 
|---|
 | 68 | } | 
|---|
 | 69 |  | 
|---|
 | 70 | bool Opcode::SetupShadowFeeler(RayCollider& collider) | 
|---|
 | 71 | { | 
|---|
 | 72 |         collider.SetFirstContact(true); | 
|---|
 | 73 |         collider.SetHitCallback(null); | 
|---|
 | 74 |         return true; | 
|---|
 | 75 | } | 
|---|
 | 76 |  | 
|---|
 | 77 | bool Opcode::SetupInOutTest(RayCollider& collider) | 
|---|
 | 78 | { | 
|---|
 | 79 |         collider.SetFirstContact(false); | 
|---|
 | 80 |         collider.SetHitCallback(null); | 
|---|
 | 81 |         // Results with collider.GetNbIntersections() | 
|---|
 | 82 |         return true; | 
|---|
 | 83 | } | 
|---|
 | 84 |  | 
|---|
 | 85 | bool Opcode::Picking( | 
|---|
 | 86 | CollisionFace& picked_face, | 
|---|
 | 87 | const Ray& world_ray, const Model& model, const Matrix4x4* world, | 
|---|
 | 88 | float min_dist, float max_dist, const Point& view_point, CullModeCallback callback, void* user_data) | 
|---|
 | 89 | { | 
|---|
 | 90 |         struct Local | 
|---|
 | 91 |         { | 
|---|
 | 92 |                 struct CullData | 
|---|
 | 93 |                 { | 
|---|
 | 94 |                         CollisionFace*                  Closest; | 
|---|
 | 95 |                         float                                   MinLimit; | 
|---|
 | 96 |                         CullModeCallback                Callback; | 
|---|
 | 97 |                         void*                                   UserData; | 
|---|
 | 98 |                         Point                                   ViewPoint; | 
|---|
 | 99 |                         const MeshInterface*    IMesh; | 
|---|
 | 100 |                 }; | 
|---|
 | 101 |  | 
|---|
 | 102 |                 // Called for each stabbed face | 
|---|
 | 103 |                 static void RenderCullingCallback(const CollisionFace& hit, void* user_data) | 
|---|
 | 104 |                 { | 
|---|
 | 105 |                         CullData* Data = (CullData*)user_data; | 
|---|
 | 106 |  | 
|---|
 | 107 |                         // Discard face if we already have a closer hit | 
|---|
 | 108 |                         if(hit.mDistance>=Data->Closest->mDistance)     return; | 
|---|
 | 109 |  | 
|---|
 | 110 |                         // Discard face if hit point is smaller than min limit. This mainly happens when the face is in front | 
|---|
 | 111 |                         // of the near clip plane (or straddles it). If we keep the face nonetheless, the user can select an | 
|---|
 | 112 |                         // object that he may not even be able to see, which is very annoying. | 
|---|
 | 113 |                         if(hit.mDistance<=Data->MinLimit)       return; | 
|---|
 | 114 |  | 
|---|
 | 115 |                         // This is the index of currently stabbed triangle. | 
|---|
 | 116 |                         udword StabbedFaceIndex = hit.mFaceID; | 
|---|
 | 117 |  | 
|---|
 | 118 |                         // We may keep it or not, depending on backface culling | 
|---|
 | 119 |                         bool KeepIt = true; | 
|---|
 | 120 |  | 
|---|
 | 121 |                         // Catch *render* cull mode for this face | 
|---|
 | 122 |                         CullMode CM = (Data->Callback)(StabbedFaceIndex, Data->UserData); | 
|---|
 | 123 |  | 
|---|
 | 124 |                         if(CM!=CULLMODE_NONE)   // Don't even compute culling for double-sided triangles | 
|---|
 | 125 |                         { | 
|---|
 | 126 |                                 // Compute backface culling for current face | 
|---|
 | 127 |  | 
|---|
 | 128 |                                 VertexPointers VP; | 
|---|
 | 129 |                                 Data->IMesh->GetTriangle(VP, StabbedFaceIndex); | 
|---|
 | 130 |                                 if(VP.BackfaceCulling(Data->ViewPoint)) | 
|---|
 | 131 |                                 { | 
|---|
 | 132 |                                         if(CM==CULLMODE_CW)             KeepIt = false; | 
|---|
 | 133 |                                 } | 
|---|
 | 134 |                                 else | 
|---|
 | 135 |                                 { | 
|---|
 | 136 |                                         if(CM==CULLMODE_CCW)    KeepIt = false; | 
|---|
 | 137 |                                 } | 
|---|
 | 138 |                         } | 
|---|
 | 139 |  | 
|---|
 | 140 |                         if(KeepIt)      *Data->Closest = hit; | 
|---|
 | 141 |                 } | 
|---|
 | 142 |         }; | 
|---|
 | 143 |  | 
|---|
 | 144 |         RayCollider RC; | 
|---|
 | 145 |         RC.SetMaxDist(max_dist); | 
|---|
 | 146 |         RC.SetTemporalCoherence(false); | 
|---|
 | 147 |         RC.SetCulling(false);           // We need all faces since some of them can be double-sided | 
|---|
 | 148 |         RC.SetFirstContact(false); | 
|---|
 | 149 |         RC.SetHitCallback(Local::RenderCullingCallback); | 
|---|
 | 150 |  | 
|---|
 | 151 |         picked_face.mFaceID             = INVALID_ID; | 
|---|
 | 152 |         picked_face.mDistance   = MAX_FLOAT; | 
|---|
 | 153 |         picked_face.mU                  = 0.0f; | 
|---|
 | 154 |         picked_face.mV                  = 0.0f; | 
|---|
 | 155 |  | 
|---|
 | 156 |         Local::CullData Data; | 
|---|
 | 157 |         Data.Closest                    = &picked_face; | 
|---|
 | 158 |         Data.MinLimit                   = min_dist; | 
|---|
 | 159 |         Data.Callback                   = callback; | 
|---|
 | 160 |         Data.UserData                   = user_data; | 
|---|
 | 161 |         Data.ViewPoint                  = view_point; | 
|---|
 | 162 |         Data.IMesh                              = model.GetMeshInterface(); | 
|---|
 | 163 |  | 
|---|
 | 164 |         if(world) | 
|---|
 | 165 |         { | 
|---|
 | 166 |                 // Get matrices | 
|---|
 | 167 |                 Matrix4x4 InvWorld; | 
|---|
 | 168 |                 InvertPRMatrix(InvWorld, *world); | 
|---|
 | 169 |  | 
|---|
 | 170 |                 // Compute camera position in mesh space | 
|---|
 | 171 |                 Data.ViewPoint *= InvWorld; | 
|---|
 | 172 |         } | 
|---|
 | 173 |  | 
|---|
 | 174 |         RC.SetUserData(&Data); | 
|---|
 | 175 |         if(RC.Collide(world_ray, model, world)) | 
|---|
 | 176 |         { | 
|---|
 | 177 |                 return picked_face.mFaceID!=INVALID_ID; | 
|---|
 | 178 |         } | 
|---|
 | 179 |         return false; | 
|---|
 | 180 | } | 
|---|
 | 181 |  | 
|---|
 | 182 | #endif | 
|---|