Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
intersec.inl
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#if defined(_MSC_VER)
21#pragma once
22#endif
23
24#ifndef INTERSEC_INL
25#define INTERSEC_INL
26
27#include "camera.h"
28
29
31
32#ifdef DEBUG_NORMALS
33
34#include "d:/g/app/main/debug_o.h"
35
36inline bool Verify_Normal(Vector3 &Normal, Vector3 &loc1, Vector3 &loc2, Vector3 &loc3)
37{
38
39 double d1 = Vector3::Dot_Product(Normal, loc1);
40 double d2 = Vector3::Dot_Product(Normal, loc2);
41 double d3 = Vector3::Dot_Product(Normal, loc3);
42
43 double e1 = d1 - d2;
44 double e2 = d2 - d3;
45 double e3 = d3 - d1;
46
47 if((fabs(e1) > 0.001) || (fabs(e2) > 0.001) || (fabs(e3) > 0.001)) {
48 Debug.Print("----------\n");
49 Debug.Print("dots", Vector3(d1,d2,d3));
50 Debug.Print("err", Vector3(e1,e2,e3));
51 return false;
52 }
53 return true;
54}
55
56inline void Verify_Normal2(Vector3 &Normal, Vector3 &loc1, Vector3 &loc2, Vector3 &loc3)
57{
58 Vector3 v1 = loc2 - loc1;
59 Vector3 v2 = loc3 - loc1;
60 Vector3 normal = Vector3::Cross_Product(v1,v2);
61 normal.Normalize();
62 if(!Verify_Normal(Normal, loc1,loc2,loc3)) {
63 Vector3 diff = Normal - normal;
64 if(Verify_Normal(normal, loc1,loc2,loc3)) {
65 Debug.Print("calculated worked.\n");
66
67 }
68 }
69// Normal = normal;
70}
71
72#endif
73
75
76/*
77** Determine the ray that corresponds to the specified screen coordinates with respect
78** to the camera location, direction and projection information.
79*/
80
81inline void IntersectionClass::Get_Screen_Ray(float screen_x, float screen_y, const LayerClass &Layer)
82{
83
84 // copy screen coords to member data
85 ScreenX = screen_x;
86 ScreenY = screen_y;
87
88 // extract needed pointers from the world
89 CameraClass *camera = Layer.Camera;
90
91 // determine the ray corresponding to the camera and distance to projection plane
92 Matrix3D camera_matrix = camera->Get_Transform();
93 Vector3 camera_location = camera->Get_Position();
94
95 // the projected ray has the same origin as the camera
96 *RayLocation = camera_location;
97
98// these 6 lines worked for SR 1.1
99// build the projected screen vector
100// float x_offset = width / (float)Scene->width; // render width in pixels divided by display width in pixels = ratio of displayed area
101// float y_offset = height / (float)Scene->height;
102// float zmod = Scene->perspective;
103// float xmod = ((ScreenX / x_offset) * width - xmid - Scene->xstart) * zmod * 16384.0f/ (Scene->axratio * 128.0f);
104// float ymod = ((ScreenY / y_offset) * height - ymid - Scene->ystart) * zmod * 16384.0f/ (Scene->ayratio * 128.0f);
105
106 // determine the location of the screen coordinate in camera-model space
107 const ViewportClass &viewport = camera->Get_Viewport();
108
109// float aspect = camera->Get_Aspect_Ratio();
110
112 camera->Get_View_Plane(min,max);
113 float xscale = (max.X - min.X);
114 float yscale = (max.Y - min.Y);
115
116 float zmod = -1.0; // Scene->vpd; // Note: view plane distance is now always 1.0 from the camera
117 float xmod = (-ScreenX + 0.5 + viewport.Min.X) * zmod * xscale;// / aspect;
118 float ymod = (ScreenY - 0.5 - viewport.Min.Y) * zmod * yscale;// * aspect;
119
120// float xmod = (ScreenX - 0.5 - viewport.Min.X) * zmod / Scene->axratio;
121// float ymod = (ScreenY - 0.5 - viewport.Min.Y) * zmod / Scene->ayratio;
122
123// sr1.2
124// float xmod = (ScreenX - 0.5 - Scene->xstart) * zmod / Scene->axratio;
125// float ymod = (ScreenY - 0.5 - Scene->ystart) * zmod / Scene->ayratio;
126// sr1.1
127// float xmod = x_offset * zmod; //projection_width;
128// float ymod = y_offset * zmod; //projection_height;
129
130 // transform the screen coordinates by the camera's matrix into world coordinates.
131 float x = zmod * camera_matrix[0][2] + xmod * camera_matrix[0][0] + ymod * camera_matrix[0][1];
132 float y = zmod * camera_matrix[1][2] + xmod * camera_matrix[1][0] + ymod * camera_matrix[1][1];
133 float z = zmod * camera_matrix[2][2] + xmod * camera_matrix[2][0] + ymod * camera_matrix[2][1];
134
135 RayDirection->Set(x,y,z);
136 RayDirection->Normalize();
137
138 // set the maximum intersection distance to the back clipping plane
139 MaxDistance = camera->Get_Depth();
140 //Max_Distance = Scene->zstop * Scene->depth;
141
142}
143
144/*
145** This is the Point_In_Polygon_Z low level function, optimized for use by _Intersect_Triangles_Z.
146** If it is inside, it will adjust the Z value of the point to be on the triangle plane.
147*/
149 Vector3 &Point,
150 Vector3 &Corner1,
151 Vector3 &Corner2,
152 Vector3 &Corner3
153)
154{
155// these defines could be variables if support for other axis were neccessary
156#define AXIS_1 0
157#define AXIS_2 1
158#define AXIS_3 2
159
160 double u0 = Point[AXIS_1] - Corner1[AXIS_1];
161 double v0 = Point[AXIS_2] - Corner1[AXIS_2];
162
163 // determine the 2d vectors on the dominant plane from the first vertex to the other two
164 double u1 = Corner2[AXIS_1] - Corner1[AXIS_1];
165 double v1 = Corner2[AXIS_2] - Corner1[AXIS_2];
166 double u2 = Corner3[AXIS_1] - Corner1[AXIS_1];
167 double v2 = Corner3[AXIS_2] - Corner1[AXIS_2];
168
169 double alpha, beta;
170 bool intersect = false;
171
172 // calculate alpha and beta as normalized (0..1) percentages across the 2d projected triangle
173 // and do bounds checking (sum <= 1) to determine whether or not the triangle intersection occurs.
174
175 if (u1 == 0.0f) {
176 beta = u0 / u2; // beta is the percentage down the edge Corner1->Corner3
177 if ((beta >= 0.0f) && (beta <= 1.0f)) { // make sure it's within the edge segment
178 alpha = (v0 - beta * v2) / v1; // alpha is the percentage down the edge Corner1->Corner2
179
180 // if alpha is valid & the sum of alpha & beta is <= 1 then it's within the triangle
181 // note: 0.00001 added after testing an intersection of a square in the middle indicated
182 // an error of 0.0000001350, apparently due to roundoff.
183 intersect = ((alpha >= 0.0) && ((alpha + beta) <= 1.0));
184 }
185 } else {
186 beta = (v0 * u1 - u0 * v1) / (v2 * u1 - u2 * v1);
187 if ((beta >= 0.0) && (beta <= 1.0)) {
188 alpha = (u0 - beta * u2) / u1;
189 intersect = ((alpha >= 0.0) && ((alpha + beta) <= 1.0));
190 }
191 }
192
193 // if it is inside, adjust the Z value to sit upon the triangle plane.
194 if(intersect) {
195 float u3 = Corner2[AXIS_3] - Corner1[AXIS_3];
196 float v3 = Corner3[AXIS_3] - Corner1[AXIS_3];
197
198 Point[AXIS_3] = u3 * alpha + v3 * beta + Corner1[AXIS_3];
199 }
200
201 return intersect;
202}
203
204/*
205** Another way to access the Point_In_Polygon function
206**
207*/
209 Vector3 &Point,
210 Vector3 Corners[3]
211)
212{
213 return _Point_In_Polygon_Z(Point, Corners[0], Corners[1], Corners[2]);
214}
215
216/*
217** This is the general purpose Point_In_Polygon low level function. It can be called directly if you know
218** the dominant projection axes, such as in the case of 2d intersecion with heightfields.
219*/
221 Vector3 &Point,
222 Vector3 &loc1,
223 Vector3 &loc2,
224 Vector3 &loc3,
225 int axis_1,
226 int axis_2,
227 float &Alpha,
228 float &Beta)
229{
230
231 double u0 = Point[axis_1] - loc1[axis_1];
232 double v0 = Point[axis_2] - loc1[axis_2];
233
234 // determine the 2d vectors on the dominant plane from the first vertex to the other two
235 double u1 = loc2[axis_1] - loc1[axis_1];
236 double v1 = loc2[axis_2] - loc1[axis_2];
237 double u2 = loc3[axis_1] - loc1[axis_1];
238 double v2 = loc3[axis_2] - loc1[axis_2];
239
240 double alpha, beta;
241 bool intersect = false;
242
243 // calculate alpha and beta as normalized (0..1) percentages across the 2d projected triangle
244 // and do bounds checking (sum <= 1) to determine whether or not the triangle intersection occurs.
245
246#ifdef DEBUG_NORMALS
247 bool debugmode = false;
248 if(FinalResult->Alpha == 777) {
249 debugmode = true;
250 }
251#endif
252
253 if (u1 == 0.0f) {
254 Beta = beta = u0 / u2; // beta is the percentage down the edge loc1->loc3
255 if ((beta >= 0.0f) && (beta <= 1.0f)) { // make sure it's within the edge segment
256 Alpha = alpha = (v0 - beta * v2) / v1; // alpha is the percentage down the edge loc1->loc2
257
258 // if alpha is valid & the sum of alpha & beta is <= 1 then it's within the triangle
259 // note: 0.00001 added after testing an intersection of a square in the middle indicated
260 // an error of 0.0000001350, apparently due to roundoff.
261 intersect = ((alpha >= 0.0) && ((alpha + beta) <= 1.0));
262 }
263 } else {
264 Beta = beta = (v0 * u1 - u0 * v1) / (v2 * u1 - u2 * v1);
265 if ((beta >= 0.0) && (beta <= 1.0)) {
266 Alpha = alpha = (u0 - beta * u2) / u1;
267 intersect = ((alpha >= 0.0) && ((alpha + beta) <= 1.0));
268 }
269 }
270
271#ifdef DEBUG_NORMALS
272 if(debugmode) {
273 Debug.Print("Intersect", intersect);
274 Debug.Print("Normal ", Normal);
275 Debug.Print("Point 1", loc1);
276 Debug.Print("Point 2", loc2);
277 Debug.Print("Point 3", loc3);
278 Debug.Print("Inter ", FinalResult->Intersection);
279 Debug.Print("a/b", (float) alpha, (float) beta);
280 Debug.Print("sum", (float) alpha + (float) beta);
281 Debug.Print("diff", (float) (alpha - beta));
282 float d1 = Vector3::Dot_Product(Normal, loc1);
283 float d2 = Vector3::Dot_Product(Normal, loc2);
284 float d3 = Vector3::Dot_Product(Normal, loc3);
285
286 float e1 = d1 - d2;
287 float e2 = d2 - d3;
288 float e3 = d3 - d1;
289
290 Debug.Print("dots", Vector3(d1,d2,d3));
291 Debug.Print("err", Vector3(e1,e2,e3));
292 }
293#endif
294
295
296 return intersect;
297}
298
299/*
300** This version calls the base form using member data from the FinalResult struct for
301** some of it's arguments.
302*/
304 IntersectionResultClass *FinalResult,
305 Vector3 &loc1,
306 Vector3 &loc2,
307 Vector3 &loc3,
308 int axis_1,
309 int axis_2)
310{
311 return (FinalResult->Intersects = _Point_In_Polygon( FinalResult->Intersection, loc1, loc2, loc3,
312 axis_1, axis_2, FinalResult->Alpha, FinalResult->Beta));
313}
314
315/*
316** This version determines the dominant plane of the 3d triangle to be point-in-poly tested
317** and then calls the next form of _Point_In_Polygon
318*/
319inline bool IntersectionClass::_Point_In_Polygon(IntersectionResultClass *FinalResult, Vector3 &Normal, Vector3 &loc1, Vector3 &loc2, Vector3 &loc3) {
320
321 // first, find the dominant axis and use the plane perpendicular to it as defined by axis_1, axis_2
322 int axis_1, axis_2;
323 _Find_Polygon_Dominant_Plane(Normal, axis_1, axis_2);
324
325 return _Point_In_Polygon(FinalResult, loc1, loc2, loc3, axis_1, axis_2);
326}
327
328
329/*
330** Determine the Z distance to the specified polygon.
331*/
332inline float IntersectionClass::Plane_Z_Distance(Vector3 &PlaneNormal, Vector3 &PlanePoint)
333{
334 // do a parallel check
335 float divisor = (PlaneNormal[0] *(*RayDirection)[0] + PlaneNormal[1] *(*RayDirection)[1] + PlaneNormal[2] * (*RayDirection)[2]);
336 if(divisor == 0) return false; // parallel
337
338 // determine distance to plane
339 double d = - (PlanePoint[0] * PlaneNormal[0] + PlanePoint[1] * PlaneNormal[1] + PlanePoint[2] * PlaneNormal[2]);
340
341 float value = - (d + PlaneNormal[0] * (*RayLocation)[0] + PlaneNormal[1] * (*RayLocation)[1] + PlaneNormal[2] * (*RayLocation)[2]) / divisor;
342
343 return value;
344}
345
346/*
347** This function will find the z elevation for the passed Vector3 whose x/y components
348** are defined, using the specified vertex & surface normal to determine the correct value
349*/
351 Vector3 &Point,
352 Vector3 &PlanePoint,
353 Vector3 &PlaneNormal)
354{
355
356 // do a parallel check
357 if(PlaneNormal[2] == 0) return false;
358
359 // determine distance to plane
360 double d = - (PlanePoint[0] * PlaneNormal[0] + PlanePoint[1] * PlaneNormal[1] + PlanePoint[2] * PlaneNormal[2]);
361
362 float value = - (d + PlaneNormal[0] * Point[0] + PlaneNormal[1] * Point[1] ) / PlaneNormal[2];
363
364 return value;
365}
366
367/*
368** Optimized intersection test that only considers the x/y component of the intersection object
369** and will determine the intersection location down the Z axis.
370*/
372{
373
374 Result->Range = Plane_Z_Distance(PolygonNormal, v1);
375 (Result->Intersection)[0] = (*RayLocation)[0];
376 (Result->Intersection)[1] = (*RayLocation)[1];
377 (Result->Intersection)[2] = (*RayLocation)[2] - Result->Range;
378 return _Point_In_Polygon(Result, PolygonNormal, v1, v2, v3);
379}
380
381
382/*
383** Scale the normalized direction ray to the distance of intersection
384*/
386{
387 (Result->Intersection)[0] = (*RayLocation)[0] + (*RayDirection)[0] * Result->Range;
388 (Result->Intersection)[1] = (*RayLocation)[1] + (*RayDirection)[1] * Result->Range;
389 (Result->Intersection)[2] = (*RayLocation)[2] + (*RayDirection)[2] * Result->Range;
390}
391
392/*
393** Plane intersection test that assumes a normalized RayDirection. Only determines if
394** plane is parallel and if not, the range to it (which may be negative or beyond MaxRange).
395** It doesn't determine point of intersection either.
396*/
398{
399 // do a parallel check
400 float divisor = (PlaneNormal[0] *(*RayDirection)[0] + PlaneNormal[1] *(*RayDirection)[1] + PlaneNormal[2] * (*RayDirection)[2]);
401 if(divisor == 0) return false; // parallel
402
403 // determine distance to plane
404 float d = - (PlanePoint[0] * PlaneNormal[0] + PlanePoint[1] * PlaneNormal[1] + PlanePoint[2] * PlaneNormal[2]);
405 Result->Range = - (d + PlaneNormal[0] * (*RayLocation)[0] + PlaneNormal[1] * (*RayLocation)[1] + PlaneNormal[2] * (*RayLocation)[2]) / divisor;
406
407 return true;
408}
409
410/*
411** Determine if the specified ray will intersect the plane; returns false for planes
412** parallel and behind ray origin.
413** Sets Range to the distance from the ray location to the intersection.
414** Note: Range is undefined if an intersection didn't occur.
415*/
417
418 // normalize the ray direction
419 RayDirection->Normalize();
420
421 // call the quick test routine
422 if(!Intersect_Plane_Quick(Result, PlaneNormal, PlanePoint)) return false;
423
424 // check to make sure it's not behind the ray's origin
425 if(Result->Range <= 0) return false;
426
427 // check to make sure it's not beyond max distance
428 if(Result->Range > MaxDistance) return false;
429
430 // determine point of intersection
432
433 return true;
434}
435
436
437
438/*
439** Return the index of the largest normal component 0..2
440** used by Find_Triangle_Dominant_Plane()
441*/
443{
444 float x = fabsf(v[0]);
445 float y = fabsf(v[1]);
446 float z = fabsf(v[2]);
447 if(x > y) {
448 if(x > z) {
449 return 0; // x > y && x > z --> x is the max
450 }
451 return 2; // x > y && !(x > z) --> z is the max
452 }
453 if(y > z)
454 return 1; // x <= y && y > z --> y is the max
455 return 2; // y > x && y > z --> z is the max
456}
457
458/*
459** Use the Polygon's currently defined surface normal to determine it's dominant axis.
460** Axis_1 and Axis_2 are set to the indices of the two axis that define the dominant plane.
461*/
462inline void IntersectionClass::_Find_Polygon_Dominant_Plane(Vector3 &Normal, int &Axis_1, int &Axis_2)
463{
464 switch (_Largest_Normal_Index(Normal))
465 {
466 case 0:
467 // Dominant is the X axis
468 Axis_1 = 2;
469 Axis_2 = 1;
470 break;
471 case 1:
472 // Dominant is the Y axis
473 Axis_1 = 2;
474 Axis_2 = 0;
475 break;
476 case 2:
477 // Dominant is the Z axis
478 Axis_1 = 0;
479 Axis_2 = 1;
480 break;
481 }
482}
483
484/*
485** Returns true if ray intersects polygon.
486** Changes passed Intersection argument to location of intersection if it occurs,
487** and sets Range to the distance from the ray location to the intersection.
488** If Interpolated_Normal is specified it will interpolate the surface normal based
489** on the vertex normals.
490*/
492{
493 // first check to see if it hits the plane; determine plane normal and find point on plane (from a vertex)
494
495#ifdef DEBUG_NORMALS
496 Verify_Normal2(PolygonNormal, v1,v2,v3);
497#endif
498
499 if(Intersect_Plane(Result, PolygonNormal, v1)) {
500 // then check to see if it it actually intersects the polygon.
501 return _Point_In_Polygon(Result, PolygonNormal, v1, v2, v3);
502 }
503 // doesn't even hit the plane, return false.
504 return false;
505}
506
507/*
508** This version will calc the normal for the polygon before calling
509** a lower form of Intersect_Polygon
510*/
512{
513 Vector3 vec1 = v2 - v1;
514 Vector3 vec2 = v3 - v1;
515#ifdef ALLOW_TEMPORARIES
516 Vector3 normal = Vector3::Cross_Product(vec1, vec2);
517#else
518 Vector3 normal;
519 Vector3::Cross_Product(vec1, vec2, &normal);
520#endif
521
522 return Intersect_Polygon(Result, normal, v1,v2,v3);
523}
524
525
526// called after Interpolate_Intersection_Normal.
527// transform the intersection and the normal from model coords into world coords
529{
530#ifdef ALLOW_TEMPORARIES
531 FinalResult->Intersection = FinalResult->ModelMatrix * FinalResult->Intersection + FinalResult->ModelLocation;
532 if(IntersectionNormal != 0)
533 {
535 *IntersectionNormal = FinalResult->ModelMatrix * normal;
536 }
537#else
538 FinalResult->ModelMatrix.mulVector3(FinalResult->Intersection);
539 FinalResult->Intersection += FinalResult->ModelLocation;
540 if(IntersectionNormal != 0)
541 {
543 }
544#endif
545}
546
547
548
550 Vector4 &Area,
551 RenderObjClass *obj)
552{
553 if(Final_Result->Intersects = ((ScreenX >= Area[0]) && (ScreenX <= Area[2]) && (ScreenY >= Area[1]) && (ScreenY <= Area[3]))) {
555 Final_Result->IntersectedRenderObject = obj;
556 Final_Result->Range = 0;
557 return true;
558 }
559 return false;
560}
561
562
563/*
564** Determines the point of intersection, if any between the line segments AB and CD.
565** If an intersection occurs, then the UV values are interpolated along AB.
566** Disregards the Z value and considers only the X/Y data except for determining
567** the Z value of the intersection.
568** This function could be easily modified to support other axes.
569* /
570void IntersectionClass::_Intersect_Lines_Z(
571 Vector3 &A,
572 Vector3 &B,
573 Vector2 &UVStart,
574 Vector2 &UVEnd,
575 Vector3 &C,
576 Vector3 &D,
577 Vector3 ClippedPoints[6],
578 Vector2 ClippedUV[6],
579 int &DestIndex)
580{
581 /*
582 Let A,B,C,D be 2-space position vectors. Then the directed line segments AB & CD are given by:
583
584 AB=A+r(B-A), r in [0,1]
585 CD=C+s(D-C), s in [0,1]
586 If AB & CD intersect, then
587
588 A+r(B-A)=C+s(D-C), or
589
590 Ax+r(Bx-Ax)=Cx+s(Dx-Cx)
591 Ay+r(By-Ay)=Cy+s(Dy-Cy) for some r,s in [0,1]
592 Solving the above for r and s yields
593
594 (Ay-Cy)(Dx-Cx)-(Ax-Cx)(Dy-Cy)
595 r = ----------------------------- (eqn 1)
596 (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx)
597 (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
598 s = ----------------------------- (eqn 2)
599 (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx)
600 Let P be the position vector of the intersection point, then
601
602 P=A+r(B-A) or
603
604 Px=Ax+r(Bx-Ax)
605 Py=Ay+r(By-Ay)
606 By examining the values of r & s, you can also determine some other limiting conditions:
607
608 If 0<=r<=1 & 0<=s<=1, intersection exists
609 r<0 or r>1 or s<0 or s>1 line segments do not intersect
610 If the denominator in eqn 1 is zero, AB & CD are parallel
611
612 If the numerator in eqn 1 is also zero, AB & CD are coincident
613
614 If the intersection point of the 2 lines are needed (lines in this context mean infinite lines) regardless whether the two line segments intersect, then
615
616 If r>1, P is located on extension of AB
617 If r<0, P is located on extension of BA
618 If s>1, P is located on extension of CD
619 If s<0, P is located on extension of DC
620 * /
621
622 // the numerator is required for all execution routes
623 float numerator = (A[AXIS_2] - C[AXIS_2]) * (D[AXIS_1] - C[AXIS_1]) - (A[AXIS_1] - C[AXIS_1]) * (D[AXIS_2] - C[AXIS_2]);
624
625 // if the denominator is zero, then the segments are parallel.
626 float denominator = (B[AXIS_1] - A[AXIS_1]) * (D[AXIS_2] - C[AXIS_2]) - (B[AXIS_2] - A[AXIS_2]) * (D[AXIS_1] - C[AXIS_1]);
627
628 // r & s are percentages through the line segment.
629 float r, s;
630
631 // check to see if they are parallel
632 if(denominator == 0) {
633
634 // check to see if they are coincident
635 // a numerator of zero with a denominator of zero indicates coincident lines.
636 if (numerator != 0) {
637
638 // parallel, not coincident lines (and segments) do not intersect.
639 return;
640 }
641
642 // perform special case for parallel segments
643
644 // determine relative position 0..1 of C and D on one of the 1d vectors of A-B
645 float len = B[AXIS_1] - A[AXIS_1];
646 float cpos,dpos;
647
648 // if the length of the edge on the first axis is zero, use the other axis instead.
649 if(len) {
650 len = 1.0 / len;
651 cpos = (C[AXIS_1] - A[AXIS_1]) * len;
652 dpos = (D[AXIS_1] - A[AXIS_1]) * len;
653 } else {
654 len = B[AXIS_2] - A[AXIS_2];
655
656 // degenerate triangle test
657 if(len == 0)
658 return;
659
660 len = 1.0 / len;
661 cpos = (C[AXIS_2] - A[AXIS_2]) * len;
662 dpos = (D[AXIS_2] - A[AXIS_2]) * len;
663 }
664
665 // check to see if there's any overlap
666 // one of the two pos values must be 0>pos>1 or there is no intersection.
667 // this test will ensure that cpos & dpos will not both be outside the same end of the segment.
668 if(((cpos < 0) && (dpos < 0)) || ((cpos > 1) && (dpos > 1)))
669 return;
670
671 if(cpos < 0) {
672 // C is outside, therefore D is inside or on other side.
673 // use the original vertex.
674 ClippedPoints[DestIndex] = A;
675 ClippedUV[DestIndex++] = UVStart;
676 } else if (cpos > 1) {
677 // C is outside far side, therefore D is inside or on other side.
678 // use the far vertex.
679 ClippedPoints[DestIndex] = B;
680 ClippedUV[DestIndex++] = UVEnd;
681 } else {
682 // C is inside.
683 // Use C as the vertex, and interpolate the UV coords.
684 ClippedPoints[DestIndex] = C;
685 ClippedUV[DestIndex++] = (UVEnd - UVStart) * cpos + UVStart;
686 }
687
688 if(dpos < 0) {
689 // D is outside near vertex, therefore C is inside or outside far vertex
690 // use near vertex
691 ClippedPoints[DestIndex] = A;
692 ClippedUV[DestIndex++] = UVStart;
693 } else if (dpos > 1) {
694 // D is outside far vertex, therefore C is inside or outside the near vertex.
695 // use the far vertex.
696 ClippedPoints[DestIndex] = B;
697 ClippedUV[DestIndex++] = UVEnd;
698 } else {
699 // D is inside.
700 // Use D as the vertex, and interpolate the UV coords.
701 ClippedPoints[DestIndex] = D;
702 ClippedUV[DestIndex++] = (UVEnd - UVStart) * dpos + UVStart;
703 }
704 return;
705
706 }
707
708 // determine the percentage into the line segments that the intersection occurs.
709 // an intersection of segments will produce r & s values between 0 & 1.
710 denominator = 1.0 / denominator;
711 r = numerator * denominator;
712
713 numerator = (A[AXIS_2] - C[AXIS_2]) * (B[AXIS_1] - A[AXIS_1]) - (A[AXIS_1] - C[AXIS_1]) * (B[AXIS_2] - A[AXIS_2]);
714 s = numerator * denominator;
715
716 // determine if the line intersect within the defined segments.
717 if((0.0 <= r) && (r <= 1.0) && (0.0 <= s) && (s <= 1.0)) {
718
719 // they intersect.
720 // determine intersection point
721 Vector3 v = D - C;
722// float len = v.Length();
723 ClippedPoints[DestIndex] = C + v * s;
724
725 // interpolate UV values
726 Vector2 uv = UVEnd - UVStart;
727// len = uv.Length();
728 ClippedUV[DestIndex++] = UVStart + uv * r;
729 }
730}
731
732/*
733 A failed attempt to use a graphics gem vol 2 example
734
735
736 // Compute a1, b1, c1, where line joining points 1 and 2
737 // is "a1 x + b1 y + c1 = 0".
738 float a1 = B[AXIS_2] - A[AXIS_2];
739 float b1 = B[AXIS_1] - A[AXIS_1];
740 float c1 = B[AXIS_2] * A[AXIS_1] - A[AXIS_1] * B[AXIS_2];
741
742 // Compute r3 & r4, the sign values
743 float r3 = a1 * C[AXIS_1] + b1 * C[AXIS_2] + c1;
744 float r4 = a1 * D[AXIS_1] + b1 * D[AXIS_2] + c1;
745
746 // Check signs of r3 and r4. If both point 3 and point 4 lie on
747 // same side of line 1, the line segments do not intersect.
748 if ( r3 != 0 && r4 != 0 && (((r3 < 0) && (r4 < 0)) || ((r3 > 0) && (r4 > 0)))
749 return; // ( DONT_INTERSECT );
750
751 // Compute a2, b2, c2
752 float a2 = D[AXIS_2] - C[AXIS_2];
753 float b2 = C[AXIS_1] - D[AXIS_1];
754 float c2 = D[AXIS_1] * C[AXIS_2] - C[AXIS_1] * D[AXIS_2];
755
756 // Compute r1 and r2
757 float r1 = a2 * A[AXIS_1] + b2 * A[AXIS_2] + c2;
758 float r2 = a2 * B[AXIS_1] + b2 * B[AXIS_2] + c2;
759
760 // Check signs of r1 and r2. If both point 1 and point 2 lie
761 // on same side of second line segment, the line segments do
762 // not intersect.
763 if ( r1 != 0 && r2 != 0 && (((r1 < 0) && (r2 < 0)) || ((r1 > 0) && (r2 > 0))))
764 return; // ( DONT_INTERSECT );
765
766 // Line segments intersect: compute intersection point.
767 float denom = a1 * b2 - a2 * b1;
768 if ( denom == 0 )
769 return; // ( COLLINEAR );
770
771 float offset = denom < 0 ? - denom * 0.5f : denom * 0.5f;
772
773 // The denom/2 is to get rounding instead of truncating. It
774 // is added or subtracted to the numerator, depending upon the
775 // sign of the numerator.
776
777 float num = b1 * c2 - b2 * c1;
778 float x = ( num < 0 ? num - offset : num + offset ) / denom;
779
780 num = a2 * c1 - a1 * c2;
781 float y = ( num < 0 ? num - offset : num + offset ) / denom;
782
783 ClippedPoints[DestIndex] = Vector3(x,y,0);
784 ClippedUV[DestIndex++] = Vector3
785 return; //( DO_INTERSECT ); // lines_intersect
786*/
787
789(
790 const Vector3 & p, // point to test
791 const Vector3 & e0, // point on edge
792 const Vector3 & de // direction of edge
793)
794{
795 Vector3 dp = p - e0;
796 float val = de.X*dp.Y - de.Y*dp.X;
797 if (val > 0.0f) {
798 return true;
799 }
800 return false;
801}
802
804(
805 const Vector3 & p0, // start of line segment
806 const Vector3 & p1, // end of line segment
807 const Vector3 & e0, // point on clipping edge
808 const Vector3 & de // direction of clipping edge
809)
810{
811 float dpx = p1.X - p0.X;
812 float dpy = p1.Y - p0.Y;
813
814 float den = de.Y * dpx - de.X * dpy;
815
816 if (fabs(den) > WWMATH_EPSILON) {
817
818 float num = p0.Y*de.X - p0.X*de.Y + e0.X*de.Y - e0.Y*de.X;
819 float t = num/den;
820 if ((t >= 0.0f) && (t <= 1.0f)) {
821 return t;
822 }
823 }
824
825 return 0.0f;
826}
827
828
829#define EMIT(p,uv) OutPoints[outnum] = p; OutUVs[outnum] = uv; outnum++;
830
831
833 int incount,
834 Vector3 * InPoints,
835 Vector2 * InUVs,
836 Vector3 * OutPoints,
837 Vector2 * OutUVs,
838 const Vector3 & edge_point0,
839 const Vector3 & edge_point1
840)
841{
842 Vector3 e0 = edge_point0;
843 Vector3 de = edge_point1 - edge_point0;
844
845 // number of verts output.
846 int outnum = 0;
847
848 // start and end verts of the current edge
849 int p0,p1;
850 p0 = incount-1;
851
852 // intersection temporaries.
853 float intersection;
854 Vector3 intersection_point;
855 Vector2 intersection_uv;
856
857 // loop over each edge in the input polygon
858 for (p1=0; p1<incount; p1++) {
859
860 if (In_Front_Of_Line(InPoints[p1],e0,de)) {
861 if (In_Front_Of_Line(InPoints[p0],e0,de)) {
862
863 // both inside, emit p1
864 EMIT(InPoints[p1],InUVs[p1]);
865
866 } else {
867
868 // edge going out->in, emit intersection and endpoint
869 intersection = Intersect_Lines(InPoints[p0], InPoints[p1], e0, de);
870 intersection_point = (1.0f - intersection) * InPoints[p0] + intersection * InPoints[p1];
871 intersection_uv = (1.0f - intersection) * InUVs[p0] + intersection * InUVs[p1];
872 EMIT(intersection_point,intersection_uv);
873 EMIT(InPoints[p1],InUVs[p1]);
874 }
875 } else {
876
877 if (In_Front_Of_Line(InPoints[p0], e0, de)) {
878
879 // edge going in->out, emit intersection
880 intersection = Intersect_Lines(InPoints[p0],InPoints[p1], e0, de);
881 intersection_point = (1.0f - intersection) * InPoints[p0] + intersection * InPoints[p1];
882 intersection_uv = (1.0f - intersection) * InUVs[p0] + intersection * InUVs[p1];
883 EMIT(intersection_point,intersection_uv);
884
885 }
886
887 }
888
889 // move to next edge
890 p0 = p1;
891 }
892
893 return outnum;
894}
895
897 Vector3 ClipPoints[3],
898 Vector3 TrianglePoints[3],
899 Vector2 UV[3],
900 Vector3 ClippedPoints[6],
901 Vector2 ClippedUV[6]
902)
903{
904 int count;
905 Vector3 tmp_points[6];
906 Vector2 tmp_uv[6];
907
908 count = Clip_Triangle_To_LineXY(3,TrianglePoints,UV,ClippedPoints,ClippedUV,ClipPoints[0],ClipPoints[1]);
909 count = Clip_Triangle_To_LineXY(count,ClippedPoints,ClippedUV,tmp_points,tmp_uv,ClipPoints[1],ClipPoints[2]);
910 count = Clip_Triangle_To_LineXY(count,tmp_points,tmp_uv,ClippedPoints,ClippedUV,ClipPoints[2],ClipPoints[0]);
911
912 return count;
913}
914
915/*
916** This function will fill the passed array with the set of points & uv values that represent
917** the boolean operation of the anding of the ClipPoints with the TrianglePoints. The UV values
918** provided for the TrianglePoints triangle are used to generate accurate UV values for any
919** new points created by this operation.
920** This function returns the number of vertices it required to define the intersection.
921* /
922int IntersectionClass::_Intersect_Triangles_Z(
923 Vector3 ClipPoints[3],
924 Vector3 TrianglePoints[3],
925 Vector2 UV[3],
926 Vector3 ClippedPoints[6],
927 Vector2 ClippedUV[6]
928)
929{
930 // first, check to see if all triangle points are inside clip area
931 // the point in polygon will drop any inside points to the clip triangle plane.
932 bool inside[3];
933
934 bool noclip;
935 noclip = inside[0] = _Point_In_Polygon_Z(TrianglePoints[0], ClipPoints);
936 noclip &= inside[1] = _Point_In_Polygon_Z(TrianglePoints[1], ClipPoints);
937 noclip &= inside[2] = _Point_In_Polygon_Z(TrianglePoints[2], ClipPoints);
938
939 // if all points are inside clip area, then copy the triangle points &
940 // UV's to the destination & return 3 (the number of points in the clipped polygon).
941 if(noclip) {
942 ClippedPoints[0] = TrianglePoints[0];
943 ClippedPoints[1] = TrianglePoints[1];
944 ClippedPoints[2] = TrianglePoints[2];
945 ClippedUV[0] = UV[0];
946 ClippedUV[1] = UV[1];
947 ClippedUV[2] = UV[2];
948
949 return 3;
950 }
951
952 int points = 0; // number of output polygon points
953
954 // not all uv triangle points are inside the clip triangle.
955 // Test to see if any clip points are inside the uv triangle
956 float alpha, beta;
957 if(_Point_In_Polygon(ClipPoints[0], TrianglePoints[0], TrianglePoints[1], TrianglePoints[2], 0, 1, alpha, beta)) {
958 ClippedPoints[points] = ClipPoints[0];
959 Vector2 uv1 = UV[1] - UV[0];
960 Vector2 uv2 = UV[2] - UV[0];
961 ClippedUV[points++] = UV[0] + alpha * uv1 + beta * uv2;
962 }
963
964 if(_Point_In_Polygon(ClipPoints[1], TrianglePoints[0], TrianglePoints[1], TrianglePoints[2], 0, 1, alpha, beta)) {
965 ClippedPoints[points] = ClipPoints[1];
966 Vector2 uv1 = UV[1] - UV[0];
967 Vector2 uv2 = UV[2] - UV[0];
968 ClippedUV[points++] = UV[0] + alpha * uv1 + beta * uv2;
969 }
970
971 if(_Point_In_Polygon(ClipPoints[2], TrianglePoints[0], TrianglePoints[1], TrianglePoints[2], 0, 1, alpha, beta)) {
972 ClippedPoints[points] = ClipPoints[2];
973 Vector2 uv1 = UV[1] - UV[0];
974 Vector2 uv2 = UV[2] - UV[0];
975 ClippedUV[points++] = UV[0] + alpha * uv1 + beta * uv2;
976 }
977
978 // if all 3 clip points are inside the decal triangle then return
979 if(points == 3)
980 return;
981
982 // The clip triangle does not fully contain the uv triangle, and the uv triangle
983 // does not fully contain the clip triangle.
984 // Intersect any edge which has at least one outside point with all of the clip edges.
985 // First, determine which edges to test. Those points that are already clipped (by being inside)
986 // are immediately copied to the clipped point & uv arrays.
987
988 // these bools indicate which edges of the triangle to be clipped are to be tested.
989 bool test_01 = false;
990 bool test_02 = false;
991 bool test_12 = false;
992
993 if( inside[0] ) { ClippedPoints[points] = TrianglePoints[0]; ClippedUV[points++] = UV[0]; }
994 else { test_01 = test_02 = true; }
995
996 if( inside[1] ) { ClippedPoints[points] = TrianglePoints[1]; ClippedUV[points++] = UV[1]; }
997 else { test_01 = test_12 = true; }
998
999 if( inside[2] ) { ClippedPoints[points] = TrianglePoints[2]; ClippedUV[points++] = UV[2];}
1000 else { test_02 = test_12 = true; }
1001
1002 // Now test each indicated segment.
1003 // Intersect_2D_Lines will interpolate the clipped UV values if an intersection occurs, and it
1004 // will also increment the points variable (passed as a reference).
1005 // Any intersections are stored in the passed ClippedPoints array.
1006 if(test_01) {
1007 _Intersect_Lines_Z( TrianglePoints[0], TrianglePoints[1],
1008 UV[0], UV[1],
1009 ClipPoints[0], ClipPoints[1],
1010 ClippedPoints,
1011 ClippedUV,
1012 points);
1013 _Intersect_Lines_Z( TrianglePoints[0], TrianglePoints[1],
1014 UV[0], UV[1],
1015 ClipPoints[0], ClipPoints[2],
1016 ClippedPoints,
1017 ClippedUV,
1018 points);
1019 _Intersect_Lines_Z( TrianglePoints[0], TrianglePoints[1],
1020 UV[0], UV[1],
1021 ClipPoints[1], ClipPoints[2],
1022 ClippedPoints,
1023 ClippedUV,
1024 points);
1025 }
1026 if(test_02) {
1027 _Intersect_Lines_Z( TrianglePoints[0], TrianglePoints[2],
1028 UV[0], UV[2],
1029 ClipPoints[0], ClipPoints[1],
1030 ClippedPoints,
1031 ClippedUV,
1032 points);
1033 _Intersect_Lines_Z( TrianglePoints[0], TrianglePoints[2],
1034 UV[0], UV[2],
1035 ClipPoints[0], ClipPoints[2],
1036 ClippedPoints,
1037 ClippedUV,
1038 points);
1039 _Intersect_Lines_Z( TrianglePoints[0], TrianglePoints[2],
1040 UV[0], UV[2],
1041 ClipPoints[1], ClipPoints[2],
1042 ClippedPoints,
1043 ClippedUV,
1044 points);
1045 }
1046 if(test_12) {
1047 _Intersect_Lines_Z( TrianglePoints[1], TrianglePoints[2],
1048 UV[1], UV[2],
1049 ClipPoints[0], ClipPoints[1],
1050 ClippedPoints,
1051 ClippedUV,
1052 points);
1053 _Intersect_Lines_Z( TrianglePoints[1], TrianglePoints[2],
1054 UV[1], UV[2],
1055 ClipPoints[0], ClipPoints[2],
1056 ClippedPoints,
1057 ClippedUV,
1058 points);
1059 _Intersect_Lines_Z( TrianglePoints[1], TrianglePoints[2],
1060 UV[1], UV[2],
1061 ClipPoints[1], ClipPoints[2],
1062 ClippedPoints,
1063 ClippedUV,
1064 points);
1065 }
1066
1067 // If no intersections have occurred, then the triangle must be completely outside
1068 // the clipping area.
1069/*
1070 // if it is determined that no intersections have occurred, then copy the clip triangle points
1071 // into the destination array and determine the correct UV values for the subset of the
1072 // triangle that was clipped.
1073 if(points == 0) {
1074 ClippedPoints[0] = ClipPoints[0];
1075 ClippedPoints[1] = ClipPoints[1];
1076 ClippedPoints[2] = ClipPoints[2];
1077 ClippedUV[0] = UV[0];
1078 ClippedUV[1] = UV[1];
1079 ClippedUV[2] = UV[2];
1080
1081 return 3;
1082 }
1083* /
1084 // points will be 0, 3, 4, 5 or 6
1085 if(!((points == 0) || (points == 3) || (points == 4) || (points == 5) || (points == 6))) {
1086 Debug.Print("points", points);
1087 return 0; //_Intersect_Triangles_Z( ClipPoints, TrianglePoints, UV, ClippedPoints, ClippedUV);
1088 }
1089
1090 return points;
1091
1092}
1093*/
1094
1095
1096#endif
#define min(x, y)
Definition BaseType.h:101
#define max(x, y)
Definition BaseType.h:105
void const char * value
#define WWMATH_EPSILON
Definition wwmath.h:54
void Get_View_Plane(Vector2 &set_min, Vector2 &set_max) const
Definition camera.cpp:380
void Get_Viewport(Vector2 &set_min, Vector2 &set_max) const
Definition camera.h:281
float Get_Depth(void) const
Definition camera.h:259
Debug module main class (singleton).
Definition debug_debug.h:45
bool Intersect_Plane(IntersectionResultClass *Result, Vector3 &Plane_Normal, Vector3 &Plane_Point)
Definition intersec.inl:416
IntersectionResultClass Result
Definition intersec.h:133
void Transform_Model_To_World_Coords(IntersectionResultClass *FinalResult)
Definition intersec.inl:528
void Get_Screen_Ray(float ScreenX, float ScreenY, const LayerClass &Layer)
debug code that will be tossed
Definition intersec.inl:81
static float Intersect_Lines(const Vector3 &p0, const Vector3 &p1, const Vector3 &e0, const Vector3 &de)
Definition intersec.inl:804
Vector3 * IntersectionNormal
Definition intersec.h:110
static bool In_Front_Of_Line(const Vector3 &p, const Vector3 &e0, const Vector3 &de)
Definition intersec.inl:789
Vector3 * RayLocation
Definition intersec.h:108
float Plane_Z_Distance(Vector3 &PlaneNormal, Vector3 &PlanePoint)
Definition intersec.inl:332
static int Clip_Triangle_To_LineXY(int incount, Vector3 *InPoints, Vector2 *InUVs, Vector3 *OutPoints, Vector2 *OutUVs, const Vector3 &edge_point0, const Vector3 &edge_point1)
Definition intersec.inl:832
static void _Find_Polygon_Dominant_Plane(Vector3 &Normal, int &Axis_1, int &Axis_2)
Definition intersec.inl:462
bool Intersect_Plane_Quick(IntersectionResultClass *Result, Vector3 &Plane_Normal, Vector3 &Plane_Point)
Definition intersec.inl:397
static int _Intersect_Triangles_Z(Vector3 ClipPoints[3], Vector3 TrianglePoints[3], Vector2 UV[3], Vector3 ClippedPoints[6], Vector2 ClippedUV[6])
Definition intersec.inl:896
bool Intersect_Screen_Object(IntersectionResultClass *Final_Result, Vector4 &Area, RenderObjClass *obj=0)
Definition intersec.inl:549
static float _Get_Z_Elevation(Vector3 &Point, Vector3 &PlanePoint, Vector3 &PlaneNormal)
Definition intersec.inl:350
Vector3 * RayDirection
Definition intersec.h:109
void Calculate_Intersection(IntersectionResultClass *Result)
Definition intersec.inl:385
static bool _Point_In_Polygon_Z(Vector3 &Point, Vector3 Corners[3])
Definition intersec.inl:208
bool Intersect_Polygon_Z(IntersectionResultClass *Result, Vector3 &PolygonNormal, Vector3 &v1, Vector3 &v2, Vector3 &v3)
Definition intersec.inl:371
static bool _Point_In_Polygon(IntersectionResultClass *FinalResult, Vector3 &Normal, Vector3 &loc1, Vector3 &loc2, Vector3 &loc3)
Definition intersec.inl:319
bool Intersect_Polygon(IntersectionResultClass *Result, Vector3 &PolygonNormal, Vector3 &v1, Vector3 &v2, Vector3 &v3)
Definition intersec.inl:491
static int _Largest_Normal_Index(Vector3 &v)
Definition intersec.inl:442
RenderObjClass * IntersectedRenderObject
Definition intersec.h:74
enum IntersectionResultClass::INTERSECTION_TYPE IntersectionType
void mulVector3(const Vector3 &in, Vector3 &out) const
Definition matrix3d.h:1650
Vector3 Get_Position(void) const
Definition rendobj.cpp:508
const Matrix3D & Get_Transform(void) const
Definition rendobj.h:617
float Y
Definition vector2.h:79
float X
Definition vector2.h:74
static WWINLINE float Dot_Product(const Vector3 &a, const Vector3 &b)
Definition vector3.h:293
float X
Definition vector3.h:90
float Y
Definition vector3.h:91
void Normalize(void)
Definition vector3.h:417
static WWINLINE void Cross_Product(const Vector3 &a, const Vector3 &b, Vector3 *result)
Definition vector3.h:374
Vector2 Min
Definition camera.h:80
#define EMIT(p, uv)
Definition intersec.inl:829
#define AXIS_2
#define AXIS_3
#define AXIS_1
unsigned char d1
Definition vchannel.cpp:275
unsigned char d3
Definition vchannel.cpp:277
unsigned char d2
Definition vchannel.cpp:276