ShadowManager.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 "ShadowManager.h"
00033 #include "SoShadowCaster.h"
00034 #include "SoShadowVolume.h"
00035 
00036 
00037 #ifdef _WIN32
00038   #include <windows.h> // needed by gl.h
00039 #endif
00040 
00041 // Must be linked with glu32.lib opengl32.lib.
00042 #include <GL/gl.h>
00043 
00044 //----------------------------------------------------------------------------
00045 // IMPLEMENTATION
00046 //----------------------------------------------------------------------------
00047 
00048 float CShadowManager::envIntensity = 0.0f;
00049 
00068 CShadowManager::CShadowManager(SoSeparator *sr, SoEnvironment * env)
00069     : sceneRoot(sr),
00070       environment(env)
00071 {
00072 
00073   if ( this->sceneRoot == NULL )
00074   {
00075     this->printError("Your scene root node is NULL.");
00076   }
00077   else
00078   {
00079     fprintf(stdout,"\nShadows generated by Shadow Engine v %s\n",SE_VERSION);
00080     sceneRoot->ref(); // pokud se v konstruktoru nevola createShadowScene
00081                       // musi se ref  
00082   }
00083 
00084   first = TRUE;
00085   // auto increment indices
00086   objectIndex = 0;
00087   lightIndex = 0;
00088 
00089   // default SM settings
00090   settings = new struct TShadowSettings;
00091   settings->method = zpass;
00092   settings->dropShadows = TRUE;
00093   settings->fDepth = 150.f;  
00094   this->method2algorithm();
00095   ONDEBUG( this->printSettings() );
00096 
00097   // casters' root node
00098   shadowCastersRoot = new SoSeparator;
00099   shadowCastersRoot->setName("ShadowCastersRoot");
00100   shadowCastersRoot->ref();
00101 
00102   // whole shadow scene root
00103   shadowSceneRoot = new SoSeparator;
00104   shadowSceneRoot->setName("ShadowSceneRoot");
00105   shadowSceneRoot->ref();
00106 
00107   // volumes subgraph root 
00108   shadowLightsRoot = new SoSeparator;
00109   shadowLightsRoot->setName("shadowLightsRoot");
00110   shadowLightsRoot->ref();
00111 
00112   switchNode = new SoSwitch;
00113   sceneNoShadows = new SoSeparator;
00114   sceneWithShadows = new SoSeparator;
00115   sceneWithShadowVolumes = new SoSeparator;
00116 
00117   // the order of these children is important for the switchNode
00118   switchNode->addChild(sceneWithShadows);       // 0
00119   switchNode->addChild(sceneNoShadows);         // 1 
00120   switchNode->addChild(sceneWithShadowVolumes); // 2  
00121 
00122   // set default environment node
00123   if ( environment == NULL )
00124   {
00125     ONDEBUG( printf("look for  env node\n") );
00126     // try to find the node
00127     environment = this->findEnvironmentNode();
00128     if ( environment == NULL )
00129     {      
00130       ONDEBUG( printf("my own env\n") );
00131       environment = new SoEnvironment;      
00132       // default amb. light color and intensity (defaults as in Coin)
00133       environment->ambientColor.setValue(SbColor(1.f, 1.f, 1.f));
00134 
00135       environment->ambientIntensity.setValue(0.2f);
00136       this->shadowSceneRoot->addChild(environment);      
00137     }       
00138   }
00139   environment->ref();
00140 
00141   shadowSceneRoot->addChild(switchNode); // after env node
00142   this->setSceneType(CShadowManager::SHADOWS); // default
00143 }
00144 
00145 
00149 CShadowManager::~CShadowManager()
00150 {
00151   ONDEBUG( printf("--CShadowManager::destructor()\n") );
00152 
00153   if ( this->sceneRoot != NULL )
00154     sceneRoot->unref();
00155 
00156   environment->unref();
00157 
00158   shadowCastersRoot->removeAllChildren();
00159   shadowCastersRoot->unref(); 
00160   shadowCastersRoot = NULL;
00161 
00162   shadowLightsRoot->removeAllChildren();
00163   shadowLightsRoot->unref(); 
00164   shadowLightsRoot = NULL;
00165 
00166   shadowSceneRoot->removeAllChildren();
00167   shadowSceneRoot->unref();
00168   shadowSceneRoot = NULL;
00169 
00170   switchNode = NULL;
00171 }
00172 
00173 
00177 void CShadowManager::createShadows()
00178 {
00179   ONDEBUG( printf("--CShadowManager::createShadows()\n") );
00180 
00181   int cnt = this->shadowLightsRoot->getNumChildren();
00182   ONDEBUG( printf("--CShadowManager:: SVN cnt: %d\n",cnt) );
00183   for (int i = 0; i < cnt; i++) // create SV for one caster
00184   {
00185     SoShadowLight * slight = static_cast<SoShadowLight *>(this->shadowLightsRoot->getChild(i));
00186     slight->createShadowVolumes();
00187   }
00188   
00189   if ( this->sceneRoot != NULL )
00190     this->sceneRoot->touch();
00191 }
00192 
00193 
00199 void CShadowManager::setSceneType(enum CShadowManager::SCENE_TYPE type)
00200 {
00201   // the type is the order of node to traverse
00202   this->switchNode->whichChild.setValue(type);
00203 }
00204 
00205 
00211 void CShadowManager::setManager(TShadowSettings * s)
00212 {
00213   settings = s;  
00214   this->method2algorithm();
00215   this->createShadows();  
00216 }
00217 
00218 
00224 const struct TShadowSettings * CShadowManager::readSettings()
00225 {
00226   return this->settings;
00227 }
00228 
00229 
00235 void CShadowManager::setMethod(enum TShadowMethod newMethod)
00236 {  
00237   enum TShadowAlgorithm old = this->algorithm;
00238   this->settings->method = newMethod;
00239   this->method2algorithm();
00240   if ( old != this->algorithm ) 
00241   {
00242     ONDEBUG ( printf("setMethod: new algorithm => createShadows\n"); );
00243     this->createShadows();
00244   }
00245   else
00246   {
00247     ONDEBUG ( printf("setMethod: algorithm is not updated\n"); );
00248   }
00249   ONDEBUG ( printSettings() );
00250 }
00251 
00252 
00258 void CShadowManager::setSVDepth(float newfDepth)
00259 {  
00260   this->settings->fDepth = newfDepth;
00261   this->createShadows();
00262   ONDEBUG ( printSettings() );
00263 }
00264 
00265 
00269 void CShadowManager::printSettings()
00270 { 
00271   char * a = "";
00272   char * m = "";
00273   char * ds = "";
00274   switch (settings->method) 
00275   {
00276     case zpass:   m = "z-pass";  break;
00277     case zfail:   m = "z-fail";  break;
00278     case autoset: m = "autoset"; break;
00279     default: m = "unknown"; break;
00280   }
00281   algorithm == zpassAlg ? a = "z-pass alg." : a = "z-fail alg.";
00282   settings->dropShadows ? ds = "shadows" : ds = "shadow volumes";  
00283 
00284   printf("\nSM Settings:\n");
00285   printf("  method:    %s\n", m);
00286   printf("  algorithm: %s\n", a);
00287   printf("  show:      %s\n", ds);
00288   printf("  far depth: %.2f\n\n", settings->fDepth);
00289 }
00290 
00291 
00297 TShadowAlgorithm * CShadowManager::getAlgorithm()
00298 {
00299   return &algorithm;
00300 }
00301 
00302 
00306 void CShadowManager::method2algorithm()
00307 {  
00308   ONDEBUG(printf("CShadowManager::method2algorithm\n"));
00309   switch ( settings->method )
00310   {
00311     case zpass: algorithm = zpassAlg; break;
00312 
00313     case zfail: algorithm = zfailAlg; break;
00314 
00315     case autoset: // TODO: determine algoritm on fly according camera position
00316                   // zfail is for now only
00317       algorithm = zfailAlg;
00318     break;
00319 
00320     default: algorithm = zfailAlg; break;
00321   }
00322 }
00323 
00324 
00333 void CShadowManager::disableSensors()
00334 {
00335   // for every caster create and add a new volume node
00336   int cnt = this->shadowCastersRoot->getNumChildren();
00337   ONDEBUG( printf("  disableSensors: SVN has %d children:\n",cnt));
00338   if ( cnt > 0 ) {  
00339     for (int i = 0; i < cnt; i++ ) {
00340       SoShadowCaster * caster = (SoShadowCaster *) this->shadowCastersRoot->getChild(i);
00341       caster->getMoveSensor()->detach();
00342       caster->getShapeSensor()->detach();
00343     } 
00344   } 
00345 }
00346 
00347 
00351 void CShadowManager::enableSensors()
00352 {
00353   // for every caster create and add a new volume node
00354   int cnt = this->shadowCastersRoot->getNumChildren();
00355   ONDEBUG( printf("  enableSensors: SVN has %d children:\n",cnt));
00356   if ( cnt > 0 ) {  
00357     for (int i = 0; i < cnt; i++ ) {
00358       SoShadowCaster * caster = (SoShadowCaster *) this->shadowCastersRoot->getChild(i);
00359       caster->getMoveSensor()->attach(caster->path);
00360       caster->getShapeSensor()->attach(caster->objectRoot);
00361     } 
00362   }
00363 }
00364 
00367 
00368 
00374 SoEnvironment * CShadowManager::getEnvironmentNode()
00375 {
00376   return this->environment;
00377 }
00378 
00379 
00387 void CShadowManager::setAmbientIntensity(float val)
00388 {
00389   this->environment->ambientIntensity.setValue(val);
00390 }
00391 
00401 SoEnvironment * CShadowManager::findEnvironmentNode()
00402 {
00403   if ( this->sceneRoot != NULL )
00404   {
00405     SoSearchAction * sa = new SoSearchAction;
00406     sa->setType(SoEnvironment::getClassTypeId());
00407     sa->setSearchingAll(FALSE);
00408     sa->apply(this->sceneRoot);
00409 
00410     SoPath * nodePath = sa->getPath();
00411     if ( nodePath == NULL ) {
00412       ONDEBUG( printf("SoEnvironment not FOUND\n") );
00413       return NULL;
00414     }
00415     else
00416     {
00417       if (nodePath->getTail()->isOfType(SoEnvironment::getClassTypeId()))
00418       {
00419         ONDEBUG( printf("SoEnvironment is FOUND !!!\n") );
00420         SoEnvironment * env = (SoEnvironment*) nodePath->getTail();
00421         return env;
00422       }
00423     }
00424   }
00425   return NULL;  
00426 }
00427 
00430 
00437 void CShadowManager::lightMoveCallback(void * userdata, SoSensor *s)
00438 {
00439   ONDEBUG( printf("CShadowManager::lightMoveCallback for one light\n") );
00440 
00441   SoShadowLight * slight = static_cast<SoShadowLight *> (userdata);
00442   slight->createShadowVolumes();
00443 }
00444 
00445 
00451 void CShadowManager::addLight(SoLight * light)
00452 {  
00453   ONDEBUG( printf("addLight:\n") );
00454   int i = 0;
00455   int cnt = 0;
00456 
00457   // check, if the light is in the scene graph
00458   SoSearchAction * sa = new SoSearchAction;
00459   sa->setNode(light);
00460   sa->setSearchingAll(FALSE);
00461   sa->apply(this->sceneRoot);
00462 
00463   SoPath * nodePath = sa->getPath(); // tato cesta by se dala vyuzit i v senzoru napojenym na 
00464                                      // cestu
00465   if ( nodePath == NULL ) { // light is not in the scene graph, do not add it
00466     printError("addLight (warning): Light was not found in the scene graph.\nTherefore it was not added in the Shadow Manager\n");
00467   }
00468   else
00469   {
00470     bool found = FALSE;
00471 
00472     // for every caster create and add a new volume node
00473     // it has a sense to test if the light is not already in SM
00474     cnt = this->shadowLightsRoot->getNumChildren();
00475     if ( cnt > 0 )
00476     {  
00477       for (int i = 0; i < cnt; i++ )
00478       {
00479         SoShadowLight * slight = (SoShadowLight *) this->shadowLightsRoot->getChild(i);
00480         if ( slight->getLight() == light )
00481         {
00482           found = TRUE;
00483         }
00484       }
00485     }
00486 
00487     if ( !found ) // light is not there
00488     {
00489 
00490       // volume node name
00491       SbString lindex(lightIndex);
00492       SbString lname = "ShadowLight_";
00493       lname += lindex;
00494       ONDEBUG( printf("  sh light name: %s\n",lname.getString()) );
00495 
00496       light->ref(); // test -> presunout az do SoShL nebo nechat v SM?
00497       SoShadowLight * slight = new SoShadowLight(this, light);
00498       slight->setName(lname);
00499       slight->setLightName(lightIndex);
00500 
00501       // new sensor
00502       SoNodeSensor * lightSensor = new SoNodeSensor(this->lightMoveCallback, slight);
00503       lightSensor->attach((SoNode *) light);
00504       slight->setSensor(lightSensor);
00505 
00506       this->shadowLightsRoot->addChild(slight);
00507 
00508       // create shadow volumes for this light and all existing casters
00509       int cntc = this->shadowCastersRoot->getNumChildren();
00510       ONDEBUG( printf("  add light: num. casters: %d\n",cntc));
00511       if ( cntc > 0 ) {  
00512         for (int i = 0; i < cntc; i++ ) {
00513           SoShadowCaster * caster = (SoShadowCaster *) this->shadowCastersRoot->getChild(i);
00514 
00515           // 2 indexy
00516           // volume node name
00517           SbString cindex(caster->getCasterName());
00518           SbString vname = "SV_L";
00519           vname += lindex;
00520           vname += "_C";
00521           vname += cindex;
00522           ONDEBUG( printf("  sh light name: %s\n",vname.getString()) );
00523 
00524           //new volume node
00525           SoShadowVolume * volume = new SoShadowVolume(slight, caster->getCasterName());
00526           volume->setName(vname);
00527           slight->addVolume(volume);
00528           
00529           ONDEBUG( fprintf(stdout,"  child %d: %s\n",i,caster->getName().getString()) );
00530         } 
00531       } 
00532 
00533       lightIndex++;
00534       // force shadows re-computation
00535       this->createShadows();
00536     } else {
00537       this->printError("Light is already present.");
00538     }
00539   }
00540   ONDEBUG(
00541     printf(" num. lights %d \n", this->shadowLightsRoot->getNumChildren() );
00542   );
00543   this->checkLights();  
00544   ONDEBUG( printf("addLight end\n\n") );  
00545 }
00546 
00547 
00558 void CShadowManager::removeLight(SoLight * light)
00559 { 
00560   ONDEBUG( printf("removeLight:\n") );
00561 
00562   int i = 0;
00563 
00564   if ( light == NULL ) 
00565   {
00566     this->printError("Light is NULL.");       
00567   }
00568   else
00569   {  
00570     int cnt = this->shadowLightsRoot->getNumChildren();
00571     if ( cnt > 0 )
00572     {  
00573       for ( i = 0; i < cnt; i++ )
00574       {
00575         SoShadowLight * slight = (SoShadowLight *) this->shadowLightsRoot->getChild(i);
00576         if ( slight->getLight() == light )
00577         {          
00578           this->shadowLightsRoot->removeChild(i);
00579           // force shadows re-computation
00580           this->createShadows();          
00581           light->unref();  
00582           break;
00583         }
00584       }
00585       if ( i == cnt ) 
00586         this->printError("Light is not in SM.");   
00587     }
00588   }
00589 
00590   ONDEBUG(
00591     checkLights();
00592     printf("  lights %d \n", this->shadowLightsRoot->getNumChildren() );
00593     printf("removeLight end\n\n");
00594   );
00595 }
00596 
00597 
00601 void CShadowManager::checkLights()
00602 {  
00603   bool found = FALSE;
00604 
00605   int cnt = this->shadowLightsRoot->getNumChildren();
00606   if ( cnt > 0 )
00607   {  
00608     for (int i = 0; i < cnt; i++ )
00609     {
00610       SoShadowLight * slight = (SoShadowLight *) this->shadowLightsRoot->getChild(i);
00611 
00612       slight->getLight()->on.enableNotify(FALSE);
00613       SbBool s = slight->getLight()->on.getValue(); // ligtht's status
00614       char * status = "";
00615       s ? status = "on" : status = "off";
00616 
00617       char * typ = "";
00618       if (slight->getLight()->getTypeId() == SoDirectionalLight::getClassTypeId() )
00619         typ = "SoDirectionalLight";
00620       else if (slight->getLight()->getTypeId() == SoDirectionalLightManip::getClassTypeId() )
00621         typ = "SoDirectionalLightManip";
00622       else if (slight->getLight()->getTypeId() == SoPointLight::getClassTypeId() )
00623         typ = "SoPointLight";
00624       else if (slight->getLight()->getTypeId() == SoPointLightManip::getClassTypeId() )
00625         typ = "SoPointLightManip";
00626       else if (slight->getLight()->getTypeId() == SoSpotLight::getClassTypeId() )
00627         typ = "SoSpotLight";
00628       else if (slight->getLight()->getTypeId() == SoSpotLightManip::getClassTypeId() )
00629         typ = "SoSpotLightManip";
00630       else 
00631         typ = "Unknown light type";
00632 
00633       ONDEBUG( fprintf(stdout,"  light %d: %s %s\n",i,status,typ) );
00634     }
00635   }
00636 
00637 }
00638 
00641 
00652 void CShadowManager::objectMoveCallback(void * userdata, SoSensor *s)
00653 {
00654   ONDEBUG( printf("@@@caster path CB\n") );
00655 
00656 /*
00657   o co tady jde: 
00658   1) pri zmene geometrie objektu (polygony) vytvorit znovu face model objektu
00659      sem spada i zmena scale -> v tom pripade by se model nemusel prepocitavat cely,
00660      jen k nemu pridat scale
00661 
00662      potom prepocitat i stinove teleso
00663 
00664   2) zmeni-li se jen poloha/natoceni objektu ve scene, jen prepocitat stinove teleso
00665     
00666   Problem: jak tyto dve veci od sebe rozlisit?
00667   
00668 */
00669 
00670   SoShadowCaster * caster = static_cast<SoShadowCaster *>(userdata);  
00671 
00672   ONDEBUG( printf("@@@caster path CB called by %s\n", caster->getName().getString()) );
00673 
00674   // we know the sensor is really a data sensor
00675   SoDataSensor *mySensor = (SoDataSensor *)s;
00676     
00677   SoNode *changedNode = mySensor->getTriggerNode();
00678   SoField *changedField = mySensor->getTriggerField();
00679   
00680   if ( changedNode != NULL ) {
00681     ONDEBUG( printf("  The node named '%s' changed\n", changedNode->getName().getString()) );
00682     if ( changedNode->getTypeId().isDerivedFrom(SoTransformation::getClassTypeId()) )
00683     {
00684       // translation or rotation has changed
00685       if ( !changedNode->isOfType(SoScale::getClassTypeId()) ) {
00686         ONDEBUG( printf("  create shadow volume for the caster (not a scale tr.)\n") );
00687         caster->setMoved(TRUE);
00688         caster->createShadowVolumes();        
00689       } else { // scale has changed
00690         ONDEBUG( printf("  create shadow volume: scale transform\n") );
00691         caster->createFaceModel();
00692         caster->createShadowVolumes();
00693       }
00694     }
00695     else
00696     {
00697       // something in the scene graph has changed (some node was removed or added)
00698       // or touch called
00699       // re-compute face model (for sure) and shadow volumes
00700       // this is not affected by moving with the light
00701       if ( changedField == NULL )
00702       {
00703 /*
00704         ONDEBUG( printf("  changedNode is NOT NULL but changedField is NULL, no SoTransformation \n") );
00705         caster->createFaceModel();
00706         caster->createShadowVolumes();
00707 */
00708       }
00709 /*
00710 // toto je strasne divny, reakce na animaci
00711       else
00712       {
00713         if ( !changedNode->isOfType(SoLight::getClassTypeId()) ) {
00714           ONDEBUG( printf("  changedNode is NOT NULL and changedField is NOT NULL as well, no SoTransformation, no SoLight \n") );
00715 //        caster->createFaceModel();
00716           caster->createShadowVolumes();
00717         }
00718       }
00719 */
00720     }
00721   } 
00722   else 
00723   {
00724     ONDEBUG( printf("  changedNode is NULL \n") );
00725   }
00726 
00727   ONDEBUG( printf("@@@caster path CB done\n") );
00728 }
00729 
00730 
00737 void CShadowManager::objectShapeCallback(void * userdata, SoSensor *s)
00738 {
00739   ONDEBUG( printf("###caster shape CB\n") );
00740 
00741   SoShadowCaster * caster = static_cast<SoShadowCaster *>(userdata);
00742 
00743   // we know the sensor is really a data sensor
00744   SoDataSensor * mySensor = (SoDataSensor *) s;
00745     
00746   SoNode *changedNode = mySensor->getTriggerNode();
00747   SoField *changedField = mySensor->getTriggerField();
00748     
00749   if ( changedNode != NULL ) {
00750     ONDEBUG( printf("  The node named '%s' changed\n", changedNode->getName().getString()) );
00751 
00752     if (changedField == NULL) // can be caused by add child or touch
00753     {                         // it is called when a new object is added
00754 
00755       ONDEBUG( printf("  changedField == NULL\n") );
00756       if ( changedNode->isOfType(SoSeparator::getClassTypeId()) ) {
00757         ONDEBUG( printf("  added %d \n",caster->getCasterName()) );
00758         // recompute caster model
00759         caster->createFaceModel();
00760         // prepocitat SV
00761         caster->createShadowVolumes();
00762       }
00763     }
00764   }
00765   else
00766   {
00767     ONDEBUG( printf("  changedNode is NULL in shape CB\n") );
00768   }
00769   ONDEBUG( printf("###caster shape CB\n") );
00770 }
00771 
00779 int CShadowManager::findObject(SoSeparator * object)
00780 {
00781   // check, if the object is not already in the shadow manager
00782   int found = -1;
00783   int cnt = this->shadowCastersRoot->getNumChildren();
00784   if ( cnt > 0 )
00785   {
00786     for (int i = 0; i < cnt; i++ )
00787     {
00788       SoShadowCaster * caster = (SoShadowCaster *) this->shadowCastersRoot->getChild(i);
00789       if ( caster->getObjectNode() == object )
00790       {
00791         ONDEBUG( printf("findObject: Object is already in SM: %d\n", caster->getCasterName()) );
00792         return caster->getCasterName();
00793       }    
00794     } 
00795   }
00796   ONDEBUG( printf("findObject: Object is not in SM\n") );
00797   return found;  
00798 }
00799 
00800 
00814 void CShadowManager::addObject(SoSeparator * object)
00815 {   
00816   ONDEBUG( printf("add Object\n") );
00817   int i = 0;
00818 
00819   // check, if the object is in the scene graph  
00820   SoSearchAction * sa = new SoSearchAction;
00821   sa->setNode(object);
00822   sa->setSearchingAll(FALSE);
00823   sa->apply(this->sceneRoot);
00824 
00825   // a path from scene root to the object node to detect any transformation changes
00826   SoPath * nodePath = sa->getPath();
00827   if ( nodePath == NULL ) { // object is not in the scene graph, do not add it
00828     printError("addObject (warning): Object was not found in the scene graph.\nTherefore it was not added in the Shadow Manager.\n");
00829   }
00830   else // object is in the scene graph
00831   { 
00832     if ( findObject(object) < 0 ) // add object
00833     { 
00834       // add new casting object node
00835       SoShadowCaster * caster = new SoShadowCaster(this, object);
00836       caster->setCasterName(objectIndex);
00837       this->shadowCastersRoot->addChild(caster);
00838       objectIndex++;
00839   
00840       // ref the object, for sure
00841       object->ref();
00842                   
00843       // create a new object sensor to detect location changes
00844       SoPathSensor * objectSensor = new SoPathSensor(this->objectMoveCallback, caster);
00845       objectSensor->setPriority(0); // important
00846       objectSensor->attach(nodePath);
00847       caster->setMoveSensor(objectSensor);
00848 
00849       caster->path = nodePath;
00850 
00851       // create a new object sensor to detect shape changes
00852       SoNodeSensor * objectSensorC = new SoNodeSensor(this->objectShapeCallback, caster);
00853       objectSensorC->attach((SoNode *) object);
00854       objectSensorC->setPriority(0); // important
00855       caster->setShapeSensor(objectSensorC);
00856 
00857       // tohle by se melo dat do nejake metody
00858       // create volume nodes for all lights in SM and this object
00859       int cnt = this->shadowLightsRoot->getNumChildren();
00860       if ( cnt > 0 )
00861       {
00862         for (int i = 0; i < cnt; i++ )
00863         {
00864           SoShadowLight * slight = (SoShadowLight *) this->shadowLightsRoot->getChild(i);
00865       
00866           // 2 indexy
00867           // volume node name
00868           SbString cindex(caster->getCasterName());
00869           SbString lindex(slight->getLightName());
00870           SbString vname = "SV_L";
00871           vname += lindex;
00872           vname += "_C";
00873           vname += cindex;
00874           ONDEBUG( printf("  sh volume name: %s\n",vname.getString()) );
00875 
00876           //new volume node
00877           SoShadowVolume * volume = new SoShadowVolume(slight, caster->getCasterName());
00878           volume->setName(vname);
00879           
00880           slight->addVolume(volume);
00881         }
00882       }
00883 
00884       ONDEBUG( printf("  child %d: %s\n",i,caster->getName().getString()) );
00885       ONDEBUG( printf("  add obj: volume added\n") );
00886       ONDEBUG( printf("  The new caster has %d children.\n", caster->getNumChildren()) );
00887 
00888       // very importatnt thing. this nottyfies the attached sensor and 
00889       // calls appropriate CB method which creates object's model and shadows
00890       // also causes redraw of the scene, i.e. shadow appears in it
00891       object->touch();
00892       ONDEBUG( this->printMsg("  Object was added.") );
00893 
00894     } else {
00895       this->printError("Object is already present.");
00896     }    
00897   }
00898   ONDEBUG( checkObjects() );
00899   ONDEBUG( printf("add object done\n\n") );
00900 }
00901 
00902 
00911 void CShadowManager::removeObject(SoSeparator * object)
00912 { 
00913 
00914   ONDEBUG( printf("remove object\n") );
00915   // check, if the object is not already in the shadow manager
00916   int found = -1;
00917   int cnt = this->shadowCastersRoot->getNumChildren();
00918   if ( cnt > 0 ) 
00919   {  
00920     for (int i = 0; i < cnt; i++ )
00921     {
00922       SoShadowCaster * caster = (SoShadowCaster *) this->shadowCastersRoot->getChild(i);
00923       if ( caster->getObjectNode() == object )
00924       {
00925         ONDEBUG( printf("  removing caster: %d\n", caster->getCasterName()) );
00926         found = caster->getCasterName();
00927 
00928         // delete shadow volumes of this caster and each light
00929         int cntl = this->shadowLightsRoot->getNumChildren();
00930         for (int j = 0; j < cntl; j++ )
00931         {
00932           SoShadowLight * slight = (SoShadowLight *) this->shadowLightsRoot->getChild(j);
00933           slight->deleteVolume(caster->getCasterName());
00934         }
00935 
00936         this->shadowCastersRoot->removeChild(i);        
00937         // unref the object, was ref()ed
00938         object->unref();
00939 
00940         break; // to prevent failure; remove the first occurence only
00941         // musi tady byt break, ptz pocet deti se snizi o 1 a po dstraneni 1 se
00942         // saha za konec () cnt se neupdatuje, musel by se pouzit while nejak
00943       }    
00944     } 
00945   }  
00946   if ( found < 0 ) { 
00947     this->printError("removeObject: object not found.");
00948   }
00949   ONDEBUG( checkObjects() );
00950   ONDEBUG( printf("remove object done\n\n") );
00951 
00952 }
00953 
00954 
00963 void CShadowManager::createObjectsShadows(SoSeparator * object)
00964 { 
00965   ONDEBUG( printf("recreateObjectsShadows\n") );
00966   // check, if the object is not already in the shadow manager
00967   int found = -1;
00968   int cnt = this->shadowCastersRoot->getNumChildren();
00969   if ( cnt > 0 ) 
00970   {  
00971     for (int i = 0; i < cnt; i++ )
00972     {
00973       SoShadowCaster * caster = (SoShadowCaster *) this->shadowCastersRoot->getChild(i);
00974       if ( caster->getObjectNode() == object )
00975       {
00976         found = 1;
00977         caster->createFaceModel();
00978         caster->createShadowVolumes();
00979       }    
00980     } 
00981   }  
00982   if ( found < 0 ) { 
00983     this->printError("recreateObjectsShadows: object not found.");
00984   }
00985   ONDEBUG( printf("recreateObjectsShadows done\n\n") );
00986 }
00987 
00988 
00992 void CShadowManager::checkObjects()
00993 {  
00994   int cnt = this->shadowCastersRoot->getNumChildren();
00995   ONDEBUG( fprintf(stdout,"\nSVN has %d children:\n",cnt) );
00996   if ( cnt > 0 ) {  
00997     for (int i = 0; i < cnt; i++ ) {
00998       SoShadowCaster * caster = (SoShadowCaster *) this->shadowCastersRoot->getChild(i);
00999       ONDEBUG( fprintf(stdout,"  child %d: %s\n",i,caster->getName().getString()) );
01000     } 
01001   } 
01002   ONDEBUG( fprintf(stdout,"\n") );
01003 }
01004 
01005 
01011 void CShadowManager::createCasterVolumes(int index)
01012 {
01013   int cnt = this->shadowLightsRoot->getNumChildren();
01014   if ( cnt > 0 )
01015   {
01016     for (int i = 0; i < cnt; i++ )
01017     {
01018       SoShadowLight * slight = (SoShadowLight *) this->shadowLightsRoot->getChild(i);
01019 
01020       int vcnt = slight->getNumVolumes();
01021       if ( vcnt > 0 )
01022       {
01023         for (int j = 0; j < vcnt; j++ )
01024         {      
01025           //new volume node
01026           SoShadowVolume * volume = (SoShadowVolume *) slight->getVolume(j);
01027           if ( volume->getCasterName() == index )
01028           {          
01029             volume->create();
01030           }
01031         }
01032       }
01033     }
01034   }
01035 }
01036 
01037 
01040 
01046 void CShadowManager::createShadowScene()
01047 {  
01048   ONDEBUG( printf("creating shadow scene graph...\n") );
01049 
01050 // rendering callbacks
01051   // scene without shadows
01052   SoCallback * nslightsOffCallback = new SoCallback;
01053   nslightsOffCallback->setCallback(nslightsOffCB, this->shadowLightsRoot);
01054 
01055   SoCallback * nslightsOnCallback = new SoCallback;
01056   nslightsOnCallback->setCallback(nslightsOnCB, this->shadowLightsRoot);
01057 
01058   SoCallback * nsambientOffCallback = new SoCallback;
01059   nsambientOffCallback->setCallback(nsambientOffCB, this->environment);
01060 
01061   SoCallback * nsambientOnCallback = new SoCallback;
01062   nsambientOnCallback->setCallback(nsambientOnCB, this->environment);
01063 
01064   // scene with shadows
01065   SoCallback * initCallback = new SoCallback;
01066   initCallback->setCallback(initCB, this->shadowLightsRoot);
01067   
01068   SoCallback * endCallback = new SoCallback;
01069   endCallback->setCallback(endCB, this->shadowLightsRoot);
01070 
01071   ONDEBUG( this->printSettings() ); 
01072 
01073   if ( this->sceneRoot != NULL )
01074   {
01075 
01076     // what to show
01077 
01078     // only user scene
01079     this->sceneNoShadows->addChild(nslightsOffCallback);    
01080     this->sceneNoShadows->addChild(this->sceneRoot);
01081     this->sceneNoShadows->addChild(nslightsOnCallback);  
01082     this->sceneNoShadows->addChild(nsambientOffCallback);  
01083     this->sceneNoShadows->addChild(this->sceneRoot);
01084     this->sceneNoShadows->addChild(nsambientOnCallback);
01085 
01086     // scene with shadows
01087     
01088     // create top part of shadow scene graph
01089     SoSeparator * aboveShadowVloumesRoot = new SoSeparator;
01090     this->sceneWithShadows->addChild(aboveShadowVloumesRoot);
01091 
01092     aboveShadowVloumesRoot->addChild(initCallback);
01093     aboveShadowVloumesRoot->addChild(this->sceneRoot);
01094 
01095     aboveShadowVloumesRoot->addChild(shadowLightsRoot);
01096     aboveShadowVloumesRoot->addChild(endCallback);
01097 
01098     // scene with shadow volumes ??? 
01099 
01100 /*
01101     // create top part of shadow scene graph
01102     SoSeparator * aboveShadowVloumesRoot = new SoSeparator;
01103     shadowSceneRoot->addChild(aboveShadowVloumesRoot);
01104 
01105     aboveShadowVloumesRoot->addChild(initCallback);
01106     aboveShadowVloumesRoot->addChild(this->sceneRoot);
01107 
01108     aboveShadowVloumesRoot->addChild(shadowLightsRoot);
01109     aboveShadowVloumesRoot->addChild(endCallback);
01110 */
01111   }
01112 }
01113 
01114 
01120 SoSeparator * CShadowManager::getShadowSceneRoot()
01121 {
01122   if ( first ) {
01123     this->createShadowScene();
01124     first = FALSE;
01125   }
01126   return this->shadowSceneRoot;
01127 }
01128 
01129 
01135 SoSeparator * CShadowManager::getSceneRoot()
01136 {
01137   return this->sceneRoot;
01138 }
01139 
01140 
01143 
01149 void CShadowManager::printMsg(const char *msg)
01150 {
01151   fprintf(stdout,"SM: %s\n",msg);
01152 }
01153 
01154 
01160 void CShadowManager::printError(const char *msg)
01161 {
01162   fprintf(stderr,"SM Error: %s\n",msg);
01163 }
01164 
01165 
01171 void CShadowManager::export(const char * filename)
01172 {
01173   SoOutput output;
01174   if ( output.openFile(filename) ) {
01175     SoWriteAction * writer = new SoWriteAction(&output);
01176     writer->apply(this->shadowLightsRoot);
01177     delete writer;
01178   }
01179   else
01180   {
01181     char * buf = NULL;
01182     sprintf(buf,"Can not open file '%s' for export.",filename);
01183     this->printError(buf);
01184   }
01185 }
01186 
01187 
01188 /*
01189 //TODO: Load a shadow scene graph from a file.
01190 void CShadowManager::import(const char * filename)
01191 {
01192   if ( filename != NULL ) 
01193   {
01194     SoInput in;
01195     if (!in.openFile(filename)) {
01196       char * buf = NULL;
01197       sprintf(buf,"Can not open file '%s' for import.",filename);
01198       this->printError(buf);
01199     }
01200 
01201     SoSeparator * loadNode = SoDB::readAll(&in);
01202     loadNode = SoDB::readAll(&in);
01203     loadNode->setName("loadNode");
01204     if (loadNode == NULL) {
01205       char * buf = NULL;
01206       sprintf(buf,"Can not read file '%s' for import.",filename);
01207       this->printError(buf);
01208     }
01209     else
01210     {
01211       this->shadowCastersRoot->removeAllChildren();
01212       this->shadowLightsRoot->removeAllChildren();
01213       this->shadowLightsRoot->addChild(loadNode);
01214     }    
01215   }
01216 }
01217 */
01218 
01219 
01220 
01221 
01222 
01223 
01224 
01225 
01226 
01227 
01228 
01230 // NO Shadow rendering callbacks
01232 
01233 
01234 
01243 void CShadowManager::nslightsOffCB(void *userdata, SoAction *action)
01244 {  
01245   if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
01246 
01247     ONDEBUG(printf("nslightsOffCB\n"));
01248 
01249     // depth
01250     glClearDepth(1.0f);
01251 
01252     glEnable(GL_DEPTH_TEST);
01253     glDepthFunc(GL_LEQUAL);    
01254 
01255     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // ma vliv na barvu a text. souradnice
01256 //    glEnable(GL_CULL_FACE);    
01257     
01258     // Clear all buffers
01259     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
01260     glPushAttrib(GL_ENABLE_BIT); 
01261 
01262     glEnable(GL_LIGHTING);
01263 
01264     // turn off the lights and save each light status
01265     SoSeparator * lightRoot = (SoSeparator * ) userdata;
01266     int cnt = lightRoot->getNumChildren();
01267     for ( int i = 0; i < cnt; i++ )
01268     {
01269       SoShadowLight * slight = static_cast<SoShadowLight *>(lightRoot->getChild(i));
01270       slight->getLight()->on.enableNotify(FALSE);
01271       slight->status = slight->getLight()->on.getValue();
01272       slight->getLight()->on = FALSE;
01273       slight->getLight()->on.enableNotify(TRUE);
01274     }
01275    
01276   }
01277 } 
01278 
01279 
01288 void CShadowManager::nslightsOnCB(void *userdata, SoAction *action)
01289 {  
01290   if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
01291 
01292     ONDEBUG(printf("nslightsOnCB\n"));
01293 
01294     // turn on the lights to its saved status
01295     SoSeparator * lightRoot = (SoSeparator * ) userdata;
01296     int cnt = lightRoot->getNumChildren();
01297     for ( int i = 0; i < cnt; i++ )
01298     {
01299       SoShadowLight * slight = static_cast<SoShadowLight *>(lightRoot->getChild(i));
01300       slight->getLight()->on.enableNotify(FALSE);
01301       slight->getLight()->on = slight->status;
01302       slight->getLight()->on.enableNotify(TRUE);
01303     }   
01304   }
01305 } 
01306 
01307 
01316 void CShadowManager::nsambientOffCB(void *userdata, SoAction *action)
01317 {  
01318   if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
01319     ONDEBUG(printf("nsambientOffCB\n"));    
01320 
01321     glBlendFunc(GL_ONE, GL_ONE);
01322     glEnable(GL_BLEND);    
01323 
01324     SoEnvironment * env = (SoEnvironment * ) userdata;
01325 
01326     // disable ambient light (additive blending)
01327     // (save ambient int. value)
01328     if ( env != NULL )
01329     {
01330       env->ambientIntensity.enableNotify(FALSE);
01331       envIntensity = env->ambientIntensity.getValue();
01332       env->ambientIntensity.setValue(0.0f);
01333       env->ambientIntensity.enableNotify(TRUE);
01334     }
01335   }
01336 } 
01337 
01338 
01348 void CShadowManager::nsambientOnCB(void *userdata, SoAction *action)
01349 {  
01350   if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
01351     ONDEBUG(printf("nsambientOnCB\n"));
01352 
01353     SoEnvironment * env = (SoEnvironment * ) userdata;
01354 
01355     // enable ambient light 
01356     if ( env != NULL )
01357     {
01358       env->ambientIntensity.enableNotify(FALSE);
01359       env->ambientIntensity.setValue(envIntensity);
01360       env->ambientIntensity.enableNotify(TRUE);
01361     }
01362     
01363     glDisable(GL_BLEND);
01364     glDepthFunc(GL_LEQUAL);
01365     glPopAttrib();
01366   }
01367 } 
01368 
01369 
01371 // Shadow rendering callbacks
01373 
01374 
01384 void CShadowManager::initCB(void *userdata, SoAction *action)
01385 {  
01386   if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
01387     ONDEBUG(printf("initCB\n"));    
01388 
01389     // depth
01390     glClearDepth(1.0f);
01391 
01392     glEnable(GL_DEPTH_TEST);
01393     glDepthFunc(GL_LEQUAL);    
01394 
01395     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // ma vliv na barvu a text. souradnice
01396     glEnable(GL_CULL_FACE);    
01397     
01398     // Clear all buffers
01399     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
01400     glPushAttrib(GL_ENABLE_BIT); 
01401 
01402     glEnable(GL_LIGHTING);
01403 
01404     // turn off the lights and save each light status
01405     SoSeparator * lightRoot = (SoSeparator * ) userdata;
01406     int cnt = lightRoot->getNumChildren();
01407     for ( int i = 0; i < cnt; i++ )
01408     {
01409       SoShadowLight * slight = static_cast<SoShadowLight *>(lightRoot->getChild(i));
01410       slight->getLight()->on.enableNotify(FALSE);
01411       slight->status = slight->getLight()->on.getValue();
01412       slight->getLight()->on = FALSE;
01413       slight->getLight()->on.enableNotify(TRUE);
01414     }
01415   }
01416 } 
01417 
01418 
01428 void CShadowManager::endCB(void *userdata, SoAction *action)
01429 {  
01430   if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
01431     ONDEBUG(printf("endCB\n"));
01432     
01433     // set back each light status 
01434     SoSeparator * lightRoot = (SoSeparator * ) userdata;
01435     int cnt = lightRoot->getNumChildren();
01436     for ( int i = 0; i < cnt; i++ )
01437     {
01438       SoShadowLight * slight = static_cast<SoShadowLight *>(lightRoot->getChild(i));
01439       slight->getLight()->on.enableNotify(FALSE);      
01440       slight->getLight()->on = slight->status;
01441       slight->getLight()->on.enableNotify(TRUE);
01442     }
01443     
01444     glDepthFunc(GL_LEQUAL);
01445     glPopAttrib();
01446   }
01447 } 

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