]> git.mxchange.org Git - simgear.git/blob - simgear/scene/tgdb/apt_signs.cxx
Remove unused SGMakeRunwaySign function.
[simgear.git] / simgear / scene / tgdb / apt_signs.cxx
1 // apt_signs.cxx -- build airport signs on the fly
2 //
3 // Written by Curtis Olson, started July 2001.
4 //
5 // Copyright (C) 2001  Curtis L. Olson  - http://www.flightgear.org/~curt
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 //
21 // $Id$
22
23 #ifdef HAVE_CONFIG_H
24 #  include <simgear_config.h>
25 #endif
26
27 #include <vector>
28
29 #include <osg/StateSet>
30 #include <osg/Geode>
31 #include <osg/Geometry>
32 #include <osg/Group>
33
34 #include <simgear/debug/logstream.hxx>
35 #include <simgear/math/sg_types.hxx>
36 #include <simgear/scene/material/Effect.hxx>
37 #include <simgear/scene/material/EffectGeode.hxx>
38 #include <simgear/scene/material/mat.hxx>
39 #include <simgear/scene/material/matlib.hxx>
40
41 #include "apt_signs.hxx"
42
43 #define SIGN "OBJECT_SIGN: "
44
45 using std::vector;
46 using namespace simgear;
47
48 // for temporary storage of sign elements
49 struct element_info {
50     element_info(SGMaterial *m, Effect *s, SGMaterialGlyph *g, double h)
51         : material(m), state(s), glyph(g), height(h)
52     {
53         scale = h * m->get_xsize()
54                 / (m->get_ysize() < 0.001 ? 1.0 : m->get_ysize());
55     }
56     SGMaterial *material;
57     Effect *state;
58     SGMaterialGlyph *glyph;
59     double height;
60     double scale;
61 };
62
63
64 // standard panel height sizes
65 const double HT[5] = {0.460, 0.610, 0.760, 1.220, 0.760};
66
67
68 // translation table for "command" to "glyph name"
69 struct pair {
70     const char *keyword;
71     const char *glyph_name;
72 } cmds[] = {
73     {"@u",       "^u"},
74     {"@d",       "^d"},
75     {"@l",       "^l"},
76     {"@lu",      "^lu"},
77     {"@ul",      "^lu"},
78     {"@ld",      "^ld"},
79     {"@dl",      "^ld"},
80     {"@r",       "^r"},
81     {"@ru",      "^ru"},
82     {"@ur",      "^ru"},
83     {"@rd",      "^rd"},
84     {"@dr",      "^rd"},
85     {0, 0},
86 };
87
88
89 // see $FG_ROOT/Docs/README.scenery
90 //
91 osg::Node*
92 SGMakeSign(SGMaterialLib *matlib, const string& content)
93 {
94     double sign_height = 1.0;  // meter
95     bool lighted = true;
96     string newmat = "BlackSign";
97
98     vector<element_info *> elements;
99     element_info *close = 0;
100     double total_width = 0.0;
101     bool cmd = false;
102     int size = -1;
103     char oldtype = 0, newtype = 0;
104
105     osg::Group* object = new osg::Group;
106     object->setName(content);
107
108     SGMaterial *material = 0;
109     Effect *lighted_state = 0;
110     Effect *unlighted_state = 0;
111
112     // Part I: parse & measure
113     for (const char *s = content.data(); *s; s++) {
114         string name;
115         string value;
116
117         if (*s == '{') {
118             if (cmd)
119                 SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "Illegal taxiway sign syntax. Unexpected '{' in '" << content << "'.");
120             cmd = true;
121             continue;
122
123         } else if (*s == '}') {
124             if (!cmd)
125                 SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "Illegal taxiway sign syntax. Unexpected '{' in '" << content << "'.");
126             cmd = false;
127             continue;
128
129         } else if (!cmd) {
130             name = *s;
131
132         } else {
133             if (*s == ',')
134                 continue;
135
136             for (; *s; s++) {
137                 name += *s;
138                 if (s[1] == ',' || s[1] == '}' || s[1] == '=')
139                     break;
140             }
141             if (!*s) {
142                 SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "unclosed { in sign contents");
143             } else if (s[1] == '=') {
144                 for (s += 2; *s; s++) {
145                     value += *s;
146                     if (s[1] == ',' || s[1] == '}')
147                         break;
148                 }
149                 if (!*s)
150                     SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "unclosed { in sign contents");
151             }
152
153             if (name == "@size") {
154                 sign_height = strtod(value.data(), 0);
155                 continue;
156             }
157
158             if (name == "@light") {
159                 lighted = (value != "0" && value != "no" && value != "off" && value != "false");
160                 continue;
161             }
162
163             if (name == "@material") {
164                 newmat = value.data();
165                 continue;
166
167             } else if (name.size() == 2 || name.size() == 3) {
168                 string n = name;
169                 if (n.size() == 3 && n[2] >= '1' && n[2] <= '5') {
170                     size = n[2] - '1';
171                     n = n.substr(0, 2);
172                 }
173
174                 if (n == "@Y") {
175                     if (size < 3) {
176                         sign_height = HT[size < 0 ? 2 : size];
177                         newmat = "YellowSign";
178                         newtype = 'Y';
179                         continue;
180                     }
181
182                 } else if (n == "@R") {
183                     if (size < 3) {
184                         sign_height = HT[size < 0 ? 2 : size];
185                         newmat = "RedSign";
186                         newtype = 'R';
187                         continue;
188                     }
189
190                 } else if (n == "@L") {
191                     if (size < 3) {
192                         sign_height = HT[size < 0 ? 2 : size];
193                         newmat = "FramedSign";
194                         newtype = 'L';
195                         continue;
196                     }
197
198                 } else if (n == "@B") {
199                     if (size < 0 || size == 3 || size == 4) {
200                         sign_height = HT[size < 0 ? 3 : size];
201                         newmat = "BlackSign";
202                         newtype = 'B';
203                         continue;
204                     }
205                 }
206             }
207
208             for (int i = 0; cmds[i].keyword; i++) {
209                 if (name == cmds[i].keyword) {
210                     name = cmds[i].glyph_name;
211                     break;
212                 }
213             }
214
215             if (name[0] == '@') {
216                 SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "ignoring unknown command `" << name << '\'');
217                 continue;
218             }
219         }
220
221         if (newmat.size()) {
222             SGMaterial *m = matlib->find(newmat);
223             if (!m) {
224                 // log error, but keep using previous material to at least show something
225                 SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "ignoring unknown material `" << newmat << '\'');
226             } else {
227                 material = m;
228                 // set material states (lighted & unlighted)
229                 lighted_state = material->get_effect();
230                 newmat.append(".unlighted");
231
232                 m = matlib->find(newmat);
233                 if (m) {
234                     unlighted_state = m->get_effect();
235                 } else {
236                     SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "ignoring unknown material `" << newmat << '\'');
237                     unlighted_state = lighted_state;
238                 }
239             }
240             newmat.clear();
241         }
242
243         // This can only happen if the default material is missing.
244         // Error has been already logged in the block above.
245         if (!material) continue;
246  
247         SGMaterialGlyph *glyph = material->get_glyph(name);
248         if (!glyph) {
249             SG_LOG( SG_TERRAIN, SG_ALERT, SIGN "unsupported glyph `" << *s << '\'');
250             continue;
251         }
252
253         // in managed mode push frame stop and frame start first
254         Effect *state = lighted ? lighted_state : unlighted_state;
255         element_info *e;
256         if (newtype && newtype != oldtype) {
257             if (close) {
258                 elements.push_back(close);
259                 total_width += close->glyph->get_width() * close->scale;
260                 close = 0;
261             }
262             oldtype = newtype;
263             SGMaterialGlyph *g = material->get_glyph("stop-frame");
264             if (g)
265                 close = new element_info(material, state, g, sign_height);
266             g = material->get_glyph("start-frame");
267             if (g) {
268                 e = new element_info(material, state, g, sign_height);
269                 elements.push_back(e);
270                 total_width += e->glyph->get_width() * e->scale;
271             }
272         }
273         // now the actually requested glyph
274         e = new element_info(material, state, glyph, sign_height);
275         elements.push_back(e);
276         total_width += e->glyph->get_width() * e->scale;
277     }
278
279     // in managed mode close frame
280     if (close) {
281         elements.push_back(close);
282         total_width += close->glyph->get_width() * close->scale;
283         close = 0;
284     }
285
286
287     // Part II: typeset
288     double hpos = -total_width / 2;
289     const double dist = 0.25;        // hard-code distance from surface for now
290
291     for (unsigned int i = 0; i < elements.size(); i++) {
292         element_info *element = elements[i];
293
294         double xoffset = element->glyph->get_left();
295         double height = element->height;
296         double width = element->glyph->get_width();
297         double abswidth = width * element->scale;
298
299         // vertices
300         osg::Vec3Array* vl = new osg::Vec3Array;
301         vl->push_back(osg::Vec3(0, hpos,            dist));
302         vl->push_back(osg::Vec3(0, hpos + abswidth, dist));
303         vl->push_back(osg::Vec3(0, hpos,            dist + height));
304         vl->push_back(osg::Vec3(0, hpos + abswidth, dist + height));
305
306         // texture coordinates
307         osg::Vec2Array* tl = new osg::Vec2Array;
308         tl->push_back(osg::Vec2(xoffset,         0));
309         tl->push_back(osg::Vec2(xoffset + width, 0));
310         tl->push_back(osg::Vec2(xoffset,         1));
311         tl->push_back(osg::Vec2(xoffset + width, 1));
312
313         // normals
314         osg::Vec3Array* nl = new osg::Vec3Array;
315         nl->push_back(osg::Vec3(0, -1, 0));
316
317         // colors
318         osg::Vec4Array* cl = new osg::Vec4Array;
319         cl->push_back(osg::Vec4(1, 1, 1, 1));
320
321         osg::Geometry* geometry = new osg::Geometry;
322         geometry->setVertexArray(vl);
323         geometry->setNormalArray(nl);
324         geometry->setNormalBinding(osg::Geometry::BIND_OVERALL);
325         geometry->setColorArray(cl);
326         geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
327         geometry->setTexCoordArray(0, tl);
328         geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, vl->size()));
329         EffectGeode* geode = new EffectGeode;
330         geode->addDrawable(geometry);
331         geode->setEffect(element->state);
332
333         object->addChild(geode);
334         hpos += abswidth;
335         delete element;
336     }
337
338
339     // minimalistic backside
340     osg::Vec3Array* vl = new osg::Vec3Array;
341     vl->push_back(osg::Vec3(0, hpos,               dist));
342     vl->push_back(osg::Vec3(0, hpos - total_width, dist));
343     vl->push_back(osg::Vec3(0, hpos,               dist + sign_height));
344     vl->push_back(osg::Vec3(0, hpos - total_width, dist + sign_height));
345
346     osg::Vec2Array* tl = new osg::Vec2Array;
347     for (int i = 0; i < 4; ++i)
348         tl->push_back(osg::Vec2(0.0, 0.0));
349     osg::Vec3Array* nl = new osg::Vec3Array;
350     nl->push_back(osg::Vec3(0, 1, 0));
351     osg::Vec4Array* cl = new osg::Vec4Array;
352     cl->push_back(osg::Vec4(0.0, 0.0, 0.0, 1.0));
353     osg::Geometry* geometry = new osg::Geometry;
354     geometry->setVertexArray(vl);
355     geometry->setNormalArray(nl);
356     geometry->setNormalBinding(osg::Geometry::BIND_OVERALL);
357     geometry->setTexCoordArray(0, tl);
358     geometry->setColorArray(cl);
359     geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
360     geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, vl->size()));
361     EffectGeode* geode = new EffectGeode;
362     geode->addDrawable(geometry);
363     SGMaterial *mat = matlib->find("BlackSign");
364     if (mat)
365       geode->setEffect(mat->get_effect());
366     object->addChild(geode);
367
368     return object;
369 }