00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef HAVE_CONFIG_H
00024 # include <simgear_config.h>
00025 #endif
00026
00027 #include <plib/sg.h>
00028 #include <simgear/debug/logstream.hxx>
00029 #include <simgear/screen/extensions.hxx>
00030 #include <simgear/scene/model/animation.hxx>
00031 #include <simgear/scene/model/model.hxx>
00032 #include <simgear/environment/visual_enviro.hxx>
00033 #include SG_GLU_H
00034
00035 #include "shadowvolume.hxx"
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090 static int statSilhouette=0;
00091 static int statGeom=0;
00092 static int statObj=0;
00093
00094 static SGShadowVolume *states;
00095 static glBlendEquationProc glBlendEquationPtr = NULL;
00096 #define GL_MIN_EXT 0x8007
00097 #define GL_MAX_EXT 0x8008
00098
00099
00100 SGShadowVolume::ShadowCaster::ShadowCaster( int _num_tri, ssgBranch * _geometry_leaf ) :
00101 geometry_leaf ( _geometry_leaf ),
00102 scenery_object ( 0 ),
00103 first_select ( 0 ),
00104 frameNumber ( 0 ),
00105 indices ( 0 ),
00106 numTriangles ( 0 ),
00107 vertices ( 0 ),
00108 lastSilhouetteIndicesCount ( 0 )
00109 {
00110 int num_tri = _num_tri;
00111 numTriangles = num_tri;
00112 triangles = new triData[ num_tri ];
00113 indices = new int[1 + num_tri * 3];
00114 vertices = new sgVec4[1 + num_tri * 3];
00115 silhouetteEdgeIndices = new GLushort[(1+num_tri) * 3*3];
00116 indices [ num_tri * 3 ] = num_tri * 3;
00117 sgSetVec3(last_lightpos, 0.0, 0.0, 0.0);
00118 statGeom ++;
00119
00120 ssgBranch *branch = (ssgBranch *) _geometry_leaf;
00121 while( branch && branch->getNumParents() > 0 ) {
00122 if( branch->isAKindOf(ssgTypeSelector())) {
00123 first_select = branch;
00124 break;
00125 }
00126 if( sgCheckAnimationBranch( (ssgEntity *) branch ) )
00127 if( ((SGAnimation *) branch->getUserData())->get_animation_type() == 1) {
00128 first_select = branch;
00129 break;
00130 }
00131 branch = branch->getParent(0);
00132 }
00133 }
00134
00135 void SGShadowVolume::ShadowCaster::addLeaf( int & tri_idx, int & ind_idx, ssgLeaf *geometry_leaf ) {
00136 int num_tri = geometry_leaf->getNumTriangles();
00137 for(int i = 0; i < num_tri ; i ++ ) {
00138 short v1, v2, v3;
00139 sgVec3 a, b, c;
00140 geometry_leaf->getTriangle( i, &v1, &v2, &v3 );
00141 sgCopyVec3(a, geometry_leaf->getVertex(v1));
00142 sgCopyVec3(b, geometry_leaf->getVertex(v2));
00143 sgCopyVec3(c, geometry_leaf->getVertex(v3));
00144
00145 int p = tri_idx;
00146 sgMakePlane ( triangles[p].planeEquations, a, b, c );
00147 sgCopyVec3(vertices[ind_idx + v1], a);
00148 sgCopyVec3(vertices[ind_idx + v2], b);
00149 sgCopyVec3(vertices[ind_idx + v3], c);
00150 vertices[ind_idx + v1][SG_W] = 1.0f;
00151 vertices[ind_idx + v2][SG_W] = 1.0f;
00152 vertices[ind_idx + v3][SG_W] = 1.0f;
00153 indices[p*3] = ind_idx + v1;
00154 indices[p*3+1] = ind_idx + v2;
00155 indices[p*3+2] = ind_idx + v3;
00156
00157 tri_idx++;
00158 }
00159 if( num_tri == 0 )
00160 return;
00161 isTranslucent |= geometry_leaf->isTranslucent() ? true : false;
00162 int num_ind = geometry_leaf->getNumVertices();
00163 ind_idx += num_ind;
00164 }
00165
00166 SGShadowVolume::ShadowCaster::~ShadowCaster() {
00167 delete [] indices ;
00168 delete [] vertices ;
00169 delete [] triangles;
00170 delete [] silhouetteEdgeIndices;
00171 }
00172
00173
00174
00175 bool SGShadowVolume::ShadowCaster::sameVertex(int edge1, int edge2) {
00176 if( edge1 == edge2)
00177 return true;
00178 sgVec3 delta_v;
00179 sgSubVec3( delta_v, vertices[edge1], vertices[edge2]);
00180 if( delta_v[SG_X] != 0.0) return false;
00181 if( delta_v[SG_Y] != 0.0) return false;
00182 if( delta_v[SG_Z] != 0.0) return false;
00183 return true;
00184 }
00185
00186
00187
00188
00189 void SGShadowVolume::ShadowCaster::SetConnectivity(void)
00190 {
00191 int edgeCount = 0;
00192
00193
00194 for(int ii=0; ii<numTriangles; ++ii)
00195 triangles[ii].neighbourIndices[0] =
00196 triangles[ii].neighbourIndices[1] =
00197 triangles[ii].neighbourIndices[2] = -1;
00198
00199
00200 for(int i=0; i<numTriangles-1; ++i)
00201 {
00202
00203 for(int edgeI=0; edgeI<3; ++edgeI)
00204 {
00205
00206 if(triangles[i].neighbourIndices[ edgeI ]!=-1)
00207 continue;
00208
00209
00210 int edgeI1=indices[i*3+edgeI];
00211 int edgeI2=indices[i*3+(edgeI == 2 ? 0 : edgeI+1)];
00212
00213
00214 for(int j=i+1; j<numTriangles; ++j)
00215 {
00216
00217 for(int edgeJ=0; edgeJ<3; ++edgeJ)
00218 {
00219
00220 if(triangles[j].neighbourIndices[ edgeJ ]!=-1) {
00221 continue;
00222 }
00223
00224 int edgeJ1=indices[j*3+edgeJ];
00225 int edgeJ2=indices[j*3+(edgeJ == 2 ? 0 : edgeJ+1)];
00226
00227
00228 #if 0
00229
00230
00231 if( sameVertex(edgeI1, edgeJ1) && sameVertex(edgeI2, edgeJ2) ) {
00232
00233
00234 continue;
00235 }
00236 #endif
00237 if( sameVertex(edgeI1, edgeJ2) && sameVertex(edgeI2, edgeJ1) )
00238 {
00239 int edgeI3=indices[i*3+(edgeI == 0 ? 2 : edgeI-1)];
00240 int edgeJ3=indices[j*3+(edgeJ == 0 ? 2 : edgeJ-1)];
00241 if( sameVertex(edgeI3, edgeJ3) ) {
00242
00243
00244
00245 break;
00246 }
00247 triangles[i].neighbourIndices[edgeI]=j;
00248 triangles[j].neighbourIndices[edgeJ]=i;
00249 edgeCount ++;
00250
00251 j = numTriangles;
00252 break;
00253 }
00254 }
00255 }
00256 }
00257 }
00258
00259 }
00260
00261
00262 void SGShadowVolume::ShadowCaster::CalculateSilhouetteEdges(sgVec3 lightPosition)
00263 {
00264
00265 for(int i=0; i<numTriangles; ++i)
00266 {
00267 if( sgDistToPlaneVec3 ( triangles[i].planeEquations, lightPosition ) > 0.0 )
00268 triangles[i].isFacingLight=true;
00269 else
00270 triangles[i].isFacingLight=false;
00271 }
00272
00273
00274 int iEdgeIndices = 0;
00275 sgVec4 farCap = {-lightPosition[SG_X], -lightPosition[SG_Y], -lightPosition[SG_Z], 1.0f};
00276 sgCopyVec4( vertices[ numTriangles*3 ], farCap );
00277
00278 for(int t=0; t < numTriangles; t++) {
00279 int v = t * 3;
00280
00281 if(!triangles[t].isFacingLight)
00282 {
00283 triangles[t].isSilhouetteEdge[0]=false;
00284 triangles[t].isSilhouetteEdge[1]=false;
00285 triangles[t].isSilhouetteEdge[2]=false;
00286 continue;
00287 }
00288
00289 for(int j = 0 ; j < 3 ; j++) {
00290
00291
00292
00293 if(triangles[t].neighbourIndices[j]==-1 ||
00294 !triangles[triangles[t].neighbourIndices[j]].isFacingLight ) {
00295 triangles[t].isSilhouetteEdge[j]=true;
00296 silhouetteEdgeIndices[ iEdgeIndices++ ] = indices[v+(j == 2 ? 0 : j+1)];
00297 silhouetteEdgeIndices[ iEdgeIndices++ ] = indices[v+j];
00298 silhouetteEdgeIndices[ iEdgeIndices++ ] = numTriangles * 3;
00299 }
00300 else
00301 triangles[t].isSilhouetteEdge[j]=false;
00302 }
00303 }
00304 lastSilhouetteIndicesCount = iEdgeIndices;
00305 }
00306
00307 void SGShadowVolume::ShadowCaster::DrawInfiniteShadowVolume(sgVec3 lightPosition, bool drawCaps)
00308 {
00309 glEnableClientState ( GL_VERTEX_ARRAY ) ;
00310 glVertexPointer ( 4, GL_FLOAT, 0, vertices ) ;
00311 glDrawElements ( GL_TRIANGLES, lastSilhouetteIndicesCount, GL_UNSIGNED_SHORT, silhouetteEdgeIndices ) ;
00312
00313
00314 if(drawCaps)
00315 {
00316 glBegin(GL_TRIANGLES);
00317 {
00318 for(int i=0; i<numTriangles; ++i)
00319 {
00320 if(triangles[i].isFacingLight) {
00321 int v = i*3;
00322 glVertex3fv( vertices[indices[v+0]] );
00323 glVertex3fv( vertices[indices[v+1]] );
00324 glVertex3fv( vertices[indices[v+2]] );
00325 }
00326 }
00327 }
00328 glEnd();
00329 }
00330 }
00331
00332
00333 void SGShadowVolume::ShadowCaster::getNetTransform ( ssgBranch * branch, sgMat4 xform )
00334 {
00335
00336 bool first = true;
00337 while( branch && branch != lib_object ) {
00338 if( branch->isA(ssgTypeTransform()) ) {
00339 sgMat4 transform;
00340 if( first ) {
00341 ((ssgTransform *) branch)->getTransform( xform );
00342 first = false;
00343 } else {
00344 ((ssgTransform *) branch)->getTransform(transform);
00345 sgPostMultMat4 ( xform, transform ) ;
00346 }
00347 }
00348 branch = branch->getParent( 0 );
00349 }
00350 if( first )
00351 sgMakeIdentMat4 ( xform ) ;
00352 }
00353
00354
00355
00356 bool SGShadowVolume::ShadowCaster::isSelected ( ssgBranch * branch, float dist ) {
00357 while( branch && branch != lib_object) {
00358 if( sgCheckAnimationBranch( (ssgEntity *) branch ) ) {
00359 if( ((SGAnimation *) branch->getUserData())->get_animation_type() == 1)
00360 if( ((SGShadowAnimation *) branch->getUserData())->get_condition_value() )
00361 return false;
00362 }
00363
00364
00365 if( branch->isA(ssgTypeRangeSelector()) )
00366 if( dist >= ((ssgRangeSelector *) branch)->getRange(1) ||
00367 dist < ((ssgRangeSelector *) branch)->getRange(0))
00368 return false;
00369 if( branch->isA(ssgTypeSelector()) )
00370 if( !((ssgSelector *) branch)->isSelected(0) )
00371 return false;
00372 branch = branch->getParent(0);
00373 }
00374 return true;
00375 }
00376
00377
00378
00379
00380
00381
00382
00383
00384 void SGShadowVolume::ShadowCaster::computeShadows(sgMat4 rotation, sgMat4 rotation_translation,
00385 OccluderType occluder_type) {
00386
00387
00388
00389 sgVec4 trans;
00390 sgCopyVec4( trans, rotation_translation[3] );
00391 sgAddVec4( trans, states->CameraViewM[3] );
00392 float dist = sgLengthVec3( trans );
00393
00394 if( first_select && ! isSelected( first_select, dist) )
00395 return;
00396
00397
00398
00399 sgMat4 transf;
00400 sgVec3 lightPos;
00401 int deltaFrame = occluder_type == SGShadowVolume::occluderTypeAircraft ? 0 : 9;
00402 if( states->frameNumber - frameNumber > deltaFrame) {
00403 sgMat4 transform ;
00404 sgMat4 invTransform;
00405 getNetTransform( (ssgBranch *) geometry_leaf, transform );
00406 sgCopyMat4( last_transform, transform );
00407 sgPostMultMat4( transform, rotation );
00408 sgTransposeNegateMat4 ( invTransform, transform );
00409
00410 sgCopyVec3( lightPos, states->sunPos );
00411 sgXformPnt3( lightPos, invTransform );
00412
00413 sgVec3 lightPosNorm;
00414 sgNormaliseVec3( lightPosNorm, lightPos );
00415 float deltaPos = sgAbs(lightPosNorm[0] - last_lightpos[0]) +
00416 sgAbs(lightPosNorm[1] - last_lightpos[1]) +
00417 sgAbs(lightPosNorm[2] - last_lightpos[2]);
00418
00419
00420
00421 if( deltaPos > 0.0 ) {
00422 CalculateSilhouetteEdges( lightPos );
00423 sgCopyVec3( last_lightpos, lightPosNorm );
00424 frameNumber = states->frameNumber ;
00425 statSilhouette ++;
00426 }
00427 }
00428 sgCopyMat4( transf, last_transform );
00429 sgPostMultMat4( transf, rotation_translation );
00430 glLoadMatrixf ( (float *) states->CameraViewM ) ;
00431 glMultMatrixf( (float *) transf );
00432
00433 if( states->shadowsDebug_enabled )
00434 {
00435 glStencilFunc(GL_ALWAYS, 0, ~0);
00436 glDisable( GL_CULL_FACE );
00437 glDisable( GL_DEPTH_TEST );
00438 glDisable(GL_STENCIL_TEST);
00439 glColorMask(1, 1, 1, 1);
00440 glColor4f(0.0, 0.0, 1.0, 1.0);
00441 glBegin(GL_LINES);
00442 for(int i=0; i<numTriangles; ++i)
00443 {
00444 if(!triangles[i].isFacingLight)
00445 continue;
00446 int v = i*3;
00447
00448 sgVec3 vertex1, vertex2, vertex3;
00449 sgCopyVec3(vertex1, vertices[indices[v+0]]);
00450 sgCopyVec3(vertex2, vertices[indices[v+1]]);
00451 sgCopyVec3(vertex3, vertices[indices[v+2]]);
00452
00453 if(triangles[i].isSilhouetteEdge[0]) {
00454 glVertex3fv(vertex2);
00455 glVertex3fv(vertex1);
00456 }
00457 if(triangles[i].isSilhouetteEdge[1]) {
00458 glVertex3fv(vertex2);
00459 glVertex3fv(vertex3);
00460 }
00461 if(triangles[i].isSilhouetteEdge[2]) {
00462 glVertex3fv(vertex3);
00463 glVertex3fv(vertex1);
00464 }
00465 }
00466 glEnd();
00467 glColorMask(0, 0, 0, 0);
00468 glEnable( GL_CULL_FACE );
00469 glEnable( GL_DEPTH_TEST );
00470 glEnable(GL_STENCIL_TEST);
00471 }
00472
00473
00474
00475 bool needZFail=false;
00476
00477
00478
00479 if(needZFail)
00480 {
00481
00482 glStencilFunc(GL_ALWAYS, 0, ~0);
00483 glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
00484 glCullFace(GL_FRONT);
00485
00486 DrawInfiniteShadowVolume( lightPos, true);
00487
00488
00489 glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
00490 glCullFace(GL_BACK);
00491
00492 DrawInfiniteShadowVolume( lightPos, true);
00493 }
00494 else
00495 {
00496
00497 if( states->use_alpha ) {
00498 glBlendEquationPtr( GL_FUNC_ADD );
00499 glBlendFunc( GL_ONE, GL_ONE );
00500 glColor4ub(1, 1, 1, 16);
00501 } else {
00502 glColor4f(1.0f, 1.0f, 0.0f, 0.5f);
00503 glStencilFunc(GL_ALWAYS, 0, ~0);
00504 glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
00505 }
00506 glCullFace(GL_BACK);
00507
00508 DrawInfiniteShadowVolume( lightPos, states->shadowsAC_transp_enabled & isTranslucent);
00509
00510
00511 if( states->use_alpha ) {
00512 glBlendEquationPtr( GL_FUNC_REVERSE_SUBTRACT );
00513 glBlendFunc( GL_ONE, GL_ONE );
00514 glColor4ub(1, 1, 1, 16);
00515 } else {
00516 glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
00517 }
00518 glCullFace(GL_FRONT);
00519
00520 DrawInfiniteShadowVolume( lightPos, states->shadowsAC_transp_enabled & isTranslucent);
00521 }
00522 }
00523
00524
00525 void SGShadowVolume::SceneryObject::computeShadows(void) {
00526
00527
00528
00529
00530 if( !scenery_object ) {
00531 if( states->frameNumber - states->lastTraverseTreeFrame > 5 ) {
00532 find_trans();
00533 if( scenery_object )
00534 traverseTree( pending_object );
00535 states->lastTraverseTreeFrame = states->frameNumber;
00536 }
00537 return;
00538 }
00539 sgMat4 rotation, rotation_translation;
00540 scenery_object->getNetTransform ( rotation_translation );
00541
00542
00543
00544
00545 sgCopyMat4( rotation, rotation_translation );
00546 sgSetVec4( rotation[3], 0, 0, 0, 1);
00547
00548 ShadowCaster_list::iterator iShadowCaster;
00549 for(iShadowCaster = parts.begin() ; iShadowCaster != parts.end() ; iShadowCaster ++ ) {
00550 (*iShadowCaster)->computeShadows(rotation, rotation_translation, occluder_type);
00551 }
00552 }
00553
00554 static ssgCullResult cull_test ( ssgEntity *e, sgFrustum *f, sgMat4 m, int test_needed )
00555 {
00556 if ( ! test_needed )
00557 return SSG_INSIDE ;
00558
00559 sgSphere tmp = *(e->getBSphere()) ;
00560
00561 if ( tmp.isEmpty () )
00562 return SSG_OUTSIDE ;
00563
00564 tmp . orthoXform ( m ) ;
00565 if( tmp.center[2] == 0.0 )
00566 return SSG_STRADDLE;
00567
00568 if ( tmp.radius / sgAbs(tmp.center[2]) < 1.0 / 40.0 )
00569 return SSG_OUTSIDE ;
00570
00571 return (ssgCullResult) f -> contains ( &tmp ) ;
00572 }
00573
00574
00575 void SGShadowVolume::cull ( ssgBranch *b, sgFrustum *f, sgMat4 m, int test_needed )
00576 {
00577 int cull_result = cull_test ( (ssgEntity *) b, f, m, test_needed ) ;
00578
00579 if ( cull_result == SSG_OUTSIDE )
00580 return ;
00581 if( b->isA( ssgTypeTransform() ) ) {
00582
00583 SceneryObject_map::iterator iSceneryObject = sceneryObjects.find( b );
00584 if( iSceneryObject != sceneryObjects.end() ) {
00585 SceneryObject *an_occluder = iSceneryObject->second;
00586 if( shadowsTO_enabled && (an_occluder->occluder_type == occluderTypeTileObject) ||
00587 shadowsAI_enabled && (an_occluder->occluder_type == occluderTypeAI ) ||
00588 shadowsAC_enabled && (an_occluder->occluder_type == occluderTypeAircraft ) )
00589 an_occluder->computeShadows();
00590
00591 return;
00592 }
00593 sgMat4 tmp, transform ;
00594 sgCopyMat4 ( tmp, m ) ;
00595 ((ssgTransform *)b)->getTransform( transform );
00596 sgPreMultMat4 ( tmp, transform ) ;
00597 glPushMatrix () ;
00598 glLoadMatrixf ( (float *) tmp ) ;
00599 for ( ssgEntity *e = b->getKid ( 0 ) ; e != NULL ; e = b->getNextKid() )
00600 cull ( (ssgBranch *) e, f, tmp, cull_result != SSG_INSIDE ) ;
00601 glPopMatrix () ;
00602 } else if( b->isAKindOf( ssgTypeSelector() ) ) {
00603 int s = ((ssgSelector *) b)->getSelect() ;
00604 if( b->isA( ssgTypeRangeSelector() ) ) {
00605 float range = sgLengthVec3 ( m [ 3 ] ) ;
00606 s = (range < ((ssgRangeSelector *) b)->getRange(1) &&
00607 range >= ((ssgRangeSelector *) b)->getRange(0) ) ? 1 : 0;
00608 }
00609 for ( ssgEntity *e = b->getKid ( 0 ) ; e != NULL ; e = b->getNextKid(), s >>= 1 )
00610 if ( s & 1 )
00611 cull ( (ssgBranch *) e, f, m, cull_result != SSG_INSIDE ) ;
00612 } else if( b->isAKindOf( ssgTypeBranch() ) ) {
00613 char *name = b->getName();
00614
00615 if( name && !strcmp(name, "LocalTerrain") )
00616 return;
00617 for ( ssgEntity *e = b->getKid ( 0 ) ; e != NULL ; e = b->getNextKid() )
00618 if( ! e->isAKindOf( ssgTypeLeaf() ) )
00619 cull ( (ssgBranch *) e, f, m, cull_result != SSG_INSIDE ) ;
00620 }
00621 }
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635 static bool filterLeaf(ssgLeaf *this_kid) {
00636 const char *leaf_name = this_kid->getName();
00637
00638
00639
00640 if( ! leaf_name )
00641 return true;
00642 char lname[20];
00643 unsigned int l = 0;
00644 char *buff;
00645 for( buff = lname; *leaf_name && l < (sizeof( lname )-1); ++buff, l++ )
00646 *buff = tolower(*leaf_name++);
00647 *buff = 0;
00648 if( !strncmp(lname, "noshadow", 8) ) {
00649 SG_LOG(SG_ALL, SG_WARN, "use of deprecated noshadow prefix in '"
00650 << this_kid->getName() << '\'');
00651 return false;
00652 }
00653 return true;
00654 }
00655 void SGShadowVolume::SceneryObject::traverseTree(ssgBranch *branch) {
00656 int num_tri = 0;
00657 int num_leaf = 0;
00658
00659 if( sgCheckAnimationBranch( (ssgEntity *) branch ) ) {
00660 if( ((SGAnimation *) branch->getUserData())->get_animation_type() == 1)
00661 if( ((SGShadowAnimation *) branch->getUserData())->get_condition_value() )
00662 return;
00663 }
00664
00665 for(int i = 0 ; i < branch->getNumKids() ; i++) {
00666 ssgEntity *this_kid = branch->getKid( i );
00667 if( this_kid->isAKindOf(ssgTypeLeaf()) ) {
00668 if( filterLeaf( (ssgLeaf *) this_kid ) ) {
00669 num_tri += ((ssgLeaf *) this_kid)->getNumTriangles();
00670 num_leaf ++;
00671 }
00672 } else
00673 traverseTree( (ssgBranch *) this_kid );
00674 }
00675 if( num_tri > 0) {
00676 int tri_idx = 0;
00677 int ind_idx = 0;
00678 ShadowCaster *new_part = new ShadowCaster( num_tri, branch);
00679 new_part->scenery_object = scenery_object;
00680 new_part->lib_object = lib_object;
00681 new_part->isTranslucent = false;
00682 for(int i = 0 ; i < branch->getNumKids() ; i++) {
00683 ssgEntity *this_kid = branch->getKid( i );
00684 if( this_kid->isAKindOf(ssgTypeLeaf()) ) {
00685 if( filterLeaf( (ssgLeaf *) this_kid ) )
00686 new_part->addLeaf( tri_idx, ind_idx, (ssgLeaf *) this_kid );
00687 }
00688 }
00689
00690 if( occluder_type != SGShadowVolume::occluderTypeAircraft )
00691 new_part->isTranslucent = false;
00692 new_part->SetConnectivity();
00693 parts.push_back( new_part );
00694 }
00695 }
00696
00697 void SGShadowVolume::SceneryObject::find_trans(void) {
00698 ssgBranch *branch = pending_object;
00699
00700 while( branch && branch->getNumParents() > 0 ) {
00701 branch = branch->getParent(0);
00702 }
00703
00704 if( !branch->isA(ssgTypeRoot() ) )
00705 return;
00706 scenery_object = pending_object;
00707 }
00708
00709 SGShadowVolume::SceneryObject::SceneryObject(ssgBranch *_scenery_object, OccluderType _occluder_type) :
00710 scenery_object ( 0 ),
00711 pending_object ( _scenery_object ),
00712 occluder_type ( _occluder_type )
00713 {
00714
00715
00716 statObj++;
00717 if( occluder_type == SGShadowVolume::occluderTypeAircraft )
00718 lib_object = _scenery_object;
00719 else
00720 lib_object = (ssgBranch *) ((ssgBranch *)_scenery_object->getKid(0))->getKid(0);
00721 }
00722
00723 SGShadowVolume::SceneryObject::~SceneryObject()
00724 {
00725 ShadowCaster_list::iterator iParts;
00726 for(iParts = parts.begin() ; iParts != parts.end(); iParts++ ) {
00727 delete *iParts;
00728 }
00729 parts.clear();
00730 }
00731
00732 void SGShadowVolume::computeShadows(void) {
00733
00734
00735
00736 double dot_light = cos(sun_angle);
00737
00738 if( dot_light < 0.2 )
00739 return;
00740
00741
00742 glPushAttrib(GL_ALL_ATTRIB_BITS);
00743 glPushClientAttrib ( GL_CLIENT_VERTEX_ARRAY_BIT ) ;
00744 glDisableClientState ( GL_COLOR_ARRAY ) ;
00745 glDisableClientState ( GL_NORMAL_ARRAY ) ;
00746 glDisableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
00747
00748 if( use_alpha ) {
00749 glColorMask(0, 0, 0, 1);
00750 glClearColor(0.0, 0.0, 0.0, 0.0 );
00751 glClear(GL_COLOR_BUFFER_BIT);
00752 glDisable(GL_ALPHA);
00753 glEnable(GL_BLEND);
00754 } else {
00755 glClearStencil( 0 );
00756 glClear(GL_STENCIL_BUFFER_BIT);
00757 glColorMask(0, 0, 0, 0);
00758 glEnable(GL_STENCIL_TEST);
00759 glDisable(GL_ALPHA);
00760 glDisable(GL_BLEND);
00761 }
00762 glDisable( GL_LIGHTING );
00763 glDisable( GL_FOG );
00764 glEnable( GL_CULL_FACE );
00765
00766 glPolygonOffset(0.0,2.0);
00767
00768 glEnable(GL_POLYGON_OFFSET_FILL);
00769
00770 glShadeModel(GL_FLAT);
00771
00772 glDepthMask( false );
00773 glEnable( GL_DEPTH_TEST );
00774 glDepthFunc(GL_LESS);
00775
00776 {
00777 float w, h;
00778 sgFrustum frustum;
00779 sgEnviro.getFOV( w, h );
00780 frustum.setFOV( w, h );
00781 frustum.setNearFar(0.1f, 5000.0f);
00782 sgMat4 m;
00783 ssgGetModelviewMatrix( m );
00784 cull( ssg_root, &frustum, m, true);
00785 }
00786
00787
00788 glMatrixMode ( GL_PROJECTION ) ;
00789 glPushMatrix () ;
00790 glLoadIdentity () ;
00791 glOrtho ( -100, 100, -100, 100, -1, 1 ) ;
00792 glMatrixMode ( GL_MODELVIEW ) ;
00793 glPushMatrix () ;
00794 glLoadIdentity () ;
00795
00796 glDisable(GL_DEPTH_TEST);
00797 glDisable(GL_CULL_FACE);
00798
00799 glPolygonMode(GL_FRONT, GL_FILL);
00800 if( use_alpha ) {
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812 glBlendEquationPtr( GL_MIN_EXT );
00813 glBlendFunc( GL_DST_COLOR, GL_ONE );
00814 glColor4ub(1, 1, 1, 16);
00815 glRectf(-100,-100,100,100);
00816
00817 glBlendEquationPtr( GL_FUNC_ADD );
00818 glBlendFunc( GL_DST_COLOR, GL_ONE );
00819 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
00820 glRectf(-100,-100,100,100);
00821 glRectf(-100,-100,100,100);
00822
00823 glBlendFunc( GL_ONE_MINUS_DST_COLOR, GL_ZERO );
00824 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
00825 glRectf(-100,-100,100,100);
00826
00827 glColorMask(1, 1, 1, 1);
00828 glBlendFunc( GL_ZERO, GL_DST_ALPHA );
00829 glColor4f(1.0f, 0.5f, 0.2f, 1.0f);
00830 glRectf(-100,-100,100,100);
00831 } else {
00832
00833
00834
00835 glColorMask(1, 1, 1, 1);
00836 glStencilFunc(GL_NOTEQUAL, 0, ~0);
00837 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
00838 glEnable(GL_STENCIL_TEST);
00839 glEnable(GL_ALPHA);
00840 glAlphaFunc(GL_GREATER, 0.0f);
00841 glEnable(GL_BLEND);
00842 glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
00843 glColor4f(0.0, 0.0, 0.0, sgLerp(0.1, 0.3, dot_light) );
00844
00845 glColor4f(0.0, 0.0, 0.0, 0.3 );
00846 glRectf(-100,-100,100,100);
00847 }
00848 glMatrixMode ( GL_PROJECTION ) ;
00849 glPopMatrix () ;
00850 glMatrixMode ( GL_MODELVIEW ) ;
00851 glPopMatrix () ;
00852
00853 glDisable(GL_STENCIL_TEST);
00854 glPopClientAttrib ( ) ;
00855 glPopAttrib();
00856 }
00857
00858 SGShadowVolume::SGShadowVolume( ssgBranch *root ) :
00859 shadows_enabled( false ),
00860 frameNumber( 0 ),
00861 lastTraverseTreeFrame ( 0 ),
00862 ssg_root( root ),
00863 shadows_rendered( false )
00864 {
00865 states = this;
00866 }
00867
00868 SGShadowVolume::~SGShadowVolume() {
00869 SceneryObject_map::iterator iSceneryObject;
00870 for(iSceneryObject = sceneryObjects.begin() ; iSceneryObject != sceneryObjects.end(); iSceneryObject++ ) {
00871 delete iSceneryObject->second;
00872 }
00873 sceneryObjects.clear();
00874 }
00875
00876 void SGShadowVolume::init(SGPropertyNode *sim_rendering_options) {
00877 shadows_enabled = true;
00878 sim_rendering = sim_rendering_options;
00879 GLint stencilBits = 0, alphaBits = 0;
00880 glGetIntegerv( GL_STENCIL_BITS, &stencilBits );
00881 glGetIntegerv( GL_ALPHA_BITS, &alphaBits );
00882 bool hasSubtractiveBlend = SGIsOpenGLExtensionSupported("GL_EXT_blend_subtract");
00883 bool hasMinMaxBlend = SGIsOpenGLExtensionSupported("GL_EXT_blend_minmax");
00884 if( hasSubtractiveBlend )
00885 glBlendEquationPtr = (glBlendEquationProc ) SGLookupFunction("glBlendEquationEXT");
00886 canDoAlpha = (alphaBits >= 8) && hasSubtractiveBlend && hasMinMaxBlend;
00887 canDoStencil = (stencilBits >= 3);
00888 if( !canDoStencil )
00889 if( canDoAlpha )
00890 SG_LOG(SG_ALL, SG_WARN, "SGShadowVolume:no stencil buffer, using alpha buffer");
00891 else
00892 SG_LOG(SG_ALL, SG_WARN, "SGShadowVolume:no stencil buffer and no alpha buffer");
00893 }
00894
00895 void SGShadowVolume::startOfFrame(void) {
00896 }
00897 void SGShadowVolume::deleteOccluderFromTile(ssgBranch *tile) {
00898 SceneryObject_map::iterator iSceneryObject;
00899 for(iSceneryObject = sceneryObjects.begin() ; iSceneryObject != sceneryObjects.end(); ) {
00900 SceneryObject_map::iterator iCurrent = iSceneryObject ++;
00901 if( iCurrent->second->tile == tile ) {
00902 delete iCurrent->second;
00903 sceneryObjects.erase( iCurrent );
00904 }
00905 }
00906 }
00907
00908 void SGShadowVolume::deleteOccluder(ssgBranch *occluder) {
00909
00910 while( occluder && !occluder->isA(ssgTypeTransform()))
00911 occluder = (ssgBranch *) occluder->getKid(0);
00912
00913
00914 SceneryObject_map::iterator iSceneryObject = sceneryObjects.find( occluder );
00915 if( iSceneryObject != sceneryObjects.end() ) {
00916 delete iSceneryObject->second;
00917 sceneryObjects.erase( occluder );
00918 }
00919 }
00920
00921 void SGShadowVolume::addOccluder(ssgBranch *occluder, OccluderType occluder_type, ssgBranch *tile) {
00922
00923 while( occluder && !occluder->isA(ssgTypeTransform()))
00924 occluder = (ssgBranch *) occluder->getKid(0);
00925
00926
00927 SceneryObject_map::iterator iSceneryObject = sceneryObjects.find( occluder );
00928 if( iSceneryObject == sceneryObjects.end() ) {
00929
00930 SceneryObject *entry = new SceneryObject( occluder, occluder_type );
00931 entry->tile = tile;
00932 sceneryObjects[ occluder ] = entry;
00933 }
00934
00935 }
00936
00937 void SGShadowVolume::setupShadows( double lon, double lat,
00938 double gst, double SunRightAscension, double SunDeclination, double sunAngle) {
00939
00940 #ifdef __APPLE__
00941
00942
00943
00944
00945 static bool re_initialized = false;
00946 if (!re_initialized) {
00947 this->init(sim_rendering);
00948 re_initialized = true;
00949 }
00950 #endif
00951 shadowsAC_enabled = sim_rendering->getBoolValue("shadows-ac", false);
00952 shadowsAC_transp_enabled = sim_rendering->getBoolValue("shadows-ac-transp", false);
00953 shadowsAI_enabled = sim_rendering->getBoolValue("shadows-ai", false);
00954 shadowsTO_enabled = sim_rendering->getBoolValue("shadows-to", false);
00955 shadowsDebug_enabled = sim_rendering->getBoolValue("shadows-debug", false);
00956 shadows_enabled = shadowsAC_enabled || shadowsAI_enabled || shadowsTO_enabled;
00957 shadows_enabled &= canDoAlpha || canDoStencil;
00958 use_alpha = ((!canDoStencil) || sim_rendering->getBoolValue("shadows-alpha", false)) &&
00959 canDoAlpha;
00960
00961 if( ! shadows_enabled )
00962 return;
00963
00964 shadows_rendered = false;
00965 sun_angle = sunAngle;
00966 {
00967 sgMat4 GST, RA, DEC;
00968 sgVec3 axis;
00969
00970
00971 sgSetVec3( axis, 0.0, 0.0, -1.0 );
00972 sgMakeRotMat4( GST, (gst) * 15.0, axis );
00973
00974 sgSetVec3( axis, 0.0, 0.0, 1.0 );
00975 sgMakeRotMat4( RA, (SunRightAscension * SGD_RADIANS_TO_DEGREES) - 90.0, axis );
00976
00977 sgSetVec3( axis, 1.0, 0.0, 0.0 );
00978 sgMakeRotMat4( DEC, SunDeclination * SGD_RADIANS_TO_DEGREES, axis );
00979
00980 sgMat4 TRANSFORM;
00981 sgMakeIdentMat4( TRANSFORM );
00982 sgPreMultMat4( TRANSFORM, GST );
00983 sgPreMultMat4( TRANSFORM, RA );
00984 sgPreMultMat4( TRANSFORM, DEC );
00985 sgSetVec3( sunPos, 0.0, 9900000.0, 0.0);
00986 sgXformPnt3( sunPos, TRANSFORM );
00987 }
00988
00989 ssgGetModelviewMatrix( CameraViewM );
00990
00991 }
00992
00993 void SGShadowVolume::endOfFrame(void) {
00994 if( ! shadows_enabled )
00995 return;
00996 if( shadows_rendered )
00997 return;
00998 glBindTexture(GL_TEXTURE_2D, 0);
00999 glBindTexture(GL_TEXTURE_1D, 0);
01000
01001 glMatrixMode(GL_MODELVIEW);
01002 computeShadows();
01003 frameNumber ++;
01004 shadows_rendered = true;
01005 }
01006
01007 int SGShadowVolume::ACpostTravCB( ssgEntity *entity, int traversal_mask ) {
01008 if( states->shadowsAC_transp_enabled && (SSGTRAV_CULL & traversal_mask) )
01009 states->endOfFrame();
01010 return 0;
01011 }
01012