]> git.mxchange.org Git - flightgear.git/blob - src/Objects/fragment.cxx
Lighting/ssgSimpleState fixes.
[flightgear.git] / src / Objects / fragment.cxx
1 // fragment.cxx -- routines to handle "atomic" display objects
2 //
3 // Written by Curtis Olson, started August 1998.
4 //
5 // Copyright (C) 1998  Curtis L. Olson  - curt@me.umn.edu
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 // $Id$
22
23
24 #include <Include/fg_constants.h>
25 #include <Math/mat3.h>
26 #include <Math/point3d.hxx>
27 #include <Scenery/tileentry.hxx>
28
29 #include "fragment.hxx"
30
31
32 template <class T>
33 inline const int FG_SIGN(const T& x) {
34     return x < T(0) ? -1 : 1;
35 }
36
37 template <class T>
38 inline const T& FG_MIN(const T& a, const T& b) {
39     return b < a ? b : a;
40 }
41
42 template <class T>
43 inline const T& FG_MAX(const T& a, const T& b) {
44     return  a < b ? b : a;
45 }
46
47 // return the minimum of the three values
48 template <class T>
49 inline const T& fg_min3( const T& a, const T& b, const T& c)
50 {
51     return (a > b ? FG_MIN (b, c) : FG_MIN (a, c));
52 }
53
54
55 // return the maximum of the three values
56 template <class T>
57 inline const T& fg_max3 (const T& a, const T& b, const T& c)
58 {
59     return (a < b ? FG_MAX (b, c) : FG_MAX (a, c));
60 }
61
62 // Add a face to the face list
63 // Copy constructor
64 fgFRAGMENT::fgFRAGMENT ( const fgFRAGMENT & rhs ) :
65     center         ( rhs.center          ),
66     bounding_radius( rhs.bounding_radius ),
67     material_ptr   ( rhs.material_ptr    ),
68     tile_ptr       ( rhs.tile_ptr        ),
69     /* display_list   ( rhs.display_list    ), */
70     faces          ( rhs.faces           )
71 {
72 }
73
74 fgFRAGMENT & fgFRAGMENT::operator = ( const fgFRAGMENT & rhs )
75 {
76     if(!(this == &rhs )) {
77         center          = rhs.center;
78         bounding_radius = rhs.bounding_radius;
79         material_ptr    = rhs.material_ptr;
80         tile_ptr        = rhs.tile_ptr;
81         // display_list    = rhs.display_list;
82         faces           = rhs.faces;
83     }
84     return *this;
85 }
86
87
88 // test if line intesects with this fragment.  p0 and p1 are the two
89 // line end points of the line.  If side_flag is true, check to see
90 // that end points are on opposite sides of face.  Returns 1 if it
91 // intersection found, 0 otherwise.  If it intesects, result is the
92 // point of intersection
93
94 int fgFRAGMENT::intersect( const Point3D& end0,
95                            const Point3D& end1,
96                            int side_flag,
97                            Point3D& result) const
98 {
99     FGTileEntry *t;
100     MAT3vec v1, v2, n, center;
101     double p1[3], p2[3], p3[3];
102     double x, y, z;  // temporary holding spot for result
103     double a, b, c, d;
104     double x0, y0, z0, x1, y1, z1, a1, b1, c1;
105     double t1, t2, t3;
106     double xmin, xmax, ymin, ymax, zmin, zmax;
107     double dx, dy, dz, min_dim, x2, y2, x3, y3, rx, ry;
108     int side1, side2;
109
110     // find the associated tile
111     t = tile_ptr;
112
113     // printf("Intersecting\n");
114
115     // traverse the face list for this fragment
116     const_iterator last = faces.end();
117     for ( const_iterator current = faces.begin(); current != last; ++current )
118     {
119         // printf(".");
120
121         // get face vertex coordinates
122         center[0] = t->center.x();
123         center[1] = t->center.y();
124         center[2] = t->center.z();
125
126         MAT3_ADD_VEC(p1, t->nodes[(*current).n1], center);
127         MAT3_ADD_VEC(p2, t->nodes[(*current).n2], center);
128         MAT3_ADD_VEC(p3, t->nodes[(*current).n3], center);
129
130         // printf("point 1 = %.2f %.2f %.2f\n", p1[0], p1[1], p1[2]);
131         // printf("point 2 = %.2f %.2f %.2f\n", p2[0], p2[1], p2[2]);
132         // printf("point 3 = %.2f %.2f %.2f\n", p3[0], p3[1], p3[2]);
133
134         // calculate two edge vectors, and the face normal
135         MAT3_SUB_VEC(v1, p2, p1);
136         MAT3_SUB_VEC(v2, p3, p1);
137         MAT3cross_product(n, v1, v2);
138
139         // calculate the plane coefficients for the plane defined by
140         // this face.  If n is the normal vector, n = (a, b, c) and p1
141         // is a point on the plane, p1 = (x0, y0, z0), then the
142         // equation of the line is a(x-x0) + b(y-y0) + c(z-z0) = 0
143         a = n[0];
144         b = n[1];
145         c = n[2];
146         d = a * p1[0] + b * p1[1] + c * p1[2];
147         // printf("a, b, c, d = %.2f %.2f %.2f %.2f\n", a, b, c, d);
148
149         // printf("p1(d) = %.2f\n", a * p1[0] + b * p1[1] + c * p1[2]);
150         // printf("p2(d) = %.2f\n", a * p2[0] + b * p2[1] + c * p2[2]);
151         // printf("p3(d) = %.2f\n", a * p3[0] + b * p3[1] + c * p3[2]);
152
153         // calculate the line coefficients for the specified line
154         x0 = end0.x();  x1 = end1.x();
155         y0 = end0.y();  y1 = end1.y();
156         z0 = end0.z();  z1 = end1.z();
157
158         if ( fabs(x1 - x0) > FG_EPSILON ) {
159             a1 = 1.0 / (x1 - x0);
160         } else {
161             // we got a big divide by zero problem here
162             a1 = 0.0;
163         }
164         b1 = y1 - y0;
165         c1 = z1 - z0;
166
167         // intersect the specified line with this plane
168         t1 = b * b1 * a1;
169         t2 = c * c1 * a1;
170
171         // printf("a = %.2f  t1 = %.2f  t2 = %.2f\n", a, t1, t2);
172
173         if ( fabs(a + t1 + t2) > FG_EPSILON ) {
174             x = (t1*x0 - b*y0 + t2*x0 - c*z0 + d) / (a + t1 + t2);
175             t3 = a1 * (x - x0);
176             y = b1 * t3 + y0;
177             z = c1 * t3 + z0;       
178             // printf("result(d) = %.2f\n", a * x + b * y + c * z);
179         } else {
180             // no intersection point
181             continue;
182         }
183
184         if ( side_flag ) {
185             // check to see if end0 and end1 are on opposite sides of
186             // plane
187             if ( (x - x0) > FG_EPSILON ) {
188                 t1 = x;
189                 t2 = x0;
190                 t3 = x1;
191             } else if ( (y - y0) > FG_EPSILON ) {
192                 t1 = y;
193                 t2 = y0;
194                 t3 = y1;
195             } else if ( (z - z0) > FG_EPSILON ) {
196                 t1 = z;
197                 t2 = z0;
198                 t3 = z1;
199             } else {
200                 // everything is too close together to tell the difference
201                 // so the current intersection point should work as good
202                 // as any
203                 result = Point3D(x, y, z);
204                 return(1);
205             }
206             side1 = FG_SIGN (t1 - t2);
207             side2 = FG_SIGN (t1 - t3);
208             if ( side1 == side2 ) {
209                 // same side, punt
210                 continue;
211             }
212         }
213
214         // check to see if intersection point is in the bounding
215         // cube of the face
216 #ifdef XTRA_DEBUG_STUFF
217         xmin = fg_min3 (p1[0], p2[0], p3[0]);
218         xmax = fg_max3 (p1[0], p2[0], p3[0]);
219         ymin = fg_min3 (p1[1], p2[1], p3[1]);
220         ymax = fg_max3 (p1[1], p2[1], p3[1]);
221         zmin = fg_min3 (p1[2], p2[2], p3[2]);
222         zmax = fg_max3 (p1[2], p2[2], p3[2]);
223         printf("bounding cube = %.2f,%.2f,%.2f  %.2f,%.2f,%.2f\n",
224                xmin, ymin, zmin, xmax, ymax, zmax);
225 #endif
226         // punt if outside bouding cube
227         if ( x < (xmin = fg_min3 (p1[0], p2[0], p3[0])) ) {
228             continue;
229         } else if ( x > (xmax = fg_max3 (p1[0], p2[0], p3[0])) ) {
230             continue;
231         } else if ( y < (ymin = fg_min3 (p1[1], p2[1], p3[1])) ) {
232             continue;
233         } else if ( y > (ymax = fg_max3 (p1[1], p2[1], p3[1])) ) {
234             continue;
235         } else if ( z < (zmin = fg_min3 (p1[2], p2[2], p3[2])) ) {
236             continue;
237         } else if ( z > (zmax = fg_max3 (p1[2], p2[2], p3[2])) ) {
238             continue;
239         }
240
241         // (finally) check to see if the intersection point is
242         // actually inside this face
243
244         //first, drop the smallest dimension so we only have to work
245         //in 2d.
246         dx = xmax - xmin;
247         dy = ymax - ymin;
248         dz = zmax - zmin;
249         min_dim = fg_min3 (dx, dy, dz);
250         if ( fabs(min_dim - dx) <= FG_EPSILON ) {
251             // x is the smallest dimension
252             x1 = p1[1];
253             y1 = p1[2];
254             x2 = p2[1];
255             y2 = p2[2];
256             x3 = p3[1];
257             y3 = p3[2];
258             rx = y;
259             ry = z;
260         } else if ( fabs(min_dim - dy) <= FG_EPSILON ) {
261             // y is the smallest dimension
262             x1 = p1[0];
263             y1 = p1[2];
264             x2 = p2[0];
265             y2 = p2[2];
266             x3 = p3[0];
267             y3 = p3[2];
268             rx = x;
269             ry = z;
270         } else if ( fabs(min_dim - dz) <= FG_EPSILON ) {
271             // z is the smallest dimension
272             x1 = p1[0];
273             y1 = p1[1];
274             x2 = p2[0];
275             y2 = p2[1];
276             x3 = p3[0];
277             y3 = p3[1];
278             rx = x;
279             ry = y;
280         } else {
281             // all dimensions are really small so lets call it close
282             // enough and return a successful match
283             result = Point3D(x, y, z);
284             return(1);
285         }
286
287         // check if intersection point is on the same side of p1 <-> p2 as p3
288         t1 = (y1 - y2) / (x1 - x2);
289         side1 = FG_SIGN (t1 * ((x3) - x2) + y2 - (y3));
290         side2 = FG_SIGN (t1 * ((rx) - x2) + y2 - (ry));
291         if ( side1 != side2 ) {
292             // printf("failed side 1 check\n");
293             continue;
294         }
295
296         // check if intersection point is on correct side of p2 <-> p3 as p1
297         t1 = (y2 - y3) / (x2 - x3);
298         side1 = FG_SIGN (t1 * ((x1) - x3) + y3 - (y1));
299         side2 = FG_SIGN (t1 * ((rx) - x3) + y3 - (ry));
300         if ( side1 != side2 ) {
301             // printf("failed side 2 check\n");
302             continue;
303         }
304
305         // check if intersection point is on correct side of p1 <-> p3 as p2
306         t1 = (y1 - y3) / (x1 - x3);
307         side1 = FG_SIGN (t1 * ((x2) - x3) + y3 - (y2));
308         side2 = FG_SIGN (t1 * ((rx) - x3) + y3 - (ry));
309         if ( side1 != side2 ) {
310             // printf("failed side 3  check\n");
311             continue;
312         }
313
314         // printf( "intersection point = %.2f %.2f %.2f\n", x, y, z);
315         result = Point3D(x, y, z);
316         return(1);
317     }
318
319     // printf("\n");
320
321     return(0);
322 }
323