]> git.mxchange.org Git - simgear.git/blob - simgear/scene/tgdb/apt_signs.cxx
- commands do now have to start with @
[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 <simgear/debug/logstream.hxx>
28 #include <simgear/math/sg_types.hxx>
29 #include <simgear/scene/tgdb/leaf.hxx>
30 #include <simgear/scene/material/mat.hxx>
31 #include <simgear/scene/material/matlib.hxx>
32
33 #include "apt_signs.hxx"
34
35 #define TAXI "OBJECT_TAXI_SIGN: "
36 #define RWY "OBJECT_RUNWAY_SIGN: "
37
38
39 // for temporary storage of sign elements
40 struct element_info {
41     element_info(SGMaterial *m, SGMaterialGlyph *g, double h, bool l)
42         : material(m), glyph(g), height(h), lighted(l)
43     {
44         scale = h * m->get_xsize()
45                 / (m->get_ysize() < 0.001 ? 1.0 : m->get_ysize());
46     }
47     SGMaterial *material;
48     SGMaterialGlyph *glyph;
49     double height;
50     double scale;
51     bool lighted;
52 };
53
54
55 // standard panel height sizes
56 const double HT[5] = {0.460, 0.610, 0.760, 1.220, 0.760};
57
58
59 // translation table for "command" to "glyph name"
60 struct pair {
61     const char *keyword;
62     const char *glyph_name;
63 } cmds[] = {
64     {"@u",       "up"},
65     {"@d",       "down"},
66     {"@l",       "left"},
67     {"@lu",      "left-up"},
68     {"@ul",      "left-up"},
69     {"@ld",      "left-down"},
70     {"@dl",      "left-down"},
71     {"@r",       "right"},
72     {"@ru",      "right-up"},
73     {"@ur",      "right-up"},
74     {"@rd",      "right-down"},
75     {"@dr",      "right-down"},
76     {0, 0},
77 };
78
79
80 // Y ... black on yellow            -> direction, destination, boundary
81 // R ... white on red               -> mandatory instruction
82 // L ... yellow on black with frame -> runway/taxiway location
83 // B ... white on black             -> runway distance remaining
84 //
85 // u/d/l/r     ... up/down/left/right arrow or two-letter combinations
86 //                 thereof (ur, dl, ...)
87 //
88 // Example: {l}E|{L}[T]|{Y,ur}L|E{r}
89 //
90 ssgBranch *sgMakeTaxiSign( SGMaterialLib *matlib,
91                            const string path, const string content )
92 {
93     double sign_height = 1.0;  // meter
94     bool lighted = true;
95
96     vector<element_info *> elements;
97     element_info *close = 0;
98     double total_width = 0.0;
99     bool cmd = false;
100     char *newmat = "BlackSign";
101     int size = -1;
102     char oldtype = 0, newtype = 0;
103
104     ssgBranch *object = new ssgBranch();
105     object->setName((char *)content.c_str());
106     SGMaterial *material = matlib->find(newmat);
107
108     // Part I: parse & measure
109     for (const char *s = content.data(); *s; s++) {
110         string name;
111         const char *newmat = 0;
112
113         if (*s == '{') {
114             if (cmd)
115                 SG_LOG(SG_TERRAIN, SG_ALERT, TAXI "unexpected { in sign contents");
116             cmd = true;
117             continue;
118
119         } else if (*s == '}') {
120             if (!cmd)
121                 SG_LOG(SG_TERRAIN, SG_ALERT, TAXI "unexpected } in sign contents");
122             cmd = false;
123             continue;
124
125         } else if (!cmd) {
126             name = *s;
127
128         } else {
129             if (*s == ',')
130                 continue;
131
132             string value;
133             for (; *s; s++) {
134                 name += *s;
135                 if (s[1] == ',' || s[1] == '}' || s[1] == '=')
136                     break;
137             }
138             if (!*s) {
139                 SG_LOG(SG_TERRAIN, SG_ALERT, TAXI "unclosed { in sign contents");
140             } else if (s[1] == '=') {
141                 for (s += 2; *s; s++) {
142                     value += *s;
143                     if (s[1] == ',' || s[1] == '}')
144                         break;
145                 }
146                 if (!*s)
147                     SG_LOG(SG_TERRAIN, SG_ALERT, TAXI "unclosed { in sign contents");
148             }
149
150             if (name == "@size") {
151                 sign_height = strtod(value.data(), 0);
152                 continue;
153             }
154
155             if (name == "@light") {
156                 lighted = (value != "0" && value != "no" && value != "off" && value != "false");
157                 continue;
158             }
159
160             if (name == "@material")
161                 newmat = value.data();
162             else if (name.size() == 2 || name.size() == 3) {
163                 if (name.size() == 3 && name[2] >= '1' && name[2] <= '5') {
164                     size = name[2] - '1';
165                     name = name.substr(0, 2);
166                 }
167
168                 if (name == "@Y") {
169                     if (size < 3) {
170                         sign_height = HT[size < 0 ? 2 : size];
171                         newmat = "YellowSign";
172                         newtype = 'Y';
173                     }
174                 } else if (name == "@R") {
175                     if (size < 3) {
176                         sign_height = HT[size < 0 ? 2 : size];
177                         newmat = "RedSign";
178                         newtype = 'R';
179                     }
180                 } else if (name == "@L") {
181                     if (size < 3) {
182                         sign_height = HT[size < 0 ? 2 : size];
183                         newmat = "FramedSign";
184                         newtype = 'L';
185                     }
186                 } else if (name == "@B") {
187                     if (size < 0 || size == 3 || size == 4) {
188                         sign_height = HT[size < 0 ? 3 : size];
189                         newmat = "BlackSign";
190                         newtype = 'B';
191                     }
192                 }
193             }
194
195             if (newmat) {
196                 material = matlib->find(newmat);
197                 continue;
198             }
199
200             for (int i = 0; cmds[i].keyword; i++) {
201                 if (name == cmds[i].keyword) {
202                     name = cmds[i].glyph_name;
203                     break;
204                 }
205             }
206
207             if (name[0] == '@') {
208                 SG_LOG(SG_TERRAIN, SG_ALERT, TAXI "ignoring unknown command `" << name << '\'');
209                 continue;
210             }
211         }
212
213         if (!material) {
214             SG_LOG( SG_TERRAIN, SG_ALERT, TAXI "material doesn't exit");
215             continue;
216         }
217
218         SGMaterialGlyph *glyph = material->get_glyph(name);
219         if (!glyph) {
220             SG_LOG( SG_TERRAIN, SG_ALERT, TAXI "unsupported glyph `" << *s << '\'');
221             continue;
222         }
223
224         // in managed mode push frame stop and frame start first
225         element_info *e;
226         if (newtype && newtype != oldtype) {
227             if (close) {
228                 elements.push_back(close);
229                 total_width += close->glyph->get_width() * close->scale;
230                 close = 0;
231             }
232             oldtype = newtype;
233             SGMaterialGlyph *g = material->get_glyph("stop-frame");
234             if (g)
235                 close = new element_info(material, g, sign_height, lighted);
236             g = material->get_glyph("start-frame");
237             if (g) {
238                 e = new element_info(material, g, sign_height, lighted);
239                 elements.push_back(e);
240                 total_width += e->glyph->get_width() * e->scale;
241             }
242         }
243         // now the actually requested glyph
244         e = new element_info(material, glyph, sign_height, lighted);
245         elements.push_back(e);
246         total_width += e->glyph->get_width() * e->scale;
247     }
248
249     // in managed mode close frame
250     if (close) {
251         elements.push_back(close);
252         total_width += close->glyph->get_width() * close->scale;
253         close = 0;
254     }
255
256
257     // Part II: typeset
258     double hpos = -total_width / 2;
259
260     sgVec3 normal;
261     sgSetVec3(normal, 0, -1, 0);
262
263     sgVec4 color;
264     sgSetVec4(color, 1.0, 1.0, 1.0, 1.0);
265
266     for (unsigned int i = 0; i < elements.size(); i++) {
267         element_info *element = elements[i];
268
269         double xoffset = element->glyph->get_left();
270         double height = element->height;
271         double width = element->glyph->get_width();
272         double abswidth = width * element->scale;
273
274         // vertices
275         ssgVertexArray *vl = new ssgVertexArray(4);
276         vl->add(hpos,            0, 0);
277         vl->add(hpos + abswidth, 0, 0);
278         vl->add(hpos,            0, height);
279         vl->add(hpos + abswidth, 0, height);
280
281         // texture coordinates
282         ssgTexCoordArray *tl = new ssgTexCoordArray(4);
283         tl->add(xoffset,         0);
284         tl->add(xoffset + width, 0);
285         tl->add(xoffset,         1);
286         tl->add(xoffset + width, 1);
287
288         // normals
289         ssgNormalArray *nl = new ssgNormalArray(1);
290         nl->add(normal);
291
292         // colors
293         ssgColourArray *cl = new ssgColourArray(1);
294         cl->add(color);
295
296         ssgLeaf *leaf = new ssgVtxTable(GL_TRIANGLE_STRIP, vl, nl, tl, cl);
297         ssgSimpleState *state = element->material->get_state();
298         if (!element->lighted) {
299             // FIXME: clone state for unlighted elements only once per material
300             state = (ssgSimpleState *)state->clone(SSG_CLONE_STATE);
301             state->setMaterial(GL_EMISSION, 0.3, 0.3, 0.3, 1);
302         }
303         leaf->setState(state);
304
305         object->addKid(leaf);
306         hpos += abswidth;
307         delete element;
308     }
309
310     return object;
311 }
312
313
314
315
316
317 ssgBranch *sgMakeRunwaySign( SGMaterialLib *matlib,
318                              const string path, const string name )
319 {
320     // for demo purposes we assume each element (letter) is 1x1 meter.
321     // Sign is placed 0.25 meters above the ground
322
323     ssgBranch *object = new ssgBranch();
324     object->setName( (char *)name.c_str() );
325
326     double width = name.length() / 3.0;
327
328     string material = name;
329
330     point_list nodes;
331     point_list normals;
332     point_list texcoords;
333     int_list vertex_index;
334     int_list normal_index;
335     int_list tex_index;
336
337     nodes.push_back( Point3D( -width, 0, 0.25 ) );
338     nodes.push_back( Point3D( width + 1, 0, 0.25 ) );
339     nodes.push_back( Point3D( -width, 0, 1.25 ) );
340     nodes.push_back( Point3D( width + 1, 0, 1.25 ) );
341
342     normals.push_back( Point3D( 0, -1, 0 ) );
343
344     texcoords.push_back( Point3D( 0, 0, 0 ) );
345     texcoords.push_back( Point3D( 1, 0, 0 ) );
346     texcoords.push_back( Point3D( 0, 1, 0 ) );
347     texcoords.push_back( Point3D( 1, 1, 0 ) );
348
349     vertex_index.push_back( 0 );
350     vertex_index.push_back( 1 );
351     vertex_index.push_back( 2 );
352     vertex_index.push_back( 3 );
353
354     normal_index.push_back( 0 );
355     normal_index.push_back( 0 );
356     normal_index.push_back( 0 );
357     normal_index.push_back( 0 );
358
359     tex_index.push_back( 0 );
360     tex_index.push_back( 1 );
361     tex_index.push_back( 2 );
362     tex_index.push_back( 3 );
363
364     ssgLeaf *leaf = sgMakeLeaf( path, GL_TRIANGLE_STRIP, matlib, material,
365                                 nodes, normals, texcoords,
366                                 vertex_index, normal_index, tex_index,
367                                 false, NULL );
368
369     object->addKid( leaf );
370
371     return object;
372 }