Blender  V2.59
ntl_world.cpp
Go to the documentation of this file.
00001 
00004 /******************************************************************************
00005  *
00006  * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
00007  * Copyright 2003-2006 Nils Thuerey
00008  *
00009  * Main renderer class
00010  *
00011  *****************************************************************************/
00012 
00013 
00014 #include <sys/stat.h>
00015 #include <sstream>
00016 #include "utilities.h"
00017 #include "ntl_world.h"
00018 #include "parametrizer.h"
00019 
00020 // for non-threaded renderViz
00021 #ifndef NOGUI
00022 #include "../gui/ntl_openglrenderer.h"
00023 #include "../gui/guifuncs.h"
00024 #include "../gui/frame.h"
00025 #endif
00026 
00027 
00028 /* external parser functions from cfgparser.cxx */
00029 #ifndef ELBEEM_PLUGIN
00030 /* parse given file as config file */
00031 void parseFile(string filename);
00032 /* set pointers for parsing */
00033 void setPointers( ntlRenderGlobals *setglob);
00034 #endif // ELBEEM_PLUGIN
00035 
00036 
00037 /******************************************************************************
00038  * Constructor
00039  *****************************************************************************/
00040 
00041 ntlWorld::ntlWorld() {
00042         initDefaults();
00043 }
00044 
00045 ntlWorld::ntlWorld(string filename, bool commandlineMode) 
00046 {
00047 #ifndef ELBEEM_PLUGIN
00048 
00049                 initDefaults();
00050 #       ifdef NOGUI
00051                 commandlineMode = true; // remove warning...
00052 #       endif // NOGUI
00053 
00054                 // load config
00055                 setPointers( getRenderGlobals() );
00056                 parseFile( filename.c_str() );
00057 #       ifndef NOGUI
00058                 // setup opengl display, save first animation step for start time 
00059                 // init after parsing file...
00060                 if(!commandlineMode) {
00061                         mpOpenGLRenderer = new ntlOpenGLRenderer( mpGlob );
00062                 }
00063 #       endif // NOGUI
00064                 finishWorldInit();
00065 
00066 #else // ELBEEM_PLUGIN
00067         errFatal("ntlWorld::init","Cfg file parsing not supported for API version! "<<filename<<" "<<commandlineMode, SIMWORLD_INITERROR);
00068 #endif // ELBEEM_PLUGIN
00069 }
00070 
00071 
00072 int globalDomainCounter = 1;
00073 int ntlWorld::addDomain(elbeemSimulationSettings *settings)
00074 {
00075         // create domain obj
00076         SimulationObject *sim = new SimulationObject();
00077         char simname[100];
00078         snprintf(simname,100,"domain%04d",globalDomainCounter);
00079         globalDomainCounter++;
00080         sim->setName(string(simname));
00081         mpGlob->getSims()->push_back( sim );
00082 
00083         // important - add to both, only render scene objects are free'd 
00084         mpGlob->getRenderScene()->addGeoClass( sim );
00085         mpGlob->getSimScene()->addGeoClass( sim );
00086         sim->setGeoStart(ntlVec3Gfx(settings->geoStart[0],settings->geoStart[1],settings->geoStart[2]));
00087         sim->setGeoEnd(ntlVec3Gfx(
00088                         settings->geoStart[0]+settings->geoSize[0],
00089                         settings->geoStart[1]+settings->geoSize[1],
00090                         settings->geoStart[2]+settings->geoSize[2] ));
00091         // further init in postGeoConstrInit/initializeLbmSimulation of SimulationObject
00092         sim->copyElbeemSettings(settings);
00093 
00094         Parametrizer *param = sim->getParametrizer();
00095         param->setSize( settings->resolutionxyz );
00096         param->setDomainSize( settings->realsize );
00097         param->setAniStart( settings->animStart );
00098         param->setNormalizedGStar( settings->gstar );
00099 
00100         // init domain channels
00101         vector<ParamFloat> valf; 
00102         vector<ParamVec> valv; 
00103         vector<double> time;
00104 
00105 #define INIT_CHANNEL_FLOAT(channel,size) \
00106         valf.clear(); time.clear(); elbeemSimplifyChannelFloat(channel,&size); \
00107         for(int i=0; i<size; i++) { valf.push_back( channel[2*i+0] ); time.push_back( channel[2*i+1] ); } 
00108 #define INIT_CHANNEL_VEC(channel,size) \
00109         valv.clear(); time.clear(); elbeemSimplifyChannelVec3(channel,&size); \
00110         for(int i=0; i<size; i++) { valv.push_back( ParamVec(channel[4*i+0],channel[4*i+1],channel[4*i+2]) ); time.push_back( channel[4*i+3] ); } 
00111 
00112         param->setViscosity( settings->viscosity );
00113         if((settings->channelViscosity)&&(settings->channelSizeViscosity>0)) {
00114                 INIT_CHANNEL_FLOAT(settings->channelViscosity, settings->channelSizeViscosity);
00115                 param->initViscosityChannel(valf,time); }
00116 
00117         param->setGravity( ParamVec(settings->gravity[0], settings->gravity[1], settings->gravity[2]) );
00118         if((settings->channelGravity)&&(settings->channelSizeGravity>0)) {
00119                 INIT_CHANNEL_VEC(settings->channelGravity, settings->channelSizeGravity);
00120                 param->initGravityChannel(valv,time); }
00121 
00122         param->setAniFrameTimeChannel( settings->aniFrameTime );
00123         if((settings->channelFrameTime)&&(settings->channelSizeFrameTime>0)) {
00124                 INIT_CHANNEL_FLOAT(settings->channelFrameTime, settings->channelSizeFrameTime);
00125                 param->initAniFrameTimeChannel(valf,time); }
00126 
00127 #undef INIT_CHANNEL_FLOAT
00128 #undef INIT_CHANNEL_VEC
00129         
00130         // might be set by previous domain
00131         if(mpGlob->getAniFrames() < settings->noOfFrames)       mpGlob->setAniFrames( settings->noOfFrames );
00132         // set additionally to SimulationObject->mOutFilename
00133         mpGlob->setOutFilename( settings->outputPath );
00134 
00135         return 0;
00136 }
00137 
00138 void ntlWorld::initDefaults()
00139 {
00140         mStopRenderVisualization = false;
00141         mThreadRunning =  false;
00142         mSimulationTime = 0.0; 
00143         mFirstSim = 1;
00144         mSingleStepDebug =  false;
00145         mFrameCnt = 0;
00146         mpOpenGLRenderer = NULL;
00147 
00148   /* create scene storage */
00149   mpGlob = new ntlRenderGlobals();
00150   mpLightList = new vector<ntlLightObject*>;
00151   mpPropList = new vector<ntlMaterial*>;
00152   mpSims = new vector<SimulationObject*>;
00153 
00154   mpGlob->setLightList(mpLightList);
00155   mpGlob->setMaterials(mpPropList);
00156   mpGlob->setSims(mpSims);
00157 
00158         /* init default material */
00159   ntlMaterial *def = GET_GLOBAL_DEFAULT_MATERIAL;
00160         mpPropList->push_back( def );
00161 
00162         /* init the scene object */
00163         ntlScene *renderscene = new ntlScene( mpGlob, true );
00164         mpGlob->setRenderScene( renderscene );
00165         // sim scene shouldnt delete objs, may only contain subset
00166         ntlScene *simscene = new ntlScene( mpGlob, false );
00167         mpGlob->setSimScene( simscene );
00168 }
00169 
00170 void ntlWorld::finishWorldInit()
00171 {
00172         if(! isSimworldOk() ) return;
00173 
00174         // init the scene for the first time
00175   long sstartTime = getTime();
00176 
00177         // first init sim scene for geo setup
00178         mpGlob->getSimScene()->buildScene(0.0, true);
00179         if(! isSimworldOk() ) return;
00180         mpGlob->getRenderScene()->buildScene(0.0, true);
00181         if(! isSimworldOk() ) return;
00182         long sstopTime = getTime();
00183         debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Scene build time: "<< getTimeString(sstopTime-sstartTime) <<" ", 10);
00184 
00185         // TODO check simulations, run first steps
00186         mFirstSim = -1;
00187         if(mpSims->size() > 0) {
00188 
00189                 // use values from first simulation as master time scale
00190                 long startTime = getTime();
00191                 
00192                 // remember first active sim
00193                 for(size_t i=0;i<mpSims->size();i++) {
00194                         if(!(*mpSims)[i]->getVisible()) continue;
00195                         if((*mpSims)[i]->getPanic())    continue;
00196 
00197                         // check largest timestep
00198                         if(mFirstSim>=0) {
00199                                 if( (*mpSims)[i]->getTimestep() > (*mpSims)[mFirstSim]->getTimestep() ) {
00200                                         mFirstSim = i;
00201                                         debMsgStd("ntlWorld::ntlWorld",DM_MSG,"First Sim changed: "<<i ,10);
00202                                 }
00203                         }
00204                         // check any valid sim
00205                         if(mFirstSim<0) {
00206                                 mFirstSim = i;
00207                                 debMsgStd("ntlWorld::ntlWorld",DM_MSG,"First Sim: "<<i ,10);
00208                         }
00209                 }
00210 
00211                 if(mFirstSim>=0) {
00212                         debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Anistart Time: "<<(*mpSims)[mFirstSim]->getStartTime() ,10);
00213                         while(mSimulationTime < (*mpSims)[mFirstSim]->getStartTime() ) {
00214                         debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Anistart Time: "<<(*mpSims)[mFirstSim]->getStartTime()<<" simtime:"<<mSimulationTime ,10);
00215                                 advanceSims(-1);
00216                         }
00217                         long stopTime = getTime();
00218 
00219                         mSimulationTime += (*mpSims)[mFirstSim]->getStartTime();
00220                         debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Time for start-sims:"<< getTimeString(stopTime-startTime) , 1);
00221 #ifndef NOGUI
00222                         guiResetSimulationTimeRange( mSimulationTime );
00223 #endif
00224                 } else {
00225                         if(!mpGlob->getSingleFrameMode()) debMsgStd("ntlWorld::ntlWorld",DM_WARNING,"No active simulations!", 1);
00226                 }
00227         }
00228 
00229         if(! isSimworldOk() ) return;
00230         setElbeemState( SIMWORLD_INITED );
00231 }
00232 
00233 
00234 
00235 /******************************************************************************
00236  * Destructor
00237  *****************************************************************************/
00238 ntlWorld::~ntlWorld()
00239 {
00240         delete mpGlob->getRenderScene();
00241         delete mpGlob->getSimScene();
00242   
00243         delete mpGlob;
00244         
00245         
00246         // these get assigned to mpGlob but not freed there
00247         delete mpLightList;
00248         delete mpPropList; // materials
00249         delete mpSims;
00250   
00251 #ifndef NOGUI
00252         if(mpOpenGLRenderer) delete mpOpenGLRenderer;
00253 #endif // NOGUI
00254         debMsgStd("ntlWorld",DM_NOTIFY, "ntlWorld done", 10);
00255 }
00256 
00257 /******************************************************************************/
00259 void ntlWorld::setSingleFrameOut(string singleframeFilename) {
00260         mpGlob->setSingleFrameMode(true);
00261         mpGlob->setSingleFrameFilename(singleframeFilename);
00262 }
00263 
00264 /******************************************************************************
00265  * render a whole animation (command line mode) 
00266  *****************************************************************************/
00267 
00268 int ntlWorld::renderAnimation( void )
00269 {
00270         // only single pic currently
00271         //debMsgStd("ntlWorld::renderAnimation : Warning only simulating...",1);
00272         if(mpGlob->getAniFrames() < 0) {
00273                 debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"No frames to render... ",1);
00274                 return 1;
00275         }
00276 
00277         if(mFirstSim<0) {
00278                 debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"No reference animation found...",1);
00279                 return 1;
00280         } 
00281 
00282         mThreadRunning = true; // not threaded, but still use the same flags
00283         if(getElbeemState() == SIMWORLD_INITED) {
00284                 renderScene();
00285         } else if(getElbeemState() == SIMWORLD_STOP) {
00286                 // dont render now, just continue
00287                 setElbeemState( SIMWORLD_INITED );
00288                 mFrameCnt--; // counted one too many from last abort...
00289         } else {
00290                 debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"Not properly inited, stopping...",1);
00291                 return 1;
00292         }
00293         
00294         if(mpSims->size() <= 0) {
00295                 debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"No simulations found, stopping...",1);
00296                 return 1;
00297         }
00298 
00299         bool simok = true;
00300         for( ; ((mFrameCnt<mpGlob->getAniFrames()) && (!getStopRenderVisualization() ) && (simok)); mFrameCnt++) {
00301                 if(!advanceSims(mFrameCnt)) {
00302                         renderScene();
00303                 } // else means sim panicked, so dont render...
00304                 else { simok=false; }
00305         }
00306         mThreadRunning = false;
00307         return 0;
00308 }
00309 
00310 /******************************************************************************
00311  * render a whole animation (visualization mode) 
00312  * this function is run in another thread, and communicates 
00313  * with the parent thread via a mutex 
00314  *****************************************************************************/
00315 int ntlWorld::renderVisualization( bool multiThreaded ) 
00316 {
00317 #ifndef NOGUI
00318         if(getElbeemState() != SIMWORLD_INITED) { return 0; }
00319 
00320         if(multiThreaded) mThreadRunning = true;
00321         // TODO, check global state?
00322         while(!getStopRenderVisualization()) {
00323 
00324                 if(mpSims->size() <= 0) {
00325                         debMsgStd("ntlWorld::renderVisualization",DM_NOTIFY,"No simulations found, stopping...",1);
00326                         stopSimulationThread();
00327                         break;
00328                 }
00329 
00330                 // determine stepsize
00331                 if(!mSingleStepDebug) {
00332                         long startTime = getTime();
00333                         advanceSims(mFrameCnt);
00334                         mFrameCnt++;
00335                         long stopTime = getTime();
00336                         debMsgStd("ntlWorld::renderVisualization",DM_MSG,"Time for t="<<mSimulationTime<<": "<< getTimeString(stopTime-startTime) <<" ", 10);
00337                 } else {
00338                         double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getTimestep();
00339                         singleStepSims(targetTime);
00340 
00341                         // check paniced sims (normally done by advanceSims
00342                         bool allPanic = true;
00343                         for(size_t i=0;i<mpSims->size();i++) {
00344                                 if(!(*mpSims)[i]->getPanic()) allPanic = false;
00345                         }
00346                         if(allPanic) {
00347                                 warnMsg("ntlWorld::advanceSims","All sims panicked... stopping thread" );
00348                                 setStopRenderVisualization( true );
00349                         }
00350                         if(! isSimworldOk() ) {
00351                                 warnMsg("ntlWorld::advanceSims","World state error... stopping" );
00352                                 setStopRenderVisualization( true );
00353                         }
00354                 }
00355 
00356                 // save frame
00357                 if(mpOpenGLRenderer) mpOpenGLRenderer->saveAnimationFrame( mSimulationTime );
00358                 
00359                 // for non-threaded check events
00360                 if(!multiThreaded) {
00361                         Fl::check();
00362       gpElbeemFrame->SceneDisplay->doOnlyForcedRedraw();
00363                 }
00364 
00365         }
00366         mThreadRunning = false;
00367         stopSimulationRestoreGui();
00368 #else 
00369         multiThreaded = false; // remove warning
00370 #endif
00371         return 0;
00372 }
00374 int ntlWorld::singleStepVisualization( void ) 
00375 {
00376         mThreadRunning = true;
00377         double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getTimestep();
00378         singleStepSims(targetTime);
00379         mSimulationTime = (*mpSims)[0]->getCurrentTime();
00380 
00381 #ifndef NOGUI
00382         if(mpOpenGLRenderer) mpOpenGLRenderer->saveAnimationFrame( mSimulationTime );
00383         Fl::check();
00384   gpElbeemFrame->SceneDisplay->doOnlyForcedRedraw();
00385         mThreadRunning = false;
00386         stopSimulationRestoreGui();
00387 #else
00388         mThreadRunning = false;
00389 #endif // NOGUI
00390         return 0;
00391 }
00392 
00393 // dont use LBM_EPSILON here, time is always double-precision!
00394 #define LBM_TIME_EPSILON 1e-10
00395 
00396 /******************************************************************************
00397  * advance simulations by time t 
00398  *****************************************************************************/
00399 int ntlWorld::advanceSims(int framenum)
00400 {
00401         bool done = false;
00402         bool allPanic = true;
00403 
00404         // stop/quit, dont display/render
00405         if(getElbeemState()==SIMWORLD_STOP) { 
00406                 return 1;
00407         }
00408 
00409         for(size_t i=0;i<mpSims->size();i++) { (*mpSims)[i]->setFrameNum(framenum); }
00410         double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getFrameTime(framenum);
00411 
00412         // time stopped? nothing else to do...
00413         if( (*mpSims)[mFirstSim]->getFrameTime(framenum) <= 0.0 ){ 
00414                 done=true; allPanic=false; 
00415         }
00416 
00417         int gstate = 0;
00418         myTime_t advsstart = getTime();
00419 
00420         // step all the sims, and check for panic
00421         debMsgStd("ntlWorld::advanceSims",DM_MSG, " sims "<<mpSims->size()<<" t"<<targetTime<<" done:"<<done<<" panic:"<<allPanic<<" gstate:"<<gstate, 10); // debug // timedebug
00422         while(!done) {
00423                 double nextTargetTime = (*mpSims)[mFirstSim]->getCurrentTime() + (*mpSims)[mFirstSim]->getTimestep();
00424                 singleStepSims(nextTargetTime);
00425 
00426                 // check target times
00427                 done = true;
00428                 allPanic = false;
00429                 
00430                 if((*mpSims)[mFirstSim]->getTimestep() <1e-9 ) { 
00431                         // safety check, avoid timesteps that are too small
00432                         errMsg("ntlWorld::advanceSims","Invalid time step, causing panic! curr:"<<(*mpSims)[mFirstSim]->getCurrentTime()<<" next:"<<nextTargetTime<<", stept:"<< (*mpSims)[mFirstSim]->getTimestep() );
00433                         allPanic = true; 
00434                 } else {
00435                         for(size_t i=0;i<mpSims->size();i++) {
00436                                 if(!(*mpSims)[i]->getVisible()) continue;
00437                                 if((*mpSims)[i]->getPanic()) allPanic = true; // do any panic now!?
00438                                 debMsgStd("ntlWorld::advanceSims",DM_MSG, "Sim "<<i<<", currt:"<<(*mpSims)[i]->getCurrentTime()<<", nt:"<<nextTargetTime<<", panic:"<<(*mpSims)[i]->getPanic()<<", targett:"<<targetTime, 10); // debug // timedebug
00439                         } 
00440                 }
00441                 if( (targetTime - (*mpSims)[mFirstSim]->getCurrentTime()) > LBM_TIME_EPSILON) done=false;
00442                 if(allPanic) done = true;
00443         }
00444 
00445         if(allPanic) {
00446                 warnMsg("ntlWorld::advanceSims","All sims panicked... stopping thread" );
00447                 setStopRenderVisualization( true );
00448                 return 1;
00449         }
00450 
00451         myTime_t advsend = getTime();
00452         debMsgStd("ntlWorld::advanceSims",DM_MSG,"Overall steps so far took:"<< getTimeString(advsend-advsstart)<<" for sim time "<<targetTime, 4);
00453 
00454         // finish step
00455         for(size_t i=0;i<mpSims->size();i++) {
00456                 SimulationObject *sim = (*mpSims)[i];
00457                 if(!sim->getVisible()) continue;
00458                 if(sim->getPanic()) continue;
00459                 sim->prepareVisualization();
00460         }
00461 
00462         return 0;
00463 }
00464 
00465 /* advance simulations by a single step */
00466 /* dont check target time, if *targetTime==NULL */
00467 void ntlWorld::singleStepSims(double targetTime) {
00468         const bool debugTime = false;
00469         //double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getTimestep();
00470         if(debugTime) errMsg("ntlWorld::singleStepSims","Target time: "<<targetTime);
00471 
00472         for(size_t i=0;i<mpSims->size();i++) {
00473                 SimulationObject *sim = (*mpSims)[i];
00474                 if(!sim->getVisible()) continue;
00475                 if(sim->getPanic()) continue;
00476                 bool done = false;
00477                 while(!done) {
00478                         // try to prevent round off errs
00479                         if(debugTime) errMsg("ntlWorld::singleStepSims","Test sim "<<i<<" curt:"<< sim->getCurrentTime()<<" target:"<<targetTime<<" delta:"<<(targetTime - sim->getCurrentTime())<<" stept:"<<sim->getTimestep()<<" leps:"<<LBM_TIME_EPSILON ); // timedebug
00480                         if( (targetTime - sim->getCurrentTime()) > LBM_TIME_EPSILON) {
00481                                 if(debugTime) errMsg("ntlWorld::singleStepSims","Stepping sim "<<i<<" t:"<< sim->getCurrentTime()); // timedebug
00482                                 sim->step();
00483                         } else {
00484                                 done = true;
00485                         }
00486                 }
00487         }
00488 
00489         mSimulationTime = (*mpSims)[mFirstSim]->getCurrentTime();
00490 #ifndef NOGUI
00491         if(mpOpenGLRenderer) mpOpenGLRenderer->notifyOfNextStep(mSimulationTime);
00492 #endif // NOGUI
00493 }
00494 
00495 
00496 
00497 extern bool glob_mpactive;
00498 extern int glob_mpindex;
00499 
00500 /******************************************************************************
00501  * Render the current scene
00502  * uses the global variables from the parser
00503  *****************************************************************************/
00504 int ntlWorld::renderScene( void )
00505 {
00506 #ifndef ELBEEM_PLUGIN
00507         char nrStr[5];                                                                                                          // nr conversion 
00508         std::ostringstream outfn_conv("");                      // converted ppm with other suffix 
00509   ntlRenderGlobals *glob;                       // storage for global rendering parameters 
00510   myTime_t timeStart,totalStart,timeEnd;                // measure user running time 
00511   myTime_t rendStart,rendEnd;                           // measure user rendering time 
00512   glob = mpGlob;
00513 
00514         // deactivate for all with index!=0 
00515         if((glob_mpactive)&&(glob_mpindex>0)) return(0);
00516 
00517         /* check if picture already exists... */
00518         if(!glob->getSingleFrameMode() ) {
00519                 snprintf(nrStr, 5, "%04d", glob->getAniCount() );
00520 
00521                 if(glob_mpactive) {
00522                         outfn_conv  << glob->getOutFilename() <<"_"<<glob_mpindex<<"_" << nrStr << ".png"; 
00523                 } else {
00524                         // ORG
00525                         outfn_conv  << glob->getOutFilename() <<"_" << nrStr << ".png";
00526                 }
00527                 
00528                 //if((mpGlob->getDisplayMode() == DM_RAY)&&(mpGlob->getFrameSkip())) {
00529                 if(mpGlob->getFrameSkip()) {
00530                         struct stat statBuf;
00531                         if(stat(outfn_conv.str().c_str(),&statBuf) == 0) {
00532                                 errorOut("ntlWorld::renderscene Warning: file "<<outfn_conv.str()<<" already exists - skipping frame..."); 
00533                                 glob->setAniCount( glob->getAniCount() +1 );
00534                                 return(2);
00535                         }
00536                 } // RAY mode
00537         } else {
00538                 // single frame rendering, overwrite if necessary...
00539                 outfn_conv << glob->getSingleFrameFilename();
00540         }
00541 
00542   /* start program */
00543         timeStart = getTime();
00544 
00545         /* build scene geometry, calls buildScene(t,false) */
00546         glob->getRenderScene()->prepareScene(mSimulationTime);
00547 
00548   /* start program */
00549         totalStart = getTime();
00550 
00551 
00552         /* view parameters are currently not animated */
00553         /* calculate rays through projection plane */
00554         ntlVec3Gfx direction = glob->getLookat() - glob->getEye();
00555         /* calculate width of screen using perpendicular triangle diven by
00556          * viewing direction and screen plane */
00557         gfxReal screenWidth = norm(direction)*tan( (glob->getFovy()*0.5/180.0)*M_PI );
00558 
00559         /* calculate vector orthogonal to up and viewing direction */
00560         ntlVec3Gfx upVec = glob->getUpVec();
00561         ntlVec3Gfx rightVec( cross(upVec,direction) );
00562         normalize(rightVec);
00563 
00564         /* calculate screen plane up vector, perpendicular to viewdir and right vec */
00565         upVec = ntlVec3Gfx( cross(rightVec,direction) );
00566         normalize(upVec);
00567 
00568         /* check if vectors are valid */
00569         if( (equal(upVec,ntlVec3Gfx(0.0))) || (equal(rightVec,ntlVec3Gfx(0.0))) ) {
00570                 errMsg("ntlWorld::renderScene","Invalid viewpoint vectors! up="<<upVec<<" right="<<rightVec);
00571                 return(1);
00572         }
00573 
00574         /* length from center to border of screen plane */
00575         rightVec *= (screenWidth*glob->getAspect() * -1.0);
00576         upVec *= (screenWidth * -1.0);
00577 
00578         /* screen traversal variables */
00579         ntlVec3Gfx screenPos;                          /* current position on virtual screen */
00580         int Xres = glob->getResX();                  /* X resolution */
00581         int Yres = glob->getResY();                  /* Y resolution */
00582         ntlVec3Gfx rightStep = (rightVec/(Xres/2.0));  /* one step right for a pixel */
00583         ntlVec3Gfx upStep    = (upVec/(Yres/2.0));     /* one step up for a pixel */
00584     
00585 
00586         /* anti alias init */
00587         char  showAAPic = 0;
00588         int   aaDepth = glob->getAADepth();
00589         int   aaLength;
00590         if(aaDepth>=0) aaLength = (2<<aaDepth);
00591         else           aaLength = 0;
00592         float aaSensRed   = 0.1;
00593         float aaSensGreen = 0.1;
00594         float aaSensBlue  = 0.1;
00595         int   aaArrayX = aaLength*Xres+1;
00596         int   aaArrayY = ( aaLength+1 );
00597         ntlColor *aaCol = new ntlColor[ aaArrayX*aaArrayY ];
00598         char  *aaUse = new char[ aaArrayX*aaArrayY ];
00599 
00600         /* picture storage */
00601         int picX = Xres;
00602         int picY = Yres;
00603         if(showAAPic) {
00604                 picX = Xres *aaLength+1;
00605                 picY = Yres *aaLength+1;
00606         }
00607         ntlColor *finalPic = new ntlColor[picX * picY];
00608 
00609 
00610         /* reset picture vars */
00611         for(int j=0;j<aaArrayY;j++) {
00612                 for(int i=0;i<aaArrayX;i++) {
00613                         aaCol[j*aaArrayX+i] = ntlColor(0.0, 0.0, 0.0);
00614                         aaUse[j*aaArrayX+i] = 0;
00615                 }
00616         }
00617         for(int j=0;j<picY;j++) {
00618                 for(int i=0;i<picX;i++) {
00619                         finalPic[j*picX+i] = ntlColor(0.0, 0.0, 0.0);
00620                 }
00621         }
00622 
00623         /* loop over all y lines in screen, from bottom to top because
00624          * ppm format wants 0,0 top left */
00625         rendStart = getTime();
00626         glob->setCounterShades(0);
00627         glob->setCounterSceneInter(0);
00628         for (int scanline=Yres ; scanline > 0 ; --scanline) {
00629     
00630                 debugOutInter( "ntlWorld::renderScene: Line "<<scanline<<
00631                                                                  " ("<< ((Yres-scanline)*100/Yres) <<"%) ", 2, 2000 );
00632                 screenPos = glob->getLookat() + upVec*((2.0*scanline-Yres)/Yres)
00633                         - rightVec;
00634 
00635                 /* loop over all pixels in line */
00636                 for (int sx=0 ; sx < Xres ; ++sx) {
00637 
00638                         if((sx==glob->getDebugPixelX())&&(scanline==(Yres-glob->getDebugPixelY()) )) {
00639                                 // DEBUG!!!
00640                                 glob->setDebugOut(10);
00641                         } else glob->setDebugOut(0);
00642                         
00643                         /* compute ray from eye through current pixel into scene... */
00644                         ntlColor col;
00645                         if(aaDepth<0) {
00646                                 ntlVec3Gfx dir(screenPos - glob->getEye());
00647                                 ntlRay the_ray(glob->getEye(), getNormalized(dir), 0, 1.0, glob );
00648 
00649                                 /* ...and trace it */
00650                                 col = the_ray.shade();
00651                         } else {
00652                                 /* anti alias */
00653                                 int ai,aj;                   /* position in grid */
00654                                 int aOrg = sx*aaLength;      /* grid offset x */
00655                                 int currStep = aaLength;     /* step size */
00656                                 char colDiff = 1;            /* do colors still differ too much? */
00657                                 ntlColor minCol,maxCol;         /* minimum and maximum Color Values */
00658                                 minCol = ntlColor(1.0,1.0,1.0);
00659                                 maxCol = ntlColor(0.0,0.0,0.0);
00660 
00661                                 while((colDiff) && (currStep>0)) {
00662                                         colDiff = 0;
00663             
00664                                         for(aj = 0;aj<=aaLength;aj+= currStep) {
00665                                                 for(ai = 0;ai<=aaLength;ai+= currStep) {
00666 
00667                                                         /* shade pixel if not done */
00668                                                         if(aaUse[aj*aaArrayX +ai +aOrg] == 0) {
00669                                                                 aaUse[aj*aaArrayX +ai +aOrg] = 1;
00670                                                                 ntlVec3Gfx aaPos( screenPos +
00671                                                                                                                                 (rightStep * (ai- aaLength/2)/(gfxReal)aaLength ) +
00672                                                                                                                                 (upStep    * (aj- aaLength/2)/(gfxReal)aaLength ) );
00673 
00674                                                                 ntlVec3Gfx dir(aaPos - glob->getEye());
00675                                                                 ntlRay the_ray(glob->getEye(), getNormalized(dir), 0, 1.0, glob );
00676 
00677                                                                 /* ...and trace it */
00678                                                                 ntlColor newCol= the_ray.shade();
00679                                                                 aaCol[aj*aaArrayX +ai +aOrg]= newCol;
00680                                                         } /* not used? */
00681 
00682                                                 }
00683                                         }
00684 
00685                                         /* check color differences */
00686                                         for(aj = 0;aj<aaLength;aj+= currStep) {
00687                                                 for(ai = 0;ai<aaLength;ai+= currStep) {
00688 
00689                                                         char thisColDiff = 0;
00690                                                         if( 
00691                                                                  (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] - 
00692                                                                                          aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][0])> aaSensRed ) ||
00693                                                                  (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] - 
00694                                                                                          aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][1])> aaSensGreen ) ||
00695                                                                  (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] - 
00696                                                                                          aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][2])> aaSensBlue ) ) {
00697                                                                 thisColDiff = 1;
00698                                                         } else
00699                                                                 if( 
00700                                                                          (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] - 
00701                                                                                                  aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][0])> aaSensRed ) ||
00702                                                                          (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] - 
00703                                                                                                  aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][1])> aaSensGreen ) ||
00704                                                                          (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] - 
00705                                                                                                  aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][2])> aaSensBlue ) ) {
00706                                                                         thisColDiff = 1;
00707                                                                 } else
00708                                                                         if( 
00709                                                                                  (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] - 
00710                                                                                                          aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][0])> aaSensRed ) ||
00711                                                                                  (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] - 
00712                                                                                                          aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][1])> aaSensGreen ) ||
00713                                                                                  (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] - 
00714                                                                                                          aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][2])> aaSensBlue ) ) {
00715                                                                                 thisColDiff = 1;
00716                                                                         } 
00717 
00718                                                         //colDiff =1;
00719                                                         if(thisColDiff) {
00720                                                                 /* set diff flag */
00721                                                                 colDiff = thisColDiff;
00722                                                                 for(int bj=aj;bj<=aj+currStep;bj++) {
00723                                                                         for(int bi=ai;bi<=ai+currStep;bi++) {
00724                                                                                 if(aaUse[bj*aaArrayX +bi +aOrg]==2) {
00725                                                                                         //if(showAAPic) 
00726                                                                                         aaUse[bj*aaArrayX +bi +aOrg] = 0;
00727                                                                                 }
00728                                                                         }
00729                                                                 }
00730                                                         } else {
00731                                                                 /* set all values */
00732                                                                 ntlColor avgCol = (
00733                                                                                                                                          aaCol[(aj+0       )*aaArrayX +(ai+0       ) +aOrg] +
00734                                                                                                                                          aaCol[(aj+0       )*aaArrayX +(ai+currStep) +aOrg] +
00735                                                                                                                                          aaCol[(aj+currStep)*aaArrayX +(ai+0       ) +aOrg] +
00736                                                                                                                                          aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg] ) *0.25;
00737                                                                 for(int bj=aj;bj<=aj+currStep;bj++) {
00738                                                                         for(int bi=ai;bi<=ai+currStep;bi++) {
00739                                                                                 if(aaUse[bj*aaArrayX +bi +aOrg]==0) {
00740                                                                                         aaCol[bj*aaArrayX +bi +aOrg] = avgCol; 
00741                                                                                         aaUse[bj*aaArrayX +bi +aOrg] = 2;
00742                                                                                 }
00743                                                                         }
00744                                                                 }
00745                                                         } /* smaller values set */
00746 
00747                                                 }
00748                                         }
00749 
00750                                         /* half step size */
00751                                         currStep /= 2;
00752 
00753                                 } /* repeat until diff not too big */
00754 
00755                                 /* get average color */
00756                                 gfxReal colNum = 0.0;
00757                                 col = ntlColor(0.0, 0.0, 0.0);
00758                                 for(aj = 0;aj<=aaLength;aj++) {
00759                                         for(ai = 0;ai<=aaLength;ai++) {
00760                                                 col += aaCol[aj*aaArrayX +ai +aOrg];
00761                                                 colNum += 1.0;
00762                                         }
00763                                 }
00764                                 col /= colNum;
00765 
00766                         }
00767 
00768                   /* mark pixels with debugging */
00769                         if( glob->getDebugOut() > 0) col = ntlColor(0,1,0);
00770 
00771                         /* store pixel */
00772                         if(!showAAPic) {
00773                                 finalPic[(scanline-1)*picX+sx] = col; 
00774                         }
00775                         screenPos +=  rightStep;
00776 
00777                 } /* foreach x */
00778 
00779                 /* init aa array */
00780                 if(showAAPic) {
00781                         for(int j=0;j<=aaArrayY-1;j++) {
00782                                 for(int i=0;i<=aaArrayX-1;i++) {
00783                                         if(aaUse[j*aaArrayX +i]==1) finalPic[((scanline-1)*aaLength +j)*picX+i][0] = 1.0;
00784                                 }
00785                         }
00786                 }
00787 
00788                 for(int i=0;i<aaArrayX;i++) {
00789                         aaCol[(aaArrayY-1)*aaArrayX+i] = aaCol[0*aaArrayX+i];
00790                         aaUse[(aaArrayY-1)*aaArrayX+i] = aaUse[0*aaArrayX+i];
00791                 }
00792                 for(int j=0;j<aaArrayY-1;j++) {
00793                         for(int i=0;i<aaArrayX;i++) {
00794                                 aaCol[j*aaArrayX+i] = ntlColor(0.0, 0.0, 0.0);
00795                                 aaUse[j*aaArrayX+i] = 0;
00796                         }
00797                 }
00798 
00799         } /* foreach y */
00800         rendEnd = getTime();
00801 
00802 
00803         /* write png file */
00804         {
00805                 int w = picX;
00806                 int h = picY;
00807 
00808                 unsigned rowbytes = w*4;
00809                 unsigned char *screenbuf, **rows;
00810                 screenbuf = (unsigned char*)malloc( h*rowbytes );
00811                 rows = (unsigned char**)malloc( h*sizeof(unsigned char*) );
00812                 unsigned char *filler = screenbuf;
00813 
00814                 // cutoff color values 0..1
00815                 for(int j=0;j<h;j++) {
00816                         for(int i=0;i<w;i++) {
00817                                 ntlColor col = finalPic[j*w+i];
00818                                 for (unsigned int cc=0; cc<3; cc++) {
00819                                         if(col[cc] <= 0.0) col[cc] = 0.0;
00820                                         if(col[cc] >= 1.0) col[cc] = 1.0;
00821                                 }
00822                                 *filler = (unsigned char)( col[0]*255.0 ); 
00823                                 filler++;
00824                                 *filler = (unsigned char)( col[1]*255.0 ); 
00825                                 filler++;
00826                                 *filler = (unsigned char)( col[2]*255.0 ); 
00827                                 filler++;
00828                                 *filler = (unsigned char)( 255.0 ); 
00829                                 filler++; // alpha channel
00830                         }
00831                 }
00832 
00833                 for(int i = 0; i < h; i++) rows[i] = &screenbuf[ (h - i - 1)*rowbytes ];
00834                 writePng(outfn_conv.str().c_str(), rows, w, h);
00835         }
00836 
00837 
00838         // next frame 
00839         glob->setAniCount( glob->getAniCount() +1 );
00840 
00841         // done 
00842         timeEnd = getTime();
00843 
00844         char resout[1024];
00845         snprintf(resout,1024, "NTL Done %s, frame %d/%d (took %s scene, %s raytracing, %s total, %d shades, %d i.s.'s)!\n", 
00846                                  outfn_conv.str().c_str(), (glob->getAniCount()), (glob->getAniFrames()+1),
00847                                  getTimeString(totalStart-timeStart).c_str(), getTimeString(rendEnd-rendStart).c_str(), getTimeString(timeEnd-timeStart).c_str(),
00848                                  glob->getCounterShades(),
00849                                  glob->getCounterSceneInter() );
00850         debMsgStd("ntlWorld::renderScene",DM_MSG, resout, 1 );
00851 
00852         /* clean stuff up */
00853         delete [] aaCol;
00854         delete [] aaUse;
00855         delete [] finalPic;
00856         glob->getRenderScene()->cleanupScene();
00857 
00858         if(mpGlob->getSingleFrameMode() ) {
00859                 debMsgStd("ntlWorld::renderScene",DM_NOTIFY, "Single frame mode done...", 1 );
00860                 return 1;
00861         }
00862 #endif // ELBEEM_PLUGIN
00863         return 0;
00864 }
00865 
00866 
00867 /******************************************************************************
00868  * renderglobals
00869  *****************************************************************************/
00870 
00871 
00872 /*****************************************************************************/
00873 /* Constructor with standard value init */
00874 ntlRenderGlobals::ntlRenderGlobals() :
00875         mpRenderScene(NULL), mpSimScene(NULL),
00876   mpLightList( NULL ), mpMaterials( NULL ), mpSims( NULL ),
00877   mResX(320), mResY(200), mAADepth(-1), mMaxColVal(255), 
00878   mRayMaxDepth( 5 ),
00879   mvEye(0.0,0.0,5.0), mvLookat(0.0,0.0,0.0), mvUpvec(0.0,1.0,0.0), 
00880   mAspect(320.0/200.0), 
00881   mFovy(45), mcBackgr(0.0,0.0,0.0), mcAmbientLight(0.0,0.0,0.0), 
00882   mDebugOut( 0 ),
00883   mAniStart(0), mAniFrames( -1 ), mAniCount( 0 ),
00884         mFrameSkip( 0 ),
00885   mCounterRays( 0 ), mCounterShades( 0 ), mCounterSceneInter( 0 ),
00886         mOutFilename( "pic" ),
00887         mTreeMaxDepth( 30 ), mTreeMaxTriangles( 30 ),
00888         mpOpenGlAttr(NULL),
00889         mpBlenderAttr(NULL),
00890         mTestSphereEnabled( false ),
00891         mDebugPixelX( -1 ), mDebugPixelY( -1 ), mTestMode(false),
00892         mSingleFrameMode(false), mSingleFrameFilename("")
00893         //,mpRndDirections( NULL ), mpRndRoulette( NULL )
00894 { 
00895         // create internal attribute list for opengl renderer
00896         mpOpenGlAttr = new AttributeList("__ntlOpenGLRenderer");
00897         mpBlenderAttr = new AttributeList("__ntlBlenderAttr");
00898 };
00899 
00900 
00901 /*****************************************************************************/
00902 /* Destructor */
00903 ntlRenderGlobals::~ntlRenderGlobals() {
00904         if(mpOpenGlAttr) delete mpOpenGlAttr;
00905         if(mpBlenderAttr) delete mpBlenderAttr;
00906         
00907         
00908 }
00909 
00910 
00911 /*****************************************************************************/
00913 //ntlVec3Gfx ntlRenderGlobals::getRandomDirection( void ) { 
00914         //return ntlVec3Gfx( 
00915                         //(mpRndDirections->getGfxReal()-0.5), 
00916                         //(mpRndDirections->getGfxReal()-0.5),  
00917                         //(mpRndDirections->getGfxReal()-0.5) ); 
00918 //} 
00919 
00920