29 #include "rawVolModel.h"
40 static GLuint createPreintegrationTable(
const uint8_t* Table );
42 static bool readTransferFunction( FILE* file, std::vector<uint8_t>& TF );
44 static bool readDimensionsAndScaling
47 uint32_t& w, uint32_t& h, uint32_t& d,
48 VolumeScaling& volScaling
53 RawVolumeModel::RawVolumeModel(
const std::string& filename )
54 : _headerLoaded( false )
55 , _filename( filename )
63 , _hasDerivatives( true )
67 bool RawVolumeModel::loadHeader(
const float brightness,
const float alpha )
69 LBASSERT( !_headerLoaded );
70 LBASSERT( brightness > 0.0f );
71 LBASSERT( alpha > 0.0f );
72 LBLOG(
eq::LOG_CUSTOM ) <<
"-------------------------------------------"
73 << std::endl <<
"model: " << _filename;
75 hFile header( fopen( ( _filename + std::string(
".vhf" ) ).c_str(),
"rb" ));
79 LBERROR <<
"Can't open header file" << std::endl;
84 const size_t fNameLen = _filename.length();
86 ( fNameLen >= 6 && _filename.substr( fNameLen-6, 6 ) ==
"_d.raw" ) ?
89 if( !readDimensionsAndScaling( header.f, _w, _h, _d, _volScaling ) )
92 _resolution = LB_MAX( _w, LB_MAX( _h, _d ) );
94 if( !readTransferFunction( header.f, _TF ))
99 if( brightness != 1.0f )
101 for(
size_t i = 0; i < _TF.size(); i+=4 )
103 _TF[i+0] =
static_cast< uint8_t
>( _TF[i+0] * brightness );
104 _TF[i+1] =
static_cast< uint8_t
>( _TF[i+1] * brightness );
105 _TF[i+2] =
static_cast< uint8_t
>( _TF[i+2] * brightness );
110 for(
size_t i = 3; i < _TF.size(); i+=4 )
111 _TF[i] = static_cast< uint8_t >( _TF[i] * alpha );
117 static int32_t calcHashKey(
const eq::Range& range )
119 return static_cast<int32_t
>(( range.start*10000.f + range.end )*10000.f );
123 bool RawVolumeModel::getVolumeInfo( VolumeInfo& info,
const eq::Range& range )
125 if( !_headerLoaded && !loadHeader( 1.0f, 1.0f ))
128 if( _preintName == 0 )
131 _preintName = createPreintegrationTable( &_TF[0] );
134 VolumePart* volumePart = 0;
135 const int32_t key = calcHashKey( range );
137 if( _volumeHash.find( key ) == _volumeHash.end( ) )
140 volumePart = &_volumeHash[ key ];
141 if( !_createVolumeTexture( volumePart->volume, volumePart->TD, range ))
146 volumePart = &_volumeHash[ key ];
149 info.volume = volumePart->volume;
150 info.TD = volumePart->TD;
151 info.preint = _preintName;
152 info.volScaling = _volScaling;
153 info.hasDerivatives = _hasDerivatives;
154 if( _hasDerivatives )
156 info.voxelSize.W = 1.f;
157 info.voxelSize.H = 1.f;
158 info.voxelSize.D = 1.f;
161 info.voxelSize.W = 1.f / _tW;
162 info.voxelSize.H = 1.f / _tH;
163 info.voxelSize.D = 1.f / _tD;
169 void RawVolumeModel::releaseVolumeInfo(
const eq::Range& range )
171 const int32_t key = calcHashKey( range );
172 if( _volumeHash.find( key ) == _volumeHash.end() )
175 _volumeHash.erase( key );
181 static uint32_t calcMinPow2( uint32_t size )
200 bool RawVolumeModel::_createVolumeTexture( GLuint& volume,
202 const eq::Range& range )
204 const uint32_t w = _w;
205 const uint32_t h = _h;
206 const uint32_t d = _d;
207 const uint32_t bytes = _hasDerivatives ? 4 : 1;
209 const int32_t bwStart = 2;
210 const int32_t bwEnd = 2;
213 clip<int32_t>(
static_cast< int32_t
>( d*range.start ), 0, d-1 );
216 clip<int32_t>(
static_cast< int32_t
>( d*range.end-1 ), 0, d-1 );
218 const uint32_t start =
219 static_cast<uint32_t
>( clip<int32_t>( s-bwStart, 0, d-1 ) );
222 static_cast<uint32_t
>( clip<int32_t>( e+bwEnd , 0, d-1 ) );
224 const uint32_t depth = end-start+1;
226 _tW = calcMinPow2( w );
227 _tH = calcMinPow2( h );
228 _tD = calcMinPow2( depth );
231 TD.
W =
static_cast<float>( w ) / static_cast<float>( _tW );
232 TD.
H =
static_cast<float>( h ) / static_cast<float>( _tH );
233 TD.
D =
static_cast<float>( e-s+1 ) / static_cast<float>( _tD );
234 TD.
D /= range.end>range.start ? (range.end-range.start) : 1.0f;
238 TD.
Db = range.start > 0.0001 ? bwStart /
static_cast<float>(_tD) : 0;
241 <<
"===============================================" << std::endl
242 <<
" w: " << w <<
" " << _tW
243 <<
" h: " << h <<
" " << _tH
244 <<
" d: " << d <<
" " << depth <<
" " << _tD << std::endl
245 <<
" r: " << _resolution << std::endl
246 <<
" ws: " << TD.
W <<
" hs: " << TD.
H <<
" wd: " << TD.
D
247 <<
" Do: " << TD.
Do <<
" Db: " << TD.
Db << std::endl
248 <<
" s= " << start <<
" e= " << end << std::endl;
251 std::vector<uint8_t> data( _tW*_tH*_tD*bytes, 0 );
252 const uint32_t wh4 = w * h * bytes;
253 const uint32_t tWH4 = _tW * _tH * bytes;
255 std::ifstream file ( _filename.c_str(), std::ifstream::in |
256 std::ifstream::binary | std::ifstream::ate );
258 if( !file.is_open() )
260 LBERROR <<
"Can't open model data file";
264 file.seekg( wh4*start, std::ios::beg );
266 if( w==_tW && h==_tH )
268 file.read( (
char*)( &data[0] ), wh4*depth );
272 for( uint32_t i=0; i<depth; i++ )
273 file.read( (
char*)( &data[i*tWH4] ), wh4 );
277 const uint32_t w4 = w * bytes;
278 const uint32_t tW4 = _tW * bytes;
280 for( uint32_t i=0; i<depth; i++ )
281 for( uint32_t j=0; j<h; j++ )
282 file.read( (
char*)( &data[ i*tWH4 + j*tW4] ), w4 );
287 LBASSERT( _glewContext );
289 glGenTextures( 1, &volume );
290 LBLOG(
eq::LOG_CUSTOM ) <<
"generated texture: " << volume << std::endl;
291 glBindTexture(GL_TEXTURE_3D, volume);
293 glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE );
294 glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE );
295 glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_R , GL_CLAMP_TO_EDGE );
296 glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
297 glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
299 if( _hasDerivatives )
301 glTexImage3D( GL_TEXTURE_3D,
302 0, GL_RGBA, _tW, _tH, _tD,
303 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)(&data[0]) );
306 glTexImage3D( GL_TEXTURE_3D,
307 0, GL_ALPHA, _tW, _tH, _tD,
308 0, GL_ALPHA, GL_UNSIGNED_BYTE, (GLvoid*)(&data[0]) );
319 static void normalizeScaling
328 float maxS = float( LB_MAX( w, LB_MAX( h, d ) ));
330 scaling.
W *= w / maxS;
331 scaling.
H *= h / maxS;
332 scaling.
D *= d / maxS;
335 maxS = LB_MAX( scaling.
W, LB_MAX( scaling.
H, scaling.
D ) );
343 static bool readDimensionsAndScaling
346 uint32_t& w, uint32_t& h, uint32_t& d,
347 VolumeScaling& volScaling
350 if( fscanf( file,
"w=%u\n", &w ) == EOF )
352 if( fscanf( file,
"h=%u\n", &h ) == EOF )
354 if( fscanf( file,
"d=%u\n", &d ) != 1 )
356 LBERROR <<
"Can't read dimensions from header file" << std::endl;
360 if( fscanf( file,
"wScale=%g\n", &volScaling.W ) == EOF )
362 if( fscanf( file,
"hScale=%g\n", &volScaling.H ) == EOF )
364 if( fscanf( file,
"dScale=%g\n", &volScaling.D ) != 1 )
366 LBERROR <<
"Can't read scaling from header file: " << std::endl;
370 if( w<1 || h<1 || d<1 ||
371 volScaling.W<0.001 ||
372 volScaling.H<0.001 ||
375 LBERROR <<
"volume scaling is incorrect, check header file"<< std::endl;
379 normalizeScaling( w, h, d, volScaling );
381 LBLOG(
eq::LOG_CUSTOM ) <<
" " << w <<
"x" << h <<
"x" << d << std::endl
382 <<
"( " << volScaling.W <<
" x "
383 << volScaling.H <<
" x "
384 << volScaling.D <<
" )" << std::endl;
389 static bool readTransferFunction( FILE* file, std::vector<uint8_t>& TF )
391 if( fscanf(file,
"TF:\n") !=0 )
393 LBERROR <<
"Error in header file, can't find 'TF:' marker.";
398 if( fscanf( file,
"size=%u\n", &TFSize ) == EOF )
402 LBWARN <<
"Wrong size of transfer function, should be 256" << std::endl;
404 TFSize = clip<int32_t>( TFSize, 1, 256 );
405 TF.resize( TFSize*4 );
408 for( uint32_t i=0; i<TFSize; i++ )
410 if( fscanf( file,
"r=%d\n", &tmp ) == EOF )
413 if( fscanf( file,
"g=%d\n", &tmp ) == EOF )
416 if( fscanf( file,
"b=%d\n", &tmp ) == EOF )
419 if( fscanf( file,
"a=%d\n", &tmp ) != 1 )
421 LBERROR <<
"Failed to read entity #" << i
422 <<
" of TF from header file" << std::endl;
431 static GLuint createPreintegrationTable(
const uint8_t *Table )
433 LBLOG(
eq::LOG_CUSTOM ) <<
"Calculating preintegration table" << std::endl;
435 double rInt[256]; rInt[0] = 0.;
436 double gInt[256]; gInt[0] = 0.;
437 double bInt[256]; bInt[0] = 0.;
438 double aInt[256]; aInt[0] = 0.;
441 for(
int i=1; i<256; i++ )
444 const double tauc = ( Table[(i-1)*4+3] + Table[i*4+3] ) / 2. / 255.;
448 rInt[i] = rInt[i-1] + ( Table[(i-1)*4+0] + Table[i*4+0] )/2.*tauc;
449 gInt[i] = gInt[i-1] + ( Table[(i-1)*4+1] + Table[i*4+1] )/2.*tauc;
450 bInt[i] = bInt[i-1] + ( Table[(i-1)*4+2] + Table[i*4+2] )/2.*tauc;
453 aInt[i] = aInt[i-1] + tauc;
456 std::vector<GLubyte> lookupImg( 256*256*4, 255 );
460 for(
int sb=0; sb<256; sb++ )
462 for(
int sf=0; sf<256; sf++ )
465 if( sb<sf ) { smin=sb; smax=sf; }
466 else { smin=sf; smax=sb; }
468 double rcol, gcol, bcol, acol;
471 const double factor = 1. / (double)(smax-smin);
472 rcol = ( rInt[smax] - rInt[smin] ) * factor;
473 gcol = ( gInt[smax] - gInt[smin] ) * factor;
474 bcol = ( bInt[smax] - bInt[smin] ) * factor;
475 acol = exp( -( aInt[smax] - aInt[smin] ) * factor) * 255.;
478 const int index = smin*4;
479 const double factor = 1./255.;
480 rcol = Table[index+0] * Table[index+3] * factor;
481 gcol = Table[index+1] * Table[index+3] * factor;
482 bcol = Table[index+2] * Table[index+3] * factor;
483 acol = exp( -Table[index+3] * factor ) * 256.;
485 lookupImg[lookupindex++] = clip( static_cast<int>(rcol), 0, 255 );
486 lookupImg[lookupindex++] = clip( static_cast<int>(gcol), 0, 255 );
487 lookupImg[lookupindex++] = clip( static_cast<int>(bcol), 0, 255 );
488 lookupImg[lookupindex++] = clip( static_cast<int>(acol), 0, 255 );
492 GLuint preintName = 0;
493 glGenTextures( 1, &preintName );
494 glBindTexture( GL_TEXTURE_2D, preintName );
495 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0,
496 GL_RGBA, GL_UNSIGNED_BYTE, &lookupImg[0] );
498 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
499 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
500 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
501 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
float Db
Depth border (necessary for preintegration)
float D
Depth of data in texture (0..1].
User-defined log topics (65536)
float W
Width of data in texture (0..1].
Structure that contain actual dimensions of data that is stored in volume texture.
Just helping structure to automatically close files.
Contain overal volume proportions relatively [-1,-1,-1]..[1,1,1] cube.
float H
Height of data in texture (0..1].
float Do
Depth offset (start of range)