From 560c100484e3678770c9589e6067d627ec5554e5 Mon Sep 17 00:00:00 2001 From: frohlich Date: Mon, 28 May 2007 05:00:28 +0000 Subject: [PATCH] Modified Files: simgear/bucket/newbucket.cxx simgear/bucket/newbucket.hxx simgear/io/decode_binobj.cxx simgear/io/sg_binobj.cxx simgear/io/sg_binobj.hxx simgear/math/SGVec2.hxx simgear/math/SGVec3.hxx simgear/math/SGVec4.hxx simgear/scene/material/mat.hxx simgear/scene/material/matlib.cxx simgear/scene/material/matlib.hxx simgear/scene/model/Makefile.am simgear/scene/tgdb/Makefile.am simgear/scene/tgdb/obj.cxx simgear/scene/tgdb/obj.hxx simgear/scene/tgdb/pt_lights.cxx simgear/scene/tgdb/pt_lights.hxx simgear/scene/util/Makefile.am simgear/scene/util/SGNodeMasks.hxx simgear/scene/util/SGTextureStateAttributeVisitor.cxx Added Files: simgear/scene/model/SGOffsetTransform.cxx simgear/scene/model/SGOffsetTransform.hxx simgear/scene/tgdb/SGDirectionalLightBin.hxx simgear/scene/tgdb/SGLightBin.hxx simgear/scene/tgdb/SGOceanTile.cxx simgear/scene/tgdb/SGOceanTile.hxx simgear/scene/tgdb/SGTexturedTriangleBin.hxx simgear/scene/tgdb/SGTriangleBin.hxx simgear/scene/tgdb/SGVasiDrawable.cxx simgear/scene/tgdb/SGVasiDrawable.hxx simgear/scene/tgdb/SGVertexArrayBin.hxx simgear/scene/util/SGEnlargeBoundingBox.cxx simgear/scene/util/SGEnlargeBoundingBox.hxx simgear/scene/util/SGSceneFeatures.cxx simgear/scene/util/SGSceneFeatures.hxx Removed Files: simgear/scene/tgdb/leaf.hxx simgear/scene/tgdb/vasi.hxx: Reorganize tile loaders. Build bigger leafs for the tiles. Move runway light colors into materials.xml. Split out classes that might be useful at other places. Avoid static storage on binobject loading. --- simgear/bucket/newbucket.cxx | 13 +- simgear/bucket/newbucket.hxx | 19 +- simgear/io/decode_binobj.cxx | 6 +- simgear/io/sg_binobj.cxx | 75 +- simgear/io/sg_binobj.hxx | 64 +- simgear/math/SGVec2.hxx | 9 + simgear/math/SGVec3.hxx | 9 + simgear/math/SGVec4.hxx | 9 + simgear/scene/material/mat.hxx | 14 + simgear/scene/material/matlib.cxx | 371 +----- simgear/scene/material/matlib.hxx | 2 +- simgear/scene/model/Makefile.am | 6 +- simgear/scene/model/SGOffsetTransform.cxx | 68 ++ simgear/scene/model/SGOffsetTransform.hxx | 39 + simgear/scene/tgdb/Makefile.am | 15 +- simgear/scene/tgdb/SGDirectionalLightBin.hxx | 78 ++ simgear/scene/tgdb/SGLightBin.hxx | 50 + simgear/scene/tgdb/SGOceanTile.cxx | 131 +++ simgear/scene/tgdb/SGOceanTile.hxx | 33 + simgear/scene/tgdb/SGTexturedTriangleBin.hxx | 164 +++ simgear/scene/tgdb/SGTriangleBin.hxx | 123 ++ simgear/scene/tgdb/SGVasiDrawable.cxx | 162 +++ simgear/scene/tgdb/SGVasiDrawable.hxx | 63 ++ simgear/scene/tgdb/SGVertexArrayBin.hxx | 63 ++ simgear/scene/tgdb/leaf.hxx | 58 - simgear/scene/tgdb/obj.cxx | 993 ++++++++-------- simgear/scene/tgdb/obj.hxx | 19 +- simgear/scene/tgdb/pt_lights.cxx | 1001 +++++++++-------- simgear/scene/tgdb/pt_lights.hxx | 84 +- simgear/scene/tgdb/vasi.hxx | 197 ---- simgear/scene/util/Makefile.am | 4 + simgear/scene/util/SGEnlargeBoundingBox.cxx | 49 + simgear/scene/util/SGEnlargeBoundingBox.hxx | 41 + simgear/scene/util/SGNodeMasks.hxx | 3 + simgear/scene/util/SGSceneFeatures.cxx | 109 ++ simgear/scene/util/SGSceneFeatures.hxx | 75 ++ .../util/SGTextureStateAttributeVisitor.cxx | 4 + 37 files changed, 2455 insertions(+), 1768 deletions(-) create mode 100644 simgear/scene/model/SGOffsetTransform.cxx create mode 100644 simgear/scene/model/SGOffsetTransform.hxx create mode 100644 simgear/scene/tgdb/SGDirectionalLightBin.hxx create mode 100644 simgear/scene/tgdb/SGLightBin.hxx create mode 100644 simgear/scene/tgdb/SGOceanTile.cxx create mode 100644 simgear/scene/tgdb/SGOceanTile.hxx create mode 100644 simgear/scene/tgdb/SGTexturedTriangleBin.hxx create mode 100644 simgear/scene/tgdb/SGTriangleBin.hxx create mode 100644 simgear/scene/tgdb/SGVasiDrawable.cxx create mode 100644 simgear/scene/tgdb/SGVasiDrawable.hxx create mode 100644 simgear/scene/tgdb/SGVertexArrayBin.hxx delete mode 100644 simgear/scene/tgdb/leaf.hxx delete mode 100644 simgear/scene/tgdb/vasi.hxx create mode 100644 simgear/scene/util/SGEnlargeBoundingBox.cxx create mode 100644 simgear/scene/util/SGEnlargeBoundingBox.hxx create mode 100644 simgear/scene/util/SGSceneFeatures.cxx create mode 100644 simgear/scene/util/SGSceneFeatures.hxx 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 ); - - normals.push_back(Point3D(normal[0], normal[1], normal[2])); + SGVec3f normal((ptr[0]) / 127.5 - 1.0, + (ptr[1]) / 127.5 - 1.0, + (ptr[2]) / 127.5 - 1.0); + + 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 point_list& get_colors() const { return colors; } - inline void set_colors( const point_list& c ) { colors = c; } - - inline const point_list& get_normals() const { return normals; } - inline void set_normals( const point_list& n ) { normals = n; } - - inline const point_list& get_texcoords() const { return texcoords; } - inline void set_texcoords( const point_list& t ) { texcoords = t; } + 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 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 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 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 - -#include +#include "obj.hxx" -#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 "obj.hxx" - -SG_USING_STD(string); -SG_USING_STD(list); - -struct Leaf { - GLenum type; - int index; -}; +#include +#include + +#include "SGTexturedTriangleBin.hxx" +#include "SGLightBin.hxx" +#include "SGDirectionalLightBin.hxx" + +#include "pt_lights.hxx" + +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; + + static SGVec4f + getMaterialLightColor(const SGMaterial* material) + { + if (!material) + return SGVec4f(1, 1, 1, 0.8); + return material->get_light_color(); + } + 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); + } -// Generate an ocean tile -bool SGGenTile( const string& path, const SGBucket& b, - SGMaterialLib *matlib, osg::Group* group ) -{ - osg::StateSet *state = 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 - 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 ); - } - - // 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() ); - } - - 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; + for (unsigned i = 0; i < pts_v.size(); ++i) + lights.insert(toVec3f(vertices[pts_v[i]]), normals[pts_v[i]], color); } + } - // 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; + 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 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 ); - } - 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())); + 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]); + } } - - 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())); - osg::Geode* geode = new osg::Geode; - geode->setName(path); - geode->addDrawable(geometry); - geode->setStateSet(state); - - group->addChild(geode); 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())); -#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 + static SGVec2f + getTexCoord(const std::vector& texCoords, const int_list& tc, + const SGVec2f& tcScale, unsigned i) { - 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 true; + if (tc.empty()) + return tcScale; + else if (tc.size() == 1) + return mult(texCoords[tc[0]], tcScale); + else + return mult(texCoords[tc[i]], tcScale); } - virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix, - osg::NodeVisitor* nv) const + + 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 (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); + 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; } - 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 ); + 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); } } - 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; + 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; } - // 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; + 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); + } + } + + 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; + } - group_list::size_type i; + 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; + } + } - 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 ); - + 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(); + } - geode->addDrawable( leaf ); - } + 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; } - // 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 ); + 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); } - 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 ); + + 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; } - 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 ); + 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); } - 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; + 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; + SGMaterialTriangleMap::const_iterator i; + for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) { +#define CHUNCKED +#ifdef CHUNCKED + SGMaterial *mat = matlib->find(i->first); + + std::list connectSets; + i->second.getConnectedSets(connectSets); + + 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 + } + return geode; + } -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. + 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(); - 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 ); + // 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); + } } + } - // 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()); + bool insertBinObj(const SGBinObject& obj, SGMaterialLib* matlib) + { + if (!insertPtGeometry(obj, matlib)) + return false; + if (!insertSurfaceGeometry(obj, matlib)) + return false; + return true; + } +}; - 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; - - 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 ); + 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(), 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 "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.) +#include "SGVasiDrawable.hxx" -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]; } +static void +setPointSpriteImage(unsigned char* data, unsigned log2resolution, + unsigned charsPerPixel) +{ + 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; } - - 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 osg::Image* +getPointSpriteImage(int logResolution) { - 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; - } - 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 ); + 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); + } + + 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; +} - return trans; +static osg::Texture2D* +gen_standard_light_sprite(void) +{ + // 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(); } -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 ) +SGPointSpriteLightCullCallback::SGPointSpriteLightCullCallback(const osg::Vec3& da, + float sz) : + _pointSpriteStateSet(new osg::StateSet), + _distanceAttenuationStateSet(new osg::StateSet) { - 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)); - } + 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); +} - 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" ); - } +// 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); +} - // 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; +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(); } +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); + + // 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); + + return geode; +} -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 ) +osg::Node* +SGLightFactory::getLight(const SGDirectionalLightBin::Light& light) { - 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* vertices = new osg::Vec3Array; + osg::Vec4Array* colors = new osg::Vec4Array; + + 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"); + + osg::Material* material = new osg::Material; + material->setColorMode(osg::Material::OFF); + stateSet->setAttribute(material); + + 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); + + osg::Geode* geode = new osg::Geode; + geode->addDrawable(geometry); + + return geode; +} - osg::Vec3Array *vl = new osg::Vec3Array; - osg::Vec4Array *cl = new osg::Vec4Array; - - cl->push_back(osg::Vec4(1, 1, 1, 1)); +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; + + 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"); + + 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; +} - // 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; +osg::Drawable* +SGLightFactory::getLights(const SGDirectionalLightBin& lights) +{ + if (lights.getNumLights() <= 0) + return 0; + + osg::Vec3Array* vertices = new osg::Vec3Array; + osg::Vec4Array* colors = new osg::Vec4Array; + + 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"); + + osg::Material* material = new osg::Material; + material->setColorMode(osg::Material::OFF); + stateSet->setAttribute(material); + + 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; } -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); +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; } - - 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); + 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; } -public: - double mBaseTime; - double mDuration; -}; - - -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 ) -{ - Point3D center; - calc_center_point( nodes, pnt_i, center ); - // cout << center[0] << "," << center[1] << "," << center[2] << endl; - - osg::Vec3 nup = up; - nup.normalize(); - - // OSGFIXME: implement like above ... - osg::Switch *rabbit = new osg::Switch; - rabbit->setUpdateCallback(new SGRabbitUpdateCallback(10)); - - SGMaterial *mat = matlib->find( "RWY_WHITE_LIGHTS" ); - if ( mat == NULL ) { - SG_LOG( SG_TERRAIN, SG_ALERT, - "Warning: can't material = RWY_WHITE_LIGHTS" ); - } - - 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; - - - 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^nup; - - // 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); - - 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("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() ); - - // OSGFIXME -// leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw ); -// leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw ); - - rabbit->addChild( 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*/ ); - - // 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; } +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 *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::Node* +SGLightFactory::getSequenced(const SGDirectionalLightBin& lights) { - osg::Vec3 nup = toVec3f(dup).osg(); - nup.normalize(); - - SGMaterial *mat = matlib->find( material ); - - 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 ); - } + 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; +} - return NULL; +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); +// Specify the way we want to draw directional point lights (assuming the +// appropriate extensions are available.) -typedef vector < int > int_list; -typedef int_list::iterator int_list_iterator; -typedef int_list::const_iterator int_point_list_iterator; - +inline void SGConfigureDirectionalLights( bool use_point_sprites, + bool enhanced_lighting, + bool distance_attenuation ) { + static SGSceneFeatures* sceneFeatures = SGSceneFeatures::instance(); + sceneFeatures->setEnablePointSpriteLights(use_point_sprites); + sceneFeatures->setEnableDistanceAttenuationLights(distance_attenuation); +} -// Generate a directional light. This routines creates a -// 'directional' light that can only be viewed from within 90 degrees -// of the specified dir vector. +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); -// 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. + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); -// If the triangle is drawn in glPolygonMode(GL_FRONT, GL_POINT) mode, -// then two important things happen: +private: + osg::ref_ptr _pointSpriteStateSet; + osg::ref_ptr _distanceAttenuationStateSet; +}; -// 1) Only the 3 vertex points are drawn, the 2nd two with an alpha of -// 0 so actually only the desired point is rendered. +class SGLightFactory { +public: -// 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. + static osg::Node* + getLight(const SGLightBin::Light& light); -// 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.) + static osg::Node* + getLight(const SGDirectionalLightBin::Light& light); -// Yes this get's to be long and convoluted. If you can suggest a -// simpler way, please do! :-) + static osg::Drawable* + getLights(const SGLightBin& lights, unsigned inc = 1, float alphaOff = 0); -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 ); + static osg::Drawable* + getLights(const SGDirectionalLightBin& lights); -// Specify the way we want to draw directional point lights (assuming the -// appropriate extensions are available.) + static osg::Drawable* + getVasi(const SGVec3f& up, const SGDirectionalLightBin& lights, + const SGVec4f& red, const SGVec4f& white); -void SGConfigureDirectionalLights( bool use_point_sprites, - bool enhanced_lighting, - bool distance_attenuation ); + 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() : -- 2.39.5