/****************************************************************************** *! dump particles if desired *****************************************************************************/ void ParticleTracer::notifyOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename, double simtime) { debMsgStd("ParticleTracer::notifyOfDump",DM_MSG,"obj:"<<this->getName()<<" frame:"<<frameNrStr<<" dumpp"<<mDumpParts<<" t"<<simtime, 10); // DEBUG if( (dumptype==DUMP_FULLGEOMETRY)&& (mDumpParts>0)) { // dump to binary file std::ostringstream boutfilename(""); boutfilename << outfilename <<"_particles_" << frameNrStr; if(glob_mpactive) { if(glob_mpindex>0) { boutfilename << "mp"<<glob_mpindex; } } boutfilename << ".gz"; debMsgStd("ParticleTracer::notifyOfDump",DM_MSG,"B-Dumping: "<< this->getName() <<", particles:"<<mParts.size()<<" "<< " to "<<boutfilename.str()<<" #"<<frameNr , 7); //debMsgStd("ParticleTracer::notifyOfDump",DM_MSG,"B-Dumping: partgeodeb sim:"<<mSimStart<<","<<mSimEnd<<" geosize:"<<mStart<<","<<mEnd,2 ); // output to zipped file gzFile gzf; gzf = gzopen(boutfilename.str().c_str(), "wb1"); if(gzf) { int numParts; if(sizeof(numParts)!=4) { errMsg("ParticleTracer::notifyOfDump","Invalid int size"); return; } // only dump active particles numParts = 0; for(size_t i=0; i<mParts.size(); i++) { if(!mParts[i].getActive()) continue; numParts++; } gzwrite(gzf, &numParts, sizeof(numParts)); for(size_t i=0; i<mParts.size(); i++) { if(!mParts[i].getActive()) { continue; } ParticleObject *p = &mParts[i]; //int type = p->getType(); // export whole type info int type = p->getFlags(); // debug export whole type & status info ntlVec3Gfx pos = p->getPos(); float size = p->getSize(); if(type&PART_FLOAT) { // WARNING same handling for dump! // add one gridcell offset //pos[2] += 1.0; } // display as drop for now externally //else if(type&PART_TRACER) { type |= PART_DROP; } pos = (*mpTrafo) * pos; ntlVec3Gfx v = p->getVel(); v[0] *= mpTrafo->value[0][0]; v[1] *= mpTrafo->value[1][1]; v[2] *= mpTrafo->value[2][2]; // FIXME check: pos = (*mpTrafo) * pos; gzwrite(gzf, &type, sizeof(type)); gzwrite(gzf, &size, sizeof(size)); for(int j=0; j<3; j++) { gzwrite(gzf, &pos[j], sizeof(float)); } for(int j=0; j<3; j++) { gzwrite(gzf, &v[j], sizeof(float)); } } gzclose( gzf ); } } // dump? }
/****************************************************************************** * render a whole animation (visualization mode) * this function is run in another thread, and communicates * with the parent thread via a mutex *****************************************************************************/ int ntlWorld::renderVisualization( bool multiThreaded ) { #ifndef NOGUI if(getElbeemState() != SIMWORLD_INITED) { return 0; } if(multiThreaded) mThreadRunning = true; // TODO, check global state? while(!getStopRenderVisualization()) { if(mpSims->size() <= 0) { debMsgStd("ntlWorld::renderVisualization",DM_NOTIFY,"No simulations found, stopping...",1); stopSimulationThread(); break; } // determine stepsize if(!mSingleStepDebug) { long startTime = getTime(); advanceSims(mFrameCnt); mFrameCnt++; long stopTime = getTime(); debMsgStd("ntlWorld::renderVisualization",DM_MSG,"Time for t="<<mSimulationTime<<": "<< getTimeString(stopTime-startTime) <<" ", 10); } else { double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getTimestep(); singleStepSims(targetTime); // check paniced sims (normally done by advanceSims bool allPanic = true; for(size_t i=0;i<mpSims->size();i++) { if(!(*mpSims)[i]->getPanic()) allPanic = false; } if(allPanic) { warnMsg("ntlWorld::advanceSims","All sims panicked... stopping thread" ); setStopRenderVisualization( true ); } if(! isSimworldOk() ) { warnMsg("ntlWorld::advanceSims","World state error... stopping" ); setStopRenderVisualization( true ); } } // save frame if(mpOpenGLRenderer) mpOpenGLRenderer->saveAnimationFrame( mSimulationTime ); // for non-threaded check events if(!multiThreaded) { Fl::check(); gpElbeemFrame->SceneDisplay->doOnlyForcedRedraw(); } } mThreadRunning = false; stopSimulationRestoreGui(); #else multiThreaded = false; // remove warning #endif return 0; }
// copy & remember settings for later use void SimulationObject::copyElbeemSettings(elbeemSimulationSettings *settings) { mpElbeemSettings = new elbeemSimulationSettings; *mpElbeemSettings = *settings; mGeoInitId = settings->domainId+1; debMsgStd("SimulationObject",DM_MSG,"mGeoInitId="<<mGeoInitId<<", domainId="<<settings->domainId, 8); }
void elbeemCheckDebugEnv(void) { const char *strEnvName = "BLENDER_ELBEEMDEBUG"; const char *strEnvName2 = "ELBEEM_DEBUGLEVEL"; if(globalFirstEnvCheck) return; if(getenv(strEnvName)) { gDebugLevel = atoi(getenv(strEnvName)); if(gDebugLevel>0) debMsgStd("performElbeemSimulation",DM_NOTIFY,"Using envvar '"<<strEnvName<<"'='"<<getenv(strEnvName)<<"', debugLevel set to: "<<gDebugLevel<<"\n", 1); } if(getenv(strEnvName2)) { gDebugLevel = atoi(getenv(strEnvName2)); if(gDebugLevel>0) debMsgStd("performElbeemSimulation",DM_NOTIFY,"Using envvar '"<<strEnvName2<<"'='"<<getenv(strEnvName2)<<"', debugLevel set to: "<<gDebugLevel<<"\n", 1); } if(gDebugLevel< 0) gDebugLevel = 0; if(gDebugLevel>10) gDebugLevel = 0; // only use valid values globalFirstEnvCheck = 1; }
/****************************************************************************** * Destructor *****************************************************************************/ SimulationObject::~SimulationObject() { if(mpGiTree) delete mpGiTree; if(mpElbeemSettings) delete mpElbeemSettings; if(mpLbm) delete mpLbm; if(mpParam) delete mpParam; if(mpParts) delete mpParts; debMsgStd("SimulationObject",DM_MSG,"El'Beem Done!\n",10); }
int ntlWorld::renderAnimation( void ) { // only single pic currently //debMsgStd("ntlWorld::renderAnimation : Warning only simulating...",1); if(mpGlob->getAniFrames() < 0) { debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"No frames to render... ",1); return 1; } if(mFirstSim<0) { debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"No reference animation found...",1); return 1; } mThreadRunning = true; // not threaded, but still use the same flags if(getElbeemState() == SIMWORLD_INITED) { renderScene(); } else if(getElbeemState() == SIMWORLD_STOP) { // dont render now, just continue setElbeemState( SIMWORLD_INITED ); mFrameCnt--; // counted one too many from last abort... } else { debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"Not properly inited, stopping...",1); return 1; } if(mpSims->size() <= 0) { debMsgStd("ntlWorld::renderAnimation",DM_NOTIFY,"No simulations found, stopping...",1); return 1; } bool simok = true; for( ; ((mFrameCnt<mpGlob->getAniFrames()) && (!getStopRenderVisualization() ) && (simok)); mFrameCnt++) { if(!advanceSims(mFrameCnt)) { renderScene(); } // else means sim panicked, so dont render... else { simok=false; } } mThreadRunning = false; return 0; }
/****************************************************************************** * Destructor *****************************************************************************/ ntlWorld::~ntlWorld() { delete mpGlob->getRenderScene(); delete mpGlob->getSimScene(); delete mpGlob; // these get assigned to mpGlob but not freed there delete mpLightList; delete mpPropList; // materials delete mpSims; #ifndef NOGUI if(mpOpenGLRenderer) delete mpOpenGLRenderer; #endif // NOGUI debMsgStd("ntlWorld",DM_NOTIFY, "ntlWorld done", 10); }
/****************************************************************************** * Standard constructor *****************************************************************************/ ParticleTracer::ParticleTracer() : ntlGeometryObject(), mParts(), //mTrailLength(1), mTrailInterval(1),mTrailIntervalCounter(0), mPartSize(0.01), mStart(-1.0), mEnd(1.0), mSimStart(-1.0), mSimEnd(1.0), mPartScale(0.1) , mPartHeadDist( 0.1 ), mPartTailDist( -0.1 ), mPartSegments( 4 ), mValueScale(0), mValueCutoffTop(0.0), mValueCutoffBottom(0.0), mDumpParts(0), //mDumpText(0), mDumpTextFile(""), mDumpTextInterval(0.), mDumpTextLastTime(0.), mDumpTextCount(0), mShowOnly(0), mNumInitialParts(0), mpTrafo(NULL), mInitStart(-1.), mInitEnd(-1.), mPrevs(), mTrailTimeLast(0.), mTrailInterval(-1.), mTrailLength(0) { debMsgStd("ParticleTracer::ParticleTracer",DM_MSG,"inited",10); };
/*! check status (e.g. stop/abort) from calling program, returns !=0 if sth. happened... */ int SimulationObject::checkCallerStatus(int status, int frame) { //return 0; // DEBUG int ret = 0; if((mpElbeemSettings)&&(mpElbeemSettings->runsimCallback)) { ret = (mpElbeemSettings->runsimCallback)(mpElbeemSettings->runsimUserData, status,frame); if(ret!=FLUIDSIM_CBRET_CONTINUE) { if(ret==FLUIDSIM_CBRET_STOP) { debMsgStd("SimulationObject::notifySolverOfDump",DM_NOTIFY,"Got stop signal from caller",1); setElbeemState( SIMWORLD_STOP ); } else if(ret==FLUIDSIM_CBRET_ABORT) { errFatal("SimulationObject::notifySolverOfDump","Got abort signal from caller, aborting...", SIMWORLD_GENERICERROR ); mPanic = 1; } else { errMsg("SimulationObject::notifySolverOfDump","Invalid callback return value: "<<ret<<", ignoring... "); } } } //debMsgStd("SimulationObject::checkCallerStatus",DM_MSG, "s="<<status<<",f="<<frame<<" "<<this->getName()<<" ret="<<ret); if(isSimworldOk()) return 0; return 1; }
ParticleTracer::~ParticleTracer() { debMsgStd("ParticleTracer::~ParticleTracer",DM_MSG,"destroyed",10); if(mpTrafo) delete mpTrafo; }
/****************************************************************************** * Get triangles for rendering *****************************************************************************/ void ParticleTracer::getTriangles(double time, vector<ntlTriangle> *triangles, vector<ntlVec3Gfx> *vertices, vector<ntlVec3Gfx> *normals, int objectId ) { #ifdef ELBEEM_PLUGIN // suppress warnings... vertices = NULL; triangles = NULL; normals = NULL; objectId = 0; time = 0.; #else // ELBEEM_PLUGIN int pcnt = 0; // currently not used in blender objectId = 0; // remove, deprecated if(mDumpParts>1) { return; // only dump, no tri-gen } const bool debugParts = false; int tris = 0; int segments = mPartSegments; ntlVec3Gfx scale = ntlVec3Gfx( (mEnd[0]-mStart[0])/(mSimEnd[0]-mSimStart[0]), (mEnd[1]-mStart[1])/(mSimEnd[1]-mSimStart[1]), (mEnd[2]-mStart[2])/(mSimEnd[2]-mSimStart[2])); ntlVec3Gfx trans = mStart; time = 0.; // doesnt matter for(size_t t=0; t<mPrevs.size()+1; t++) { vector<ParticleObject> *dparts; if(t==0) { dparts = &mParts; } else { dparts = &mPrevs[t-1]; } //errMsg("TRAILT","prevs"<<t<<"/"<<mPrevs.size()<<" parts:"<<dparts->size() ); gfxReal partscale = mPartScale; if(t>1) { partscale *= (gfxReal)(mPrevs.size()+1-t) / (gfxReal)(mPrevs.size()+1); } gfxReal partNormSize = 0.01 * partscale; //for(size_t i=0; i<mParts.size(); i++) { for(size_t i=0; i<dparts->size(); i++) { ParticleObject *p = &( (*dparts)[i] ); // mParts[i]; if(mShowOnly!=10) { // 10=show only deleted if( p->getActive()==false ) continue; } else { if( p->getActive()==true ) continue; } int type = p->getType(); if(mShowOnly>0) { switch(mShowOnly) { case 1: if(!(type&PART_BUBBLE)) continue; break; case 2: if(!(type&PART_DROP)) continue; break; case 3: if(!(type&PART_INTER)) continue; break; case 4: if(!(type&PART_FLOAT)) continue; break; case 5: if(!(type&PART_TRACER)) continue; break; } } else { // by default dont display inter if(type&PART_INTER) continue; } pcnt++; ntlVec3Gfx pnew = p->getPos(); if(type&PART_FLOAT) { // WARNING same handling for dump! if(p->getStatus()&PART_IN) { pnew[2] += 0.8; } // offset for display // add one gridcell offset //pnew[2] += 1.0; } #if LBMDIM==2 pnew[2] += 0.001; // DEBUG pnew[2] += 0.009; // DEBUG #endif ntlVec3Gfx pdir = p->getVel(); gfxReal plen = normalize( pdir ); if( plen < 1e-05) pdir = ntlVec3Gfx(-1.0 ,0.0 ,0.0); ntlVec3Gfx pos = (*mpTrafo) * pnew; gfxReal partsize = 0.0; if(debugParts) errMsg("DebugParts"," i"<<i<<" new"<<pnew<<" vel"<<pdir<<" pos="<<pos ); //if(i==0 &&(debugParts)) errMsg("DebugParts"," i"<<i<<" new"<<pnew[0]<<" pos="<<pos[0]<<" scale="<<scale[0]<<" t="<<trans[0] ); // value length scaling? if(mValueScale==1) { partsize = partscale * plen; } else if(mValueScale==2) { // cut off scaling if(plen > mValueCutoffTop) continue; if(plen < mValueCutoffBottom) continue; partsize = partscale * plen; } else { partsize = partscale; // no length scaling } //if(type&(PART_DROP|PART_BUBBLE)) partsize *= p->getSize()/5.0; ntlVec3Gfx pstart( mPartHeadDist *partsize, 0.0, 0.0 ); ntlVec3Gfx pend ( mPartTailDist *partsize, 0.0, 0.0 ); gfxReal phi = 0.0; gfxReal phiD = 2.0*M_PI / (gfxReal)segments; ntlMat4Gfx cvmat; cvmat.initId(); pdir *= -1.0; ntlVec3Gfx cv1 = pdir; ntlVec3Gfx cv2 = ntlVec3Gfx(pdir[1], -pdir[0], 0.0); ntlVec3Gfx cv3 = cross( cv1, cv2); //? for(int l=0; l<3; l++) { cvmat.value[l][0] = cv1[l]; cvmat.value[l][1] = cv2[l]; cvmat.value[l][2] = cv3[l]; } pstart = (cvmat * pstart); pend = (cvmat * pend); for(int s=0; s<segments; s++) { ntlVec3Gfx p1( 0.0 ); ntlVec3Gfx p2( 0.0 ); gfxReal radscale = partNormSize; radscale = (partsize+partNormSize)*0.5; p1[1] += cos(phi) * radscale; p1[2] += sin(phi) * radscale; p2[1] += cos(phi + phiD) * radscale; p2[2] += sin(phi + phiD) * radscale; ntlVec3Gfx n1 = ntlVec3Gfx( 0.0, cos(phi), sin(phi) ); ntlVec3Gfx n2 = ntlVec3Gfx( 0.0, cos(phi + phiD), sin(phi + phiD) ); ntlVec3Gfx ns = n1*0.5 + n2*0.5; p1 = (cvmat * p1); p2 = (cvmat * p2); sceneAddTriangle( pos+pstart, pos+p1, pos+p2, ns,n1,n2, ntlVec3Gfx(0.0), 1, triangles,vertices,normals ); sceneAddTriangle( pos+pend , pos+p2, pos+p1, ns,n2,n1, ntlVec3Gfx(0.0), 1, triangles,vertices,normals ); phi += phiD; tris += 2; } } } // t debMsgStd("ParticleTracer::getTriangles",DM_MSG,"Dumped "<<pcnt<<"/"<<mParts.size()<<" parts, tris:"<<tris<<", showonly:"<<mShowOnly,10); return; // DEBUG #endif // ELBEEM_PLUGIN }
void ParticleTracer::checkDumpTextPositions(double simtime) { // dfor partial & full dump if(mDumpTextInterval>0.) { debMsgStd("ParticleTracer::checkDumpTextPositions",DM_MSG,"t="<<simtime<<" last:"<<mDumpTextLastTime<<" inter:"<<mDumpTextInterval,7); } if((mDumpTextInterval>0.) && (simtime>mDumpTextLastTime+mDumpTextInterval)) { // dump to binary file std::ostringstream boutfilename(""); if(mDumpTextFile.length()>1) { boutfilename << mDumpTextFile << ".cpart2"; } else { boutfilename << "_particles" << ".cpart2"; } debMsgStd("ParticleTracer::checkDumpTextPositions",DM_MSG,"T-Dumping: "<< this->getName() <<", particles:"<<mParts.size()<<" "<< " to "<<boutfilename.str()<<" " , 7); int numParts = 0; // only dump bubble particles for(size_t i=0; i<mParts.size(); i++) { //if(!mParts[i].getActive()) continue; //if(!(mParts[i].getType()&PART_BUBBLE)) continue; numParts++; } // output to text file //gzFile gzf; FILE *stf; if(mDumpTextCount==0) { //gzf = gzopen(boutfilename.str().c_str(), "w0"); stf = fopen(boutfilename.str().c_str(), "w"); fprintf( stf, "\n\n# cparts generated by elbeem \n# no. of parts \nN %d \n\n",numParts); // fixed time scale for now fprintf( stf, "T %f \n\n", 1.0); } else { //gzf = gzopen(boutfilename.str().c_str(), "a+0"); stf = fopen(boutfilename.str().c_str(), "a+"); } // add current set if(stf) { fprintf( stf, "\n\n# new set at frame %d,t%f,p%d --------------------------------- \n\n", mDumpTextCount, simtime, numParts ); fprintf( stf, "S %f \n\n", simtime ); for(size_t i=0; i<mParts.size(); i++) { ParticleObject *p = &mParts[i]; ntlVec3Gfx pos = p->getPos(); float size = p->getSize(); float infl = 1.; //if(!mParts[i].getActive()) { size=0.; } // switch "off" if(!mParts[i].getActive()) { infl=0.; } // switch "off" if(!mParts[i].getInFluid()) { infl=0.; } // switch "off" if(mParts[i].getLifeTime()<0.) { infl=0.; } // not yet active... pos = (*mpTrafo) * pos; ntlVec3Gfx v = p->getVel(); v[0] *= mpTrafo->value[0][0]; v[1] *= mpTrafo->value[1][1]; v[2] *= mpTrafo->value[2][2]; fprintf( stf, "P %f %f %f \n", pos[0],pos[1],pos[2] ); if(size!=1.0) fprintf( stf, "s %f \n", size ); if(infl!=1.0) fprintf( stf, "i %f \n", infl ); fprintf( stf, "\n" ); } fprintf( stf, "# %d end ", mDumpTextCount ); //gzclose( gzf ); fclose( stf ); mDumpTextCount++; } mDumpTextLastTime += mDumpTextInterval; } }
/****************************************************************************** * Destructor *****************************************************************************/ ntlBlenderDumper::~ntlBlenderDumper() { debMsgStd("ntlBlenderDumper",DM_NOTIFY, "ntlBlenderDumper done", 10); }
/****************************************************************************** * advance simulations by time t *****************************************************************************/ int ntlWorld::advanceSims(int framenum) { bool done = false; bool allPanic = true; // stop/quit (abort), dont display/render if(!isSimworldOk()) { return 1; } for(size_t i=0;i<mpSims->size();i++) { (*mpSims)[i]->setFrameNum(framenum); } // time stopped? nothing else to do... if( (*mpSims)[mFirstSim]->getFrameTime(framenum) <= 0.0 ){ done=true; allPanic=false; /* DG: Need to check for user cancel here (fix for [#30298]) */ (*mpSims)[mFirstSim]->checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0); } // Prevent bug [#29186] Object contribute to fluid sim animation start earlier than keyframe // Was: double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getFrameTime(framenum); - DG double totalTime = 0.0, targetTime = 0.0; for(size_t i = 0; i < mSimFrameCnt; i++) { /* We need an intermediate array "mSimFrameValue" because otherwise if we don't start with starttime = 0, the sim gets out of sync - DG */ totalTime += (*mpSims)[mFirstSim]->getFrameTime(mSimFrameValue[i]); } targetTime = totalTime + (*mpSims)[mFirstSim]->getFrameTime(framenum); int gstate = 0; myTime_t advsstart = getTime(); // step all the sims, and check for panic debMsgStd("ntlWorld::advanceSims",DM_MSG, " sims "<<mpSims->size()<<" t"<<targetTime<<" done:"<<done<<" panic:"<<allPanic<<" gstate:"<<gstate, 10); // debug // timedebug while(!done) { double nextTargetTime = (*mpSims)[mFirstSim]->getCurrentTime() + (*mpSims)[mFirstSim]->getTimestep(); singleStepSims(nextTargetTime); // check target times done = true; allPanic = false; if((*mpSims)[mFirstSim]->getTimestep() <1e-9 ) { // safety check, avoid timesteps that are too small errMsg("ntlWorld::advanceSims","Invalid time step, causing panic! curr:"<<(*mpSims)[mFirstSim]->getCurrentTime()<<" next:"<<nextTargetTime<<", stept:"<< (*mpSims)[mFirstSim]->getTimestep() ); allPanic = true; } else { for(size_t i=0;i<mpSims->size();i++) { if(!(*mpSims)[i]->getVisible()) continue; if((*mpSims)[i]->getPanic()) allPanic = true; // do any panic now!? debMsgStd("ntlWorld::advanceSims",DM_MSG, "Sim "<<i<<", currt:"<<(*mpSims)[i]->getCurrentTime()<<", nt:"<<nextTargetTime<<", panic:"<<(*mpSims)[i]->getPanic()<<", targett:"<<targetTime, 10); // debug // timedebug } } if( (targetTime - (*mpSims)[mFirstSim]->getCurrentTime()) > LBM_TIME_EPSILON) done=false; if(allPanic) done = true; } if(allPanic) { warnMsg("ntlWorld::advanceSims","All sims panicked... stopping thread" ); setStopRenderVisualization( true ); return 1; } myTime_t advsend = getTime(); debMsgStd("ntlWorld::advanceSims",DM_MSG,"Overall steps so far took:"<< getTimeString(advsend-advsstart)<<" for sim time "<<targetTime, 4); // finish step for(size_t i=0;i<mpSims->size();i++) { SimulationObject *sim = (*mpSims)[i]; if(!sim->getVisible()) continue; if(sim->getPanic()) continue; sim->prepareVisualization(); } mSimFrameValue.push_back(framenum); mSimFrameCnt++; return 0; }
void ntlWorld::finishWorldInit() { if(! isSimworldOk() ) return; // init the scene for the first time long sstartTime = getTime(); // first init sim scene for geo setup mpGlob->getSimScene()->buildScene(0.0, true); if(! isSimworldOk() ) return; mpGlob->getRenderScene()->buildScene(0.0, true); if(! isSimworldOk() ) return; long sstopTime = getTime(); debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Scene build time: "<< getTimeString(sstopTime-sstartTime) <<" ", 10); // TODO check simulations, run first steps mFirstSim = -1; if(mpSims->size() > 0) { // use values from first simulation as master time scale long startTime = getTime(); // remember first active sim for(size_t i=0;i<mpSims->size();i++) { if(!(*mpSims)[i]->getVisible()) continue; if((*mpSims)[i]->getPanic()) continue; // check largest timestep if(mFirstSim>=0) { if( (*mpSims)[i]->getTimestep() > (*mpSims)[mFirstSim]->getTimestep() ) { mFirstSim = i; debMsgStd("ntlWorld::ntlWorld",DM_MSG,"First Sim changed: "<<i ,10); } } // check any valid sim if(mFirstSim<0) { mFirstSim = i; debMsgStd("ntlWorld::ntlWorld",DM_MSG,"First Sim: "<<i ,10); } } if(mFirstSim>=0) { debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Anistart Time: "<<(*mpSims)[mFirstSim]->getStartTime() ,10); while(mSimulationTime < (*mpSims)[mFirstSim]->getStartTime() ) { debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Anistart Time: "<<(*mpSims)[mFirstSim]->getStartTime()<<" simtime:"<<mSimulationTime ,10); advanceSims(-1); } long stopTime = getTime(); mSimulationTime += (*mpSims)[mFirstSim]->getStartTime(); debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Time for start-sims:"<< getTimeString(stopTime-startTime) , 1); #ifndef NOGUI guiResetSimulationTimeRange( mSimulationTime ); #endif } else { if(!mpGlob->getSingleFrameMode()) debMsgStd("ntlWorld::ntlWorld",DM_WARNING,"No active simulations!", 1); } } if(! isSimworldOk() ) return; setElbeemState( SIMWORLD_INITED ); }
void LbmControlData::parseControldataAttrList(AttributeList *attr) { // controlpart vars mSetForceStrength = attr->readFloat("tforcestrength", mSetForceStrength,"LbmControlData", "mSetForceStrength", false); //errMsg("tforcestrength set to "," "<<mSetForceStrength); mCpUpdateInterval = attr->readInt("controlparticle_updateinterval", mCpUpdateInterval,"LbmControlData","mCpUpdateInterval", false); // tracer output file mCpOutfile = attr->readString("controlparticle_outfile",mCpOutfile,"LbmControlData","mCpOutfile", false); if(getenv("ELBEEM_CPOUTFILE")) { string outfile(getenv("ELBEEM_CPOUTFILE")); mCpOutfile = outfile; debMsgStd("LbmControlData::parseAttrList",DM_NOTIFY,"Using envvar ELBEEM_CPOUTFILE to set mCpOutfile to "<<outfile<<","<<mCpOutfile,7); } for(int cpii=0; cpii<10; cpii++) { string suffix(""); //if(cpii>0) { suffix = string("0"); suffix[0]+=cpii; } LbmControlSet *cset; cset = new LbmControlSet(); cset->initCparts(); cset->mContrPartFile = attr->readString("controlparticle"+suffix+"_file",cset->mContrPartFile,"LbmControlData","cset->mContrPartFile", false); if((cpii==0) && (getenv("ELBEEM_CPINFILE")) ) { string infile(getenv("ELBEEM_CPINFILE")); cset->mContrPartFile = infile; debMsgStd("LbmControlData::parseAttrList",DM_NOTIFY,"Using envvar ELBEEM_CPINFILE to set mContrPartFile to "<<infile<<","<<cset->mContrPartFile,7); } LbmFloat cpvort=0.; cset->mcRadiusAtt = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_radiusatt", 0., "LbmControlData","mcRadiusAtt" ); cset->mcRadiusVel = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_radiusvel", 0., "LbmControlData","mcRadiusVel" ); cset->mcRadiusVel = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_radiusvel", 0., "LbmControlData","mcRadiusVel" ); cset->mCparts->setRadiusAtt(cset->mcRadiusAtt.get(0.)); cset->mCparts->setRadiusVel(cset->mcRadiusVel.get(0.)); // WARNING currently only for first set //if(cpii==0) { cset->mcForceAtt = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_attraction", 0. , "LbmControlData","cset->mcForceAtt", false); cset->mcForceVel = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_velocity", 0. , "LbmControlData","mcForceVel", false); cset->mcForceMaxd = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_maxdist", 0. , "LbmControlData","mcForceMaxd", false); cset->mCparts->setInfluenceAttraction(cset->mcForceAtt.get(0.) ); // warning - stores temprorarily, value converted to dt dep. factor cset->mCparts->setInfluenceVelocity(cset->mcForceVel.get(0.) , 0.01 ); // dummy dt cset->mCparts->setInfluenceMaxdist(cset->mcForceMaxd.get(0.) ); cpvort = attr->readFloat("controlparticle"+suffix+"_vorticity", cpvort, "LbmControlData","cpvort", false); cset->mCparts->setInfluenceTangential(cpvort); cset->mcRadiusMind = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_radiusmin", cset->mcRadiusMind.get(0.), "LbmControlData","mcRadiusMind", false); cset->mcRadiusMaxd = attr->readChannelSinglePrecFloat("controlparticle"+suffix+"_radiusmax", cset->mcRadiusMind.get(0.), "LbmControlData","mcRadiusMaxd", false); cset->mCparts->setRadiusMinMaxd(cset->mcRadiusMind.get(0.)); cset->mCparts->setRadiusMaxd(cset->mcRadiusMaxd.get(0.)); //} // now local... //LbmVec cpOffset(0.), cpScale(1.); LbmFloat cpTimescale = 1.; string cpMirroring(""); //cset->mcCpOffset = attr->readChannelVec3f("controlparticle"+suffix+"_offset", ntlVec3f(0.),"LbmControlData","mcCpOffset", false); //cset->mcCpScale = attr->readChannelVec3f("controlparticle"+suffix+"_scale", ntlVec3f(1.), "LbmControlData","mcCpScale", false); cset->mcCpOffset = attr->readChannelVec3f("controlparticle"+suffix+"_offset", ntlVec3f(0.),"LbmControlData","mcCpOffset", false); cset->mcCpScale = attr->readChannelVec3f("controlparticle"+suffix+"_scale", ntlVec3f(1.), "LbmControlData","mcCpScale", false); cpTimescale = attr->readFloat("controlparticle"+suffix+"_timescale", cpTimescale, "LbmControlData","cpTimescale", false); cpMirroring = attr->readString("controlparticle"+suffix+"_mirror", cpMirroring, "LbmControlData","cpMirroring", false); LbmFloat cpsWidth = cset->mCparts->getCPSWith(); cpsWidth = attr->readFloat("controlparticle"+suffix+"_cpswidth", cpsWidth, "LbmControlData","cpsWidth", false); LbmFloat cpsDt = cset->mCparts->getCPSTimestep(); cpsDt = attr->readFloat("controlparticle"+suffix+"_cpstimestep", cpsDt, "LbmControlData","cpsDt", false); LbmFloat cpsTstart = cset->mCparts->getCPSTimeStart(); cpsTstart = attr->readFloat("controlparticle"+suffix+"_cpststart", cpsTstart, "LbmControlData","cpsTstart", false); LbmFloat cpsTend = cset->mCparts->getCPSTimeEnd(); cpsTend = attr->readFloat("controlparticle"+suffix+"_cpstend", cpsTend, "LbmControlData","cpsTend", false); LbmFloat cpsMvmfac = cset->mCparts->getCPSMvmWeightFac(); cpsMvmfac = attr->readFloat("controlparticle"+suffix+"_cpsmvmfac", cpsMvmfac, "LbmControlData","cpsMvmfac", false); cset->mCparts->setCPSWith(cpsWidth); cset->mCparts->setCPSTimestep(cpsDt); cset->mCparts->setCPSTimeStart(cpsTstart); cset->mCparts->setCPSTimeEnd(cpsTend); cset->mCparts->setCPSMvmWeightFac(cpsMvmfac); cset->mCparts->setOffset( vec2L(cset->mcCpOffset.get(0.)) ); cset->mCparts->setScale( vec2L(cset->mcCpScale.get(0.)) ); cset->mCparts->setInitTimeScale( cpTimescale ); cset->mCparts->setInitMirror( cpMirroring ); int mDebugInit = 0; mDebugInit = attr->readInt("controlparticle"+suffix+"_debuginit", mDebugInit,"LbmControlData","mDebugInit", false); cset->mCparts->setDebugInit(mDebugInit); // motion particle settings LbmVec mcpOffset(0.), mcpScale(1.); LbmFloat mcpTimescale = 1.; string mcpMirroring(""); cset->mCpmotionFile = attr->readString("cpmotion"+suffix+"_file",cset->mCpmotionFile,"LbmControlData","mCpmotionFile", false); mcpTimescale = attr->readFloat("cpmotion"+suffix+"_timescale", mcpTimescale, "LbmControlData","mcpTimescale", false); mcpMirroring = attr->readString("cpmotion"+suffix+"_mirror", mcpMirroring, "LbmControlData","mcpMirroring", false); mcpOffset = vec2L( attr->readVec3d("cpmotion"+suffix+"_offset", vec2P(mcpOffset),"LbmControlData","cpOffset", false) ); mcpScale = vec2L( attr->readVec3d("cpmotion"+suffix+"_scale", vec2P(mcpScale), "LbmControlData","cpScale", false) ); cset->mCpmotion->setOffset( vec2L(mcpOffset) ); cset->mCpmotion->setScale( vec2L(mcpScale) ); cset->mCpmotion->setInitTimeScale( mcpTimescale ); cset->mCpmotion->setInitMirror( mcpMirroring ); if(cset->mContrPartFile.length()>1) { errMsg("LbmControlData","Using control particle set "<<cpii<<" file:"<<cset->mContrPartFile<<" cpmfile:"<<cset->mCpmotionFile<<" mirr:'"<<cset->mCpmotion->getInitMirror()<<"' " ); mCons.push_back( cset ); } else { delete cset; } } // debug, testing - make sure theres at least an empty set if(mCons.size()<1) { mCons.push_back( new LbmControlSet() ); mCons[0]->initCparts(); } // take from first set for(int cpii=1; cpii<(int)mCons.size(); cpii++) { mCons[cpii]->mCparts->setRadiusMinMaxd( mCons[0]->mCparts->getRadiusMinMaxd() ); mCons[cpii]->mCparts->setRadiusMaxd( mCons[0]->mCparts->getRadiusMaxd() ); mCons[cpii]->mCparts->setInfluenceAttraction( mCons[0]->mCparts->getInfluenceAttraction() ); mCons[cpii]->mCparts->setInfluenceTangential( mCons[0]->mCparts->getInfluenceTangential() ); mCons[cpii]->mCparts->setInfluenceVelocity( mCons[0]->mCparts->getInfluenceVelocity() , 0.01 ); // dummy dt mCons[cpii]->mCparts->setInfluenceMaxdist( mCons[0]->mCparts->getInfluenceMaxdist() ); } // invert for usage in relax macro mDiffVelCon = 1.-attr->readFloat("cpdiffvelcon", mDiffVelCon, "LbmControlData","mDiffVelCon", false); mDebugCpscale = attr->readFloat("cpdebug_cpscale", mDebugCpscale, "LbmControlData","mDebugCpscale", false); mDebugMaxdScale = attr->readFloat("cpdebug_maxdscale", mDebugMaxdScale, "LbmControlData","mDebugMaxdScale", false); mDebugAttScale = attr->readFloat("cpdebug_attscale", mDebugAttScale, "LbmControlData","mDebugAttScale", false); mDebugVelScale = attr->readFloat("cpdebug_velscale", mDebugVelScale, "LbmControlData","mDebugVelScale", false); mDebugCompavScale = attr->readFloat("cpdebug_compavscale", mDebugCompavScale, "LbmControlData","mDebugCompavScale", false); mDebugAvgVelScale = attr->readFloat("cpdebug_avgvelsc", mDebugAvgVelScale, "LbmControlData","mDebugAvgVelScale", false); }
void LbmFsgrSolver::initCpdata() { // enable for cps via env. vars //if( (getenv("ELBEEM_CPINFILE")) || (getenv("ELBEEM_CPOUTFILE")) ){ mUseTestdata=1; } // manually switch on! if this is zero, nothing is done... mpControl->mSetForceStrength = this->mTForceStrength = 1.; mpControl->mCons.clear(); // init all control fluid objects int numobjs = (int)(mpGiObjects->size()); for(int o=0; o<numobjs; o++) { ntlGeometryObjModel *obj = (ntlGeometryObjModel *)(*mpGiObjects)[o]; if(obj->getGeoInitType() & FGI_CONTROL) { // add new control set per object LbmControlSet *cset; cset = new LbmControlSet(); cset->initCparts(); // dont load any file cset->mContrPartFile = string(""); cset->mcForceAtt = obj->getCpsAttrFStr(); cset->mcRadiusAtt = obj->getCpsAttrFRad(); cset->mcForceVel = obj->getCpsVelFStr(); cset->mcRadiusVel = obj->getCpsVelFRad(); cset->mCparts->setCPSTimeStart(obj->getCpsTimeStart()); cset->mCparts->setCPSTimeEnd(obj->getCpsTimeEnd()); if(obj->getCpsQuality() > LBM_EPSILON) cset->mCparts->setCPSWith(1.0 / obj->getCpsQuality()); // this value can be left at 0.5: cset->mCparts->setCPSMvmWeightFac(0.5); mpControl->mCons.push_back( cset ); mpControl->mCons[mpControl->mCons.size()-1]->mCparts->initFromObject(obj); } } // NT blender integration manual test setup if(0) { // manually switch on! if this is zero, nothing is done... mpControl->mSetForceStrength = this->mTForceStrength = 1.; mpControl->mCons.clear(); // add new set LbmControlSet *cset; cset = new LbmControlSet(); cset->initCparts(); // dont load any file cset->mContrPartFile = string(""); // set radii for attraction & velocity forces // set strength of the forces // don't set directly! but use channels: // mcForceAtt, mcForceVel, mcForceMaxd, mcRadiusAtt, mcRadiusVel, mcRadiusMind, mcRadiusMaxd etc. // wrong: cset->mCparts->setInfluenceAttraction(1.15); cset->mCparts->setRadiusAtt(1.5); // right, e.g., to init some constant values: cset->mcForceAtt = AnimChannel<float>(0.2); cset->mcRadiusAtt = AnimChannel<float>(0.75); cset->mcForceVel = AnimChannel<float>(0.2); cset->mcRadiusVel = AnimChannel<float>(0.75); // this value can be left at 0.5: cset->mCparts->setCPSMvmWeightFac(0.5); mpControl->mCons.push_back( cset ); // instead of reading from file (cset->mContrPartFile), manually init some particles mpControl->mCons[0]->mCparts->initBlenderTest(); // other values that might be interesting to change: //cset->mCparts->setCPSTimestep(0.02); //cset->mCparts->setCPSTimeStart(0.); //cset->mCparts->setCPSTimeEnd(1.); //mpControl->mDiffVelCon = 1.; // more rigid velocity control, 0 (default) allows more turbulence } // control particle ------------------------------------------------------------------------------------- // init cppf stage, use set 0! if(mCppfStage>0) { if(mpControl->mCpOutfile.length()<1) mpControl->mCpOutfile = string("cpout"); // use getOutFilename !? char strbuf[100]; const char *cpFormat = "_d%dcppf%d"; // initial coarse stage, no input if(mCppfStage==1) { mpControl->mCons[0]->mContrPartFile = ""; } else { // read from prev stage snprintf(strbuf,100, cpFormat ,LBMDIM,mCppfStage-1); mpControl->mCons[0]->mContrPartFile = mpControl->mCpOutfile; mpControl->mCons[0]->mContrPartFile += strbuf; mpControl->mCons[0]->mContrPartFile += ".cpart2"; } snprintf(strbuf,100, cpFormat ,LBMDIM,mCppfStage); mpControl->mCpOutfile += strbuf; } // */ for(int cpssi=0; cpssi<(int)mpControl->mCons.size(); cpssi++) { ControlParticles *cparts = mpControl->mCons[cpssi]->mCparts; ControlParticles *cpmotion = mpControl->mCons[cpssi]->mCpmotion; // now set with real dt cparts->setInfluenceVelocity( mpControl->mCons[cpssi]->mcForceVel.get(0.), mLevel[mMaxRefine].timestep); cparts->setCharLength( mLevel[mMaxRefine].nodeSize ); cparts->setCharLength( mLevel[mMaxRefine].nodeSize ); errMsg("LbmControlData","CppfStage "<<mCppfStage<<" in:"<<mpControl->mCons[cpssi]->mContrPartFile<< " out:"<<mpControl->mCpOutfile<<" cl:"<< cparts->getCharLength() ); // control particle test init if(mpControl->mCons[cpssi]->mCpmotionFile.length()>=1) cpmotion->initFromTextFile(mpControl->mCons[cpssi]->mCpmotionFile); // not really necessary... //? cparts->setFluidSpacing( mLevel[mMaxRefine].nodeSize ); // use grid coords!? //? cparts->calculateKernelWeight(); //? debMsgStd("LbmFsgrSolver::initCpdata",DM_MSG,"ControlParticles - motion inited: "<<cparts->getSize() ,10); // ensure both are on for env. var settings // when no particles, but outfile enabled, initialize const int lev = mMaxRefine; if((mpParticles) && (mpControl->mCpOutfile.length()>=1) && (cpssi==0)) { // check if auto num if( (mpParticles->getNumInitialParticles()<=1) && (mpParticles->getNumParticles()<=1) ) { // initParticles done afterwards anyway int tracers = 0; const int workSet = mLevel[lev].setCurr; FSGR_FORIJK_BOUNDS(lev) { if(RFLAG(lev,i,j,k, workSet)&(CFFluid)) tracers++; } if(LBMDIM==3) tracers /= 8; else tracers /= 4; mpParticles->setNumInitialParticles(tracers); mpParticles->setDumpTextFile(mpControl->mCpOutfile); debMsgStd("LbmFsgrSolver::initCpdata",DM_MSG,"ControlParticles - set tracers #"<<tracers<<", actual #"<<mpParticles->getNumParticles() ,10); } if(mpParticles->getDumpTextInterval()<=0.) { mpParticles->setDumpTextInterval(mLevel[lev].timestep * mLevel[lev].lSizex); debMsgStd("LbmFsgrSolver::initCpdata",DM_MSG,"ControlParticles - dump delta t not set, using dti="<< mpParticles->getDumpTextInterval()<<", sim dt="<<mLevel[lev].timestep, 5 ); } mpParticles->setDumpParts(true); // DEBUG? also dump as particle system } if(mpControl->mCons[cpssi]->mContrPartFile.length()>=1) cparts->initFromTextFile(mpControl->mCons[cpssi]->mContrPartFile); cparts->setFluidSpacing( mLevel[lev].nodeSize ); // use grid coords!? cparts->calculateKernelWeight(); debMsgStd("LbmFsgrSolver::initCpdata",DM_MSG,"ControlParticles mCons"<<cpssi<<" - inited, parts:"<<cparts->getTotalSize()<<","<<cparts->getSize()<<" dt:"<<mpParam->getTimestep()<<" control time:"<<cparts->getControlTimStart()<<" to "<<cparts->getControlTimEnd() ,10); } // cpssi
/****************************************************************************** * Only dump time dep. objects to file *****************************************************************************/ int ntlBlenderDumper::renderScene( void ) { char nrStr[5]; /* nr conversion */ ntlRenderGlobals *glob = mpGlob; ntlScene *scene = mpGlob->getSimScene(); bool debugOut = false; bool debugRender = false; #if ELBEEM_PLUGIN==1 debugOut = false; #endif // ELBEEM_PLUGIN==1 vector<string> gmName; // gm names vector<string> gmMat; // materials for gm int numGMs = 0; // no. of .obj models created if(debugOut) debMsgStd("ntlBlenderDumper::renderScene",DM_NOTIFY,"Dumping geometry data", 1); long startTime = getTime(); snprintf(nrStr, 5, "%04d", glob->getAniCount() ); // local scene vars vector<ntlTriangle> Triangles; vector<ntlVec3Gfx> Vertices; vector<ntlVec3Gfx> VertNormals; // check geo objects int idCnt = 0; // give IDs to objects for (vector<ntlGeometryClass*>::iterator iter = scene->getGeoClasses()->begin(); iter != scene->getGeoClasses()->end(); iter++) { if(!(*iter)->getVisible()) continue; int tid = (*iter)->getTypeId(); if(tid & GEOCLASSTID_OBJECT) { // normal geom. objects -> ignore } if(tid & GEOCLASSTID_SHADER) { ntlGeometryShader *geoshad = (ntlGeometryShader*)(*iter); //dynamic_cast<ntlGeometryShader*>(*iter); string outname = geoshad->getOutFilename(); if(outname.length()<1) outname = mpGlob->getOutFilename(); geoshad->notifyShaderOfDump(DUMP_FULLGEOMETRY, glob->getAniCount(),nrStr,outname); for (vector<ntlGeometryObject*>::iterator siter = geoshad->getObjectsBegin(); siter != geoshad->getObjectsEnd(); siter++) { if(debugOut) debMsgStd("ntlBlenderDumper::BuildScene",DM_MSG,"added shader geometry "<<(*siter)->getName(), 8); (*siter)->notifyOfDump(DUMP_FULLGEOMETRY, glob->getAniCount(),nrStr,outname, this->mSimulationTime); bool doDump = false; bool isPreview = false; // only dump final&preview surface meshes if( (*siter)->getName().find( "final" ) != string::npos) { doDump = true; } else if( (*siter)->getName().find( "preview" ) != string::npos) { doDump = true; isPreview = true; } if(!doDump) continue; // dont quit, some objects need notifyOfDump call if((glob_mpactive) && (glob_mpindex>0)) { continue; //return 0; } // only dump geo shader objects Triangles.clear(); Vertices.clear(); VertNormals.clear(); (*siter)->initialize( mpGlob ); (*siter)->getTriangles(this->mSimulationTime, &Triangles, &Vertices, &VertNormals, idCnt); idCnt ++; // WARNING - this is dirty, but simobjs are the only geoshaders right now SimulationObject *sim = (SimulationObject *)geoshad; LbmSolverInterface *lbm = sim->getSolver(); // always dump mesh, even empty ones... // dump to binary file std::ostringstream boutfilename(""); //boutfilename << ecrpath.str() << outname <<"_"<< (*siter)->getName() <<"_" << nrStr << ".obj"; boutfilename << outname <<"_"<< (*siter)->getName() <<"_" << nrStr; if(debugOut) debMsgStd("ntlBlenderDumper::renderScene",DM_MSG,"B-Dumping: "<< (*siter)->getName() <<", triangles:"<<Triangles.size()<<", vertices:"<<Vertices.size()<< " to "<<boutfilename.str() , 7); gzFile gzf; // output velocities if desired if((!isPreview) && (lbm->getDumpVelocities())) { std::ostringstream bvelfilename; bvelfilename << boutfilename.str(); bvelfilename << ".bvel.gz"; gzf = gzopen(bvelfilename.str().c_str(), "wb9"); if(gzf) { int numVerts; if(sizeof(numVerts)!=4) { errMsg("ntlBlenderDumper::renderScene","Invalid int size"); return 1; } numVerts = Vertices.size(); gzwrite(gzf, &numVerts, sizeof(numVerts)); for(size_t i=0; i<Vertices.size(); i++) { // returns smoothed velocity, scaled by frame time ntlVec3Gfx v = lbm->getVelocityAt( Vertices[i][0], Vertices[i][1], Vertices[i][2] ); // translation not necessary, test rotation & scaling? for(int j=0; j<3; j++) { float vertp = v[j]; //if(i<20) errMsg("ntlBlenderDumper","DUMP_VEL final "<<i<<" = "<<v); gzwrite(gzf, &vertp, sizeof(vertp)); } } gzclose( gzf ); } } // compress all bobj's boutfilename << ".bobj.gz"; gzf = gzopen(boutfilename.str().c_str(), "wb1"); // wb9 is slow for large meshes! if (!gzf) { errMsg("ntlBlenderDumper::renderScene","Unable to open output '"<<boutfilename<<"' "); return 1; } // dont transform velocity output, this is handled in blender // current transform matrix ntlMatrix4x4<gfxReal> *trafo; trafo = lbm->getDomainTrafo(); if(trafo) { // transform into source space for(size_t i=0; i<Vertices.size(); i++) { Vertices[i] = (*trafo) * Vertices[i]; } } // rotate vertnormals ntlMatrix4x4<gfxReal> rottrafo; rottrafo.initId(); if(lbm->getDomainTrafo()) { // dont modifiy original! rottrafo = *lbm->getDomainTrafo(); ntlVec3Gfx rTrans,rScale,rRot,rShear; rottrafo.decompose(rTrans,rScale,rRot,rShear); rottrafo.initRotationXYZ(rRot[0],rRot[1],rRot[2]); // only rotate here... for(size_t i=0; i<Vertices.size(); i++) { VertNormals[i] = rottrafo * VertNormals[i]; normalize(VertNormals[i]); // remove scaling etc. } } // write to file int numVerts; if(sizeof(numVerts)!=4) { errMsg("ntlBlenderDumper::renderScene","Invalid int size"); return 1; } numVerts = Vertices.size(); gzwrite(gzf, &numVerts, sizeof(numVerts)); for(size_t i=0; i<Vertices.size(); i++) { for(int j=0; j<3; j++) { float vertp = Vertices[i][j]; gzwrite(gzf, &vertp, sizeof(vertp)); } } // should be the same as Vertices.size if(VertNormals.size() != (size_t)numVerts) { errMsg("ntlBlenderDumper::renderScene","Normals have to have same size as vertices!"); VertNormals.resize( Vertices.size() ); } gzwrite(gzf, &numVerts, sizeof(numVerts)); for(size_t i=0; i<VertNormals.size(); i++) { for(int j=0; j<3; j++) { float normp = VertNormals[i][j]; gzwrite(gzf, &normp, sizeof(normp)); } } int numTris = Triangles.size(); gzwrite(gzf, &numTris, sizeof(numTris)); for(size_t i=0; i<Triangles.size(); i++) { for(int j=0; j<3; j++) { int triIndex = Triangles[i].getPoints()[j]; gzwrite(gzf, &triIndex, sizeof(triIndex)); } } gzclose( gzf ); debMsgStd("ntlBlenderDumper::renderScene",DM_NOTIFY," Wrote: '"<<boutfilename.str()<<"' ", 2); numGMs++; } } } // output ecr config file if(numGMs>0) { if(debugOut) debMsgStd("ntlBlenderDumper::renderScene",DM_MSG,"Objects dumped: "<<numGMs, 10); } else { if((glob_mpactive) && (glob_mpindex>0)) { // ok, nothing to do anyway... } else { errFatal("ntlBlenderDumper::renderScene","No objects to dump! Aborting...",SIMWORLD_INITERROR); return 1; } } // debug timing long stopTime = getTime(); debMsgStd("ntlBlenderDumper::renderScene",DM_MSG,"Scene #"<<nrStr<<" dump time: "<< getTimeString(stopTime-startTime) <<" ", 10); // still render for preview... if(debugRender) { debMsgStd("ntlBlenderDumper::renderScene",DM_NOTIFY,"Performing preliminary render", 1); ntlWorld::renderScene(); } else { // next frame glob->setAniCount( glob->getAniCount() +1 ); } return 0; }
int SimulationObject::initializeLbmSimulation(ntlRenderGlobals *glob) { if(! isSimworldOk() ) return 1; // already inited? if(mpLbm) return 0; mpGlob = glob; if(!getVisible()) { mpAttrs->setAllUsed(); return 0; } mGeoInitId = mpAttrs->readInt("geoinitid", mGeoInitId,"LbmSolverInterface", "mGeoInitId", false); //mDimension, mSolverType are deprecated string mSolverType(""); mSolverType = mpAttrs->readString("solver", mSolverType, "SimulationObject","mSolverType", false ); mpLbm = createSolver(); /* check lbm pointer */ if(mpLbm == NULL) { errFatal("SimulationObject::initializeLbmSimulation","Unable to init LBM solver! ", SIMWORLD_INITERROR); return 2; } debMsgStd("SimulationObject::initialized",DM_MSG,"IdStr:"<<mpLbm->getIdString() <<" LBM solver! ", 2); mpParts = new ParticleTracer(); // for non-param simulations mpLbm->setParametrizer( mpParam ); mpParam->setAttrList( getAttributeList() ); // not needed.. done in solver_init: mpParam->setSize ... in solver_interface mpParam->parseAttrList(); mpLbm->setAttrList( getAttributeList() ); mpLbm->setSwsAttrList( getSwsAttributeList() ); mpLbm->parseAttrList(); mpParts->parseAttrList( getAttributeList() ); if(! isSimworldOk() ) return 3; mpParts->setName( getName() + "_part" ); mpParts->initialize( glob ); if(! isSimworldOk() ) return 4; // init material settings string matMc("default"); matMc = mpAttrs->readString("material_surf", matMc, "SimulationObject","matMc", false ); mShowSurface = mpAttrs->readInt("showsurface", mShowSurface, "SimulationObject","mShowSurface", false ); mShowParticles = mpAttrs->readInt("showparticles", mShowParticles, "SimulationObject","mShowParticles", false ); checkBoundingBox( mGeoStart, mGeoEnd, "SimulationObject::initializeSimulation" ); mpLbm->setLbmInitId( mGeoInitId ); mpLbm->setGeoStart( mGeoStart ); mpLbm->setGeoEnd( mGeoEnd ); mpLbm->setRenderGlobals( mpGlob ); mpLbm->setName( getName() + "_lbm" ); mpLbm->setParticleTracer( mpParts ); if(mpElbeemSettings) { // set further settings from API struct init if(mpElbeemSettings->outputPath) this->mOutFilename = string(mpElbeemSettings->outputPath); mpLbm->initDomainTrafo( mpElbeemSettings->surfaceTrafo ); mpLbm->setSmoothing(1.0 * mpElbeemSettings->surfaceSmoothing, 1.0 * mpElbeemSettings->surfaceSmoothing); mpLbm->setIsoSubdivs(mpElbeemSettings->surfaceSubdivs); mpLbm->setSizeX(mpElbeemSettings->resolutionxyz); mpLbm->setSizeY(mpElbeemSettings->resolutionxyz); mpLbm->setSizeZ(mpElbeemSettings->resolutionxyz); mpLbm->setPreviewSize(mpElbeemSettings->previewresxyz); mpLbm->setRefinementDesired(mpElbeemSettings->maxRefine); mpLbm->setGenerateParticles(mpElbeemSettings->generateParticles); // set initial particles mpParts->setNumInitialParticles(mpElbeemSettings->numTracerParticles); // surface generation flag mpLbm->setSurfGenSettings(mpElbeemSettings->mFsSurfGenSetting); string dinitType = string("no"); if (mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_PARTSLIP) dinitType = string("part"); else if(mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_FREESLIP) dinitType = string("free"); else /*if(mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_NOSLIP)*/ dinitType = string("no"); mpLbm->setDomainBound(dinitType); mpLbm->setDomainPartSlip(mpElbeemSettings->domainobsPartslip); mpLbm->setDumpVelocities(mpElbeemSettings->generateVertexVectors); mpLbm->setFarFieldSize(mpElbeemSettings->farFieldSize); debMsgStd("SimulationObject::initialize",DM_MSG,"Added domain bound: "<<dinitType<<" ps="<<mpElbeemSettings->domainobsPartslip<<" vv"<<mpElbeemSettings->generateVertexVectors<<","<<mpLbm->getDumpVelocities(), 9 ); debMsgStd("SimulationObject::initialize",DM_MSG,"Set ElbeemSettings values "<<mpLbm->getGenerateParticles(),10); } if(! mpLbm->initializeSolverMemory() ) { errMsg("SimulationObject::initialize","initializeSolverMemory failed"); mPanic=true; return 10; } if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverMemory status"); mPanic=true; return 11; } if(! mpLbm->initializeSolverGrids() ) { errMsg("SimulationObject::initialize","initializeSolverGrids failed"); mPanic=true; return 12; } if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverGrids status"); mPanic=true; return 13; } if(! mpLbm->initializeSolverPostinit() ) { errMsg("SimulationObject::initialize","initializeSolverPostin failed"); mPanic=true; return 14; } if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverPostin status"); mPanic=true; return 15; } // print cell type stats bool printStats = true; if(glob_mpnum>0) printStats=false; // skip in this case if(printStats) { const int jmax = sizeof(CellFlagType)*8; int totalCells = 0; int flagCount[jmax]; for(int j=0; j<jmax ; j++) flagCount[j] = 0; int diffInits = 0; LbmSolverInterface::CellIdentifier cid = mpLbm->getFirstCell(); for(; mpLbm->noEndCell( cid ); mpLbm->advanceCell( cid ) ) { int flag = mpLbm->getCellFlag(cid,0); int flag2 = mpLbm->getCellFlag(cid,1); if(flag != flag2) { diffInits++; } for(int j=0; j<jmax ; j++) { if( flag&(1<<j) ) flagCount[j]++; } totalCells++; } mpLbm->deleteCellIterator( &cid ); char charNl = '\n'; debugOutNnl("SimulationObject::initializeLbmSimulation celltype stats: " <<charNl, 5); debugOutNnl("no. of cells = "<<totalCells<<", "<<charNl ,5); for(int j=0; j<jmax ; j++) { std::ostringstream out; if(flagCount[j]>0) { out<<"\t" << flagCount[j] <<" x "<< convertCellFlagType2String( (CellFlagType)(1<<j) ) <<", " << charNl; debugOutNnl(out.str(), 5); } } // compute dist. of empty/bnd - fluid - if // cfEmpty = (1<<0), cfBnd = (1<< 2), cfFluid = (1<<10), cfInter = (1<<11), if(1){ std::ostringstream out; out.precision(2); out.width(4); int totNum = flagCount[1]+flagCount[2]+flagCount[7]+flagCount[8]; double ebFrac = (double)(flagCount[1]+flagCount[2]) / totNum; double flFrac = (double)(flagCount[7]) / totNum; double ifFrac = (double)(flagCount[8]) / totNum; //??? out<<"\tFractions: [empty/bnd - fluid - interface - ext. if] = [" << ebFrac<<" - " << flFrac<<" - " << ifFrac<<"] "<< charNl; if(diffInits > 0) { debMsgStd("SimulationObject::initializeLbmSimulation",DM_MSG,"celltype Warning: Diffinits="<<diffInits<<"!" , 5); } debugOutNnl(out.str(), 5); } } // cellstats // might be modified by mpLbm //mpParts->setStart( mGeoStart );? mpParts->setEnd( mGeoEnd );? mpParts->setStart( mpLbm->getGeoStart() ); mpParts->setEnd( mpLbm->getGeoEnd() ); mpParts->setCastShadows( false ); mpParts->setReceiveShadows( false ); mpParts->searchMaterial( glob->getMaterials() ); // this has to be inited here - before, the values might be unknown IsoSurface *surf = mpLbm->getSurfaceGeoObj(); if(surf) { surf->setName( "final" ); // final surface mesh // warning - this might cause overwriting effects for multiple sims and geom dump... surf->setCastShadows( true ); surf->setReceiveShadows( false ); surf->searchMaterial( glob->getMaterials() ); if(mShowSurface) mObjects.push_back( surf ); } #ifdef ELBEEM_PLUGIN mShowParticles=1; // for e.g. dumping #endif // ELBEEM_PLUGIN if((mpLbm->getGenerateParticles()>0.0)||(mpParts->getNumInitialParticles()>0)) { mShowParticles=1; mpParts->setDumpParts(true); } //debMsgStd("SimulationObject::init",DM_NOTIFY,"Using envvar ELBEEM_DUMPPARTICLE to set mShowParticles, DEBUG!",1); //} // DEBUG ENABLE!!!!!!!!!! if(mShowParticles) { mObjects.push_back(mpParts); } // add objects to display for debugging (e.g. levelset particles) vector<ntlGeometryObject *> debugObjs = mpLbm->getDebugObjects(); for(size_t i=0;i<debugObjs.size(); i++) { debugObjs[i]->setCastShadows( false ); debugObjs[i]->setReceiveShadows( false ); debugObjs[i]->searchMaterial( glob->getMaterials() ); mObjects.push_back( debugObjs[i] ); debMsgStd("SimulationObject::init",DM_NOTIFY,"Added debug obj "<<debugObjs[i]->getName(), 10 ); } return 0; }
/****************************************************************************** * advance simulations by time t *****************************************************************************/ int ntlWorld::advanceSims(int framenum) { bool done = false; bool allPanic = true; // stop/quit, dont display/render if(getElbeemState()==SIMWORLD_STOP) { return 1; } for(size_t i=0;i<mpSims->size();i++) { (*mpSims)[i]->setFrameNum(framenum); } double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getFrameTime(framenum); // time stopped? nothing else to do... if( (*mpSims)[mFirstSim]->getFrameTime(framenum) <= 0.0 ){ done=true; allPanic=false; } int gstate = 0; myTime_t advsstart = getTime(); // step all the sims, and check for panic debMsgStd("ntlWorld::advanceSims",DM_MSG, " sims "<<mpSims->size()<<" t"<<targetTime<<" done:"<<done<<" panic:"<<allPanic<<" gstate:"<<gstate, 10); // debug // timedebug while(!done) { double nextTargetTime = (*mpSims)[mFirstSim]->getCurrentTime() + (*mpSims)[mFirstSim]->getTimestep(); singleStepSims(nextTargetTime); // check target times done = true; allPanic = false; if((*mpSims)[mFirstSim]->getTimestep() <1e-9 ) { // safety check, avoid timesteps that are too small errMsg("ntlWorld::advanceSims","Invalid time step, causing panic! curr:"<<(*mpSims)[mFirstSim]->getCurrentTime()<<" next:"<<nextTargetTime<<", stept:"<< (*mpSims)[mFirstSim]->getTimestep() ); allPanic = true; } else { for(size_t i=0;i<mpSims->size();i++) { if(!(*mpSims)[i]->getVisible()) continue; if((*mpSims)[i]->getPanic()) allPanic = true; // do any panic now!? debMsgStd("ntlWorld::advanceSims",DM_MSG, "Sim "<<i<<", currt:"<<(*mpSims)[i]->getCurrentTime()<<", nt:"<<nextTargetTime<<", panic:"<<(*mpSims)[i]->getPanic()<<", targett:"<<targetTime, 10); // debug // timedebug } } if( (targetTime - (*mpSims)[mFirstSim]->getCurrentTime()) > LBM_TIME_EPSILON) done=false; if(allPanic) done = true; } if(allPanic) { warnMsg("ntlWorld::advanceSims","All sims panicked... stopping thread" ); setStopRenderVisualization( true ); return 1; } myTime_t advsend = getTime(); debMsgStd("ntlWorld::advanceSims",DM_MSG,"Overall steps so far took:"<< getTimeString(advsend-advsstart)<<" for sim time "<<targetTime, 4); // finish step for(size_t i=0;i<mpSims->size();i++) { SimulationObject *sim = (*mpSims)[i]; if(!sim->getVisible()) continue; if(sim->getPanic()) continue; sim->prepareVisualization(); } return 0; }
/****************************************************************************** * Render the current scene * uses the global variables from the parser *****************************************************************************/ int ntlWorld::renderScene( void ) { #ifndef ELBEEM_PLUGIN char nrStr[5]; // nr conversion std::ostringstream outfn_conv(""); // converted ppm with other suffix ntlRenderGlobals *glob; // storage for global rendering parameters myTime_t timeStart,totalStart,timeEnd; // measure user running time myTime_t rendStart,rendEnd; // measure user rendering time glob = mpGlob; // deactivate for all with index!=0 if((glob_mpactive)&&(glob_mpindex>0)) return(0); /* check if picture already exists... */ if(!glob->getSingleFrameMode() ) { snprintf(nrStr, 5, "%04d", glob->getAniCount() ); if(glob_mpactive) { outfn_conv << glob->getOutFilename() <<"_"<<glob_mpindex<<"_" << nrStr << ".png"; /// DEBUG! } else { // ORG outfn_conv << glob->getOutFilename() <<"_" << nrStr << ".png"; } //if((mpGlob->getDisplayMode() == DM_RAY)&&(mpGlob->getFrameSkip())) { if(mpGlob->getFrameSkip()) { struct stat statBuf; if(stat(outfn_conv.str().c_str(),&statBuf) == 0) { errorOut("ntlWorld::renderscene Warning: file "<<outfn_conv.str()<<" already exists - skipping frame..."); glob->setAniCount( glob->getAniCount() +1 ); return(2); } } // RAY mode } else { // single frame rendering, overwrite if necessary... outfn_conv << glob->getSingleFrameFilename(); } /* start program */ timeStart = getTime(); /* build scene geometry, calls buildScene(t,false) */ glob->getRenderScene()->prepareScene(mSimulationTime); /* start program */ totalStart = getTime(); /* view parameters are currently not animated */ /* calculate rays through projection plane */ ntlVec3Gfx direction = glob->getLookat() - glob->getEye(); /* calculate width of screen using perpendicular triangle diven by * viewing direction and screen plane */ gfxReal screenWidth = norm(direction)*tan( (glob->getFovy()*0.5/180.0)*M_PI ); /* calculate vector orthogonal to up and viewing direction */ ntlVec3Gfx upVec = glob->getUpVec(); ntlVec3Gfx rightVec( cross(upVec,direction) ); normalize(rightVec); /* calculate screen plane up vector, perpendicular to viewdir and right vec */ upVec = ntlVec3Gfx( cross(rightVec,direction) ); normalize(upVec); /* check if vectors are valid */ if( (equal(upVec,ntlVec3Gfx(0.0))) || (equal(rightVec,ntlVec3Gfx(0.0))) ) { errMsg("ntlWorld::renderScene","Invalid viewpoint vectors! up="<<upVec<<" right="<<rightVec); return(1); } /* length from center to border of screen plane */ rightVec *= (screenWidth*glob->getAspect() * -1.0); upVec *= (screenWidth * -1.0); /* screen traversal variables */ ntlVec3Gfx screenPos; /* current position on virtual screen */ int Xres = glob->getResX(); /* X resolution */ int Yres = glob->getResY(); /* Y resolution */ ntlVec3Gfx rightStep = (rightVec/(Xres/2.0)); /* one step right for a pixel */ ntlVec3Gfx upStep = (upVec/(Yres/2.0)); /* one step up for a pixel */ /* anti alias init */ char showAAPic = 0; int aaDepth = glob->getAADepth(); int aaLength; if(aaDepth>=0) aaLength = (2<<aaDepth); else aaLength = 0; float aaSensRed = 0.1; float aaSensGreen = 0.1; float aaSensBlue = 0.1; int aaArrayX = aaLength*Xres+1; int aaArrayY = ( aaLength+1 ); ntlColor *aaCol = new ntlColor[ aaArrayX*aaArrayY ]; char *aaUse = new char[ aaArrayX*aaArrayY ]; /* picture storage */ int picX = Xres; int picY = Yres; if(showAAPic) { picX = Xres *aaLength+1; picY = Yres *aaLength+1; } ntlColor *finalPic = new ntlColor[picX * picY]; /* reset picture vars */ for(int j=0;j<aaArrayY;j++) { for(int i=0;i<aaArrayX;i++) { aaCol[j*aaArrayX+i] = ntlColor(0.0, 0.0, 0.0); aaUse[j*aaArrayX+i] = 0; } } for(int j=0;j<picY;j++) { for(int i=0;i<picX;i++) { finalPic[j*picX+i] = ntlColor(0.0, 0.0, 0.0); } } /* loop over all y lines in screen, from bottom to top because * ppm format wants 0,0 top left */ rendStart = getTime(); glob->setCounterShades(0); glob->setCounterSceneInter(0); for (int scanline=Yres ; scanline > 0 ; --scanline) { debugOutInter( "ntlWorld::renderScene: Line "<<scanline<< " ("<< ((Yres-scanline)*100/Yres) <<"%) ", 2, 2000 ); screenPos = glob->getLookat() + upVec*((2.0*scanline-Yres)/Yres) - rightVec; /* loop over all pixels in line */ for (int sx=0 ; sx < Xres ; ++sx) { if((sx==glob->getDebugPixelX())&&(scanline==(Yres-glob->getDebugPixelY()) )) { // DEBUG!!! glob->setDebugOut(10); } else glob->setDebugOut(0); /* compute ray from eye through current pixel into scene... */ ntlColor col; if(aaDepth<0) { ntlVec3Gfx dir(screenPos - glob->getEye()); ntlRay the_ray(glob->getEye(), getNormalized(dir), 0, 1.0, glob ); /* ...and trace it */ col = the_ray.shade(); } else { /* anti alias */ int ai,aj; /* position in grid */ int aOrg = sx*aaLength; /* grid offset x */ int currStep = aaLength; /* step size */ char colDiff = 1; /* do colors still differ too much? */ ntlColor minCol,maxCol; /* minimum and maximum Color Values */ minCol = ntlColor(1.0,1.0,1.0); maxCol = ntlColor(0.0,0.0,0.0); while((colDiff) && (currStep>0)) { colDiff = 0; for(aj = 0;aj<=aaLength;aj+= currStep) { for(ai = 0;ai<=aaLength;ai+= currStep) { /* shade pixel if not done */ if(aaUse[aj*aaArrayX +ai +aOrg] == 0) { aaUse[aj*aaArrayX +ai +aOrg] = 1; ntlVec3Gfx aaPos( screenPos + (rightStep * (ai- aaLength/2)/(gfxReal)aaLength ) + (upStep * (aj- aaLength/2)/(gfxReal)aaLength ) ); ntlVec3Gfx dir(aaPos - glob->getEye()); ntlRay the_ray(glob->getEye(), getNormalized(dir), 0, 1.0, glob ); /* ...and trace it */ ntlColor newCol= the_ray.shade(); aaCol[aj*aaArrayX +ai +aOrg]= newCol; } /* not used? */ } } /* check color differences */ for(aj = 0;aj<aaLength;aj+= currStep) { for(ai = 0;ai<aaLength;ai+= currStep) { char thisColDiff = 0; if( (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] - aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][0])> aaSensRed ) || (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] - aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][1])> aaSensGreen ) || (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] - aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][2])> aaSensBlue ) ) { thisColDiff = 1; } else if( (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] - aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][0])> aaSensRed ) || (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] - aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][1])> aaSensGreen ) || (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] - aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][2])> aaSensBlue ) ) { thisColDiff = 1; } else if( (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] - aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][0])> aaSensRed ) || (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] - aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][1])> aaSensGreen ) || (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] - aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][2])> aaSensBlue ) ) { thisColDiff = 1; } //colDiff =1; if(thisColDiff) { /* set diff flag */ colDiff = thisColDiff; for(int bj=aj;bj<=aj+currStep;bj++) { for(int bi=ai;bi<=ai+currStep;bi++) { if(aaUse[bj*aaArrayX +bi +aOrg]==2) { //if(showAAPic) aaUse[bj*aaArrayX +bi +aOrg] = 0; } } } } else { /* set all values */ ntlColor avgCol = ( aaCol[(aj+0 )*aaArrayX +(ai+0 ) +aOrg] + aaCol[(aj+0 )*aaArrayX +(ai+currStep) +aOrg] + aaCol[(aj+currStep)*aaArrayX +(ai+0 ) +aOrg] + aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg] ) *0.25; for(int bj=aj;bj<=aj+currStep;bj++) { for(int bi=ai;bi<=ai+currStep;bi++) { if(aaUse[bj*aaArrayX +bi +aOrg]==0) { aaCol[bj*aaArrayX +bi +aOrg] = avgCol; aaUse[bj*aaArrayX +bi +aOrg] = 2; } } } } /* smaller values set */ } } /* half step size */ currStep /= 2; } /* repeat until diff not too big */ /* get average color */ gfxReal colNum = 0.0; col = ntlColor(0.0, 0.0, 0.0); for(aj = 0;aj<=aaLength;aj++) { for(ai = 0;ai<=aaLength;ai++) { col += aaCol[aj*aaArrayX +ai +aOrg]; colNum += 1.0; } } col /= colNum; } /* mark pixels with debugging */ if( glob->getDebugOut() > 0) col = ntlColor(0,1,0); /* store pixel */ if(!showAAPic) { finalPic[(scanline-1)*picX+sx] = col; } screenPos += rightStep; } /* foreach x */ /* init aa array */ if(showAAPic) { for(int j=0;j<=aaArrayY-1;j++) { for(int i=0;i<=aaArrayX-1;i++) { if(aaUse[j*aaArrayX +i]==1) finalPic[((scanline-1)*aaLength +j)*picX+i][0] = 1.0; } } } for(int i=0;i<aaArrayX;i++) { aaCol[(aaArrayY-1)*aaArrayX+i] = aaCol[0*aaArrayX+i]; aaUse[(aaArrayY-1)*aaArrayX+i] = aaUse[0*aaArrayX+i]; } for(int j=0;j<aaArrayY-1;j++) { for(int i=0;i<aaArrayX;i++) { aaCol[j*aaArrayX+i] = ntlColor(0.0, 0.0, 0.0); aaUse[j*aaArrayX+i] = 0; } } } /* foreach y */ rendEnd = getTime(); /* write png file */ { int w = picX; int h = picY; unsigned rowbytes = w*4; unsigned char *screenbuf, **rows; screenbuf = (unsigned char*)malloc( h*rowbytes ); rows = (unsigned char**)malloc( h*sizeof(unsigned char*) ); unsigned char *filler = screenbuf; // cutoff color values 0..1 for(int j=0;j<h;j++) { for(int i=0;i<w;i++) { ntlColor col = finalPic[j*w+i]; for (unsigned int cc=0; cc<3; cc++) { if(col[cc] <= 0.0) col[cc] = 0.0; if(col[cc] >= 1.0) col[cc] = 1.0; } *filler = (unsigned char)( col[0]*255.0 ); filler++; *filler = (unsigned char)( col[1]*255.0 ); filler++; *filler = (unsigned char)( col[2]*255.0 ); filler++; *filler = (unsigned char)( 255.0 ); filler++; // alpha channel } } for(int i = 0; i < h; i++) rows[i] = &screenbuf[ (h - i - 1)*rowbytes ]; writePng(outfn_conv.str().c_str(), rows, w, h); } // next frame glob->setAniCount( glob->getAniCount() +1 ); // done timeEnd = getTime(); char resout[1024]; snprintf(resout,1024, "NTL Done %s, frame %d/%d (took %s scene, %s raytracing, %s total, %d shades, %d i.s.'s)!\n", outfn_conv.str().c_str(), (glob->getAniCount()), (glob->getAniFrames()+1), getTimeString(totalStart-timeStart).c_str(), getTimeString(rendEnd-rendStart).c_str(), getTimeString(timeEnd-timeStart).c_str(), glob->getCounterShades(), glob->getCounterSceneInter() ); debMsgStd("ntlWorld::renderScene",DM_MSG, resout, 1 ); /* clean stuff up */ delete [] aaCol; delete [] aaUse; delete [] finalPic; glob->getRenderScene()->cleanupScene(); if(mpGlob->getSingleFrameMode() ) { debMsgStd("ntlWorld::renderScene",DM_NOTIFY, "Single frame mode done...", 1 ); return 1; } #endif // ELBEEM_PLUGIN return 0; }
ParticleTracer::~ParticleTracer() { debMsgStd("ParticleTracer::~ParticleTracer",DM_MSG,"destroyed",10); }
//ntlTree::ntlTree(int depth, int objnum, vector<ntlVec3Gfx> *vertices, vector<ntlVec3Gfx> *normals, vector<ntlTriangle> *trilist) : ntlTree::ntlTree(int depth, int objnum, ntlScene *scene, int triFlagMask) : mStart(0.0), mEnd(0.0), mMaxDepth( depth ), mMaxListLength( objnum ), mpRoot( NULL) , mpNodeStack( NULL), mpTBB( NULL ), mTriangleMask( 0xFFFF ), mCurrentDepth(0), mCurrentNodes(0), mTriDoubles(0) { // init scene data pointers mpVertices = scene->getVertexPointer(); mpVertNormals = scene->getVertexNormalPointer(); mpTriangles = scene->getTrianglePointer(); mTriangleMask = triFlagMask; if(mpTriangles == NULL) { errFatal( "ntlTree Cons","no triangle list!\n",SIMWORLD_INITERROR); return; } if(mpTriangles->size() == 0) { warnMsg( "ntlTree::ntlTree","No triangles ("<< mpTriangles->size() <<")!\n"); mStart = mEnd = ntlVec3Gfx(0,0,0); return; } if(depth>=BSP_STACK_SIZE) { errFatal( "ntlTree::ntlTree","Depth to high ("<< mMaxDepth <<")!\n", SIMWORLD_INITERROR ); return; } /* check triangles (a bit inefficient, but we dont know which vertices belong to this tree), and generate bounding boxes */ mppTriangles = new vector<ntlTriangle *>; int noOfTriangles = mpTriangles->size(); mpTBB = new TriangleBBox[ noOfTriangles ]; int bbCount = 0; mStart = mEnd = (*mpVertices)[ mpTriangles->front().getPoints()[0] ]; //errMsg("TreeDebug","Start"); for (vector<ntlTriangle>::iterator iter = mpTriangles->begin(); iter != mpTriangles->end(); iter++ ) { //errorOut(" d "<< convertFlags2String((int)(*iter).getFlags()) <<" "<< convertFlags2String( (int)mTriangleMask)<<" add? "<<( ((int)(*iter).getFlags() & (int)mTriangleMask) != 0 ) ); // discard triangles that dont match mask if( ((int)(*iter).getFlags() & (int)mTriangleMask) == 0 ) { continue; } // test? TODO ntlVec3Gfx tnormal = (*mpVertNormals)[ (*iter).getPoints()[0] ]+ (*mpVertNormals)[ (*iter).getPoints()[1] ]+ (*mpVertNormals)[ (*iter).getPoints()[2] ]; ntlVec3Gfx triangleNormal = (*iter).getNormal(); if( equal(triangleNormal, ntlVec3Gfx(0.0)) ) continue; if( equal( tnormal, ntlVec3Gfx(0.0)) ) continue; // */ ntlVec3Gfx bbs, bbe; //errMsg("TreeDebug","Triangle"); for(int i=0;i<3;i++) { int index = (*iter).getPoints()[i]; ntlVec3Gfx tp = (*mpVertices)[ index ]; //errMsg("TreeDebug"," Point "<<i<<" = "<<tp<<" "); if(tp[0] < mStart[0]) mStart[0]= tp[0]; if(tp[0] > mEnd[0]) mEnd[0]= tp[0]; if(tp[1] < mStart[1]) mStart[1]= tp[1]; if(tp[1] > mEnd[1]) mEnd[1]= tp[1]; if(tp[2] < mStart[2]) mStart[2]= tp[2]; if(tp[2] > mEnd[2]) mEnd[2]= tp[2]; if(i==0) { bbs = bbe = tp; } else { if( tp[0] < bbs[0] ) bbs[0] = tp[0]; if( tp[0] > bbe[0] ) bbe[0] = tp[0]; if( tp[1] < bbs[1] ) bbs[1] = tp[1]; if( tp[1] > bbe[1] ) bbe[1] = tp[1]; if( tp[2] < bbs[2] ) bbs[2] = tp[2]; if( tp[2] > bbe[2] ) bbe[2] = tp[2]; } } mppTriangles->push_back( &(*iter) ); //errMsg("TreeDebug","Triangle "<<(*mpVertices)[(*iter).getPoints()[0]]<<" "<<(*mpVertices)[(*iter).getPoints()[1]]<<" "<<(*mpVertices)[(*iter).getPoints()[2]]<<" "); // add BB mpTBB[ bbCount ].start = bbs; mpTBB[ bbCount ].end = bbe; (*iter).setBBoxId( bbCount ); bbCount++; } /* slighlty enlarge bounding tolerance for tree to avoid problems with triangles paralell to slabs */ mStart -= ntlVec3Gfx( getVecEpsilon() ); mEnd += ntlVec3Gfx( getVecEpsilon() ); /* init root node and stack */ mpNodeStack = new BSPStack; mpRoot = new BSPNode; mpRoot->min = mStart; mpRoot->max = mEnd; mpRoot->axis = AXIS_X; mpRoot->members = mppTriangles; mpRoot->child[0] = mpRoot->child[1] = NULL; mpRoot->cloneVec = 0; globalSortingPoints = mpVertices; mpTriDist = new char[ mppTriangles->size() ]; mNumNodes = 1; mAbortSubdiv = 0; /* create tree */ debugOutInter( "Generating BSP Tree... (Nodes "<< mCurrentNodes << ", Depth "<<mCurrentDepth<< ") ", 2, 2000 ); subdivide(mpRoot, 0, AXIS_X); debMsgStd("ntlTree::ntlTree",DM_MSG,"Generated Tree: Nodes "<< mCurrentNodes << ", Depth "<<mCurrentDepth<< " with "<<noOfTriangles<<" triangles", 2 ); delete [] mpTriDist; delete [] mpTBB; mpTriDist = NULL; mpTBB = NULL; /* calculate some stats about tree */ int noLeafs = 0; gfxReal avgDepth = 0.0; gfxReal triPerLeaf = 0.0; int totalTris = 0; calcStats(mpRoot,0, noLeafs, avgDepth, triPerLeaf, totalTris); avgDepth /= (gfxReal)noLeafs; triPerLeaf /= (gfxReal)noLeafs; debMsgStd("ntlTree::ntlTree",DM_MSG,"Tree ("<<doSort<<","<<chooseAxis<<") Stats: Leafs:"<<noLeafs<<", avgDepth:"<<avgDepth<< ", triPerLeaf:"<<triPerLeaf<<", triDoubles:"<<mTriDoubles<<", totalTris:"<<totalTris <<" nodes:"<<mNumNodes //<<" T"<< (totalTris%3) // 0=ich, 1=f, 2=a , 2 ); if(mAbortSubdiv) { errMsg("ntlTree::ntlTree","Aborted... "<<mNumNodes); deleteNode(mpRoot); mpRoot = NULL; } }