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.
26 #include <simgear/scene/material/mat.hxx>
27 #include <simgear/scene/material/matlib.hxx>
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 *sgMakeDirectionalLight( sgVec3 pt, sgVec3 dir, sgVec3 up,
51 const SGMaterial *mat ) {
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 );
121 leaf->setState( mat->get_state() );
123 SG_LOG( SG_TERRAIN, SG_ALERT, "Warning: mat = NULL" );
130 static void calc_center_point( const point_list &nodes,
131 const int_list &pnt_i,
134 sgSetVec3( pt, nodes[pnt_i[0]][0], nodes[pnt_i[0]][1], nodes[pnt_i[0]][2] );
143 for ( unsigned int i = 0; i < pnt_i.size(); ++i ) {
144 sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
145 nodes[pnt_i[i]][2] );
146 if ( pt[0] < minx ) { minx = pt[0]; }
147 if ( pt[0] > maxx ) { minx = pt[0]; }
148 if ( pt[1] < miny ) { miny = pt[1]; }
149 if ( pt[1] > maxy ) { miny = pt[1]; }
150 if ( pt[2] < minz ) { minz = pt[2]; }
151 if ( pt[2] > maxz ) { minz = pt[2]; }
154 sgSetVec3( result, (minx + maxx) / 2.0, (miny + maxy) / 2.0,
155 (minz + maxz) / 2.0 );
159 static ssgTransform *gen_dir_light_group( const point_list &nodes,
160 const point_list &normals,
161 const int_list &pnt_i,
162 const int_list &nml_i,
163 const SGMaterial *mat,
164 sgVec3 up, bool vertical = false )
167 calc_center_point( nodes, pnt_i, center );
168 // cout << center[0] << "," << center[1] << "," << center[2] << endl;
171 // find a vector perpendicular to the normal.
174 // normal isn't vertical so we can use up as our first vector
175 sgNormalizeVec3( perp1, up );
177 // normal is vertical so we have to work a bit harder to
178 // determine our first vector
180 sgSetVec3( pt1, nodes[pnt_i[0]][0], nodes[pnt_i[0]][1],
181 nodes[pnt_i[0]][2] );
182 sgSetVec3( pt2, nodes[pnt_i[1]][0], nodes[pnt_i[1]][1],
183 nodes[pnt_i[1]][2] );
185 sgSubVec3( perp1, pt2, pt1 );
186 sgNormalizeVec3( perp1 );
189 ssgVertexArray *vl = new ssgVertexArray( 3 * pnt_i.size() );
190 ssgNormalArray *nl = new ssgNormalArray( 3 * pnt_i.size() );
191 ssgColourArray *cl = new ssgColourArray( 3 * pnt_i.size() );
195 for ( i = 0; i < pnt_i.size(); ++i ) {
196 sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
197 nodes[pnt_i[i]][2] );
198 sgSubVec3( pt, center );
199 sgSetVec3( normal, normals[nml_i[i]][0], normals[nml_i[i]][1],
200 normals[nml_i[i]][2] );
202 // calculate a vector perpendicular to dir and up
204 sgVectorProductVec3( perp2, normal, perp1 );
208 sgCopyVec3( tmp3, pt );
210 sgAddVec3( tmp3, perp1 );
212 sgAddVec3( tmp3, perp2 );
214 // sgSubVec3( tmp3, perp1 );
220 // nl->add( normal );
223 sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
225 sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
232 new ssgVtxTable ( GL_TRIANGLES, vl, nl, NULL, cl );
235 leaf->setState( mat->get_state() );
237 SG_LOG( SG_TERRAIN, SG_ALERT, "Warning: material = NULL" );
240 // put an LOD on each lighting component
241 ssgRangeSelector *lod = new ssgRangeSelector;
242 lod->setRange( 0, SG_ZERO );
243 lod->setRange( 1, 20000 );
246 // create the transformation.
248 sgSetCoord( &coord, center[0], center[1], center[2], 0.0, 0.0, 0.0 );
249 ssgTransform *trans = new ssgTransform;
250 trans->setTransform( &coord );
251 trans->addKid( lod );
257 static ssgTransform *gen_reil_lights( const point_list &nodes,
258 const point_list &normals,
259 const int_list &pnt_i,
260 const int_list &nml_i,
261 SGMaterialLib *matlib,
265 calc_center_point( nodes, pnt_i, center );
266 // cout << center[0] << "," << center[1] << "," << center[2] << endl;
269 sgNormalizeVec3( nup, up );
271 ssgVertexArray *vl = new ssgVertexArray( 3 * pnt_i.size() );
272 ssgNormalArray *nl = new ssgNormalArray( 3 * pnt_i.size() );
273 ssgColourArray *cl = new ssgColourArray( 3 * pnt_i.size() );
277 for ( i = 0; i < pnt_i.size(); ++i ) {
278 sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
279 nodes[pnt_i[i]][2] );
280 sgSubVec3( pt, center );
281 sgSetVec3( normal, normals[nml_i[i]][0], normals[nml_i[i]][1],
282 normals[nml_i[i]][2] );
284 // calculate a vector perpendicular to dir and up
286 sgVectorProductVec3( perp, normal, nup );
290 sgCopyVec3( tmp3, pt );
292 sgAddVec3( tmp3, nup );
294 sgAddVec3( tmp3, perp );
296 // sgSubVec3( tmp3, nup );
302 // nl->add( normal );
305 sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
307 sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
314 new ssgVtxTable ( GL_TRIANGLES, vl, nl, NULL, cl );
316 SGMaterial *mat = matlib->find( "RWY_WHITE_LIGHTS" );
319 leaf->setState( mat->get_state() );
321 SG_LOG( SG_TERRAIN, SG_ALERT,
322 "Warning: can't find material = RWY_WHITE_LIGHTS" );
325 leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw );
326 leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw );
328 ssgTimedSelector *reil = new ssgTimedSelector;
330 // need to add this twice to work around an ssg bug
331 reil->addKid( leaf );
332 reil->addKid( leaf );
334 reil->setDuration( 60 );
335 reil->setLimits( 0, 2 );
336 reil->setMode( SSG_ANIM_SHUTTLE );
337 reil->control( SSG_ANIM_START );
339 // put an LOD on each lighting component
340 ssgRangeSelector *lod = new ssgRangeSelector;
341 lod->setRange( 0, SG_ZERO );
342 lod->setRange( 1, 12000 );
345 // create the transformation.
347 sgSetCoord( &coord, center[0], center[1], center[2], 0.0, 0.0, 0.0 );
348 ssgTransform *trans = new ssgTransform;
349 trans->setTransform( &coord );
350 trans->addKid( lod );
356 static ssgTransform *gen_odals_lights( const point_list &nodes,
357 const point_list &normals,
358 const int_list &pnt_i,
359 const int_list &nml_i,
360 SGMaterialLib *matlib,
364 calc_center_point( nodes, pnt_i, center );
365 // cout << center[0] << "," << center[1] << "," << center[2] << endl;
367 ssgTimedSelector *odals = new ssgTimedSelector;
370 sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
372 // we don't want directional lights here
373 SGMaterial *mat = matlib->find( "GROUND_LIGHTS" );
375 SG_LOG( SG_TERRAIN, SG_ALERT,
376 "Warning: can't material = GROUND_LIGHTS" );
379 // center line strobes
382 for ( i = (int)pnt_i.size() - 1; i >= 2; --i ) {
383 ssgVertexArray *vl = new ssgVertexArray( 1 );
384 ssgColourArray *cl = new ssgColourArray( 1 );
386 sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
387 nodes[pnt_i[i]][2] );
388 sgSubVec3( pt, center );
394 new ssgVtxTable ( GL_POINTS, vl, NULL, NULL, cl );
396 leaf->setState( mat->get_state() );
397 leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw );
398 leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw );
400 odals->addKid( leaf );
403 // runway end strobes
404 ssgVertexArray *vl = new ssgVertexArray( 2 );
405 ssgColourArray *cl = new ssgColourArray( 2 );
407 sgSetVec3( pt, nodes[pnt_i[0]][0], nodes[pnt_i[0]][1],
408 nodes[pnt_i[0]][2] );
409 sgSubVec3( pt, center );
413 sgSetVec3( pt, nodes[pnt_i[1]][0], nodes[pnt_i[1]][1],
414 nodes[pnt_i[1]][2] );
415 sgSubVec3( pt, center );
420 new ssgVtxTable ( GL_POINTS, vl, NULL, NULL, cl );
422 leaf->setState( mat->get_state() );
423 leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw );
424 leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw );
426 odals->addKid( leaf );
430 odals->setDuration( 10 );
431 odals->setLimits( 0, pnt_i.size() - 1 );
432 odals->setMode( SSG_ANIM_SHUTTLE );
433 odals->control( SSG_ANIM_START );
435 // put an LOD on each lighting component
436 ssgRangeSelector *lod = new ssgRangeSelector;
437 lod->setRange( 0, SG_ZERO );
438 lod->setRange( 1, 12000 );
439 lod->addKid( odals );
441 // create the transformation.
443 sgSetCoord( &coord, center[0], center[1], center[2], 0.0, 0.0, 0.0 );
444 ssgTransform *trans = new ssgTransform;
445 trans->setTransform( &coord );
446 trans->addKid( lod );
452 static ssgTransform *gen_rabbit_lights( const point_list &nodes,
453 const point_list &normals,
454 const int_list &pnt_i,
455 const int_list &nml_i,
456 SGMaterialLib *matlib,
460 calc_center_point( nodes, pnt_i, center );
461 // cout << center[0] << "," << center[1] << "," << center[2] << endl;
464 sgNormalizeVec3( nup, up );
466 ssgTimedSelector *rabbit = new ssgTimedSelector;
468 SGMaterial *mat = matlib->find( "RWY_WHITE_LIGHTS" );
470 SG_LOG( SG_TERRAIN, SG_ALERT,
471 "Warning: can't material = RWY_WHITE_LIGHTS" );
476 for ( i = (int)pnt_i.size() - 1; i >= 0; --i ) {
477 ssgVertexArray *vl = new ssgVertexArray( 3 );
478 ssgNormalArray *nl = new ssgNormalArray( 3 );
479 ssgColourArray *cl = new ssgColourArray( 3 );
481 sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
482 nodes[pnt_i[i]][2] );
483 sgSubVec3( pt, center );
485 sgSetVec3( normal, normals[nml_i[i]][0], normals[nml_i[i]][1],
486 normals[nml_i[i]][2] );
488 // calculate a vector perpendicular to dir and up
490 sgVectorProductVec3( perp, normal, nup );
494 sgCopyVec3( tmp3, pt );
496 sgAddVec3( tmp3, nup );
498 sgAddVec3( tmp3, perp );
500 // sgSubVec3( tmp3, nup );
506 // nl->add( normal );
509 sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
511 sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
517 new ssgVtxTable ( GL_TRIANGLES, vl, nl, NULL, cl );
519 leaf->setState( mat->get_state() );
520 leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw );
521 leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw );
523 rabbit->addKid( leaf );
526 rabbit->setDuration( 10 );
527 rabbit->setLimits( 0, pnt_i.size() - 1 );
528 rabbit->setMode( SSG_ANIM_SHUTTLE );
529 rabbit->control( SSG_ANIM_START );
531 // put an LOD on each lighting component
532 ssgRangeSelector *lod = new ssgRangeSelector;
533 lod->setRange( 0, SG_ZERO );
534 lod->setRange( 1, 12000 );
535 lod->addKid( rabbit );
537 // create the transformation.
539 sgSetCoord( &coord, center[0], center[1], center[2], 0.0, 0.0, 0.0 );
540 ssgTransform *trans = new ssgTransform;
541 trans->setTransform( &coord );
542 trans->addKid( lod );
548 #if 0 // debugging infrastructure
549 // Generate a normal line
550 static ssgLeaf *gen_normal_line( SGMaterialLib *matlib,
551 sgVec3 pt, sgVec3 dir, sgVec3 up ) {
553 ssgVertexArray *vl = new ssgVertexArray( 3 );
554 ssgColourArray *cl = new ssgColourArray( 3 );
557 sgCopyVec3( tmp3, pt );
559 sgAddVec3( tmp3, dir );
563 sgSetVec4( color, 1.0, 0.0, 0.0, 1.0 );
568 new ssgVtxTable ( GL_LINES, vl, NULL, NULL, cl );
570 SGMaterial *mat = matlib->find( "GROUND_LIGHTS" );
571 leaf->setState( mat->get_state() );
578 ssgBranch *sgMakeDirectionalLights( const point_list &nodes,
579 const point_list &normals,
580 const int_list &pnt_i,
581 const int_list &nml_i,
582 SGMaterialLib *matlib,
583 const string &material,
587 sgNormalizeVec3( nup, up );
589 SGMaterial *mat = matlib->find( material );
591 if ( material == "RWY_REIL_LIGHTS" ) {
592 // cout << "found a reil" << endl;
593 ssgTransform *reil = gen_reil_lights( nodes, normals, pnt_i, nml_i,
596 } else if ( material == "RWY_ODALS_LIGHTS" ) {
597 // cout << "found a odals" << endl;
598 ssgTransform *odals = gen_odals_lights( nodes, normals, pnt_i, nml_i,
601 } else if ( material == "RWY_SEQUENCED_LIGHTS" ) {
602 // cout << "found a rabbit" << endl;
603 ssgTransform *rabbit = gen_rabbit_lights( nodes, normals,
607 } else if ( material == "RWY_BLUE_TAXIWAY_LIGHTS" ) {
608 ssgTransform *light_group = gen_dir_light_group( nodes, normals, pnt_i,
613 ssgTransform *light_group = gen_dir_light_group( nodes, normals, pnt_i,