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