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