OpenWalnut  1.4.0
WDataTexture3D.h
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 #ifndef WDATATEXTURE3D_H
00026 #define WDATATEXTURE3D_H
00027 
00028 #include <algorithm>
00029 #include <limits>
00030 #include <string>
00031 
00032 #include <boost/shared_ptr.hpp>
00033 #include <boost/signals2.hpp>
00034 
00035 #include "../graphicsEngine/WGETexture.h"
00036 #include "../graphicsEngine/WGETypeTraits.h"
00037 #include "../common/WProperties.h"
00038 #include "../common/WLogger.h"
00039 
00040 #include "WValueSetBase.h"
00041 #include "WGridRegular3D.h"
00042 
00043 /**
00044  * Namespace provides some scaling functions for scaling data values to meet the OpenGL requirements.
00045  */
00046 namespace WDataTexture3DScalers
00047 {
00048     /**
00049      * Scales the specified value to the interval [0,1] using m_min and m_scale. As the method is inline, the additional parameters are no
00050      * problem.
00051      *
00052      * \param value the value to scale
00053      * \param minimum the min value
00054      * \param maximum the max value
00055      * \param scaler the scaler
00056      *
00057      * \return the value scaled to [0,1]
00058      *
00059      * \note Most integral types need to be scaled. See WGETypeTraits.h for details.
00060      */
00061     template < typename T >
00062     inline typename wge::GLType< T >::Type scaleInterval( T value, T minimum, T maximum, double scaler )
00063     {
00064         return static_cast< double >( std::min( std::max( value, minimum ), maximum ) - minimum ) / scaler;
00065     }
00066 
00067     /**
00068      * Byte data is transferred to texture mem as is without any scaling.
00069      *
00070      * \param value the value to scale
00071      *
00072      * \return the value
00073      */
00074     inline int8_t scaleInterval( int8_t value, int8_t /*minimum*/, int8_t /*maximum*/, double /*scaler*/ )
00075     {
00076         return value;
00077     }
00078 
00079     /**
00080      * Byte data is transferred to texture mem as is without any scaling.
00081      *
00082      * \param value the value to scale
00083      *
00084      * \return the value
00085      */
00086     inline uint8_t scaleInterval( uint8_t value, uint8_t /*minimum*/, uint8_t /*maximum*/, double /*scaler*/ )
00087     {
00088         return value;
00089     }
00090 }
00091 
00092 /**
00093  * This class allows simple creation of WGETexture3D by using a specified grid and value-set. One advantage: the
00094  * first call to the texture's update callback ensures texture creation. It is not created earlier.
00095  */
00096 class WDataTexture3D: public WGETexture3D
00097 {
00098 public:
00099     /**
00100      * Constructor. Creates the texture. Just run it after graphics engine was initialized.
00101      *
00102      * \param valueSet  the value set to use
00103      * \param grid the grid to use
00104      */
00105      WDataTexture3D( boost::shared_ptr< WValueSetBase > valueSet, boost::shared_ptr< WGridRegular3D > grid );
00106 
00107     /**
00108      * Destructor.
00109      */
00110     virtual ~WDataTexture3D();
00111 
00112     /**
00113      * Returns the texture's bounding box. This is const. Although there exists the transformation() property, it is an information property and
00114      * can't be changed. This represents the underlying grid.
00115      *
00116      * \return the bounding box.
00117      */
00118     virtual WBoundingBox getBoundingBox() const;
00119 
00120 protected:
00121     /**
00122      * Creates the texture data. This method creates the texture during the first update traversal using the value set and grid.
00123      */
00124     virtual void create();
00125 
00126 private:
00127     /**
00128      * The value set from which the texture gets created.
00129      */
00130     boost::shared_ptr< WValueSetBase > m_valueSet;
00131 
00132     /**
00133      * The bounding box of the underlying grid.
00134      */
00135     WBoundingBox m_boundingBox;
00136 
00137     /**
00138      * The lock for securing createTexture.
00139      */
00140     boost::shared_mutex m_creationLock;
00141 
00142     /**
00143      * Creates a properly sized osg::Image from the specified source data.
00144      *
00145      * \param source the source data
00146      * \param components number of components
00147      * \tparam T the type of source data
00148      *
00149      * \return
00150      */
00151     template < typename T >
00152     osg::ref_ptr< osg::Image > createTexture( T* source, int components = 1 );
00153 };
00154 
00155 /**
00156  * Extend the wge utils namespace with additional methods relating WDataTexture3D.
00157  */
00158 namespace wge
00159 {
00160     /**
00161      * Binds the specified texture to the specified unit. It automatically adds several uniforms which then can be utilized in the shader:
00162      * - u_textureXUnit: the unit number (useful for accessing correct gl_TexCoord and so on)
00163      * - u_textureXSampler: the needed sampler
00164      * - u_textureXSizeX: width of the texture in pixels
00165      * - u_textureXSizeY: height of the texture in pixels
00166      * - u_textureXSizeZ: depth of the texture in pixels
00167      * If the specified texture is a WGETexture, it additionally adds u_textureXMin and u_textureXScale for unscaling.
00168      *
00169      * \param node where to bind
00170      * \param unit the unit to use
00171      * \param texture the texture to use.
00172      * \param prefix if specified, defines the uniform name prefix. (Sampler, Unit, Sizes, ...)
00173      * \tparam T the type of texture. Usually osg::Texture3D or osg::Texture2D.
00174      */
00175     void bindTexture( osg::ref_ptr< osg::Node > node, osg::ref_ptr< WDataTexture3D > texture,
00176                                            size_t unit = 0, std::string prefix = ""  );
00177 }
00178 
00179 template < typename T >
00180 osg::ref_ptr< osg::Image > WDataTexture3D::createTexture( T* source, int components )
00181 {
00182     // get lock
00183     boost::unique_lock< boost::shared_mutex > lock( m_creationLock );
00184 
00185     // get the current scaling info
00186     T min = static_cast< T >( minimum()->get() );
00187     double scaler = scale()->get();
00188     T max = min + static_cast< T >( scaler );
00189 
00190     typedef typename wge::GLType< T >::Type TexType;
00191     GLenum type = wge::GLType< T >::TypeEnum;
00192 
00193     wlog::debug( "WDataTexture3D" ) << "Resolution: " << getTextureWidth() << "x" << getTextureHeight() << "x" << getTextureDepth();
00194     wlog::debug( "WDataTexture3D" ) << "Channels: " << components;
00195     // NOTE: the casting is needed as if T == uint8_t -> it will be interpreted as ASCII code -> bad.
00196     wlog::debug( "WDataTexture3D" ) << "Value Range: [" << static_cast< float >( min ) << "," << static_cast< float >( max ) <<
00197                                                        "] - Scaler: " << scaler;
00198     osg::ref_ptr< osg::Image > ima = new osg::Image;
00199 
00200     size_t nbVoxels = getTextureWidth() * getTextureHeight() * getTextureDepth();
00201 
00202     if( components == 1)
00203     {
00204         // OpenGL just supports float textures
00205         ima->allocateImage( getTextureWidth(), getTextureHeight(), getTextureDepth(), GL_LUMINANCE_ALPHA, type );
00206         TexType* data = reinterpret_cast< TexType* >( ima->data() );
00207 
00208         // Copy the data pixel wise and convert to float
00209         for( unsigned int i = 0; i < nbVoxels; ++i )
00210         {
00211             data[ 2 * i ] = WDataTexture3DScalers::scaleInterval( source[i], min, max, scaler );
00212             // NOTE: this is done to avoid ugly black borders when interpolation is active.
00213             data[ ( 2 * i ) + 1] = wge::GLType< T >::FullIntensity() * ( source[i] != min );
00214         }
00215     }
00216     else if( components == 2)
00217     {
00218         // OpenGL just supports float textures
00219         ima->allocateImage( getTextureWidth(), getTextureHeight(), getTextureDepth(), GL_RGBA, type );
00220         ima->setInternalTextureFormat( GL_RGBA );
00221         TexType* data = reinterpret_cast< TexType* >( ima->data() );
00222 
00223         // Copy the data pixel wise and convert to float
00224         for( unsigned int i = 0; i < nbVoxels; ++i )
00225         {
00226             data[ ( 4 * i ) ]     = WDataTexture3DScalers::scaleInterval( source[ ( 2 * i ) ], min, max, scaler );
00227             data[ ( 4 * i ) + 1 ] = WDataTexture3DScalers::scaleInterval( source[ ( 2 * i ) + 1 ], min, max, scaler );
00228             data[ ( 4 * i ) + 2 ] = 0;
00229             data[ ( 4 * i ) + 3 ] = wge::GLType< T >::FullIntensity();
00230         }
00231     }
00232     else if( components == 3)
00233     {
00234         // OpenGL just supports float textures
00235         ima->allocateImage( getTextureWidth(), getTextureHeight(), getTextureDepth(), GL_RGBA, type );
00236         ima->setInternalTextureFormat( GL_RGBA );
00237         TexType* data = reinterpret_cast< TexType* >( ima->data() );
00238 
00239         // Copy the data pixel wise and convert to float
00240         for( unsigned int i = 0; i < nbVoxels; ++i )
00241         {
00242             data[ ( 4 * i ) ]     = WDataTexture3DScalers::scaleInterval( source[ ( 3 * i ) ], min, max, scaler );
00243             data[ ( 4 * i ) + 1 ] = WDataTexture3DScalers::scaleInterval( source[ ( 3 * i ) + 1 ], min, max, scaler );
00244             data[ ( 4 * i ) + 2 ] = WDataTexture3DScalers::scaleInterval( source[ ( 3 * i ) + 2 ], min, max, scaler );
00245             data[ ( 4 * i ) + 3 ] = wge::GLType< T >::FullIntensity();
00246         }
00247     }
00248     else if( components == 4)
00249     {
00250         // OpenGL just supports float textures
00251         ima->allocateImage( getTextureWidth(), getTextureHeight(), getTextureDepth(), GL_RGBA, type );
00252         ima->setInternalTextureFormat( GL_RGBA );
00253         TexType* data = reinterpret_cast< TexType* >( ima->data() );
00254 
00255         // Copy the data pixel wise and convert to float
00256         for( unsigned int i = 0; i < nbVoxels; ++i )
00257         {
00258             data[ ( 4 * i ) ]     = WDataTexture3DScalers::scaleInterval( source[ ( 4 * i ) ], min, max, scaler );
00259             data[ ( 4 * i ) + 1 ] = WDataTexture3DScalers::scaleInterval( source[ ( 4 * i ) + 1 ], min, max, scaler );
00260             data[ ( 4 * i ) + 2 ] = WDataTexture3DScalers::scaleInterval( source[ ( 4 * i ) + 2 ], min, max, scaler );
00261             data[ ( 4 * i ) + 3 ] = WDataTexture3DScalers::scaleInterval( source[ ( 4 * i ) + 3 ], min, max, scaler );
00262         }
00263     }
00264     else
00265     {
00266         wlog::error( "WDataTexture3D" ) << "Did not handle dataset ( components != 1,2,3 or 4 ).";
00267     }
00268 
00269     // done, unlock
00270     lock.unlock();
00271 
00272     return ima;
00273 }
00274 
00275 #endif  // WDATATEXTURE3D_H
00276