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       else
00710       {
00711         ONDEBUG( printf("  changedNode is NOT NULL and changedField is NOT NULL as well, no SoTransformation \n") );
00712 //        caster->createFaceModel();
00713         caster->createShadowVolumes();
00714       }
00715 
00716     }
00717   } 
00718   else 
00719   {
00720     ONDEBUG( printf("  changedNode is NULL \n") );
00721   }
00722 
00723   ONDEBUG( printf("@@@caster path CB done\n") );
00724 }
00725 
00726 
00733 void CShadowManager::objectShapeCallback(void * userdata, SoSensor *s)
00734 {
00735   ONDEBUG( printf("###caster shape CB\n") );
00736 
00737   SoShadowCaster * caster = static_cast<SoShadowCaster *>(userdata);
00738 
00739   // we know the sensor is really a data sensor
00740   SoDataSensor * mySensor = (SoDataSensor *) s;
00741     
00742   SoNode *changedNode = mySensor->getTriggerNode();
00743   SoField *changedField = mySensor->getTriggerField();
00744     
00745   if ( changedNode != NULL ) {
00746     ONDEBUG( printf("  The node named '%s' changed\n", changedNode->getName().getString()) );
00747 
00748     if (changedField == NULL) // can be caused by add child or touch
00749     {                         // it is called when a new object is added
00750 
00751       ONDEBUG( printf("  changedField == NULL\n") );
00752       if ( changedNode->isOfType(SoSeparator::getClassTypeId()) ) {
00753         ONDEBUG( printf("  added %d \n",caster->getCasterName()) );
00754         // recompute caster model
00755         caster->createFaceModel();
00756         // prepocitat SV
00757         caster->createShadowVolumes();
00758       }
00759     }
00760   }
00761   else
00762   {
00763     ONDEBUG( printf("  changedNode is NULL in shape CB\n") );
00764   }
00765   ONDEBUG( printf("###caster shape CB\n") );
00766 }
00767 
00775 int CShadowManager::findObject(SoSeparator * object)
00776 {
00777   // check, if the object is not already in the shadow manager
00778   int found = -1;
00779   int cnt = this->shadowCastersRoot->getNumChildren();
00780   if ( cnt > 0 )
00781   {
00782     for (int i = 0; i < cnt; i++ )
00783     {
00784       SoShadowCaster * caster = (SoShadowCaster *) this->shadowCastersRoot->getChild(i);
00785       if ( caster->getObjectNode() == object )
00786       {
00787         ONDEBUG( printf("findObject: Object is already in SM: %d\n", caster->getCasterName()) );
00788         return caster->getCasterName();
00789       }    
00790     } 
00791   }
00792   ONDEBUG( printf("findObject: Object is not in SM\n") );
00793   return found;  
00794 }
00795 
00796 
00810 void CShadowManager::addObject(SoSeparator * object)
00811 {   
00812   ONDEBUG( printf("add Object\n") );
00813   int i = 0;
00814 
00815   // check, if the object is in the scene graph  
00816   SoSearchAction * sa = new SoSearchAction;
00817   sa->setNode(object);
00818   sa->setSearchingAll(FALSE);
00819   sa->apply(this->sceneRoot);
00820 
00821   // a path from scene root to the object node to detect any transformation changes
00822   SoPath * nodePath = sa->getPath();
00823   if ( nodePath == NULL ) { // object is not in the scene graph, do not add it
00824     printError("addObject (warning): Object was not found in the scene graph.\nTherefore it was not added in the Shadow Manager.\n");
00825   }
00826   else // object is in the scene graph
00827   { 
00828     if ( findObject(object) < 0 ) // add object
00829     { 
00830       // add new casting object node
00831       SoShadowCaster * caster = new SoShadowCaster(this, object);
00832       caster->setCasterName(objectIndex);
00833       this->shadowCastersRoot->addChild(caster);
00834       objectIndex++;
00835   
00836       // ref the object, for sure
00837       object->ref();
00838                   
00839       // create a new object sensor to detect location changes
00840       SoPathSensor * objectSensor = new SoPathSensor(this->objectMoveCallback, caster);
00841       objectSensor->setPriority(0); // important
00842       objectSensor->attach(nodePath);
00843       caster->setMoveSensor(objectSensor);
00844 
00845       caster->path = nodePath;
00846 
00847       // create a new object sensor to detect shape changes
00848       SoNodeSensor * objectSensorC = new SoNodeSensor(this->objectShapeCallback, caster);
00849       objectSensorC->attach((SoNode *) object);
00850       objectSensorC->setPriority(0); // important
00851       caster->setShapeSensor(objectSensorC);
00852 
00853       // tohle by se melo dat do nejake metody
00854       // create volume nodes for all lights in SM and this object
00855       int cnt = this->shadowLightsRoot->getNumChildren();
00856       if ( cnt > 0 )
00857       {
00858         for (int i = 0; i < cnt; i++ )
00859         {
00860           SoShadowLight * slight = (SoShadowLight *) this->shadowLightsRoot->getChild(i);
00861       
00862           // 2 indexy
00863           // volume node name
00864           SbString cindex(caster->getCasterName());
00865           SbString lindex(slight->getLightName());
00866           SbString vname = "SV_L";
00867           vname += lindex;
00868           vname += "_C";
00869           vname += cindex;
00870           ONDEBUG( printf("  sh volume name: %s\n",vname.getString()) );
00871 
00872           //new volume node
00873           SoShadowVolume * volume = new SoShadowVolume(slight, caster->getCasterName());
00874           volume->setName(vname);
00875           
00876           slight->addVolume(volume);
00877         }
00878       }
00879 
00880       ONDEBUG( printf("  child %d: %s\n",i,caster->getName().getString()) );
00881       ONDEBUG( printf("  add obj: volume added\n") );
00882       ONDEBUG( printf("  The new caster has %d children.\n", caster->getNumChildren()) );
00883 
00884       // very importatnt thing. this nottyfies the attached sensor and 
00885       // calls appropriate CB method which creates object's model and shadows
00886       // also causes redraw of the scene, i.e. shadow appears in it
00887       object->touch();
00888       ONDEBUG( this->printMsg("  Object was added.") );
00889 
00890     } else {
00891       this->printError("Object is already present.");
00892     }    
00893   }
00894   ONDEBUG( checkObjects() );
00895   ONDEBUG( printf("add object done\n\n") );
00896 }
00897 
00898 
00907 void CShadowManager::removeObject(SoSeparator * object)
00908 { 
00909 
00910   ONDEBUG( printf("remove object\n") );
00911   // check, if the object is not already in the shadow manager
00912   int found = -1;
00913   int cnt = this->shadowCastersRoot->getNumChildren();
00914   if ( cnt > 0 ) 
00915   {  
00916     for (int i = 0; i < cnt; i++ )
00917     {
00918       SoShadowCaster * caster = (SoShadowCaster *) this->shadowCastersRoot->getChild(i);
00919       if ( caster->getObjectNode() == object )
00920       {
00921         ONDEBUG( printf("  removing caster: %d\n", caster->getCasterName()) );
00922         found = caster->getCasterName();
00923 
00924         // delete shadow volumes of this caster and each light
00925         int cntl = this->shadowLightsRoot->getNumChildren();
00926         for (int j = 0; j < cntl; j++ )
00927         {
00928           SoShadowLight * slight = (SoShadowLight *) this->shadowLightsRoot->getChild(j);
00929           slight->deleteVolume(caster->getCasterName());
00930         }
00931 
00932         this->shadowCastersRoot->removeChild(i);        
00933         // unref the object, was ref()ed
00934         object->unref();
00935 
00936         break; // to prevent failure; remove the first occurence only
00937         // musi tady byt break, ptz pocet deti se snizi o 1 a po dstraneni 1 se
00938         // saha za konec () cnt se neupdatuje, musel by se pouzit while nejak
00939       }    
00940     } 
00941   }  
00942   if ( found < 0 ) { 
00943     this->printError("removeObject: object not found.");
00944   }
00945   ONDEBUG( checkObjects() );
00946   ONDEBUG( printf("remove object done\n\n") );
00947 
00948 }
00949 
00950 
00959 void CShadowManager::createObjectsShadows(SoSeparator * object)
00960 { 
00961   ONDEBUG( printf("recreateObjectsShadows\n") );
00962   // check, if the object is not already in the shadow manager
00963   int found = -1;
00964   int cnt = this->shadowCastersRoot->getNumChildren();
00965   if ( cnt > 0 ) 
00966   {  
00967     for (int i = 0; i < cnt; i++ )
00968     {
00969       SoShadowCaster * caster = (SoShadowCaster *) this->shadowCastersRoot->getChild(i);
00970       if ( caster->getObjectNode() == object )
00971       {
00972         found = 1;
00973         caster->createFaceModel();
00974         caster->createShadowVolumes();
00975       }    
00976     } 
00977   }  
00978   if ( found < 0 ) { 
00979     this->printError("recreateObjectsShadows: object not found.");
00980   }
00981   ONDEBUG( printf("recreateObjectsShadows done\n\n") );
00982 }
00983 
00984 
00988 void CShadowManager::checkObjects()
00989 {  
00990   int cnt = this->shadowCastersRoot->getNumChildren();
00991   ONDEBUG( fprintf(stdout,"\nSVN has %d children:\n",cnt) );
00992   if ( cnt > 0 ) {  
00993     for (int i = 0; i < cnt; i++ ) {
00994       SoShadowCaster * caster = (SoShadowCaster *) this->shadowCastersRoot->getChild(i);
00995       ONDEBUG( fprintf(stdout,"  child %d: %s\n",i,caster->getName().getString()) );
00996     } 
00997   } 
00998   ONDEBUG( fprintf(stdout,"\n") );
00999 }
01000 
01001 
01007 void CShadowManager::createCasterVolumes(int index)
01008 {
01009   int cnt = this->shadowLightsRoot->getNumChildren();
01010   if ( cnt > 0 )
01011   {
01012     for (int i = 0; i < cnt; i++ )
01013     {
01014       SoShadowLight * slight = (SoShadowLight *) this->shadowLightsRoot->getChild(i);
01015 
01016       int vcnt = slight->getNumVolumes();
01017       if ( vcnt > 0 )
01018       {
01019         for (int j = 0; j < vcnt; j++ )
01020         {      
01021           //new volume node
01022           SoShadowVolume * volume = (SoShadowVolume *) slight->getVolume(j);
01023           if ( volume->getCasterName() == index )
01024           {          
01025             volume->create();
01026           }
01027         }
01028       }
01029     }
01030   }
01031 }
01032 
01033 
01036 
01042 void CShadowManager::createShadowScene()
01043 {  
01044   ONDEBUG( printf("creating shadow scene graph...\n") );
01045 
01046 // rendering callbacks
01047   // scene without shadows
01048   SoCallback * nslightsOffCallback = new SoCallback;
01049   nslightsOffCallback->setCallback(nslightsOffCB, this->shadowLightsRoot);
01050 
01051   SoCallback * nslightsOnCallback = new SoCallback;
01052   nslightsOnCallback->setCallback(nslightsOnCB, this->shadowLightsRoot);
01053 
01054   SoCallback * nsambientOffCallback = new SoCallback;
01055   nsambientOffCallback->setCallback(nsambientOffCB, this->environment);
01056 
01057   SoCallback * nsambientOnCallback = new SoCallback;
01058   nsambientOnCallback->setCallback(nsambientOnCB, this->environment);
01059 
01060   // scene with shadows
01061   SoCallback * initCallback = new SoCallback;
01062   initCallback->setCallback(initCB, this->shadowLightsRoot);
01063   
01064   SoCallback * endCallback = new SoCallback;
01065   endCallback->setCallback(endCB, this->shadowLightsRoot);
01066 
01067   ONDEBUG( this->printSettings() ); 
01068 
01069   if ( this->sceneRoot != NULL )
01070   {
01071 
01072     // what to show
01073 
01074     // only user scene
01075     this->sceneNoShadows->addChild(nslightsOffCallback);    
01076     this->sceneNoShadows->addChild(this->sceneRoot);
01077     this->sceneNoShadows->addChild(nslightsOnCallback);  
01078     this->sceneNoShadows->addChild(nsambientOffCallback);  
01079     this->sceneNoShadows->addChild(this->sceneRoot);
01080     this->sceneNoShadows->addChild(nsambientOnCallback);
01081 
01082     // scene with shadows
01083     
01084     // create top part of shadow scene graph
01085     SoSeparator * aboveShadowVloumesRoot = new SoSeparator;
01086     this->sceneWithShadows->addChild(aboveShadowVloumesRoot);
01087 
01088     aboveShadowVloumesRoot->addChild(initCallback);
01089     aboveShadowVloumesRoot->addChild(this->sceneRoot);
01090 
01091     aboveShadowVloumesRoot->addChild(shadowLightsRoot);
01092     aboveShadowVloumesRoot->addChild(endCallback);
01093 
01094     // scene with shadow volumes ??? 
01095 
01096 /*
01097     // create top part of shadow scene graph
01098     SoSeparator * aboveShadowVloumesRoot = new SoSeparator;
01099     shadowSceneRoot->addChild(aboveShadowVloumesRoot);
01100 
01101     aboveShadowVloumesRoot->addChild(initCallback);
01102     aboveShadowVloumesRoot->addChild(this->sceneRoot);
01103 
01104     aboveShadowVloumesRoot->addChild(shadowLightsRoot);
01105     aboveShadowVloumesRoot->addChild(endCallback);
01106 */
01107   }
01108 }
01109 
01110 
01116 SoSeparator * CShadowManager::getShadowSceneRoot()
01117 {
01118   if ( first ) {
01119     this->createShadowScene();
01120     first = FALSE;
01121   }
01122   return this->shadowSceneRoot;
01123 }
01124 
01125 
01131 SoSeparator * CShadowManager::getSceneRoot()
01132 {
01133   return this->sceneRoot;
01134 }
01135 
01136 
01139 
01145 void CShadowManager::printMsg(const char *msg)
01146 {
01147   fprintf(stdout,"SM: %s\n",msg);
01148 }
01149 
01150 
01156 void CShadowManager::printError(const char *msg)
01157 {
01158   fprintf(stderr,"SM Error: %s\n",msg);
01159 }
01160 
01161 
01167 void CShadowManager::export(const char * filename)
01168 {
01169   SoOutput output;
01170   if ( output.openFile(filename) ) {
01171     SoWriteAction * writer = new SoWriteAction(&output);
01172     writer->apply(this->shadowLightsRoot);
01173     delete writer;
01174   }
01175   else
01176   {
01177     char * buf = NULL;
01178     sprintf(buf,"Can not open file '%s' for export.",filename);
01179     this->printError(buf);
01180   }
01181 }
01182 
01183 
01184 /*
01185 //TODO: Load a shadow scene graph from a file.
01186 void CShadowManager::import(const char * filename)
01187 {
01188   if ( filename != NULL ) 
01189   {
01190     SoInput in;
01191     if (!in.openFile(filename)) {
01192       char * buf = NULL;
01193       sprintf(buf,"Can not open file '%s' for import.",filename);
01194       this->printError(buf);
01195     }
01196 
01197     SoSeparator * loadNode = SoDB::readAll(&in);
01198     loadNode = SoDB::readAll(&in);
01199     loadNode->setName("loadNode");
01200     if (loadNode == NULL) {
01201       char * buf = NULL;
01202       sprintf(buf,"Can not read file '%s' for import.",filename);
01203       this->printError(buf);
01204     }
01205     else
01206     {
01207       this->shadowCastersRoot->removeAllChildren();
01208       this->shadowLightsRoot->removeAllChildren();
01209       this->shadowLightsRoot->addChild(loadNode);
01210     }    
01211   }
01212 }
01213 */
01214 
01215 
01216 
01217 
01218 
01219 
01220 
01221 
01222 
01223 
01224 
01226 // NO Shadow rendering callbacks
01228 
01229 
01230 
01239 void CShadowManager::nslightsOffCB(void *userdata, SoAction *action)
01240 {  
01241   if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
01242 
01243     ONDEBUG(printf("nslightsOffCB\n"));
01244 
01245     // depth
01246     glClearDepth(1.0f);
01247 
01248     glEnable(GL_DEPTH_TEST);
01249     glDepthFunc(GL_LEQUAL);    
01250 
01251     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // ma vliv na barvu a text. souradnice
01252 //    glEnable(GL_CULL_FACE);    
01253     
01254     // Clear all buffers
01255     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
01256     glPushAttrib(GL_ENABLE_BIT); 
01257 
01258     glEnable(GL_LIGHTING);
01259 
01260     // turn off the lights and save each light status
01261     SoSeparator * lightRoot = (SoSeparator * ) userdata;
01262     int cnt = lightRoot->getNumChildren();
01263     for ( int i = 0; i < cnt; i++ )
01264     {
01265       SoShadowLight * slight = static_cast<SoShadowLight *>(lightRoot->getChild(i));
01266       slight->getLight()->on.enableNotify(FALSE);
01267       slight->status = slight->getLight()->on.getValue();
01268       slight->getLight()->on = FALSE;
01269       slight->getLight()->on.enableNotify(TRUE);
01270     }
01271    
01272   }
01273 } 
01274 
01275 
01284 void CShadowManager::nslightsOnCB(void *userdata, SoAction *action)
01285 {  
01286   if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
01287 
01288     ONDEBUG(printf("nslightsOnCB\n"));
01289 
01290     // turn on the lights to its saved status
01291     SoSeparator * lightRoot = (SoSeparator * ) userdata;
01292     int cnt = lightRoot->getNumChildren();
01293     for ( int i = 0; i < cnt; i++ )
01294     {
01295       SoShadowLight * slight = static_cast<SoShadowLight *>(lightRoot->getChild(i));
01296       slight->getLight()->on.enableNotify(FALSE);
01297       slight->getLight()->on = slight->status;
01298       slight->getLight()->on.enableNotify(TRUE);
01299     }   
01300   }
01301 } 
01302 
01303 
01312 void CShadowManager::nsambientOffCB(void *userdata, SoAction *action)
01313 {  
01314   if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
01315     ONDEBUG(printf("nsambientOffCB\n"));    
01316 
01317     glBlendFunc(GL_ONE, GL_ONE);
01318     glEnable(GL_BLEND);    
01319 
01320     SoEnvironment * env = (SoEnvironment * ) userdata;
01321 
01322     // disable ambient light (additive blending)
01323     // (save ambient int. value)
01324     if ( env != NULL )
01325     {
01326       env->ambientIntensity.enableNotify(FALSE);
01327       envIntensity = env->ambientIntensity.getValue();
01328       env->ambientIntensity.setValue(0.0f);
01329       env->ambientIntensity.enableNotify(TRUE);
01330     }
01331   }
01332 } 
01333 
01334 
01344 void CShadowManager::nsambientOnCB(void *userdata, SoAction *action)
01345 {  
01346   if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
01347     ONDEBUG(printf("nsambientOnCB\n"));
01348 
01349     SoEnvironment * env = (SoEnvironment * ) userdata;
01350 
01351     // enable ambient light 
01352     if ( env != NULL )
01353     {
01354       env->ambientIntensity.enableNotify(FALSE);
01355       env->ambientIntensity.setValue(envIntensity);
01356       env->ambientIntensity.enableNotify(TRUE);
01357     }
01358     
01359     glDisable(GL_BLEND);
01360     glDepthFunc(GL_LEQUAL);
01361     glPopAttrib();
01362   }
01363 } 
01364 
01365 
01367 // Shadow rendering callbacks
01369 
01370 
01380 void CShadowManager::initCB(void *userdata, SoAction *action)
01381 {  
01382   if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
01383     ONDEBUG(printf("initCB\n"));    
01384 
01385     // depth
01386     glClearDepth(1.0f);
01387 
01388     glEnable(GL_DEPTH_TEST);
01389     glDepthFunc(GL_LEQUAL);    
01390 
01391     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // ma vliv na barvu a text. souradnice
01392     glEnable(GL_CULL_FACE);    
01393     
01394     // Clear all buffers
01395     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
01396     glPushAttrib(GL_ENABLE_BIT); 
01397 
01398     glEnable(GL_LIGHTING);
01399 
01400     // turn off the lights and save each light status
01401     SoSeparator * lightRoot = (SoSeparator * ) userdata;
01402     int cnt = lightRoot->getNumChildren();
01403     for ( int i = 0; i < cnt; i++ )
01404     {
01405       SoShadowLight * slight = static_cast<SoShadowLight *>(lightRoot->getChild(i));
01406       slight->getLight()->on.enableNotify(FALSE);
01407       slight->status = slight->getLight()->on.getValue();
01408       slight->getLight()->on = FALSE;
01409       slight->getLight()->on.enableNotify(TRUE);
01410     }
01411   }
01412 } 
01413 
01414 
01424 void CShadowManager::endCB(void *userdata, SoAction *action)
01425 {  
01426   if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
01427     ONDEBUG(printf("endCB\n"));
01428     
01429     // set back each light status 
01430     SoSeparator * lightRoot = (SoSeparator * ) userdata;
01431     int cnt = lightRoot->getNumChildren();
01432     for ( int i = 0; i < cnt; i++ )
01433     {
01434       SoShadowLight * slight = static_cast<SoShadowLight *>(lightRoot->getChild(i));
01435       slight->getLight()->on.enableNotify(FALSE);      
01436       slight->getLight()->on = slight->status;
01437       slight->getLight()->on.enableNotify(TRUE);
01438     }
01439     
01440     glDepthFunc(GL_LEQUAL);
01441     glPopAttrib();
01442   }
01443 } 

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