00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef HAVE_CONFIG_H
00024 # include <simgear_config.h>
00025 #endif
00026
00027 #include <vector>
00028
00029 #include <osg/StateSet>
00030 #include <osg/Geode>
00031 #include <osg/Geometry>
00032 #include <osg/Group>
00033
00034 #include <simgear/debug/logstream.hxx>
00035 #include <simgear/math/sg_types.hxx>
00036 #include <simgear/scene/material/Effect.hxx>
00037 #include <simgear/scene/material/EffectGeode.hxx>
00038 #include <simgear/scene/material/mat.hxx>
00039 #include <simgear/scene/material/matlib.hxx>
00040
00041 #include "apt_signs.hxx"
00042
00043 #define SIGN "OBJECT_SIGN: "
00044 #define RWY "OBJECT_RUNWAY_SIGN: "
00045
00046 using std::vector;
00047 using namespace simgear;
00048
00049
00050 struct element_info {
00051 element_info(SGMaterial *m, Effect *s, SGMaterialGlyph *g, double h)
00052 : material(m), state(s), glyph(g), height(h)
00053 {
00054 scale = h * m->get_xsize()
00055 / (m->get_ysize() < 0.001 ? 1.0 : m->get_ysize());
00056 }
00057 SGMaterial *material;
00058 Effect *state;
00059 SGMaterialGlyph *glyph;
00060 double height;
00061 double scale;
00062 };
00063
00064
00065
00066 const double HT[5] = {0.460, 0.610, 0.760, 1.220, 0.760};
00067
00068
00069
00070 struct pair {
00071 const char *keyword;
00072 const char *glyph_name;
00073 } cmds[] = {
00074 {"@u", "^u"},
00075 {"@d", "^d"},
00076 {"@l", "^l"},
00077 {"@lu", "^lu"},
00078 {"@ul", "^lu"},
00079 {"@ld", "^ld"},
00080 {"@dl", "^ld"},
00081 {"@r", "^r"},
00082 {"@ru", "^ru"},
00083 {"@ur", "^ru"},
00084 {"@rd", "^rd"},
00085 {"@dr", "^rd"},
00086 {0, 0},
00087 };
00088
00089
00090
00091
00092 osg::Node*
00093 SGMakeSign(SGMaterialLib *matlib, const string& path, const string& content)
00094 {
00095 double sign_height = 1.0;
00096 bool lighted = true;
00097 string newmat = "BlackSign";
00098
00099 vector<element_info *> elements;
00100 element_info *close = 0;
00101 double total_width = 0.0;
00102 bool cmd = false;
00103 int size = -1;
00104 char oldtype = 0, newtype = 0;
00105
00106 osg::Group* object = new osg::Group;
00107 object->setName(content);
00108
00109 SGMaterial *material = 0;
00110 Effect *lighted_state = 0;
00111 Effect *unlighted_state = 0;
00112
00113
00114 for (const char *s = content.data(); *s; s++) {
00115 string name;
00116 string value;
00117
00118 if (*s == '{') {
00119 if (cmd)
00120 SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "unexpected { in sign contents");
00121 cmd = true;
00122 continue;
00123
00124 } else if (*s == '}') {
00125 if (!cmd)
00126 SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "unexpected } in sign contents");
00127 cmd = false;
00128 continue;
00129
00130 } else if (!cmd) {
00131 name = *s;
00132
00133 } else {
00134 if (*s == ',')
00135 continue;
00136
00137 for (; *s; s++) {
00138 name += *s;
00139 if (s[1] == ',' || s[1] == '}' || s[1] == '=')
00140 break;
00141 }
00142 if (!*s) {
00143 SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "unclosed { in sign contents");
00144 } else if (s[1] == '=') {
00145 for (s += 2; *s; s++) {
00146 value += *s;
00147 if (s[1] == ',' || s[1] == '}')
00148 break;
00149 }
00150 if (!*s)
00151 SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "unclosed { in sign contents");
00152 }
00153
00154 if (name == "@size") {
00155 sign_height = strtod(value.data(), 0);
00156 continue;
00157 }
00158
00159 if (name == "@light") {
00160 lighted = (value != "0" && value != "no" && value != "off" && value != "false");
00161 continue;
00162 }
00163
00164 if (name == "@material") {
00165 newmat = value.data();
00166 continue;
00167
00168 } else if (name.size() == 2 || name.size() == 3) {
00169 string n = name;
00170 if (n.size() == 3 && n[2] >= '1' && n[2] <= '5') {
00171 size = n[2] - '1';
00172 n = n.substr(0, 2);
00173 }
00174
00175 if (n == "@Y") {
00176 if (size < 3) {
00177 sign_height = HT[size < 0 ? 2 : size];
00178 newmat = "YellowSign";
00179 newtype = 'Y';
00180 continue;
00181 }
00182
00183 } else if (n == "@R") {
00184 if (size < 3) {
00185 sign_height = HT[size < 0 ? 2 : size];
00186 newmat = "RedSign";
00187 newtype = 'R';
00188 continue;
00189 }
00190
00191 } else if (n == "@L") {
00192 if (size < 3) {
00193 sign_height = HT[size < 0 ? 2 : size];
00194 newmat = "FramedSign";
00195 newtype = 'L';
00196 continue;
00197 }
00198
00199 } else if (n == "@B") {
00200 if (size < 0 || size == 3 || size == 4) {
00201 sign_height = HT[size < 0 ? 3 : size];
00202 newmat = "BlackSign";
00203 newtype = 'B';
00204 continue;
00205 }
00206 }
00207 }
00208
00209 for (int i = 0; cmds[i].keyword; i++) {
00210 if (name == cmds[i].keyword) {
00211 name = cmds[i].glyph_name;
00212 break;
00213 }
00214 }
00215
00216 if (name[0] == '@') {
00217 SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "ignoring unknown command `" << name << '\'');
00218 continue;
00219 }
00220 }
00221
00222 if (newmat.size()) {
00223 SGMaterial *m = matlib->find(newmat);
00224 if (!m) {
00225
00226 SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "ignoring unknown material `" << newmat << '\'');
00227 } else {
00228 material = m;
00229
00230 lighted_state = material->get_effect();
00231 newmat.append(".unlighted");
00232
00233 m = matlib->find(newmat);
00234 if (m) {
00235 unlighted_state = m->get_effect();
00236 } else {
00237 SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "ignoring unknown material `" << newmat << '\'');
00238 unlighted_state = lighted_state;
00239 }
00240 }
00241 newmat.clear();
00242 }
00243
00244
00245
00246 if (!material) continue;
00247
00248 SGMaterialGlyph *glyph = material->get_glyph(name);
00249 if (!glyph) {
00250 SG_LOG( SG_TERRAIN, SG_ALERT, SIGN "unsupported glyph `" << *s << '\'');
00251 continue;
00252 }
00253
00254
00255 Effect *state = lighted ? lighted_state : unlighted_state;
00256 element_info *e;
00257 if (newtype && newtype != oldtype) {
00258 if (close) {
00259 elements.push_back(close);
00260 total_width += close->glyph->get_width() * close->scale;
00261 close = 0;
00262 }
00263 oldtype = newtype;
00264 SGMaterialGlyph *g = material->get_glyph("stop-frame");
00265 if (g)
00266 close = new element_info(material, state, g, sign_height);
00267 g = material->get_glyph("start-frame");
00268 if (g) {
00269 e = new element_info(material, state, g, sign_height);
00270 elements.push_back(e);
00271 total_width += e->glyph->get_width() * e->scale;
00272 }
00273 }
00274
00275 e = new element_info(material, state, glyph, sign_height);
00276 elements.push_back(e);
00277 total_width += e->glyph->get_width() * e->scale;
00278 }
00279
00280
00281 if (close) {
00282 elements.push_back(close);
00283 total_width += close->glyph->get_width() * close->scale;
00284 close = 0;
00285 }
00286
00287
00288
00289 double hpos = -total_width / 2;
00290 const double dist = 0.25;
00291
00292 for (unsigned int i = 0; i < elements.size(); i++) {
00293 element_info *element = elements[i];
00294
00295 double xoffset = element->glyph->get_left();
00296 double height = element->height;
00297 double width = element->glyph->get_width();
00298 double abswidth = width * element->scale;
00299
00300
00301 osg::Vec3Array* vl = new osg::Vec3Array;
00302 vl->push_back(osg::Vec3(0, hpos, dist));
00303 vl->push_back(osg::Vec3(0, hpos + abswidth, dist));
00304 vl->push_back(osg::Vec3(0, hpos, dist + height));
00305 vl->push_back(osg::Vec3(0, hpos + abswidth, dist + height));
00306
00307
00308 osg::Vec2Array* tl = new osg::Vec2Array;
00309 tl->push_back(osg::Vec2(xoffset, 0));
00310 tl->push_back(osg::Vec2(xoffset + width, 0));
00311 tl->push_back(osg::Vec2(xoffset, 1));
00312 tl->push_back(osg::Vec2(xoffset + width, 1));
00313
00314
00315 osg::Vec3Array* nl = new osg::Vec3Array;
00316 nl->push_back(osg::Vec3(0, -1, 0));
00317
00318
00319 osg::Vec4Array* cl = new osg::Vec4Array;
00320 cl->push_back(osg::Vec4(1, 1, 1, 1));
00321
00322 osg::Geometry* geometry = new osg::Geometry;
00323 geometry->setVertexArray(vl);
00324 geometry->setNormalArray(nl);
00325 geometry->setNormalBinding(osg::Geometry::BIND_OVERALL);
00326 geometry->setColorArray(cl);
00327 geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
00328 geometry->setTexCoordArray(0, tl);
00329 geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, vl->size()));
00330 EffectGeode* geode = new EffectGeode;
00331 geode->addDrawable(geometry);
00332 geode->setEffect(element->state);
00333
00334 object->addChild(geode);
00335 hpos += abswidth;
00336 delete element;
00337 }
00338
00339
00340
00341 osg::Vec3Array* vl = new osg::Vec3Array;
00342 vl->push_back(osg::Vec3(0, hpos, dist));
00343 vl->push_back(osg::Vec3(0, hpos - total_width, dist));
00344 vl->push_back(osg::Vec3(0, hpos, dist + sign_height));
00345 vl->push_back(osg::Vec3(0, hpos - total_width, dist + sign_height));
00346
00347 osg::Vec3Array* nl = new osg::Vec3Array;
00348 nl->push_back(osg::Vec3(0, 1, 0));
00349
00350 osg::Geometry* geometry = new osg::Geometry;
00351 geometry->setVertexArray(vl);
00352 geometry->setNormalArray(nl);
00353 geometry->setNormalBinding(osg::Geometry::BIND_OVERALL);
00354 geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, vl->size()));
00355 EffectGeode* geode = new EffectGeode;
00356 geode->addDrawable(geometry);
00357 SGMaterial *mat = matlib->find("BlackSign");
00358 if (mat)
00359 geode->setEffect(mat->get_effect());
00360 object->addChild(geode);
00361
00362 return object;
00363 }
00364
00365 osg::Node*
00366 SGMakeRunwaySign(SGMaterialLib *matlib, const string& path, const string& name)
00367 {
00368
00369
00370
00371 float width = name.length() / 3.0;
00372
00373 osg::Vec3 corner(-width, 0, 0.25f);
00374 osg::Vec3 widthVec(2*width + 1, 0, 0);
00375 osg::Vec3 heightVec(0, 0, 1);
00376 osg::Geometry* geometry;
00377 geometry = osg::createTexturedQuadGeometry(corner, widthVec, heightVec);
00378 EffectGeode* geode = new EffectGeode;
00379 geode->setName(name);
00380 geode->addDrawable(geometry);
00381 SGMaterial *mat = matlib->find(name);
00382 if (mat)
00383 geode->setEffect(mat->get_effect());
00384
00385 return geode;
00386 }