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 
00066 CShadowManager::CShadowManager(SoSeparator *sr, SoEnvironment * env)
00067     : sceneRoot(sr),
00068       environment(env)
00069 {
00070 
00071   if ( this->sceneRoot == NULL )
00072   {
00073     this->printError("Your scene root node is NULL.");
00074   }
00075   else
00076   {
00077     fprintf(stdout,"\nShadows generated by Shadow Engine v %s\n",SE_VERSION);
00078     sceneRoot->ref(); // pokud se v konstruktoru nevola createShadowScene
00079                       // musi se ref  
00080   }
00081 
00082   first = TRUE;
00083   sceneType = SHADOWS;
00084   psceneType = &sceneType;
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       environment->ambientIntensity.setValue(0.2f);
00135       this->shadowSceneRoot->addChild(environment);      
00136     }       
00137   }
00138   environment->ref();
00139 
00140   shadowSceneRoot->addChild(switchNode); // after env node
00141 //  this->setSceneType(CShadowManager::SHADOWS); // default
00142   this->switchNode->whichChild.setValue(CShadowManager::SHADOWS);
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   this->sceneType = type;
00202   // the type is the order of node to traverse
00203 //  this->switchNode->whichChild.setValue(this->sceneType);
00204 }
00205 
00206 
00212 enum CShadowManager::SCENE_TYPE CShadowManager::getSceneType()
00213 {
00214   return this->sceneType;
00215 }
00216 
00217 
00223 void CShadowManager::setManager(TShadowSettings * s)
00224 {
00225   settings = s;  
00226   this->method2algorithm();
00227   this->createShadows();  
00228 }
00229 
00230 
00236 const struct TShadowSettings * CShadowManager::readSettings()
00237 {
00238   return this->settings;
00239 }
00240 
00241 
00247 void CShadowManager::setMethod(enum TShadowMethod newMethod)
00248 {  
00249   enum TShadowAlgorithm old = this->algorithm;
00250   this->settings->method = newMethod;
00251   this->method2algorithm();
00252   if ( old != this->algorithm ) 
00253   {
00254     ONDEBUG ( printf("setMethod: new algorithm => createShadows\n"); );
00255     this->createShadows();
00256   }
00257   else
00258   {
00259     ONDEBUG ( printf("setMethod: algorithm is not updated\n"); );
00260   }
00261   ONDEBUG ( printSettings() );
00262 }
00263 
00264 
00270 void CShadowManager::setSVDepth(float newfDepth)
00271 {  
00272   this->settings->fDepth = newfDepth;
00273   this->createShadows();
00274   ONDEBUG ( printSettings() );
00275 }
00276 
00277 
00281 void CShadowManager::printSettings()
00282 { 
00283   char * a = "";
00284   char * m = "";
00285   char * ds = "";
00286   switch (settings->method) 
00287   {
00288     case zpass:   m = "z-pass";  break;
00289     case zfail:   m = "z-fail";  break;
00290     case autoset: m = "autoset"; break;
00291     default: m = "unknown"; break;
00292   }
00293   algorithm == zpassAlg ? a = "z-pass alg." : a = "z-fail alg.";
00294   settings->dropShadows ? ds = "shadows" : ds = "shadow volumes";  
00295 
00296   printf("\nSM Settings:\n");
00297   printf("  method:    %s\n", m);
00298   printf("  algorithm: %s\n", a);
00299   printf("  show:      %s\n", ds);
00300   printf("  far depth: %.2f\n\n", settings->fDepth);
00301 }
00302 
00303 
00309 TShadowAlgorithm * CShadowManager::getAlgorithm()
00310 {
00311   return &algorithm;
00312 }
00313 
00314 
00318 void CShadowManager::method2algorithm()
00319 {  
00320   ONDEBUG(printf("CShadowManager::method2algorithm\n"));
00321   switch ( settings->method )
00322   {
00323     case zpass: algorithm = zpassAlg; break;
00324 
00325     case zfail: algorithm = zfailAlg; break;
00326 
00327     case autoset: // TODO: determine algoritm on fly according camera position
00328                   // zfail is for now only
00329       algorithm = zfailAlg;
00330     break;
00331 
00332     default: algorithm = zfailAlg; break;
00333   }
00334 }
00335 
00336 
00345 void CShadowManager::disableSensors()
00346 {
00347   // for every caster create and add a new volume node
00348   int cnt = this->shadowCastersRoot->getNumChildren();
00349   ONDEBUG( printf("  disableSensors: SVN has %d children:\n",cnt));
00350   if ( cnt > 0 ) {  
00351     for (int i = 0; i < cnt; i++ ) {
00352       SoShadowCaster * caster = (SoShadowCaster *) this->shadowCastersRoot->getChild(i);
00353       caster->getMoveSensor()->detach();
00354       caster->getShapeSensor()->detach();
00355     } 
00356   } 
00357 }
00358 
00359 
00363 void CShadowManager::enableSensors()
00364 {
00365   // for every caster create and add a new volume node
00366   int cnt = this->shadowCastersRoot->getNumChildren();
00367   ONDEBUG( printf("  enableSensors: SVN has %d children:\n",cnt));
00368   if ( cnt > 0 ) {  
00369     for (int i = 0; i < cnt; i++ ) {
00370       SoShadowCaster * caster = (SoShadowCaster *) this->shadowCastersRoot->getChild(i);
00371       caster->getMoveSensor()->attach(caster->path);
00372       caster->getShapeSensor()->attach(caster->objectRoot);
00373     } 
00374   }
00375 }
00376 
00379 
00380 
00386 SoEnvironment * CShadowManager::getEnvironmentNode()
00387 {
00388   return this->environment;
00389 }
00390 
00391 
00399 void CShadowManager::setAmbientIntensity(float val)
00400 {
00401   this->environment->ambientIntensity.setValue(val);
00402 }
00403 
00413 SoEnvironment * CShadowManager::findEnvironmentNode()
00414 {
00415   if ( this->sceneRoot != NULL )
00416   {
00417     SoSearchAction * sa = new SoSearchAction;
00418     sa->setType(SoEnvironment::getClassTypeId());
00419     sa->setSearchingAll(FALSE);
00420     sa->apply(this->sceneRoot);
00421 
00422     SoPath * nodePath = sa->getPath();
00423     if ( nodePath == NULL ) {
00424       ONDEBUG( printf("SoEnvironment not FOUND\n") );
00425       return NULL;
00426     }
00427     else
00428     {
00429       if (nodePath->getTail()->isOfType(SoEnvironment::getClassTypeId()))
00430       {
00431         ONDEBUG( printf("SoEnvironment is FOUND !!!\n") );
00432         SoEnvironment * env = (SoEnvironment*) nodePath->getTail();
00433         return env;
00434       }
00435     }
00436   }
00437   return NULL;  
00438 }
00439 
00442 
00449 void CShadowManager::lightMoveCallback(void * userdata, SoSensor *s)
00450 {
00451   ONDEBUG( printf("CShadowManager::lightMoveCallback for one light\n") );
00452 
00453   SoShadowLight * slight = static_cast<SoShadowLight *> (userdata);
00454   slight->createShadowVolumes();
00455 }
00456 
00457 
00463 void CShadowManager::addLight(SoLight * light)
00464 {  
00465   ONDEBUG( printf("addLight:\n") );
00466   int i = 0;
00467   int cnt = 0;
00468 
00469   // check, if the light is in the scene graph
00470   SoSearchAction * sa = new SoSearchAction;
00471   sa->setNode(light);
00472   sa->setSearchingAll(FALSE);
00473   sa->apply(this->sceneRoot);
00474 
00475   SoPath * nodePath = sa->getPath(); // tato cesta by se dala vyuzit i v senzoru napojenym na 
00476                                      // cestu
00477   if ( nodePath == NULL ) { // light is not in the scene graph, do not add it
00478     printError("addLight (warning): Light was not found in the scene graph.\nTherefore it was not added in the Shadow Manager\n");
00479   }
00480   else
00481   {
00482     bool found = FALSE;
00483 
00484     // for every caster create and add a new volume node
00485     // it has a sense to test if the light is not already in SM
00486     cnt = this->shadowLightsRoot->getNumChildren();
00487     if ( cnt > 0 )
00488     {  
00489       for (int i = 0; i < cnt; i++ )
00490       {
00491         SoShadowLight * slight = (SoShadowLight *) this->shadowLightsRoot->getChild(i);
00492         if ( slight->getLight() == light )
00493         {
00494           found = TRUE;
00495         }
00496       }
00497     }
00498 
00499     if ( !found ) // light is not there
00500     {
00501 
00502       // volume node name
00503       SbString lindex(lightIndex);
00504       SbString lname = "ShadowLight_";
00505       lname += lindex;
00506       ONDEBUG( printf("  sh light name: %s\n",lname.getString()) );
00507 
00508       light->ref(); // test -> presunout az do SoShL nebo nechat v SM?
00509       SoShadowLight * slight = new SoShadowLight(this, light);
00510       slight->setName(lname);
00511       slight->setLightName(lightIndex);
00512 
00513       // new sensor
00514       SoNodeSensor * lightSensor = new SoNodeSensor(this->lightMoveCallback, slight);
00515       lightSensor->attach((SoNode *) light);
00516       slight->setSensor(lightSensor);
00517 
00518       this->shadowLightsRoot->addChild(slight);
00519 
00520       // create shadow volumes for this light and all existing casters
00521       int cntc = this->shadowCastersRoot->getNumChildren();
00522       ONDEBUG( printf("  add light: num. casters: %d\n",cntc));
00523       if ( cntc > 0 ) {  
00524         for (int i = 0; i < cntc; i++ ) {
00525           SoShadowCaster * caster = (SoShadowCaster *) this->shadowCastersRoot->getChild(i);
00526 
00527           // 2 indexy
00528           // volume node name
00529           SbString cindex(caster->getCasterName());
00530           SbString vname = "SV_L";
00531           vname += lindex;
00532           vname += "_C";
00533           vname += cindex;
00534           ONDEBUG( printf("  sh light name: %s\n",vname.getString()) );
00535 
00536           //new volume node
00537           SoShadowVolume * volume = new SoShadowVolume(slight, caster->getCasterName());
00538           volume->setName(vname);
00539           slight->addVolume(volume);
00540           
00541           ONDEBUG( fprintf(stdout,"  child %d: %s\n",i,caster->getName().getString()) );
00542         } 
00543       } 
00544 
00545       lightIndex++;
00546       // force shadows re-computation
00547       this->createShadows();
00548     } else {
00549       this->printError("Light is already present.");
00550     }
00551   }
00552   ONDEBUG(
00553     printf(" num. lights %d \n", this->shadowLightsRoot->getNumChildren() );
00554   );
00555   this->checkLights();  
00556   ONDEBUG( printf("addLight end\n\n") );  
00557 }
00558 
00559 
00570 void CShadowManager::removeLight(SoLight * light)
00571 { 
00572   ONDEBUG( printf("removeLight:\n") );
00573 
00574   int i = 0;
00575 
00576   if ( light == NULL ) 
00577   {
00578     this->printError("Light is NULL.");       
00579   }
00580   else
00581   {  
00582     int cnt = this->shadowLightsRoot->getNumChildren();
00583     if ( cnt > 0 )
00584     {  
00585       for ( i = 0; i < cnt; i++ )
00586       {
00587         SoShadowLight * slight = (SoShadowLight *) this->shadowLightsRoot->getChild(i);
00588         if ( slight->getLight() == light )
00589         {          
00590           this->shadowLightsRoot->removeChild(i);
00591           // force shadows re-computation
00592           this->createShadows();          
00593           light->unref();  
00594           break;
00595         }
00596       }
00597       if ( i == cnt ) 
00598         this->printError("Light is not in SM.");   
00599     }
00600   }
00601 
00602   ONDEBUG(
00603     checkLights();
00604     printf("  lights %d \n", this->shadowLightsRoot->getNumChildren() );
00605     printf("removeLight end\n\n");
00606   );
00607 }
00608 
00609 
00613 void CShadowManager::checkLights()
00614 {  
00615   bool found = FALSE;
00616 
00617   int cnt = this->shadowLightsRoot->getNumChildren();
00618   if ( cnt > 0 )
00619   {  
00620     for (int i = 0; i < cnt; i++ )
00621     {
00622       SoShadowLight * slight = (SoShadowLight *) this->shadowLightsRoot->getChild(i);
00623 
00624       slight->getLight()->on.enableNotify(FALSE);
00625       SbBool s = slight->getLight()->on.getValue(); // ligtht's status
00626       char * status = "";
00627       s ? status = "on" : status = "off";
00628 
00629       char * typ = "";
00630       if (slight->getLight()->getTypeId() == SoDirectionalLight::getClassTypeId() )
00631         typ = "SoDirectionalLight";
00632       else if (slight->getLight()->getTypeId() == SoDirectionalLightManip::getClassTypeId() )
00633         typ = "SoDirectionalLightManip";
00634       else if (slight->getLight()->getTypeId() == SoPointLight::getClassTypeId() )
00635         typ = "SoPointLight";
00636       else if (slight->getLight()->getTypeId() == SoPointLightManip::getClassTypeId() )
00637         typ = "SoPointLightManip";
00638       else if (slight->getLight()->getTypeId() == SoSpotLight::getClassTypeId() )
00639         typ = "SoSpotLight";
00640       else if (slight->getLight()->getTypeId() == SoSpotLightManip::getClassTypeId() )
00641         typ = "SoSpotLightManip";
00642       else 
00643         typ = "Unknown light type";
00644 
00645       ONDEBUG( fprintf(stdout,"  light %d: %s %s\n",i,status,typ) );
00646     }
00647   }
00648 
00649 }
00650 
00653 
00664 void CShadowManager::objectMoveCallback(void * userdata, SoSensor *s)
00665 {
00666   ONDEBUG( printf("@@@caster path CB\n") );
00667 
00668 /*
00669   o co tady jde: 
00670   1) pri zmene geometrie objektu (polygony) vytvorit znovu face model objektu
00671      sem spada i zmena scale -> v tom pripade by se model nemusel prepocitavat cely,
00672      jen k nemu pridat scale
00673 
00674      potom prepocitat i stinove teleso
00675 
00676   2) zmeni-li se jen poloha/natoceni objektu ve scene, jen prepocitat stinove teleso
00677     
00678   Problem: jak tyto dve veci od sebe rozlisit?
00679   
00680 */
00681 
00682   SoShadowCaster * caster = static_cast<SoShadowCaster *>(userdata);  
00683 
00684   ONDEBUG( printf("@@@caster path CB called by %s\n", caster->getName().getString()) );
00685 
00686   // we know the sensor is really a data sensor
00687   SoDataSensor *mySensor = (SoDataSensor *)s;
00688     
00689   SoNode *changedNode = mySensor->getTriggerNode();
00690   SoField *changedField = mySensor->getTriggerField();
00691   
00692   if ( changedNode != NULL ) {
00693     ONDEBUG( printf("  The node named '%s' changed\n", changedNode->getName().getString()) );
00694     if ( changedNode->getTypeId().isDerivedFrom(SoTransformation::getClassTypeId()) )
00695     {
00696       // translation or rotation has changed
00697       if ( !changedNode->isOfType(SoScale::getClassTypeId()) ) {
00698         ONDEBUG( printf("  create shadow volume for the caster (not a scale tr.)\n") );
00699         caster->setMoved(TRUE);
00700         caster->createShadowVolumes();        
00701       } else { // scale has changed
00702         ONDEBUG( printf("  create shadow volume: scale transform\n") );
00703         caster->createFaceModel();
00704         caster->createShadowVolumes();
00705       }
00706     }
00707     else
00708     {
00709       // something in the scene graph has changed (some node was removed or added)
00710       // or touch called
00711       // re-compute face model (for sure) and shadow volumes
00712       // this is not affected by moving with the light
00713       if ( changedField == NULL )
00714       {
00715 /*
00716         ONDEBUG( printf("  changedNode is NOT NULL but changedField is NULL, no SoTransformation \n") );
00717         caster->createFaceModel();
00718         caster->createShadowVolumes();
00719 */
00720       }
00721     }
00722   } 
00723   else 
00724   {
00725     ONDEBUG( printf("  changedNode is NULL \n") );
00726   }
00727 
00728   ONDEBUG( printf("@@@caster path CB done\n") );
00729 }
00730 
00731 
00738 void CShadowManager::objectShapeCallback(void * userdata, SoSensor *s)
00739 {
00740   ONDEBUG( printf("###caster shape CB\n") );
00741 
00742   SoShadowCaster * caster = static_cast<SoShadowCaster *>(userdata);
00743 
00744   // we know the sensor is really a data sensor
00745   SoDataSensor * mySensor = (SoDataSensor *) s;
00746     
00747   SoNode *changedNode = mySensor->getTriggerNode();
00748   SoField *changedField = mySensor->getTriggerField();
00749     
00750   if ( changedNode != NULL ) {
00751     ONDEBUG( printf("  The node named '%s' changed\n", changedNode->getName().getString()) );
00752 
00753     if (changedField == NULL) // can be caused by add child or touch
00754     {                         // it is called when a new object is added
00755 
00756       ONDEBUG( printf("  changedField == NULL\n") );
00757       if ( changedNode->isOfType(SoSeparator::getClassTypeId()) ) {
00758         ONDEBUG( printf("  added %d \n",caster->getCasterName()) );
00759         // recompute caster model
00760         caster->createFaceModel();
00761         // prepocitat SV
00762         caster->createShadowVolumes();
00763       }
00764 
00765     }
00766 
00767   }
00768   else
00769   {
00770     ONDEBUG( printf("  changedNode is NULL in shape CB\n") );
00771   }
00772   ONDEBUG( printf("###caster shape CB\n") );
00773 }
00774 
00782 int CShadowManager::findObject(SoSeparator * object)
00783 {
00784   // check, if the object is not already in the shadow manager
00785   int found = -1;
00786   int cnt = this->shadowCastersRoot->getNumChildren();
00787   if ( cnt > 0 )
00788   {
00789     for (int i = 0; i < cnt; i++ )
00790     {
00791       SoShadowCaster * caster = (SoShadowCaster *) this->shadowCastersRoot->getChild(i);
00792       if ( caster->getObjectNode() == object )
00793       {
00794         ONDEBUG( printf("findObject: Object is already in SM: %d\n", caster->getCasterName()) );
00795         return caster->getCasterName();
00796       }    
00797     } 
00798   }
00799   ONDEBUG( printf("findObject: Object is not in SM\n") );
00800   return found;  
00801 }
00802 
00803 
00817 void CShadowManager::addObject(SoSeparator * object)
00818 {   
00819   ONDEBUG( printf("add Object\n") );
00820   int i = 0;
00821 
00822   // check, if the object is in the scene graph  
00823   SoSearchAction * sa = new SoSearchAction;
00824   sa->setNode(object);
00825   sa->setSearchingAll(FALSE);
00826   sa->apply(this->sceneRoot);
00827 
00828   // a path from scene root to the object node to detect any transformation changes
00829   SoPath * nodePath = sa->getPath();
00830   if ( nodePath == NULL ) { // object is not in the scene graph, do not add it
00831     printError("addObject (warning): Object was not found in the scene graph.\nTherefore it was not added in the Shadow Manager.\n");
00832   }
00833   else // object is in the scene graph
00834   { 
00835     if ( findObject(object) < 0 ) // add object
00836     { 
00837       // add new casting object node
00838       SoShadowCaster * caster = new SoShadowCaster(this, object);
00839       caster->setCasterName(objectIndex);
00840       this->shadowCastersRoot->addChild(caster);
00841       objectIndex++;
00842   
00843       // ref the object, for sure
00844       object->ref();
00845                   
00846       // create a new object sensor to detect location changes
00847       SoPathSensor * objectSensor = new SoPathSensor(this->objectMoveCallback, caster);
00848       objectSensor->setPriority(0); // important
00849       objectSensor->attach(nodePath);
00850       caster->setMoveSensor(objectSensor);
00851 
00852       caster->path = nodePath;
00853 
00854       // create a new object sensor to detect shape changes
00855       SoNodeSensor * objectSensorC = new SoNodeSensor(this->objectShapeCallback, caster);
00856       objectSensorC->attach((SoNode *) object);
00857       objectSensorC->setPriority(0); // important
00858       caster->setShapeSensor(objectSensorC);
00859 
00860       // tohle by se melo dat do nejake metody
00861       // create volume nodes for all lights in SM and this object
00862       int cnt = this->shadowLightsRoot->getNumChildren();
00863       if ( cnt > 0 )
00864       {
00865         for (int i = 0; i < cnt; i++ )
00866         {
00867           SoShadowLight * slight = (SoShadowLight *) this->shadowLightsRoot->getChild(i);
00868       
00869           // 2 indexy
00870           // volume node name
00871           SbString cindex(caster->getCasterName());
00872           SbString lindex(slight->getLightName());
00873           SbString vname = "SV_L";
00874           vname += lindex;
00875           vname += "_C";
00876           vname += cindex;
00877           ONDEBUG( printf("  sh volume name: %s\n",vname.getString()) );
00878 
00879           //new volume node
00880           SoShadowVolume * volume = new SoShadowVolume(slight, caster->getCasterName());
00881           volume->setName(vname);
00882           
00883           slight->addVolume(volume);
00884         }
00885       }
00886 
00887       ONDEBUG( printf("  child %d: %s\n",i,caster->getName().getString()) );
00888       ONDEBUG( printf("  add obj: volume added\n") );
00889       ONDEBUG( printf("  The new caster has %d children.\n", caster->getNumChildren()) );
00890 
00891       // very importatnt thing. this nottyfies the attached sensor and 
00892       // calls appropriate CB method which creates object's model and shadows
00893       // also causes redraw of the scene, i.e. shadow appears in it
00894       object->touch();
00895       ONDEBUG( this->printMsg("  Object was added.") );
00896 
00897     } else {
00898       this->printError("Object is already present.");
00899     }    
00900   }
00901   ONDEBUG( checkObjects() );
00902   ONDEBUG( printf("add object done\n\n") );
00903 }
00904 
00905 
00914 void CShadowManager::removeObject(SoSeparator * object)
00915 { 
00916 
00917   ONDEBUG( printf("remove object\n") );
00918   // check, if the object is not already in the shadow manager
00919   int found = -1;
00920   int cnt = this->shadowCastersRoot->getNumChildren();
00921   if ( cnt > 0 ) 
00922   {  
00923     for (int i = 0; i < cnt; i++ )
00924     {
00925       SoShadowCaster * caster = (SoShadowCaster *) this->shadowCastersRoot->getChild(i);
00926       if ( caster->getObjectNode() == object )
00927       {
00928         ONDEBUG( printf("  removing caster: %d\n", caster->getCasterName()) );
00929         found = caster->getCasterName();
00930 
00931         // delete shadow volumes of this caster and each light
00932         int cntl = this->shadowLightsRoot->getNumChildren();
00933         for (int j = 0; j < cntl; j++ )
00934         {
00935           SoShadowLight * slight = (SoShadowLight *) this->shadowLightsRoot->getChild(j);
00936           slight->deleteVolume(caster->getCasterName());
00937         }
00938 
00939         this->shadowCastersRoot->removeChild(i);        
00940         // unref the object, was ref()ed
00941         object->unref();
00942 
00943         break; // to prevent failure; remove the first occurence only
00944         // musi tady byt break, ptz pocet deti se snizi o 1 a po dstraneni 1 se
00945         // saha za konec () cnt se neupdatuje, musel by se pouzit while nejak
00946       }    
00947     } 
00948   }  
00949   if ( found < 0 ) { 
00950     this->printError("removeObject: object not found.");
00951   }
00952   ONDEBUG( checkObjects() );
00953   ONDEBUG( printf("remove object done\n\n") );
00954 
00955 }
00956 
00957 
00966 void CShadowManager::createObjectsShadows(SoSeparator * object)
00967 { 
00968   ONDEBUG( printf("recreateObjectsShadows\n") );
00969   // check, if the object is not already in the shadow manager
00970   int found = -1;
00971   int cnt = this->shadowCastersRoot->getNumChildren();
00972   if ( cnt > 0 ) 
00973   {  
00974     for (int i = 0; i < cnt; i++ )
00975     {
00976       SoShadowCaster * caster = (SoShadowCaster *) this->shadowCastersRoot->getChild(i);
00977       if ( caster->getObjectNode() == object )
00978       {
00979         found = 1;
00980         caster->createFaceModel();
00981         caster->createShadowVolumes();
00982       }    
00983     } 
00984   }  
00985   if ( found < 0 ) { 
00986     this->printError("recreateObjectsShadows: object not found.");
00987   }
00988   ONDEBUG( printf("recreateObjectsShadows done\n\n") );
00989 }
00990 
00991 
00995 void CShadowManager::checkObjects()
00996 {  
00997   int cnt = this->shadowCastersRoot->getNumChildren();
00998   ONDEBUG( fprintf(stdout,"\nSVN has %d children:\n",cnt) );
00999   if ( cnt > 0 ) {  
01000     for (int i = 0; i < cnt; i++ ) {
01001       SoShadowCaster * caster = (SoShadowCaster *) this->shadowCastersRoot->getChild(i);
01002       ONDEBUG( fprintf(stdout,"  child %d: %s\n",i,caster->getName().getString()) );
01003     } 
01004   } 
01005   ONDEBUG( fprintf(stdout,"\n") );
01006 }
01007 
01008 
01014 void CShadowManager::createCasterVolumes(int index)
01015 {
01016   int cnt = this->shadowLightsRoot->getNumChildren();
01017   if ( cnt > 0 )
01018   {
01019     for (int i = 0; i < cnt; i++ )
01020     {
01021       SoShadowLight * slight = (SoShadowLight *) this->shadowLightsRoot->getChild(i);
01022 
01023       int vcnt = slight->getNumVolumes();
01024       if ( vcnt > 0 )
01025       {
01026         for (int j = 0; j < vcnt; j++ )
01027         {      
01028           //new volume node
01029           SoShadowVolume * volume = (SoShadowVolume *) slight->getVolume(j);
01030           if ( volume->getCasterName() == index )
01031           {          
01032             volume->create();
01033           }
01034         }
01035       }
01036     }
01037   }
01038 }
01039 
01040 
01043 
01049 void CShadowManager::createShadowScene()
01050 {  
01051   ONDEBUG( printf("creating shadow scene graph...\n") );
01052 
01053   // rendering callbacks
01054   SoCallback * initCallback = new SoCallback;
01055   initCallback->setCallback(initCB, this->shadowLightsRoot);
01056 
01057   // rendering callbacks
01058   SoCallback * endCallback = new SoCallback;
01059   endCallback->setCallback(endCB, this->shadowLightsRoot);
01060 
01061   ONDEBUG( this->printSettings() ); 
01062 
01063   if ( this->sceneRoot != NULL )
01064   {
01065 
01066     // what to show
01067 
01068     // only user scene
01069     this->sceneNoShadows->addChild(this->sceneRoot);
01070 
01071     // scene with shadows
01072     
01073     // create top part of shadow scene graph
01074     SoSeparator * aboveShadowVloumesRoot = new SoSeparator;
01075     this->sceneWithShadows->addChild(aboveShadowVloumesRoot);
01076 
01077     aboveShadowVloumesRoot->addChild(initCallback);
01078     aboveShadowVloumesRoot->addChild(this->sceneRoot);
01079 
01080     aboveShadowVloumesRoot->addChild(shadowLightsRoot);
01081     aboveShadowVloumesRoot->addChild(endCallback);
01082 
01083     // scene with shadow volumes ??? 
01084 
01085 /*
01086     // create top part of shadow scene graph
01087     SoSeparator * aboveShadowVloumesRoot = new SoSeparator;
01088     shadowSceneRoot->addChild(aboveShadowVloumesRoot);
01089 
01090     aboveShadowVloumesRoot->addChild(initCallback);
01091     aboveShadowVloumesRoot->addChild(this->sceneRoot);
01092 
01093     aboveShadowVloumesRoot->addChild(shadowLightsRoot);
01094     aboveShadowVloumesRoot->addChild(endCallback);
01095 */
01096   }
01097 }
01098 
01099 
01105 SoSeparator * CShadowManager::getShadowSceneRoot()
01106 {
01107   if ( first ) {
01108     this->createShadowScene();
01109     first = FALSE;
01110   }
01111   return this->shadowSceneRoot;
01112 }
01113 
01114 
01120 SoSeparator * CShadowManager::getSceneRoot()
01121 {
01122   return this->sceneRoot;
01123 }
01124 
01125 
01128 
01134 void CShadowManager::printMsg(const char *msg)
01135 {
01136   fprintf(stdout,"SM: %s\n",msg);
01137 }
01138 
01139 
01145 void CShadowManager::printError(const char *msg)
01146 {
01147   fprintf(stderr,"SM Error: %s\n",msg);
01148 }
01149 
01150 
01156 void CShadowManager::export(const char * filename)
01157 {
01158   SoOutput output;
01159   if ( output.openFile(filename) ) {
01160     SoWriteAction * writer = new SoWriteAction(&output);
01161     writer->apply(this->shadowLightsRoot);
01162     delete writer;
01163   }
01164   else
01165   {
01166     char * buf = NULL;
01167     sprintf(buf,"Can not open file '%s' for export.",filename);
01168     this->printError(buf);
01169   }
01170 }
01171 
01172 
01173 /*
01174 //TODO: Load a shadow scene graph from a file.
01175 void CShadowManager::import(const char * filename)
01176 {
01177   if ( filename != NULL ) 
01178   {
01179     SoInput in;
01180     if (!in.openFile(filename)) {
01181       char * buf = NULL;
01182       sprintf(buf,"Can not open file '%s' for import.",filename);
01183       this->printError(buf);
01184     }
01185 
01186     SoSeparator * loadNode = SoDB::readAll(&in);
01187     loadNode = SoDB::readAll(&in);
01188     loadNode->setName("loadNode");
01189     if (loadNode == NULL) {
01190       char * buf = NULL;
01191       sprintf(buf,"Can not read file '%s' for import.",filename);
01192       this->printError(buf);
01193     }
01194     else
01195     {
01196       this->shadowCastersRoot->removeAllChildren();
01197       this->shadowLightsRoot->removeAllChildren();
01198       this->shadowLightsRoot->addChild(loadNode);
01199     }    
01200   }
01201 }
01202 */
01203 
01205 // Shadow rendering callbacks
01207 
01208 
01218 void CShadowManager::initCB(void *userdata, SoAction *action)
01219 {  
01220   if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
01221     ONDEBUG(printf("initCB\n"));    
01222 
01223     // depth
01224     glClearDepth(1.0f);
01225 
01226     glEnable(GL_DEPTH_TEST);
01227     glDepthFunc(GL_LEQUAL);    
01228 
01229     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // ma vliv na barvu a text. souradnice
01230     glEnable(GL_CULL_FACE);    
01231     
01232     // Clear all buffers
01233     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
01234     glPushAttrib(GL_ENABLE_BIT); 
01235 
01236     glEnable(GL_LIGHTING);
01237 
01238     // turn off the lights and save each light status
01239     SoSeparator * lightRoot = (SoSeparator * ) userdata;
01240     int cnt = lightRoot->getNumChildren();
01241     for ( int i = 0; i < cnt; i++ )
01242     {
01243       SoShadowLight * slight = static_cast<SoShadowLight *>(lightRoot->getChild(i));
01244       slight->getLight()->on.enableNotify(FALSE);
01245       slight->status = slight->getLight()->on.getValue();
01246       slight->getLight()->on = FALSE;
01247       slight->getLight()->on.enableNotify(TRUE);
01248     }
01249   }
01250 } 
01251 
01252 
01262 void CShadowManager::endCB(void *userdata, SoAction *action)
01263 {  
01264   if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
01265     ONDEBUG(printf("endCB\n"));
01266     
01267     // set back each light status 
01268     SoSeparator * lightRoot = (SoSeparator * ) userdata;
01269     int cnt = lightRoot->getNumChildren();
01270     for ( int i = 0; i < cnt; i++ )
01271     {
01272       SoShadowLight * slight = static_cast<SoShadowLight *>(lightRoot->getChild(i));
01273       slight->getLight()->on.enableNotify(FALSE);      
01274       slight->getLight()->on = slight->status;
01275       slight->getLight()->on.enableNotify(TRUE);
01276     }
01277     
01278     glDisable(GL_LIGHTING);
01279     glDepthFunc(GL_LEQUAL);
01280     glPopAttrib();
01281   }
01282 } 

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