From: curt Date: Sun, 12 Jul 1998 03:18:27 +0000 (+0000) Subject: Added ground collision detection. This involved: X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=262b2f060747a92fdff7695b12202efb87e60e1b;p=flightgear.git 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) --- diff --git a/Scenery/obj.cxx b/Scenery/obj.cxx index bcb81893b..fca63e6ff 100644 --- a/Scenery/obj.cxx +++ b/Scenery/obj.cxx @@ -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 = ¤t_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 > :: 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 diff --git a/Scenery/scenery.cxx b/Scenery/scenery.cxx index 858c8f6a5..395d3f5cc 100644 --- a/Scenery/scenery.cxx +++ b/Scenery/scenery.cxx @@ -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. * diff --git a/Scenery/scenery.hxx b/Scenery/scenery.hxx index 47777580d..0aa0e552e 100644 --- a/Scenery/scenery.hxx +++ b/Scenery/scenery.hxx @@ -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. * diff --git a/Scenery/tile.cxx b/Scenery/tile.cxx index 3ad353fb3..e22f91600 100644 --- a/Scenery/tile.cxx +++ b/Scenery/tile.cxx @@ -22,6 +22,10 @@ // (Log is kept at end of this file) +#include +#include +#include + #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 diff --git a/Scenery/tile.hxx b/Scenery/tile.hxx index e79a8dc82..535b9ff7c 100644 --- a/Scenery/tile.hxx +++ b/Scenery/tile.hxx @@ -53,6 +53,16 @@ using namespace std; #include #include +#include + + +// 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 diff --git a/Scenery/tilecache.cxx b/Scenery/tilecache.cxx index cf7e361f9..c870ca7a7 100644 --- a/Scenery/tilecache.cxx +++ b/Scenery/tilecache.cxx @@ -39,6 +39,7 @@ #include
#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. // diff --git a/Scenery/tilemgr.cxx b/Scenery/tilemgr.cxx index d4b5f85f0..252fd83c1 100644 --- a/Scenery/tilemgr.cxx +++ b/Scenery/tilemgr.cxx @@ -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