1 // pt_lights.cxx -- build a 'directional' light on the fly
3 // Written by Curtis Olson, started March 2002.
5 // Copyright (C) 2002 Curtis L. Olson - curt@flightgear.org
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include "pt_lights.hxx"
32 // strobe pre-draw (we want a larger point size)
33 static int StrobePreDraw( ssgEntity *e ) {
34 glPushAttrib( GL_POINT_BIT );
36 glEnable(GL_POINT_SMOOTH);
41 // strobe post-draw (we want a larger point size)
42 static int StrobePostDraw( ssgEntity *e ) {
49 // Generate a directional light
50 ssgLeaf *gen_directional_light( sgVec3 pt, sgVec3 dir, sgVec3 up,
51 const string &material ) {
53 // calculate a vector perpendicular to dir and up
55 sgVectorProductVec3( perp, dir, up );
57 ssgVertexArray *vl = new ssgVertexArray( 3 );
58 ssgNormalArray *nl = new ssgNormalArray( 3 );
59 ssgColourArray *cl = new ssgColourArray( 3 );
63 sgCopyVec3( tmp3, pt );
65 sgAddVec3( tmp3, up );
67 sgAddVec3( tmp3, perp );
69 // sgSubVec3( tmp3, up );
78 sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
80 sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
86 // temporarily do back face
87 sgCopyVec3( tmp3, pt );
89 sgAddVec3( tmp3, up );
91 sgAddVec3( tmp3, perp );
99 sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
101 sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
106 /* ssgTexCoordArray *tl = new ssgTexCoordArray( 4 );
108 sgSetVec2( tmp2, 0.0, 0.0 );
110 sgSetVec2( tmp2, 1.0, 0.0 );
112 sgSetVec2( tmp2, 1.0, 1.0 );
114 sgSetVec2( tmp2, 0.0, 1.0 );
118 new ssgVtxTable ( GL_TRIANGLES, vl, nl, NULL, cl );
120 FGNewMat *newmat = material_lib.find( material );
122 if ( newmat != NULL ) {
123 leaf->setState( newmat->get_state() );
125 SG_LOG( SG_TERRAIN, SG_ALERT, "Warning: can't material = "
133 static void calc_center_point( const point_list &nodes,
134 const int_list &pnt_i,
137 sgSetVec3( pt, nodes[pnt_i[0]][0], nodes[pnt_i[0]][1], nodes[pnt_i[0]][2] );
146 for ( unsigned int i = 0; i < pnt_i.size(); ++i ) {
147 sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
148 nodes[pnt_i[i]][2] );
149 if ( pt[0] < minx ) { minx = pt[0]; }
150 if ( pt[0] > maxx ) { minx = pt[0]; }
151 if ( pt[1] < miny ) { miny = pt[1]; }
152 if ( pt[1] > maxy ) { miny = pt[1]; }
153 if ( pt[2] < minz ) { minz = pt[2]; }
154 if ( pt[2] > maxz ) { minz = pt[2]; }
157 sgSetVec3( result, (minx + maxx) / 2.0, (miny + maxy) / 2.0,
158 (minz + maxz) / 2.0 );
162 ssgTransform *gen_dir_light_group( const point_list &nodes,
163 const point_list &normals,
164 const int_list &pnt_i,
165 const int_list &nml_i,
166 const string &material,
167 sgVec3 up, bool vertical = false )
170 calc_center_point( nodes, pnt_i, center );
171 // cout << center[0] << "," << center[1] << "," << center[2] << endl;
174 // find a vector perpendicular to the normal.
177 // normal isn't vertical so we can use up as our first vector
178 sgNormalizeVec3( perp1, up );
180 // normal is vertical so we have to work a bit harder to
181 // determine our first vector
183 sgSetVec3( pt1, nodes[pnt_i[0]][0], nodes[pnt_i[0]][1],
184 nodes[pnt_i[0]][2] );
185 sgSetVec3( pt2, nodes[pnt_i[1]][0], nodes[pnt_i[1]][1],
186 nodes[pnt_i[1]][2] );
188 sgSubVec3( perp1, pt2, pt1 );
189 sgNormalizeVec3( perp1 );
192 ssgVertexArray *vl = new ssgVertexArray( 3 * pnt_i.size() );
193 ssgNormalArray *nl = new ssgNormalArray( 3 * pnt_i.size() );
194 ssgColourArray *cl = new ssgColourArray( 3 * pnt_i.size() );
198 for ( i = 0; i < pnt_i.size(); ++i ) {
199 sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
200 nodes[pnt_i[i]][2] );
201 sgSubVec3( pt, center );
202 sgSetVec3( normal, normals[nml_i[i]][0], normals[nml_i[i]][1],
203 normals[nml_i[i]][2] );
205 // calculate a vector perpendicular to dir and up
207 sgVectorProductVec3( perp2, normal, perp1 );
211 sgCopyVec3( tmp3, pt );
213 sgAddVec3( tmp3, perp1 );
215 sgAddVec3( tmp3, perp2 );
217 // sgSubVec3( tmp3, perp1 );
223 // nl->add( normal );
226 sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
228 sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
235 new ssgVtxTable ( GL_TRIANGLES, vl, nl, NULL, cl );
237 FGNewMat *newmat = material_lib.find( material );
239 if ( newmat != NULL ) {
240 leaf->setState( newmat->get_state() );
242 SG_LOG( SG_TERRAIN, SG_ALERT, "Warning: can't material = "
246 // put an LOD on each lighting component
247 ssgRangeSelector *lod = new ssgRangeSelector;
248 lod->setRange( 0, SG_ZERO );
249 lod->setRange( 1, 20000 );
252 // create the transformation.
254 sgSetCoord( &coord, center[0], center[1], center[2], 0.0, 0.0, 0.0 );
255 ssgTransform *trans = new ssgTransform;
256 trans->setTransform( &coord );
257 trans->addKid( lod );
263 ssgTransform *gen_reil_lights( const point_list &nodes,
264 const point_list &normals,
265 const int_list &pnt_i,
266 const int_list &nml_i,
267 const string &material,
271 calc_center_point( nodes, pnt_i, center );
272 // cout << center[0] << "," << center[1] << "," << center[2] << endl;
275 sgNormalizeVec3( nup, up );
277 ssgVertexArray *vl = new ssgVertexArray( 3 * pnt_i.size() );
278 ssgNormalArray *nl = new ssgNormalArray( 3 * pnt_i.size() );
279 ssgColourArray *cl = new ssgColourArray( 3 * pnt_i.size() );
283 for ( i = 0; i < pnt_i.size(); ++i ) {
284 sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
285 nodes[pnt_i[i]][2] );
286 sgSubVec3( pt, center );
287 sgSetVec3( normal, normals[nml_i[i]][0], normals[nml_i[i]][1],
288 normals[nml_i[i]][2] );
290 // calculate a vector perpendicular to dir and up
292 sgVectorProductVec3( perp, normal, nup );
296 sgCopyVec3( tmp3, pt );
298 sgAddVec3( tmp3, nup );
300 sgAddVec3( tmp3, perp );
302 // sgSubVec3( tmp3, nup );
308 // nl->add( normal );
311 sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
313 sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
320 new ssgVtxTable ( GL_TRIANGLES, vl, nl, NULL, cl );
322 FGNewMat *newmat = material_lib.find( "RWY_WHITE_LIGHTS" );
324 if ( newmat != NULL ) {
325 leaf->setState( newmat->get_state() );
327 SG_LOG( SG_TERRAIN, SG_ALERT, "Warning: can't material = "
331 leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw );
332 leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw );
334 ssgTimedSelector *reil = new ssgTimedSelector;
336 // need to add this twice to work around an ssg bug
337 reil->addKid( leaf );
338 reil->addKid( leaf );
340 reil->setDuration( 60 );
341 reil->setLimits( 0, 2 );
342 reil->setMode( SSG_ANIM_SHUTTLE );
343 reil->control( SSG_ANIM_START );
345 // put an LOD on each lighting component
346 ssgRangeSelector *lod = new ssgRangeSelector;
347 lod->setRange( 0, SG_ZERO );
348 lod->setRange( 1, 12000 );
351 // create the transformation.
353 sgSetCoord( &coord, center[0], center[1], center[2], 0.0, 0.0, 0.0 );
354 ssgTransform *trans = new ssgTransform;
355 trans->setTransform( &coord );
356 trans->addKid( lod );
362 ssgTransform *gen_odals_lights( const point_list &nodes,
363 const point_list &normals,
364 const int_list &pnt_i,
365 const int_list &nml_i,
366 const string &material,
370 calc_center_point( nodes, pnt_i, center );
371 // cout << center[0] << "," << center[1] << "," << center[2] << endl;
373 ssgTimedSelector *odals = new ssgTimedSelector;
376 sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
378 // center line strobes
381 for ( i = (int)pnt_i.size() - 1; i >= 2; --i ) {
382 ssgVertexArray *vl = new ssgVertexArray( 1 );
383 ssgColourArray *cl = new ssgColourArray( 1 );
385 sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
386 nodes[pnt_i[i]][2] );
387 sgSubVec3( pt, center );
393 new ssgVtxTable ( GL_POINTS, vl, NULL, NULL, cl );
395 // we don't want directional lights here
396 FGNewMat *newmat = material_lib.find( "GROUND_LIGHTS" );
398 if ( newmat != NULL ) {
399 leaf->setState( newmat->get_state() );
401 SG_LOG( SG_TERRAIN, SG_ALERT, "Warning: can't material = "
405 leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw );
406 leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw );
408 odals->addKid( leaf );
411 // runway end strobes
412 ssgVertexArray *vl = new ssgVertexArray( 2 );
413 ssgColourArray *cl = new ssgColourArray( 2 );
415 sgSetVec3( pt, nodes[pnt_i[0]][0], nodes[pnt_i[0]][1],
416 nodes[pnt_i[0]][2] );
417 sgSubVec3( pt, center );
421 sgSetVec3( pt, nodes[pnt_i[1]][0], nodes[pnt_i[1]][1],
422 nodes[pnt_i[1]][2] );
423 sgSubVec3( pt, center );
428 new ssgVtxTable ( GL_POINTS, vl, NULL, NULL, cl );
430 // we don't want directional lights here
431 FGNewMat *newmat = material_lib.find( "GROUND_LIGHTS" );
433 if ( newmat != NULL ) {
434 leaf->setState( newmat->get_state() );
436 SG_LOG( SG_TERRAIN, SG_ALERT, "Warning: can't material = "
440 leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw );
441 leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw );
443 odals->addKid( leaf );
447 odals->setDuration( 10 );
448 odals->setLimits( 0, pnt_i.size() - 1 );
449 odals->setMode( SSG_ANIM_SHUTTLE );
450 odals->control( SSG_ANIM_START );
452 // put an LOD on each lighting component
453 ssgRangeSelector *lod = new ssgRangeSelector;
454 lod->setRange( 0, SG_ZERO );
455 lod->setRange( 1, 12000 );
456 lod->addKid( odals );
458 // create the transformation.
460 sgSetCoord( &coord, center[0], center[1], center[2], 0.0, 0.0, 0.0 );
461 ssgTransform *trans = new ssgTransform;
462 trans->setTransform( &coord );
463 trans->addKid( lod );
469 ssgTransform *gen_rabbit_lights( const point_list &nodes,
470 const point_list &normals,
471 const int_list &pnt_i,
472 const int_list &nml_i,
473 const string &material,
477 calc_center_point( nodes, pnt_i, center );
478 // cout << center[0] << "," << center[1] << "," << center[2] << endl;
481 sgNormalizeVec3( nup, up );
483 ssgTimedSelector *rabbit = new ssgTimedSelector;
487 for ( i = (int)pnt_i.size() - 1; i >= 0; --i ) {
488 ssgVertexArray *vl = new ssgVertexArray( 3 );
489 ssgNormalArray *nl = new ssgNormalArray( 3 );
490 ssgColourArray *cl = new ssgColourArray( 3 );
492 sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
493 nodes[pnt_i[i]][2] );
494 sgSubVec3( pt, center );
496 sgSetVec3( normal, normals[nml_i[i]][0], normals[nml_i[i]][1],
497 normals[nml_i[i]][2] );
499 // calculate a vector perpendicular to dir and up
501 sgVectorProductVec3( perp, normal, nup );
505 sgCopyVec3( tmp3, pt );
507 sgAddVec3( tmp3, nup );
509 sgAddVec3( tmp3, perp );
511 // sgSubVec3( tmp3, nup );
517 // nl->add( normal );
520 sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
522 sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
528 new ssgVtxTable ( GL_TRIANGLES, vl, nl, NULL, cl );
530 FGNewMat *newmat = material_lib.find( "RWY_WHITE_LIGHTS" );
532 if ( newmat != NULL ) {
533 leaf->setState( newmat->get_state() );
535 SG_LOG( SG_TERRAIN, SG_ALERT, "Warning: can't material = "
539 leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw );
540 leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw );
542 rabbit->addKid( leaf );
545 rabbit->setDuration( 10 );
546 rabbit->setLimits( 0, pnt_i.size() - 1 );
547 rabbit->setMode( SSG_ANIM_SHUTTLE );
548 rabbit->control( SSG_ANIM_START );
550 // put an LOD on each lighting component
551 ssgRangeSelector *lod = new ssgRangeSelector;
552 lod->setRange( 0, SG_ZERO );
553 lod->setRange( 1, 12000 );
554 lod->addKid( rabbit );
556 // create the transformation.
558 sgSetCoord( &coord, center[0], center[1], center[2], 0.0, 0.0, 0.0 );
559 ssgTransform *trans = new ssgTransform;
560 trans->setTransform( &coord );
561 trans->addKid( lod );
567 // Generate a directional light
568 ssgLeaf *gen_normal_line( sgVec3 pt, sgVec3 dir, sgVec3 up ) {
570 ssgVertexArray *vl = new ssgVertexArray( 3 );
571 ssgColourArray *cl = new ssgColourArray( 3 );
574 sgCopyVec3( tmp3, pt );
576 sgAddVec3( tmp3, dir );
580 sgSetVec4( color, 1.0, 0.0, 0.0, 1.0 );
585 new ssgVtxTable ( GL_LINES, vl, NULL, NULL, cl );
587 FGNewMat *newmat = material_lib.find( "GROUND_LIGHTS" );
588 leaf->setState( newmat->get_state() );
594 ssgBranch *gen_directional_lights( const point_list &nodes,
595 const point_list &normals,
596 const int_list &pnt_i,
597 const int_list &nml_i,
598 const string &material,
602 sgNormalizeVec3( nup, up );
604 if ( material == "RWY_REIL_LIGHTS" ) {
605 // cout << "found a reil" << endl;
606 ssgTransform *reil = gen_reil_lights( nodes, normals, pnt_i, nml_i,
609 } else if ( material == "RWY_ODALS_LIGHTS" ) {
610 // cout << "found a odals" << endl;
611 ssgTransform *odals = gen_odals_lights( nodes, normals, pnt_i, nml_i,
614 } else if ( material == "RWY_SEQUENCED_LIGHTS" ) {
615 // cout << "found a rabbit" << endl;
616 ssgTransform *rabbit = gen_rabbit_lights( nodes, normals,
620 } else if ( material == "RWY_BLUE_TAXIWAY_LIGHTS" ) {
621 ssgTransform *light_group = gen_dir_light_group( nodes, normals, pnt_i,
626 ssgTransform *light_group = gen_dir_light_group( nodes, normals, pnt_i,
627 nml_i, material, up );