]> git.mxchange.org Git - simgear.git/blob - simgear/scene/model/shadowvolume.cxx
Somehow gcc allows function overriding but MIPSpro doesn't. Fix this.
[simgear.git] / simgear / scene / model / shadowvolume.cxx
1 // Shadow volume class
2 //
3 // Written by Harald JOHNSEN, started June 2005.
4 //
5 // Copyright (C) 2005  Harald JOHNSEN - hjohnsen@evc.net
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, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
20 //
21 //
22
23 #include <plib/sg.h>
24 #include <plib/ssg.h>
25 #include <simgear/props/props.hxx>
26 #include <simgear/debug/logstream.hxx>
27 #include <simgear/screen/extensions.hxx>
28 #include <simgear/scene/model/animation.hxx>
29 #include <simgear/scene/model/model.hxx>
30 #include SG_GLU_H
31
32 #include "shadowvolume.hxx"
33
34 /*
35  geometry and edge list
36  - traverse object graph until leaf to get geometry
37  - what about transform and selection ?
38         - use sub objects rather then objects
39         - get local transform and selection
40                 - range anim : ssgRangeSelector ( min, max ) => ssgSelector ( true/false )
41                         => selection [0..n], kids [0..n]
42                 - select/timed anim : ssgSelector ( true/false )
43                         => isSelected( nkid )
44                 - spin/rotate/trans/scale/... : ssgTransform ( matrix )
45                         => getNetTransform
46  - on new object :
47         - for one object branch
48                 - for each leaf
49                         - save geometry
50                         - save address in cache
51  - when rendering object
52         - for each leaf
53                 - getNetTransform + object global rotation (ac) => transform for light position
54                 - go up in tree and check isSelected( self )
55  - generate connectivity each time the geometry change
56         => using local light so connectivity never changes
57  - generate active edge list when :
58         - light moves
59         - subpart moves (animation code)
60         - ac rotate
61                 => cache rotation matrix and generate edge list only if something change
62                 => even if it changes, no need to do that every frame
63
64  - static objects have static edge list if light does not move
65
66  shadowing a scene
67  - render full scene as normal
68  - render occluder in stencil buffer with their shadow volumes
69  - apply stencil to framebuffer (darkens shadowed parts)
70
71         shadows using the alpha buffer
72         http://wwwvis.informatik.uni-stuttgart.de/~roettger/html/Pages/shadows.html
73 */
74
75 // TODO
76 //      - shadow for objects
77 //              * aircraft
78 //              * tile objects (from .stg)
79 //              - ai objects
80 //              - random objects => tie shadow geometry to lib objects and reuse them
81 //      - zfail if camera inside shadow
82 //      - queue geometry work if lot of objects
83 //      * add a render property on/off (for aircraft, for scene objects, for ai)
84 //      * add a render property in rendering dialog
85 //      * filter : halo, light, shadow, disc, disk, flame, (exhaust), noshadow
86
87 static int statSilhouette=0;
88 static int statGeom=0;
89 static int statObj=0;
90
91 static SGShadowVolume *states;
92 static glBlendEquationProc glBlendEquationPtr = NULL;
93 #define GL_MIN_EXT                          0x8007
94 #define GL_MAX_EXT                          0x8008
95
96
97 SGShadowVolume::ShadowCaster::ShadowCaster( int _num_tri, ssgBranch * _geometry_leaf ) : 
98         geometry_leaf ( _geometry_leaf ),
99         scenery_object ( 0 ),
100         first_select ( 0 ),
101         frameNumber ( 0 ),
102         numTriangles ( 0 ),
103         indices ( 0 ),
104         vertices ( 0 ),
105         lastSilhouetteIndicesCount ( 0 )
106 {
107         int num_tri = _num_tri;
108         numTriangles = num_tri;
109         triangles = new triData[ num_tri ];
110         indices = new int[1 + num_tri * 3];
111         vertices = new sgVec4[1 + num_tri * 3];
112         silhouetteEdgeIndices = new GLushort[(1+num_tri) * 3*3];
113         indices [ num_tri * 3 ] = num_tri * 3;
114         sgSetVec3(last_lightpos, 0.0, 0.0, 0.0);
115         statGeom ++;
116
117         ssgBranch *branch = (ssgBranch *) _geometry_leaf;
118         while( branch && branch->getNumParents() > 0 ) {
119                 if( !first_select && branch->isA(ssgTypeSelector())) {
120                         first_select = branch;
121                         break;
122                 }
123                 branch = branch->getParent(0);
124         }
125 }
126
127 void SGShadowVolume::ShadowCaster::addLeaf( int & tri_idx, int & ind_idx, ssgLeaf *geometry_leaf ) {
128         int num_tri = geometry_leaf->getNumTriangles();
129         for(int i = 0; i < num_tri ; i ++ ) {
130                 short v1, v2, v3;
131                 sgVec3 a, b, c;
132                 geometry_leaf->getTriangle( i, &v1, &v2, &v3 );
133                 sgCopyVec3(a, geometry_leaf->getVertex(v1));
134                 sgCopyVec3(b, geometry_leaf->getVertex(v2));
135                 sgCopyVec3(c, geometry_leaf->getVertex(v3));
136
137                 int p = tri_idx;
138                 sgMakePlane ( triangles[p].planeEquations, a, b, c );
139                 sgCopyVec3(vertices[ind_idx + v1], a);
140                 sgCopyVec3(vertices[ind_idx + v2], b);
141                 sgCopyVec3(vertices[ind_idx + v3], c);
142                 vertices[ind_idx + v1][SG_W] = 1.0f;
143                 vertices[ind_idx + v2][SG_W] = 1.0f;
144                 vertices[ind_idx + v3][SG_W] = 1.0f;
145                 indices[p*3] = ind_idx + v1;
146                 indices[p*3+1] = ind_idx + v2;
147                 indices[p*3+2] = ind_idx + v3;
148
149                 tri_idx++;
150         }
151         if( num_tri == 0 )
152                 return;
153         int num_ind = geometry_leaf->getNumVertices();
154         ind_idx += num_ind;
155 }
156
157 SGShadowVolume::ShadowCaster::~ShadowCaster() {
158         delete [] indices ;
159         delete [] vertices ;
160         delete [] triangles;
161         delete [] silhouetteEdgeIndices;
162 }
163
164
165
166 bool SGShadowVolume::ShadowCaster::sameVertex(int edge1, int edge2) {
167         if( edge1 == edge2)
168                 return true;
169         sgVec3 delta_v;
170         sgSubVec3( delta_v, vertices[edge1], vertices[edge2]);
171         if( delta_v[SG_X] != 0.0)       return false;
172         if( delta_v[SG_Y] != 0.0)       return false;
173         if( delta_v[SG_Z] != 0.0)       return false;
174         return true;
175 }
176
177
178 //Calculate neighbour faces for each edge
179 // caution, this is O(n2)
180 void SGShadowVolume::ShadowCaster::SetConnectivity(void)
181 {
182         int edgeCount = 0;
183
184         //set the neighbour indices to be -1
185         for(int ii=0; ii<numTriangles; ++ii)
186                 triangles[ii].neighbourIndices[0] = 
187                 triangles[ii].neighbourIndices[1] = 
188                 triangles[ii].neighbourIndices[2] = -1;
189
190         //loop through triangles
191         for(int i=0; i<numTriangles-1; ++i)
192         {
193                 //loop through edges on the first triangle
194                 for(int edgeI=0; edgeI<3; ++edgeI)
195                 {
196                         //continue if this edge already has a neighbour set
197                         if(triangles[i].neighbourIndices[ edgeI ]!=-1)
198                                 continue;
199
200                         //get the vertex indices on each edge
201                         int edgeI1=indices[i*3+edgeI];
202                         int edgeI2=indices[i*3+(edgeI == 2 ? 0 : edgeI+1)];
203
204                         //loop through triangles with greater indices than this one
205                         for(int j=i+1; j<numTriangles; ++j)
206                         {
207                                 //loop through edges on triangle j
208                                 for(int edgeJ=0; edgeJ<3; ++edgeJ)
209                                 {
210                                         //continue if this edge already has a neighbour set
211                                         if(triangles[j].neighbourIndices[ edgeJ ]!=-1) {
212                                                 continue;
213                                         }
214                                         //get the vertex indices on each edge
215                                         int edgeJ1=indices[j*3+edgeJ];
216                                         int edgeJ2=indices[j*3+(edgeJ == 2 ? 0 : edgeJ+1)];
217
218                                         //if these are the same (possibly reversed order), these faces are neighbours
219 #if 0
220                                         //no, we only use reverse order because same order means that
221                                         //the triangle is wrongly oriented and that will cause shadow artifact
222                                         if(     sameVertex(edgeI1, edgeJ1) && sameVertex(edgeI2, edgeJ2) ) {
223                                                         // can happens with 'bad' geometry
224 //                                                      printf("flipped triangle detected...check your model\n");
225                                                 continue;
226                                         }
227 #endif
228                                         if(     sameVertex(edgeI1, edgeJ2) && sameVertex(edgeI2, edgeJ1) )
229                                         {
230                                                 int edgeI3=indices[i*3+(edgeI == 0 ? 2 : edgeI-1)];
231                                                 int edgeJ3=indices[j*3+(edgeJ == 0 ? 2 : edgeJ-1)];
232                                                 if(     sameVertex(edgeI3, edgeJ3) ) {
233                                                         // can happens with 'bad' geometry
234 //                                                      printf("duplicated tri...check your model\n");
235                                                         // exit loop
236                                                         break;
237                                                 }
238                                                 triangles[i].neighbourIndices[edgeI]=j;
239                                                 triangles[j].neighbourIndices[edgeJ]=i;
240                                                 edgeCount ++;
241                                                 // exit loop
242                                                 j = numTriangles;
243                                                 break;
244                                         }
245                                 }
246                         }
247                 }
248         }
249 //      printf("submodel has %d triangles and %d shared edges\n", numTriangles, edgeCount);
250 }
251
252 //calculate silhouette edges
253 void SGShadowVolume::ShadowCaster::CalculateSilhouetteEdges(sgVec3 lightPosition)
254 {
255         //Calculate which faces face the light
256         for(int i=0; i<numTriangles; ++i)
257         {
258                 if( sgDistToPlaneVec3 ( triangles[i].planeEquations, lightPosition ) > 0.0 )
259                         triangles[i].isFacingLight=true;
260                 else
261                         triangles[i].isFacingLight=false;
262         }
263
264         //loop through faces
265         int iEdgeIndices = 0;
266         sgVec4 farCap = {-lightPosition[SG_X], -lightPosition[SG_Y], -lightPosition[SG_Z], 1.0f};
267         sgCopyVec4( vertices[ numTriangles*3 ], farCap );
268
269         for(int t=0; t < numTriangles; t++) {
270                 int v = t * 3;
271                 //if this face is not facing the light, not a silhouette edge
272                 if(!triangles[t].isFacingLight)
273                 {
274                         triangles[t].isSilhouetteEdge[0]=false;
275                         triangles[t].isSilhouetteEdge[1]=false;
276                         triangles[t].isSilhouetteEdge[2]=false;
277                         continue;
278                 }
279                 //loop through edges
280                 for(int j = 0 ; j < 3 ; j++) {
281                         //this face is facing the light
282                         //if the neighbouring face is not facing the light, or there is no neighbouring face,
283                         //then this is a silhouette edge
284                         if(triangles[t].neighbourIndices[j]==-1 || 
285                                 !triangles[triangles[t].neighbourIndices[j]].isFacingLight ) {
286                                 triangles[t].isSilhouetteEdge[j]=true;
287                                 silhouetteEdgeIndices[ iEdgeIndices++ ] = indices[v+(j == 2 ? 0 : j+1)];
288                                 silhouetteEdgeIndices[ iEdgeIndices++ ] = indices[v+j];
289                                 silhouetteEdgeIndices[ iEdgeIndices++ ] = numTriangles * 3;
290                         }
291                         else 
292                                 triangles[t].isSilhouetteEdge[j]=false;
293                 }
294         }
295         lastSilhouetteIndicesCount = iEdgeIndices;
296 }
297
298 void SGShadowVolume::ShadowCaster::DrawInfiniteShadowVolume(sgVec3 lightPosition, bool drawCaps)
299 {
300         glEnableClientState ( GL_VERTEX_ARRAY ) ;
301         glVertexPointer ( 4, GL_FLOAT, 0, vertices ) ;
302         glDrawElements ( GL_TRIANGLES, lastSilhouetteIndicesCount, GL_UNSIGNED_SHORT, silhouetteEdgeIndices ) ;
303
304         //Draw caps if required
305         if(drawCaps)
306         {
307                 glBegin(GL_TRIANGLES);
308                 {
309                         for(int i=0; i<numTriangles; ++i)
310                         {
311                                 if(triangles[i].isFacingLight) {
312                                         int v = i*3;
313                                         glVertex3fv( vertices[indices[v+0]] );
314                                         glVertex3fv( vertices[indices[v+1]] );
315                                         glVertex3fv( vertices[indices[v+2]] );
316                                 }
317                         }
318                 }
319                 glEnd();
320         }
321 }
322
323
324 void SGShadowVolume::ShadowCaster::getNetTransform ( ssgBranch * branch, sgMat4 xform )
325 {
326         // one less matmult...
327         bool first = true;
328         while( branch && branch != lib_object ) {
329                 if( branch->isA(ssgTypeTransform()) ) {
330                         sgMat4 transform;
331                         if( first ) {
332                                 ((ssgTransform *) branch)->getTransform( xform );
333                                 first = false;
334                         } else {
335                                 ((ssgTransform *) branch)->getTransform(transform);
336                                 sgPostMultMat4 ( xform, transform ) ;
337                         }
338                 }
339                 branch = branch->getParent( 0 );
340         }
341         if( first )
342                 sgMakeIdentMat4 ( xform ) ;
343 }
344
345 // check the value of <select> and <range> animation
346 // wich have been computed during the rendering
347 bool SGShadowVolume::ShadowCaster::isSelected (  ssgBranch * branch ) {
348         while( branch && branch != lib_object) {
349                 if( branch->isA(ssgTypeSelector()) )
350                         if( !((ssgSelector *) branch)->isSelected(0) )
351                                 return false;
352                 branch = branch->getParent(0);
353         }
354         return true;
355 }
356 /*
357         trans ----- personality ---- shared object
358         perso1 *-----
359                      \
360                       *--------* shared object
361                      /
362         perso2 *-----
363 */
364 void SGShadowVolume::ShadowCaster::computeShadows(sgMat4 rotation, sgMat4 rotation_translation) {
365   
366         // check the select and range ssgSelector node
367         // object can't cast shadow if it is not visible
368
369         if( first_select && ! isSelected( first_select) )
370                 return;
371
372                 sgMat4 transform ;
373                 sgMat4 invTransform;
374                 // get the transformations : this comes from animation code for example
375                 // or static transf
376                 getNetTransform( (ssgBranch *) geometry_leaf, transform );
377                 sgMat4 transf;
378                 sgCopyMat4( transf, transform );
379                 sgPostMultMat4( transf, rotation_translation );
380                 sgPostMultMat4( transform, rotation );
381                 sgTransposeNegateMat4 ( invTransform, transform ); 
382
383                 glLoadMatrixf ( (float *) states->CameraViewM ) ;
384                 glMultMatrixf( (float *) transf );
385
386                 sgVec3 lightPos;
387                 sgCopyVec3( lightPos, states->sunPos );
388                 sgXformPnt3( lightPos, invTransform );
389
390                 sgVec3 lightPosNorm;
391                 sgNormaliseVec3( lightPosNorm, lightPos );
392                 float deltaPos = sgAbs(lightPosNorm[0] - last_lightpos[0]) + 
393                                 sgAbs(lightPosNorm[1] - last_lightpos[1]) +
394                                 sgAbs(lightPosNorm[2] - last_lightpos[2]);
395                 // if the geometry has rotated/moved enought then
396                 // we need to recompute the silhouette
397                 // but this computation does not need to be done each frame
398                 if( (deltaPos > 0.0) && ( states->frameNumber - frameNumber > 4)) {
399                         CalculateSilhouetteEdges( lightPos );
400                         sgCopyVec3( last_lightpos, lightPosNorm );
401                         frameNumber = states->frameNumber ;
402                         statSilhouette ++;
403                 }
404
405         if( states->shadowsDebug_enabled )
406         {
407                 glStencilFunc(GL_ALWAYS, 0, ~0);
408                 glDisable( GL_CULL_FACE  );
409                 glDisable( GL_DEPTH_TEST );
410                 glDisable(GL_STENCIL_TEST);
411                 glColorMask(1, 1, 1, 1);
412                 glColor4f(0.0, 0.0, 1.0, 1.0);
413                 glBegin(GL_LINES);
414                 for(int i=0; i<numTriangles; ++i)
415                 {
416                         if(!triangles[i].isFacingLight)
417                                 continue;
418                         int v = i*3;
419                         //Loop through edges on this face
420                         sgVec3 vertex1, vertex2, vertex3;
421                         sgCopyVec3(vertex1, vertices[indices[v+0]]);
422                         sgCopyVec3(vertex2, vertices[indices[v+1]]);
423                         sgCopyVec3(vertex3, vertices[indices[v+2]]);
424
425                         if(triangles[i].isSilhouetteEdge[0]) {
426                                 glVertex3fv(vertex2);
427                                 glVertex3fv(vertex1);
428                         }
429                         if(triangles[i].isSilhouetteEdge[1]) {
430                                 glVertex3fv(vertex2);
431                                 glVertex3fv(vertex3);
432                         }
433                         if(triangles[i].isSilhouetteEdge[2]) {
434                                 glVertex3fv(vertex3);
435                                 glVertex3fv(vertex1);
436                         }
437                 }
438                 glEnd();
439                 glColorMask(0, 0, 0, 0);
440                 glEnable( GL_CULL_FACE  );
441                 glEnable( GL_DEPTH_TEST );
442                 glEnable(GL_STENCIL_TEST);
443         }
444
445
446                 // TODO:compute intersection with near clip plane...
447                 bool needZFail=false;
448
449                 // GL_INCR_WRAP_EXT, GL_DECR_WRAP_EXT
450
451                 if(needZFail)
452                 {
453                         //Increment stencil buffer for back face depth fail
454                         glStencilFunc(GL_ALWAYS, 0, ~0);
455                         glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
456                         glCullFace(GL_FRONT);
457
458                         DrawInfiniteShadowVolume( lightPos, true);
459
460                         //Decrement stencil buffer for front face depth fail
461                         glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
462                         glCullFace(GL_BACK);
463
464                         DrawInfiniteShadowVolume( lightPos, true);
465                 }
466                 else    //using zpass
467                 {
468                         //Increment stencil buffer for front face depth pass
469                         if( states->use_alpha ) {
470                                 glBlendEquationPtr( GL_FUNC_ADD );
471                                 glBlendFunc( GL_ONE, GL_ONE );
472                                 glColor4ub(1, 1, 1, 16);
473                         } else {
474                                 glColor4f(1.0f, 1.0f, 0.0f, 0.5f);
475                                 glStencilFunc(GL_ALWAYS, 0, ~0);
476                                 glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
477                         }
478                         glCullFace(GL_BACK);
479
480                         DrawInfiniteShadowVolume( lightPos, false);
481
482                         //Decrement stencil buffer for back face depth pass
483                         if( states->use_alpha ) {
484                                 glBlendEquationPtr( GL_FUNC_REVERSE_SUBTRACT );
485                                 glBlendFunc( GL_ONE, GL_ONE );
486                                 glColor4ub(1, 1, 1, 16);
487                         } else {
488                                 glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
489                         }
490                         glCullFace(GL_FRONT);
491
492                         DrawInfiniteShadowVolume( lightPos, false);
493                 }
494 }
495
496
497 void SGShadowVolume::SceneryObject::computeShadows(void) {
498
499         bool intersect = true;
500         // compute intersection with view frustum
501         // use pending_object (pointer on obj transform) & tile transform
502         // to get position
503         sgMat4 position, CamXpos;
504         sgFrustum *f = ssgGetFrustum();
505         pending_object->getParent(0)->getNetTransform( position );
506         sgCopyMat4 ( CamXpos, states->CameraViewM ) ;
507         sgPreMultMat4 ( CamXpos, position ) ;
508
509         sgSphere tmp = *(pending_object->getBSphere()) ;
510         if ( tmp.isEmpty () )
511                 intersect = false;
512         else {
513                 // 7000
514                 float max_dist = 5000.0f;
515                 tmp . orthoXform ( CamXpos ) ;
516                 // cull if too far
517                 if ( -tmp.center[2] - tmp.radius > max_dist )
518                         intersect = false;
519                 else if( tmp.center[2] == 0.0 )
520                         intersect = true;
521                 // cull if too small on screen
522                 else if ( tmp.radius / sgAbs(tmp.center[2]) < 1.0 / 40.0 )
523                         intersect = false;
524                 else
525                         intersect = SSG_OUTSIDE != (ssgCullResult) f -> contains ( &tmp );
526         }
527
528         if( intersect ) {
529                 if( !scenery_object ) {
530                         if( states->frameNumber - states->lastTraverseTreeFrame > 5 ) {
531                                 find_trans();
532                                 if( scenery_object )
533                                         traverseTree( pending_object );
534                                         states->lastTraverseTreeFrame = states->frameNumber;
535                         }
536                         return;
537                 }
538                 sgMat4 rotation, rotation_translation;
539                 scenery_object->getNetTransform ( rotation_translation );
540                 // split placement offset into rotation and offset
541                 // rotation from model inside world
542                 // we are not interested in translation since the light is very far away
543                 // without translation we reduce the frequency of updates of the silouhette
544                 sgCopyMat4( rotation, rotation_translation );
545                 sgSetVec4( rotation[3], 0, 0, 0, 1);
546
547                 ShadowCaster_list::iterator iShadowCaster;
548                 for(iShadowCaster = parts.begin() ; iShadowCaster != parts.end() ; iShadowCaster ++ ) {
549                         (*iShadowCaster)->computeShadows(rotation, rotation_translation);
550                 }
551         }
552 }
553
554 /*
555         1) starting at the root of a scene object we follow all branch to find vertex leaf.
556         each vertex leaf will create a shadow sub object so that the shadow casted by this
557         geometry can be correctly rendered according to select or transform nodes.
558         2) models are not optimized for shadows because the geometry is cut by
559                 - select / transform nodes
560                 - material differences
561         since we are not interested in the geometry material we try to merge same level
562         leafs. this can divide the number of shadow sub models by a lot (reducing the cpu
563         overhead for matrix computation) and at the end this will reduce the number of
564         silouhette edge by a lot too.
565 */
566 static bool filterName(const char *leaf_name) {
567         if( ! leaf_name )
568                 return true;
569         char lname[20];
570         int l = 0;
571         char *buff;
572         for( buff = lname; *leaf_name && l < (sizeof( lname )-1); ++buff, l++ )
573              *buff = tolower(*leaf_name++);
574         *buff = 0;
575         if( !strncmp(lname, "noshadow", 8) )
576                 return false;
577         return true;
578 }
579 void SGShadowVolume::SceneryObject::traverseTree(ssgBranch *branch) {
580         int num_tri = 0;
581         int num_leaf = 0;
582
583         if( sgCheckAnimationBranch( (ssgEntity *) branch ) ) {
584                 if( ((SGAnimation *) branch->getUserData())->get_animation_type() == 1)
585                         return;
586         }
587
588         for(int i = 0 ; i < branch->getNumKids() ; i++) {
589                 ssgEntity *this_kid = branch->getKid( i );
590                 if( this_kid->isAKindOf(ssgTypeLeaf()) ) {
591                         if( filterName( this_kid->getName()) ) {
592                                 num_tri += ((ssgLeaf *) this_kid)->getNumTriangles();
593                                 num_leaf ++;
594                         }
595                 } else
596                         traverseTree( (ssgBranch *) this_kid );
597         }
598         if( num_tri > 0) {
599                 int tri_idx = 0;
600                 int ind_idx = 0;
601                 ShadowCaster *new_part = new ShadowCaster( num_tri, branch);
602                 new_part->scenery_object = scenery_object;
603                 new_part->lib_object = lib_object;
604                 for(int i = 0 ; i < branch->getNumKids() ; i++) {
605                         ssgEntity *this_kid = branch->getKid( i );
606                         if( this_kid->isAKindOf(ssgTypeLeaf()) ) {
607                                 if( filterName( this_kid->getName()) )
608                                         new_part->addLeaf( tri_idx, ind_idx, (ssgLeaf *) this_kid );
609                         }
610                 }
611                 new_part->SetConnectivity();
612                 parts.push_back( new_part );
613         }
614 }
615
616 void SGShadowVolume::SceneryObject::find_trans(void) {
617         ssgBranch *branch = pending_object;
618         ssgBranch *prev_branch = pending_object;
619         // check the existence of the root node
620         while( branch && branch->getNumParents() > 0 ) {
621                 prev_branch = branch;
622                 branch = branch->getParent(0);
623         }
624         // check if we are connected to the scene graph
625         if( !branch->isA(ssgTypeRoot() ) )
626                 return;
627         scenery_object = pending_object;
628 }
629
630 SGShadowVolume::SceneryObject::SceneryObject(ssgBranch *_scenery_object, OccluderType _occluder_type) :
631         pending_object ( _scenery_object ),
632         occluder_type ( _occluder_type ),
633         scenery_object ( 0 )
634 {
635         // queue objects, don't do all the work in the first frames because of
636         // massive cpu power needed
637         statObj++;
638         if( occluder_type == SGShadowVolume::occluderTypeAircraft )
639                 lib_object = _scenery_object;
640         else
641                 lib_object = (ssgBranch *) ((ssgBranch *)_scenery_object->getKid(0))->getKid(0);
642 }
643
644 SGShadowVolume::SceneryObject::~SceneryObject()
645 {
646         ShadowCaster_list::iterator iParts;
647         for(iParts = parts.begin() ; iParts != parts.end(); iParts++ ) {
648                 delete *iParts;
649         }
650         parts.clear();
651 }
652
653 void SGShadowVolume::computeShadows(void) {
654
655         // intensity = ambient + lights
656         // lights = sun_const * (sun_angle . normal)
657         double dot_light = cos(sun_angle);
658         // do nothing if sun is under horizon
659         if( dot_light < 0.2 )
660                 return;
661
662         //Draw shadow volumes
663         glPushAttrib(GL_ALL_ATTRIB_BITS);
664         glPushClientAttrib ( GL_CLIENT_VERTEX_ARRAY_BIT ) ;
665         glDisableClientState ( GL_COLOR_ARRAY         ) ;
666         glDisableClientState ( GL_NORMAL_ARRAY        ) ;
667         glDisableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
668
669         if( use_alpha ) {
670                 glColorMask(0, 0, 0, 1);
671                 glClearColor(0.0, 0.0, 0.0, 0.0 );
672                 glClear(GL_COLOR_BUFFER_BIT);
673                 glDisable(GL_ALPHA);
674                 glEnable(GL_BLEND);
675         } else {
676                 glClearStencil( 0 );
677                 glClear(GL_STENCIL_BUFFER_BIT);
678                 glColorMask(0, 0, 0, 0);
679                 glEnable(GL_STENCIL_TEST);
680                 glDisable(GL_ALPHA);
681                 glDisable(GL_BLEND);
682         }
683         glDisable( GL_LIGHTING );
684         glDisable( GL_FOG );
685         glEnable( GL_CULL_FACE  );
686 //      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
687 //    glPolygonOffset(0.0,5.0);
688     glPolygonOffset(0.0,30.0);
689     glEnable(GL_POLYGON_OFFSET_FILL);
690
691         glShadeModel(GL_FLAT);
692
693         glDepthMask( false );
694         glEnable( GL_DEPTH_TEST );
695         glDepthFunc(GL_LESS);
696
697         SceneryObject_map::iterator iSceneryObject;
698         // compute shadows for each objects
699         for(iSceneryObject = sceneryObjects.begin() ; iSceneryObject != sceneryObjects.end(); iSceneryObject++ ) {
700                 SceneryObject *an_occluder = iSceneryObject->second;
701                 if( shadowsTO_enabled && (an_occluder->occluder_type == occluderTypeTileObject) ||
702                         shadowsAI_enabled && (an_occluder->occluder_type == occluderTypeAI ) ||
703                         shadowsAC_enabled && (an_occluder->occluder_type == occluderTypeAircraft ) )
704                                 an_occluder->computeShadows();
705         }
706
707
708         glMatrixMode   ( GL_PROJECTION ) ;
709         glPushMatrix   () ;
710         glLoadIdentity () ;
711         glOrtho        ( -100, 100, -100, 100, -1, 1 ) ;
712         glMatrixMode   ( GL_MODELVIEW ) ;
713         glPushMatrix   () ;
714         glLoadIdentity () ;
715
716         glDisable(GL_DEPTH_TEST);
717         glDisable(GL_CULL_FACE);
718 //      glBindTexture(GL_TEXTURE_2D, 0);
719         glPolygonMode(GL_FRONT, GL_FILL);
720         if( use_alpha ) {
721                 // there is a flaw in the Roettger paper, this does not work for some geometry
722                 // where we increment (multiply) the buffer a few times then we
723                 // decrement (divide) a few times. Decrementing more then once will give a
724                 // non shadowed parts with mask value < 0.25 because the incrementation was
725                 // clamped
726                 // Solution : don't use a start value as high as 0.25 but the smallest value
727                 // posible ie 1/256. This is not a general solution, a stencil buffer will
728                 // support 255 incrementation before clamping, the alpha mask only 7.
729                 // => that still does not work with our geometry so use subtractive blend
730
731                 // clamp mask = {0,16,32,64,...} => {0,16,16,16,...}
732                 glBlendEquationPtr( GL_MIN_EXT );
733                 glBlendFunc( GL_DST_COLOR, GL_ONE );
734                 glColor4ub(1, 1, 1, 16);
735                 glRectf(-100,-100,100,100);
736                 // scale mask = {0,16} => {0,64}
737                 glBlendEquationPtr( GL_FUNC_ADD );
738                 glBlendFunc( GL_DST_COLOR, GL_ONE );
739                 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
740                 glRectf(-100,-100,100,100);
741                 glRectf(-100,-100,100,100);
742                 // negate mask => {0,64} => {255, 191}
743                 glBlendFunc( GL_ONE_MINUS_DST_COLOR, GL_ZERO );
744                 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
745                 glRectf(-100,-100,100,100);
746                 // apply mask
747                 glColorMask(1, 1, 1, 1);
748                 glBlendFunc( GL_ZERO, GL_DST_ALPHA );
749                 glColor4f(1.0f, 0.5f, 0.2f, 1.0f);
750                 glRectf(-100,-100,100,100);
751         } else {
752                 // now the stencil contains 0 for scenery in light and != 0 for parts in shadow
753                 // draw a quad covering the screen, the stencil will be the mask
754                 // we darken the shadowed parts
755                 glColorMask(1, 1, 1, 1);
756                 glStencilFunc(GL_NOTEQUAL, 0, ~0);
757                 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
758                 glEnable(GL_STENCIL_TEST);
759                 glEnable(GL_ALPHA);
760                 glAlphaFunc(GL_GREATER, 0.0f);
761                 glEnable(GL_BLEND);
762                 glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
763                 glColor4f(0.0, 0.0, 0.0, sgLerp(0.1, 0.3, dot_light) );
764                 // fixed value is better, the previous line is surely wrong
765                 glColor4f(0.0, 0.0, 0.0, 0.3 );
766                 glRectf(-100,-100,100,100);
767         }
768         glMatrixMode   ( GL_PROJECTION ) ;
769         glPopMatrix    () ;
770         glMatrixMode   ( GL_MODELVIEW ) ;
771         glPopMatrix    () ;
772
773         glDisable(GL_STENCIL_TEST);
774         glPopClientAttrib ( ) ;
775         glPopAttrib();
776 }
777
778 SGShadowVolume::SGShadowVolume() : 
779         init_done( false ),
780         shadows_enabled( false ),
781         frameNumber( 0 ),
782         lastTraverseTreeFrame ( 0 )
783 {
784         states = this;
785 }
786
787 SGShadowVolume::~SGShadowVolume() {
788         SceneryObject_map::iterator iSceneryObject;
789         for(iSceneryObject = sceneryObjects.begin() ; iSceneryObject != sceneryObjects.end();  ) {
790                 delete iSceneryObject->second;
791                 sceneryObjects.erase( iSceneryObject );
792         }
793 }
794
795 void SGShadowVolume::init(SGPropertyNode *sim_rendering_options) {
796         init_done = true;
797         shadows_enabled = true;
798         sim_rendering = sim_rendering_options;
799         int stencilBits = 0, alphaBits = 0;
800         glGetIntegerv( GL_STENCIL_BITS, &stencilBits );
801         glGetIntegerv( GL_ALPHA_BITS, &alphaBits );
802         bool hasSubtractiveBlend = SGIsOpenGLExtensionSupported("GL_EXT_blend_subtract");
803         bool hasMinMaxBlend = SGIsOpenGLExtensionSupported("GL_EXT_blend_minmax");
804         if( hasSubtractiveBlend )
805                 glBlendEquationPtr = (glBlendEquationProc ) SGLookupFunction("glBlendEquationEXT");
806         canDoAlpha = (alphaBits >= 8) && hasSubtractiveBlend && hasMinMaxBlend;
807         canDoStencil = (stencilBits >= 3);
808         if( !canDoStencil )
809                 if( canDoAlpha )
810                         SG_LOG(SG_ALL, SG_WARN, "SGShadowVolume:no stencil buffer, using alpha buffer");
811                 else
812                         SG_LOG(SG_ALL, SG_WARN, "SGShadowVolume:no stencil buffer and no alpha buffer");
813 }
814
815 void SGShadowVolume::startOfFrame(void) {
816 }
817 void SGShadowVolume::deleteOccluderFromTile(ssgBranch *tile) {
818         SceneryObject_map::iterator iSceneryObject;
819         for(iSceneryObject = sceneryObjects.begin() ; iSceneryObject != sceneryObjects.end();  ) {
820                 if( iSceneryObject->second->tile == tile ) {
821                         delete iSceneryObject->second;
822                         sceneryObjects.erase( iSceneryObject );
823                 }
824                 else 
825                         iSceneryObject++;
826         }
827 }
828
829 void SGShadowVolume::deleteOccluder(ssgBranch *occluder) {
830         ssgBranch *branch = occluder;
831         // skip first node and go to first transform (placement)
832         while( occluder && !occluder->isA(ssgTypeTransform()))
833                 occluder = (ssgBranch *) occluder->getKid(0);
834
835         // check if we allready know this object
836         SceneryObject_map::iterator iSceneryObject = sceneryObjects.find( occluder );
837         if( iSceneryObject != sceneryObjects.end() ) {
838                 delete iSceneryObject->second;
839                 sceneryObjects.erase( occluder );
840         }
841 }
842
843 void SGShadowVolume::addOccluder(ssgBranch *occluder, OccluderType occluder_type, ssgBranch *tile) {
844
845         ssgBranch *branch = occluder;
846
847         // skip first node and go to first transform (placement)
848         while( occluder && !occluder->isA(ssgTypeTransform()))
849                 occluder = (ssgBranch *) occluder->getKid(0);
850
851         // check if we allready know this object
852         SceneryObject_map::iterator iSceneryObject = sceneryObjects.find( occluder );
853         if( iSceneryObject == sceneryObjects.end() ) {
854 //              printf("adding model %x %x\n", occluder, tile);
855                 SceneryObject *entry = new SceneryObject( occluder, occluder_type );
856                 entry->tile = tile;
857                 sceneryObjects[ occluder ] = entry;
858         }
859
860 }
861
862 void SGShadowVolume::setupShadows( double lon, double lat,
863                 double gst, double SunRightAscension, double SunDeclination, double sunAngle) {
864
865         shadowsAC_enabled = sim_rendering->getBoolValue("shadows-ac", false);
866         shadowsAI_enabled = sim_rendering->getBoolValue("shadows-ai", false);
867         shadowsTO_enabled = sim_rendering->getBoolValue("shadows-to", false);
868         shadowsDebug_enabled = sim_rendering->getBoolValue("shadows-debug", false);
869 //      shadows_enabled   = sim_rendering->getBoolValue("shadows", false);
870         shadows_enabled = shadowsAC_enabled || shadowsAI_enabled || shadowsTO_enabled;
871         shadows_enabled &= canDoAlpha || canDoStencil;
872         use_alpha = ((!canDoStencil) || sim_rendering->getBoolValue("shadows-alpha", false)) &&
873                 canDoAlpha;
874
875         if( ! shadows_enabled )
876                 return;
877
878         sgMat4 view_angle;
879         sun_angle = sunAngle;
880         {
881                 sgMat4 LON, LAT;
882                 sgVec3 axis;
883
884                 sgSetVec3( axis, 0.0, 0.0, 1.0 );
885                 sgMakeRotMat4( LON, lon, axis );
886
887                 sgSetVec3( axis, 0.0, 1.0, 0.0 );
888                 sgMakeRotMat4( LAT, 90.0 - lat, axis );
889
890                 sgMat4 TRANSFORM;
891
892                 sgMakeIdentMat4 ( TRANSFORM );
893                 sgPreMultMat4( TRANSFORM, LON );
894                 sgPreMultMat4( TRANSFORM, LAT );
895
896                 sgCoord pos;
897                 sgSetCoord( &pos, TRANSFORM );
898
899                 sgMakeCoordMat4( view_angle, &pos );
900         }
901         {
902         sgMat4 GST, RA, DEC;
903         sgVec3 axis;
904
905
906         sgSetVec3( axis, 0.0, 0.0, -1.0 );
907         sgMakeRotMat4( GST, (gst) * 15.0, axis );
908
909         sgSetVec3( axis, 0.0, 0.0, 1.0 );
910         sgMakeRotMat4( RA, (SunRightAscension * SGD_RADIANS_TO_DEGREES) - 90.0, axis );
911
912         sgSetVec3( axis, 1.0, 0.0, 0.0 );
913         sgMakeRotMat4( DEC, SunDeclination * SGD_RADIANS_TO_DEGREES, axis );
914
915         sgInvertMat4( invViewAngle, view_angle); 
916
917         sgMat4 TRANSFORM;
918         sgMakeIdentMat4( TRANSFORM );
919         sgPreMultMat4( TRANSFORM, GST );
920         sgPreMultMat4( TRANSFORM, RA );
921         sgPreMultMat4( TRANSFORM, DEC );
922         sgSetVec3( sunPos, 0.0, 9900000.0, 0.0);
923         sgXformPnt3( sunPos, TRANSFORM );
924         }
925
926         ssgGetModelviewMatrix( CameraViewM );
927
928 }
929
930 void SGShadowVolume::endOfFrame(void) {
931         if( ! shadows_enabled )
932                 return;
933         glBindTexture(GL_TEXTURE_2D, 0);
934         glBindTexture(GL_TEXTURE_1D, 0);
935
936         glMatrixMode(GL_MODELVIEW);
937
938         computeShadows();
939
940         frameNumber ++;
941 }
942