X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fscene%2Ftgdb%2Fapt_signs.cxx;h=4053dda16ff204b0a513d4af480ba9d48a1bd3dc;hb=d4c7e950927b1e19a7a7622a7919f32233a6b7a8;hp=2f80afe3ef76a7b0b99b0bdde075978f63c8693e;hpb=dbda8ef893995d2a65434f5701371fc815684ad9;p=simgear.git diff --git a/simgear/scene/tgdb/apt_signs.cxx b/simgear/scene/tgdb/apt_signs.cxx index 2f80afe3..4053dda1 100644 --- a/simgear/scene/tgdb/apt_signs.cxx +++ b/simgear/scene/tgdb/apt_signs.cxx @@ -24,252 +24,357 @@ # include #endif +#include + +#include +#include +#include +#include + #include #include -#include #include #include #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) { - scale = m->get_xsize() / (m->get_ysize() < 0.001 ? 1.0 : m->get_ysize()); + 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 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; } } - 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); + for (int i = 0; cmds[i].keyword; i++) { + if (name == cmds[i].keyword) { + name = cmds[i].glyph_name; + break; + } + } + + 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; } - element_info *e = new element_info(material, glyph); + // 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 += glyph->get_width() * e->scale; + 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->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; }