Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

VolumeTexture.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr
00003  *cr            (C) Copyright 1995-2011 The Board of Trustees of the
00004  *cr                        University of Illinois
00005  *cr                         All Rights Reserved
00006  *cr
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  * RCS INFORMATION:
00011  *
00012  *      $RCSfile: VolumeTexture.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.14 $      $Date: 2012/03/01 16:46:01 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *   Class for managing volumetric texture maps for use by the various
00019  *   DrawMolItem representation methods.
00020  ***************************************************************************/
00021 
00022 #include "VolumeTexture.h"
00023 #include "VolumetricData.h"
00024 #include "AtomColor.h"
00025 #include "Scene.h"
00026 #include "VMDApp.h"
00027 #include "Inform.h"
00028 
00029 #include <math.h>
00030 #include <stdio.h>
00031 
00032 VolumeTexture::VolumeTexture()
00033 : v(NULL), texmap(NULL), texid(0) {
00034 
00035   size[0] = size[1] = size[2] = 0;
00036 }
00037 
00038 VolumeTexture::~VolumeTexture() {
00039   if (texmap) vmd_dealloc(texmap);
00040 }
00041 
00042 void VolumeTexture::setGridData(const VolumetricData *voldata) {
00043   if (v == voldata) return;
00044   v = voldata;
00045   if (texmap) {
00046     vmd_dealloc(texmap);
00047     texmap = NULL;
00048   }
00049   size[0] = size[1] = size[2] = 0;
00050   texid = 0;
00051 }
00052 
00053 int VolumeTexture::allocateTextureMap(int npixels) {
00054   texid = 0;
00055   if (texmap) {
00056     vmd_dealloc(texmap);
00057     texmap = NULL;
00058   }
00059   texmap = (unsigned char *) vmd_alloc(npixels*3*sizeof(unsigned char));
00060   if (texmap == NULL) {
00061     msgErr << "Texture map allocation failed, out of memory?" << sendmsg;
00062     return FALSE;
00063   }
00064   memset(texmap, 0, npixels*3*sizeof(unsigned char));
00065   texid = VMDApp::get_texserialnum();
00066   return TRUE;
00067 }
00068 
00069 void VolumeTexture::generatePosTexture() {
00070   // nice small texture that will work everywhere
00071   size[0] = size[1] = size[2] = 32; 
00072   int x, y, z;
00073   int addr, addr2;
00074   int num = size[0]*size[1]*size[2];
00075 
00076   if (!allocateTextureMap(num)) return;
00077 
00078   for (z=0; z<size[2]; z++) {
00079     for (y=0; y<size[1]; y++) {
00080       addr = z * size[0] * size[1] + y * size[0];
00081       for (x=0; x<size[0]; x++) {
00082         addr2 = (addr + x) * 3;
00083         texmap[addr2    ] = (unsigned char) (((float) x / (float) size[0]) * 255.0f);
00084         texmap[addr2 + 1] = (unsigned char) (((float) y / (float) size[1]) * 255.0f);
00085         texmap[addr2 + 2] = (unsigned char) (((float) z / (float) size[2]) * 255.0f);
00086       }
00087     }
00088   }
00089 }
00090 
00091 // convert Hue/Saturation/Value to RGB colors
00092 static void HSItoRGB(float h, float s, float i, 
00093                      unsigned char *r, unsigned char *g, unsigned char *b) {
00094   float rv, gv, bv, t;
00095 
00096   t=float(VMD_TWOPI)*h;
00097   rv=(float) (1 + s*sinf(t - VMD_TWOPI/3));
00098   gv=(float) (1 + s*sinf(t));
00099   bv=(float) (1 + s*sinf(t + VMD_TWOPI/3));
00100 
00101   t=(float) (254.9999 * i / 2);
00102   
00103   *r=(unsigned char)(rv*t);
00104   *g=(unsigned char)(gv*t);
00105   *b=(unsigned char)(bv*t);
00106 }
00107 
00108 // return the smallest power of two greater than size, up to 2^16.
00109 static int nextpower2(int size) {
00110   int i;
00111   int power;
00112 
00113   if (size == 1)
00114     return 1;
00115 
00116   power=1;
00117   for (i=0; i<16; i++) {
00118     power <<= 1;
00119     if (power >= size)
00120       return power;
00121   } 
00122  
00123   return power; 
00124 }
00125 
00126 void VolumeTexture::generateIndexTexture() {
00127   // nice small texture that will work everywhere
00128   size[0] = size[1] = size[2] = 32; 
00129   int x, y, z;
00130   int addr, addr2, addr3, index;
00131   int num = size[0]*size[1]*size[2];
00132   unsigned char coltable[3 * 4096];
00133 
00134   if (!allocateTextureMap(num)) return;
00135 
00136   // build a fast color lookup table
00137   for (index=0; index<4096; index++) {
00138     addr = index * 3;
00139     HSItoRGB(8.0f * index / 4096.0f, 0.75, 1.0,
00140              coltable+addr, coltable+addr+1, coltable+addr+2);
00141   }
00142 
00143   for (z=0; z<size[2]; z++) {
00144     for (y=0; y<size[1]; y++) {
00145       addr = z * size[0] * size[1] + y * size[0];
00146       for (x=0; x<size[0]; x++) {
00147         index = addr + x;
00148         addr2 = index * 3;
00149         addr3 = ((int) ((index / (float) num) * 4095)) * 3;
00150         texmap[addr2    ] = coltable[addr3    ];
00151         texmap[addr2 + 1] = coltable[addr3 + 1];
00152         texmap[addr2 + 2] = coltable[addr3 + 2];
00153       }
00154     }
00155   }
00156 }
00157 
00158 void VolumeTexture::generateChargeTexture(float vmin, float vmax) {
00159   // need a volumetric dataset for this
00160   if (!v) return;
00161 
00162   int x, y, z;
00163   int addr, addr2;
00164   int daddr;
00165   float vscale, vrange;
00166 
00167   size[0] = v->xsize;
00168   size[1] = v->ysize;
00169   size[2] = v->zsize;
00170   for (int i=0; i<3; i++) {
00171     size[i] = nextpower2(size[i]);
00172   }
00173   int num = size[0]*size[1]*size[2];
00174   if (!allocateTextureMap(num)) return;
00175 
00176   vrange = vmax - vmin;
00177   if (fabs(vrange) < 0.00001)
00178     vscale = 0.0f;
00179   else
00180     vscale = 1.00001f / vrange;
00181 
00182   // map volume data scalars to colors
00183   for (z=0; z<v->zsize; z++) {
00184     for (y=0; y<v->ysize; y++) {
00185        addr = z * size[0] * size[1] + y * size[0];
00186       daddr = z * v->xsize * v->ysize + y * v->xsize;
00187       for (x=0; x<v->xsize; x++) {
00188         addr2 = (addr + x) * 3;
00189         float level, r, g, b;
00190 
00191         // map data to range 0->1        
00192         level = (v->data[daddr + x] - vmin) * vscale; 
00193         level = level < 0 ? 0 :
00194                 level > 1 ? 1 : level;
00195 
00196         // low values are mapped to red, high to blue
00197         r = (1.0f - level) * 255.0f;
00198         b = level * 255.0f;
00199         if (level < 0.5f) {
00200           g = level * 2.0f * 128.0f;
00201         } else {
00202           g = (0.5f - (level - 0.5f)) * 2.0f * 128.0f;
00203         }
00204 
00205         texmap[addr2    ] = (unsigned char) r;
00206         texmap[addr2 + 1] = (unsigned char) g;
00207         texmap[addr2 + 2] = (unsigned char) b;
00208       }
00209     }
00210   }
00211 }
00212 
00213 void VolumeTexture::generateHSVTexture(float vmin, float vmax) {
00214   int x, y, z;
00215   int index, addr, addr2, addr3;
00216   int daddr;
00217   float vscale, vrange;
00218   unsigned char coltable[3 * 4096];
00219 
00220   size[0] = v->xsize;
00221   size[1] = v->ysize;
00222   size[2] = v->zsize;
00223   for (int i=0; i<3; i++) {
00224     size[i] = nextpower2(size[i]);
00225   }
00226   int num = size[0]*size[1]*size[2];
00227   if (!allocateTextureMap(num)) return;
00228 
00229   // build a fast color lookup table
00230   for (index=0; index<4096; index++) {
00231     addr = index * 3;
00232     HSItoRGB(4.0f * index / 4096.0f, 0.75, 1.0,
00233              coltable+addr, coltable+addr+1, coltable+addr+2);
00234   }
00235 
00236   // calculate scaling factors
00237   vrange = vmax - vmin;
00238   if (fabs(vrange) < 0.00001)
00239     vscale = 0.0f;
00240   else
00241     vscale = 1.00001f / vrange;
00242 
00243   // map volume data scalars to colors
00244   for (z=0; z<v->zsize; z++) {
00245     for (y=0; y<v->ysize; y++) {
00246        addr = z * size[0] * size[1] + y * size[0];
00247       daddr = z * v->xsize * v->ysize + y * v->xsize;
00248       for (x=0; x<v->xsize; x++) {
00249         addr2 = (addr + x) * 3;
00250         float level;
00251 
00252         // map data to range 0->1        
00253         level = (v->data[daddr + x] - vmin) * vscale; 
00254         level = level < 0 ? 0 :
00255                 level > 1 ? 1 : level;
00256 
00257         // map values to an HSV color map
00258         addr3 = ((int) (level * 4095)) * 3;
00259         texmap[addr2    ] = coltable[addr3    ];
00260         texmap[addr2 + 1] = coltable[addr3 + 1];
00261         texmap[addr2 + 2] = coltable[addr3 + 2];
00262       }
00263     }
00264   }
00265 }
00266 
00267 void VolumeTexture::generateColorScaleTexture(float vmin, float vmax, const Scene *scene) {
00268 
00269   int x, y, z;
00270   int addr, addr2;
00271   int daddr;
00272   float vscale, vrange;
00273 
00274   size[0] = v->xsize;
00275   size[1] = v->ysize;
00276   size[2] = v->zsize;
00277   for (int i=0; i<3; i++) {
00278     size[i] = nextpower2(size[i]);
00279   }
00280   int num = size[0]*size[1]*size[2];
00281   if (!allocateTextureMap(num)) return;
00282 
00283   vrange = vmax - vmin;
00284   if (fabs(vrange) < 0.00001)
00285     vscale = 0.0f;
00286   else
00287     vscale = 1.00001f / vrange;
00288 
00289   // map volume data scalars to colors
00290   for (z=0; z<v->zsize; z++) {
00291     for (y=0; y<v->ysize; y++) {
00292        addr = z * size[0] * size[1] + y * size[0];
00293       daddr = z * v->xsize * v->ysize + y * v->xsize;
00294       for (x=0; x<v->xsize; x++) {
00295         addr2 = (addr + x) * 3;
00296         float level;
00297 
00298         // map data min/max to range 0->1
00299         // values must be clamped before use, since user-specified
00300         // min/max can cause out-of-range color indices to be generated
00301         level = (v->data[daddr + x] - vmin) * vscale; 
00302 
00303         int colindex = (int)(level * MAPCLRS-1);
00304 
00305         if (colindex < 0) 
00306           colindex = 0;
00307         else if (colindex >= MAPCLRS) 
00308           colindex = MAPCLRS-1;
00309 
00310         const float *rgb = scene->color_value(MAPCOLOR(colindex));
00311         texmap[addr2    ] = (unsigned char)(rgb[0]*255.0f);
00312         texmap[addr2 + 1] = (unsigned char)(rgb[1]*255.0f);
00313         texmap[addr2 + 2] = (unsigned char)(rgb[2]*255.0f);
00314       }
00315     }
00316   }
00317 }
00318 
00319 void VolumeTexture::generateContourLineTexture(float densityperline, float linewidth) {
00320   int x, y, z;
00321   int addr, addr2;
00322   float xp, yp, zp;
00323 
00324 printf("Contour lines...\n");
00325 printf("range / densityperline: %f\n", log(v->datamax - v->datamin) / densityperline);
00326 
00327   size[0] = nextpower2(v->xsize*2);
00328   size[1] = nextpower2(v->ysize*2);
00329   size[2] = nextpower2(v->zsize*2);
00330   int num = size[0]*size[1]*size[2];
00331   if (!allocateTextureMap(num)) return;
00332 
00333   // map volume data scalars to contour line colors
00334   for (z=0; z<size[2]; z++) {
00335     zp = ((float) z / size[2]) * v->zsize;
00336     for (y=0; y<size[1]; y++) {
00337       addr = z * size[0] * size[1] + y * size[0];
00338       yp = ((float) y / size[1]) * v->ysize;
00339       for (x=0; x<size[0]; x++) {
00340         addr2 = (addr + x) * 3;
00341         xp = ((float) x / size[0]) * v->xsize;
00342         float level;
00343 
00344         level = float(fmod(log(v->voxel_value_interpolate(xp,yp,zp)), densityperline) / densityperline);
00345 
00346         if (level < linewidth) {
00347           texmap[addr2    ] = 0;
00348           texmap[addr2 + 1] = 0;
00349           texmap[addr2 + 2] = 0;
00350         } else {        
00351           texmap[addr2    ] = 255;
00352           texmap[addr2 + 1] = 255;
00353           texmap[addr2 + 2] = 255;
00354         }
00355       }
00356     }
00357   }
00358 }
00359 
00360 
00361 void VolumeTexture::calculateTexgenPlanes(float v0[3], float v1[3], float v2[3], float v3[3]) const {
00362 
00363   int i;
00364   if (!texmap || !v) {
00365     // do something sensible
00366     vec_zero(v0);
00367     vec_zero(v1);
00368     vec_zero(v2);
00369     vec_zero(v3);
00370     v1[0] = v2[1] = v3[2] = 1;
00371     return;
00372   }
00373 
00374   // rescale texture coordinates by the portion of the 
00375   // entire texture volume they reference
00376   // XXX added an additional scale factor to keep "nearest" texture modes 
00377   //     rounding into the populated area rather than catching black
00378   //     texels in the empty part of the texture volume
00379   float tscale[3];
00380   tscale[0] = (v->xsize / (float)size[0]) * 0.99999f;
00381   tscale[1] = (v->ysize / (float)size[1]) * 0.99999f;
00382   tscale[2] = (v->zsize / (float)size[2]) * 0.99999f;
00383 
00384   // calculate length squared of volume axes
00385   float lensq[3];
00386   vec_zero(lensq);
00387   for (i=0; i<3; i++) {
00388     lensq[0] += float(v->xaxis[i] * v->xaxis[i]);
00389     lensq[1] += float(v->yaxis[i] * v->yaxis[i]);
00390     lensq[2] += float(v->zaxis[i] * v->zaxis[i]);
00391   }
00392 
00393   // Calculate reciprocal space lattice vectors, which are used
00394   // in the OpenGL texgen eye space plane equations in order to transform
00395   // incoming world coordinates to the correct texture coordinates.
00396   // This code should work for both orthogonal and non-orthogonal volumes.
00397   // The last step adds in the NPOT texture scaling where necessary.
00398   // Reference: Introductory Solid State Physics, H.P.Myers, page 43
00399   float xaxdir[3], yaxdir[3], zaxdir[3];
00400   float nxaxdir[3], nyaxdir[3], nzaxdir[3];
00401   float bxc[3], cxa[3], axb[3];
00402   float tmp;
00403 
00404   // copy axis direction vectors
00405   for (i=0; i<3; i++) {
00406     xaxdir[i] = float(v->xaxis[i]);
00407     yaxdir[i] = float(v->yaxis[i]);
00408     zaxdir[i] = float(v->zaxis[i]);
00409   }
00410 
00411   // calculate reciprocal lattice vector for X texture coordiante
00412   cross_prod(bxc, yaxdir, zaxdir);
00413   tmp = dot_prod(xaxdir, bxc); 
00414   for (i=0; i<3; i++) {
00415     nxaxdir[i] = bxc[i] / tmp;
00416   }
00417 
00418   // calculate reciprocal lattice vector for Y texture coordiante
00419   cross_prod(cxa, zaxdir, xaxdir);
00420   tmp = dot_prod(yaxdir, cxa); 
00421   for (i=0; i<3; i++) {
00422     nyaxdir[i] = cxa[i] / tmp;
00423   }
00424 
00425   // calculate reciprocal lattice vector for Z texture coordiante
00426   cross_prod(axb, xaxdir, yaxdir);
00427   tmp = dot_prod(zaxdir, axb); 
00428   for (i=0; i<3; i++) {
00429     nzaxdir[i] = axb[i] / tmp;
00430   }
00431 
00432   // negate and transform the volume origin to reciprocal space
00433   // for use in the OpenGL texgen plane equation
00434   float norigin[3];
00435   for (i=0; i<3; i++)
00436     norigin[i] = float(v->origin[i]);
00437 
00438   v0[0] = -dot_prod(norigin, nxaxdir) * tscale[0];
00439   v0[1] = -dot_prod(norigin, nyaxdir) * tscale[1];
00440   v0[2] = -dot_prod(norigin, nzaxdir) * tscale[2];
00441 
00442   // scale the volume axes for the OpenGL texgen plane equation
00443   for (i=0; i<3; i++) {
00444     v1[i] = nxaxdir[i] * tscale[0];
00445     v2[i] = nyaxdir[i] * tscale[1];
00446     v3[i] = nzaxdir[i] * tscale[2];
00447   }
00448 }
00449 

Generated on Sat May 26 01:48:39 2012 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002