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