Equalizer 1.0
|
00001 00002 /* Copyright (c) 2007 Maxim Makhinya 00003 * 00004 * Redistribution and use in source and binary forms, with or without 00005 * modification, are permitted provided that the following conditions are met: 00006 * 00007 * - Redistributions of source code must retain the above copyright notice, this 00008 * list of conditions and the following disclaimer. 00009 * - Redistributions in binary form must reproduce the above copyright notice, 00010 * this list of conditions and the following disclaimer in the documentation 00011 * and/or other materials provided with the distribution. 00012 * - Neither the name of Eyescale Software GmbH nor the names of its 00013 * contributors may be used to endorse or promote products derived from this 00014 * software without specific prior written permission. 00015 * 00016 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00017 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00018 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00019 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00020 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00021 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00022 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00023 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00024 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00025 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00026 * POSSIBILITY OF SUCH DAMAGE. 00027 */ 00028 00029 #include "rawVolModel.h" 00030 #include "hlp.h" 00031 00032 namespace eVolve 00033 { 00034 00035 00036 using hlpFuncs::clip; 00037 using hlpFuncs::hFile; 00038 00039 00040 static GLuint createPreintegrationTable( const uint8_t* Table ); 00041 00042 static bool readTransferFunction( FILE* file, std::vector<uint8_t>& TF ); 00043 00044 static bool readDimensionsAndScaling 00045 ( 00046 FILE* file, 00047 uint32_t& w, uint32_t& h, uint32_t& d, 00048 VolumeScaling& volScaling 00049 ); 00050 00051 00052 // Read volume dimensions, scaling and transfer function 00053 RawVolumeModel::RawVolumeModel( const std::string& filename ) 00054 : _headerLoaded( false ) 00055 , _filename( filename ) 00056 , _preintName ( 0 ) 00057 , _glewContext( 0 ) 00058 {} 00059 00060 bool RawVolumeModel::loadHeader( const float brightness, const float alpha ) 00061 { 00062 EQASSERT( !_headerLoaded ); 00063 EQASSERT( brightness > 0.0f ); 00064 EQASSERT( alpha > 0.0f ); 00065 EQLOG( eq::LOG_CUSTOM ) << "-------------------------------------------" 00066 << std::endl << "model: " << _filename; 00067 00068 hFile header( fopen( ( _filename + std::string( ".vhf" ) ).c_str(), "rb" )); 00069 00070 if( header.f==0 ) 00071 { 00072 EQERROR << "Can't open header file" << std::endl; 00073 return false; 00074 } 00075 00076 if( !readDimensionsAndScaling( header.f, _w, _h, _d, _volScaling ) ) 00077 return false; 00078 00079 _resolution = EQ_MAX( _w, EQ_MAX( _h, _d ) ); 00080 00081 if( !readTransferFunction( header.f, _TF )) 00082 return false; 00083 00084 _headerLoaded = true; 00085 00086 if( brightness != 1.0f ) 00087 { 00088 for( size_t i = 0; i < _TF.size(); i+=4 ) 00089 { 00090 _TF[i+0] = static_cast< uint8_t >( _TF[i+0] * brightness ); 00091 _TF[i+1] = static_cast< uint8_t >( _TF[i+1] * brightness ); 00092 _TF[i+2] = static_cast< uint8_t >( _TF[i+2] * brightness ); 00093 } 00094 } 00095 00096 if( alpha != 1.0f ) 00097 for( size_t i = 3; i < _TF.size(); i+=4 ) 00098 _TF[i] = static_cast< uint8_t >( _TF[i] * alpha ); 00099 00100 return true; 00101 } 00102 00103 00104 static int32_t calcHashKey( const eq::Range& range ) 00105 { 00106 return static_cast<int32_t>(( range.start*10000.f + range.end )*10000.f ); 00107 } 00108 00109 00110 bool RawVolumeModel::getVolumeInfo( VolumeInfo& info, const eq::Range& range ) 00111 { 00112 if( !_headerLoaded && !loadHeader( 1.0f, 1.0f )) 00113 return false; 00114 00115 if( _preintName == 0 ) 00116 { 00117 EQLOG( eq::LOG_CUSTOM ) << "Creating preint" << std::endl; 00118 _preintName = createPreintegrationTable( &_TF[0] ); 00119 } 00120 00121 VolumePart* volumePart = 0; 00122 const int32_t key = calcHashKey( range ); 00123 00124 if( _volumeHash.find( key ) == _volumeHash.end( ) ) 00125 { 00126 // new key 00127 volumePart = &_volumeHash[ key ]; 00128 if( !_createVolumeTexture( volumePart->volume, volumePart->TD, range )) 00129 return false; 00130 } 00131 else 00132 { // old key 00133 volumePart = &_volumeHash[ key ]; 00134 } 00135 00136 info.volume = volumePart->volume; 00137 info.TD = volumePart->TD; 00138 info.preint = _preintName; 00139 info.volScaling = _volScaling; 00140 00141 return true; 00142 } 00143 00144 00145 void RawVolumeModel::releaseVolumeInfo( const eq::Range& range ) 00146 { 00147 const int32_t key = calcHashKey( range ); 00148 if( _volumeHash.find( key ) == _volumeHash.end() ) 00149 return; 00150 00151 _volumeHash.erase( key ); 00152 } 00153 00154 00157 static uint32_t calcMinPow2( uint32_t size ) 00158 { 00159 if( size == 0 ) 00160 return 0; 00161 00162 size--; 00163 uint32_t res = 1; 00164 00165 while( size > 0 ) 00166 { 00167 res <<= 1; 00168 size >>= 1; 00169 } 00170 return res; 00171 } 00172 00173 00176 bool RawVolumeModel::_createVolumeTexture( GLuint& volume, 00177 DataInTextureDimensions& TD, 00178 const eq::Range& range ) 00179 { 00180 const uint32_t w = _w; 00181 const uint32_t h = _h; 00182 const uint32_t d = _d; 00183 00184 const int32_t bwStart = 2; //border width from left 00185 const int32_t bwEnd = 2; //border width from right 00186 00187 const int32_t s = 00188 clip<int32_t>( static_cast< int32_t >( d*range.start ), 0, d-1 ); 00189 00190 const int32_t e = 00191 clip<int32_t>( static_cast< int32_t >( d*range.end-1 ), 0, d-1 ); 00192 00193 const uint32_t start = 00194 static_cast<uint32_t>( clip<int32_t>( s-bwStart, 0, d-1 ) ); 00195 00196 const uint32_t end = 00197 static_cast<uint32_t>( clip<int32_t>( e+bwEnd , 0, d-1 ) ); 00198 00199 const uint32_t depth = end-start+1; 00200 00201 const uint32_t tW = calcMinPow2( w ); 00202 const uint32_t tH = calcMinPow2( h ); 00203 const uint32_t tD = calcMinPow2( depth ); 00204 00205 //texture scaling coefficients 00206 TD.W = static_cast<float>( w ) / static_cast<float>( tW ); 00207 TD.H = static_cast<float>( h ) / static_cast<float>( tH ); 00208 TD.D = static_cast<float>( e-s+1 ) / static_cast<float>( tD ); 00209 TD.D /= range.end>range.start ? (range.end-range.start) : 1.0f; 00210 00211 // Shift coefficient and left border in texture for depth 00212 TD.Do = range.start; 00213 TD.Db = range.start > 0.0001 ? bwStart / static_cast<float>(tD) : 0; 00214 00215 EQLOG( eq::LOG_CUSTOM ) 00216 << "===============================================" << std::endl 00217 << " w: " << w << " " << tW 00218 << " h: " << h << " " << tH 00219 << " d: " << d << " " << depth << " " << tD << std::endl 00220 << " r: " << _resolution << std::endl 00221 << " ws: " << TD.W << " hs: " << TD.H << " wd: " << TD.D 00222 << " Do: " << TD.Do << " Db: " << TD.Db << std::endl 00223 << " s= " << start << " e= " << end << std::endl; 00224 00225 // Reading of requested part of a volume 00226 std::vector<uint8_t> data( tW*tH*tD*4, 0 ); 00227 const uint32_t wh4 = w * h * 4; 00228 const uint32_t tWH4 = tW * tH * 4; 00229 00230 std::ifstream file ( _filename.c_str(), std::ifstream::in | 00231 std::ifstream::binary | std::ifstream::ate ); 00232 00233 if( !file.is_open() ) 00234 { 00235 EQERROR << "Can't open model data file"; 00236 return false; 00237 } 00238 00239 file.seekg( wh4*start, std::ios::beg ); 00240 00241 if( w==tW && h==tH ) // width and height are power of 2 00242 { 00243 file.read( (char*)( &data[0] ), wh4*depth ); 00244 } 00245 else if( w==tW ) // only width is power of 2 00246 { 00247 for( uint32_t i=0; i<depth; i++ ) 00248 file.read( (char*)( &data[i*tWH4] ), wh4 ); 00249 } 00250 else 00251 { // nor width nor heigh is power of 2 00252 const uint32_t w4 = w * 4; 00253 const uint32_t tW4 = tW * 4; 00254 00255 for( uint32_t i=0; i<depth; i++ ) 00256 for( uint32_t j=0; j<h; j++ ) 00257 file.read( (char*)( &data[ i*tWH4 + j*tW4] ), w4 ); 00258 } 00259 00260 file.close(); 00261 00262 EQASSERT( _glewContext ); 00263 // create 3D texture 00264 glGenTextures( 1, &volume ); 00265 EQLOG( eq::LOG_CUSTOM ) << "generated texture: " << volume << std::endl; 00266 glBindTexture(GL_TEXTURE_3D, volume); 00267 00268 glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ); 00269 glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ); 00270 glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_R , GL_CLAMP_TO_EDGE ); 00271 glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); 00272 glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); 00273 00274 glTexImage3D( GL_TEXTURE_3D, 00275 0, GL_RGBA, tW, tH, tD, 00276 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)(&data[0]) ); 00277 return true; 00278 } 00279 00280 00285 static void normalizeScaling 00286 ( 00287 const uint32_t w, 00288 const uint32_t h, 00289 const uint32_t d, 00290 VolumeScaling& scaling 00291 ) 00292 { 00293 //Correct proportions according to real size of volume 00294 float maxS = float( EQ_MAX( w, EQ_MAX( h, d ) )); 00295 00296 scaling.W *= w / maxS; 00297 scaling.H *= h / maxS; 00298 scaling.D *= d / maxS; 00299 00300 //Make maximum proportion equal to 1.0 00301 maxS = EQ_MAX( scaling.W, EQ_MAX( scaling.H, scaling.D ) ); 00302 00303 scaling.W /= maxS; 00304 scaling.H /= maxS; 00305 scaling.D /= maxS; 00306 } 00307 00308 00309 static bool readDimensionsAndScaling 00310 ( 00311 FILE* file, 00312 uint32_t& w, uint32_t& h, uint32_t& d, 00313 VolumeScaling& volScaling 00314 ) 00315 { 00316 if( fscanf( file, "w=%u\n", &w ) == EOF ) 00317 return false; 00318 if( fscanf( file, "h=%u\n", &h ) == EOF ) 00319 return false; 00320 if( fscanf( file, "d=%u\n", &d ) != 1 ) 00321 { 00322 EQERROR << "Can't read dimensions from header file" << std::endl; 00323 return false; 00324 } 00325 00326 if( fscanf( file, "wScale=%g\n", &volScaling.W ) == EOF ) 00327 return false; 00328 if( fscanf( file, "hScale=%g\n", &volScaling.H ) == EOF ) 00329 return false; 00330 if( fscanf( file, "dScale=%g\n", &volScaling.D ) != 1 ) 00331 { 00332 EQERROR << "Can't read scaling from header file: " << std::endl; 00333 return false; 00334 } 00335 00336 if( w<1 || h<1 || d<1 || 00337 volScaling.W<0.001 || 00338 volScaling.H<0.001 || 00339 volScaling.W<0.001 ) 00340 { 00341 EQERROR << "volume scaling is incorrect, check header file"<< std::endl; 00342 return false; 00343 } 00344 00345 normalizeScaling( w, h, d, volScaling ); 00346 00347 EQLOG( eq::LOG_CUSTOM ) << " " << w << "x" << h << "x" << d << std::endl 00348 << "( " << volScaling.W << " x " 00349 << volScaling.H << " x " 00350 << volScaling.D << " )" << std::endl; 00351 return true; 00352 } 00353 00354 00355 static bool readTransferFunction( FILE* file, std::vector<uint8_t>& TF ) 00356 { 00357 if( fscanf(file,"TF:\n") !=0 ) 00358 { 00359 EQERROR << "Error in header file, can't find 'TF:' marker."; 00360 return false; 00361 } 00362 00363 uint32_t TFSize; 00364 if( fscanf( file, "size=%u\n", &TFSize ) == EOF ) 00365 return false; 00366 00367 if( TFSize!=256 ) 00368 EQWARN << "Wrong size of transfer function, should be 256" << std::endl; 00369 00370 TFSize = clip<int32_t>( TFSize, 1, 256 ); 00371 TF.resize( TFSize*4 ); 00372 00373 int tmp; 00374 for( uint32_t i=0; i<TFSize; i++ ) 00375 { 00376 if( fscanf( file, "r=%d\n", &tmp ) == EOF ) 00377 return false; 00378 TF[4*i ] = tmp; 00379 if( fscanf( file, "g=%d\n", &tmp ) == EOF ) 00380 return false; 00381 TF[4*i+1] = tmp; 00382 if( fscanf( file, "b=%d\n", &tmp ) == EOF ) 00383 return false; 00384 TF[4*i+2] = tmp; 00385 if( fscanf( file, "a=%d\n", &tmp ) != 1 ) 00386 { 00387 EQERROR << "Failed to read entity #" << i 00388 << " of TF from header file" << std::endl; 00389 return i; 00390 } 00391 TF[4*i+3] = tmp; 00392 } 00393 00394 return true; 00395 } 00396 00397 00398 static GLuint createPreintegrationTable( const uint8_t *Table ) 00399 { 00400 EQLOG( eq::LOG_CUSTOM ) << "Calculating preintegration table" << std::endl; 00401 00402 double rInt[256]; rInt[0] = 0.; 00403 double gInt[256]; gInt[0] = 0.; 00404 double bInt[256]; bInt[0] = 0.; 00405 double aInt[256]; aInt[0] = 0.; 00406 00407 for( int i=1; i<256; i++ ) 00408 { 00409 const double tauc = ( Table[(i-1)*4+3] + Table[i*4+3] ) / 2.; 00410 00411 rInt[i] = rInt[i-1] + ( Table[(i-1)*4+0] + Table[i*4+0] )/2.*tauc/255.; 00412 gInt[i] = gInt[i-1] + ( Table[(i-1)*4+1] + Table[i*4+1] )/2.*tauc/255.; 00413 bInt[i] = bInt[i-1] + ( Table[(i-1)*4+2] + Table[i*4+2] )/2.*tauc/255.; 00414 aInt[i] = aInt[i-1] + tauc; 00415 } 00416 00417 std::vector<GLubyte> lookupImg( 256*256*4, 255 ); // Preint Texture 00418 00419 int lookupindex=0; 00420 00421 for( int sb=0; sb<256; sb++ ) 00422 { 00423 for( int sf=0; sf<256; sf++ ) 00424 { 00425 int smin, smax; 00426 if( sb<sf ) { smin=sb; smax=sf; } 00427 else { smin=sf; smax=sb; } 00428 00429 int rcol, gcol, bcol, acol; 00430 if( smax != smin ) 00431 { 00432 const double factor = 1. / (double)(smax-smin); 00433 rcol = static_cast<int>( (rInt[smax]-rInt[smin])*factor ); 00434 gcol = static_cast<int>( (gInt[smax]-gInt[smin])*factor ); 00435 bcol = static_cast<int>( (bInt[smax]-bInt[smin])*factor ); 00436 acol = static_cast<int>( 00437 256.*( exp(-(aInt[smax]-aInt[smin])*factor/255.))); 00438 } else 00439 { 00440 const int index = smin*4; 00441 const double factor = 1./255.; 00442 rcol = static_cast<int>( Table[index+0]*Table[index+3]*factor ); 00443 gcol = static_cast<int>( Table[index+1]*Table[index+3]*factor ); 00444 bcol = static_cast<int>( Table[index+2]*Table[index+3]*factor ); 00445 acol = static_cast<int>( 256.*( exp(-Table[index+3]/255.)) ); 00446 } 00447 lookupImg[lookupindex++] = clip( rcol, 0, 255 );//MIN( rcol, 255 ); 00448 lookupImg[lookupindex++] = clip( gcol, 0, 255 );//MIN( gcol, 255 ); 00449 lookupImg[lookupindex++] = clip( bcol, 0, 255 );//MIN( bcol, 255 ); 00450 lookupImg[lookupindex++] = clip( acol, 0, 255 );//MIN( acol, 255 ); 00451 } 00452 } 00453 00454 GLuint preintName = 0; 00455 glGenTextures( 1, &preintName ); 00456 glBindTexture( GL_TEXTURE_2D, preintName ); 00457 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, 00458 GL_RGBA, GL_UNSIGNED_BYTE, &lookupImg[0] ); 00459 00460 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); 00461 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); 00462 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); 00463 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); 00464 00465 return preintName; 00466 } 00467 00468 00469 }