Blender V2.61 - r43446

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             debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Time for start-sims:"<< getTimeString(stopTime-startTime) , 1);
00220 #ifndef NOGUI
00221             guiResetSimulationTimeRange( mSimulationTime );
00222 #endif
00223         } else {
00224             if(!mpGlob->getSingleFrameMode()) debMsgStd("ntlWorld::ntlWorld",DM_WARNING,"No active simulations!", 1);
00225         }
00226     }
00227 
00228     if(! isSimworldOk() ) return;
00229     setElbeemState( SIMWORLD_INITED );
00230 }
00231 
00232 
00233 
00234 /******************************************************************************
00235  * Destructor
00236  *****************************************************************************/
00237 ntlWorld::~ntlWorld()
00238 {
00239     delete mpGlob->getRenderScene();
00240     delete mpGlob->getSimScene();
00241   
00242     delete mpGlob;
00243     
00244     
00245     // these get assigned to mpGlob but not freed there
00246     delete mpLightList;
00247     delete mpPropList; // materials
00248     delete mpSims;
00249   
00250 #ifndef NOGUI
00251     if(mpOpenGLRenderer) delete mpOpenGLRenderer;
00252 #endif // NOGUI
00253     debMsgStd("ntlWorld",DM_NOTIFY, "ntlWorld done", 10);
00254 }
00255 
00256 /******************************************************************************/
00258 void ntlWorld::setSingleFrameOut(string singleframeFilename) {
00259     mpGlob->setSingleFrameMode(true);
00260     mpGlob->setSingleFrameFilename(singleframeFilename);
00261 }
00262 
00263 /******************************************************************************
00264  * render a whole animation (command line mode) 
00265  *****************************************************************************/
00266 
00267 int ntlWorld::renderAnimation( void )
00268 {
00269     // only single pic currently
00270     //debMsgStd("ntlWorld::renderAnimation : Warning only simulating...",1);
00271     if(mpGlob->getAniFrames() < 0) {
00272         debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"No frames to render... ",1);
00273         return 1;
00274     }
00275 
00276     if(mFirstSim<0) {
00277         debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"No reference animation found...",1);
00278         return 1;
00279     } 
00280 
00281     mThreadRunning = true; // not threaded, but still use the same flags
00282     if(getElbeemState() == SIMWORLD_INITED) {
00283         renderScene();
00284     } else if(getElbeemState() == SIMWORLD_STOP) {
00285         // dont render now, just continue
00286         setElbeemState( SIMWORLD_INITED );
00287         mFrameCnt--; // counted one too many from last abort...
00288     } else {
00289         debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"Not properly inited, stopping...",1);
00290         return 1;
00291     }
00292     
00293     if(mpSims->size() <= 0) {
00294         debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"No simulations found, stopping...",1);
00295         return 1;
00296     }
00297 
00298     bool simok = true;
00299     for( ; ((mFrameCnt<mpGlob->getAniFrames()) && (!getStopRenderVisualization() ) && (simok)); mFrameCnt++) {
00300         if(!advanceSims(mFrameCnt)) {
00301             renderScene();
00302         } // else means sim panicked, so dont render...
00303         else { simok=false; }
00304     }
00305     mThreadRunning = false;
00306     return 0;
00307 }
00308 
00309 /******************************************************************************
00310  * render a whole animation (visualization mode) 
00311  * this function is run in another thread, and communicates 
00312  * with the parent thread via a mutex 
00313  *****************************************************************************/
00314 int ntlWorld::renderVisualization( bool multiThreaded ) 
00315 {
00316 #ifndef NOGUI
00317     if(getElbeemState() != SIMWORLD_INITED) { return 0; }
00318 
00319     if(multiThreaded) mThreadRunning = true;
00320     // TODO, check global state?
00321     while(!getStopRenderVisualization()) {
00322 
00323         if(mpSims->size() <= 0) {
00324             debMsgStd("ntlWorld::renderVisualization",DM_NOTIFY,"No simulations found, stopping...",1);
00325             stopSimulationThread();
00326             break;
00327         }
00328 
00329         // determine stepsize
00330         if(!mSingleStepDebug) {
00331             long startTime = getTime();
00332             advanceSims(mFrameCnt);
00333             mFrameCnt++;
00334             long stopTime = getTime();
00335             debMsgStd("ntlWorld::renderVisualization",DM_MSG,"Time for t="<<mSimulationTime<<": "<< getTimeString(stopTime-startTime) <<" ", 10);
00336         } else {
00337             double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getTimestep();
00338             singleStepSims(targetTime);
00339 
00340             // check paniced sims (normally done by advanceSims
00341             bool allPanic = true;
00342             for(size_t i=0;i<mpSims->size();i++) {
00343                 if(!(*mpSims)[i]->getPanic()) allPanic = false;
00344             }
00345             if(allPanic) {
00346                 warnMsg("ntlWorld::advanceSims","All sims panicked... stopping thread" );
00347                 setStopRenderVisualization( true );
00348             }
00349             if(! isSimworldOk() ) {
00350                 warnMsg("ntlWorld::advanceSims","World state error... stopping" );
00351                 setStopRenderVisualization( true );
00352             }
00353         }
00354 
00355         // save frame
00356         if(mpOpenGLRenderer) mpOpenGLRenderer->saveAnimationFrame( mSimulationTime );
00357         
00358         // for non-threaded check events
00359         if(!multiThreaded) {
00360             Fl::check();
00361       gpElbeemFrame->SceneDisplay->doOnlyForcedRedraw();
00362         }
00363 
00364     }
00365     mThreadRunning = false;
00366     stopSimulationRestoreGui();
00367 #else 
00368     multiThreaded = false; // remove warning
00369 #endif
00370     return 0;
00371 }
00373 int ntlWorld::singleStepVisualization( void ) 
00374 {
00375     mThreadRunning = true;
00376     double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getTimestep();
00377     singleStepSims(targetTime);
00378     mSimulationTime = (*mpSims)[0]->getCurrentTime();
00379 
00380 #ifndef NOGUI
00381     if(mpOpenGLRenderer) mpOpenGLRenderer->saveAnimationFrame( mSimulationTime );
00382     Fl::check();
00383   gpElbeemFrame->SceneDisplay->doOnlyForcedRedraw();
00384     mThreadRunning = false;
00385     stopSimulationRestoreGui();
00386 #else
00387     mThreadRunning = false;
00388 #endif // NOGUI
00389     return 0;
00390 }
00391 
00392 // dont use LBM_EPSILON here, time is always double-precision!
00393 #define LBM_TIME_EPSILON 1e-10
00394 
00395 /******************************************************************************
00396  * advance simulations by time t 
00397  *****************************************************************************/
00398 int ntlWorld::advanceSims(int framenum)
00399 {
00400     bool done = false;
00401     bool allPanic = true;
00402 
00403     // stop/quit, dont display/render
00404     if(getElbeemState()==SIMWORLD_STOP) { 
00405         return 1;
00406     }
00407 
00408     for(size_t i=0;i<mpSims->size();i++) { (*mpSims)[i]->setFrameNum(framenum); }
00409     double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getFrameTime(framenum);
00410 
00411     // time stopped? nothing else to do...
00412     if( (*mpSims)[mFirstSim]->getFrameTime(framenum) <= 0.0 ){ 
00413         done=true; allPanic=false; 
00414     }
00415 
00416     int gstate = 0;
00417     myTime_t advsstart = getTime();
00418 
00419     // step all the sims, and check for panic
00420     debMsgStd("ntlWorld::advanceSims",DM_MSG, " sims "<<mpSims->size()<<" t"<<targetTime<<" done:"<<done<<" panic:"<<allPanic<<" gstate:"<<gstate, 10); // debug // timedebug
00421     while(!done) {
00422         double nextTargetTime = (*mpSims)[mFirstSim]->getCurrentTime() + (*mpSims)[mFirstSim]->getTimestep();
00423         singleStepSims(nextTargetTime);
00424 
00425         // check target times
00426         done = true;
00427         allPanic = false;
00428         
00429         if((*mpSims)[mFirstSim]->getTimestep() <1e-9 ) { 
00430             // safety check, avoid timesteps that are too small
00431             errMsg("ntlWorld::advanceSims","Invalid time step, causing panic! curr:"<<(*mpSims)[mFirstSim]->getCurrentTime()<<" next:"<<nextTargetTime<<", stept:"<< (*mpSims)[mFirstSim]->getTimestep() );
00432             allPanic = true; 
00433         } else {
00434             for(size_t i=0;i<mpSims->size();i++) {
00435                 if(!(*mpSims)[i]->getVisible()) continue;
00436                 if((*mpSims)[i]->getPanic()) allPanic = true; // do any panic now!?
00437                 debMsgStd("ntlWorld::advanceSims",DM_MSG, "Sim "<<i<<", currt:"<<(*mpSims)[i]->getCurrentTime()<<", nt:"<<nextTargetTime<<", panic:"<<(*mpSims)[i]->getPanic()<<", targett:"<<targetTime, 10); // debug // timedebug
00438             } 
00439         }
00440         if( (targetTime - (*mpSims)[mFirstSim]->getCurrentTime()) > LBM_TIME_EPSILON) done=false;
00441         if(allPanic) done = true;
00442     }
00443 
00444     if(allPanic) {
00445         warnMsg("ntlWorld::advanceSims","All sims panicked... stopping thread" );
00446         setStopRenderVisualization( true );
00447         return 1;
00448     }
00449 
00450     myTime_t advsend = getTime();
00451     debMsgStd("ntlWorld::advanceSims",DM_MSG,"Overall steps so far took:"<< getTimeString(advsend-advsstart)<<" for sim time "<<targetTime, 4);
00452 
00453     // finish step
00454     for(size_t i=0;i<mpSims->size();i++) {
00455         SimulationObject *sim = (*mpSims)[i];
00456         if(!sim->getVisible()) continue;
00457         if(sim->getPanic()) continue;
00458         sim->prepareVisualization();
00459     }
00460 
00461     return 0;
00462 }
00463 
00464 /* advance simulations by a single step */
00465 /* dont check target time, if *targetTime==NULL */
00466 void ntlWorld::singleStepSims(double targetTime) {
00467     const bool debugTime = false;
00468     //double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getTimestep();
00469     if(debugTime) errMsg("ntlWorld::singleStepSims","Target time: "<<targetTime);
00470 
00471     for(size_t i=0;i<mpSims->size();i++) {
00472         SimulationObject *sim = (*mpSims)[i];
00473         if(!sim->getVisible()) continue;
00474         if(sim->getPanic()) continue;
00475         bool done = false;
00476         while(!done) {
00477             // try to prevent round off errs
00478             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
00479             if( (targetTime - sim->getCurrentTime()) > LBM_TIME_EPSILON) {
00480                 if(debugTime) errMsg("ntlWorld::singleStepSims","Stepping sim "<<i<<" t:"<< sim->getCurrentTime()); // timedebug
00481                 sim->step();
00482             } else {
00483                 done = true;
00484             }
00485         }
00486     }
00487 
00488     mSimulationTime = (*mpSims)[mFirstSim]->getCurrentTime();
00489 #ifndef NOGUI
00490     if(mpOpenGLRenderer) mpOpenGLRenderer->notifyOfNextStep(mSimulationTime);
00491 #endif // NOGUI
00492 }
00493 
00494 
00495 
00496 extern bool glob_mpactive;
00497 extern int glob_mpindex;
00498 
00499 /******************************************************************************
00500  * Render the current scene
00501  * uses the global variables from the parser
00502  *****************************************************************************/
00503 int ntlWorld::renderScene( void )
00504 {
00505 #ifndef ELBEEM_PLUGIN
00506     char nrStr[5];                                                      // nr conversion 
00507     std::ostringstream outfn_conv("");              // converted ppm with other suffix 
00508   ntlRenderGlobals *glob;                   // storage for global rendering parameters 
00509   myTime_t timeStart,totalStart,timeEnd;        // measure user running time 
00510   myTime_t rendStart,rendEnd;                   // measure user rendering time 
00511   glob = mpGlob;
00512 
00513     // deactivate for all with index!=0 
00514     if((glob_mpactive)&&(glob_mpindex>0)) return(0);
00515 
00516     /* check if picture already exists... */
00517     if(!glob->getSingleFrameMode() ) {
00518         snprintf(nrStr, 5, "%04d", glob->getAniCount() );
00519 
00520         if(glob_mpactive) {
00521             outfn_conv  << glob->getOutFilename() <<"_"<<glob_mpindex<<"_" << nrStr << ".png"; 
00522         } else {
00523             // ORG
00524             outfn_conv  << glob->getOutFilename() <<"_" << nrStr << ".png";
00525         }
00526         
00527         //if((mpGlob->getDisplayMode() == DM_RAY)&&(mpGlob->getFrameSkip())) {
00528         if(mpGlob->getFrameSkip()) {
00529             struct stat statBuf;
00530             if(stat(outfn_conv.str().c_str(),&statBuf) == 0) {
00531                 errorOut("ntlWorld::renderscene Warning: file "<<outfn_conv.str()<<" already exists - skipping frame..."); 
00532                 glob->setAniCount( glob->getAniCount() +1 );
00533                 return(2);
00534             }
00535         } // RAY mode
00536     } else {
00537         // single frame rendering, overwrite if necessary...
00538         outfn_conv << glob->getSingleFrameFilename();
00539     }
00540 
00541   /* start program */
00542     timeStart = getTime();
00543 
00544     /* build scene geometry, calls buildScene(t,false) */
00545     glob->getRenderScene()->prepareScene(mSimulationTime);
00546 
00547   /* start program */
00548     totalStart = getTime();
00549 
00550 
00551     /* view parameters are currently not animated */
00552     /* calculate rays through projection plane */
00553     ntlVec3Gfx direction = glob->getLookat() - glob->getEye();
00554     /* calculate width of screen using perpendicular triangle diven by
00555      * viewing direction and screen plane */
00556     gfxReal screenWidth = norm(direction)*tan( (glob->getFovy()*0.5/180.0)*M_PI );
00557 
00558     /* calculate vector orthogonal to up and viewing direction */
00559     ntlVec3Gfx upVec = glob->getUpVec();
00560     ntlVec3Gfx rightVec( cross(upVec,direction) );
00561     normalize(rightVec);
00562 
00563     /* calculate screen plane up vector, perpendicular to viewdir and right vec */
00564     upVec = ntlVec3Gfx( cross(rightVec,direction) );
00565     normalize(upVec);
00566 
00567     /* check if vectors are valid */
00568     if( (equal(upVec,ntlVec3Gfx(0.0))) || (equal(rightVec,ntlVec3Gfx(0.0))) ) {
00569         errMsg("ntlWorld::renderScene","Invalid viewpoint vectors! up="<<upVec<<" right="<<rightVec);
00570         return(1);
00571     }
00572 
00573     /* length from center to border of screen plane */
00574     rightVec *= (screenWidth*glob->getAspect() * -1.0);
00575     upVec *= (screenWidth * -1.0);
00576 
00577     /* screen traversal variables */
00578     ntlVec3Gfx screenPos;                          /* current position on virtual screen */
00579     int Xres = glob->getResX();                  /* X resolution */
00580     int Yres = glob->getResY();                  /* Y resolution */
00581     ntlVec3Gfx rightStep = (rightVec/(Xres/2.0));  /* one step right for a pixel */
00582     ntlVec3Gfx upStep    = (upVec/(Yres/2.0));     /* one step up for a pixel */
00583     
00584 
00585     /* anti alias init */
00586     char  showAAPic = 0;
00587     int   aaDepth = glob->getAADepth();
00588     int   aaLength;
00589     if(aaDepth>=0) aaLength = (2<<aaDepth);
00590     else           aaLength = 0;
00591     float aaSensRed   = 0.1;
00592     float aaSensGreen = 0.1;
00593     float aaSensBlue  = 0.1;
00594     int   aaArrayX = aaLength*Xres+1;
00595     int   aaArrayY = ( aaLength+1 );
00596     ntlColor *aaCol = new ntlColor[ aaArrayX*aaArrayY ];
00597     char  *aaUse = new char[ aaArrayX*aaArrayY ];
00598 
00599     /* picture storage */
00600     int picX = Xres;
00601     int picY = Yres;
00602     if(showAAPic) {
00603         picX = Xres *aaLength+1;
00604         picY = Yres *aaLength+1;
00605     }
00606     ntlColor *finalPic = new ntlColor[picX * picY];
00607 
00608 
00609     /* reset picture vars */
00610     for(int j=0;j<aaArrayY;j++) {
00611         for(int i=0;i<aaArrayX;i++) {
00612             aaCol[j*aaArrayX+i] = ntlColor(0.0, 0.0, 0.0);
00613             aaUse[j*aaArrayX+i] = 0;
00614         }
00615     }
00616     for(int j=0;j<picY;j++) {
00617         for(int i=0;i<picX;i++) {
00618             finalPic[j*picX+i] = ntlColor(0.0, 0.0, 0.0);
00619         }
00620     }
00621 
00622     /* loop over all y lines in screen, from bottom to top because
00623      * ppm format wants 0,0 top left */
00624     rendStart = getTime();
00625     glob->setCounterShades(0);
00626     glob->setCounterSceneInter(0);
00627     for (int scanline=Yres ; scanline > 0 ; --scanline) {
00628     
00629         debugOutInter( "ntlWorld::renderScene: Line "<<scanline<<
00630                                  " ("<< ((Yres-scanline)*100/Yres) <<"%) ", 2, 2000 );
00631         screenPos = glob->getLookat() + upVec*((2.0*scanline-Yres)/Yres)
00632             - rightVec;
00633 
00634         /* loop over all pixels in line */
00635         for (int sx=0 ; sx < Xres ; ++sx) {
00636 
00637             if((sx==glob->getDebugPixelX())&&(scanline==(Yres-glob->getDebugPixelY()) )) {
00638                 // DEBUG!!!
00639                 glob->setDebugOut(10);
00640             } else glob->setDebugOut(0);
00641             
00642             /* compute ray from eye through current pixel into scene... */
00643             ntlColor col;
00644             if(aaDepth<0) {
00645                 ntlVec3Gfx dir(screenPos - glob->getEye());
00646                 ntlRay the_ray(glob->getEye(), getNormalized(dir), 0, 1.0, glob );
00647 
00648                 /* ...and trace it */
00649                 col = the_ray.shade();
00650             } else {
00651                 /* anti alias */
00652                 int ai,aj;                   /* position in grid */
00653                 int aOrg = sx*aaLength;      /* grid offset x */
00654                 int currStep = aaLength;     /* step size */
00655                 char colDiff = 1;            /* do colors still differ too much? */
00656                 ntlColor minCol,maxCol;         /* minimum and maximum Color Values */
00657                 minCol = ntlColor(1.0,1.0,1.0);
00658                 maxCol = ntlColor(0.0,0.0,0.0);
00659 
00660                 while((colDiff) && (currStep>0)) {
00661                     colDiff = 0;
00662         
00663                     for(aj = 0;aj<=aaLength;aj+= currStep) {
00664                         for(ai = 0;ai<=aaLength;ai+= currStep) {
00665 
00666                             /* shade pixel if not done */
00667                             if(aaUse[aj*aaArrayX +ai +aOrg] == 0) {
00668                                 aaUse[aj*aaArrayX +ai +aOrg] = 1;
00669                                 ntlVec3Gfx aaPos( screenPos +
00670                                                                 (rightStep * (ai- aaLength/2)/(gfxReal)aaLength ) +
00671                                                                 (upStep    * (aj- aaLength/2)/(gfxReal)aaLength ) );
00672 
00673                                 ntlVec3Gfx dir(aaPos - glob->getEye());
00674                                 ntlRay the_ray(glob->getEye(), getNormalized(dir), 0, 1.0, glob );
00675 
00676                                 /* ...and trace it */
00677                                 ntlColor newCol= the_ray.shade();
00678                                 aaCol[aj*aaArrayX +ai +aOrg]= newCol;
00679                             } /* not used? */
00680 
00681                         }
00682                     }
00683 
00684                     /* check color differences */
00685                     for(aj = 0;aj<aaLength;aj+= currStep) {
00686                         for(ai = 0;ai<aaLength;ai+= currStep) {
00687 
00688                             char thisColDiff = 0;
00689                             if( 
00690                                  (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] - 
00691                                              aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][0])> aaSensRed ) ||
00692                                  (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] - 
00693                                              aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][1])> aaSensGreen ) ||
00694                                  (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] - 
00695                                              aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][2])> aaSensBlue ) ) {
00696                                 thisColDiff = 1;
00697                             } else
00698                                 if( 
00699                                      (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] - 
00700                                                  aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][0])> aaSensRed ) ||
00701                                      (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] - 
00702                                                  aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][1])> aaSensGreen ) ||
00703                                      (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] - 
00704                                                  aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][2])> aaSensBlue ) ) {
00705                                     thisColDiff = 1;
00706                                 } else
00707                                     if( 
00708                                          (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] - 
00709                                                      aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][0])> aaSensRed ) ||
00710                                          (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] - 
00711                                                      aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][1])> aaSensGreen ) ||
00712                                          (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] - 
00713                                                      aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][2])> aaSensBlue ) ) {
00714                                         thisColDiff = 1;
00715                                     } 
00716 
00717                             //colDiff =1;
00718                             if(thisColDiff) {
00719                                 /* set diff flag */
00720                                 colDiff = thisColDiff;
00721                                 for(int bj=aj;bj<=aj+currStep;bj++) {
00722                                     for(int bi=ai;bi<=ai+currStep;bi++) {
00723                                         if(aaUse[bj*aaArrayX +bi +aOrg]==2) {
00724                                             //if(showAAPic) 
00725                                             aaUse[bj*aaArrayX +bi +aOrg] = 0;
00726                                         }
00727                                     }
00728                                 }
00729                             } else {
00730                                 /* set all values */
00731                                 ntlColor avgCol = (
00732                                                                      aaCol[(aj+0       )*aaArrayX +(ai+0       ) +aOrg] +
00733                                                                      aaCol[(aj+0       )*aaArrayX +(ai+currStep) +aOrg] +
00734                                                                      aaCol[(aj+currStep)*aaArrayX +(ai+0       ) +aOrg] +
00735                                                                      aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg] ) *0.25;
00736                                 for(int bj=aj;bj<=aj+currStep;bj++) {
00737                                     for(int bi=ai;bi<=ai+currStep;bi++) {
00738                                         if(aaUse[bj*aaArrayX +bi +aOrg]==0) {
00739                                             aaCol[bj*aaArrayX +bi +aOrg] = avgCol; 
00740                                             aaUse[bj*aaArrayX +bi +aOrg] = 2;
00741                                         }
00742                                     }
00743                                 }
00744                             } /* smaller values set */
00745 
00746                         }
00747                     }
00748 
00749                     /* half step size */
00750                     currStep /= 2;
00751 
00752                 } /* repeat until diff not too big */
00753 
00754                 /* get average color */
00755                 gfxReal colNum = 0.0;
00756                 col = ntlColor(0.0, 0.0, 0.0);
00757                 for(aj = 0;aj<=aaLength;aj++) {
00758                     for(ai = 0;ai<=aaLength;ai++) {
00759                         col += aaCol[aj*aaArrayX +ai +aOrg];
00760                         colNum += 1.0;
00761                     }
00762                 }
00763                 col /= colNum;
00764 
00765             }
00766 
00767           /* mark pixels with debugging */
00768             if( glob->getDebugOut() > 0) col = ntlColor(0,1,0);
00769 
00770             /* store pixel */
00771             if(!showAAPic) {
00772                 finalPic[(scanline-1)*picX+sx] = col; 
00773             }
00774             screenPos +=  rightStep;
00775 
00776         } /* foreach x */
00777 
00778         /* init aa array */
00779         if(showAAPic) {
00780             for(int j=0;j<=aaArrayY-1;j++) {
00781                 for(int i=0;i<=aaArrayX-1;i++) {
00782                     if(aaUse[j*aaArrayX +i]==1) finalPic[((scanline-1)*aaLength +j)*picX+i][0] = 1.0;
00783                 }
00784             }
00785         }
00786 
00787         for(int i=0;i<aaArrayX;i++) {
00788             aaCol[(aaArrayY-1)*aaArrayX+i] = aaCol[0*aaArrayX+i];
00789             aaUse[(aaArrayY-1)*aaArrayX+i] = aaUse[0*aaArrayX+i];
00790         }
00791         for(int j=0;j<aaArrayY-1;j++) {
00792             for(int i=0;i<aaArrayX;i++) {
00793                 aaCol[j*aaArrayX+i] = ntlColor(0.0, 0.0, 0.0);
00794                 aaUse[j*aaArrayX+i] = 0;
00795             }
00796         }
00797 
00798     } /* foreach y */
00799     rendEnd = getTime();
00800 
00801 
00802     /* write png file */
00803     {
00804         int w = picX;
00805         int h = picY;
00806 
00807         unsigned rowbytes = w*4;
00808         unsigned char *screenbuf, **rows;
00809         screenbuf = (unsigned char*)malloc( h*rowbytes );
00810         rows = (unsigned char**)malloc( h*sizeof(unsigned char*) );
00811         unsigned char *filler = screenbuf;
00812 
00813         // cutoff color values 0..1
00814         for(int j=0;j<h;j++) {
00815             for(int i=0;i<w;i++) {
00816                 ntlColor col = finalPic[j*w+i];
00817                 for (unsigned int cc=0; cc<3; cc++) {
00818                     if(col[cc] <= 0.0) col[cc] = 0.0;
00819                     if(col[cc] >= 1.0) col[cc] = 1.0;
00820                 }
00821                 *filler = (unsigned char)( col[0]*255.0 ); 
00822                 filler++;
00823                 *filler = (unsigned char)( col[1]*255.0 ); 
00824                 filler++;
00825                 *filler = (unsigned char)( col[2]*255.0 ); 
00826                 filler++;
00827                 *filler = (unsigned char)( 255.0 ); 
00828                 filler++; // alpha channel
00829             }
00830         }
00831 
00832         for(int i = 0; i < h; i++) rows[i] = &screenbuf[ (h - i - 1)*rowbytes ];
00833         writePng(outfn_conv.str().c_str(), rows, w, h);
00834     }
00835 
00836 
00837     // next frame 
00838     glob->setAniCount( glob->getAniCount() +1 );
00839 
00840     // done 
00841     timeEnd = getTime();
00842 
00843     char resout[1024];
00844     snprintf(resout,1024, "NTL Done %s, frame %d/%d (took %s scene, %s raytracing, %s total, %d shades, %d i.s.'s)!\n", 
00845                  outfn_conv.str().c_str(), (glob->getAniCount()), (glob->getAniFrames()+1),
00846                  getTimeString(totalStart-timeStart).c_str(), getTimeString(rendEnd-rendStart).c_str(), getTimeString(timeEnd-timeStart).c_str(),
00847                  glob->getCounterShades(),
00848                  glob->getCounterSceneInter() );
00849     debMsgStd("ntlWorld::renderScene",DM_MSG, resout, 1 );
00850 
00851     /* clean stuff up */
00852     delete [] aaCol;
00853     delete [] aaUse;
00854     delete [] finalPic;
00855     glob->getRenderScene()->cleanupScene();
00856 
00857     if(mpGlob->getSingleFrameMode() ) {
00858         debMsgStd("ntlWorld::renderScene",DM_NOTIFY, "Single frame mode done...", 1 );
00859         return 1;
00860     }
00861 #endif // ELBEEM_PLUGIN
00862     return 0;
00863 }
00864 
00865 
00866 /******************************************************************************
00867  * renderglobals
00868  *****************************************************************************/
00869 
00870 
00871 /*****************************************************************************/
00872 /* Constructor with standard value init */
00873 ntlRenderGlobals::ntlRenderGlobals() :
00874     mpRenderScene(NULL), mpSimScene(NULL),
00875   mpLightList( NULL ), mpMaterials( NULL ), mpSims( NULL ),
00876   mResX(320), mResY(200), mAADepth(-1), mMaxColVal(255), 
00877   mRayMaxDepth( 5 ),
00878   mvEye(0.0,0.0,5.0), mvLookat(0.0,0.0,0.0), mvUpvec(0.0,1.0,0.0), 
00879   mAspect(320.0/200.0), 
00880   mFovy(45), mcBackgr(0.0,0.0,0.0), mcAmbientLight(0.0,0.0,0.0), 
00881   mDebugOut( 0 ),
00882   mAniStart(0), mAniFrames( -1 ), mAniCount( 0 ),
00883     mFrameSkip( 0 ),
00884   mCounterRays( 0 ), mCounterShades( 0 ), mCounterSceneInter( 0 ),
00885     mOutFilename( "pic" ),
00886     mTreeMaxDepth( 30 ), mTreeMaxTriangles( 30 ),
00887     mpOpenGlAttr(NULL),
00888     mpBlenderAttr(NULL),
00889     mTestSphereEnabled( false ),
00890     mDebugPixelX( -1 ), mDebugPixelY( -1 ), mTestMode(false),
00891     mSingleFrameMode(false), mSingleFrameFilename("")
00892     //,mpRndDirections( NULL ), mpRndRoulette( NULL )
00893 { 
00894     // create internal attribute list for opengl renderer
00895     mpOpenGlAttr = new AttributeList("__ntlOpenGLRenderer");
00896     mpBlenderAttr = new AttributeList("__ntlBlenderAttr");
00897 };
00898 
00899 
00900 /*****************************************************************************/
00901 /* Destructor */
00902 ntlRenderGlobals::~ntlRenderGlobals() {
00903     if(mpOpenGlAttr) delete mpOpenGlAttr;
00904     if(mpBlenderAttr) delete mpBlenderAttr;
00905     
00906     
00907 }
00908 
00909 
00910 /*****************************************************************************/
00912 //ntlVec3Gfx ntlRenderGlobals::getRandomDirection( void ) { 
00913     //return ntlVec3Gfx( 
00914             //(mpRndDirections->getGfxReal()-0.5), 
00915             //(mpRndDirections->getGfxReal()-0.5),  
00916             //(mpRndDirections->getGfxReal()-0.5) ); 
00917 //} 
00918 
00919