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