Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

SheetSplat.cpp

Go to the documentation of this file.
00001 #include <stdio.h>
00002 #include <fstream.h>
00003 #include <math.h>
00004 
00005 #include "SheetSplat.h"
00006 
00007 #include "vuColour7a.h"
00008 #include "vuColour31a.h"
00009 #include "vuColourXYZa.h"
00010 #include "vuColourRGBa.h"
00011 #include "vuColourSpec.h"
00012 
00013 #define SHSP_SPLAT_CROP_RATIO   0.0             // ratio of slice width below which splat is ignored
00014 #define SHSP_SPLATSTDSCALE      1               // scaling for the standard deviation of the splat is scaled
00015                                                 // the integral is not normalized so values != 1 suck...
00016 #define SHSP_SPLATRADIUS        2.3             // changed from 1.6
00017                                                 // 1.6 is not enough for BCC grids, a larger texture up
00018                                                 // to 2.2 hugely increases quality.
00019                                                 // 2.6 finally makes artifacts disappear.
00020 #define SHSP_SHEETWIDTH         1
00021 
00022 /* notes
00023    least distance on grid with T=sqrt(2) is 1.2247449 (=sqrt(3/2))
00024    that times 1.6 is 1.9595918
00025    sqrt(2) * 1.6 is 2.2627417
00026 */
00027 
00028 //----------------------------------------------------------------------------
00032 float pow(float b, unsigned int e)
00033 {
00034   float r = 1;
00035   while(e) {
00036     if(e&1) r*=b;
00037     b*=b;
00038     e=e>>1;
00039   }
00040 
00041   vuColourXYZa xyz;
00042   xyz.from(vuColourRGBa(1));
00043   return r;
00044 }
00045 
00046 //----------------------------------------------------------------------------
00047 //------------------------- The default constructor --------------------------
00048 //----------------------------------------------------------------------------
00049 
00050 vu1512112::vu1512112()
00051 {
00052   //choose size of splat depending on size of framebuffer
00053   //(to avoid resizing)
00054   m_DataPrepared = false;
00055   m_SplatPos = NULL;
00056   m_Slices = NULL;
00057   m_SliceDist = NULL;
00058   setSliceWidth(SHSP_SHEETWIDTH);
00059   setFootprintSize(SHSP_SPLATRADIUS);
00060   m_Normals = NULL;
00061   m_Shading = NULL;
00062   m_LightDir = vuVector(-1,0,0);
00063   m_LightDiffuse = 0.9;
00064   m_LightAmbient = 0.1;
00065   float scol[] = {1,1,1,0};
00066   m_LightSpecular = vuColourRGBa(scol);
00067   m_LightShininess = 20;
00068   setBGColour(0,0,0);
00069   setImageSize(200,200);
00070 
00071   m_Camera = new vuParallelCamera;
00072 }
00073 
00074 //----------------------------------------------------------------------------
00075 //------------------------- The destructor -----------------------------------
00076 //----------------------------------------------------------------------------
00077 
00078 vu1512112::~vu1512112()
00079 {
00080   clearSheets();
00081   if (m_Camera != NULL) {
00082     delete m_Camera;
00083     m_Camera = NULL;
00084   }
00085 }
00086 
00087 //----------------------------------------------------------------------------
00088 //------------------------- The assignment operator --------------------------
00089 //----------------------------------------------------------------------------
00090 
00091 vu1512112& vu1512112::operator=(const vu1512112& rhs)
00092 {
00093     if (this != &rhs)
00094     {
00095         vu151211::operator=(rhs);
00096     }
00097     return *this;
00098 }
00099 
00100 //----------------------------------------------------------------------------
00101 //------------------------- public getFootprintSize() ------------------------
00102 //----------------------------------------------------------------------------
00103 
00104 float vu1512112::getFootprintSize() const
00105 {
00106     return m_SplatRadius;
00107 }
00108 
00109 //----------------------------------------------------------------------------
00110 //------------------------- public setFootprintSize() ------------------------
00111 //----------------------------------------------------------------------------
00112 
00113 void vu1512112::setFootprintSize(float size)
00114 {
00115   m_SplatRadius = size;
00116   m_SpS_2 = int(m_SplatRadius/m_SliceWidth)+1;
00117 }
00118 
00119 //----------------------------------------------------------------------------
00120 
00121 float vu1512112::getSliceWidth() const
00122 {
00123     return m_SliceWidth;
00124 }
00125 
00126 //----------------------------------------------------------------------------
00127 
00128 void vu1512112::setSliceWidth(const float size)
00129 {
00130   if(size<0.05) m_SliceWidth = 0.05;
00131   else m_SliceWidth = size;
00132   m_SpS_2 = int(m_SplatRadius/m_SliceWidth)+1;
00133   m_SplatCrop = m_SliceWidth*SHSP_SPLAT_CROP_RATIO;
00134 }
00135 
00136 //----------------------------------------------------------------------------
00137 //------------------------- public setViewVectors() --------------------------
00138 //----------------------------------------------------------------------------
00139 
00140 void vu1512112::setViewVectors(const vuVector& view,const vuVector& up,const vuVector& right)
00141 {
00142   //we own the camera, so this call is not really important... (?)
00143 }
00144 
00145 //----------------------------------------------------------------------------
00146 //------------------------- public read() ------------------------------------
00147 //----------------------------------------------------------------------------
00148 
00149 bool vu1512112::read()
00150 {
00151     bool success = vu151211::read();
00152     if (!success) return false;
00153 
00154     m_Center = getVoxelPosition(m_Dim1Size, m_Dim2Size, m_Dim3Size);
00155     m_Center *= 0.5;
00156     m_Camera->setPosition(m_Center);
00157     m_Camera->translateXYZ(0,0,-100);
00158     //m_Camera->setLookAtVector(m_Center-m_Camera->getPosition());
00159     cout<<"cpos";
00160     m_Camera->getPosition().print();
00161 
00162     //Allocate memory for the normals.
00163     if (m_Normals != 0) delete [] m_Normals;
00164     m_Normals = new vuVector[m_DataSize];
00165     if (m_Shading != 0) delete [] m_Shading;
00166     m_Shading = new float[m_DataSize*2];
00167     //Allocate memory for projected splat information
00168     if (m_SplatPos != 0) delete m_SplatPos;
00169     m_SplatPos = new float[m_DataSize*3];
00170     //showHistogram();
00171 
00172     preprocess();
00173     return true;
00174 }
00175 
00176 void vu1512112::showHistogram()
00177 {
00178   dword hist[256];
00179   dword i;
00180   for(i=0;i<256;i++)
00181     hist[i]=0;
00182   byte *dat = m_Data;
00183   for(i=0;i<m_DataSize;i++,dat++)
00184     hist[*dat]++;
00185   for(i=0;i<256;i++)
00186     printf("[%i]=%i ",int(i),int(hist[i]));
00187   putchar('n');
00188 }
00189 
00190 //----------------------------------------------------------------------------
00191 //------------------------- public readRaw() ---------------------------------
00192 //----------------------------------------------------------------------------
00193 
00194 bool vu1512112::readRaw(void)
00195 {
00196     dword len;
00197     ifstream in;
00198 
00199 
00200 #ifdef IS_NOCREATE_NEEDED
00201     in.open(m_FileName, ios::in|ios::binary|ios::nocreate);
00202 #else
00203         // The nocreate is not available on the IRIX boxes that we were compiling
00204         // this code on, so we had to remove this part from
00205     in.open(m_FileName, ios::in|ios::binary);
00206 #endif
00207     if (!in.is_open()) return false;
00208 
00209     in.seekg(0, ios::end);
00210     len = in.tellg();
00211     in.seekg(0, ios::beg);
00212 
00213     in >> m_Dim1Size >> m_Dim2Size >> m_Dim3Size;
00214     if (in.fail()) return false;
00215     m_DataSize = m_Dim1Size*m_Dim2Size*m_Dim3Size;
00216 
00217     m_Data = new byte[m_DataSize];
00218     in.read((char *)m_Data, (int)m_DataSize);
00219     if (in.fail()) return false;
00220 
00221     in.close();
00222 
00223     m_Center = getVoxelPosition(m_Dim1Size, m_Dim2Size, m_Dim3Size);
00224     m_Center *= 0.5;
00225     m_Camera->setPosition(m_Center);
00226     m_Camera->translateXYZ(0,0,-100);
00227     //m_Camera->setLookAtVector(m_Center-m_Camera->getPosition());
00228     cout<<"cpos";
00229     m_Camera->getPosition().print();
00230 
00231     //Allocate memory for the normals.
00232     if (m_Normals != 0) delete [] m_Normals;
00233     m_Normals = new vuVector[m_DataSize];
00234     if (m_Shading != 0) delete [] m_Shading;
00235     m_Shading = new float[m_DataSize*2];
00236     //Allocate memory for projected splat information
00237     if (m_SplatPos != 0) delete m_SplatPos;
00238     m_SplatPos = new float[m_DataSize*3];
00239     //showHistogram();
00240     preprocess();
00241 
00242     return true;
00243 }
00244 
00245 //----------------------------------------------------------------------------
00246 //------------------------- private preprocess() -----------------------------
00247 //----------------------------------------------------------------------------
00248 
00249 void vu1512112::preprocess(void)
00250 {
00251   
00252     // calculate and store normals
00253     dword w, wh;
00254     dword i, j, k, index;
00255 
00256     w = m_Dim1Size;
00257     wh = m_Dim1Size*m_Dim2Size;
00258 
00259     //
00260     // Compute all of the normals and create a quantization
00261     // table with 256 entries.
00262     //
00263     index = 0;
00264     for(k=0;k<m_Dim3Size;++k)
00265     {
00266         for(j=0;j<m_Dim2Size;++j)
00267         {
00268             for(i=0;i<m_Dim1Size;++i)
00269             {
00270                 if (i == 0)
00271                     m_Normals[index][0] = m_Data[index+1]-m_Data[index];
00272                 else if (i == m_Dim1Size-1)
00273                     m_Normals[index][0] = m_Data[index]-m_Data[index-1];
00274                 else
00275                     m_Normals[index][0] = (m_Data[index+1]-m_Data[index-1])*0.5;
00276 
00277                 if (j == 0)
00278                     m_Normals[index][1] = m_Data[index+w]-m_Data[index];
00279                 else if (j == m_Dim2Size-1)
00280                     m_Normals[index][1] = m_Data[index]-m_Data[index-w];
00281                 else
00282                     m_Normals[index][1] = (m_Data[index+w]-m_Data[index-w])*0.5;
00283 
00284                 if ((k == 0) || (k == 1))
00285                     m_Normals[index][2] = m_Data[index+2*wh]-m_Data[index];
00286                 else if ((k == m_Dim3Size-1) || (k == m_Dim3Size-2))
00287                     m_Normals[index][2] = m_Data[index]-m_Data[index-2*wh];
00288                 else
00289                     m_Normals[index][2] = (m_Data[index+2*wh]-m_Data[index-2*wh])*0.5;
00290 
00291                 m_Normals[index].makeUnit();
00292 
00293                 ++index;
00294             }
00295         }
00296     }
00297     
00298     m_DataPrepared = true;
00299 }
00300 
00301 
00302 void vu1512112::setBGColour(float r, float g, float b)
00303 {
00304   m_BGColour[0] = r;
00305   m_BGColour[1] = g;
00306   m_BGColour[2] = b;
00307   m_BGColour[3] = 0;
00308 }
00309 
00310 void vu1512112::run(int whatsup, void* data)
00311 {
00312   drawSlices();
00313 }
00314 
00315 //----------------------------------------------------------------------------
00316 //------------------------- public render() ----------------------------------
00317 //----------------------------------------------------------------------------
00318 
00319 void vu1512112::drawSlices()
00320 {
00321   float black[] = {0,0,0,0};
00322   RGBABuffer sheetBuffer;
00323   sheetBuffer.setSize(m_FBWidth, m_FBHeight);
00324   int cs;
00325   while((cs=m_CurrentSheet++)<m_NSlices) {
00326     sheetBuffer.clear(vuColourRGBa(black));
00327     drawSlice(sheetBuffer, cs);
00328     m_FBMutex.lock();
00329     m_FrameBuffer.blendUnder(sheetBuffer);
00330     m_FBMutex.unlock();
00331     cout<<'.'<<flush;
00332   }
00333 }
00334 
00335 void vu1512112::render(void)
00336 {
00337   if(!m_Data || !m_DataPrepared) return;
00338 
00339   int i,j;
00340 
00341   if(m_Refresh) {
00342 
00343     // build preintegrated splat lut
00344     int pixsize = int(ceil(m_Camera->getWidth()/((vuParallelCamera *)m_Camera)->getXRange()*2*m_SplatRadius));
00345     int piysize = int(ceil(m_Camera->getHeight()/((vuParallelCamera *)m_Camera)->getYRange()*2*m_SplatRadius));
00346     m_Splat.buildSplat(m_SplatRadius/SHSP_SPLATSTDSCALE,pixsize, piysize,128);
00347 
00348     // decide which parts of the transfer function to exclude from splatting
00349     for(i=0; i<256; i++) {
00350       m_Exclude[i] = m_TFunc[i][3] < 0.001;
00351     }
00352     
00353     cout<<"sorting..."<<endl;
00354     sortByDistance();
00355     
00356     cout<<"drawing"<<flush;
00357 
00358     m_FrameBuffer.clear(m_BGColour);
00359     m_CurrentSheet = 0;
00360 
00361     startThread(0);
00362     drawSlices();
00363 
00364     cout<<endl;
00365 
00366     /*
00367     for(i=m_NSlices-1;i>=0;i--) {
00368       m_SheetBuffer.clear(black);
00369       drawSlice(i);
00370       m_FrameBuffer.blendOver(m_SheetBuffer);
00371       cout<<'.'<<flush;
00372     }
00373     */
00374 
00375     m_Refresh = false;
00376   }
00377 
00378   fbtype *fbuf = m_FrameBuffer.getData();
00379   byte *sbuf = new byte[3*m_FBHeight*m_FBWidth];
00380   byte *screen = sbuf;
00381   if(!sbuf) return;
00382   for(i=0;i<m_FBHeight;i++)
00383     for(j=0;j<m_FBWidth;j++) {
00384 #ifdef FB_FLOAT
00385       if(*fbuf>1) *fbuf = 1;
00386       else if(*fbuf<0) *fbuf = 0;
00387       *(screen++) = int(*(fbuf++)*255);
00388       if(*fbuf>1) *fbuf = 1;
00389       else if(*fbuf<0) *fbuf = 0;
00390       *(screen++) = int(*(fbuf++)*255);
00391       if(*fbuf>1) *fbuf = 1;
00392       else if(*fbuf<0) *fbuf = 0;
00393       *(screen++) = int(*(fbuf++)*255);
00394 #else
00395       *(screen++) = (*(fbuf++))>>8;             //FB_WORD
00396       *(screen++) = (*(fbuf++))>>8;
00397       *(screen++) = (*(fbuf++))>>8;
00398 #endif
00399       fbuf++;
00400     }
00401   glRasterPos2f(0,0);
00402   glPixelStorei(GL_UNPACK_ALIGNMENT,1);
00403   glDrawPixels(m_FBWidth,m_FBHeight,GL_RGB,GL_UNSIGNED_BYTE,sbuf);
00404   delete sbuf;
00405 }
00406 
00407 
00408 bool vu1512112::setImageSize(int width, int height)
00409 {
00410   if(!m_FrameBuffer.setSize(width,height)) return false;
00411   m_FrameBuffer.clear(m_BGColour);
00412   m_Camera->setWidth(width);
00413   m_Camera->setHeight(height);
00414   m_FBWidth = width;
00415   m_FBHeight = height;
00416   //doRefresh();
00417   return true;
00418 }
00419 
00420 //----------------------------------------------------------------------------
00421 //------------------------- public initOpenGL() ------------------------------
00422 //----------------------------------------------------------------------------
00423 
00424 void vu1512112::initOpenGL(void)
00425 {
00426 }
00427 
00428 void vu1512112::initSheets(float dist0, float ddist)
00429 {
00430   if(m_Slices != 0) clearSheets();
00431   m_Slices = new dword*[m_NSlices];
00432   m_SliceDist = new float[m_NSlices];
00433   if(!m_Slices) return;
00434   int i;
00435   for(i=0;i<m_NSlices;i++) {
00436     m_Slices[i] = new dword[1];
00437     m_Slices[i][0] = 0;
00438     m_SliceDist[i] = dist0+i*ddist;
00439   }
00440 }
00441 
00442 void vu1512112::prepareSheets()
00443 {
00444   if(m_Slices == 0) return;
00445   int i;
00446   for(i=0;i<m_NSlices;i++) {
00447     int n = m_Slices[i][0]+1;
00448     delete [] m_Slices[i];
00449     m_Slices[i] = new dword[n];
00450     m_Slices[i][0] = 1;         // first entry is reserved for number of contents
00451   }
00452 }
00453 
00454 void vu1512112::clearSheets()
00455 {
00456   if(m_Slices == 0) return;
00457   int i;
00458   for(i=0;i<m_NSlices;i++)
00459     delete [] m_Slices[i];
00460   delete [] m_Slices;
00461   delete [] m_SliceDist;
00462   m_SliceDist = NULL;
00463   m_Slices = NULL;
00464 }
00465 
00466 void vu1512112::sortByDistance()
00467 {
00468   if(m_Dim1Size<2) return;
00469 
00470   m_LightDir = m_Center;
00471   m_LightDir -= m_Camera->getPosition();
00472   m_LightDir.makeUnit();
00473 
00474   clearSheets();
00475 
00476   // figure out number of slices
00477   // find nearest corner
00478   vuVector ldir = m_Camera->getPosition();
00479   ldir -= m_Center;
00480 
00481   int nx,ny,nz;
00482   nx = (ldir[0]>0);
00483   ny = (ldir[1]>0);
00484   nz = (ldir[2]>0);
00485 
00486   int splatslices = int(m_SplatRadius*2/m_SliceWidth)+1;
00487   //if((splatslices*m_SliceWidth)-(m_SplatRadius*2) > 0.1) splatslices++;
00488   float nearest = ((vuParallelCamera *)m_Camera)->getDistance(getVoxelPosition(m_Dim1Size*nx,
00489                                                           m_Dim2Size*ny,
00490                                                           m_Dim3Size*nz));
00491   float farest = ((vuParallelCamera *)m_Camera)->getDistance(getVoxelPosition(m_Dim1Size* (!nx),
00492                                                     m_Dim2Size* (!ny),
00493                                                     m_Dim3Size* (!nz)));
00494   nearest -= (splatslices*m_SliceWidth)/2;
00495   farest += (splatslices*m_SliceWidth)/2;
00496   m_NSlices = (int)ceil((farest-nearest)/m_SliceWidth) + 2;
00497   farest = nearest+ m_SliceWidth*m_NSlices;
00498   printf("near = %4.4f far = %4.4f nslices = %i\n", nearest, farest, m_NSlices);
00499 
00500   initSheets(nearest,m_SliceWidth);
00501 
00502   dword i,j,k;
00503   int index=0, index3=0;                // set to first voxel
00504   float sd;
00505   dword sind;
00506 
00507   for(k=0;k<m_Dim3Size;k++) {
00508     for(j=0;j<m_Dim2Size;j++) {
00509       index = 0+(j*m_Dim1Size)+(k*m_Dim1Size*m_Dim2Size);
00510       index3 = index*3;
00511       vuVector p0 = getVoxelPosition(0,j,k);
00512       vuVector pr0=  p0;
00513       ((vuParallelCamera *)m_Camera)->project(pr0);
00514       memcpy(&m_SplatPos[index3],pr0.getData(),sizeof(float)*3);
00515       if(!m_Exclude[m_Data[index]]) {
00516         sd = m_SplatPos[index3+2]-nearest;
00517         sind = int(sd/m_SliceWidth);
00518         dword lslice = sind+m_SpS_2+1;  //assign splat to the near slices
00519         for(sind = sind-m_SpS_2;sind<lslice;sind++)
00520           m_Slices[sind][0]++;
00521         m_Shading[index<<1] = m_LightDir.dot(m_Normals[index]);
00522       }
00523 
00524       index = 1+(j*m_Dim1Size)+(k*m_Dim1Size*m_Dim2Size);
00525       index3 = index*3;
00526       vuVector p1 = getVoxelPosition(1,j,k);
00527       vuVector pr1= p1;
00528       ((vuParallelCamera *)m_Camera)->project(pr1);
00529       memcpy(&m_SplatPos[index3],pr1.getData(),sizeof(float)*3);
00530       if(!m_Exclude[m_Data[index]]) {
00531         sd = m_SplatPos[index3+2]-nearest;
00532         sind = int(sd/m_SliceWidth);
00533 
00534         dword lslice = sind+m_SpS_2+1;  //assign splat to the near slices
00535         for(sind = sind-m_SpS_2;sind<lslice;sind++)
00536           m_Slices[sind][0]++;
00537 
00538         m_Shading[index<<1] = m_LightDir.dot(m_Normals[index]);
00539       }
00540 
00541       p0 = p1-p0;       // p0 is now step from one position to the next
00542       pr0 = pr1-pr0;    // pr0 is now step of xy projection and distance
00543 
00544       for(i=2;i<m_Dim1Size;i++) {
00545         index = i+(j*m_Dim1Size)+(k*m_Dim1Size*m_Dim2Size);
00546         index3 = index*3;
00547         p1 += p0;
00548         pr1 += pr0;
00549         
00550         if(!m_Exclude[m_Data[index]]) {
00551           memcpy(&m_SplatPos[index3],pr1.getData(),sizeof(float)*3);
00552           sd = m_SplatPos[index3+2]-nearest;
00553           //#if(SHSP_SHEETWIDTH == 1)
00554           //sind = int(sd);
00555           //#else
00556           sind = int(sd/m_SliceWidth);
00557           //#endif
00558           dword lslice = sind+m_SpS_2+1;        //assign splat to the near slices
00559           for(sind = sind-m_SpS_2;sind<lslice;sind++)
00560             m_Slices[sind][0]++;
00561           
00562           // do shading calculation
00563           vuVector& n = m_Normals[index];
00564           float d = m_LightDir.dot(n);                  // diffuse
00565           m_Shading[index<<1] = (d > 0 ? d : 0)*m_LightDiffuse + m_LightAmbient;
00566           vuVector r = p1-m_Camera->getPosition();      // ray from eye to point
00567           r.makeUnit();
00568           r -= ((2*r.dot(n))*n);                                // reflect
00569           float s = m_LightDir.dot(r);          // has negative sign
00570           s = s<0 ? -s : 0;                     // cut?
00571           m_Shading[(index<<1)+1] = pow(s,m_LightShininess); //shininess
00572         }
00573       }
00574     }
00575   }
00576 
00577   //int s;
00578   //for(s=0;s<m_NSlices;s++)
00579   //  cout<<s<<":"<<m_Slices[s][0]<<"  ";
00580   //cout<<endl;
00581 
00582   prepareSheets();
00583 
00584   index = index3 = 0;
00585   for(k=0;k<m_Dim3Size;k++) {
00586     for(j=0;j<m_Dim2Size;j++) {
00587       for(i=0;
00588           i<m_Dim1Size;
00589           i++) {
00590         index = i+(j*m_Dim1Size)+(k*m_Dim1Size*m_Dim2Size);
00591         index3 = index*3;
00592 
00593         if(!m_Exclude[m_Data[index]]) {
00594           sd = m_SplatPos[index3+2]-nearest;
00595           //#if(SHSP_SHEETWIDTH == 1)
00596           //sind = int(sd);
00597           //#else
00598           sind = int(sd/m_SliceWidth);
00599           //#endif
00600           if(sind>0 && sind<(dword)m_NSlices-1) {
00601             dword lslice = sind+m_SpS_2+1;      //assign splat to the near slices
00602             for(sind = sind-m_SpS_2;sind<lslice;sind++)
00603               m_Slices[sind][m_Slices[sind][0]++] = index;
00604           }
00605         }
00606       }
00607     }
00608   }
00609 }
00610 
00611 void vu1512112::drawSlice(RGBABuffer& sheet, int n)
00612 {
00613   dword *splat = &m_Slices[n][1];
00614   byte density;
00615   int w2 = int (m_Camera->getWidth()/2);
00616   int h2 = int (m_Camera->getHeight()/2);
00617   float sdist = m_SliceDist[n];
00618   for(int SC = m_Slices[n][0]-1; SC!=0; SC--, splat++) {
00619 
00620     dword index = *splat;
00621     dword index3 = index*3;
00622     density = m_Data[index];
00623     float t0=sdist-m_SplatPos[index3+2];
00624     float t1=t0+m_SliceWidth;
00625 
00626     vuColourRGBa col(m_TFunc[density]);
00627     col*=m_Shading[index<<1];
00628     vuColourRGBa spec = m_LightSpecular;
00631     spec*=m_Shading[(index<<1)+1];
00632     col += spec;
00633     col.clampTo01();
00634 
00635     sheet.addColourWithM1subM2(m_Splat.getSpla(t1), m_Splat.getSpla(t0),
00636                                col,
00637                                (int) m_SplatPos[index3]+w2, 
00638                                (int) (h2-m_SplatPos[index3+1]));        //flip y-coord
00639   }
00640 }
00641 

Generated on Wed Dec 15 21:20:31 2004 for vuVolume by  doxygen 1.3.9.1