]> git.mxchange.org Git - simgear.git/blobdiff - simgear/scene/model/shadowvolume.cxx
Provide something more sensible for the properties root
[simgear.git] / simgear / scene / model / shadowvolume.cxx
index de106bcd343fe5704166c05458af6cd5492cfb43..3a164a16509772653f7cc529af31c355fbe92ade 100644 (file)
 //
 // You should have received a copy of the GNU General Public License
 // along with this program; if not, write to the Free Software
-// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 //
 //
 
+#ifdef HAVE_CONFIG_H
+#  include <simgear_config.h>
+#endif
+
 #include <plib/sg.h>
-#include <plib/ssg.h>
-#include <simgear/props/props.hxx>
 #include <simgear/debug/logstream.hxx>
-#include SG_GLU_H
+#include <simgear/screen/extensions.hxx>
+#include <simgear/scene/model/animation.hxx>
+#include <simgear/scene/model/model.hxx>
+#include <simgear/environment/visual_enviro.hxx>
+#include <osg/GLU>
 
 #include "shadowvolume.hxx"
 
@@ -65,6 +71,8 @@
  - render occluder in stencil buffer with their shadow volumes
  - apply stencil to framebuffer (darkens shadowed parts)
 
+       shadows using the alpha buffer
+       http://wwwvis.informatik.uni-stuttgart.de/~roettger/html/Pages/shadows.html
 */
 
 // TODO
 //     * add a render property on/off (for aircraft, for scene objects, for ai)
 //     * add a render property in rendering dialog
 //     * filter : halo, light, shadow, disc, disk, flame, (exhaust), noshadow
-// BUG
-//     - ghost objects ?
-//     - no shadow : check static 737/747
-// why has the ggb an alpha animation = 0.01 ?
 
 static int statSilhouette=0;
 static int statGeom=0;
 static int statObj=0;
 
 static SGShadowVolume *states;
+static glBlendEquationProc glBlendEquationPtr = NULL;
+#define GL_MIN_EXT                          0x8007
+#define GL_MAX_EXT                          0x8008
 
 
 SGShadowVolume::ShadowCaster::ShadowCaster( int _num_tri, ssgBranch * _geometry_leaf ) : 
@@ -95,36 +102,37 @@ SGShadowVolume::ShadowCaster::ShadowCaster( int _num_tri, ssgBranch * _geometry_
        scenery_object ( 0 ),
        first_select ( 0 ),
        frameNumber ( 0 ),
-       numTriangles ( 0 ),
        indices ( 0 ),
+       numTriangles ( 0 ),
        vertices ( 0 ),
-       planeEquations ( 0 ),
-       isFacingLight ( 0 ),
-       neighbourIndices ( 0 ),
-       isSilhouetteEdge ( 0 )
+       lastSilhouetteIndicesCount ( 0 )
 {
        int num_tri = _num_tri;
        numTriangles = num_tri;
-       indices = new int[num_tri * 3];
-       vertices = new sgVec3[num_tri * 3];
-       planeEquations = new sgVec4[num_tri];
-       neighbourIndices = new int[num_tri * 3];
-       isSilhouetteEdge = new bool[num_tri * 3];
-       isFacingLight = new bool[num_tri];
+       triangles = new triData[ num_tri ];
+       indices = new int[1 + num_tri * 3];
+       vertices = new sgVec4[1 + num_tri * 3];
+       silhouetteEdgeIndices = new GLushort[(1+num_tri) * 3*3];
+       indices [ num_tri * 3 ] = num_tri * 3;
        sgSetVec3(last_lightpos, 0.0, 0.0, 0.0);
        statGeom ++;
 
        ssgBranch *branch = (ssgBranch *) _geometry_leaf;
        while( branch && branch->getNumParents() > 0 ) {
-               if( !first_select && branch->isA(ssgTypeSelector())) {
+               if( branch->isAKindOf(ssgTypeSelector())) {
                        first_select = branch;
                        break;
                }
+               if( sgCheckAnimationBranch( (ssgEntity *) branch ) )
+                       if( ((SGAnimation *) branch->getUserData())->get_animation_type() == 1) {
+                               first_select = branch;
+                               break;
+                       }
                branch = branch->getParent(0);
        }
 }
 
-void SGShadowVolume::ShadowCaster::addLeaf( int & tri_idx, ssgLeaf *geometry_leaf ) {
+void SGShadowVolume::ShadowCaster::addLeaf( int & tri_idx, int & ind_idx, ssgLeaf *geometry_leaf ) {
        int num_tri = geometry_leaf->getNumTriangles();
        for(int i = 0; i < num_tri ; i ++ ) {
                short v1, v2, v3;
@@ -133,38 +141,38 @@ void SGShadowVolume::ShadowCaster::addLeaf( int & tri_idx, ssgLeaf *geometry_lea
                sgCopyVec3(a, geometry_leaf->getVertex(v1));
                sgCopyVec3(b, geometry_leaf->getVertex(v2));
                sgCopyVec3(c, geometry_leaf->getVertex(v3));
-               addTri( tri_idx++, a, b, c);
+
+               int p = tri_idx;
+               sgMakePlane ( triangles[p].planeEquations, a, b, c );
+               sgCopyVec3(vertices[ind_idx + v1], a);
+               sgCopyVec3(vertices[ind_idx + v2], b);
+               sgCopyVec3(vertices[ind_idx + v3], c);
+               vertices[ind_idx + v1][SG_W] = 1.0f;
+               vertices[ind_idx + v2][SG_W] = 1.0f;
+               vertices[ind_idx + v3][SG_W] = 1.0f;
+               indices[p*3] = ind_idx + v1;
+               indices[p*3+1] = ind_idx + v2;
+               indices[p*3+2] = ind_idx + v3;
+
+               tri_idx++;
        }
+       if( num_tri == 0 )
+               return;
+       isTranslucent |= geometry_leaf->isTranslucent() ? true : false;
+       int num_ind = geometry_leaf->getNumVertices();
+       ind_idx += num_ind;
 }
 
 SGShadowVolume::ShadowCaster::~ShadowCaster() {
        delete [] indices ;
        delete [] vertices ;
-       delete [] planeEquations ;
-       delete [] isFacingLight ;
-       delete [] neighbourIndices ;
-       delete [] isSilhouetteEdge ;
+       delete [] triangles;
+       delete [] silhouetteEdgeIndices;
 }
 
 
-void SGShadowVolume::ShadowCaster::addTri(int p, sgVec3 a, sgVec3 b, sgVec3 c) {
-       sgVec4 tri_plane;
-       assert( p >= 0 && p < numTriangles );
-
-       sgMakePlane ( tri_plane, a, b, c );
-       sgCopyVec4(planeEquations[p], tri_plane);
-       sgCopyVec3(vertices[p*3], a);
-       sgCopyVec3(vertices[p*3+1], b);
-       sgCopyVec3(vertices[p*3+2], c);
-       indices[p*3] = p*3;
-       indices[p*3+1] = p*3+1;
-       indices[p*3+2] = p*3+2;
-}
 
 bool SGShadowVolume::ShadowCaster::sameVertex(int edge1, int edge2) {
-//     const float epsilon = 0.01;     // 1cm
-//     const float epsilon = 0.0;      // 1cm
-//return false;
        if( edge1 == edge2)
                return true;
        sgVec3 delta_v;
@@ -183,8 +191,10 @@ void SGShadowVolume::ShadowCaster::SetConnectivity(void)
        int edgeCount = 0;
 
        //set the neighbour indices to be -1
-       for(int ii=0; ii<numTriangles*3; ++ii)
-               neighbourIndices[ii]=-1;
+       for(int ii=0; ii<numTriangles; ++ii)
+               triangles[ii].neighbourIndices[0] = 
+               triangles[ii].neighbourIndices[1] = 
+               triangles[ii].neighbourIndices[2] = -1;
 
        //loop through triangles
        for(int i=0; i<numTriangles-1; ++i)
@@ -193,12 +203,12 @@ void SGShadowVolume::ShadowCaster::SetConnectivity(void)
                for(int edgeI=0; edgeI<3; ++edgeI)
                {
                        //continue if this edge already has a neighbour set
-                       if(neighbourIndices[ i*3+edgeI ]!=-1)
+                       if(triangles[i].neighbourIndices[ edgeI ]!=-1)
                                continue;
 
                        //get the vertex indices on each edge
                        int edgeI1=indices[i*3+edgeI];
-                       int edgeI2=indices[i*3+(edgeI+1)%3];
+                       int edgeI2=indices[i*3+(edgeI == 2 ? 0 : edgeI+1)];
 
                        //loop through triangles with greater indices than this one
                        for(int j=i+1; j<numTriangles; ++j)
@@ -206,11 +216,16 @@ void SGShadowVolume::ShadowCaster::SetConnectivity(void)
                                //loop through edges on triangle j
                                for(int edgeJ=0; edgeJ<3; ++edgeJ)
                                {
+                                       //continue if this edge already has a neighbour set
+                                       if(triangles[j].neighbourIndices[ edgeJ ]!=-1) {
+                                               continue;
+                                       }
                                        //get the vertex indices on each edge
                                        int edgeJ1=indices[j*3+edgeJ];
                                        int edgeJ2=indices[j*3+(edgeJ == 2 ? 0 : edgeJ+1)];
 
                                        //if these are the same (possibly reversed order), these faces are neighbours
+#if 0
                                        //no, we only use reverse order because same order means that
                                        //the triangle is wrongly oriented and that will cause shadow artifact
                                        if(     sameVertex(edgeI1, edgeJ1) && sameVertex(edgeI2, edgeJ2) ) {
@@ -218,25 +233,19 @@ void SGShadowVolume::ShadowCaster::SetConnectivity(void)
 //                                                     printf("flipped triangle detected...check your model\n");
                                                continue;
                                        }
-                                       if(     false && sameVertex(edgeI1, edgeJ1) && sameVertex(edgeI2, edgeJ2)
-                                               || sameVertex(edgeI1, edgeJ2) && sameVertex(edgeI2, edgeJ1) )
+#endif
+                                       if(     sameVertex(edgeI1, edgeJ2) && sameVertex(edgeI2, edgeJ1) )
                                        {
-                                               int edgeI3=indices[i*3+(edgeI+2)%3];
-                                               int edgeJ3=indices[j*3+(edgeJ+2)%3];
+                                               int edgeI3=indices[i*3+(edgeI == 0 ? 2 : edgeI-1)];
+                                               int edgeJ3=indices[j*3+(edgeJ == 0 ? 2 : edgeJ-1)];
                                                if(     sameVertex(edgeI3, edgeJ3) ) {
                                                        // can happens with 'bad' geometry
 //                                                     printf("duplicated tri...check your model\n");
                                                        // exit loop
                                                        break;
                                                }
-                                               //continue if this edge already has a neighbour set
-                                               // can happens with 'bad' geometry
-                                               if(neighbourIndices[ j*3+edgeJ ]!=-1) {
-//                                                     printf("bad edge detected\n");
-                                                       continue;
-                                               }
-                                               neighbourIndices[i*3+edgeI]=j;
-                                               neighbourIndices[j*3+edgeJ]=i;
+                                               triangles[i].neighbourIndices[edgeI]=j;
+                                               triangles[j].neighbourIndices[edgeJ]=i;
                                                edgeCount ++;
                                                // exit loop
                                                j = numTriangles;
@@ -255,105 +264,64 @@ void SGShadowVolume::ShadowCaster::CalculateSilhouetteEdges(sgVec3 lightPosition
        //Calculate which faces face the light
        for(int i=0; i<numTriangles; ++i)
        {
-               if( sgDistToPlaneVec3 ( planeEquations[i], lightPosition ) > 0.0 )
-                       isFacingLight[i]=true;
+               if( sgDistToPlaneVec3 ( triangles[i].planeEquations, lightPosition ) > 0.0 )
+                       triangles[i].isFacingLight=true;
                else
-                       isFacingLight[i]=false;
+                       triangles[i].isFacingLight=false;
        }
 
        //loop through faces
+       int iEdgeIndices = 0;
+       sgVec4 farCap = {-lightPosition[SG_X], -lightPosition[SG_Y], -lightPosition[SG_Z], 1.0f};
+       sgCopyVec4( vertices[ numTriangles*3 ], farCap );
 
        for(int t=0; t < numTriangles; t++) {
                int v = t * 3;
                //if this face is not facing the light, not a silhouette edge
-               if(!isFacingLight[t])
+               if(!triangles[t].isFacingLight)
                {
-                       isSilhouetteEdge[v+0]=false;
-                       isSilhouetteEdge[v+1]=false;
-                       isSilhouetteEdge[v+2]=false;
+                       triangles[t].isSilhouetteEdge[0]=false;
+                       triangles[t].isSilhouetteEdge[1]=false;
+                       triangles[t].isSilhouetteEdge[2]=false;
                        continue;
                }
                //loop through edges
-               for(int i = v ; i < v+3 ; i++) {
+               for(int j = 0 ; j < 3 ; j++) {
                        //this face is facing the light
                        //if the neighbouring face is not facing the light, or there is no neighbouring face,
                        //then this is a silhouette edge
-                       if(neighbourIndices[i]==-1 || !isFacingLight[neighbourIndices[i]])
-                               isSilhouetteEdge[i]=true;
+                       if(triangles[t].neighbourIndices[j]==-1 || 
+                               !triangles[triangles[t].neighbourIndices[j]].isFacingLight ) {
+                               triangles[t].isSilhouetteEdge[j]=true;
+                               silhouetteEdgeIndices[ iEdgeIndices++ ] = indices[v+(j == 2 ? 0 : j+1)];
+                               silhouetteEdgeIndices[ iEdgeIndices++ ] = indices[v+j];
+                               silhouetteEdgeIndices[ iEdgeIndices++ ] = numTriangles * 3;
+                       }
                        else 
-                               isSilhouetteEdge[i]=false;
+                               triangles[t].isSilhouetteEdge[j]=false;
                }
        }
+       lastSilhouetteIndicesCount = iEdgeIndices;
 }
 
-// TODO: everyhting here is constant, store the vertex in a cache buffer and call drawelements
 void SGShadowVolume::ShadowCaster::DrawInfiniteShadowVolume(sgVec3 lightPosition, bool drawCaps)
 {
-       glColor4f(1.0, 1.0, 0.0, 0.5);
-       //TODO: no need for a quad here
-//     glBegin(GL_QUADS);
-       glBegin(GL_TRIANGLES);
-       {
-               for(int i=0; i<numTriangles; ++i)
-               {
-                       //if this face does not face the light, continue
-                       if(!isFacingLight[i])
-                               continue;
-
-                       int v = i*3;
-                       //Loop through edges on this face
-                       for(int j=0; j<3; ++j)
-                       {
-                               //Draw the shadow volume "edge" if this is a silhouette edge
-                               if(isSilhouetteEdge[v+j])
-                               {
-                                       sgVec3 vertex1, vertex2;
-                                       sgCopyVec3(vertex1, vertices[indices[v+j]]);
-                                       sgCopyVec3(vertex2, vertices[indices[v+(j == 2 ? 0 : j+1)]]);
-
-                                       glVertex3fv(vertex2);
-                                       glVertex3fv(vertex1);
-                                       // w == 0 for infinite shadow
-#if 0
-                                       glVertex4f(     vertex1[SG_X]-lightPosition[SG_X],
-                                                               vertex1[SG_Y]-lightPosition[SG_Y],
-                                                               vertex1[SG_Z]-lightPosition[SG_Z], 0.0f);
-//                                     glVertex4f(     vertex2[SG_X]-lightPosition[SG_X],
-//                                                             vertex2[SG_Y]-lightPosition[SG_Y],
-//                                                             vertex2[SG_Z]-lightPosition[SG_Z], 0.0f);
-#else
-                                       glVertex3f(     vertex1[SG_X]-lightPosition[SG_X],
-                                                               vertex1[SG_Y]-lightPosition[SG_Y],
-                                                               vertex1[SG_Z]-lightPosition[SG_Z]);
-//                                     glVertex3f(     vertex2[SG_X]-lightPosition[SG_X],
-//                                                             vertex2[SG_Y]-lightPosition[SG_Y],
-//                                                             vertex2[SG_Z]-lightPosition[SG_Z]);
-#endif
-                               }
-                       }
-               }
-       }
-       glEnd();
+       glEnableClientState ( GL_VERTEX_ARRAY ) ;
+       glVertexPointer ( 4, GL_FLOAT, 0, vertices ) ;
+       glDrawElements ( GL_TRIANGLES, lastSilhouetteIndicesCount, GL_UNSIGNED_SHORT, silhouetteEdgeIndices ) ;
 
        //Draw caps if required
-       if(drawCaps)
+       if(drawCaps)
        {
                glBegin(GL_TRIANGLES);
                {
                        for(int i=0; i<numTriangles; ++i)
                        {
-                               int v = i*3;
-                               for(int j=0; j<3; ++j)
-                               {
-                                       sgVec3 vertex;
-                                       sgCopyVec3(vertex, vertices[indices[v+j]]);
-
-                                       if(isFacingLight[i])
-                                               glVertex3fv(vertex);
-                                       else
-                                               glVertex4f(     vertex[SG_X]-lightPosition[SG_X],
-                                                                       vertex[SG_Y]-lightPosition[SG_Y],
-                                                                       vertex[SG_Z]-lightPosition[SG_Z], 0.0f);
+                               if(triangles[i].isFacingLight) {
+                                       int v = i*3;
+                                       glVertex3fv( vertices[indices[v+0]] );
+                                       glVertex3fv( vertices[indices[v+1]] );
+                                       glVertex3fv( vertices[indices[v+2]] );
                                }
                        }
                }
@@ -366,7 +334,6 @@ void SGShadowVolume::ShadowCaster::getNetTransform ( ssgBranch * branch, sgMat4
 {
        // one less matmult...
        bool first = true;
-//     sgMakeIdentMat4 ( xform ) ;
        while( branch && branch != lib_object ) {
                if( branch->isA(ssgTypeTransform()) ) {
                        sgMat4 transform;
@@ -386,8 +353,19 @@ void SGShadowVolume::ShadowCaster::getNetTransform ( ssgBranch * branch, sgMat4
 
 // check the value of <select> and <range> animation
 // wich have been computed during the rendering
-bool SGShadowVolume::ShadowCaster::isSelected (  ssgBranch * branch ) {
+bool SGShadowVolume::ShadowCaster::isSelected (  ssgBranch * branch, float dist ) {
        while( branch && branch != lib_object) {
+               if( sgCheckAnimationBranch( (ssgEntity *) branch ) ) {
+                       if( ((SGAnimation *) branch->getUserData())->get_animation_type() == 1)
+                               if( ((SGShadowAnimation *) branch->getUserData())->get_condition_value() )
+                                       return false;
+               }
+               // recompute range check since the value in the branch is shared by multiple objects
+               // we can only have the last value
+               if( branch->isA(ssgTypeRangeSelector()) )
+                       if( dist >= ((ssgRangeSelector *) branch)->getRange(1) ||
+                               dist < ((ssgRangeSelector *) branch)->getRange(0))
+                               return false;
                if( branch->isA(ssgTypeSelector()) )
                        if( !((ssgSelector *) branch)->isSelected(0) )
                                return false;
@@ -403,30 +381,32 @@ bool SGShadowVolume::ShadowCaster::isSelected (  ssgBranch * branch ) {
                     /
        perso2 *-----
 */
-void SGShadowVolume::ShadowCaster::computeShadows(sgMat4 rotation, sgMat4 rotation_translation) {
+void SGShadowVolume::ShadowCaster::computeShadows(sgMat4 rotation, sgMat4 rotation_translation,
+       OccluderType occluder_type) {
   
        // check the select and range ssgSelector node
        // object can't cast shadow if it is not visible
+       sgVec4 trans;
+       sgCopyVec4( trans, rotation_translation[3] );
+       sgAddVec4( trans, states->CameraViewM[3] );
+       float dist = sgLengthVec3( trans );
 
-       if( first_select && ! isSelected( first_select) )
+       if( first_select && ! isSelected( first_select, dist) )
                return;
 
-               sgMat4 transform ;
-               sgMat4 invTransform;
                // get the transformations : this comes from animation code for example
                // or static transf
+       sgMat4 transf;
+       sgVec3 lightPos;
+       int deltaFrame = occluder_type == SGShadowVolume::occluderTypeAircraft ? 0 : 9;
+       if( states->frameNumber - frameNumber > deltaFrame) {
+               sgMat4 transform ;
+               sgMat4 invTransform;
                getNetTransform( (ssgBranch *) geometry_leaf, transform );
-               sgMat4 transf;
-               sgCopyMat4( transf, transform );
-               sgPostMultMat4( transf, rotation_translation );
+               sgCopyMat4( last_transform, transform );
                sgPostMultMat4( transform, rotation );
-//             sgInvertMat4( invTransform, transform ); 
                sgTransposeNegateMat4 ( invTransform, transform ); 
 
-               glLoadMatrixf ( (float *) states->CameraViewM ) ;
-               glMultMatrixf( (float *) transf );
-
-               sgVec3 lightPos;
                sgCopyVec3( lightPos, states->sunPos );
                sgXformPnt3( lightPos, invTransform );
 
@@ -438,13 +418,17 @@ void SGShadowVolume::ShadowCaster::computeShadows(sgMat4 rotation, sgMat4 rotati
                // if the geometry has rotated/moved enought then
                // we need to recompute the silhouette
                // but this computation does not need to be done each frame
-               // -6 fps
-               if( (deltaPos > 0.0) && ( states->frameNumber - frameNumber > 0)) {
+               if( deltaPos > 0.0 ) {
                        CalculateSilhouetteEdges( lightPos );
                        sgCopyVec3( last_lightpos, lightPosNorm );
                        frameNumber = states->frameNumber ;
                        statSilhouette ++;
                }
+       }
+       sgCopyMat4( transf, last_transform );
+       sgPostMultMat4( transf, rotation_translation );
+       glLoadMatrixf ( (float *) states->CameraViewM ) ;
+       glMultMatrixf( (float *) transf );
 
        if( states->shadowsDebug_enabled )
        {
@@ -453,11 +437,11 @@ void SGShadowVolume::ShadowCaster::computeShadows(sgMat4 rotation, sgMat4 rotati
                glDisable( GL_DEPTH_TEST );
                glDisable(GL_STENCIL_TEST);
                glColorMask(1, 1, 1, 1);
-               glColor4f(0.0, 0.0, 1.0, 0.8);
+               glColor4f(0.0, 0.0, 1.0, 1.0);
                glBegin(GL_LINES);
                for(int i=0; i<numTriangles; ++i)
                {
-                       if(!isFacingLight[i])
+                       if(!triangles[i].isFacingLight)
                                continue;
                        int v = i*3;
                        //Loop through edges on this face
@@ -466,27 +450,26 @@ void SGShadowVolume::ShadowCaster::computeShadows(sgMat4 rotation, sgMat4 rotati
                        sgCopyVec3(vertex2, vertices[indices[v+1]]);
                        sgCopyVec3(vertex3, vertices[indices[v+2]]);
 
-                       if(isSilhouetteEdge[i*3+0]) {
+                       if(triangles[i].isSilhouetteEdge[0]) {
                                glVertex3fv(vertex2);
                                glVertex3fv(vertex1);
                        }
-                       if(isSilhouetteEdge[i*3+1]) {
+                       if(triangles[i].isSilhouetteEdge[1]) {
                                glVertex3fv(vertex2);
                                glVertex3fv(vertex3);
                        }
-                       if(isSilhouetteEdge[i*3+2]) {
+                       if(triangles[i].isSilhouetteEdge[2]) {
                                glVertex3fv(vertex3);
                                glVertex3fv(vertex1);
                        }
                }
-                       glEnd();
+               glEnd();
                glColorMask(0, 0, 0, 0);
                glEnable( GL_CULL_FACE  );
                glEnable( GL_DEPTH_TEST );
                glEnable(GL_STENCIL_TEST);
        }
 
-       // -11 fps
 
                // TODO:compute intersection with near clip plane...
                bool needZFail=false;
@@ -511,60 +494,47 @@ void SGShadowVolume::ShadowCaster::computeShadows(sgMat4 rotation, sgMat4 rotati
                else    //using zpass
                {
                        //Increment stencil buffer for front face depth pass
-                       glStencilFunc(GL_ALWAYS, 0, ~0);
-                       glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
+                       if( states->use_alpha ) {
+                               glBlendEquationPtr( GL_FUNC_ADD );
+                               glBlendFunc( GL_ONE, GL_ONE );
+                               glColor4ub(1, 1, 1, 16);
+                       } else {
+                               glColor4f(1.0f, 1.0f, 0.0f, 0.5f);
+                               glStencilFunc(GL_ALWAYS, 0, ~0);
+                               glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
+                       }
                        glCullFace(GL_BACK);
 
-                       DrawInfiniteShadowVolume( lightPos, false);
+                       DrawInfiniteShadowVolume( lightPos, states->shadowsAC_transp_enabled & isTranslucent);
 
                        //Decrement stencil buffer for back face depth pass
-                       glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
+                       if( states->use_alpha ) {
+                               glBlendEquationPtr( GL_FUNC_REVERSE_SUBTRACT );
+                               glBlendFunc( GL_ONE, GL_ONE );
+                               glColor4ub(1, 1, 1, 16);
+                       } else {
+                               glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
+                       }
                        glCullFace(GL_FRONT);
 
-                       DrawInfiniteShadowVolume( lightPos, false);
+                       DrawInfiniteShadowVolume( lightPos, states->shadowsAC_transp_enabled & isTranslucent);
                }
-       // -15 fps
 }
 
 
 void SGShadowVolume::SceneryObject::computeShadows(void) {
 
-       bool intersect = true;
        // compute intersection with view frustum
        // use pending_object (pointer on obj transform) & tile transform
        // to get position
-       sgMat4 position, CamXpos;
-       sgFrustum *f = ssgGetFrustum();
-       pending_object->getParent(0)->getNetTransform( position );
-       sgCopyMat4 ( CamXpos, states->CameraViewM ) ;
-       sgPreMultMat4 ( CamXpos, position ) ;
-
-       sgSphere tmp = *(pending_object->getBSphere()) ;
-       if ( tmp.isEmpty () )
-               intersect = false;
-       else {
-               // 7000
-               float max_dist = 5000.0f;
-               tmp . orthoXform ( CamXpos ) ;
-               // cull if too far
-               if ( -tmp.center[2] - tmp.radius > max_dist )
-                       intersect = false;
-               else if( tmp.center[2] == 0.0 )
-                       intersect = true;
-               // cull if too small on screen
-               else if ( tmp.radius / sgAbs(tmp.center[2]) < 1.0 / 40.0 )
-                       intersect = false;
-               else
-                       intersect = SSG_OUTSIDE != (ssgCullResult) f -> contains ( &tmp );
-       }
-
-       if( intersect ) {
                if( !scenery_object ) {
-                       find_trans();
-                       if( scenery_object )
-                               traverseTree( pending_object );
-                       else
-                               return;
+                       if( states->frameNumber - states->lastTraverseTreeFrame > 5 ) {
+                               find_trans();
+                               if( scenery_object )
+                                       traverseTree( pending_object );
+                                       states->lastTraverseTreeFrame = states->frameNumber;
+                       }
+                       return;
                }
                sgMat4 rotation, rotation_translation;
                scenery_object->getNetTransform ( rotation_translation );
@@ -577,8 +547,76 @@ void SGShadowVolume::SceneryObject::computeShadows(void) {
 
                ShadowCaster_list::iterator iShadowCaster;
                for(iShadowCaster = parts.begin() ; iShadowCaster != parts.end() ; iShadowCaster ++ ) {
-                       (*iShadowCaster)->computeShadows(rotation, rotation_translation);
+                       (*iShadowCaster)->computeShadows(rotation, rotation_translation, occluder_type);
                }
+}
+
+static ssgCullResult cull_test ( ssgEntity *e, sgFrustum *f, sgMat4 m, int test_needed )
+{
+  if ( ! test_needed )
+    return SSG_INSIDE ;
+
+  sgSphere tmp = *(e->getBSphere()) ;
+
+  if ( tmp.isEmpty () )
+    return SSG_OUTSIDE ;
+
+  tmp . orthoXform ( m ) ;
+  if( tmp.center[2] == 0.0 )
+         return SSG_STRADDLE;
+  // cull if too small on screen
+  if ( tmp.radius / sgAbs(tmp.center[2]) < 1.0 / 40.0 )
+    return SSG_OUTSIDE ;
+
+  return (ssgCullResult) f -> contains ( &tmp ) ;
+}
+
+
+void SGShadowVolume::cull ( ssgBranch *b, sgFrustum *f, sgMat4 m, int test_needed )
+{
+       int cull_result = cull_test ( (ssgEntity *) b, f, m, test_needed ) ;
+
+       if ( cull_result == SSG_OUTSIDE )
+               return ;
+       if( b->isA( ssgTypeTransform() ) ) {
+
+               SceneryObject_map::iterator iSceneryObject = sceneryObjects.find( b );
+               if( iSceneryObject != sceneryObjects.end() ) {
+                       SceneryObject *an_occluder = iSceneryObject->second;
+                       if( shadowsTO_enabled && (an_occluder->occluder_type == occluderTypeTileObject) ||
+                               shadowsAI_enabled && (an_occluder->occluder_type == occluderTypeAI ) ||
+                               shadowsAC_enabled && (an_occluder->occluder_type == occluderTypeAircraft ) )
+                                       an_occluder->computeShadows();
+
+                       return;
+               }
+               sgMat4 tmp, transform ;
+               sgCopyMat4 ( tmp, m ) ;
+               ((ssgTransform *)b)->getTransform( transform );
+               sgPreMultMat4 ( tmp,  transform ) ;
+               glPushMatrix () ;
+               glLoadMatrixf ( (float *) tmp ) ;
+               for ( ssgEntity *e = b->getKid ( 0 ) ; e != NULL ; e = b->getNextKid() )
+                       cull ( (ssgBranch *) e, f, tmp, cull_result != SSG_INSIDE ) ;
+               glPopMatrix () ;
+       } else if( b->isAKindOf( ssgTypeSelector() ) ) {
+               int s = ((ssgSelector *) b)->getSelect() ;
+               if( b->isA( ssgTypeRangeSelector() ) ) {
+                       float range = sgLengthVec3 ( m [ 3 ] ) ;
+                       s = (range < ((ssgRangeSelector *) b)->getRange(1) &&
+                               range >= ((ssgRangeSelector *) b)->getRange(0) ) ? 1 : 0;
+               }
+               for ( ssgEntity *e = b->getKid ( 0 ) ; e != NULL ; e = b->getNextKid(), s >>= 1 )
+                       if ( s & 1 )
+                               cull ( (ssgBranch *) e, f, m, cull_result != SSG_INSIDE ) ;
+       } else if( b->isAKindOf( ssgTypeBranch() ) ) {
+               char *name = b->getName();
+               // quick exit for the hundreds of ground leafs
+               if( name && !strcmp(name, "LocalTerrain") )
+                       return;
+               for ( ssgEntity *e = b->getKid ( 0 ) ; e != NULL ; e = b->getNextKid() )
+                       if( ! e->isAKindOf( ssgTypeLeaf() ) )
+                               cull ( (ssgBranch *) e, f, m, cull_result != SSG_INSIDE ) ;
        }
 }
 
@@ -594,27 +632,37 @@ void SGShadowVolume::SceneryObject::computeShadows(void) {
        overhead for matrix computation) and at the end this will reduce the number of
        silouhette edge by a lot too.
 */
-static bool filterName(const char *leaf_name) {
+static bool filterLeaf(ssgLeaf *this_kid) {
+       const char *leaf_name = this_kid->getName();
+/*     ssgSimpleState *sst = (ssgSimpleState *) this_kid->getState();
+       if( sst && sst->isTranslucent() )
+               return false;*/
        if( ! leaf_name )
                return true;
        char lname[20];
-       int l = 0;
-           char *buff;
+       unsigned int l = 0;
+       char *buff;
        for( buff = lname; *leaf_name && l < (sizeof( lname )-1); ++buff, l++ )
             *buff = tolower(*leaf_name++);
        *buff = 0;
-       if( strstr(lname, "shadow") || strstr(lname, "light") || strstr(lname, "disk") ||
-               strstr(lname, "disk") || strstr(lname, "flame") || strstr(lname, "halo"))
+       if( !strncmp(lname, "noshadow", 8) )
                return false;
        return true;
 }
 void SGShadowVolume::SceneryObject::traverseTree(ssgBranch *branch) {
        int num_tri = 0;
        int num_leaf = 0;
+
+       if( sgCheckAnimationBranch( (ssgEntity *) branch ) ) {
+               if( ((SGAnimation *) branch->getUserData())->get_animation_type() == 1)
+                       if( ((SGShadowAnimation *) branch->getUserData())->get_condition_value() )
+                               return;
+       }
+
        for(int i = 0 ; i < branch->getNumKids() ; i++) {
                ssgEntity *this_kid = branch->getKid( i );
                if( this_kid->isAKindOf(ssgTypeLeaf()) ) {
-                       if( filterName( this_kid->getName()) ) {
+                       if( filterLeaf( (ssgLeaf *) this_kid ) ) {
                                num_tri += ((ssgLeaf *) this_kid)->getNumTriangles();
                                num_leaf ++;
                        }
@@ -623,16 +671,21 @@ void SGShadowVolume::SceneryObject::traverseTree(ssgBranch *branch) {
        }
        if( num_tri > 0) {
                int tri_idx = 0;
+               int ind_idx = 0;
                ShadowCaster *new_part = new ShadowCaster( num_tri, branch);
                new_part->scenery_object = scenery_object;
                new_part->lib_object = lib_object;
+               new_part->isTranslucent = false;
                for(int i = 0 ; i < branch->getNumKids() ; i++) {
                        ssgEntity *this_kid = branch->getKid( i );
                        if( this_kid->isAKindOf(ssgTypeLeaf()) ) {
-                               if( filterName( this_kid->getName()) )
-                                       new_part->addLeaf( tri_idx, (ssgLeaf *) this_kid );
+                               if( filterLeaf( (ssgLeaf *) this_kid ) )
+                                       new_part->addLeaf( tri_idx, ind_idx, (ssgLeaf *) this_kid );
                        }
                }
+               // only do that for aircraft
+               if( occluder_type != SGShadowVolume::occluderTypeAircraft )
+                       new_part->isTranslucent = false;
                new_part->SetConnectivity();
                parts.push_back( new_part );
        }
@@ -640,10 +693,8 @@ void SGShadowVolume::SceneryObject::traverseTree(ssgBranch *branch) {
 
 void SGShadowVolume::SceneryObject::find_trans(void) {
        ssgBranch *branch = pending_object;
-       ssgBranch *prev_branch = pending_object;
        // check the existence of the root node
        while( branch && branch->getNumParents() > 0 ) {
-               prev_branch = branch;
                branch = branch->getParent(0);
        }
        // check if we are connected to the scene graph
@@ -653,9 +704,9 @@ void SGShadowVolume::SceneryObject::find_trans(void) {
 }
 
 SGShadowVolume::SceneryObject::SceneryObject(ssgBranch *_scenery_object, OccluderType _occluder_type) :
-       pending_object ( _scenery_object ),
-       occluder_type ( _occluder_type ),
-       scenery_object ( 0 )
+        scenery_object ( 0 ),
+        pending_object ( _scenery_object ),
+        occluder_type ( _occluder_type )
 {
        // queue objects, don't do all the work in the first frames because of
        // massive cpu power needed
@@ -664,16 +715,15 @@ SGShadowVolume::SceneryObject::SceneryObject(ssgBranch *_scenery_object, Occlude
                lib_object = _scenery_object;
        else
                lib_object = (ssgBranch *) ((ssgBranch *)_scenery_object->getKid(0))->getKid(0);
-#if 0
-       find_trans();
-       if( scenery_object )
-               traverseTree( pending_object );
-#endif
 }
 
 SGShadowVolume::SceneryObject::~SceneryObject()
 {
-//     parts.erase();
+       ShadowCaster_list::iterator iParts;
+       for(iParts = parts.begin() ; iParts != parts.end(); iParts++ ) {
+               delete *iParts;
+       }
+       parts.clear();
 }
 
 void SGShadowVolume::computeShadows(void) {
@@ -687,40 +737,50 @@ void SGShadowVolume::computeShadows(void) {
 
        //Draw shadow volumes
        glPushAttrib(GL_ALL_ATTRIB_BITS);
-       glClear(GL_STENCIL_BUFFER_BIT);
-
+       glPushClientAttrib ( GL_CLIENT_VERTEX_ARRAY_BIT ) ;
+       glDisableClientState ( GL_COLOR_ARRAY         ) ;
+       glDisableClientState ( GL_NORMAL_ARRAY        ) ;
+       glDisableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
+
+       if( use_alpha ) {
+               glColorMask(0, 0, 0, 1);
+               glClearColor(0.0, 0.0, 0.0, 0.0 );
+               glClear(GL_COLOR_BUFFER_BIT);
+               glDisable(GL_ALPHA);
+               glEnable(GL_BLEND);
+       } else {
+               glClearStencil( 0 );
+               glClear(GL_STENCIL_BUFFER_BIT);
+               glColorMask(0, 0, 0, 0);
+               glEnable(GL_STENCIL_TEST);
+               glDisable(GL_ALPHA);
+               glDisable(GL_BLEND);
+       }
        glDisable( GL_LIGHTING );
        glDisable( GL_FOG );
-       glDisable(GL_ALPHA);
-       glDisable(GL_BLEND);
        glEnable( GL_CULL_FACE  );
-       glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+//     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+    glPolygonOffset(0.0,2.0);
+//    glPolygonOffset(0.0,30.0);
+    glEnable(GL_POLYGON_OFFSET_FILL);
 
-       glColorMask(0, 0, 0, 0);
        glShadeModel(GL_FLAT);
 
        glDepthMask( false );
        glEnable( GL_DEPTH_TEST );
        glDepthFunc(GL_LESS);
-       glEnable(GL_STENCIL_TEST);
 
-       SceneryObject_map::iterator iSceneryObject;
-       // compute shadows for each objects
-       for(iSceneryObject = sceneryObjects.begin() ; iSceneryObject != sceneryObjects.end(); iSceneryObject++ ) {
-               SceneryObject *an_occluder = iSceneryObject->second;
-               if( shadowsTO_enabled && (an_occluder->occluder_type == occluderTypeTileObject) ||
-                       shadowsAI_enabled && (an_occluder->occluder_type == occluderTypeAI ) ||
-                       shadowsAC_enabled && (an_occluder->occluder_type == occluderTypeAircraft ) )
-                               an_occluder->computeShadows();
+       {
+               float w, h;
+               sgFrustum frustum;
+               sgEnviro.getFOV( w, h );
+               frustum.setFOV( w, h );
+               frustum.setNearFar(0.1f, 5000.0f);
+               sgMat4 m;
+               ssgGetModelviewMatrix( m );
+               cull( ssg_root, &frustum, m, true);
        }
 
-       // now the stencil contains 0 for scenery in light and != 0 for parts in shadow
-       // draw a quad covering the screen, the stencil will be the mask
-       // we darken the shadowed parts
-       glStencilFunc(GL_NOTEQUAL, 0, ~0);
-       glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
-       glEnable(GL_STENCIL_TEST);
-       glColorMask(1, 1, 1, 1);
 
        glMatrixMode   ( GL_PROJECTION ) ;
        glPushMatrix   () ;
@@ -734,60 +794,115 @@ void SGShadowVolume::computeShadows(void) {
        glDisable(GL_CULL_FACE);
 //     glBindTexture(GL_TEXTURE_2D, 0);
        glPolygonMode(GL_FRONT, GL_FILL);
-       glEnable(GL_ALPHA);
-       glAlphaFunc(GL_GREATER, 0.0f);
-       glEnable(GL_BLEND);
-       glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
-       glColor4f(0.0, 0.0, 0.0, sgLerp(0.1, 0.3, dot_light) );
-       // fixed value is better, the previous line is surely wrong
-       glColor4f(0.0, 0.0, 0.0, 0.3 );
-//     glColor4f(1.0, 0.0, 0.0, 0.5);
-       glRectf(-100,-100,100,100);
-
+       if( use_alpha ) {
+               // there is a flaw in the Roettger paper, this does not work for some geometry
+               // where we increment (multiply) the buffer a few times then we
+               // decrement (divide) a few times. Decrementing more then once will give a
+               // non shadowed parts with mask value < 0.25 because the incrementation was
+               // clamped
+               // Solution : don't use a start value as high as 0.25 but the smallest value
+               // posible ie 1/256. This is not a general solution, a stencil buffer will
+               // support 255 incrementation before clamping, the alpha mask only 7.
+               // => that still does not work with our geometry so use subtractive blend
+
+               // clamp mask = {0,16,32,64,...} => {0,16,16,16,...}
+               glBlendEquationPtr( GL_MIN_EXT );
+               glBlendFunc( GL_DST_COLOR, GL_ONE );
+               glColor4ub(1, 1, 1, 16);
+               glRectf(-100,-100,100,100);
+               // scale mask = {0,16} => {0,64}
+               glBlendEquationPtr( GL_FUNC_ADD );
+               glBlendFunc( GL_DST_COLOR, GL_ONE );
+               glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+               glRectf(-100,-100,100,100);
+               glRectf(-100,-100,100,100);
+               // negate mask => {0,64} => {255, 191}
+               glBlendFunc( GL_ONE_MINUS_DST_COLOR, GL_ZERO );
+               glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+               glRectf(-100,-100,100,100);
+               // apply mask
+               glColorMask(1, 1, 1, 1);
+               glBlendFunc( GL_ZERO, GL_DST_ALPHA );
+               glColor4f(1.0f, 0.5f, 0.2f, 1.0f);
+               glRectf(-100,-100,100,100);
+       } else {
+               // now the stencil contains 0 for scenery in light and != 0 for parts in shadow
+               // draw a quad covering the screen, the stencil will be the mask
+               // we darken the shadowed parts
+               glColorMask(1, 1, 1, 1);
+               glStencilFunc(GL_NOTEQUAL, 0, ~0);
+               glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+               glEnable(GL_STENCIL_TEST);
+               glEnable(GL_ALPHA);
+               glAlphaFunc(GL_GREATER, 0.0f);
+               glEnable(GL_BLEND);
+               glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
+               glColor4f(0.0, 0.0, 0.0, sgLerp(0.1, 0.3, dot_light) );
+               // fixed value is better, the previous line is surely wrong
+               glColor4f(0.0, 0.0, 0.0, 0.3 );
+               glRectf(-100,-100,100,100);
+       }
        glMatrixMode   ( GL_PROJECTION ) ;
        glPopMatrix    () ;
        glMatrixMode   ( GL_MODELVIEW ) ;
        glPopMatrix    () ;
 
        glDisable(GL_STENCIL_TEST);
+       glPopClientAttrib ( ) ;
        glPopAttrib();
 }
 
-SGShadowVolume::SGShadowVolume() : 
-       init_done( false ),
+SGShadowVolume::SGShadowVolume( ssgBranch *root ) : 
        shadows_enabled( false ),
-       frameNumber( 0 )
+       frameNumber( 0 ),
+       lastTraverseTreeFrame ( 0 ),
+       ssg_root( root ),
+       shadows_rendered( false )
 {
        states = this;
 }
 
 SGShadowVolume::~SGShadowVolume() {
-//     sceneryObjects.erase();
+       SceneryObject_map::iterator iSceneryObject;
+       for(iSceneryObject = sceneryObjects.begin() ; iSceneryObject != sceneryObjects.end(); iSceneryObject++ ) {
+               delete iSceneryObject->second;
+       }
+       sceneryObjects.clear();
 }
 
 void SGShadowVolume::init(SGPropertyNode *sim_rendering_options) {
-       init_done = true;
        shadows_enabled = true;
        sim_rendering = sim_rendering_options;
+       GLint stencilBits = 0, alphaBits = 0;
+       glGetIntegerv( GL_STENCIL_BITS, &stencilBits );
+       glGetIntegerv( GL_ALPHA_BITS, &alphaBits );
+       bool hasSubtractiveBlend = SGIsOpenGLExtensionSupported("GL_EXT_blend_subtract");
+       bool hasMinMaxBlend = SGIsOpenGLExtensionSupported("GL_EXT_blend_minmax");
+       if( hasSubtractiveBlend )
+               glBlendEquationPtr = (glBlendEquationProc ) SGLookupFunction("glBlendEquationEXT");
+       canDoAlpha = (alphaBits >= 8) && hasSubtractiveBlend && hasMinMaxBlend;
+       canDoStencil = (stencilBits >= 3);
+       if( !canDoStencil )
+               if( canDoAlpha )
+                       SG_LOG(SG_ALL, SG_WARN, "SGShadowVolume:no stencil buffer, using alpha buffer");
+               else
+                       SG_LOG(SG_ALL, SG_WARN, "SGShadowVolume:no stencil buffer and no alpha buffer");
 }
 
 void SGShadowVolume::startOfFrame(void) {
 }
 void SGShadowVolume::deleteOccluderFromTile(ssgBranch *tile) {
-       SceneryObject_map::iterator iSceneryObject, iPrevious;
-       iPrevious = sceneryObjects.begin();
-       for(iSceneryObject = sceneryObjects.begin() ; iSceneryObject != sceneryObjects.end(); iSceneryObject++ ) {
-               if( iSceneryObject->second->tile == tile ) {
-                       delete iSceneryObject->second;
-                       sceneryObjects.erase( iSceneryObject );
-                       iSceneryObject = iPrevious;
+       SceneryObject_map::iterator iSceneryObject;
+       for(iSceneryObject = sceneryObjects.begin() ; iSceneryObject != sceneryObjects.end(); ) {
+               SceneryObject_map::iterator iCurrent = iSceneryObject ++;
+               if( iCurrent->second->tile == tile ) {
+                       delete iCurrent->second;
+                       sceneryObjects.erase( iCurrent );
                }
-               iPrevious = iSceneryObject;
        }
 }
 
 void SGShadowVolume::deleteOccluder(ssgBranch *occluder) {
-       ssgBranch *branch = occluder;
        // skip first node and go to first transform (placement)
        while( occluder && !occluder->isA(ssgTypeTransform()))
                occluder = (ssgBranch *) occluder->getKid(0);
@@ -801,9 +916,6 @@ void SGShadowVolume::deleteOccluder(ssgBranch *occluder) {
 }
 
 void SGShadowVolume::addOccluder(ssgBranch *occluder, OccluderType occluder_type, ssgBranch *tile) {
-
-       ssgBranch *branch = occluder;
-
        // skip first node and go to first transform (placement)
        while( occluder && !occluder->isA(ssgTypeTransform()))
                occluder = (ssgBranch *) occluder->getKid(0);
@@ -823,38 +935,20 @@ void SGShadowVolume::setupShadows( double lon, double lat,
                double gst, double SunRightAscension, double SunDeclination, double sunAngle) {
 
        shadowsAC_enabled = sim_rendering->getBoolValue("shadows-ac", false);
+       shadowsAC_transp_enabled = sim_rendering->getBoolValue("shadows-ac-transp", false);
        shadowsAI_enabled = sim_rendering->getBoolValue("shadows-ai", false);
        shadowsTO_enabled = sim_rendering->getBoolValue("shadows-to", false);
        shadowsDebug_enabled = sim_rendering->getBoolValue("shadows-debug", false);
-//     shadows_enabled   = sim_rendering->getBoolValue("shadows", false);
        shadows_enabled = shadowsAC_enabled || shadowsAI_enabled || shadowsTO_enabled;
+       shadows_enabled &= canDoAlpha || canDoStencil;
+       use_alpha = ((!canDoStencil) || sim_rendering->getBoolValue("shadows-alpha", false)) &&
+               canDoAlpha;
 
        if( ! shadows_enabled )
                return;
 
-       sgMat4 view_angle;
+       shadows_rendered = false;
        sun_angle = sunAngle;
-       {
-               sgMat4 LON, LAT;
-               sgVec3 axis;
-
-               sgSetVec3( axis, 0.0, 0.0, 1.0 );
-               sgMakeRotMat4( LON, lon, axis );
-
-               sgSetVec3( axis, 0.0, 1.0, 0.0 );
-               sgMakeRotMat4( LAT, 90.0 - lat, axis );
-
-               sgMat4 TRANSFORM;
-
-               sgMakeIdentMat4 ( TRANSFORM );
-               sgPreMultMat4( TRANSFORM, LON );
-               sgPreMultMat4( TRANSFORM, LAT );
-
-               sgCoord pos;
-               sgSetCoord( &pos, TRANSFORM );
-
-               sgMakeCoordMat4( view_angle, &pos );
-       }
        {
        sgMat4 GST, RA, DEC;
        sgVec3 axis;
@@ -869,14 +963,11 @@ void SGShadowVolume::setupShadows( double lon, double lat,
        sgSetVec3( axis, 1.0, 0.0, 0.0 );
        sgMakeRotMat4( DEC, SunDeclination * SGD_RADIANS_TO_DEGREES, axis );
 
-       sgInvertMat4( invViewAngle, view_angle); 
-
        sgMat4 TRANSFORM;
        sgMakeIdentMat4( TRANSFORM );
        sgPreMultMat4( TRANSFORM, GST );
        sgPreMultMat4( TRANSFORM, RA );
        sgPreMultMat4( TRANSFORM, DEC );
-//     sgSetVec3( sunPos, 0.0, 99000.0, 0.0);
        sgSetVec3( sunPos, 0.0, 9900000.0, 0.0);
        sgXformPnt3( sunPos, TRANSFORM );
        }
@@ -888,13 +979,20 @@ void SGShadowVolume::setupShadows( double lon, double lat,
 void SGShadowVolume::endOfFrame(void) {
        if( ! shadows_enabled )
                return;
+       if( shadows_rendered )
+               return;
        glBindTexture(GL_TEXTURE_2D, 0);
        glBindTexture(GL_TEXTURE_1D, 0);
 
        glMatrixMode(GL_MODELVIEW);
-
        computeShadows();
-
        frameNumber ++;
+       shadows_rendered = true;
+}
+
+int SGShadowVolume::ACpostTravCB( ssgEntity *entity, int traversal_mask ) {
+       if( states->shadowsAC_transp_enabled && (SSGTRAV_CULL & traversal_mask) )
+               states->endOfFrame();
+       return 0;
 }