]> git.mxchange.org Git - simgear.git/commitdiff
Moved some low level scene graph construction code over to simgear/scene/tgdb/
authorcurt <curt>
Wed, 14 May 2003 19:20:36 +0000 (19:20 +0000)
committercurt <curt>
Wed, 14 May 2003 19:20:36 +0000 (19:20 +0000)
simgear/scene/tgdb/Makefile.am [new file with mode: 0644]
simgear/scene/tgdb/apt_signs.cxx [new file with mode: 0644]
simgear/scene/tgdb/apt_signs.hxx [new file with mode: 0644]
simgear/scene/tgdb/leaf.cxx [new file with mode: 0644]
simgear/scene/tgdb/leaf.hxx [new file with mode: 0644]
simgear/scene/tgdb/pt_lights.cxx [new file with mode: 0644]
simgear/scene/tgdb/pt_lights.hxx [new file with mode: 0644]

diff --git a/simgear/scene/tgdb/Makefile.am b/simgear/scene/tgdb/Makefile.am
new file mode 100644 (file)
index 0000000..aae6321
--- /dev/null
@@ -0,0 +1,17 @@
+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)
diff --git a/simgear/scene/tgdb/apt_signs.cxx b/simgear/scene/tgdb/apt_signs.cxx
new file mode 100644 (file)
index 0000000..124d8b1
--- /dev/null
@@ -0,0 +1,167 @@
+// 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;
+}
diff --git a/simgear/scene/tgdb/apt_signs.hxx b/simgear/scene/tgdb/apt_signs.hxx
new file mode 100644 (file)
index 0000000..edd96df
--- /dev/null
@@ -0,0 +1,54 @@
+// 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
diff --git a/simgear/scene/tgdb/leaf.cxx b/simgear/scene/tgdb/leaf.cxx
new file mode 100644 (file)
index 0000000..0700ae2
--- /dev/null
@@ -0,0 +1,259 @@
+// 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;
+}
diff --git a/simgear/scene/tgdb/leaf.hxx b/simgear/scene/tgdb/leaf.hxx
new file mode 100644 (file)
index 0000000..772489b
--- /dev/null
@@ -0,0 +1,59 @@
+// 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
diff --git a/simgear/scene/tgdb/pt_lights.cxx b/simgear/scene/tgdb/pt_lights.cxx
new file mode 100644 (file)
index 0000000..393606a
--- /dev/null
@@ -0,0 +1,619 @@
+// 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;
+}
diff --git a/simgear/scene/tgdb/pt_lights.hxx b/simgear/scene/tgdb/pt_lights.hxx
new file mode 100644 (file)
index 0000000..2a2e4c0
--- /dev/null
@@ -0,0 +1,107 @@
+// 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