Manta Interactive Ray Tracer Development Mailing List

Text archives Help


[MANTA] r1151 - in trunk: . Core Core/Util DynLT Engine/Control Model Model/Groups Model/Primitives scenes


Chronological Thread 
  • From: cgribble@sci.utah.edu
  • To: manta@sci.utah.edu
  • Subject: [MANTA] r1151 - in trunk: . Core Core/Util DynLT Engine/Control Model Model/Groups Model/Primitives scenes
  • Date: Thu, 20 Jul 2006 21:25:05 -0600 (MDT)

Author: cgribble
Date: Thu Jul 20 21:24:57 2006
New Revision: 1151

Added:
   trunk/Core/Util/Stat.h
   trunk/DynLT/
   trunk/DynLT/CMakeLists.txt
   trunk/DynLT/DynLTContext.cc
   trunk/DynLT/DynLTContext.h
   trunk/DynLT/DynLTGridSpheres.cc
   trunk/DynLT/DynLTGridSpheres.h
   trunk/DynLT/DynLTQueue.cc
   trunk/DynLT/DynLTQueue.h
   trunk/DynLT/DynLTStatsCollector.cc
   trunk/DynLT/DynLTStatsCollector.h
   trunk/DynLT/DynLTWorker.cc
   trunk/DynLT/DynLTWorker.h
   trunk/scenes/dynlt.cc
Removed:
   trunk/Engine/Control/DynPLTQueue.cc
   trunk/Engine/Control/DynPLTQueue.h
   trunk/Engine/Control/DynPLTWorker.cc
   trunk/Engine/Control/DynPLTWorker.h
   trunk/Model/Primitives/DynPLTGridSpheres.cc
   trunk/Model/Primitives/DynPLTGridSpheres.h
   trunk/scenes/dynplt.cc
Modified:
   trunk/CMakeLists.txt
   trunk/Core/CMakeLists.txt
   trunk/Engine/Control/CMakeLists.txt
   trunk/Model/CMakeLists.txt
   trunk/Model/Groups/TimeSteppedParticles.cc
   trunk/Model/Groups/TimeSteppedParticles.h
   trunk/Model/Primitives/CMakeLists.txt
   trunk/Model/Primitives/GridSpheres.cc
   trunk/scenes/CMakeLists.txt
Log:
*** Major rework of Dynamic Luminance Texture stuff

DLT files are now in DynLT/ (with the exception of scenes/dynlt.cc)
Changed DynPLT --> DynLT (not technically precomputed, so drop the "P")
Now builds DynLT library:  Manta_DynLT
Removed DynPLT-related files from other directories
Removed or changed DynPLT-related references to CMakeLists.txt of other
  directories

*** Leave BUILD_DYNLT off because it's currently broken (circular dependency
    during link stage:  Manta_DynLT <--> Manta_Model)

Other changes
-------------

Core/Util/Stat.h
Core/CMakeLists.txt
  Added thread-safe, DynRT-style Stats class:  tracks min, max, avg, total,
    variance and deviation values
  Use with a StatsCollector class (see DynLT example below) to track 
interesting
    values per-frame, per-session, etc.
  If USE_STATS_COLLECTOR is not defined, all operations are no-ops, so you 
don't
    have to worry about wrapping all of your StatsCollector calls in
    #ifdef/#endif blocks or adversely affecting performance

Model/CMakeLists.txt
  Added conditional link of Manta_DynLT library --> causes circular dependency

Interface/Callback.h
Interface/CallbackHelpers.h
  Added CallbackBase_1Data create(...) function for static 1 Data, 0 Arg
    callbacks
  Added Callback_Static_1Data_0Arg class for static 1 Data, 0 Arg callbacks

Model/Groups/TimeSteppedParticles.cc
Model/Groups/TimeSteppedParticles.h
  Use DynLTGridSpheres (if supported by build); otherwise, print warning and 
use
    standard GridSpheres

CMakeLists.txt
  Added cmake flag to enable statistics collection; if *not* enabled, Stat
    member functions become no-ops so you don't have to worry about wrapping 
all
    of your StatsCollector calls in #ifdef/#endif blocks or adversely 
affecting
    performance
  BUILD_DYNLT flag now adds -DBUILD_DYNLT on the compile command lines and 
adds
    the DynLT subdirectory to the build process

scenes/dynlt.cc
  Reduced default number of samples for texture generation (32 --> 25)
  Added "-stats" cmdln parameter to dump summary statistics (if supported by
    build)
  Register some callbacks for stats collection (if supported by build)

DynLT/DynLTGridSpheres.cc
DynLT/DynLTGridSpheres.h
  Added data members and functions to track texture generation latency and
    texture generation time for each particle
  Added code to increment counters for:  requests/frame, textures
    generated/frame, etc.
  Changed UPDATE_TIME from 5 seconds to 2.5 seconds (the lag was a little too
    long)

DynLT/DynLTStatsCollector.cc
DynLT/DynLTStatsCollector.h
  Added StatsCollector for interesting things related to dynamic luminance
    textures
  Use this as an example for doing interesting things with Core/Util/Stat.h

DynLT/DynLTWorker.cc
DynLT/DynLTWorker.h
  Track texture generation times for each particle (if supported by build)
  Removed DynLTContext (now in its own file, see below)

DynLT/DynLTContext.cc
DynLT/DynLTContext.h
  Moved DynLTContext from DynLTWorker to stand-alone source files

DynLT/CMakeLists.txt
  Added file for building the Manta_DynLT library from the DynLT sources


Modified: trunk/CMakeLists.txt
==============================================================================
--- trunk/CMakeLists.txt        (original)
+++ trunk/CMakeLists.txt        Thu Jul 20 21:24:57 2006
@@ -301,7 +301,17 @@
 ENDIF(BUILD_FOX)
 
 SET(BUILD_NRRDPARTICLES 0 CACHE BOOL "Build NRRD particle data reader/scene")
-SET(BUILD_DYNPLT 0 CACHE BOOL "Lazily evaluated PLTs for NRRD particle 
datasets")
+
+SET(BUILD_DYNLT 0 CACHE BOOL "Lazily evaluated LTs for NRRD particle 
datasets")
+IF(BUILD_DYNLT)
+  ADD_DEFINITIONS(-DBUILD_DYNLT)
+  SUBDIRS(DynLT)
+ENDIF(BUILD_DYNLT)
+
+SET(USE_STATS_COLLECTOR 0 CACHE BOOL "Enable stats collection")
+IF(USE_STATS_COLLECTOR)
+  ADD_DEFINITIONS(-DUSE_STATS_COLLECTOR)
+ENDIF(USE_STATS_COLLECTOR)
 
 ##################################################################
 # Look for Teem http://teem.sourceforge.net/

Modified: trunk/Core/CMakeLists.txt
==============================================================================
--- trunk/Core/CMakeLists.txt   (original)
+++ trunk/Core/CMakeLists.txt   Thu Jul 20 21:24:57 2006
@@ -56,6 +56,7 @@
      Util/Endian.h
      Util/LargeFile.h
      Util/LargeFile.cc
+     Util/Stat.h
      Util/ThreadStorage.h
      Util/ThreadStorage.cc)
 

Added: trunk/Core/Util/Stat.h
==============================================================================
--- (empty file)
+++ trunk/Core/Util/Stat.h      Thu Jul 20 21:24:57 2006
@@ -0,0 +1,108 @@
+#ifndef Manta_Core_Stat_h
+#define Manta_Core_Stat_h
+
+#include <SCIRun/Core/Thread/Mutex.h>
+
+#include <float.h>
+#include <math.h>
+
+using namespace SCIRun;
+
+namespace Manta
+{
+  class Stat
+  {
+#ifndef USE_STATS_COLLECTOR
+  public:
+    Stat(void) { /* no-op */ }
+
+    inline void reset(void) { /* no-op */ }
+    inline void increment(float /* inc_value */ = 1.0f) { /* no-op */ }
+    inline void increment(int /* inc_value */) { /* no-op */ }
+    inline float getTotal(void) { return -1.0f; }
+    inline float getAverage(void) { return -1.0f; }
+    inline float getVariance(void) { return -1.0f; }
+    inline float getDeviation(void) { return -1.0f; }
+    inline float getMinimum(void) { return -1.0f; }
+    inline float getMaximum(void) { return -1.0f; }
+#else
+  public:
+    Stat(void) : mutex("Stat mutex") { reset(); }
+
+    inline void reset(void)
+    {
+      mutex.lock();
+
+      sum_values=sum_squares=num_values=0.0f;
+      min_value=FLT_MAX;
+      max_value =-FLT_MAX;
+
+      mutex.unlock();
+    }
+
+    inline void increment(float inc_value=1.0f)
+    {
+      mutex.lock();
+
+      sum_values += inc_value;
+      sum_squares += (inc_value*inc_value);
+      num_values += 1.0f;
+      if (inc_value<min_value)
+        min_value=inc_value;
+      if (inc_value>max_value)
+        max_value=inc_value;
+
+      mutex.unlock();
+    }
+
+    inline void increment(int inc_value)
+    {
+      increment(static_cast<float>(inc_value));
+    }
+
+    inline float getTotal(void)
+    {
+      return sum_values;
+    }
+
+    inline float getAverage(void)
+    {
+      return sum_values/num_values;
+    }
+
+    inline float getVariance(void)
+    {
+      float inv_n=1.f/num_values;
+      float first=sum_squares*inv_n;
+      float second=sum_values*inv_n;
+      return first - second*second;
+    }
+
+    inline float getDeviation(void)
+    {
+      return sqrt(getVariance());
+    }
+
+    inline float getMinimum(void)
+    {
+      return min_value;
+    }
+
+    inline float getMaximum(void)
+    {
+      return max_value;
+    }
+
+    float sum_values;
+    float sum_squares;
+    float min_value;
+    float max_value;
+    float num_values;
+
+  private:
+    Mutex mutex;
+#endif
+  };
+}
+
+#endif // Manta_Core_Stat_h

Added: trunk/DynLT/CMakeLists.txt
==============================================================================
--- (empty file)
+++ trunk/DynLT/CMakeLists.txt  Thu Jul 20 21:24:57 2006
@@ -0,0 +1,17 @@
+
+SET(Manta_DynLT_SRCS
+    DynLTContext.h
+    DynLTContext.cc
+    DynLTGridSpheres.h
+    DynLTGridSpheres.cc
+    DynLTQueue.h
+    DynLTQueue.cc
+    DynLTStatsCollector.h
+    DynLTStatsCollector.cc
+    DynLTWorker.h
+    DynLTWorker.cc
+    )
+
+ADD_LIBRARY(Manta_DynLT ${Manta_DynLT_SRCS})
+
+TARGET_LINK_LIBRARIES(Manta_DynLT Manta_Model SCIRun_Core)

Added: trunk/DynLT/DynLTContext.cc
==============================================================================
--- (empty file)
+++ trunk/DynLT/DynLTContext.cc Thu Jul 20 21:24:57 2006
@@ -0,0 +1,26 @@
+
+#include <DynLT/DynLTContext.h>
+#include <SCIRun/Core/Math/Expon.h>
+#include <SCIRun/Core/Math/MiscMath.h>
+
+using namespace Manta;
+using namespace SCIRun;
+
+DynLTContext::DynLTContext(MantaInterface* manta_interface,
+                           DynLTQueue* queue,
+                           Scene* scene, unsigned int ngroups,
+                           unsigned int nsamples, unsigned int max_depth,
+                           bool dilate, Background* background, double 
runtime,
+                           unsigned int minproc, unsigned int maxproc,
+                           Real Kd, Real Ka) :
+  manta_interface(manta_interface),
+  queue(queue), scene(scene), ngroups(ngroups), nsamples(nsamples),
+  max_depth(max_depth), dilate(dilate), background(background), 
runtime(runtime),
+  minproc(minproc), maxproc(maxproc), Kd(Kd), Ka(Ka)
+{
+  // Ensure that the number of samples is a perfect square
+  nsamples_root=static_cast<int>(Ceil(Sqrt(static_cast<Real>(nsamples))));
+  unsigned int squared=nsamples_root*nsamples_root;
+  if (squared != nsamples)
+    nsamples=squared;
+}

Added: trunk/DynLT/DynLTContext.h
==============================================================================
--- (empty file)
+++ trunk/DynLT/DynLTContext.h  Thu Jul 20 21:24:57 2006
@@ -0,0 +1,60 @@
+
+#ifndef Manta_DynLT_DynLTContext_h
+#define Manta_DynLT_DynLTContext_h
+
+#include <MantaTypes.h>
+
+#include <float.h>
+#include <limits.h>
+
+namespace Manta
+{
+  class Background;
+  class DynLTContext;
+  class DynLTMessage;
+  class DynLTQueue;
+  class MantaInterface;
+  class Scene;
+
+  class DynLTContext
+  {
+  public:
+    DynLTContext(MantaInterface* manta_interface,
+                 DynLTQueue* queue, Scene* scene,
+                 unsigned int ngroups, unsigned int nsamples,
+                 unsigned int max_depth, bool dilate,
+                 Background* background, double runtime=DBL_MAX,
+                 unsigned int minproc=0, unsigned int maxproc=INT_MAX,
+                 Real Kd=0.6, Real Ka=0.4);
+    ~DynLTContext(void) { }
+
+    // Manta interface
+    MantaInterface* manta_interface;
+
+    // DynLT work queue
+    DynLTQueue* queue;
+
+    // Manta scene
+    Scene* scene;
+    Background* background;
+
+    // Texture generation parameters
+    unsigned int ngroups;
+    unsigned int nsamples;
+    unsigned int nsamples_root;
+    unsigned int max_depth;
+    double runtime;
+    unsigned int minproc;
+    unsigned int maxproc;
+    Real Ka;
+    Real Kd;
+
+    // Texture dilation parameters
+    bool dilate;
+    unsigned int support;
+    unsigned int use_weighted_avg;
+    Real threshold;
+  };
+}
+
+#endif // Manta_DynLT_DynLTContext_h

Added: trunk/DynLT/DynLTGridSpheres.cc
==============================================================================
--- (empty file)
+++ trunk/DynLT/DynLTGridSpheres.cc     Thu Jul 20 21:24:57 2006
@@ -0,0 +1,315 @@
+
+#include <Core/Color/RegularColorMap.h>
+#include <DynLT/DynLTContext.h>
+#include <DynLT/DynLTGridSpheres.h>
+#include <DynLT/DynLTQueue.h>
+#include <DynLT/DynLTWorker.h>
+#include <Interface/AmbientLight.h>
+#include <Interface/LightSet.h>
+#include <Interface/RayPacket.h>
+
+#include <iostream>
+using std::cerr;
+
+using namespace Manta;
+using namespace SCIRun;
+
+#define UPDATE_TIME 2.5
+
+DynLTGridSpheres::DynLTGridSpheres(DynLTQueue* queue,
+                                   float* spheres, int nspheres, int nvars,
+                                   int ncells, int depth, Real radius,
+                                   int ridx, RegularColorMap* cmap, int 
cidx) :
+  queue(queue), GridSpheres(spheres, nspheres, nvars, ncells, depth, radius,
+                            ridx, cmap, cidx)
+{
+  cerr<<"Initializing DynLTGridSpheres\n";
+  plts.resize(nspheres);
+  valid.resize(nspheres);
+  allocated.resize(nspheres);
+  requested.resize(nspheres);
+#ifdef USE_STATS_COLLECTOR
+  latency.resize(nspheres);
+  texgen.resize(nspheres);
+#endif
+  for (unsigned int i=0; i<nspheres; ++i) {
+    plts[i]=0;
+    requested[i]=0;
+    allocated[i]=false;
+    valid[i]=false;
+#ifdef USE_STATS_COLLECTOR
+    latency[i]=0;
+    texgen[i]=0;
+#endif
+  }
+
+  // XXX:  hard coded for now
+  // textureMode=AmbientOcclusion;
+  textureMode=GlobalIllumination;
+}
+
+DynLTGridSpheres::~DynLTGridSpheres(void)
+{
+  // Do nothing
+}
+
+void DynLTGridSpheres::shade(const RenderContext& context,
+                             RayPacket& rays) const
+{
+  switch (textureMode) {
+  case AmbientOcclusion:
+    shadeAmbient(context, rays);
+    break;
+  case GlobalIllumination:
+  default:
+    shadeGlobal(context, rays);
+    break;
+  }
+}
+
+void DynLTGridSpheres::shadeAmbient(const RenderContext& context,
+                                    RayPacket& rays) const
+{
+  ColorArray ambient;
+
+  for (unsigned int i=rays.begin(); i<rays.end(); ) {
+    // Find a run of rays that hit the same particle
+    int offset=rays.scratchpad<int>(i);
+    unsigned int end=i + 1;
+    while (end < rays.end() && rays.scratchpad<int>(end)==offset)
+      ++end;
+
+    int particle=offset/nvars;
+
+    // Compute ambient light for the rays
+    RayPacket sub(rays, i, end);
+    if (valid[particle]) {
+      // Compute diffuse colors
+      Packet<Color> diffuse;
+      mapDiffuseColors(diffuse, sub);
+
+      // Compute textured ambient luminance
+      sub.computeTextureCoordinates2(context);
+
+      for (unsigned int i=sub.begin(); i<sub.end(); ++i) {
+        Real luminance=computeLuminance(i, sub, particle);
+        for (int j=0; j < Color::NumComponents; ++j)
+          ambient[j][i]=luminance;
+      }
+    } else {
+      // Request texture generation, if necessary
+      if (requested[particle]==0.) {
+#ifdef USE_STATS_COLLECTOR
+        // Store request time
+        latency[particle]=Time::currentSeconds();
+
+        // Increment number of requests
+        DynLTStatsCollector::TexturesRequestedPerFrame.increment();
+#endif
+
+        // Create and post message
+        double priority=computePriority(rays.getMinT(i));
+        DynLTMessage msg(particle, priority, this);
+        if (queue->trySend(msg))
+          requested[particle]=priority;
+      } else {
+#ifdef UPDATE_TIME
+        // Update priority only after UPDATE_TIME seconds
+        if (Time::currentSeconds() - requested[particle] > UPDATE_TIME) {
+          requested[particle]=computePriority(rays.getMinT(i));
+          queue->updatePriority(particle, requested[particle]);
+        }
+#else
+        requested[particle]=computePriority(rays.getMinT(i));
+        queue->updatePriority(particle, requested[particle]);
+#endif
+      }
+
+      // Use default ambient light while texture is invalid
+      activeLights->getAmbientLight()->computeAmbient(context, sub, ambient);
+    }
+
+    i=end;
+  }
+
+  // Shade the rays
+  GridSpheres::lambertianShade(context, rays, ambient);
+}
+
+void DynLTGridSpheres::shadeGlobal(const RenderContext& context,
+                                   RayPacket& rays) const
+{
+  for (unsigned int i=rays.begin(); i<rays.end(); ) {
+    // Find a run of rays that hit the same particle
+    int offset=rays.scratchpad<int>(i);
+    unsigned int end=i + 1;
+    while (end < rays.end() && rays.scratchpad<int>(end)==offset)
+      ++end;
+
+    int particle=offset/nvars;
+
+    // Shade the rays
+    RayPacket sub(rays, i, end);
+    if (valid[particle]) {
+      // Compute diffuse colors
+      Packet<Color> diffuse;
+      mapDiffuseColors(diffuse, rays);
+    
+      // Compute textured luminance
+      sub.computeTextureCoordinates2(context);
+
+      for (unsigned int i=sub.begin(); i<sub.end(); ++i) {
+        Real luminance=computeLuminance(i, rays, particle);
+        sub.setColor(i, diffuse.get(i)*luminance);
+      }
+    } else {
+      // Request texture generation, if necessary
+      if (requested[particle]==0.) {
+#ifdef USE_STATS_COLLECTOR
+        // Store request time
+        latency[particle]=Time::currentSeconds();
+
+        // Increment number of requests
+        DynLTStatsCollector::TexturesRequestedPerFrame.increment();
+#endif
+
+        // Create and post message
+        double priority=computePriority(rays.getMinT(i));
+        DynLTMessage msg(particle, priority, this);
+        if (queue->trySend(msg))
+          requested[particle]=priority;
+      } else {
+#ifdef UPDATE_TIME
+        // Update priority only after UPDATE_TIME seconds
+        if (Time::currentSeconds() - requested[particle] > UPDATE_TIME) {
+          requested[particle]=computePriority(rays.getMinT(i));
+          queue->updatePriority(particle, requested[particle]);
+        }
+#else
+        requested[particle]=computePriority(rays.getMinT(i));
+        queue->updatePriority(particle, requested[particle]);
+#endif
+      }
+
+      // Use Lambertian shading while texture is invalid
+      GridSpheres::shade(context, sub);
+    }
+
+    i=end;
+  }
+}
+
+Real DynLTGridSpheres::computeLuminance(unsigned int ray_idx, RayPacket& 
rays,
+                                        unsigned int particle) const
+{
+  // Wrap in x (assumes xres is a power of two)
+  Real x=rays.getTexCoords2(ray_idx, 0)*XRES;
+  int lx=static_cast<int>(x) & (XRES - 1);
+  int hx=(lx + 1) & (XRES - 1);
+  Real wx=x - lx;
+
+  // Clamp in y
+  Real y=rays.getTexCoords2(ray_idx, 1);
+  int ly;
+  Real wy;
+  if (y < 0) {
+    ly=0;
+    wy=0;
+  } else {
+    y *= YRES - 1;
+    ly=static_cast<int>(y);
+    if (ly > YRES - 1) {
+      ly=YRES - 1;
+      wy=0;
+    } else {
+      wy=y - ly;
+    }
+  }
+
+  int hy=ly + 1;
+
+  // Bi-linearly interpolate
+  Real a=(plts[particle]->texture[lx][ly]*(1 - wx) +
+          plts[particle]->texture[hx][ly]*wx);
+  Real b=(plts[particle]->texture[lx][hy]*(1 - wx) +
+          plts[particle]->texture[hx][hy]*wx);
+
+  return a*(1 - wy) + b*wy;
+}
+
+void DynLT::dilate(const DynLTContext* context)
+{
+  // Compute the min and max of inside texture
+  unsigned int width=XRES;
+  unsigned int height=YRES;
+  Real min=inside[0][0];
+  Real max=inside[0][0];
+  for (unsigned int y=1; y<height; ++y) {
+    for (unsigned int x=1; x<width; ++x) {
+      Real tmp=inside[x][y];
+      if (tmp < min)
+       min=tmp;
+      if (tmp > max)
+       max=tmp;
+    }
+  }
+
+  // Normalize the inside texture
+  Real inv_maxmin=1/(max-min);
+  for (unsigned int y=0; y<height; ++y)
+    for (unsigned int x=0; x<width; ++x)
+      inside[x][y]=(inside[x][y] - min)*inv_maxmin;
+
+  // Initialize the dilated texture
+  Real dilated[XRES][YRES];
+  for (unsigned int y=0; y<height; ++y)
+    for (unsigned int x=0; x<width; ++x)
+      dilated[x][y]=texture[x][y];
+  
+  // Dilate any necessary pixels
+  unsigned int support=context->support;
+  unsigned int use_weighted_avg=context->use_weighted_avg;
+  Real threshold=context->threshold;
+  
+  for (unsigned int y=0; y < height;  ++y) {
+    for (unsigned int x=0; x < width;  ++x) {
+      // Determine if the pixel should be dilated
+      Real value=inside[x][y];
+      if (value<=0)
+        continue;
+      
+      // Loop over each neighbor
+      Real avg=0;
+      Real contribution_total=0;
+      for (unsigned int j=y-support; j <= y+support; j++) {
+        for (unsigned int i=x-support; i <= x+support; i++) {
+          // Check boundary conditions
+          unsigned int newi=i;
+          if (newi >= width)
+            newi=newi - width;
+
+          unsigned int newj=j;
+          if (newj >= height)
+            newj=height - 1;
+
+          // Determine neighbor's contribution
+          Real contributer=inside[newi][newj];
+          if (contributer < threshold) {
+            contributer *= use_weighted_avg;
+            avg += texture[newi][newj]*(1 - contributer);
+            contribution_total += (1 - contributer);
+          }
+        }
+      }
+
+      // Dilate the pixel
+      if (contribution_total > 0)
+        dilated[x][y]=avg/contribution_total;
+    }
+  }
+  
+  // Update texture with dilated results
+  for (unsigned int y=0; y<height; ++y)
+    for (unsigned int x=0; x<width; ++x)
+      texture[x][y]=dilated[x][y];
+}

Added: trunk/DynLT/DynLTGridSpheres.h
==============================================================================
--- (empty file)
+++ trunk/DynLT/DynLTGridSpheres.h      Thu Jul 20 21:24:57 2006
@@ -0,0 +1,171 @@

+#ifndef Manta_DynLT_DynLTGridSpheres_h
+#define Manta_DynLT_DynLTGridSpheres_h
+
+#include <DynLT/DynLTStatsCollector.h>
+#include <Model/Primitives/GridSpheres.h>
+#include <SCIRun/Core/Thread/Mailbox.h>
+#include <SCIRun/Core/Thread/Time.h>
+
+#include <vector>
+using std::vector;
+
+#include <float.h>
+
+using namespace SCIRun;
+
+#define XRES 16
+#define YRES 16
+
+namespace Manta {
+  class DynLTContext;
+  class DynLTQueue;
+  class RegularColorMap;
+
+  class DynLT {
+  public:
+    DynLT(void) { }
+    ~DynLT(void) { }
+
+    unsigned int getXRes(void) const { return XRES; }
+    unsigned int getYRes(void) const { return YRES; }
+
+    void dilate(const DynLTContext* context);
+
+    // Luminance texture data    
+    Real texture[XRES][YRES];
+    Real inside[XRES][YRES];
+  };
+
+  class DynLTGridSpheres : public GridSpheres
+  {
+  public:
+    enum {
+      AmbientOcclusion,
+      GlobalIllumination
+    } TextureMode;
+
+    DynLTGridSpheres(DynLTQueue* queue, float* spheres,
+                     int nspheres, int nvars, int ncells, int depth,
+                     Real radius, int ridx, RegularColorMap* cmap, int cidx);
+    ~DynLTGridSpheres(void);
+
+    void shade(const RenderContext& context, RayPacket& rays) const;
+
+    const LightSet* getActiveLights(void) const { return activeLights; }
+
+    unsigned int getTextureMode(void) const { return textureMode; }
+
+    void setTextureMode(unsigned int mode)
+    {
+      if (textureMode != mode) {
+        invalidateTextures();
+        textureMode=mode;
+      }
+    }
+
+    Vector getCenter(int particle) const
+    {
+      float* data=spheres + particle*nvars;
+      return Vector(data[0], data[1], data[2]);
+    }
+
+    Real getRadius(int particle) const
+    {
+      float* data=spheres + particle*nvars;
+      if (ridx>0) {
+        if (data[ridx] <= 0)
+          return radius;
+        else
+          return data[ridx];
+      }
+
+      return radius;
+    }
+
+    bool isValid(int idx) {
+      return valid[idx];
+    }
+
+    bool isAllocated(int idx) {
+      return allocated[idx];
+    }
+
+    void setValid(int idx) {
+      valid[idx]=true;
+
+#ifdef USE_STATS_COLLECTOR
+      // Compute latency and increment counter
+      latency[idx]=Time::currentSeconds() - latency[idx];
+      
DynLTStatsCollector::TexGenLatency.increment(static_cast<float>(latency[idx]));
+#endif
+    }
+
+    void allocate(int idx) {
+      plts[idx]=new DynLT();
+      allocated[idx]=true;
+    }
+
+    void dilate(const DynLTContext* context, int idx) {
+      plts[idx]->dilate(context);
+    }
+
+    DynLT* getTexture(int idx) {
+      return plts[idx];
+    }
+    
+    double computePriority(Real t) const {
+      // Time-stamp only
+      return Time::currentSeconds();
+
+      // Distance only (closest first)
+      // return DBL_MAX - t;
+
+      // Time-stamp and distance
+      // return Time::currentSeconds() + (DBL_MAX - t);
+    }
+
+    void resetRequested(int idx) {
+      requested[idx]=0.;
+    }
+
+#ifdef USE_STATS_COLLECTOR
+    void setTexGenTime(int idx, double time)
+    {
+      // Set texture generation time and increment counters
+      texgen[idx]=time;
+      
DynLTStatsCollector::TexGenTime.increment(static_cast<float>(texgen[idx]));
+      DynLTStatsCollector::TexturesGeneratedPerFrame.increment();
+    }
+#endif
+
+  private:
+    void shadeAmbient(const RenderContext& context, RayPacket& rays) const;
+    void shadeGlobal(const RenderContext& context, RayPacket& rays) const;
+    Real computeLuminance(unsigned int ray_idx, RayPacket& rays,
+                          unsigned int particle) const;
+
+    void invalidateTextures(void)
+    {
+      for (unsigned int i=0; i<nspheres; ++i) {
+        requested[i]=0;
+        valid[i]=false;
+      }
+    }
+
+    DynLTQueue* queue;
+    mutable vector<double> requested;
+    vector<bool> allocated;
+    vector<bool> valid;
+    vector<DynLT*> plts;
+
+    unsigned int textureMode;
+
+#ifdef USE_STATS_COLLECTOR
+    mutable vector<double> latency;
+    mutable vector<double> texgen;
+#endif
+  };
+}
+
+#endif // Manta_DynLT_DynLTGridSpheres_h

Added: trunk/DynLT/DynLTQueue.cc
==============================================================================
--- (empty file)
+++ trunk/DynLT/DynLTQueue.cc   Thu Jul 20 21:24:57 2006
@@ -0,0 +1,355 @@
+
+#include <DynLT/DynLTGridSpheres.h>
+#include <DynLT/DynLTQueue.h>
+
+#include <iostream>
+using std::cerr;
+
+using namespace Manta;
+
+DynLTLifoQ::DynLTLifoQ(int size) :
+  mutex("LifoQ lock"), empty("LifoQ empty condition"),
+  full("LifoQ full condition"), top(-1), max_size(size)
+{
+  // Allocate dataspace
+  dataspace=new char[max_size*sizeof(DynLTMessage)];
+  queue=reinterpret_cast<DynLTMessage*>(dataspace);
+}
+
+DynLTLifoQ::~DynLTLifoQ(void)
+{
+  // Release all waiting threads
+  empty.conditionBroadcast();
+  full.conditionBroadcast();
+
+  // Free dataspace
+  delete [] dataspace;
+}
+
+bool DynLTLifoQ::tryReceive(DynLTMessage& msg)
+{
+  mutex.lock();
+
+  // Return false if queue is empty
+  if (top==-1) {
+    mutex.unlock();
+    return false;
+  }
+
+  // Pop top item from the queue
+  msg=pop();
+
+  mutex.unlock();
+
+  return true;
+}
+
+DynLTMessage DynLTLifoQ::receive(void)
+{
+  mutex.lock();
+
+  // Block calling thread while queue is empty
+  while (top==-1)
+    empty.wait(mutex);
+
+  // Pop top item from the queue
+  DynLTMessage msg=pop();
+
+  mutex.unlock();
+
+  return msg;
+}
+
+bool DynLTLifoQ::trySend(const DynLTMessage& msg)
+{
+  mutex.lock();
+
+  // Return false if queue is full
+  if (top==max_size - 1) {
+    mutex.unlock();
+    return false;
+  }
+
+  push(msg);
+  mutex.unlock();
+
+  return true;
+}
+
+void DynLTLifoQ::send(const DynLTMessage& msg)
+{
+  mutex.lock();
+
+  // Block calling thread while queue is full
+  while (top==max_size - 1)
+    full.wait(mutex);
+
+  push(msg);
+  mutex.unlock();
+}
+
+DynLTPriorityQ::DynLTPriorityQ(int size) :
+  mutex("PriorityQ lock"), empty("PriorityQ empty condition"),
+  full("PriorityQ full condition"), nheap(0), max_size(size)
+{
+  // Allocate dataspace
+  dataspace=new char[max_size*sizeof(DynLTMessage)];
+  heap=reinterpret_cast<DynLTMessage*>(dataspace);
+}
+
+DynLTPriorityQ::~DynLTPriorityQ(void)
+{
+  // Release all waiting threads
+  empty.conditionBroadcast();
+  full.conditionBroadcast();
+
+  // Free dataspace
+  delete [] dataspace;
+
+#ifndef FIXED_SIZE_QUEUE
+  delete [] heap_idx;
+#endif
+}
+
+bool DynLTPriorityQ::tryReceive(DynLTMessage& msg)
+{
+  mutex.lock();
+
+  // Return false if heap is empty
+  if (nheap==0) {
+    mutex.unlock();
+    return false;
+  }
+
+  // Pop top item from the heap
+  msg=pop();
+
+  mutex.unlock();
+
+  return true;
+}
+
+DynLTMessage DynLTPriorityQ::receive(void)
+{
+  mutex.lock();
+
+  // Block calling thread while heap is empty
+  while (nheap==0)
+    empty.wait(mutex);
+
+  // Pop top item from the heap
+  DynLTMessage msg=pop();
+
+  mutex.unlock();
+
+  return msg;
+}
+
+bool DynLTPriorityQ::trySend(const DynLTMessage& msg)
+{
+  mutex.lock();
+
+  // Return false if heap is full
+  if (nheap==max_size) {
+    mutex.unlock();
+    return false;
+  }
+
+  push(msg);
+  mutex.unlock();
+
+  return true;
+}
+
+void DynLTPriorityQ::send(const DynLTMessage& msg)
+{
+  mutex.lock();
+
+  // Block calling thread while heap is full
+  while (nheap==max_size)
+    full.wait(mutex);
+
+  push(msg);
+  mutex.unlock();
+}
+
+void DynLTPriorityQ::updatePriority(int particle, double priority)
+{
+#ifdef FIXED_SIZE_QUEUE
+  mutex.lock();
+
+  for (unsigned int i=0; i<nheap; ++i) {
+    if (heap[i].particle == particle) {
+      // Found particle, create new node with updated priority
+      DynLTMessage msg(particle, priority, heap[i].grid);
+
+      // Staring at old node's position in the heap, walk new node up the 
heap
+      // until its priority is less than its parent's
+      int parent=(i + 1)/2 - 1;
+      while (i && heap[parent].priority < priority) {
+        heap[i]=heap[parent];
+        i=parent;
+        parent=(i + 1)/2 - 1;
+      }
+
+      // Insert message
+      heap[i]=msg;
+
+      break;
+    }
+  }
+
+  mutex.unlock();
+#else
+  mutex.lock();
+
+  int idx=heap_idx[particle];
+  if (idx>-1) {
+    // Found particle, create new message with updated priority
+    DynLTMessage msg(particle, priority, heap[idx].grid);
+
+    // Staring at old node's position in the heap, walk new node up the heap
+    // until its priority is less than its parent's
+    int parent=(idx + 1)/2 - 1;
+    while (idx && heap[parent].priority < priority) {
+      // Swap parent
+      heap[idx]=heap[parent];
+      heap_idx[heap[idx].particle]=idx;
+
+      idx=parent;
+      parent=(idx + 1)/2 - 1;
+    }
+
+    // Insert message and update heap_idx
+    heap[idx]=msg;
+    heap_idx[particle]=idx;
+  }
+
+  mutex.unlock();
+#endif
+}
+
+void DynLTPriorityQ::push(DynLTMessage const& msg)
+{
+#ifdef FIXED_SIZE_QUEUE
+  // NOTE:  This code is supposed to implement a fixed size queue in which 
old
+  //        requests (i.e., low priority) are dropped and new ones added; it
+  //        sort of works, but I'm not sure it's bullet proof yet...
+  if (nheap<max_size) {
+    // Increment number of nodes in the heap
+    ++nheap;
+
+    // Walk node up the heap until its priority is less than its parent's
+    int i=nheap - 1;
+    int parent=(i + 1)/2 - 1;
+    while (i && heap[parent].priority < msg.priority) {
+      heap[i]=heap[parent];
+      i=parent;
+      parent=(i + 1)/2 - 1;
+    }
+
+    // Insert message and update heap_idx
+    heap[i]=msg;
+  } else {
+    // Drop last node
+    DynLTMessage last=heap[nheap-1];
+    DynLTGridSpheres* grid=const_cast<DynLTGridSpheres*>(last.grid);
+    grid->resetRequested(last.particle);
+
+    // Move old root to end, insert new node at root, and rebuild
+    heap[nheap-1]=heap[0];
+    heap[0]=msg;
+    heapify(0, nheap);
+  }
+#else
+  // NOTE:  In theory, the following code allows the queue to grow without 
bound.
+  //        However, in practice, the heap reaches some semi-stable size as
+  //        texture generation requests are produced/consumed by the threads
+  ++nheap;
+  if (nheap>=max_size) {
+    // Save old dataspace, allocate new dataspace
+    char* oldspace=dataspace;
+    dataspace=new char[2*max_size*sizeof(DynLTMessage)];
+
+    // Copy current elements
+    memcpy(reinterpret_cast<void*>(dataspace),
+           reinterpret_cast<void*>(oldspace),
+           (nheap - 1)*sizeof(DynLTMessage));
+
+    // Release old dataspace
+    delete [] oldspace;
+
+    // Update heap pointer and max_size
+    heap=reinterpret_cast<DynLTMessage*>(dataspace);
+    max_size *= 2;
+
+    /*
+      cerr<<"Heap is now "<<max_size*sizeof(DynLTMessage)<<" bytes 
("<<max_size
+      <<" messages)\n";
+    */
+  }
+
+  // Walk node up the heap until its priority is less than its parent's
+  int i=nheap - 1;
+  int parent=(i + 1)/2 - 1;
+  while (i && heap[parent].priority < msg.priority) {
+    heap[i]=heap[parent];
+    heap_idx[heap[i].particle]=i;
+
+    i=parent;
+    parent=(i + 1)/2 - 1;
+  }
+
+  // Insert message and update heap_idx
+  heap[i]=msg;
+  heap_idx[msg.particle]=i;
+#endif
+}
+
+DynLTMessage DynLTPriorityQ::pop(void)
+{
+  // Grab first message
+  DynLTMessage msg=heap[0];
+#ifndef FIXED_SIZE_QUEUE
+  heap_idx[msg.particle]=-1;
+#endif
+
+  // Rebuild the heap
+  --nheap;
+  heap[0]=heap[nheap];
+#ifndef FIXED_SIZE_QUEUE
+  heap_idx[heap[0].particle]=0;
+#endif
+  heapify(0, nheap);
+
+  return msg;
+}
+
+void DynLTPriorityQ::heapify(int i, int nnodes)
+{
+  // Initialize indices of left/right children
+  int highest=i;
+  int l=2*i + 1;
+  int r=l + 1;
+
+  // Find index of node with highest priority
+  if (l<nnodes && heap[l].priority > heap[highest].priority)
+    highest=l;
+
+  if (r<nnodes && heap[r].priority > heap[highest].priority)
+    highest=r;
+
+  // Swap heap[i] and heap[highest]
+  if (highest != i) {
+    DynLTMessage tmp=heap[i];
+    heap[i]=heap[highest];
+    heap[highest]=tmp;
+#ifndef FIXED_SIZE_QUEUE
+    heap_idx[heap[i].particle]=i;
+    heap_idx[heap[highest].particle]=highest;
+#endif
+    
+    // Recursively build the heap
+    heapify(highest, nnodes);
+  }
+}

Added: trunk/DynLT/DynLTQueue.h
==============================================================================
--- (empty file)
+++ trunk/DynLT/DynLTQueue.h    Thu Jul 20 21:24:57 2006
@@ -0,0 +1,160 @@
+
+#ifndef Manta_DynLT_DynLTQueue_h
+#define Manta_DynLT_DynLTQueue_h
+
+#include <MantaTypes.h>
+#include <SCIRun/Core/Thread/Mailbox.h>
+#include <SCIRun/Core/Thread/ConditionVariable.h>
+#include <SCIRun/Core/Thread/Mutex.h>
+
+using namespace SCIRun;
+
+// #define FIXED_SIZE_QUEUE
+
+namespace Manta
+{
+  class DynLTGridSpheres;
+
+  struct DynLTMessage {
+    DynLTMessage(int particle, double priority, const DynLTGridSpheres* 
grid) :
+      particle(particle), priority(priority), grid(grid)
+    {
+      // Do nothing
+    }
+
+    DynLTMessage(void) :
+      particle(-1), priority(0), grid(0)
+    {
+      // Do nothing
+    }
+
+    int particle;
+    double priority;
+    const DynLTGridSpheres* grid;
+  };
+
+  class DynLTQueue
+  {
+  public:
+    DynLTQueue(void) { /* no-op */ }
+    ~DynLTQueue(void) { /* no-op */ }
+
+    virtual bool tryReceive(DynLTMessage& msg) = 0;
+    virtual DynLTMessage receive(void) = 0;
+
+    virtual bool trySend(const DynLTMessage& msg) = 0;
+    virtual void send(const DynLTMessage& msg) = 0;
+
+    virtual void updatePriority(int particle, double priority) { /* no-op */ 
}
+    virtual void resizeHeapIdx(unsigned int nparticles_) { /* no-op */ }
+  };
+
+  class DynLTFifoQ : public DynLTQueue
+  {
+  public:
+    DynLTFifoQ(int size)
+    {
+      mailbox=new SCIRun::Mailbox<DynLTMessage>("DynLT Work Queue", size);
+    }
+
+    ~DynLTFifoQ(void)
+    {
+      delete mailbox;
+    }
+
+    bool tryReceive(DynLTMessage& msg)
+    {
+      return mailbox->tryReceive(msg);
+    }
+
+    DynLTMessage receive(void)
+    {
+      return mailbox->receive();
+    }
+
+    bool trySend(const DynLTMessage& msg)
+    {
+      mailbox->trySend(msg);
+    }
+
+    void send(const DynLTMessage& msg)
+    {
+      mailbox->send(msg);
+    }
+
+  private:
+    SCIRun::Mailbox<DynLTMessage>* mailbox;
+  };
+
+  class DynLTLifoQ : public DynLTQueue
+  {
+  public:
+    DynLTLifoQ(int size);
+    ~DynLTLifoQ(void);
+
+    bool tryReceive(DynLTMessage& msg);
+    DynLTMessage receive(void);
+    bool trySend(const DynLTMessage& msg);
+    void send(const DynLTMessage& msg);
+
+  private:
+    void push(DynLTMessage const& msg) { queue[++top]=msg; }
+    DynLTMessage pop(void) { return queue[top--]; }
+
+    // Thread control
+    Mutex mutex;
+    ConditionVariable empty;
+    ConditionVariable full;
+
+    // Data variables
+    DynLTMessage* queue;
+    char* dataspace;
+    int max_size;
+    int top;
+  };
+
+  class DynLTPriorityQ : public DynLTQueue
+  {
+  public:
+    DynLTPriorityQ(int size);
+    ~DynLTPriorityQ(void);
+
+    bool tryReceive(DynLTMessage& msg);
+    DynLTMessage receive(void);
+    bool trySend(const DynLTMessage& msg);
+    void send(const DynLTMessage& msg);
+
+    void updatePriority(int particle, double priority);
+#ifndef FIXED_SIZE_QUEUE
+    void resizeHeapIdx(unsigned int nparticles_)
+    {
+      nparticles=nparticles_;
+      heap_idx=new int[nparticles];
+      for (unsigned int i=0; i<nparticles; ++i)
+        heap_idx[i]=-1;
+    }
+#endif
+
+  private:
+    void push(DynLTMessage const& msg);
+    DynLTMessage pop(void);
+    void heapify(int i, int nnodes);
+
+    // Thread control
+    Mutex mutex;
+    ConditionVariable empty;
+    ConditionVariable full;
+
+    // Data variables
+    DynLTMessage* heap;
+    char* dataspace;
+    int max_size;
+    int nheap;
+#ifndef FIXED_SIZE_QUEUE
+    int* heap_idx;
+    unsigned int nparticles;
+#endif
+  };
+}
+
+#endif // Manta_DynLT_DynLTQueue_h

Added: trunk/DynLT/DynLTStatsCollector.cc
==============================================================================
--- (empty file)
+++ trunk/DynLT/DynLTStatsCollector.cc  Thu Jul 20 21:24:57 2006
@@ -0,0 +1,61 @@
+#include <DynLT/DynLTStatsCollector.h>
+
+#include <iostream>
+using std::cerr;
+
+using namespace Manta;
+
+void DynLTStatsCollector::resetPerFrameStats(int /* unused */, int /* unused 
*/)
+{
+#if 0
+  cerr<<"Per-frame stats\n";
+  cerr<<"  Requests:\t"<<TexturesRequestedPerFrame.getTotal()<<'\n';
+  cerr<<"  Generated:\t"<<TexturesGeneratedPerFrame.getTotal()<<'\n';
+#endif
+
+  // Increment total counters
+  TexturesRequested.increment(TexturesRequestedPerFrame.getTotal());
+  TexturesGenerated.increment(TexturesGeneratedPerFrame.getTotal());
+
+  // Reset per-frame counters
+  TexturesRequestedPerFrame.reset();
+  TexturesGeneratedPerFrame.reset();
+}
+
+void DynLTStatsCollector::dump(MantaInterface* /* unused */)
+{
+  cerr<<'\n';
+  cerr<<"Texture generation latency\n";
+  cerr<<"  Average:\t"<<TexGenLatency.getAverage()<<" seconds\n";
+  cerr<<"  Minimum:\t"<<TexGenLatency.getMinimum()<<" seconds\n";
+  cerr<<"  Maximum:\t"<<TexGenLatency.getMaximum()<<" seconds\n";
+  cerr<<'\n';
+  cerr<<"Texture generation time\n";
+  cerr<<"  Average:\t"<<TexGenTime.getAverage()<<" seconds\n";
+  cerr<<"  Minimum:\t"<<TexGenTime.getMinimum()<<" seconds\n";
+  cerr<<"  Maximum:\t"<<TexGenTime.getMaximum()<<" seconds\n";
+  cerr<<" ------------------------------\n";
+  cerr<<"  Total:\t"<<TexGenTime.getTotal()<<" seconds\n";
+  cerr<<'\n';
+  cerr<<"Textures requested\n";
+  cerr<<"  Average:\t"<<TexturesRequested.getAverage()<<'\n';
+  cerr<<"  Minimum:\t"<<TexturesRequested.getMinimum()<<'\n';
+  cerr<<"  Maximum:\t"<<TexturesRequested.getMaximum()<<'\n';
+  cerr<<" ------------------------------\n";
+  cerr<<"  Total:\t"<<TexturesRequested.getTotal()<<'\n';
+  cerr<<'\n';
+  cerr<<"Textures generated\n";
+  cerr<<"  Average:\t"<<TexturesGenerated.getAverage()<<'\n';
+  cerr<<"  Minimum:\t"<<TexturesGenerated.getMinimum()<<'\n';
+  cerr<<"  Maximum:\t"<<TexturesGenerated.getMaximum()<<'\n';
+  cerr<<" ------------------------------\n";
+  cerr<<"  Total:\t"<<TexturesGenerated.getTotal()<<'\n'; 
+  cerr<<'\n';
+}
+
+Stat DynLTStatsCollector::TexGenLatency;
+Stat DynLTStatsCollector::TexGenTime;
+Stat DynLTStatsCollector::TexturesRequested;
+Stat DynLTStatsCollector::TexturesRequestedPerFrame;
+Stat DynLTStatsCollector::TexturesGenerated;
+Stat DynLTStatsCollector::TexturesGeneratedPerFrame;

Added: trunk/DynLT/DynLTStatsCollector.h
==============================================================================
--- (empty file)
+++ trunk/DynLT/DynLTStatsCollector.h   Thu Jul 20 21:24:57 2006
@@ -0,0 +1,31 @@
+
+#ifndef Manta_DynLT_DynLTStatsCollector_h
+#define Manta_DynLT_DynLTStatsCollector_h
+
+#include <Core/Util/Stat.h>
+
+namespace Manta
+{
+  class MantaInterface;
+
+  class DynLTStatsCollector
+  {
+  public:
+    static void resetPerFrameStats(int, int);
+    static void dump(MantaInterface*);
+
+    // Per-particle stats
+    static Stat TexGenLatency;
+    static Stat TexGenTime;
+
+    // Per-frame stats
+    static Stat TexturesRequestedPerFrame;
+    static Stat TexturesGeneratedPerFrame;
+
+    // Per-session stats
+    static Stat TexturesRequested;
+    static Stat TexturesGenerated;
+  };
+}
+
+#endif // Manta_DynLT_DynLTStatsCollector_h

Added: trunk/DynLT/DynLTWorker.cc
==============================================================================
--- (empty file)
+++ trunk/DynLT/DynLTWorker.cc  Thu Jul 20 21:24:57 2006
@@ -0,0 +1,585 @@
+
+#include <DynLT/DynLTContext.h>
+#include <DynLT/DynLTGridSpheres.h>
+#include <DynLT/DynLTQueue.h>
+#include <DynLT/DynLTWorker.h>
+#include <Interface/Background.h>
+#include <Interface/Context.h>
+#include <Interface/Packet.h>
+#include <Interface/Scene.h>
+#include <Engine/Shadows/HardShadows.h>
+#include <Model/Primitives/Sphere.h>
+#include <SCIRun/Core/Thread/Time.h>
+
+#include <string>
+
+using namespace Manta;
+using namespace SCIRun;
+using namespace std;
+
+// XXX:  the exit strategy for static thread scheduling only works 
occasionally
+//       (no segfault) when the queue isn't empty, and never when it is empty
+
+DynLTWorker::DynLTWorker(const DynLTContext* context, unsigned int id) :
+  context(context), id(id), exitSem(0)
+{
+  // Seed the random number generator
+  rng.seed_rng(100 + id);
+
+  // Generate groups of random 2D sample points
+  sample_groups.resize(context->ngroups);
+  for (unsigned int i=0; i<context->ngroups; ++i) {
+    sample_groups[i].resize(context->nsamples);
+
+    // Generate random (u, v) samples in the texel --> [-0.5, 0.5]
+    unsigned int idx=0;
+    unsigned int nsamples_root=context->nsamples_root;
+    Real delta=1/static_cast<Real>(nsamples_root);
+    Real u=0;
+    for (unsigned int j=0; j<nsamples_root; ++j) {
+      Real v=0;
+      for (unsigned int k=0; k<nsamples_root; ++k) {
+        sample_groups[i][idx++]=Vector2D(u - 0.5 + delta*rng.gendrand(),
+                                         v - 0.5 + delta*rng.gendrand());
+
+        v += delta;
+      }
+
+      u += delta;
+    }
+
+    // Shuffle the sample points
+    unsigned int nsamples=context->nsamples;
+    unsigned int max_idx=nsamples - 1;
+    for (unsigned int j=0; j<nsamples; ++j) {
+      unsigned int target=static_cast<unsigned int>(max_idx*rng.gendrand());
+      Vector2D tmp=sample_groups[i][j];
+      sample_groups[i][j]=sample_groups[i][target];
+      sample_groups[i][target]=tmp;
+    }
+  }
+
+  // Allocate sample group indices for picking a group of sample points on 
the
+  // hemisphere at each depth
+  hidx=new int[context->max_depth];
+}
+
+DynLTWorker::~DynLTWorker(void)
+{
+  delete [] hidx;
+}
+
+void DynLTWorker::run(void)
+{
+  // Create a render context for computing ray intersections
+  vector<string> args;
+  HardShadows shadows(args);
+  // RenderContext(MantaInterface*, int, int, int, const FrameState*,
+  //               LoadBalancer*, PixelSampler*, Renderer*, ShadowAlgorithm*,
+  //               const Camera*, const Scene*, ThreadStorage*);
+  RenderContext rctx(0, 0, 0, 0, 0, 0, 0, 0, &shadows, 0, context->scene, 0);
+
+  DynLTMessage msg=context->queue->receive();
+  while (msg.particle>=0) {
+    // Generate texture
+    innerLoop(rctx, msg);
+
+    // Receive next message
+    msg=context->queue->receive();
+  }
+
+  if (exitSem)
+    exitSem->up();
+}
+
+void DynLTWorker::timedRun(int proc, int numProcs)
+{
+  // Only specified range of threads should be generating textures
+  if (proc < context->minproc || proc > context->maxproc)
+    return;
+
+  // Create a render context for computing ray intersections
+  vector<string> args;
+  HardShadows shadows(args);
+  // RenderContext(MantaInterface*, int, int, int, const FrameState*,
+  //               LoadBalancer*, PixelSampler*, Renderer*, ShadowAlgorithm*,
+  //               const Camera*, const Scene*, ThreadStorage*);
+  RenderContext rctx(0, 0, 0, 0, 0, 0, 0, 0, &shadows, 0, context->scene, 0);
+
+  double start=Time::currentSeconds();
+  DynLTMessage msg;
+  while (Time::currentSeconds() - start < context->runtime) {
+    if (context->queue->tryReceive(msg)) {
+      // Generate texture
+      innerLoop(rctx, msg);
+    } else {
+      // No texture requests available, continue with rendering immediately
+      break;
+    }
+  }
+}
+
+void DynLTWorker::innerLoop(const RenderContext& rctx, const DynLTMessage& 
msg)
+{
+#ifdef USE_STATS_COLLECTOR
+  // Store start time
+  double start=Time::currentSeconds();
+#endif
+
+  // Grab message data
+  int particle=msg.particle;
+  DynLTGridSpheres* grid=const_cast<DynLTGridSpheres*>(msg.grid);
+
+  // Skip valid textures
+  if (grid->isValid(particle))
+    return;
+
+  // Allocate new texture, if necessary
+  if (!grid->isAllocated(particle))
+    grid->allocate(particle);
+
+  bool dilateTexture=false;
+
+  // Render the texture
+  switch (grid->getTextureMode()) {
+  case DynLTGridSpheres::AmbientOcclusion:
+    dilateTexture=renderAmbient(context, rctx, grid, particle);
+    break;
+  case DynLTGridSpheres::GlobalIllumination:
+  default:
+    dilateTexture=renderGlobal(context, rctx, grid, particle);
+    break;
+  }
+
+  // Dilate texture, if necessary
+  if (context->dilate && dilateTexture)
+    grid->dilate(context, particle);
+  
+  // Mark the texture as valid
+  context->manta_interface->addTransaction("Texture valid",
+                                           Callback::create(grid, 
&DynLTGridSpheres::setValid, particle));
+
+#ifdef USE_STATS_COLLECTOR
+  // Compute texture generation time and increment counter
+  double elapsed=Time::currentSeconds() - start;
+  grid->setTexGenTime(particle, elapsed);
+#endif
+}
+
+bool DynLTWorker::renderAmbient(const DynLTContext* context,
+                                const RenderContext& rctx,
+                                DynLTGridSpheres* grid,
+                                unsigned int particle)
+{
+  // Grab useful information from the DynLT context
+  unsigned int ngroups=context->ngroups;
+  unsigned int nsamples=context->nsamples;
+  unsigned int max_depth=context->max_depth;
+  Real inv_nsamples=1/static_cast<Real>(nsamples);
+
+  // Determine texture resolution
+  DynLT* dynplt=grid->getTexture(particle);
+  unsigned int xres=dynplt->getXRes();
+  unsigned int yres=dynplt->getYRes();
+  // Real inv_width=1/static_cast<Real>(xres - 1);
+  // Real inv_height=1/static_cast<Real>(yres - 1);
+  Real inv_width=1/static_cast<Real>(xres);
+  Real inv_height=1/static_cast<Real>(yres);
+
+  // Intialize the textures
+  bzero(dynplt->texture, xres*yres*sizeof(float));
+  bzero(dynplt->inside, xres*yres*sizeof(float));
+
+  // Generate texture
+  const Vector center=grid->getCenter(particle);
+  Real radius=grid->getRadius(particle);
+  bool dilateTexture=false;
+
+  for (unsigned int v=0; v<yres; ++v) {
+    for (unsigned int u=0; u<xres; ++u) {
+      // Pick a random sample group for surface points
+      unsigned int sidx=static_cast<unsigned int>(ngroups*rng.gendrand());
+
+      // Pick random sample group for points on the hemisphere at each depth
+      for (int d=0; d<=max_depth; ++d)
+        hidx[d]=static_cast<unsigned int>(ngroups*rng.gendrand());
+
+      Real ambient=0;
+      for (unsigned int s=0; s<nsamples; s += RayPacket::MaxSize) {
+        // Initialize a ray packet
+        int size=RayPacket::MaxSize;
+        if (size >= nsamples - s) {
+          // Remaining number of samples isn't large enough to fill a ray
+          // packet, so set the size of the ray packet to the number of 
samples
+          // that remain
+          size=nsamples - s;
+        }
+
+        RayPacketData raydata;
+        RayPacket rays(raydata, RayPacket::UnknownShape, 0, size, 0, 0);
+
+        // Fill in the ray origins and directions at sample points
+        for (int i=rays.begin(); i<rays.end(); ++i) {
+          // Project surface sample point onto particle's surface
+          Vector2D sample=sample_groups[sidx][s + i];
+            
+          // Range of 2*M_PI*(u + sample.x)/(xres - 1) --> [0, 2*Pi]
+          // Range of M_PI*(v + sample.y)/(yres - 1) --> [0, Pi]
+          Real phi=2*M_PI*(u + sample.x())*inv_width;
+          Real theta=M_PI*(v + sample.y())*inv_height;
+
+          Real x=cos(phi)*sin(theta);
+          Real y=sin(phi)*sin(theta);
+          Real z=cos(theta);
+
+          Vector normal(x, y, z);
+          Vector origin=center + radius*normal;
+
+          // Compute an ONB at the surface point
+          Vector v0(Cross(normal, Vector(1,0,0)));
+          if (v0.length2()==0)
+            v0=Cross(normal, Vector(0,1,0));
+          Vector v1=Cross(normal, v0);
+          v0.normalize();
+          v1.normalize();
+
+          // Generate a random direction in the hemisphere
+          Vector2D hemi=sample_groups[hidx[0]][i];
+          Real hphi=2.0*M_PI*hemi.x();
+          Real hr=Sqrt(hemi.y());
+          Real hx=hr*cos(hphi);
+          Real hy=hr*sin(hphi);
+          Real hz=1 - hx*hx - hy*hy;
+          hz=(hz>0?Sqrt(hz):0);
+
+          Vector out=Vector(hx, hy, hz).normal();
+          Vector dir=v0*out.x() + v1*out.y() + normal*out.z();
+          dir.normalize();
+
+          // Set ray origin and direction
+          rays.setOrigin(i, origin);
+          rays.setDirection(i, dir);
+        }
+
+        // Reset ray packet
+        rays.setAllFlags(0);
+        rays.setFlag(RayPacket::NormalizedDirections);
+        rays.resetHits();
+
+        // Intersect rays with the geometry
+        context->scene->getObject()->intersect(rctx, rays);
+
+        for (unsigned int i=rays.begin(); i<rays.end();) {
+          if (rays.wasHit(i)) {
+            // Find a run of rays that hit an object
+            unsigned int end=i + 1;
+            while (end < rays.end() && rays.wasHit(end))
+              ++end;
+
+            // Rays that intersect other objects do not contribute, but 
check for
+            // invalid hits (if necessary)
+            if (context->dilate) {
+              // Compute hit positions and normals
+              RayPacket sub(rays, i, end);
+              sub.computeHitPositions();
+              sub.computeNormals(rctx);
+
+              for (unsigned int j=sub.begin(); j<sub.end(); ++j) {
+                Real dotprod=Dot(sub.getNormal(j), -sub.getDirection(j));
+                if (dotprod<=0) {
+                  // An invalid hit, resulting from:
+                  //
+                  //   1.  Intersecting spheres---Ray origin is inside of one
+                  //       sphere and it hits the inside surface of the other
+                  //
+                  //   2.  Ray origin is coincident with the surface of a
+                  //       neighboring sphere---May result in some crazy
+                  //       math, and thus a negative dot product
+                  //
+                  // Either way, ignore the hit and mark the texel for
+                  // dilation
+                  dynplt->inside[u][v] += 1;
+                  dilateTexture=true;
+                }
+              }
+            }
+
+            i=end;
+          } else {
+            // Find a run of rays that didn't hit anything
+            unsigned int end=i + 1;
+            while (end < rays.end() && !rays.wasHit(end))
+              ++end;
+
+            // Only rays that don't intersect other objects contribute to the
+            // ambient illumination at this texel
+            ambient += end - i;
+
+            i=end;
+          }
+        }
+      }
+
+      // Store the normalized result
+      dynplt->texture[u][v]=context->Ka*ambient*inv_nsamples;
+    }
+  }
+
+  return dilateTexture;
+}
+
+bool DynLTWorker::renderGlobal(const DynLTContext* context,
+                               const RenderContext& rctx,
+                               DynLTGridSpheres* grid,
+                               unsigned int particle)
+{
+  // Grab useful information from the DynLT context
+  unsigned int ngroups=context->ngroups;
+  unsigned int nsamples=context->nsamples;
+  unsigned int max_depth=context->max_depth;
+  Real inv_nsamples=1/static_cast<Real>(nsamples);
+
+  // Determine texture resolution
+  DynLT* dynplt=grid->getTexture(particle);
+  unsigned int xres=dynplt->getXRes();
+  unsigned int yres=dynplt->getYRes();
+  // Real inv_width=1/static_cast<Real>(xres - 1);
+  // Real inv_height=1/static_cast<Real>(yres - 1);
+  Real inv_width=1/static_cast<Real>(xres);
+  Real inv_height=1/static_cast<Real>(yres);
+
+  // Intialize the textures
+  bzero(dynplt->texture, xres*yres*sizeof(float));
+  bzero(dynplt->inside, xres*yres*sizeof(float));
+
+  // Generate texture
+  const Vector center=grid->getCenter(particle);
+  Real radius=grid->getRadius(particle);
+  bool dilateTexture=false;
+
+  for (unsigned int v=0; v<yres; ++v) {
+    for (unsigned int u=0; u<xres; ++u) {
+      // Pick a random sample group for surface points
+      unsigned int sidx=static_cast<unsigned int>(ngroups*rng.gendrand());
+
+      // Pick random sample group for points on the hemisphere at each depth
+      for (int d=0; d<=max_depth; ++d)
+        hidx[d]=static_cast<unsigned int>(ngroups*rng.gendrand());
+
+      for (unsigned int s=0; s<nsamples; s += RayPacket::MaxSize) {
+        Real diffuse=0;
+        Real ambient=0;
+        Packet<Real> atten;
+
+        // Initialize a ray packet
+        int size=RayPacket::MaxSize;
+        if (size >= nsamples - s) {
+          // Remaining number of samples isn't large enough to fill a ray
+          // packet, so set the size of the ray packet to the number of 
samples
+          // that remain
+          size=nsamples - s;
+        }
+
+        RayPacketData raydata;
+        RayPacket rays(raydata, RayPacket::UnknownShape, 0, size, 0, 0);
+
+        // Fill in the hit positions and surface normals at sample points
+        for (int i=rays.begin(); i<rays.end(); ++i) {
+          // Project surface sample point onto particle's surface
+          Vector2D sample=sample_groups[sidx][s + i];
+            
+          // Range of 2*M_PI*(u + sample.x)/(xres - 1) --> [0, 2*Pi]
+          // Range of M_PI*(v + sample.y)/(yres - 1) --> [0, Pi]
+          Real phi=2*M_PI*(u + sample.x())*inv_width;
+          Real theta=M_PI*(v + sample.y())*inv_height;
+
+          Real x=cos(phi)*sin(theta);
+          Real y=sin(phi)*sin(theta);
+          Real z=cos(theta);
+
+          Vector normal(x, y, z);
+          Vector surface=center + radius*normal;
+
+          rays.setHitPosition(i, surface);
+          rays.setNormal(i, normal);
+          atten.set(i, 1);
+        }
+
+        // Iteratively trace the ray packet
+        for (unsigned int d=0; d<max_depth; ++d) {
+          // Reset ray packet flags
+          rays.setAllFlags(0);
+          rays.setFlag(RayPacket::HaveHitPositions | RayPacket::HaveNormals |
+                       RayPacket::HaveUnitNormals);
+
+          // Compute direct lighting at current hit positions
+          const LightSet* activeLights=grid->getActiveLights();
+          ShadowAlgorithm::StateBuffer stateBuffer;
+          bool firstTime=true;
+          bool done;
+          do {
+            RayPacketData shadowData;
+            RayPacket shadowRays(shadowData, RayPacket::UnknownShape, 0, 0,
+                                 rays.getDepth(), 0);
+
+            // Call the shadow algorithm (SA) to generate shadow rays.  We
+            // may not be able to compute all of them, so we pass along a
+            // buffer for the SA object to store it's state.  The firstTime
+            // flag tells the SA to fill in the state rather than using
+            // anything in the state buffer.  Most SAs will only need to
+            // store an int or two in the statebuffer.
+            done=rctx.shadowAlgorithm->computeShadows(rctx, activeLights,
+                                                      rays, shadowRays,
+                                                      firstTime,
+                                                      stateBuffer);
+              
+            // Normalize directions for proper dot product computation
+            shadowRays.normalizeDirections();
+
+            for (int i=shadowRays.begin(); i<shadowRays.end(); ++i) {
+              if (!shadowRays.wasHit(i)) {
+                // Not in shadow, so compute the direct contribution
+                Vector normal=rays.getNormal(i);
+                Vector shadowdir=shadowRays.getDirection(i);
+                Real cos_theta=Dot(shadowdir, normal);
+                Color light=shadowRays.getColor(i);
+                diffuse += atten.get(i)*light.luminance()*cos_theta;
+              }
+            }
+              
+            firstTime=false;
+          } while(!done);
+
+          // Don't fill/trace ray packet if it's not going to contribute
+          if (d >= max_depth - 1)
+            break;
+
+          for (int i=rays.begin(); i<rays.end(); ++i) {
+            // Compute an ONB at the surface point
+            Vector normal=rays.getNormal(i);
+            Vector v0(Cross(normal, Vector(1,0,0)));
+            if (v0.length2()==0)
+              v0=Cross(normal, Vector(0,1,0));
+            Vector v1=Cross(normal, v0);
+            v0.normalize();
+            v1.normalize();
+            
+            // Generate a random direction in the hemisphere
+            Vector2D hemi=sample_groups[hidx[d]][i] + VectorT<Real, 2>(0.5, 
0.5);
+            Real hphi=2.0*M_PI*hemi.x();
+            Real hr=Sqrt(hemi.y());
+            Real hx=hr*cos(hphi);
+            Real hy=hr*sin(hphi);
+            Real hz=1 - hx*hx - hy*hy;
+            hz=(hz>0?Sqrt(hz):0);
+
+            Vector out=Vector(hx, hy, hz).normal();
+            Vector dir=v0*out.x() + v1*out.y() + normal*out.z();
+            dir.normalize();
+
+            // Set ray origin and direction
+            rays.setOrigin(i, rays.getHitPosition(i));
+            rays.setDirection(i, dir);
+              
+            // Update attenutation
+            atten.set(i, atten.get(i)*Dot(normal, dir));
+          }
+
+          // Reset ray packet
+          rays.setAllFlags(0);
+          rays.setFlag(RayPacket::NormalizedDirections);
+          rays.resetHits();
+
+          // Intersect rays with the geometry
+          context->scene->getObject()->intersect(rctx, rays);
+
+          // Prepare ray packet for next iteration
+          unsigned int validRays=0;
+          for (unsigned int i=rays.begin(); i<rays.end();) {
+            if (rays.wasHit(i)) {
+              // Find a run of rays that hit an object
+              unsigned int end=i + 1;
+              while (end < rays.end() && rays.wasHit(end))
+                ++end;
+
+              // Compute hit positions and normals
+              RayPacket sub(rays, i, end);
+              sub.computeHitPositions();
+              sub.computeNormals(rctx);
+
+              // Store hit positions, normals for valid hits
+              for (unsigned int j=sub.begin(); j<sub.end(); ++j) {
+                Real dotprod=Dot(sub.getNormal(j), -sub.getDirection(j));
+                if (dotprod>0) {
+                  rays.setHitPosition(validRays, sub.getHitPosition(j));
+                  rays.setNormal(validRays, sub.getNormal(j));
+                  atten.set(validRays, atten.get(j));
+                  ++validRays;
+                } else {
+                  // An invalid hit, resulting from:
+                  //
+                  //   1.  Intersecting spheres---Ray origin is inside of one
+                  //       sphere and it hits the inside surface of the other
+                  //
+                  //   2.  Ray origin is coincident with the surface of a
+                  //       neighboring sphere---May result in some crazy
+                  //       math, and thus a negative dot product
+                  //
+                  // Either way, ignore the hit and mark the texel for
+                  // dilation
+                  dynplt->inside[u][v] += 1;
+                  dilateTexture=true;
+                }
+              }
+
+              i=end;
+            } else {
+              // Find a run of rays that didn't hit anything
+              unsigned int end=i + 1;
+              while (end < rays.end() && !rays.wasHit(end))
+                ++end;
+
+              // Shade the rays, and accumulate background color
+              RayPacket sub(rays, i, end);
+              context->background->shade(rctx, sub);
+
+              for (unsigned int j=sub.begin(); j<sub.end(); ++j)
+                ambient += sub.getColor(j).luminance();
+
+              i=end;
+            }
+          }
+
+          // Terminate at current depth, if necessary
+          if (validRays==0)
+            break;
+
+          // Update the ray packet configuration, loop to next depth
+          rays.setDepth(rays.getDepth() + 1);
+          rays.resize(validRays);
+        }
+
+        // Store the result
+        dynplt->texture[u][v] += context->Ka*ambient + context->Kd*diffuse;
+      }
+
+      // Normalize the texel
+      dynplt->texture[u][v] *= inv_nsamples;
+    }
+  }
+
+  return dilateTexture;
+}
+
+void DynLTWorker::terminate(MantaInterface*)
+{
+  Semaphore semaphore("DynLTWorker Exit Semaphore", 0);
+
+  // Notify worker to exit
+  exitSem=&semaphore;
+  DynLTMessage fake(-1, 0., 0);
+  context->queue->send(fake);
+
+  // Block the calling thread until the worker's done
+  semaphore.down();
+}

Added: trunk/DynLT/DynLTWorker.h
==============================================================================
--- (empty file)
+++ trunk/DynLT/DynLTWorker.h   Thu Jul 20 21:24:57 2006
@@ -0,0 +1,63 @@
+
+#ifndef Manta_DynLT_DynLTWorker_h
+#define Manta_DynLT_DynLTWorker_h
+
+#include <Core/Math/MT_RNG.h>
+#include <Core/Math/vector2d.h>
+#include <Core/Util/Stat.h>
+#include <Interface/MantaInterface.h>
+#include <SCIRun/Core/Containers/Array1.h>
+#include <SCIRun/Core/Containers/Array2.h>
+#include <SCIRun/Core/Thread/Mailbox.h>
+#include <SCIRun/Core/Thread/Runnable.h>
+#include <SCIRun/Core/Thread/Semaphore.h>
+
+#include <float.h>
+
+using namespace SCIRun;
+
+namespace Manta
+{
+  class Background;
+  class DynLTContext;
+  class DynLTGridSpheres;
+  class DynLTMessage;
+  class MantaInterface;
+  class RayPacket;
+  class RenderContext;
+  class Scene;
+  class Sphere;
+
+  class DynLTWorker : public Runnable
+  {
+  public:
+    DynLTWorker(const DynLTContext* context, unsigned int id);
+    virtual ~DynLTWorker(void);
+
+    // Thread run function for static thread scheduling
+    virtual void run(void);
+
+    // Termination call back for static thread scheduling
+    void terminate(MantaInterface*);
+
+    // Parallel pre-render callback for dynamic thread scheduling
+    void timedRun(int proc, int numProcs);
+
+  private:
+    bool renderAmbient(const DynLTContext* context, const RenderContext& 
rctx,
+                       DynLTGridSpheres* grid, unsigned int particle);
+    bool renderGlobal(const DynLTContext* context, const RenderContext& rctx,
+                      DynLTGridSpheres* grid, unsigned int particle);
+    void innerLoop(const RenderContext& rctx, const DynLTMessage& msg);
+
+    const DynLTContext* context;
+    unsigned int id;
+    MT_RNG rng;
+    Array1<Array1<Vector2D> > sample_groups;
+    int* hidx;
+    Background* background;
+    Semaphore* exitSem;
+  };
+}
+
+#endif // Manta_DynLT_DynLTWorker_h

Modified: trunk/Engine/Control/CMakeLists.txt
==============================================================================
--- trunk/Engine/Control/CMakeLists.txt (original)
+++ trunk/Engine/Control/CMakeLists.txt Thu Jul 20 21:24:57 2006
@@ -3,14 +3,3 @@
      Control/RTRT.h
      Control/RTRT.cc
      )
-
-# Conditionally compile DynPLTWorker code
-IF(BUILD_DYNPLT)
-   SET(Manta_Control_SRCS
-       ${Manta_Control_SRCS}
-       Control/DynPLTQueue.h
-       Control/DynPLTQueue.cc
-       Control/DynPLTWorker.h
-       Control/DynPLTWorker.cc
-   )
-ENDIF(BUILD_DYNPLT)

Modified: trunk/Model/CMakeLists.txt
==============================================================================
--- trunk/Model/CMakeLists.txt  (original)
+++ trunk/Model/CMakeLists.txt  Thu Jul 20 21:24:57 2006
@@ -37,9 +37,6 @@
 
 TARGET_LINK_LIBRARIES(Manta_Model Manta_Interface Manta_Core Manta_Image)
 
-IF(BUILD_DYNPLT)
-   TARGET_LINK_LIBRARIES(Manta_Model
-                        ${FOUND_TEEM_LIB})
-ENDIF(BUILD_DYNPLT)
-
-
+IF(BUILD_DYNLT)
+  TARGET_LINK_LIBRARIES(Manta_Model Manta_DynLT)
+ENDIF(BUILD_DYNLT)

Modified: trunk/Model/Groups/TimeSteppedParticles.cc
==============================================================================
--- trunk/Model/Groups/TimeSteppedParticles.cc  (original)
+++ trunk/Model/Groups/TimeSteppedParticles.cc  Thu Jul 20 21:24:57 2006
@@ -1,7 +1,9 @@
 
 #include <Core/Exceptions/InputError.h>
 #include <Core/Exceptions/OutputError.h>
-#include <Engine/Control/DynPLTQueue.h>
+#ifdef BUILD_DYNLT
+#include <DynLT/DynLTGridSpheres.h>
+#endif
 #include <Model/Groups/TimeSteppedParticles.h>
 #include <Model/Primitives/GridSpheres.h>
 #include <Model/Readers/ParticleNRRD.h>
@@ -9,15 +11,15 @@
 #include <fstream>
 using std::ifstream;
 
-using namespace Manta;
-
 #include <iostream>
 using std::cerr;
 
+using namespace Manta;
+
 TimeSteppedParticles::TimeSteppedParticles(const string& filename, int 
ncells,
                                            int depth, Real radius, int ridx,
                                            RegularColorMap* cmap, int cidx,
-                                           DynPLTQueue* queue,
+                                           DynLTQueue* queue,
                                            int min, int max) :
   tstep(0)
 {
@@ -25,16 +27,21 @@
   string::size_type pos=filename.find(".nrrd", 0);
   if (pos != string::npos) {
     ParticleNRRD pnrrd(filename);
+#ifdef BUILD_DYNLT
     if (queue) {
-      queue->resizeHeapIdx(pnrrd.getNParticles());
-      add(new DynPLTGridSpheres(queue, pnrrd.getParticleData(),
+      add(new DynLTGridSpheres(queue, pnrrd.getParticleData(),
                                 pnrrd.getNParticles(), pnrrd.getNVars(), 
ncells,
                                 depth, radius, ridx, cmap, cidx));
     } else {
+#else
+      cerr<<"TimeSteppedParticles - DynLTGridSpheres is not supported\n";
+#endif
       add(new GridSpheres(pnrrd.getParticleData(), pnrrd.getNParticles(),
                           pnrrd.getNVars(), ncells, depth, radius, ridx, 
cmap,
                           cidx));
+#ifdef BUILD_DYNLT
     }
+#endif
 
     return;
   }
@@ -59,15 +66,21 @@
 
     // Load the particle data
     ParticleNRRD pnrrd(fname);
+#ifdef BUILD_DYNLT
     if (queue) {
-      add(new DynPLTGridSpheres(queue, pnrrd.getParticleData(),
+      add(new DynLTGridSpheres(queue, pnrrd.getParticleData(),
                                 pnrrd.getNParticles(), pnrrd.getNVars(), 
ncells,
                                 depth, radius, ridx, cmap, cidx));
     } else {
+#else
+      cerr<<"TimeSteppedParticles - DynLTGridSpheres is not supported\n";
+#endif
       add(new GridSpheres(pnrrd.getParticleData(), pnrrd.getNParticles(),
                           pnrrd.getNVars(), ncells, depth, radius, ridx, 
cmap,
                           cidx));
+#ifdef BUILD_DYNLT
     }
+#endif
 
     ++nloaded;
   }

Modified: trunk/Model/Groups/TimeSteppedParticles.h
==============================================================================
--- trunk/Model/Groups/TimeSteppedParticles.h   (original)
+++ trunk/Model/Groups/TimeSteppedParticles.h   Thu Jul 20 21:24:57 2006
@@ -4,7 +4,6 @@
 
 #include <MantaTypes.h>
 #include <Model/Groups/Group.h>
-#include <Model/Primitives/DynPLTGridSpheres.h>
 #include <SCIRun/Core/Thread/Mailbox.h>
 
 #include <string>
@@ -14,7 +13,7 @@
 
 namespace Manta
 {
-  class DynPLTQueue;
+  class DynLTQueue;
   class RegularColorMap;
 
   class TimeSteppedParticles : public Group
@@ -22,7 +21,7 @@
   public:
     TimeSteppedParticles(const string& filename, int ncells, int depth,
                          Real radius, int ridx, RegularColorMap* cmap, int 
cidx,
-                         DynPLTQueue* queue=0, int min=0,
+                         DynLTQueue* queue=0, int min=0,
                          int max=INT_MAX);
     ~TimeSteppedParticles(void);
 

Modified: trunk/Model/Primitives/CMakeLists.txt
==============================================================================
--- trunk/Model/Primitives/CMakeLists.txt       (original)
+++ trunk/Model/Primitives/CMakeLists.txt       Thu Jul 20 21:24:57 2006
@@ -10,8 +10,6 @@
      Primitives/Cylinder.h
      Primitives/Disk.cc
      Primitives/Disk.h
-     Primitives/DynPLTGridSpheres.cc
-     Primitives/DynPLTGridSpheres.h
      Primitives/GridSpheres.cc
      Primitives/GridSpheres.h
      Primitives/HeavyTriangle.cc

Modified: trunk/Model/Primitives/GridSpheres.cc
==============================================================================
--- trunk/Model/Primitives/GridSpheres.cc       (original)
+++ trunk/Model/Primitives/GridSpheres.cc       Thu Jul 20 21:24:57 2006
@@ -31,6 +31,8 @@
   spheres(spheres), nspheres(nspheres), nvars(nvars), ncells(ncells),
   depth(depth), radius(radius), ridx(ridx), cmap(cmap), cidx(cidx)
 {
+  cerr<<"Initializing GridSpheres\n";
+
   if (radius <= 0) {
     if (ridx <= 0)
       cerr<<"Resetting default radius to 1\n";

Modified: trunk/scenes/CMakeLists.txt
==============================================================================
--- trunk/scenes/CMakeLists.txt (original)
+++ trunk/scenes/CMakeLists.txt Thu Jul 20 21:24:57 2006
@@ -104,8 +104,8 @@
    TARGET_LINK_LIBRARIES(scene_pnrrd ${MANTA_SCENE_LINK})
 ENDIF(BUILD_NRRDPARTICLES)
 
-# Lazily evaluated PLTs for NRRD particle datasets
-IF(BUILD_DYNPLT)
-   ADD_LIBRARY(scene_dynplt dynplt.cc)
-   TARGET_LINK_LIBRARIES(scene_dynplt ${MANTA_SCENE_LINK})
-ENDIF(BUILD_DYNPLT)
+# Lazily evaluated LTs for NRRD particle datasets
+IF(BUILD_DYNLT)
+   ADD_LIBRARY(scene_dynlt dynlt.cc)
+   TARGET_LINK_LIBRARIES(scene_dynlt ${MANTA_SCENE_LINK})
+ENDIF(BUILD_DYNLT)

Added: trunk/scenes/dynlt.cc
==============================================================================
--- (empty file)
+++ trunk/scenes/dynlt.cc       Thu Jul 20 21:24:57 2006
@@ -0,0 +1,276 @@
+
+#include <Core/Color/RegularColorMap.h>
+#include <Core/Exceptions/IllegalArgument.h>
+#include <Core/Geometry/Vector.h>
+#include <Core/Util/Args.h>
+#include <DynLT/DynLTGridSpheres.h>
+#include <DynLT/DynLTQueue.h>
+#include <DynLT/DynLTStatsCollector.h>
+#include <DynLT/DynLTWorker.h>
+#include <Interface/Context.h>
+#include <Interface/LightSet.h>
+#include <Interface/MantaInterface.h>
+#include <Interface/Scene.h>
+#include <Model/AmbientLights/ConstantAmbient.h>
+#include <Model/Backgrounds/ConstantBackground.h>
+#include <Model/Backgrounds/EnvMapBackground.h>
+#include <Model/Groups/TimeSteppedParticles.h>
+#include <Model/Lights/PointLight.h>
+#include <Model/Primitives/Sphere.h>
+#include <Model/Readers/ParticleNRRD.h>
+#include <SCIRun/Core/Thread/Thread.h>
+
+#include <sgi_stl_warnings_off.h>
+#include <iostream>
+#include <sgi_stl_warnings_on.h>
+
+#include <float.h>
+
+#define WORKER_THREAD_STACKSIZE 8*1024*1024
+
+using namespace Manta;
+using namespace SCIRun;
+using namespace std;
+
+extern "C"
+Scene* make_scene(ReadContext const& context, vector<string> const& args)
+{
+  Group* world=0;
+  int cidx=0;
+  string env_fname="";
+  bool use_envmap=false;
+  string fname="";
+  int depth=1;
+  bool dilate=false;
+  bool fifo=false;
+  bool lifo=false;
+  int max_depth=3;
+  int ncells=2;
+  int ngroups=100;
+  int nsamples=25;
+  int nthreads=1;
+  int qsize=16;
+  double radius=1.;
+  int ridx=-1;
+  bool static_threads=false;
+  bool stats=false;
+  double runtime=1./25.;
+  int minproc=0;
+  int maxproc=INT_MAX;
+
+  int argc=static_cast<int>(args.size());
+  for(int i=0; i<argc; ++i) {
+    string arg=args[i];
+#if 0
+    if (arg=="-bv") {
+      string s;
+      if (!getStringArg(i, args, s))
+        throw IllegalArgument("scene dynplt -bv", i, args);
+      world=context.manta_interface->makeGroup(s);
+#endif
+      if (arg=="-cidx") {
+        if (!getIntArg(i, args, cidx))
+          throw IllegalArgument("scene pnrrd -cidx", i, args);
+      } else if (arg=="-depth") {
+        if (!getIntArg(i, args, depth))
+          throw IllegalArgument("scene dynplt -depth", i, args);
+      } else if (arg=="-dilate") {
+        dilate=true;
+      } else if (arg=="-fifo") {
+        fifo=true;
+        lifo=false;
+      } else if (arg=="-envmap") {
+        string s;
+        if (!getStringArg(i, args, s))
+          throw IllegalArgument("scene dynplt -envmap", i, args);
+
+        if (s[0] != '-') {
+          if (s=="bg") {
+            use_envmap=true;
+            if (!getStringArg(i, args, env_fname))
+              throw IllegalArgument("scene dynplt -envmap", i, args);
+          } else {
+            env_fname=s;
+          }
+        } else {
+          throw IllegalArgument("scene dynplt -envmap", i, args);
+        }
+      } else if (arg=="-i") {
+        if (!getStringArg(i, args, fname))
+          throw IllegalArgument("scene dynplt -i", i, args);
+      } else if (arg=="-lifo") {
+        fifo=false;
+        lifo=true;
+      } else if (arg=="-nbounces") {
+        if (!getIntArg(i, args, max_depth))
+          throw IllegalArgument("scene dynplt -nbounces", i, args);
+        ++max_depth;
+      } else if (arg=="-ncells") {
+        if (!getIntArg(i, args, ncells))
+          throw IllegalArgument("scene dynplt -ncells", i, args);
+      } else if (arg=="-ngroups") {
+        if (!getIntArg(i, args, ngroups))
+          throw IllegalArgument("scene dynplt -ngroups", i, args);
+      } else if (arg=="-nsamples") {
+        if (!getIntArg(i, args, nsamples))
+          throw IllegalArgument("scene dynplt -nsamples", i, args);
+      } else if (arg=="-nthreads") {
+        static_threads=true;
+        if (!getIntArg(i, args, nthreads))
+          throw IllegalArgument("scene dynplt -nthreads", i, args);
+      } else if (arg=="-radius") {
+        if (!getDoubleArg(i, args, radius))
+          throw IllegalArgument("scene dynplt -radius", i, args);
+      } else if (arg=="-ridx") {
+        if (!getIntArg(i, args, ridx))
+          throw IllegalArgument("scene dynplt -ridx", i, args);
+      } else if (arg=="-qsize") {
+        if (!getIntArg(i, args, qsize))
+          throw IllegalArgument("scene dynplt -qsize", i, args);
+      } else if (arg=="-stats") {
+        stats=true;
+      } else if (arg=="-timed") {
+        string s;
+        if (getStringArg(i, args, s)) {
+          if (s[0] != '-') {
+            runtime=atof(s.c_str());
+            if (getStringArg(i, args, s)) {
+              minproc=atoi(s.c_str());
+              if (!getIntArg(i, args, maxproc))
+                throw IllegalArgument("scene dynplt -nthreads", i, args);
+            }
+          }
+        }
+      } else {
+        cerr<<"Valid options for scene dynplt:\n";
+        // cerr<<"  -bv <string>                     bounding volume 
{bvh|grid|group}\n";
+        cerr<<"  -cidx <int>                       data value index for 
color mapping\n";
+        cerr<<"  -depth <int>                      grid depth\n";
+        cerr<<"  -dilate                           dilate textures during 
generation\n";
+        cerr<<"  -fifo                             use fifo queue for 
texture requests\n";
+        cerr<<"  -envmap [bg] <string>             environment map 
filename\n";
+        cerr<<"  -i <string>                       particle data filename\n";
+        cerr<<"  -lifo                             use lifo queue for 
texture requests\n";
+        cerr<<"  -nbounces <int>                   number of indirect 
nbounces\n";
+        cerr<<"  -ncells <int>                     grid resolution\n";
+        cerr<<"  -ngroups <int>                    number of sample 
groups\n";
+        cerr<<"  -nsamples <int>                   number of 
samples/texel\n";
+        cerr<<"  -nthreads <int>                   number of static dynplt 
workers\n";
+        cerr<<"  -qsize <int>                      maximum queue qsize\n";
+        cerr<<"  -radius <float>                   particle radius\n";
+        cerr<<"  -ridx <int>                       radius index\n";
+        cerr<<"  -stats                            dump summary stats on 
exit (if stats collection supported by build)\n";
+        cerr<<"  -timed [<double> [<int> <int>]]   texgen thread range and 
runtime (in seconds)\n";
+        throw IllegalArgument("scene dynplt", i, args);
+      }
+    }
+
+    if (!world)
+      world=new Group();
+
+    // Create a scene
+    Scene* scene=new Scene();
+
+    // Create DynLT work queue
+    DynLTQueue* queue;
+    if (fifo) {
+      queue=new DynLTFifoQ(nthreads*qsize);
+      cerr<<"Using FIFO Queue\n";
+    } else if (lifo) {
+      queue=new DynLTLifoQ(nthreads*qsize);
+      cerr<<"Using LIFO Queue\n";
+    } else {
+      queue=new DynLTPriorityQ(nthreads*qsize);
+      cerr<<"Using Priority Queue\n";
+    }
+
+    Background* bg=0;
+    if (env_fname != "")
+      bg=new EnvMapBackground(env_fname);
+    else
+      bg=new ConstantBackground(Color(RGB(0, 0, 0)));
+
+    if (static_threads) {
+      // Static thread scheduling --> create DynLTWorker threads
+      DynLTContext* dpltctx=new DynLTContext(context.manta_interface,
+                                             queue, scene, ngroups, nsamples,
+                                             max_depth, dilate, bg /*, 
runtime,
+                                                                     
minproc, maxproc, kd, ka */);
+
+      for (unsigned int i=0; i<nthreads; ++i) {
+        ostringstream name;
+        name<<"DynLT Worker "<<i;
+        DynLTWorker* worker=new DynLTWorker(dpltctx, i);
+        Thread* thread=new Thread(worker, name.str().c_str(), 0,
+                                  Thread::NotActivated);
+        thread->setStackSize(WORKER_THREAD_STACKSIZE);
+        thread->activate(false);
+      
+        // Register termination callback
+        
context.manta_interface->registerTerminationCallback(Callback::create(worker, 
&DynLTWorker::terminate));
+      }
+    } else {
+      // Dynamic thread scheduling --> register timed texgen function
+      DynLTContext* dpltctx=new DynLTContext(context.manta_interface,
+                                             queue, scene, ngroups, nsamples,
+                                             max_depth, dilate, bg, runtime,
+                                             minproc, maxproc /*, kd, ka */);
+
+      DynLTWorker* worker=new DynLTWorker(dpltctx, 0);
+      
context.manta_interface->registerParallelPreRenderCallback(Callback::create(worker,
 &DynLTWorker::timedRun));
+    }
+
+#ifdef USE_STATS_COLLECTOR
+    // Register DynLTStatsCollector::resetPerFrameStats to reset per-frame 
stats
+    
context.manta_interface->registerSerialPreRenderCallback(Callback::create(DynLTStatsCollector::resetPerFrameStats));
+
+    if (stats) {
+      // Register DynLTStatsCollector::dump to output statistics on exit
+      
context.manta_interface->registerTerminationCallback(Callback::create(DynLTStatsCollector::dump));
+    }
+#else
+    if (stats)
+      cerr<<"Warning:  USE_STATS_COLLECTOR not defined\n";
+#endif
+
+    // Create color map
+    unsigned int type=RegularColorMap::parseType("InvRainbowIso");
+    RegularColorMap* cmap=new RegularColorMap(type);
+
+    // Load particle data, add particles to group
+    TimeSteppedParticles* tsteps=new TimeSteppedParticles(fname, ncells, 
depth,
+                                                          radius, ridx, 
cmap, cidx,
+                                                          queue);
+
+    // Initialize the scene
+    if (env_fname != "" && use_envmap)
+      scene->setBackground(bg);
+    else
+      scene->setBackground(new ConstantBackground(Color(RGB(0, 0, 0))));
+    scene->setObject(tsteps);
+
+    // Add lights
+    LightSet* lights=new LightSet();
+    lights->add(new PointLight(Vector(10, 10, 10), Color(RGB(1, 1, 1))));
+    lights->setAmbientLight(new ConstantAmbient(Color(RGB(0.4, 0.4, 0.4))));
+    scene->setLights(lights);
+
+    /*
+      scene->addBookmark("debug 0", Vector(0.06, 26.9721, 0.06),
+      Vector(0.06, 0.06, 0.06), Vector(0, 0, 1), 0.59);
+      scene->addBookmark("view 0", Vector(0.02, 1.02, 0.20),
+      Vector(0.02, 0.02, 0.20), Vector(0, 0, 1),
+      0.59);
+      scene->addBookmark("view 1", Vector(0.83, 0.85, 4.71),
+      Vector(0.02, 0.01, 0.29), Vector(-0.54, -0.58, 0.59),
+      0.59);
+      scene->addBookmark("view 2", Vector(-0.83, 0.85, 4.71),
+      Vector(0.02, 0.01, 0.29), Vector(-0.59, -0.59, 0.59),
+      0.59);
+      scene->addBookmark("view 3", Vector(1.01349, 0.0783629, 0.297803),
+      Vector(0.02, 0.02, 0.2),
+      Vector(-0.0890283, -0.13761, 0.986477), 0.204219);
+    */
+
+    return scene;
+  }




  • [MANTA] r1151 - in trunk: . Core Core/Util DynLT Engine/Control Model Model/Groups Model/Primitives scenes, cgribble, 07/20/2006

Archive powered by MHonArc 2.6.16.

Top of page