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