]> git.mxchange.org Git - simgear.git/blob - simgear/scene/tgdb/pt_lights.cxx
Smarter vasi coloring.
[simgear.git] / simgear / scene / tgdb / pt_lights.cxx
1 // pt_lights.cxx -- build a 'directional' light on the fly
2 //
3 // Written by Curtis Olson, started March 2002.
4 //
5 // Copyright (C) 2002  Curtis L. Olson  - curt@flightgear.org
6 //
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.
11 //
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.
16 //
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.
20 //
21 // $Id$
22
23
24 #include <plib/sg.h>
25
26 #include <simgear/scene/material/mat.hxx>
27 #include <simgear/scene/material/matlib.hxx>
28
29 #include "vasi.hxx"
30
31 #include "pt_lights.hxx"
32
33
34 // strobe pre-draw (we want a larger point size)
35 static int StrobePreDraw( ssgEntity *e ) {
36     glPushAttrib( GL_POINT_BIT );
37     glPointSize(3.0);
38     glEnable(GL_POINT_SMOOTH);
39
40     return true;
41 }
42
43 // strobe post-draw (we want a larger point size)
44 static int StrobePostDraw( ssgEntity *e ) {
45     glPopAttrib();
46
47     return true;
48 }
49
50
51 // Generate a directional light
52 ssgLeaf *sgMakeDirectionalLight( sgVec3 pt, sgVec3 dir, sgVec3 up, 
53                                  const SGMaterial *mat ) {
54
55     // calculate a vector perpendicular to dir and up
56     sgVec3 perp;
57     sgVectorProductVec3( perp, dir, up );
58
59     ssgVertexArray   *vl = new ssgVertexArray( 3 );
60     ssgNormalArray   *nl = new ssgNormalArray( 3 );
61     ssgColourArray   *cl = new ssgColourArray( 3 );
62
63     // front face
64     sgVec3 tmp3;
65     sgCopyVec3( tmp3, pt );
66     vl->add( tmp3 );
67     sgAddVec3( tmp3, up );
68     vl->add( tmp3 );
69     sgAddVec3( tmp3, perp );
70     vl->add( tmp3 );
71     // sgSubVec3( tmp3, up );
72     // vl->add( tmp3 );
73
74     nl->add( dir );
75     nl->add( dir );
76     nl->add( dir );
77     // nl->add( dir );
78
79     sgVec4 color;
80     sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
81     cl->add( color );
82     sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
83     cl->add( color );
84     cl->add( color );
85     // cl->add( color );
86
87     /*
88     // temporarily do back face
89     sgCopyVec3( tmp3, pt );
90     vl->add( tmp3 );
91     sgAddVec3( tmp3, up );
92     vl->add( tmp3 );
93     sgAddVec3( tmp3, perp );
94     vl->add( tmp3 );
95
96     sgNegateVec3( dir );
97     nl->add( dir );
98     nl->add( dir );
99     nl->add( dir );
100
101     sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
102     cl->add( color );
103     sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
104     cl->add( color );
105     cl->add( color );
106     */
107
108     /* ssgTexCoordArray *tl = new ssgTexCoordArray( 4 );
109     sgVec2 tmp2;
110     sgSetVec2( tmp2, 0.0, 0.0 );
111     tl->add( tmp2 );
112     sgSetVec2( tmp2, 1.0, 0.0 );
113     tl->add( tmp2 );
114     sgSetVec2( tmp2, 1.0, 1.0 );
115     tl->add( tmp2 );
116     sgSetVec2( tmp2, 0.0, 1.0 );
117     tl->add( tmp2 ); */
118
119     ssgLeaf *leaf = 
120         new ssgVtxTable ( GL_TRIANGLES, vl, nl, NULL, cl );
121
122     if ( mat != NULL ) {
123         leaf->setState( mat->get_state() );
124     } else {
125         SG_LOG( SG_TERRAIN, SG_ALERT, "Warning: mat = NULL" );
126     }
127
128     return leaf;
129 }
130
131
132 static void calc_center_point( const point_list &nodes,
133                                const int_list &pnt_i,
134                                sgVec3 result ) {
135     sgVec3 pt;
136     sgSetVec3( pt, nodes[pnt_i[0]][0], nodes[pnt_i[0]][1], nodes[pnt_i[0]][2] );
137
138     double minx = pt[0];
139     double maxx = pt[0];
140     double miny = pt[1];
141     double maxy = pt[1];
142     double minz = pt[2];
143     double maxz = pt[2];
144
145     for ( unsigned int i = 0; i < pnt_i.size(); ++i ) {
146         sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
147                    nodes[pnt_i[i]][2] );
148         if ( pt[0] < minx ) { minx = pt[0]; }
149         if ( pt[0] > maxx ) { minx = pt[0]; }
150         if ( pt[1] < miny ) { miny = pt[1]; }
151         if ( pt[1] > maxy ) { miny = pt[1]; }
152         if ( pt[2] < minz ) { minz = pt[2]; }
153         if ( pt[2] > maxz ) { minz = pt[2]; }
154     }
155
156     sgSetVec3( result, (minx + maxx) / 2.0, (miny + maxy) / 2.0,
157                (minz + maxz) / 2.0 );
158 }
159
160
161 static ssgTransform *gen_dir_light_group( const point_list &nodes,
162                                           const point_list &normals,
163                                           const int_list &pnt_i,
164                                           const int_list &nml_i,
165                                           const SGMaterial *mat,
166                                           sgVec3 up, bool vertical )
167 {
168     sgVec3 center;
169     calc_center_point( nodes, pnt_i, center );
170     // cout << center[0] << "," << center[1] << "," << center[2] << endl;
171
172
173     // find a vector perpendicular to the normal.
174     sgVec3 perp1;
175     if ( !vertical ) {
176         // normal isn't vertical so we can use up as our first vector
177         sgNormalizeVec3( perp1, up );
178     } else {
179         // normal is vertical so we have to work a bit harder to
180         // determine our first vector
181         sgVec3 pt1, pt2;
182         sgSetVec3( pt1, nodes[pnt_i[0]][0], nodes[pnt_i[0]][1],
183                    nodes[pnt_i[0]][2] );
184         sgSetVec3( pt2, nodes[pnt_i[1]][0], nodes[pnt_i[1]][1],
185                    nodes[pnt_i[1]][2] );
186
187         sgSubVec3( perp1, pt2, pt1 );
188         sgNormalizeVec3( perp1 );
189     }
190
191     ssgVertexArray *vl = new ssgVertexArray( 3 * pnt_i.size() );
192     ssgNormalArray *nl = new ssgNormalArray( 3 * pnt_i.size() );
193     ssgColourArray *cl = new ssgColourArray( 3 * pnt_i.size() );
194
195     unsigned int i;
196     sgVec3 pt, normal;
197     for ( i = 0; i < pnt_i.size(); ++i ) {
198         sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
199                    nodes[pnt_i[i]][2] );
200         sgSubVec3( pt, center );
201         sgSetVec3( normal, normals[nml_i[i]][0], normals[nml_i[i]][1],
202                    normals[nml_i[i]][2] );
203
204         // calculate a vector perpendicular to dir and up
205         sgVec3 perp2;
206         sgVectorProductVec3( perp2, normal, perp1 );
207
208         // front face
209         sgVec3 tmp3;
210         sgCopyVec3( tmp3, pt );
211         vl->add( tmp3 );
212         sgAddVec3( tmp3, perp1 );
213         vl->add( tmp3 );
214         sgAddVec3( tmp3, perp2 );
215         vl->add( tmp3 );
216         // sgSubVec3( tmp3, perp1 );
217         // vl->add( tmp3 );
218
219         nl->add( normal );
220         nl->add( normal );
221         nl->add( normal );
222         // nl->add( normal );
223
224         sgVec4 color;
225         sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
226         cl->add( color );
227         sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
228         cl->add( color );
229         cl->add( color );
230         // cl->add( color );
231     }
232
233     ssgLeaf *leaf = 
234         new ssgVtxTable ( GL_TRIANGLES, vl, nl, NULL, cl );
235
236     if ( mat != NULL ) {
237         leaf->setState( mat->get_state() );
238     } else {
239         SG_LOG( SG_TERRAIN, SG_ALERT, "Warning: material = NULL" );
240     }
241
242     // put an LOD on each lighting component
243     ssgRangeSelector *lod = new ssgRangeSelector;
244     lod->setRange( 0, SG_ZERO );
245     lod->setRange( 1, 20000 );
246     lod->addKid( leaf );
247
248     // create the transformation.
249     sgCoord coord;
250     sgSetCoord( &coord, center[0], center[1], center[2], 0.0, 0.0, 0.0 );
251     ssgTransform *trans = new ssgTransform;
252     trans->setTransform( &coord );
253     trans->addKid( lod );
254
255     return trans;
256 }
257
258
259 static ssgTransform *gen_reil_lights( const point_list &nodes,
260                                       const point_list &normals,
261                                       const int_list &pnt_i,
262                                       const int_list &nml_i,
263                                       SGMaterialLib *matlib,
264                                       sgVec3 up )
265 {
266     sgVec3 center;
267     calc_center_point( nodes, pnt_i, center );
268     // cout << center[0] << "," << center[1] << "," << center[2] << endl;
269
270     sgVec3 nup;
271     sgNormalizeVec3( nup, up );
272
273     ssgVertexArray   *vl = new ssgVertexArray( 3 * pnt_i.size() );
274     ssgNormalArray   *nl = new ssgNormalArray( 3 * pnt_i.size() );
275     ssgColourArray   *cl = new ssgColourArray( 3 * pnt_i.size() );
276
277     unsigned int i;
278     sgVec3 pt, normal;
279     for ( i = 0; i < pnt_i.size(); ++i ) {
280         sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
281                    nodes[pnt_i[i]][2] );
282         sgSubVec3( pt, center );
283         sgSetVec3( normal, normals[nml_i[i]][0], normals[nml_i[i]][1],
284                    normals[nml_i[i]][2] );
285
286         // calculate a vector perpendicular to dir and up
287         sgVec3 perp;
288         sgVectorProductVec3( perp, normal, nup );
289
290         // front face
291         sgVec3 tmp3;
292         sgCopyVec3( tmp3, pt );
293         vl->add( tmp3 );
294         sgAddVec3( tmp3, nup );
295         vl->add( tmp3 );
296         sgAddVec3( tmp3, perp );
297         vl->add( tmp3 );
298         // sgSubVec3( tmp3, nup );
299         // vl->add( tmp3 );
300
301         nl->add( normal );
302         nl->add( normal );
303         nl->add( normal );
304         // nl->add( normal );
305
306         sgVec4 color;
307         sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
308         cl->add( color );
309         sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
310         cl->add( color );
311         cl->add( color );
312         // cl->add( color );
313     }
314
315     ssgLeaf *leaf = 
316         new ssgVtxTable ( GL_TRIANGLES, vl, nl, NULL, cl );
317
318     SGMaterial *mat = matlib->find( "RWY_WHITE_LIGHTS" );
319
320     if ( mat != NULL ) {
321         leaf->setState( mat->get_state() );
322     } else {
323         SG_LOG( SG_TERRAIN, SG_ALERT,
324                 "Warning: can't find material = RWY_WHITE_LIGHTS" );
325     }
326
327     leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw );
328     leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw );
329
330     ssgTimedSelector *reil = new ssgTimedSelector;
331
332     // need to add this twice to work around an ssg bug
333     reil->addKid( leaf );
334     reil->addKid( leaf );
335
336     reil->setDuration( 60 );
337     reil->setLimits( 0, 2 );
338     reil->setMode( SSG_ANIM_SHUTTLE );
339     reil->control( SSG_ANIM_START );
340    
341     // put an LOD on each lighting component
342     ssgRangeSelector *lod = new ssgRangeSelector;
343     lod->setRange( 0, SG_ZERO );
344     lod->setRange( 1, 12000 );
345     lod->addKid( reil );
346
347     // create the transformation.
348     sgCoord coord;
349     sgSetCoord( &coord, center[0], center[1], center[2], 0.0, 0.0, 0.0 );
350     ssgTransform *trans = new ssgTransform;
351     trans->setTransform( &coord );
352     trans->addKid( lod );
353
354     return trans;
355 }
356
357
358 static ssgTransform *gen_odals_lights( const point_list &nodes,
359                                        const point_list &normals,
360                                        const int_list &pnt_i,
361                                        const int_list &nml_i,
362                                        SGMaterialLib *matlib,
363                                        sgVec3 up )
364 {
365     sgVec3 center;
366     calc_center_point( nodes, pnt_i, center );
367     // cout << center[0] << "," << center[1] << "," << center[2] << endl;
368
369     ssgTimedSelector *odals = new ssgTimedSelector;
370
371     sgVec4 color;
372     sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
373
374     // we don't want directional lights here
375     SGMaterial *mat = matlib->find( "GROUND_LIGHTS" );
376     if ( mat == NULL ) {
377         SG_LOG( SG_TERRAIN, SG_ALERT,
378                 "Warning: can't material = GROUND_LIGHTS" );
379     }
380
381     // center line strobes
382     int i;
383     sgVec3 pt;
384     for ( i = (int)pnt_i.size() - 1; i >= 2; --i ) {
385         ssgVertexArray   *vl = new ssgVertexArray( 1 );
386         ssgColourArray   *cl = new ssgColourArray( 1 );
387      
388         sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
389                    nodes[pnt_i[i]][2] );
390         sgSubVec3( pt, center );
391         vl->add( pt );
392
393         cl->add( color );
394
395         ssgLeaf *leaf = 
396             new ssgVtxTable ( GL_POINTS, vl, NULL, NULL, cl );
397
398         leaf->setState( mat->get_state() );
399         leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw );
400         leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw );
401
402         odals->addKid( leaf );
403     }
404
405     // runway end strobes
406     ssgVertexArray   *vl = new ssgVertexArray( 2 );
407     ssgColourArray   *cl = new ssgColourArray( 2 );
408      
409     sgSetVec3( pt, nodes[pnt_i[0]][0], nodes[pnt_i[0]][1],
410                nodes[pnt_i[0]][2] );
411     sgSubVec3( pt, center );
412     vl->add( pt );
413     cl->add( color );
414
415     sgSetVec3( pt, nodes[pnt_i[1]][0], nodes[pnt_i[1]][1],
416                nodes[pnt_i[1]][2] );
417     sgSubVec3( pt, center );
418     vl->add( pt );
419     cl->add( color );
420
421     ssgLeaf *leaf = 
422         new ssgVtxTable ( GL_POINTS, vl, NULL, NULL, cl );
423
424     leaf->setState( mat->get_state() );
425     leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw );
426     leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw );
427
428     odals->addKid( leaf );
429
430     // setup animition
431
432     odals->setDuration( 10 );
433     odals->setLimits( 0, pnt_i.size() - 1 );
434     odals->setMode( SSG_ANIM_SHUTTLE );
435     odals->control( SSG_ANIM_START );
436    
437     // put an LOD on each lighting component
438     ssgRangeSelector *lod = new ssgRangeSelector;
439     lod->setRange( 0, SG_ZERO );
440     lod->setRange( 1, 12000 );
441     lod->addKid( odals );
442
443     // create the transformation.
444     sgCoord coord;
445     sgSetCoord( &coord, center[0], center[1], center[2], 0.0, 0.0, 0.0 );
446     ssgTransform *trans = new ssgTransform;
447     trans->setTransform( &coord );
448     trans->addKid( lod );
449
450     return trans;
451 }
452
453
454 static ssgTransform *gen_rabbit_lights( const point_list &nodes,
455                                         const point_list &normals,
456                                         const int_list &pnt_i,
457                                         const int_list &nml_i,
458                                         SGMaterialLib *matlib,
459                                         sgVec3 up )
460 {
461     sgVec3 center;
462     calc_center_point( nodes, pnt_i, center );
463     // cout << center[0] << "," << center[1] << "," << center[2] << endl;
464
465     sgVec3 nup;
466     sgNormalizeVec3( nup, up );
467
468     ssgTimedSelector *rabbit = new ssgTimedSelector;
469
470     SGMaterial *mat = matlib->find( "RWY_WHITE_LIGHTS" );
471     if ( mat == NULL ) {
472         SG_LOG( SG_TERRAIN, SG_ALERT,
473                 "Warning: can't material = RWY_WHITE_LIGHTS" );
474     }
475
476     int i;
477     sgVec3 pt, normal;
478     for ( i = (int)pnt_i.size() - 1; i >= 0; --i ) {
479         ssgVertexArray   *vl = new ssgVertexArray( 3 );
480         ssgNormalArray   *nl = new ssgNormalArray( 3 );
481         ssgColourArray   *cl = new ssgColourArray( 3 );
482      
483         sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
484                    nodes[pnt_i[i]][2] );
485         sgSubVec3( pt, center );
486
487         sgSetVec3( normal, normals[nml_i[i]][0], normals[nml_i[i]][1],
488                    normals[nml_i[i]][2] );
489
490         // calculate a vector perpendicular to dir and up
491         sgVec3 perp;
492         sgVectorProductVec3( perp, normal, nup );
493
494         // front face
495         sgVec3 tmp3;
496         sgCopyVec3( tmp3, pt );
497         vl->add( tmp3 );
498         sgAddVec3( tmp3, nup );
499         vl->add( tmp3 );
500         sgAddVec3( tmp3, perp );
501         vl->add( tmp3 );
502         // sgSubVec3( tmp3, nup );
503         // vl->add( tmp3 );
504
505         nl->add( normal );
506         nl->add( normal );
507         nl->add( normal );
508         // nl->add( normal );
509
510         sgVec4 color;
511         sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
512         cl->add( color );
513         sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
514         cl->add( color );
515         cl->add( color );
516         // cl->add( color );
517
518         ssgLeaf *leaf = 
519             new ssgVtxTable ( GL_TRIANGLES, vl, nl, NULL, cl );
520
521         leaf->setState( mat->get_state() );
522         leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw );
523         leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw );
524
525         rabbit->addKid( leaf );
526     }
527
528     rabbit->setDuration( 10 );
529     rabbit->setLimits( 0, pnt_i.size() - 1 );
530     rabbit->setMode( SSG_ANIM_SHUTTLE );
531     rabbit->control( SSG_ANIM_START );
532    
533     // put an LOD on each lighting component
534     ssgRangeSelector *lod = new ssgRangeSelector;
535     lod->setRange( 0, SG_ZERO );
536     lod->setRange( 1, 12000 );
537     lod->addKid( rabbit );
538
539     // create the transformation.
540     sgCoord coord;
541     sgSetCoord( &coord, center[0], center[1], center[2], 0.0, 0.0, 0.0 );
542     ssgTransform *trans = new ssgTransform;
543     trans->setTransform( &coord );
544     trans->addKid( lod );
545
546     return trans;
547 }
548
549
550 #if 0 // debugging infrastructure
551 // Generate a normal line 
552 static ssgLeaf *gen_normal_line( SGMaterialLib *matlib,
553                                  sgVec3 pt, sgVec3 dir, sgVec3 up )
554 {
555
556     ssgVertexArray *vl = new ssgVertexArray( 3 );
557     ssgColourArray *cl = new ssgColourArray( 3 );
558
559     sgVec3 tmp3;
560     sgCopyVec3( tmp3, pt );
561     vl->add( tmp3 );
562     sgAddVec3( tmp3, dir );
563     vl->add( tmp3 );
564
565     sgVec4 color;
566     sgSetVec4( color, 1.0, 0.0, 0.0, 1.0 );
567     cl->add( color );
568     cl->add( color );
569
570     ssgLeaf *leaf = 
571         new ssgVtxTable ( GL_LINES, vl, NULL, NULL, cl );
572
573     SGMaterial *mat = matlib->find( "GROUND_LIGHTS" );
574     leaf->setState( mat->get_state() );
575
576     return leaf;
577 }
578 #endif
579
580
581 ssgBranch *sgMakeDirectionalLights( const point_list &nodes,
582                                     const point_list &normals,
583                                     const int_list &pnt_i,
584                                     const int_list &nml_i,
585                                     SGMaterialLib *matlib,
586                                     const string &material,
587                                     sgdVec3 dup )
588 {
589     sgVec3 up;
590     sgSetVec3( up, dup );
591
592     sgVec3 nup;
593     sgNormalizeVec3( nup, up );
594
595     SGMaterial *mat = matlib->find( material );
596
597     if ( material == "RWY_REIL_LIGHTS" ) {
598         // cout << "found a reil" << endl;
599         ssgTransform *reil = gen_reil_lights( nodes, normals, pnt_i, nml_i,
600                                               matlib, up );
601         return reil;
602     } else if ( material == "RWY_ODALS_LIGHTS" ) {
603         // cout << "found a odals" << endl;
604         ssgTransform *odals = gen_odals_lights( nodes, normals, pnt_i, nml_i,
605                                                 matlib, up );
606         return odals;
607     } else if ( material == "RWY_SEQUENCED_LIGHTS" ) {
608         // cout << "found a rabbit" << endl;
609         ssgTransform *rabbit = gen_rabbit_lights( nodes, normals,
610                                                   pnt_i, nml_i,
611                                                   matlib, up );
612         return rabbit;
613     } else if ( material == "RWY_VASI_LIGHTS" ) {
614         ssgTransform *light_group = gen_dir_light_group( nodes, normals, pnt_i,
615                                                          nml_i, mat, up,
616                                                          false );
617
618         // calculate the geocentric position of this vasi and use it
619         // to init the vasi structure and save it in the userdata slot
620         sgdVec3 pos;
621         sgdSetVec3( pos, nodes[pnt_i[0]][0], nodes[pnt_i[0]][1],
622                     nodes[pnt_i[0]][2] );
623         // dup is the double version of the "up" vector which is also
624         // the reference center point of this tile.  The reference
625         // center + the coordinate of the first light gives the actual
626         // location of the first light.
627         sgdAddVec3( pos, dup );
628
629         // extract a pointer to the leaf node so a) we can set the
630         // phat light call back and b) we can pass this to the vasi
631         // structure.
632         ssgRangeSelector *lod = (ssgRangeSelector *)light_group->getKid(0);
633         ssgLeaf *leaf = (ssgLeaf *)lod->getKid(0);
634         // leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw );
635         // leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw );
636
637         SGVASIUserData *vasi = new SGVASIUserData( pos, leaf );
638
639         light_group->setUserData( vasi );
640
641         return light_group;
642     } else if ( material == "RWY_BLUE_TAXIWAY_LIGHTS" ) {
643         ssgTransform *light_group = gen_dir_light_group( nodes, normals, pnt_i,
644                                                          nml_i, mat, up,
645                                                          true );
646         return light_group;
647     } else {
648         ssgTransform *light_group = gen_dir_light_group( nodes, normals, pnt_i,
649                                                          nml_i, mat, up,
650                                                          false );
651         return light_group;
652     }
653
654     return NULL;
655 }