|
Blender
V2.59
|
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