OpenWalnut  1.4.0
WGETextureUtils.cpp
00001 //---------------------------------------------------------------------------
00002 //
00003 // Project: OpenWalnut ( http://www.openwalnut.org )
00004 //
00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
00006 // For more information see http://www.openwalnut.org/copying
00007 //
00008 // This file is part of OpenWalnut.
00009 //
00010 // OpenWalnut is free software: you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as published by
00012 // the Free Software Foundation, either version 3 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // OpenWalnut is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public License
00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
00022 //
00023 //---------------------------------------------------------------------------
00024 
00025 #include <algorithm>
00026 #include <vector>
00027 
00028 #include <boost/random.hpp>
00029 
00030 #include "../common/exceptions/WPreconditionNotMet.h"
00031 
00032 #include "WGETexture.h"
00033 
00034 #include "WGETextureUtils.h"
00035 
00036 void wge::unbindTexture( osg::ref_ptr< osg::Node > node, size_t unit, size_t count )
00037 {
00038     for( size_t i = unit; i < unit + count; ++i )
00039     {
00040         node->getOrCreateStateSet()->removeTextureAttribute( i, osg::StateAttribute::TEXTURE );
00041         node->getOrCreateStateSet()->removeTextureAttribute( i, osg::StateAttribute::TEXMAT );
00042     }
00043 }
00044 
00045 size_t wge::getMaxTexUnits()
00046 {
00047     // GLint ret;
00048     // glGetIntegerv( GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &ret );
00049     // Why do we not use these glGet things here? The answer is simple: The GLSL 1.20 Standard does not define a way to access more than 8
00050     // texture coordinate attributes.
00051     return 8;
00052 }
00053 
00054 osg::ref_ptr< WGETexture< osg::Texture1D > > wge::genWhiteNoiseTexture( size_t sizeX, size_t channels )
00055 {
00056     // put it into an texture
00057     osg::ref_ptr< WGETexture1D > randTexture = new WGETexture1D( genWhiteNoiseImage( sizeX, 1, 1, channels ) );
00058     randTexture->setTextureWidth( sizeX );
00059     randTexture->setFilter( osg::Texture1D::MIN_FILTER, osg::Texture1D::NEAREST );
00060     randTexture->setFilter( osg::Texture1D::MAG_FILTER, osg::Texture1D::NEAREST );
00061     randTexture->setWrap( osg::Texture1D::WRAP_S, osg::Texture1D::REPEAT );
00062 
00063     return randTexture;
00064 }
00065 
00066 osg::ref_ptr< WGETexture< osg::Texture2D > > wge::genWhiteNoiseTexture( size_t sizeX, size_t sizeY, size_t channels )
00067 {
00068     osg::ref_ptr< WGETexture2D > randTexture = new WGETexture2D( genWhiteNoiseImage( sizeX, sizeY, 1, channels ) );
00069     randTexture->setTextureWidth( sizeX );
00070     randTexture->setTextureHeight( sizeY );
00071     randTexture->setFilter( osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST );
00072     randTexture->setFilter( osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST );
00073     randTexture->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT );
00074     randTexture->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT );
00075 
00076     return randTexture;
00077 }
00078 
00079 osg::ref_ptr< WGETexture< osg::Texture3D > > wge::genWhiteNoiseTexture( size_t sizeX, size_t sizeY, size_t sizeZ, size_t channels )
00080 {
00081     osg::ref_ptr< WGETexture3D > randTexture = new WGETexture3D( genWhiteNoiseImage( sizeX, sizeY, sizeZ, channels ) );
00082     randTexture->setTextureWidth( sizeX );
00083     randTexture->setTextureHeight( sizeY );
00084     randTexture->setTextureDepth( sizeZ );
00085     randTexture->setFilter( osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST );
00086     randTexture->setFilter( osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST );
00087     randTexture->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT );
00088     randTexture->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT );
00089     randTexture->setWrap( osg::Texture2D::WRAP_R, osg::Texture2D::REPEAT );
00090 
00091     return randTexture;
00092 }
00093 
00094 osg::ref_ptr< osg::Image > wge::genWhiteNoiseImage( size_t sizeX, size_t sizeY, size_t sizeZ, size_t channels )
00095 {
00096     WPrecond( ( channels == 1 ) || ( channels == 3 ) || ( channels == 4 ), "Invalid number of channels. Valid are: 1, 3 and 4."  );
00097 
00098     // create an osg::Image at first.
00099     std::srand( time( 0 ) );
00100     osg::ref_ptr< osg::Image > randImage = new osg::Image();
00101     GLenum type = GL_LUMINANCE;
00102     if( channels == 3 )
00103     {
00104         type = GL_RGB;
00105     }
00106     else if( channels == 4 )
00107     {
00108         type = GL_RGBA;
00109     }
00110     randImage->allocateImage( sizeX, sizeY, sizeZ, type, GL_UNSIGNED_BYTE );
00111     unsigned char *randomLuminance = randImage->data();  // should be 4 megs
00112     for( size_t i = 0; i < channels * sizeX * sizeY * sizeZ; ++i )
00113     {
00114         // - stylechecker says "use rand_r" but I am not sure about portability.
00115         unsigned char r = static_cast< unsigned char >( std::rand() % 255 );  // NOLINT - no we want std::rand instead of rand_r
00116         randomLuminance[ i ] = r;
00117     }
00118 
00119     return randImage;
00120 }
00121 
00122 osg::ref_ptr< WGETexture< osg::Texture3D > > wge::genTuringNoiseTexture( std::size_t sizeX, std::size_t sizeY,
00123                                                                          std::size_t sizeZ, std::size_t channels )
00124 {
00125     WPrecond( channels == 1 || channels == 3 || channels == 4, "Invalid number of channels. Valid are: 1, 3 and 4." );
00126 
00127     // some constants, maybe change to parameters
00128     float const spotIrregularity = 0.05f;   // 0.0 - 1.0
00129     std::size_t const iterations = 200;
00130     float const spotSize = 0.5;
00131     float const spotFactor = ( 0.02f + 0.58f * ( 1.0f - spotSize ) ) / 15.0f;
00132     float const d1 = 0.125f;
00133     float const d2 = 0.03125f;
00134     float const speed = 1.0f;
00135 
00136     osg::ref_ptr< osg::Image > img = new osg::Image;
00137     GLenum type = GL_LUMINANCE;
00138     if( channels == 3 )
00139     {
00140         type = GL_RGB;
00141     }
00142     else if( channels == 4 )
00143     {
00144         type = GL_RGBA;
00145     }
00146 
00147     std::vector< float > concentration1( sizeX * sizeY * sizeZ, 4.0 );
00148     std::vector< float > concentration2( sizeX * sizeY * sizeZ, 4.0 );
00149     std::vector< float > delta1( sizeX * sizeY * sizeZ, 0.0 );
00150     std::vector< float > delta2( sizeX * sizeY * sizeZ, 0.0 );
00151     std::vector< float > noise( sizeX * sizeY * sizeZ );
00152 
00153     boost::mt19937 generator( std::time( 0 ) );
00154 
00155     float noiseRange = 0.1f + 4.9f * spotIrregularity;
00156 
00157     boost::uniform_real< float > dist( 12.0 - noiseRange, 12.0 + noiseRange );
00158     boost::variate_generator< boost::mt19937&, boost::uniform_real< float > > rand( generator, dist );
00159 
00160     // initialization step
00161     for( std::size_t i = 0; i < sizeX; ++i )
00162     {
00163         for( std::size_t j = 0; j < sizeY; ++j )
00164         {
00165             for( std::size_t k = 0; k < sizeZ; ++k )
00166             {
00167                 std::size_t idx = i + j * sizeX + k * sizeX * sizeY;
00168                 noise[ idx ] = rand();
00169             }
00170         }
00171     }
00172 
00173     // iteration
00174     for( std::size_t iter = 0; iter < iterations; ++iter )
00175     {
00176         std::cout << "iterations: " << iter << std::endl;
00177 
00178         for( std::size_t i = 0; i < sizeX; ++i )
00179         {
00180             std::size_t iNext = ( i + 1 ) % sizeX;
00181             std::size_t iPrev = ( i + sizeX - 1 ) % sizeX;
00182 
00183             for( std::size_t j = 0; j < sizeY; ++j )
00184             {
00185                 std::size_t jNext = ( j + 1 ) % sizeY;
00186                 std::size_t jPrev = ( j + sizeY - 1 ) % sizeY;
00187 
00188                 for( std::size_t k = 0; k < sizeZ; ++k )
00189                 {
00190                     std::size_t kNext = ( k + 1 ) % sizeZ;
00191                     std::size_t kPrev = ( k + sizeZ - 1 ) % sizeZ;
00192 
00193                     std::size_t idx = i + j * sizeX + k * sizeX * sizeY;
00194 
00195                     // estimate change in concentrations
00196                     // we use a 3d laplace filter here instead of the 2d filter as in Eichelbaum et al.
00197                     float dc1 = 0.0;
00198                     dc1 += concentration1[ iPrev + j * sizeX + k * sizeX * sizeY ];
00199                     dc1 += concentration1[ iNext + j * sizeX + k * sizeX * sizeY ];
00200                     dc1 += concentration1[ i + jPrev * sizeX + k * sizeX * sizeY ];
00201                     dc1 += concentration1[ i + jNext * sizeX + k * sizeX * sizeY ];
00202                     dc1 += concentration1[ i + j * sizeX + kPrev * sizeX * sizeY ];
00203                     dc1 += concentration1[ i + j * sizeX + kNext * sizeX * sizeY ];
00204                     dc1 -= 6.0f * concentration1[ idx ];
00205 
00206                     float dc2 = 0.0;
00207                     dc2 += concentration2[ iPrev + j * sizeX + k * sizeX * sizeY ];
00208                     dc2 += concentration2[ iNext + j * sizeX + k * sizeX * sizeY ];
00209                     dc2 += concentration2[ i + jPrev * sizeX + k * sizeX * sizeY ];
00210                     dc2 += concentration2[ i + jNext * sizeX + k * sizeX * sizeY ];
00211                     dc2 += concentration2[ i + j * sizeX + kPrev * sizeX * sizeY ];
00212                     dc2 += concentration2[ i + j * sizeX + kNext * sizeX * sizeY ];
00213                     dc2 -= 6.0f * concentration2[ idx ];
00214 
00215                     // diffusion
00216                     delta1[ idx ] = spotFactor * ( 16.0f - concentration1[ idx ] * concentration2[ idx ] ) + d1 * dc1;
00217                     delta2[ idx ] = spotFactor * ( concentration1[ idx ] * concentration2[ idx ] - concentration2[ idx ] - noise[ idx ] ) + d2 * dc2;
00218                 }
00219             }
00220         }
00221 
00222         for( std::size_t i = 0; i < sizeX; ++i )
00223         {
00224             for( std::size_t j = 0; j < sizeY; ++j )
00225             {
00226                 for( std::size_t k = 0; k < sizeZ; ++k )
00227                 {
00228                     std::size_t idx = i + j * sizeX + k * sizeX * sizeY;
00229 
00230                     concentration1[ idx ] += speed * delta1[ idx ];
00231                     concentration2[ idx ] += speed * delta2[ idx ];
00232                 }
00233             }
00234         }
00235     }
00236 
00237     img->allocateImage( sizeX, sizeY, sizeZ, type, GL_UNSIGNED_BYTE );
00238 
00239     // find min and max
00240     float c1min = *std::min_element( concentration1.begin(), concentration1.end() );
00241     float c1max = *std::max_element( concentration1.begin(), concentration1.end() );
00242 
00243     // copy to image
00244     for( std::size_t i = 0; i < sizeX; ++i )
00245     {
00246         for( std::size_t j = 0; j < sizeY; ++j )
00247         {
00248             for( std::size_t k = 0; k < sizeZ; ++k )
00249             {
00250                 std::size_t idx = i + j * sizeX + k * sizeX * sizeY;
00251                 img->data()[ idx ] = 255.0f * ( concentration1[ idx ] - c1min ) / ( c1max - c1min );
00252             }
00253         }
00254     }
00255 
00256     return osg::ref_ptr< WGETexture< osg::Texture3D > >( new WGETexture< osg::Texture3D >( img ) );
00257 }
00258