]> git.mxchange.org Git - simgear.git/commitdiff
build signs for an STG into single geometry.
authorJames Turner <zakalawe@mac.com>
Tue, 8 May 2012 12:29:34 +0000 (13:29 +0100)
committerJames Turner <zakalawe@mac.com>
Fri, 11 May 2012 08:50:26 +0000 (09:50 +0100)
simgear/scene/tgdb/ReaderWriterSTG.cxx
simgear/scene/tgdb/ReaderWriterSTG.hxx
simgear/scene/tgdb/apt_signs.cxx
simgear/scene/tgdb/apt_signs.hxx

index 8dc917d03b7cb0357ad631cbd9fb570ed6977f53..21a47ba677a3746bd50bef01e34a7c4977b704d8 100644 (file)
 
 using namespace simgear;
 
+static SGBucket bucketIndexFromFileName(const std::string& fileName)
+{
+  // Extract the bucket from the filename
+  std::istringstream ss(osgDB::getNameLessExtension(fileName));
+  long index;
+  ss >> index;
+  if (ss.fail())
+    return SGBucket();
+  
+  return SGBucket(index);
+}
+
 ReaderWriterSTG::ReaderWriterSTG()
 {
     supportsExtension("stg", "SimGear stg database format");
@@ -76,16 +88,11 @@ ReaderWriterSTG::readNode(const std::string& fileName, const osgDB::Options* opt
     if (!options)
         return ReadResult::FILE_NOT_FOUND;
 
-    // Extract the bucket from the filename
-    std::istringstream ss(osgDB::getNameLessExtension(fileName));
-    long index;
-    ss >> index;
-    if (ss.fail())
-        return ReadResult::FILE_NOT_FOUND;
+
 
     SG_LOG(SG_TERRAIN, SG_INFO, "Loading tile " << fileName);
 
-    SGBucket bucket(index);
+    SGBucket bucket(bucketIndexFromFileName(fileName));
     std::string basePath = bucket.gen_base_path();
 
     osg::ref_ptr<osg::Group> group = new osg::Group;
@@ -100,14 +107,14 @@ ReaderWriterSTG::readNode(const std::string& fileName, const osgDB::Options* opt
         objects.append("Objects");
         objects.append(basePath);
         objects.append(fileName);
-        if (readStgFile(objects.str(), *group, options))
+        if (readStgFile(objects.str(), bucket, *group, options))
             foundBase = true;
         
         SGPath terrain(*i);
         terrain.append("Terrain");
         terrain.append(basePath);
         terrain.append(fileName);
-        if (readStgFile(terrain.str(), *group, options))
+        if (readStgFile(terrain.str(), bucket, *group, options))
             foundBase = true;
     }
     
@@ -135,14 +142,15 @@ ReaderWriterSTG::readStgFile(const std::string& fileName, const osgDB::Options*
     // This is considered a real existing file.
     // We still apply the search path algorithms for relative files.
     osg::ref_ptr<osg::Group> group = new osg::Group;
-
-    readStgFile(osgDB::findDataFile(fileName, options), *group, options);
+    std::string path = osgDB::findDataFile(fileName, options);
+    readStgFile(path, bucketIndexFromFileName(path), *group, options);
 
     return group.get();
 }
 
 bool
 ReaderWriterSTG::readStgFile(const std::string& absoluteFileName,
+                             const SGBucket& bucket,
                              osg::Group& group, const osgDB::Options* options) const
 {
     if (absoluteFileName.empty())
@@ -172,6 +180,8 @@ ReaderWriterSTG::readStgFile(const std::string& absoluteFileName,
     std::string fg_root = options->getPluginStringData("SimGear::FG_ROOT");
     sharedOptions->getDatabasePathList().push_back(fg_root);
     
+    simgear::AirportSignBuilder signBuilder(staticOptions->getMaterialLib(), bucket.get_center());
+  
     bool has_base = false;
     while ( ! in.eof() ) {
         std::string token;
@@ -259,8 +269,8 @@ ReaderWriterSTG::readStgFile(const std::string& absoluteFileName,
                 }
                 
             } else if ( token == "OBJECT_SIGN" ) {
-                node = SGMakeSign(staticOptions->getMaterialLib(), name);
-                
+                //node = SGMakeSign(staticOptions->getMaterialLib(), name);
+              signBuilder.addSign(SGGeod::fromDegM(lon, lat, elev), hdg, name);
             } else {
                 SG_LOG( SG_TERRAIN, SG_ALERT, absoluteFileName
                         << ": Unknown token '" << token << "'" );
@@ -285,6 +295,8 @@ ReaderWriterSTG::readStgFile(const std::string& absoluteFileName,
         
         in >> ::skipeol;
     }
+  
+    group.addChild(signBuilder.getSignsGroup());
 
     return has_base;
 }
index 0d5e0b306b1e3790d686cd2e3bc1a2e7d50a564a..63c3eb72943ad8dad25fefc4be233a0794010577 100644 (file)
@@ -24,6 +24,8 @@
 
 #include <osgDB/ReaderWriter>
 
+class SGBucket;
+
 namespace simgear {
 
 class ReaderWriterSTG : public osgDB::ReaderWriter {
@@ -44,7 +46,7 @@ private:
     /// Read an real existing stg file that exists on disk and return true
     /// if a BASE_OBJECT is found.
     bool
-    readStgFile(const std::string&, osg::Group&, const osgDB::Options*) const;
+    readStgFile(const std::string&, const SGBucket& bucket,  osg::Group&, const osgDB::Options*) const;
 };
 
 }
index 8341005189fb7f0940c829b99ae3f26748c2741d..288ee3989f31ac194ab67c0dede407b9ff354085 100644 (file)
@@ -49,15 +49,14 @@ using namespace simgear;
 
 // for temporary storage of sign elements
 struct element_info {
-    element_info(SGMaterial *m, Effect *s, SGMaterialGlyph *g, double h, double c)
-        : material(m), state(s), glyph(g), height(h), coverwidth(c)
+    element_info(SGMaterial *m, SGMaterialGlyph *g, double h, double c)
+        : material(m), glyph(g), height(h), coverwidth(c)
     {
         scale = h * m->get_xsize()
                 / (m->get_ysize() < 0.001 ? 1.0 : m->get_ysize());
         abswidth = c == 0 ? g->get_width() * scale : c;
     }
     SGMaterial *material;
-    Effect *state;
     SGMaterialGlyph *glyph;
     double height;
     double scale;
@@ -67,9 +66,6 @@ struct element_info {
 
 typedef std::vector<element_info*> ElementVec;
 
-
-
-
 const double HT[5] = {0.460, 0.610, 0.760, 1.220, 0.760}; // standard panel height sizes
 const double grounddist = 0.2;     // hard-code sign distance from surface for now
 const double thick = 0.1;    // half the thickness of the 3D sign
@@ -128,6 +124,8 @@ struct GlyphGeometry
   
   void addSignCase(double caseWidth, double caseHeight, const osg::Matrix& xform)
   {
+    int last = vertices->size();
+    
     vertices->push_back(osg::Vec3(-thick, -caseWidth,  grounddist));
     vertices->push_back(osg::Vec3(thick, -caseWidth,  grounddist));
     vertices->push_back(osg::Vec3(thick, -caseWidth,  grounddist + caseHeight));
@@ -135,7 +133,7 @@ struct GlyphGeometry
     
     
     for (int i=0; i<4; ++i)
-      normals->push_back(xform.preMult(osg::Vec3(-1, 0.0, 0)));
+      normals->push_back(osg::Vec3(-1, 0.0, 0));
     
     vertices->push_back(osg::Vec3(-thick, -caseWidth,  grounddist + caseHeight));
     vertices->push_back(osg::Vec3(thick,  -caseWidth,  grounddist + caseHeight));
@@ -143,7 +141,7 @@ struct GlyphGeometry
     vertices->push_back(osg::Vec3(-thick, caseWidth, grounddist + caseHeight));
     
     for (int i=0; i<4; ++i)
-      normals->push_back(xform.preMult(osg::Vec3(0, 0, 1)));
+      normals->push_back(osg::Vec3(0, 0, 1));
     
     vertices->push_back(osg::Vec3(-thick, caseWidth, grounddist + caseHeight));
     vertices->push_back(osg::Vec3(thick,  caseWidth, grounddist + caseHeight));
@@ -151,7 +149,7 @@ struct GlyphGeometry
     vertices->push_back(osg::Vec3(-thick, caseWidth, grounddist));
     
     for (int i=0; i<4; ++i)
-      normals->push_back(xform.preMult(osg::Vec3(1, 0.0, 0)));
+      normals->push_back(osg::Vec3(1, 0.0, 0));
     
     for (int i = 0; i < 3; ++i) {
       uvs->push_back(osg::Vec2(1,    1));
@@ -160,22 +158,18 @@ struct GlyphGeometry
       uvs->push_back(osg::Vec2(1,    0));
     }
     
+  // transform all the newly added vertices and normals by the matrix
+    for (unsigned int i=last; i<vertices->size(); ++i) {
+      (*vertices)[i]= xform.preMult((*vertices)[i]);
+      (*normals)[i] = xform.preMult((*normals)[i]);
+    }
+    
     quads->setCount(vertices->size());
   }
 };
 
 typedef std::map<Effect*, GlyphGeometry*> EffectGeometryMap;
 
-void SGMakeSignFace(EffectGeometryMap& glyphs, const ElementVec& elements, double hpos, const osg::Matrix& xform)
-{
-    BOOST_FOREACH(element_info* element, elements) {
-        GlyphGeometry* gg = glyphs[element->state];
-        gg->addGlyph(element->glyph, hpos, grounddist, element->abswidth, element->height, xform);
-        hpos += element->abswidth;
-        delete element;
-    }
-}
-
 GlyphGeometry* makeGeometry(Effect* eff, osg::Group* group)
 {
   GlyphGeometry* gg = new GlyphGeometry;
@@ -206,9 +200,67 @@ GlyphGeometry* makeGeometry(Effect* eff, osg::Group* group)
 }
 
 // see $FG_ROOT/Docs/README.scenery
-//
-osg::Node*
-SGMakeSign(SGMaterialLib *matlib, const string& content)
+
+namespace simgear
+{
+
+class AirportSignBuilder::AirportSignBuilderPrivate
+{
+public:
+    SGMaterialLib* materials;
+    EffectGeometryMap geometries;
+    osg::MatrixTransform* signsGroup;
+    GlyphGeometry* signCaseGeometry;
+    
+    GlyphGeometry* getGeometry(Effect* eff)
+    {
+        EffectGeometryMap::iterator it = geometries.find(eff);
+        if (it != geometries.end()) {
+            return it->second;
+        }
+        
+        GlyphGeometry* gg = makeGeometry(eff, signsGroup);
+        geometries[eff] = gg;
+        return gg;
+    }
+    
+    void makeFace(const ElementVec& elements, double hpos, const osg::Matrix& xform)
+    {
+        BOOST_FOREACH(element_info* element, elements) {
+            GlyphGeometry* gg = getGeometry(element->material->get_effect());
+            gg->addGlyph(element->glyph, hpos, grounddist, element->abswidth, element->height, xform);
+            hpos += element->abswidth;
+            delete element;
+        }
+    }
+    
+};
+
+AirportSignBuilder::AirportSignBuilder(SGMaterialLib* mats, const SGGeod& center) :
+    d(new AirportSignBuilderPrivate)
+{
+    d->signsGroup = new osg::MatrixTransform;
+    d->signsGroup->setMatrix(makeZUpFrame(center));
+    
+    assert(mats);
+    d->materials = mats;
+    d->signCaseGeometry = d->getGeometry(d->materials->find("signcase")->get_effect());
+}
+
+osg::Node* AirportSignBuilder::getSignsGroup()
+{
+    return d->signsGroup;
+}
+
+AirportSignBuilder::~AirportSignBuilder()
+{
+    EffectGeometryMap::iterator it;
+    for (it = d->geometries.begin(); it != d->geometries.end(); ++it) {
+        delete it->second;
+    }
+}
+
+void AirportSignBuilder::addSign(const SGGeod& pos, double heading, const std::string& content)
 {
     double sign_height = 1.0;  // meter
     string newmat = "BlackSign";
@@ -221,12 +273,6 @@ SGMakeSign(SGMaterialLib *matlib, const string& content)
     bool isBackside = false;
     int size = -1;
     char oldtype = 0, newtype = 0;
-
-    EffectGeometryMap geoms;
-  
-    osg::Group* object = new osg::Group;
-    object->setName(content);
-
     SGMaterial *material = 0;
 
     // Part I: parse & measure
@@ -334,7 +380,7 @@ SGMakeSign(SGMaterialLib *matlib, const string& content)
         }
 
         if (newmat.size()) {
-            material = matlib->find(newmat);
+            material = d->materials->find(newmat);
             newmat.clear();
         }
  
@@ -344,14 +390,7 @@ SGMakeSign(SGMaterialLib *matlib, const string& content)
             continue;
         }
 
-        // in managed mode push frame stop and frame start first
-        Effect *state = material->get_effect();
-        if (geoms[state] == NULL) {
-          geoms[state] = makeGeometry(state, object);
-        }
-      
-        element_info *e1;
-        element_info *e2;
+    // in managed mode push frame stop and frame start first
         if (!isBackside) {
             if (newtype && newtype != oldtype) {
                 if (close1) {
@@ -362,16 +401,16 @@ SGMakeSign(SGMaterialLib *matlib, const string& content)
                 oldtype = newtype;
                 SGMaterialGlyph *g = material->get_glyph("stop-frame");
                 if (g)
-                    close1 = new element_info(material, state, g, sign_height, 0);
+                    close1 = new element_info(material, g, sign_height, 0);
                 g = material->get_glyph("start-frame");
                 if (g) {
-                    e1 = new element_info(material, state, g, sign_height, 0);
+                    element_info* e1 = new element_info(material, g, sign_height, 0);
                     elements1.push_back(e1);
                     total_width1 += e1->glyph->get_width() * e1->scale;
                 }
             }
             // now the actually requested glyph (front)
-            e1 = new element_info(material, state, glyph, sign_height, 0);
+            element_info* e1 = new element_info(material, glyph, sign_height, 0);
             elements1.push_back(e1);
             total_width1 += e1->glyph->get_width() * e1->scale;
         } else {
@@ -384,16 +423,16 @@ SGMakeSign(SGMaterialLib *matlib, const string& content)
                 oldtype = newtype;
                 SGMaterialGlyph *g = material->get_glyph("stop-frame");
                 if (g)
-                    close2 = new element_info(material, state, g, sign_height, 0);
+                    close2 = new element_info(material, g, sign_height, 0);
                 g = material->get_glyph("start-frame");
                 if (g) {
-                    e2 = new element_info(material, state, g, sign_height, 0);
+                    element_info* e2 = new element_info(material, g, sign_height, 0);
                     elements2.push_back(e2);
                     total_width2 += e2->glyph->get_width() * e2->scale;
                 }
             }
             // now the actually requested glyph (back)
-            e2 = new element_info(material, state, glyph, sign_height, 0);
+            element_info* e2 = new element_info(material, glyph, sign_height, 0);
             elements2.push_back(e2);
             total_width2 += e2->glyph->get_width() * e2->scale;
         }
@@ -412,39 +451,44 @@ SGMakeSign(SGMaterialLib *matlib, const string& content)
         close2 = 0;
     }
 
-
   // Part II: typeset
     double boxwidth = std::max(total_width1, total_width2) * 0.5;
     double hpos = -boxwidth;
-    SGMaterial *mat = matlib->find("signcase");
-    geoms[mat->get_effect()] = makeGeometry(mat->get_effect(), object);
+    SGMaterial *mat = d->materials->find("signcase");
   
     double coverSize = fabs(total_width1 - total_width2) * 0.5;
+    element_info* s1 = new element_info(mat, mat->get_glyph("cover"), sign_height, coverSize);
+    element_info* s2 = new element_info(mat, mat->get_glyph("cover"), sign_height, coverSize);
   
-    if (total_width1 < total_width2) {
-        if (mat) {
-            element_info* s1 = new element_info(mat, mat->get_effect(), mat->get_glyph("cover"), sign_height, coverSize);
-            element_info* s2 = new element_info(mat, mat->get_effect(), mat->get_glyph("cover"), sign_height, coverSize);
-            elements1.insert(elements1.begin(), s1);
-            elements1.push_back(s2);
-        }
-
+    if (total_width1 < total_width2) {            
+        elements1.insert(elements1.begin(), s1);
+        elements1.push_back(s2);
     } else if (total_width2 < total_width1) {
-        if (mat) {
-            element_info* s1 = new element_info(mat, mat->get_effect(), mat->get_glyph("cover"), sign_height, coverSize);
-            element_info* s2 = new element_info(mat, mat->get_effect(), mat->get_glyph("cover"), sign_height, coverSize);
-            elements2.insert(elements2.begin(), s1);
-            elements2.push_back(s2);
-        }
+        elements2.insert(elements2.begin(), s1);
+        elements2.push_back(s2);
+    } else {
+        delete s1;
+        delete s2;
     }
+    
+// position the sign
+    const osg::Vec3 Z_AXIS(0, 0, 1);
+    osg::Matrix m(makeZUpFrame(pos));
+    m.preMultRotate(osg::Quat(SGMiscd::deg2rad(heading), Z_AXIS));
+    
+    // apply the inverse of the group transform, so sign vertices
+    // are relative to the tile center, and hence have a magnitude which
+    // fits in a float with sufficent precision.
+    m.postMult(d->signsGroup->getInverseMatrix());
+    
+    d->makeFace(elements1, hpos, m);
+// Create back side
+    osg::Matrix back(m);
+    back.preMultRotate(osg::Quat(M_PI, Z_AXIS));
+    d->makeFace(elements2, hpos, back);
+    
+    d->signCaseGeometry->addSignCase(boxwidth, sign_height, m);
+}
 
-    // Create front side
-    SGMakeSignFace(geoms, elements1, hpos, osg::Matrix::identity());
+} // of namespace simgear
 
-    // Create back side
-    const osg::Vec3d axis(0, 0, 1);
-    SGMakeSignFace(geoms, elements2, hpos, osg::Matrix::rotate( M_PI, axis));
-    geoms[mat->get_effect()]->addSignCase(boxwidth, sign_height, osg::Matrix::identity());
-  
-    return object;
-}
index 01339401944072cb044bb2a8ae128c241d085e76..31334e4a63992c5fd8996d598e658c34ec608578 100644 (file)
 #ifndef _SG_APT_SIGNS_HXX
 #define _SG_APT_SIGNS_HXX
 
-
-#ifndef __cplusplus
-# error This library requires C++
-#endif
-
-
 #include <simgear/compiler.h>
 
 #include <string>
+#include <memory> // for auto-ptr
 
 #include <osg/Node>
 
 class SGMaterialLib;            // forward declaration
-
+class SGGeod;
 
 // Generate a generic sign
 osg::Node* SGMakeSign( SGMaterialLib *matlib, const std::string& content );
 
+namespace simgear
+{
+
+class AirportSignBuilder
+{
+public:
+    AirportSignBuilder(SGMaterialLib* mats, const SGGeod& center);
+    ~AirportSignBuilder();
+    
+    void addSign(const SGGeod& pos, double heading, const std::string& content);
+        
+    osg::Node* getSignsGroup();
+private:
+    class AirportSignBuilderPrivate;
+    std::auto_ptr<AirportSignBuilderPrivate> d;
+};
+
+} // of namespace simgear
 
 #endif // _SG_APT_SIGNS_HXX