OpenWalnut  1.2.5
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
WDataTexture3D.h
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #ifndef WDATATEXTURE3D_H
26 #define WDATATEXTURE3D_H
27 
28 #include <algorithm>
29 #include <limits>
30 #include <string>
31 
32 #include <boost/shared_ptr.hpp>
33 #include <boost/signals2.hpp>
34 
35 #include "../graphicsEngine/WGETexture.h"
36 #include "../graphicsEngine/WGETypeTraits.h"
37 #include "../common/WProperties.h"
38 
39 #include "WValueSetBase.h"
40 #include "WGridRegular3D.h"
41 
42 #include "WExportDataHandler.h"
43 
44 /**
45  * Namespace provides some scaling functions for scaling data values to meet the OpenGL requirements.
46  */
47 namespace WDataTexture3DScalers
48 {
49  /**
50  * 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
51  * problem.
52  *
53  * \param value the value to scale
54  * \param minimum the min value
55  * \param maximum the max value
56  * \param scaler the scaler
57  *
58  * \return the value scaled to [0,1]
59  *
60  * \note Most integral types need to be scaled. See WGETypeTraits.h for details.
61  */
62  template < typename T >
63  inline typename wge::GLType< T >::Type scaleInterval( T value, T minimum, T maximum, double scaler )
64  {
65  return static_cast< double >( std::min( std::max( value, minimum ), maximum ) - minimum ) / scaler;
66  }
67 
68  /**
69  * Byte data is transferred to texture mem as is without any scaling.
70  *
71  * \param value the value to scale
72  *
73  * \return the value
74  */
75  inline int8_t scaleInterval( int8_t value, int8_t /*minimum*/, int8_t /*maximum*/, double /*scaler*/ )
76  {
77  return value;
78  }
79 
80  /**
81  * Byte data is transferred to texture mem as is without any scaling.
82  *
83  * \param value the value to scale
84  *
85  * \return the value
86  */
87  inline uint8_t scaleInterval( uint8_t value, uint8_t /*minimum*/, uint8_t /*maximum*/, double /*scaler*/ )
88  {
89  return value;
90  }
91 }
92 
93 /**
94  * This class allows simple creation of WGETexture3D by using a specified grid and value-set. One advantage: the
95  * first call to the texture's update callback ensures texture creation. It is not created earlier.
96  */
98 {
99 public:
100 
101  /**
102  * Constructor. Creates the texture. Just run it after graphics engine was initialized.
103  *
104  * \param valueSet the value set to use
105  * \param grid the grid to use
106  */
107  WDataTexture3D( boost::shared_ptr< WValueSetBase > valueSet, boost::shared_ptr< WGridRegular3D > grid );
108 
109  /**
110  * Destructor.
111  */
112  virtual ~WDataTexture3D();
113 
114  /**
115  * Returns the texture's bounding box. This is const. Although there exists the transformation() property, it is an information property and
116  * can't be changed. This represents the underlying grid.
117  *
118  * \return the bounding box.
119  */
120  virtual WBoundingBox getBoundingBox() const;
121 
122 protected:
123 
124  /**
125  * Creates the texture data. This method creates the texture during the first update traversal using the value set and grid.
126  */
127  virtual void create();
128 
129 private:
130 
131  /**
132  * The value set from which the texture gets created.
133  */
134  boost::shared_ptr< WValueSetBase > m_valueSet;
135 
136  /**
137  * The bounding box of the underlying grid.
138  */
140 
141  /**
142  * The lock for securing createTexture.
143  */
144  boost::shared_mutex m_creationLock;
145 
146  /**
147  * Creates a properly sized osg::Image from the specified source data.
148  *
149  * \param source the source data
150  * \param components number of components
151  * \tparam T the type of source data
152  *
153  * \return
154  */
155  template < typename T >
156  osg::ref_ptr< osg::Image > createTexture( T* source, int components = 1 );
157 };
158 
159 /**
160  * Extend the wge utils namespace with additional methods relating WDataTexture3D.
161  */
162 namespace wge
163 {
164  /**
165  * Binds the specified texture to the specified unit. It automatically adds several uniforms which then can be utilized in the shader:
166  * - u_textureXUnit: the unit number (useful for accessing correct gl_TexCoord and so on)
167  * - u_textureXSampler: the needed sampler
168  * - u_textureXSizeX: width of the texture in pixels
169  * - u_textureXSizeY: height of the texture in pixels
170  * - u_textureXSizeZ: depth of the texture in pixels
171  * If the specified texture is a WGETexture, it additionally adds u_textureXMin and u_textureXScale for unscaling.
172  *
173  * \param node where to bind
174  * \param unit the unit to use
175  * \param texture the texture to use.
176  * \param prefix if specified, defines the uniform name prefix. (Sampler, Unit, Sizes, ...)
177  * \tparam T the type of texture. Usually osg::Texture3D or osg::Texture2D.
178  */
179  void OWDATAHANDLER_EXPORT bindTexture( osg::ref_ptr< osg::Node > node, osg::ref_ptr< WDataTexture3D > texture,
180  size_t unit = 0, std::string prefix = "" );
181 }
182 
183 template < typename T >
184 osg::ref_ptr< osg::Image > WDataTexture3D::createTexture( T* source, int components )
185 {
186  // get lock
187  boost::unique_lock< boost::shared_mutex > lock( m_creationLock );
188 
189  // get the current scaling info
190  T min = static_cast< T >( minimum()->get() );
191  double scaler = scale()->get();
192  T max = min + static_cast< T >( scaler );
193 
194  typedef typename wge::GLType< T >::Type TexType;
195  GLenum type = wge::GLType< T >::TypeEnum;
196 
197  wlog::debug( "WDataTexture3D" ) << "Resolution: " << getTextureWidth() << "x" << getTextureHeight() << "x" << getTextureDepth();
198  wlog::debug( "WDataTexture3D" ) << "Channels: " << components;
199  // NOTE: the casting is needed as if T == uint8_t -> it will be interpreted as ASCII code -> bad.
200  wlog::debug( "WDataTexture3D" ) << "Value Range: [" << static_cast< float >( min ) << "," << static_cast< float >( max ) <<
201  "] - Scaler: " << scaler;
202  osg::ref_ptr< osg::Image > ima = new osg::Image;
203 
204  size_t nbVoxels = getTextureWidth() * getTextureHeight() * getTextureDepth();
205 
206  if( components == 1)
207  {
208  // OpenGL just supports float textures
209  ima->allocateImage( getTextureWidth(), getTextureHeight(), getTextureDepth(), GL_LUMINANCE_ALPHA, type );
210  TexType* data = reinterpret_cast< TexType* >( ima->data() );
211 
212  // Copy the data pixel wise and convert to float
213  for( unsigned int i = 0; i < nbVoxels; ++i )
214  {
215  data[ 2 * i ] = WDataTexture3DScalers::scaleInterval( source[i], min, max, scaler );
216  // NOTE: this is done to avoid ugly black borders when interpolation is active.
217  data[ ( 2 * i ) + 1] = wge::GLType< T >::FullIntensity() * ( source[i] != min );
218  }
219  }
220  else if( components == 2)
221  {
222  // OpenGL just supports float textures
223  ima->allocateImage( getTextureWidth(), getTextureHeight(), getTextureDepth(), GL_RGBA, type );
224  ima->setInternalTextureFormat( GL_RGBA );
225  TexType* data = reinterpret_cast< TexType* >( ima->data() );
226 
227  // Copy the data pixel wise and convert to float
228  for( unsigned int i = 0; i < nbVoxels; ++i )
229  {
230  data[ ( 4 * i ) ] = WDataTexture3DScalers::scaleInterval( source[ ( 2 * i ) ], min, max, scaler );
231  data[ ( 4 * i ) + 1 ] = WDataTexture3DScalers::scaleInterval( source[ ( 2 * i ) + 1 ], min, max, scaler );
232  data[ ( 4 * i ) + 2 ] = 0;
233  data[ ( 4 * i ) + 3 ] = wge::GLType< T >::FullIntensity();
234  }
235  }
236  else if( components == 3)
237  {
238  // OpenGL just supports float textures
239  ima->allocateImage( getTextureWidth(), getTextureHeight(), getTextureDepth(), GL_RGBA, type );
240  ima->setInternalTextureFormat( GL_RGBA );
241  TexType* data = reinterpret_cast< TexType* >( ima->data() );
242 
243  // Copy the data pixel wise and convert to float
244  for( unsigned int i = 0; i < nbVoxels; ++i )
245  {
246  data[ ( 4 * i ) ] = WDataTexture3DScalers::scaleInterval( source[ ( 3 * i ) ], min, max, scaler );
247  data[ ( 4 * i ) + 1 ] = WDataTexture3DScalers::scaleInterval( source[ ( 3 * i ) + 1 ], min, max, scaler );
248  data[ ( 4 * i ) + 2 ] = WDataTexture3DScalers::scaleInterval( source[ ( 3 * i ) + 2 ], min, max, scaler );
249  data[ ( 4 * i ) + 3 ] = wge::GLType< T >::FullIntensity();
250  }
251  }
252  else if( components == 4)
253  {
254  // OpenGL just supports float textures
255  ima->allocateImage( getTextureWidth(), getTextureHeight(), getTextureDepth(), GL_RGBA, type );
256  ima->setInternalTextureFormat( GL_RGBA );
257  TexType* data = reinterpret_cast< TexType* >( ima->data() );
258 
259  // Copy the data pixel wise and convert to float
260  for( unsigned int i = 0; i < nbVoxels; ++i )
261  {
262  data[ ( 4 * i ) ] = WDataTexture3DScalers::scaleInterval( source[ ( 4 * i ) ], min, max, scaler );
263  data[ ( 4 * i ) + 1 ] = WDataTexture3DScalers::scaleInterval( source[ ( 4 * i ) + 1 ], min, max, scaler );
264  data[ ( 4 * i ) + 2 ] = WDataTexture3DScalers::scaleInterval( source[ ( 4 * i ) + 2 ], min, max, scaler );
265  data[ ( 4 * i ) + 3 ] = WDataTexture3DScalers::scaleInterval( source[ ( 4 * i ) + 3 ], min, max, scaler );
266  }
267  }
268  else
269  {
270  wlog::error( "WDataTexture3D" ) << "Did not handle dataset ( components != 1,2,3 or 4 ).";
271  }
272 
273  // done, unlock
274  lock.unlock();
275 
276  return ima;
277 }
278 
279 #endif // WDATATEXTURE3D_H
280