1 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3 * OPCODE - Optimized Collision Detection
4 * Copyright (C) 2001 Pierre Terdiman
5 * Homepage: http://www.codercorner.com/Opcode.htm
7 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
9 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
11 * Contains code to perform "picking".
12 * \file OPC_Picking.cpp
13 * \author Pierre Terdiman
14 * \date March, 20, 2001
16 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
18 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
22 using namespace Opcode
;
24 #ifdef OPC_RAYHIT_CALLBACK
27 Possible RayCollider usages:
28 - boolean query (shadow feeler)
31 - number of intersection (boolean)
35 bool Opcode::SetupAllHits(RayCollider
& collider
, CollisionFaces
& contacts
)
39 static void AllContacts(const CollisionFace
& hit
, void* user_data
)
41 CollisionFaces
* CF
= (CollisionFaces
*)user_data
;
46 collider
.SetFirstContact(false);
47 collider
.SetHitCallback(Local::AllContacts
);
48 collider
.SetUserData(&contacts
);
52 bool Opcode::SetupClosestHit(RayCollider
& collider
, CollisionFace
& closest_contact
)
56 static void ClosestContact(const CollisionFace
& hit
, void* user_data
)
58 CollisionFace
* CF
= (CollisionFace
*)user_data
;
59 if(hit
.mDistance
<CF
->mDistance
) *CF
= hit
;
63 collider
.SetFirstContact(false);
64 collider
.SetHitCallback(Local::ClosestContact
);
65 collider
.SetUserData(&closest_contact
);
66 closest_contact
.mDistance
= MAX_FLOAT
;
70 bool Opcode::SetupShadowFeeler(RayCollider
& collider
)
72 collider
.SetFirstContact(true);
73 collider
.SetHitCallback(null
);
77 bool Opcode::SetupInOutTest(RayCollider
& collider
)
79 collider
.SetFirstContact(false);
80 collider
.SetHitCallback(null
);
81 // Results with collider.GetNbIntersections()
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
)
94 CollisionFace
* Closest
;
96 CullModeCallback Callback
;
99 const MeshInterface
* IMesh
;
102 // Called for each stabbed face
103 static void RenderCullingCallback(const CollisionFace
& hit
, void* user_data
)
105 CullData
* Data
= (CullData
*)user_data
;
107 // Discard face if we already have a closer hit
108 if(hit
.mDistance
>=Data
->Closest
->mDistance
) return;
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;
115 // This is the index of currently stabbed triangle.
116 udword StabbedFaceIndex
= hit
.mFaceID
;
118 // We may keep it or not, depending on backface culling
121 // Catch *render* cull mode for this face
122 CullMode CM
= (Data
->Callback
)(StabbedFaceIndex
, Data
->UserData
);
124 if(CM
!=CULLMODE_NONE
) // Don't even compute culling for double-sided triangles
126 // Compute backface culling for current face
130 Data
->IMesh
->GetTriangle(VP
, StabbedFaceIndex
, VC
);
131 if(VP
.BackfaceCulling(Data
->ViewPoint
))
133 if(CM
==CULLMODE_CW
) KeepIt
= false;
137 if(CM
==CULLMODE_CCW
) KeepIt
= false;
141 if(KeepIt
) *Data
->Closest
= hit
;
146 RC
.SetMaxDist(max_dist
);
147 RC
.SetTemporalCoherence(false);
148 RC
.SetCulling(false); // We need all faces since some of them can be double-sided
149 RC
.SetFirstContact(false);
150 RC
.SetHitCallback(Local::RenderCullingCallback
);
152 picked_face
.mFaceID
= INVALID_ID
;
153 picked_face
.mDistance
= MAX_FLOAT
;
154 picked_face
.mU
= 0.0f
;
155 picked_face
.mV
= 0.0f
;
157 Local::CullData Data
;
158 Data
.Closest
= &picked_face
;
159 Data
.MinLimit
= min_dist
;
160 Data
.Callback
= callback
;
161 Data
.UserData
= user_data
;
162 Data
.ViewPoint
= view_point
;
163 Data
.IMesh
= model
.GetMeshInterface();
169 InvertPRMatrix(InvWorld
, *world
);
171 // Compute camera position in mesh space
172 Data
.ViewPoint
*= InvWorld
;
175 RC
.SetUserData(&Data
);
176 if(RC
.Collide(world_ray
, model
, world
))
178 return picked_face
.mFaceID
!=INVALID_ID
;