Manta Interactive Ray Tracer Development Mailing List

Text archives Help


[MANTA] r553 - in branches/AFR: Engine/Control Engine/ImageTraversers Engine/ImageTraversers/AFR Image


Chronological Thread 
  • From: abhinav@sci.utah.edu
  • To: manta@sci.utah.edu
  • Subject: [MANTA] r553 - in branches/AFR: Engine/Control Engine/ImageTraversers Engine/ImageTraversers/AFR Image
  • Date: Fri, 16 Sep 2005 15:29:05 -0600 (MDT)

Author: abhinav
Date: Fri Sep 16 15:27:11 2005
New Revision: 553

Added:
   branches/AFR/Engine/ImageTraversers/AFRImageTraverser.cc
   branches/AFR/Engine/ImageTraversers/AFRImageTraverser.h
   branches/AFR/Engine/ImageTraversers/GSTAFRImageTraverser.cc
   branches/AFR/Engine/ImageTraversers/GSTAFRImageTraverser.h
Modified:
   branches/AFR/Engine/Control/AFRPipeline.cc
   branches/AFR/Engine/Control/AFRPipeline.h
   branches/AFR/Engine/Control/RTRT_register.cc
   branches/AFR/Engine/ImageTraversers/AFR/kdtree.cc
   branches/AFR/Engine/ImageTraversers/AFR/kdtree.h
   branches/AFR/Engine/ImageTraversers/AFR/sample.h
   branches/AFR/Engine/ImageTraversers/AFR/tiles.cc
   branches/AFR/Engine/ImageTraversers/AFR/tiles.h
   branches/AFR/Engine/ImageTraversers/CMakeLists.txt
   branches/AFR/Image/SimpleImage.h
Log:
okay, this is first attempt on shared tree. a group of threads share a tree. 
It wont compile as I tried to add a 
separate header etc. Abe will be looking into adding these into command line 
options. For example the 
AFRImageTraverser will inherit three classes AFImageTraverser, 
GSTAFRImageTraverser and STAFRImageTraverser (not 
done). GSTAFR stands for gropu shared tree and STFR stands for single shared 
ttree and AFImageTraverser is our old 
per thread tree aproach. 



Modified: branches/AFR/Engine/Control/AFRPipeline.cc
==============================================================================
--- branches/AFR/Engine/Control/AFRPipeline.cc  (original)
+++ branches/AFR/Engine/Control/AFRPipeline.cc  Fri Sep 16 15:27:11 2005
@@ -463,17 +463,22 @@
         // Update Tiling. (Master task)
         
///////////////////////////////////////////////////////////////////////
         
///////////////////////////////////////////////////////////////////////
-        currentImageTraverser->masterTask( myContext, image );
-        
+        if(currentImageTraverser->isMaster(myContext.proc))
+        {
+          currentImageTraverser->masterTask( myContext, image );
+          image->setValid(true);
+        }
         
///////////////////////////////////////////////////////////////////////
         
///////////////////////////////////////////////////////////////////////
         // Inner Loop: Pipeline Stage 2. 
         // Sampling / Rendering
         
///////////////////////////////////////////////////////////////////////
         
///////////////////////////////////////////////////////////////////////
-        currentImageTraverser->clientTask( myContext, image );
+        {        
+          currentImageTraverser->clientTask( myContext, image );
         
-        image->setValid(true);
+          //image->setValid(true);
+        }
       }
                        
       // Determine how to break out of inner loop. !!!!!!!!!!!!!!!!!!!!!!!!!!
@@ -482,8 +487,8 @@
     if(proc==0)
     {
       if (currentImageTraverser->debug_window) 
-       // do the display stuff here
-       currentImageTraverser->display_stats();
+             // do the display stuff here
+             currentImageTraverser->display_stats();
     }
   } // End of outer loop.
 }

Modified: branches/AFR/Engine/Control/AFRPipeline.h
==============================================================================
--- branches/AFR/Engine/Control/AFRPipeline.h   (original)
+++ branches/AFR/Engine/Control/AFRPipeline.h   Fri Sep 16 15:27:11 2005
@@ -58,7 +58,7 @@
 
                using namespace std;
 
-    class AFImageTraverser;
+    class AFRImageTraverser;
     
                RTRTInterface* createAFRPipeline();
 
@@ -235,7 +235,7 @@
                        typedef map<string, ImageTraverserCreator> 
ImageTraverserMapType;
                        ImageTraverserMapType imageTraversers;
 
-      AFImageTraverser* currentImageTraverser;
+                        AFRImageTraverser* currentImageTraverser;
                        
                        typedef map<string, LoadBalancerCreator> 
LoadBalancerMapType;
                        LoadBalancerMapType loadBalancers;

Modified: branches/AFR/Engine/Control/RTRT_register.cc
==============================================================================
--- branches/AFR/Engine/Control/RTRT_register.cc        (original)
+++ branches/AFR/Engine/Control/RTRT_register.cc        Fri Sep 16 15:27:11 
2005
@@ -6,7 +6,7 @@
 #include <Engine/ImageTraversers/NullImageTraverser.h>
 #include <Engine/ImageTraversers/TiledImageTraverser.h>
 #include <Engine/ImageTraversers/FramelessImageTraverser.h>
-#include <Engine/ImageTraversers/AFImageTraverser.h>
+#include <Engine/ImageTraversers/AFRImageTraverser.h>
 #include <Engine/ImageTraversers/DissolveImageTraverser.h>
 #include <Engine/ImageTraversers/DissolveTiledImageTraverser.h>
 #include <Engine/LoadBalancers/CyclicLoadBalancer.h>
@@ -54,7 +54,9 @@
     rtrt->registerComponent("null", &NullImageTraverser::create);
     rtrt->registerComponent("tiled", &TiledImageTraverser::create);
     rtrt->registerComponent("frameless", &FramelessImageTraverser::create);
-    rtrt->registerComponent("afr", &Afr::AFImageTraverser::create);
+    rtrt->registerComponent("afr", &Afr::AFRImageTraverser::create);
+    rtrt->registerComponent("gstafr", &Afr::AFRImageTraverser::create);
+    rtrt->registerComponent("stafr", &Afr::AFRImageTraverser::create);
     rtrt->registerComponent("dissolve", &DissolveImageTraverser::create);
     rtrt->registerComponent("dissolvetiled", 
&DissolveTiledImageTraverser::create);
 

Modified: branches/AFR/Engine/ImageTraversers/AFR/kdtree.cc
==============================================================================
--- branches/AFR/Engine/ImageTraversers/AFR/kdtree.cc   (original)
+++ branches/AFR/Engine/ImageTraversers/AFR/kdtree.cc   Fri Sep 16 15:27:11 
2005
@@ -394,21 +394,26 @@
 // return a random tile
 // this returna a random valid tile in O(log n). we traverse from the root
 // randomly picking up left or right until we reach the cut
-int KDTree::getRandomTile()
+int KDTree::getRandomTile(MT_RNG &rnogen)
 {
-       int j;
-       int count;
-       
-       
-       if(numTiles==0) return 0;
-       int retval = pseudostart; //tile[0].getNextTile();;
-       
-       j = (int)(myRandomNumber.genfrand()*numTiles/5);
-       for(count=0; count<j; count++)
-               retval = tile[retval].getNextRandomTile();
-       if(retval==0) 
-               retval = tile[retval].getNextRandomTile();
-       return retval;
+       int index = 1;
+  float rno;
+  while(!tile[index].isValid() && 
tile[index].getTileSize()>Tile::min_tile_area)
+  {
+    rno = rnogen.genfrand();
+    index *= 2;
+    if(rno<0.5)
+      index++;
+  }
+  //cout << "getting " << index << "th tile of " << numTiles << " tiles" << 
endl;
+  return index;
+  /*
+  int index = getNextTile(0);
+  int order = (int)(rnogen.genfrand()*numTiles);
+  cout << "getting " << order << "th tile of " << numTiles << " tiles" << 
endl;
+  for(int i=0; i<order; i++)
+    index = getNextTile(index);
+  return index;*/
 }
 
 int KDTree::getNextTile(int index) 
@@ -441,7 +446,6 @@
 // insert a tile in the random list
 void KDTree::insertRandom(int index)
 {
-       resetPseudoRandomSeed();
        // get a pseudo random tile O(1)
        int loc = getPseudoRandomTile();
        //cout << "in insertRandom, inserting after " << loc << endl;
@@ -504,6 +508,50 @@
        if(pseudostart==0) 
                pseudostart = tile[pseudostart].getNextRandomTile();
        return retval;
+}
+
+void KDTree::updateStatsAddPartialSampleSet(PartialSampleSet *newsampleset, 
Timestamp currenttime, unsigned int samplingrate)
+{
+       /*
+       do the following:
+       check the queue in deepbuffer, if full delete the last element and 
delete its contribution from tile
+       add the new element 
+       */
+  newsampleset->tileindex = getTileforXY(newsampleset->viewX, 
newsampleset->viewY);
+  //cout << "adding to location " << newsampleset->viewX << ", " << 
newsampleset->viewY << endl;
+#ifndef ONLY_NODE_UPDATE
+       int x, y;
+       
+       x = (int)newsampleset->viewX;
+       y = (int)newsampleset->viewY;
+       int index = Tile::leafMapping[x/xfac][y/yfac];
+       if(!tile[index].checkBounds(x,y)) return;
+       int vtileindex=-1;
+       while(tile[index].getLevel()>0)//=Tile::meanLevel-1)
+       {
+               tile[index].updateStatsAddPartialSampleSet(newsampleset, 
currenttime, A, B, tile, numTiles, samplingrate);
+               if(tile[index].isValid()) vtileindex = index;
+               index/=2;
+       }
+       if(vtileindex==-1)
+       { 
+          cout << "error: split/merge do not constrain tile sizes 
appropriately" << endl;
+       }
+       else
+         updateMinMax(vtileindex);
+#else
+#ifndef COARSE_UPDATES
+       int x, y;
+       x = (int)newsampleset->viewX;
+       y = (int)newsampleset->viewY;
+       int index = Tile::leafMapping[x/xfac][y/yfac];
+        if(!tile[index].checkBounds(x,y)) return;
+       tile[index].updateStatsAddPartialSampleSet(newsampleset, currenttime, 
A, B, tile, numTiles, samplingrate);
+#endif
+       
tile[newsampleset->tileindex].updateStatsAddPartialSampleSet(newsampleset, 
currenttime, A, B, tile, numTiles, samplingrate);
+       
tile[newsampleset->tileindex/2].updateStatsAddPartialSampleSet(newsampleset, 
currenttime, A, B, tile, numTiles, samplingrate);
+       updateMinMax(newsampleset->tileindex);
+#endif
 }
 
 void KDTree::updateStatsAddSampleSet(SampleSet *newsampleset, Timestamp 
currenttime, unsigned int samplingrate)

Modified: branches/AFR/Engine/ImageTraversers/AFR/kdtree.h
==============================================================================
--- branches/AFR/Engine/ImageTraversers/AFR/kdtree.h    (original)
+++ branches/AFR/Engine/ImageTraversers/AFR/kdtree.h    Fri Sep 16 15:27:11 
2005
@@ -60,7 +60,7 @@
       int getminErrorParentTile();     // get the min var tile
       inline double getmaxError() { return tile[1].maxError(); }       // 
get the maximum variance value
       inline double getminError() { return tile[1].minError(); } // get the 
minimum variance value
-      int getRandomTile();     // get a random tile
+      int getRandomTile(MT_RNG &rnogen);       // get a random tile
       int getRandomSample(int &x, int &y, MT_RNG &rnogen); // get a random 
sample in x,y and returns the tile index too
       void getRandomSamplefromTile(int index, int &x, int &y, MT_RNG 
&rnogen);
       inline Tile* getTile(int index) { return &(tile[index]); } // return 
the tile with the index value
@@ -71,7 +71,8 @@
       void deleteRandom(int index);    // delete tile from the random list
       void updateMinMax(int index);    // update the min/max when some tile 
changes
       int getPseudoRandomTile();       // get a pseudo random tile
-      void resetPseudoRandomSeed() { pseudostart = getRandomTile(); } // 
update seed for pseudo random tile
+      inline void resetPseudoRandomSeed(MT_RNG &rnogen) 
+      { pseudostart = getRandomTile(rnogen); } // update seed for pseudo 
random tile
       inline float xGrad() { return tile[1].xGrad(); }
       inline float yGrad() { return tile[1].yGrad(); }
       float tGrad(); 
@@ -94,6 +95,7 @@
       }
       inline float getB() { return B; };
       void updateStatsAddSampleSet(SampleSet *newsampleset, Timestamp 
currenttime, unsigned int samplingrate);
+      void updateStatsAddPartialSampleSet(PartialSampleSet *newsampleset, 
Timestamp currenttime, unsigned int samplingrate);
       void updateStatsAddSample(Sample *newsample, Timestamp currenttime, 
float tgrad, bool occ, unsigned int samplingrate);
       void displayTiles(TileDisplayMode displaymode, Timestamp currenttime, 
float visScale, int samplingrate); 
       inline void setMaxTreeDepth(int m)

Modified: branches/AFR/Engine/ImageTraversers/AFR/sample.h
==============================================================================
--- branches/AFR/Engine/ImageTraversers/AFR/sample.h    (original)
+++ branches/AFR/Engine/ImageTraversers/AFR/sample.h    Fri Sep 16 15:27:11 
2005
@@ -100,7 +100,7 @@
               else
                 return false;
             }
-                       void operator=(const Sample &value)
+                       /*void operator=(const Sample &value)
                        {
                                int i;
                                for(i=0; i<3; i++)
@@ -111,7 +111,7 @@
                                }
                                t = value.t;
                                tileindex = value.tileindex;
-                       }
+                       }*/
                
                        void writeToFile(FILE *fp)
                        {
@@ -312,6 +312,157 @@
           
if(fabsf(sample[TEMPORAL_SAMPLE].worldCoord[0]-sample[CENTER_SAMPLE].worldCoord[0])>
 epsilon 
           || 
fabsf(sample[TEMPORAL_SAMPLE].worldCoord[1]-sample[CENTER_SAMPLE].worldCoord[1])>
 epsilon 
           || 
fabsf(sample[TEMPORAL_SAMPLE].worldCoord[2]-sample[CENTER_SAMPLE].worldCoord[2])>
 epsilon )
+            return true;
+          else
+            return false;
+        }
+        
+               };
+    
+    
///////////////////////////////////////////////////////////////////////////
+    
///////////////////////////////////////////////////////////////////////////
+    // SAMPLE SET  SAMPLE SET  SAMPLE SET  SAMPLE SET  SAMPLE SET  SAMPLE 
SET  
+    
///////////////////////////////////////////////////////////////////////////
+    
///////////////////////////////////////////////////////////////////////////   
                       
+               // Position in the sampling pattern of each sample.
+               enum PartialCrosshairSampleLoc { C_SAMPLE, 
+                                     X_SAMPLE, 
+                                                                             
                                           Y_SAMPLE, 
+                                     T_SAMPLE };
+    class PartialSampleSet {
+                       public:
+                               
+        Sample sample[4];
+        
+        float tgrad, xgrad, ygrad;
+        float viewX, viewY, viewZ; 
+        int tileindex; 
+        bool complete;      
+        // Constructor.
+        PartialSampleSet() { reset(); }
+        
+        void reset()
+        {
+          xgrad = ygrad = tgrad = 0.0;
+          viewX = viewY = viewZ = 0;
+          complete = false;
+          // Reset the samples.
+          for (int i=0;i<4;++i) {
+            sample[i].reset();
+          }
+        }
+        
+        void set(int sloc, const float x, const float y, const Timestamp 
tstamp, 
+                 const float wx, const float wy, const float wz,
+                 const float r, const float g, const float b)
+        {
+          sample[sloc].set(x,y,tstamp,wx,wy,wz,r,g,b); 
+          if(sloc==T_SAMPLE)
+            complete = true;
+          if(sloc==C_SAMPLE)
+          {
+            viewX = sample[C_SAMPLE].viewCoord[0];
+            viewY = sample[C_SAMPLE].viewCoord[1];
+            viewZ = sample[C_SAMPLE].viewCoord[2];
+          }
+        }
+                   
+        void setTempXhair(float x, float y, 
+                          const int xres, const int yres, 
+                          const int tindex, const Timestamp tstamp)
+        {
+          reset();
+          if(x<0) x = 0;
+          if(x>xres-1) x = xres-1;
+          if(y<0) y = 0;
+          if(y>yres-1) y = yres-1;
+          sample[C_SAMPLE].init(x, y, tstamp);
+          sample[X_SAMPLE].init(x+1.0f, y, tstamp);
+          sample[Y_SAMPLE].init(x, y+1.0f, tstamp);
+          tileindex = tindex;
+          viewX = sample[C_SAMPLE].viewCoord[0];
+          viewY = sample[C_SAMPLE].viewCoord[1];
+          viewZ = sample[C_SAMPLE].viewCoord[2];
+        }
+        
+        void computeGradients(Timestamp currenttime) {
+             
+          viewX = sample[C_SAMPLE].viewCoord[0];
+          viewY = sample[C_SAMPLE].viewCoord[1];
+          viewZ = sample[C_SAMPLE].viewCoord[2];
+          
+          
if(fabsf(sample[C_SAMPLE].viewCoord[0]-sample[X_SAMPLE].viewCoord[0])>0.001)
+          {
+            xgrad = sample[C_SAMPLE].getRGBDistance(sample[X_SAMPLE].c) / 
+            
fabsf(sample[C_SAMPLE].viewCoord[0]-sample[X_SAMPLE].viewCoord[0]); 
+          }
+          else
+          {
+           xgrad = sample[C_SAMPLE].getRGBDistance(sample[X_SAMPLE].c);
+          }
+          
+          
if(fabsf(sample[C_SAMPLE].viewCoord[1]-sample[Y_SAMPLE].viewCoord[1])>0.001)
+          {
+            ygrad = sample[C_SAMPLE].getRGBDistance(sample[Y_SAMPLE].c) /
+            
fabsf(sample[C_SAMPLE].viewCoord[1]-sample[Y_SAMPLE].viewCoord[1]); 
+          }
+          else
+          {
+            ygrad = sample[C_SAMPLE].getRGBDistance(sample[Y_SAMPLE].c);
+          }
+          //cout << "xgrad = " << xgrad << ", " << "ygrad = " << ygrad << 
endl;
+          if(complete)
+          {
+            if(fabsf(sample[T_SAMPLE].t-sample[C_SAMPLE].t)>0.001)
+            {
+              tgrad = sample[T_SAMPLE].getRGBDistance(sample[C_SAMPLE].c)/
+                                fabsf(sample[T_SAMPLE].t - 
sample[C_SAMPLE].t);
+            }
+            else
+            {
+              tgrad = sample[T_SAMPLE].getRGBDistance(sample[C_SAMPLE].c);
+            }                  
+            //cout << "tgrad = " << tgrad << endl;
+          }
+          //<TODO> set occlusion status here
+        }
+        
+        void writeToFile(int sloc, FILE *fp)
+        {
+          sample[sloc].writeToFile(fp);
+        }
+        
+        void print()
+        {
+          cout << "partial sample set ---------------->" << endl;
+          cout << "C: "; sample[C_SAMPLE].print();
+          cout << "X: "; sample[X_SAMPLE].print();
+          cout << "Y: "; sample[Y_SAMPLE].print();
+          cout << "T: "; sample[T_SAMPLE].print();
+          cout << "<---------------------------" << endl << endl;
+        }
+        
+        float getIntensity(PartialCrosshairSampleLoc sloc) { return 
sample[sloc].intensity(); }
+        float getR(PartialCrosshairSampleLoc sloc) { return 
sample[sloc].c[0]; }
+        float getG(PartialCrosshairSampleLoc sloc) { return 
sample[sloc].c[1]; }
+        float getB(PartialCrosshairSampleLoc sloc) { return 
sample[sloc].c[2]; }
+        
+        Timestamp getSampleTimeStamp(PartialCrosshairSampleLoc sloc) { 
return sample[sloc].t; } 
+        
+        inline bool isOccluded() { 
+          const static float epsilon = 0.001;
+          if(!complete) return false;
+          if(isinf(sample[T_SAMPLE].worldCoord[0]) 
+          || isinf(sample[T_SAMPLE].worldCoord[1])
+          || isinf(sample[T_SAMPLE].worldCoord[2])
+          || isinf(sample[C_SAMPLE].worldCoord[0])
+          || isinf(sample[C_SAMPLE].worldCoord[1])
+          || isinf(sample[C_SAMPLE].worldCoord[2]))
+            return false;
+          
+          
if(fabsf(sample[T_SAMPLE].worldCoord[0]-sample[C_SAMPLE].worldCoord[0])> 
epsilon 
+          || 
fabsf(sample[T_SAMPLE].worldCoord[1]-sample[C_SAMPLE].worldCoord[1])> epsilon 
+          || 
fabsf(sample[T_SAMPLE].worldCoord[2]-sample[C_SAMPLE].worldCoord[2])> epsilon 
)
             return true;
           else
             return false;

Modified: branches/AFR/Engine/ImageTraversers/AFR/tiles.cc
==============================================================================
--- branches/AFR/Engine/ImageTraversers/AFR/tiles.cc    (original)
+++ branches/AFR/Engine/ImageTraversers/AFR/tiles.cc    Fri Sep 16 15:27:11 
2005
@@ -115,13 +115,14 @@
        }
 }
 
-float Tile::getUnderSampling(const Timestamp currenttime, const int 
samplingrate, Tile *tree, const float B)
+float Tile::getUnderSampling(const Timestamp currenttime, const int 
samplingrate, Tile *tree, const float B, int nTiles)
 {
   //float meanGlobalAge = 0.5*(float)tree[1].num_pixels/(float)samplingrate;
   float a = -B;
   //float meanGlobalAge = currenttime - 
(1.0f/(a*a*currenttime))*(expf(a*currenttime)*(a*currenttime-1.0f) + 1.0f);
   float globalAge = (1.0f/(a*a))*(1.0 - 
expf(a*currenttime)*(B*currenttime+1.0f));
   float sumWeights = (1.0f/B)*(1.0- - expf(a*currenttime));
+  globalAge*=(float)num_pixels/((float)tree[1].num_pixels/(float)nTiles);
  /* float expectedSamples = 
ceilf(currenttime*samplingrate*((float)tree[1].num_pixels/(float)num_pixels));
   float r = currenttime/expectedSamples;
   float efac = expf(B*r);
@@ -148,7 +149,7 @@
 void Tile::setError(Tile *tree, const int nTiles, const Timestamp 
currenttime, const unsigned int samplingrate, const float B)
 {
        error =  2.0*(r.getVariance() + g.getVariance() + b.getVariance() + 
AMBIENT_ERROR)*num_pixels; 
-       //error += 0.25*getUnderSampling(currenttime, samplingrate, tree, 
B)*num_pixels; 
+       error += 0.25*getUnderSampling(currenttime, samplingrate, tree, B, 
nTiles)*num_pixels; 
        error += 0.25*getOcclusionMeasure(tree, nTiles)*num_pixels;
 }
 
@@ -159,8 +160,6 @@
        // well what about the derivative
        setDerivative(currenttime);
        total_error = KOEFF*(error) + (1.0-KOEFF)*derivative;
-       //total_error =error;
-       time_last_updated = currenttime;
 }
 
 void Tile::updateCommon(const Timestamp currenttime, Tile *tree, const int 
nTiles, const unsigned int samplingrate, const float B)
@@ -240,6 +239,71 @@
        occlusion.addElement(occ, wt_new, ratio);
 
        updateCommon(currenttime, tree, nTiles, samplingrate, B);
+  
+       time_last_updated = currenttime;
+}
+
+void Tile::updateStatsAddPartialSampleSet(PartialSampleSet *newsampleset, 
const Timestamp currenttime, const float A, const float B, 
+                          Tile *tree, const int nTiles, const unsigned int 
samplingrate)
+{
+       float ratio = getWeight(A, B, (currenttime - time_last_updated));
+  float wt1, wt2;
+  wt1 = getWeight(A, B, currenttime - 
newsampleset->getSampleTimeStamp(C_SAMPLE));
+  //cout << "wt1 = " << wt1 << ", currenttime = " << currenttime << 
+  //     ", c_sample time = " << newsampleset->getSampleTimeStamp(C_SAMPLE) 
+  //     << ", t_sample time = " << 
newsampleset->getSampleTimeStamp(T_SAMPLE) << endl;
+  if(newsampleset->complete)
+  {
+    wt1 = getWeight(A, B, currenttime - 
newsampleset->getSampleTimeStamp(T_SAMPLE));
+    r.addElement(newsampleset->getR(C_SAMPLE), wt1, ratio);
+         r.addElement(newsampleset->getR(X_SAMPLE), wt1, 1.0);
+         r.addElement(newsampleset->getR(Y_SAMPLE), wt1, 1.0);
+         r.addElement(newsampleset->getR(T_SAMPLE), wt1, 1.0);
+    
+    g.addElement(newsampleset->getR(C_SAMPLE), wt1, ratio);
+         g.addElement(newsampleset->getR(X_SAMPLE), wt1, 1.0);
+         g.addElement(newsampleset->getR(Y_SAMPLE), wt1, 1.0);
+         g.addElement(newsampleset->getR(T_SAMPLE), wt1, 1.0);
+    
+    b.addElement(newsampleset->getR(C_SAMPLE), wt1, ratio);
+         b.addElement(newsampleset->getR(X_SAMPLE), wt1, 1.0);
+         b.addElement(newsampleset->getR(Y_SAMPLE), wt1, 1.0);
+         b.addElement(newsampleset->getR(T_SAMPLE), wt1, 1.0);
+    
+    xGradient.addElement(newsampleset->xgrad, wt1, ratio);
+         yGradient.addElement(newsampleset->ygrad, wt1, ratio);
+         tGradient.addElement(newsampleset->tgrad, wt1, ratio);
+    
+    sumTstamp.addElement(newsampleset->getSampleTimeStamp(T_SAMPLE), wt1, 
ratio);
+    float occ = (newsampleset->isOccluded())? 1.0 : 0.0;
+    //if(occ>0) cout << "occluded " << endl;
+         occlusion.addElement(occ, wt1, ratio);
+  }
+  else
+  {
+    r.addElement(newsampleset->getR(C_SAMPLE), wt1, ratio);
+         r.addElement(newsampleset->getR(X_SAMPLE), wt1, 1.0);
+         r.addElement(newsampleset->getR(Y_SAMPLE), wt1, 1.0);
+    
+    g.addElement(newsampleset->getR(C_SAMPLE), wt1, ratio);
+         g.addElement(newsampleset->getR(X_SAMPLE), wt1, 1.0);
+         g.addElement(newsampleset->getR(Y_SAMPLE), wt1, 1.0);
+    
+    b.addElement(newsampleset->getR(C_SAMPLE), wt1, ratio);
+         b.addElement(newsampleset->getR(X_SAMPLE), wt1, 1.0);
+         b.addElement(newsampleset->getR(Y_SAMPLE), wt1, 1.0);
+    
+    xGradient.addElement(newsampleset->xgrad, wt1, ratio);
+         yGradient.addElement(newsampleset->ygrad, wt1, ratio);
+    
+    sumTstamp.uniformDecrease(ratio);
+    tGradient.uniformDecrease(ratio);
+         occlusion.uniformDecrease(ratio);
+  }
+  
+       updateCommon(currenttime, tree, nTiles, samplingrate, B);
+  
+       time_last_updated = currenttime;
 }
 
 void Tile::updateStatsAddSample(Sample *newsample, Timestamp currenttime, 
const float A, const float B, 
@@ -251,7 +315,7 @@
        r.addElement(newsample->c[0], wt_new, ratio);
        g.addElement(newsample->c[1], wt_new, ratio);
        b.addElement(newsample->c[2], wt_new, ratio);
-    if(newsample->isInfinite())
+  if(newsample->isInfinite())
          sumTstamp.addElement(newsample->t, wt_new, ratio);
        else
       sumTstamp.uniformDecrease(ratio);
@@ -261,6 +325,8 @@
        occlusion.uniformDecrease(ratio);
 
        updateCommon(currenttime, tree, nTiles, samplingrate, B);
+  
+       time_last_updated = currenttime;
 }
 
 void Tile::updateMinMax(Tile *tree)
@@ -459,7 +525,7 @@
                case AVERAGE_AGE:
                        {
                                glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-                               float dcol= getUnderSampling(currenttime, 
samplingrate, tree, B);
+                               float dcol= getUnderSampling(currenttime, 
samplingrate, tree, B, nTiles);
                                dcol *= visScale;
                                glColor3f(0.6*dcol, 0.3*dcol, 0.9*dcol);
                                //float a = -B;

Modified: branches/AFR/Engine/ImageTraversers/AFR/tiles.h
==============================================================================
--- branches/AFR/Engine/ImageTraversers/AFR/tiles.h     (original)
+++ branches/AFR/Engine/ImageTraversers/AFR/tiles.h     Fri Sep 16 15:27:11 
2005
@@ -141,6 +141,8 @@
                void updateCommon(const Timestamp currenttime, Tile *tree, 
const int nTiles, const unsigned int samplingrate, const float B);
                void updateStatsAddSampleSet(SampleSet *newsampleset, 
Timestamp currenttime, float A, float B, 
                                        Tile *tree, int nTiles, unsigned int 
samplingrate);
+               void updateStatsAddPartialSampleSet(PartialSampleSet 
*newsampleset, Timestamp currenttime, float A, float B, 
+                                       Tile *tree, int nTiles, unsigned int 
samplingrate);
                void recomputeStats(Tile *tree);
                void updateStatsAddSample(Sample *newsample, const Timestamp 
currenttime, const float A, const float B, 
                           Tile *tree, const int nTiles, float tgrad, bool 
occ, const unsigned int samplingrate);
@@ -183,7 +185,7 @@
                        return (num_pixels<min_tile_area);
                }
                void writeToFile(FILE *fp, Tile *tree, int nTiles, Timestamp 
currenttime, int samplingrate);
-               float getUnderSampling(const Timestamp currenttime, const int 
samplingrate, Tile *tree, const float B);
+               float getUnderSampling(const Timestamp currenttime, const int 
samplingrate, Tile *tree, const float B, int nTiles);
                float getOcclusionMeasure(Tile *tree, const int nTiles);
                bool checkBounds(int x, int y);
     void display(TileDisplayMode displaymode, const int nTiles, Tile *tree, 

Added: branches/AFR/Engine/ImageTraversers/AFRImageTraverser.cc
==============================================================================
--- (empty file)
+++ branches/AFR/Engine/ImageTraversers/AFRImageTraverser.cc    Fri Sep 16 
15:27:11 2005
@@ -0,0 +1,908 @@
+
+#include <Engine/ImageTraversers/AFRImageTraverser.h>
+
+using namespace std;
+using namespace Manta;
+using namespace Manta::Afr;
+
+using SCIRun::IllegalValue;
+using SCIRun::InternalError;
+
+using namespace std;
+
+// args are the command line options, if the user wants to pas to th
+// eimage traverser look in TiledimageTraverser.cc for usage
+ImageTraverser* AFRImageTraverser::create(const vector<string>& args)
+{
+  return new GSTAFRImageTraverser(args);
+}
+
+GSTAFRImageTraverser::GSTAFRImageTraverser(const vector<string>& args) :
+  myRandomNumber( 0 ),
+  inner_loop_time( 0.06 ),
+  chunk_size( 256 ),
+  debug_window( false ),
+  samplingrate( 400000 ),
+  displayClientId( 0 ),
+  visScale( 1.0 ),
+  outputStreams( false ),
+  spatialCoherence( false ),
+  num_masters( 1 ),
+  //streamlock( "streamlock" ),
+  tmode(SOLID)
+{
+
+  for (int i=0;i<args.size();++i) {
+    if (args[i] == "-inner") {
+      if (!getArg( i, args, inner_loop_time )) {
+        throw IllegalArgument("-inner <Real>", i, args);
+      }
+    }
+    if (args[i] == "-chunk") {
+      if (!getArg( i, args, chunk_size )) {
+        throw IllegalArgument("-chunk <Int>", i, args);
+      }
+    }
+    if (args[i] == "-samplingrate") {
+      if (!getArg( i, args, samplingrate )) {
+        throw IllegalArgument("-samplingrate <Int>", i, args);
+      }
+    }
+    if (args[i] == "-groups") {
+      if (!getArg( i, args, num_masters )) {
+        throw IllegalArgument("-groups <Int>", i, args);
+      }
+    }
+    if (args[i] == "-stream") {
+      if (!getArg( i, args, streamfilename )) {
+        throw IllegalArgument("-streamfilename <string>", i, args);
+      }
+      outputStreams = true;
+    }
+    if (args[i] == "-spatial") {
+      spatialCoherence = true;
+    }
+    if (args[i] == "-debug") {
+      debug_window = true;
+    }
+  }
+}
+
+GSTAFRImageTraverser::~GSTAFRImageTraverser()
+{
+  if(myRandomNumber!=NULL) delete [] myRandomNumber;
+  // free the kdtree and queues. I suppose this will be done automatically
+  // confirm!
+}
+
+
+void GSTAFRImageTraverser::createStatsWin()
+{
+  XHelper::Xlock.lock();
+  // Open the display and make sure it has opengl
+  dpy = XOpenDisplay(NULL);
+  if(!dpy) {
+    XHelper::Xlock.unlock();
+    throw InternalError("Error opening display", __FILE__, __LINE__);
+  }
+  int error, event;
+  if ( !glXQueryExtension( dpy, &error, &event) ) {
+    XCloseDisplay(dpy);
+    dpy=0;
+    XHelper::Xlock.unlock();
+    throw InternalError("GL extension NOT available!\n", __FILE__, __LINE__);
+  }
+  
+  int screen=DefaultScreen(dpy);
+    
+  // Form the criteria for the 
+  vector<int> attribList;
+  attribList.push_back(GLX_RGBA);
+  attribList.push_back(GLX_RED_SIZE); attribList.push_back(1);
+  attribList.push_back(GLX_GREEN_SIZE); attribList.push_back(1);
+  attribList.push_back(GLX_BLUE_SIZE); attribList.push_back(1);
+  attribList.push_back(GLX_ALPHA_SIZE); attribList.push_back(0);
+  attribList.push_back(GLX_DEPTH_SIZE); attribList.push_back(0);
+  attribList.push_back(GLX_DOUBLEBUFFER); // This must be the last one
+  attribList.push_back(None);
+
+  XVisualInfo* vi = glXChooseVisual(dpy, screen, &attribList[0]);
+  if(!vi){
+    // We failed to choose a visual.  Try again without the double-buffer 
flag
+    attribList.pop_back();
+    attribList.pop_back();
+    attribList.push_back(None);
+    vi = glXChooseVisual(dpy, screen, &attribList[0]);
+  }
+
+  Colormap cmap = XCreateColormap(dpy, RootWindow(dpy, screen),
+                                 vi->visual, AllocNone);
+
+  XSetWindowAttributes atts;
+  int flags=CWColormap|CWEventMask|CWBackPixmap|CWBorderPixel;
+  atts.background_pixmap = None;
+  atts.border_pixmap = None;
+  atts.border_pixel = 0;
+  atts.colormap=cmap;
+  
atts.event_mask=StructureNotifyMask|ExposureMask|KeyPressMask|KeyReleaseMask;
+  Window parent = RootWindow(dpy, screen);
+  statsWindow.window=XCreateWindow(dpy, parent, 600, 0, DISPLAY_WIDTH, 
DISPLAY_HEIGHT, 0, vi->depth,
+                   InputOutput, vi->visual, flags, &atts);
+
+  XTextProperty tp;
+  char* name = "AFR Debug";
+  XStringListToTextProperty(&name, 1, &tp);
+  XSizeHints sh;
+  sh.flags = USPosition|USSize;
+  
+  XSetWMProperties(dpy, statsWindow.window, &tp, &tp, 0, 0, &sh, 0, 0);
+  XMapWindow(dpy, statsWindow.window);
+
+  // Wait for the window to appear before proceeding
+  for(;;){
+    XEvent e;
+    XNextEvent(dpy, &e);
+    if(e.type == MapNotify)
+      break;
+  }
+
+  windowOpen = true;
+
+  gl_context = glXCreateContext(dpy, vi, NULL, True);
+  XFree(vi);
+
+  if(!glXMakeCurrent(dpy, statsWindow.window, gl_context)) {
+    XHelper::Xlock.unlock();
+    throw InternalError("glXMakeCurrent failed!\n", __FILE__, __LINE__);
+  }
+  
+  glViewport(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT);
+  glMatrixMode(GL_PROJECTION);
+  glLoadIdentity();
+  gluOrtho2D(0, DISPLAY_WIDTH, 0, DISPLAY_HEIGHT);
+  glMatrixMode(GL_MODELVIEW);
+  glLoadIdentity();
+  
+  glClearColor(.05, .1, .2, 0);
+  glClear(GL_COLOR_BUFFER_BIT);
+  
+  glXSwapBuffers(dpy, statsWindow.window);
+  glFinish();
+
+  // Get the fonts.  You need to call this with a current GL context.
+  fontInfo = XHelper::getX11Font(dpy);
+  if (!fontInfo) {
+    XHelper::Xlock.unlock();
+    throw InternalError("getX11Font failed!\n", __FILE__, __LINE__);
+  }
+  fontbase = XHelper::getGLFont(fontInfo);
+  if (fontbase == 0) {
+    XHelper::Xlock.unlock();
+    throw InternalError("getGLFont failed!\n", __FILE__, __LINE__);
+  }
+
+  if(!glXMakeCurrent(dpy, None, NULL)) {
+    XHelper::Xlock.unlock();
+    throw InternalError("glXMakeCurrent failed!\n", __FILE__, __LINE__);
+  }
+  
+  XHelper::Xlock.unlock();
+}
+
+void GSTAFRImageTraverser::display_stats() {
+  static int fcount = 0;
+     // Display textual information on the screen:
+    char text[200];
+    
+    switch(tmode)
+    {
+      case SOLID: sprintf(text, "Client: %d: Random Color Tiles (x %d)", 
displayClientId, (int)visScale); break;
+      case BOUNDARY: sprintf(text, "Client: %d: Tiles colored by size (x 
%d)", displayClientId, (int)visScale); break;
+      case DERIVATIVE: sprintf(text, "Client: %d: Derivative (x %d)", 
displayClientId, (int)visScale); break;
+      case OCCLUSION: sprintf(text, "Client: %d: Occlusion; (x %d)", 
displayClientId, (int)visScale); break;
+      case ABSOLUTE_GRADIENT: sprintf(text, "Client: %d: ABS Gradients (x 
%d)", displayClientId, (int)visScale); break;
+      case RELATIVE_GRADIENT: sprintf(text, "Client: %d: REL Gradients (x 
%d)", displayClientId, (int)visScale); break;
+      case SAMPLING_DENSITY: sprintf(text, "Client: %d: Sample density (x 
%d)", displayClientId, (int)visScale); break;
+      case UNDERSAMPLING: sprintf(text, "Client: %d: Undersampling (x %d)", 
displayClientId, (int)visScale); break;
+      case AVERAGE_AGE: sprintf(text, "Client: %d: Average Age (x %d)", 
displayClientId, (int)visScale); break;
+      case JITTERING: sprintf(text, "Client: %d: Jittering (x %d)", 
displayClientId, (int)visScale); break;
+      default: sprintf(text, "Client: %d: Random Color Tiles (x %d)", 
displayClientId, (int)visScale); break;
+    };
+  
+    if(!glXMakeCurrent(dpy, statsWindow.window, gl_context))
+      throw InternalError("GSTAFRImageTraverser::glXMakeCurrent failed!\n",
+                          __FILE__, __LINE__);
+    glClearColor(.05, .1, .2, 0);
+    glClear(GL_COLOR_BUFFER_BIT);
+    kdtree[displayClientId].displayTiles(tmode, 
chunkTimeStamp[displayClientId], visScale, samplingrate);
+    // Figure out how wide the string is
+    int width = XHelper::calc_width(fontInfo, text);
+    // Now we want to draw a gray box beneth the font using blending. :)
+    glEnable(GL_BLEND);
+    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+    glColor4f(0.5,0.5,0.5,0.5);
+    glRecti(8,3-fontInfo->descent-2,25+width,fontInfo->ascent+3);
+    glDisable(GL_BLEND);
+    XHelper::printString(fontbase, 10, 3, text, RGBColor(1,1,1));
+    glXSwapBuffers(dpy, statsWindow.window);
+    glFinish();
+    // Suck up X events to keep opengl happy
+    while (XPending(dpy)) {
+      XEvent e;
+      XNextEvent(dpy, &e);
+      switch (e.type) {
+      case KeyPress:
+        {
+            unsigned long key = XKeycodeToKeysym(dpy, e.xkey.keycode, 0);
+            switch (key) {
+                case XK_m:
+                case XK_M:
+                    toggleTileDisplayMode();
+                    break;
+                case XK_b:
+                case XK_B:
+                    visScale++;
+                    break;
+                case XK_l:
+                case XK_L:
+                    if (visScale>0) visScale--;
+                    break;
+                               case XK_t:
+                               case XK_T:
+                                       displayClientId++;
+                                       if(displayClientId>=num_masters) 
+                                               displayClientId = 0;
+                                       break;
+            }
+        }
+      };
+    }
+  
+}
+
+void GSTAFRImageTraverser::toggleTileDisplayMode()
+{
+       switch(tmode)
+               {
+                       case SOLID: tmode = BOUNDARY; break;
+                       case BOUNDARY: tmode = DERIVATIVE; break;
+                       case DERIVATIVE: tmode = OCCLUSION; break;
+                       case OCCLUSION: tmode = ABSOLUTE_GRADIENT; break;
+                       case ABSOLUTE_GRADIENT: tmode=RELATIVE_GRADIENT; 
break;
+                       case RELATIVE_GRADIENT: tmode=SAMPLING_DENSITY; break;
+                       case SAMPLING_DENSITY: tmode = AVERAGE_AGE; break;
+                       case AVERAGE_AGE: tmode = UNDERSAMPLING; break;
+                       case UNDERSAMPLING: tmode = JITTERING; break;
+                       case JITTERING: tmode = SOLID; break;   
+                       default: tmode = SOLID; break;
+               };                      
+}
+
+void GSTAFRImageTraverser::setupBegin(SetupContext& context, int 
numChannels) {
+
+  context.loadBalancer->setupBegin(context, numChannels);
+
+  if (debug_window) {
+    context.setMultipleGLWindows();
+    statsWindow.xres = DISPLAY_WIDTH; statsWindow.yres = DISPLAY_HEIGHT;
+    createStatsWin();
+  }
+}
+
+#define DESIRED_FRAME_RATE 15
+void GSTAFRImageTraverser::initStreams(int xres, int yres)
+{              // print the version info
+           char fname[80];
+               time_t t;
+               time(&t);
+               //streamlock.lock();
+               for(int i=0; i<num_clients; i++)
+               {
+                 sprintf(fname,"%s%03d",streamfilename.c_str(),i);
+                 streamfile[i] = fopen(fname,"wb");
+                 fprintf(streamfile[i], "Version 1.3\n");
+                 fprintf(streamfile[i],"Created on: %s", ctime(&t));
+                 // print the width and height
+                 fprintf(streamfile[i],"width %d\n", xres);
+                 fprintf(streamfile[i],"height %d\n", yres);
+                 // print the simulated frame rate
+                 fprintf(streamfile[i],"frame_rate %d\n",DESIRED_FRAME_RATE);
+                 fprintf(streamfile[i],"END\n");
+                 //streamlock.unlock();
+                 cout << "initialized stream for client " << i << endl;
+        }
+}
+
+void GSTAFRImageTraverser::write_Tile_and_Camera(RenderContext& context)
+{
+  if(!outputStreams) return;
+  
+  
+  //streamlock.lock();
+  int myID = context.proc;
+  
+  fprintf(streamfile[myID],"\n\nbegin_tiles\n");
+  fprintf(streamfile[myID],"num_tiles %d\n",kdtree[myID].number_of_tiles());
+  // call thread's tree, print to file function
+  kdtree[myID].writeToFile(streamfile[myID], 
(float)chunkTimeStamp[context.proc], samplingrate);
+  // have flag for camera and dump the camera
+  fprintf(streamfile[myID],"\n\nbegin_camera\n");
+  // print camera to file
+  context.camera->writeToFile(streamfile[myID]);
+  // have a flag saying sampling begun
+  fprintf(streamfile[myID],"\n\nbegin_samples\n");
+       
+  if(firsttime[myID]==1)
+    firsttime[myID] = 0;
+  else
+  // print the total samples done in this chunk in the space reserved for 
that before
+  {
+    int samplesDoneThisChunk = samples_done[myID].load() - 
last_samples_done[myID];
+         last_samples_done[myID] = samples_done[myID].load();
+    fpos_t tpos;
+         fgetpos(streamfile[myID], &tpos);
+         fsetpos(streamfile[myID],&numsamples_pos[myID]);
+         fprintf(streamfile[myID],"%d",samplesDoneThisChunk);
+         fsetpos(streamfile[myID], &tpos);
+  }
+  
+  // reserve space for total samples in this chunk
+  fprintf(streamfile[myID],"num_samples ");
+  fgetpos(streamfile[myID], &numsamples_pos[myID]);
+  fprintf(streamfile[myID],"                                               
\n");
+
+  //streamlock.unlock();
+}
+
+void GSTAFRImageTraverser::setupDisplayChannel(SetupContext& context) {
+
+       // Specify that the rendering pipeline should use only one image 
buffer.
+  if (debug_window)
+    context.setMultipleGLWindows();
+
+  context.constrainPipelineDepth(1,1); // single buffer mode is set here
+       
+  bool stereo; // get whether it is stereo, (shoot two rays for left
+               // and right eye)
+  int i;
+  int xres,yres;
+  num_clients = context.numProcs;
+  cout << "number of masters = " << num_masters << endl;
+  groupSize = new int[num_masters];
+  avgGroupSize = num_clients/num_masters;
+  for(i=0; i<num_masters-1; i++)
+  {
+         groupSize[i] = avgGroupSize;
+    cout << " number of clients for master " << i+1 << " = " << avgGroupSize 
<< endl;
+  }
+  groupSize[num_masters-1] = num_clients-avgGroupSize*(num_masters-1);
+  cout << " number of clients for master " << num_masters << " = " << 
groupSize[num_masters-1] << endl;
+  
+  cout << "samplingrate = " << samplingrate << endl;
+  // Samples done.
+#ifdef __ia64__
+  samples_done = (SamplesDone *)memalign( 128, 
sizeof(SamplesDone)*num_clients );
+#else
+  samples_done = (SamplesDone *)malloc( sizeof(SamplesDone)*num_clients );
+#endif
+  memset( samples_done, 0x0, sizeof(SamplesDone)*num_clients );
+  last_samples_done = new int[num_masters];
+  chunkTimeStamp = new double[num_masters];
+
+  // this will change when we can actually simulate 
+  context.getResolution(stereo, xres, yres);
+  cout << "context resolution is: " << xres << ", " << yres << endl;
+  //---------------------------------------------------------
+  // initialize random number generators for each thread.
+  //---------------------------------------------------------
+  myRandomNumber = new MT_RNG[context.numProcs];
+  for(i=0; i<context.numProcs; i++) {
+    myRandomNumber[i].seed_rng(1234*(i+1)); // just to begin give a simple 
seed
+  }
+       
+  
/////////////////////////////////////////////////////////////////////////////
+  // Create a kdtree for each master.
+       
+  //---------------------------------------------------------
+  // make our kdtree, given the resolution of image/channel
+  //---------------------------------------------------------
+  kdtree = new KDTree[num_masters];
+  updatecount = new int[num_masters];
+  for(i=0; i<num_masters; i++)
+  {
+    // samples_done[i] = 0;
+    
+    chunkTimeStamp[i] = (float)SCIRun::Time::currentSeconds();
+         last_samples_done[i] = 0;
+    kdtree[i].setAB(samplingrate);
+    kdtree[i].init(xres, yres, samplingrate);  // initialize the tree
+    updatecount[i] = 0;
+    // set a mean number of tiles, i.e. cut at middle of tree
+    kdtree[i].resetPseudoRandomSeed(myRandomNumber[i*avgGroupSize]);
+  }
+  
+  // chunk_size = 256; // this is a fixed number as of now
+  maxQSize = qSize = (int)(samplingrate*0.1); // temporal queue size
+  temporalQ = new CQ<PartialSampleSet>[num_clients];
+  outputQ = new CQ<PartialSampleSet>[num_clients];
+  newSampleSet = new PartialSampleSet* [num_clients];
+  newTempSampleSet = new PartialSampleSet* [num_clients];
+  color = new Color* [num_clients];
+  initpass = new bool[num_clients];
+  lastxhairindex = new int[num_clients];
+  // Initialize 
+  for(i = 0; i<num_clients; i++)
+  {
+    initpass[i] = false;
+    lastxhairindex[i] = 0;
+    temporalQ[i].init(qSize+1);
+    outputQ[i].init(chunk_size*20);
+    color[i] = new Color [10*chunk_size];
+    newSampleSet[i] = new PartialSampleSet[10*chunk_size];
+    newTempSampleSet[i] = new PartialSampleSet[10*chunk_size]; 
+  }
+  if(outputStreams)
+  {
+    firsttime = new int[num_clients];
+         for(i=0; i<num_clients; i++)
+           firsttime[i] = 1;
+    numsamples_pos = (fpos_t*)malloc(num_clients*sizeof(fpos_t));
+    streamfile = (FILE**)malloc(num_clients*sizeof(FILE*));
+    initStreams(xres, yres);   
+  }
+}
+
+int GSTAFRImageTraverser::renderCrossHair(const RenderContext& context, int 
myID, 
+                                      Image *image, const int xres, const 
int yres, 
+                                      PartialSampleSet *sampleset, int 
sscount, bool endChunk)
+{
+  int start = lastxhairindex[myID];
+  //cout << "now rendering xhair " << myID << ", " << xres << ", " << yres 
<< ", " << sscount << ", " << endChunk << ", " << XhairPacketSize << endl;
+  if((sscount-start+1)<RayPacket::MaxSize && !endChunk)
+  {
+    newSampleSet[myID][sscount].reset();
+    newSampleSet[myID][sscount] = *sampleset;
+    //newSampleSet[myID][sscount].tileindex = 
kdtree[context.proc].getTileforXY(s->viewCoord[0], s->viewCoord[1]);
+    //cout << "checking ...sscount = " << sscount << ", blockstart = " << 
xhairBlockStart[myID] << endl;
+    return 0;
+  }
+  if(start>=sscount) return 0;
+  int myMasterID = myID/avgGroupSize;
+  float t = (float)chunkTimeStamp[myMasterID];
+  int flags = RayPacket::HaveImageCoordinates | RayPacket::ConstantEye;
+  int depth = 0;
+  RayPacketData raydata;
+  RayPacket rays(raydata, (sscount-start+1), depth, flags);
+  int i, j;
+  j = 0;
+  //cout << "size = " << (sscount-start+1) << endl;
+  for(i=start; i<=sscount; i++) {
+    double px, py;
+    if(xres > yres) // let the smaller dimension be mapped to [-1,1]
+    {
+      px = (double)(-1.0 + 
2.0*(newSampleSet[myID][i].sample[C_SAMPLE].viewCoord[0])/(double)yres); 
+      py = (double)(-1.0 + 
2.0*(newSampleSet[myID][i].sample[C_SAMPLE].viewCoord[1])/(double)yres);
+    }
+    else
+    {
+      px = (double)(-1.0 + 
2.0*(newSampleSet[myID][i].sample[C_SAMPLE].viewCoord[0])/(double)xres); 
+      py = (double)(-1.0 + 
2.0*(newSampleSet[myID][i].sample[C_SAMPLE].viewCoord[1])/(double)xres);
+    }  
+      
+    // Specify the pixel.
+    rays.setPixel(j, 0, px, py, &color[myID][j]);
+    j++;
+  }
+  
/////////////////////////////////////////////////////////////////////////////
+  // Trace the rays.  The results will automatically go into the fragment  
+  context.renderer->traceEyeRays(context, rays);
+  rays.computeHitPositions();
+  lastxhairindex[myID] = sscount+1;
+  
/////////////////////////////////////////////////////////////////////////////
+  // okay now copy from fragment to temporalQ
+  j = 0;
+  for(i=start; i<=sscount; i++) {
+    RayPacket::Element& re = rays.get(j);
+    RGBColor tempcol = color[myID][j].convertRGB();
+    //cout << "processing sampleset " << i << endl;
+    newSampleSet[myID][i].set( T_SAMPLE, 
+                newSampleSet[myID][i].sample[C_SAMPLE].viewCoord[0],
+                newSampleSet[myID][i].sample[C_SAMPLE].viewCoord[1], t, 
+                re.hitPosition.x(), re.hitPosition.y(), re.hitPosition.z(),
+                tempcol.r(), tempcol.g(), tempcol.b() ); 
+    newSampleSet[myID][i].computeGradients(t);
+    //cout << "grad info <complete>: " << newSampleSet[myID][i].xgrad << ", "
+    //     << newSampleSet[myID][i].ygrad << ", " 
+    //     << newSampleSet[myID][i].tgrad << endl;
+    samples_done[myID].addOne();  
+    image->set( (int)(newSampleSet[myID][i].sample[C_SAMPLE].viewCoord[0]), 
+                (int)(newSampleSet[myID][i].sample[C_SAMPLE].viewCoord[1]), 
color[myID][j] );
+    j++;
+  }
+
+  //cout << "done one xhairBlock" << endl;
+  return (sscount-start+1);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Render all of samples in a fragment of the chunk.
+///////////////////////////////////////////////////////////////////////////////
+void GSTAFRImageTraverser::renderChunk(const RenderContext& context,
+                                      Image* image, 
+                                      int xres, int yres)
+{
+  //cout << "inside renderChunk " << endl;
+       
+  // renders the fragment by jittering it and stores result in temporalQ
+  int flags = RayPacket::HaveImageCoordinates | RayPacket::ConstantEye;
+  int i, j, f;
+  int myID = context.proc;
+  int myMasterID = myID/avgGroupSize;
+  int fsize = chunk_size;
+  float t = (float)chunkTimeStamp[myMasterID];
+  if(initpass[myID])
+  {
+    fsize = (chunk_size>(qSize-temporalQ[myID].getN()))? chunk_size : 
qSize-temporalQ[myID].getN();
+    if((fsize + temporalQ[myID].getN()) > temporalQ[myID].getMaxSize())
+           fsize = temporalQ[myID].getMaxSize() - temporalQ[myID].getN() -1;
+    //cout << "fsize = " << fsize << endl;
+  }
+  Color color[RayPacket::MaxSize];
+  //Sample newSample[RayPacket::MaxSize];
+  //cout << "fsize = " << fsize << ", myID = " << myID << endl;
+  
/////////////////////////////////////////////////////////////////////////////
+  // Create ray packets.
+  int raypacketsize = 3*(RayPacket::MaxSize/3);
+  //cout << "raypacketsize = " << raypacketsize << endl;
+  int numXhairPerRayPack = raypacketsize/3;
+ // cout << "numXhairPerRayPack = " << numXhairPerRayPack << endl;
+  if(isMaster(myID))
+  {
+    float scalefac = (avgGroupSize>10)? 0.0f : (10.0f-avgGroupSize+1)/10.0f;
+    fsize = (int)(fsize*scalefac);
+  }
+  
+  for(f=0;f<fsize;f+=numXhairPerRayPack) {
+    // Create a ray packet
+    int depth = 0;
+    RayPacketData raydata;
+    RayPacket rays(raydata, raypacketsize, depth, flags);
+    int cx, cy, ox, oy;
+    int tindex = kdtree[myMasterID].getRandomTile(myRandomNumber[myID]);
+    //int tindex = kdtree[myID].getPseudoRandomTile();
+    //cout << "got tile " << tindex << endl;
+    
+    //if(spatialCoherence)
+    //{
+      // do the 10x4 thing here
+    //}
+    //else 
+    for(i=0; i<numXhairPerRayPack; i++)
+    {
+      kdtree[myMasterID].getRandomSamplefromTile(tindex, cx, cy, 
myRandomNumber[myID]);
+      //cout << "got random loc: " << cx << ", " << cy << endl;
+      double jitterx, jittery;
+      jitterx = myRandomNumber[myID].genfrand()-0.5;
+      jittery = myRandomNumber[myID].genfrand()-0.5;
+      newTempSampleSet[myID][f+i].setTempXhair((cx+jitterx), (cy+jittery), 
xres, yres, tindex, t);
+      for(j=0; j<3; j++)
+      {
+        // normalized
+        double px, py;
+                       
+        if(xres>yres) // let the smaller dimension be mapped to [-1,1]
+        {
+          px = (double)(-1.0 + 
2.0*((double)newTempSampleSet[myID][f+i].sample[j].viewCoord[0])/(double)yres);
 
+          py = (double)(-1.0 + 
2.0*((double)newTempSampleSet[myID][f+i].sample[j].viewCoord[1])/(double)yres);
+        }
+        else
+        {
+          px = (double)(-1.0 + 
2.0*((double)newTempSampleSet[myID][f+i].sample[j].viewCoord[0])/(double)xres);
 
+          py = (double)(-1.0 + 
2.0*((double)newTempSampleSet[myID][f+i].sample[j].viewCoord[1])/(double)xres);
+        }  
+                               // samples_done[context.proc] ++;
+        samples_done[myID].addOne();
+        // Specify the position and color pointer for the packet element.
+        rays.setPixel(i*3+j, 0, px, py, &color[i*3+j]);
+        if(!spatialCoherence) tindex = 
kdtree[myMasterID].getRandomTile(myRandomNumber[myID]);
+        //tindex = kdtree[myMasterID].getPseudoRandomTile();
+        //cout << "got tile " << tindex << endl;
+      }
+    }
+    
+    
//////////////////////////////////////////////////////////////////////////
+    // Trace the rays.  The results will automatically go into the fragment  
+    context.renderer->traceEyeRays(context, rays);
+               
+    // Compute world space hit positions.
+    rays.computeHitPositions();
+               
+    
///////////////////////////////////////////////////////////////////////////
+    // okay now copy from fragment to temporalQ
+    for(i=0;i<raypacketsize;i++) {
+    
+      RayPacket::Element& re = rays.get(i);
+      RGBColor tempcol = color[i].convertRGB();      
+      newTempSampleSet[myID][f+i/3].set(i%3, 
+                                        
newTempSampleSet[myID][f+i/3].sample[i%3].viewCoord[0],
+                                        
newTempSampleSet[myID][f+i/3].sample[i%3].viewCoord[1],
+                                        t,
+                                        re.hitPosition.x(), 
re.hitPosition.y(), re.hitPosition.z(),
+                                        tempcol.r(), tempcol.g(), 
tempcol.b() );
+      /*cout << "setting: " << i%3 << ", " 
+           << newTempSampleSet[myID][f+i/3].sample[i%3].viewCoord[0] << ", " 
+           << newTempSampleSet[myID][f+i/3].sample[i%3].viewCoord[1] << ", " 
+           << newTempSampleSet[myID][f+i/3].timestamp << ", " 
+           << re.hitPosition.x() << ", " << re.hitPosition.y() << ", "  << 
re.hitPosition.z() << ", " 
+           << tempcol.r() << ", " << tempcol.g() << ", " << tempcol.b() << 
endl;*/
+      
/////////////////////////////////////////////////////////////////////////////
+      // Skip reconstruction and set the image pixel.
+      
image->set((int)(newTempSampleSet[myID][f+i/3].sample[i%3].viewCoord[0]), 
+                 
(int)(newTempSampleSet[myID][f+i/3].sample[i%3].viewCoord[1]), 
+                 color[i]);
+    }
+  }
+  for(f=0; f<fsize; f++)
+  {
+    newTempSampleSet[myID][f].computeGradients(t);
+    //cout << "grad info (chunk): " << newSampleSet[myID][f].xgrad << ", "
+    //     << newSampleSet[myID][f].ygrad << ", " 
+    //     << endl;
+    temporalQ[myID].qInsert(&newTempSampleSet[myID][f]);
+    outputQ[myID].qInsert(&newTempSampleSet[myID][f]);
+  }
+       // write to stream if required and to the queues
+  if(outputStreams)
+  {
+    for(f=0; f<fsize; f++)
+    {
+      newTempSampleSet[myID][f].writeToFile(C_SAMPLE, streamfile[myID]);
+      newTempSampleSet[myID][f].writeToFile(X_SAMPLE, streamfile[myID]);
+      newTempSampleSet[myID][f].writeToFile(Y_SAMPLE, streamfile[myID]);
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// This method implements the master thread functionality.
+///////////////////////////////////////////////////////////////////////////////
+void GSTAFRImageTraverser::masterTask(const RenderContext& context, Image* 
image) {
+
+  // update kdtree based on previous results from the client threads
+  
+  bool stereo;
+  int i, j;
+  int xres, yres;
+  image->getResolution(stereo, xres, yres);
+  // get the masterID
+  int masterID;
+  masterID = context.proc/avgGroupSize;
+  chunkTimeStamp[masterID] = (float)SCIRun::Time::currentSeconds();
+  
+  //cout << "master = " << masterID << ", has " << groupSize[masterID] << " 
clients" << endl; 
+  // for clients context.proc+1 to context.proc+groupSize[masterID]
+  // read output queue of all clients and update the kdtree[masterID]
+  
+  for(i=masterID; i<masterID+groupSize[masterID]; i++)
+  {
+    int qsize = outputQ[i].getN()-1;
+    if(qsize>=chunk_size-2)
+      for(j=0; j<qsize; j++)
+      {
+        PartialSampleSet *npss = outputQ[i].seekLast();
+        outputQ[i].qDelete();
+        if(npss==NULL) break;
+        updatecount[masterID]++;
+        // add sample to the corresponding kdtree
+        //npss->print();
+       // if(npss->xgrad>0 || npss->ygrad>0 || npss->tgrad>0)
+       // {
+       //   cout << "grads: ( " << npss->xgrad 
+       //        << ", " << npss->ygrad 
+       //        << ", " << npss->tgrad << " ) " << endl;
+       // }
+        kdtree[masterID].updateStatsAddPartialSampleSet(npss, 
(float)chunkTimeStamp[masterID], samplingrate);
+      }
+  }
+  //cout << "time (thread = " << context.proc << " ) is now " << 
chunkTimeStamp[context.proc] << endl; 
+  // return during intialization here 
+  if(updatecount[masterID] >= chunk_size)
+  {
+    //cout << updatecount[masterID] <<  " xhairs added to tree " << endl;
+    updatecount[masterID] = 0;
+    // adjust tiles based on current status
+    if(chunkTimeStamp[masterID]>5)
+    adjustTiles(masterID, (float)chunkTimeStamp[masterID]);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// This method implements the master thread functionality.
+///////////////////////////////////////////////////////////////////////////////
+void GSTAFRImageTraverser::clientTask(const RenderContext& context, Image* 
image) {
+
+  //cout << "inside clientThread for frametype " << frametype[context.proc] 
<< endl;
+  bool stereo;
+  int xres, yres;
+  image->getResolution(stereo, xres, yres);
+  int myID = context.proc;
+  int myMasterID = myID/avgGroupSize;
+  Sample s;
+  kdtree[myMasterID].setAB(samplingrate);
+  // render the chunk
+  renderChunk(context, image, xres, yres);
+  
+  int xhairRendered = 0;
+  if(!initpass[myID])
+  {
+    if(temporalQ[myID].isFull()) {
+      initpass[myID] = true;
+      std::cerr << "Thread: " << context.proc << " has its queues 
initialized" << std::endl;
+    }
+  }
+  else 
+  {
+    // initialization is done so we can reproject one chunk worth
+    int i, j;
+         int sscount=0;
+    PartialSampleSet *sp;
+    //cout << "now making xhairs" << endl;
+       
+    int  fsize = temporalQ[myID].getN()-qSize;
+    for(i=0; i<fsize; i++)
+      temporalQ[myID].qDelete();
+               
+    //cout << "fsize = " << fsize << endl;
+    if(isMaster(myID))
+    {
+      float scalefac = (avgGroupSize>10)? 0.0f : 
(10.0f-avgGroupSize+1)/10.0f;
+      fsize = (int)(chunk_size*scalefac);
+    }
+    else
+      fsize = chunk_size;
+    for(i=0; i<fsize; i++) {
+               
+      sp = temporalQ[myID].seekLast();
+      if(sp!=NULL) {
+        temporalQ[myID].qDelete();
+        Manta::Real px, py, pz;
+        for(j=0; j<3; j++)
+        {
+          px = sp->sample[j].worldCoord[0];
+          py = sp->sample[j].worldCoord[1];
+          pz = sp->sample[j].worldCoord[2];
+        
+        //if the point is INF, no need to reproject as it will remain the 
same
+#ifdef __sgi
+          if(finite(px) && finite(py) && finite(pz))
+#else
+          if(!isinf(px) && !isinf(py) && !isinf(pz))
+#endif
+          {
+            const Point p(px, py, pz);
+            Point rp;
+            rp = context.camera->project(p);
+            sp->sample[j].viewCoord[0] = rp.x()*xres;
+            sp->sample[j].viewCoord[1] = rp.y()*yres;
+            sp->sample[j].viewCoord[2] = rp.z();
+          }
+        }
+        if(sp->sample[C_SAMPLE].viewCoord[0]<xres && 
sp->sample[C_SAMPLE].viewCoord[0]>=0 
+           && sp->sample[C_SAMPLE].viewCoord[1]<yres && 
sp->sample[C_SAMPLE].viewCoord[1]>=0
+           && sp->sample[C_SAMPLE].viewCoord[2]<=1.0)
+        {
+          xhairRendered += renderCrossHair(context, myID, image, xres, yres, 
sp, sscount);
+          sscount++;
+        }
+      }
+      else break;
+    }
+    xhairRendered += renderCrossHair(context, myID, image, xres, yres, sp, 
sscount-1, true);
+         lastxhairindex[myID] = 0;
+    // write to file or outputQ
+         for(i=0; i<xhairRendered; i++)
+         {
+      if(outputStreams)
+                   newSampleSet[myID][i].writeToFile(T_SAMPLE, 
streamfile[myID]);
+      outputQ[myID].qInsert( &newSampleSet[myID][i] );
+         }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// This method adjusts the kdtree-cut by either merging nodes along the cut
+// or splitting nodes and adding their children to the cut.
+///////////////////////////////////////////////////////////////////////////////
+void GSTAFRImageTraverser::adjustTiles(int id, Timestamp currenttime)
+{
+  float minError, maxError;
+       int count;
+  int required_tiles = kdtree[id].getMaxTiles();
+  count = 0;
+  if(kdtree[id].number_of_tiles()!=required_tiles)
+  {
+    do
+    {
+      while(kdtree[id].number_of_tiles()>required_tiles && 
count<MAX_MERGE_SPLIT_LIMIT)  
+      {
+        count++;
+        kdtree[id].merge(kdtree[id].getminErrorParentTile(), currenttime, 
samplingrate); 
+      }
+      while(kdtree[id].number_of_tiles()<required_tiles && 
count<MAX_MERGE_SPLIT_LIMIT) 
+      { 
+        count++;
+        kdtree[id].split(kdtree[id].getmaxErrorTile(), currenttime, 
samplingrate);
+      }
+    }
+    while(kdtree[id].number_of_tiles()!=required_tiles && 
count<MAX_MERGE_SPLIT_LIMIT);
+  }
+     
+  minError = kdtree[id].getminError();
+  maxError = kdtree[id].getmaxError();
+  //cout << "minError = " << minError << ",  maxError = " << maxError << 
endl;
+  if(minError/maxError<MAX_MIN_RATIO)
+  {
+    int num_tiles_merged, i;
+    count = 0;
+    do
+    {
+      count++;
+      num_tiles_merged = 
kdtree[id].merge(kdtree[id].getminErrorParentTile(), currenttime, 
samplingrate); 
+      for(i=0; i<num_tiles_merged && count<MAX_MERGE_SPLIT_LIMIT; i++)
+      {
+        count++;
+        kdtree[id].split(kdtree[id].getmaxErrorTile(), currenttime, 
samplingrate);
+      }
+      minError = kdtree[id].getminError();
+      maxError = kdtree[id].getmaxError();
+    }
+    while(minError/maxError<MAX_MIN_RATIO && count<MAX_MERGE_SPLIT_LIMIT);
+  }
+}
+
+#include <Interface/RTRTInterface.h>
+#include <Interface/Callback.h>
+
+
+// If all of the threads have initialized start the benchmark.
+void BenchHelper::tryStart( int, int ) {
+  
+  GSTAFRImageTraverser *traverser = (GSTAFRImageTraverser 
*)rtrt->getImageTraverser();
+  
+  // Check to see if all threads initialized.
+  if (!traverser->allThreadsInitialized()) {
+    // std::cout << "Try setup failed" << std::endl;
+    rtrt->addOneShotCallback(RTRTInterface::Relative, 10,
+                             Callback::create(this, &BenchHelper::tryStart));
+    return;
+  }
+
+  // std::cout << "Beginning benchmark" << std::endl;
+  
+  // Otherwise
+  start_time = SCIRun::Time::currentSeconds();
+  start_samples = traverser->getSamplesDone();
+  
+  rtrt->addOneShotCallback(RTRTInterface::Relative, outer_loops,
+                           Callback::create(this, &BenchHelper::stop));
+}
+
+// Take the final measurement.
+void BenchHelper::stop (int, int) {
+  
+  GSTAFRImageTraverser *traverser = (GSTAFRImageTraverser 
*)rtrt->getImageTraverser();
+  
+  double end_time = SCIRun::Time::currentSeconds();
+  unsigned int end_samples = traverser->getSamplesDone();
+
+  // Determine samples per second.
+  double sps = (double)(end_samples - start_samples) / (end_time - 
start_time);
+  
+  // Output performance.
+  std::cout << sps << std::endl;
+  
+  delete this;
+  
+  SCIRun::Thread::exitAll(0);
+}

Added: branches/AFR/Engine/ImageTraversers/AFRImageTraverser.h
==============================================================================
--- (empty file)
+++ branches/AFR/Engine/ImageTraversers/AFRImageTraverser.h     Fri Sep 16 
15:27:11 2005
@@ -0,0 +1,69 @@
+
+#ifndef Manta_Engine_AFImageTraverser_h
+#define Manta_Engine_AFImageTraverser_h
+
+#include <SCIRun/Core/Thread/Time.h>
+#include <SCIRun/Core/Thread/Thread.h>
+
+#include <Interface/ImageTraverser.h>
+#include <Interface/Fragment.h>
+#include <sgi_stl_warnings_off.h>
+#include <string>
+#include <vector>
+#include <sgi_stl_warnings_on.h>
+#include <Engine/ImageTraversers/AFR/kdtree.h>
+#include <Engine/ImageTraversers/AFR/CQ.h>
+#include <Engine/ImageTraversers/AFR/sample.h>
+#include <Interface/XWindow.h>
+//#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include <GL/glx.h>
+
+#ifdef __ia64__
+#include <malloc.h>
+#include <ia64intrin.h>
+#endif
+
+namespace Manta {
+
+  using namespace std;
+  
+       namespace Afr {
+
+               class AFImageTraverser : public ImageTraverser {
+    
+      friend class AFRPipeline;
+    
+               public:
+    
+                       AFImageTraverser(const vector<string>& args);
+                       virtual ~AFImageTraverser();
+                       virtual void setupBegin(SetupContext&, int 
numChannels);
+                       virtual void setupDisplayChannel(SetupContext&);
+                       virtual void setupFrame(const RenderContext& context) 
{ /*Undefined for AFRPipeline.*/ };
+                       virtual void renderImage(const RenderContext& 
context, Image* image) { /*Undefined for AFRPipeline. */ };
+                       
+                       virtual void renderChunk(const RenderContext& 
context, Image* image, int xres, int yres);
+                       virtual int renderCrossHair(const RenderContext& 
context, int myID, 
+                          Image *image, const int xres, const int yres, 
+                          PartialSampleSet *sampleset, const int sscount,
+                          bool endChunk=false)=0;
+                       
+                       // Master thread task.
+                       virtual void masterTask(const RenderContext& context, 
Image* image)=0;
+                       
+                       // Sampler/Renderer task.
+                       virtual void clientTask(const RenderContext& context, 
Image* image)=0;
+                       virtual inline bool isMaster(int id)=0;
+                       // Update kdtree-cut.
+                       virtual void adjustTiles(int id, Timestamp 
currenttime)=0;
+                       virtual void createStatsWin()=0;
+                       virtual void display_stats()=0;
+                       virtual void toggleTileDisplayMode()=0;
+                       virtual void initStreams(int xres, int yres)=0;
+                       virtual void write_Tile_and_Camera(RenderContext& 
context)=0;
+                       virtual int setSamplingRate(unsigned int srate)=0;
+                       static ImageTraverser* create(const vector<string>& 
args);
+};
+
+#endif

Modified: branches/AFR/Engine/ImageTraversers/CMakeLists.txt
==============================================================================
--- branches/AFR/Engine/ImageTraversers/CMakeLists.txt  (original)
+++ branches/AFR/Engine/ImageTraversers/CMakeLists.txt  Fri Sep 16 15:27:11 
2005
@@ -6,8 +6,11 @@
      ImageTraversers/DissolveImageTraverser.cc
      ImageTraversers/DissolveTiledImageTraverser.cc
 
+     ImageTraversers/AFRImageTraverser.h
      ImageTraversers/AFImageTraverser.h
      ImageTraversers/AFImageTraverser.cc
+     ImageTraversers/GSTAFRImageTraverser.h
+     ImageTraversers/GSTAFRImageTraverser.cc
      ImageTraversers/AFR/CQ.h
      ImageTraversers/AFR/evil.h
      ImageTraversers/AFR/kdtree.cc
@@ -19,4 +22,4 @@
      ImageTraversers/AFR/tiles.h
     )
 
-# SOURCE_GROUP(ImageTraversers FILES ${Manta_ImageTraversers_SRCS})
\ No newline at end of file
+# SOURCE_GROUP(ImageTraversers FILES ${Manta_ImageTraversers_SRCS})

Added: branches/AFR/Engine/ImageTraversers/GSTAFRImageTraverser.cc
==============================================================================
--- (empty file)
+++ branches/AFR/Engine/ImageTraversers/GSTAFRImageTraverser.cc Fri Sep 16 
15:27:11 2005
@@ -0,0 +1,936 @@
+
+#include <Engine/ImageTraversers/GSTAFRImageTraverser.h>
+#include <Interface/RayPacket.h>
+#include <Interface/Renderer.h>
+#include <Interface/Context.h>
+#include <Interface/Fragment.h>
+#include <Interface/Camera.h>
+#include <Interface/Image.h>
+#include <Interface/LoadBalancer.h>
+#include <Interface/PixelSampler.h>
+#include <Core/Exceptions/IllegalArgument.h>
+#include <Core/Exceptions/IllegalValue.h>
+#include <Core/Exceptions/InternalError.h>
+#include <Core/Util/Args.h>
+#include <Core/Util/NotFinished.h>
+#include <Core/Thread/Mutex.h>
+#include <Core/XUtils/XHelper.h>
+
+
+#include <SCIRun/Core/Thread/Time.h>
+#include <cmath>
+
+#ifdef __sgi
+#include <ieeefp.h>
+#endif
+
+#include <GL/glu.h>
+#define XhairPacketSize RayPacket::MaxSize/3
+#define MAX_MIN_RATIO 0.5
+#define MAX_MERGE_SPLIT_LIMIT 50
+
+using namespace std;
+using namespace Manta;
+using namespace Manta::Afr;
+
+using SCIRun::IllegalValue;
+using SCIRun::InternalError;
+
+using namespace std;
+
+// args are the command line options, if the user wants to pas to th
+// eimage traverser look in TiledimageTraverser.cc for usage
+ImageTraverser* GSTAFRImageTraverser::create(const vector<string>& args)
+{
+  return new GSTAFRImageTraverser(args);
+}
+
+GSTAFRImageTraverser::GSTAFRImageTraverser(const vector<string>& args) :
+  myRandomNumber( 0 ),
+  inner_loop_time( 0.06 ),
+  chunk_size( 256 ),
+  debug_window( false ),
+  samplingrate( 400000 ),
+  displayClientId( 0 ),
+  visScale( 1.0 ),
+  outputStreams( false ),
+  spatialCoherence( false ),
+  num_masters( 1 ),
+  //streamlock( "streamlock" ),
+  tmode(SOLID)
+{
+
+  for (int i=0;i<args.size();++i) {
+    if (args[i] == "-inner") {
+      if (!getArg( i, args, inner_loop_time )) {
+        throw IllegalArgument("-inner <Real>", i, args);
+      }
+    }
+    if (args[i] == "-chunk") {
+      if (!getArg( i, args, chunk_size )) {
+        throw IllegalArgument("-chunk <Int>", i, args);
+      }
+    }
+    if (args[i] == "-samplingrate") {
+      if (!getArg( i, args, samplingrate )) {
+        throw IllegalArgument("-samplingrate <Int>", i, args);
+      }
+    }
+    if (args[i] == "-groups") {
+      if (!getArg( i, args, num_masters )) {
+        throw IllegalArgument("-groups <Int>", i, args);
+      }
+    }
+    if (args[i] == "-stream") {
+      if (!getArg( i, args, streamfilename )) {
+        throw IllegalArgument("-streamfilename <string>", i, args);
+      }
+      outputStreams = true;
+    }
+    if (args[i] == "-spatial") {
+      spatialCoherence = true;
+    }
+    if (args[i] == "-debug") {
+      debug_window = true;
+    }
+  }
+}
+
+GSTAFRImageTraverser::~GSTAFRImageTraverser()
+{
+  if(myRandomNumber!=NULL) delete [] myRandomNumber;
+  // free the kdtree and queues. I suppose this will be done automatically
+  // confirm!
+}
+
+
+void GSTAFRImageTraverser::createStatsWin()
+{
+  XHelper::Xlock.lock();
+  // Open the display and make sure it has opengl
+  dpy = XOpenDisplay(NULL);
+  if(!dpy) {
+    XHelper::Xlock.unlock();
+    throw InternalError("Error opening display", __FILE__, __LINE__);
+  }
+  int error, event;
+  if ( !glXQueryExtension( dpy, &error, &event) ) {
+    XCloseDisplay(dpy);
+    dpy=0;
+    XHelper::Xlock.unlock();
+    throw InternalError("GL extension NOT available!\n", __FILE__, __LINE__);
+  }
+  
+  int screen=DefaultScreen(dpy);
+    
+  // Form the criteria for the 
+  vector<int> attribList;
+  attribList.push_back(GLX_RGBA);
+  attribList.push_back(GLX_RED_SIZE); attribList.push_back(1);
+  attribList.push_back(GLX_GREEN_SIZE); attribList.push_back(1);
+  attribList.push_back(GLX_BLUE_SIZE); attribList.push_back(1);
+  attribList.push_back(GLX_ALPHA_SIZE); attribList.push_back(0);
+  attribList.push_back(GLX_DEPTH_SIZE); attribList.push_back(0);
+  attribList.push_back(GLX_DOUBLEBUFFER); // This must be the last one
+  attribList.push_back(None);
+
+  XVisualInfo* vi = glXChooseVisual(dpy, screen, &attribList[0]);
+  if(!vi){
+    // We failed to choose a visual.  Try again without the double-buffer 
flag
+    attribList.pop_back();
+    attribList.pop_back();
+    attribList.push_back(None);
+    vi = glXChooseVisual(dpy, screen, &attribList[0]);
+  }
+
+  Colormap cmap = XCreateColormap(dpy, RootWindow(dpy, screen),
+                                 vi->visual, AllocNone);
+
+  XSetWindowAttributes atts;
+  int flags=CWColormap|CWEventMask|CWBackPixmap|CWBorderPixel;
+  atts.background_pixmap = None;
+  atts.border_pixmap = None;
+  atts.border_pixel = 0;
+  atts.colormap=cmap;
+  
atts.event_mask=StructureNotifyMask|ExposureMask|KeyPressMask|KeyReleaseMask;
+  Window parent = RootWindow(dpy, screen);
+  statsWindow.window=XCreateWindow(dpy, parent, 600, 0, DISPLAY_WIDTH, 
DISPLAY_HEIGHT, 0, vi->depth,
+                   InputOutput, vi->visual, flags, &atts);
+
+  XTextProperty tp;
+  char* name = "AFR Debug";
+  XStringListToTextProperty(&name, 1, &tp);
+  XSizeHints sh;
+  sh.flags = USPosition|USSize;
+  
+  XSetWMProperties(dpy, statsWindow.window, &tp, &tp, 0, 0, &sh, 0, 0);
+  XMapWindow(dpy, statsWindow.window);
+
+  // Wait for the window to appear before proceeding
+  for(;;){
+    XEvent e;
+    XNextEvent(dpy, &e);
+    if(e.type == MapNotify)
+      break;
+  }
+
+  windowOpen = true;
+
+  gl_context = glXCreateContext(dpy, vi, NULL, True);
+  XFree(vi);
+
+  if(!glXMakeCurrent(dpy, statsWindow.window, gl_context)) {
+    XHelper::Xlock.unlock();
+    throw InternalError("glXMakeCurrent failed!\n", __FILE__, __LINE__);
+  }
+  
+  glViewport(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT);
+  glMatrixMode(GL_PROJECTION);
+  glLoadIdentity();
+  gluOrtho2D(0, DISPLAY_WIDTH, 0, DISPLAY_HEIGHT);
+  glMatrixMode(GL_MODELVIEW);
+  glLoadIdentity();
+  
+  glClearColor(.05, .1, .2, 0);
+  glClear(GL_COLOR_BUFFER_BIT);
+  
+  glXSwapBuffers(dpy, statsWindow.window);
+  glFinish();
+
+  // Get the fonts.  You need to call this with a current GL context.
+  fontInfo = XHelper::getX11Font(dpy);
+  if (!fontInfo) {
+    XHelper::Xlock.unlock();
+    throw InternalError("getX11Font failed!\n", __FILE__, __LINE__);
+  }
+  fontbase = XHelper::getGLFont(fontInfo);
+  if (fontbase == 0) {
+    XHelper::Xlock.unlock();
+    throw InternalError("getGLFont failed!\n", __FILE__, __LINE__);
+  }
+
+  if(!glXMakeCurrent(dpy, None, NULL)) {
+    XHelper::Xlock.unlock();
+    throw InternalError("glXMakeCurrent failed!\n", __FILE__, __LINE__);
+  }
+  
+  XHelper::Xlock.unlock();
+}
+
+void GSTAFRImageTraverser::display_stats() {
+  static int fcount = 0;
+     // Display textual information on the screen:
+    char text[200];
+    
+    switch(tmode)
+    {
+      case SOLID: sprintf(text, "Client: %d: Random Color Tiles (x %d)", 
displayClientId, (int)visScale); break;
+      case BOUNDARY: sprintf(text, "Client: %d: Tiles colored by size (x 
%d)", displayClientId, (int)visScale); break;
+      case DERIVATIVE: sprintf(text, "Client: %d: Derivative (x %d)", 
displayClientId, (int)visScale); break;
+      case OCCLUSION: sprintf(text, "Client: %d: Occlusion; (x %d)", 
displayClientId, (int)visScale); break;
+      case ABSOLUTE_GRADIENT: sprintf(text, "Client: %d: ABS Gradients (x 
%d)", displayClientId, (int)visScale); break;
+      case RELATIVE_GRADIENT: sprintf(text, "Client: %d: REL Gradients (x 
%d)", displayClientId, (int)visScale); break;
+      case SAMPLING_DENSITY: sprintf(text, "Client: %d: Sample density (x 
%d)", displayClientId, (int)visScale); break;
+      case UNDERSAMPLING: sprintf(text, "Client: %d: Undersampling (x %d)", 
displayClientId, (int)visScale); break;
+      case AVERAGE_AGE: sprintf(text, "Client: %d: Average Age (x %d)", 
displayClientId, (int)visScale); break;
+      case JITTERING: sprintf(text, "Client: %d: Jittering (x %d)", 
displayClientId, (int)visScale); break;
+      default: sprintf(text, "Client: %d: Random Color Tiles (x %d)", 
displayClientId, (int)visScale); break;
+    };
+  
+    if(!glXMakeCurrent(dpy, statsWindow.window, gl_context))
+      throw InternalError("GSTAFRImageTraverser::glXMakeCurrent failed!\n",
+                          __FILE__, __LINE__);
+    glClearColor(.05, .1, .2, 0);
+    glClear(GL_COLOR_BUFFER_BIT);
+    kdtree[displayClientId].displayTiles(tmode, 
chunkTimeStamp[displayClientId], visScale, samplingrate);
+    // Figure out how wide the string is
+    int width = XHelper::calc_width(fontInfo, text);
+    // Now we want to draw a gray box beneth the font using blending. :)
+    glEnable(GL_BLEND);
+    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+    glColor4f(0.5,0.5,0.5,0.5);
+    glRecti(8,3-fontInfo->descent-2,25+width,fontInfo->ascent+3);
+    glDisable(GL_BLEND);
+    XHelper::printString(fontbase, 10, 3, text, RGBColor(1,1,1));
+    glXSwapBuffers(dpy, statsWindow.window);
+    glFinish();
+    // Suck up X events to keep opengl happy
+    while (XPending(dpy)) {
+      XEvent e;
+      XNextEvent(dpy, &e);
+      switch (e.type) {
+      case KeyPress:
+        {
+            unsigned long key = XKeycodeToKeysym(dpy, e.xkey.keycode, 0);
+            switch (key) {
+                case XK_m:
+                case XK_M:
+                    toggleTileDisplayMode();
+                    break;
+                case XK_b:
+                case XK_B:
+                    visScale++;
+                    break;
+                case XK_l:
+                case XK_L:
+                    if (visScale>0) visScale--;
+                    break;
+                               case XK_t:
+                               case XK_T:
+                                       displayClientId++;
+                                       if(displayClientId>=num_masters) 
+                                               displayClientId = 0;
+                                       break;
+            }
+        }
+      };
+    }
+  
+}
+
+void GSTAFRImageTraverser::toggleTileDisplayMode()
+{
+       switch(tmode)
+               {
+                       case SOLID: tmode = BOUNDARY; break;
+                       case BOUNDARY: tmode = DERIVATIVE; break;
+                       case DERIVATIVE: tmode = OCCLUSION; break;
+                       case OCCLUSION: tmode = ABSOLUTE_GRADIENT; break;
+                       case ABSOLUTE_GRADIENT: tmode=RELATIVE_GRADIENT; 
break;
+                       case RELATIVE_GRADIENT: tmode=SAMPLING_DENSITY; break;
+                       case SAMPLING_DENSITY: tmode = AVERAGE_AGE; break;
+                       case AVERAGE_AGE: tmode = UNDERSAMPLING; break;
+                       case UNDERSAMPLING: tmode = JITTERING; break;
+                       case JITTERING: tmode = SOLID; break;   
+                       default: tmode = SOLID; break;
+               };                      
+}
+
+void GSTAFRImageTraverser::setupBegin(SetupContext& context, int 
numChannels) {
+
+  context.loadBalancer->setupBegin(context, numChannels);
+
+  if (debug_window) {
+    context.setMultipleGLWindows();
+    statsWindow.xres = DISPLAY_WIDTH; statsWindow.yres = DISPLAY_HEIGHT;
+    createStatsWin();
+  }
+}
+
+#define DESIRED_FRAME_RATE 15
+void GSTAFRImageTraverser::initStreams(int xres, int yres)
+{              // print the version info
+           char fname[80];
+               time_t t;
+               time(&t);
+               //streamlock.lock();
+               for(int i=0; i<num_clients; i++)
+               {
+                 sprintf(fname,"%s%03d",streamfilename.c_str(),i);
+                 streamfile[i] = fopen(fname,"wb");
+                 fprintf(streamfile[i], "Version 1.3\n");
+                 fprintf(streamfile[i],"Created on: %s", ctime(&t));
+                 // print the width and height
+                 fprintf(streamfile[i],"width %d\n", xres);
+                 fprintf(streamfile[i],"height %d\n", yres);
+                 // print the simulated frame rate
+                 fprintf(streamfile[i],"frame_rate %d\n",DESIRED_FRAME_RATE);
+                 fprintf(streamfile[i],"END\n");
+                 //streamlock.unlock();
+                 cout << "initialized stream for client " << i << endl;
+        }
+}
+
+void GSTAFRImageTraverser::write_Tile_and_Camera(RenderContext& context)
+{
+  if(!outputStreams) return;
+  
+  
+  //streamlock.lock();
+  int myID = context.proc;
+  
+  fprintf(streamfile[myID],"\n\nbegin_tiles\n");
+  fprintf(streamfile[myID],"num_tiles %d\n",kdtree[myID].number_of_tiles());
+  // call thread's tree, print to file function
+  kdtree[myID].writeToFile(streamfile[myID], 
(float)chunkTimeStamp[context.proc], samplingrate);
+  // have flag for camera and dump the camera
+  fprintf(streamfile[myID],"\n\nbegin_camera\n");
+  // print camera to file
+  context.camera->writeToFile(streamfile[myID]);
+  // have a flag saying sampling begun
+  fprintf(streamfile[myID],"\n\nbegin_samples\n");
+       
+  if(firsttime[myID]==1)
+    firsttime[myID] = 0;
+  else
+  // print the total samples done in this chunk in the space reserved for 
that before
+  {
+    int samplesDoneThisChunk = samples_done[myID].load() - 
last_samples_done[myID];
+         last_samples_done[myID] = samples_done[myID].load();
+    fpos_t tpos;
+         fgetpos(streamfile[myID], &tpos);
+         fsetpos(streamfile[myID],&numsamples_pos[myID]);
+         fprintf(streamfile[myID],"%d",samplesDoneThisChunk);
+         fsetpos(streamfile[myID], &tpos);
+  }
+  
+  // reserve space for total samples in this chunk
+  fprintf(streamfile[myID],"num_samples ");
+  fgetpos(streamfile[myID], &numsamples_pos[myID]);
+  fprintf(streamfile[myID],"                                               
\n");
+
+  //streamlock.unlock();
+}
+
+void GSTAFRImageTraverser::setupDisplayChannel(SetupContext& context) {
+
+       // Specify that the rendering pipeline should use only one image 
buffer.
+  if (debug_window)
+    context.setMultipleGLWindows();
+
+  context.constrainPipelineDepth(1,1); // single buffer mode is set here
+       
+  bool stereo; // get whether it is stereo, (shoot two rays for left
+               // and right eye)
+  int i;
+  int xres,yres;
+  num_clients = context.numProcs;
+  cout << "number of masters = " << num_masters << endl;
+  groupSize = new int[num_masters];
+  avgGroupSize = num_clients/num_masters;
+  for(i=0; i<num_masters-1; i++)
+  {
+         groupSize[i] = avgGroupSize;
+    cout << " number of clients for master " << i+1 << " = " << avgGroupSize 
<< endl;
+  }
+  groupSize[num_masters-1] = num_clients-avgGroupSize*(num_masters-1);
+  cout << " number of clients for master " << num_masters << " = " << 
groupSize[num_masters-1] << endl;
+  
+  cout << "samplingrate = " << samplingrate << endl;
+  // Samples done.
+#ifdef __ia64__
+  samples_done = (SamplesDone *)memalign( 128, 
sizeof(SamplesDone)*num_clients );
+#else
+  samples_done = (SamplesDone *)malloc( sizeof(SamplesDone)*num_clients );
+#endif
+  memset( samples_done, 0x0, sizeof(SamplesDone)*num_clients );
+  last_samples_done = new int[num_masters];
+  chunkTimeStamp = new double[num_masters];
+
+  // this will change when we can actually simulate 
+  context.getResolution(stereo, xres, yres);
+  cout << "context resolution is: " << xres << ", " << yres << endl;
+  //---------------------------------------------------------
+  // initialize random number generators for each thread.
+  //---------------------------------------------------------
+  myRandomNumber = new MT_RNG[context.numProcs];
+  for(i=0; i<context.numProcs; i++) {
+    myRandomNumber[i].seed_rng(1234*(i+1)); // just to begin give a simple 
seed
+  }
+       
+  
/////////////////////////////////////////////////////////////////////////////
+  // Create a kdtree for each master.
+       
+  //---------------------------------------------------------
+  // make our kdtree, given the resolution of image/channel
+  //---------------------------------------------------------
+  kdtree = new KDTree[num_masters];
+  updatecount = new int[num_masters];
+  for(i=0; i<num_masters; i++)
+  {
+    // samples_done[i] = 0;
+    
+    chunkTimeStamp[i] = (float)SCIRun::Time::currentSeconds();
+         last_samples_done[i] = 0;
+    kdtree[i].setAB(samplingrate);
+    kdtree[i].init(xres, yres, samplingrate);  // initialize the tree
+    updatecount[i] = 0;
+    // set a mean number of tiles, i.e. cut at middle of tree
+    kdtree[i].resetPseudoRandomSeed(myRandomNumber[i*avgGroupSize]);
+  }
+  
+  // chunk_size = 256; // this is a fixed number as of now
+  maxQSize = qSize = (int)(samplingrate*0.1); // temporal queue size
+  temporalQ = new CQ<PartialSampleSet>[num_clients];
+  outputQ = new CQ<PartialSampleSet>[num_clients];
+  newSampleSet = new PartialSampleSet* [num_clients];
+  newTempSampleSet = new PartialSampleSet* [num_clients];
+  color = new Color* [num_clients];
+  initpass = new bool[num_clients];
+  lastxhairindex = new int[num_clients];
+  // Initialize 
+  for(i = 0; i<num_clients; i++)
+  {
+    initpass[i] = false;
+    lastxhairindex[i] = 0;
+    temporalQ[i].init(qSize+1);
+    outputQ[i].init(chunk_size*20);
+    color[i] = new Color [10*chunk_size];
+    newSampleSet[i] = new PartialSampleSet[10*chunk_size];
+    newTempSampleSet[i] = new PartialSampleSet[10*chunk_size]; 
+  }
+  if(outputStreams)
+  {
+    firsttime = new int[num_clients];
+         for(i=0; i<num_clients; i++)
+           firsttime[i] = 1;
+    numsamples_pos = (fpos_t*)malloc(num_clients*sizeof(fpos_t));
+    streamfile = (FILE**)malloc(num_clients*sizeof(FILE*));
+    initStreams(xres, yres);   
+  }
+}
+
+int GSTAFRImageTraverser::renderCrossHair(const RenderContext& context, int 
myID, 
+                                      Image *image, const int xres, const 
int yres, 
+                                      PartialSampleSet *sampleset, int 
sscount, bool endChunk)
+{
+  int start = lastxhairindex[myID];
+  //cout << "now rendering xhair " << myID << ", " << xres << ", " << yres 
<< ", " << sscount << ", " << endChunk << ", " << XhairPacketSize << endl;
+  if((sscount-start+1)<RayPacket::MaxSize && !endChunk)
+  {
+    newSampleSet[myID][sscount].reset();
+    newSampleSet[myID][sscount] = *sampleset;
+    //newSampleSet[myID][sscount].tileindex = 
kdtree[context.proc].getTileforXY(s->viewCoord[0], s->viewCoord[1]);
+    //cout << "checking ...sscount = " << sscount << ", blockstart = " << 
xhairBlockStart[myID] << endl;
+    return 0;
+  }
+  if(start>=sscount) return 0;
+  int myMasterID = myID/avgGroupSize;
+  float t = (float)chunkTimeStamp[myMasterID];
+  int flags = RayPacket::HaveImageCoordinates | RayPacket::ConstantEye;
+  int depth = 0;
+  RayPacketData raydata;
+  RayPacket rays(raydata, (sscount-start+1), depth, flags);
+  int i, j;
+  j = 0;
+  //cout << "size = " << (sscount-start+1) << endl;
+  for(i=start; i<=sscount; i++) {
+    double px, py;
+    if(xres > yres) // let the smaller dimension be mapped to [-1,1]
+    {
+      px = (double)(-1.0 + 
2.0*(newSampleSet[myID][i].sample[C_SAMPLE].viewCoord[0])/(double)yres); 
+      py = (double)(-1.0 + 
2.0*(newSampleSet[myID][i].sample[C_SAMPLE].viewCoord[1])/(double)yres);
+    }
+    else
+    {
+      px = (double)(-1.0 + 
2.0*(newSampleSet[myID][i].sample[C_SAMPLE].viewCoord[0])/(double)xres); 
+      py = (double)(-1.0 + 
2.0*(newSampleSet[myID][i].sample[C_SAMPLE].viewCoord[1])/(double)xres);
+    }  
+      
+    // Specify the pixel.
+    rays.setPixel(j, 0, px, py, &color[myID][j]);
+    j++;
+  }
+  
/////////////////////////////////////////////////////////////////////////////
+  // Trace the rays.  The results will automatically go into the fragment  
+  context.renderer->traceEyeRays(context, rays);
+  rays.computeHitPositions();
+  lastxhairindex[myID] = sscount+1;
+  
/////////////////////////////////////////////////////////////////////////////
+  // okay now copy from fragment to temporalQ
+  j = 0;
+  for(i=start; i<=sscount; i++) {
+    RayPacket::Element& re = rays.get(j);
+    RGBColor tempcol = color[myID][j].convertRGB();
+    //cout << "processing sampleset " << i << endl;
+    newSampleSet[myID][i].set( T_SAMPLE, 
+                newSampleSet[myID][i].sample[C_SAMPLE].viewCoord[0],
+                newSampleSet[myID][i].sample[C_SAMPLE].viewCoord[1], t, 
+                re.hitPosition.x(), re.hitPosition.y(), re.hitPosition.z(),
+                tempcol.r(), tempcol.g(), tempcol.b() ); 
+    newSampleSet[myID][i].computeGradients(t);
+    //cout << "grad info <complete>: " << newSampleSet[myID][i].xgrad << ", "
+    //     << newSampleSet[myID][i].ygrad << ", " 
+    //     << newSampleSet[myID][i].tgrad << endl;
+    samples_done[myID].addOne();  
+    image->set( (int)(newSampleSet[myID][i].sample[C_SAMPLE].viewCoord[0]), 
+                (int)(newSampleSet[myID][i].sample[C_SAMPLE].viewCoord[1]), 
color[myID][j] );
+    j++;
+  }
+
+  //cout << "done one xhairBlock" << endl;
+  return (sscount-start+1);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Render all of samples in a fragment of the chunk.
+///////////////////////////////////////////////////////////////////////////////
+void GSTAFRImageTraverser::renderChunk(const RenderContext& context,
+                                      Image* image, 
+                                      int xres, int yres)
+{
+  //cout << "inside renderChunk " << endl;
+       
+  // renders the fragment by jittering it and stores result in temporalQ
+  int flags = RayPacket::HaveImageCoordinates | RayPacket::ConstantEye;
+  int i, j, f;
+  int myID = context.proc;
+  int myMasterID = myID/avgGroupSize;
+  int fsize = chunk_size;
+  float t = (float)chunkTimeStamp[myMasterID];
+  if(initpass[myID])
+  {
+    fsize = (chunk_size>(qSize-temporalQ[myID].getN()))? chunk_size : 
qSize-temporalQ[myID].getN();
+    if((fsize + temporalQ[myID].getN()) > temporalQ[myID].getMaxSize())
+           fsize = temporalQ[myID].getMaxSize() - temporalQ[myID].getN() -1;
+    //cout << "fsize = " << fsize << endl;
+  }
+  Color color[RayPacket::MaxSize];
+  //Sample newSample[RayPacket::MaxSize];
+  //cout << "fsize = " << fsize << ", myID = " << myID << endl;
+  
/////////////////////////////////////////////////////////////////////////////
+  // Create ray packets.
+  int raypacketsize = 3*(RayPacket::MaxSize/3);
+  //cout << "raypacketsize = " << raypacketsize << endl;
+  int numXhairPerRayPack = raypacketsize/3;
+ // cout << "numXhairPerRayPack = " << numXhairPerRayPack << endl;
+  if(isMaster(myID))
+  {
+    float scalefac = (avgGroupSize>10)? 0.0f : (10.0f-avgGroupSize+1)/10.0f;
+    fsize = (int)(fsize*scalefac);
+  }
+  
+  for(f=0;f<fsize;f+=numXhairPerRayPack) {
+    // Create a ray packet
+    int depth = 0;
+    RayPacketData raydata;
+    RayPacket rays(raydata, raypacketsize, depth, flags);
+    int cx, cy, ox, oy;
+    int tindex = kdtree[myMasterID].getRandomTile(myRandomNumber[myID]);
+    //int tindex = kdtree[myID].getPseudoRandomTile();
+    //cout << "got tile " << tindex << endl;
+    
+    //if(spatialCoherence)
+    //{
+      // do the 10x4 thing here
+    //}
+    //else 
+    for(i=0; i<numXhairPerRayPack; i++)
+    {
+      kdtree[myMasterID].getRandomSamplefromTile(tindex, cx, cy, 
myRandomNumber[myID]);
+      //cout << "got random loc: " << cx << ", " << cy << endl;
+      double jitterx, jittery;
+      jitterx = myRandomNumber[myID].genfrand()-0.5;
+      jittery = myRandomNumber[myID].genfrand()-0.5;
+      newTempSampleSet[myID][f+i].setTempXhair((cx+jitterx), (cy+jittery), 
xres, yres, tindex, t);
+      for(j=0; j<3; j++)
+      {
+        // normalized
+        double px, py;
+                       
+        if(xres>yres) // let the smaller dimension be mapped to [-1,1]
+        {
+          px = (double)(-1.0 + 
2.0*((double)newTempSampleSet[myID][f+i].sample[j].viewCoord[0])/(double)yres);
 
+          py = (double)(-1.0 + 
2.0*((double)newTempSampleSet[myID][f+i].sample[j].viewCoord[1])/(double)yres);
+        }
+        else
+        {
+          px = (double)(-1.0 + 
2.0*((double)newTempSampleSet[myID][f+i].sample[j].viewCoord[0])/(double)xres);
 
+          py = (double)(-1.0 + 
2.0*((double)newTempSampleSet[myID][f+i].sample[j].viewCoord[1])/(double)xres);
+        }  
+                               // samples_done[context.proc] ++;
+        samples_done[myID].addOne();
+        // Specify the position and color pointer for the packet element.
+        rays.setPixel(i*3+j, 0, px, py, &color[i*3+j]);
+        if(!spatialCoherence) tindex = 
kdtree[myMasterID].getRandomTile(myRandomNumber[myID]);
+        //tindex = kdtree[myMasterID].getPseudoRandomTile();
+        //cout << "got tile " << tindex << endl;
+      }
+    }
+    
+    
//////////////////////////////////////////////////////////////////////////
+    // Trace the rays.  The results will automatically go into the fragment  
+    context.renderer->traceEyeRays(context, rays);
+               
+    // Compute world space hit positions.
+    rays.computeHitPositions();
+               
+    
///////////////////////////////////////////////////////////////////////////
+    // okay now copy from fragment to temporalQ
+    for(i=0;i<raypacketsize;i++) {
+    
+      RayPacket::Element& re = rays.get(i);
+      RGBColor tempcol = color[i].convertRGB();      
+      newTempSampleSet[myID][f+i/3].set(i%3, 
+                                        
newTempSampleSet[myID][f+i/3].sample[i%3].viewCoord[0],
+                                        
newTempSampleSet[myID][f+i/3].sample[i%3].viewCoord[1],
+                                        t,
+                                        re.hitPosition.x(), 
re.hitPosition.y(), re.hitPosition.z(),
+                                        tempcol.r(), tempcol.g(), 
tempcol.b() );
+      /*cout << "setting: " << i%3 << ", " 
+           << newTempSampleSet[myID][f+i/3].sample[i%3].viewCoord[0] << ", " 
+           << newTempSampleSet[myID][f+i/3].sample[i%3].viewCoord[1] << ", " 
+           << newTempSampleSet[myID][f+i/3].timestamp << ", " 
+           << re.hitPosition.x() << ", " << re.hitPosition.y() << ", "  << 
re.hitPosition.z() << ", " 
+           << tempcol.r() << ", " << tempcol.g() << ", " << tempcol.b() << 
endl;*/
+      
/////////////////////////////////////////////////////////////////////////////
+      // Skip reconstruction and set the image pixel.
+      
image->set((int)(newTempSampleSet[myID][f+i/3].sample[i%3].viewCoord[0]), 
+                 
(int)(newTempSampleSet[myID][f+i/3].sample[i%3].viewCoord[1]), 
+                 color[i]);
+    }
+  }
+  for(f=0; f<fsize; f++)
+  {
+    newTempSampleSet[myID][f].computeGradients(t);
+    //cout << "grad info (chunk): " << newSampleSet[myID][f].xgrad << ", "
+    //     << newSampleSet[myID][f].ygrad << ", " 
+    //     << endl;
+    temporalQ[myID].qInsert(&newTempSampleSet[myID][f]);
+    outputQ[myID].qInsert(&newTempSampleSet[myID][f]);
+  }
+       // write to stream if required and to the queues
+  if(outputStreams)
+  {
+    for(f=0; f<fsize; f++)
+    {
+      newTempSampleSet[myID][f].writeToFile(C_SAMPLE, streamfile[myID]);
+      newTempSampleSet[myID][f].writeToFile(X_SAMPLE, streamfile[myID]);
+      newTempSampleSet[myID][f].writeToFile(Y_SAMPLE, streamfile[myID]);
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// This method implements the master thread functionality.
+///////////////////////////////////////////////////////////////////////////////
+void GSTAFRImageTraverser::masterTask(const RenderContext& context, Image* 
image) {
+
+  // update kdtree based on previous results from the client threads
+  
+  bool stereo;
+  int i, j;
+  int xres, yres;
+  image->getResolution(stereo, xres, yres);
+  // get the masterID
+  int masterID;
+  masterID = context.proc/avgGroupSize;
+  chunkTimeStamp[masterID] = (float)SCIRun::Time::currentSeconds();
+  
+  //cout << "master = " << masterID << ", has " << groupSize[masterID] << " 
clients" << endl; 
+  // for clients context.proc+1 to context.proc+groupSize[masterID]
+  // read output queue of all clients and update the kdtree[masterID]
+  
+  for(i=masterID; i<masterID+groupSize[masterID]; i++)
+  {
+    int qsize = outputQ[i].getN()-1;
+    if(qsize>=chunk_size-2)
+      for(j=0; j<qsize; j++)
+      {
+        PartialSampleSet *npss = outputQ[i].seekLast();
+        outputQ[i].qDelete();
+        if(npss==NULL) break;
+        updatecount[masterID]++;
+        // add sample to the corresponding kdtree
+        //npss->print();
+       // if(npss->xgrad>0 || npss->ygrad>0 || npss->tgrad>0)
+       // {
+       //   cout << "grads: ( " << npss->xgrad 
+       //        << ", " << npss->ygrad 
+       //        << ", " << npss->tgrad << " ) " << endl;
+       // }
+        kdtree[masterID].updateStatsAddPartialSampleSet(npss, 
(float)chunkTimeStamp[masterID], samplingrate);
+      }
+  }
+  //cout << "time (thread = " << context.proc << " ) is now " << 
chunkTimeStamp[context.proc] << endl; 
+  // return during intialization here 
+  if(updatecount[masterID] >= chunk_size)
+  {
+    //cout << updatecount[masterID] <<  " xhairs added to tree " << endl;
+    updatecount[masterID] = 0;
+    // adjust tiles based on current status
+    if(chunkTimeStamp[masterID]>5)
+    adjustTiles(masterID, (float)chunkTimeStamp[masterID]);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// This method implements the master thread functionality.
+///////////////////////////////////////////////////////////////////////////////
+void GSTAFRImageTraverser::clientTask(const RenderContext& context, Image* 
image) {
+
+  //cout << "inside clientThread for frametype " << frametype[context.proc] 
<< endl;
+  bool stereo;
+  int xres, yres;
+  image->getResolution(stereo, xres, yres);
+  int myID = context.proc;
+  int myMasterID = myID/avgGroupSize;
+  Sample s;
+  kdtree[myMasterID].setAB(samplingrate);
+  // render the chunk
+  renderChunk(context, image, xres, yres);
+  
+  int xhairRendered = 0;
+  if(!initpass[myID])
+  {
+    if(temporalQ[myID].isFull()) {
+      initpass[myID] = true;
+      std::cerr << "Thread: " << context.proc << " has its queues 
initialized" << std::endl;
+    }
+  }
+  else 
+  {
+    // initialization is done so we can reproject one chunk worth
+    int i, j;
+         int sscount=0;
+    PartialSampleSet *sp;
+    //cout << "now making xhairs" << endl;
+       
+    int  fsize = temporalQ[myID].getN()-qSize;
+    for(i=0; i<fsize; i++)
+      temporalQ[myID].qDelete();
+               
+    //cout << "fsize = " << fsize << endl;
+    if(isMaster(myID))
+    {
+      float scalefac = (avgGroupSize>10)? 0.0f : 
(10.0f-avgGroupSize+1)/10.0f;
+      fsize = (int)(chunk_size*scalefac);
+    }
+    else
+      fsize = chunk_size;
+    for(i=0; i<fsize; i++) {
+               
+      sp = temporalQ[myID].seekLast();
+      if(sp!=NULL) {
+        temporalQ[myID].qDelete();
+        Manta::Real px, py, pz;
+        for(j=0; j<3; j++)
+        {
+          px = sp->sample[j].worldCoord[0];
+          py = sp->sample[j].worldCoord[1];
+          pz = sp->sample[j].worldCoord[2];
+        
+        //if the point is INF, no need to reproject as it will remain the 
same
+#ifdef __sgi
+          if(finite(px) && finite(py) && finite(pz))
+#else
+          if(!isinf(px) && !isinf(py) && !isinf(pz))
+#endif
+          {
+            const Point p(px, py, pz);
+            Point rp;
+            rp = context.camera->project(p);
+            sp->sample[j].viewCoord[0] = rp.x()*xres;
+            sp->sample[j].viewCoord[1] = rp.y()*yres;
+            sp->sample[j].viewCoord[2] = rp.z();
+          }
+        }
+        if(sp->sample[C_SAMPLE].viewCoord[0]<xres && 
sp->sample[C_SAMPLE].viewCoord[0]>=0 
+           && sp->sample[C_SAMPLE].viewCoord[1]<yres && 
sp->sample[C_SAMPLE].viewCoord[1]>=0
+           && sp->sample[C_SAMPLE].viewCoord[2]<=1.0)
+        {
+          xhairRendered += renderCrossHair(context, myID, image, xres, yres, 
sp, sscount);
+          sscount++;
+        }
+      }
+      else break;
+    }
+    xhairRendered += renderCrossHair(context, myID, image, xres, yres, sp, 
sscount-1, true);
+         lastxhairindex[myID] = 0;
+    // write to file or outputQ
+         for(i=0; i<xhairRendered; i++)
+         {
+      if(outputStreams)
+                   newSampleSet[myID][i].writeToFile(T_SAMPLE, 
streamfile[myID]);
+      outputQ[myID].qInsert( &newSampleSet[myID][i] );
+         }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// This method adjusts the kdtree-cut by either merging nodes along the cut
+// or splitting nodes and adding their children to the cut.
+///////////////////////////////////////////////////////////////////////////////
+void GSTAFRImageTraverser::adjustTiles(int id, Timestamp currenttime)
+{
+  float minError, maxError;
+       int count;
+  int required_tiles = kdtree[id].getMaxTiles();
+  count = 0;
+  if(kdtree[id].number_of_tiles()!=required_tiles)
+  {
+    do
+    {
+      while(kdtree[id].number_of_tiles()>required_tiles && 
count<MAX_MERGE_SPLIT_LIMIT)  
+      {
+        count++;
+        kdtree[id].merge(kdtree[id].getminErrorParentTile(), currenttime, 
samplingrate); 
+      }
+      while(kdtree[id].number_of_tiles()<required_tiles && 
count<MAX_MERGE_SPLIT_LIMIT) 
+      { 
+        count++;
+        kdtree[id].split(kdtree[id].getmaxErrorTile(), currenttime, 
samplingrate);
+      }
+    }
+    while(kdtree[id].number_of_tiles()!=required_tiles && 
count<MAX_MERGE_SPLIT_LIMIT);
+  }
+     
+  minError = kdtree[id].getminError();
+  maxError = kdtree[id].getmaxError();
+  //cout << "minError = " << minError << ",  maxError = " << maxError << 
endl;
+  if(minError/maxError<MAX_MIN_RATIO)
+  {
+    int num_tiles_merged, i;
+    count = 0;
+    do
+    {
+      count++;
+      num_tiles_merged = 
kdtree[id].merge(kdtree[id].getminErrorParentTile(), currenttime, 
samplingrate); 
+      for(i=0; i<num_tiles_merged && count<MAX_MERGE_SPLIT_LIMIT; i++)
+      {
+        count++;
+        kdtree[id].split(kdtree[id].getmaxErrorTile(), currenttime, 
samplingrate);
+      }
+      minError = kdtree[id].getminError();
+      maxError = kdtree[id].getmaxError();
+    }
+    while(minError/maxError<MAX_MIN_RATIO && count<MAX_MERGE_SPLIT_LIMIT);
+  }
+}
+
+#include <Interface/RTRTInterface.h>
+#include <Interface/Callback.h>
+
+
+// If all of the threads have initialized start the benchmark.
+void BenchHelper::tryStart( int, int ) {
+  
+  GSTAFRImageTraverser *traverser = (GSTAFRImageTraverser 
*)rtrt->getImageTraverser();
+  
+  // Check to see if all threads initialized.
+  if (!traverser->allThreadsInitialized()) {
+    // std::cout << "Try setup failed" << std::endl;
+    rtrt->addOneShotCallback(RTRTInterface::Relative, 10,
+                             Callback::create(this, &BenchHelper::tryStart));
+    return;
+  }
+
+  // std::cout << "Beginning benchmark" << std::endl;
+  
+  // Otherwise
+  start_time = SCIRun::Time::currentSeconds();
+  start_samples = traverser->getSamplesDone();
+  
+  rtrt->addOneShotCallback(RTRTInterface::Relative, outer_loops,
+                           Callback::create(this, &BenchHelper::stop));
+}
+
+// Take the final measurement.
+void BenchHelper::stop (int, int) {
+  
+  GSTAFRImageTraverser *traverser = (GSTAFRImageTraverser 
*)rtrt->getImageTraverser();
+  
+  double end_time = SCIRun::Time::currentSeconds();
+  unsigned int end_samples = traverser->getSamplesDone();
+
+  // Determine samples per second.
+  double sps = (double)(end_samples - start_samples) / (end_time - 
start_time);
+  
+  // Output performance.
+  std::cout << sps << std::endl;
+  
+  delete this;
+  
+  SCIRun::Thread::exitAll(0);
+}

Added: branches/AFR/Engine/ImageTraversers/GSTAFRImageTraverser.h
==============================================================================
--- (empty file)
+++ branches/AFR/Engine/ImageTraversers/GSTAFRImageTraverser.h  Fri Sep 16 
15:27:11 2005
@@ -0,0 +1,205 @@
+
+#ifndef Manta_Engine_GSTAFRImageTraverser_h
+#define Manta_Engine_GSTAFRImageTraverser_h
+
+#include <SCIRun/Core/Thread/Time.h>
+#include <SCIRun/Core/Thread/Thread.h>
+
+#include <Interface/ImageTraverser.h>
+#include <Interface/Fragment.h>
+#include <sgi_stl_warnings_off.h>
+#include <string>
+#include <vector>
+#include <sgi_stl_warnings_on.h>
+#include <Engine/ImageTraversers/AFRImageTraverser.h>
+#include <Engine/ImageTraversers/AFR/kdtree.h>
+#include <Engine/ImageTraversers/AFR/CQ.h>
+#include <Engine/ImageTraversers/AFR/sample.h>
+#include <Interface/XWindow.h>
+//#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include <GL/glx.h>
+
+#ifdef __ia64__
+#include <malloc.h>
+#include <ia64intrin.h>
+#endif
+
+namespace Manta {
+
+  using namespace std;
+  
+       namespace Afr {
+
+       class GSTAFRImageTraverser : public AFRImageTraverser {
+    
+      friend class AFRPipeline;
+    
+               public:
+    
+                       GSTAFRImageTraverser(const vector<string>& args);
+                       virtual ~GSTAFRImageTraverser();
+                       virtual void setupBegin(SetupContext&, int 
numChannels);
+                       virtual void setupDisplayChannel(SetupContext&);
+                       virtual void setupFrame(const RenderContext& context) 
{ /*Undefined for AFRPipeline.*/ };
+                       virtual void renderImage(const RenderContext& 
context, Image* image) { /*Undefined for AFRPipeline. */ };
+                       
+                       void renderChunk(const RenderContext& context, Image* 
image, int xres, int yres);
+                       int renderCrossHair(const RenderContext& context, int 
myID, 
+                          Image *image, const int xres, const int yres, 
+                          PartialSampleSet *sampleset, const int sscount,
+                          bool endChunk=false);
+                       
+                       // Master thread task.
+                       void masterTask(const RenderContext& context, Image* 
image);
+                       
+                       // Sampler/Renderer task.
+                       void clientTask(const RenderContext& context, Image* 
image);
+                       inline bool isMaster(int id)
+      {
+        return ((id%avgGroupSize)==0);
+      }
+                       // Update kdtree-cut.
+                       void adjustTiles(int id, Timestamp currenttime);
+                       void createStatsWin();
+                       void display_stats();
+                       void toggleTileDisplayMode();
+                       void initStreams(int xres, int yres);
+                       void write_Tile_and_Camera(RenderContext& context);
+                       int setSamplingRate(unsigned int srate)
+      {
+                         static unsigned int numUpdates=0;
+                         //cout << "srate = " << srate << endl;
+                         float rate = (float)srate;//(float)num_clients;
+                         if(numUpdates==0)
+                               samplingrate = (int)rate;
+                         else
+                         {
+                           samplingrate = 
(int)(((float)samplingrate*numUpdates + rate)/(float)(numUpdates+1));
+                         }
+                         numUpdates++;
+                         if(numUpdates%1000==0)
+                         {
+                           qSize = (int)(samplingrate*0.1);
+                           if(qSize>maxQSize) qSize = maxQSize;
+                         }  
+                       }
+                       static ImageTraverser* create(const vector<string>& 
args);
+                       
+    private:
+      GSTAFRImageTraverser(const GSTAFRImageTraverser&);
+      GSTAFRImageTraverser& operator=(const GSTAFRImageTraverser&);
+      
+      // Image kd-tree. per thread
+      KDTree *kdtree;
+      int qSize, maxQSize;
+      // number of fragments a chunk is divided into. It is divided equally 
amongst all clients
+      int numFragments;
+      bool outputStreams;
+      bool spatialCoherence;
+      string streamfilename;
+      FILE **streamfile;
+      //SCIRun::Mutex streamlock;
+      fpos_t *numsamples_pos;
+      int *firsttime;
+      // the reprojection queue per thread
+      CQ<PartialSampleSet> *temporalQ;
+      CQ<PartialSampleSet> *outputQ;
+      PartialSampleSet **newSampleSet, **newTempSampleSet;
+      Color **color;
+      // Random number generator array??
+      MT_RNG *myRandomNumber;
+      // display stuff
+      bool debug_window;
+      XWindow statsWindow;
+      Display* dpy;
+      GLXContext gl_context;
+      int displayClientId;
+      int displayCount;
+      // These contain stuff for font stuff.
+      XFontStruct* fontInfo;
+      GLuint fontbase;
+      bool windowOpen;
+      bool madeCurrent;
+      TileDisplayMode tmode;
+      float visScale;
+      
+      // ??????????????
+      int num_clients;
+      int num_masters, avgGroupSize;
+           int *groupSize;
+      int chunk_size;
+      int samplingrate;
+      int *lastxhairindex, *updatecount;
+      
+      // Arguments.
+      Real inner_loop_time;
+      
/////////////////////////////////////////////////////////////////////////
+      // Samples done.
+      struct SamplesDone {
+           SamplesDone() : value (0) {};
+        unsigned int value;
+        unsigned int padding[31];
+#ifdef __ia64__
+        inline void addOne()  { __fetchadd4_acq( &value, 1 ); };
+        inline void addFive() { addOne(); __fetchadd4_acq( &value, 4 ); };
+        inline void addThree() { addOne(); __fetchadd4_acq( &value, 2 ); };
+        inline unsigned int load()    { return __ld4_acq( &value ); };
+#else
+        inline void addOne()  { value++; };
+        inline void addFive() { value+=5; };
+        inline void addThree() { value+=3; };
+        inline unsigned int load()    { return value; };
+#endif
+      };
+      
+    public:
+    
+      // Sum up all of the samples done by all of the threads.
+      inline unsigned int getSamplesDone() {
+        unsigned int total = 0;
+        for (int i=0;i<num_clients;++i) {
+          total += samples_done[i].load();
+        }
+        return total;
+      };
+
+      inline bool allThreadsInitialized() {
+        bool all = true;
+        for (int i=0;(i<num_clients)&&all;++i) {
+          all = initpass[i] && all;
+        }
+
+        return all;
+      }
+               };
+
+
+    
///////////////////////////////////////////////////////////////////////////
+    
///////////////////////////////////////////////////////////////////////////
+    // SAMPLES PER SECOND BENCH  SAMPLES PER SECOND BENCH  SAMPLES PER SECOND
+    
///////////////////////////////////////////////////////////////////////////
+    
///////////////////////////////////////////////////////////////////////////
+    class BenchHelper {
+    private:
+      RTRTInterface *rtrt;
+      long outer_loops;
+
+      double start_time;
+      unsigned int start_samples;
+
+      
+    public:
+      BenchHelper( RTRTInterface *rtrt_, long outer_loops_ ) :
+        rtrt( rtrt_ ), outer_loops( outer_loops_ ) { };
+
+      void tryStart( int, int );
+      void stop( int, int );
+
+    };
+
+    
+       };
+};
+
+#endif

Modified: branches/AFR/Image/SimpleImage.h
==============================================================================
--- branches/AFR/Image/SimpleImage.h    (original)
+++ branches/AFR/Image/SimpleImage.h    Fri Sep 16 15:27:11 2005
@@ -104,7 +104,7 @@
 
   template<class Pixel>
   void SimpleImage<Pixel>::set( int x, int y, const Color &color, int 
which_eye ) {
-    
+    //cout << "adding to image loc: " << x << ", " << y << endl;
     // Check to be certain the pixel specified is in bounds.
     if((x<xres && x>=0) && (y<yres && y>=0)) {
       convertToPixel(eyeStart[which_eye][y][x], color.convertRGB());




  • [MANTA] r553 - in branches/AFR: Engine/Control Engine/ImageTraversers Engine/ImageTraversers/AFR Image, abhinav, 09/16/2005

Archive powered by MHonArc 2.6.16.

Top of page