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   linfo->sceneType = (int *)this->manager->psceneType;
00219 
00220   shadowCallback->setCallback(litStencilCB, linfo);
00221 
00222   SoCallback * finishStencilCallback = new SoCallback;
00223   finishStencilCallback->setCallback(finishStencilCB, linfo);
00224   // end of rendering callbacks
00225 
00226   // Create a super root with callbacks and add scene, shadows and 
00227   // callbacks to switch stencil buffer settings for rendering shadows.
00228 
00229   //
00230   // create shadows scene graph
00231   //
00232   if ( this->manager->readSettings()->dropShadows ) // create shadows
00233   {           
00234     this->lightRenderRoot->addChild(incrementStencilCallback);        
00235     this->lightRenderRoot->addChild(pOffset);
00236     this->lightRenderRoot->addChild(this->volumesRoot);
00237     this->lightRenderRoot->addChild(decrementStencilCallback);
00238     this->lightRenderRoot->addChild(this->volumesRoot);
00239     this->lightRenderRoot->addChild(shadowCallback);
00240     this->lightRenderRoot->addChild(this->manager->getSceneRoot());
00241     this->lightRenderRoot->addChild(finishStencilCallback);    
00242   } 
00243   else // shadow volumes only, no shadows
00244   {    
00245     this->lightRenderRoot->addChild(this->manager->getSceneRoot());
00246     this->lightRenderRoot->addChild(pOffset);
00247     this->lightRenderRoot->addChild(this->volumesRoot);
00248   } 
00249 }
00250 
00251 
00257 CShadowManager * SoShadowLight::getManager()
00258 {
00259   return this->manager;
00260 }
00261 
00262 
00268 SoLight * SoShadowLight::getLight()
00269 {
00270   return this->light;
00271 }
00272 
00273 
00279 void SoShadowLight::setLightName(int lightIndex)
00280 {
00281   SbString index(lightIndex);
00282   SbString name = "Light_";
00283   name += index;
00284   ONDEBUG( printf("-- light name: %s\n",name.getString()) );
00285   this->nameIndex = lightIndex;
00286   this->setName(name);
00287 }
00288 
00289 
00295 int SoShadowLight::getLightName()
00296 {
00297   return this->nameIndex;
00298 }
00299 
00300 
00306 void SoShadowLight::setSensor(SoNodeSensor * sensor)
00307 {
00308   this->sensor = sensor;
00309 }
00310 
00311 
00317 SoNodeSensor * SoShadowLight::getSensor()
00318 {
00319   return this->sensor;
00320 }
00321 
00322 
00323 
00329 void SoShadowLight::addVolume(SoSeparator * volume)
00330 {
00331   ONDEBUG( printf("--SoShadowLight::addVolume()\n") );
00332   this->volumesRoot->addChild(volume);
00333 }
00334 
00335 
00339 void SoShadowLight::deleteVolumes()
00340 {
00341   ONDEBUG( printf("--SoShadowLight::deleteVolumes()\n") );
00342   this->volumesRoot->removeAllChildren();
00343 }
00344 
00345 
00351 void SoShadowLight::deleteVolume(int casterName)
00352 {
00353   ONDEBUG( printf("--SoShadowLight::deleteVolume()\n") );
00354   int cnt = this->volumesRoot->getNumChildren();
00355   if ( cnt > 0 )
00356   {
00357     for ( int j = 0; j < cnt; j++ )
00358     {
00359       SoShadowVolume * volume = static_cast<SoShadowVolume *> (this->volumesRoot->getChild(j));
00360       if (volume->getCasterName() == casterName)
00361       {
00362         this->volumesRoot->removeChild(j);
00363       }
00364     }
00365   }
00366 
00367 }
00368 
00369 
00375 int SoShadowLight::getNumVolumes()
00376 {
00377   return this->volumesRoot->getNumChildren();
00378 }
00379 
00380 
00388 SoSeparator * SoShadowLight::getVolume(int i)
00389 {
00390   SoSeparator * volume = static_cast<SoSeparator *> (this->volumesRoot->getChild(i));
00391   return volume;
00392 }
00393 
00394 
00398 void SoShadowLight::createShadowVolumes()
00399 {
00400   ONDEBUG( printf("--SoShadowLight::createShadowVolumes()\n") );
00401 
00402 
00403   int cnt = this->volumesRoot->getNumChildren();
00404   ONDEBUG( printf("--SoShadowLight:: vol. root cnt: %d\n",cnt) );
00405   for (int i = 0; i < cnt; i++) // create SV for one light
00406   {
00407     SoShadowVolume * volume = static_cast<SoShadowVolume *>(this->volumesRoot->getChild(i));
00408     volume->create(); // this->nameIndex -1
00409   }
00410 
00411 }
00412 
00418 void SoShadowLight::createShadowVolumes(int caster)
00419 {
00420   ONDEBUG( printf("--SoShadowLight::createShadowVolumes()\n") );
00421 
00422 
00423   int cnt = this->volumesRoot->getNumChildren();
00424   ONDEBUG( printf("--SoShadowLight:: vol. root cnt: %d\n",cnt) );
00425   for (int i = 0; i < cnt; i++) // create SV for one light
00426   {
00427     SoShadowVolume * volume = static_cast<SoShadowVolume *>(this->getChild(i));
00428     if (volume->getCasterName() == caster )
00429     {
00430       volume->create();
00431       break;
00432     }
00433   }
00434 
00435 }
00436 
00437 
00439 // Shadow rendering callbacks
00441 
00442 /*
00443  * According to the light status enables/disables rendering traversal 
00444  * of shadow volumes under the light.
00445  *
00446  * Sets stencil test according to the chosen algorithm.
00447  *
00448  * @param userdata Pointer to the pair of saved light status and the switch node.
00449  * @param action Pointer to the callback action.
00450  */
00451 /*
00452 void SoShadowLight::lightStatusCB(void *userdata, SoAction *action)
00453 { 
00454   if (action->isOfType(SoGLRenderAction::getClassTypeId()))
00455   {       
00456     struct TLightSwitch * switchPair = (TLightSwitch *) userdata;
00457     ONDEBUG(printf("lightStatusCB light is %d\n", *switchPair->status ));
00458     if ( *switchPair->status == TRUE )
00459     {
00460       switchPair->switchNode->whichChild.enableNotify(FALSE);
00461       switchPair->switchNode->whichChild.setValue(SO_SWITCH_ALL);
00462       switchPair->switchNode->whichChild.enableNotify(TRUE);
00463       // check stencil extension
00464       checkStencilExt();
00465     }
00466     else
00467     {
00468       switchPair->switchNode->whichChild.enableNotify(FALSE);
00469       switchPair->switchNode->whichChild.setValue(SO_SWITCH_NONE);
00470       switchPair->switchNode->whichChild.enableNotify(TRUE);
00471     }
00472   }
00473 }
00474 */
00475 
00476 
00485 void SoShadowLight::incrementStencilCB(void *userdata, SoAction *action)
00486 {  
00487   if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
00488     ONDEBUG(printf("incrementStencilCB\n"));    
00489 
00490     // check stencil extension
00491     checkStencilExt();
00492 
00493     glPopAttrib();
00494     
00495     glPushAttrib(GL_ALL_ATTRIB_BITS);
00496 
00497     glClear(GL_STENCIL_BUFFER_BIT);
00498     
00499     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
00500     glShadeModel(GL_FLAT);
00501     glDepthMask(GL_FALSE);
00502     glDepthFunc(GL_LESS);
00503     glEnable(GL_STENCIL_TEST);
00504     glStencilFunc(GL_ALWAYS, 0, ~0);
00505 
00506     enum TShadowAlgorithm * algorithm = (TShadowAlgorithm *) userdata;
00507     if ( *algorithm == zfailAlg ) {
00508       ONDEBUG(printf("incrementStencilCB: zfail\n"));
00509       // z-fail
00510       //Increment stencil buffer for back face depth fail            
00511       // glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
00512       glStencilOp(GL_KEEP, incValue, GL_KEEP);
00513       glCullFace(GL_FRONT);
00514     } else {
00515       ONDEBUG(printf("incrementStencilCB: zpass\n"));
00516       // z-pass
00517       //Increment stencil buffer for front face depth pass      
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     glBlendFunc(GL_ONE, GL_ONE);
00601     glEnable(GL_BLEND);    
00602    
00603     // set stencil test
00604     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00605     glDepthFunc(GL_EQUAL);
00606 
00607     if ( *linfo->sceneType == 0 ) 
00608     {
00609       glStencilFunc(GL_EQUAL, 0, ~0);
00610       glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
00611       glEnable(GL_STENCIL_TEST);
00612     }
00613 
00614   }
00615 } 
00616 
00617 
00627 void SoShadowLight::finishStencilCB(void *userdata, SoAction *action)
00628 {  
00629   if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
00630     ONDEBUG(printf("finishStencilCB\n"));
00631 
00632     glPopAttrib();    
00633 
00634     glDisable(GL_LIGHTING);
00635     glDisable(GL_STENCIL_TEST);
00636     glDisable(GL_BLEND);
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 //      printf("-- global intensity = %.2f \n", linfo->globEnv->ambientIntensity.getValue());
00645 //      printf("-- envIntensity = %.2f \n", envIntensity);
00646       linfo->globEnv->ambientIntensity.enableNotify(FALSE);
00647       linfo->globEnv->ambientIntensity.setValue(envIntensity);
00648       linfo->globEnv->ambientIntensity.enableNotify(TRUE);
00649     }
00650 
00651     // turn off the light
00652     linfo->light->enableNotify(FALSE);
00653     linfo->light->on = FALSE;
00654     linfo->light->enableNotify(TRUE);    
00655   }
00656 } 
00657 

Generated on Wed May 17 08:24:45 2006 for Shadow Engine by  doxygen 1.4.6-NO