From 1ae257944b87f67bbc10cabe013975a7298c816e Mon Sep 17 00:00:00 2001 From: curt Date: Wed, 14 May 2003 19:20:36 +0000 Subject: [PATCH] Moved some low level scene graph construction code over to simgear/scene/tgdb/ --- simgear/scene/tgdb/Makefile.am | 17 + simgear/scene/tgdb/apt_signs.cxx | 167 +++++++++ simgear/scene/tgdb/apt_signs.hxx | 54 +++ simgear/scene/tgdb/leaf.cxx | 259 +++++++++++++ simgear/scene/tgdb/leaf.hxx | 59 +++ simgear/scene/tgdb/pt_lights.cxx | 619 +++++++++++++++++++++++++++++++ simgear/scene/tgdb/pt_lights.hxx | 107 ++++++ 7 files changed, 1282 insertions(+) create mode 100644 simgear/scene/tgdb/Makefile.am create mode 100644 simgear/scene/tgdb/apt_signs.cxx create mode 100644 simgear/scene/tgdb/apt_signs.hxx create mode 100644 simgear/scene/tgdb/leaf.cxx create mode 100644 simgear/scene/tgdb/leaf.hxx create mode 100644 simgear/scene/tgdb/pt_lights.cxx create mode 100644 simgear/scene/tgdb/pt_lights.hxx diff --git a/simgear/scene/tgdb/Makefile.am b/simgear/scene/tgdb/Makefile.am new file mode 100644 index 00000000..aae63218 --- /dev/null +++ b/simgear/scene/tgdb/Makefile.am @@ -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 index 00000000..124d8b1f --- /dev/null +++ b/simgear/scene/tgdb/apt_signs.cxx @@ -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 +#include +#include + +#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 index 00000000..edd96dfb --- /dev/null +++ b/simgear/scene/tgdb/apt_signs.hxx @@ -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 + +#include STL_STRING + +#include // 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 index 00000000..0700ae20 --- /dev/null +++ b/simgear/scene/tgdb/leaf.cxx @@ -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 +#endif + +#include + +#ifdef SG_MATH_EXCEPTION_CLASH +# include +#endif + +#include STL_STRING + +#include +#include +#include +#include + +#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 index 00000000..772489b5 --- /dev/null +++ b/simgear/scene/tgdb/leaf.hxx @@ -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 + +#include STL_STRING + +#include // plib include + +#include + +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 index 00000000..393606a7 --- /dev/null +++ b/simgear/scene/tgdb/pt_lights.cxx @@ -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 + +#include +#include + +#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 index 00000000..2a2e4c01 --- /dev/null +++ b/simgear/scene/tgdb/pt_lights.hxx @@ -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 + +#include STL_STRING +#include // STL + +#include +#include // plib include + +#include + +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 -- 2.39.5