--- /dev/null
+includedir = @includedir@/scene/tgdb
+
+lib_LIBRARIES = libsgtgdb.a
+
+noinst_HEADERS =
+
+include_HEADERS = \
+ apt_signs.hxx \
+ leaf.hxx \
+ pt_lights.hxx
+
+libsgtgdb_a_SOURCES = \
+ apt_signs.cxx \
+ leaf.cxx \
+ pt_lights.cxx
+
+INCLUDES = -I$(top_srcdir)
--- /dev/null
+// apt_signs.cxx -- build airport signs on the fly
+//
+// Written by Curtis Olson, started July 2001.
+//
+// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+
+#include <simgear/debug/logstream.hxx>
+#include <simgear/math/sg_types.hxx>
+#include <simgear/scene/tgdb/leaf.hxx>
+
+#include "apt_signs.hxx"
+
+
+ssgBranch *gen_taxi_sign( SGMaterialLib *matlib,
+ const string path, const string content )
+{
+ // for demo purposes we assume each element (letter) is 1x1 meter.
+ // Sign is placed 0.25 meters above the ground
+
+ ssgBranch *object = new ssgBranch();
+ object->setName( (char *)content.c_str() );
+
+ double offset = content.length() / 2.0;
+
+ for ( unsigned int i = 0; i < content.length(); ++i ) {
+ string material;
+
+ char item = content[i];
+ if ( item == '<' ) {
+ material = "ArrowL.rgb";
+ } else if ( item == '>' ) {
+ material = "ArrowR.rgb";
+ } else if ( item >= 'A' && item <= 'Z' ) {
+ material = "Letter";
+ material += item;
+ material += ".rgb";
+ } else if ( item >= 'a' && item <= 'z' ) {
+ int tmp = item - 'a';
+ char c = 'A' + tmp;
+ material = "Black";
+ material += c;
+ material += ".rgb";
+ } else {
+ SG_LOG( SG_TERRAIN, SG_ALERT,
+ "Unknown taxi sign code = '" << item << "' !!!!" );
+ return NULL;
+ }
+
+ point_list nodes; nodes.clear();
+ point_list normals; normals.clear();
+ point_list texcoords; texcoords.clear();
+ int_list vertex_index; vertex_index.clear();
+ int_list normal_index; normal_index.clear();
+ int_list tex_index; tex_index.clear();
+
+ nodes.push_back( Point3D( -offset + i, 0, 0.25 ) );
+ nodes.push_back( Point3D( -offset + i + 1, 0, 0.25 ) );
+ nodes.push_back( Point3D( -offset + i, 0, 1.25 ) );
+ nodes.push_back( Point3D( -offset + i + 1, 0, 1.25 ) );
+
+ normals.push_back( Point3D( 0, -1, 0 ) );
+
+ texcoords.push_back( Point3D( 0, 0, 0 ) );
+ texcoords.push_back( Point3D( 1, 0, 0 ) );
+ texcoords.push_back( Point3D( 0, 1, 0 ) );
+ texcoords.push_back( Point3D( 1, 1, 0 ) );
+
+ vertex_index.push_back( 0 );
+ vertex_index.push_back( 1 );
+ vertex_index.push_back( 2 );
+ vertex_index.push_back( 3 );
+
+ normal_index.push_back( 0 );
+ normal_index.push_back( 0 );
+ normal_index.push_back( 0 );
+ normal_index.push_back( 0 );
+
+ tex_index.push_back( 0 );
+ tex_index.push_back( 1 );
+ tex_index.push_back( 2 );
+ tex_index.push_back( 3 );
+
+ ssgLeaf *leaf = sgMakeLeaf( path, GL_TRIANGLE_STRIP, matlib, material,
+ nodes, normals, texcoords,
+ vertex_index, normal_index, tex_index,
+ false, NULL );
+
+ object->addKid( leaf );
+ }
+
+ return object;
+}
+
+
+ssgBranch *gen_runway_sign( SGMaterialLib *matlib,
+ const string path, const string name )
+{
+ // for demo purposes we assume each element (letter) is 1x1 meter.
+ // Sign is placed 0.25 meters above the ground
+
+ ssgBranch *object = new ssgBranch();
+ object->setName( (char *)name.c_str() );
+
+ double width = name.length() / 3.0;
+
+ string material = name + ".rgb";
+
+ point_list nodes; nodes.clear();
+ point_list normals; normals.clear();
+ point_list texcoords; texcoords.clear();
+ int_list vertex_index; vertex_index.clear();
+ int_list normal_index; normal_index.clear();
+ int_list tex_index; tex_index.clear();
+
+ nodes.push_back( Point3D( -width, 0, 0.25 ) );
+ nodes.push_back( Point3D( width + 1, 0, 0.25 ) );
+ nodes.push_back( Point3D( -width, 0, 1.25 ) );
+ nodes.push_back( Point3D( width + 1, 0, 1.25 ) );
+
+ normals.push_back( Point3D( 0, -1, 0 ) );
+
+ texcoords.push_back( Point3D( 0, 0, 0 ) );
+ texcoords.push_back( Point3D( 1, 0, 0 ) );
+ texcoords.push_back( Point3D( 0, 1, 0 ) );
+ texcoords.push_back( Point3D( 1, 1, 0 ) );
+
+ vertex_index.push_back( 0 );
+ vertex_index.push_back( 1 );
+ vertex_index.push_back( 2 );
+ vertex_index.push_back( 3 );
+
+ normal_index.push_back( 0 );
+ normal_index.push_back( 0 );
+ normal_index.push_back( 0 );
+ normal_index.push_back( 0 );
+
+ tex_index.push_back( 0 );
+ tex_index.push_back( 1 );
+ tex_index.push_back( 2 );
+ tex_index.push_back( 3 );
+
+ ssgLeaf *leaf = sgMakeLeaf( path, GL_TRIANGLE_STRIP, matlib, material,
+ nodes, normals, texcoords,
+ vertex_index, normal_index, tex_index,
+ false, NULL );
+
+ object->addKid( leaf );
+
+ return object;
+}
--- /dev/null
+// apt_signs.hxx -- build airport signs on the fly
+//
+// Written by Curtis Olson, started July 2001.
+//
+// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+
+#ifndef _APT_SIGNS_HXX
+#define _APT_SIGNS_HXX
+
+
+#ifndef __cplusplus
+# error This library requires C++
+#endif
+
+
+#include <simgear/compiler.h>
+
+#include STL_STRING
+
+#include <plib/ssg.h> // plib include
+
+class SGMaterialLib; // forward declaration
+
+SG_USING_STD(string);
+
+
+// Generate a taxi sign
+ssgBranch *gen_taxi_sign( SGMaterialLib *matlib,
+ const string path, const string content );
+
+
+// Generate a runway sign
+ssgBranch *gen_runway_sign( SGMaterialLib *matlib,
+ const string path, const string name );
+
+
+#endif // _APT_SIGNS_HXX
--- /dev/null
+// leaf.cxx -- function to build and ssg leaf from higher level data.
+//
+// Written by Curtis Olson, started October 1997.
+//
+// Copyright (C) 1997 - 2003 Curtis L. Olson - curt@flightgear.org
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+
+#ifdef HAVE_CONFIG_H
+# include <simgear_config.h>
+#endif
+
+#include <simgear/compiler.h>
+
+#ifdef SG_MATH_EXCEPTION_CLASH
+# include <math.h>
+#endif
+
+#include STL_STRING
+
+#include <simgear/debug/logstream.hxx>
+#include <simgear/math/sg_random.h>
+#include <simgear/scene/material/mat.hxx>
+#include <simgear/scene/material/matlib.hxx>
+
+#include "leaf.hxx"
+
+SG_USING_STD(string);
+SG_USING_STD(vector);
+
+
+typedef vector < int > int_list;
+typedef int_list::iterator int_list_iterator;
+typedef int_list::const_iterator int_point_list_iterator;
+
+
+static void random_pt_inside_tri( float *res,
+ float *n1, float *n2, float *n3 )
+{
+ double a = sg_random();
+ double b = sg_random();
+ if ( a + b > 1.0 ) {
+ a = 1.0 - a;
+ b = 1.0 - b;
+ }
+ double c = 1 - a - b;
+
+ res[0] = n1[0]*a + n2[0]*b + n3[0]*c;
+ res[1] = n1[1]*a + n2[1]*b + n3[1]*c;
+ res[2] = n1[2]*a + n2[2]*b + n3[2]*c;
+}
+
+
+static void gen_random_surface_points( ssgLeaf *leaf, ssgVertexArray *lights,
+ double factor ) {
+ int tris = leaf->getNumTriangles();
+ if ( tris > 0 ) {
+ short int n1, n2, n3;
+ float *p1, *p2, *p3;
+ sgVec3 result;
+
+ // generate a repeatable random seed
+ p1 = leaf->getVertex( 0 );
+ unsigned int seed = (unsigned int)(fabs(p1[0]*100));
+ sg_srandom( seed );
+
+ for ( int i = 0; i < tris; ++i ) {
+ leaf->getTriangle( i, &n1, &n2, &n3 );
+ p1 = leaf->getVertex(n1);
+ p2 = leaf->getVertex(n2);
+ p3 = leaf->getVertex(n3);
+ double area = sgTriArea( p1, p2, p3 );
+ double num = area / factor;
+
+ // generate a light point for each unit of area
+ while ( num > 1.0 ) {
+ random_pt_inside_tri( result, p1, p2, p3 );
+ lights->add( result );
+ num -= 1.0;
+ }
+ // for partial units of area, use a zombie door method to
+ // create the proper random chance of a light being created
+ // for this triangle
+ if ( num > 0.0 ) {
+ if ( sg_random() <= num ) {
+ // a zombie made it through our door
+ random_pt_inside_tri( result, p1, p2, p3 );
+ lights->add( result );
+ }
+ }
+ }
+ }
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+// Scenery loaders.
+////////////////////////////////////////////////////////////////////////
+
+ssgLeaf *sgMakeLeaf( const string& path,
+ const GLenum ty,
+ SGMaterialLib *matlib, const string& material,
+ const point_list& nodes, const point_list& normals,
+ const point_list& texcoords,
+ const int_list& node_index,
+ const int_list& normal_index,
+ const int_list& tex_index,
+ const bool calc_lights, ssgVertexArray *lights )
+{
+ double tex_width = 1000.0, tex_height = 1000.0;
+ ssgSimpleState *state = NULL;
+ float coverage = -1;
+
+ SGMaterial *mat = matlib->find( material );
+ if ( mat == NULL ) {
+ // see if this is an on the fly texture
+ string file = path;
+ string::size_type pos = file.rfind( "/" );
+ file = file.substr( 0, pos );
+ // cout << "current file = " << file << endl;
+ file += "/";
+ file += material;
+ // cout << "current file = " << file << endl;
+ if ( ! matlib->add_item( file ) ) {
+ SG_LOG( SG_TERRAIN, SG_ALERT,
+ "Ack! unknown usemtl name = " << material
+ << " in " << path );
+ } else {
+ // locate our newly created material
+ mat = matlib->find( material );
+ if ( mat == NULL ) {
+ SG_LOG( SG_TERRAIN, SG_ALERT,
+ "Ack! bad on the fly material create = "
+ << material << " in " << path );
+ }
+ }
+ }
+
+ if ( mat != NULL ) {
+ // set the texture width and height values for this
+ // material
+ tex_width = mat->get_xsize();
+ tex_height = mat->get_ysize();
+ state = mat->get_state();
+ coverage = mat->get_light_coverage();
+ // cout << "(w) = " << tex_width << " (h) = "
+ // << tex_width << endl;
+ } else {
+ coverage = -1;
+ }
+
+ sgVec2 tmp2;
+ sgVec3 tmp3;
+ sgVec4 tmp4;
+ int i;
+
+ // vertices
+ int size = node_index.size();
+ if ( size < 1 ) {
+ SG_LOG( SG_TERRAIN, SG_ALERT, "Woh! node list size < 1" );
+ exit(-1);
+ }
+ ssgVertexArray *vl = new ssgVertexArray( size );
+ Point3D node;
+ for ( i = 0; i < size; ++i ) {
+ node = nodes[ node_index[i] ];
+ sgSetVec3( tmp3, node[0], node[1], node[2] );
+ vl -> add( tmp3 );
+ }
+
+ // normals
+ Point3D normal;
+ ssgNormalArray *nl = new ssgNormalArray( size );
+ if ( normal_index.size() ) {
+ // object file specifies normal indices (i.e. normal indices
+ // aren't 'implied'
+ for ( i = 0; i < size; ++i ) {
+ normal = normals[ normal_index[i] ];
+ sgSetVec3( tmp3, normal[0], normal[1], normal[2] );
+ nl -> add( tmp3 );
+ }
+ } else {
+ // use implied normal indices. normal index = vertex index.
+ for ( i = 0; i < size; ++i ) {
+ normal = normals[ node_index[i] ];
+ sgSetVec3( tmp3, normal[0], normal[1], normal[2] );
+ nl -> add( tmp3 );
+ }
+ }
+
+ // colors
+ ssgColourArray *cl = new ssgColourArray( 1 );
+ sgSetVec4( tmp4, 1.0, 1.0, 1.0, 1.0 );
+ cl->add( tmp4 );
+
+ // texture coordinates
+ size = tex_index.size();
+ Point3D texcoord;
+ ssgTexCoordArray *tl = new ssgTexCoordArray( size );
+ if ( size == 1 ) {
+ texcoord = texcoords[ tex_index[0] ];
+ sgSetVec2( tmp2, texcoord[0], texcoord[1] );
+ sgSetVec2( tmp2, texcoord[0], texcoord[1] );
+ if ( tex_width > 0 ) {
+ tmp2[0] *= (1000.0 / tex_width);
+ }
+ if ( tex_height > 0 ) {
+ tmp2[1] *= (1000.0 / tex_height);
+ }
+ tl -> add( tmp2 );
+ } else if ( size > 1 ) {
+ for ( i = 0; i < size; ++i ) {
+ texcoord = texcoords[ tex_index[i] ];
+ sgSetVec2( tmp2, texcoord[0], texcoord[1] );
+ if ( tex_width > 0 ) {
+ tmp2[0] *= (1000.0 / tex_width);
+ }
+ if ( tex_height > 0 ) {
+ tmp2[1] *= (1000.0 / tex_height);
+ }
+ tl -> add( tmp2 );
+ }
+ }
+
+ ssgLeaf *leaf = new ssgVtxTable ( ty, vl, nl, tl, cl );
+
+ // lookup the state record
+
+ leaf->setState( state );
+
+ if ( calc_lights ) {
+ if ( coverage > 0.0 ) {
+ if ( coverage < 10000.0 ) {
+ SG_LOG(SG_INPUT, SG_ALERT, "Light coverage is "
+ << coverage << ", pushing up to 10000");
+ coverage = 10000;
+ }
+ gen_random_surface_points(leaf, lights, coverage);
+ }
+ }
+
+ return leaf;
+}
--- /dev/null
+// leaf.hxx -- function to build and ssg leaf from higher level data.
+//
+// Written by Curtis Olson, started October 1997.
+//
+// Copyright (C) 1997 - 2003 Curtis L. Olson - curt@flightgear.org
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+
+#ifndef _SG_LEAF_HXX
+#define _SG_LEAF_HXX
+
+
+#ifndef __cplusplus
+# error This library requires C++
+#endif
+
+
+#include <simgear/compiler.h>
+
+#include STL_STRING
+
+#include <plib/ssg.h> // plib include
+
+#include <simgear/math/sg_types.hxx>
+
+SG_USING_STD(string);
+
+
+class SGMaterialLib; // forward declaration.
+
+
+// Create a ssg leaf
+ssgLeaf *sgMakeLeaf( const string& path,
+ const GLenum ty,
+ SGMaterialLib *matlib, const string& material,
+ const point_list& nodes, const point_list& normals,
+ const point_list& texcoords,
+ const int_list& node_index,
+ const int_list& normal_index,
+ const int_list& tex_index,
+ const bool calc_lights, ssgVertexArray *lights );
+
+
+#endif // _SG_LEAF_HXX
--- /dev/null
+// pt_lights.cxx -- build a 'directional' light on the fly
+//
+// Written by Curtis Olson, started March 2002.
+//
+// Copyright (C) 2002 Curtis L. Olson - curt@flightgear.org
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+
+#include <plib/sg.h>
+
+#include <simgear/scene/material/mat.hxx>
+#include <simgear/scene/material/matlib.hxx>
+
+#include "pt_lights.hxx"
+
+
+// strobe pre-draw (we want a larger point size)
+static int StrobePreDraw( ssgEntity *e ) {
+ glPushAttrib( GL_POINT_BIT );
+ glPointSize(4.0);
+ glEnable(GL_POINT_SMOOTH);
+
+ return true;
+}
+
+// strobe post-draw (we want a larger point size)
+static int StrobePostDraw( ssgEntity *e ) {
+ glPopAttrib();
+
+ return true;
+}
+
+
+// Generate a directional light
+ssgLeaf *gen_directional_light( sgVec3 pt, sgVec3 dir, sgVec3 up,
+ const SGMaterial *mat ) {
+
+ // calculate a vector perpendicular to dir and up
+ sgVec3 perp;
+ sgVectorProductVec3( perp, dir, up );
+
+ ssgVertexArray *vl = new ssgVertexArray( 3 );
+ ssgNormalArray *nl = new ssgNormalArray( 3 );
+ ssgColourArray *cl = new ssgColourArray( 3 );
+
+ // front face
+ sgVec3 tmp3;
+ sgCopyVec3( tmp3, pt );
+ vl->add( tmp3 );
+ sgAddVec3( tmp3, up );
+ vl->add( tmp3 );
+ sgAddVec3( tmp3, perp );
+ vl->add( tmp3 );
+ // sgSubVec3( tmp3, up );
+ // vl->add( tmp3 );
+
+ nl->add( dir );
+ nl->add( dir );
+ nl->add( dir );
+ // nl->add( dir );
+
+ sgVec4 color;
+ sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
+ cl->add( color );
+ sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
+ cl->add( color );
+ cl->add( color );
+ // cl->add( color );
+
+ /*
+ // temporarily do back face
+ sgCopyVec3( tmp3, pt );
+ vl->add( tmp3 );
+ sgAddVec3( tmp3, up );
+ vl->add( tmp3 );
+ sgAddVec3( tmp3, perp );
+ vl->add( tmp3 );
+
+ sgNegateVec3( dir );
+ nl->add( dir );
+ nl->add( dir );
+ nl->add( dir );
+
+ sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
+ cl->add( color );
+ sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
+ cl->add( color );
+ cl->add( color );
+ */
+
+ /* ssgTexCoordArray *tl = new ssgTexCoordArray( 4 );
+ sgVec2 tmp2;
+ sgSetVec2( tmp2, 0.0, 0.0 );
+ tl->add( tmp2 );
+ sgSetVec2( tmp2, 1.0, 0.0 );
+ tl->add( tmp2 );
+ sgSetVec2( tmp2, 1.0, 1.0 );
+ tl->add( tmp2 );
+ sgSetVec2( tmp2, 0.0, 1.0 );
+ tl->add( tmp2 ); */
+
+ ssgLeaf *leaf =
+ new ssgVtxTable ( GL_TRIANGLES, vl, nl, NULL, cl );
+
+ if ( mat != NULL ) {
+ leaf->setState( mat->get_state() );
+ } else {
+ SG_LOG( SG_TERRAIN, SG_ALERT, "Warning: mat = NULL" );
+ }
+
+ return leaf;
+}
+
+
+static void calc_center_point( const point_list &nodes,
+ const int_list &pnt_i,
+ sgVec3 result ) {
+ sgVec3 pt;
+ sgSetVec3( pt, nodes[pnt_i[0]][0], nodes[pnt_i[0]][1], nodes[pnt_i[0]][2] );
+
+ double minx = pt[0];
+ double maxx = pt[0];
+ double miny = pt[1];
+ double maxy = pt[1];
+ double minz = pt[2];
+ double maxz = pt[2];
+
+ for ( unsigned int i = 0; i < pnt_i.size(); ++i ) {
+ sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
+ nodes[pnt_i[i]][2] );
+ if ( pt[0] < minx ) { minx = pt[0]; }
+ if ( pt[0] > maxx ) { minx = pt[0]; }
+ if ( pt[1] < miny ) { miny = pt[1]; }
+ if ( pt[1] > maxy ) { miny = pt[1]; }
+ if ( pt[2] < minz ) { minz = pt[2]; }
+ if ( pt[2] > maxz ) { minz = pt[2]; }
+ }
+
+ sgSetVec3( result, (minx + maxx) / 2.0, (miny + maxy) / 2.0,
+ (minz + maxz) / 2.0 );
+}
+
+
+static ssgTransform *gen_dir_light_group( const point_list &nodes,
+ const point_list &normals,
+ const int_list &pnt_i,
+ const int_list &nml_i,
+ const SGMaterial *mat,
+ sgVec3 up, bool vertical = false )
+{
+ sgVec3 center;
+ calc_center_point( nodes, pnt_i, center );
+ // cout << center[0] << "," << center[1] << "," << center[2] << endl;
+
+
+ // find a vector perpendicular to the normal.
+ sgVec3 perp1;
+ if ( !vertical ) {
+ // normal isn't vertical so we can use up as our first vector
+ sgNormalizeVec3( perp1, up );
+ } else {
+ // normal is vertical so we have to work a bit harder to
+ // determine our first vector
+ sgVec3 pt1, pt2;
+ sgSetVec3( pt1, nodes[pnt_i[0]][0], nodes[pnt_i[0]][1],
+ nodes[pnt_i[0]][2] );
+ sgSetVec3( pt2, nodes[pnt_i[1]][0], nodes[pnt_i[1]][1],
+ nodes[pnt_i[1]][2] );
+
+ sgSubVec3( perp1, pt2, pt1 );
+ sgNormalizeVec3( perp1 );
+ }
+
+ ssgVertexArray *vl = new ssgVertexArray( 3 * pnt_i.size() );
+ ssgNormalArray *nl = new ssgNormalArray( 3 * pnt_i.size() );
+ ssgColourArray *cl = new ssgColourArray( 3 * pnt_i.size() );
+
+ unsigned int i;
+ sgVec3 pt, normal;
+ for ( i = 0; i < pnt_i.size(); ++i ) {
+ sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
+ nodes[pnt_i[i]][2] );
+ sgSubVec3( pt, center );
+ sgSetVec3( normal, normals[nml_i[i]][0], normals[nml_i[i]][1],
+ normals[nml_i[i]][2] );
+
+ // calculate a vector perpendicular to dir and up
+ sgVec3 perp2;
+ sgVectorProductVec3( perp2, normal, perp1 );
+
+ // front face
+ sgVec3 tmp3;
+ sgCopyVec3( tmp3, pt );
+ vl->add( tmp3 );
+ sgAddVec3( tmp3, perp1 );
+ vl->add( tmp3 );
+ sgAddVec3( tmp3, perp2 );
+ vl->add( tmp3 );
+ // sgSubVec3( tmp3, perp1 );
+ // vl->add( tmp3 );
+
+ nl->add( normal );
+ nl->add( normal );
+ nl->add( normal );
+ // nl->add( normal );
+
+ sgVec4 color;
+ sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
+ cl->add( color );
+ sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
+ cl->add( color );
+ cl->add( color );
+ // cl->add( color );
+ }
+
+ ssgLeaf *leaf =
+ new ssgVtxTable ( GL_TRIANGLES, vl, nl, NULL, cl );
+
+ if ( mat != NULL ) {
+ leaf->setState( mat->get_state() );
+ } else {
+ SG_LOG( SG_TERRAIN, SG_ALERT, "Warning: material = NULL" );
+ }
+
+ // put an LOD on each lighting component
+ ssgRangeSelector *lod = new ssgRangeSelector;
+ lod->setRange( 0, SG_ZERO );
+ lod->setRange( 1, 20000 );
+ lod->addKid( leaf );
+
+ // create the transformation.
+ sgCoord coord;
+ sgSetCoord( &coord, center[0], center[1], center[2], 0.0, 0.0, 0.0 );
+ ssgTransform *trans = new ssgTransform;
+ trans->setTransform( &coord );
+ trans->addKid( lod );
+
+ return trans;
+}
+
+
+static ssgTransform *gen_reil_lights( const point_list &nodes,
+ const point_list &normals,
+ const int_list &pnt_i,
+ const int_list &nml_i,
+ SGMaterialLib *matlib,
+ sgVec3 up )
+{
+ sgVec3 center;
+ calc_center_point( nodes, pnt_i, center );
+ // cout << center[0] << "," << center[1] << "," << center[2] << endl;
+
+ sgVec3 nup;
+ sgNormalizeVec3( nup, up );
+
+ ssgVertexArray *vl = new ssgVertexArray( 3 * pnt_i.size() );
+ ssgNormalArray *nl = new ssgNormalArray( 3 * pnt_i.size() );
+ ssgColourArray *cl = new ssgColourArray( 3 * pnt_i.size() );
+
+ unsigned int i;
+ sgVec3 pt, normal;
+ for ( i = 0; i < pnt_i.size(); ++i ) {
+ sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
+ nodes[pnt_i[i]][2] );
+ sgSubVec3( pt, center );
+ sgSetVec3( normal, normals[nml_i[i]][0], normals[nml_i[i]][1],
+ normals[nml_i[i]][2] );
+
+ // calculate a vector perpendicular to dir and up
+ sgVec3 perp;
+ sgVectorProductVec3( perp, normal, nup );
+
+ // front face
+ sgVec3 tmp3;
+ sgCopyVec3( tmp3, pt );
+ vl->add( tmp3 );
+ sgAddVec3( tmp3, nup );
+ vl->add( tmp3 );
+ sgAddVec3( tmp3, perp );
+ vl->add( tmp3 );
+ // sgSubVec3( tmp3, nup );
+ // vl->add( tmp3 );
+
+ nl->add( normal );
+ nl->add( normal );
+ nl->add( normal );
+ // nl->add( normal );
+
+ sgVec4 color;
+ sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
+ cl->add( color );
+ sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
+ cl->add( color );
+ cl->add( color );
+ // cl->add( color );
+ }
+
+ ssgLeaf *leaf =
+ new ssgVtxTable ( GL_TRIANGLES, vl, nl, NULL, cl );
+
+ SGMaterial *mat = matlib->find( "RWY_WHITE_LIGHTS" );
+
+ if ( mat != NULL ) {
+ leaf->setState( mat->get_state() );
+ } else {
+ SG_LOG( SG_TERRAIN, SG_ALERT,
+ "Warning: can't find material = RWY_WHITE_LIGHTS" );
+ }
+
+ leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw );
+ leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw );
+
+ ssgTimedSelector *reil = new ssgTimedSelector;
+
+ // need to add this twice to work around an ssg bug
+ reil->addKid( leaf );
+ reil->addKid( leaf );
+
+ reil->setDuration( 60 );
+ reil->setLimits( 0, 2 );
+ reil->setMode( SSG_ANIM_SHUTTLE );
+ reil->control( SSG_ANIM_START );
+
+ // put an LOD on each lighting component
+ ssgRangeSelector *lod = new ssgRangeSelector;
+ lod->setRange( 0, SG_ZERO );
+ lod->setRange( 1, 12000 );
+ lod->addKid( reil );
+
+ // create the transformation.
+ sgCoord coord;
+ sgSetCoord( &coord, center[0], center[1], center[2], 0.0, 0.0, 0.0 );
+ ssgTransform *trans = new ssgTransform;
+ trans->setTransform( &coord );
+ trans->addKid( lod );
+
+ return trans;
+}
+
+
+static ssgTransform *gen_odals_lights( const point_list &nodes,
+ const point_list &normals,
+ const int_list &pnt_i,
+ const int_list &nml_i,
+ SGMaterialLib *matlib,
+ sgVec3 up )
+{
+ sgVec3 center;
+ calc_center_point( nodes, pnt_i, center );
+ // cout << center[0] << "," << center[1] << "," << center[2] << endl;
+
+ ssgTimedSelector *odals = new ssgTimedSelector;
+
+ sgVec4 color;
+ sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
+
+ // we don't want directional lights here
+ SGMaterial *mat = matlib->find( "GROUND_LIGHTS" );
+ if ( mat == NULL ) {
+ SG_LOG( SG_TERRAIN, SG_ALERT,
+ "Warning: can't material = GROUND_LIGHTS" );
+ }
+
+ // center line strobes
+ int i;
+ sgVec3 pt;
+ for ( i = (int)pnt_i.size() - 1; i >= 2; --i ) {
+ ssgVertexArray *vl = new ssgVertexArray( 1 );
+ ssgColourArray *cl = new ssgColourArray( 1 );
+
+ sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
+ nodes[pnt_i[i]][2] );
+ sgSubVec3( pt, center );
+ vl->add( pt );
+
+ cl->add( color );
+
+ ssgLeaf *leaf =
+ new ssgVtxTable ( GL_POINTS, vl, NULL, NULL, cl );
+
+ leaf->setState( mat->get_state() );
+ leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw );
+ leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw );
+
+ odals->addKid( leaf );
+ }
+
+ // runway end strobes
+ ssgVertexArray *vl = new ssgVertexArray( 2 );
+ ssgColourArray *cl = new ssgColourArray( 2 );
+
+ sgSetVec3( pt, nodes[pnt_i[0]][0], nodes[pnt_i[0]][1],
+ nodes[pnt_i[0]][2] );
+ sgSubVec3( pt, center );
+ vl->add( pt );
+ cl->add( color );
+
+ sgSetVec3( pt, nodes[pnt_i[1]][0], nodes[pnt_i[1]][1],
+ nodes[pnt_i[1]][2] );
+ sgSubVec3( pt, center );
+ vl->add( pt );
+ cl->add( color );
+
+ ssgLeaf *leaf =
+ new ssgVtxTable ( GL_POINTS, vl, NULL, NULL, cl );
+
+ leaf->setState( mat->get_state() );
+ leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw );
+ leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw );
+
+ odals->addKid( leaf );
+
+ // setup animition
+
+ odals->setDuration( 10 );
+ odals->setLimits( 0, pnt_i.size() - 1 );
+ odals->setMode( SSG_ANIM_SHUTTLE );
+ odals->control( SSG_ANIM_START );
+
+ // put an LOD on each lighting component
+ ssgRangeSelector *lod = new ssgRangeSelector;
+ lod->setRange( 0, SG_ZERO );
+ lod->setRange( 1, 12000 );
+ lod->addKid( odals );
+
+ // create the transformation.
+ sgCoord coord;
+ sgSetCoord( &coord, center[0], center[1], center[2], 0.0, 0.0, 0.0 );
+ ssgTransform *trans = new ssgTransform;
+ trans->setTransform( &coord );
+ trans->addKid( lod );
+
+ return trans;
+}
+
+
+static ssgTransform *gen_rabbit_lights( const point_list &nodes,
+ const point_list &normals,
+ const int_list &pnt_i,
+ const int_list &nml_i,
+ SGMaterialLib *matlib,
+ sgVec3 up )
+{
+ sgVec3 center;
+ calc_center_point( nodes, pnt_i, center );
+ // cout << center[0] << "," << center[1] << "," << center[2] << endl;
+
+ sgVec3 nup;
+ sgNormalizeVec3( nup, up );
+
+ ssgTimedSelector *rabbit = new ssgTimedSelector;
+
+ SGMaterial *mat = matlib->find( "RWY_WHITE_LIGHTS" );
+ if ( mat == NULL ) {
+ SG_LOG( SG_TERRAIN, SG_ALERT,
+ "Warning: can't material = RWY_WHITE_LIGHTS" );
+ }
+
+ int i;
+ sgVec3 pt, normal;
+ for ( i = (int)pnt_i.size() - 1; i >= 0; --i ) {
+ ssgVertexArray *vl = new ssgVertexArray( 3 );
+ ssgNormalArray *nl = new ssgNormalArray( 3 );
+ ssgColourArray *cl = new ssgColourArray( 3 );
+
+ sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
+ nodes[pnt_i[i]][2] );
+ sgSubVec3( pt, center );
+
+ sgSetVec3( normal, normals[nml_i[i]][0], normals[nml_i[i]][1],
+ normals[nml_i[i]][2] );
+
+ // calculate a vector perpendicular to dir and up
+ sgVec3 perp;
+ sgVectorProductVec3( perp, normal, nup );
+
+ // front face
+ sgVec3 tmp3;
+ sgCopyVec3( tmp3, pt );
+ vl->add( tmp3 );
+ sgAddVec3( tmp3, nup );
+ vl->add( tmp3 );
+ sgAddVec3( tmp3, perp );
+ vl->add( tmp3 );
+ // sgSubVec3( tmp3, nup );
+ // vl->add( tmp3 );
+
+ nl->add( normal );
+ nl->add( normal );
+ nl->add( normal );
+ // nl->add( normal );
+
+ sgVec4 color;
+ sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
+ cl->add( color );
+ sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
+ cl->add( color );
+ cl->add( color );
+ // cl->add( color );
+
+ ssgLeaf *leaf =
+ new ssgVtxTable ( GL_TRIANGLES, vl, nl, NULL, cl );
+
+ leaf->setState( mat->get_state() );
+ leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw );
+ leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw );
+
+ rabbit->addKid( leaf );
+ }
+
+ rabbit->setDuration( 10 );
+ rabbit->setLimits( 0, pnt_i.size() - 1 );
+ rabbit->setMode( SSG_ANIM_SHUTTLE );
+ rabbit->control( SSG_ANIM_START );
+
+ // put an LOD on each lighting component
+ ssgRangeSelector *lod = new ssgRangeSelector;
+ lod->setRange( 0, SG_ZERO );
+ lod->setRange( 1, 12000 );
+ lod->addKid( rabbit );
+
+ // create the transformation.
+ sgCoord coord;
+ sgSetCoord( &coord, center[0], center[1], center[2], 0.0, 0.0, 0.0 );
+ ssgTransform *trans = new ssgTransform;
+ trans->setTransform( &coord );
+ trans->addKid( lod );
+
+ return trans;
+}
+
+
+#if 0 // debugging infrastructure
+// Generate a normal line
+static ssgLeaf *gen_normal_line( SGMaterialLib *matlib,
+ sgVec3 pt, sgVec3 dir, sgVec3 up ) {
+
+ ssgVertexArray *vl = new ssgVertexArray( 3 );
+ ssgColourArray *cl = new ssgColourArray( 3 );
+
+ sgVec3 tmp3;
+ sgCopyVec3( tmp3, pt );
+ vl->add( tmp3 );
+ sgAddVec3( tmp3, dir );
+ vl->add( tmp3 );
+
+ sgVec4 color;
+ sgSetVec4( color, 1.0, 0.0, 0.0, 1.0 );
+ cl->add( color );
+ cl->add( color );
+
+ ssgLeaf *leaf =
+ new ssgVtxTable ( GL_LINES, vl, NULL, NULL, cl );
+
+ SGMaterial *mat = matlib->find( "GROUND_LIGHTS" );
+ leaf->setState( mat->get_state() );
+
+ return leaf;
+}
+#endif
+
+
+ssgBranch *gen_directional_lights( const point_list &nodes,
+ const point_list &normals,
+ const int_list &pnt_i,
+ const int_list &nml_i,
+ SGMaterialLib *matlib,
+ const string &material,
+ sgVec3 up )
+{
+ sgVec3 nup;
+ sgNormalizeVec3( nup, up );
+
+ SGMaterial *mat = matlib->find( material );
+
+ if ( material == "RWY_REIL_LIGHTS" ) {
+ // cout << "found a reil" << endl;
+ ssgTransform *reil = gen_reil_lights( nodes, normals, pnt_i, nml_i,
+ matlib, up );
+ return reil;
+ } else if ( material == "RWY_ODALS_LIGHTS" ) {
+ // cout << "found a odals" << endl;
+ ssgTransform *odals = gen_odals_lights( nodes, normals, pnt_i, nml_i,
+ matlib, up );
+ return odals;
+ } else if ( material == "RWY_SEQUENCED_LIGHTS" ) {
+ // cout << "found a rabbit" << endl;
+ ssgTransform *rabbit = gen_rabbit_lights( nodes, normals,
+ pnt_i, nml_i,
+ matlib, up );
+ return rabbit;
+ } else if ( material == "RWY_BLUE_TAXIWAY_LIGHTS" ) {
+ ssgTransform *light_group = gen_dir_light_group( nodes, normals, pnt_i,
+ nml_i, mat, up,
+ true );
+ return light_group;
+ } else {
+ ssgTransform *light_group = gen_dir_light_group( nodes, normals, pnt_i,
+ nml_i, mat, up );
+ return light_group;
+ }
+
+ return NULL;
+}
--- /dev/null
+// pt_lights.hxx -- build a 'directional' light on the fly
+//
+// Written by Curtis Olson, started March 2002.
+//
+// Copyright (C) 2002 Curtis L. Olson - curt@flightgear.org
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+
+#ifndef _PT_LIGHTS_HXX
+#define _PT_LIGHTS_HXX
+
+
+#ifndef __cplusplus
+# error This library requires C++
+#endif
+
+
+#include <simgear/compiler.h>
+
+#include STL_STRING
+#include <vector> // STL
+
+#include <plib/sg.h>
+#include <plib/ssg.h> // plib include
+
+#include <simgear/math/sg_types.hxx>
+
+SG_USING_STD(string);
+SG_USING_STD(vector);
+
+
+typedef vector < int > int_list;
+typedef int_list::iterator int_list_iterator;
+typedef int_list::const_iterator int_point_list_iterator;
+
+
+// Define the various supported light types
+typedef enum {
+ FG_RWYLIGHT_TAXI = 0,
+ FG_RWYLIGHT_VASI,
+ FG_RWYLIGHT_EDGE,
+ FG_RWYLIGHT_TOUCHDOWN,
+ FG_RWYLIGHT_THRESHOLD,
+ FG_RWYLIGHT_WHITE,
+ FG_RWYLIGHT_RED,
+ FG_RWYLIGHT_GREEN,
+ FG_RWYLIGHT_YELLOW
+} fgRunwayLightType;
+
+
+// Generate a directional light. This routines creates a
+// 'directional' light that can only be viewed from within 90 degrees
+// of the specified dir vector.
+
+// To accomplish this, he routine creates a triangle with the 1st
+// point coincident with the specified pt and the 2nd and 3rd points
+// extending upward. The 1st point is created with an 'alpha' value
+// of 1 while the 2nd and 3rd points are created with an 'alpha' of
+// 0.0.
+
+// If the triangle is drawn in glPolygonMode(GL_FRONT, GL_POINT) mode,
+// then two important things happen:
+
+// 1) Only the 3 vertex points are drawn, the 2nd two with an alpha of
+// 0 so actually only the desired point is rendered.
+
+// 2) since we are drawing a triangle, back face culling takes care of
+// eliminating this poing when the view angle relative to dir is
+// greater than 90 degrees.
+
+// The final piece of this puzzle is that if we now use environment
+// mapping on this point, via an appropriate texture we can then
+// control the intensity and color of the point based on the view
+// angle relative to 'dir' the optimal view direction of the light
+// (i.e. the direction the light is pointing.)
+
+// Yes this get's to be long and convoluted. If you can suggest a
+// simpler way, please do! :-)
+
+ssgLeaf *gen_directional_light( sgVec3 pt, sgVec3 dir, sgVec3 up );
+
+
+ssgBranch *gen_directional_lights( const point_list &nodes,
+ const point_list &normals,
+ const int_list &pnt_i,
+ const int_list &nml_i,
+ SGMaterialLib *matlib,
+ const string &material,
+ sgVec3 up );
+
+
+#endif // _PT_LIGHTS_HXX