initial commit of the fluid simulator.
[blender.git] / intern / elbeem / intern / ntl_raytracer.cpp
1 /******************************************************************************
2  *
3  * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
4  * Copyright 2003,2004 Nils Thuerey
5  *
6  * Main renderer class
7  *
8  *****************************************************************************/
9
10
11 #include <sys/stat.h>
12 #include <sstream>
13 #include "utilities.h"
14 #include "ntl_raytracer.h"
15 #include "ntl_scene.h"
16 #include "parametrizer.h"
17 #include "globals.h"
18
19 // for non-threaded renderViz
20 #ifndef NOGUI
21 #include "../gui/ntl_openglrenderer.h"
22 #include "../gui/guifuncs.h"
23 #include "../gui/frame.h"
24 #endif
25
26
27 /* external parser functions from cfgparser.cxx */
28 //#include "cfgparse_functions.h"
29
30 /* parse given file as config file */
31 void parseFile(string filename);
32
33 /* set pointers for parsing */
34 void setPointers( ntlRenderGlobals *setglob);
35
36
37 /******************************************************************************
38  * Constructor
39  *****************************************************************************/
40 ntlRaytracer::ntlRaytracer(string filename, bool commandlineMode) :
41         mpGlob(NULL), 
42   mpLightList(NULL), mpPropList(NULL), mpSims(NULL),
43         mpOpenGLRenderer(NULL),
44         mStopRenderVisualization( false ),
45         mThreadRunning( false ), 
46         mSimulationTime(0.0), mFirstSim(-1),
47         mSingleStepDebug( false )
48 {
49   /* create scene storage */
50   mpGlob = new ntlRenderGlobals();
51   mpLightList = new vector<ntlLightObject*>;
52   mpPropList = new vector<ntlMaterial*>;
53   mpSims = new vector<SimulationObject*>;
54
55   mpGlob->setLightList(mpLightList);
56   mpGlob->setMaterials(mpPropList);
57   mpGlob->setSims(mpSims);
58
59         /* init default material */
60   ntlMaterial *def = GET_GLOBAL_DEFAULT_MATERIAL;
61         mpPropList->push_back( def );
62
63         /* init the scene object */
64         ntlScene *scene;
65         scene = new ntlScene( mpGlob );
66         mpGlob->setScene( scene );
67
68         // load config
69   setPointers( getRenderGlobals() );
70   parseFile( filename.c_str() );
71         
72
73         // init the scene for the first time
74   long startTime = getTime();
75         scene->buildScene();
76         long stopTime = getTime();
77         debMsgStd("ntlRaytracer::ntlRaytracer",DM_MSG,"Scene build time: "<< getTimeString(stopTime-startTime) <<" ", 10);
78
79         // TODO check simulations, run first steps
80         mFirstSim = -1;
81         if(mpSims->size() > 0) {
82
83                 // use values from first simulation as master time scale
84                 long startTime = getTime();
85                 
86                 // remember first active sim
87                 for(size_t i=0;i<mpSims->size();i++) {
88                         if(!(*mpSims)[i]->getVisible()) continue;
89                         if((*mpSims)[i]->getPanic())    continue;
90
91                         // check largest timestep
92                         if(mFirstSim>=0) {
93                                 if( (*mpSims)[i]->getStepTime() > (*mpSims)[mFirstSim]->getStepTime() ) {
94                                         mFirstSim = i;
95                                         debMsgStd("ntlRaytracer::ntlRaytracer",DM_MSG,"First Sim changed: "<<i ,10);
96                                 }
97                         }
98                         // check any valid sim
99                         if(mFirstSim<0) {
100                                 mFirstSim = i;
101                                 debMsgStd("ntlRaytracer::ntlRaytracer",DM_MSG,"First Sim: "<<i ,10);
102                         }
103                 }
104
105                 if(mFirstSim>=0) {
106                         debMsgStd("ntlRaytracer::ntlRaytracer",DM_MSG,"Anistart Time: "<<(*mpSims)[mFirstSim]->getStartTime() ,10);
107                         while(mSimulationTime < (*mpSims)[mFirstSim]->getStartTime() ) {
108                         debMsgStd("ntlRaytracer::ntlRaytracer",DM_MSG,"Anistart Time: "<<(*mpSims)[mFirstSim]->getStartTime()<<" simtime:"<<mSimulationTime ,10);
109                                 advanceSims();
110                         }
111                         long stopTime = getTime();
112
113                         mSimulationTime += (*mpSims)[mFirstSim]->getStartTime();
114                         debMsgStd("ntlRaytracer::ntlRaytracer",DM_MSG,"Time for start simulations times "<<": "<< getTimeString(stopTime-startTime) <<"s ", 1);
115 #ifndef NOGUI
116                         guiResetSimulationTimeRange( mSimulationTime );
117 #endif
118                 } else {
119                         if(!mpGlob->getSingleFrameMode()) debMsgStd("ntlRaytracer::ntlRaytracer",DM_WARNING,"No active simulations!", 1);
120                 }
121         }
122
123 #ifndef NOGUI
124         // setup opengl display, save first animation step for start time 
125         if(!commandlineMode) {
126                 mpOpenGLRenderer = new ntlOpenGLRenderer( mpGlob, scene );
127         }
128 #else // NOGUI
129         commandlineMode = true; // remove warning...
130 #endif // NOGUI
131 }
132
133
134
135 /******************************************************************************
136  * Destructor
137  *****************************************************************************/
138 ntlRaytracer::~ntlRaytracer()
139 {
140         delete mpGlob->getScene();
141   delete mpGlob;
142   delete mpLightList;
143   delete mpPropList;
144   delete mpSims;
145 #ifndef NOGUI
146         if(mpOpenGLRenderer) delete mpOpenGLRenderer;
147 #endif // NOGUI
148 }
149
150 /******************************************************************************/
151 /*! set single frame rendering to filename */
152 void ntlRaytracer::setSingleFrameOut(string singleframeFilename) {
153         mpGlob->setSingleFrameMode(true);
154         mpGlob->setSingleFrameFilename(singleframeFilename);
155 }
156
157 /******************************************************************************
158  * render a whole animation (command line mode) 
159  *****************************************************************************/
160 #if ELBEEM_BLENDER==1
161 extern "C" {
162         void simulateThreadIncreaseFrame(void);
163 }
164 #endif // ELBEEM_BLENDER==1
165 int ntlRaytracer::renderAnimation( void )
166 {
167         // only single pic currently
168         //debMsgStd("ntlRaytracer::renderAnimation : Warning only simulating...",1);
169         if(mpGlob->getAniFrames() < 0) {
170                 debMsgStd("ntlRaytracer::renderAnimation",DM_NOTIFY,"No frames to render... ",1);
171                 return 1;
172         }
173
174         if(mFirstSim<0) {
175                 debMsgStd("ntlRaytracer::renderAnimation",DM_NOTIFY,"No reference animation found...",1);
176                 return 1;
177         } 
178
179         mThreadRunning = true; // not threaded, but still use the same flags
180         renderScene();
181         for(int i=0; ((i<mpGlob->getAniFrames()) && (!getStopRenderVisualization() )); i++) {
182                 advanceSims();
183                 renderScene();
184 #if ELBEEM_BLENDER==1
185                 // update gui display
186                 simulateThreadIncreaseFrame();
187 #endif // ELBEEM_BLENDER==1
188
189                 if(mpSims->size() <= 0) {
190                         debMsgStd("ntlRaytracer::renderAnimation",DM_NOTIFY,"No simulations found, stopping...",1);
191                         return 1;
192                 }
193         }
194         mThreadRunning = false;
195         
196         return 0;
197 }
198
199 /******************************************************************************
200  * render a whole animation (visualization mode) 
201  * this function is run in another thread, and communicates 
202  * with the parent thread via a mutex 
203  *****************************************************************************/
204 int ntlRaytracer::renderVisualization( bool multiThreaded ) 
205 {
206 #ifndef NOGUI
207         //gfxReal deltat = 0.0015;
208         if(multiThreaded) mThreadRunning = true;
209         while(!getStopRenderVisualization()) {
210
211                 if(mpSims->size() <= 0) {
212                         debMsgStd("ntlRaytracer::renderVisualization",DM_NOTIFY,"No simulations found, stopping...",1);
213                         stopSimulationThread();
214                         break;
215                 }
216
217                 // determine stepsize
218                 if(!mSingleStepDebug) {
219                         long startTime = getTime();
220                         advanceSims();
221                         long stopTime = getTime();
222                         debMsgStd("ntlRaytracer::renderVisualization",DM_MSG,"Time for "<<mSimulationTime<<": "<< getTimeString(stopTime-startTime) <<"s ", 10);
223                 } else {
224                         double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getStepTime();
225                         singleStepSims(targetTime);
226
227                         // check paniced sims (normally done by advanceSims
228                         bool allPanic = true;
229                         for(size_t i=0;i<mpSims->size();i++) {
230                                 if(!(*mpSims)[i]->getPanic()) allPanic = false;
231                         }
232                         if(allPanic) {
233                                 warnMsg("ntlRaytracer::advanceSims","All sims panicked... stopping thread" );
234                                 setStopRenderVisualization( true );
235                         }
236                         //? mSimulationTime = (*mpSims)[mFirstSim]->getCurrentTime();
237                         //debMsgStd("ntlRaytracer::renderVisualization : single step mode ", 10);
238                         //debMsgStd("", 10 );
239                 }
240
241 #ifndef NOGUI
242                 // save frame
243                 if(mpOpenGLRenderer) mpOpenGLRenderer->saveAnimationFrame( mSimulationTime );
244 #endif // NOGUI
245                 
246                 // for non-threaded check events
247                 if(!multiThreaded) {
248                         //if(gpElbeemFrame->ElbeemWindow->visible()) {
249                                 //if (!Fl::check()) break;  // returns immediately
250                         //} 
251                         Fl::check();
252       //gpElbeemFrame->SceneDisplay->doIdleRedraw();
253       gpElbeemFrame->SceneDisplay->doOnlyForcedRedraw();
254                 }
255
256         }
257         mThreadRunning = false;
258         stopSimulationRestoreGui();
259 #else 
260         multiThreaded = false; // remove warning
261 #endif
262         return 0;
263 }
264 /*! render a single step for viz mode */
265 int ntlRaytracer::singleStepVisualization( void ) 
266 {
267         mThreadRunning = true;
268         double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getStepTime();
269         singleStepSims(targetTime);
270         mSimulationTime = (*mpSims)[0]->getCurrentTime();
271
272 #ifndef NOGUI
273         if(mpOpenGLRenderer) mpOpenGLRenderer->saveAnimationFrame( mSimulationTime );
274         Fl::check();
275   gpElbeemFrame->SceneDisplay->doOnlyForcedRedraw();
276 #endif // NOGUI
277
278         mThreadRunning = false;
279 #ifndef NOGUI
280         stopSimulationRestoreGui();
281 #endif
282         return 0;
283 }
284
285 // dont use LBM_EPSILON here, time is always double-precision!
286 #define LBM_TIME_EPSILON 1e-10
287
288 /******************************************************************************
289  * advance simulations by time t 
290  *****************************************************************************/
291 int ntlRaytracer::advanceSims()
292 {
293         //gfxReal currTime[ mpSims->size() ]; 
294         
295         bool done = false;
296         bool allPanic = true;
297         double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getFrameTime();
298         //debMsgStd("ntlRaytracer::advanceSims",DM_MSG,"Advancing sims to "<<targetTime, 10 ); // timedebug
299
300         while(!done) {
301                 double nextTargetTime = (*mpSims)[mFirstSim]->getCurrentTime() + (*mpSims)[mFirstSim]->getStepTime();
302                 singleStepSims(nextTargetTime);
303
304                 // check target times
305                 done = true;
306                 allPanic = false;
307                 for(size_t i=0;i<mpSims->size();i++) {
308                         if(!(*mpSims)[i]->getVisible()) continue;
309                         if((*mpSims)[i]->getPanic()) allPanic = true; // do any panic now!?
310                         //debMsgStd("ntlRaytracer::advanceSims",DM_MSG, " sim "<<i<<" c"<<(*mpSims)[i]->getCurrentTime()<<" p"<<(*mpSims)[i]->getPanic()<<" t"<<targetTime, 10); // debug // timedebug
311                 }
312                 //if((*mpSims)[mFirstSim]->getCurrentTime() < targetTime) done = false;
313                 if( (targetTime - (*mpSims)[mFirstSim]->getCurrentTime()) > LBM_TIME_EPSILON) done=false;
314                 if(allPanic) done = true;
315         }
316
317         if(allPanic) {
318                 warnMsg("ntlRaytracer::advanceSims","All sims panicked... stopping thread" );
319                 setStopRenderVisualization( true );
320         }
321         for(size_t i=0;i<mpSims->size();i++) {
322                 SimulationObject *sim = (*mpSims)[i];
323                 if(!sim->getVisible()) continue;
324                 if(sim->getPanic()) continue;
325                 sim->prepareVisualization();
326         }
327
328         return 0;
329 }
330
331 /* advance simulations by a single step */
332 /* dont check target time, if *targetTime==NULL */
333 void ntlRaytracer::singleStepSims(double targetTime) {
334         const bool debugTime = false;
335         //double targetTime = mSimulationTime + (*mpSims)[mFirstSim]->getStepTime();
336         if(debugTime) errMsg("ntlRaytracer::singleStepSims","Target time: "<<targetTime);
337
338         for(size_t i=0;i<mpSims->size();i++) {
339                 SimulationObject *sim = (*mpSims)[i];
340                 if(!sim->getVisible()) continue;
341                 if(sim->getPanic()) continue;
342                 bool done = false;
343                 while(!done) {
344                         // try to prevent round off errs
345                         if(debugTime) errMsg("ntlRaytracer::singleStepSims","Test sim "<<i<<" curt:"<< sim->getCurrentTime()<<" target:"<<targetTime<<" delta:"<<(targetTime - sim->getCurrentTime())<<" stept:"<<sim->getStepTime()<<" leps:"<<LBM_TIME_EPSILON ); // timedebug
346                         if( (targetTime - sim->getCurrentTime()) > LBM_TIME_EPSILON) {
347                                 if(debugTime) errMsg("ntlRaytracer::singleStepSims","Stepping sim "<<i<<" t:"<< sim->getCurrentTime()); // timedebug
348                                 sim->step();
349                         } else {
350                                 done = true;
351                         }
352                 }
353         }
354
355         mSimulationTime = (*mpSims)[mFirstSim]->getCurrentTime();
356 #ifndef NOGUI
357         if(mpOpenGLRenderer) mpOpenGLRenderer->notifyOfNextStep(mSimulationTime);
358 #endif // NOGUI
359 }
360
361
362
363
364 /******************************************************************************
365  * Render the current scene
366  * uses the global variables from the parser
367  *****************************************************************************/
368 int ntlRaytracer::renderScene( void )
369 {
370         char nrStr[5];                                                                                                          /* nr conversion */
371         //std::ostringstream outfilename("");                                     /* ppm file */
372         std::ostringstream outfn_conv("");                                              /* converted ppm with other suffix */
373   ntlRenderGlobals *glob;                       /* storage for global rendering parameters */
374   myTime_t timeStart,totalStart,timeEnd;                /* measure user running time */
375   myTime_t rendStart,rendEnd;                           /* measure user rendering time */
376   glob = mpGlob;
377
378         /* check if picture already exists... */
379         if(!glob->getSingleFrameMode() ) {
380                 snprintf(nrStr, 5, "%04d", glob->getAniCount() );
381                 //outfilename << glob->getOutFilename() <<"_" << nrStr << ".ppm";
382                 outfn_conv  << glob->getOutFilename() <<"_" << nrStr << ".png";
383                 
384                 //if((mpGlob->getDisplayMode() == DM_RAY)&&(mpGlob->getFrameSkip())) {
385                 if(mpGlob->getFrameSkip()) {
386                         struct stat statBuf;
387                         if(stat(outfn_conv.str().c_str(),&statBuf) == 0) {
388                                 errorOut("ntlRaytracer::renderscene Warning: file "<<outfn_conv.str()<<" already exists - skipping frame..."); 
389                                 glob->setAniCount( glob->getAniCount() +1 );
390                                 return(2);
391                         }
392                 } // RAY mode
393         } else {
394                 // single frame rendering, overwrite if necessary...
395                 outfn_conv << glob->getSingleFrameFilename();
396         }
397
398   /* start program */
399         timeStart = getTime();
400
401         /* build scene geometry */
402         glob->getScene()->prepareScene();
403
404   /* start program */
405         totalStart = getTime();
406
407
408         /* view parameters are currently not animated */
409         /* calculate rays through projection plane */
410         ntlVec3Gfx direction = glob->getLookat() - glob->getEye();
411         /* calculate width of screen using perpendicular triangle diven by
412          * viewing direction and screen plane */
413         gfxReal screenWidth = norm(direction)*tan( (glob->getFovy()*0.5/180.0)*M_PI );
414
415         /* calculate vector orthogonal to up and viewing direction */
416         ntlVec3Gfx upVec = glob->getUpVec();
417         ntlVec3Gfx rightVec( cross(upVec,direction) );
418         normalize(rightVec);
419
420         /* calculate screen plane up vector, perpendicular to viewdir and right vec */
421         upVec = ntlVec3Gfx( cross(rightVec,direction) );
422         normalize(upVec);
423
424         /* check if vectors are valid */
425         if( (equal(upVec,ntlVec3Gfx(0.0))) || (equal(rightVec,ntlVec3Gfx(0.0))) ) {
426                 errorOut("NTL ERROR: Invalid viewpoint vectors!\n");
427                 return(1);
428         }
429
430         /* length from center to border of screen plane */
431         rightVec *= (screenWidth*glob->getAspect() * -1.0);
432         upVec *= (screenWidth * -1.0);
433
434         /* screen traversal variables */
435         ntlVec3Gfx screenPos;                          /* current position on virtual screen */
436         int Xres = glob->getResX();                  /* X resolution */
437         int Yres = glob->getResY();                  /* Y resolution */
438         ntlVec3Gfx rightStep = (rightVec/(Xres/2.0));  /* one step right for a pixel */
439         ntlVec3Gfx upStep    = (upVec/(Yres/2.0));     /* one step up for a pixel */
440     
441
442         /* anti alias init */
443         char  showAAPic = 0;
444         int   aaDepth = glob->getAADepth();
445         int   aaLength;
446         if(aaDepth>=0) aaLength = (2<<aaDepth);
447         else           aaLength = 0;
448         float aaSensRed   = 0.1;
449         float aaSensGreen = 0.1;
450         float aaSensBlue  = 0.1;
451         int   aaArrayX = aaLength*Xres+1;
452         int   aaArrayY = ( aaLength+1 );
453         ntlColor *aaCol = new ntlColor[ aaArrayX*aaArrayY ];
454         char  *aaUse = new char[ aaArrayX*aaArrayY ];
455
456         /* picture storage */
457         int picX = Xres;
458         int picY = Yres;
459         if(showAAPic) {
460                 picX = Xres *aaLength+1;
461                 picY = Yres *aaLength+1;
462         }
463         ntlColor *finalPic = new ntlColor[picX * picY];
464
465
466         /* reset picture vars */
467         for(int j=0;j<aaArrayY;j++) {
468                 for(int i=0;i<aaArrayX;i++) {
469                         aaCol[j*aaArrayX+i] = ntlColor(0.0, 0.0, 0.0);
470                         aaUse[j*aaArrayX+i] = 0;
471                 }
472         }
473         for(int j=0;j<picY;j++) {
474                 for(int i=0;i<picX;i++) {
475                         finalPic[j*picX+i] = ntlColor(0.0, 0.0, 0.0);
476                 }
477         }
478
479         /* loop over all y lines in screen, from bottom to top because
480          * ppm format wants 0,0 top left */
481         rendStart = getTime();
482         glob->setCounterShades(0);
483         glob->setCounterSceneInter(0);
484         for (int scanline=Yres ; scanline > 0 ; --scanline) {
485     
486                 debugOutInter( "ntlRaytracer::renderScene: Line "<<scanline<<
487                                                                  " ("<< ((Yres-scanline)*100/Yres) <<"%) ", 2, 2000 );
488                 screenPos = glob->getLookat() + upVec*((2.0*scanline-Yres)/Yres)
489                         - rightVec;
490
491                 /* loop over all pixels in line */
492                 for (int sx=0 ; sx < Xres ; ++sx) {
493
494                         if((sx==glob->getDebugPixelX())&&(scanline==(Yres-glob->getDebugPixelY()) )) {
495                                 // DEBUG!!!
496                                 glob->setDebugOut(10);
497                         } else glob->setDebugOut(0);
498                         
499                         /* compute ray from eye through current pixel into scene... */
500                         ntlColor col;
501                         if(aaDepth<0) {
502                                 ntlVec3Gfx dir(screenPos - glob->getEye());
503                                 ntlRay the_ray(glob->getEye(), getNormalized(dir), 0, 1.0, glob );
504
505                                 /* ...and trace it */
506                                 col = the_ray.shade();
507                         } else {
508                                 /* anti alias */
509                                 int ai,aj;                   /* position in grid */
510                                 int aOrg = sx*aaLength;      /* grid offset x */
511                                 int currStep = aaLength;     /* step size */
512                                 char colDiff = 1;            /* do colors still differ too much? */
513                                 ntlColor minCol,maxCol;         /* minimum and maximum Color Values */
514                                 minCol = ntlColor(1.0,1.0,1.0);
515                                 maxCol = ntlColor(0.0,0.0,0.0);
516
517                                 while((colDiff) && (currStep>0)) {
518                                         colDiff = 0;
519             
520                                         for(aj = 0;aj<=aaLength;aj+= currStep) {
521                                                 for(ai = 0;ai<=aaLength;ai+= currStep) {
522
523                                                         /* shade pixel if not done */
524                                                         if(aaUse[aj*aaArrayX +ai +aOrg] == 0) {
525                                                                 aaUse[aj*aaArrayX +ai +aOrg] = 1;
526                                                                 ntlVec3Gfx aaPos( screenPos +
527                                                                                                                                 (rightStep * (ai- aaLength/2)/(gfxReal)aaLength ) +
528                                                                                                                                 (upStep    * (aj- aaLength/2)/(gfxReal)aaLength ) );
529
530                                                                 ntlVec3Gfx dir(aaPos - glob->getEye());
531                                                                 ntlRay the_ray(glob->getEye(), getNormalized(dir), 0, 1.0, glob );
532
533                                                                 /* ...and trace it */
534                                                                 ntlColor newCol= the_ray.shade();
535                                                                 aaCol[aj*aaArrayX +ai +aOrg]= newCol;
536                                                         } /* not used? */
537
538                                                 }
539                                         }
540
541                                         /* check color differences */
542                                         for(aj = 0;aj<aaLength;aj+= currStep) {
543                                                 for(ai = 0;ai<aaLength;ai+= currStep) {
544
545                                                         char thisColDiff = 0;
546                                                         if( 
547                                                                  (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] - 
548                                                                                          aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][0])> aaSensRed ) ||
549                                                                  (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] - 
550                                                                                          aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][1])> aaSensGreen ) ||
551                                                                  (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] - 
552                                                                                          aaCol[(aj+0)*aaArrayX +(ai+currStep) +aOrg][2])> aaSensBlue ) ) {
553                                                                 thisColDiff = 1;
554                                                         } else
555                                                                 if( 
556                                                                          (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] - 
557                                                                                                  aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][0])> aaSensRed ) ||
558                                                                          (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] - 
559                                                                                                  aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][1])> aaSensGreen ) ||
560                                                                          (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] - 
561                                                                                                  aaCol[(aj+currStep)*aaArrayX +(ai+0) +aOrg][2])> aaSensBlue ) ) {
562                                                                         thisColDiff = 1;
563                                                                 } else
564                                                                         if( 
565                                                                                  (fabs(aaCol[aj*aaArrayX +ai +aOrg][0] - 
566                                                                                                          aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][0])> aaSensRed ) ||
567                                                                                  (fabs(aaCol[aj*aaArrayX +ai +aOrg][1] - 
568                                                                                                          aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][1])> aaSensGreen ) ||
569                                                                                  (fabs(aaCol[aj*aaArrayX +ai +aOrg][2] - 
570                                                                                                          aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg][2])> aaSensBlue ) ) {
571                                                                                 thisColDiff = 1;
572                                                                         } 
573
574                                                         //colDiff =1;
575                                                         if(thisColDiff) {
576                                                                 /* set diff flag */
577                                                                 colDiff = thisColDiff;
578                                                                 for(int bj=aj;bj<=aj+currStep;bj++) {
579                                                                         for(int bi=ai;bi<=ai+currStep;bi++) {
580                                                                                 if(aaUse[bj*aaArrayX +bi +aOrg]==2) {
581                                                                                         //if(showAAPic) 
582                                                                                         aaUse[bj*aaArrayX +bi +aOrg] = 0;
583                                                                                 }
584                                                                         }
585                                                                 }
586                                                         } else {
587                                                                 /* set all values */
588                                                                 ntlColor avgCol = (
589                                                                                                                                          aaCol[(aj+0       )*aaArrayX +(ai+0       ) +aOrg] +
590                                                                                                                                          aaCol[(aj+0       )*aaArrayX +(ai+currStep) +aOrg] +
591                                                                                                                                          aaCol[(aj+currStep)*aaArrayX +(ai+0       ) +aOrg] +
592                                                                                                                                          aaCol[(aj+currStep)*aaArrayX +(ai+currStep) +aOrg] ) *0.25;
593                                                                 for(int bj=aj;bj<=aj+currStep;bj++) {
594                                                                         for(int bi=ai;bi<=ai+currStep;bi++) {
595                                                                                 if(aaUse[bj*aaArrayX +bi +aOrg]==0) {
596                                                                                         aaCol[bj*aaArrayX +bi +aOrg] = avgCol; 
597                                                                                         aaUse[bj*aaArrayX +bi +aOrg] = 2;
598                                                                                 }
599                                                                         }
600                                                                 }
601                                                         } /* smaller values set */
602
603                                                 }
604                                         }
605
606                                         /* half step size */
607                                         currStep /= 2;
608
609                                 } /* repeat until diff not too big */
610
611                                 /* get average color */
612                                 gfxReal colNum = 0.0;
613                                 col = ntlColor(0.0, 0.0, 0.0);
614                                 for(aj = 0;aj<=aaLength;aj++) {
615                                         for(ai = 0;ai<=aaLength;ai++) {
616                                                 col += aaCol[aj*aaArrayX +ai +aOrg];
617                                                 colNum += 1.0;
618                                         }
619                                 }
620                                 col /= colNum;
621
622                         }
623
624                   /* mark pixels with debugging */
625                         if( glob->getDebugOut() > 0) col = ntlColor(0,1,0);
626
627                         /* store pixel */
628                         if(!showAAPic) {
629                                 finalPic[(scanline-1)*picX+sx] = col; 
630                         }
631                         screenPos +=  rightStep;
632
633                 } /* foreach x */
634
635                 /* init aa array */
636                 if(showAAPic) {
637                         for(int j=0;j<=aaArrayY-1;j++) {
638                                 for(int i=0;i<=aaArrayX-1;i++) {
639                                         if(aaUse[j*aaArrayX +i]==1) finalPic[((scanline-1)*aaLength +j)*picX+i][0] = 1.0;
640                                 }
641                         }
642                 }
643
644                 for(int i=0;i<aaArrayX;i++) {
645                         aaCol[(aaArrayY-1)*aaArrayX+i] = aaCol[0*aaArrayX+i];
646                         aaUse[(aaArrayY-1)*aaArrayX+i] = aaUse[0*aaArrayX+i];
647                 }
648                 for(int j=0;j<aaArrayY-1;j++) {
649                         for(int i=0;i<aaArrayX;i++) {
650                                 aaCol[j*aaArrayX+i] = ntlColor(0.0, 0.0, 0.0);
651                                 aaUse[j*aaArrayX+i] = 0;
652                         }
653                 }
654
655         } /* foreach y */
656         rendEnd = getTime();
657
658
659         /* write png file */
660         {
661                 int w = picX;
662                 int h = picY;
663
664                 unsigned rowbytes = w*4;
665                 unsigned char *screenbuf, **rows;
666                 screenbuf = (unsigned char*)malloc( h*rowbytes );
667                 rows = (unsigned char**)malloc( h*sizeof(unsigned char*) );
668                 unsigned char *filler = screenbuf;
669
670                 // cutoff color values 0..1
671                 for(int j=0;j<h;j++) {
672                         for(int i=0;i<w;i++) {
673                                 ntlColor col = finalPic[j*w+i];
674                                 for (unsigned int cc=0; cc<3; cc++) {
675                                         if(col[cc] <= 0.0) col[cc] = 0.0;
676                                         if(col[cc] >= 1.0) col[cc] = 1.0;
677                                 }
678                                 *filler = (unsigned char)( col[0]*255.0 ); 
679                                 filler++;
680                                 *filler = (unsigned char)( col[1]*255.0 ); 
681                                 filler++;
682                                 *filler = (unsigned char)( col[2]*255.0 ); 
683                                 filler++;
684                                 *filler = (unsigned char)( 255.0 ); 
685                                 filler++; // alpha channel
686                         }
687                 }
688
689                 for(int i = 0; i < h; i++) rows[i] = &screenbuf[ (h - i - 1)*rowbytes ];
690 #ifndef NOPNG
691                 writePng(outfn_conv.str().c_str(), rows, w, h);
692 #else // NOPNG
693                 debMsgStd("ntlRaytracer::renderScene",DM_NOTIFY, "No PNG linked, no picture...", 1);
694 #endif // NOPNG
695         }
696
697
698         // next frame 
699         glob->setAniCount( glob->getAniCount() +1 );
700
701         // done 
702         timeEnd = getTime();
703
704         char resout[1024];
705         snprintf(resout,1024, "NTL Done %s, frame %d/%d (%s scene, %s raytracing, %s total, %d shades, %d i.s.'s)!\n", 
706                                  outfn_conv.str().c_str(), (glob->getAniCount()), (glob->getAniFrames()+1),
707                                  getTimeString(totalStart-timeStart).c_str(), getTimeString(rendEnd-rendStart).c_str(), getTimeString(timeEnd-timeStart).c_str(),
708                                  glob->getCounterShades(),
709                                  glob->getCounterSceneInter() );
710         debMsgStd("ntlRaytracer::renderScene",DM_MSG, resout, 1 );
711
712         /* clean stuff up */
713         delete [] aaCol;
714         delete [] aaUse;
715         delete [] finalPic;
716         glob->getScene()->cleanupScene();
717
718         if(mpGlob->getSingleFrameMode() ) {
719                 debMsgStd("ntlRaytracer::renderScene",DM_NOTIFY, "Single frame mode done...", 1 );
720                 exit(1);
721         }
722         return 0;
723 }
724
725
726