X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FObjects%2Fobj.cxx;h=a33178ae44783b18b51ce93a0cafa334d5e00983;hb=ab381e5c013292935c598dbe80bdd092bcbdd3ff;hp=eb400bb78ccd6067b287fd198b8a0b4eaf47204c;hpb=dec6e86f6ed39bf66678c9061e50a04c5ea068bf;p=flightgear.git diff --git a/src/Objects/obj.cxx b/src/Objects/obj.cxx index eb400bb78..a33178ae4 100644 --- a/src/Objects/obj.cxx +++ b/src/Objects/obj.cxx @@ -25,47 +25,40 @@ # include #endif -#ifdef FG_MATH_EXCEPTION_CLASH +#ifdef SG_MATH_EXCEPTION_CLASH # include #endif -#ifdef HAVE_WINDOWS_H -# include -#endif - #include #include -#include -#include -// #if defined ( __sun__ ) -// extern "C" void *memmove(void *, const void *, size_t); -// extern "C" void *memset(void *, int, size_t); -// #endif - -#include +#include +#include #include STL_STRING #include // STL #include // STL #include // isdigit() -#include -#include -#include -#include
-#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include
+#include
#include -#include "materialmgr.hxx" +#include "matlib.hxx" #include "obj.hxx" -FG_USING_STD(string); -FG_USING_STD(vector); +SG_USING_STD(string); +SG_USING_STD(vector); typedef vector < int > int_list; @@ -77,29 +70,10 @@ static double normals[FG_MAX_NODES][3]; static double tex_coords[FG_MAX_NODES*3][3]; -// given three points defining a triangle, calculate the normal -static void calc_normal(Point3D p1, Point3D p2, - Point3D p3, double normal[3]) -{ - double v1[3], v2[3]; - double temp; - - v1[0] = p2[0] - p1[0]; v1[1] = p2[1] - p1[1]; v1[2] = p2[2] - p1[2]; - v2[0] = p3[0] - p1[0]; v2[1] = p3[1] - p1[1]; v2[2] = p3[2] - p1[2]; - - MAT3cross_product(normal, v1, v2); - MAT3_NORMALIZE_VEC(normal,temp); - - // fgPrintf( FG_TERRAIN, FG_DEBUG, " Normal = %.2f %.2f %.2f\n", - // normal[0], normal[1], normal[2]); -} - - #define FG_TEX_CONSTANT 69.0 - // Calculate texture coordinates for a given point. -static Point3D calc_tex_coords(const Point3D& node, const Point3D& ref) { +static Point3D local_calc_tex_coords(const Point3D& node, const Point3D& ref) { Point3D cp; Point3D pp; // double tmplon, tmplat; @@ -111,14 +85,14 @@ static Point3D calc_tex_coords(const Point3D& node, const Point3D& ref) { node[1] + ref.y(), node[2] + ref.z() ); - pp = fgCartToPolar3d(cp); + pp = sgCartToPolar3d(cp); - // tmplon = pp.lon() * RAD_TO_DEG; - // tmplat = pp.lat() * RAD_TO_DEG; + // tmplon = pp.lon() * SGD_RADIANS_TO_DEGREES; + // tmplat = pp.lat() * SGD_RADIANS_TO_DEGREES; // cout << tmplon << " " << tmplat << endl; - pp.setx( fmod(RAD_TO_DEG * FG_TEX_CONSTANT * pp.x(), 11.0) ); - pp.sety( fmod(RAD_TO_DEG * FG_TEX_CONSTANT * pp.y(), 11.0) ); + pp.setx( fmod(SGD_RADIANS_TO_DEGREES * FG_TEX_CONSTANT * pp.x(), 11.0) ); + pp.sety( fmod(SGD_RADIANS_TO_DEGREES * FG_TEX_CONSTANT * pp.y(), 11.0) ); if ( pp.x() < 0.0 ) { pp.setx( pp.x() + 11.0 ); @@ -134,51 +108,269 @@ static Point3D calc_tex_coords(const Point3D& node, const Point3D& ref) { } -// Load a .obj file and build the GL fragment list -ssgBranch *fgObjLoad( const string& path, FGTileEntry *t) { - fgFRAGMENT fragment; +// Generate a generic ocean tile on the fly +ssgBranch *fgGenTile( const string& path, FGTileEntry *t) { + FGNewMat *newmat; + + ssgSimpleState *state = NULL; + + ssgBranch *tile = new ssgBranch () ; + if ( !tile ) { + SG_LOG( SG_TERRAIN, SG_ALERT, "fgGenTile(): NO MEMORY" ); + return NULL; + } + + tile -> setName ( (char *)path.c_str() ) ; + + double tex_width = 1000.0; + // double tex_height; + + // find Ocean material in the properties list + newmat = material_lib.find( "Ocean" ); + if ( newmat != NULL ) { + // set the texture width and height values for this + // material + tex_width = newmat->get_xsize(); + // tex_height = newmat->get_ysize(); + + // set ssgState + state = newmat->get_state(); + } else { + SG_LOG( SG_TERRAIN, SG_ALERT, + "Ack! unknown usemtl name = " << "Ocean" + << " in " << path ); + } + + // Calculate center point + SGBucket b = t->tile_bucket; + double clon = b.get_center_lon(); + double clat = b.get_center_lat(); + double height = b.get_height(); + double width = b.get_width(); + + Point3D center = sgGeodToCart(Point3D(clon*SGD_DEGREES_TO_RADIANS,clat*SGD_DEGREES_TO_RADIANS,0.0)); + t->center = center; + // cout << "center = " << center << endl;; + + // Caculate corner vertices + Point3D geod[4]; + geod[0] = Point3D( clon - width/2.0, clat - height/2.0, 0.0 ); + geod[1] = Point3D( clon + width/2.0, clat - height/2.0, 0.0 ); + geod[2] = Point3D( clon + width/2.0, clat + height/2.0, 0.0 ); + geod[3] = Point3D( clon - width/2.0, clat + height/2.0, 0.0 ); + + Point3D rad[4]; + int i; + for ( i = 0; i < 4; ++i ) { + rad[i] = Point3D( geod[i].x() * SGD_DEGREES_TO_RADIANS, + geod[i].y() * SGD_DEGREES_TO_RADIANS, + geod[i].z() ); + } + + Point3D cart[4], rel[4]; + t->nodes.clear(); + for ( i = 0; i < 4; ++i ) { + cart[i] = sgGeodToCart(rad[i]); + rel[i] = cart[i] - center; + t->nodes.push_back( rel[i] ); + // cout << "corner " << i << " = " << cart[i] << endl; + } + + t->ncount = 4; + + // Calculate bounding radius + t->bounding_radius = center.distance3D( cart[0] ); + // cout << "bounding radius = " << t->bounding_radius << endl; + + // Calculate normals + Point3D normals[4]; + for ( i = 0; i < 4; ++i ) { + double length = cart[i].distance3D( Point3D(0.0) ); + normals[i] = cart[i] / length; + // cout << "normal = " << normals[i] << endl; + } + + // Calculate texture coordinates + point_list geod_nodes; + geod_nodes.clear(); + int_list rectangle; + rectangle.clear(); + for ( i = 0; i < 4; ++i ) { + geod_nodes.push_back( geod[i] ); + rectangle.push_back( i ); + } + point_list texs = calc_tex_coords( b, geod_nodes, rectangle, + 1000.0 / tex_width ); + + // Allocate ssg structure + ssgVertexArray *vl = new ssgVertexArray( 4 ); + ssgNormalArray *nl = new ssgNormalArray( 4 ); + ssgTexCoordArray *tl = new ssgTexCoordArray( 4 ); + ssgColourArray *cl = new ssgColourArray( 1 ); + + sgVec4 color; + sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 ); + cl->add( color ); + + // sgVec3 *vtlist = new sgVec3 [ 4 ]; + // t->vec3_ptrs.push_back( vtlist ); + // sgVec3 *vnlist = new sgVec3 [ 4 ]; + // t->vec3_ptrs.push_back( vnlist ); + // sgVec2 *tclist = new sgVec2 [ 4 ]; + // t->vec2_ptrs.push_back( tclist ); + + sgVec2 tmp2; + sgVec3 tmp3; + for ( i = 0; i < 4; ++i ) { + sgSetVec3( tmp3, + rel[i].x(), rel[i].y(), rel[i].z() ); + vl->add( tmp3 ); + + sgSetVec3( tmp3, + normals[i].x(), normals[i].y(), normals[i].z() ); + nl->add( tmp3 ); + + sgSetVec2( tmp2, texs[i].x(), texs[i].y()); + tl->add( tmp2 ); + } + + ssgLeaf *leaf = + new ssgVtxTable ( GL_TRIANGLE_FAN, vl, nl, tl, cl ); + + leaf->setState( state ); + + tile->addKid( leaf ); + + return tile; +} + + +static void random_pt_inside_tri( float *res, + float *n1, float *n2, float *n3 ) +{ + sgVec3 p1, p2, p3; + + double a = sg_random(); + double b = sg_random(); + if ( a + b > 1.0 ) { + a = 1.0 - a; + b = 1.0 - b; + } + double c = 1 - a - b; + + sgScaleVec3( p1, n1, a ); + sgScaleVec3( p2, n2, b ); + sgScaleVec3( p3, n3, c ); + + sgAddVec3( res, p1, p2 ); + sgAddVec3( res, p3 ); +} + + +static void gen_random_surface_points( ssgLeaf *leaf, ssgVertexArray *lights, + double factor ) { + int num = leaf->getNumTriangles(); + if ( num > 0 ) { + short int n1, n2, n3; + float *p1, *p2, *p3; + sgVec3 result; + + // generate a repeatable random seed + p1 = leaf->getVertex( 0 ); + unsigned int seed = (unsigned int)p1[0]; + sg_srandom( seed ); + + for ( int i = 0; i < num; ++i ) { + leaf->getTriangle( i, &n1, &n2, &n3 ); + p1 = leaf->getVertex(n1); + p2 = leaf->getVertex(n2); + p3 = leaf->getVertex(n3); + double area = sgTriArea( p1, p2, p3 ); + double num = area / factor; + + // generate a light point for each unit of area + while ( num > 1.0 ) { + random_pt_inside_tri( result, p1, p2, p3 ); + lights->add( result ); + num -= 1.0; + } + // for partial units of area, use a zombie door method to + // create the proper random chance of a light being created + // for this triangle + if ( num > 0.0 ) { + if ( sg_random() <= num ) { + // a zombie made it through our door + random_pt_inside_tri( result, p1, p2, p3 ); + lights->add( result ); + } + } + } + } +} + + +// Load an Ascii obj file +ssgBranch *fgAsciiObjLoad( const string& path, FGTileEntry *t, + ssgVertexArray *lights, const bool is_base) +{ + FGNewMat *newmat = NULL; + string material; + float coverage = -1; Point3D pp; - double approx_normal[3], normal[3] /*, scale = 0.0 */; + // sgVec3 approx_normal; + // double normal[3], scale = 0.0; // double x, y, z, xmax, xmin, ymax, ymin, zmax, zmin; // GLfloat sgenparams[] = { 1.0, 0.0, 0.0, 0.0 }; - GLint display_list = 0; + // GLint display_list = 0; int shading; - bool in_fragment = false, in_faces = false; + bool in_faces = false; int vncount, vtcount; - int n1 = 0, n2 = 0, n3 = 0, n4 = 0; + int n1 = 0, n2 = 0, n3 = 0; int tex; - int last1 = 0, last2 = 0, odd = 0; + // int last1 = 0, last2 = 0; + bool odd = false; point_list nodes; Point3D node; Point3D center; + double scenery_version = 0.0; double tex_width = 1000.0, tex_height = 1000.0; bool shared_done = false; int_list fan_vertices; int_list fan_tex_coords; int i; ssgSimpleState *state = NULL; + sgVec3 *vtlist, *vnlist; + sgVec2 *tclist; ssgBranch *tile = new ssgBranch () ; - tile -> setName ( path.c_str() ) ; + + tile -> setName ( (char *)path.c_str() ) ; // Attempt to open "path.gz" or "path" - fg_gzifstream in( path ); + sg_gzifstream in( path ); if ( ! in.is_open() ) { - FG_LOG( FG_TERRAIN, FG_ALERT, "Cannot open file: " << path ); + SG_LOG( SG_TERRAIN, SG_DEBUG, "Cannot open file: " << path ); + SG_LOG( SG_TERRAIN, SG_DEBUG, "default to ocean tile: " << path ); + + delete tile; + return NULL; } - shading = current_options.get_shading(); + shading = fgGetBool("/sim/rendering/shading"); - in_fragment = false; - t->ncount = 0; + if ( is_base ) { + t->ncount = 0; + } vncount = 0; vtcount = 0; - t->bounding_radius = 0.0; + if ( is_base ) { + t->bounding_radius = 0.0; + } center = t->center; - StopWatch stopwatch; - stopwatch.start(); + // StopWatch stopwatch; + // stopwatch.start(); // ignore initial comments and blank lines. (priming the pump) // in >> skipcomment; @@ -194,11 +386,7 @@ ssgBranch *fgObjLoad( const string& path, FGTileEntry *t) { while ( ! in.eof() ) { #endif -#if defined( MACOS ) in >> ::skipws; -#else - in >> skipws; -#endif if ( in.get( c ) && c == '#' ) { // process a comment line @@ -208,19 +396,38 @@ ssgBranch *fgObjLoad( const string& path, FGTileEntry *t) { in >> token; - if ( token == "gbs" ) { + if ( token == "Version" ) { + // read scenery versions number + in >> scenery_version; + // cout << "scenery_version = " << scenery_version << endl; + if ( scenery_version > 0.4 ) { + SG_LOG( SG_TERRAIN, SG_ALERT, + "\nYou are attempting to load a tile format that\n" + << "is newer than this version of flightgear can\n" + << "handle. You should upgrade your copy of\n" + << "FlightGear to the newest version. For\n" + << "details, please see:\n" + << "\n http://www.flightgear.org\n" ); + exit(-1); + } + } else if ( token == "gbs" ) { // reference point (center offset) - in >> t->center >> t->bounding_radius; + if ( is_base ) { + in >> t->center >> t->bounding_radius; + } else { + Point3D junk1; + double junk2; + in >> junk1 >> junk2; + } center = t->center; // cout << "center = " << center // << " radius = " << t->bounding_radius << endl; } else if ( token == "bs" ) { // reference point (center offset) - in >> fragment.center; - in >> fragment.bounding_radius; - - // cout << "center = " << fragment.center - // << " radius = " << fragment.bounding_radius << endl; + // (skip past this) + Point3D junk1; + double junk2; + in >> junk1 >> junk2; } else if ( token == "usemtl" ) { // material property specification @@ -228,97 +435,88 @@ ssgBranch *fgObjLoad( const string& path, FGTileEntry *t) { // shared_done true and build the ssg shared lists if ( ! shared_done ) { // sanity check - if ( nodes.size() != vncount ) { - FG_LOG( FG_TERRAIN, FG_ALERT, - "Tile has mismatched nodes and normals: " + if ( (int)nodes.size() != vncount ) { + SG_LOG( SG_TERRAIN, SG_ALERT, + "Tile has mismatched nodes = " << nodes.size() + << " and normals = " << vncount << " : " << path ); // exit(-1); } shared_done = true; - t->vtlist = new sgVec3 [ nodes.size() ]; - t->vnlist = new sgVec3 [ vncount ]; - t->tclist = new sgVec2 [ vtcount ]; + vtlist = new sgVec3 [ nodes.size() ]; + t->vec3_ptrs.push_back( vtlist ); + vnlist = new sgVec3 [ vncount ]; + t->vec3_ptrs.push_back( vnlist ); + tclist = new sgVec2 [ vtcount ]; + t->vec2_ptrs.push_back( tclist ); for ( i = 0; i < (int)nodes.size(); ++i ) { - sgSetVec3( t->vtlist[i], + sgSetVec3( vtlist[i], nodes[i][0], nodes[i][1], nodes[i][2] ); } for ( i = 0; i < vncount; ++i ) { - sgSetVec3( t->vnlist[i], + sgSetVec3( vnlist[i], normals[i][0], normals[i][1], normals[i][2] ); } for ( i = 0; i < vtcount; ++i ) { - sgSetVec2( t->tclist[i], - tex_coords[i][0], tex_coords[i][1] ); + sgSetVec2( tclist[i], + tex_coords[i][0], + tex_coords[i][1] ); } } - // series of individual triangles - if ( in_faces ) { - xglEnd(); - } - - // this also signals the start of a new fragment - if ( in_fragment ) { - // close out the previous structure and start the next - xglEndList(); - // printf("xglEnd(); xglEndList();\n"); - - // update fragment - fragment.display_list = display_list; - - // push this fragment onto the tile's object list - t->fragment_list.push_back(fragment); - } else { - in_fragment = true; - } - - // printf("start of fragment (usemtl)\n"); - - display_list = xglGenLists(1); - xglNewList(display_list, GL_COMPILE); + // display_list = xglGenLists(1); + // xglNewList(display_list, GL_COMPILE); // printf("xglGenLists(); xglNewList();\n"); in_faces = false; - // reset the existing face list - // printf("cleaning a fragment with %d faces\n", - // fragment.faces.size()); - fragment.init(); - // scan the material line - string material; in >> material; - fragment.tile_ptr = t; // find this material in the properties list - if ( ! material_mgr.find( material, fragment.material_ptr )) { - FG_LOG( FG_TERRAIN, FG_ALERT, - "Ack! unknown usemtl name = " << material - << " in " << path ); + + newmat = material_lib.find( material ); + if ( newmat == NULL ) { + // see if this is an on the fly texture + string file = path; + int pos = file.rfind( "/" ); + file = file.substr( 0, pos ); + cout << "current file = " << file << endl; + file += "/"; + file += material; + cout << "current file = " << file << endl; + if ( ! material_lib.add_item( file ) ) { + SG_LOG( SG_TERRAIN, SG_ALERT, + "Ack! unknown usemtl name = " << material + << " in " << path ); + } else { + // locate our newly created material + newmat = material_lib.find( material ); + if ( newmat == NULL ) { + SG_LOG( SG_TERRAIN, SG_ALERT, + "Ack! bad on the fly materia create = " + << material << " in " << path ); + } + } } - // set the texture width and height values for this - // material - FGMaterial m = fragment.material_ptr->get_m(); - tex_width = m.get_xsize(); - tex_height = m.get_ysize(); - state = fragment.material_ptr->get_state(); - // cout << "(w) = " << tex_width << " (h) = " - // << tex_width << endl; - - // initialize the fragment transformation matrix - /* - for ( i = 0; i < 16; i++ ) { - fragment.matrix[i] = 0.0; - } - fragment.matrix[0] = fragment.matrix[5] = - fragment.matrix[10] = fragment.matrix[15] = 1.0; - */ + if ( newmat != NULL ) { + // set the texture width and height values for this + // material + tex_width = newmat->get_xsize(); + tex_height = newmat->get_ysize(); + state = newmat->get_state(); + coverage = newmat->get_light_coverage(); + // cout << "(w) = " << tex_width << " (h) = " + // << tex_width << endl; + } else { + coverage = -1; + } } else { - // unknown comment, just gobble the input untill the + // unknown comment, just gobble the input until the // end of line in >> skipeol; @@ -338,7 +536,7 @@ ssgBranch *fgObjLoad( const string& path, FGTileEntry *t) { >> normals[vncount][2]; vncount++; } else { - FG_LOG( FG_TERRAIN, FG_ALERT, + SG_LOG( SG_TERRAIN, SG_ALERT, "Read too many vertex normals in " << path << " ... dying :-(" ); exit(-1); @@ -350,7 +548,7 @@ ssgBranch *fgObjLoad( const string& path, FGTileEntry *t) { >> tex_coords[vtcount][1]; vtcount++; } else { - FG_LOG( FG_TERRAIN, FG_ALERT, + SG_LOG( SG_TERRAIN, SG_ALERT, "Read too many vertex texture coords in " << path << " ... dying :-(" ); @@ -364,163 +562,74 @@ ssgBranch *fgObjLoad( const string& path, FGTileEntry *t) { >> nodes[t->ncount][2]; */ in >> node; nodes.push_back(node); - t->ncount++; + if ( is_base ) { + t->ncount++; + } } else { - FG_LOG( FG_TERRAIN, FG_ALERT, + SG_LOG( SG_TERRAIN, SG_ALERT, "Read too many nodes in " << path << " ... dying :-("); exit(-1); } - } else if ( token == "t" ) { - // start a new triangle strip - - n1 = n2 = n3 = n4 = 0; - - // fgPrintf( FG_TERRAIN, FG_DEBUG, - // " new tri strip = %s", line); - in >> n1 >> n2 >> n3; - fragment.add_face(n1, n2, n3); - - // fgPrintf( FG_TERRAIN, FG_DEBUG, "(t) = "); - - xglBegin(GL_TRIANGLE_STRIP); - // printf("xglBegin(tristrip) %d %d %d\n", n1, n2, n3); - - odd = 1; - // scale = 1.0; - - if ( shading ) { - // Shading model is "GL_SMOOTH" so use precalculated - // (averaged) normals - // MAT3_SCALE_VEC(normal, normals[n1], scale); - xglNormal3dv(normal); - pp = calc_tex_coords(nodes[n1], center); - xglTexCoord2f(pp.lon(), pp.lat()); - xglVertex3dv(nodes[n1].get_n()); - - // MAT3_SCALE_VEC(normal, normals[n2], scale); - xglNormal3dv(normal); - pp = calc_tex_coords(nodes[n2], center); - xglTexCoord2f(pp.lon(), pp.lat()); - xglVertex3dv(nodes[n2].get_n()); - - // MAT3_SCALE_VEC(normal, normals[n3], scale); - xglNormal3dv(normal); - pp = calc_tex_coords(nodes[n3], center); - xglTexCoord2f(pp.lon(), pp.lat()); - xglVertex3dv(nodes[n3].get_n()); - } 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); - } else { - calc_normal(nodes[n2], nodes[n1], - nodes[n3], approx_normal); - } - // MAT3_SCALE_VEC(normal, approx_normal, scale); - xglNormal3dv(normal); - - pp = calc_tex_coords(nodes[n1], center); - xglTexCoord2f(pp.lon(), pp.lat()); - xglVertex3dv(nodes[n1].get_n()); - - pp = calc_tex_coords(nodes[n2], center); - xglTexCoord2f(pp.lon(), pp.lat()); - xglVertex3dv(nodes[n2].get_n()); - - pp = calc_tex_coords(nodes[n3], center); - xglTexCoord2f(pp.lon(), pp.lat()); - xglVertex3dv(nodes[n3].get_n()); - } - // printf("some normals, texcoords, and vertices\n"); - - odd = 1 - odd; - last1 = n2; - last2 = n3; - - // There can be three or four values - char c; - while ( in.get(c) ) { - if ( c == '\n' ) { - break; // only the one - } - if ( isdigit(c) ){ - in.putback(c); - in >> n4; - break; - } - } - - if ( n4 > 0 ) { - fragment.add_face(n3, n2, n4); - - if ( 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); - // MAT3_SCALE_VEC(normal, approx_normal, scale); - } - xglNormal3dv(normal); - pp = calc_tex_coords(nodes[n4], center); - xglTexCoord2f(pp.lon(), pp.lat()); - xglVertex3dv(nodes[n4].get_n()); - - odd = 1 - odd; - last1 = n3; - last2 = n4; - // printf("a normal, texcoord, and vertex (4th)\n"); - } - } else if ( token == "tf" ) { - // triangle fan - // fgPrintf( FG_TERRAIN, FG_DEBUG, "new fan"); + } else if ( (token == "tf") || (token == "ts") || (token == "f") ) { + // triangle fan, strip, or individual face + // SG_LOG( SG_TERRAIN, SG_INFO, "new fan or strip"); fan_vertices.clear(); fan_tex_coords.clear(); + odd = true; - xglBegin(GL_TRIANGLE_FAN); + // xglBegin(GL_TRIANGLE_FAN); in >> n1; fan_vertices.push_back( n1 ); - xglNormal3dv(normals[n1]); + // xglNormal3dv(normals[n1]); if ( in.get( c ) && c == '/' ) { in >> tex; fan_tex_coords.push_back( tex ); + if ( scenery_version >= 0.4 ) { + if ( tex_width > 0 ) { + tclist[tex][0] *= (1000.0 / tex_width); + } + if ( tex_height > 0 ) { + tclist[tex][1] *= (1000.0 / tex_height); + } + } pp.setx( tex_coords[tex][0] * (1000.0 / tex_width) ); pp.sety( tex_coords[tex][1] * (1000.0 / tex_height) ); } else { in.putback( c ); - pp = calc_tex_coords(nodes[n1], center); + pp = local_calc_tex_coords(nodes[n1], center); } - xglTexCoord2f(pp.x(), pp.y()); - xglVertex3dv(nodes[n1].get_n()); + // xglTexCoord2f(pp.x(), pp.y()); + // xglVertex3dv(nodes[n1].get_n()); in >> n2; fan_vertices.push_back( n2 ); - xglNormal3dv(normals[n2]); + // xglNormal3dv(normals[n2]); if ( in.get( c ) && c == '/' ) { in >> tex; fan_tex_coords.push_back( tex ); + if ( scenery_version >= 0.4 ) { + if ( tex_width > 0 ) { + tclist[tex][0] *= (1000.0 / tex_width); + } + if ( tex_height > 0 ) { + tclist[tex][1] *= (1000.0 / tex_height); + } + } pp.setx( tex_coords[tex][0] * (1000.0 / tex_width) ); pp.sety( tex_coords[tex][1] * (1000.0 / tex_height) ); } else { in.putback( c ); - pp = calc_tex_coords(nodes[n2], center); + pp = local_calc_tex_coords(nodes[n2], center); } - xglTexCoord2f(pp.x(), pp.y()); - xglVertex3dv(nodes[n2].get_n()); + // xglTexCoord2f(pp.x(), pp.y()); + // xglVertex3dv(nodes[n2].get_n()); // read all subsequent numbers until next thing isn't a number while ( true ) { -#if defined( MACOS ) in >> ::skipws; -#else - in >> skipws; -#endif char c; in.get(c); @@ -534,214 +643,365 @@ ssgBranch *fgObjLoad( const string& path, FGTileEntry *t) { // cout << " triangle = " // << n1 << "," << n2 << "," << n3 // << endl; - xglNormal3dv(normals[n3]); + // xglNormal3dv(normals[n3]); if ( in.get( c ) && c == '/' ) { in >> tex; fan_tex_coords.push_back( tex ); + if ( scenery_version >= 0.4 ) { + if ( tex_width > 0 ) { + tclist[tex][0] *= (1000.0 / tex_width); + } + if ( tex_height > 0 ) { + tclist[tex][1] *= (1000.0 / tex_height); + } + } pp.setx( tex_coords[tex][0] * (1000.0 / tex_width) ); pp.sety( tex_coords[tex][1] * (1000.0 / tex_height) ); } else { in.putback( c ); - pp = calc_tex_coords(nodes[n3], center); + pp = local_calc_tex_coords(nodes[n3], center); } - xglTexCoord2f(pp.x(), pp.y()); - xglVertex3dv(nodes[n3].get_n()); + // xglTexCoord2f(pp.x(), pp.y()); + // xglVertex3dv(nodes[n3].get_n()); - fragment.add_face(n1, n2, n3); - n2 = n3; + if ( (token == "tf") || (token == "f") ) { + // triangle fan + n2 = n3; + } else { + // triangle strip + odd = !odd; + n1 = n2; + n2 = n3; + } } - xglEnd(); + // xglEnd(); // build the ssg entity - unsigned short *vindex = - new unsigned short [ fan_vertices.size() ]; - unsigned short *tindex = - new unsigned short [ fan_tex_coords.size() ]; - for ( i = 0; i < (int)fan_vertices.size(); ++i ) { - vindex[i] = fan_vertices[i]; + int size = (int)fan_vertices.size(); + ssgVertexArray *vl = new ssgVertexArray( size ); + ssgNormalArray *nl = new ssgNormalArray( size ); + ssgTexCoordArray *tl = new ssgTexCoordArray( size ); + ssgColourArray *cl = new ssgColourArray( 1 ); + + sgVec4 color; + sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 ); + cl->add( color ); + + sgVec2 tmp2; + sgVec3 tmp3; + for ( i = 0; i < size; ++i ) { + sgCopyVec3( tmp3, vtlist[ fan_vertices[i] ] ); + vl -> add( tmp3 ); + + sgCopyVec3( tmp3, vnlist[ fan_vertices[i] ] ); + nl -> add( tmp3 ); + + sgCopyVec2( tmp2, tclist[ fan_tex_coords[i] ] ); + tl -> add( tmp2 ); } - for ( i = 0; i < (int)fan_tex_coords.size(); ++i ) { - tindex[i] = fan_tex_coords[i]; + + ssgLeaf *leaf = NULL; + if ( token == "tf" ) { + // triangle fan + leaf = + new ssgVtxTable ( GL_TRIANGLE_FAN, vl, nl, tl, cl ); + } else if ( token == "ts" ) { + // triangle strip + leaf = + new ssgVtxTable ( GL_TRIANGLE_STRIP, vl, nl, tl, cl ); + } else if ( token == "f" ) { + // triangle + leaf = + new ssgVtxTable ( GL_TRIANGLES, vl, nl, tl, cl ); } - ssgLeaf *leaf = - new ssgVTable ( GL_TRIANGLE_FAN, - fan_vertices.size(), vindex, t->vtlist, - fan_vertices.size(), vindex, t->vnlist, - fan_tex_coords.size(), tindex, t->tclist, - 0, NULL, NULL ) ; + // leaf->makeDList(); leaf->setState( state ); tile->addKid( leaf ); - } else if ( token == "f" ) { - // unoptimized face - - if ( !in_faces ) { - xglBegin(GL_TRIANGLES); - // printf("xglBegin(triangles)\n"); - in_faces = true; + if ( is_base ) { + if ( coverage > 0.0 ) { + if ( coverage < 10000.0 ) { + SG_LOG(SG_INPUT, SG_ALERT, "Light coverage is " + << coverage << ", pushing up to 10000"); + coverage = 10000; + } + gen_random_surface_points(leaf, lights, coverage); + } } + } else { + SG_LOG( SG_TERRAIN, SG_WARN, "Unknown token in " + << path << " = " << token ); + } - // fgPrintf( FG_TERRAIN, FG_DEBUG, "new triangle = %s", line);*/ - in >> n1 >> n2 >> n3; - fragment.add_face(n1, n2, n3); + // eat white space before start of while loop so if we are + // done with useful input it is noticed before hand. + in >> ::skipws; + } + } - // xglNormal3d(normals[n1][0], normals[n1][1], normals[n1][2]); - xglNormal3dv(normals[n1]); - pp = calc_tex_coords(nodes[n1], center); - xglTexCoord2f(pp.lon(), pp.lat()); - xglVertex3dv(nodes[n1].get_n()); + if ( is_base ) { + t->nodes = nodes; + } - xglNormal3dv(normals[n2]); - pp = calc_tex_coords(nodes[n2], center); - xglTexCoord2f(pp.lon(), pp.lat()); - xglVertex3dv(nodes[n2].get_n()); - - xglNormal3dv(normals[n3]); - pp = calc_tex_coords(nodes[n3], center); - xglTexCoord2f(pp.lon(), pp.lat()); - xglVertex3dv(nodes[n3].get_n()); - // printf("some normals, texcoords, and vertices (tris)\n"); - } else if ( token == "q" ) { - // continue a triangle strip - n1 = n2 = 0; - - // fgPrintf( FG_TERRAIN, FG_DEBUG, "continued tri strip = %s ", - // line); - in >> n1; + // stopwatch.stop(); + // SG_LOG( SG_TERRAIN, SG_DEBUG, + // "Loaded " << path << " in " + // << stopwatch.elapsedSeconds() << " seconds" ); - // There can be one or two values - char c; - while ( in.get(c) ) { - if ( c == '\n' ) { - break; // only the one - } + return tile; +} - if ( isdigit(c) ) { - in.putback(c); - in >> n2; - break; - } - } - // 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); - } +ssgLeaf *gen_leaf( const string& path, + const GLenum ty, const string& material, + const point_list& nodes, const point_list& normals, + const point_list& texcoords, + const int_list node_index, + const int_list& tex_index, + const bool calc_lights, ssgVertexArray *lights ) +{ + double tex_width = 1000.0, tex_height = 1000.0; + ssgSimpleState *state = NULL; + float coverage = -1; + + FGNewMat *newmat = material_lib.find( material ); + if ( newmat == NULL ) { + // see if this is an on the fly texture + string file = path; + int pos = file.rfind( "/" ); + file = file.substr( 0, pos ); + cout << "current file = " << file << endl; + file += "/"; + file += material; + cout << "current file = " << file << endl; + if ( ! material_lib.add_item( file ) ) { + SG_LOG( SG_TERRAIN, SG_ALERT, + "Ack! unknown usemtl name = " << material + << " in " << path ); + } else { + // locate our newly created material + newmat = material_lib.find( material ); + if ( newmat == NULL ) { + SG_LOG( SG_TERRAIN, SG_ALERT, + "Ack! bad on the fly material create = " + << material << " in " << path ); + } + } + } - if ( shading ) { - // Shading model is "GL_SMOOTH" - // MAT3_SCALE_VEC(normal, normals[n1], scale); - } else { - // Shading model is "GL_FLAT" - if ( odd ) { - calc_normal(nodes[last1], nodes[last2], - nodes[n1], approx_normal); - } else { - calc_normal(nodes[last2], nodes[last1], - nodes[n1], approx_normal); - } - // MAT3_SCALE_VEC(normal, approx_normal, scale); - } - xglNormal3dv(normal); + if ( newmat != NULL ) { + // set the texture width and height values for this + // material + tex_width = newmat->get_xsize(); + tex_height = newmat->get_ysize(); + state = newmat->get_state(); + coverage = newmat->get_light_coverage(); + // cout << "(w) = " << tex_width << " (h) = " + // << tex_width << endl; + } else { + coverage = -1; + } - pp = calc_tex_coords(nodes[n1], center); - xglTexCoord2f(pp.lon(), pp.lat()); - xglVertex3dv(nodes[n1].get_n()); - // printf("a normal, texcoord, and vertex (4th)\n"); - - odd = 1 - odd; - last1 = last2; - last2 = n1; + // cout << "before list allocs" << endl; - if ( n2 > 0 ) { - // fgPrintf( FG_TERRAIN, FG_DEBUG, " (cont)\n"); + // cout << "before vl, size = " << size << endl; + // cout << "before nl" << endl; + // cout << "before tl" << endl; + // cout << "before cl" << endl; - if ( odd ) { - fragment.add_face(last1, last2, n2); - } else { - fragment.add_face(last2, last1, n2); - } + sgVec2 tmp2; + sgVec3 tmp3; + sgVec4 tmp4; + int i; - if ( shading ) { - // Shading model is "GL_SMOOTH" - // MAT3_SCALE_VEC(normal, normals[n2], scale); - } else { - // Shading model is "GL_FLAT" - if ( odd ) { - calc_normal(nodes[last1], nodes[last2], - nodes[n2], approx_normal); - } else { - calc_normal(nodes[last2], nodes[last1], - nodes[n2], approx_normal); - } - // MAT3_SCALE_VEC(normal, approx_normal, scale); - } - xglNormal3dv(normal); - - pp = calc_tex_coords(nodes[n2], center); - xglTexCoord2f(pp.lon(), pp.lat()); - xglVertex3dv(nodes[n2].get_n()); - // printf("a normal, texcoord, and vertex (4th)\n"); - - odd = 1 -odd; - last1 = last2; - last2 = n2; - } - } else { - FG_LOG( FG_TERRAIN, FG_WARN, "Unknown token in " - << path << " = " << token ); - } + // vertices + int size = node_index.size(); + if ( size < 1 ) { + SG_LOG( SG_TERRAIN, SG_ALERT, "Woh! node list size < 1" ); + exit(-1); + } + ssgVertexArray *vl = new ssgVertexArray( size ); + Point3D node; + for ( i = 0; i < size; ++i ) { + node = nodes[ node_index[i] ]; + sgSetVec3( tmp3, node[0], node[1], node[2] ); + vl -> add( tmp3 ); + } - // eat white space before start of while loop so if we are - // done with useful input it is noticed before hand. -#if defined( MACOS ) - in >> ::skipws; -#else - in >> skipws; -#endif - } + // colors + ssgColourArray *cl = new ssgColourArray( 1 ); + sgSetVec4( tmp4, 1.0, 1.0, 1.0, 1.0 ); + cl->add( tmp4 ); + + // normals + Point3D normal; + ssgNormalArray *nl = new ssgNormalArray( size ); + if ( normals.size() == 1 ) { + normal = normals[ 0 ]; + sgSetVec3( tmp3, normal[0], normal[1], normal[2] ); + nl -> add( tmp3 ); + } else if ( normals.size() > 1 ) { + for ( i = 0; i < size; ++i ) { + normal = normals[ node_index[i] ]; + sgSetVec3( tmp3, normal[0], normal[1], normal[2] ); + nl -> add( tmp3 ); + } } - if ( in_fragment ) { - // close out the previous structure and start the next - xglEnd(); - xglEndList(); - // printf("xglEnd(); xglEndList();\n"); - - // update fragment - fragment.display_list = display_list; - - // push this fragment onto the tile's object list - t->fragment_list.push_back(fragment); + // texture coordinates + size = tex_index.size(); + Point3D texcoord; + ssgTexCoordArray *tl = new ssgTexCoordArray( size ); + if ( size == 1 ) { + texcoord = texcoords[ tex_index[0] ]; + sgSetVec2( tmp2, texcoord[0], texcoord[1] ); + sgSetVec2( tmp2, texcoord[0], texcoord[1] ); + if ( tex_width > 0 ) { + tmp2[0] *= (1000.0 / tex_width); + } + if ( tex_height > 0 ) { + tmp2[1] *= (1000.0 / tex_height); + } + tl -> add( tmp2 ); + } else if ( size > 1 ) { + for ( i = 0; i < size; ++i ) { + texcoord = texcoords[ tex_index[i] ]; + sgSetVec2( tmp2, texcoord[0], texcoord[1] ); + if ( tex_width > 0 ) { + tmp2[0] *= (1000.0 / tex_width); + } + if ( tex_height > 0 ) { + tmp2[1] *= (1000.0 / tex_height); + } + tl -> add( tmp2 ); + } } -#if 0 - // Draw normal vectors (for visually verifying normals) - xglBegin(GL_LINES); - xglColor3f(0.0, 0.0, 0.0); - for ( i = 0; i < t->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]); - } - xglEnd(); -#endif + // cout << "before leaf create" << endl; + ssgLeaf *leaf = new ssgVtxTable ( ty, vl, nl, tl, cl ); + // cout << "after leaf create" << endl; - t->nodes = nodes; + // lookup the state record + // cout << "looking up material = " << endl; + // cout << material << endl; + // cout << "'" << endl; - stopwatch.stop(); - FG_LOG( FG_TERRAIN, FG_INFO, - "Loaded " << path << " in " - << stopwatch.elapsedSeconds() << " seconds" ); - - return tile; + leaf->setState( state ); + + if ( calc_lights ) { + if ( coverage > 0.0 ) { + if ( coverage < 10000.0 ) { + SG_LOG(SG_INPUT, SG_ALERT, "Light coverage is " + << coverage << ", pushing up to 10000"); + coverage = 10000; + } + gen_random_surface_points(leaf, lights, coverage); + } + } + + return leaf; } +// Load an Binary obj file +ssgBranch *fgBinObjLoad( const string& path, FGTileEntry *t, + ssgVertexArray *lights, const bool is_base) +{ + int i; + + SGBinObject obj; + bool result = obj.read_bin( path ); + + if ( !result ) { + return NULL; + } + + // cout << "fans size = " << obj.get_fans_v().size() + // << " fan_mats size = " << obj.get_fan_materials().size() << endl; + + ssgBranch *object = new ssgBranch(); + object->setName( (char *)path.c_str() ); + + if ( is_base && t != NULL ) { + // reference point (center offset/bounding sphere) + t->center = obj.get_gbs_center(); + t->bounding_radius = obj.get_gbs_radius(); + } + + point_list nodes = obj.get_wgs84_nodes(); + point_list colors = obj.get_colors(); + point_list normals = obj.get_normals(); + point_list texcoords = obj.get_texcoords(); + + string material; + int_list vertex_index; + int_list tex_index; + + // generate points + string_list pt_materials = obj.get_pt_materials(); + group_list pts_v = obj.get_pts_v(); + for ( i = 0; i < (int)pts_v.size(); ++i ) { + cout << "pts_v.size() = " << pts_v.size() << endl; + material = pt_materials[i]; + vertex_index = pts_v[i]; + tex_index.clear(); + ssgLeaf *leaf = gen_leaf( path, GL_POINTS, material, + nodes, normals, texcoords, + vertex_index, tex_index, + false, lights ); + + object->addKid( leaf ); + } + + // generate triangles + string_list tri_materials = obj.get_tri_materials(); + group_list tris_v = obj.get_tris_v(); + group_list tris_tc = obj.get_tris_tc(); + for ( i = 0; i < (int)tris_v.size(); ++i ) { + material = tri_materials[i]; + vertex_index = tris_v[i]; + tex_index = tris_tc[i]; + ssgLeaf *leaf = gen_leaf( path, GL_TRIANGLES, material, + nodes, normals, texcoords, + vertex_index, tex_index, + is_base, lights ); + + object->addKid( leaf ); + } + + // generate strips + string_list strip_materials = obj.get_strip_materials(); + group_list strips_v = obj.get_strips_v(); + group_list strips_tc = obj.get_strips_tc(); + for ( i = 0; i < (int)strips_v.size(); ++i ) { + material = strip_materials[i]; + vertex_index = strips_v[i]; + tex_index = strips_tc[i]; + ssgLeaf *leaf = gen_leaf( path, GL_TRIANGLE_STRIP, material, + nodes, normals, texcoords, + vertex_index, tex_index, + is_base, lights ); + + object->addKid( leaf ); + } + + // generate fans + string_list fan_materials = obj.get_fan_materials(); + group_list fans_v = obj.get_fans_v(); + group_list fans_tc = obj.get_fans_tc(); + for ( i = 0; i < (int)fans_v.size(); ++i ) { + material = fan_materials[i]; + vertex_index = fans_v[i]; + tex_index = fans_tc[i]; + ssgLeaf *leaf = gen_leaf( path, GL_TRIANGLE_FAN, material, + nodes, normals, texcoords, + vertex_index, tex_index, + is_base, lights ); + + object->addKid( leaf ); + } + + return object; +}