]> git.mxchange.org Git - simgear.git/blobdiff - simgear/scene/tgdb/apt_signs.cxx
Replace SG_USE_STD() by using std::
[simgear.git] / simgear / scene / tgdb / apt_signs.cxx
index 175e5c6fa9d60a47b5ff3a5a66ba7e38baf8f597..4053dda16ff204b0a513d4af480ba9d48a1bd3dc 100644 (file)
 #  include <simgear_config.h>
 #endif
 
+#include <vector>
+
+#include <osg/StateSet>
+#include <osg/Geode>
+#include <osg/Geometry>
+#include <osg/Group>
+
 #include <simgear/debug/logstream.hxx>
 #include <simgear/math/sg_types.hxx>
-#include <simgear/scene/tgdb/leaf.hxx>
 #include <simgear/scene/material/mat.hxx>
 #include <simgear/scene/material/matlib.hxx>
 
 #include "apt_signs.hxx"
 
-#define TAXI "OBJECT_TAXI_SIGN: "
+#define SIGN "OBJECT_SIGN: "
 #define RWY "OBJECT_RUNWAY_SIGN: "
 
+using std::vector;
 
 // for temporary storage of sign elements
 struct element_info {
-    element_info(SGMaterial *m, SGMaterialGlyph *g) : material(m), glyph(g) {}
+    element_info(SGMaterial *m, osg::StateSet *s, SGMaterialGlyph *g, double h)
+        : material(m), state(s), glyph(g), height(h)
+    {
+        scale = h * m->get_xsize()
+                / (m->get_ysize() < 0.001 ? 1.0 : m->get_ysize());
+    }
     SGMaterial *material;
+    osg::StateSet *state;
     SGMaterialGlyph *glyph;
+    double height;
+    double scale;
 };
 
 
-// translation table for 'command' to glyph name
+// standard panel height sizes
+const double HT[5] = {0.460, 0.610, 0.760, 1.220, 0.760};
+
+
+// translation table for "command" to "glyph name"
 struct pair {
     const char *keyword;
     const char *glyph_name;
 } cmds[] = {
-    {"l",       "left"},
-    {"lu",      "up-left"},
-    {"ld",      "down-left"},
-    {"r",       "right"},
-    {"ru",      "up-right"},
-    {"rd",      "down-right"},
-    {"u",       "up"},
-    {"ul",      "up-left"},
-    {"ur",      "up-right"},
-    {"d",       "down"},
-    {"dl",      "down-left"},
-    {"dr",      "down-right"},
-    {"no-exit", "no-exit"},
+    {"@u",       "^u"},
+    {"@d",       "^d"},
+    {"@l",       "^l"},
+    {"@lu",      "^lu"},
+    {"@ul",      "^lu"},
+    {"@ld",      "^ld"},
+    {"@dl",      "^ld"},
+    {"@r",       "^r"},
+    {"@ru",      "^ru"},
+    {"@ur",      "^ru"},
+    {"@rd",      "^rd"},
+    {"@dr",      "^rd"},
     {0, 0},
 };
 
 
-// Y ... black on yellow            -> direction, destination, boundary
-// R ... white on red               -> mandatory instruction
-// L ... yellow on black with frame -> runway/taxiway location
-// B ... white on black             -> runway distance remaining
+// see $FG_ROOT/Docs/README.scenery
 //
-// u/d/l/r     ... up/down/left/right arrow or two-letter combinations
-//                 thereof (ur, dl, ...)
-//
-// Example: {l}E|{L}[T]|{Y,ur}L|E{r}
-//
-ssgBranch *sgMakeTaxiSign( SGMaterialLib *matlib,
-                           const string path, const string content )
+osg::Node*
+SGMakeSign(SGMaterialLib *matlib, const string& path, const string& content)
 {
-    const double sign_height = 1.0;   // meter     TODO make configurable
+    double sign_height = 1.0;  // meter
+    bool lighted = true;
+    string newmat = "BlackSign";
 
     vector<element_info *> elements;
+    element_info *close = 0;
     double total_width = 0.0;
     bool cmd = false;
-    char *newmat = "YellowSign";
+    int size = -1;
+    char oldtype = 0, newtype = 0;
 
-    ssgBranch *object = new ssgBranch();
-    object->setName((char *)content.c_str());
-    SGMaterial *material = matlib->find(newmat);
+    osg::Group* object = new osg::Group;
+    object->setName(content);
+
+    SGMaterial *material;
+    osg::StateSet *lighted_state;
+    osg::StateSet *unlighted_state;
 
+    // Part I: parse & measure
     for (const char *s = content.data(); *s; s++) {
         string name;
-        const char *newmat = 0;
+        string value;
 
         if (*s == '{') {
             if (cmd)
-                SG_LOG(SG_TERRAIN, SG_ALERT, TAXI "unexpected { in sign contents");
+                SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "unexpected { in sign contents");
             cmd = true;
             continue;
+
         } else if (*s == '}') {
             if (!cmd)
-                SG_LOG(SG_TERRAIN, SG_ALERT, TAXI "unexpected } in sign contents");
+                SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "unexpected } in sign contents");
             cmd = false;
             continue;
-        } else if (cmd) {
+
+        } else if (!cmd) {
+            name = *s;
+
+        } else {
             if (*s == ',')
                 continue;
-            else if (*s == 'Y')
-                newmat = "YellowSign";
-            else if (*s == 'R')
-                newmat = "RedSign";
-            else if (*s == 'L')
-                newmat = "FramedSign";
-            else if (*s == 'B')
-                newmat = "BlackSign";
-            else {
-                // find longest match of cmds[]
-                int maxlen = 0, len;
-                for (int i = 0; cmds[i].keyword; i++) {
-                    len = strlen(cmds[i].keyword);
-                    if (!strncmp(s, cmds[i].keyword, len)) {
-                        maxlen = len;
-                        name = cmds[i].glyph_name;
+
+            for (; *s; s++) {
+                name += *s;
+                if (s[1] == ',' || s[1] == '}' || s[1] == '=')
+                    break;
+            }
+            if (!*s) {
+                SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "unclosed { in sign contents");
+            } else if (s[1] == '=') {
+                for (s += 2; *s; s++) {
+                    value += *s;
+                    if (s[1] == ',' || s[1] == '}')
+                        break;
+                }
+                if (!*s)
+                    SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "unclosed { in sign contents");
+            }
+
+            if (name == "@size") {
+                sign_height = strtod(value.data(), 0);
+                continue;
+            }
+
+            if (name == "@light") {
+                lighted = (value != "0" && value != "no" && value != "off" && value != "false");
+                continue;
+            }
+
+            if (name == "@material") {
+                newmat = value.data();
+                continue;
+
+            } else if (name.size() == 2 || name.size() == 3) {
+                string n = name;
+                if (n.size() == 3 && n[2] >= '1' && n[2] <= '5') {
+                    size = n[2] - '1';
+                    n = n.substr(0, 2);
+                }
+
+                if (n == "@Y") {
+                    if (size < 3) {
+                        sign_height = HT[size < 0 ? 2 : size];
+                        newmat = "YellowSign";
+                        newtype = 'Y';
+                        continue;
+                    }
+
+                } else if (n == "@R") {
+                    if (size < 3) {
+                        sign_height = HT[size < 0 ? 2 : size];
+                        newmat = "RedSign";
+                        newtype = 'R';
+                        continue;
+                    }
+
+                } else if (n == "@L") {
+                    if (size < 3) {
+                        sign_height = HT[size < 0 ? 2 : size];
+                        newmat = "FramedSign";
+                        newtype = 'L';
+                        continue;
                     }
+
+                } else if (n == "@B") {
+                    if (size < 0 || size == 3 || size == 4) {
+                        sign_height = HT[size < 0 ? 3 : size];
+                        newmat = "BlackSign";
+                        newtype = 'B';
+                        continue;
+                    }
+                }
+            }
+
+            for (int i = 0; cmds[i].keyword; i++) {
+                if (name == cmds[i].keyword) {
+                    name = cmds[i].glyph_name;
+                    break;
                 }
-                if (maxlen)
-                    s += maxlen - 1;
             }
-            if (s[1] != ',' && s[1] != '}')
-                SG_LOG(SG_TERRAIN, SG_ALERT, TAXI "garbage after command `" << s << '\'');
 
-            if (newmat) {
-                material = matlib->find(newmat);
+            if (name[0] == '@') {
+                SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "ignoring unknown command `" << name << '\'');
                 continue;
             }
+        }
 
-            if (name.empty()) {
-                SG_LOG(SG_TERRAIN, SG_ALERT, TAXI "unknown command `" << s << '\'');
+        if (newmat.size()) {
+            material = matlib->find(newmat);
+            if (!material) {
+                SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "ignoring unknown material `" << newmat << '\'');
                 continue;
             }
-        } else
-            name = *s;
 
-        if (!material) {
-            SG_LOG( SG_TERRAIN, SG_ALERT, TAXI "material doesn't exit");
-            continue;
+            // set material states (lighted & unlighted)
+            lighted_state = material->get_state();
+            string u = newmat + ".unlighted";
+
+            SGMaterial *m = matlib->find(u);
+            if (m) {
+                unlighted_state = m->get_state();
+            } else {
+                SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "ignoring unknown material `" << u << '\'');
+                unlighted_state = lighted_state;
+            }
+            newmat = "";
         }
 
         SGMaterialGlyph *glyph = material->get_glyph(name);
         if (!glyph) {
-            SG_LOG( SG_TERRAIN, SG_ALERT, TAXI "unsupported character `" << *s << '\'');
+            SG_LOG( SG_TERRAIN, SG_ALERT, SIGN "unsupported glyph `" << *s << '\'');
             continue;
         }
 
-        elements.push_back(new element_info(material, glyph));
-        total_width += glyph->get_width() * material->get_xscale();
+        // in managed mode push frame stop and frame start first
+        osg::StateSet *state = lighted ? lighted_state : unlighted_state;
+        element_info *e;
+        if (newtype && newtype != oldtype) {
+            if (close) {
+                elements.push_back(close);
+                total_width += close->glyph->get_width() * close->scale;
+                close = 0;
+            }
+            oldtype = newtype;
+            SGMaterialGlyph *g = material->get_glyph("stop-frame");
+            if (g)
+                close = new element_info(material, state, g, sign_height);
+            g = material->get_glyph("start-frame");
+            if (g) {
+                e = new element_info(material, state, g, sign_height);
+                elements.push_back(e);
+                total_width += e->glyph->get_width() * e->scale;
+            }
+        }
+        // now the actually requested glyph
+        e = new element_info(material, state, glyph, sign_height);
+        elements.push_back(e);
+        total_width += e->glyph->get_width() * e->scale;
     }
 
-    double hpos = -total_width / 2;
+    // in managed mode close frame
+    if (close) {
+        elements.push_back(close);
+        total_width += close->glyph->get_width() * close->scale;
+        close = 0;
+    }
 
-    sgVec3 normal;
-    sgSetVec3(normal, 0, -1, 0);
 
-    sgVec4 color;
-    sgSetVec4(color, 1.0, 1.0, 1.0, 1.0);
+    // Part II: typeset
+    double hpos = -total_width / 2;
+    const double dist = 0.25;        // hard-code distance from surface for now
 
     for (unsigned int i = 0; i < elements.size(); i++) {
         element_info *element = elements[i];
 
         double xoffset = element->glyph->get_left();
+        double height = element->height;
         double width = element->glyph->get_width();
-        double abswidth = width * element->material->get_xscale();
+        double abswidth = width * element->scale;
 
         // vertices
-        ssgVertexArray *vl = new ssgVertexArray(4);
-        vl->add(hpos,            0, 0);
-        vl->add(hpos + abswidth, 0, 0);
-        vl->add(hpos,            0, sign_height);
-        vl->add(hpos + abswidth, 0, sign_height);
+        osg::Vec3Array* vl = new osg::Vec3Array;
+        vl->push_back(osg::Vec3(0, hpos,            dist));
+        vl->push_back(osg::Vec3(0, hpos + abswidth, dist));
+        vl->push_back(osg::Vec3(0, hpos,            dist + height));
+        vl->push_back(osg::Vec3(0, hpos + abswidth, dist + height));
 
         // texture coordinates
-        ssgTexCoordArray *tl = new ssgTexCoordArray(4);
-        tl->add(xoffset,         0);
-        tl->add(xoffset + width, 0);
-        tl->add(xoffset,         1);
-        tl->add(xoffset + width, 1);
+        osg::Vec2Array* tl = new osg::Vec2Array;
+        tl->push_back(osg::Vec2(xoffset,         0));
+        tl->push_back(osg::Vec2(xoffset + width, 0));
+        tl->push_back(osg::Vec2(xoffset,         1));
+        tl->push_back(osg::Vec2(xoffset + width, 1));
 
         // normals
-        ssgNormalArray *nl = new ssgNormalArray(1);
-        nl->add(normal);
+        osg::Vec3Array* nl = new osg::Vec3Array;
+        nl->push_back(osg::Vec3(0, -1, 0));
 
         // colors
-        ssgColourArray *cl = new ssgColourArray(1);
-        cl->add(color);
-
-        ssgLeaf *leaf = new ssgVtxTable(GL_TRIANGLE_STRIP, vl, nl, tl, cl);
-        ssgSimpleState *state = element->material->get_state();
-        //if (!lighted)
-        //    state->setMaterial(GL_EMISSION, 0, 0, 0, 1);
-        leaf->setState(state);
-
-        object->addKid(leaf);
+        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_OVERALL);
+        geometry->setColorArray(cl);
+        geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
+        geometry->setTexCoordArray(0, tl);
+        geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, vl->size()));
+        osg::Geode* geode = new osg::Geode;
+        geode->addDrawable(geometry);
+        geode->setStateSet(element->state);
+
+        object->addChild(geode);
         hpos += abswidth;
         delete element;
     }
 
-    return object;
-}
-
-
 
+    // minimalistic backside
+    osg::Vec3Array* vl = new osg::Vec3Array;
+    vl->push_back(osg::Vec3(0, hpos,               dist));
+    vl->push_back(osg::Vec3(0, hpos - total_width, dist));
+    vl->push_back(osg::Vec3(0, hpos,               dist + sign_height));
+    vl->push_back(osg::Vec3(0, hpos - total_width, dist + sign_height));
+
+    osg::Vec3Array* nl = new osg::Vec3Array;
+    nl->push_back(osg::Vec3(0, 1, 0));
+
+    osg::Geometry* geometry = new osg::Geometry;
+    geometry->setVertexArray(vl);
+    geometry->setNormalArray(nl);
+    geometry->setNormalBinding(osg::Geometry::BIND_OVERALL);
+    geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, vl->size()));
+    osg::Geode* geode = new osg::Geode;
+    geode->addDrawable(geometry);
+    SGMaterial *mat = matlib->find("BlackSign");
+    if (mat)
+      geode->setStateSet(mat->get_state());
+    object->addChild(geode);
 
+    return object;
+}
 
-ssgBranch *sgMakeRunwaySign( SGMaterialLib *matlib,
-                             const string path, const string name )
+osg::Node*
+SGMakeRunwaySign(SGMaterialLib *matlib, const string& path, const string& name)
 {
     // for demo purposes we assume each element (letter) is 1x1 meter.
     // Sign is placed 0.25 meters above the ground
 
-    ssgBranch *object = new ssgBranch();
-    object->setName( (char *)name.c_str() );
-
-    double width = name.length() / 3.0;
+    float width = name.length() / 3.0;
 
-    string material = name;
+    osg::Vec3 corner(-width, 0, 0.25f);
+    osg::Vec3 widthVec(2*width + 1, 0, 0);
+    osg::Vec3 heightVec(0, 0, 1);
+    osg::Geometry* geometry;
+    geometry = osg::createTexturedQuadGeometry(corner, widthVec, heightVec);
 
-    point_list nodes;
-    point_list normals;
-    point_list texcoords;
-    int_list vertex_index;
-    int_list normal_index;
-    int_list tex_index;
+    SGMaterial *mat = matlib->find(name);
+    if (mat)
+      geometry->setStateSet(mat->get_state());
 
-    nodes.push_back( Point3D( -width, 0, 0.25 ) );
-    nodes.push_back( Point3D( width + 1, 0, 0.25 ) );
-    nodes.push_back( Point3D( -width, 0, 1.25 ) );
-    nodes.push_back( Point3D( width + 1, 0, 1.25 ) );
+    osg::Geode* geode = new osg::Geode;
+    geode->setName(name);
+    geode->addDrawable(geometry);
 
-    normals.push_back( Point3D( 0, -1, 0 ) );
-
-    texcoords.push_back( Point3D( 0, 0, 0 ) );
-    texcoords.push_back( Point3D( 1, 0, 0 ) );
-    texcoords.push_back( Point3D( 0, 1, 0 ) );
-    texcoords.push_back( Point3D( 1, 1, 0 ) );
-
-    vertex_index.push_back( 0 );
-    vertex_index.push_back( 1 );
-    vertex_index.push_back( 2 );
-    vertex_index.push_back( 3 );
-
-    normal_index.push_back( 0 );
-    normal_index.push_back( 0 );
-    normal_index.push_back( 0 );
-    normal_index.push_back( 0 );
-
-    tex_index.push_back( 0 );
-    tex_index.push_back( 1 );
-    tex_index.push_back( 2 );
-    tex_index.push_back( 3 );
-
-    ssgLeaf *leaf = sgMakeLeaf( path, GL_TRIANGLE_STRIP, matlib, material,
-                                nodes, normals, texcoords,
-                                vertex_index, normal_index, tex_index,
-                                false, NULL );
-
-    object->addKid( leaf );
-
-    return object;
+    return geode;
 }