1 // apt_signs.cxx -- build airport signs on the fly
3 // Written by Curtis Olson, started July 2001.
5 // Copyright (C) 2001 Curtis L. Olson - http://www.flightgear.org/~curt
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.
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.
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.
24 # include <simgear_config.h>
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>
35 #include "apt_signs.hxx"
37 #define SIGN "OBJECT_SIGN: "
38 #define RWY "OBJECT_RUNWAY_SIGN: "
42 // for temporary storage of sign elements
44 element_info(SGMaterial *m, ssgSimpleState *s, SGMaterialGlyph *g, double h)
45 : material(m), state(s), glyph(g), height(h)
47 scale = h * m->get_xsize()
48 / (m->get_ysize() < 0.001 ? 1.0 : m->get_ysize());
51 ssgSimpleState *state;
52 SGMaterialGlyph *glyph;
58 // standard panel height sizes
59 const double HT[5] = {0.460, 0.610, 0.760, 1.220, 0.760};
62 // translation table for "command" to "glyph name"
65 const char *glyph_name;
77 {"@rd", "right-down"},
78 {"@dr", "right-down"},
83 // see $FG_ROOT/Docs/README.scenery
85 ssgBranch *sgMakeSign(SGMaterialLib *matlib, const string path, const string content)
87 double sign_height = 1.0; // meter
89 string newmat = "BlackSign";
91 vector<element_info *> elements;
92 element_info *close = 0;
93 double total_width = 0.0;
96 char oldtype = 0, newtype = 0;
98 ssgBranch *object = new ssgBranch();
99 object->setName((char *)content.c_str());
101 SGMaterial *material;
102 ssgSimpleState *lighted_state;
103 ssgSimpleState *unlighted_state;
105 // Part I: parse & measure
106 for (const char *s = content.data(); *s; s++) {
112 SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "unexpected { in sign contents");
116 } else if (*s == '}') {
118 SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "unexpected } in sign contents");
131 if (s[1] == ',' || s[1] == '}' || s[1] == '=')
135 SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "unclosed { in sign contents");
136 } else if (s[1] == '=') {
137 for (s += 2; *s; s++) {
139 if (s[1] == ',' || s[1] == '}')
143 SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "unclosed { in sign contents");
146 if (name == "@size") {
147 sign_height = strtod(value.data(), 0);
151 if (name == "@light") {
152 lighted = (value != "0" && value != "no" && value != "off" && value != "false");
156 if (name == "@material") {
157 newmat = value.data();
160 } else if (name.size() == 2 || name.size() == 3) {
162 if (n.size() == 3 && n[2] >= '1' && n[2] <= '5') {
169 sign_height = HT[size < 0 ? 2 : size];
170 newmat = "YellowSign";
175 } else if (n == "@R") {
177 sign_height = HT[size < 0 ? 2 : size];
183 } else if (n == "@L") {
185 sign_height = HT[size < 0 ? 2 : size];
186 newmat = "FramedSign";
191 } else if (n == "@B") {
192 if (size < 0 || size == 3 || size == 4) {
193 sign_height = HT[size < 0 ? 3 : size];
194 newmat = "BlackSign";
201 for (int i = 0; cmds[i].keyword; i++) {
202 if (name == cmds[i].keyword) {
203 name = cmds[i].glyph_name;
208 if (name[0] == '@') {
209 SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "ignoring unknown command `" << name << '\'');
215 material = matlib->find(newmat);
217 SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "ignoring unknown material `" << newmat << '\'');
221 // set material states (lighted & unlighted)
222 lighted_state = material->get_state();
223 string u = newmat + ".unlighted";
225 SGMaterial *m = matlib->find(u);
227 unlighted_state = m->get_state();
229 SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "ignoring unknown material `" << u << '\'');
230 unlighted_state = lighted_state;
235 SGMaterialGlyph *glyph = material->get_glyph(name);
237 SG_LOG( SG_TERRAIN, SG_ALERT, SIGN "unsupported glyph `" << *s << '\'');
241 // in managed mode push frame stop and frame start first
242 ssgSimpleState *state = lighted ? lighted_state : unlighted_state;
244 if (newtype && newtype != oldtype) {
246 elements.push_back(close);
247 total_width += close->glyph->get_width() * close->scale;
251 SGMaterialGlyph *g = material->get_glyph("stop-frame");
253 close = new element_info(material, state, g, sign_height);
254 g = material->get_glyph("start-frame");
256 e = new element_info(material, state, g, sign_height);
257 elements.push_back(e);
258 total_width += e->glyph->get_width() * e->scale;
261 // now the actually requested glyph
262 e = new element_info(material, state, glyph, sign_height);
263 elements.push_back(e);
264 total_width += e->glyph->get_width() * e->scale;
267 // in managed mode close frame
269 elements.push_back(close);
270 total_width += close->glyph->get_width() * close->scale;
276 double hpos = -total_width / 2;
277 const double dist = 0.25; // hard-code distance from surface for now
280 sgSetVec3(normal, 0, -1, 0);
283 sgSetVec4(color, 1.0, 1.0, 1.0, 1.0);
285 for (unsigned int i = 0; i < elements.size(); i++) {
286 element_info *element = elements[i];
288 double xoffset = element->glyph->get_left();
289 double height = element->height;
290 double width = element->glyph->get_width();
291 double abswidth = width * element->scale;
294 ssgVertexArray *vl = new ssgVertexArray(4);
295 vl->add(0, hpos, dist);
296 vl->add(0, hpos + abswidth, dist);
297 vl->add(0, hpos, dist + height);
298 vl->add(0, hpos + abswidth, dist + height);
300 // texture coordinates
301 ssgTexCoordArray *tl = new ssgTexCoordArray(4);
303 tl->add(xoffset + width, 0);
305 tl->add(xoffset + width, 1);
308 ssgNormalArray *nl = new ssgNormalArray(1);
312 ssgColourArray *cl = new ssgColourArray(1);
315 ssgLeaf *leaf = new ssgVtxTable(GL_TRIANGLE_STRIP, vl, nl, tl, cl);
316 leaf->setState(element->state);
318 object->addKid(leaf);
324 // minimalistic backside
325 ssgVertexArray *vl = new ssgVertexArray(4);
326 vl->add(0, hpos, dist);
327 vl->add(0, hpos - total_width, dist);
328 vl->add(0, hpos, dist + sign_height);
329 vl->add(0, hpos - total_width, dist + sign_height);
331 ssgNormalArray *nl = new ssgNormalArray(1);
334 ssgLeaf *leaf = new ssgVtxTable(GL_TRIANGLE_STRIP, vl, nl, 0, 0);
335 SGMaterial *mat = matlib->find("BlackSign");
337 leaf->setState(mat->get_state());
338 object->addKid(leaf);
347 ssgBranch *sgMakeRunwaySign( SGMaterialLib *matlib,
348 const string path, const string name )
350 // for demo purposes we assume each element (letter) is 1x1 meter.
351 // Sign is placed 0.25 meters above the ground
353 ssgBranch *object = new ssgBranch();
354 object->setName( (char *)name.c_str() );
356 double width = name.length() / 3.0;
358 string material = name;
362 point_list texcoords;
363 int_list vertex_index;
364 int_list normal_index;
367 nodes.push_back( Point3D( -width, 0, 0.25 ) );
368 nodes.push_back( Point3D( width + 1, 0, 0.25 ) );
369 nodes.push_back( Point3D( -width, 0, 1.25 ) );
370 nodes.push_back( Point3D( width + 1, 0, 1.25 ) );
372 normals.push_back( Point3D( 0, -1, 0 ) );
374 texcoords.push_back( Point3D( 0, 0, 0 ) );
375 texcoords.push_back( Point3D( 1, 0, 0 ) );
376 texcoords.push_back( Point3D( 0, 1, 0 ) );
377 texcoords.push_back( Point3D( 1, 1, 0 ) );
379 vertex_index.push_back( 0 );
380 vertex_index.push_back( 1 );
381 vertex_index.push_back( 2 );
382 vertex_index.push_back( 3 );
384 normal_index.push_back( 0 );
385 normal_index.push_back( 0 );
386 normal_index.push_back( 0 );
387 normal_index.push_back( 0 );
389 tex_index.push_back( 0 );
390 tex_index.push_back( 1 );
391 tex_index.push_back( 2 );
392 tex_index.push_back( 3 );
394 ssgLeaf *leaf = sgMakeLeaf( path, GL_TRIANGLE_STRIP, matlib, material,
395 nodes, normals, texcoords,
396 vertex_index, normal_index, tex_index,
399 object->addKid( leaf );