Equalizer  1.8.0
Parallel Rendering Framework
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
rawVolModel.cpp
1 
2 /* Copyright (c) 2007-2011, Maxim Makhinya <maxmah@gmail.com>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * - Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  * - Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12  * - Neither the name of Eyescale Software GmbH nor the names of its
13  * contributors may be used to endorse or promote products derived from this
14  * software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "rawVolModel.h"
30 #include "hlp.h"
31 
32 namespace eVolve
33 {
34 
35 
36 using hlpFuncs::clip;
37 using hlpFuncs::hFile;
38 
39 
40 static GLuint createPreintegrationTable( const uint8_t* Table );
41 
42 static bool readTransferFunction( FILE* file, std::vector<uint8_t>& TF );
43 
44 static bool readDimensionsAndScaling
45 (
46  FILE* file,
47  uint32_t& w, uint32_t& h, uint32_t& d,
48  VolumeScaling& volScaling
49 );
50 
51 
52 // Read volume dimensions, scaling and transfer function
53 RawVolumeModel::RawVolumeModel( const std::string& filename )
54  : _headerLoaded( false )
55  , _filename( filename )
56  , _preintName ( 0 )
57  , _w( 0 )
58  , _h( 0 )
59  , _d( 0 )
60  , _tW( 0 )
61  , _tH( 0 )
62  , _tD( 0 )
63  , _hasDerivatives( true )
64  , _glewContext( 0 )
65 {}
66 
67 bool RawVolumeModel::loadHeader( const float brightness, const float alpha )
68 {
69  LBASSERT( !_headerLoaded );
70  LBASSERT( brightness > 0.0f );
71  LBASSERT( alpha > 0.0f );
72  LBLOG( eq::LOG_CUSTOM ) << "-------------------------------------------"
73  << std::endl << "model: " << _filename;
74 
75  hFile header( fopen( ( _filename + std::string( ".vhf" ) ).c_str(), "rb" ));
76 
77  if( header.f==0 )
78  {
79  LBERROR << "Can't open header file" << std::endl;
80  return false;
81  }
82 
83  // test for raw+der or raw
84  const size_t fNameLen = _filename.length();
85  _hasDerivatives =
86  ( fNameLen >= 6 && _filename.substr( fNameLen-6, 6 ) == "_d.raw" ) ?
87  true : false;
88 
89  if( !readDimensionsAndScaling( header.f, _w, _h, _d, _volScaling ) )
90  return false;
91 
92  _resolution = LB_MAX( _w, LB_MAX( _h, _d ) );
93 
94  if( !readTransferFunction( header.f, _TF ))
95  return false;
96 
97  _headerLoaded = true;
98 
99  if( brightness != 1.0f )
100  {
101  for( size_t i = 0; i < _TF.size(); i+=4 )
102  {
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 );
106  }
107  }
108 
109  if( alpha != 1.0f )
110  for( size_t i = 3; i < _TF.size(); i+=4 )
111  _TF[i] = static_cast< uint8_t >( _TF[i] * alpha );
112 
113  return true;
114 }
115 
116 
117 static int32_t calcHashKey( const eq::Range& range )
118 {
119  return static_cast<int32_t>(( range.start*10000.f + range.end )*10000.f );
120 }
121 
122 
123 bool RawVolumeModel::getVolumeInfo( VolumeInfo& info, const eq::Range& range )
124 {
125  if( !_headerLoaded && !loadHeader( 1.0f, 1.0f ))
126  return false;
127 
128  if( _preintName == 0 )
129  {
130  LBLOG( eq::LOG_CUSTOM ) << "Creating preint" << std::endl;
131  _preintName = createPreintegrationTable( &_TF[0] );
132  }
133 
134  VolumePart* volumePart = 0;
135  const int32_t key = calcHashKey( range );
136 
137  if( _volumeHash.find( key ) == _volumeHash.end( ) )
138  {
139  // new key
140  volumePart = &_volumeHash[ key ];
141  if( !_createVolumeTexture( volumePart->volume, volumePart->TD, range ))
142  return false;
143  }
144  else
145  { // old key
146  volumePart = &_volumeHash[ key ];
147  }
148 
149  info.volume = volumePart->volume;
150  info.TD = volumePart->TD;
151  info.preint = _preintName;
152  info.volScaling = _volScaling;
153  if( _hasDerivatives )
154  {
155  info.voxelSize.W = 1.f;
156  info.voxelSize.H = 1.f;
157  info.voxelSize.D = 1.f;
158  }else
159  {
160  info.voxelSize.W = 1.f / _tW;
161  info.voxelSize.H = 1.f / _tH;
162  info.voxelSize.D = 1.f / _tD;
163  }
164  return true;
165 }
166 
167 
168 void RawVolumeModel::releaseVolumeInfo( const eq::Range& range )
169 {
170  const int32_t key = calcHashKey( range );
171  if( _volumeHash.find( key ) == _volumeHash.end() )
172  return;
173 
174  _volumeHash.erase( key );
175 }
176 
177 
180 static uint32_t calcMinPow2( uint32_t size )
181 {
182  if( size == 0 )
183  return 0;
184 
185  size--;
186  uint32_t res = 1;
187 
188  while( size > 0 )
189  {
190  res <<= 1;
191  size >>= 1;
192  }
193  return res;
194 }
195 
196 
199 bool RawVolumeModel::_createVolumeTexture( GLuint& volume,
201  const eq::Range& range )
202 {
203  const uint32_t w = _w;
204  const uint32_t h = _h;
205  const uint32_t d = _d;
206  const uint32_t bytes = _hasDerivatives ? 4 : 1;
207 
208  const int32_t bwStart = 2; //border width from left
209  const int32_t bwEnd = 2; //border width from right
210 
211  const int32_t s =
212  clip<int32_t>( static_cast< int32_t >( d*range.start ), 0, d-1 );
213 
214  const int32_t e =
215  clip<int32_t>( static_cast< int32_t >( d*range.end-1 ), 0, d-1 );
216 
217  const uint32_t start =
218  static_cast<uint32_t>( clip<int32_t>( s-bwStart, 0, d-1 ) );
219 
220  const uint32_t end =
221  static_cast<uint32_t>( clip<int32_t>( e+bwEnd , 0, d-1 ) );
222 
223  const uint32_t depth = end-start+1;
224 
225  _tW = calcMinPow2( w );
226  _tH = calcMinPow2( h );
227  _tD = calcMinPow2( depth );
228 
229  //texture scaling coefficients
230  TD.W = static_cast<float>( w ) / static_cast<float>( _tW );
231  TD.H = static_cast<float>( h ) / static_cast<float>( _tH );
232  TD.D = static_cast<float>( e-s+1 ) / static_cast<float>( _tD );
233  TD.D /= range.end>range.start ? (range.end-range.start) : 1.0f;
234 
235  // Shift coefficient and left border in texture for depth
236  TD.Do = range.start;
237  TD.Db = range.start > 0.0001 ? bwStart / static_cast<float>(_tD) : 0;
238 
239  LBLOG( eq::LOG_CUSTOM )
240  << "===============================================" << std::endl
241  << " w: " << w << " " << _tW
242  << " h: " << h << " " << _tH
243  << " d: " << d << " " << depth << " " << _tD << std::endl
244  << " r: " << _resolution << std::endl
245  << " ws: " << TD.W << " hs: " << TD.H << " wd: " << TD.D
246  << " Do: " << TD.Do << " Db: " << TD.Db << std::endl
247  << " s= " << start << " e= " << end << std::endl;
248 
249  // Reading of requested part of a volume
250  std::vector<uint8_t> data( _tW*_tH*_tD*bytes, 0 );
251  const uint32_t wh4 = w * h * bytes;
252  const uint32_t tWH4 = _tW * _tH * bytes;
253 
254  std::ifstream file ( _filename.c_str(), std::ifstream::in |
255  std::ifstream::binary | std::ifstream::ate );
256 
257  if( !file.is_open() )
258  {
259  LBERROR << "Can't open model data file";
260  return false;
261  }
262 
263  file.seekg( wh4*start, std::ios::beg );
264 
265  if( w==_tW && h==_tH ) // width and height are power of 2
266  {
267  file.read( (char*)( &data[0] ), wh4*depth );
268  }
269  else if( w==_tW ) // only width is power of 2
270  {
271  for( uint32_t i=0; i<depth; i++ )
272  file.read( (char*)( &data[i*tWH4] ), wh4 );
273  }
274  else
275  { // nor width nor heigh is power of 2
276  const uint32_t w4 = w * bytes;
277  const uint32_t tW4 = _tW * bytes;
278 
279  for( uint32_t i=0; i<depth; i++ )
280  for( uint32_t j=0; j<h; j++ )
281  file.read( (char*)( &data[ i*tWH4 + j*tW4] ), w4 );
282  }
283 
284  file.close();
285 
286  LBASSERT( _glewContext );
287  // create 3D texture
288  glGenTextures( 1, &volume );
289  LBLOG( eq::LOG_CUSTOM ) << "generated texture: " << volume << std::endl;
290  glBindTexture(GL_TEXTURE_3D, volume);
291 
292  glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE );
293  glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE );
294  glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_R , GL_CLAMP_TO_EDGE );
295  glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
296  glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
297 
298  if( _hasDerivatives )
299  {
300  glTexImage3D( GL_TEXTURE_3D,
301  0, GL_RGBA, _tW, _tH, _tD,
302  0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)(&data[0]) );
303  }else
304  {
305  glTexImage3D( GL_TEXTURE_3D,
306  0, GL_ALPHA, _tW, _tH, _tD,
307  0, GL_ALPHA, GL_UNSIGNED_BYTE, (GLvoid*)(&data[0]) );
308  }
309 
310  return true;
311 }
312 
313 
318 static void normalizeScaling
319 (
320  const uint32_t w,
321  const uint32_t h,
322  const uint32_t d,
323  VolumeScaling& scaling
324 )
325 {
326 //Correct proportions according to real size of volume
327  float maxS = float( LB_MAX( w, LB_MAX( h, d ) ));
328 
329  scaling.W *= w / maxS;
330  scaling.H *= h / maxS;
331  scaling.D *= d / maxS;
332 
333 //Make maximum proportion equal to 1.0
334  maxS = LB_MAX( scaling.W, LB_MAX( scaling.H, scaling.D ) );
335 
336  scaling.W /= maxS;
337  scaling.H /= maxS;
338  scaling.D /= maxS;
339 }
340 
341 
342 static bool readDimensionsAndScaling
343 (
344  FILE* file,
345  uint32_t& w, uint32_t& h, uint32_t& d,
346  VolumeScaling& volScaling
347 )
348 {
349  if( fscanf( file, "w=%u\n", &w ) == EOF )
350  return false;
351  if( fscanf( file, "h=%u\n", &h ) == EOF )
352  return false;
353  if( fscanf( file, "d=%u\n", &d ) != 1 )
354  {
355  LBERROR << "Can't read dimensions from header file" << std::endl;
356  return false;
357  }
358 
359  if( fscanf( file, "wScale=%g\n", &volScaling.W ) == EOF )
360  return false;
361  if( fscanf( file, "hScale=%g\n", &volScaling.H ) == EOF )
362  return false;
363  if( fscanf( file, "dScale=%g\n", &volScaling.D ) != 1 )
364  {
365  LBERROR << "Can't read scaling from header file: " << std::endl;
366  return false;
367  }
368 
369  if( w<1 || h<1 || d<1 ||
370  volScaling.W<0.001 ||
371  volScaling.H<0.001 ||
372  volScaling.W<0.001 )
373  {
374  LBERROR << "volume scaling is incorrect, check header file"<< std::endl;
375  return false;
376  }
377 
378  normalizeScaling( w, h, d, volScaling );
379 
380  LBLOG( eq::LOG_CUSTOM ) << " " << w << "x" << h << "x" << d << std::endl
381  << "( " << volScaling.W << " x "
382  << volScaling.H << " x "
383  << volScaling.D << " )" << std::endl;
384  return true;
385 }
386 
387 
388 static bool readTransferFunction( FILE* file, std::vector<uint8_t>& TF )
389 {
390  if( fscanf(file,"TF:\n") !=0 )
391  {
392  LBERROR << "Error in header file, can't find 'TF:' marker.";
393  return false;
394  }
395 
396  uint32_t TFSize;
397  if( fscanf( file, "size=%u\n", &TFSize ) == EOF )
398  return false;
399 
400  if( TFSize!=256 )
401  LBWARN << "Wrong size of transfer function, should be 256" << std::endl;
402 
403  TFSize = clip<int32_t>( TFSize, 1, 256 );
404  TF.resize( TFSize*4 );
405 
406  int tmp;
407  for( uint32_t i=0; i<TFSize; i++ )
408  {
409  if( fscanf( file, "r=%d\n", &tmp ) == EOF )
410  return false;
411  TF[4*i ] = tmp;
412  if( fscanf( file, "g=%d\n", &tmp ) == EOF )
413  return false;
414  TF[4*i+1] = tmp;
415  if( fscanf( file, "b=%d\n", &tmp ) == EOF )
416  return false;
417  TF[4*i+2] = tmp;
418  if( fscanf( file, "a=%d\n", &tmp ) != 1 )
419  {
420  LBERROR << "Failed to read entity #" << i
421  << " of TF from header file" << std::endl;
422  return i;
423  }
424  TF[4*i+3] = tmp;
425  }
426  return true;
427 }
428 
429 
430 static GLuint createPreintegrationTable( const uint8_t *Table )
431 {
432  LBLOG( eq::LOG_CUSTOM ) << "Calculating preintegration table" << std::endl;
433 
434  double rInt[256]; rInt[0] = 0.;
435  double gInt[256]; gInt[0] = 0.;
436  double bInt[256]; bInt[0] = 0.;
437  double aInt[256]; aInt[0] = 0.;
438 
439  // Creating SAT (Summed Area Tables) from averaged neighbouring RGBA values
440  for( int i=1; i<256; i++ )
441  {
442  // average Alpha from two neighbouring TF values
443  const double tauc = ( Table[(i-1)*4+3] + Table[i*4+3] ) / 2. / 255.;
444 
445  // SAT of average RGBs from two neighbouring TF values
446  // multiplied with Alpha
447  rInt[i] = rInt[i-1] + ( Table[(i-1)*4+0] + Table[i*4+0] )/2.*tauc;
448  gInt[i] = gInt[i-1] + ( Table[(i-1)*4+1] + Table[i*4+1] )/2.*tauc;
449  bInt[i] = bInt[i-1] + ( Table[(i-1)*4+2] + Table[i*4+2] )/2.*tauc;
450 
451  // SAT of average Alpha values
452  aInt[i] = aInt[i-1] + tauc;
453  }
454 
455  std::vector<GLubyte> lookupImg( 256*256*4, 255 ); // Preint Texture
456 
457  int lookupindex=0;
458 
459  for( int sb=0; sb<256; sb++ )
460  {
461  for( int sf=0; sf<256; sf++ )
462  {
463  int smin, smax;
464  if( sb<sf ) { smin=sb; smax=sf; }
465  else { smin=sf; smax=sb; }
466 
467  double rcol, gcol, bcol, acol;
468  if( smax != smin )
469  {
470  const double factor = 1. / (double)(smax-smin);
471  rcol = ( rInt[smax] - rInt[smin] ) * factor;
472  gcol = ( gInt[smax] - gInt[smin] ) * factor;
473  bcol = ( bInt[smax] - bInt[smin] ) * factor;
474  acol = exp( -( aInt[smax] - aInt[smin] ) * factor) * 255.;
475  } else
476  {
477  const int index = smin*4;
478  const double factor = 1./255.;
479  rcol = Table[index+0] * Table[index+3] * factor;
480  gcol = Table[index+1] * Table[index+3] * factor;
481  bcol = Table[index+2] * Table[index+3] * factor;
482  acol = exp( -Table[index+3] * factor ) * 256.;
483  }
484  lookupImg[lookupindex++] = clip( static_cast<int>(rcol), 0, 255 );
485  lookupImg[lookupindex++] = clip( static_cast<int>(gcol), 0, 255 );
486  lookupImg[lookupindex++] = clip( static_cast<int>(bcol), 0, 255 );
487  lookupImg[lookupindex++] = clip( static_cast<int>(acol), 0, 255 );
488  }
489  }
490 
491  GLuint preintName = 0;
492  glGenTextures( 1, &preintName );
493  glBindTexture( GL_TEXTURE_2D, preintName );
494  glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0,
495  GL_RGBA, GL_UNSIGNED_BYTE, &lookupImg[0] );
496 
497  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
498  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
499  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
500  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
501 
502  return preintName;
503 }
504 
505 
506 }
User-defined log topics (65536)
Definition: client/log.h:36
float D
Depth of data in texture (0..1].
Definition: rawVolModel.h:56
float Do
Depth offset (start of range)
Definition: rawVolModel.h:57
float D
depth scale
Definition: rawVolModel.h:70
float W
width scale
Definition: rawVolModel.h:66
Contain overall volume proportions relatively [-1,-1,-1]..[1,1,1] cube.
Definition: rawVolModel.h:63
float Db
Depth border (necessary for preintegration)
Definition: rawVolModel.h:58
Just helping structure to automatically close files.
Definition: hlp.h:41
float W
Width of data in texture (0..1].
Definition: rawVolModel.h:54
float H
height scale
Definition: rawVolModel.h:68
float H
Height of data in texture (0..1].
Definition: rawVolModel.h:55
Structure that contain actual dimensions of data that is stored in volume texture.
Definition: rawVolModel.h:52