]> git.mxchange.org Git - simgear.git/blob - simgear/scene/tgdb/pt_lights.cxx
Just a bit of renaming.
[simgear.git] / simgear / scene / tgdb / pt_lights.cxx
1 // pt_lights.cxx -- build a 'directional' light on the fly
2 //
3 // Written by Curtis Olson, started March 2002.
4 //
5 // Copyright (C) 2002  Curtis L. Olson  - curt@flightgear.org
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 // $Id$
22
23
24 #include <plib/sg.h>
25
26 #include <simgear/scene/material/mat.hxx>
27 #include <simgear/scene/material/matlib.hxx>
28
29 #include "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 *sgMakeDirectionalLight( sgVec3 pt, sgVec3 dir, sgVec3 up, 
51                                  const SGMaterial *mat ) {
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     if ( mat != NULL ) {
121         leaf->setState( mat->get_state() );
122     } else {
123         SG_LOG( SG_TERRAIN, SG_ALERT, "Warning: mat = NULL" );
124     }
125
126     return leaf;
127 }
128
129
130 static void calc_center_point( const point_list &nodes,
131                                const int_list &pnt_i,
132                                sgVec3 result ) {
133     sgVec3 pt;
134     sgSetVec3( pt, nodes[pnt_i[0]][0], nodes[pnt_i[0]][1], nodes[pnt_i[0]][2] );
135
136     double minx = pt[0];
137     double maxx = pt[0];
138     double miny = pt[1];
139     double maxy = pt[1];
140     double minz = pt[2];
141     double maxz = pt[2];
142
143     for ( unsigned int i = 0; i < pnt_i.size(); ++i ) {
144         sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
145                    nodes[pnt_i[i]][2] );
146         if ( pt[0] < minx ) { minx = pt[0]; }
147         if ( pt[0] > maxx ) { minx = pt[0]; }
148         if ( pt[1] < miny ) { miny = pt[1]; }
149         if ( pt[1] > maxy ) { miny = pt[1]; }
150         if ( pt[2] < minz ) { minz = pt[2]; }
151         if ( pt[2] > maxz ) { minz = pt[2]; }
152     }
153
154     sgSetVec3( result, (minx + maxx) / 2.0, (miny + maxy) / 2.0,
155                (minz + maxz) / 2.0 );
156 }
157
158
159 static ssgTransform *gen_dir_light_group( const point_list &nodes,
160                                           const point_list &normals,
161                                           const int_list &pnt_i,
162                                           const int_list &nml_i,
163                                           const SGMaterial *mat,
164                                           sgVec3 up, bool vertical = false )
165 {
166     sgVec3 center;
167     calc_center_point( nodes, pnt_i, center );
168     // cout << center[0] << "," << center[1] << "," << center[2] << endl;
169
170
171     // find a vector perpendicular to the normal.
172     sgVec3 perp1;
173     if ( !vertical ) {
174         // normal isn't vertical so we can use up as our first vector
175         sgNormalizeVec3( perp1, up );
176     } else {
177         // normal is vertical so we have to work a bit harder to
178         // determine our first vector
179         sgVec3 pt1, pt2;
180         sgSetVec3( pt1, nodes[pnt_i[0]][0], nodes[pnt_i[0]][1],
181                    nodes[pnt_i[0]][2] );
182         sgSetVec3( pt2, nodes[pnt_i[1]][0], nodes[pnt_i[1]][1],
183                    nodes[pnt_i[1]][2] );
184
185         sgSubVec3( perp1, pt2, pt1 );
186         sgNormalizeVec3( perp1 );
187     }
188
189     ssgVertexArray *vl = new ssgVertexArray( 3 * pnt_i.size() );
190     ssgNormalArray *nl = new ssgNormalArray( 3 * pnt_i.size() );
191     ssgColourArray *cl = new ssgColourArray( 3 * pnt_i.size() );
192
193     unsigned int i;
194     sgVec3 pt, normal;
195     for ( i = 0; i < pnt_i.size(); ++i ) {
196         sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
197                    nodes[pnt_i[i]][2] );
198         sgSubVec3( pt, center );
199         sgSetVec3( normal, normals[nml_i[i]][0], normals[nml_i[i]][1],
200                    normals[nml_i[i]][2] );
201
202         // calculate a vector perpendicular to dir and up
203         sgVec3 perp2;
204         sgVectorProductVec3( perp2, normal, perp1 );
205
206         // front face
207         sgVec3 tmp3;
208         sgCopyVec3( tmp3, pt );
209         vl->add( tmp3 );
210         sgAddVec3( tmp3, perp1 );
211         vl->add( tmp3 );
212         sgAddVec3( tmp3, perp2 );
213         vl->add( tmp3 );
214         // sgSubVec3( tmp3, perp1 );
215         // vl->add( tmp3 );
216
217         nl->add( normal );
218         nl->add( normal );
219         nl->add( normal );
220         // nl->add( normal );
221
222         sgVec4 color;
223         sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
224         cl->add( color );
225         sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
226         cl->add( color );
227         cl->add( color );
228         // cl->add( color );
229     }
230
231     ssgLeaf *leaf = 
232         new ssgVtxTable ( GL_TRIANGLES, vl, nl, NULL, cl );
233
234     if ( mat != NULL ) {
235         leaf->setState( mat->get_state() );
236     } else {
237         SG_LOG( SG_TERRAIN, SG_ALERT, "Warning: material = NULL" );
238     }
239
240     // put an LOD on each lighting component
241     ssgRangeSelector *lod = new ssgRangeSelector;
242     lod->setRange( 0, SG_ZERO );
243     lod->setRange( 1, 20000 );
244     lod->addKid( leaf );
245
246     // create the transformation.
247     sgCoord coord;
248     sgSetCoord( &coord, center[0], center[1], center[2], 0.0, 0.0, 0.0 );
249     ssgTransform *trans = new ssgTransform;
250     trans->setTransform( &coord );
251     trans->addKid( lod );
252
253     return trans;
254 }
255
256
257 static ssgTransform *gen_reil_lights( const point_list &nodes,
258                                       const point_list &normals,
259                                       const int_list &pnt_i,
260                                       const int_list &nml_i,
261                                       SGMaterialLib *matlib,
262                                       sgVec3 up )
263 {
264     sgVec3 center;
265     calc_center_point( nodes, pnt_i, center );
266     // cout << center[0] << "," << center[1] << "," << center[2] << endl;
267
268     sgVec3 nup;
269     sgNormalizeVec3( nup, up );
270
271     ssgVertexArray   *vl = new ssgVertexArray( 3 * pnt_i.size() );
272     ssgNormalArray   *nl = new ssgNormalArray( 3 * pnt_i.size() );
273     ssgColourArray   *cl = new ssgColourArray( 3 * pnt_i.size() );
274
275     unsigned int i;
276     sgVec3 pt, normal;
277     for ( i = 0; i < pnt_i.size(); ++i ) {
278         sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
279                    nodes[pnt_i[i]][2] );
280         sgSubVec3( pt, center );
281         sgSetVec3( normal, normals[nml_i[i]][0], normals[nml_i[i]][1],
282                    normals[nml_i[i]][2] );
283
284         // calculate a vector perpendicular to dir and up
285         sgVec3 perp;
286         sgVectorProductVec3( perp, normal, nup );
287
288         // front face
289         sgVec3 tmp3;
290         sgCopyVec3( tmp3, pt );
291         vl->add( tmp3 );
292         sgAddVec3( tmp3, nup );
293         vl->add( tmp3 );
294         sgAddVec3( tmp3, perp );
295         vl->add( tmp3 );
296         // sgSubVec3( tmp3, nup );
297         // vl->add( tmp3 );
298
299         nl->add( normal );
300         nl->add( normal );
301         nl->add( normal );
302         // nl->add( normal );
303
304         sgVec4 color;
305         sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
306         cl->add( color );
307         sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
308         cl->add( color );
309         cl->add( color );
310         // cl->add( color );
311     }
312
313     ssgLeaf *leaf = 
314         new ssgVtxTable ( GL_TRIANGLES, vl, nl, NULL, cl );
315
316     SGMaterial *mat = matlib->find( "RWY_WHITE_LIGHTS" );
317
318     if ( mat != NULL ) {
319         leaf->setState( mat->get_state() );
320     } else {
321         SG_LOG( SG_TERRAIN, SG_ALERT,
322                 "Warning: can't find material = RWY_WHITE_LIGHTS" );
323     }
324
325     leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw );
326     leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw );
327
328     ssgTimedSelector *reil = new ssgTimedSelector;
329
330     // need to add this twice to work around an ssg bug
331     reil->addKid( leaf );
332     reil->addKid( leaf );
333
334     reil->setDuration( 60 );
335     reil->setLimits( 0, 2 );
336     reil->setMode( SSG_ANIM_SHUTTLE );
337     reil->control( SSG_ANIM_START );
338    
339     // put an LOD on each lighting component
340     ssgRangeSelector *lod = new ssgRangeSelector;
341     lod->setRange( 0, SG_ZERO );
342     lod->setRange( 1, 12000 );
343     lod->addKid( reil );
344
345     // create the transformation.
346     sgCoord coord;
347     sgSetCoord( &coord, center[0], center[1], center[2], 0.0, 0.0, 0.0 );
348     ssgTransform *trans = new ssgTransform;
349     trans->setTransform( &coord );
350     trans->addKid( lod );
351
352     return trans;
353 }
354
355
356 static ssgTransform *gen_odals_lights( const point_list &nodes,
357                                        const point_list &normals,
358                                        const int_list &pnt_i,
359                                        const int_list &nml_i,
360                                        SGMaterialLib *matlib,
361                                        sgVec3 up )
362 {
363     sgVec3 center;
364     calc_center_point( nodes, pnt_i, center );
365     // cout << center[0] << "," << center[1] << "," << center[2] << endl;
366
367     ssgTimedSelector *odals = new ssgTimedSelector;
368
369     sgVec4 color;
370     sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
371
372     // we don't want directional lights here
373     SGMaterial *mat = matlib->find( "GROUND_LIGHTS" );
374     if ( mat == NULL ) {
375         SG_LOG( SG_TERRAIN, SG_ALERT,
376                 "Warning: can't material = GROUND_LIGHTS" );
377     }
378
379     // center line strobes
380     int i;
381     sgVec3 pt;
382     for ( i = (int)pnt_i.size() - 1; i >= 2; --i ) {
383         ssgVertexArray   *vl = new ssgVertexArray( 1 );
384         ssgColourArray   *cl = new ssgColourArray( 1 );
385      
386         sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
387                    nodes[pnt_i[i]][2] );
388         sgSubVec3( pt, center );
389         vl->add( pt );
390
391         cl->add( color );
392
393         ssgLeaf *leaf = 
394             new ssgVtxTable ( GL_POINTS, vl, NULL, NULL, cl );
395
396         leaf->setState( mat->get_state() );
397         leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw );
398         leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw );
399
400         odals->addKid( leaf );
401     }
402
403     // runway end strobes
404     ssgVertexArray   *vl = new ssgVertexArray( 2 );
405     ssgColourArray   *cl = new ssgColourArray( 2 );
406      
407     sgSetVec3( pt, nodes[pnt_i[0]][0], nodes[pnt_i[0]][1],
408                nodes[pnt_i[0]][2] );
409     sgSubVec3( pt, center );
410     vl->add( pt );
411     cl->add( color );
412
413     sgSetVec3( pt, nodes[pnt_i[1]][0], nodes[pnt_i[1]][1],
414                nodes[pnt_i[1]][2] );
415     sgSubVec3( pt, center );
416     vl->add( pt );
417     cl->add( color );
418
419     ssgLeaf *leaf = 
420         new ssgVtxTable ( GL_POINTS, vl, NULL, NULL, cl );
421
422     leaf->setState( mat->get_state() );
423     leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw );
424     leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw );
425
426     odals->addKid( leaf );
427
428     // setup animition
429
430     odals->setDuration( 10 );
431     odals->setLimits( 0, pnt_i.size() - 1 );
432     odals->setMode( SSG_ANIM_SHUTTLE );
433     odals->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( odals );
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_rabbit_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     sgVec3 nup;
464     sgNormalizeVec3( nup, up );
465
466     ssgTimedSelector *rabbit = new ssgTimedSelector;
467
468     SGMaterial *mat = matlib->find( "RWY_WHITE_LIGHTS" );
469     if ( mat == NULL ) {
470         SG_LOG( SG_TERRAIN, SG_ALERT,
471                 "Warning: can't material = RWY_WHITE_LIGHTS" );
472     }
473
474     int i;
475     sgVec3 pt, normal;
476     for ( i = (int)pnt_i.size() - 1; i >= 0; --i ) {
477         ssgVertexArray   *vl = new ssgVertexArray( 3 );
478         ssgNormalArray   *nl = new ssgNormalArray( 3 );
479         ssgColourArray   *cl = new ssgColourArray( 3 );
480      
481         sgSetVec3( pt, nodes[pnt_i[i]][0], nodes[pnt_i[i]][1],
482                    nodes[pnt_i[i]][2] );
483         sgSubVec3( pt, center );
484
485         sgSetVec3( normal, normals[nml_i[i]][0], normals[nml_i[i]][1],
486                    normals[nml_i[i]][2] );
487
488         // calculate a vector perpendicular to dir and up
489         sgVec3 perp;
490         sgVectorProductVec3( perp, normal, nup );
491
492         // front face
493         sgVec3 tmp3;
494         sgCopyVec3( tmp3, pt );
495         vl->add( tmp3 );
496         sgAddVec3( tmp3, nup );
497         vl->add( tmp3 );
498         sgAddVec3( tmp3, perp );
499         vl->add( tmp3 );
500         // sgSubVec3( tmp3, nup );
501         // vl->add( tmp3 );
502
503         nl->add( normal );
504         nl->add( normal );
505         nl->add( normal );
506         // nl->add( normal );
507
508         sgVec4 color;
509         sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
510         cl->add( color );
511         sgSetVec4( color, 1.0, 1.0, 1.0, 0.0 );
512         cl->add( color );
513         cl->add( color );
514         // cl->add( color );
515
516         ssgLeaf *leaf = 
517             new ssgVtxTable ( GL_TRIANGLES, vl, nl, NULL, cl );
518
519         leaf->setState( mat->get_state() );
520         leaf->setCallback( SSG_CALLBACK_PREDRAW, StrobePreDraw );
521         leaf->setCallback( SSG_CALLBACK_POSTDRAW, StrobePostDraw );
522
523         rabbit->addKid( leaf );
524     }
525
526     rabbit->setDuration( 10 );
527     rabbit->setLimits( 0, pnt_i.size() - 1 );
528     rabbit->setMode( SSG_ANIM_SHUTTLE );
529     rabbit->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( rabbit );
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 #if 0 // debugging infrastructure
549 // Generate a normal line 
550 static ssgLeaf *gen_normal_line( SGMaterialLib *matlib,
551                                  sgVec3 pt, sgVec3 dir, sgVec3 up ) {
552
553     ssgVertexArray *vl = new ssgVertexArray( 3 );
554     ssgColourArray *cl = new ssgColourArray( 3 );
555
556     sgVec3 tmp3;
557     sgCopyVec3( tmp3, pt );
558     vl->add( tmp3 );
559     sgAddVec3( tmp3, dir );
560     vl->add( tmp3 );
561
562     sgVec4 color;
563     sgSetVec4( color, 1.0, 0.0, 0.0, 1.0 );
564     cl->add( color );
565     cl->add( color );
566
567     ssgLeaf *leaf = 
568         new ssgVtxTable ( GL_LINES, vl, NULL, NULL, cl );
569
570     SGMaterial *mat = matlib->find( "GROUND_LIGHTS" );
571     leaf->setState( mat->get_state() );
572
573     return leaf;
574 }
575 #endif
576
577
578 ssgBranch *sgMakeDirectionalLights( const point_list &nodes,
579                                     const point_list &normals,
580                                     const int_list &pnt_i,
581                                     const int_list &nml_i,
582                                     SGMaterialLib *matlib,
583                                     const string &material,
584                                     sgVec3 up )
585 {
586     sgVec3 nup;
587     sgNormalizeVec3( nup, up );
588
589     SGMaterial *mat = matlib->find( material );
590
591     if ( material == "RWY_REIL_LIGHTS" ) {
592         // cout << "found a reil" << endl;
593         ssgTransform *reil = gen_reil_lights( nodes, normals, pnt_i, nml_i,
594                                               matlib, up );
595         return reil;
596     } else if ( material == "RWY_ODALS_LIGHTS" ) {
597         // cout << "found a odals" << endl;
598         ssgTransform *odals = gen_odals_lights( nodes, normals, pnt_i, nml_i,
599                                                 matlib, up );
600         return odals;
601     } else if ( material == "RWY_SEQUENCED_LIGHTS" ) {
602         // cout << "found a rabbit" << endl;
603         ssgTransform *rabbit = gen_rabbit_lights( nodes, normals,
604                                                   pnt_i, nml_i,
605                                                   matlib, up );
606         return rabbit;
607     } else if ( material == "RWY_BLUE_TAXIWAY_LIGHTS" ) {
608         ssgTransform *light_group = gen_dir_light_group( nodes, normals, pnt_i,
609                                                          nml_i, mat, up,
610                                                          true );
611         return light_group;
612     } else {
613         ssgTransform *light_group = gen_dir_light_group( nodes, normals, pnt_i,
614                                                          nml_i, mat, up );
615         return light_group;
616     }
617
618     return NULL;
619 }