+// 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;
+ }
+ }