X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FObjects%2Fobj.cxx;h=4fb53463cdad10dd8d44140f64250677406f6e67;hb=b4a9d7621597c9eef97f8ec84d246d5585b4b7ea;hp=001c55fb67431c94310771554ec0b15e762a418e;hpb=84440e9b5e46c2678d79f13499667e969427e452;p=flightgear.git diff --git a/src/Objects/obj.cxx b/src/Objects/obj.cxx index 001c55fb6..4fb53463c 100644 --- a/src/Objects/obj.cxx +++ b/src/Objects/obj.cxx @@ -25,19 +25,15 @@ # include #endif -#ifdef FG_MATH_EXCEPTION_CLASH +#ifdef SG_MATH_EXCEPTION_CLASH # include #endif #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 STL_STRING #include // STL @@ -50,18 +46,19 @@ #include #include #include -#include +#include #include #include #include
+#include
#include #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; @@ -73,25 +70,6 @@ static double normals[FG_MAX_NODES][3]; static double tex_coords[FG_MAX_NODES*3][3]; -#if 0 -// given three points defining a triangle, calculate the normal -static void calc_normal(Point3D p1, Point3D p2, - Point3D p3, sgVec3 normal) -{ - sgVec3 v1, v2; - - 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]; - - sgVectorProductVec3( normal, v1, v2 ); - sgNormalizeVec3( normal ); - - // fgPrintf( FG_TERRAIN, FG_DEBUG, " Normal = %.2f %.2f %.2f\n", - // normal[0], normal[1], normal[2]); -} -#endif - - #define FG_TEX_CONSTANT 69.0 // Calculate texture coordinates for a given point. @@ -109,12 +87,12 @@ static Point3D local_calc_tex_coords(const Point3D& node, const Point3D& ref) { 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 ); @@ -153,19 +131,19 @@ ssgBranch *fgGenTile( const string& path, FGTileEntry *t) { // set ssgState state = newmat->get_state(); } else { - FG_LOG( FG_TERRAIN, FG_ALERT, + SG_LOG( SG_TERRAIN, SG_ALERT, "Ack! unknown usemtl name = " << "Ocean" << " in " << path ); } // Calculate center point - FGBucket b = t->tile_bucket; + 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*DEG_TO_RAD,clat*DEG_TO_RAD,0.0)); + Point3D center = sgGeodToCart(Point3D(clon*SGD_DEGREES_TO_RADIANS,clat*SGD_DEGREES_TO_RADIANS,0.0)); t->center = center; // cout << "center = " << center << endl;; @@ -179,7 +157,7 @@ ssgBranch *fgGenTile( const string& path, FGTileEntry *t) { Point3D rad[4]; int i; for ( i = 0; i < 4; ++i ) { - rad[i] = Point3D( geod[i].x() * DEG_TO_RAD, geod[i].y() * DEG_TO_RAD, + rad[i] = Point3D( geod[i].x() * SGD_DEGREES_TO_RADIANS, geod[i].y() * SGD_DEGREES_TO_RADIANS, geod[i].z() ); } @@ -259,59 +237,11 @@ ssgBranch *fgGenTile( const string& path, FGTileEntry *t) { leaf->setState( state ); tile->addKid( leaf ); - // if ( globals->get_options()->get_clouds() ) { - // fgGenCloudTile(path, t, tile); - // } return tile; } -static float sgTriArea( sgVec3 p0, sgVec3 p1, sgVec3 p2 ) { - /* - From comp.graph.algorithms FAQ - 2A(P) = abs(N.(sum_{i=0}^{n-1}(v_i x v_{i+1}))) - */ - sgVec3 sum; - sgZeroVec3( sum ); - - sgVec3 norm; - sgMakeNormal( norm, p0, p1, p2 ); - - float *vv[3]; - vv[0] = p0; - vv[1] = p1; - vv[2] = p2; - - for( int i=0; i<3; i++ ) { - int ii = (i+1) % 3; - sum[0] += (vv[i][1] * vv[ii][2] - vv[i][2] * vv[ii][1]) ; - sum[1] += (vv[i][2] * vv[ii][0] - vv[i][0] * vv[ii][2]) ; - sum[2] += (vv[i][0] * vv[ii][1] - vv[i][1] * vv[ii][0]) ; - } - - return( sgAbs(sgScalarProductVec3( norm, sum )) * SG_HALF ); -} - - -#if 0 -// this works too, but Norman claims sgTriArea() is more efficient :-) -static double triangle_area_3d( float *p1, float *p2, float *p3 ) { - // Heron's formula: A^2 = s(s-a)(s-b)(s-c) where A is the area, - // a,b,c are the side lengths, s=(a+b+c)/2. In R^3 you can compute - // the lengths of the sides with the distance formula, of course. - - double a = sgDistanceVec3( p1, p2 ); - double b = sgDistanceVec3( p2, p3 ); - double c = sgDistanceVec3( p3, p1 ); - - double s = (a + b + c) / 2.0; - - return sqrt( s * ( s - a ) * ( s - b ) * ( s - c ) ); -} -#endif - - static void random_pt_inside_tri( float *res, float *n1, float *n2, float *n3 ) { @@ -337,41 +267,48 @@ static void random_pt_inside_tri( float *res, static void gen_random_surface_points( ssgLeaf *leaf, ssgVertexArray *lights, double factor ) { int num = leaf->getNumTriangles(); - short int n1, n2, n3; - float *p1, *p2, *p3; - sgVec3 result; - - 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 + 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 a .obj file -ssgBranch *fgObjLoad( const string& path, FGTileEntry *t, - ssgVertexArray *lights, const bool is_base) +// Load an Ascii obj file +ssgBranch *fgAsciiObjLoad( const string& path, FGTileEntry *t, + ssgVertexArray *lights, const bool is_base) { FGNewMat *newmat = NULL; string material; @@ -407,15 +344,15 @@ ssgBranch *fgObjLoad( const string& path, FGTileEntry *t, 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 ); - FG_LOG( FG_TERRAIN, FG_ALERT, "default to ocean tile: " << path ); + SG_LOG( SG_TERRAIN, SG_DEBUG, "Cannot open file: " << path ); + SG_LOG( SG_TERRAIN, SG_DEBUG, "default to ocean tile: " << path ); - return fgGenTile( path, t ); + return NULL; } - shading = globals->get_options()->get_shading(); + shading = fgGetBool("/sim/rendering/shading"); if ( is_base ) { t->ncount = 0; @@ -444,11 +381,7 @@ ssgBranch *fgObjLoad( const string& path, FGTileEntry *t, while ( ! in.eof() ) { #endif -#if defined( macintosh ) || defined( _MSC_VER ) in >> ::skipws; -#else - in >> skipws; -#endif if ( in.get( c ) && c == '#' ) { // process a comment line @@ -462,6 +395,16 @@ ssgBranch *fgObjLoad( const string& path, FGTileEntry *t, // 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) if ( is_base ) { @@ -488,7 +431,7 @@ ssgBranch *fgObjLoad( const string& path, FGTileEntry *t, if ( ! shared_done ) { // sanity check if ( (int)nodes.size() != vncount ) { - FG_LOG( FG_TERRAIN, FG_ALERT, + SG_LOG( SG_TERRAIN, SG_ALERT, "Tile has mismatched nodes = " << nodes.size() << " and normals = " << vncount << " : " << path ); @@ -541,14 +484,14 @@ ssgBranch *fgObjLoad( const string& path, FGTileEntry *t, file += material; cout << "current file = " << file << endl; if ( ! material_lib.add_item( file ) ) { - FG_LOG( FG_TERRAIN, FG_ALERT, + 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 ) { - FG_LOG( FG_TERRAIN, FG_ALERT, + SG_LOG( SG_TERRAIN, SG_ALERT, "Ack! bad on the fly materia create = " << material << " in " << path ); } @@ -588,7 +531,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); @@ -600,7 +543,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 :-(" ); @@ -618,14 +561,14 @@ ssgBranch *fgObjLoad( const string& path, FGTileEntry *t, 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 == "tf") || (token == "ts") || (token == "f") ) { // triangle fan, strip, or individual face - // FG_LOG( FG_TERRAIN, FG_INFO, "new fan or strip"); + // SG_LOG( SG_TERRAIN, SG_INFO, "new fan or strip"); fan_vertices.clear(); fan_tex_coords.clear(); @@ -681,11 +624,7 @@ ssgBranch *fgObjLoad( const string& path, FGTileEntry *t, // read all subsequent numbers until next thing isn't a number while ( true ) { -#if defined( macintosh ) || defined( _MSC_VER ) in >> ::skipws; -#else - in >> skipws; -#endif char c; in.get(c); @@ -779,60 +718,21 @@ ssgBranch *fgObjLoad( const string& path, FGTileEntry *t, if ( is_base ) { if ( coverage > 0.0 ) { if ( coverage < 10000.0 ) { - FG_LOG(FG_INPUT, FG_ALERT, "Light coverage is " + SG_LOG(SG_INPUT, SG_ALERT, "Light coverage is " << coverage << ", pushing up to 10000"); coverage = 10000; } gen_random_surface_points(leaf, lights, coverage); } -// // generate lighting -// if ( material == "Urban" || material == "BuiltUpCover" ) { -// gen_random_surface_points( leaf, lights, 100000.0 ); -// } else if ( material == "EvergreenBroadCover" || -// material == "Default" || material == "Island" || -// material == "SomeSort" || -// material == "DeciduousBroadCover" || -// material == "EvergreenNeedleCover" || -// material == "DeciduousNeedleCover" ) { -// gen_random_surface_points( leaf, lights, 10000000.0 ); -// } else if ( material == "Road") { -// gen_random_surface_points( leaf, lights, 10000.0); -// } else if ( material == "MixedForestCover" ) { -// gen_random_surface_points( leaf, lights, 5000000.0 ); -// } else if ( material == "WoodedTundraCover" || -// material == "BareTundraCover" || -// material == "HerbTundraCover" || -// material == "MixedTundraCover" || -// material == "Marsh" || -// material == "HerbWetlandCover" || -// material == "WoodedWetlandCover" ) { -// gen_random_surface_points( leaf, lights, 20000000.0 ); -// } else if ( material == "ShrubCover" || -// material == "ShrubGrassCover" ) { -// gen_random_surface_points( leaf, lights, 4000000.0 ); -// } else if ( material == "GrassCover" || -// material == "SavannaCover" ) { -// gen_random_surface_points( leaf, lights, 4000000.0 ); -// } else if ( material == "MixedCropPastureCover" || -// material == "IrrCropPastureCover" || -// material == "DryCropPastureCover" || -// material == "CropGrassCover" || -// material == "CropWoodCover" ) { -// gen_random_surface_points( leaf, lights, 2000000.0 ); -// } } } else { - FG_LOG( FG_TERRAIN, FG_WARN, "Unknown token in " + SG_LOG( SG_TERRAIN, SG_WARN, "Unknown token in " << path << " = " << token ); } // eat white space before start of while loop so if we are // done with useful input it is noticed before hand. -#if defined( macintosh ) || defined( _MSC_VER ) in >> ::skipws; -#else - in >> skipws; -#endif } } @@ -841,15 +741,215 @@ ssgBranch *fgObjLoad( const string& path, FGTileEntry *t, } stopwatch.stop(); - FG_LOG( FG_TERRAIN, FG_DEBUG, + SG_LOG( SG_TERRAIN, SG_DEBUG, "Loaded " << path << " in " << stopwatch.elapsedSeconds() << " seconds" ); - // Generate a cloud layer above the tiles - // if ( globals->get_options()->get_clouds() ) { - // fgGenCloudTile(path, t, tile); - // } return tile; } +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 ( 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; + } + + // cout << "before list allocs" << endl; + + int size = node_index.size(); + + if ( size < 1 ) { + SG_LOG( SG_TERRAIN, SG_ALERT, "Woh! list size < 1" ); + exit(-1); + } + + // cout << "before vl, size = " << size << endl; + ssgVertexArray *vl = new ssgVertexArray( size ); + // cout << "before nl" << endl; + ssgNormalArray *nl = new ssgNormalArray( size ); + // cout << "before tl" << endl; + ssgTexCoordArray *tl = new ssgTexCoordArray( size ); + // cout << "before cl" << endl; + ssgColourArray *cl = new ssgColourArray( 1 ); + + sgVec4 color; + sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 ); + cl->add( color ); + + sgVec2 tmp2; + sgVec3 tmp3; + int i; + for ( i = 0; i < size; ++i ) { + Point3D node = nodes[ node_index[i] ]; + sgSetVec3( tmp3, node[0], node[1], node[2] ); + vl -> add( tmp3 ); + + Point3D normal = normals[ node_index[i] ]; + sgSetVec3( tmp3, normal[0], normal[1], normal[2] ); + nl -> add( tmp3 ); + + Point3D 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 ); + } + + // cout << "before leaf create" << endl; + ssgLeaf *leaf = new ssgVtxTable ( ty, vl, nl, tl, cl ); + // cout << "after leaf create" << endl; + + // lookup the state record + // cout << "looking up material = " << endl; + // cout << material << endl; + // cout << "'" << endl; + + 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 normals = obj.get_normals(); + point_list texcoords = obj.get_texcoords(); + + string material; + int_list vertex_index; + int_list tex_index; + + // 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; +}