]> git.mxchange.org Git - flightgear.git/commitdiff
Added ground collision detection. This involved:
authorcurt <curt>
Sun, 12 Jul 1998 03:18:27 +0000 (03:18 +0000)
committercurt <curt>
Sun, 12 Jul 1998 03:18:27 +0000 (03:18 +0000)
- saving the entire vertex list for each tile with the tile records.
- saving the face list for each fragment with the fragment records.
- code to intersect the current vertical line with the proper face in
  an efficient manner as possible.
Fixed a bug where the tiles weren't being shifted to "near" (0,0,0)

Scenery/obj.cxx
Scenery/scenery.cxx
Scenery/scenery.hxx
Scenery/tile.cxx
Scenery/tile.hxx
Scenery/tilecache.cxx
Scenery/tilemgr.cxx

index bcb81893baa46affb350485896177da7294e501c..fca63e6ffad6c7a7aaaf9f125d5e263c96048b48 100644 (file)
@@ -60,10 +60,7 @@ using namespace std;
 #include "tile.hxx"
 
 
-#define MAXNODES 100000
-
-static double nodes[MAXNODES][3];
-static double normals[MAXNODES][3];
+static double normals[MAX_NODES][3];
 
 
 // given three points defining a triangle, calculate the normal
@@ -106,7 +103,7 @@ fgPoint3d calc_tex_coords(double *node, fgPoint3d *ref) {
 
 
 // Load a .obj file and build the GL fragment list
-int fgObjLoad(char *path, fgTILE *tile) {
+int fgObjLoad(char *path, fgTILE *t) {
     fgOPTIONS *o;
     fgFRAGMENT fragment;
     fgPoint3d pp;
@@ -116,7 +113,7 @@ int fgObjLoad(char *path, fgTILE *tile) {
     // GLfloat sgenparams[] = { 1.0, 0.0, 0.0, 0.0 };
     GLint display_list;
     fgFile f;
-    int in_fragment, in_faces, ncount, vncount, n1, n2, n3, n4;
+    int in_fragment, in_faces, vncount, n1, n2, n3, n4;
     int last1, last2, odd;
 
     o = &current_options;
@@ -140,9 +137,9 @@ int fgObjLoad(char *path, fgTILE *tile) {
     }
 
     in_fragment = 0;
-    ncount = 1;
+    t->ncount = 1;
     vncount = 1;
-    tile->bounding_radius = 0.0;
+    t->bounding_radius = 0.0;
 
     while ( fggets(f, line, 250) != NULL ) {
        if ( line[0] == '#' ) {
@@ -152,8 +149,8 @@ int fgObjLoad(char *path, fgTILE *tile) {
        } else if ( strncmp(line, "gbs ", 4) == 0 ) {
            // reference point (center offset)
            sscanf(line, "gbs %lf %lf %lf %lf\n", 
-                  &tile->center.x, &tile->center.y, &tile->center.z, 
-                  &tile->bounding_radius);
+                  &t->center.x, &t->center.y, &t->center.z, 
+                  &t->bounding_radius);
        } else if ( strncmp(line, "bs ", 3) == 0 ) {
            // reference point (center offset)
            sscanf(line, "bs %lf %lf %lf %lf\n", 
@@ -161,20 +158,21 @@ int fgObjLoad(char *path, fgTILE *tile) {
                   &fragment.bounding_radius);
        } else if ( strncmp(line, "v ", 2) == 0 ) {
            // node (vertex)
-           if ( ncount < MAXNODES ) {
+           if ( t->ncount < MAX_NODES ) {
                // fgPrintf( FG_TERRAIN, FG_DEBUG, "vertex = %s", line);
                sscanf(line, "v %lf %lf %lf\n", 
-                      &nodes[ncount][0], &nodes[ncount][1], 
-                      &nodes[ncount][2]);
+                      &(t->nodes[t->ncount][0]), &(t->nodes[t->ncount][1]), 
+                      &(t->nodes[t->ncount][2]));
+
+               t->ncount++;
 
-               ncount++;
            } else {
                fgPrintf( FG_TERRAIN, FG_EXIT, 
                          "Read too many nodes ... dying :-(\n");
            }
        } else if ( strncmp(line, "vn ", 3) == 0 ) {
            // vertex normal
-           if ( vncount < MAXNODES ) {
+           if ( vncount < MAX_NODES ) {
                // fgPrintf( FG_TERRAIN, FG_DEBUG, "vertex normal = %s", line);
                sscanf(line, "vn %lf %lf %lf\n", 
                       &normals[vncount][0], &normals[vncount][1], 
@@ -197,7 +195,7 @@ int fgObjLoad(char *path, fgTILE *tile) {
                fragment.display_list = display_list;
 
                // push this fragment onto the tile's object list
-               tile->fragment_list.push_back(fragment);
+               t->fragment_list.push_back(fragment);
            } else {
                in_fragment = 1;
            }
@@ -206,11 +204,19 @@ int fgObjLoad(char *path, fgTILE *tile) {
            xglNewList(display_list, GL_COMPILE);
            in_faces = 0;
 
+           // reset the existing face list
+           // printf("cleaning a fragment with %d faces\n", 
+           //        fragment.faces.size());
+           while ( fragment.faces.size() ) {
+               //  printf("emptying face list\n");
+               fragment.faces.pop_front();
+           }
+
            // scan the material line
            sscanf(line, "usemtl %s\n", material);
 
            // give the fragment a pointer back to the tile
-           (fgTILE *)fragment.tile_ptr = tile;
+           (fgTILE *)fragment.tile_ptr = t;
 
            // find this material in the properties list
            map < string, fgMATERIAL, less<string> > :: iterator myfind = 
@@ -239,6 +245,8 @@ int fgObjLoad(char *path, fgTILE *tile) {
            // fgPrintf( FG_TERRAIN, FG_DEBUG, "    new tri strip = %s", line);
            sscanf(line, "t %d %d %d %d\n", &n1, &n2, &n3, &n4);
 
+           fragment.add_face(n1, n2, n3);
+
            // fgPrintf( FG_TERRAIN, FG_DEBUG, "(t) = ");
 
            xglBegin(GL_TRIANGLE_STRIP);
@@ -251,45 +259,45 @@ int fgObjLoad(char *path, fgTILE *tile) {
                // (averaged) normals
                MAT3_SCALE_VEC(normal, normals[n1], scale);
                xglNormal3dv(normal);
-               pp = calc_tex_coords(nodes[n1], &tile->center);
+               pp = calc_tex_coords(t->nodes[n1], &t->center);
                xglTexCoord2f(pp.lon, pp.lat);
-               xglVertex3d(nodes[n1][0], nodes[n1][1], nodes[n1][2]);
+               xglVertex3d(t->nodes[n1][0], t->nodes[n1][1], t->nodes[n1][2]);
 
                MAT3_SCALE_VEC(normal, normals[n2], scale);
                xglNormal3dv(normal);
-                pp = calc_tex_coords(nodes[n2], &tile->center);
+                pp = calc_tex_coords(t->nodes[n2], &t->center);
                 xglTexCoord2f(pp.lon, pp.lat);
-               xglVertex3d(nodes[n2][0], nodes[n2][1], nodes[n2][2]);
+               xglVertex3d(t->nodes[n2][0], t->nodes[n2][1], t->nodes[n2][2]);
 
                MAT3_SCALE_VEC(normal, normals[n3], scale);
                xglNormal3dv(normal);
-                pp = calc_tex_coords(nodes[n3], &tile->center);
+                pp = calc_tex_coords(t->nodes[n3], &t->center);
                 xglTexCoord2f(pp.lon, pp.lat);
-               xglVertex3d(nodes[n3][0], nodes[n3][1], nodes[n3][2]);
+               xglVertex3d(t->nodes[n3][0], t->nodes[n3][1], t->nodes[n3][2]);
            } else {
                // Shading model is "GL_FLAT" so calculate per face
                // normals on the fly.
                if ( odd ) {
-                   calc_normal(nodes[n1], nodes[n2], 
-                               nodes[n3], approx_normal);
+                   calc_normal(t->nodes[n1], t->nodes[n2], 
+                               t->nodes[n3], approx_normal);
                } else {
-                   calc_normal(nodes[n2], nodes[n1], 
-                               nodes[n3], approx_normal);
+                   calc_normal(t->nodes[n2], t->nodes[n1], 
+                               t->nodes[n3], approx_normal);
                }
                MAT3_SCALE_VEC(normal, approx_normal, scale);
                xglNormal3dv(normal);
 
-                pp = calc_tex_coords(nodes[n1], &tile->center);
+                pp = calc_tex_coords(t->nodes[n1], &t->center);
                 xglTexCoord2f(pp.lon, pp.lat);
-               xglVertex3d(nodes[n1][0], nodes[n1][1], nodes[n1][2]);
+               xglVertex3d(t->nodes[n1][0], t->nodes[n1][1], t->nodes[n1][2]);
 
-                pp = calc_tex_coords(nodes[n2], &tile->center);
+                pp = calc_tex_coords(t->nodes[n2], &t->center);
                 xglTexCoord2f(pp.lon, pp.lat);
-               xglVertex3d(nodes[n2][0], nodes[n2][1], nodes[n2][2]);
+               xglVertex3d(t->nodes[n2][0], t->nodes[n2][1], t->nodes[n2][2]);
 
-                pp = calc_tex_coords(nodes[n3], &tile->center);
+                pp = calc_tex_coords(t->nodes[n3], &t->center);
                 xglTexCoord2f(pp.lon, pp.lat);
-               xglVertex3d(nodes[n3][0], nodes[n3][1], nodes[n3][2]);
+               xglVertex3d(t->nodes[n3][0], t->nodes[n3][1], t->nodes[n3][2]);
            }
 
            odd = 1 - odd;
@@ -297,18 +305,21 @@ int fgObjLoad(char *path, fgTILE *tile) {
            last2 = n3;
 
            if ( n4 > 0 ) {
+               fragment.add_face(n3, n2, n4);
+
                if ( o->shading ) {
                    // Shading model is "GL_SMOOTH"
                    MAT3_SCALE_VEC(normal, normals[n4], scale);
                } else {
                    // Shading model is "GL_FLAT"
-                   calc_normal(nodes[n3], nodes[n2], nodes[n4], approx_normal);
+                   calc_normal(t->nodes[n3], t->nodes[n2], t->nodes[n4], 
+                               approx_normal);
                    MAT3_SCALE_VEC(normal, approx_normal, scale);
                }
                xglNormal3dv(normal);
-               pp = calc_tex_coords(nodes[n4], &tile->center);
+               pp = calc_tex_coords(t->nodes[n4], &t->center);
                 xglTexCoord2f(pp.lon, pp.lat);
-               xglVertex3d(nodes[n4][0], nodes[n4][1], nodes[n4][2]);
+               xglVertex3d(t->nodes[n4][0], t->nodes[n4][1], t->nodes[n4][2]);
 
                odd = 1 - odd;
                last1 = n3;
@@ -325,20 +336,22 @@ int fgObjLoad(char *path, fgTILE *tile) {
            // fgPrintf( FG_TERRAIN, FG_DEBUG, "new triangle = %s", line);*/
            sscanf(line, "f %d %d %d\n", &n1, &n2, &n3);
 
+           fragment.add_face(n1, n2, n3);
+
             xglNormal3d(normals[n1][0], normals[n1][1], normals[n1][2]);
-           pp = calc_tex_coords(nodes[n1], &tile->center);
+           pp = calc_tex_coords(t->nodes[n1], &t->center);
            xglTexCoord2f(pp.lon, pp.lat);
-           xglVertex3d(nodes[n1][0], nodes[n1][1], nodes[n1][2]);
+           xglVertex3d(t->nodes[n1][0], t->nodes[n1][1], t->nodes[n1][2]);
 
             xglNormal3d(normals[n2][0], normals[n2][1], normals[n2][2]);
-            pp = calc_tex_coords(nodes[n2], &tile->center);
+            pp = calc_tex_coords(t->nodes[n2], &t->center);
             xglTexCoord2f(pp.lon, pp.lat);
-           xglVertex3d(nodes[n2][0], nodes[n2][1], nodes[n2][2]);
+           xglVertex3d(t->nodes[n2][0], t->nodes[n2][1], t->nodes[n2][2]);
                
             xglNormal3d(normals[n3][0], normals[n3][1], normals[n3][2]);
-            pp = calc_tex_coords(nodes[n3], &tile->center);
+            pp = calc_tex_coords(t->nodes[n3], &t->center);
             xglTexCoord2f(pp.lon, pp.lat);
-           xglVertex3d(nodes[n3][0], nodes[n3][1], nodes[n3][2]);
+           xglVertex3d(t->nodes[n3][0], t->nodes[n3][1], t->nodes[n3][2]);
        } else if ( line[0] == 'q' ) {
            // continue a triangle strip
            n1 = n2 = 0;
@@ -348,6 +361,12 @@ int fgObjLoad(char *path, fgTILE *tile) {
            sscanf(line, "q %d %d\n", &n1, &n2);
            // fgPrintf( FG_TERRAIN, FG_DEBUG, "read %d %d\n", n1, n2);
 
+           if ( odd ) {
+               fragment.add_face(last1, last2, n1);
+           } else {
+               fragment.add_face(last2, last1, n1);
+           }
+
            if ( o->shading ) {
                // Shading model is "GL_SMOOTH"
                MAT3_SCALE_VEC(normal, normals[n1], scale);
@@ -355,19 +374,19 @@ int fgObjLoad(char *path, fgTILE *tile) {
            } else {
                // Shading model is "GL_FLAT"
                if ( odd ) {
-                   calc_normal(nodes[last1], nodes[last2], nodes[n1], 
+                   calc_normal(t->nodes[last1], t->nodes[last2], t->nodes[n1], 
                                approx_normal);
                } else {
-                   calc_normal(nodes[last2], nodes[last1], nodes[n1], 
+                   calc_normal(t->nodes[last2], t->nodes[last1], t->nodes[n1], 
                                approx_normal);
                }
                MAT3_SCALE_VEC(normal, approx_normal, scale);
                xglNormal3dv(normal);
            }
 
-            pp = calc_tex_coords(nodes[n1], &tile->center);
+            pp = calc_tex_coords(t->nodes[n1], &t->center);
             xglTexCoord2f(pp.lon, pp.lat);
-           xglVertex3d(nodes[n1][0], nodes[n1][1], nodes[n1][2]);
+           xglVertex3d(t->nodes[n1][0], t->nodes[n1][1], t->nodes[n1][2]);
     
            odd = 1 - odd;
            last1 = last2;
@@ -376,6 +395,12 @@ int fgObjLoad(char *path, fgTILE *tile) {
            if ( n2 > 0 ) {
                // fgPrintf( FG_TERRAIN, FG_DEBUG, " (cont)\n");
 
+               if ( odd ) {
+                   fragment.add_face(last1, last2, n2);
+               } else {
+                   fragment.add_face(last2, last1, n2);
+               }
+
                if ( o->shading ) {
                    // Shading model is "GL_SMOOTH"
                    MAT3_SCALE_VEC(normal, normals[n2], scale);
@@ -383,19 +408,19 @@ int fgObjLoad(char *path, fgTILE *tile) {
                } else {
                    // Shading model is "GL_FLAT"
                    if ( odd ) {
-                       calc_normal(nodes[last1], nodes[last2], nodes[n2], 
-                                   approx_normal);
+                       calc_normal(t->nodes[last1], t->nodes[last2], 
+                                   t->nodes[n2], approx_normal);
                    } else {
-                       calc_normal(nodes[last2], nodes[last1], nodes[n2], 
-                                   approx_normal);
+                       calc_normal(t->nodes[last2], t->nodes[last1], 
+                                   t->nodes[n2], approx_normal);
                    }
                    MAT3_SCALE_VEC(normal, approx_normal, scale);
                    xglNormal3dv(normal);
                }
 
-               pp = calc_tex_coords(nodes[n2], &tile->center);
+               pp = calc_tex_coords(t->nodes[n2], &t->center);
                xglTexCoord2f(pp.lon, pp.lat);
-               xglVertex3d(nodes[n2][0], nodes[n2][1], nodes[n2][2]);
+               xglVertex3d(t->nodes[n2][0], t->nodes[n2][1], t->nodes[n2][2]);
 
                odd = 1 -odd;
                last1 = last2;
@@ -416,20 +441,20 @@ int fgObjLoad(char *path, fgTILE *tile) {
        fragment.display_list = display_list;
        
        // push this fragment onto the tile's object list
-       tile->fragment_list.push_back(fragment);
+       t->fragment_list.push_back(fragment);
     }
 
     // Draw normal vectors (for visually verifying normals)
     /*
     xglBegin(GL_LINES);
     xglColor3f(0.0, 0.0, 0.0);
-    for ( i = 0; i < ncount; i++ ) {
-        xglVertex3d(nodes[i][0],
-                   nodes[i][1] ,
-                   nodes[i][2]);
-       xglVertex3d(nodes[i][0] + 500*normals[i][0],
-                   nodes[i][1] + 500*normals[i][1],
-                   nodes[i][2] + 500*normals[i][2]);
+    for ( i = 0; i < t->ncount; i++ ) {
+        xglVertex3d(t->nodes[i][0],
+                   t->nodes[i][1] ,
+                   t->nodes[i][2]);
+       xglVertex3d(t->nodes[i][0] + 500*normals[i][0],
+                   t->nodes[i][1] + 500*normals[i][1],
+                   t->nodes[i][2] + 500*normals[i][2]);
     } 
     xglEnd();
     */   
@@ -441,6 +466,14 @@ int fgObjLoad(char *path, fgTILE *tile) {
 
 
 // $Log$
+// Revision 1.18  1998/07/12 03:18:27  curt
+// Added ground collision detection.  This involved:
+// - saving the entire vertex list for each tile with the tile records.
+// - saving the face list for each fragment with the fragment records.
+// - code to intersect the current vertical line with the proper face in
+//   an efficient manner as possible.
+// Fixed a bug where the tiles weren't being shifted to "near" (0,0,0)
+//
 // Revision 1.17  1998/07/08 14:47:21  curt
 // Fix GL_MODULATE vs. GL_DECAL problem introduced by splash screen.
 // polare3d.h renamed to polar3d.hxx
index 858c8f6a5a0254747d18629f41aad478581ca24b..395d3f5ccd0a6f2bcd15d7bf058895dca3cf04ca 100644 (file)
@@ -66,31 +66,8 @@ int fgSceneryInit( void ) {
 
     fgPrintf(FG_TERRAIN, FG_INFO, "Initializing scenery subsystem\n");
 
-#ifdef 0
-    /* set the default terrain detail level */
-    // scenery.terrain_skip = 6;
+    scenery.cur_elev = -9999;
 
-    /* temp: load in a demo texture */
-    path[0] = '\0';
-    strcat(path, o->fg_root);
-    strcat(path, "/Textures/");
-    strcat(path, "desert.rgb");
-
-    // Try uncompressed
-    if ( (texbuf = read_rgb_texture(path, &width, &height)) == NULL ) {
-       // Try compressed
-       strcpy(fgpath, path);
-       strcat(fgpath, ".gz");
-       if ( (texbuf = read_rgb_texture(fgpath, &width, &height)) == NULL ) {
-           fgPrintf( FG_GENERAL, FG_EXIT, "Error in loading texture %s\n",
-                     path );
-           return(0);
-       } 
-    } 
-
-    xglTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0,
-                 GL_RGB, GL_UNSIGNED_BYTE, texbuf);
-#endif // 0
     return(1);
 }
 
@@ -125,11 +102,19 @@ void fgSceneryRender( void ) {
 
 
 /* $Log$
-/* Revision 1.5  1998/06/17 21:36:41  curt
-/* Load and manage multiple textures defined in the Materials library.
-/* Boost max material fagments for each material property to 800.
-/* Multiple texture support when rendering.
+/* Revision 1.6  1998/07/12 03:18:27  curt
+/* Added ground collision detection.  This involved:
+/* - saving the entire vertex list for each tile with the tile records.
+/* - saving the face list for each fragment with the fragment records.
+/* - code to intersect the current vertical line with the proper face in
+/*   an efficient manner as possible.
+/* Fixed a bug where the tiles weren't being shifted to "near" (0,0,0)
 /*
+ * Revision 1.5  1998/06/17 21:36:41  curt
+ * Load and manage multiple textures defined in the Materials library.
+ * Boost max material fagments for each material property to 800.
+ * Multiple texture support when rendering.
+ *
  * Revision 1.4  1998/05/13 18:26:40  curt
  * Root path info moved to fgOPTIONS.
  *
index 47777580d3b2b5f442913552499eaea017e7b6bb..0aa0e552eadea6dce5616600aa4bd6fa8a53e905 100644 (file)
@@ -38,9 +38,6 @@
 
 /* Define a structure containing global scenery parameters */
 struct fgSCENERY {
-    /* number of terrain data points to skip */
-    int terrain_skip;
-
     /* center of current scenery chunk */
     fgPoint3d center;
 
@@ -49,6 +46,10 @@ struct fgSCENERY {
 
     /* angle of sun relative to current local horizontal */
     double sun_angle;
+
+    // elevation of terrain at our current lat/lon (based on the
+    // actual drawn polygons)
+    double cur_elev;
 };
 
 extern struct fgSCENERY scenery;
@@ -71,12 +72,20 @@ void fgSceneryRender( void );
 
 
 /* $Log$
-/* Revision 1.3  1998/07/08 14:47:22  curt
-/* Fix GL_MODULATE vs. GL_DECAL problem introduced by splash screen.
-/* polare3d.h renamed to polar3d.hxx
-/* fg{Cartesian,Polar}Point3d consolodated.
-/* Added some initial support for calculating local current ground elevation.
+/* Revision 1.4  1998/07/12 03:18:28  curt
+/* Added ground collision detection.  This involved:
+/* - saving the entire vertex list for each tile with the tile records.
+/* - saving the face list for each fragment with the fragment records.
+/* - code to intersect the current vertical line with the proper face in
+/*   an efficient manner as possible.
+/* Fixed a bug where the tiles weren't being shifted to "near" (0,0,0)
 /*
+ * Revision 1.3  1998/07/08 14:47:22  curt
+ * Fix GL_MODULATE vs. GL_DECAL problem introduced by splash screen.
+ * polare3d.h renamed to polar3d.hxx
+ * fg{Cartesian,Polar}Point3d consolodated.
+ * Added some initial support for calculating local current ground elevation.
+ *
  * Revision 1.2  1998/05/02 01:52:16  curt
  * Playing around with texture coordinates.
  *
index 3ad353fb39a87622f3425afeea1d74f1e6207b4b..e22f916005d5ab7bbcbae06e22a97839fae536d1 100644 (file)
 // (Log is kept at end of this file)
 
 
+#include <Include/fg_constants.h>
+#include <Include/fg_types.h>
+#include <Math/mat3.h>
+
 #include "tile.hxx"
 
 
@@ -30,22 +34,289 @@ fgFRAGMENT::fgFRAGMENT ( void ) {
 }
 
 
+// Add a face to the face list
+void fgFRAGMENT::add_face(int n1, int n2, int n3) {
+    fgFACE face;
+
+    face.n1 = n1;
+    face.n2 = n2;
+    face.n3 = n3;
+
+    faces.push_back(face);
+}
+
+
+// return the sign of a value
+static int fg_sign( double x ) {
+    if ( x >= 0 ) {
+       return(1);
+    } else {
+       return(-1);
+    }
+}
+
+
+// return the minimum of the three values
+static double fg_min( double a, double b, double c ) {
+    double result;
+    result = a;
+    if (result > b) result = b;
+    if (result > c) result = c;
+
+    return(result);
+}
+
+
+// return the maximum of the three values
+static double fg_max( double a, double b, double c ) {
+    double result;
+    result = a;
+    if (result < b) result = b;
+    if (result < c) result = c;
+
+    return(result);
+}
+
+
+// test if line intesects with this fragment.  p0 and p1 are the two
+// line end points of the line.  If side_flag is true, check to see
+// that end points are on opposite sides of face.  Returns 1 if it
+// does, 0 otherwise.  If it intesects, result is the point of
+// intersection
+
+int fgFRAGMENT::intersect( fgPoint3d *end0, fgPoint3d *end1, int side_flag,
+                          fgPoint3d *result)
+{
+    fgTILE *t;
+    fgFACE face;
+    MAT3vec v1, v2, n, center;
+    double p1[3], p2[3], p3[3];
+    double a, b, c, d;
+    double x0, y0, z0, x1, y1, z1, a1, b1, c1;
+    double t1, t2, t3;
+    double xmin, xmax, ymin, ymax, zmin, zmax;
+    double dx, dy, dz, min_dim, x2, y2, x3, y3, rx, ry;
+    int side1, side2;
+    list < fgFACE > :: iterator current;
+    list < fgFACE > :: iterator last;
+
+    // find the associated tile
+    t = (fgTILE *)tile_ptr;
+
+    // printf("Intersecting\n");
+
+    // traverse the face list for this fragment
+    current = faces.begin();
+    last = faces.end();
+    while ( current != last ) {
+       face = *current;
+       current++;
+
+       // printf(".");
+
+       // get face vertex coordinates
+       center[0] = t->center.x;
+       center[1] = t->center.y;
+       center[2] = t->center.z;
+
+       MAT3_ADD_VEC(p1, t->nodes[face.n1], center);
+       MAT3_ADD_VEC(p2, t->nodes[face.n2], center);
+       MAT3_ADD_VEC(p3, t->nodes[face.n3], center);
+
+       // printf("point 1 = %.2f %.2f %.2f\n", p1[0], p1[1], p1[2]);
+       // printf("point 2 = %.2f %.2f %.2f\n", p2[0], p2[1], p2[2]);
+       // printf("point 3 = %.2f %.2f %.2f\n", p3[0], p3[1], p3[2]);
+
+       // calculate two edge vectors, and the face normal
+       MAT3_SUB_VEC(v1, p2, p1);
+       MAT3_SUB_VEC(v2, p3, p1);
+       MAT3cross_product(n, v1, v2);
+
+       // calculate the plane coefficients for the plane defined by
+       // this face.  If n is the normal vector, n = (a, b, c) and p1
+       // is a point on the plane, p1 = (x0, y0, z0), then the
+       // equation of the line is a(x-x0) + b(y-y0) + c(z-z0) = 0
+       a = n[0];
+       b = n[1];
+       c = n[2];
+       d = a * p1[0] + b * p1[1] + c * p1[2];
+       // printf("a, b, c, d = %.2f %.2f %.2f %.2f\n", a, b, c, d);
+
+       // printf("p1(d) = %.2f\n", a * p1[0] + b * p1[1] + c * p1[2]);
+       // printf("p2(d) = %.2f\n", a * p2[0] + b * p2[1] + c * p2[2]);
+       // printf("p3(d) = %.2f\n", a * p3[0] + b * p3[1] + c * p3[2]);
+
+       // calculate the line coefficients for the specified line
+       x0 = end0->x;  x1 = end1->x;
+       y0 = end0->y;  y1 = end1->y;
+       z0 = end0->z;  z1 = end1->z;
+
+       a1 = x1 - x0;
+       b1 = y1 - y0;
+       c1 = z1 - z0;
+
+       // intersect the specified line with this plane
+       t1 = b * b1 / a1;
+       t2 = c * c1 / a1;
+
+       // printf("a = %.2f  t1 = %.2f  t2 = %.2f\n", a, t1, t2);
+
+       if ( fabs(a + t1 + t2) > FG_EPSILON ) {
+           result->x = (t1*x0 - b*y0 + t2*x0 - c*z0 + d) / (a + t1 + t2);
+           result->y = (b1/a1) * (result->x - x0) + y0;
+           result->z = (c1/a1) * (result->x - x0) + z0;            
+           // printf("result(d) = %.2f\n", 
+           //        a * result->x + b * result->y + c * result->z);
+       } else {
+           // no intersection point
+           continue;
+       }
+
+       if ( side_flag ) {
+           // check to see if end0 and end1 are on opposite sides of
+           // plane
+           if ( (result->x - x0) > FG_EPSILON ) {
+               t1 = result->x; t2 = x0; t3 = x1;
+           } else if ( (result->y - y0) > FG_EPSILON ) {
+               t1 = result->y; t2 = y0; t3 = y1;
+           } else if ( (result->z - z0) > FG_EPSILON ) {
+               t1 = result->z; t2 = z0; t3 = z1;
+           } else {
+               // everything is too close together to tell the difference
+               // so the current intersection point should work as good
+               // as any
+               return(1);
+           }
+           if ( fg_sign(t1 - t2) == fg_sign(t1 - t3) ) {
+               // same side, punt
+               continue;
+           }
+       }
+
+       // check to see if intersection point is in the bounding
+       // cube of the face
+       xmin = fg_min(p1[0], p2[0], p3[0]);
+       xmax = fg_max(p1[0], p2[0], p3[0]);
+       ymin = fg_min(p1[1], p2[1], p3[1]);
+       ymax = fg_max(p1[1], p2[1], p3[1]);
+       zmin = fg_min(p1[2], p2[2], p3[2]);
+       zmax = fg_max(p1[2], p2[2], p3[2]);
+       // printf("bounding cube = %.2f,%.2f,%.2f  %.2f,%.2f,%.2f\n",
+       //        xmin, ymin, zmin, xmax, ymax, zmax);
+       // punt if outside bouding cube
+       if ( result->x < xmin ) {
+           continue;
+       } else if ( result->x > xmax ) {
+           continue;
+       } else if ( result->y < ymin ) {
+           continue;
+       } else if ( result->y > ymax ) {
+           continue;
+       } else if ( result->z < zmin ) {
+           continue;
+       } else if ( result->z > zmax ) {
+           continue;
+       }
+
+       // (finally) check to see if the intersection point is
+       // actually inside this face
+
+       //first, drop the smallest dimension so we only have to work
+       //in 2d.
+       dx = xmax - xmin;
+       dy = ymax - ymin;
+       dz = zmax - zmin;
+       min_dim = fg_min(dx, dy, dz);
+       if ( fabs(min_dim - dx) <= FG_EPSILON ) {
+           // x is the smallest dimension
+           x1 = p1[1]; y1 = p1[2];
+           x2 = p2[1]; y2 = p2[2];
+           x3 = p3[1]; y3 = p3[2];
+           rx = result->y; ry = result->z;
+       } else if ( fabs(min_dim - dy) <= FG_EPSILON ) {
+           // y is the smallest dimension
+           x1 = p1[0]; y1 = p1[2];
+           x2 = p2[0]; y2 = p2[2];
+           x3 = p3[0]; y3 = p3[2];
+           rx = result->x; ry = result->z;
+       } else if ( fabs(min_dim - dz) <= FG_EPSILON ) {
+           // z is the smallest dimension
+           x1 = p1[0]; y1 = p1[1];
+           x2 = p2[0]; y2 = p2[1];
+           x3 = p3[0]; y3 = p3[1];
+           rx = result->x; ry = result->y;
+       }
+
+       // check if intersection point is on the same side of p1 <-> p2 as p3
+       side1 = fg_sign((y1 - y2) * ((x3) - x2) / (x1 - x2) + y2 - (y3));
+       side2 = fg_sign((y1 - y2) * ((rx) - x2) / (x1 - x2) + y2 - (ry));
+       if ( side1 != side2 ) {
+           // printf("failed side 1 check\n");
+           continue;
+       }
+
+       // check if intersection point is on correct side of p2 <-> p3 as p1
+       side1 = fg_sign((y2 - y3) * ((x1) - x3) / (x2 - x3) + y3 - (y1));
+       side2 = fg_sign((y2 - y3) * ((rx) - x3) / (x2 - x3) + y3 - (ry));
+       if ( side1 != side2 ) {
+           // printf("failed side 2 check\n");
+           continue;
+       }
+
+       // check if intersection point is on correct side of p1 <-> p3 as p2
+       side1 = fg_sign((y1 - y3) * ((x2) - x3) / (x1 - x3) + y3 - (y2));
+       side2 = fg_sign((y1 - y3) * ((rx) - x3) / (x1 - x3) + y3 - (ry));
+       if ( side1 != side2 ) {
+           // printf("failed side 3  check\n");
+           continue;
+       }
+
+       // printf( "intersection point = %.2f %.2f %.2f\n", 
+       //         result->x, result->y, result->z);
+       return(1);
+    }
+
+    // printf("\n");
+
+    return(0);
+}
+
+
 // Destructor
 fgFRAGMENT::~fgFRAGMENT ( void ) {
+    // Step through the face list deleting the items until the list is
+    // empty
+
+    // printf("destructing a fragment with %d faces\n", faces.size());
+
+    while ( faces.size() ) {
+       //  printf("emptying face list\n");
+       faces.pop_front();
+    }
 }
 
 
 // Constructor
 fgTILE::fgTILE ( void ) {
+    nodes = new double[MAX_NODES][3];
 }
 
 
 // Destructor
 fgTILE::~fgTILE ( void ) {
+    free(nodes);
 }
 
 
 // $Log$
+// Revision 1.2  1998/07/12 03:18:28  curt
+// Added ground collision detection.  This involved:
+// - saving the entire vertex list for each tile with the tile records.
+// - saving the face list for each fragment with the fragment records.
+// - code to intersect the current vertical line with the proper face in
+//   an efficient manner as possible.
+// Fixed a bug where the tiles weren't being shifted to "near" (0,0,0)
+//
 // Revision 1.1  1998/05/23 14:09:21  curt
 // Added tile.cxx and tile.hxx.
 // Working on rewriting the tile management system so a tile is just a list
index e79a8dc8205437c8caa286bc6192de1040d78813..535b9ff7c53fd06be967d4a643df90a8598650f3 100644 (file)
@@ -53,6 +53,16 @@ using namespace std;
 
 #include <Bucket/bucketutils.h>
 #include <Include/fg_types.h>
+#include <Math/mat3.h>
+
+
+// Maximum nodes per tile
+#define MAX_NODES 1000
+
+
+typedef struct {
+    int n1, n2, n3;
+} fgFACE;
 
 
 // Object fragment data class
@@ -82,9 +92,23 @@ public:
     // OpenGL display list for fragment data
     GLint display_list;
 
+    // face list (this indexes into the master tile vertex list)
+    list < fgFACE > faces;
+
     // Constructor
     fgFRAGMENT ( void );
 
+    // Add a face to the face list
+    void add_face(int n1, int n2, int n3);
+
+    // test if line intesects with this fragment.  p0 and p1 are the
+    // two line end points of the line.  If side_flag is true, check
+    // to see that end points are on opposite sides of face.  Returns
+    // 1 if it does, 0 otherwise.  If it intesects, result is the
+    // point of intersection
+    int intersect( fgPoint3d *end0, fgPoint3d *end1, int side_flag,
+                  fgPoint3d *result);
+
     // Destructor
     ~fgFRAGMENT ( void );
 };
@@ -95,6 +119,10 @@ class fgTILE {
 
 public:
 
+    // node list (the per fragment face lists reference this node list)
+    double (*nodes)[3];
+    int ncount;
+
     // culling data for whole tile (course grain culling)
     fgPoint3d center;
     double bounding_radius;
@@ -121,6 +149,14 @@ public:
 
 
 // $Log$
+// Revision 1.11  1998/07/12 03:18:28  curt
+// Added ground collision detection.  This involved:
+// - saving the entire vertex list for each tile with the tile records.
+// - saving the face list for each fragment with the fragment records.
+// - code to intersect the current vertical line with the proper face in
+//   an efficient manner as possible.
+// Fixed a bug where the tiles weren't being shifted to "near" (0,0,0)
+//
 // Revision 1.10  1998/07/08 14:47:22  curt
 // Fix GL_MODULATE vs. GL_DECAL problem introduced by splash screen.
 // polare3d.h renamed to polar3d.hxx
index cf7e361f9badea8edb2d4d086f29decdce9e3d77..c870ca7a7cf654921fd1020673d7880aa3acd489 100644 (file)
@@ -39,6 +39,7 @@
 #include <Main/views.hxx>
 
 #include "obj.hxx"
+#include "tile.hxx"
 #include "tilecache.hxx"
 
 
@@ -117,7 +118,7 @@ void fgTILECACHE::EntryFillIn( int index, fgBUCKET *p ) {
 
 // Free a tile cache entry
 void fgTILECACHE::EntryFree( int index ) {
-    fgFRAGMENT fragment;
+    fgFRAGMENT *fragment;
 
     // Mark this cache entry as un-used
     tile_cache[index].used = 0;
@@ -133,8 +134,11 @@ void fgTILECACHE::EntryFree( int index ) {
     // Step through the fragment list, deleting the display list, then
     // the fragment, until the list is empty.
     while ( tile_cache[index].fragment_list.size() ) {
-       fragment = tile_cache[index].fragment_list.front();
-       xglDeleteLists( fragment.display_list, 1 );
+       list < fgFRAGMENT > :: iterator current =
+           tile_cache[index].fragment_list.begin();
+       fragment = &(*current);
+       xglDeleteLists( fragment->display_list, 1 );
+
        tile_cache[index].fragment_list.pop_front();
     }
 }
@@ -209,6 +213,14 @@ fgTILECACHE::~fgTILECACHE( void ) {
 
 
 // $Log$
+// Revision 1.12  1998/07/12 03:18:29  curt
+// Added ground collision detection.  This involved:
+// - saving the entire vertex list for each tile with the tile records.
+// - saving the face list for each fragment with the fragment records.
+// - code to intersect the current vertical line with the proper face in
+//   an efficient manner as possible.
+// Fixed a bug where the tiles weren't being shifted to "near" (0,0,0)
+//
 // Revision 1.11  1998/07/04 00:54:30  curt
 // Added automatic mipmap generation.
 //
index d4b5f85f05be10d42f85e0ab6aefca1f34ed7302..252fd83c13e24c2d1f8bfa2df950c69a48b99ea4 100644 (file)
@@ -316,13 +316,13 @@ void fgTileMgrRender( void ) {
     fgTILECACHE *c;
     fgFLIGHT *f;
     fgOPTIONS *o;
-    fgTILE *t;
+    fgTILE *t, *last_tile_ptr;
     fgVIEW *v;
     fgBUCKET p;
-    fgPoint3d frag_offset, fc, pp;
+    fgPoint3d frag_offset, pp;
+    fgPoint3d earth_center, result;
     fgFRAGMENT *frag_ptr;
     fgMATERIAL *mtl_ptr;
-    fgTILE *last_tile_ptr;
     GLdouble *m;
     double dist, min_dist, lat_geod, alt, sea_level_r;
     double x, y, z;
@@ -343,6 +343,14 @@ void fgTileMgrRender( void ) {
     index = c->Exists(&p);
     t = c->GetTile(index);
 
+    scenery.next_center.x = t->center.x;
+    scenery.next_center.y = t->center.y;
+    scenery.next_center.z = t->center.z;
+
+    earth_center.x = 0.0;
+    earth_center.y = 0.0;
+    earth_center.z = 0.0;
+
     fgPrintf( FG_TERRAIN, FG_DEBUG, 
              "Pos = (%.2f, %.2f) Current bucket = %d %d %d %d  Index = %ld\n", 
              FG_Longitude * RAD_TO_DEG, FG_Latitude * RAD_TO_DEG,
@@ -370,6 +378,7 @@ void fgTileMgrRender( void ) {
        }
 
        // Calculate the model_view transformation matrix for this tile
+       // This is equivalent to doing a glTranslatef(x, y, z);
        m[12] = m[0] * x + m[4] * y + m[8]  * z + m[12];
        m[13] = m[1] * x + m[5] * y + m[9]  * z + m[13];
        m[14] = m[2] * x + m[6] * y + m[10] * z + m[14];
@@ -378,7 +387,12 @@ void fgTileMgrRender( void ) {
        // temp ... calc current terrain elevation
        // calculate distance from vertical tangent line at
        // current position to center of tile.
-       dist = point_line_dist(&(t->offset), &(v->view_pos), v->local_up);
+       
+       /* printf("distance = %.2f, bounding radius = %.2f\n", 
+              point_line_dist(&(t->offset), &(v->view_pos), v->local_up),
+              t->bounding_radius); */
+
+       dist = point_line_dist(&(t->center), &(v->abs_view_pos), v->local_up);
        if ( dist < t->bounding_radius ) {
 
            // traverse fragment list for tile
@@ -388,23 +402,28 @@ void fgTileMgrRender( void ) {
            while ( current != last ) {
                frag_ptr = &(*current);
                current++;
-               dist = point_line_dist( &(frag_ptr->center), &(v->view_pos), 
-                                       v->local_up);
+               /* printf("distance = %.2f, bounding radius = %.2f\n", 
+                      point_line_dist( &(frag_ptr->center), 
+                                       &(v->abs_view_pos), v->local_up),
+                      frag_ptr->bounding_radius); */
+
+               dist = point_line_dist( &(frag_ptr->center), 
+                                       &(v->abs_view_pos), v->local_up);
                if ( dist <= frag_ptr->bounding_radius ) {
-                   if ( dist < min_dist ) {
-                       min_dist = dist;
+                   if ( frag_ptr->intersect( &(v->abs_view_pos), 
+                                             &earth_center, 0, &result ) ) {
                        // compute geocentric coordinates of tile center
-                       pp = fgCartToPolar3d(frag_ptr->center);
+                       pp = fgCartToPolar3d(result);
                        // convert to geodetic coordinates
                        fgGeocToGeod(pp.lat, pp.radius, &lat_geod, 
                                     &alt, &sea_level_r);
+                       // printf("alt = %.2f\n", alt);
+                       scenery.cur_elev = alt;
+                       // exit this loop since we found an intersection
+                       break;
                    }
                }
            }
-
-           if ( min_dist <= t->bounding_radius ) {
-               printf("min_dist = %.2f  alt = %.2f\n", min_dist, alt);
-           }
        }
 
        // Course (tile based) culling
@@ -531,6 +550,14 @@ void fgTileMgrRender( void ) {
 
 
 // $Log$
+// Revision 1.24  1998/07/12 03:18:29  curt
+// Added ground collision detection.  This involved:
+// - saving the entire vertex list for each tile with the tile records.
+// - saving the face list for each fragment with the fragment records.
+// - code to intersect the current vertical line with the proper face in
+//   an efficient manner as possible.
+// Fixed a bug where the tiles weren't being shifted to "near" (0,0,0)
+//
 // Revision 1.23  1998/07/08 14:47:23  curt
 // Fix GL_MODULATE vs. GL_DECAL problem introduced by splash screen.
 // polare3d.h renamed to polar3d.hxx