From: curt Date: Sun, 6 Oct 2002 03:53:19 +0000 (+0000) Subject: Begin work on rendering runway lights using environment maps. The basics X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=c162577340cbe2d3696bccd676acd5fe82218fe8;p=flightgear.git Begin work on rendering runway lights using environment maps. The basics 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. --- diff --git a/src/Main/main.cxx b/src/Main/main.cxx index a9486a90f..6b461876c 100644 --- a/src/Main/main.cxx +++ b/src/Main/main.cxx @@ -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 diff --git a/src/Objects/Makefile.am b/src/Objects/Makefile.am index 6561f7f05..38d4623e7 100644 --- a/src/Objects/Makefile.am +++ b/src/Objects/Makefile.am @@ -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 index 2b1cffa5d..000000000 --- a/src/Objects/dir_lights.cxx +++ /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 index a9fec7a61..000000000 --- a/src/Objects/dir_lights.hxx +++ /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 -#endif - -#include - -#include // STL -#include STL_STRING - -#include // 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 diff --git a/src/Objects/matlib.cxx b/src/Objects/matlib.cxx index e80bd1492..8b8ce17d0 100644 --- a/src/Objects/matlib.cxx +++ b/src/Objects/matlib.cxx @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -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); - - vectornames = 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); + + vectornames = 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; } diff --git a/src/Objects/newmat.cxx b/src/Objects/newmat.cxx index afc392e1a..04dee8a06 100644 --- a/src/Objects/newmat.cxx +++ b/src/Objects/newmat.cxx @@ -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 diff --git a/src/Objects/obj.cxx b/src/Objects/obj.cxx index 8abd10ce0..6fb8a8ad4 100644 --- a/src/Objects/obj.cxx +++ b/src/Objects/obj.cxx @@ -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 index 000000000..23bb92045 --- /dev/null +++ b/src/Objects/pt_lights.cxx @@ -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 + +#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 index 000000000..10b20c999 --- /dev/null +++ b/src/Objects/pt_lights.hxx @@ -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 +#endif + +#include + +#include // STL +#include STL_STRING + +#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, + sgVec3 up ); + + +#endif // _PT_LIGHTS_HXX diff --git a/src/Scenery/scenery.cxx b/src/Scenery/scenery.cxx index b319cefe8..5323c05cb 100644 --- a/src/Scenery/scenery.cxx +++ b/src/Scenery/scenery.cxx @@ -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" ); } diff --git a/src/Scenery/scenery.hxx b/src/Scenery/scenery.hxx index c4bf330c8..aa9e11103 100644 --- a/src/Scenery/scenery.hxx +++ b/src/Scenery/scenery.hxx @@ -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; } }; diff --git a/src/Scenery/tileentry.cxx b/src/Scenery/tileentry.cxx index f1de66b59..133f46f80 100644 --- a/src/Scenery/tileentry.cxx +++ b/src/Scenery/tileentry.cxx @@ -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 ); diff --git a/src/Scenery/tilemgr.cxx b/src/Scenery/tilemgr.cxx index 7cc4224b0..d95ded203 100644 --- a/src/Scenery/tilemgr.cxx +++ b/src/Scenery/tilemgr.cxx @@ -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 " }