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