rawVolModel.cpp

00001 
00002 /* Copyright (c) 2007       Maxim Makhinya
00003  *
00004  * This library is free software; you can redistribute it and/or modify it under
00005  * the terms of the GNU Lesser General Public License version 2.1 as published
00006  * by the Free Software Foundation.
00007  *  
00008  * This library is distributed in the hope that it will be useful, but WITHOUT
00009  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00010  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00011  * details.
00012  * 
00013  * You should have received a copy of the GNU Lesser General Public License
00014  * along with this library; if not, write to the Free Software Foundation, Inc.,
00015  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
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 // Read volume dimensions, scaling and transfer function
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         // new key
00116         volumePart = &_volumeHash[ key ];
00117         if( !_createVolumeTexture( volumePart->volume, volumePart->TD, range ))
00118             return false;
00119     }
00120     else
00121     {   // old key
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; //border width from left
00174     const int32_t bwEnd   = 2; //border width from right
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     //texture scaling coefficients
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     // Shift coefficient and left border in texture for depth
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     // Reading of requested part of a volume
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 ) // width and height are power of 2
00231     {
00232         file.read( (char*)( &data[0] ), wh4*depth );
00233     }
00234     else if( w==tW )     // only width is power of 2
00235     {
00236         for( uint32_t i=0; i<depth; i++ )
00237             file.read( (char*)( &data[i*tWH4] ), wh4 );
00238     }
00239     else
00240     {               // nor width nor heigh is power of 2
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     // create 3D texture
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 //Correct proportions according to real size of volume
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 //Make maximum proportion equal to 1.0
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 ); // Preint Texture
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 );//MIN( rcol, 255 );
00426             lookupImg[lookupindex++] = clip( gcol, 0, 255 );//MIN( gcol, 255 );
00427             lookupImg[lookupindex++] = clip( bcol, 0, 255 );//MIN( bcol, 255 );
00428             lookupImg[lookupindex++] = clip( acol, 0, 255 );//MIN( acol, 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 }
Generated on Mon Aug 10 18:58:41 2009 for Equalizer 0.9 by  doxygen 1.5.8