00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "rawVolModel.h"
00019 #include "hlp.h"
00020
00021 namespace eVolve
00022 {
00023
00024
00025 using hlpFuncs::clip;
00026 using hlpFuncs::hFile;
00027
00028
00029 static GLuint createPreintegrationTable( const uint8_t* Table );
00030
00031 static bool readTransferFunction( FILE* file, std::vector<uint8_t>& TF );
00032
00033 static bool readDimensionsAndScaling
00034 (
00035 FILE* file,
00036 uint32_t& w, uint32_t& h, uint32_t& d,
00037 VolumeScaling& volScaling
00038 );
00039
00040
00041
00042 RawVolumeModel::RawVolumeModel( const std::string& filename )
00043 : _headerLoaded( false )
00044 , _filename( filename )
00045 , _preintName ( 0 )
00046 , _glewContext( 0 )
00047 {}
00048
00049 bool RawVolumeModel::loadHeader( const float brightness, const float alpha )
00050 {
00051 EQASSERT( !_headerLoaded );
00052 EQASSERT( brightness > 0.0f );
00053 EQASSERT( alpha > 0.0f );
00054 EQLOG( eq::LOG_CUSTOM ) << "-------------------------------------------"
00055 << std::endl << "model: " << _filename;
00056
00057 hFile header( fopen( ( _filename + std::string( ".vhf" ) ).c_str(), "rb" ));
00058
00059 if( header.f==0 )
00060 {
00061 EQERROR << "Can't open header file" << std::endl;
00062 return false;
00063 }
00064
00065 if( !readDimensionsAndScaling( header.f, _w, _h, _d, _volScaling ) )
00066 return false;
00067
00068 _resolution = EQ_MAX( _w, EQ_MAX( _h, _d ) );
00069
00070 if( !readTransferFunction( header.f, _TF ))
00071 return false;
00072
00073 _headerLoaded = true;
00074
00075 if( brightness != 1.0f )
00076 {
00077 for( size_t i = 0; i < _TF.size(); i+=4 )
00078 {
00079 _TF[i+0] = static_cast< uint8_t >( _TF[i+0] * brightness );
00080 _TF[i+1] = static_cast< uint8_t >( _TF[i+1] * brightness );
00081 _TF[i+2] = static_cast< uint8_t >( _TF[i+2] * brightness );
00082 }
00083 }
00084
00085 if( alpha != 1.0f )
00086 for( size_t i = 3; i < _TF.size(); i+=4 )
00087 _TF[i] = static_cast< uint8_t >( _TF[i] * alpha );
00088
00089 return true;
00090 }
00091
00092
00093 static int32_t calcHashKey( const eq::Range& range )
00094 {
00095 return static_cast<int32_t>(( range.start*10000.f + range.end )*10000.f );
00096 }
00097
00098
00099 bool RawVolumeModel::getVolumeInfo( VolumeInfo& info, const eq::Range& range )
00100 {
00101 if( !_headerLoaded && !loadHeader( 1.0f, 1.0f ))
00102 return false;
00103
00104 if( _preintName == 0 )
00105 {
00106 EQLOG( eq::LOG_CUSTOM ) << "Creating preint" << std::endl;
00107 _preintName = createPreintegrationTable( &_TF[0] );
00108 }
00109
00110 VolumePart* volumePart = 0;
00111 const int32_t key = calcHashKey( range );
00112
00113 if( _volumeHash.find( key ) == _volumeHash.end( ) )
00114 {
00115
00116 volumePart = &_volumeHash[ key ];
00117 if( !_createVolumeTexture( volumePart->volume, volumePart->TD, range ))
00118 return false;
00119 }
00120 else
00121 {
00122 volumePart = &_volumeHash[ key ];
00123 }
00124
00125 info.volume = volumePart->volume;
00126 info.TD = volumePart->TD;
00127 info.preint = _preintName;
00128 info.volScaling = _volScaling;
00129
00130 return true;
00131 }
00132
00133
00134 void RawVolumeModel::releaseVolumeInfo( const eq::Range& range )
00135 {
00136 const int32_t key = calcHashKey( range );
00137 if( _volumeHash.find( key ) == _volumeHash.end() )
00138 return;
00139
00140 _volumeHash.erase( key );
00141 }
00142
00143
00146 static uint32_t calcMinPow2( uint32_t size )
00147 {
00148 if( size == 0 )
00149 return 0;
00150
00151 size--;
00152 uint32_t res = 1;
00153
00154 while( size > 0 )
00155 {
00156 res <<= 1;
00157 size >>= 1;
00158 }
00159 return res;
00160 }
00161
00162
00165 bool RawVolumeModel::_createVolumeTexture( GLuint& volume,
00166 DataInTextureDimensions& TD,
00167 const eq::Range& range )
00168 {
00169 const uint32_t w = _w;
00170 const uint32_t h = _h;
00171 const uint32_t d = _d;
00172
00173 const int32_t bwStart = 2;
00174 const int32_t bwEnd = 2;
00175
00176 const int32_t s =
00177 clip<int32_t>( static_cast< int32_t >( d*range.start ), 0, d-1 );
00178
00179 const int32_t e =
00180 clip<int32_t>( static_cast< int32_t >( d*range.end-1 ), 0, d-1 );
00181
00182 const uint32_t start =
00183 static_cast<uint32_t>( clip<int32_t>( s-bwStart, 0, d-1 ) );
00184
00185 const uint32_t end =
00186 static_cast<uint32_t>( clip<int32_t>( e+bwEnd , 0, d-1 ) );
00187
00188 const uint32_t depth = end-start+1;
00189
00190 const uint32_t tW = calcMinPow2( w );
00191 const uint32_t tH = calcMinPow2( h );
00192 const uint32_t tD = calcMinPow2( depth );
00193
00194
00195 TD.W = static_cast<float>( w ) / static_cast<float>( tW );
00196 TD.H = static_cast<float>( h ) / static_cast<float>( tH );
00197 TD.D = static_cast<float>( e-s+1 ) / static_cast<float>( tD );
00198 TD.D /= range.end>range.start ? (range.end-range.start) : 1.0 ;
00199
00200
00201 TD.Do = range.start;
00202 TD.Db = range.start > 0.0001 ? bwStart / static_cast<float>(tD) : 0;
00203
00204 EQLOG( eq::LOG_CUSTOM )
00205 << "===============================================" << std::endl
00206 << " w: " << w << " " << tW
00207 << " h: " << h << " " << tH
00208 << " d: " << d << " " << depth << " " << tD << std::endl
00209 << " r: " << _resolution << std::endl
00210 << " ws: " << TD.W << " hs: " << TD.H << " wd: " << TD.D
00211 << " Do: " << TD.Do << " Db: " << TD.Db << std::endl
00212 << " s= " << start << " e= " << end << std::endl;
00213
00214
00215 std::vector<uint8_t> data( tW*tH*tD*4, 0 );
00216 const uint32_t wh4 = w * h * 4;
00217 const uint32_t tWH4 = tW * tH * 4;
00218
00219 std::ifstream file ( _filename.c_str(), std::ifstream::in |
00220 std::ifstream::binary | std::ifstream::ate );
00221
00222 if( !file.is_open() )
00223 {
00224 EQERROR << "Can't open model data file";
00225 return false;
00226 }
00227
00228 file.seekg( wh4*start, std::ios::beg );
00229
00230 if( w==tW && h==tH )
00231 {
00232 file.read( (char*)( &data[0] ), wh4*depth );
00233 }
00234 else if( w==tW )
00235 {
00236 for( uint32_t i=0; i<depth; i++ )
00237 file.read( (char*)( &data[i*tWH4] ), wh4 );
00238 }
00239 else
00240 {
00241 const uint32_t w4 = w * 4;
00242 const uint32_t tW4 = tW * 4;
00243
00244 for( uint32_t i=0; i<depth; i++ )
00245 for( uint32_t j=0; j<h; j++ )
00246 file.read( (char*)( &data[ i*tWH4 + j*tW4] ), w4 );
00247 }
00248
00249 file.close();
00250
00251 EQASSERT( _glewContext );
00252
00253 glGenTextures( 1, &volume );
00254 EQLOG( eq::LOG_CUSTOM ) << "generated texture: " << volume << std::endl;
00255 glBindTexture(GL_TEXTURE_3D, volume);
00256
00257 glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE );
00258 glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE );
00259 glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_R , GL_CLAMP_TO_EDGE );
00260 glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
00261 glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
00262
00263 glTexImage3D( GL_TEXTURE_3D,
00264 0, GL_RGBA, tW, tH, tD,
00265 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)(&data[0]) );
00266 return true;
00267 }
00268
00269
00274 static void normalizeScaling
00275 (
00276 const uint32_t w,
00277 const uint32_t h,
00278 const uint32_t d,
00279 VolumeScaling& scaling
00280 )
00281 {
00282
00283 float maxS = EQ_MAX( w, EQ_MAX( h, d ) );
00284
00285 scaling.W *= w / maxS;
00286 scaling.H *= h / maxS;
00287 scaling.D *= d / maxS;
00288
00289
00290 maxS = EQ_MAX( scaling.W, EQ_MAX( scaling.H, scaling.D ) );
00291
00292 scaling.W /= maxS;
00293 scaling.H /= maxS;
00294 scaling.D /= maxS;
00295 }
00296
00297
00298 static bool readDimensionsAndScaling
00299 (
00300 FILE* file,
00301 uint32_t& w, uint32_t& h, uint32_t& d,
00302 VolumeScaling& volScaling
00303 )
00304 {
00305 fscanf( file, "w=%u\n", &w );
00306 fscanf( file, "h=%u\n", &h );
00307 if( fscanf( file, "d=%u\n", &d ) != 1 )
00308 {
00309 EQERROR << "Can't read dimensions from header file" << std::endl;
00310 return false;
00311 }
00312
00313 fscanf( file, "wScale=%g\n", &volScaling.W );
00314 fscanf( file, "hScale=%g\n", &volScaling.H );
00315 if( fscanf( file, "dScale=%g\n", &volScaling.D ) != 1 )
00316 {
00317 EQERROR << "Can't read scaling from header file: " << std::endl;
00318 return false;
00319 }
00320
00321 if( w<1 || h<1 || d<1 ||
00322 volScaling.W<0.001 ||
00323 volScaling.H<0.001 ||
00324 volScaling.W<0.001 )
00325 {
00326 EQERROR << "volume scaling is incorrect, check header file"<< std::endl;
00327 return false;
00328 }
00329
00330 normalizeScaling( w, h, d, volScaling );
00331
00332 EQLOG( eq::LOG_CUSTOM ) << " " << w << "x" << h << "x" << d << std::endl
00333 << "( " << volScaling.W << " x "
00334 << volScaling.H << " x "
00335 << volScaling.D << " )" << std::endl;
00336 return true;
00337 }
00338
00339
00340 static bool readTransferFunction( FILE* file, std::vector<uint8_t>& TF )
00341 {
00342 if( fscanf(file,"TF:\n") !=0 )
00343 {
00344 EQERROR << "Error in header file, can't find 'TF:' marker.";
00345 return false;
00346 }
00347
00348 uint32_t TFSize;
00349 fscanf( file, "size=%u\n", &TFSize );
00350
00351 if( TFSize!=256 )
00352 EQWARN << "Wrong size of transfer function, should be 256" << std::endl;
00353
00354 TFSize = clip<int32_t>( TFSize, 1, 256 );
00355 TF.resize( TFSize*4 );
00356
00357 int tmp;
00358 for( uint32_t i=0; i<TFSize; i++ )
00359 {
00360 fscanf( file, "r=%d\n", &tmp ); TF[4*i ] = tmp;
00361 fscanf( file, "g=%d\n", &tmp ); TF[4*i+1] = tmp;
00362 fscanf( file, "b=%d\n", &tmp ); TF[4*i+2] = tmp;
00363 if( fscanf( file, "a=%d\n", &tmp ) != 1 )
00364 {
00365 EQERROR << "Failed to read entity #" << i
00366 << " of TF from header file" << std::endl;
00367 return i;
00368 }
00369 TF[4*i+3] = tmp;
00370 }
00371
00372 return true;
00373 }
00374
00375
00376 static GLuint createPreintegrationTable( const uint8_t *Table )
00377 {
00378 EQLOG( eq::LOG_CUSTOM ) << "Calculating preintegration table" << std::endl;
00379
00380 double rInt[256]; rInt[0] = 0.;
00381 double gInt[256]; gInt[0] = 0.;
00382 double bInt[256]; bInt[0] = 0.;
00383 double aInt[256]; aInt[0] = 0.;
00384
00385 for( int i=1; i<256; i++ )
00386 {
00387 const double tauc = ( Table[(i-1)*4+3] + Table[i*4+3] ) / 2.;
00388
00389 rInt[i] = rInt[i-1] + ( Table[(i-1)*4+0] + Table[i*4+0] )/2.*tauc/255.;
00390 gInt[i] = gInt[i-1] + ( Table[(i-1)*4+1] + Table[i*4+1] )/2.*tauc/255.;
00391 bInt[i] = bInt[i-1] + ( Table[(i-1)*4+2] + Table[i*4+2] )/2.*tauc/255.;
00392 aInt[i] = aInt[i-1] + tauc;
00393 }
00394
00395 std::vector<GLubyte> lookupImg( 256*256*4, 255 );
00396
00397 int lookupindex=0;
00398
00399 for( int sb=0; sb<256; sb++ )
00400 {
00401 for( int sf=0; sf<256; sf++ )
00402 {
00403 int smin, smax;
00404 if( sb<sf ) { smin=sb; smax=sf; }
00405 else { smin=sf; smax=sb; }
00406
00407 int rcol, gcol, bcol, acol;
00408 if( smax != smin )
00409 {
00410 const double factor = 1. / (double)(smax-smin);
00411 rcol = static_cast<int>( (rInt[smax]-rInt[smin])*factor );
00412 gcol = static_cast<int>( (gInt[smax]-gInt[smin])*factor );
00413 bcol = static_cast<int>( (bInt[smax]-bInt[smin])*factor );
00414 acol = static_cast<int>(
00415 256.*( exp(-(aInt[smax]-aInt[smin])*factor/255.)));
00416 } else
00417 {
00418 const int index = smin*4;
00419 const double factor = 1./255.;
00420 rcol = static_cast<int>( Table[index+0]*Table[index+3]*factor );
00421 gcol = static_cast<int>( Table[index+1]*Table[index+3]*factor );
00422 bcol = static_cast<int>( Table[index+2]*Table[index+3]*factor );
00423 acol = static_cast<int>( 256.*( exp(-Table[index+3]/255.)) );
00424 }
00425 lookupImg[lookupindex++] = clip( rcol, 0, 255 );
00426 lookupImg[lookupindex++] = clip( gcol, 0, 255 );
00427 lookupImg[lookupindex++] = clip( bcol, 0, 255 );
00428 lookupImg[lookupindex++] = clip( acol, 0, 255 );
00429 }
00430 }
00431
00432 GLuint preintName = 0;
00433 glGenTextures( 1, &preintName );
00434 glBindTexture( GL_TEXTURE_2D, preintName );
00435 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0,
00436 GL_RGBA, GL_UNSIGNED_BYTE, &lookupImg[0] );
00437
00438 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
00439 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
00440 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
00441 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
00442
00443 return preintName;
00444 }
00445
00446
00447 }