Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
intersec.cpp
Go to the documentation of this file.
1/*
2** Command & Conquer Generals Zero Hour(tm)
3** Copyright 2025 Electronic Arts Inc.
4**
5** This program is free software: you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation, either version 3 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/***********************************************************************************************
20 *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
21 ***********************************************************************************************
22 * *
23 * Project Name : G *
24 * *
25 * $Archive:: /Commando/Code/ww3d2/intersec.cpp $*
26 * *
27 * $Author:: Greg_h $*
28 * *
29 * $Modtime:: 2/06/01 5:41p $*
30 * *
31 * $Revision:: 3 $*
32 * *
33 *---------------------------------------------------------------------------------------------*
34 * Functions: *
35 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
36
37
38
39#include "intersec.h"
40#include "camera.h"
41#include "scene.h"
42#include "intersec.inl"
43
44
46// Construction/Destruction
48
49// these statics are used for single-threaded use of the IntersectionClass ONLY
53
54
56{
57 Get_Screen_Ray(screen_x, screen_y, Layer);
58 return Intersect_RenderObject(RObj, FinalResult);
59}
60
62{
63 if(FinalResult == 0)
64 FinalResult = &Result;
65
66 return RObj->Intersect(this, FinalResult);
67}
68
69// iterate through the layers of a world, front to back, returning true if/when an intersection
70// with an object occurs.
72(
73 float screen_x,
74 float screen_y,
75 const LayerClass &TopLayer,
76 const LayerClass &BackLayer
77)
78{
79
80 // intersect from front layer to back layers. An intersection with an object
81 // in any layer is assumed to be in front of any potential intersections in layers
82 // below it.
83
84 // find the last layer in the list
85 const LayerClass *Layer = &TopLayer;
86
87 // iterate through all layers in list
88 while(Layer->Is_Valid()) {
89 if(Intersect_Screen_Point_Layer(screen_x, screen_y, *Layer))
90 return true;
91
92 // if this is the back layer then that is all we need to test
93 if(Layer == &BackLayer)
94 return false;
95
96 Layer = Layer->Next();
97 }
98 return false;
99}
100
101
102bool IntersectionClass::Intersect_Screen_Point_Layer(float screen_x, float screen_y, const LayerClass &Layer)
103{
104 // mark this object as not intersecting yet
105 Result.Intersects = false;
106
107 // first, do a test to make sure the screen coords are within the rendering area for this layer.
108 const ViewportClass &v = Layer.Camera->Get_Viewport();
109
110 if((screen_x < v.Min.X) ||
111 (screen_x > v.Max.X) ||
112 (screen_y < v.Min.Y) ||
113 (screen_y > v.Max.Y))
114 return false;
115
116 Result.Range = Layer.Camera->Get_Depth(); //scene->depth * scene->zstop;
117
118 // get the ray for these screen coordinates
119 Get_Screen_Ray(screen_x, screen_y, Layer);
120
121 return Intersect_Layer(Layer, false);
122}
123
125{
126 IntersectionResultClass FinalResult;
127
128 Result.Intersects = false;
129
130 SceneIterator *it = Layer.Scene->Create_Iterator(!Test_All);
131
132 // select the first object
133 it->First();
134
135 // loop through all render objects in this layer:
136 while(!it->Is_Done()) {
137
138 // get the render object
139 RenderObjClass * robj = it->Current_Item();
140 it->Next();
141
142 // only intersect if it was visible or if we must test all in layer
143 // Added 'Generals' code to only detect intersection on matching Collision_Type. MW
144 if( robj->Get_Collision_Type() & Result.CollisionType && (Test_All || robj->Is_Really_Visible()) && robj->Intersect(this, &FinalResult)) {
145 if(FinalResult.Range < Result.Range) {
146 Copy_Results(&FinalResult);
147 }
148 }
149 }
150
151 Layer.Scene->Destroy_Iterator(it);
152
153 return Result.Intersects;
154}
155
156
158 int MaxCount,
159 int &CurrentCount,
160 RenderObjClass **ObjectArray,
162{
163 if(CurrentCount < MaxCount) {
164 ObjectArray[CurrentCount] = Object;
165 CurrentCount++;
166 return;
167 }
168 WWDEBUG_SAY(("IntersectionClass::Append_Object_Array - Too many objects\n"));
169}
170
171// determines if specified plane-intersection point (co-planar with polygon) is within the the passed polygon.
172// If Interpolated_Normal is specified, it will interpolate the normal for the intersection point
173// note: Polygon normal MUST BE CORRECT
174
175// this will return true if the ray intersects the specified box
176// sets the point of intersection within the Request->Result.Intersection vector
178 // Fast Ray-Box Intersection, modified from code written by Andrew Woo from "Graphics Gems", Academic Press, 1990
179
180 enum {
181 RIGHT = 0,
182 LEFT,
183 MIDDLE,
184 PLANE_COUNT
185 };
186
187 bool inside = true;
188 char quadrant[PLANE_COUNT];
189 int counter;
190 float distance[PLANE_COUNT];
191 float candidate_plane[PLANE_COUNT];
192
193 register Vector3 *intersection = &FinalResult->Intersection;
194
195 // Find candidate planes and determine if the ray is outside the box
196 for (counter = 0; counter < PLANE_COUNT; counter++) {
197 if((*RayLocation)[counter] < Box_Min[counter]) {
198 quadrant[counter] = LEFT;
199 candidate_plane[counter] = Box_Min[counter];
200 inside = false;
201 } else {
202 if ((*RayLocation)[counter] > Box_Max[counter]) {
203 quadrant[counter] = RIGHT;
204 candidate_plane[counter] = Box_Max[counter];
205 inside = false;
206 } else {
207 quadrant[counter] = MIDDLE;
208 }
209 }
210 }
211
212 // check to see if the ray origin is inside bounding box
213 if(inside) {
214 *intersection = *RayLocation;
215 return FinalResult->Intersects = true;
216 }
217
218 // Calculate distances to candidate planes
219 for (counter = 0; counter < PLANE_COUNT; counter++) {
220 if ((quadrant[counter] != MIDDLE) && ((*RayDirection)[counter] != 0.0f))
221 distance[counter] = (candidate_plane[counter] - (*RayLocation)[counter]) / (*RayDirection)[counter];
222 else
223 distance[counter] = -1.0f;
224 }
225
226 // get the largest of the distances for final choice of intersection
227 int nearest_plane = 0;
228 for (counter = 1; counter < PLANE_COUNT; counter++) {
229 if (distance[nearest_plane] < distance[counter])
230 nearest_plane = counter;
231 }
232
233 // Check to make sure the nearest plane is not behind the ray (inside box tested above)
234 if (distance[nearest_plane] < 0.0f)
235 return FinalResult->Intersects = false;
236
237 for (counter = 0; counter < PLANE_COUNT; counter++) {
238 if (nearest_plane != counter) {
239 (*intersection)[counter] = (*RayLocation)[counter] + distance[nearest_plane] *(*RayDirection)[counter];
240 if ((*intersection)[counter] < Box_Min[counter] || (*intersection)[counter] > Box_Max[counter])
241 return FinalResult->Intersects = false;
242 } else {
243 (*intersection)[counter] = candidate_plane[counter];
244 }
245 }
246 return FinalResult->Intersects = true; // ray hits box
247}
248
249
250// simply returns true if a ray hits the bounding sphere of any node in a hierarchy
251// note: Result will only contain range, not the intersection point/normal.
253{
254
255 int counter = Hierarchy->Get_Num_Sub_Objects();
256 while(counter--) {
257 RenderObjClass *obj = Hierarchy->Get_Sub_Object(counter);
258 obj->Release_Ref(); // you already own a reference to this object indirectly..
259 if(obj->Intersect_Sphere_Quick(this, FinalResult))
260 return true;
261 }
262 return false;
263}
264
265// returns true if a ray hits the bounding sphere of any node in a hierarchy
266// note: Result will contain range and the intersection point/normal.
268
269 int counter = Hierarchy->Get_Num_Sub_Objects();
270 while(counter--) {
271 RenderObjClass *obj = Hierarchy->Get_Sub_Object(counter);
272 obj->Release_Ref(); // you already own a reference to this object indirectly..
273 if(obj->Intersect_Sphere(this, FinalResult))
274 return true;
275 }
276 return false;
277}
278
280 int MaxCount,
281 int &CurrentCount,
282 RenderObjClass **ObjectArray,
283 RenderObjClass *Hierarchy,
284 bool Test_Bounding_Sphere,
285 bool Convex)
286{
288
289 // first check the bounding spheres for hits (if specified)
290 int counter = Hierarchy->Get_Num_Sub_Objects();
291 if(Test_Bounding_Sphere) {
292 while(counter--) {
293 RenderObjClass *obj = Hierarchy->Get_Sub_Object(counter);
294 obj->Release_Ref(); // you already own a reference to the object indirectly
295 if(obj->Intersect_Sphere_Quick(this, &result)) {
296 Append_Object_Array(MaxCount, CurrentCount, ObjectArray, obj);
297// OutputDebugString("o"); // this shows one o per sphere intersection
298 } else {
299// OutputDebugString("."); // this shows one . per sphere miss
300 }
301 }
302
303 } else {
304 // simply copy the pointers into the array
305 while(counter--) {
306 RenderObjClass *obj = Hierarchy->Get_Sub_Object(counter);
307 Append_Object_Array(MaxCount, CurrentCount, ObjectArray, obj);
308 obj->Release_Ref(); // you already own a reference to this object indirectly..
309 }
310 }
311}
312
313bool IntersectionClass::Intersect_Hierarchy(RenderObjClass *Hierarchy, IntersectionResultClass *FinalResult, bool Test_Bounding_Sphere, bool Convex ) {
314
315// OutputDebugString("\n");
316// return FinalResult->Intersects = false;
317
318 RenderObjClass *candidate_objects[MAX_HIERARCHY_NODE_COUNT];
319 int candidate_count = 0;
320
321 Append_Hierarchy_Objects(MAX_HIERARCHY_NODE_COUNT, candidate_count, candidate_objects, Hierarchy, Test_Bounding_Sphere, Convex);
322
323 // make sure there's at least one sphere hit before continuing to more expensive tests below..
324 if(candidate_count == 0) {
325 // OutputDebugString("/"); // no sphere intersections
326 return FinalResult->Intersects = false;
327 }
328
329 // note: Test_Bounding_Sphere argument is false because the Append_Hierarchy_Objects will have
330 // already performed that test if indicated.
331 if(Intersect_Object_Array(candidate_count, candidate_objects, FinalResult, false, Convex)) {
332 return true;
333 }
334 return false;
335}
336
338{
339 if (robj->Get_Num_Sub_Objects()) {
340 for (int lp = 0; lp < robj->Get_Num_Sub_Objects(); lp++) {
341 RenderObjClass *sub = robj->Get_Sub_Object(lp);
342 RenderObjClass *retval = Intersect_Sub_Object(screenx, screeny, layer, sub, result);
343 sub->Release_Ref();
344 if (retval) return retval;
345 }
346 }
347 if (Intersect_Screen_Point_RenderObject(screenx, screeny, layer, robj, result)) {
348 return robj;
349 }
350 return NULL;
351}
352
353// finds the intersection of the nearest object in the array.
354// This will usually be the last stage after determining potential intersections
355// using Intersect_Sphere_Quick() and adding hits to the array for this
356// more accurate test, as done in Intersect_Heirarchy().
358 int Object_Count,
359 RenderObjClass **ObjectArray,
360 IntersectionResultClass *FinalResult,
361 bool Test_Bounding_Sphere,
362 bool Convex
363 )
364{
366 assert(Object_Count <= MAX_HIERARCHY_NODE_COUNT);
367 return Intersect_Object_Array(Object_Count, ObjectArray, FinalResult, TemporaryResults, Test_Bounding_Sphere, Convex);
368}
369
371 int Object_Count,
372 RenderObjClass **ObjectArray,
373 IntersectionResultClass *FinalResult,
374 IntersectionResultClass *TemporaryResults,
375 bool Test_Bounding_Sphere,
376 bool Convex
377 )
378{
379 // Determine ranges for all intersections
380 IntersectionClass temp(this);
381 int counter = Object_Count;
382 bool hit = false;
383
384 // if it's a convex hierarchy (ie a control panel) then find the first hit otherwise use the more expensive exact intersection routine
385 // for use with potentially concave hierarchies.
386 int nearest_index = -1;
387 if(ConvexTest || Convex) {
388 if(Test_Bounding_Sphere) {
389 while(counter--) {
390 if(ObjectArray[counter]->Intersect_Sphere_Quick(this, &TemporaryResults[counter])) {
391 hit = ObjectArray[counter]->Intersect(this, FinalResult);
392 }
393 if(hit) {
394 nearest_index = counter;
395 counter = 0;
396 }
397 }
398 } else {
399 while(counter--) {
400 hit = ObjectArray[counter]->Intersect(this, FinalResult);
401 if(hit) {
402 nearest_index = counter;
403 counter = 0;
404 }
405 }
406 }
407 } else {
408 if(Test_Bounding_Sphere) {
409 while(counter--) {
410 if(ObjectArray[counter]->Intersect_Sphere_Quick(this, &TemporaryResults[counter])) {
411 hit |= ObjectArray[counter]->Intersect(this, &TemporaryResults[counter]);
412 }
413 }
414 } else {
415 while(counter--) {
416 hit |= ObjectArray[counter]->Intersect(this, &TemporaryResults[counter]);
417 }
418 }
419 }
420 // test to see if anything actually hit a mesh
421 if( ! hit ) {
422// OutputDebugString("!"); // no mesh intersections
423 return FinalResult->Intersects = false;
424 }
425
426 if(! (Convex || ConvexTest)) {
427 // now find the nearest of the actual hits
428 float nearest_range = (float) (2<<28);
429 counter = Object_Count;
430 while(counter--) {
431 if(TemporaryResults[counter].Intersects && (nearest_range > TemporaryResults[counter].Range)) {
432 nearest_index = counter;
433 nearest_range = TemporaryResults[counter].Range;
434 }
435 }
436 Copy_Results(FinalResult, &TemporaryResults[nearest_index]);
437 }
438// OutputDebugString("+");
439// Debug.Print("Mesh ", Object_Array[nearest_index]);
440// Intersection_Node = candidate_indices[nearest_index];
441 return true;
442}
443
#define NULL
Definition BaseType.h:92
bool Intersect_Screen_Point_RenderObject(float screen_x, float screen_y, const LayerClass &Layer, RenderObjClass *RObj, IntersectionResultClass *FinalResult)
Definition intersec.cpp:55
IntersectionResultClass Result
Definition intersec.h:133
RenderObjClass * Intersect_Sub_Object(float screenx, float screeny, LayerClass &layer, RenderObjClass *robj, IntersectionResultClass *result)
Definition intersec.cpp:337
bool Intersect_Hierarchy_Sphere(RenderObjClass *Hierarchy, IntersectionResultClass *FinalResult)
Definition intersec.cpp:267
void Get_Screen_Ray(float ScreenX, float ScreenY, const LayerClass &Layer)
debug code that will be tossed
Definition intersec.inl:81
bool Intersect_Screen_Point_Layer(float ScreenX, float ScreenY, const LayerClass &Layer)
Definition intersec.cpp:102
bool Intersect_Sphere_Quick(SphereClass &Sphere, IntersectionResultClass *FinalResult)
Definition intersec.h:228
static Vector3 _IntersectionNormal
Definition intersec.h:399
void Append_Hierarchy_Objects(int MaxCount, int &CurrentCount, RenderObjClass **ObjectArray, RenderObjClass *Heirarchy, bool Test_Bounding_Spheres, bool Convex)
Definition intersec.cpp:279
bool Intersect_Box(Vector3 &Box_Min, Vector3 &Box_Max, IntersectionResultClass *FinalResult)
Definition intersec.cpp:177
bool Intersect_RenderObject(RenderObjClass *RObj, IntersectionResultClass *FinalResult=0)
Definition intersec.cpp:61
bool Intersect_Hierarchy_Sphere_Quick(RenderObjClass *Hierarchy, IntersectionResultClass *FinalResult)
Definition intersec.cpp:252
static Vector3 _RayLocation
Definition intersec.h:399
Vector3 * RayLocation
Definition intersec.h:108
bool Intersect_Layer(const LayerClass &Layer, bool Test_All=true)
Definition intersec.cpp:124
static Vector3 _RayDirection
Definition intersec.h:399
bool Intersect_Screen_Point_Layer_Range(float ScreenX, float ScreenY, const LayerClass &TopLayer, const LayerClass &BackLayer)
Definition intersec.cpp:72
Vector3 * RayDirection
Definition intersec.h:109
void Copy_Results(IntersectionResultClass *Destination, IntersectionResultClass *Source)
Definition intersec.h:176
void Append_Object_Array(int MaxCount, int &CurrentCount, RenderObjClass **ObjectArray, RenderObjClass *Object)
Definition intersec.cpp:157
bool Intersect_Object_Array(int ObjectCount, RenderObjClass **ObjectArray, IntersectionResultClass *FinalResult, bool Test_Bounding_Sphere, bool Convex)
Definition intersec.cpp:357
bool Intersect_Hierarchy(RenderObjClass *Hierarchy, IntersectionResultClass *FinalResult, bool Test_Bounding_Sphere=true, bool Convex=false)
Definition intersec.cpp:313
WWINLINE void Release_Ref(void) const
Definition refcount.h:146
virtual bool Intersect_Sphere_Quick(IntersectionClass *Intersection, IntersectionResultClass *Final_Result)
Definition rendobj.cpp:1034
virtual int Is_Really_Visible(void)
Definition rendobj.h:462
virtual bool Intersect_Sphere(IntersectionClass *Intersection, IntersectionResultClass *Final_Result)
Definition rendobj.cpp:1015
virtual int Get_Num_Sub_Objects(void) const
Definition rendobj.h:309
virtual RenderObjClass * Get_Sub_Object(int index) const
Definition rendobj.h:310
virtual int Get_Collision_Type(void) const
Definition rendobj.h:484
virtual bool Intersect(IntersectionClass *Intersection, IntersectionResultClass *Final_Result)
Definition rendobj.cpp:972
virtual void Next(void)=0
virtual RenderObjClass * Current_Item(void)=0
virtual void First(void)=0
virtual bool Is_Done(void)=0
float Y
Definition vector2.h:79
float X
Definition vector2.h:74
Vector2 Min
Definition camera.h:80
Vector2 Max
Definition camera.h:81
int counter
Definition patch.cpp:410
const int RIGHT
Definition vxllayer.cpp:76
const int LEFT
Definition vxllayer.cpp:75
#define WWDEBUG_SAY(x)
Definition wwdebug.h:114