Blender V2.61 - r43446
|
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