SoShadowLight.cpp

Go to the documentation of this file.
00001 
00007 /* ---------------------------------------------------------------------------
00008  * Authors:      Tomáš Burian (tburian _AT centrum.cz)
00009  * Thanks to:    PCJohn (peciva _AT fit.vutbr.cz)
00010  * Contributors:
00011  *
00012  * THIS SOFTWARE IS NOT COPYRIGHTED
00013  *
00014  * This source code is offered for use in the public domain.
00015  * You may use, modify or distribute it freely.
00016  *
00017  * This source code is distributed in the hope that it will be useful but
00018  * WITHOUT ANY WARRANTY.  ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
00019  * DISCLAIMED.  This includes but is not limited to warranties of
00020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00021  *
00022  * If you find the source code useful, authors will kindly welcome
00023  * if you give them credit and keep their names with their source code,
00024  * but do not feel to be forced to do so.
00025  * ---------------------------------------------------------------------------
00026  */
00027 
00028 //----------------------------------------------------------------------------
00029 // INCLUDEs
00030 //----------------------------------------------------------------------------
00031 
00032 #include "SoShadowLight.h"
00033 #include "SoShadowVolume.h"
00034 
00035 //----------------------------------------------------------------------------
00036 // IMPLEMENTATION
00037 //----------------------------------------------------------------------------
00038 
00045 GLboolean SoShadowLight::CheckExtension( char * extName )
00046 {
00047   /*
00048    ** Search for extName in the extensions string.  Use of strstr()
00049    ** is not sufficient because extension names can be prefixes of
00050    ** other extension names.  Could use strtok() but the constant
00051    ** string returned by glGetString can be in read-only memory.
00052    */
00053   char *p = (char *) glGetString(GL_EXTENSIONS);
00054   char *end = NULL;
00055   int extNameLen;
00056 
00057   extNameLen = (int)strlen(extName);
00058   end = p + strlen(p);
00059 
00060   while (p < end) {
00061       int n = (int)strcspn(p, " ");
00062       if ((extNameLen == n) && (strncmp(extName, p, n) == 0)) {
00063           return GL_TRUE;
00064       }
00065       p += (n + 1);
00066   }
00067   return GL_FALSE;
00068 }
00069 
00070 
00071 GLenum SoShadowLight::incValue = GL_INCR;
00072 GLenum SoShadowLight::decValue = GL_DECR;
00073  
00074 float SoShadowLight::envIntensity = 0.0f;
00075 
00076 
00080 void SoShadowLight::checkStencilExt()
00081 {
00082 /*
00083   int bits, max;   
00084   glGetIntegerv(GL_STENCIL_BITS, &bits);
00085   max = (1 << bits) - 1;
00086   printf("max stencil vals: %d\n",max);
00087 */
00088 
00089   // const GLubyte * extStr = glGetString(GL_EXTENSIONS);
00090   // printf("GL ext: %s\n",extStr);
00091 
00092 /*
00093   GLenum incValue = GL_INCR;
00094   GLenum decValue = GL_DECR;
00095 */
00096   if ( CheckExtension("GL_EXT_stencil_wrap") )
00097   {
00098     incValue = GL_INCR_WRAP_EXT;
00099     decValue = GL_DECR_WRAP_EXT;
00100   }
00101   else
00102   {
00103     incValue = GL_INCR;
00104     decValue = GL_DECR;  
00105   }
00106 
00107 }
00108 
00115 SoShadowLight::SoShadowLight(CShadowManager * sm, SoLight * l)
00116     : manager(sm),
00117       light(l)
00118 {  
00119   nameIndex = -1;
00120   status = TRUE;
00121 
00122   pstatus = &this->status;
00123 
00124   lightRenderRoot = new SoSeparator;
00125   lightRenderRoot->setName("lightRenderRoot");
00126   lightRenderRoot->ref();  
00127 
00128   // switchNode = new SoSwitch(10); // problem with z-fail
00129 
00130   volumesRoot = new SoSeparator;
00131   volumesRoot->setName("volumesRoot");
00132   volumesRoot->ref();
00133 
00134   init();  
00135 }
00136 
00137 
00141 SoShadowLight::~SoShadowLight()
00142 {
00143   // sensor must be detached 
00144   this->sensor->detach();
00145   this->removeAllChildren();
00146 
00147   lightRenderRoot->unref();
00148 
00149   volumesRoot->unref();
00150 }
00151 
00152 
00158 void SoShadowLight::init()
00159 {
00160 
00161   // problem with z-fail
00162 /*
00163   switchNode->whichChild.setValue(SO_SWITCH_ALL);
00164      
00165 
00166   struct TLightSwitch * switchPair = new struct TLightSwitch;
00167   switchPair->switchNode = this->switchNode;
00168   switchPair->status = this->pstatus;
00169 
00170   SoCallback * lightStatusCallback = new SoCallback;
00171   lightStatusCallback->setCallback(lightStatusCB, switchPair );
00172 
00173   this->addChild(lightStatusCallback);
00174   this->switchNode->addChild(lightRenderRoot);
00175   this->addChild(switchNode);
00176 */
00177   // instead of to SoSwitch add lightRoot direct to this
00178   this->addChild(lightRenderRoot);
00179 
00180 
00181 /*  
00182 //
00183   // testy hodnot pro polygon offset
00184   pOffset->factor.setValue(0.1f); // 0.01? martyn
00185   pOffset->factor.setValue(0.1f); // 0.1 - TB vyzkouseno
00186   
00187   pOffset->factor.setValue(1.f); // test - asi ano, ale pro simple_ship se delaji hrany :(
00188 
00189   pOffset->units.setValue(50.0f); // 
00190   pOffset->units.setValue(50.0f); // TB - vypada OK
00191 
00192   // stadion
00193   pOffset->factor.setValue(0.01f); // 0.01? martyn
00194   pOffset->units.setValue(50.0f); // 1
00195 //
00196 */
00197   // Polygon offset (need for zfail) must be set exactly like this
00198   SoPolygonOffset * pOffset = new SoPolygonOffset;
00199 
00200   pOffset->factor.setValue(0.1f); // default
00201   pOffset->units.setValue(50.0f); // default
00202 
00203   pOffset->styles.setValue(SoPolygonOffset::FILLED);
00204 
00205   // rendering callbacks
00206   SoCallback * incrementStencilCallback = new SoCallback;
00207   incrementStencilCallback->setCallback(incrementStencilCB, this->manager->getAlgorithm() ); // this->manager->getAlgorithm2()   //this->settings
00208 
00209   SoCallback * decrementStencilCallback = new SoCallback;
00210   decrementStencilCallback->setCallback(decrementStencilCB, this->manager->getAlgorithm() ); //this->settings
00211 
00212   SoCallback * shadowCallback = new SoCallback;
00213 
00214   struct TLightInfo * linfo = new struct TLightInfo;
00215   linfo->light = this->light;
00216   linfo->status = this->pstatus;
00217   linfo->globEnv = this->manager->getEnvironmentNode();
00218   shadowCallback->setCallback(litStencilCB, linfo);
00219 
00220   SoCallback * finishStencilCallback = new SoCallback;
00221   finishStencilCallback->setCallback(finishStencilCB, linfo);
00222   // end of rendering callbacks
00223 
00224   // Create a super root with callbacks and add scene, shadows and 
00225   // callbacks to switch stencil buffer settings for rendering shadows.
00226 
00227   //
00228   // create shadows scene graph
00229   //
00230   if ( this->manager->readSettings()->dropShadows ) // create shadows
00231   {           
00232     this->lightRenderRoot->addChild(incrementStencilCallback);        
00233     this->lightRenderRoot->addChild(pOffset);
00234     this->lightRenderRoot->addChild(this->volumesRoot);
00235     this->lightRenderRoot->addChild(decrementStencilCallback);
00236     this->lightRenderRoot->addChild(this->volumesRoot);
00237     this->lightRenderRoot->addChild(shadowCallback);
00238     this->lightRenderRoot->addChild(this->manager->getSceneRoot());
00239     this->lightRenderRoot->addChild(finishStencilCallback);    
00240   } 
00241   else // shadow volumes only, no shadows
00242   {    
00243     this->lightRenderRoot->addChild(this->manager->getSceneRoot());
00244     this->lightRenderRoot->addChild(pOffset);
00245     this->lightRenderRoot->addChild(this->volumesRoot);
00246   } 
00247 }
00248 
00249 
00255 CShadowManager * SoShadowLight::getManager()
00256 {
00257   return this->manager;
00258 }
00259 
00260 
00266 SoLight * SoShadowLight::getLight()
00267 {
00268   return this->light;
00269 }
00270 
00271 
00277 void SoShadowLight::setLightName(int lightIndex)
00278 {
00279   SbString index(lightIndex);
00280   SbString name = "Light_";
00281   name += index;
00282   ONDEBUG( printf("-- light name: %s\n",name.getString()) );
00283   this->nameIndex = lightIndex;
00284   this->setName(name);
00285 }
00286 
00287 
00293 int SoShadowLight::getLightName()
00294 {
00295   return this->nameIndex;
00296 }
00297 
00298 
00304 void SoShadowLight::setSensor(SoNodeSensor * sensor)
00305 {
00306   this->sensor = sensor;
00307 }
00308 
00309 
00315 SoNodeSensor * SoShadowLight::getSensor()
00316 {
00317   return this->sensor;
00318 }
00319 
00320 
00321 
00327 void SoShadowLight::addVolume(SoSeparator * volume)
00328 {
00329   ONDEBUG( printf("--SoShadowLight::addVolume()\n") );
00330   this->volumesRoot->addChild(volume);
00331 }
00332 
00333 
00337 void SoShadowLight::deleteVolumes()
00338 {
00339   ONDEBUG( printf("--SoShadowLight::deleteVolumes()\n") );
00340   this->volumesRoot->removeAllChildren();
00341 }
00342 
00343 
00349 void SoShadowLight::deleteVolume(int casterName)
00350 {
00351   ONDEBUG( printf("--SoShadowLight::deleteVolume()\n") );
00352   int cnt = this->volumesRoot->getNumChildren();
00353   if ( cnt > 0 )
00354   {
00355     for ( int j = 0; j < cnt; j++ )
00356     {
00357       SoShadowVolume * volume = static_cast<SoShadowVolume *> (this->volumesRoot->getChild(j));
00358       if (volume->getCasterName() == casterName)
00359       {
00360         this->volumesRoot->removeChild(j);
00361       }
00362     }
00363   }
00364 
00365 }
00366 
00367 
00373 int SoShadowLight::getNumVolumes()
00374 {
00375   return this->volumesRoot->getNumChildren();
00376 }
00377 
00378 
00386 SoSeparator * SoShadowLight::getVolume(int i)
00387 {
00388   SoSeparator * volume = static_cast<SoSeparator *> (this->volumesRoot->getChild(i));
00389   return volume;
00390 }
00391 
00392 
00396 void SoShadowLight::createShadowVolumes()
00397 {
00398   ONDEBUG( printf("--SoShadowLight::createShadowVolumes()\n") );
00399 
00400 
00401   int cnt = this->volumesRoot->getNumChildren();
00402   ONDEBUG( printf("--SoShadowLight:: vol. root cnt: %d\n",cnt) );
00403   for (int i = 0; i < cnt; i++) // create SV for one light
00404   {
00405     SoShadowVolume * volume = static_cast<SoShadowVolume *>(this->volumesRoot->getChild(i));
00406     volume->create(); // this->nameIndex -1
00407   }
00408 
00409 }
00410 
00416 void SoShadowLight::createShadowVolumes(int caster)
00417 {
00418   ONDEBUG( printf("--SoShadowLight::createShadowVolumes()\n") );
00419 
00420 
00421   int cnt = this->volumesRoot->getNumChildren();
00422   ONDEBUG( printf("--SoShadowLight:: vol. root cnt: %d\n",cnt) );
00423   for (int i = 0; i < cnt; i++) // create SV for one light
00424   {
00425     SoShadowVolume * volume = static_cast<SoShadowVolume *>(this->getChild(i));
00426     if (volume->getCasterName() == caster )
00427     {
00428       volume->create();
00429       break;
00430     }
00431   }
00432 
00433 }
00434 
00435 
00437 // Shadow rendering callbacks
00439 
00440 /*
00441  * According to the light status enables/disables rendering traversal 
00442  * of shadow volumes under the light.
00443  *
00444  * Sets stencil test according to the chosen algorithm.
00445  *
00446  * @param userdata Pointer to the pair of saved light status and the switch node.
00447  * @param action Pointer to the callback action.
00448  */
00449 /*
00450 void SoShadowLight::lightStatusCB(void *userdata, SoAction *action)
00451 { 
00452   if (action->isOfType(SoGLRenderAction::getClassTypeId()))
00453   {       
00454     struct TLightSwitch * switchPair = (TLightSwitch *) userdata;
00455     ONDEBUG(printf("lightStatusCB light is %d\n", *switchPair->status ));
00456     if ( *switchPair->status == TRUE )
00457     {
00458       switchPair->switchNode->whichChild.enableNotify(FALSE);
00459       switchPair->switchNode->whichChild.setValue(SO_SWITCH_ALL);
00460       switchPair->switchNode->whichChild.enableNotify(TRUE);
00461       // check stencil extension
00462       checkStencilExt();
00463     }
00464     else
00465     {
00466       switchPair->switchNode->whichChild.enableNotify(FALSE);
00467       switchPair->switchNode->whichChild.setValue(SO_SWITCH_NONE);
00468       switchPair->switchNode->whichChild.enableNotify(TRUE);
00469     }
00470   }
00471 }
00472 */
00473 
00474 
00483 void SoShadowLight::incrementStencilCB(void *userdata, SoAction *action)
00484 {  
00485   if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
00486     ONDEBUG(printf("incrementStencilCB\n"));    
00487 
00488     // check stencil extension
00489     checkStencilExt();
00490 
00491 
00492     glPopAttrib();
00493     
00494     glPushAttrib(GL_ALL_ATTRIB_BITS);
00495 
00496     glClear( GL_STENCIL_BUFFER_BIT );    
00497     
00498     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
00499     glShadeModel(GL_FLAT);
00500     glDepthMask(GL_FALSE);
00501     glDepthFunc(GL_LESS);
00502     glEnable(GL_STENCIL_TEST);
00503 
00504     enum TShadowAlgorithm * algorithm = (TShadowAlgorithm *) userdata;
00505     if ( *algorithm == zfailAlg ) {
00506       ONDEBUG(printf("incrementStencilCB: zfail\n"));
00507       // z-fail
00508       //Increment stencil buffer for back face depth fail
00509       glStencilFunc(GL_ALWAYS, 0, ~0);
00510       // glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
00511       glStencilOp(GL_KEEP, incValue, GL_KEEP);
00512       glCullFace(GL_FRONT);
00513     } else {
00514       ONDEBUG(printf("incrementStencilCB: zpass\n"));
00515       // z-pass
00516       //Increment stencil buffer for front face depth pass
00517       glStencilFunc(GL_ALWAYS, 0, ~0);
00518       // glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
00519       glStencilOp(GL_KEEP, GL_KEEP, incValue);
00520       glCullFace(GL_BACK);
00521     }
00522   }
00523 } 
00524 
00525 
00534 void SoShadowLight::decrementStencilCB(void *userdata, SoAction *action)
00535 {  
00536   if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
00537     ONDEBUG(printf("decrementStencilCB\n"));
00538 
00539     enum TShadowAlgorithm * algorithm = (TShadowAlgorithm *) userdata;
00540     if ( *algorithm == zfailAlg ) {
00541       ONDEBUG(printf("decrementStencilCB: zfail\n"));
00542       // z-fail
00543       // Decrement stencil buffer for back face depth pass
00544       // glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
00545       glStencilOp(GL_KEEP, decValue, GL_KEEP);
00546       glCullFace(GL_BACK);
00547     } else {
00548       ONDEBUG(printf("decrementStencilCB: zpass\n"));
00549       // z-pass
00550       // Decrement stencil buffer for front face depth pass
00551       // glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
00552       glStencilOp(GL_KEEP, GL_KEEP, decValue);
00553       glCullFace(GL_FRONT);
00554     }
00555   }
00556 } 
00557 
00558 
00570 void SoShadowLight::litStencilCB(void *userdata, SoAction *action)
00571 {  
00572   if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
00573 
00574     ONDEBUG(printf("litStencilCB\n"));
00575 
00576     glPopAttrib();
00577 
00578     // Draw lit where stencil == 0
00579 
00580     glPushAttrib(GL_ENABLE_BIT);
00581 
00582     struct TLightInfo * linfo = (struct TLightInfo * ) userdata;
00583 
00584     // disable ambient light (additive blending)
00585     // (save ambient int. value)
00586     if ( linfo->globEnv != NULL )
00587     {
00588       linfo->globEnv->ambientIntensity.enableNotify(FALSE);
00589       envIntensity = linfo->globEnv->ambientIntensity.getValue();
00590       linfo->globEnv->ambientIntensity.setValue(0.0f);
00591       linfo->globEnv->ambientIntensity.enableNotify(TRUE);
00592     }
00593 
00594     // turn on the light (set the light to its saved value on/off)
00595     linfo->light->enableNotify(FALSE);
00596     linfo->light->on = *linfo->status;    
00597     linfo->light->enableNotify(TRUE);
00598 
00599     glEnable(GL_LIGHTING);
00600 
00601     glBlendFunc(GL_ONE, GL_ONE);
00602     glEnable(GL_BLEND);    
00603    
00604     // set stencil test
00605     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00606     glDepthFunc(GL_EQUAL);
00607     glStencilFunc(GL_EQUAL, 0, ~0);
00608     glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
00609     glEnable(GL_STENCIL_TEST);
00610 
00611   }
00612 } 
00613 
00614 
00624 void SoShadowLight::finishStencilCB(void *userdata, SoAction *action)
00625 {  
00626   if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
00627     ONDEBUG(printf("finishStencilCB\n"));
00628 
00629     glPopAttrib();    
00630 
00631     glDisable(GL_LIGHTING);
00632 
00633     glDisable(GL_STENCIL_TEST);
00634 
00635     glDisable(GL_BLEND);
00636 
00637     glPushAttrib(GL_ENABLE_BIT);
00638         
00639     struct TLightInfo * linfo = (struct TLightInfo * ) userdata;
00640 
00641     // enable ambient light 
00642     if ( linfo->globEnv != NULL )
00643     {
00644       linfo->globEnv->ambientIntensity.enableNotify(FALSE);
00645       linfo->globEnv->ambientIntensity.setValue(envIntensity);
00646       linfo->globEnv->ambientIntensity.enableNotify(TRUE);
00647     }
00648 
00649     // turn off the light
00650     linfo->light->enableNotify(FALSE);
00651     linfo->light->on = FALSE;
00652     linfo->light->enableNotify(TRUE);    
00653   }
00654 } 
00655 

Generated on Wed May 17 17:27:52 2006 for Shadow Engine by  doxygen 1.4.6-NO