]> git.mxchange.org Git - flightgear.git/blob - Scenery/tile.cxx
Attempting to iron out seg faults and crashes.
[flightgear.git] / Scenery / tile.cxx
1 // tile.cxx -- routines to handle a scenery tile
2 //
3 // Written by Curtis Olson, started May 1998.
4 //
5 // Copyright (C) 1998  Curtis L. Olson  - curt@infoplane.com
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 // (Log is kept at end of this file)
23
24
25 #include <Include/fg_constants.h>
26 #include <Include/fg_types.h>
27 #include <Math/mat3.h>
28
29 #include "tile.hxx"
30
31
32 // return the sign of a value
33 #define FG_SIGN( x )  ((x) < 0 ? -1 : 1)
34
35 // return min or max of two values
36 #define FG_MIN(A,B)     ((A) < (B) ? (A) :  (B))
37 #define FG_MAX(A,B)     ((A) > (B) ? (A) :  (B))
38
39
40 fgFACE :: fgFACE () : 
41     n1(0), n2(0), n3(0)
42 {
43 }
44
45 fgFACE :: ~fgFACE()
46 {
47 }
48
49 fgFACE :: fgFACE( const fgFACE & image ) :
50     n1( image.n1), n2( image.n2), n3( image.n3)
51 {
52 }
53
54 bool fgFACE :: operator < (const fgFACE & rhs )
55 {
56     return ( n1 < rhs.n1 ? true : false);
57 }
58
59 bool fgFACE :: operator == (const fgFACE & rhs )
60 {
61     return ((n1 == rhs.n1) && (n2 == rhs.n2) && ( n3 == rhs.n3));
62 }
63
64
65 // Constructor
66 fgFRAGMENT::fgFRAGMENT ( void ) {
67 }
68
69
70 // Copy constructor
71 fgFRAGMENT ::   fgFRAGMENT ( const fgFRAGMENT & rhs ) :
72     center         ( rhs.center          ),
73     bounding_radius( rhs.bounding_radius ),
74     material_ptr   ( rhs.material_ptr    ),
75     tile_ptr       ( rhs.tile_ptr        ),
76     display_list   ( rhs.display_list    ),
77     faces          ( rhs.faces           ),
78     num_faces      ( rhs.num_faces       )
79 {
80 }
81
82 fgFRAGMENT & fgFRAGMENT :: operator = ( const fgFRAGMENT & rhs )
83 {
84     if(!(this == &rhs )) {
85         center          = rhs.center;
86         bounding_radius = rhs.bounding_radius;
87         material_ptr    = rhs.material_ptr;
88         tile_ptr        = rhs.tile_ptr;
89         // display_list    = rhs.display_list;
90         faces           = rhs.faces;
91     }
92     return *this;
93 }
94
95
96 // Add a face to the face list
97 void fgFRAGMENT::add_face(int n1, int n2, int n3) {
98     fgFACE face;
99
100     face.n1 = n1;
101     face.n2 = n2;
102     face.n3 = n3;
103
104     faces.push_back(face);
105     num_faces++;
106 }
107
108
109 /*
110 // return the sign of a value
111 static int fg_sign( double x ) {
112     if ( x >= 0 ) {
113         return(1);
114     } else {
115         return(-1);
116     }
117 }
118
119
120 // return the minimum of the three values
121 static double fg_min( double a, double b, double c ) {
122     double result;
123     result = a;
124     if (result > b) result = b;
125     if (result > c) result = c;
126
127     return(result);
128 }
129
130
131 // return the maximum of the three values
132 static double fg_max( double a, double b, double c ) {
133     double result;
134     result = a;
135     if (result < b) result = b;
136     if (result < c) result = c;
137
138     return(result);
139 }
140 */
141
142
143 // return the minimum of the three values
144 static double fg_min3 (double a, double b, double c)
145 {
146     return (a > b ? FG_MIN (b, c) : FG_MIN (a, c));
147 }
148
149
150 // return the maximum of the three values
151 static double fg_max3 (double a, double b, double c)
152 {
153   return (a < b ? FG_MAX (b, c) : FG_MAX (a, c));
154 }
155
156
157 // test if line intesects with this fragment.  p0 and p1 are the two
158 // line end points of the line.  If side_flag is true, check to see
159 // that end points are on opposite sides of face.  Returns 1 if it
160 // intersection found, 0 otherwise.  If it intesects, result is the
161 // point of intersection
162
163 int fgFRAGMENT::intersect( fgPoint3d *end0, fgPoint3d *end1, int side_flag,
164                            fgPoint3d *result)
165 {
166     fgTILE *t;
167     fgFACE face;
168     MAT3vec v1, v2, n, center;
169     double p1[3], p2[3], p3[3];
170     double x, y, z;  // temporary holding spot for result
171     double a, b, c, d;
172     double x0, y0, z0, x1, y1, z1, a1, b1, c1;
173     double t1, t2, t3;
174     double xmin, xmax, ymin, ymax, zmin, zmax;
175     double dx, dy, dz, min_dim, x2, y2, x3, y3, rx, ry;
176     int side1, side2;
177     list < fgFACE > :: iterator current;
178     list < fgFACE > :: iterator last;
179
180     // find the associated tile
181     t = tile_ptr;
182
183     // printf("Intersecting\n");
184
185     // traverse the face list for this fragment
186     current = faces.begin();
187     last = faces.end();
188     while ( current != last ) {
189         face = *current;
190         current++;
191
192         // printf(".");
193
194         // get face vertex coordinates
195         center[0] = t->center.x;
196         center[1] = t->center.y;
197         center[2] = t->center.z;
198
199         MAT3_ADD_VEC(p1, t->nodes[face.n1], center);
200         MAT3_ADD_VEC(p2, t->nodes[face.n2], center);
201         MAT3_ADD_VEC(p3, t->nodes[face.n3], center);
202
203         // printf("point 1 = %.2f %.2f %.2f\n", p1[0], p1[1], p1[2]);
204         // printf("point 2 = %.2f %.2f %.2f\n", p2[0], p2[1], p2[2]);
205         // printf("point 3 = %.2f %.2f %.2f\n", p3[0], p3[1], p3[2]);
206
207         // calculate two edge vectors, and the face normal
208         MAT3_SUB_VEC(v1, p2, p1);
209         MAT3_SUB_VEC(v2, p3, p1);
210         MAT3cross_product(n, v1, v2);
211
212         // calculate the plane coefficients for the plane defined by
213         // this face.  If n is the normal vector, n = (a, b, c) and p1
214         // is a point on the plane, p1 = (x0, y0, z0), then the
215         // equation of the line is a(x-x0) + b(y-y0) + c(z-z0) = 0
216         a = n[0];
217         b = n[1];
218         c = n[2];
219         d = a * p1[0] + b * p1[1] + c * p1[2];
220         // printf("a, b, c, d = %.2f %.2f %.2f %.2f\n", a, b, c, d);
221
222         // printf("p1(d) = %.2f\n", a * p1[0] + b * p1[1] + c * p1[2]);
223         // printf("p2(d) = %.2f\n", a * p2[0] + b * p2[1] + c * p2[2]);
224         // printf("p3(d) = %.2f\n", a * p3[0] + b * p3[1] + c * p3[2]);
225
226         // calculate the line coefficients for the specified line
227         x0 = end0->x;  x1 = end1->x;
228         y0 = end0->y;  y1 = end1->y;
229         z0 = end0->z;  z1 = end1->z;
230
231         if ( fabs(x1 - x0) > FG_EPSILON ) {
232             a1 = 1.0 / (x1 - x0);
233         } else {
234             // we got a big divide by zero problem here
235             a1 = 0.0;
236         }
237         b1 = y1 - y0;
238         c1 = z1 - z0;
239
240         // intersect the specified line with this plane
241         t1 = b * b1 * a1;
242         t2 = c * c1 * a1;
243
244         // printf("a = %.2f  t1 = %.2f  t2 = %.2f\n", a, t1, t2);
245
246         if ( fabs(a + t1 + t2) > FG_EPSILON ) {
247             x = (t1*x0 - b*y0 + t2*x0 - c*z0 + d) / (a + t1 + t2);
248             t3 = a1 * (x - x0);
249             y = b1 * t3 + y0;
250             z = c1 * t3 + z0;       
251             // printf("result(d) = %.2f\n", a * x + b * y + c * z);
252         } else {
253             // no intersection point
254             continue;
255         }
256
257         if ( side_flag ) {
258             // check to see if end0 and end1 are on opposite sides of
259             // plane
260             if ( (x - x0) > FG_EPSILON ) {
261                 t1 = x;
262                 t2 = x0;
263                 t3 = x1;
264             } else if ( (y - y0) > FG_EPSILON ) {
265                 t1 = y;
266                 t2 = y0;
267                 t3 = y1;
268             } else if ( (z - z0) > FG_EPSILON ) {
269                 t1 = z;
270                 t2 = z0;
271                 t3 = z1;
272             } else {
273                 // everything is too close together to tell the difference
274                 // so the current intersection point should work as good
275                 // as any
276                 result->x = x;
277                 result->y = y;
278                 result->z = z;
279                 return(1);
280             }
281             side1 = FG_SIGN (t1 - t2);
282             side2 = FG_SIGN (t1 - t3);
283             if ( side1 == side2 ) {
284                 // same side, punt
285                 continue;
286             }
287         }
288
289         // check to see if intersection point is in the bounding
290         // cube of the face
291         xmin = fg_min3 (p1[0], p2[0], p3[0]);
292         xmax = fg_max3 (p1[0], p2[0], p3[0]);
293         ymin = fg_min3 (p1[1], p2[1], p3[1]);
294         ymax = fg_max3 (p1[1], p2[1], p3[1]);
295         zmin = fg_min3 (p1[2], p2[2], p3[2]);
296         zmax = fg_max3 (p1[2], p2[2], p3[2]);
297         // printf("bounding cube = %.2f,%.2f,%.2f  %.2f,%.2f,%.2f\n",
298         //        xmin, ymin, zmin, xmax, ymax, zmax);
299         // punt if outside bouding cube
300         if ( x < (xmin = fg_min3 (p1[0], p2[0], p3[0])) ) {
301             continue;
302         } else if ( x > (xmax = fg_max3 (p1[0], p2[0], p3[0])) ) {
303             continue;
304         } else if ( y < (ymin = fg_min3 (p1[1], p2[1], p3[1])) ) {
305             continue;
306         } else if ( y > (ymax = fg_max3 (p1[1], p2[1], p3[1])) ) {
307             continue;
308         } else if ( z < (zmin = fg_min3 (p1[2], p2[2], p3[2])) ) {
309             continue;
310         } else if ( z > (zmax = fg_max3 (p1[2], p2[2], p3[2])) ) {
311             continue;
312         }
313
314         // (finally) check to see if the intersection point is
315         // actually inside this face
316
317         //first, drop the smallest dimension so we only have to work
318         //in 2d.
319         dx = xmax - xmin;
320         dy = ymax - ymin;
321         dz = zmax - zmin;
322         min_dim = fg_min3 (dx, dy, dz);
323         if ( fabs(min_dim - dx) <= FG_EPSILON ) {
324             // x is the smallest dimension
325             x1 = p1[1];
326             y1 = p1[2];
327             x2 = p2[1];
328             y2 = p2[2];
329             x3 = p3[1];
330             y3 = p3[2];
331             rx = y;
332             ry = z;
333         } else if ( fabs(min_dim - dy) <= FG_EPSILON ) {
334             // y is the smallest dimension
335             x1 = p1[0];
336             y1 = p1[2];
337             x2 = p2[0];
338             y2 = p2[2];
339             x3 = p3[0];
340             y3 = p3[2];
341             rx = x;
342             ry = z;
343         } else if ( fabs(min_dim - dz) <= FG_EPSILON ) {
344             // z is the smallest dimension
345             x1 = p1[0];
346             y1 = p1[1];
347             x2 = p2[0];
348             y2 = p2[1];
349             x3 = p3[0];
350             y3 = p3[1];
351             rx = x;
352             ry = y;
353         } else {
354             // all dimensions are really small so lets call it close
355             // enough and return a successful match
356             result->x = x;
357             result->y = y;
358             result->z = z;
359             return(1);
360         }
361
362         // check if intersection point is on the same side of p1 <-> p2 as p3
363         t1 = (y1 - y2) / (x1 - x2);
364         side1 = FG_SIGN (t1 * ((x3) - x2) + y2 - (y3));
365         side2 = FG_SIGN (t1 * ((rx) - x2) + y2 - (ry));
366         if ( side1 != side2 ) {
367             // printf("failed side 1 check\n");
368             continue;
369         }
370
371         // check if intersection point is on correct side of p2 <-> p3 as p1
372         t1 = (y2 - y3) / (x2 - x3);
373         side1 = FG_SIGN (t1 * ((x1) - x3) + y3 - (y1));
374         side2 = FG_SIGN (t1 * ((rx) - x3) + y3 - (ry));
375         if ( side1 != side2 ) {
376             // printf("failed side 2 check\n");
377             continue;
378         }
379
380         // check if intersection point is on correct side of p1 <-> p3 as p2
381         t1 = (y1 - y3) / (x1 - x3);
382         side1 = FG_SIGN (t1 * ((x2) - x3) + y3 - (y2));
383         side2 = FG_SIGN (t1 * ((rx) - x3) + y3 - (ry));
384         if ( side1 != side2 ) {
385             // printf("failed side 3  check\n");
386             continue;
387         }
388
389         // printf( "intersection point = %.2f %.2f %.2f\n", x, y, z);
390         result->x = x;
391         result->y = y;
392         result->z = z;
393         return(1);
394     }
395
396     // printf("\n");
397
398     return(0);
399 }
400
401
402 // Destructor
403 fgFRAGMENT::~fgFRAGMENT ( void ) {
404     // Step through the face list deleting the items until the list is
405     // empty
406
407     // printf("destructing a fragment with %d faces\n", faces.size());
408
409     while ( faces.size() ) {
410         //  printf("emptying face list\n");
411         faces.pop_front();
412     }
413 }
414
415
416 // equality operator
417 bool  fgFRAGMENT :: operator == ( const fgFRAGMENT & rhs)
418 {
419     if(( center.x - rhs.center.x ) < FG_EPSILON) {
420         if(( center.y - rhs.center.y) < FG_EPSILON) {
421             if(( center.z - rhs.center.z) < FG_EPSILON) {
422                 return true;
423             }
424         }
425     }
426     return false;
427 }
428
429 // comparison operator
430 bool  fgFRAGMENT :: operator < ( const fgFRAGMENT &rhs)
431 {
432     // This is completely arbitrary. It satisfies RW's STL implementation
433
434     return bounding_radius < rhs.bounding_radius;
435 }
436
437
438 // Constructor
439 fgTILE::fgTILE ( void ) {
440     nodes = new double[MAX_NODES][3];
441 }
442
443
444 // Destructor
445 fgTILE::~fgTILE ( void ) {
446     free(nodes);
447 }
448
449
450 // $Log$
451 // Revision 1.8  1998/08/22 14:49:58  curt
452 // Attempting to iron out seg faults and crashes.
453 // Did some shuffling to fix a initialization order problem between view
454 // position, scenery elevation.
455 //
456 // Revision 1.7  1998/08/20 15:12:05  curt
457 // Used a forward declaration of classes fgTILE and fgMATERIAL to eliminate
458 // the need for "void" pointers and casts.
459 // Quick hack to count the number of scenery polygons that are being drawn.
460 //
461 // Revision 1.6  1998/08/12 21:13:05  curt
462 // material.cxx: don't load textures if they are disabled
463 // obj.cxx: optimizations from Norman Vine
464 // tile.cxx: minor tweaks
465 // tile.hxx: addition of num_faces
466 // tilemgr.cxx: minor tweaks
467 //
468 // Revision 1.5  1998/07/24 21:42:08  curt
469 // material.cxx: whups, double method declaration with no definition.
470 // obj.cxx: tweaks to avoid errors in SGI's CC.
471 // tile.cxx: optimizations by Norman Vine.
472 // tilemgr.cxx: optimizations by Norman Vine.
473 //
474 // Revision 1.4  1998/07/22 21:41:42  curt
475 // Add basic fgFACE methods contributed by Charlie Hotchkiss.
476 // intersect optimization from Norman Vine.
477 //
478 // Revision 1.3  1998/07/16 17:34:24  curt
479 // Ground collision detection optimizations contributed by Norman Vine.
480 //
481 // Revision 1.2  1998/07/12 03:18:28  curt
482 // Added ground collision detection.  This involved:
483 // - saving the entire vertex list for each tile with the tile records.
484 // - saving the face list for each fragment with the fragment records.
485 // - code to intersect the current vertical line with the proper face in
486 //   an efficient manner as possible.
487 // Fixed a bug where the tiles weren't being shifted to "near" (0,0,0)
488 //
489 // Revision 1.1  1998/05/23 14:09:21  curt
490 // Added tile.cxx and tile.hxx.
491 // Working on rewriting the tile management system so a tile is just a list
492 // fragments, and the fragment record contains the display list for that fragment.
493 //