Loading [MathJax]/extensions/TeX/AMSmath.js
Radium Engine  1.7.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Texture.cpp
1
2#include <Core/Tasks/Task.hpp>
3#include <Core/Tasks/TaskQueue.hpp>
4#include <Core/Utils/Index.hpp>
5#include <Core/Utils/Log.hpp>
6#include <Engine/Data/Texture.hpp>
7#include <Engine/OpenGL.hpp>
8#include <Engine/RadiumEngine.hpp>
9#include <algorithm>
10#include <cmath>
11#include <glbinding-aux/types_to_string.h>
12#include <glbinding/gl/enum.h>
13#include <globjects/Texture.h>
14#include <globjects/base/Instantiator.inl>
15#include <iterator>
16#include <ostream>
17#include <utility>
18
19namespace Ra {
20namespace Engine {
21namespace Data {
22using namespace Core::Utils; // log
23
24Texture::Texture( const TextureParameters& texParameters ) :
25 m_textureParameters { texParameters }, m_texture { nullptr }, m_isMipMapped { false } {}
26
27class DeleteTextureTask : public Core::Task
28{
29 public:
30 explicit DeleteTextureTask( std::unique_ptr<globjects::Texture> texture ) :
31 m_texture( std::move( texture ) ) {}
32
34 std::string getName() const override { return "DeleteTextureTask"; };
35
37 virtual void process() override {
38 m_texture->detach();
39 m_texture.reset();
40 };
41
42 private:
44};
45
47 if ( m_updateImageTaskId.isValid() ) {
48 RadiumEngine::getInstance()->removeGpuTask( m_updateImageTaskId );
49 }
50
51 if ( m_updateSamplerTaskId.isValid() ) {
52 RadiumEngine::getInstance()->removeGpuTask( m_updateSamplerTaskId );
53 }
54
55 // register delayed destroy gpu texture task
56 destroy();
57}
58
60 if ( !isSupportedTarget() ) return;
61 // Transform texels if needed
62
63 computeIsMipMappedFlag();
64
65 // Update the sampler parameters
67
68 // upload texture to the GPU
70}
71
73 if ( !isSupportedTarget() ) return;
74 computeIsMipMappedFlag();
75
76 createTexture();
79}
80
82 if ( m_texture ) {
83 // if engine is still available
84 if ( auto engine = RadiumEngine::getInstance() ) {
85 auto task = std::make_unique<DeleteTextureTask>( std::move( m_texture ) );
86 engine->addGpuTask( std::move( task ) );
87 }
88 // else gpu representation will not be cleaned by the application.
89 m_texture.reset();
90 }
91}
92
94 m_texture->detach();
95 m_texture.reset();
96}
97
99 // register gpu task to update opengl representation before next rendering
100 std::lock_guard<std::mutex> lock( m_updateMutex );
101 m_textureParameters.image.texels = newData;
103}
104
105void Texture::resize( size_t w, size_t h, size_t d, std::shared_ptr<void> pix ) {
106 m_textureParameters.image.width = w;
107 m_textureParameters.image.height = h;
108 m_textureParameters.image.depth = d;
109 m_textureParameters.image.texels = pix;
110 if ( createTexture() ) {
111 computeIsMipMappedFlag();
114 }
115 else { sendImageDataToGpu(); }
116}
117
118void Texture::setParameters( const TextureParameters& textureParameters ) {
119 setSamplerParameters( textureParameters.sampler );
120 setImageParameters( textureParameters.image );
121}
122
123void Texture::setImageParameters( const ImageParameters& imageParameters ) {
124 std::lock_guard<std::mutex> lock( m_updateMutex );
125 m_textureParameters.image = imageParameters;
127}
128
129void Texture::setSamplerParameters( const SamplerParameters& samplerParameters ) {
130 std::lock_guard<std::mutex> lock( m_updateMutex );
131 m_textureParameters.sampler = samplerParameters;
133}
134
135void Texture::bind( int unit ) {
136 if ( unit >= 0 ) { m_texture->bindActive( uint( unit ) ); }
137 else { m_texture->bind(); }
138}
139
141 GLint level,
142 GLboolean layered,
143 GLint layer,
144 GLenum access ) {
145 m_texture->bindImageTexture(
146 uint( unit ), level, layered, layer, access, m_textureParameters.image.internalFormat );
147}
148
150 if ( !image.isLinear ) {
151 // Only RGB and RGBA texture contains color information
152 // (others are not really colors and must be managed explicitly by the user)
153 uint numComp = 0;
154 bool hasAlpha = false;
155 switch ( image.format ) {
156 // RED texture store a gray scale color. Verify if we need to convert
157 case GL_RED:
158 numComp = 1;
159 break;
160 case GL_RGB:
161 numComp = 3;
162 break;
163 case GL_RGBA:
164 numComp = 4;
165 hasAlpha = true;
166 break;
167 default:
168 LOG( logERROR ) << "Textures with format " << image.format << " can't be linearized.\n";
169 return;
170 }
171 if ( image.type == GL_TEXTURE_CUBE_MAP ) { linearizeCubeMap( image, numComp, hasAlpha ); }
172 else {
173 srgbToLinearRgb( reinterpret_cast<uint8_t*>( std::get<0>( image.texels ).get() ),
174 image.width,
175 image.height,
176 image.depth,
177 numComp,
178 hasAlpha );
179 }
180 image.isLinear = true;
181 }
182}
183
184bool Texture::isSupportedTarget() {
185 if ( ( m_textureParameters.image.target != GL_TEXTURE_1D ) &&
186 ( m_textureParameters.image.target != GL_TEXTURE_2D ) &&
187 ( m_textureParameters.image.target != GL_TEXTURE_RECTANGLE ) &&
188 ( m_textureParameters.image.target != GL_TEXTURE_3D ) &&
189 ( m_textureParameters.image.target != GL_TEXTURE_CUBE_MAP ) ) {
190 LOG( logERROR ) << "Texture of type " << m_textureParameters.image.target
191 << " must be generated explicitly!";
192 return false;
193 }
194 return true;
195}
196
197void Texture::computeIsMipMappedFlag() {
198 m_isMipMapped = !( m_textureParameters.sampler.minFilter == GL_NEAREST ||
199 m_textureParameters.sampler.minFilter == GL_LINEAR );
200}
201
202bool Texture::createTexture() {
203 if ( m_texture == nullptr ) {
204 m_texture = globjects::Texture::create( m_textureParameters.image.target );
205 GL_CHECK_ERROR;
206 return true;
207 }
208 return false;
209}
210
212 // register gpu task to update opengl representation before next rendering
213 if ( m_updateImageTaskId.isInvalid() ) {
214 auto taskFunc = [this]() {
215 std::lock_guard<std::mutex> taskLock( m_updateMutex );
216 // Generate OpenGL texture
217 this->createTexture();
218 this->sendImageDataToGpu();
219 m_updateImageTaskId = Core::TaskQueue::TaskId::Invalid();
220 };
221 auto task = std::make_unique<Core::FunctionTask>( taskFunc, getName() );
222 m_updateImageTaskId = RadiumEngine::getInstance()->addGpuTask( std::move( task ) );
223 }
224}
225
227 if ( m_updateSamplerTaskId.isInvalid() ) {
228 auto taskFunc = [this]() {
229 std::lock_guard<std::mutex> taskLock( m_updateMutex );
230 // Generate OpenGL texture
231 this->createTexture();
233 m_updateSamplerTaskId = Core::TaskQueue::TaskId::Invalid();
234 };
235 auto task = std::make_unique<Core::FunctionTask>( taskFunc, getName() );
236 m_updateSamplerTaskId = RadiumEngine::getInstance()->addGpuTask( std::move( task ) );
237 }
238}
239
241 CORE_ASSERT( m_texture != nullptr, "Cannot update non initialized texture" );
242 switch ( m_texture->target() ) {
243 case GL_TEXTURE_1D: {
244 m_texture->image1D( 0,
245 m_textureParameters.image.internalFormat,
246 GLsizei( m_textureParameters.image.width ),
247 0,
248 m_textureParameters.image.format,
249 m_textureParameters.image.type,
250 getTexels() );
251 GL_CHECK_ERROR
252 } break;
253 case GL_TEXTURE_2D:
254 case GL_TEXTURE_RECTANGLE: {
255 m_texture->image2D( 0,
256 m_textureParameters.image.internalFormat,
257 GLsizei( m_textureParameters.image.width ),
258 GLsizei( m_textureParameters.image.height ),
259 0,
260 m_textureParameters.image.format,
261 m_textureParameters.image.type,
262 getTexels() );
263 GL_CHECK_ERROR
264 } break;
265 case GL_TEXTURE_3D: {
266 m_texture->image3D( 0,
267 m_textureParameters.image.internalFormat,
268 GLsizei( m_textureParameters.image.width ),
269 GLsizei( m_textureParameters.image.height ),
270 GLsizei( m_textureParameters.image.depth ),
271 0,
272 m_textureParameters.image.format,
273 m_textureParameters.image.type,
274 getTexels() );
275 GL_CHECK_ERROR
276 } break;
277 case GL_TEXTURE_CUBE_MAP: {
278 // Load the 6 faces of the cube-map
279 auto cubeMap = m_textureParameters.image.getCubeMap();
280
282 std::transform( std::begin( cubeMap ),
283 std::end( cubeMap ),
284 std::begin( data ),
285 []( const std::shared_ptr<void>& val ) { return val.get(); } );
286
287 m_texture->cubeMapImage( 0,
288 m_textureParameters.image.internalFormat,
289 GLsizei( m_textureParameters.image.width ),
290 GLsizei( m_textureParameters.image.height ),
291 0,
292 m_textureParameters.image.format,
293 m_textureParameters.image.type,
294 data );
295
296 GL_CHECK_ERROR
297 } break;
298 default: {
299 CORE_ASSERT( 0, "Unsupported texture type ?" );
300 } break;
301 }
302 // Generate mip-map if needed.
303 if ( m_isMipMapped ) { m_texture->generateMipmap(); }
304
305 GL_CHECK_ERROR;
306}
307
308void Texture::readFromGpu( int level ) {
309 CORE_ASSERT( m_texture != nullptr, "Cannot get non initialized texture" );
310 CORE_ASSERT( m_textureParameters.image.isTexelOfType<ImageParameters::ImageType>(),
311 "Can only get image typf" );
312 CORE_ASSERT( m_textureParameters.image.getTexels() != nullptr, "Can only get image type" );
313 CORE_ASSERT( GL_TEXTURE_CUBE_MAP != m_texture->target(), "Cannot get cube map" );
314
315 m_texture->getImage( level,
316 m_textureParameters.image.format,
317 m_textureParameters.image.type,
318 m_textureParameters.image.getImage().get() );
319}
320
321// let the compiler warn about case fallthrough
323 switch ( m_texture->target() ) {
324 case GL_TEXTURE_CUBE_MAP:
325 case GL_TEXTURE_3D:
326 m_texture->setParameter( GL_TEXTURE_WRAP_R, m_textureParameters.sampler.wrapR );
327 GL_CHECK_ERROR;
328 [[fallthrough]];
329 case GL_TEXTURE_2D:
330 case GL_TEXTURE_RECTANGLE:
331 m_texture->setParameter( GL_TEXTURE_WRAP_T, m_textureParameters.sampler.wrapT );
332 GL_CHECK_ERROR;
333 [[fallthrough]];
334 case GL_TEXTURE_1D:
335 m_texture->setParameter( GL_TEXTURE_WRAP_S, m_textureParameters.sampler.wrapS );
336 GL_CHECK_ERROR;
337 break;
338 default:
339 break;
340 }
341 m_texture->setParameter( GL_TEXTURE_MIN_FILTER, m_textureParameters.sampler.minFilter );
342 GL_CHECK_ERROR;
343 m_texture->setParameter( GL_TEXTURE_MAG_FILTER, m_textureParameters.sampler.magFilter );
344 GL_CHECK_ERROR;
345}
346
348void Texture::srgbToLinearRgb( uint8_t* texels,
349 uint width,
350 uint height,
351 uint depth,
352 uint numComponent,
353 bool hasAlphaChannel ) {
354 // auto linearize = [gamma](float in)-> float {
355 auto linearize = []( uint8_t in ) -> uint8_t {
356 // Constants are described at https://en.wikipedia.org/wiki/SRGB
357 float c = float( in ) / 255;
358 if ( c < 0.04045 ) { c = c / 12.92f; }
359 else { c = std::pow( ( ( c + 0.055f ) / ( 1.055f ) ), 2.4f ); }
360 return uint8_t( c * 255 );
361 };
362 uint numValues = hasAlphaChannel ? numComponent - 1 : numComponent;
363#pragma omp parallel for
364 for ( int i = 0; i < int( width * height * depth ); ++i ) {
365 // Convert each R or RGB value while keeping alpha unchanged
366 for ( uint p = i * numComponent; p < i * numComponent + numValues; ++p ) {
367 texels[p] = linearize( texels[p] );
368 }
369 }
370}
371
372void Texture::linearizeCubeMap( ImageParameters& image, uint numComponent, bool hasAlphaChannel ) {
373 if ( image.type == gl::GLenum::GL_UNSIGNED_BYTE ) {
376 const auto cubeMap = image.getCubeMap();
377 for ( int i = 0; i < 6; ++i ) {
378 srgbToLinearRgb( reinterpret_cast<uint8_t*>( cubeMap[i].get() ),
379 image.width,
380 image.height,
381 image.depth,
382 numComponent,
383 hasAlphaChannel );
384 }
385 }
386}
387
388} // namespace Data
389} // namespace Engine
390} // namespace Ra
T begin(T... args)
void bind(int unit=-1)
Bind the texture to GPU texture unit to enable its use in a shader. Need active OpenGL context.
Definition Texture.cpp:135
void registerUpdateImageDataTask()
Regiter gpu task to RadiumEngine. Will call sendImageDataToGpu during next RadiumEngine::runGpuTasks(...
Definition Texture.cpp:211
void setSamplerParameters(const SamplerParameters &samplerParameters)
set TerctureParameters.samples
Definition Texture.cpp:129
void initialize()
Generate the OpenGL representation of the texture according to the stored TextureData (delayed).
Definition Texture.cpp:59
void destroyNow()
Generate the GPU representation of the texture right now. Need an active OpenGL context.
Definition Texture.cpp:93
void destroy()
destroy the GPU texture representation.
Definition Texture.cpp:81
void setImageParameters(const ImageParameters &imageParameters)
set TextureParameters.image
Definition Texture.cpp:123
void updateData(std::shared_ptr< void > newData)
Update the cpu representation of data contained by the texture.
Definition Texture.cpp:98
~Texture()
Texture destructor. Both internal data and GPU representation are deleted.
Definition Texture.cpp:46
void sendImageDataToGpu()
Send image data to the GPU and generate mipmap if needed.
Definition Texture.cpp:240
void resize(size_t w=1, size_t h=1, size_t d=1, std::shared_ptr< void > pix=nullptr)
Resize the texture. Need active OpenGL context.
Definition Texture.cpp:105
void setParameters(const TextureParameters &textureParameters)
set TextureParameters.
Definition Texture.cpp:118
std::string getName() const
Definition Texture.hpp:171
void initializeNow()
Generate the GPU representation of the texture right now. Need an active OpenGL context.
Definition Texture.cpp:72
static void linearize(ImageParameters &image)
Convert a color texture from sRGB to Linear RGB spaces.
Definition Texture.cpp:149
const void * getTexels()
Definition Texture.hpp:188
void bindImageTexture(int unit, GLint level, GLboolean layered, GLint layer, GLenum access)
Bind the texture to an image unit for the purpose of reading and writing it from shaders....
Definition Texture.cpp:140
void registerUpdateSamplerParametersTask()
Regiter gpu task to RadiumEngine. Will call sendSamplerParametersToGpu during next RadiumEngine::runG...
Definition Texture.cpp:226
Texture(const Texture &)=delete
Textures are not copyable, delete copy constructor.
void sendSamplerParametersToGpu()
Send sampler parameters to the GPU.
Definition Texture.cpp:322
T end(T... args)
T get(T... args)
T move(T... args)
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:4
STL namespace.
T pow(T... args)
T reset(T... args)
bool isLinear
set to true when linearize texture rgb component. If true, linearize has no effect.
Definition Texture.hpp:80
const CubeMapType getCubeMap() const
Definition Texture.hpp:65
GLenum internalFormat
OpenGL internal format (WARNING, for Integer textures, must be GL_XXX_INTEGER)
Definition Texture.hpp:77
const void * getTexels() const
Definition Texture.hpp:60
bool isTexelOfType() const
check which type is held by texels
Definition Texture.hpp:47
GPU Sampler configuration.
Definition Texture.hpp:22
GLenum wrapT
OpenGL wrap mode in the t direction.
Definition Texture.hpp:26
GLenum minFilter
OpenGL minification filter ( GL_LINEAR or GL_NEAREST or GL_XXX_MIPMAP_YYY )
Definition Texture.hpp:30
GLenum wrapS
OpenGL wrap mode in the s direction.
Definition Texture.hpp:24
GLenum wrapR
OpenGL wrap mode in the r direction.
Definition Texture.hpp:28
GLenum magFilter
OpenGL magnification filter ( GL_LINEAR or GL_NEAREST )
Definition Texture.hpp:32
Describes the sampler and image of a texture.
Definition Texture.hpp:99
T transform(T... args)