]> git.mxchange.org Git - flightgear.git/commitdiff
Begin work on rendering runway lights using environment maps. The basics
authorcurt <curt>
Sun, 6 Oct 2002 03:53:19 +0000 (03:53 +0000)
committercurt <curt>
Sun, 6 Oct 2002 03:53:19 +0000 (03:53 +0000)
are now working.  A runway light is defined by a point and a direction.  The
point and direction are combined with the local up vector to create a small
triangle orthogonal to the direction.  The two ficticous corners of the
triangle are given an alpha value of zero, the orignal corner is given an
alpha of one.  The triangle is drawn in glPolygonMode(GL_FRONT, GL_POINT)
mode which means only the corner points are drawn, and since two have alpha=0
only the original point is drawn.  This is a long way to go to draw a point,
but it ensures that the point is only visible within 90 degrees of the light
direction, behind the light it is not visible.  This is still a long way
to get to drawing a point, but we use an environement map, with the direction
vector as the normal to mimic a light that is brightest when viewed head
on and dimmest when viewed perpendicularly or disappears when viewed from
behind.

- warning, there is a bug in how the current runway light direction vector
  is calculated which will adversely effect runway lighting.  The airports
  should be regenerated in order to fix this problem.

13 files changed:
src/Main/main.cxx
src/Objects/Makefile.am
src/Objects/dir_lights.cxx [deleted file]
src/Objects/dir_lights.hxx [deleted file]
src/Objects/matlib.cxx
src/Objects/newmat.cxx
src/Objects/obj.cxx
src/Objects/pt_lights.cxx [new file with mode: 0644]
src/Objects/pt_lights.hxx [new file with mode: 0644]
src/Scenery/scenery.cxx
src/Scenery/scenery.hxx
src/Scenery/tileentry.cxx
src/Scenery/tilemgr.cxx

index a9486a90f20c249ce46d1bded07c3e2776e25632..6b461876c03aaf5863eca295605a5cd45e88ec0e 100644 (file)
@@ -397,7 +397,8 @@ void trRenderFrame( void ) {
     // draw the lights
     glFogf (GL_FOG_DENSITY, fog_exp2_punch_through);
     ssgSetNearFar( scene_nearplane, scene_farplane );
-    ssgCullAndDraw( globals->get_scenery()->get_lighting() );
+    ssgCullAndDraw( globals->get_scenery()->get_gnd_lights_root() );
+    ssgCullAndDraw( globals->get_scenery()->get_rwy_lights_root() );
 
     if (fgGetBool("/environment/clouds/status"))
       thesky->postDraw( cur_fdm_state->get_Altitude() * SG_FEET_TO_METER );
@@ -749,7 +750,17 @@ void fgRenderFrame() {
 #endif
 
         ssgSetNearFar( scene_nearplane, scene_farplane );
-       ssgCullAndDraw( globals->get_scenery()->get_lighting() );
+       ssgCullAndDraw( globals->get_scenery()->get_gnd_lights_root() );
+
+        glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
+        glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
+        glEnable(GL_TEXTURE_GEN_S);
+        glEnable(GL_TEXTURE_GEN_T);
+        glPolygonMode(GL_FRONT, GL_POINT);
+       ssgCullAndDraw( globals->get_scenery()->get_rwy_lights_root() );
+        glPolygonMode(GL_FRONT, GL_FILL);
+        glDisable(GL_TEXTURE_GEN_S);
+        glDisable(GL_TEXTURE_GEN_T);
 
        //static int _frame_count = 0;
        //if (_frame_count % 30 == 0) {
@@ -855,9 +866,6 @@ void fgUpdateTimeDepCalcs() {
     //SG_LOG(SG_FLIGHT,SG_INFO, "Updating time dep calcs()");
 
     fgLIGHT *l = &cur_light_params;
-    int i;
-
-    long multi_loop = 1;
 
     // Initialize the FDM here if it hasn't been and if we have a
     // scenery elevation hit.
@@ -2069,7 +2077,7 @@ void fgLoadDCS(void) {
                                                    //dummy_tile->lightmaps_sequence->setTraversalMaskBits( SSGTRAV_HOT );
                                                        lightpoints_transform->addKid( dummy_tile->lightmaps_sequence );
                                                        lightpoints_transform->ref();
-                                                       globals->get_scenery()->get_gnd_lights_branch()->addKid( lightpoints_transform );
+                                                       globals->get_scenery()->get_gnd_lights_root()->addKid( lightpoints_transform );
                                                } 
                                        } //if in1 
                 } //if objc
index 6561f7f0575a08af7ae3384ec7cdd218f9317e03..38d4623e77f44d90e567116276651810a6a8fe7e 100644 (file)
@@ -2,10 +2,10 @@ noinst_LIBRARIES = libObjects.a
 
 libObjects_a_SOURCES = \
        apt_signs.cxx apt_signs.hxx \
-       dir_lights.cxx dir_lights.hxx \
        newmat.cxx newmat.hxx \
        matlib.cxx matlib.hxx \
        obj.cxx obj.hxx \
+       pt_lights.cxx pt_lights.hxx \
        texload.c texload.h colours.h
 
 INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
diff --git a/src/Objects/dir_lights.cxx b/src/Objects/dir_lights.cxx
deleted file mode 100644 (file)
index 2b1cffa..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-// dir_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 "dir_lights.hxx"
-
-
-// Generate a directional light
-ssgLeaf *gen_directional_light( sgVec3 pt, sgVec3 dir ) {
-return NULL;
-}
diff --git a/src/Objects/dir_lights.hxx b/src/Objects/dir_lights.hxx
deleted file mode 100644 (file)
index a9fec7a..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-// dir_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 _DIR_LIGHTS_HXX
-#define _DIR_LIGHTS_HXX
-
-
-#ifndef __cplusplus                                                          
-# error This library requires C++
-#endif                                   
-
-
-#ifdef HAVE_CONFIG_H
-#  include <config.h>
-#endif
-
-#include <simgear/compiler.h>
-
-#include <vector>              // STL
-#include STL_STRING
-
-#include <plib/ssg.h>          // plib 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
-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 );
-
-
-/* ssgLeaf *gen_directional_lights( const point_list &nodes,
-                                const point_list &normals,
-                                const int_list &pnt_i,
-                                const int_list &nml_i );
-*/
-
-#endif // _DIR_LIGHTS_HXX
index e80bd149232e4589ac4799226fc3d00ce0a45826..8b8ce17d0e226bcf9dc9d13a229174c525d4767d 100644 (file)
@@ -37,6 +37,7 @@
 #include <GL/gl.h>
 
 #include <simgear/compiler.h>
+#include <simgear/constants.h>
 #include <simgear/misc/exception.hxx>
 
 #include <string.h>
@@ -68,54 +69,145 @@ FGMaterialLib::FGMaterialLib ( void ) {
 }
 
 
+static int gen_test_light_map() {
+    static const int env_tex_res = 32;
+    int half_res = env_tex_res / 2;
+    unsigned char env_map[env_tex_res][env_tex_res][4];
+    GLuint tex_name;
+
+    for ( int i = 0; i < env_tex_res; ++i ) {
+        for ( int j = 0; j < env_tex_res; ++j ) {
+            double x = (i - half_res) / (double)half_res;
+            double y = (j - half_res) / (double)half_res;
+            double dist = sqrt(x*x + y*y);
+            if ( dist > 1.0 ) { dist = 1.0; }
+
+            // cout << x << "," << y << " " << (int)(dist * 255) << ","
+            //      << (int)((1.0 - dist) * 255) << endl;
+            env_map[i][j][0] = (int)(dist * 255);
+            env_map[i][j][1] = (int)((1.0 - dist) * 255);
+            env_map[i][j][2] = 0;
+            env_map[i][j][3] = 255;
+        }
+    }
+
+    glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+    glGenTextures( 1, &tex_name );
+    glBindTexture( GL_TEXTURE_2D, tex_name );
+  
+    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
+    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
+    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, env_tex_res, env_tex_res, 0,
+                  GL_RGBA, GL_UNSIGNED_BYTE, env_map);
+
+    return tex_name;
+}
+
+
+static int gen_light_map() {
+    static const int env_tex_res = 32;
+    int half_res = env_tex_res / 2;
+    unsigned char env_map[env_tex_res][env_tex_res][4];
+    GLuint tex_name;
+
+    for ( int i = 0; i < env_tex_res; ++i ) {
+        for ( int j = 0; j < env_tex_res; ++j ) {
+            double x = (i - half_res) / (double)half_res;
+            double y = (j - half_res) / (double)half_res;
+            double dist = sqrt(x*x + y*y);
+            if ( dist > 1.0 ) { dist = 1.0; }
+            double bright = cos( dist * SGD_PI_2 );
+            if ( bright < 0.3 ) { bright = 0.3; }
+            env_map[i][j][0] = 255;
+            env_map[i][j][1] = 255;
+            env_map[i][j][2] = 255;
+            env_map[i][j][3] = (int)(bright * 255);
+        }
+    }
+
+    glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+    glGenTextures( 1, &tex_name );
+    glBindTexture( GL_TEXTURE_2D, tex_name );
+  
+    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
+    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
+    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, env_tex_res, env_tex_res, 0,
+                  GL_RGBA, GL_UNSIGNED_BYTE, env_map);
+
+    return tex_name;
+}
+
+
 // Load a library of material properties
 bool FGMaterialLib::load( const string& mpath ) {
 
-  SGPropertyNode materials;
-
-  SG_LOG(SG_INPUT, SG_INFO, "Reading materials from " << mpath);
-  try {
-    readProperties(mpath, &materials);
-  } catch (const sg_exception &ex) {
-    SG_LOG(SG_INPUT, SG_ALERT, "Error reading materials: " << ex.getMessage());
-    throw ex;
-  }
-
-  int nMaterials = materials.nChildren();
-  for (int i = 0; i < nMaterials; i++) {
-    const SGPropertyNode * node = materials.getChild(i);
-    if (!strcmp(node->getName(), "material")) {
-      FGNewMat * m = new FGNewMat(node);
-
-      vector<SGPropertyNode_ptr>names = node->getChildren("name");
-      for (unsigned int j = 0; j < names.size(); j++) {
-       string name = names[j]->getStringValue();
-       m->ref();
-       // cerr << "Material " << name << endl;
-       matlib[name] = m;
-       SG_LOG( SG_TERRAIN, SG_INFO, "  Loading material "
-               << names[j]->getStringValue());
-      }
-    } else {
-      SG_LOG(SG_INPUT, SG_ALERT,
-            "Skipping bad material entry " << node->getName());
+    SGPropertyNode materials;
+
+    SG_LOG( SG_INPUT, SG_INFO, "Reading materials from " << mpath );
+    try {
+        readProperties( mpath, &materials );
+    } catch (const sg_exception &ex) {
+        SG_LOG( SG_INPUT, SG_ALERT, "Error reading materials: "
+                << ex.getMessage() );
+        throw ex;
     }
-  }
-
-    // hard coded light state
-    ssgSimpleState *lights = new ssgSimpleState;
-    lights->ref();
-    lights->disable( GL_TEXTURE_2D );
-    lights->enable( GL_CULL_FACE );
-    lights->enable( GL_COLOR_MATERIAL );
-    lights->setColourMaterial( GL_AMBIENT_AND_DIFFUSE );
-    lights->setMaterial( GL_EMISSION, 0, 0, 0, 1 );
-    lights->setMaterial( GL_SPECULAR, 0, 0, 0, 1 );
-    lights->enable( GL_BLEND );
-    lights->disable( GL_ALPHA_TEST );
-    lights->disable( GL_LIGHTING );
-
-    matlib["LIGHTS"] = new FGNewMat(lights);
+
+    int nMaterials = materials.nChildren();
+    for (int i = 0; i < nMaterials; i++) {
+        const SGPropertyNode * node = materials.getChild(i);
+        if (!strcmp(node->getName(), "material")) {
+            FGNewMat * m = new FGNewMat(node);
+
+            vector<SGPropertyNode_ptr>names = node->getChildren("name");
+            for ( unsigned int j = 0; j < names.size(); j++ ) {
+                string name = names[j]->getStringValue();
+                m->ref();
+                // cerr << "Material " << name << endl;
+                matlib[name] = m;
+                SG_LOG( SG_TERRAIN, SG_INFO, "  Loading material "
+                        << names[j]->getStringValue() );
+            }
+        } else {
+            SG_LOG(SG_INPUT, SG_ALERT,
+                   "Skipping bad material entry " << node->getName());
+        }
+    }
+
+    // hard coded ground light state
+    ssgSimpleState *gnd_lights = new ssgSimpleState;
+    gnd_lights->ref();
+    gnd_lights->disable( GL_TEXTURE_2D );
+    gnd_lights->enable( GL_CULL_FACE );
+    gnd_lights->enable( GL_COLOR_MATERIAL );
+    gnd_lights->setColourMaterial( GL_AMBIENT_AND_DIFFUSE );
+    gnd_lights->setMaterial( GL_EMISSION, 0, 0, 0, 1 );
+    gnd_lights->setMaterial( GL_SPECULAR, 0, 0, 0, 1 );
+    gnd_lights->enable( GL_BLEND );
+    gnd_lights->disable( GL_ALPHA_TEST );
+    gnd_lights->disable( GL_LIGHTING );
+    matlib["GROUND_LIGHTS"] = new FGNewMat(gnd_lights);
+
+    // hard coded runway light state
+    ssgSimpleState *rwy_lights = new ssgSimpleState();
+    rwy_lights->ref();
+
+    rwy_lights->disable( GL_LIGHTING );
+    rwy_lights->enable ( GL_CULL_FACE ) ;
+    rwy_lights->enable( GL_TEXTURE_2D );
+    rwy_lights->enable( GL_BLEND );
+    rwy_lights->enable( GL_ALPHA_TEST );
+    rwy_lights->enable( GL_COLOR_MATERIAL );
+    rwy_lights->setMaterial ( GL_AMBIENT, 1.0, 1.0, 1.0, 1.0 );
+    rwy_lights->setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0 );
+    rwy_lights->setMaterial ( GL_SPECULAR, 0.0, 0.0, 0.0, 0.0 );
+    rwy_lights->setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 0.0 );
+
+    rwy_lights->setTexture( gen_light_map() );
+    matlib["RUNWAY_LIGHTS"] = new FGNewMat(rwy_lights);
 
     return true;
 }
index afc392e1a16b310c870b57e9bc98642862d3aa6e..04dee8a06f43f1af39eeb9e2f77cddabc2b57ae9 100644 (file)
@@ -131,7 +131,7 @@ FGNewMat::Object::load_models () const
 {
                                // Load model only on demand
   if (!_models_loaded) {
-    for (int i = 0; i < _paths.size(); i++) {
+    for (unsigned int i = 0; i < _paths.size(); i++) {
       ssgEntity * entity = globals->get_model_loader()->load_model(_paths[i]);
       if (entity != 0) {
                                 // FIXME: this stuff can be handled
@@ -256,7 +256,7 @@ FGNewMat::FGNewMat (const string &texpath)
     build_ssg_state(true);
 }
 
-FGNewMat::FGNewMat (ssgSimpleState * s)
+FGNewMat::FGNewMat (ssgSimpleState *s)
 {
     init();
     set_ssg_state(s);
@@ -370,9 +370,9 @@ void
 FGNewMat::build_ssg_state (bool defer_tex_load)
 {
     GLenum shade_model =
-      (fgGetBool("/sim/rendering/shading") ? GL_SMOOTH : GL_FLAT);
+        (fgGetBool("/sim/rendering/shading") ? GL_SMOOTH : GL_FLAT);
     bool texture_default = fgGetBool("/sim/rendering/textures");
-
+    
     state = new ssgStateSelector(2);
     state->ref();
 
@@ -389,15 +389,6 @@ FGNewMat::build_ssg_state (bool defer_tex_load)
     textured->enable( GL_TEXTURE_2D );
     textured->disable( GL_BLEND );
     textured->disable( GL_ALPHA_TEST );
-#if 0
-#  ifdef GL_EXT_texture_filter_anisotropic
-    float max_anisotropy;
-    glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy );
-    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
-                    max_anisotropy );
-    cout << "Max anisotropy = " << max_anisotropy << endl;
-#  endif
-#endif
     if ( !defer_tex_load ) {
        textured->setTexture( (char *)texture_path.c_str(), wrapu, wrapv );
        texture_loaded = true;
@@ -462,25 +453,31 @@ FGNewMat::build_ssg_state (bool defer_tex_load)
 
 void FGNewMat::set_ssg_state( ssgSimpleState *s )
 {
+    GLenum shade_model =
+        (fgGetBool("/sim/rendering/shading") ? GL_SMOOTH : GL_FLAT);
+    bool texture_default = fgGetBool("/sim/rendering/textures");
+
     state = new ssgStateSelector(2);
     state->ref();
 
     textured = s;
+    texture_loaded = true;
 
     nontextured = new ssgSimpleState();
     nontextured->ref();
 
+    // Set up the textured state
+    textured->setShadeModel( shade_model );
+
     // Set up the coloured state
     nontextured->enable( GL_LIGHTING );
-    nontextured->setShadeModel( GL_FLAT );
+    nontextured->setShadeModel( shade_model );
     nontextured->enable ( GL_CULL_FACE      ) ;
     nontextured->disable( GL_TEXTURE_2D );
     nontextured->disable( GL_BLEND );
     nontextured->disable( GL_ALPHA_TEST );
     nontextured->disable( GL_COLOR_MATERIAL );
 
-    /* cout << "ambient = " << ambient[0] << "," << ambient[1] 
-       << "," << ambient[2] << endl; */
     nontextured->setMaterial ( GL_AMBIENT, 
                               ambient[0], ambient[1], 
                               ambient[2], ambient[3] ) ;
@@ -499,7 +496,11 @@ void FGNewMat::set_ssg_state( ssgSimpleState *s )
     state->setStep( 1, nontextured ); // untextured
 
     // Choose the appropriate starting state.
-    state->selectStep(0);
+    if ( texture_default ) {
+       state->selectStep(0);
+    } else {
+       state->selectStep(1);
+    }
 }
 
 // end of newmat.cxx
index 8abd10ce02b5092fb378113b669105876c808b72..6fb8a8ad465b0acbe3f73c3bd28b468489cff060 100644 (file)
@@ -59,6 +59,7 @@
 
 #include "newmat.hxx"
 #include "matlib.hxx"
+#include "pt_lights.hxx"
 #include "obj.hxx"
 
 SG_USING_STD(string);
@@ -1376,12 +1377,9 @@ bool fgBinObjLoad( const string& path, const bool is_base,
 
     geometry->setName( (char *)path.c_str() );
 
-    if ( is_base ) {
-        // reference point (center offset/bounding sphere)
-        *center = obj.get_gbs_center();
-        *bounding_radius = obj.get_gbs_radius();
-
-    }
+    // reference point (center offset/bounding sphere)
+    *center = obj.get_gbs_center();
+    *bounding_radius = obj.get_gbs_radius();
 
     point_list const& nodes = obj.get_wgs84_nodes();
     point_list const& colors = obj.get_colors();
@@ -1401,29 +1399,30 @@ bool fgBinObjLoad( const string& path, const bool is_base,
     for ( i = 0; i < pts_v.size(); ++i ) {
         // cout << "pts_v.size() = " << pts_v.size() << endl;
        if ( pt_materials[i].substr(0, 3) == "RWY" ) {
-            material = "LIGHTS";
+            material = "GROUND_LIGHTS";
             is_lighting = true;
-        } else {
+            sgVec3 up;
+            sgSetVec3( up, center->x(), center->y(), center->z() );
+            ssgBranch *branch = gen_directional_lights( nodes, normals,
+                                                        pts_v[i], pts_n[i],
+                                                        up );
+            float ranges[] = { 0, 12000 };
+            // branch->setCallback( SSG_CALLBACK_PREDRAW, runway_lights_predraw );
+            ssgRangeSelector * lod = new ssgRangeSelector;
+            lod->setRanges( ranges, 2 );
+            lod->addKid( branch );
+            rwy_lights->addKid( lod );
+       } else {
             material = pt_materials[i];
-        }
-        tex_index.clear();
-        ssgLeaf *leaf = gen_leaf( path, GL_POINTS, material,
-                                  nodes, normals, texcoords,
-                                  pts_v[i], pts_n[i], tex_index,
-                                  false, ground_lights );
+            tex_index.clear();
+            ssgLeaf *leaf = gen_leaf( path, GL_POINTS, material,
+                                      nodes, normals, texcoords,
+                                      pts_v[i], pts_n[i], tex_index,
+                                      false, ground_lights );
+            geometry->addKid( leaf );
+       }
 
         if ( is_lighting ) {
-            float ranges[] = {
-                0,
-                12000
-            };
-            leaf->setCallback(SSG_CALLBACK_PREDRAW, runway_lights_predraw);
-            ssgRangeSelector * lod = new ssgRangeSelector;
-            lod->setRanges(ranges, 2);
-            lod->addKid(leaf);
-            rwy_lights->addKid(lod);
-        } else {
-            geometry->addKid( leaf );
         }
     }
 
diff --git a/src/Objects/pt_lights.cxx b/src/Objects/pt_lights.cxx
new file mode 100644 (file)
index 0000000..23bb920
--- /dev/null
@@ -0,0 +1,159 @@
+// 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 "newmat.hxx"
+#include "matlib.hxx"
+
+#include "pt_lights.hxx"
+
+
+// Generate a directional light
+ssgLeaf *gen_directional_light( sgVec3 pt, sgVec3 dir, sgVec3 up ) {
+
+    // calculate a vector perpendicular to dir and up
+    sgVec3 perp;
+    sgVectorProductVec3( perp, dir, up );
+
+    ssgVertexArray   *vl = new ssgVertexArray( 3 );
+    ssgNormalArray   *nl = new ssgNormalArray( 1 );
+    ssgColourArray   *cl = new ssgColourArray( 1 );
+
+    // front face
+    sgVec3 tmp3;
+    sgCopyVec3( tmp3, pt );
+    vl->add( tmp3 );
+    sgAddVec3( tmp3, up );
+    vl->add( tmp3 );
+    sgSubVec3( tmp3, perp );
+    vl->add( tmp3 );
+
+    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 );
+
+    // 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 );
+
+    FGNewMat *newmat = material_lib.find( "RUNWAY_LIGHTS" );
+    // FGNewMat *newmat = material_lib.find( "IrrCropPastureCover" );
+    leaf->setState( newmat->get_state() );
+
+    return leaf;
+}
+
+
+// Generate a directional light
+ssgLeaf *gen_normal_line( sgVec3 pt, sgVec3 dir, sgVec3 up ) {
+
+    ssgVertexArray   *vl = new ssgVertexArray( 3 );
+    ssgNormalArray   *nl = new ssgNormalArray( 1 );
+    ssgColourArray   *cl = new ssgColourArray( 1 );
+
+    sgVec3 tmp3;
+    sgCopyVec3( tmp3, pt );
+    vl->add( tmp3 );
+    sgAddVec3( tmp3, dir );
+    vl->add( tmp3 );
+
+    sgVec4 color;
+    sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
+    cl->add( color );
+    cl->add( color );
+
+    ssgLeaf *leaf = 
+        new ssgVtxTable ( GL_LINES, vl, NULL, NULL, cl );
+
+    FGNewMat *newmat = material_lib.find( "GROUND_LIGHTS" );
+    // FGNewMat *newmat = material_lib.find( "IrrCropPastureCover" );
+    leaf->setState( newmat->get_state() );
+
+    return leaf;
+}
+
+
+ssgBranch *gen_directional_lights( const point_list &nodes,
+                                   const point_list &normals,
+                                   const int_list &pnt_i,
+                                   const int_list &nml_i,
+                                   sgVec3 up )
+{
+    ssgBranch *result = new ssgBranch;
+
+    sgVec3 nup;
+    sgNormalizeVec3( nup, up );
+
+    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] );
+        sgSetVec3( normal, normals[nml_i[i]][0], normals[nml_i[i]][1],
+                   normals[nml_i[i]][2] );
+        ssgLeaf *light = gen_directional_light( pt, normal, nup );
+        result->addKid( light );
+        // light = gen_normal_line( pt, normal, nup );
+        // result->addKid( light );
+    }
+
+    return result;
+}
diff --git a/src/Objects/pt_lights.hxx b/src/Objects/pt_lights.hxx
new file mode 100644 (file)
index 0000000..10b20c9
--- /dev/null
@@ -0,0 +1,109 @@
+// 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                                   
+
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <simgear/compiler.h>
+
+#include <vector>              // STL
+#include STL_STRING
+
+#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,
+                                   sgVec3 up );
+
+
+#endif // _PT_LIGHTS_HXX
index b319cefe8a29352f90e0590d2e77726eef0677ff..5323c05cb4d1a78386c8b9de4f7d3c20d6dbdf3a 100644 (file)
@@ -61,9 +61,6 @@ void FGScenery::init() {
     scene_graph = new ssgRoot;
     scene_graph->setName( "Scene" );
 
-    lighting = new ssgRoot;
-    lighting->setName( "Lighting" );
-
     // Terrain branch
     terrain_branch = new ssgBranch;
     terrain_branch->setName( "Terrain" );
@@ -78,13 +75,11 @@ void FGScenery::init() {
     scene_graph->addKid( aircraft_branch );
 
     // Lighting
-    gnd_lights_branch = new ssgBranch;
-    gnd_lights_branch->setName( "Ground Lighting" );
-    lighting->addKid( gnd_lights_branch );
+    gnd_lights_root = new ssgRoot;
+    gnd_lights_root->setName( "Ground Lighting Root" );
 
-    rwy_lights_branch = new ssgBranch;
-    rwy_lights_branch->setName( "Runway Lighting" );
-    lighting->addKid( rwy_lights_branch );
+    rwy_lights_root = new ssgRoot;
+    rwy_lights_root->setName( "Runway Lighting Root" );
 }
 
 
index c4bf330c81e971349c8ee3ce95b02f681ef69a65..aa9e111032fe9f73fba10352ebd98eb0f4c1f3eb 100644 (file)
@@ -61,14 +61,12 @@ class FGScenery : public FGSubsystem {
     sgdVec3 cur_normal;
 
     // SSG scene graph
-    ssgRoot * scene_graph;
-    ssgBranch * terrain_branch;
-    ssgBranch * gnd_lights_branch;
-    ssgBranch * rwy_lights_branch;
-    ssgBranch * models_branch;
-    ssgBranch * aircraft_branch;
-
-    ssgRoot *lighting;
+    ssgRoot *scene_graph;
+    ssgBranch *terrain_branch;
+    ssgRoot *gnd_lights_root;
+    ssgRoot *rwy_lights_root;
+    ssgBranch *models_branch;
+    ssgBranch *aircraft_branch;
 
 public:
 
@@ -93,42 +91,39 @@ public:
     inline void set_cur_radius( double r ) { cur_radius = r; }
     inline void set_cur_normal( sgdVec3 n ) { sgdCopyVec3( cur_normal, n ); }
 
-    inline ssgRoot * get_scene_graph () const { return scene_graph; }
+    inline ssgRoot *get_scene_graph () const { return scene_graph; }
     inline void set_scene_graph (ssgRoot * s) { scene_graph = s; }
 
-    inline ssgBranch * get_terrain_branch () const { return terrain_branch; }
+    inline ssgBranch *get_terrain_branch () const { return terrain_branch; }
     inline void set_terrain_branch (ssgBranch * t) { terrain_branch = t; }
 
-    inline ssgBranch * get_gnd_lights_branch () const {
-      return gnd_lights_branch;
+    inline ssgRoot *get_gnd_lights_root () const {
+        return gnd_lights_root;
     }
-    inline void set_gnd_lights_branch (ssgBranch * t) {
-      gnd_lights_branch = t;
+    inline void set_gnd_lights_root (ssgRoot *r) {
+        gnd_lights_root = r;
     }
 
-    inline ssgBranch * get_rwy_lights_branch () const {
-      return rwy_lights_branch;
+    inline ssgRoot *get_rwy_lights_root () const {
+        return rwy_lights_root;
     }
-    inline void set_rwy_lights_branch (ssgBranch * t) {
-      rwy_lights_branch = t;
+    inline void set_rwy_lights_root (ssgRoot *r) {
+        rwy_lights_root = r;
     }
 
-    inline ssgBranch * get_models_branch () const {
-      return models_branch;
+    inline ssgBranch *get_models_branch () const {
+        return models_branch;
     }
-    inline void set_models_branch (ssgBranch * t) {
-      models_branch = t;
+    inline void set_models_branch (ssgBranch *t) {
+        models_branch = t;
     }
 
-    inline ssgBranch * get_aircraft_branch () const {
-      return aircraft_branch;
+    inline ssgBranch *get_aircraft_branch () const {
+        return aircraft_branch;
     }
-    inline void set_aircraft_branch (ssgBranch * t) {
-      aircraft_branch = t;
+    inline void set_aircraft_branch (ssgBranch *t) {
+        aircraft_branch = t;
     }
-
-    inline ssgRoot * get_lighting () const { return lighting; }
-    inline void set_lighting (ssgRoot *l) { lighting = l; }
 };
 
 
index f1de66b594518a49f4946292ca38e82e3ba4451c..133f46f8072f54bebc18c168a687614e8f3d3b57 100644 (file)
@@ -1061,7 +1061,7 @@ ssgLeaf* FGTileEntry::gen_lights( ssgVertexArray *lights, int inc, float bright
         new ssgVtxTable ( GL_POINTS, vl, nl, tl, cl );
 
     // assign state
-    FGNewMat *newmat = material_lib.find( "LIGHTS" );
+    FGNewMat *newmat = material_lib.find( "GROUND_LIGHTS" );
     leaf->setState( newmat->get_state() );
     leaf->setCallback( SSG_CALLBACK_PREDRAW, fgLightsPredraw );
     leaf->setCallback( SSG_CALLBACK_POSTDRAW, fgLightsPostdraw );
index 7cc4224b0ba3137feb33901a05ca2b203da9f431..d95ded2039474408c077cc08c7993450dec0ace3 100644 (file)
@@ -370,8 +370,8 @@ int FGTileMgr::update( double lon, double lat, double visibility_meters,
        attach_queue.pop();
 #endif
        e->add_ssg_nodes( globals->get_scenery()->get_terrain_branch(),
-                         globals->get_scenery()->get_gnd_lights_branch(),
-                         globals->get_scenery()->get_rwy_lights_branch() );
+                         globals->get_scenery()->get_gnd_lights_root(),
+                         globals->get_scenery()->get_rwy_lights_root() );
        // cout << "Adding ssg nodes for "
     }