diff --git a/simgear/bucket/newbucket.cxx b/simgear/bucket/newbucket.cxx index 6a4b2ecb..9a4b20eb 100644 --- a/simgear/bucket/newbucket.cxx +++ b/simgear/bucket/newbucket.cxx @@ -44,6 +44,9 @@ SGBucket::SGBucket(const double dlon, const double dlat) { set_bucket(dlon, dlat); } +SGBucket::SGBucket(const SGGeod& geod) { + set_bucket(geod); +} // create an impossible bucket if false SGBucket::SGBucket(const bool is_good) { @@ -73,11 +76,6 @@ SGBucket::SGBucket(const long int bindex) { } -// default destructor -SGBucket::~SGBucket() { -} - - // Set the bucket params for the specified lat and lon void SGBucket::set_bucket( double *lonlat ) { set_bucket( lonlat[0], lonlat[1] ); @@ -135,6 +133,11 @@ void SGBucket::set_bucket( double dlon, double dlat ) { } +void SGBucket::set_bucket(const SGGeod& geod) +{ + set_bucket(geod.getLongitudeDeg(), geod.getLatitudeDeg()); +} + // Build the path name for this bucket string SGBucket::gen_base_path() const { // long int index; diff --git a/simgear/bucket/newbucket.hxx b/simgear/bucket/newbucket.hxx index 955ce8b1..ccb5a8f9 100644 --- a/simgear/bucket/newbucket.hxx +++ b/simgear/bucket/newbucket.hxx @@ -134,6 +134,13 @@ public: */ SGBucket(const double dlon, const double dlat); + /** + * Construct a bucket given a specific location. + * @param dlon longitude specified in degrees + * @param dlat latitude specified in degrees + */ + SGBucket(const SGGeod& geod); + /** Construct a bucket. * @param is_good if false, create an invalid bucket. This is * useful * if you are comparing cur_bucket to last_bucket and @@ -147,11 +154,6 @@ public: */ SGBucket(const long int bindex); - /** - * Default destructor. - */ - ~SGBucket(); - /** * Reset a bucket to represent a new lat and lon * @param dlon longitude specified in degrees @@ -166,6 +168,13 @@ public: */ void set_bucket( double *lonlat ); + /** + * Reset a bucket to represent a new lat and lon + * @param dlon longitude specified in degrees + * @param dlat latitude specified in degrees + */ + void set_bucket(const SGGeod& geod); + /** * Create an impossible bucket. * This is useful if you are comparing cur_bucket to last_bucket diff --git a/simgear/io/decode_binobj.cxx b/simgear/io/decode_binobj.cxx index 06181c8b..2865db57 100644 --- a/simgear/io/decode_binobj.cxx +++ b/simgear/io/decode_binobj.cxx @@ -37,14 +37,14 @@ int main( int argc, char **argv ) { obj.get_gbs_radius()); cout << endl; - point_list nodes = obj.get_wgs84_nodes(); + std::vector nodes = obj.get_wgs84_nodes(); cout << "# vertex list" << endl; for ( i = 0; i < (int)nodes.size(); ++i ) { printf("v %.5f %.5f %.5f\n", nodes[i].x(), nodes[i].y(), nodes[i].z() ); } cout << endl; - point_list normals = obj.get_normals(); + std::vector normals = obj.get_normals(); cout << "# vertex normal list" << endl; for ( i = 0; i < (int)normals.size(); ++i ) { printf("vn %.5f %.5f %.5f\n", @@ -52,7 +52,7 @@ int main( int argc, char **argv ) { } cout << endl; - point_list texcoords = obj.get_texcoords(); + std::vector texcoords = obj.get_texcoords(); cout << "# texture coordinate list" << endl; for ( i = 0; i < (int)texcoords.size(); ++i ) { printf("vt %.5f %.5f\n", diff --git a/simgear/io/sg_binobj.cxx b/simgear/io/sg_binobj.cxx index 19f2c0bb..ee976d68 100644 --- a/simgear/io/sg_binobj.cxx +++ b/simgear/io/sg_binobj.cxx @@ -174,7 +174,7 @@ static void read_object( gzFile fp, int idx_size; bool do_vertices, do_normals, do_colors, do_texcoords; int j, k, idx; - static sgSimpleBuffer buf( 32768 ); // 32 Kb + sgSimpleBuffer buf( 32768 ); // 32 Kb char material[256]; // default values @@ -280,13 +280,13 @@ static void read_object( gzFile fp, // read a binary file and populate the provided structures. bool SGBinObject::read_bin( const string& file ) { - Point3D p; + SGVec3d p; int i, j, k; unsigned int nbytes; - static sgSimpleBuffer buf( 32768 ); // 32 Kb + sgSimpleBuffer buf( 32768 ); // 32 Kb // zero out structures - gbs_center = Point3D( 0 ); + gbs_center = SGVec3d(0, 0, 0); gbs_radius = 0.0; wgs84_nodes.clear(); @@ -407,7 +407,7 @@ bool SGBinObject::read_bin( const string& file ) { sgEndianSwap( (uint64_t *)&(dptr[1]) ); sgEndianSwap( (uint64_t *)&(dptr[2]) ); } - gbs_center = Point3D( dptr[0], dptr[1], dptr[2] ); + gbs_center = SGVec3d( dptr[0], dptr[1], dptr[2] ); // cout << "Center = " << gbs_center << endl; ptr += sizeof(double) * 3; @@ -447,7 +447,7 @@ bool SGBinObject::read_bin( const string& file ) { sgEndianSwap( (uint32_t *)&(fptr[1]) ); sgEndianSwap( (uint32_t *)&(fptr[2]) ); } - wgs84_nodes.push_back( Point3D(fptr[0], fptr[1], fptr[2]) ); + wgs84_nodes.push_back( SGVec3d(fptr[0], fptr[1], fptr[2]) ); fptr += 3; } } @@ -481,7 +481,8 @@ bool SGBinObject::read_bin( const string& file ) { sgEndianSwap( (uint32_t *)&(fptr[2]) ); sgEndianSwap( (uint32_t *)&(fptr[3]) ); } - colors.push_back( Point3D( fptr[0], fptr[1], fptr[2] ) ); + SGVec4f color( fptr[0], fptr[1], fptr[2], fptr[3] ); + colors.push_back( color ); fptr += 4; } } @@ -508,14 +509,11 @@ bool SGBinObject::read_bin( const string& file ) { int count = nbytes / 3; normals.reserve( count ); for ( k = 0; k < count; ++k ) { - sgdVec3 normal; - sgdSetVec3( normal, - (ptr[0]) / 127.5 - 1.0, - (ptr[1]) / 127.5 - 1.0, - (ptr[2]) / 127.5 - 1.0 ); - sgdNormalizeVec3( normal ); + SGVec3f normal((ptr[0]) / 127.5 - 1.0, + (ptr[1]) / 127.5 - 1.0, + (ptr[2]) / 127.5 - 1.0); - normals.push_back(Point3D(normal[0], normal[1], normal[2])); + normals.push_back(normalize(normal)); ptr += 3; } } @@ -547,7 +545,7 @@ bool SGBinObject::read_bin( const string& file ) { sgEndianSwap( (uint32_t *)&(fptr[0]) ); sgEndianSwap( (uint32_t *)&(fptr[1]) ); } - texcoords.push_back( Point3D( fptr[0], fptr[1], 0 ) ); + texcoords.push_back( SGVec2f( fptr[0], fptr[1] ) ); fptr += 2; } } @@ -612,10 +610,6 @@ bool SGBinObject::read_bin( const string& file ) { bool SGBinObject::write_bin( const string& base, const string& name, const SGBucket& b ) { - Point3D p; - sgVec2 t; - sgVec3 pt; - sgVec4 color; int i, j; unsigned char idx_mask; int idx_size; @@ -738,9 +732,8 @@ bool SGBinObject::write_bin( const string& base, const string& name, sgWriteShort( fp, 1 ); // nelements sgWriteUInt( fp, wgs84_nodes.size() * sizeof(float) * 3 ); // nbytes for ( i = 0; i < (int)wgs84_nodes.size(); ++i ) { - p = wgs84_nodes[i] - gbs_center; - sgSetVec3( pt, p.x(), p.y(), p.z() ); - sgWriteVec3( fp, pt ); + SGVec3f p = toVec3f(wgs84_nodes[i] - gbs_center); + sgWriteVec3( fp, p.data() ); } // dump vertex color list @@ -749,12 +742,7 @@ bool SGBinObject::write_bin( const string& base, const string& name, sgWriteShort( fp, 1 ); // nelements sgWriteUInt( fp, colors.size() * sizeof(float) * 4 ); // nbytes for ( i = 0; i < (int)colors.size(); ++i ) { - p = colors[i]; - // Right now we have a place holder for color alpha but we - // need to update the interface so the calling program can - // provide the info. - sgSetVec4( color, p.x(), p.y(), p.z(), 1.0 ); - sgWriteVec4( fp, color ); + sgWriteVec4( fp, colors[i].data() ); } // dump vertex normal list @@ -764,7 +752,7 @@ bool SGBinObject::write_bin( const string& base, const string& name, sgWriteUInt( fp, normals.size() * 3 ); // nbytes char normal[3]; for ( i = 0; i < (int)normals.size(); ++i ) { - p = normals[i]; + SGVec3f p = normals[i]; normal[0] = (unsigned char)((p.x() + 1.0) * 127.5); normal[1] = (unsigned char)((p.y() + 1.0) * 127.5); normal[2] = (unsigned char)((p.z() + 1.0) * 127.5); @@ -777,9 +765,7 @@ bool SGBinObject::write_bin( const string& base, const string& name, sgWriteShort( fp, 1 ); // nelements sgWriteUInt( fp, texcoords.size() * sizeof(float) * 2 ); // nbytes for ( i = 0; i < (int)texcoords.size(); ++i ) { - p = texcoords[i]; - sgSetVec2( t, p.x(), p.y() ); - sgWriteVec2( fp, t ); + sgWriteVec2( fp, texcoords[i].data() ); } // dump point groups if they exist @@ -1042,7 +1028,6 @@ bool SGBinObject::write_bin( const string& base, const string& name, bool SGBinObject::write_ascii( const string& base, const string& name, const SGBucket& b ) { - Point3D p; int i, j; SGPath file = base + "/" + b.gen_base_path() + "/" + name; @@ -1084,7 +1069,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name, // dump vertex list fprintf(fp, "# vertex list\n"); for ( i = 0; i < (int)wgs84_nodes.size(); ++i ) { - p = wgs84_nodes[i] - gbs_center; + SGVec3d p = wgs84_nodes[i] - gbs_center; fprintf(fp, "v %.5f %.5f %.5f\n", p.x(), p.y(), p.z() ); } @@ -1092,7 +1077,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name, fprintf(fp, "# vertex normal list\n"); for ( i = 0; i < (int)normals.size(); ++i ) { - p = normals[i]; + SGVec3f p = normals[i]; fprintf(fp, "vn %.5f %.5f %.5f\n", p.x(), p.y(), p.z() ); } fprintf(fp, "\n"); @@ -1100,7 +1085,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name, // dump texture coordinates fprintf(fp, "# texture coordinate list\n"); for ( i = 0; i < (int)texcoords.size(); ++i ) { - p = texcoords[i]; + SGVec2f p = texcoords[i]; fprintf(fp, "vt %.5f %.5f\n", p.x(), p.y() ); } fprintf(fp, "\n"); @@ -1126,13 +1111,13 @@ bool SGBinObject::write_ascii( const string& base, const string& name, // make a list of points for the group point_list group_nodes; group_nodes.clear(); - Point3D bs_center; + SGVec3d bs_center; double bs_radius = 0; for ( i = start; i < end; ++i ) { for ( j = 0; j < (int)tris_v[i].size(); ++j ) { - group_nodes.push_back( wgs84_nodes[ tris_v[i][j] ] ); - bs_center = sgCalcCenter( group_nodes ); - bs_radius = sgCalcBoundingRadius( bs_center, group_nodes ); + group_nodes.push_back( Point3D::fromSGVec3(wgs84_nodes[ tris_v[i][j] ]) ); + bs_center = sgCalcCenter( group_nodes ).toSGVec3d(); + bs_radius = sgCalcBoundingRadius( Point3D::fromSGVec3(bs_center), group_nodes ); } } @@ -1177,13 +1162,13 @@ bool SGBinObject::write_ascii( const string& base, const string& name, // make a list of points for the group point_list group_nodes; group_nodes.clear(); - Point3D bs_center; + SGVec3d bs_center; double bs_radius = 0; for ( i = start; i < end; ++i ) { for ( j = 0; j < (int)strips_v[i].size(); ++j ) { - group_nodes.push_back( wgs84_nodes[ strips_v[i][j] ] ); - bs_center = sgCalcCenter( group_nodes ); - bs_radius = sgCalcBoundingRadius( bs_center, group_nodes ); + group_nodes.push_back( Point3D::fromSGVec3(wgs84_nodes[ strips_v[i][j] ]) ); + bs_center = sgCalcCenter( group_nodes ).toSGVec3d(); + bs_radius = sgCalcBoundingRadius( Point3D::fromSGVec3(bs_center), group_nodes ); } } diff --git a/simgear/io/sg_binobj.hxx b/simgear/io/sg_binobj.hxx index 542a333a..cc4f9498 100644 --- a/simgear/io/sg_binobj.hxx +++ b/simgear/io/sg_binobj.hxx @@ -89,13 +89,13 @@ typedef group_list::const_iterator const_group_list_iterator; class SGBinObject { unsigned short version; - Point3D gbs_center; + SGVec3d gbs_center; float gbs_radius; - point_list wgs84_nodes; // vertex list - point_list colors; // color list - point_list normals; // normal list - point_list texcoords; // texture coordinate list + std::vector wgs84_nodes; // vertex list + std::vector colors; // color list + std::vector normals; // normal list + std::vector texcoords; // texture coordinate list group_list pts_v; // points vertex index group_list pts_n; // points normal index @@ -125,23 +125,51 @@ public: inline unsigned short get_version() const { return version; } - inline const Point3D& get_gbs_center() const { return gbs_center; } - inline void set_gbs_center( const Point3D& p ) { gbs_center = p; } + inline Point3D get_gbs_center() const { return Point3D::fromSGVec3(gbs_center); } + inline void set_gbs_center( const Point3D& p ) { gbs_center = p.toSGVec3d(); } + inline const SGVec3d& get_gbs_center2() const { return gbs_center; } + inline void set_gbs_center( const SGVec3d& p ) { gbs_center = p; } inline float get_gbs_radius() const { return gbs_radius; } inline void set_gbs_radius( float r ) { gbs_radius = r; } - inline const point_list& get_wgs84_nodes() const { return wgs84_nodes; } - inline void set_wgs84_nodes( const point_list& n ) { wgs84_nodes = n; } + inline const std::vector& get_wgs84_nodes() const + { return wgs84_nodes; } + inline void set_wgs84_nodes( const std::vector& n ) + { wgs84_nodes = n; } + inline void set_wgs84_nodes( const point_list& n ) + { + wgs84_nodes.resize(n.size()); + for (unsigned i = 0; i < wgs84_nodes.size(); ++i) + wgs84_nodes[i] = n[i].toSGVec3d(); + } - inline const point_list& get_colors() const { return colors; } - inline void set_colors( const point_list& c ) { colors = c; } + inline const std::vector& get_colors() const { return colors; } + inline void set_colors( const std::vector& c ) { colors = c; } + inline void set_colors( const point_list& c ) + { + colors.resize(c.size()); + for (unsigned i = 0; i < colors.size(); ++i) + colors[i] = SGVec4f(c[i].toSGVec3f(), 1); + } - inline const point_list& get_normals() const { return normals; } - inline void set_normals( const point_list& n ) { normals = n; } + inline const std::vector& get_normals() const { return normals; } + inline void set_normals( const std::vector& n ) { normals = n; } + inline void set_normals( const point_list& n ) + { + normals.resize(n.size()); + for (unsigned i = 0; i < normals.size(); ++i) + normals[i] = n[i].toSGVec3f(); + } - inline const point_list& get_texcoords() const { return texcoords; } - inline void set_texcoords( const point_list& t ) { texcoords = t; } + inline const std::vector& get_texcoords() const { return texcoords; } + inline void set_texcoords( const std::vector& t ) { texcoords = t; } + inline void set_texcoords( const point_list& t ) + { + texcoords.resize(t.size()); + for (unsigned i = 0; i < texcoords.size(); ++i) + texcoords[i] = t[i].toSGVec2f(); + } inline const group_list& get_pts_v() const { return pts_v; } inline void set_pts_v( const group_list& g ) { pts_v = g; } diff --git a/simgear/math/SGVec2.hxx b/simgear/math/SGVec2.hxx index 155b8a67..6b49bc61 100644 --- a/simgear/math/SGVec2.hxx +++ b/simgear/math/SGVec2.hxx @@ -204,6 +204,15 @@ SGVec2 operator*(const SGVec2& v, S s) { return SGVec2(s*v(0), s*v(1)); } +/// multiplication as a multiplicator, that is assume that the first vector +/// represents a 2x2 diagonal matrix with the diagonal elements in the vector. +/// Then the result is the product of that matrix times the second vector. +template +inline +SGVec2 +mult(const SGVec2& v1, const SGVec2& v2) +{ return SGVec2(v1(0)*v2(0), v1(1)*v2(1)); } + /// component wise min template inline diff --git a/simgear/math/SGVec3.hxx b/simgear/math/SGVec3.hxx index bed95dad..76958199 100644 --- a/simgear/math/SGVec3.hxx +++ b/simgear/math/SGVec3.hxx @@ -261,6 +261,15 @@ SGVec3 operator*(const SGVec3& v, S s) { return SGVec3(s*v(0), s*v(1), s*v(2)); } +/// multiplication as a multiplicator, that is assume that the first vector +/// represents a 3x3 diagonal matrix with the diagonal elements in the vector. +/// Then the result is the product of that matrix times the second vector. +template +inline +SGVec3 +mult(const SGVec3& v1, const SGVec3& v2) +{ return SGVec3(v1(0)*v2(0), v1(1)*v2(1), v1(2)*v2(2)); } + /// component wise min template inline diff --git a/simgear/math/SGVec4.hxx b/simgear/math/SGVec4.hxx index f854274d..13cacc9d 100644 --- a/simgear/math/SGVec4.hxx +++ b/simgear/math/SGVec4.hxx @@ -223,6 +223,15 @@ SGVec4 operator*(const SGVec4& v, S s) { return SGVec4(s*v(0), s*v(1), s*v(2), s*v(3)); } +/// multiplication as a multiplicator, that is assume that the first vector +/// represents a 4x4 diagonal matrix with the diagonal elements in the vector. +/// Then the result is the product of that matrix times the second vector. +template +inline +SGVec4 +mult(const SGVec4& v1, const SGVec4& v2) +{ return SGVec4(v1(0)*v2(0), v1(1)*v2(1), v1(2)*v2(2), v1(3)*v2(3)); } + /// component wise min template inline diff --git a/simgear/scene/material/mat.hxx b/simgear/scene/material/mat.hxx index ea96abab..9e93343f 100644 --- a/simgear/scene/material/mat.hxx +++ b/simgear/scene/material/mat.hxx @@ -208,6 +208,20 @@ public: */ SGMaterialGlyph * get_glyph (const string& name) const; + void set_light_color(const SGVec4f& color) + { emission = color; } + const SGVec4f& get_light_color() const + { return emission; } + + SGVec2f get_tex_coord_scale() const + { + float tex_width = get_xsize(); + float tex_height = get_ysize(); + + return SGVec2f((0 < tex_width) ? 1000.0f/tex_width : 1.0f, + (0 < tex_height) ? 1000.0f/tex_height : 1.0f); + } + protected: diff --git a/simgear/scene/material/matlib.cxx b/simgear/scene/material/matlib.cxx index bd8a7725..9c02cb96 100644 --- a/simgear/scene/material/matlib.cxx +++ b/simgear/scene/material/matlib.cxx @@ -46,7 +46,6 @@ #include #include #include -// #include #include #include #include @@ -69,114 +68,10 @@ SG_USING_NAMESPACE(std); SG_USING_STD(string); -extern bool SGPointLightsUseSprites; -extern bool SGPointLightsEnhancedLighting; -extern bool SGPointLightsDistanceAttenuation; - -// FIXME: should make this configurable -static const bool sprite_lighting = true; - // Constructor SGMaterialLib::SGMaterialLib ( void ) { } -// generate standard colored directional light environment texture map -static osg::Texture2D* -gen_standard_dir_light_map( int r, int g, int b, int alpha ) { - const int env_tex_res = 32; - int half_res = env_tex_res / 2; - - osg::Image* image = new osg::Image; - image->allocateImage(env_tex_res, env_tex_res, 1, - GL_RGBA, GL_UNSIGNED_BYTE); - for ( int i = 0; i < env_tex_res; ++i ) { - for ( int j = 0; j < env_tex_res; ++j ) { - double x = (i - half_res) / (double)half_res; - double y = (j - half_res) / (double)half_res; - double dist = sqrt(x*x + y*y); - if ( dist > 1.0 ) { dist = 1.0; } - double bright = cos( dist * SGD_PI_2 ); - if ( bright < 0.3 ) { bright = 0.3; } - unsigned char* env_map = image->data(i, j); - env_map[0] = r; - env_map[1] = g; - env_map[2] = b; - env_map[3] = (int)(bright * alpha); - } - } - - osg::Texture2D* texture = new osg::Texture2D; - texture->setImage(image); - - return texture; -} - - -// generate standard colored directional light environment texture map -static osg::Texture2D* -gen_taxiway_dir_light_map( int r, int g, int b, int alpha ) { - const int env_tex_res = 32; - int half_res = env_tex_res / 2; - - osg::Image* image = new osg::Image; - image->allocateImage(env_tex_res, env_tex_res, 1, - GL_RGBA, GL_UNSIGNED_BYTE); - - for ( int i = 0; i < env_tex_res; ++i ) { - for ( int j = 0; j < env_tex_res; ++j ) { - double x = (i - half_res) / (double)half_res; - double y = (j - half_res) / (double)half_res; - double tmp = sqrt(x*x + y*y); - double dist = tmp * tmp; - if ( dist > 1.0 ) { dist = 1.0; } - double bright = sin( dist * SGD_PI_2 ); - if ( bright < 0.2 ) { bright = 0.2; } - unsigned char* env_map = image->data(i, j); - env_map[0] = r; - env_map[1] = g; - env_map[2] = b; - env_map[3] = (int)(bright * alpha); - } - } - - osg::Texture2D* texture = new osg::Texture2D; - texture->setImage(image); - - return texture; -} - -static osg::Texture2D* -gen_standard_light_sprite( int r, int g, int b, int alpha ) { - const int env_tex_res = 32; - int half_res = env_tex_res / 2; - - osg::Image* image = new osg::Image; - image->allocateImage(env_tex_res, env_tex_res, 1, - GL_RGBA, GL_UNSIGNED_BYTE); - - for ( int i = 0; i < env_tex_res; ++i ) { - for ( int j = 0; j < env_tex_res; ++j ) { - double x = (i - half_res) / (double)half_res; - double y = (j - half_res) / (double)half_res; - double dist = sqrt(x*x + y*y); - if ( dist > 1.0 ) { dist = 1.0; } - double bright = cos( dist * SGD_PI_2 ); - if ( bright < 0.01 ) { bright = 0.0; } - unsigned char* env_map = image->data(i, j); - env_map[0] = r; - env_map[1] = g; - env_map[2] = b; - env_map[3] = (int)(bright * alpha); - } - } - - osg::Texture2D* texture = new osg::Texture2D; - texture->setImage(image); - - return texture; -} - - // Load a library of material properties bool SGMaterialLib::load( const string &fg_root, const string& mpath, const char *season ) { @@ -191,13 +86,11 @@ bool SGMaterialLib::load( const string &fg_root, const string& mpath, const char throw; } - SGSharedPtr m; - int nMaterials = materials.nChildren(); for (int i = 0; i < nMaterials; i++) { const SGPropertyNode * node = materials.getChild(i); if (!strcmp(node->getName(), "material")) { - m = new SGMaterial( fg_root, node, season ); + SGSharedPtr m = new SGMaterial(fg_root, node, season); vectornames = node->getChildren("name"); for ( unsigned int j = 0; j < names.size(); j++ ) { @@ -214,268 +107,6 @@ bool SGMaterialLib::load( const string &fg_root, const string& mpath, const char } } - osg::ref_ptr lightStateSet = new osg::StateSet; - { - lightStateSet->setRenderBinDetails(9, "DepthSortedBin"); - lightStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF); -// lightStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON); - - lightStateSet->setMode(GL_BLEND, osg::StateAttribute::ON); - - lightStateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF); - lightStateSet->setAttribute(new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01)); - lightStateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON); - - osg::CullFace* cullFace = new osg::CullFace; - cullFace->setMode(osg::CullFace::BACK); - lightStateSet->setAttributeAndModes(cullFace, osg::StateAttribute::ON); - - osg::BlendFunc* blendFunc = new osg::BlendFunc; - blendFunc->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA); - lightStateSet->setAttributeAndModes(blendFunc, osg::StateAttribute::ON); - - osg::PolygonMode* polygonMode = new osg::PolygonMode; - polygonMode->setMode(osg::PolygonMode::FRONT, osg::PolygonMode::POINT); - lightStateSet->setAttribute(polygonMode); - -// if (SGPointLightsUseSprites) { - osg::PointSprite* pointSprite = new osg::PointSprite; - lightStateSet->setTextureAttributeAndModes(0, pointSprite, osg::StateAttribute::ON); -// } - -// if (SGPointLightsDistanceAttenuation) { - osg::Point* point = new osg::Point; - point->setMinSize(2); - point->setSize(8); - point->setDistanceAttenuation(osg::Vec3(1.0, 0.001, 0.000001)); - lightStateSet->setAttribute(point); -// } - - osg::PolygonOffset* polygonOffset = new osg::PolygonOffset; - polygonOffset->setFactor(-1); - polygonOffset->setUnits(-1); - lightStateSet->setAttributeAndModes(polygonOffset, osg::StateAttribute::ON); - - osg::TexGen* texGen = new osg::TexGen; - texGen->setMode(osg::TexGen::SPHERE_MAP); - lightStateSet->setTextureAttribute(0, texGen); - lightStateSet->setTextureMode(0, GL_TEXTURE_GEN_S, osg::StateAttribute::ON); - lightStateSet->setTextureMode(0, GL_TEXTURE_GEN_T, osg::StateAttribute::ON); - osg::TexEnv* texEnv = new osg::TexEnv; - texEnv->setMode(osg::TexEnv::MODULATE); - lightStateSet->setTextureAttribute(0, texEnv); - - osg::Material* material = new osg::Material; - lightStateSet->setAttribute(material); - } - - - // hard coded ground light state - osg::StateSet *gnd_lights = static_cast(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL)); -// if (SGPointLightsDistanceAttenuation) { - osg::Point* point = new osg::Point; - point->setMinSize(1); - point->setSize(2); - point->setMaxSize(4); - point->setDistanceAttenuation(osg::Vec3(1.0, 0.01, 0.0001)); - while (gnd_lights->getAttribute(osg::StateAttribute::POINT)) { - gnd_lights->removeAttribute(osg::StateAttribute::POINT); - } - gnd_lights->setAttribute(point); -// } - m = new SGMaterial( gnd_lights ); - m->add_name("GROUND_LIGHTS"); - matlib["GROUND_LIGHTS"] = m; - - // hard coded runway white light state - osg::Texture2D* texture; - if ( sprite_lighting ) { - texture = gen_standard_light_sprite(235, 235, 195, 255); - } else { - texture = gen_standard_dir_light_map(235, 235, 195, 255); - } - osg::StateSet *rwy_white_lights = static_cast(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL)); - rwy_white_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - - m = new SGMaterial( rwy_white_lights ); - m->add_name("RWY_WHITE_LIGHTS"); - matlib["RWY_WHITE_LIGHTS"] = m; - // For backwards compatibility ... remove someday - m->add_name("RUNWAY_LIGHTS"); - matlib["RUNWAY_LIGHTS"] = m; - m->add_name("RWY_LIGHTS"); - matlib["RWY_LIGHTS"] = m; - // end of backwards compatitibilty - - // hard coded runway medium intensity white light state - if ( sprite_lighting ) { - texture = gen_standard_light_sprite( 235, 235, 195, 205 ); - } else { - texture = gen_standard_dir_light_map( 235, 235, 195, 205 ); - } - osg::StateSet *rwy_white_medium_lights = static_cast(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL)); - rwy_white_medium_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - - m = new SGMaterial( rwy_white_medium_lights ); - m->add_name("RWY_WHITE_MEDIUM_LIGHTS"); - matlib["RWY_WHITE_MEDIUM_LIGHTS"] = m; - - // hard coded runway low intensity white light state - if ( sprite_lighting ) { - texture = gen_standard_light_sprite( 235, 235, 195, 155 ); - } else { - texture = gen_standard_dir_light_map( 235, 235, 195, 155 ); - } - osg::StateSet *rwy_white_low_lights = static_cast(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL)); - rwy_white_medium_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - m = new SGMaterial( rwy_white_low_lights ); - m->add_name("RWY_WHITE_LOW_LIGHTS"); - matlib["RWY_WHITE_LOW_LIGHTS"] = m; - - // hard coded runway yellow light state - if ( sprite_lighting ) { - texture = gen_standard_light_sprite( 235, 215, 20, 255 ); - } else { - texture = gen_standard_dir_light_map( 235, 215, 20, 255 ); - } - osg::StateSet *rwy_yellow_lights = static_cast(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL)); - rwy_yellow_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - m = new SGMaterial( rwy_yellow_lights ); - m->add_name("RWY_YELLOW_LIGHTS"); - matlib["RWY_YELLOW_LIGHTS"] = m; - - // hard coded runway medium intensity yellow light state - if ( sprite_lighting ) { - texture = gen_standard_light_sprite( 235, 215, 20, 205 ); - } else { - texture = gen_standard_dir_light_map( 235, 215, 20, 205 ); - } - osg::StateSet *rwy_yellow_medium_lights = static_cast(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL)); - rwy_yellow_medium_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - m = new SGMaterial( rwy_yellow_medium_lights ); - m->add_name("RWY_YELLOW_MEDIUM_LIGHTS"); - matlib["RWY_YELLOW_MEDIUM_LIGHTS"] = m; - - // hard coded runway low intensity yellow light state - if ( sprite_lighting ) { - texture = gen_standard_light_sprite( 235, 215, 20, 155 ); - } else { - texture = gen_standard_dir_light_map( 235, 215, 20, 155 ); - } - osg::StateSet *rwy_yellow_low_lights = static_cast(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL)); - rwy_yellow_low_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - m = new SGMaterial( rwy_yellow_low_lights ); - m->add_name("RWY_YELLOW_LOW_LIGHTS"); - matlib["RWY_YELLOW_LOW_LIGHTS"] = m; - - // hard coded runway red light state - if ( sprite_lighting ) { - texture = gen_standard_light_sprite( 235, 90, 90, 255 ); - } else { - texture = gen_standard_dir_light_map( 235, 90, 90, 255 ); - } - osg::StateSet *rwy_red_lights = static_cast(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL)); - rwy_red_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - m = new SGMaterial( rwy_red_lights ); - m->add_name("RWY_RED_LIGHTS"); - matlib["RWY_RED_LIGHTS"] = m; - - // hard coded medium intensity runway red light state - if ( sprite_lighting ) { - texture = gen_standard_light_sprite( 235, 90, 90, 205 ); - } else { - texture = gen_standard_dir_light_map( 235, 90, 90, 205 ); - } - osg::StateSet *rwy_red_medium_lights = static_cast(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL)); - rwy_red_medium_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - m = new SGMaterial( rwy_red_medium_lights ); - m->add_name("RWY_RED_MEDIUM_LIGHTS"); - matlib["RWY_RED_MEDIUM_LIGHTS"] = m; - - // hard coded low intensity runway red light state - if ( sprite_lighting ) { - texture = gen_standard_light_sprite( 235, 90, 90, 155 ); - } else { - texture = gen_standard_dir_light_map( 235, 90, 90, 155 ); - } - osg::StateSet *rwy_red_low_lights = static_cast(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL)); - rwy_red_low_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - m = new SGMaterial( rwy_red_low_lights ); - m->add_name("RWY_RED_LOW_LIGHTS"); - matlib["RWY_RED_LOW_LIGHTS"] = m; - - // hard coded runway green light state - if ( sprite_lighting ) { - texture = gen_standard_light_sprite( 20, 235, 20, 255 ); - } else { - texture = gen_standard_dir_light_map( 20, 235, 20, 255 ); - } - osg::StateSet *rwy_green_lights = static_cast(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL)); - rwy_green_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - m = new SGMaterial( rwy_green_lights ); - m->add_name("RWY_GREEN_LIGHTS"); - matlib["RWY_GREEN_LIGHTS"] = m; - - // hard coded medium intensity runway green light state - if ( sprite_lighting ) { - texture = gen_standard_light_sprite( 20, 235, 20, 205 ); - } else { - texture = gen_standard_dir_light_map( 20, 235, 20, 205 ); - } - osg::StateSet *rwy_green_medium_lights = static_cast(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL)); - rwy_green_medium_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - m = new SGMaterial( rwy_green_medium_lights ); - m->add_name("RWY_GREEN_MEDIUM_LIGHTS"); - matlib["RWY_GREEN_MEDIUM_LIGHTS"] = m; - - // hard coded low intensity runway green light state - if ( sprite_lighting ) { - texture = gen_standard_light_sprite( 20, 235, 20, 155 ); - } else { - texture = gen_standard_dir_light_map( 20, 235, 20, 155 ); - } - osg::StateSet *rwy_green_low_lights = static_cast(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL)); - rwy_green_low_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - m = new SGMaterial( rwy_green_low_lights ); - m->add_name("RWY_GREEN_LOW_LIGHTS"); - matlib["RWY_GREEN_LOW_LIGHTS"] = m; - m->add_name("RWY_GREEN_TAXIWAY_LIGHTS"); - matlib["RWY_GREEN_TAXIWAY_LIGHTS"] = m; - - // hard coded low intensity taxiway blue light state - if ( sprite_lighting ) { - texture = gen_standard_light_sprite( 90, 90, 235, 205 ); - } else { - texture = gen_taxiway_dir_light_map( 90, 90, 235, 205 ); - } - osg::StateSet *taxiway_blue_low_lights = static_cast(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL)); - taxiway_blue_low_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - m = new SGMaterial( taxiway_blue_low_lights ); - m->add_name("RWY_BLUE_TAXIWAY_LIGHTS"); - matlib["RWY_BLUE_TAXIWAY_LIGHTS"] = m; - - // hard coded runway vasi light state - if ( sprite_lighting ) { - texture = gen_standard_light_sprite( 235, 235, 195, 255 ); - } else { - texture = gen_standard_dir_light_map( 235, 235, 195, 255 ); - } - osg::StateSet *rwy_vasi_lights = static_cast(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL)); -// if (SGPointLightsDistanceAttenuation) { - point = new osg::Point; - point->setMinSize(4); - point->setSize(10); - point->setDistanceAttenuation(osg::Vec3(1.0, 0.01, 0.0001)); - while (rwy_vasi_lights->getAttribute(osg::StateAttribute::POINT)) { - rwy_vasi_lights->removeAttribute(osg::StateAttribute::POINT); - } - rwy_vasi_lights->setAttribute(point); -// } - rwy_vasi_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); - m = new SGMaterial( rwy_vasi_lights ); - m->add_name("RWY_VASI_LIGHTS"); - matlib["RWY_VASI_LIGHTS"] = m; - return true; } diff --git a/simgear/scene/material/matlib.hxx b/simgear/scene/material/matlib.hxx index 52f414e0..e7f2ca2a 100644 --- a/simgear/scene/material/matlib.hxx +++ b/simgear/scene/material/matlib.hxx @@ -53,7 +53,7 @@ class SGMaterialLib { private: // associative array of materials - typedef map < string, SGSharedPtr, less > material_map; + typedef map < string, SGSharedPtr > material_map; typedef material_map::iterator material_map_iterator; typedef material_map::const_iterator const_material_map_iterator; diff --git a/simgear/scene/model/Makefile.am b/simgear/scene/model/Makefile.am index b1ff2734..d3eaff3f 100644 --- a/simgear/scene/model/Makefile.am +++ b/simgear/scene/model/Makefile.am @@ -12,7 +12,8 @@ include_HEADERS = \ persparam.hxx \ placement.hxx \ placementtrans.hxx \ - SGMaterialAnimation.hxx + SGMaterialAnimation.hxx \ + SGOffsetTransform.hxx libsgmodel_a_SOURCES = \ animation.cxx \ @@ -23,6 +24,7 @@ libsgmodel_a_SOURCES = \ placement.cxx \ placementtrans.cxx \ shadanim.cxx \ - SGMaterialAnimation.cxx + SGMaterialAnimation.cxx \ + SGOffsetTransform.cxx INCLUDES = -I$(top_srcdir) diff --git a/simgear/scene/model/SGOffsetTransform.cxx b/simgear/scene/model/SGOffsetTransform.cxx new file mode 100644 index 00000000..b59aebd8 --- /dev/null +++ b/simgear/scene/model/SGOffsetTransform.cxx @@ -0,0 +1,68 @@ +/* -*-c++-*- + * + * Copyright (C) 2006-2007 Mathias Froehlich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "SGOffsetTransform.hxx" + +SGOffsetTransform::SGOffsetTransform(double scaleFactor) : + _scaleFactor(scaleFactor), + _rScaleFactor(1/scaleFactor) +{ +} + +bool +SGOffsetTransform::computeLocalToWorldMatrix(osg::Matrix& matrix, + osg::NodeVisitor* nv) const +{ + if (nv && nv->getVisitorType() == osg::NodeVisitor::CULL_VISITOR) { + osg::Vec3 center = nv->getEyePoint(); + osg::Matrix transform; + transform(0,0) = _scaleFactor; + transform(1,1) = _scaleFactor; + transform(2,2) = _scaleFactor; + transform(3,0) = center[0]*(1 - _scaleFactor); + transform(3,1) = center[1]*(1 - _scaleFactor); + transform(3,2) = center[2]*(1 - _scaleFactor); + matrix.preMult(transform); + } + return true; +} + +bool +SGOffsetTransform::computeWorldToLocalMatrix(osg::Matrix& matrix, + osg::NodeVisitor* nv) const +{ + if (nv && nv->getVisitorType() == osg::NodeVisitor::CULL_VISITOR) { + osg::Vec3 center = nv->getEyePoint(); + osg::Matrix transform; + transform(0,0) = _rScaleFactor; + transform(1,1) = _rScaleFactor; + transform(2,2) = _rScaleFactor; + transform(3,0) = center[0]*(1 - _rScaleFactor); + transform(3,1) = center[1]*(1 - _rScaleFactor); + transform(3,2) = center[2]*(1 - _rScaleFactor); + matrix.postMult(transform); + } + return true; +} diff --git a/simgear/scene/model/SGOffsetTransform.hxx b/simgear/scene/model/SGOffsetTransform.hxx new file mode 100644 index 00000000..5edddadb --- /dev/null +++ b/simgear/scene/model/SGOffsetTransform.hxx @@ -0,0 +1,39 @@ +/* -*-c++-*- + * + * Copyright (C) 2006-2007 Mathias Froehlich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifndef SG_OFFSET_TRASNFORM_HXX +#define SG_OFFSET_TRASNFORM_HXX + +#include + +class SGOffsetTransform : public osg::Transform { +public: + SGOffsetTransform(double scaleFactor); + virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, + osg::NodeVisitor* nv) const; + virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix, + osg::NodeVisitor* nv) const; +private: + double _scaleFactor; + double _rScaleFactor; +}; + +#endif diff --git a/simgear/scene/tgdb/Makefile.am b/simgear/scene/tgdb/Makefile.am index bdc8cf53..21ab3fb8 100644 --- a/simgear/scene/tgdb/Makefile.am +++ b/simgear/scene/tgdb/Makefile.am @@ -6,17 +6,24 @@ noinst_HEADERS = include_HEADERS = \ apt_signs.hxx \ - leaf.hxx \ obj.hxx \ pt_lights.hxx \ userdata.hxx \ - vasi.hxx + SGOceanTile.hxx \ + SGVasiDrawable.hxx \ + SGDirectionalLightBin.hxx \ + SGLightBin.hxx \ + SGOceanTile.hxx \ + SGTexturedTriangleBin.hxx \ + SGTriangleBin.hxx \ + SGVertexArrayBin.hxx libsgtgdb_a_SOURCES = \ apt_signs.cxx \ - leaf.cxx \ obj.cxx \ pt_lights.cxx \ - userdata.cxx + userdata.cxx \ + SGOceanTile.cxx \ + SGVasiDrawable.cxx INCLUDES = -I$(top_srcdir) diff --git a/simgear/scene/tgdb/SGDirectionalLightBin.hxx b/simgear/scene/tgdb/SGDirectionalLightBin.hxx new file mode 100644 index 00000000..4b2be508 --- /dev/null +++ b/simgear/scene/tgdb/SGDirectionalLightBin.hxx @@ -0,0 +1,78 @@ +/* -*-c++-*- + * + * Copyright (C) 2006-2007 Mathias Froehlich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifndef SG_DIRECTIONAL_LIGHT_BIN_HXX +#define SG_DIRECTIONAL_LIGHT_BIN_HXX + +class SGDirectionalLightBin { +public: + struct Light { + Light(const SGVec3f& p, const SGVec3f& n, const SGVec4f& c) : + position(p), normal(n), color(c) + { } + SGVec3f position; + SGVec3f normal; + SGVec4f color; + }; + typedef std::vector LightList; + + void insert(const Light& light) + { _lights.push_back(light); } + void insert(const SGVec3f& p, const SGVec3f& n, const SGVec4f& c) + { insert(Light(p, n, c)); } + + unsigned getNumLights() const + { return _lights.size(); } + const Light& getLight(unsigned i) const + { return _lights[i]; } + + // helper for sorting lights back to front ... + struct DirectionLess { + DirectionLess(const SGVec3f& direction) : + _direction(direction) + { } + inline bool operator() (const Light& l, const Light& r) const + { return dot(_direction, l.position) < dot(_direction, r.position); } + private: + SGVec3f _direction; + }; + typedef std::multiset LightSet; + + LightList getSortedLights(const SGVec3f& sortDirection) const + { + LightSet lightSet = LightSet(DirectionLess(sortDirection)); + for (unsigned i = 0; i < _lights.size(); ++i) + lightSet.insert(_lights[i]); + + LightList sortedLights; + sortedLights.reserve(_lights.size()); + LightSet::const_iterator i; + for (i = lightSet.begin(); i != lightSet.end(); ++i) + sortedLights.push_back(*i); + + return sortedLights; + } + +private: + LightList _lights; +}; + +#endif diff --git a/simgear/scene/tgdb/SGLightBin.hxx b/simgear/scene/tgdb/SGLightBin.hxx new file mode 100644 index 00000000..09df31e3 --- /dev/null +++ b/simgear/scene/tgdb/SGLightBin.hxx @@ -0,0 +1,50 @@ +/* -*-c++-*- + * + * Copyright (C) 2006-2007 Mathias Froehlich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifndef SG_LIGHT_BIN_HXX +#define SG_LIGHT_BIN_HXX + +class SGLightBin { +public: + struct Light { + Light(const SGVec3f& p, const SGVec4f& c) : + position(p), color(c) + { } + SGVec3f position; + SGVec4f color; + }; + typedef std::vector LightList; + + void insert(const Light& light) + { _lights.push_back(light); } + void insert(const SGVec3f& p, const SGVec4f& c) + { insert(Light(p, c)); } + + unsigned getNumLights() const + { return _lights.size(); } + const Light& getLight(unsigned i) const + { return _lights[i]; } + +private: + LightList _lights; +}; + +#endif diff --git a/simgear/scene/tgdb/SGOceanTile.cxx b/simgear/scene/tgdb/SGOceanTile.cxx new file mode 100644 index 00000000..017436ea --- /dev/null +++ b/simgear/scene/tgdb/SGOceanTile.cxx @@ -0,0 +1,131 @@ +/* -*-c++-*- + * + * Copyright (C) 2006-2007 Mathias Froehlich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "SGOceanTile.hxx" + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +// Generate an ocean tile +osg::Node* SGOceanTile(const SGBucket& b, SGMaterialLib *matlib) +{ + osg::StateSet *stateSet = 0; + + double tex_width = 1000.0; + + // find Ocean material in the properties list + SGMaterial *mat = matlib->find( "Ocean" ); + if ( mat != NULL ) { + // set the texture width and height values for this + // material + tex_width = mat->get_xsize(); + + // set ssgState + stateSet = mat->get_state(); + } else { + SG_LOG( SG_TERRAIN, SG_ALERT, "Ack! unknown use material name = Ocean"); + } + + // Calculate center point + SGVec3d cartCenter = SGVec3d::fromGeod(b.get_center()); + Point3D center = Point3D(cartCenter[0], cartCenter[1], cartCenter[2]); + + double clon = b.get_center_lon(); + double clat = b.get_center_lat(); + double height = b.get_height(); + double width = b.get_width(); + + // Caculate corner vertices + SGGeod geod[4]; + geod[0] = SGGeod::fromDeg( clon - 0.5*width, clat - 0.5*height ); + geod[1] = SGGeod::fromDeg( clon + 0.5*width, clat - 0.5*height ); + geod[2] = SGGeod::fromDeg( clon + 0.5*width, clat + 0.5*height ); + geod[3] = SGGeod::fromDeg( clon - 0.5*width, clat + 0.5*height ); + + int i; + SGVec3f normals[4]; + SGVec3d rel[4]; + for ( i = 0; i < 4; ++i ) { + SGVec3d cart = SGVec3d::fromGeod(geod[i]); + rel[i] = cart - center.toSGVec3d(); + normals[i] = toVec3f(normalize(cart)); + } + + // Calculate texture coordinates + point_list geod_nodes; + geod_nodes.clear(); + geod_nodes.reserve(4); + int_list rectangle; + rectangle.clear(); + rectangle.reserve(4); + for ( i = 0; i < 4; ++i ) { + geod_nodes.push_back( Point3D::fromSGGeod(geod[i]) ); + rectangle.push_back( i ); + } + point_list texs = sgCalcTexCoords( b, geod_nodes, rectangle, + 1000.0 / tex_width ); + + // Allocate ssg structure + osg::Vec3Array *vl = new osg::Vec3Array; + osg::Vec3Array *nl = new osg::Vec3Array; + osg::Vec2Array *tl = new osg::Vec2Array; + + for ( i = 0; i < 4; ++i ) { + vl->push_back(rel[i].osg()); + nl->push_back(normals[i].osg()); + tl->push_back(texs[i].toSGVec2f().osg()); + } + + osg::Vec4Array* cl = new osg::Vec4Array; + cl->push_back(osg::Vec4(1, 1, 1, 1)); + + osg::Geometry* geometry = new osg::Geometry; + geometry->setVertexArray(vl); + geometry->setNormalArray(nl); + geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); + geometry->setColorArray(cl); + geometry->setColorBinding(osg::Geometry::BIND_OVERALL); + geometry->setTexCoordArray(0, tl); + osg::DrawArrays* drawArrays; + drawArrays = new osg::DrawArrays(GL_TRIANGLE_FAN, 0, vl->size()); + geometry->addPrimitiveSet(drawArrays); + + osg::Geode* geode = new osg::Geode; + geode->setName("Ocean tile"); + geode->addDrawable(geometry); + geode->setStateSet(stateSet); + + return geode; +} diff --git a/simgear/scene/tgdb/SGOceanTile.hxx b/simgear/scene/tgdb/SGOceanTile.hxx new file mode 100644 index 00000000..3e48aebc --- /dev/null +++ b/simgear/scene/tgdb/SGOceanTile.hxx @@ -0,0 +1,33 @@ +/* -*-c++-*- + * + * Copyright (C) 2006-2007 Mathias Froehlich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifndef _SG_OceanTile_HXX +#define _SG_OceanTile_HXX + +#include + +class SGBucket; +class SGMaterialLib; + +// Generate an ocean tile +osg::Node* SGOceanTile(const SGBucket& b, SGMaterialLib *matlib); + +#endif // _SG_OBJ_HXX diff --git a/simgear/scene/tgdb/SGTexturedTriangleBin.hxx b/simgear/scene/tgdb/SGTexturedTriangleBin.hxx new file mode 100644 index 00000000..a2ff327b --- /dev/null +++ b/simgear/scene/tgdb/SGTexturedTriangleBin.hxx @@ -0,0 +1,164 @@ +/* -*-c++-*- + * + * Copyright (C) 2006-2007 Mathias Froehlich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifndef SG_TEXTURED_TRIANGLE_BIN_HXX +#define SG_TEXTURED_TRIANGLE_BIN_HXX + +#include +#include +#include + +#include +#include +#include "SGTriangleBin.hxx" + +struct SGVertNormTex { + SGVertNormTex() + { } + SGVertNormTex(const SGVec3f& v, const SGVec3f& n, const SGVec2f& t) : + vertex(v), normal(n), texCoord(t) + { } + struct less + { + inline bool operator() (const SGVertNormTex& l, + const SGVertNormTex& r) const + { + if (l.vertex < r.vertex) return true; + else if (r.vertex < l.vertex) return false; + else if (l.normal < r.normal) return true; + else if (r.normal < l.normal) return false; + else return l.texCoord < r.texCoord; + } + }; + + SGVec3f vertex; + SGVec3f normal; + SGVec2f texCoord; +}; + +class SGTexturedTriangleBin : public SGTriangleBin { +public: + + // Computes and adds random surface points to the points list. + // The random points are computed with a density of (coverage points)/1 + // The points are offsetted away from the triangles in + // offset * positive normal direction. + void addRandomSurfacePoints(float coverage, float offset, + std::vector& points) const + { + unsigned num = getNumTriangles(); + for (unsigned i = 0; i < num; ++i) { + triangle_ref triangleRef = getTriangleRef(i); + SGVec3f v0 = getVertex(triangleRef[0]).vertex; + SGVec3f v1 = getVertex(triangleRef[1]).vertex; + SGVec3f v2 = getVertex(triangleRef[2]).vertex; + SGVec3f normal = cross(v1 - v0, v2 - v0); + + // Compute the area + float area = 0.5f*length(normal); + if (area <= SGLimitsf::min()) + continue; + + // For partial units of area, use a zombie door method to + // create the proper random chance of a light being created + // for this triangle + float unit = area + sg_random()*coverage; + + SGVec3f offsetVector = offset*normalize(normal); + // generate a light point for each unit of area + while ( coverage < unit ) { + float a = sg_random(); + float b = sg_random(); + if ( a + b > 1 ) { + a = 1 - a; + b = 1 - b; + } + float c = 1 - a - b; + SGVec3f randomPoint = offsetVector + a*v0 + b*v1 + c*v2; + points.push_back(randomPoint); + unit -= coverage; + } + } + } + + osg::Geometry* buildGeometry(const TriangleVector& triangles) const + { + // Do not build anything if there is nothing in here ... + if (empty() || triangles.empty()) + return 0; + + // FIXME: do not include all values here ... + osg::Vec3Array* vertices = new osg::Vec3Array; + osg::Vec3Array* normals = new osg::Vec3Array; + osg::Vec2Array* texCoords = new osg::Vec2Array; + + osg::Vec4Array* colors = new osg::Vec4Array; + colors->push_back(osg::Vec4(1, 1, 1, 1)); + + osg::Geometry* geometry = new osg::Geometry; + geometry->setVertexArray(vertices); + geometry->setNormalArray(normals); + geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); + geometry->setColorArray(colors); + geometry->setColorBinding(osg::Geometry::BIND_OVERALL); + geometry->setTexCoordArray(0, texCoords); + + const unsigned invalid = ~unsigned(0); + std::vector indexMap(getNumVertices(), invalid); + + osg::DrawElementsUInt* drawElements; + drawElements = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES); + for (index_type i = 0; i < triangles.size(); ++i) { + triangle_ref triangle = triangles[i]; + if (indexMap[triangle[0]] == invalid) { + indexMap[triangle[0]] = vertices->size(); + vertices->push_back(getVertex(triangle[0]).vertex.osg()); + normals->push_back(getVertex(triangle[0]).normal.osg()); + texCoords->push_back(getVertex(triangle[0]).texCoord.osg()); + } + drawElements->push_back(indexMap[triangle[0]]); + + if (indexMap[triangle[1]] == invalid) { + indexMap[triangle[1]] = vertices->size(); + vertices->push_back(getVertex(triangle[1]).vertex.osg()); + normals->push_back(getVertex(triangle[1]).normal.osg()); + texCoords->push_back(getVertex(triangle[1]).texCoord.osg()); + } + drawElements->push_back(indexMap[triangle[1]]); + + if (indexMap[triangle[2]] == invalid) { + indexMap[triangle[2]] = vertices->size(); + vertices->push_back(getVertex(triangle[2]).vertex.osg()); + normals->push_back(getVertex(triangle[2]).normal.osg()); + texCoords->push_back(getVertex(triangle[2]).texCoord.osg()); + } + drawElements->push_back(indexMap[triangle[2]]); + } + geometry->addPrimitiveSet(drawElements); + + return geometry; + } + + osg::Geometry* buildGeometry() const + { return buildGeometry(getTriangles()); } +}; + +#endif diff --git a/simgear/scene/tgdb/SGTriangleBin.hxx b/simgear/scene/tgdb/SGTriangleBin.hxx new file mode 100644 index 00000000..2ba045f6 --- /dev/null +++ b/simgear/scene/tgdb/SGTriangleBin.hxx @@ -0,0 +1,123 @@ +/* -*-c++-*- + * + * Copyright (C) 2006-2007 Mathias Froehlich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifndef SG_TRIANGLE_BIN_HXX +#define SG_TRIANGLE_BIN_HXX + +#include +#include +#include "SGVertexArrayBin.hxx" + +template +class SGTriangleBin : public SGVertexArrayBin { +public: +#define BUILD_EDGE_MAP + typedef typename SGVertexArrayBin::value_type value_type; + typedef typename SGVertexArrayBin::index_type index_type; + typedef SGVec2 edge_ref; + typedef SGVec3 triangle_ref; + typedef std::vector TriangleVector; + typedef std::vector TriangleList; + typedef std::map EdgeMap; + + void insert(const value_type& v0, const value_type& v1, const value_type& v2) + { + index_type i0 = SGVertexArrayBin::insert(v0); + index_type i1 = SGVertexArrayBin::insert(v1); + index_type i2 = SGVertexArrayBin::insert(v2); + index_type triangleIndex = _triangleVector.size(); + _triangleVector.push_back(triangle_ref(i0, i1, i2)); +#ifdef BUILD_EDGE_MAP + _edgeMap[edge_ref(i0, i1)].push_back(triangleIndex); + _edgeMap[edge_ref(i1, i2)].push_back(triangleIndex); + _edgeMap[edge_ref(i2, i0)].push_back(triangleIndex); +#endif + } + + unsigned getNumTriangles() const + { return _triangleVector.size(); } + const triangle_ref& getTriangleRef(index_type i) const + { return _triangleVector[i]; } + const TriangleVector& getTriangles() const + { return _triangleVector; } + +#ifdef BUILD_EDGE_MAP +// protected: //FIXME + void getConnectedSets(std::list& connectSets) const + { + std::vector processedTriangles(getNumTriangles(), false); + for (index_type i = 0; i < getNumTriangles(); ++i) { + if (processedTriangles[i]) + continue; + + TriangleVector currentSet; + std::vector edgeStack; + + { + triangle_ref triangleRef = getTriangleRef(i); + edgeStack.push_back(edge_ref(triangleRef[0], triangleRef[1])); + edgeStack.push_back(edge_ref(triangleRef[1], triangleRef[2])); + edgeStack.push_back(edge_ref(triangleRef[2], triangleRef[0])); + currentSet.push_back(triangleRef); + processedTriangles[i] = true; + } + + while (!edgeStack.empty()) { + edge_ref edge = edgeStack.back(); + edgeStack.pop_back(); + + typename EdgeMap::const_iterator emiList[2] = { + _edgeMap.find(edge), + _edgeMap.find(edge_ref(edge[1], edge[0])) + }; + for (unsigned ei = 0; ei < 2; ++ei) { + typename EdgeMap::const_iterator emi = emiList[ei]; + if (emi == _edgeMap.end()) + continue; + + for (unsigned ti = 0; ti < emi->second.size(); ++ti) { + index_type triangleIndex = emi->second[ti]; + if (processedTriangles[triangleIndex]) + continue; + + triangle_ref triangleRef = getTriangleRef(triangleIndex); + edgeStack.push_back(edge_ref(triangleRef[0], triangleRef[1])); + edgeStack.push_back(edge_ref(triangleRef[1], triangleRef[2])); + edgeStack.push_back(edge_ref(triangleRef[2], triangleRef[0])); + currentSet.push_back(triangleRef); + processedTriangles[triangleIndex] = true; + } + } + } + + connectSets.push_back(currentSet); + } + } +#endif + +private: + TriangleVector _triangleVector; +#ifdef BUILD_EDGE_MAP + EdgeMap _edgeMap; +#endif +}; + +#endif diff --git a/simgear/scene/tgdb/SGVasiDrawable.cxx b/simgear/scene/tgdb/SGVasiDrawable.cxx new file mode 100644 index 00000000..24e55388 --- /dev/null +++ b/simgear/scene/tgdb/SGVasiDrawable.cxx @@ -0,0 +1,162 @@ +/* -*-c++-*- + * + * Copyright (C) 2006-2007 Mathias Froehlich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "SGVasiDrawable.hxx" + +struct SGVasiDrawable::LightData { + LightData(const SGVec3f& p, const SGVec3f& n, const SGVec3f& up) : + position(p), + normal(n), + horizontal(normalize(cross(up, n))), + normalCrossHorizontal(normalize(cross(n, horizontal))) + { } + + void draw(const SGVec4f& color) const + { + glBegin(GL_POINTS); + glColor4fv(color.data()); + glNormal3fv(normal.data()); + glVertex3fv(position.data()); + glEnd(); + } + + SGVec3f position; + SGVec3f normal; + SGVec3f horizontal; + SGVec3f normalCrossHorizontal; +}; + +SGVasiDrawable::SGVasiDrawable(const SGVasiDrawable& vd, const osg::CopyOp&) : + _lights(vd._lights), + _red(vd._red), + _white(vd._white) +{ + setUseDisplayList(false); + setSupportsDisplayList(false); +} + +SGVasiDrawable::SGVasiDrawable(const SGVec4f& red, const SGVec4f& white) : + _red(red), + _white(white) +{ + setUseDisplayList(false); + setSupportsDisplayList(false); +} + +void +SGVasiDrawable::addLight(const SGVec3f& position, const SGVec3f& normal, + const SGVec3f& up, float azimutDeg) +{ + SGVec3f horizontal(normalize(cross(up, normal))); + SGVec3f zeroGlideSlope = normalize(cross(horizontal, up)); + SGQuatf rotation = SGQuatf::fromAngleAxisDeg(azimutDeg, horizontal); + SGVec3f azimutGlideSlope = rotation.transform(zeroGlideSlope); + addLight(position, azimutGlideSlope, up); +} + +void +SGVasiDrawable::addLight(const SGVec3f& position, const SGVec3f& normal, + const SGVec3f& up) +{ + _lights.push_back(LightData(position, normal, up)); +} + +void +SGVasiDrawable::drawImplementation(osg::RenderInfo& renderInfo) const +{ + // Make sure we have the current state set +// renderInfo.getState()->apply(); + + // Retrieve the eye point in local coords + osg::Matrix m; + m.invert(renderInfo.getState()->getModelViewMatrix()); + SGVec3f eyePoint(m.preMult(osg::Vec3(0, 0, 0))); + + // paint the points + for (unsigned i = 0; i < _lights.size(); ++i) + draw(eyePoint, _lights[i]); +} + +osg::BoundingBox +SGVasiDrawable::computeBound() const +{ + osg::BoundingBox bb; + for (unsigned i = 0; i < _lights.size(); ++i) + bb.expandBy(_lights[i].position.osg()); + + // blow up to avoid being victim to small feature culling ... + bb.expandBy(bb._min - osg::Vec3(1, 1, 1)); + bb.expandBy(bb._max + osg::Vec3(1, 1, 1)); + return bb; +} + +SGVec4f +SGVasiDrawable::getColor(float angleDeg) const +{ + float transDeg = 0.05f; + if (angleDeg < -transDeg) { + return _red; + } else if (angleDeg < transDeg) { + float fac = angleDeg*0.5f/transDeg + 0.5f; + return _red + fac*(_white - _red); + } else { + return _white; + } +} + +void +SGVasiDrawable::draw(const SGVec3f& eyePoint, const LightData& light) const +{ + // vector pointing from the light position to the eye + SGVec3f lightToEye = eyePoint - light.position; + + // dont' draw, we are behind it + if (dot(lightToEye, light.normal) < SGLimitsf::min()) + return; + + // Now project the eye point vector into the plane defined by the + // glideslope direction and the up direction + SGVec3f projLightToEye = lightToEye + - light.horizontal*dot(lightToEye, light.horizontal); + + // dont' draw, if we are to near, looks like we are already behind + float sqrProjLightToEyeLength = dot(projLightToEye, projLightToEye); + if (sqrProjLightToEyeLength < 1e-3*1e-3) + return; + + // the scalar product of the glide slope up direction with the eye vector + float dotProd = dot(projLightToEye, light.normalCrossHorizontal); + float sinAngle = dotProd/sqrt(sqrProjLightToEyeLength); + if (sinAngle < -1) + sinAngle = -1; + if (1 < sinAngle) + sinAngle = 1; + + float angleDeg = SGMiscf::rad2deg(asin(sinAngle)); + light.draw(getColor(angleDeg)); +} + diff --git a/simgear/scene/tgdb/SGVasiDrawable.hxx b/simgear/scene/tgdb/SGVasiDrawable.hxx new file mode 100644 index 00000000..242e3935 --- /dev/null +++ b/simgear/scene/tgdb/SGVasiDrawable.hxx @@ -0,0 +1,63 @@ +/* -*-c++-*- + * + * Copyright (C) 2006-2007 Mathias Froehlich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifndef _SG_VASI_DRAWABLE_HXX +#define _SG_VASI_DRAWABLE_HXX + +#include + +#include +#include + +class SGVasiDrawable : public osg::Drawable { + struct LightData; +public: + META_Object(SimGear, SGVasiDrawable); + SGVasiDrawable(const SGVasiDrawable&, const osg::CopyOp&); + SGVasiDrawable(const SGVec4f& red = SGVec4f(1, 0, 0, 1), + const SGVec4f& white = SGVec4f(1, 1, 1, 1)); + + /// Add a red/white switching light pointing into the direction that + /// is computed to point in about the given normal with the given + /// azimut angle upwards. The up direction is the world up direction + /// that defines the horizontal plane. + void addLight(const SGVec3f& position, const SGVec3f& normal, + const SGVec3f& up, float azimutDeg); + + /// add a red/white switching light pointing towards normal + /// at the given position with the given up vector. The up direction + /// is the world up direction that defines the horizontal plane. + void addLight(const SGVec3f& position, const SGVec3f& normal, + const SGVec3f& up); + + virtual void drawImplementation(osg::RenderInfo& renderInfo) const; + virtual osg::BoundingBox computeBound() const; + +private: + SGVec4f getColor(float angleDeg) const; + void draw(const SGVec3f& eyePoint, const LightData& light) const; + + std::vector _lights; + SGVec4f _red; + SGVec4f _white; +}; + +#endif // _SG_VASI_LIGHT_HXX diff --git a/simgear/scene/tgdb/SGVertexArrayBin.hxx b/simgear/scene/tgdb/SGVertexArrayBin.hxx new file mode 100644 index 00000000..464ac89c --- /dev/null +++ b/simgear/scene/tgdb/SGVertexArrayBin.hxx @@ -0,0 +1,63 @@ +/* -*-c++-*- + * + * Copyright (C) 2006-2007 Mathias Froehlich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifndef SG_VERTEX_ARRAY_BIN_HXX +#define SG_VERTEX_ARRAY_BIN_HXX + +#include +#include + +template +class SGVertexArrayBin { +public: + typedef T value_type; + typedef typename value_type::less less; + typedef std::vector ValueVector; + typedef typename ValueVector::size_type index_type; + typedef std::map ValueMap; + + index_type insert(const value_type& t) + { + typename ValueMap::iterator i = _valueMap.find(t); + if (i != _valueMap.end()) + return i->second; + + index_type index = _values.size(); + _valueMap[t] = index; + _values.push_back(t); + return index; + } + + const value_type& getVertex(index_type index) const + { return _values[index]; } + + index_type getNumVertices() const + { return _values.size(); } + + bool empty() const + { return _values.empty(); } + +private: + ValueVector _values; + ValueMap _valueMap; +}; + +#endif diff --git a/simgear/scene/tgdb/leaf.hxx b/simgear/scene/tgdb/leaf.hxx deleted file mode 100644 index 61506ec9..00000000 --- a/simgear/scene/tgdb/leaf.hxx +++ /dev/null @@ -1,58 +0,0 @@ -// leaf.hxx -- function to build and ssg leaf from higher level data. -// -// Written by Curtis Olson, started October 1997. -// -// Copyright (C) 1997 - 2003 Curtis L. Olson - http://www.flightgear.org/~curt -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// $Id$ - - -#ifndef _SG_LEAF_HXX -#define _SG_LEAF_HXX - - -#ifndef __cplusplus -# error This library requires C++ -#endif - - -#include - -#include STL_STRING - -#include -#include - -#include - -SG_USING_STD(string); - - -class SGMaterialLib; // forward declaration. - - -// Create a ssg leaf -osg::Drawable* SGMakeLeaf( const string& path, - const GLenum ty, SGMaterial *mat, - const point_list& nodes, const point_list& normals, - const point_list& texcoords, - const int_list& node_index, - const int_list& normal_index, - const int_list& tex_index, - const bool calc_lights, osg::Vec3Array *lights ); - -#endif // _SG_LEAF_HXX diff --git a/simgear/scene/tgdb/obj.cxx b/simgear/scene/tgdb/obj.cxx index 5251a263..def9e98a 100644 --- a/simgear/scene/tgdb/obj.cxx +++ b/simgear/scene/tgdb/obj.cxx @@ -26,595 +26,424 @@ # include #endif +#include "obj.hxx" + #include -#include - -#include STL_STRING - -#include #include #include #include #include #include #include +#include #include +#include -#include -#include - -#include +#include #include #include #include -#include -#include #include #include +#include #include #include -#include -#include -#include +#include +#include -#include "obj.hxx" +#include "SGTexturedTriangleBin.hxx" +#include "SGLightBin.hxx" +#include "SGDirectionalLightBin.hxx" -SG_USING_STD(string); -SG_USING_STD(list); +#include "pt_lights.hxx" -struct Leaf { - GLenum type; - int index; -}; +typedef std::map SGMaterialTriangleMap; +typedef std::list SGLightListBin; +typedef std::list SGDirectionalLightListBin; +struct SGTileGeometryBin { + SGMaterialTriangleMap materialTriangleMap; + SGLightBin tileLights; + SGLightBin randomTileLights; + SGDirectionalLightBin runwayLights; + SGDirectionalLightBin taxiLights; + SGDirectionalLightListBin vasiLights; + SGDirectionalLightListBin rabitLights; + SGLightListBin odalLights; + SGDirectionalLightListBin reilLights; -// Generate an ocean tile -bool SGGenTile( const string& path, const SGBucket& b, - SGMaterialLib *matlib, osg::Group* group ) -{ - osg::StateSet *state = 0; + static SGVec4f + getMaterialLightColor(const SGMaterial* material) + { + if (!material) + return SGVec4f(1, 1, 1, 0.8); + return material->get_light_color(); + } - double tex_width = 1000.0; + static void + addPointGeometry(SGLightBin& lights, + const std::vector& vertices, + const SGVec4f& color, + const int_list& pts_v) + { + for (unsigned i = 0; i < pts_v.size(); ++i) + lights.insert(toVec3f(vertices[pts_v[i]]), color); + } - // find Ocean material in the properties list - SGMaterial *mat = matlib->find( "Ocean" ); - if ( mat != NULL ) { - // set the texture width and height values for this - // material - tex_width = mat->get_xsize(); - - // set ssgState - state = mat->get_state(); + static void + addPointGeometry(SGDirectionalLightBin& lights, + const std::vector& vertices, + const std::vector& normals, + const SGVec4f& color, + const int_list& pts_v, + const int_list& pts_n) + { + // If the normal indices match the vertex indices, use seperate + // normal indices. Else reuse the vertex indices for the normals. + if (pts_v.size() == pts_n.size()) { + for (unsigned i = 0; i < pts_v.size(); ++i) + lights.insert(toVec3f(vertices[pts_v[i]]), normals[pts_n[i]], color); } else { - SG_LOG( SG_TERRAIN, SG_ALERT, - "Ack! unknown usemtl name = " << "Ocean" - << " in " << path ); + for (unsigned i = 0; i < pts_v.size(); ++i) + lights.insert(toVec3f(vertices[pts_v[i]]), normals[pts_v[i]], color); + } + } + + bool + insertPtGeometry(const SGBinObject& obj, SGMaterialLib* matlib) + { + if (obj.get_pts_v().size() != obj.get_pts_n().size()) { + SG_LOG(SG_TERRAIN, SG_ALERT, + "Group list sizes for points do not match!"); + return false; } - // Calculate center point - SGVec3d cartCenter = SGVec3d::fromGeod(b.get_center()); - Point3D center = Point3D(cartCenter[0], cartCenter[1], cartCenter[2]); - - double clon = b.get_center_lon(); - double clat = b.get_center_lat(); - double height = b.get_height(); - double width = b.get_width(); - - // 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() ); + for (unsigned grp = 0; grp < obj.get_pts_v().size(); ++grp) { + std::string materialName = obj.get_pt_materials()[grp]; + SGMaterial* material = matlib->find(materialName); + SGVec4f color = getMaterialLightColor(material); + + if (3 <= materialName.size() && materialName.substr(0, 3) != "RWY") { + // Just plain lights. Not something for the runway. + addPointGeometry(tileLights, obj.get_wgs84_nodes(), color, + obj.get_pts_v()[grp]); + } else if (materialName == "RWY_BLUE_TAXIWAY_LIGHTS" + || materialName == "RWY_GREEN_TAXIWAY_LIGHTS") { + addPointGeometry(taxiLights, obj.get_wgs84_nodes(), obj.get_normals(), + color, obj.get_pts_v()[grp], obj.get_pts_n()[grp]); + } else if (materialName == "RWY_VASI_LIGHTS") { + vasiLights.push_back(SGDirectionalLightBin()); + addPointGeometry(vasiLights.back(), obj.get_wgs84_nodes(), + obj.get_normals(), color, obj.get_pts_v()[grp], + obj.get_pts_n()[grp]); + } else if (materialName == "RWY_SEQUENCED_LIGHTS") { + rabitLights.push_back(SGDirectionalLightBin()); + addPointGeometry(rabitLights.back(), obj.get_wgs84_nodes(), + obj.get_normals(), color, obj.get_pts_v()[grp], + obj.get_pts_n()[grp]); + } else if (materialName == "RWY_ODALS_LIGHTS") { + odalLights.push_back(SGLightBin()); + addPointGeometry(odalLights.back(), obj.get_wgs84_nodes(), + color, obj.get_pts_v()[grp]); + } else if (materialName == "RWY_REIL_LIGHTS") { + reilLights.push_back(SGDirectionalLightBin()); + addPointGeometry(reilLights.back(), obj.get_wgs84_nodes(), + obj.get_normals(), color, obj.get_pts_v()[grp], + obj.get_pts_n()[grp]); + } else { + // what is left must be runway lights + addPointGeometry(runwayLights, obj.get_wgs84_nodes(), + obj.get_normals(), color, obj.get_pts_v()[grp], + obj.get_pts_n()[grp]); + } } - Point3D cart[4], rel[4]; - for ( i = 0; i < 4; ++i ) { - cart[i] = sgGeodToCart(rad[i]); - rel[i] = cart[i] - center; - // cout << "corner " << i << " = " << cart[i] << endl; + return true; + } + + + static SGVec2f + getTexCoord(const std::vector& texCoords, const int_list& tc, + const SGVec2f& tcScale, unsigned i) + { + if (tc.empty()) + return tcScale; + else if (tc.size() == 1) + return mult(texCoords[tc[0]], tcScale); + else + return mult(texCoords[tc[i]], tcScale); + } + + static void + addTriangleGeometry(SGTexturedTriangleBin& triangles, + const std::vector& vertices, + const std::vector& normals, + const std::vector& texCoords, + const int_list& tris_v, + const int_list& tris_n, + const int_list& tris_tc, + const SGVec2f& tcScale) + { + if (tris_v.size() != tris_n.size()) { + // If the normal indices do not match, they should be inmplicitly + // the same than the vertex indices. So just call ourselves again + // with the matching index vector. + addTriangleGeometry(triangles, vertices, normals, texCoords, + tris_v, tris_v, tris_tc, tcScale); + return; } - // 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; + for (unsigned i = 2; i < tris_v.size(); i += 3) { + SGVertNormTex v0; + v0.vertex = toVec3f(vertices[tris_v[i-2]]); + v0.normal = normals[tris_n[i-2]]; + v0.texCoord = getTexCoord(texCoords, tris_tc, tcScale, i-2); + SGVertNormTex v1; + v1.vertex = toVec3f(vertices[tris_v[i-1]]); + v1.normal = normals[tris_n[i-1]]; + v1.texCoord = getTexCoord(texCoords, tris_tc, tcScale, i-1); + SGVertNormTex v2; + v2.vertex = toVec3f(vertices[tris_v[i]]); + v2.normal = normals[tris_n[i]]; + v2.texCoord = getTexCoord(texCoords, tris_tc, tcScale, i); + triangles.insert(v0, v1, v2); + } + } + + static void + addStripGeometry(SGTexturedTriangleBin& triangles, + const std::vector& vertices, + const std::vector& normals, + const std::vector& texCoords, + const int_list& strips_v, + const int_list& strips_n, + const int_list& strips_tc, + const SGVec2f& tcScale) + { + if (strips_v.size() != strips_n.size()) { + // If the normal indices do not match, they should be inmplicitly + // the same than the vertex indices. So just call ourselves again + // with the matching index vector. + addStripGeometry(triangles, vertices, normals, texCoords, + strips_v, strips_v, strips_tc, tcScale); + return; } - // Calculate texture coordinates - point_list geod_nodes; - geod_nodes.clear(); - geod_nodes.reserve(4); - int_list rectangle; - rectangle.clear(); - rectangle.reserve(4); - for ( i = 0; i < 4; ++i ) { - geod_nodes.push_back( geod[i] ); - rectangle.push_back( i ); + for (unsigned i = 2; i < strips_v.size(); ++i) { + SGVertNormTex v0; + v0.vertex = toVec3f(vertices[strips_v[i-2]]); + v0.normal = normals[strips_n[i-2]]; + v0.texCoord = getTexCoord(texCoords, strips_tc, tcScale, i-2); + SGVertNormTex v1; + v1.vertex = toVec3f(vertices[strips_v[i-1]]); + v1.normal = normals[strips_n[i-1]]; + v1.texCoord = getTexCoord(texCoords, strips_tc, tcScale, i-1); + SGVertNormTex v2; + v2.vertex = toVec3f(vertices[strips_v[i]]); + v2.normal = normals[strips_n[i]]; + v2.texCoord = getTexCoord(texCoords, strips_tc, tcScale, i); + if (i%2) + triangles.insert(v1, v0, v2); + else + triangles.insert(v0, v1, v2); } - point_list texs = sgCalcTexCoords( b, geod_nodes, rectangle, - 1000.0 / tex_width ); - - // Allocate ssg structure - osg::Vec3Array *vl = new osg::Vec3Array; - osg::Vec3Array *nl = new osg::Vec3Array; - osg::Vec2Array *tl = new osg::Vec2Array; - - for ( i = 0; i < 4; ++i ) { - vl->push_back(osg::Vec3(rel[i].x(), rel[i].y(), rel[i].z())); - nl->push_back(osg::Vec3(normals[i].x(), normals[i].y(), normals[i].z())); - tl->push_back(osg::Vec2(texs[i].x(), texs[i].y())); + } + + static void + addFanGeometry(SGTexturedTriangleBin& triangles, + const std::vector& vertices, + const std::vector& normals, + const std::vector& texCoords, + const int_list& fans_v, + const int_list& fans_n, + const int_list& fans_tc, + const SGVec2f& tcScale) + { + if (fans_v.size() != fans_n.size()) { + // If the normal indices do not match, they should be implicitly + // the same than the vertex indices. So just call ourselves again + // with the matching index vector. + addFanGeometry(triangles, vertices, normals, texCoords, + fans_v, fans_v, fans_tc, tcScale); + return; } - - osg::Vec4Array* cl = new osg::Vec4Array; - cl->push_back(osg::Vec4(1, 1, 1, 1)); - osg::Geometry* geometry = new osg::Geometry; - geometry->setVertexArray(vl); - geometry->setNormalArray(nl); - geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); - geometry->setColorArray(cl); - geometry->setColorBinding(osg::Geometry::BIND_OVERALL); - geometry->setTexCoordArray(0, tl); - geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_FAN, 0, vl->size())); + SGVertNormTex v0; + v0.vertex = toVec3f(vertices[fans_v[0]]); + v0.normal = normals[fans_n[0]]; + v0.texCoord = getTexCoord(texCoords, fans_tc, tcScale, 0); + SGVertNormTex v1; + v1.vertex = toVec3f(vertices[fans_v[1]]); + v1.normal = normals[fans_n[1]]; + v1.texCoord = getTexCoord(texCoords, fans_tc, tcScale, 1); + for (unsigned i = 2; i < fans_v.size(); ++i) { + SGVertNormTex v2; + v2.vertex = toVec3f(vertices[fans_v[i]]); + v2.normal = normals[fans_n[i]]; + v2.texCoord = getTexCoord(texCoords, fans_tc, tcScale, i); + triangles.insert(v0, v1, v2); + v1 = v2; + } + } + + SGVec2f getTexCoordScale(const std::string& name, SGMaterialLib* matlib) + { + if (!matlib) + return SGVec2f(1, 1); + SGMaterial* material = matlib->find(name); + if (!material) + return SGVec2f(1, 1); + + return material->get_tex_coord_scale(); + } + + bool + insertSurfaceGeometry(const SGBinObject& obj, SGMaterialLib* matlib) + { + if (obj.get_tris_n().size() < obj.get_tris_v().size() || + obj.get_tris_tc().size() < obj.get_tris_v().size()) { + SG_LOG(SG_TERRAIN, SG_ALERT, + "Group list sizes for triangles do not match!"); + return false; + } + + for (unsigned grp = 0; grp < obj.get_tris_v().size(); ++grp) { + std::string materialName = obj.get_tri_materials()[grp]; + SGVec2f tcScale = getTexCoordScale(materialName, matlib); + addTriangleGeometry(materialTriangleMap[materialName], + obj.get_wgs84_nodes(), obj.get_normals(), + obj.get_texcoords(), obj.get_tris_v()[grp], + obj.get_tris_n()[grp], obj.get_tris_tc()[grp], + tcScale); + } + + if (obj.get_strips_n().size() < obj.get_strips_v().size() || + obj.get_strips_tc().size() < obj.get_strips_v().size()) { + SG_LOG(SG_TERRAIN, SG_ALERT, + "Group list sizes for strips do not match!"); + return false; + } + for (unsigned grp = 0; grp < obj.get_strips_v().size(); ++grp) { + std::string materialName = obj.get_strip_materials()[grp]; + SGVec2f tcScale = getTexCoordScale(materialName, matlib); + addStripGeometry(materialTriangleMap[materialName], + obj.get_wgs84_nodes(), obj.get_normals(), + obj.get_texcoords(), obj.get_strips_v()[grp], + obj.get_strips_n()[grp], obj.get_strips_tc()[grp], + tcScale); + } + + if (obj.get_fans_n().size() < obj.get_fans_v().size() || + obj.get_fans_tc().size() < obj.get_fans_v().size()) { + SG_LOG(SG_TERRAIN, SG_ALERT, + "Group list sizes for fans do not match!"); + return false; + } + for (unsigned grp = 0; grp < obj.get_fans_v().size(); ++grp) { + std::string materialName = obj.get_fan_materials()[grp]; + SGVec2f tcScale = getTexCoordScale(materialName, matlib); + addFanGeometry(materialTriangleMap[materialName], + obj.get_wgs84_nodes(), obj.get_normals(), + obj.get_texcoords(), obj.get_fans_v()[grp], + obj.get_fans_n()[grp], obj.get_fans_tc()[grp], + tcScale); + } + return true; + } + + osg::Node* getSurfaceGeometry(SGMaterialLib* matlib) const + { + if (materialTriangleMap.empty()) + return 0; + osg::Geode* geode = new osg::Geode; - geode->setName(path); - geode->addDrawable(geometry); - geode->setStateSet(state); + SGMaterialTriangleMap::const_iterator i; + for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) { +#define CHUNCKED +#ifdef CHUNCKED + SGMaterial *mat = matlib->find(i->first); - group->addChild(geode); + std::list connectSets; + i->second.getConnectedSets(connectSets); - return true; -} - - -/** - * SSG callback for an in-range leaf of randomly-placed objects. - * - * This pretraversal callback is attached to a branch that is - * traversed only when a leaf is in range. If the leaf is not - * currently prepared to be populated with randomly-placed objects, - * this callback will prepare it (actual population is handled by - * the tri_in_range_callback for individual triangles). - * - * @param entity The entity to which the callback is attached (not used). - * @param mask The entity's traversal mask (not used). - * @return Always 1, to allow traversal and culling to continue. - */ -// static int -// leaf_in_range_callback (ssgEntity * entity, int mask) -// { -// SGLeafUserData * data = (SGLeafUserData *)entity->getUserData(); - -// if (!data->is_filled_in) { -// // Iterate through all the triangles -// // and populate them. -// int num_tris = data->leaf->getNumTriangles(); -// for ( int i = 0; i < num_tris; ++i ) { -// data->setup_triangle(i); -// } -// data->is_filled_in = true; -// } -// return 1; -// } - - -/** - * SSG callback for an out-of-range leaf of randomly-placed objects. - * - * This pretraversal callback is attached to a branch that is - * traversed only when a leaf is out of range. If the leaf is - * currently prepared to be populated with randomly-placed objects (or - * is actually populated), the objects will be removed. - * - * @param entity The entity to which the callback is attached (not used). - * @param mask The entity's traversal mask (not used). - * @return Always 0, to prevent any further traversal or culling. - */ -// static int -// leaf_out_of_range_callback (ssgEntity * entity, int mask) -// { -// SGLeafUserData * data = (SGLeafUserData *)entity->getUserData(); -// if (data->is_filled_in) { -// data->branch->removeAllKids(); -// data->is_filled_in = false; -// } -// return 0; -// } - - -/** - * Randomly place objects on a surface. - * - * The leaf node provides the geometry of the surface, while the - * material provides the objects and placement density. Latitude - * and longitude are required so that the objects can be rotated - * to the world-up vector. This function does not actually add - * any objects; instead, it attaches an ssgRangeSelector to the - * branch with callbacks to generate the objects when needed. - * - * @param leaf The surface where the objects should be placed. - * @param branch The branch that will hold the randomly-placed objects. - * @param center The center of the leaf in FlightGear coordinates. - * @param material_name The name of the surface's material. - */ -static void -gen_random_surface_objects (osg::Drawable *leaf, - osg::Group *branch, - Point3D *center, - SGMaterial *mat ) -{ - // OSGFIXME -#if 0 - // If the surface has no triangles, return - // now. - int num_tris = leaf->getNumTriangles(); - if (num_tris < 1) - return; - - // If the material has no randomly-placed - // objects, return now. - if (mat->get_object_group_count() < 1) - return; - - // Calculate the geodetic centre of - // the tile, for aligning automatic - // objects. - double xyz[3], lon_rad, lat_rad, alt_m; - xyz[0] = center->x(); xyz[1] = center->y(); xyz[2] = center->z(); - sgCartToGeod(xyz, &lat_rad, &lon_rad, &alt_m); - - // LOD for the leaf - // max random object range: 20000m - osg::LOD * lod = new osg::LOD; - branch->addChild(lod); - - // Create the in-range and out-of-range - // branches. - osg::Group * in_range = new osg::Group; -// osg::Group * out_of_range = new osg::Group; - lod->addChild(in_range, 0, 20000 /*OSGFIXME hardcoded visibility ???*/); -// lod->addChild(out_of_range, 20000, 1e30); - - SGLeafUserData * data = new SGLeafUserData; - data->is_filled_in = false; - data->leaf = leaf; - data->mat = mat; - data->branch = in_range; - data->sin_lat = sin(lat_rad); - data->cos_lat = cos(lat_rad); - data->sin_lon = sin(lon_rad); - data->cos_lon = cos(lon_rad); - - in_range->setUserData(data); - // OSGFIXME: implement random objects to be loaded when in sight -// in_range->setTravCallback(SSG_CALLBACK_PRETRAV, leaf_in_range_callback); - - // OSGFIXME: implement deletion of tiles that are no longer used -// out_of_range->setUserData(data); -// out_of_range->setTravCallback(SSG_CALLBACK_PRETRAV, -// leaf_out_of_range_callback); -// out_of_range -// ->addChild(new SGDummyBSphereEntity(leaf->getBSphere()->getRadius())); + std::list::iterator j; + for (j = connectSets.begin(); j != connectSets.end(); ++j) { + osg::Geometry* geometry = i->second.buildGeometry(*j); + if (mat) + geometry->setStateSet(mat->get_state()); + geode->addDrawable(geometry); + } +#else + osg::Geometry* geometry = i->second.buildGeometry(); + SGMaterial *mat = matlib->find(i->first); + if (mat) + geometry->setStateSet(mat->get_state()); + geode->addDrawable(geometry); #endif -} - - -// Ok, somehow polygon offset for lights ... -// Could never make the polygon offset for our lights get right. -// So, why not in this way ... -class SGLightOffsetTransform : public osg::Transform { -public: -#define SCALE_FACTOR 0.94 - virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, - osg::NodeVisitor* nv) const - { - if (nv && nv->getVisitorType() == osg::NodeVisitor::CULL_VISITOR) { - double scaleFactor = SCALE_FACTOR; - osg::Vec3 center = nv->getEyePoint(); - osg::Matrix transform; - transform(0,0) = scaleFactor; - transform(1,1) = scaleFactor; - transform(2,2) = scaleFactor; - transform(3,0) = center[0]*(1 - scaleFactor); - transform(3,1) = center[1]*(1 - scaleFactor); - transform(3,2) = center[2]*(1 - scaleFactor); - matrix.preMult(transform); } + return geode; + } + + void computeRandomSurfaceLights(SGMaterialLib* matlib) + { + SGMaterialTriangleMap::const_iterator i; + for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) { + SGMaterial *mat = matlib->find(i->first); + if (!mat) + continue; + + float coverage = mat->get_light_coverage(); + if (coverage <= 0) + continue; + if (coverage < 10000.0) { + SG_LOG(SG_INPUT, SG_ALERT, "Light coverage is " + << coverage << ", pushing up to 10000"); + coverage = 10000; + } + + // generate a repeatable random seed + sg_srandom(unsigned(coverage)); + + std::vector randomPoints; + i->second.addRandomSurfacePoints(coverage, 3, randomPoints); + std::vector::iterator j; + for (j = randomPoints.begin(); j != randomPoints.end(); ++j) { + float zombie = sg_random(); + // factor = sg_random() ^ 2, range = 0 .. 1 concentrated towards 0 + float factor = sg_random(); + factor *= factor; + + float bright = 1; + SGVec4f color; + if ( zombie > 0.5 ) { + // 50% chance of yellowish + color = SGVec4f(0.9f, 0.9f, 0.3f, bright - factor * 0.2f); + } else if (zombie > 0.15f) { + // 35% chance of whitish + color = SGVec4f(0.9, 0.9f, 0.8f, bright - factor * 0.2f); + } else if (zombie > 0.05f) { + // 10% chance of orangish + color = SGVec4f(0.9f, 0.6f, 0.2f, bright - factor * 0.2f); + } else { + // 5% chance of redish + color = SGVec4f(0.9f, 0.2f, 0.2f, bright - factor * 0.2f); + } + randomTileLights.insert(*j, color); + } + } + } + + bool insertBinObj(const SGBinObject& obj, SGMaterialLib* matlib) + { + if (!insertPtGeometry(obj, matlib)) + return false; + if (!insertSurfaceGeometry(obj, matlib)) + return false; return true; } - virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix, - osg::NodeVisitor* nv) const - { - if (nv && nv->getVisitorType() == osg::NodeVisitor::CULL_VISITOR) { - double scaleFactor = 1/SCALE_FACTOR; - osg::Vec3 center = nv->getEyePoint(); - osg::Matrix transform; - transform(0,0) = scaleFactor; - transform(1,1) = scaleFactor; - transform(2,2) = scaleFactor; - transform(3,0) = center[0]*(1 - scaleFactor); - transform(3,1) = center[1]*(1 - scaleFactor); - transform(3,2) = center[2]*(1 - scaleFactor); - matrix.postMult(transform); - } - return true; - } -#undef SCALE_FACTOR }; -static SGMaterial* findMaterial(const std::string& material, - const std::string& path, - SGMaterialLib *matlib) -{ - SGMaterial *mat = matlib->find( material ); - if (mat) - return mat; - - // see if this is an on the fly texture - string file = path; - string::size_type pos = file.rfind( "/" ); - file = file.substr( 0, pos ); - // cout << "current file = " << file << endl; - file += "/"; - file += material; - // cout << "current file = " << file << endl; - if ( ! matlib->add_item( file ) ) { - SG_LOG( SG_TERRAIN, SG_ALERT, - "Ack! unknown usemtl name = " << material - << " in " << path ); - } else { - // locate our newly created material - mat = matlib->find( material ); - if ( mat == NULL ) { - SG_LOG( SG_TERRAIN, SG_ALERT, - "Ack! bad on the fly material create = " - << material << " in " << path ); - } - } - return mat; -} - - -//////////////////////////////////////////////////////////////////////// -// Scenery loaders. -//////////////////////////////////////////////////////////////////////// - -// Load an Binary obj file -static bool SGBinObjLoad( const string& path, const bool is_base, - Point3D& center, - SGMaterialLib *matlib, - bool use_random_objects, - osg::Group *local_terrain, - osg::Group *vasi_lights, - osg::Group *rwy_lights, - osg::Group *taxi_lights, - osg::Vec3Array *ground_lights ) -{ - SGBinObject obj; - - if ( ! obj.read_bin( path ) ) { - return false; - } - - // reference point (center offset/bounding sphere) - center = obj.get_gbs_center(); - - point_list const& nodes = obj.get_wgs84_nodes(); - point_list const& normals = obj.get_normals(); - point_list const& texcoords = obj.get_texcoords(); - - string material; - int_list tex_index; - - group_list::size_type i; - - osg::Geode* geode = new osg::Geode; - local_terrain->addChild( geode ); - - // generate points - string_list const& pt_materials = obj.get_pt_materials(); - group_list const& pts_v = obj.get_pts_v(); - group_list const& pts_n = obj.get_pts_n(); - for ( i = 0; i < pts_v.size(); ++i ) { - // cout << "pts_v.size() = " << pts_v.size() << endl; - if ( pt_materials[i].substr(0, 3) == "RWY" ) { - // airport environment lighting - SGVec3d up(center.x(), center.y(), center.z()); - // returns a transform -> lod -> leaf structure - osg::Node *branch = SGMakeDirectionalLights( nodes, normals, - pts_v[i], pts_n[i], - matlib, - pt_materials[i], up ); - if ( pt_materials[i] == "RWY_VASI_LIGHTS" ) { - vasi_lights->addChild( branch ); - } else if ( pt_materials[i] == "RWY_BLUE_TAXIWAY_LIGHTS" - || pt_materials[i] == "RWY_GREEN_TAXIWAY_LIGHTS" ) - { - taxi_lights->addChild( branch ); - } else { - rwy_lights->addChild( branch ); - } - } else { - // other geometry - SGMaterial *mat = findMaterial( pt_materials[i], path, matlib ); - tex_index.clear(); - osg::Drawable *leaf = SGMakeLeaf( path, GL_POINTS, mat, - nodes, normals, texcoords, - pts_v[i], pts_n[i], tex_index, - false, ground_lights ); - - - - geode->addDrawable( leaf ); - } - } - - // Put all randomly-placed objects under a separate branch - // (actually an ssgRangeSelector) named "random-models". - osg::Group * random_object_branch = 0; -// if (use_random_objects) { -// osg::LOD* object_lod = new osg::LOD; -// object_lod->setName("random-models"); -// geometry->addChild(object_lod); -// random_object_branch = new osg::Group; -// // Maximum 20km range for random objects -// object_lod->addChild(random_object_branch, 0, 20000); -// } - - typedef map > LeafMap; - LeafMap leafMap; - Leaf leaf; - leaf.type = GL_TRIANGLES; - string_list const& tri_materials = obj.get_tri_materials(); - group_list const& tris_v = obj.get_tris_v(); - group_list const& tris_n = obj.get_tris_n(); - group_list const& tris_tc = obj.get_tris_tc(); - for ( i = 0; i < tris_v.size(); i++ ) { - leaf.index = i; - leafMap[ tri_materials[i] ].push_back( leaf ); - } - leaf.type = GL_TRIANGLE_STRIP; - string_list const& strip_materials = obj.get_strip_materials(); - group_list const& strips_v = obj.get_strips_v(); - group_list const& strips_n = obj.get_strips_n(); - group_list const& strips_tc = obj.get_strips_tc(); - for ( i = 0; i < strips_v.size(); i++ ) { - leaf.index = i; - leafMap[ strip_materials[i] ].push_back( leaf ); - } - leaf.type = GL_TRIANGLE_FAN; - string_list const& fan_materials = obj.get_fan_materials(); - group_list const& fans_v = obj.get_fans_v(); - group_list const& fans_n = obj.get_fans_n(); - group_list const& fans_tc = obj.get_fans_tc(); - for ( i = 0; i < fans_v.size(); i++ ) { - leaf.index = i; - leafMap[ fan_materials[i] ].push_back( leaf ); - } - - LeafMap::iterator lmi = leafMap.begin(); - while ( lmi != leafMap.end() ) { - SGMaterial *mat = findMaterial( lmi->first, path, matlib ); - list &leaf_list = lmi->second; - list::iterator li = leaf_list.begin(); - while ( li != leaf_list.end() ) { - Leaf &leaf = *li; - int ind = leaf.index; - if ( leaf.type == GL_TRIANGLES ) { - osg::Drawable *leaf = SGMakeLeaf( path, GL_TRIANGLES, mat, - nodes, normals, texcoords, - tris_v[ind], tris_n[ind], tris_tc[ind], - is_base, ground_lights ); - if ( random_object_branch ) { - if ( mat ) { - gen_random_surface_objects( leaf, random_object_branch, - ¢er, mat ); - } - } - geode->addDrawable( leaf ); - } else if ( leaf.type == GL_TRIANGLE_STRIP ) { - osg::Drawable *leaf = SGMakeLeaf( path, GL_TRIANGLE_STRIP, mat, - nodes, normals, texcoords, - strips_v[ind], strips_n[ind], strips_tc[ind], - is_base, ground_lights ); - if ( random_object_branch ) { - if ( mat ) { - gen_random_surface_objects( leaf, random_object_branch, - ¢er, mat ); - } - } - geode->addDrawable( leaf ); - } else { - osg::Drawable *leaf = SGMakeLeaf( path, GL_TRIANGLE_FAN, mat, - nodes, normals, texcoords, - fans_v[ind], fans_n[ind], fans_tc[ind], - is_base, ground_lights ); - if ( random_object_branch ) { - if ( mat ) { - gen_random_surface_objects( leaf, random_object_branch, - ¢er, mat ); - } - } - geode->addDrawable( leaf ); - } - ++li; - } - ++lmi; - } - - return true; -} - - - - -static osg::Node* -gen_lights( SGMaterialLib *matlib, osg::Vec3Array *lights, int inc, float bright ) -{ - // generate a repeatable random seed - sg_srandom( (unsigned)(*lights)[0][0] ); - - // Allocate ssg structure - osg::Vec3Array *vl = new osg::Vec3Array; - osg::Vec4Array *cl = new osg::Vec4Array; - - for ( unsigned i = 0; i < lights->size(); ++i ) { - // this loop is slightly less efficient than it otherwise - // could be, but we want a red light to always be red, and a - // yellow light to always be yellow, etc. so we are trying to - // preserve the random sequence. - float zombie = sg_random(); - if ( i % inc == 0 ) { - vl->push_back( (*lights)[i] ); - - // factor = sg_random() ^ 2, range = 0 .. 1 concentrated towards 0 - float factor = sg_random(); - factor *= factor; - - osg::Vec4 color; - if ( zombie > 0.5 ) { - // 50% chance of yellowish - color = osg::Vec4( 0.9, 0.9, 0.3, bright - factor * 0.2 ); - } else if ( zombie > 0.15 ) { - // 35% chance of whitish - color = osg::Vec4( 0.9, 0.9, 0.8, bright - factor * 0.2 ); - } else if ( zombie > 0.05 ) { - // 10% chance of orangish - color = osg::Vec4( 0.9, 0.6, 0.2, bright - factor * 0.2 ); - } else { - // 5% chance of redish - color = osg::Vec4( 0.9, 0.2, 0.2, bright - factor * 0.2 ); - } - cl->push_back( color ); - } - } - - // create ssg leaf - osg::Geometry* geometry = new osg::Geometry; - geometry->setVertexArray(vl); - geometry->setColorArray(cl); - geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX); - geometry->addPrimitiveSet(new osg::DrawArrays(GL_POINTS, 0, vl->size())); - osg::Geode* geode = new osg::Geode; - geode->addDrawable(geometry); - - // assign state - SGMaterial *mat = matlib->find( "GROUND_LIGHTS" ); - geometry->setStateSet(mat->get_state()); - - return geode; -} class SGTileUpdateCallback : public osg::NodeCallback { public: @@ -701,23 +530,38 @@ public: } }; - osg::Node* SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool use_random_objects) { + SGBinObject obj; + if (!obj.read_bin(path)) + return false; + + SGTileGeometryBin tileGeometryBin; + if (!tileGeometryBin.insertBinObj(obj, matlib)) + return false; + + SGVec3d center = obj.get_gbs_center2(); + SGGeod geodPos = SGGeod::fromCart(center); + SGQuatd hlOr = SGQuatd::fromLonLat(geodPos); + SGVec3f up = toVec3f(hlOr.backTransform(SGVec3d(0, 0, -1))); + osg::Group* vasiLights = new osg::Group; + vasiLights->setCullCallback(new SGPointSpriteLightCullCallback(osg::Vec3(1, 0.0001, 0.000001), 6)); osg::StateSet* stateSet = vasiLights->getOrCreateStateSet(); osg::Fog* fog = new osg::Fog; fog->setUpdateCallback(new SGRunwayLightFogUpdateCallback); stateSet->setAttribute(fog); osg::Group* rwyLights = new osg::Group; + rwyLights->setCullCallback(new SGPointSpriteLightCullCallback); stateSet = rwyLights->getOrCreateStateSet(); fog = new osg::Fog; fog->setUpdateCallback(new SGRunwayLightFogUpdateCallback); stateSet->setAttribute(fog); osg::Group* taxiLights = new osg::Group; + taxiLights->setCullCallback(new SGPointSpriteLightCullCallback); stateSet = taxiLights->getOrCreateStateSet(); fog = new osg::Fog; fog->setUpdateCallback(new SGTaxiLightFogUpdateCallback); @@ -750,41 +594,90 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool lightSwitch->addChild(groundLights1, true); lightSwitch->addChild(groundLights2, true); - osg::Group* lightGroup = new SGLightOffsetTransform; + osg::Group* lightGroup = new SGOffsetTransform(0.94); lightGroup->addChild(lightSwitch); + + osg::LOD* lightLOD = new osg::LOD; + lightLOD->addChild(lightGroup, 0, 30000); unsigned nodeMask = ~0u; nodeMask &= ~SG_NODEMASK_CASTSHADOW_BIT; nodeMask &= ~SG_NODEMASK_RECIEVESHADOW_BIT; nodeMask &= ~SG_NODEMASK_PICK_BIT; nodeMask &= ~SG_NODEMASK_TERRAIN_BIT; - lightGroup->setNodeMask(nodeMask); - + lightLOD->setNodeMask(nodeMask); + osg::Group* terrainGroup = new osg::Group; + osg::Node* node = tileGeometryBin.getSurfaceGeometry(matlib); + if (node) + terrainGroup->addChild(node); - osg::ref_ptr light_pts = new osg::Vec3Array; - Point3D center; - SGBinObjLoad(path, calc_lights, center, matlib, use_random_objects, - terrainGroup, vasiLights, rwyLights, taxiLights, light_pts.get()); + if (calc_lights) { + // FIXME: ugly, has a side effect + tileGeometryBin.computeRandomSurfaceLights(matlib); - if ( light_pts->size() ) { - osg::Node *lights; + osg::Geode* geode = new osg::Geode; + groundLights0->addChild(geode); + geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.tileLights)); + + groundLights0->addChild(geode); + geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.randomTileLights, 4, -0.3f)); + + geode = new osg::Geode; + groundLights1->addChild(geode); + geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.randomTileLights, 2, -0.15f)); + + geode = new osg::Geode; + groundLights2->addChild(geode); + geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.randomTileLights)); + } + + { + SGVec4f red(1, 0, 0, 1); + SGMaterial* mat = matlib->find("RWY_RED_LIGHTS"); + if (mat) + red = mat->get_light_color(); + SGVec4f white(1, 1, 1, 1); + mat = matlib->find("RWY_WHITE_LIGHTS"); + if (mat) + white = mat->get_light_color(); + osg::Geode* geode; + geode = new osg::Geode; + vasiLights->addChild(geode); + SGDirectionalLightListBin::const_iterator i; + for (i = tileGeometryBin.vasiLights.begin(); + i != tileGeometryBin.vasiLights.end(); ++i) { + geode->addDrawable(SGLightFactory::getVasi(up, *i, red, white)); + } - lights = gen_lights( matlib, light_pts.get(), 4, 0.7 ); - groundLights0->addChild( lights ); - - lights = gen_lights( matlib, light_pts.get(), 2, 0.85 ); - groundLights1->addChild( lights ); - - lights = gen_lights( matlib, light_pts.get(), 1, 1.0 ); - groundLights2->addChild( lights ); + geode = new osg::Geode; + rwyLights->addChild(geode); + geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.runwayLights)); + for (i = tileGeometryBin.rabitLights.begin(); + i != tileGeometryBin.rabitLights.end(); ++i) { + rwyLights->addChild(SGLightFactory::getSequenced(*i)); + } + for (i = tileGeometryBin.reilLights.begin(); + i != tileGeometryBin.reilLights.end(); ++i) { + rwyLights->addChild(SGLightFactory::getSequenced(*i)); + } + + SGLightListBin::const_iterator j; + for (j = tileGeometryBin.odalLights.begin(); + j != tileGeometryBin.odalLights.end(); ++j) { + rwyLights->addChild(SGLightFactory::getOdal(*j)); + } + + geode = new osg::Geode; + taxiLights->addChild(geode); + geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.taxiLights)); } // The toplevel transform for that tile. osg::MatrixTransform* transform = new osg::MatrixTransform; transform->setName(path); - transform->setMatrix(osg::Matrix::translate(osg::Vec3d(center[0], center[1], center[2]))); + transform->setMatrix(osg::Matrix::translate(center.osg())); transform->addChild(terrainGroup); - transform->addChild(lightGroup); + transform->addChild(lightLOD); return transform; } diff --git a/simgear/scene/tgdb/obj.hxx b/simgear/scene/tgdb/obj.hxx index 34080c0c..f0c31300 100644 --- a/simgear/scene/tgdb/obj.hxx +++ b/simgear/scene/tgdb/obj.hxx @@ -25,20 +25,18 @@ #ifndef _SG_OBJ_HXX #define _SG_OBJ_HXX - #ifndef __cplusplus # error This library requires C++ #endif - #include #include STL_STRING -#include +#include #include -#include +#include "SGOceanTile.hxx" SG_USING_STD(string); @@ -46,11 +44,18 @@ class SGBucket; class SGMaterialLib; // Generate an ocean tile -bool SGGenTile( const string& path, const SGBucket& b, - SGMaterialLib *matlib, osg::Group *geometry ); +inline bool SGGenTile( const std::string&, const SGBucket& b, + SGMaterialLib *matlib, osg::Group* group ) +{ + // Generate an ocean tile + osg::Node* node = SGOceanTile(b, matlib); + if (!node) + return false; + group->addChild(node); + return true; +} osg::Node* SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool use_random_objects); - #endif // _SG_OBJ_HXX diff --git a/simgear/scene/tgdb/pt_lights.cxx b/simgear/scene/tgdb/pt_lights.cxx index 71fbdcf2..8963b3be 100644 --- a/simgear/scene/tgdb/pt_lights.cxx +++ b/simgear/scene/tgdb/pt_lights.cxx @@ -24,504 +24,577 @@ # include #endif +#include "pt_lights.hxx" + #include #include +#include #include -#include #include #include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include -#include -#include #include +#include +#include +#include +#include -#include "vasi.hxx" +#include "SGVasiDrawable.hxx" -#include "pt_lights.hxx" - -// static variables for use in ssg callbacks -bool SGPointLightsUseSprites = false; -bool SGPointLightsEnhancedLighting = false; -bool SGPointLightsDistanceAttenuation = false; - - -// Specify the way we want to draw directional point lights (assuming the -// appropriate extensions are available.) - -void SGConfigureDirectionalLights( bool use_point_sprites, - bool enhanced_lighting, - bool distance_attenuation ) { - SGPointLightsUseSprites = use_point_sprites; - SGPointLightsEnhancedLighting = enhanced_lighting; - SGPointLightsDistanceAttenuation = distance_attenuation; -} - -static void calc_center_point( const point_list &nodes, - const int_list &pnt_i, - Point3D& result ) { - double minx = nodes[pnt_i[0]][0]; - double maxx = nodes[pnt_i[0]][0]; - double miny = nodes[pnt_i[0]][1]; - double maxy = nodes[pnt_i[0]][1]; - double minz = nodes[pnt_i[0]][2]; - double maxz = nodes[pnt_i[0]][2]; - - for ( unsigned int i = 0; i < pnt_i.size(); ++i ) { - Point3D pt = nodes[pnt_i[i]]; - if ( pt[0] < minx ) { minx = pt[0]; } - if ( pt[0] > maxx ) { minx = pt[0]; } - if ( pt[1] < miny ) { miny = pt[1]; } - if ( pt[1] > maxy ) { miny = pt[1]; } - if ( pt[2] < minz ) { minz = pt[2]; } - if ( pt[2] > maxz ) { minz = pt[2]; } - } - - result = Point3D((minx + maxx) / 2.0, (miny + maxy) / 2.0, - (minz + maxz) / 2.0); -} - - -static osg::Node* -gen_dir_light_group( const point_list &nodes, - const point_list &normals, - const int_list &pnt_i, - const int_list &nml_i, - const SGMaterial *mat, - const osg::Vec3& up, bool vertical, bool vasi ) +static void +setPointSpriteImage(unsigned char* data, unsigned log2resolution, + unsigned charsPerPixel) { - Point3D center; - calc_center_point( nodes, pnt_i, center ); - // cout << center[0] << "," << center[1] << "," << center[2] << endl; - - - // find a vector perpendicular to the normal. - osg::Vec3 perp1; - if ( !vertical ) { - // normal isn't vertical so we can use up as our first vector - perp1 = up; - } else { - // normal is vertical so we have to work a bit harder to - // determine our first vector - osg::Vec3 pt1(nodes[pnt_i[0]][0], nodes[pnt_i[0]][1], - nodes[pnt_i[0]][2] ); - osg::Vec3 pt2(nodes[pnt_i[1]][0], nodes[pnt_i[1]][1], - nodes[pnt_i[1]][2] ); - - perp1 = pt2 - pt1; + int env_tex_res = (1 << log2resolution); + for (int i = 0; i < env_tex_res; ++i) { + for (int j = 0; j < env_tex_res; ++j) { + int xi = 2*i + 1 - env_tex_res; + int yi = 2*j + 1 - env_tex_res; + if (xi < 0) + xi = -xi; + if (yi < 0) + yi = -yi; + + xi -= 1; + yi -= 1; + + if (xi < 0) + xi = 0; + if (yi < 0) + yi = 0; + + float x = 1.5*xi/(float)(env_tex_res); + float y = 1.5*yi/(float)(env_tex_res); + // float x = 2*xi/(float)(env_tex_res); + // float y = 2*yi/(float)(env_tex_res); + float dist = sqrt(x*x + y*y); + float bright = SGMiscf::clip(255*(1-dist), 0, 255); + for (unsigned l = 0; l < charsPerPixel; ++l) + data[charsPerPixel*(i*env_tex_res + j) + l] = (unsigned char)bright; } - perp1.normalize(); - - osg::Vec3Array *vl = new osg::Vec3Array; - osg::Vec3Array *nl = new osg::Vec3Array; - osg::Vec4Array *cl = new osg::Vec4Array; - - unsigned int i; - for ( i = 0; i < pnt_i.size(); ++i ) { - Point3D ppt = nodes[pnt_i[i]] - center; - osg::Vec3 pt(ppt[0], ppt[1], ppt[2]); - osg::Vec3 normal(normals[nml_i[i]][0], normals[nml_i[i]][1], - normals[nml_i[i]][2] ); - - // calculate a vector perpendicular to dir and up - osg::Vec3 perp2 = normal^perp1; - - // front face - osg::Vec3 tmp3 = pt; - vl->push_back( tmp3 ); - tmp3 += perp1; - vl->push_back( tmp3 ); - tmp3 += perp2; - vl->push_back( tmp3 ); - - nl->push_back( normal ); - nl->push_back( normal ); - nl->push_back( normal ); - - cl->push_back(osg::Vec4(1, 1, 1, 1)); - cl->push_back(osg::Vec4(1, 1, 1, 0)); - cl->push_back(osg::Vec4(1, 1, 1, 0)); - } - - osg::Geometry* geometry = new osg::Geometry; - geometry->setName("Dir Lights " + mat->get_names().front()); - geometry->setVertexArray(vl); - geometry->setNormalArray(nl); - geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); - geometry->setColorArray(cl); - geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX); - geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLES, 0, vl->size())); - osg::Geode* geode = new osg::Geode; - geode->addDrawable(geometry); - - if (vasi) { - // this one is dynamic in its colors, so do not bother with dlists - geometry->setUseDisplayList(false); - geometry->setUseVertexBufferObjects(false); - osg::Vec3 dir(normals[nml_i[0]][0], normals[nml_i[0]][1], - normals[nml_i[0]][2]); - - // calculate the reference position of this vasi and use it - // to init the vasi structure - Point3D ppt = nodes[pnt_i[0]] - center; - osg::Vec3 pt(ppt[0], ppt[1], ppt[2]); - // up is the "up" vector which is also - // the reference center point of this tile. The reference - // center + the coordinate of the first light gives the actual - // location of the first light. - pt += up; - - // Set up the callback - geode->setCullCallback(new SGVasiUpdateCallback(cl, pt, up, dir)); - } - - if ( mat != NULL ) { - geode->setStateSet(mat->get_state()); - } else { - SG_LOG( SG_TERRAIN, SG_ALERT, "Warning: material = NULL" ); - } - - // put an LOD on each lighting component - osg::LOD *lod = new osg::LOD; - lod->addChild( geode, 0, 20000 ); - - // create the transformation. - osg::MatrixTransform *trans = new osg::MatrixTransform; - trans->setMatrix(osg::Matrixd::translate(osg::Vec3d(center[0], center[1], center[2]))); - trans->addChild( lod ); - - return trans; -} - -static osg::Node *gen_reil_lights( const point_list &nodes, - const point_list &normals, - const int_list &pnt_i, - const int_list &nml_i, - SGMaterialLib *matlib, - const osg::Vec3& up ) -{ - Point3D center; - calc_center_point( nodes, pnt_i, center ); - // cout << center[0] << "," << center[1] << "," << center[2] << endl; - - osg::Vec3 nup = up; - nup.normalize(); - - osg::Vec3Array *vl = new osg::Vec3Array; - osg::Vec3Array *nl = new osg::Vec3Array; - osg::Vec4Array *cl = new osg::Vec4Array; - - unsigned int i; - for ( i = 0; i < pnt_i.size(); ++i ) { - Point3D ppt = nodes[pnt_i[i]] - center; - osg::Vec3 pt(ppt[0], ppt[1], ppt[2]); - osg::Vec3 normal(normals[nml_i[i]][0], normals[nml_i[i]][1], - normals[nml_i[i]][2] ); - - // calculate a vector perpendicular to dir and up - osg::Vec3 perp = normal^up; - - // front face - osg::Vec3 tmp3 = pt; - vl->push_back( tmp3 ); - tmp3 += nup; - vl->push_back( tmp3 ); - tmp3 += perp; - vl->push_back( tmp3 ); - - nl->push_back( normal ); - nl->push_back( normal ); - nl->push_back( normal ); - - cl->push_back(osg::Vec4(1, 1, 1, 1)); - cl->push_back(osg::Vec4(1, 1, 1, 0)); - cl->push_back(osg::Vec4(1, 1, 1, 0)); - } - - SGMaterial *mat = matlib->find( "RWY_WHITE_LIGHTS" ); - - osg::Geometry* geometry = new osg::Geometry; - geometry->setName("Reil Lights " + mat->get_names().front()); - geometry->setVertexArray(vl); - geometry->setNormalArray(nl); - geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); - geometry->setColorArray(cl); - geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX); - geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLES, 0, vl->size())); - osg::Geode* geode = new osg::Geode; - geode->addDrawable(geometry); - - if ( mat != NULL ) { - geode->setStateSet( mat->get_state() ); - } else { - SG_LOG( SG_TERRAIN, SG_ALERT, - "Warning: can't find material = RWY_WHITE_LIGHTS" ); - } - - // OSGFIXME -// leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw ); -// leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw ); - - // OSGFIXME: implement an update callback that switches on/off - // based on the osg::FrameStamp - osg::Switch *reil = new osg::Switch; -// reil->setDuration( 60 ); -// reil->setLimits( 0, 2 ); -// reil->setMode( SSG_ANIM_SHUTTLE ); -// reil->control( SSG_ANIM_START ); - - // need to add this twice to work around an ssg bug - reil->addChild(geode, true); - - // put an LOD on each lighting component - osg::LOD *lod = new osg::LOD; - lod->addChild( reil, 0, 12000 /*OSGFIXME: hardcoded here?*/); - - // create the transformation. - osg::MatrixTransform *trans = new osg::MatrixTransform; - trans->setMatrix(osg::Matrixd::translate(osg::Vec3d(center[0], center[1], center[2]))); - trans->addChild( lod ); - - return trans; -} - - -static osg::Node *gen_odals_lights( const point_list &nodes, - const point_list &normals, - const int_list &pnt_i, - const int_list &nml_i, - SGMaterialLib *matlib, - const osg::Vec3& up ) -{ - Point3D center; - calc_center_point( nodes, pnt_i, center ); - // cout << center[0] << "," << center[1] << "," << center[2] << endl; - - // OSGFIXME: implement like above -// osg::Switch *odals = new osg::Switch; - osg::Group *odals = new osg::Group; - - // we don't want directional lights here - SGMaterial *mat = matlib->find( "GROUND_LIGHTS" ); - if ( mat == NULL ) { - SG_LOG( SG_TERRAIN, SG_ALERT, - "Warning: can't material = GROUND_LIGHTS" ); - } - - osg::Vec3Array *vl = new osg::Vec3Array; - osg::Vec4Array *cl = new osg::Vec4Array; - - cl->push_back(osg::Vec4(1, 1, 1, 1)); - - // center line strobes - for ( unsigned i = pnt_i.size() - 1; i >= 2; --i ) { - Point3D ppt = nodes[pnt_i[i]] - center; - osg::Vec3 pt(ppt[0], ppt[1], ppt[2]); - vl->push_back(pt); - } - - // runway end strobes - - Point3D ppt = nodes[pnt_i[0]] - center; - osg::Vec3 pt(ppt[0], ppt[1], ppt[2]); - vl->push_back(pt); - - ppt = nodes[pnt_i[1]] - center; - pt = osg::Vec3(ppt[0], ppt[1], ppt[2]); - vl->push_back(pt); - - osg::Geometry* geometry = new osg::Geometry; - geometry->setName("Odal Lights " + mat->get_names().front()); - geometry->setVertexArray(vl); - geometry->setColorArray(cl); - geometry->setColorBinding(osg::Geometry::BIND_OVERALL); - geometry->addPrimitiveSet(new osg::DrawArrays(GL_POINTS, 0, vl->size())); - osg::Geode* geode = new osg::Geode; - geode->addDrawable(geometry); - - geode->setStateSet( mat->get_state() ); - // OSGFIXME -// leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw ); -// leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw ); - - odals->addChild( geode ); - - // setup animition - -// odals->setDuration( 10 ); -// odals->setLimits( 0, pnt_i.size() - 1 ); -// odals->setMode( SSG_ANIM_SHUTTLE ); -// odals->control( SSG_ANIM_START ); - - // put an LOD on each lighting component - osg::LOD *lod = new osg::LOD; - lod->addChild( odals, 0, 12000 /*OSGFIXME hardcoded visibility*/ ); - - // create the transformation. - osg::MatrixTransform *trans = new osg::MatrixTransform; - trans->setMatrix(osg::Matrixd::translate(osg::Vec3d(center[0], center[1], center[2]))); - trans->addChild(lod); - - return trans; -} - -class SGRabbitUpdateCallback : public osg::NodeCallback { -public: - SGRabbitUpdateCallback(double duration) : - mBaseTime(sg_random()), mDuration(duration) - { - if (fabs(mDuration) < 1e-3) - mDuration = 1e-3; - mBaseTime -= mDuration*floor(mBaseTime/mDuration); } +} - virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - assert(dynamic_cast(node)); - osg::Switch* sw = static_cast(node); - double frameTime = nv->getFrameStamp()->getReferenceTime(); - double timeDiff = (frameTime - mBaseTime)/mDuration; - double reminder = timeDiff - unsigned(floor(timeDiff)); - unsigned nChildren = sw->getNumChildren(); - unsigned activeChild = unsigned(nChildren*reminder); - if (nChildren <= activeChild) - activeChild = nChildren; - sw->setSingleChildOn(activeChild); - - osg::NodeCallback::operator()(node, nv); +static osg::Image* +getPointSpriteImage(int logResolution) +{ + osg::Image* image = new osg::Image; + + osg::Image::MipmapDataType mipmapOffsets; + unsigned off = 0; + for (int i = logResolution; 0 <= i; --i) { + unsigned res = 1 << i; + off += res*res; + mipmapOffsets.push_back(off); } -public: - double mBaseTime; - double mDuration; -}; + + int env_tex_res = (1 << logResolution); + + unsigned char* imageData = new unsigned char[off]; + image->setImage(env_tex_res, env_tex_res, 1, + GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, imageData, + osg::Image::USE_NEW_DELETE); + image->setMipmapLevels(mipmapOffsets); + + for (int k = logResolution; 0 <= k; --k) { + setPointSpriteImage(image->getMipmapData(logResolution - k), k, 1); + } + + return image; +} - -static osg::Node *gen_rabbit_lights( const point_list &nodes, - const point_list &normals, - const int_list &pnt_i, - const int_list &nml_i, - SGMaterialLib *matlib, - const osg::Vec3& up ) +static osg::Texture2D* +gen_standard_light_sprite(void) { - Point3D center; - calc_center_point( nodes, pnt_i, center ); - // cout << center[0] << "," << center[1] << "," << center[2] << endl; + // double checked locking ... + static osg::ref_ptr texture; + if (texture.valid()) + return texture.get(); + + static SGMutex mutex; + SGGuard guard(mutex); + if (texture.valid()) + return texture.get(); + + texture = new osg::Texture2D; + texture->setImage(getPointSpriteImage(6)); + texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP); + texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP); + + return texture.get(); +} - osg::Vec3 nup = up; - nup.normalize(); +SGPointSpriteLightCullCallback::SGPointSpriteLightCullCallback(const osg::Vec3& da, + float sz) : + _pointSpriteStateSet(new osg::StateSet), + _distanceAttenuationStateSet(new osg::StateSet) +{ + osg::PointSprite* pointSprite = new osg::PointSprite; + _pointSpriteStateSet->setTextureAttributeAndModes(0, pointSprite, + osg::StateAttribute::ON); + osg::Texture2D* texture = gen_standard_light_sprite(); + _pointSpriteStateSet->setTextureAttribute(0, texture); + _pointSpriteStateSet->setTextureMode(0, GL_TEXTURE_2D, + osg::StateAttribute::ON); + osg::TexEnv* texEnv = new osg::TexEnv; + texEnv->setMode(osg::TexEnv::MODULATE); + _pointSpriteStateSet->setTextureAttribute(0, texEnv); + + osg::Point* point = new osg::Point; + point->setFadeThresholdSize(1); + point->setMinSize(1); + point->setMaxSize(sz); + point->setSize(sz); + point->setDistanceAttenuation(da); + _distanceAttenuationStateSet->setAttributeAndModes(point); +} - // OSGFIXME: implement like above ... - osg::Switch *rabbit = new osg::Switch; - rabbit->setUpdateCallback(new SGRabbitUpdateCallback(10)); +// FIXME make state sets static +SGPointSpriteLightCullCallback::SGPointSpriteLightCullCallback(osg::Point* point) : + _pointSpriteStateSet(new osg::StateSet), + _distanceAttenuationStateSet(new osg::StateSet) +{ + osg::PointSprite* pointSprite = new osg::PointSprite; + _pointSpriteStateSet->setTextureAttributeAndModes(0, pointSprite, + osg::StateAttribute::ON); + osg::Texture2D* texture = gen_standard_light_sprite(); + _pointSpriteStateSet->setTextureAttribute(0, texture); + _pointSpriteStateSet->setTextureMode(0, GL_TEXTURE_2D, + osg::StateAttribute::ON); + osg::TexEnv* texEnv = new osg::TexEnv; + texEnv->setMode(osg::TexEnv::MODULATE); + _pointSpriteStateSet->setTextureAttribute(0, texEnv); + + _distanceAttenuationStateSet->setAttributeAndModes(point); +} - SGMaterial *mat = matlib->find( "RWY_WHITE_LIGHTS" ); - if ( mat == NULL ) { - SG_LOG( SG_TERRAIN, SG_ALERT, - "Warning: can't material = RWY_WHITE_LIGHTS" ); - } +void +SGPointSpriteLightCullCallback::operator()(osg::Node* node, + osg::NodeVisitor* nv) +{ + assert(dynamic_cast(nv)); + osgUtil::CullVisitor* cv = static_cast(nv); + + // Test for point sprites and point parameters availibility + unsigned contextId = cv->getRenderInfo().getContextID(); + SGSceneFeatures* features = SGSceneFeatures::instance(); + bool usePointSprite = features->getEnablePointSpriteLights(contextId); + bool usePointParameters = features->getEnableDistanceAttenuationLights(contextId); + + if (usePointSprite) + cv->pushStateSet(_pointSpriteStateSet.get()); + + if (usePointParameters) + cv->pushStateSet(_distanceAttenuationStateSet.get()); + + traverse(node, nv); + + if (usePointParameters) + cv->popStateSet(); + + if (usePointSprite) + cv->popStateSet(); +} - for ( int i = pnt_i.size() - 1; i >= 0; --i ) { - osg::Vec3Array *vl = new osg::Vec3Array; - osg::Vec3Array *nl = new osg::Vec3Array; - osg::Vec4Array *cl = new osg::Vec4Array; +osg::Node* +SGLightFactory::getLight(const SGLightBin::Light& light) +{ + osg::Vec3Array* vertices = new osg::Vec3Array; + osg::Vec4Array* colors = new osg::Vec4Array; + vertices->push_back(light.position.osg()); + colors->push_back(light.color.osg()); + + osg::Geometry* geometry = new osg::Geometry; + geometry->setVertexArray(vertices); + geometry->setNormalBinding(osg::Geometry::BIND_OFF); + geometry->setColorArray(colors); + geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX); - Point3D ppt = nodes[pnt_i[i]] - center; - osg::Vec3 pt(ppt[0], ppt[1], ppt[2]); - osg::Vec3 normal(normals[nml_i[i]][0], normals[nml_i[i]][1], - normals[nml_i[i]][2] ); + // Enlarge the bounding box to avoid such light nodes being victim to + // small feature culling. + geometry->setComputeBoundingBoxCallback(new SGEnlargeBoundingBox(1)); + + osg::DrawArrays* drawArrays; + drawArrays = new osg::DrawArrays(osg::PrimitiveSet::POINTS, + 0, vertices->size()); + geometry->addPrimitiveSet(drawArrays); + + osg::StateSet* stateSet = geometry->getOrCreateStateSet(); + stateSet->setRenderBinDetails(9, "DepthSortedBin"); + stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + + osg::BlendFunc* blendFunc = new osg::BlendFunc; + stateSet->setAttribute(blendFunc); + stateSet->setMode(GL_BLEND, osg::StateAttribute::ON); + + osg::AlphaFunc* alphaFunc; + alphaFunc = new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01); + stateSet->setAttribute(alphaFunc); + stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON); + + osg::Geode* geode = new osg::Geode; + geode->addDrawable(geometry); - // calculate a vector perpendicular to dir and up - osg::Vec3 perp = normal^nup; + return geode; +} - // front face - osg::Vec3 tmp3 = pt; - vl->push_back( tmp3 ); - tmp3 += nup; - vl->push_back( tmp3 ); - tmp3 += perp; - vl->push_back( tmp3 ); +osg::Node* +SGLightFactory::getLight(const SGDirectionalLightBin::Light& light) +{ + osg::Vec3Array* vertices = new osg::Vec3Array; + osg::Vec4Array* colors = new osg::Vec4Array; - nl->push_back(normal); + SGVec4f visibleColor(light.color); + SGVec4f invisibleColor(visibleColor[0], visibleColor[1], + visibleColor[2], 0); + SGVec3f normal = normalize(light.normal); + SGVec3f perp1 = perpendicular(normal); + SGVec3f perp2 = cross(normal, perp1); + SGVec3f position = light.position; + vertices->push_back(position.osg()); + vertices->push_back((position + perp1).osg()); + vertices->push_back((position + perp2).osg()); + colors->push_back(visibleColor.osg()); + colors->push_back(invisibleColor.osg()); + colors->push_back(invisibleColor.osg()); + + osg::Geometry* geometry = new osg::Geometry; + geometry->setVertexArray(vertices); + geometry->setNormalBinding(osg::Geometry::BIND_OFF); + geometry->setColorArray(colors); + geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX); + // Enlarge the bounding box to avoid such light nodes being victim to + // small feature culling. + geometry->setComputeBoundingBoxCallback(new SGEnlargeBoundingBox(1)); + + osg::DrawArrays* drawArrays; + drawArrays = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, + 0, vertices->size()); + geometry->addPrimitiveSet(drawArrays); + + osg::StateSet* stateSet = geometry->getOrCreateStateSet(); + stateSet->setRenderBinDetails(9, "DepthSortedBin"); - cl->push_back(osg::Vec4(1, 1, 1, 1)); - cl->push_back(osg::Vec4(1, 1, 1, 0)); - cl->push_back(osg::Vec4(1, 1, 1, 0)); + osg::Material* material = new osg::Material; + material->setColorMode(osg::Material::OFF); + stateSet->setAttribute(material); - osg::Geometry* geometry = new osg::Geometry; - geometry->setName("Rabbit Lights " + mat->get_names().front()); - geometry->setVertexArray(vl); - geometry->setNormalArray(nl); - geometry->setNormalBinding(osg::Geometry::BIND_OVERALL); - geometry->setColorArray(cl); - geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX); - geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLES, 0, vl->size())); - osg::Geode* geode = new osg::Geode; - geode->addDrawable(geometry); - - geode->setStateSet( mat->get_state() ); + osg::CullFace* cullFace = new osg::CullFace; + cullFace->setMode(osg::CullFace::BACK); + stateSet->setAttribute(cullFace, osg::StateAttribute::ON); + stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + + osg::PolygonMode* polygonMode = new osg::PolygonMode; + polygonMode->setMode(osg::PolygonMode::FRONT, osg::PolygonMode::POINT); + stateSet->setAttribute(polygonMode); - // OSGFIXME -// leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw ); -// leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw ); + stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + + osg::BlendFunc* blendFunc = new osg::BlendFunc; + stateSet->setAttribute(blendFunc); + stateSet->setMode(GL_BLEND, osg::StateAttribute::ON); + + osg::AlphaFunc* alphaFunc; + alphaFunc = new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01); + stateSet->setAttribute(alphaFunc); + stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON); + + osg::Geode* geode = new osg::Geode; + geode->addDrawable(geometry); - rabbit->addChild( geode ); - } + return geode; +} -// rabbit->setDuration( 10 ); -// rabbit->setLimits( 0, pnt_i.size() - 1 ); -// rabbit->setMode( SSG_ANIM_SHUTTLE ); -// rabbit->control( SSG_ANIM_START ); - - // put an LOD on each lighting component - osg::LOD *lod = new osg::LOD; - lod->addChild( rabbit, 0, 12000 /*OSGFIXME: hadcoded*/ ); +osg::Drawable* +SGLightFactory::getLights(const SGLightBin& lights, unsigned inc, float alphaOff) +{ + if (lights.getNumLights() <= 0) + return 0; + + osg::Vec3Array* vertices = new osg::Vec3Array; + osg::Vec4Array* colors = new osg::Vec4Array; - // create the transformation. - osg::MatrixTransform *trans = new osg::MatrixTransform; - trans->setMatrix(osg::Matrixd::translate(osg::Vec3d(center[0], center[1], center[2]))); - trans->addChild(lod); + for (unsigned i = 0; i < lights.getNumLights(); i += inc) { + vertices->push_back(lights.getLight(i).position.osg()); + SGVec4f color = lights.getLight(i).color; + color[3] = SGMiscf::max(0, SGMiscf::min(1, color[3] + alphaOff)); + colors->push_back(color.osg()); + } + + osg::Geometry* geometry = new osg::Geometry; + + geometry->setVertexArray(vertices); + geometry->setNormalBinding(osg::Geometry::BIND_OFF); + geometry->setColorArray(colors); + geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX); + + osg::DrawArrays* drawArrays; + drawArrays = new osg::DrawArrays(osg::PrimitiveSet::POINTS, + 0, vertices->size()); + geometry->addPrimitiveSet(drawArrays); + + osg::StateSet* stateSet = geometry->getOrCreateStateSet(); + stateSet->setRenderBinDetails(9, "DepthSortedBin"); - return trans; + stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + + osg::BlendFunc* blendFunc = new osg::BlendFunc; + stateSet->setAttribute(blendFunc); + stateSet->setMode(GL_BLEND, osg::StateAttribute::ON); + + osg::AlphaFunc* alphaFunc; + alphaFunc = new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01); + stateSet->setAttribute(alphaFunc); + stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON); + + return geometry; } -osg::Node *SGMakeDirectionalLights( const point_list &nodes, - const point_list &normals, - const int_list &pnt_i, - const int_list &nml_i, - SGMaterialLib *matlib, - const string &material, - const SGVec3d& dup ) +osg::Drawable* +SGLightFactory::getLights(const SGDirectionalLightBin& lights) { - osg::Vec3 nup = toVec3f(dup).osg(); - nup.normalize(); + if (lights.getNumLights() <= 0) + return 0; + + osg::Vec3Array* vertices = new osg::Vec3Array; + osg::Vec4Array* colors = new osg::Vec4Array; - SGMaterial *mat = matlib->find( material ); + for (unsigned i = 0; i < lights.getNumLights(); ++i) { + SGVec4f visibleColor(lights.getLight(i).color); + SGVec4f invisibleColor(visibleColor[0], visibleColor[1], + visibleColor[2], 0); + SGVec3f normal = normalize(lights.getLight(i).normal); + SGVec3f perp1 = perpendicular(normal); + SGVec3f perp2 = cross(normal, perp1); + SGVec3f position = lights.getLight(i).position; + vertices->push_back(position.osg()); + vertices->push_back((position + perp1).osg()); + vertices->push_back((position + perp2).osg()); + colors->push_back(visibleColor.osg()); + colors->push_back(invisibleColor.osg()); + colors->push_back(invisibleColor.osg()); + } + + osg::Geometry* geometry = new osg::Geometry; + + geometry->setVertexArray(vertices); + geometry->setNormalBinding(osg::Geometry::BIND_OFF); + geometry->setColorArray(colors); + geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX); + + osg::DrawArrays* drawArrays; + drawArrays = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, + 0, vertices->size()); + geometry->addPrimitiveSet(drawArrays); + + osg::StateSet* stateSet = geometry->getOrCreateStateSet(); + stateSet->setRenderBinDetails(9, "DepthSortedBin"); - if ( material == "RWY_REIL_LIGHTS" ) { - // cout << "found a reil" << endl; - return gen_reil_lights( nodes, normals, pnt_i, nml_i, - matlib, nup ); - } else if ( material == "RWY_ODALS_LIGHTS" ) { - // cout << "found a odals" << endl; - return gen_odals_lights( nodes, normals, pnt_i, nml_i, - matlib, nup ); - } else if ( material == "RWY_SEQUENCED_LIGHTS" ) { - // cout << "found a rabbit" << endl; - return gen_rabbit_lights( nodes, normals, pnt_i, nml_i, - matlib, nup ); - } else if ( material == "RWY_VASI_LIGHTS" ) { - return gen_dir_light_group( nodes, normals, pnt_i, - nml_i, mat, nup, false, true ); - } else if ( material == "RWY_BLUE_TAXIWAY_LIGHTS" ) { - return gen_dir_light_group( nodes, normals, pnt_i, nml_i, mat, nup, - true, false ); - } else { - return gen_dir_light_group( nodes, normals, pnt_i, nml_i, mat, nup, - false, false ); - } + osg::Material* material = new osg::Material; + material->setColorMode(osg::Material::OFF); + stateSet->setAttribute(material); - return NULL; + osg::CullFace* cullFace = new osg::CullFace; + cullFace->setMode(osg::CullFace::BACK); + stateSet->setAttribute(cullFace, osg::StateAttribute::ON); + stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + + osg::PolygonMode* polygonMode = new osg::PolygonMode; + polygonMode->setMode(osg::PolygonMode::FRONT, osg::PolygonMode::POINT); + stateSet->setAttribute(polygonMode); + + stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + + osg::BlendFunc* blendFunc = new osg::BlendFunc; + stateSet->setAttribute(blendFunc); + stateSet->setMode(GL_BLEND, osg::StateAttribute::ON); + + osg::AlphaFunc* alphaFunc; + alphaFunc = new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01); + stateSet->setAttribute(alphaFunc); + stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON); + + return geometry; +} + +static SGVasiDrawable* +buildVasi(const SGDirectionalLightBin& lights, const SGVec3f& up, + const SGVec4f& red, const SGVec4f& white) +{ + unsigned count = lights.getNumLights(); + if ( count == 4 ) { + SGVasiDrawable* drawable = new SGVasiDrawable(red, white); + + // PAPI configuration + // papi D + drawable->addLight(lights.getLight(0).position, + lights.getLight(0).normal, up, 3.5); + // papi C + drawable->addLight(lights.getLight(1).position, + lights.getLight(1).normal, up, 3.167); + // papi B + drawable->addLight(lights.getLight(2).position, + lights.getLight(2).normal, up, 2.833); + // papi A + drawable->addLight(lights.getLight(3).position, + lights.getLight(3).normal, up, 2.5); + return drawable; + } + else if (count == 12) { + SGVasiDrawable* drawable = new SGVasiDrawable(red, white); + + // probably vasi, first 6 are downwind bar (2.5 deg) + for (unsigned i = 0; i < 6; ++i) + drawable->addLight(lights.getLight(i).position, + lights.getLight(i).normal, up, 2.5); + // last 6 are upwind bar (3.0 deg) + for (unsigned i = 6; i < 12; ++i) + drawable->addLight(lights.getLight(i).position, + lights.getLight(i).normal, up, 3.0); + + return drawable; + } else { + // fail safe + SG_LOG(SG_TERRAIN, SG_ALERT, + "unknown vasi/papi configuration, count = " << count); + return 0; + } +} + +osg::Drawable* +SGLightFactory::getVasi(const SGVec3f& up, const SGDirectionalLightBin& lights, + const SGVec4f& red, const SGVec4f& white) +{ + SGVasiDrawable* drawable = buildVasi(lights, up, red, white); + if (!drawable) + return 0; + + osg::StateSet* stateSet = drawable->getOrCreateStateSet(); + stateSet->setRenderBinDetails(9, "DepthSortedBin"); + stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + + osg::BlendFunc* blendFunc = new osg::BlendFunc; + stateSet->setAttribute(blendFunc); + stateSet->setMode(GL_BLEND, osg::StateAttribute::ON); + + osg::AlphaFunc* alphaFunc; + alphaFunc = new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01); + stateSet->setAttribute(alphaFunc); + stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON); + + return drawable; +} + +osg::Node* +SGLightFactory::getSequenced(const SGDirectionalLightBin& lights) +{ + if (lights.getNumLights() <= 0) + return 0; + + // generate a repeatable random seed + sg_srandom(unsigned(lights.getLight(0).position[0])); + float flashTime = 2e-2 + 5e-3*sg_random(); + osg::Sequence* sequence = new osg::Sequence; + sequence->setDefaultTime(flashTime); + + for (int i = lights.getNumLights() - 1; 0 <= i; --i) + sequence->addChild(getLight(lights.getLight(i)), flashTime); + sequence->addChild(new osg::Group, 1 + 1e-1*sg_random()); + sequence->setInterval(osg::Sequence::LOOP, 0, -1); + sequence->setDuration(1.0f, -1); + sequence->setMode(osg::Sequence::START); + sequence->setSync(true); + + osg::StateSet* stateSet = sequence->getOrCreateStateSet(); + stateSet->setRenderBinDetails(9, "DepthSortedBin"); + stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + + osg::BlendFunc* blendFunc = new osg::BlendFunc; + stateSet->setAttribute(blendFunc); + stateSet->setMode(GL_BLEND, osg::StateAttribute::ON); + + osg::AlphaFunc* alphaFunc; + alphaFunc = new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01); + stateSet->setAttribute(alphaFunc); + stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON); + + osg::Point* point = new osg::Point; + point->setMinSize(6); + point->setMaxSize(10); + point->setSize(10); + point->setDistanceAttenuation(osg::Vec3(1.0, 0.0001, 0.00000001)); + sequence->setCullCallback(new SGPointSpriteLightCullCallback(point)); + + return sequence; +} + +osg::Node* +SGLightFactory::getOdal(const SGLightBin& lights) +{ + if (lights.getNumLights() < 2) + return 0; + + // generate a repeatable random seed + sg_srandom(unsigned(lights.getLight(0).position[0])); + float flashTime = 2e-2 + 5e-3*sg_random(); + osg::Sequence* sequence = new osg::Sequence; + sequence->setDefaultTime(flashTime); + + // centerline lights + for (int i = lights.getNumLights() - 1; 2 <= i; --i) + sequence->addChild(getLight(lights.getLight(i)), flashTime); + + // runway end lights + osg::Group* group = new osg::Group; + for (unsigned i = 0; i < 2; ++i) + group->addChild(getLight(lights.getLight(i))); + sequence->addChild(group, flashTime); + + // add an extra empty group for a break + sequence->addChild(new osg::Group, 9 + 1e-1*sg_random()); + sequence->setInterval(osg::Sequence::LOOP, 0, -1); + sequence->setDuration(1.0f, -1); + sequence->setMode(osg::Sequence::START); + sequence->setSync(true); + + osg::StateSet* stateSet = sequence->getOrCreateStateSet(); + stateSet->setRenderBinDetails(9, "DepthSortedBin"); + stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + + osg::BlendFunc* blendFunc = new osg::BlendFunc; + stateSet->setAttribute(blendFunc); + stateSet->setMode(GL_BLEND, osg::StateAttribute::ON); + + osg::AlphaFunc* alphaFunc; + alphaFunc = new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01); + stateSet->setAttribute(alphaFunc); + stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON); + + osg::Point* point = new osg::Point; + point->setMinSize(6); + point->setMaxSize(10); + point->setSize(10); + point->setDistanceAttenuation(osg::Vec3(1.0, 0.0001, 0.00000001)); + sequence->setCullCallback(new SGPointSpriteLightCullCallback(point)); + + return sequence; } diff --git a/simgear/scene/tgdb/pt_lights.hxx b/simgear/scene/tgdb/pt_lights.hxx index 431233ce..aeaa49b8 100644 --- a/simgear/scene/tgdb/pt_lights.hxx +++ b/simgear/scene/tgdb/pt_lights.hxx @@ -29,67 +29,73 @@ # error This library requires C++ #endif - #include #include STL_STRING #include // STL +#include +#include +#include + #include #include +#include + +#include "SGLightBin.hxx" +#include "SGDirectionalLightBin.hxx" SG_USING_STD(string); SG_USING_STD(vector); - -typedef vector < int > int_list; -typedef int_list::iterator int_list_iterator; -typedef int_list::const_iterator int_point_list_iterator; - - -// Generate a directional light. This routines creates a -// 'directional' light that can only be viewed from within 90 degrees -// of the specified dir vector. - -// To accomplish this, he routine creates a triangle with the 1st -// point coincident with the specified pt and the 2nd and 3rd points -// extending upward. The 1st point is created with an 'alpha' value -// of 1 while the 2nd and 3rd points are created with an 'alpha' of -// 0.0. - -// If the triangle is drawn in glPolygonMode(GL_FRONT, GL_POINT) mode, -// then two important things happen: - -// 1) Only the 3 vertex points are drawn, the 2nd two with an alpha of -// 0 so actually only the desired point is rendered. - -// 2) since we are drawing a triangle, back face culling takes care of -// eliminating this poing when the view angle relative to dir is -// greater than 90 degrees. - -// The final piece of this puzzle is that if we now use environment -// mapping on this point, via an appropriate texture we can then -// control the intensity and color of the point based on the view -// angle relative to 'dir' the optimal view direction of the light -// (i.e. the direction the light is pointing.) - -// Yes this get's to be long and convoluted. If you can suggest a -// simpler way, please do! :-) - -osg::Node *SGMakeDirectionalLights( const point_list &nodes, - const point_list &normals, - const int_list &pnt_i, - const int_list &nml_i, - SGMaterialLib *matlib, - const string &material, - const SGVec3d& dup ); - // Specify the way we want to draw directional point lights (assuming the // appropriate extensions are available.) -void SGConfigureDirectionalLights( bool use_point_sprites, +inline void SGConfigureDirectionalLights( bool use_point_sprites, bool enhanced_lighting, - bool distance_attenuation ); + bool distance_attenuation ) { + static SGSceneFeatures* sceneFeatures = SGSceneFeatures::instance(); + sceneFeatures->setEnablePointSpriteLights(use_point_sprites); + sceneFeatures->setEnableDistanceAttenuationLights(distance_attenuation); +} +class SGPointSpriteLightCullCallback : public osg::NodeCallback { +public: + SGPointSpriteLightCullCallback(const osg::Vec3& da = osg::Vec3(1, 0.001, 0.0002), + float sz = 4); + SGPointSpriteLightCullCallback(osg::Point* point); + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); + +private: + osg::ref_ptr _pointSpriteStateSet; + osg::ref_ptr _distanceAttenuationStateSet; +}; + +class SGLightFactory { +public: + + static osg::Node* + getLight(const SGLightBin::Light& light); + + static osg::Node* + getLight(const SGDirectionalLightBin::Light& light); + + static osg::Drawable* + getLights(const SGLightBin& lights, unsigned inc = 1, float alphaOff = 0); + + static osg::Drawable* + getLights(const SGDirectionalLightBin& lights); + + static osg::Drawable* + getVasi(const SGVec3f& up, const SGDirectionalLightBin& lights, + const SGVec4f& red, const SGVec4f& white); + + static osg::Node* + getSequenced(const SGDirectionalLightBin& lights); + + static osg::Node* + getOdal(const SGLightBin& lights); +}; #endif // _SG_PT_LIGHTS_HXX diff --git a/simgear/scene/tgdb/vasi.hxx b/simgear/scene/tgdb/vasi.hxx deleted file mode 100644 index 92a790cb..00000000 --- a/simgear/scene/tgdb/vasi.hxx +++ /dev/null @@ -1,197 +0,0 @@ -// vasi.hxx -- a class to hold some critical vasi data -// -// Written by Curtis Olson, started December 2003. -// -// Copyright (C) 2003 Curtis L. Olson - http://www.flightgear.org/~curt -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// $Id$ - - -#ifndef _SG_VASI_HXX -#define _SG_VASI_HXX - -#ifndef __cplusplus -# error This library requires C++ -#endif - -#include - -#include -#include -#include -#include -#include -#include - -/// Callback that updates the colors of a VASI according to the view direction -/// Notet that we need the eyepoint which is only available during culling -/// So this will be a cull callback ... -class SGVasiUpdateCallback : public osg::NodeCallback { -public: - SGVasiUpdateCallback(osg::Vec4Array* vasiColorArray, - const osg::Vec3& referencePoint, - const osg::Vec3& glideSlopeUp, - const osg::Vec3& glideSlopeDir) : - mVasiColorArray(vasiColorArray), - mReferencePoint(referencePoint), - mGlideSlopeUp(glideSlopeUp), - mGlideSlopeDir(glideSlopeDir) - { - mGlideSlopeUp.normalize(); - mGlideSlopeDir.normalize(); - } - virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - // Rerieve the eye point relative to the vasi reference point - osg::Vec3 eyePoint = nv->getEyePoint() - mReferencePoint; - // Now project the eye point vector into the plane defined by the - // glideslope direction and the up direction - osg::Vec3 normal = mGlideSlopeUp^mGlideSlopeDir; - normal.normalize(); - osg::Vec3 projEyePoint = eyePoint - normal * (eyePoint*normal); - - double projEyePointLength = projEyePoint.length(); - if (fabs(projEyePointLength) < 1e-3) - set_color(3); - else { - double aSinAngle = projEyePoint*mGlideSlopeUp/projEyePointLength; - if (aSinAngle < -1) - aSinAngle = -1; - if (1 < aSinAngle) - aSinAngle = 1; - - double angle = asin(aSinAngle)*SGD_RADIANS_TO_DEGREES; - set_color(angle); - } - - // call the base implementation - osg::NodeCallback::operator()(node, nv); - } - - // color the vasi/papi correctly based on angle in degree - void set_color( double angle_deg ) { - unsigned count = mVasiColorArray->size(); - double trans = 0.05; - double color = 1; - double ref; - - if ( count == 12 ) { - // PAPI configuration - - // papi D - ref = 3.5; - if ( angle_deg < ref - trans ) { - color = 0.0; - } else if ( angle_deg < ref + trans ) { - color = 1.0 - (ref + trans - angle_deg) * (1 / (2 * trans) ); - } else { - color = 1.0; - } - for ( unsigned i = 0; i < 3; ++i ) { - (*mVasiColorArray)[i][1] = color; - (*mVasiColorArray)[i][2] = color; - } - - // papi C - ref = 3.167; - if ( angle_deg < ref - trans ) { - color = 0.0; - } else if ( angle_deg < ref + trans ) { - color = 1.0 - (ref + trans - angle_deg) * (1 / (2 * trans) ); - } else { - color = 1.0; - } - for ( unsigned i = 3; i < 6; ++i ) { - (*mVasiColorArray)[i][1] = color; - (*mVasiColorArray)[i][2] = color; - } - - // papi B - ref = 2.833; - if ( angle_deg < ref - trans ) { - color = 0.0; - } else if ( angle_deg < ref + trans ) { - color = 1.0 - (ref + trans - angle_deg) * (1 / (2 * trans) ); - } else { - color = 1.0; - } - for ( unsigned i = 6; i < 9; ++i ) { - (*mVasiColorArray)[i][1] = color; - (*mVasiColorArray)[i][2] = color; - } - - // papi A - ref = 2.5; - if ( angle_deg < ref - trans ) { - color = 0.0; - } else if ( angle_deg < ref + trans ) { - color = 1.0 - (ref + trans - angle_deg) * (1 / (2 * trans) ); - } else { - color = 1.0; - } - for ( unsigned i = 9; i < 12; ++i ) { - (*mVasiColorArray)[i][1] = color; - (*mVasiColorArray)[i][2] = color; - } - } else if ( count == 36 ) { - // probably vasi, first 18 are downwind bar (2.5 deg) - ref = 2.5; - if ( angle_deg < ref - trans ) { - color = 0.0; - } else if ( angle_deg < ref + trans ) { - color = 1.0 - (ref + trans - angle_deg) * (1 / (2 * trans) ); - } else { - color = 1.0; - } - for ( unsigned i = 0; i < 18; ++i ) { - (*mVasiColorArray)[i][1] = color; - (*mVasiColorArray)[i][2] = color; - } - - // last 6 are upwind bar (3.0 deg) - ref = 3.0; - if ( angle_deg < ref - trans ) { - color = 0.0; - } else if ( angle_deg < ref + trans ) { - color = 1.0 - (ref + trans - angle_deg) * (1 / (2 * trans) ); - } else { - color = 1.0; - } - for ( unsigned i = 18; i < 36; ++i ) { - (*mVasiColorArray)[i][1] = color; - (*mVasiColorArray)[i][2] = color; - } - } else { - // fail safe - cout << "unknown vasi/papi configuration, count = " << count << endl; - for ( unsigned i = 0; i < count; ++i ) { - (*mVasiColorArray)[i][1] = color; - (*mVasiColorArray)[i][2] = color; - } - } - // Finally mark the color array dirty - mVasiColorArray->dirty(); - } - -private: - osg::ref_ptr mVasiColorArray; - osg::Vec3 mReferencePoint; - osg::Vec3 mGlideSlopeUp; - osg::Vec3 mGlideSlopeDir; -}; - -#endif // _SG_VASI_HXX diff --git a/simgear/scene/util/Makefile.am b/simgear/scene/util/Makefile.am index df8c4c80..f7615c8e 100644 --- a/simgear/scene/util/Makefile.am +++ b/simgear/scene/util/Makefile.am @@ -7,13 +7,17 @@ noinst_HEADERS = include_HEADERS = \ SGNodeMasks.hxx \ SGUpdateVisitor.hxx \ + SGEnlargeBoundingBox.hxx \ SGDebugDrawCallback.hxx \ SGPickCallback.hxx \ + SGSceneFeatures.hxx \ SGSceneUserData.hxx \ SGStateAttributeVisitor.hxx \ SGTextureStateAttributeVisitor.hxx libsgutil_a_SOURCES = \ + SGEnlargeBoundingBox.cxx \ + SGSceneFeatures.cxx \ SGSceneUserData.cxx \ SGStateAttributeVisitor.cxx \ SGTextureStateAttributeVisitor.cxx diff --git a/simgear/scene/util/SGEnlargeBoundingBox.cxx b/simgear/scene/util/SGEnlargeBoundingBox.cxx new file mode 100644 index 00000000..8e5d8f3d --- /dev/null +++ b/simgear/scene/util/SGEnlargeBoundingBox.cxx @@ -0,0 +1,49 @@ +/* -*-c++-*- + * + * Copyright (C) 2006-2007 Mathias Froehlich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "SGEnlargeBoundingBox.hxx" +#include + +SGEnlargeBoundingBox::SGEnlargeBoundingBox(float offset) : + _offset(offset) +{ +} + +SGEnlargeBoundingBox::SGEnlargeBoundingBox(const SGEnlargeBoundingBox& cb, + const osg::CopyOp& copyOp) : + osg::Drawable::ComputeBoundingBoxCallback(cb, copyOp), + _offset(cb._offset) +{ +} + +osg::BoundingBox +SGEnlargeBoundingBox::computeBound(const osg::Drawable& drawable) const +{ + osg::BoundingBox bound = drawable.computeBound(); + if (!bound.valid()) + return bound; + return osg::BoundingBox(bound._min - osg::Vec3(_offset, _offset, _offset), + bound._max + osg::Vec3(_offset, _offset, _offset)); +} diff --git a/simgear/scene/util/SGEnlargeBoundingBox.hxx b/simgear/scene/util/SGEnlargeBoundingBox.hxx new file mode 100644 index 00000000..b5113866 --- /dev/null +++ b/simgear/scene/util/SGEnlargeBoundingBox.hxx @@ -0,0 +1,41 @@ +/* -*-c++-*- + * + * Copyright (C) 2006-2007 Mathias Froehlich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifndef SG_ENLARGE_BOUNDING_BOX_HXX +#define SG_ENLARGE_BOUNDING_BOX_HXX + +#include + +// Helper class to enlarge a bounding box of a drawable. +// Is usefull to enlarge the mounding box of single point lights that would +// be victim to small feature culling otherwise. +class SGEnlargeBoundingBox : public osg::Drawable::ComputeBoundingBoxCallback { +public: + SGEnlargeBoundingBox(float offset = 0); + SGEnlargeBoundingBox(const SGEnlargeBoundingBox& cb, const osg::CopyOp&); + META_Object(osg, SGEnlargeBoundingBox); + virtual osg::BoundingBox computeBound(const osg::Drawable& drawable) const; + +private: + float _offset; +}; + +#endif diff --git a/simgear/scene/util/SGNodeMasks.hxx b/simgear/scene/util/SGNodeMasks.hxx index 199cb2e0..7a81a823 100644 --- a/simgear/scene/util/SGNodeMasks.hxx +++ b/simgear/scene/util/SGNodeMasks.hxx @@ -33,4 +33,7 @@ /// If set, the node is pickable #define SG_NODEMASK_PICK_BIT (1<<4) +/// If set, the node is a gui element +#define SG_NODEMASK_GUI_BIT (1<<5) + #endif diff --git a/simgear/scene/util/SGSceneFeatures.cxx b/simgear/scene/util/SGSceneFeatures.cxx new file mode 100644 index 00000000..be0183a4 --- /dev/null +++ b/simgear/scene/util/SGSceneFeatures.cxx @@ -0,0 +1,109 @@ +/* -*-c++-*- + * + * Copyright (C) 2006-2007 Mathias Froehlich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "SGSceneFeatures.hxx" + +#include +#include +#include +#include + +#include +#include +#include + +SGSceneFeatures::SGSceneFeatures() : + _shaderLights(true), + _pointSpriteLights(true), + _distanceAttenuationLights(true) +{ +} + +SGSceneFeatures* +SGSceneFeatures::instance() +{ + static SGSharedPtr sceneFeatures; + if (sceneFeatures) + return sceneFeatures; + static SGMutex mutex; + SGGuard guard(mutex); + if (sceneFeatures) + return sceneFeatures; + sceneFeatures = new SGSceneFeatures; + return sceneFeatures; +} + +bool +SGSceneFeatures::getHavePointSprites(unsigned contextId) const +{ + return osg::PointSprite::isPointSpriteSupported(contextId); +} + +bool +SGSceneFeatures::getHaveFragmentPrograms(unsigned contextId) const +{ + const osg::FragmentProgram::Extensions* fpe; + fpe = osg::FragmentProgram::getExtensions(contextId, true); + if (!fpe) + return false; + if (!fpe->isFragmentProgramSupported()) + return false; + + return true; +} + +bool +SGSceneFeatures::getHaveVertexPrograms(unsigned contextId) const +{ + const osg::VertexProgram::Extensions* vpe; + vpe = osg::VertexProgram::getExtensions(contextId, true); + if (!vpe) + return false; + if (!vpe->isVertexProgramSupported()) + return false; + + return true; +} + +bool +SGSceneFeatures::getHaveShaderPrograms(unsigned contextId) const +{ + if (!getHaveFragmentPrograms(contextId)) + return false; + return getHaveVertexPrograms(contextId); +} + +bool +SGSceneFeatures::getHavePointParameters(unsigned contextId) const +{ + const osg::Point::Extensions* pe; + pe = osg::Point::getExtensions(contextId, true); + if (!pe) + return false; + if (!pe->isPointParametersSupported()) + return false; + return true; +} + diff --git a/simgear/scene/util/SGSceneFeatures.hxx b/simgear/scene/util/SGSceneFeatures.hxx new file mode 100644 index 00000000..0aa46abc --- /dev/null +++ b/simgear/scene/util/SGSceneFeatures.hxx @@ -0,0 +1,75 @@ +/* -*-c++-*- + * + * Copyright (C) 2006-2007 Mathias Froehlich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifndef SG_SCENE_FEATURES_HXX +#define SG_SCENE_FEATURES_HXX + +#include + +class SGSceneFeatures : public SGReferenced { +public: + static SGSceneFeatures* instance(); + + void setEnablePointSpriteLights(bool enable) + { _pointSpriteLights = enable; } + bool getEnablePointSpriteLights(unsigned contextId) const + { + if (!_pointSpriteLights) + return false; + return getHavePointSprites(contextId); + } + + void setEnableDistanceAttenuationLights(bool enable) + { _distanceAttenuationLights = enable; } + bool getEnableDistanceAttenuationLights(unsigned contextId) const + { + if (!_distanceAttenuationLights) + return false; + return getHavePointParameters(contextId); + } + + void setEnableShaderLights(bool enable) + { _shaderLights = enable; } + bool getEnableShaderLights(unsigned contextId) const + { + if (!_shaderLights) + return false; + return getHaveShaderPrograms(contextId); + } + +protected: + bool getHavePointSprites(unsigned contextId) const; + bool getHaveFragmentPrograms(unsigned contextId) const; + bool getHaveVertexPrograms(unsigned contextId) const; + bool getHaveShaderPrograms(unsigned contextId) const; + bool getHavePointParameters(unsigned contextId) const; + +private: + SGSceneFeatures(); + SGSceneFeatures(const SGSceneFeatures&); + SGSceneFeatures& operator=(const SGSceneFeatures&); + + bool _shaderLights; + bool _pointSpriteLights; + bool _distanceAttenuationLights; +}; + +#endif diff --git a/simgear/scene/util/SGTextureStateAttributeVisitor.cxx b/simgear/scene/util/SGTextureStateAttributeVisitor.cxx index 816cbc83..f5f5aad9 100644 --- a/simgear/scene/util/SGTextureStateAttributeVisitor.cxx +++ b/simgear/scene/util/SGTextureStateAttributeVisitor.cxx @@ -19,6 +19,10 @@ * */ +#ifdef HAVE_CONFIG_H +# include +#endif + #include "SGTextureStateAttributeVisitor.hxx" SGTextureStateAttributeVisitor::SGTextureStateAttributeVisitor() :