Visualization Library v1.0.3A lightweight C++ OpenGL middleware for 2D/3D graphics |
[Download] [Tutorials] [All Classes] [Grouped Classes] |
00001 /**************************************************************************************/ 00002 /* */ 00003 /* Visualization Library */ 00004 /* http://visualizationlibrary.org */ 00005 /* */ 00006 /* Copyright (c) 2005-2010, Michele Bosi */ 00007 /* All rights reserved. */ 00008 /* */ 00009 /* Redistribution and use in source and binary forms, with or without modification, */ 00010 /* are permitted provided that the following conditions are met: */ 00011 /* */ 00012 /* - Redistributions of source code must retain the above copyright notice, this */ 00013 /* list of conditions and the following disclaimer. */ 00014 /* */ 00015 /* - Redistributions in binary form must reproduce the above copyright notice, this */ 00016 /* list of conditions and the following disclaimer in the documentation and/or */ 00017 /* other materials provided with the distribution. */ 00018 /* */ 00019 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */ 00020 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */ 00021 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ 00022 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */ 00023 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */ 00024 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */ 00025 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */ 00026 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ 00027 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */ 00028 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 00029 /* */ 00030 /**************************************************************************************/ 00031 00032 #include <vlVolume/VolumeUtils.hpp> 00033 #include <vlCore/Log.hpp> 00034 #include <vlCore/glsl_math.hpp> 00035 00036 using namespace vl; 00037 00038 //----------------------------------------------------------------------------- 00039 ref<Image> vl::genRGBAVolume(const Image* data, const Image* trfunc, const fvec3& light_dir, bool alpha_from_data) 00040 { 00041 ref<Image> img; 00042 00043 if(data->type() == IT_UNSIGNED_BYTE) 00044 img = genRGBAVolumeT<unsigned char,IT_UNSIGNED_BYTE>(data,trfunc,light_dir,alpha_from_data); 00045 else 00046 if(data->type() == IT_UNSIGNED_SHORT) 00047 img = genRGBAVolumeT<unsigned short,IT_UNSIGNED_SHORT>(data,trfunc,light_dir,alpha_from_data); 00048 else 00049 if(data->type() == IT_FLOAT) 00050 img = genRGBAVolumeT<float,IT_FLOAT>(data,trfunc,light_dir,alpha_from_data); 00051 else 00052 Log::error("genRGBAVolume() called with non supported data type().\n"); 00053 00054 return img; 00055 } 00056 //----------------------------------------------------------------------------- 00057 ref<Image> vl::genRGBAVolume(const Image* data, const Image* trfunc, bool alpha_from_data) 00058 { 00059 ref<Image> img; 00060 00061 if(data->type() == IT_UNSIGNED_BYTE) 00062 img = genRGBAVolumeT<unsigned char,IT_UNSIGNED_BYTE>(data,trfunc,alpha_from_data); 00063 else 00064 if(data->type() == IT_UNSIGNED_SHORT) 00065 img = genRGBAVolumeT<unsigned short,IT_UNSIGNED_SHORT>(data,trfunc,alpha_from_data); 00066 else 00067 if(data->type() == IT_FLOAT) 00068 img = genRGBAVolumeT<float,IT_FLOAT>(data,trfunc,alpha_from_data); 00069 else 00070 Log::error("genRGBAVolume() called with non supported data type().\n"); 00071 00072 return img; 00073 } 00074 //----------------------------------------------------------------------------- 00075 template<typename data_type, EImageType img_type> 00076 ref<Image> vl::genRGBAVolumeT(const Image* data, const Image* trfunc, const fvec3& light_dir, bool alpha_from_data) 00077 { 00078 if (!trfunc || !data) 00079 return NULL; 00080 if (data->format() != IF_LUMINANCE) 00081 { 00082 Log::error("genRGBAVolume() called with non IF_LUMINANCE data format().\n"); 00083 return NULL; 00084 } 00085 if (data->type() != img_type) 00086 { 00087 Log::error("genRGBAVolume() called with invalid data type().\n"); 00088 return NULL; 00089 } 00090 if (data->dimension() != ID_3D) 00091 { 00092 Log::error("genRGBAVolume() called with non 3D data.\n"); 00093 return NULL; 00094 } 00095 if (trfunc->dimension() != ID_1D) 00096 { 00097 Log::error("genRGBAVolume() transfer function image must be an 1D image.\n"); 00098 return NULL; 00099 } 00100 if (trfunc->format() != IF_RGBA) 00101 { 00102 Log::error("genRGBAVolume() transfer function format() must be IF_RGBA.\n"); 00103 return NULL; 00104 } 00105 if (trfunc->type() != IT_UNSIGNED_BYTE) 00106 { 00107 Log::error("genRGBAVolume() transfer function format() must be IT_UNSIGNED_BYTE.\n"); 00108 return NULL; 00109 } 00110 00111 float normalizer_num = 0; 00112 switch(data->type()) 00113 { 00114 case IT_UNSIGNED_BYTE: normalizer_num = 1.0f/255.0f; break; 00115 case IT_UNSIGNED_SHORT: normalizer_num = 1.0f/65535.0f; break; 00116 case IT_FLOAT: normalizer_num = 1.0f; break; 00117 default: 00118 break; 00119 } 00120 00121 // light normalization 00122 fvec3 L = light_dir; 00123 L.normalize(); 00124 int w = data->width(); 00125 int h = data->height(); 00126 int d = data->depth(); 00127 int pitch = data->pitch(); 00128 const unsigned char* lum_px = data->pixels(); 00129 // generated volume 00130 ref<Image> volume = new Image( w, h, d, 1, IF_RGBA, IT_UNSIGNED_BYTE ); 00131 ubvec4* rgba_px = (ubvec4*)volume->pixels(); 00132 for(int z=0; z<d; ++z) 00133 { 00134 int z1 = z-1; 00135 int z2 = z+1; 00136 z1 = clamp(z1, 0, d-1); 00137 z2 = clamp(z2, 0, d-1); 00138 for(int y=0; y<h; ++y) 00139 { 00140 int y1 = y-1; 00141 int y2 = y+1; 00142 y1 = clamp(y1, 0, h-1); 00143 y2 = clamp(y2, 0, h-1); 00144 for(int x=0; x<w; ++x, ++rgba_px) 00145 { 00146 // value 00147 float lum = (*(data_type*)(lum_px + x*sizeof(data_type) + y*pitch + z*pitch*h)) * normalizer_num; 00148 // value -> transfer function 00149 float xval = lum*trfunc->width(); 00150 VL_CHECK(xval>=0) 00151 if (xval > trfunc->width()-1.001f) 00152 xval = trfunc->width()-1.001f; 00153 int ix1 = (int)xval; 00154 int ix2 = ix1+1; 00155 VL_CHECK(ix2<trfunc->width()) 00156 float w21 = (float)fract(xval); 00157 float w11 = 1.0f - w21; 00158 fvec4 c11 = (fvec4)((ubvec4*)trfunc->pixels())[ix1]; 00159 fvec4 c21 = (fvec4)((ubvec4*)trfunc->pixels())[ix2]; 00160 fvec4 rgba = (c11*w11 + c21*w21)*(1.0f/255.0f); 00161 00162 // bake the lighting 00163 int x1 = x-1; 00164 int x2 = x+1; 00165 x1 = clamp(x1, 0, w-1); 00166 x2 = clamp(x2, 0, w-1); 00167 data_type vx1 = (*(data_type*)(lum_px + x1*sizeof(data_type) + y *pitch + z *pitch*h)); 00168 data_type vx2 = (*(data_type*)(lum_px + x2*sizeof(data_type) + y *pitch + z *pitch*h)); 00169 data_type vy1 = (*(data_type*)(lum_px + x *sizeof(data_type) + y1*pitch + z *pitch*h)); 00170 data_type vy2 = (*(data_type*)(lum_px + x *sizeof(data_type) + y2*pitch + z *pitch*h)); 00171 data_type vz1 = (*(data_type*)(lum_px + x *sizeof(data_type) + y *pitch + z1*pitch*h)); 00172 data_type vz2 = (*(data_type*)(lum_px + x *sizeof(data_type) + y *pitch + z2*pitch*h)); 00173 fvec3 N1(float(vx1-vx2), float(vy1-vy2), float(vz1-vz2)); 00174 N1.normalize(); 00175 fvec3 N2 = -N1 * 0.15f; 00176 float l1 = max(dot(N1,L),0.0f); 00177 float l2 = max(dot(N2,L),0.0f); // opposite dim light to enhance 3D perception 00178 rgba.r() = rgba.r()*l1 + rgba.r()*l2+0.2f; // +0.2f = ambient light 00179 rgba.g() = rgba.g()*l1 + rgba.g()*l2+0.2f; 00180 rgba.b() = rgba.b()*l1 + rgba.b()*l2+0.2f; 00181 rgba.r() = clamp(rgba.r(), 0.0f, 1.0f); 00182 rgba.g() = clamp(rgba.g(), 0.0f, 1.0f); 00183 rgba.b() = clamp(rgba.b(), 0.0f, 1.0f); 00184 00185 // map pixel 00186 rgba_px->r() = (unsigned char)(rgba.r()*255.0f); 00187 rgba_px->g() = (unsigned char)(rgba.g()*255.0f); 00188 rgba_px->b() = (unsigned char)(rgba.b()*255.0f); 00189 if (alpha_from_data) 00190 rgba_px->a() = (unsigned char)(lum*255.0f); 00191 else 00192 rgba_px->a() = (unsigned char)(rgba.a()*255.0f); 00193 } 00194 } 00195 } 00196 00197 return volume; 00198 } 00199 //----------------------------------------------------------------------------- 00200 template<typename data_type, EImageType img_type> 00201 ref<Image> vl::genRGBAVolumeT(const Image* data, const Image* trfunc, bool alpha_from_data) 00202 { 00203 if (!trfunc || !data) 00204 return NULL; 00205 if (data->format() != IF_LUMINANCE) 00206 { 00207 Log::error("genRGBAVolume() called with non IF_LUMINANCE data format().\n"); 00208 return NULL; 00209 } 00210 if (data->type() != img_type) 00211 { 00212 Log::error("genRGBAVolume() called with invalid data type().\n"); 00213 return NULL; 00214 } 00215 if (data->dimension() != ID_3D) 00216 { 00217 Log::error("genRGBAVolume() called with non 3D data.\n"); 00218 return NULL; 00219 } 00220 if (trfunc->dimension() != ID_1D) 00221 { 00222 Log::error("genRGBAVolume() transfer function image must be an 1D image.\n"); 00223 return NULL; 00224 } 00225 if (trfunc->format() != IF_RGBA) 00226 { 00227 Log::error("genRGBAVolume() transfer function format() must be IF_RGBA.\n"); 00228 return NULL; 00229 } 00230 if (trfunc->type() != IT_UNSIGNED_BYTE) 00231 { 00232 Log::error("genRGBAVolume() transfer function format() must be IT_UNSIGNED_BYTE.\n"); 00233 return NULL; 00234 } 00235 00236 float normalizer_num = 0; 00237 switch(data->type()) 00238 { 00239 case IT_UNSIGNED_BYTE: normalizer_num = 1.0f/255.0f; break; 00240 case IT_UNSIGNED_SHORT: normalizer_num = 1.0f/65535.0f; break; 00241 case IT_FLOAT: normalizer_num = 1.0f; break; 00242 default: 00243 break; 00244 } 00245 00246 // light normalization 00247 int w = data->width(); 00248 int h = data->height(); 00249 int d = data->depth(); 00250 int pitch = data->pitch(); 00251 const unsigned char* lum_px = data->pixels(); 00252 // generated volume 00253 ref<Image> volume = new Image( w, h, d, 1, IF_RGBA, IT_UNSIGNED_BYTE ); 00254 ubvec4* rgba_px = (ubvec4*)volume->pixels(); 00255 for(int z=0; z<d; ++z) 00256 { 00257 int z1 = z-1; 00258 int z2 = z+1; 00259 z1 = clamp(z1, 0, d-1); 00260 z2 = clamp(z2, 0, d-1); 00261 for(int y=0; y<h; ++y) 00262 { 00263 int y1 = y-1; 00264 int y2 = y+1; 00265 y1 = clamp(y1, 0, h-1); 00266 y2 = clamp(y2, 0, h-1); 00267 for(int x=0; x<w; ++x, ++rgba_px) 00268 { 00269 // value 00270 float lum = (*(data_type*)(lum_px + x*sizeof(data_type) + y*pitch + z*pitch*h)) * normalizer_num; 00271 // value -> transfer function 00272 float xval = lum*trfunc->width(); 00273 VL_CHECK(xval>=0) 00274 if (xval > trfunc->width()-1.001f) 00275 xval = trfunc->width()-1.001f; 00276 int ix1 = (int)xval; 00277 int ix2 = ix1+1; 00278 VL_CHECK(ix2<trfunc->width()) 00279 float w21 = (float)fract(xval); 00280 float w11 = 1.0f - w21; 00281 fvec4 c11 = (fvec4)((ubvec4*)trfunc->pixels())[ix1]; 00282 fvec4 c21 = (fvec4)((ubvec4*)trfunc->pixels())[ix2]; 00283 fvec4 rgba = (c11*w11 + c21*w21)*(1.0f/255.0f); 00284 00285 // map pixel 00286 rgba_px->r() = (unsigned char)(rgba.r()*255.0f); 00287 rgba_px->g() = (unsigned char)(rgba.g()*255.0f); 00288 rgba_px->b() = (unsigned char)(rgba.b()*255.0f); 00289 if (alpha_from_data) 00290 rgba_px->a() = (unsigned char)(lum*255.0f); 00291 else 00292 rgba_px->a() = (unsigned char)(rgba.a()*255.0f); 00293 } 00294 } 00295 } 00296 00297 return volume; 00298 } 00299 //----------------------------------------------------------------------------- 00300 ref<Image> vl::genGradientNormals(const Image* img) 00301 { 00302 ref<Image> gradient = new Image; 00303 gradient->allocate3D(img->width(), img->height(), img->depth(), 1, IF_RGB, IT_FLOAT); 00304 fvec3* px = (fvec3*)gradient->pixels(); 00305 fvec3 A, B; 00306 for(int z=0; z<gradient->depth(); ++z) 00307 { 00308 for(int y=0; y<gradient->height(); ++y) 00309 { 00310 for(int x=0; x<gradient->width(); ++x) 00311 { 00312 // clamped coordinates 00313 int xp = x+1, xn = x-1; 00314 int yp = y+1, yn = y-1; 00315 int zp = z+1, zn = z-1; 00316 if (xn<0) xn = 0; 00317 if (yn<0) yn = 0; 00318 if (zn<0) zn = 0; 00319 if (xp>img->width() -1) xp = img->width() -1; 00320 if (yp>img->height()-1) yp = img->height()-1; 00321 if (zp>img->depth() -1) zp = img->depth() -1; 00322 00323 A.x() = img->sample(xn,y,z).r(); 00324 B.x() = img->sample(xp,y,z).r(); 00325 A.y() = img->sample(x,yn,z).r(); 00326 B.y() = img->sample(x,yp,z).r(); 00327 A.z() = img->sample(x,y,zn).r(); 00328 B.z() = img->sample(x,y,zp).r(); 00329 00330 // write normal packed into 0..1 format 00331 px[x + img->width()*y + img->width()*img->height()*z] = normalize(A - B) * 0.5f + 0.5f; 00332 } 00333 } 00334 } 00335 return gradient; 00336 } 00337 //-----------------------------------------------------------------------------