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