From: ehofman Date: Tue, 5 Jul 2005 17:08:27 +0000 (+0000) Subject: Harald JOHNSEN: X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=999a1e514bcfffc9c40ba432e9887277b5f5d522;p=simgear.git Harald JOHNSEN: - shadow volume vertex are now shared, using DrawElements instead of repeated calls to glVertex, this can improve performance on some systems. - added a rendering path that use the alpha channel instead of the stencill buffer. - releasing memory when tiles objects are destroyed - objects sub parts will not cast shadows if their name begins with "noshadow" or if they are in a animation - bbcache.cxx : don't ask for a 32 bits context when the primary context is only 16 bits - RenderTexture.cpp : corrected a crash when asking for a second rendering context on win32 and extensions not being supported - model.cxx, animation.cxx : added a animation, added an animation type needed by the shadow code. --- diff --git a/simgear/scene/model/animation.cxx b/simgear/scene/model/animation.cxx index a20df8d9..1307987e 100644 --- a/simgear/scene/model/animation.cxx +++ b/simgear/scene/model/animation.cxx @@ -179,7 +179,8 @@ double SGAnimation::sim_time_sec = 0.0; SGPersonalityBranch *SGAnimation::current_object = 0; SGAnimation::SGAnimation (SGPropertyNode_ptr props, ssgBranch * branch) - : _branch(branch) + : _branch(branch), + animation_type(0) { _branch->setName(props->getStringValue("name", 0)); if ( props->getBoolValue( "enable-hot", true ) ) { @@ -1501,4 +1502,19 @@ void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m ) sgPreMultMat4( r, transform ); } +//////////////////////////////////////////////////////////////////////// +// Implementation of SGShadowAnimation +//////////////////////////////////////////////////////////////////////// + +SGShadowAnimation::SGShadowAnimation (SGPropertyNode_ptr props) + : SGAnimation(props, new ssgBranch) +{ + animation_type = 1; +} + +SGShadowAnimation::~SGShadowAnimation () +{ +} + + // end of animation.cxx diff --git a/simgear/scene/model/animation.hxx b/simgear/scene/model/animation.hxx index fd7ec8c5..f6f5fa45 100644 --- a/simgear/scene/model/animation.hxx +++ b/simgear/scene/model/animation.hxx @@ -92,12 +92,15 @@ public: */ static SGPersonalityBranch *current_object; + int get_animation_type(void) { return animation_type; } + protected: static double sim_time_sec; ssgBranch * _branch; + int animation_type; }; @@ -580,5 +583,15 @@ private: SGInterpTable * _table; }; +/** + * An animation to tell wich objects don't cast shadows. + */ +class SGShadowAnimation : public SGAnimation +{ +public: + SGShadowAnimation (SGPropertyNode_ptr props); + virtual ~SGShadowAnimation (); +}; + #endif // _SG_ANIMATION_HXX diff --git a/simgear/scene/model/model.cxx b/simgear/scene/model/model.cxx index 676f834c..2a27815b 100644 --- a/simgear/scene/model/model.cxx +++ b/simgear/scene/model/model.cxx @@ -165,6 +165,8 @@ sgMakeAnimation( ssgBranch * model, animation = new SGFlashAnimation(node); } else if (!strcmp("dist-scale", type)) { animation = new SGDistScaleAnimation(node); + } else if (!strcmp("noshadow", type)) { + animation = new SGShadowAnimation(node); } else { animation = new SGNullAnimation(node); SG_LOG(SG_INPUT, SG_WARN, "Unknown animation type " << type); @@ -359,5 +361,10 @@ sgSetModelFilter( bool filter ) return old; } +bool +sgCheckAnimationBranch (ssgEntity * entity) +{ + return entity->getTravCallback(SSG_CALLBACK_PRETRAV) == animation_callback; +} // end of model.cxx diff --git a/simgear/scene/model/model.hxx b/simgear/scene/model/model.hxx index b1165045..a2ecc522 100644 --- a/simgear/scene/model/model.hxx +++ b/simgear/scene/model/model.hxx @@ -76,6 +76,12 @@ sgMakeAnimation( ssgBranch * model, bool sgSetModelFilter( bool filter ); +/** + * Check if the ssg node contains an animation + */ +bool +sgCheckAnimationBranch (ssgEntity * entity); + /** * Enable or disable Display list usage */ diff --git a/simgear/scene/model/shadowvolume.cxx b/simgear/scene/model/shadowvolume.cxx index de106bcd..74c79a1e 100644 --- a/simgear/scene/model/shadowvolume.cxx +++ b/simgear/scene/model/shadowvolume.cxx @@ -24,6 +24,9 @@ #include #include #include +#include +#include +#include #include SG_GLU_H #include "shadowvolume.hxx" @@ -65,6 +68,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 @@ -78,16 +83,15 @@ // * 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 glBlendEquation = NULL; +#define GL_MIN_EXT 0x8007 +#define GL_MAX_EXT 0x8008 SGShadowVolume::ShadowCaster::ShadowCaster( int _num_tri, ssgBranch * _geometry_leaf ) : @@ -98,19 +102,15 @@ SGShadowVolume::ShadowCaster::ShadowCaster( int _num_tri, ssgBranch * _geometry_ numTriangles ( 0 ), indices ( 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 ++; @@ -124,7 +124,7 @@ SGShadowVolume::ShadowCaster::ShadowCaster( int _num_tri, ssgBranch * _geometry_ } } -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 +133,37 @@ 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; + 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 +182,10 @@ void SGShadowVolume::ShadowCaster::SetConnectivity(void) int edgeCount = 0; //set the neighbour indices to be -1 - for(int ii=0; ii 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; iisA(ssgTypeTransform()) ) { sgMat4 transform; @@ -420,7 +378,6 @@ void SGShadowVolume::ShadowCaster::computeShadows(sgMat4 rotation, sgMat4 rotati sgCopyMat4( transf, transform ); sgPostMultMat4( transf, rotation_translation ); sgPostMultMat4( transform, rotation ); -// sgInvertMat4( invTransform, transform ); sgTransposeNegateMat4 ( invTransform, transform ); glLoadMatrixf ( (float *) states->CameraViewM ) ; @@ -438,8 +395,7 @@ 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) && ( states->frameNumber - frameNumber > 4)) { CalculateSilhouetteEdges( lightPos ); sgCopyVec3( last_lightpos, lightPosNorm ); frameNumber = states->frameNumber ; @@ -453,11 +409,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; iuse_alpha ) { + glBlendEquation( 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); //Decrement stencil buffer for back face depth pass - glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); + if( states->use_alpha ) { + glBlendEquation( 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); } - // -15 fps } @@ -560,11 +527,13 @@ void SGShadowVolume::SceneryObject::computeShadows(void) { 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 ); @@ -599,18 +568,23 @@ static bool filterName(const char *leaf_name) { return true; char lname[20]; int l = 0; - char *buff; + 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) + return; + } + for(int i = 0 ; i < branch->getNumKids() ; i++) { ssgEntity *this_kid = branch->getKid( i ); if( this_kid->isAKindOf(ssgTypeLeaf()) ) { @@ -623,6 +597,7 @@ 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; @@ -630,7 +605,7 @@ void SGShadowVolume::SceneryObject::traverseTree(ssgBranch *branch) { ssgEntity *this_kid = branch->getKid( i ); if( this_kid->isAKindOf(ssgTypeLeaf()) ) { if( filterName( this_kid->getName()) ) - new_part->addLeaf( tri_idx, (ssgLeaf *) this_kid ); + new_part->addLeaf( tri_idx, ind_idx, (ssgLeaf *) this_kid ); } } new_part->SetConnectivity(); @@ -664,16 +639,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,22 +661,38 @@ 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,5.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 @@ -714,13 +704,6 @@ void SGShadowVolume::computeShadows(void) { an_occluder->computeShadows(); } - // 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,55 +717,112 @@ 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,...} + glBlendEquation( 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} + glBlendEquation( 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 ), shadows_enabled( false ), - frameNumber( 0 ) + frameNumber( 0 ), + lastTraverseTreeFrame ( 0 ) { states = this; } SGShadowVolume::~SGShadowVolume() { -// sceneryObjects.erase(); + SceneryObject_map::iterator iSceneryObject; + for(iSceneryObject = sceneryObjects.begin() ; iSceneryObject != sceneryObjects.end(); ) { + delete iSceneryObject->second; + iSceneryObject = sceneryObjects.erase( iSceneryObject ); + } } void SGShadowVolume::init(SGPropertyNode *sim_rendering_options) { init_done = true; shadows_enabled = true; sim_rendering = sim_rendering_options; + int 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 ) + glBlendEquation = (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++ ) { + SceneryObject_map::iterator iSceneryObject; + for(iSceneryObject = sceneryObjects.begin() ; iSceneryObject != sceneryObjects.end(); ) { if( iSceneryObject->second->tile == tile ) { delete iSceneryObject->second; - sceneryObjects.erase( iSceneryObject ); - iSceneryObject = iPrevious; + iSceneryObject = sceneryObjects.erase( iSceneryObject ); } - iPrevious = iSceneryObject; + else + iSceneryObject++; } } @@ -828,6 +868,9 @@ void SGShadowVolume::setupShadows( double lon, double lat, 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; @@ -876,7 +919,6 @@ void SGShadowVolume::setupShadows( double lon, double lat, 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 ); } diff --git a/simgear/scene/model/shadowvolume.hxx b/simgear/scene/model/shadowvolume.hxx index 102da84d..c5fcec98 100644 --- a/simgear/scene/model/shadowvolume.hxx +++ b/simgear/scene/model/shadowvolume.hxx @@ -65,6 +65,13 @@ private: class ShadowCaster { public: + typedef struct { + sgVec4 planeEquations; + int neighbourIndices[3]; + bool isSilhouetteEdge[3]; + bool isFacingLight; + } triData; + ssgBranch *geometry_leaf; ssgBranch *scenery_object; ssgBranch *lib_object; @@ -74,20 +81,16 @@ private: int *indices; int numTriangles; - sgVec3 * vertices; - - // plane equation of each face - sgVec4 * planeEquations; - - bool * isFacingLight; + triData *triangles; - int * neighbourIndices; + sgVec4 * vertices; + GLushort *silhouetteEdgeIndices; + int lastSilhouetteIndicesCount; - bool * isSilhouetteEdge; ShadowCaster( int _num_tri, ssgBranch * _geometry_leaf ); ~ShadowCaster(); - void addLeaf( int & tri_idx, ssgLeaf *_geometry_leaf ); + void addLeaf( int & tri_idx, int & ind_idx, ssgLeaf *_geometry_leaf ); void SetConnectivity(); void CalculateSilhouetteEdges(sgVec3 lightPosition); void DrawInfiniteShadowVolume(sgVec3 lightPosition, bool drawCaps); @@ -96,7 +99,6 @@ private: bool isSelected ( ssgBranch * branch ); bool sameVertex(int edge1, int edge2); - void addTri(int p, sgVec3 a, sgVec3 b, sgVec3 c); }; typedef vector ShadowCaster_list; @@ -124,10 +126,13 @@ private: bool init_done; bool shadows_enabled; bool shadowsAC_enabled, shadowsAI_enabled, shadowsTO_enabled, shadowsDebug_enabled; + bool use_alpha; + bool canDoAlpha, canDoStencil; SGPropertyNode *sim_rendering; sgVec3 sunPos; int frameNumber; + int lastTraverseTreeFrame; sgMat4 CameraViewM; sgMat4 invViewAngle; double sun_angle; diff --git a/simgear/scene/sky/bbcache.cxx b/simgear/scene/sky/bbcache.cxx index da84fbce..55a2562d 100644 --- a/simgear/scene/sky/bbcache.cxx +++ b/simgear/scene/sky/bbcache.cxx @@ -109,11 +109,18 @@ SGBbCache::~SGBbCache(void) { void SGBbCache::init(int cacheCount) { + int colorBits = 0; + glGetIntegerv( GL_BLUE_BITS, &colorBits ); rt = new RenderTexture(); // don't use default rtt on nvidia/win because of poor performance of glCopyTexSubImage2D // wihtout default pattrib params - see opengl forum - rt->Reset("rgba tex2D ctt"); + if( colorBits < 8 ) + rt->Reset("rgba=5,5,5,1 ctt"); + else + rt->Reset("rgba ctt"); + +// rt->Reset("rgba tex2D ctt"); // rt->Reset("rgba tex2D"); if( rt->Initialize(256, 256, true) ) { SG_LOG(SG_ALL, SG_INFO, "bbcache:Initialize sucessfull"); diff --git a/simgear/screen/RenderTexture.cpp b/simgear/screen/RenderTexture.cpp index 2214228a..71de90ea 100644 --- a/simgear/screen/RenderTexture.cpp +++ b/simgear/screen/RenderTexture.cpp @@ -1695,7 +1695,9 @@ vector RenderTexture::_ParseBitVector(string bitVector) bool RenderTexture::_VerifyExtensions() { #ifdef _WIN32 - if ( !fctPtrInited ) + // a second call to _VerifyExtensions will allways return true, causing a crash + // if the extension is not supported + if ( true || !fctPtrInited ) { fctPtrInited = true; wglGetExtensionsStringARBProc wglGetExtensionsStringARBPtr = (wglGetExtensionsStringARBProc)wglGetProcAddress( "wglGetExtensionsStringARB" );