X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fscene%2Ftgdb%2Fapt_signs.cxx;h=8341005189fb7f0940c829b99ae3f26748c2741d;hb=71443d1c9abb0ef3aa5b1ac5ed32c0624c958c50;hp=c06e51411ea89d923e90229c80b10ff8b6d7155c;hpb=dd080de16c5dabbca769f561c23f45c1853d32ef;p=simgear.git diff --git a/simgear/scene/tgdb/apt_signs.cxx b/simgear/scene/tgdb/apt_signs.cxx index c06e5141..83410051 100644 --- a/simgear/scene/tgdb/apt_signs.cxx +++ b/simgear/scene/tgdb/apt_signs.cxx @@ -2,7 +2,7 @@ // // Written by Curtis Olson, started July 2001. // -// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org +// Copyright (C) 2001 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 @@ -16,152 +16,435 @@ // // 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // $Id$ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include +#include +#include +#include +#include #include #include -#include +#include +#include +#include +#include #include "apt_signs.hxx" +#define SIGN "OBJECT_SIGN: " + +using std::vector; +using namespace simgear; -ssgBranch *sgMakeTaxiSign( SGMaterialLib *matlib, - const string path, const string content ) +// 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) + { + 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; + double abswidth; + double coverwidth; +}; + +typedef std::vector 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 + + +// translation table for "command" to "glyph name" +struct pair { + const char *keyword; + const char *glyph_name; +} cmds[] = { + {"@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}, +}; + +struct GlyphGeometry { - // 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 *)content.c_str() ); - - double offset = content.length() / 2.0; - - for ( unsigned int i = 0; i < content.length(); ++i ) { - string material; - - char item = content[i]; - if ( item == '<' ) { - material = "ArrowL.rgb"; - } else if ( item == '>' ) { - material = "ArrowR.rgb"; - } else if ( item >= 'A' && item <= 'Z' ) { - material = "Letter"; - material += item; - material += ".rgb"; - } else if ( item >= 'a' && item <= 'z' ) { - int tmp = item - 'a'; - char c = 'A' + tmp; - material = "Black"; - material += c; - material += ".rgb"; - } else { - SG_LOG( SG_TERRAIN, SG_ALERT, - "Unknown taxi sign code = '" << item << "' !!!!" ); - return NULL; - } - - point_list nodes; nodes.clear(); - point_list normals; normals.clear(); - point_list texcoords; texcoords.clear(); - int_list vertex_index; vertex_index.clear(); - int_list normal_index; normal_index.clear(); - int_list tex_index; tex_index.clear(); - - nodes.push_back( Point3D( -offset + i, 0, 0.25 ) ); - nodes.push_back( Point3D( -offset + i + 1, 0, 0.25 ) ); - nodes.push_back( Point3D( -offset + i, 0, 1.25 ) ); - nodes.push_back( Point3D( -offset + i + 1, 0, 1.25 ) ); - - 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 ); + osg::DrawArrays* quads; + osg::Vec2Array* uvs; + osg::Vec3Array* vertices; + osg::Vec3Array* normals; + + void addGlyph(SGMaterialGlyph* glyph, double x, double y, double width, double height, const osg::Matrix& xform) + { + + vertices->push_back(xform.preMult(osg::Vec3(thick, x, y))); + vertices->push_back(xform.preMult(osg::Vec3(thick, x + width, y))); + vertices->push_back(xform.preMult(osg::Vec3(thick, x + width, y + height))); + vertices->push_back(xform.preMult(osg::Vec3(thick, x, y + height))); + + // texture coordinates + double xoffset = glyph->get_left(); + double texWidth = glyph->get_width(); + + uvs->push_back(osg::Vec2(xoffset, 0)); + uvs->push_back(osg::Vec2(xoffset + texWidth, 0)); + uvs->push_back(osg::Vec2(xoffset + texWidth, 1)); + uvs->push_back(osg::Vec2(xoffset, 1)); + + // normals + for (int i=0; i<4; ++i) + normals->push_back(xform.preMult(osg::Vec3(0, -1, 0))); + + quads->setCount(vertices->size()); + } + + void addSignCase(double caseWidth, double caseHeight, const osg::Matrix& xform) + { + 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)); + vertices->push_back(osg::Vec3(-thick, -caseWidth, grounddist + caseHeight)); + + + for (int i=0; i<4; ++i) + normals->push_back(xform.preMult(osg::Vec3(-1, 0.0, 0))); + + vertices->push_back(osg::Vec3(-thick, -caseWidth, grounddist + caseHeight)); + vertices->push_back(osg::Vec3(thick, -caseWidth, grounddist + caseHeight)); + vertices->push_back(osg::Vec3(thick, caseWidth, grounddist + caseHeight)); + 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))); + + vertices->push_back(osg::Vec3(-thick, caseWidth, grounddist + caseHeight)); + vertices->push_back(osg::Vec3(thick, caseWidth, grounddist + caseHeight)); + vertices->push_back(osg::Vec3(thick, caseWidth, grounddist)); + 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))); + + for (int i = 0; i < 3; ++i) { + uvs->push_back(osg::Vec2(1, 1)); + uvs->push_back(osg::Vec2(0.75, 1)); + uvs->push_back(osg::Vec2(0.75, 0)); + uvs->push_back(osg::Vec2(1, 0)); } + + quads->setCount(vertices->size()); + } +}; - return object; -} +typedef std::map EffectGeometryMap; - -ssgBranch *sgMakeRunwaySign( SGMaterialLib *matlib, - const string path, const string name ) +void SGMakeSignFace(EffectGeometryMap& glyphs, const ElementVec& elements, double hpos, const osg::Matrix& xform) { - // 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; - - string material = name + ".rgb"; - - point_list nodes; nodes.clear(); - point_list normals; normals.clear(); - point_list texcoords; texcoords.clear(); - int_list vertex_index; vertex_index.clear(); - int_list normal_index; normal_index.clear(); - int_list tex_index; tex_index.clear(); - - 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 ) ); + 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; + } +} - normals.push_back( Point3D( 0, -1, 0 ) ); +GlyphGeometry* makeGeometry(Effect* eff, osg::Group* group) +{ + GlyphGeometry* gg = new GlyphGeometry; + + EffectGeode* geode = new EffectGeode; + geode->setEffect(eff); + + gg->vertices = new osg::Vec3Array; + gg->normals = new osg::Vec3Array; + gg->uvs = new osg::Vec2Array; + + osg::Vec4Array* cl = new osg::Vec4Array; + cl->push_back(osg::Vec4(1, 1, 1, 1)); + + osg::Geometry* geometry = new osg::Geometry; + geometry->setVertexArray(gg->vertices); + geometry->setNormalArray(gg->normals); + geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); + geometry->setColorArray(cl); + geometry->setColorBinding(osg::Geometry::BIND_OVERALL); + geometry->setTexCoordArray(0, gg->uvs); + + gg->quads = new osg::DrawArrays(GL_QUADS, 0, gg->vertices->size()); + geometry->addPrimitiveSet(gg->quads); + geode->addDrawable(geometry); + group->addChild(geode); + return gg; +} - 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 ) ); +// see $FG_ROOT/Docs/README.scenery +// +osg::Node* +SGMakeSign(SGMaterialLib *matlib, const string& content) +{ + double sign_height = 1.0; // meter + string newmat = "BlackSign"; + ElementVec elements1, elements2; + element_info *close1 = 0; + element_info *close2 = 0; + double total_width1 = 0.0; + double total_width2 = 0.0; + bool cmd = false; + 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 + for (const char *s = content.data(); *s; s++) { + string name; + string value; + + if (*s == '{') { + if (cmd) + SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "Illegal taxiway sign syntax. Unexpected '{' in '" << content << "'."); + cmd = true; + continue; + + } else if (*s == '}') { + if (!cmd) + SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "Illegal taxiway sign syntax. Unexpected '}' in '" << content << "'."); + cmd = false; + continue; + + } else if (!cmd) { + name = *s; + + } else { + if (*s == ',') + continue; + + 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 == "@@") { + isBackside = true; + continue; + } + + if (name == "@size") { + sign_height = strtod(value.data(), 0); + continue; + } + + 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 (name[0] == '@') { + SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "ignoring unknown command `" << name << '\''); + continue; + } + } + + if (newmat.size()) { + material = matlib->find(newmat); + newmat.clear(); + } + + SGMaterialGlyph *glyph = material->get_glyph(name); + if (!glyph) { + SG_LOG( SG_TERRAIN, SG_ALERT, SIGN "unsupported glyph '" << *s << '\''); + 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; + if (!isBackside) { + if (newtype && newtype != oldtype) { + if (close1) { + elements1.push_back(close1); + total_width1 += close1->glyph->get_width() * close1->scale; + close1 = 0; + } + oldtype = newtype; + SGMaterialGlyph *g = material->get_glyph("stop-frame"); + if (g) + close1 = new element_info(material, state, g, sign_height, 0); + g = material->get_glyph("start-frame"); + if (g) { + e1 = new element_info(material, state, 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); + elements1.push_back(e1); + total_width1 += e1->glyph->get_width() * e1->scale; + } else { + if (newtype && newtype != oldtype) { + if (close2) { + elements2.push_back(close2); + total_width2 += close2->glyph->get_width() * close2->scale; + close2 = 0; + } + oldtype = newtype; + SGMaterialGlyph *g = material->get_glyph("stop-frame"); + if (g) + close2 = new element_info(material, state, g, sign_height, 0); + g = material->get_glyph("start-frame"); + if (g) { + e2 = new element_info(material, state, 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); + elements2.push_back(e2); + total_width2 += e2->glyph->get_width() * e2->scale; + } + } - vertex_index.push_back( 0 ); - vertex_index.push_back( 1 ); - vertex_index.push_back( 2 ); - vertex_index.push_back( 3 ); + // in managed mode close frame + if (close1) { + elements1.push_back(close1); + total_width1 += close1->glyph->get_width() * close1->scale; + close1 = 0; + } - normal_index.push_back( 0 ); - normal_index.push_back( 0 ); - normal_index.push_back( 0 ); - normal_index.push_back( 0 ); + if (close2) { + elements2.push_back(close2); + total_width2 += close2->glyph->get_width() * close2->scale; + close2 = 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 ); + // 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); + + double coverSize = fabs(total_width1 - total_width2) * 0.5; + + 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); + } + + } 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); + } + } - object->addKid( leaf ); + // Create front side + SGMakeSignFace(geoms, elements1, hpos, osg::Matrix::identity()); + // 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; }