Equalizer 1.0

rawVolModel.cpp

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 }
Generated on Sun May 8 2011 19:11:07 for Equalizer 1.0 by  doxygen 1.7.3