SLProject  4.2.000
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
SLGLTexture.cpp
Go to the documentation of this file.
1 /**
2  * \file SLGLTexture.cpp
3  * \date July 2014
4  * \authors Marcus Hudritsch
5  * \copyright http://opensource.org/licenses/GPL-3.0
6  * \remarks Please use clangformat to format the code. See more code style on
7  * https://github.com/cpvrlab/SLProject4/wiki/SLProject-Coding-Style
8  */
9 
10 #include <SLGLState.h>
11 #include <SLGLTexture.h>
12 #include <SLScene.h>
13 #include <SLGLProgramManager.h>
14 #include <SLAssetManager.h>
15 #include "SLFileStorage.h"
16 #include <Utils.h>
17 #include <Profiler.h>
18 
19 #ifdef SL_HAS_OPTIX
20 # include <cuda.h>
21 # include <cudaGL.h>
22 # include <SLOptix.h>
23 # include <SLOptixHelper.h>
24 # include <SLOptixRaytracer.h>
25 #endif
26 
27 //! maxAnisotropy=-1 show that GL_EXT_texture_filter_anisotropic is not checked
29 
30 //! NO. of texture byte allocated on GPU
32 //-----------------------------------------------------------------------------
33 /*! Default ctor for all stack instances such as the video textures in SLScene
34 or the textures inherited by SLRaytracer. All other constructors add the this
35 pointer to the SLScene::_texture vector for global deallocation.
36 */
38 {
39  _texID = 0;
41  _width = 0;
42  _height = 0;
43  _depth = 0;
44  _uvIndex = 0;
45  _bytesPerPixel = 0;
46  _min_filter = GL_NEAREST;
47  _mag_filter = GL_NEAREST;
48  _wrap_s = GL_REPEAT;
49  _wrap_t = GL_REPEAT;
50  _target = GL_TEXTURE_2D;
51  _bumpScale = 1.0f;
52  _resizeToPow2 = false;
53  _autoCalcTM3D = false;
54  _bytesOnGPU = 0;
55  _bytesInFile = 0;
56  _needsUpdate = false;
57  _deleteImageAfterBuild = false;
58 
59 #ifdef SL_HAS_OPTIX
60  _cudaGraphicsResource = nullptr;
61  _cudaTextureObject = 0;
62 #endif
63 }
64 //-----------------------------------------------------------------------------
65 /*!
66  Constructor for empty 2D textures.
67  Textures can be used in multiple materials. Textures can belong therefore
68  to the global assets such as meshes (SLMesh), materials (SLMaterial),
69  textures (SLGLTexture) and shader programs (SLGLProgram).
70  @param assetMgr Pointer to a global asset manager. If passed the asset
71  manager is the owner of the instance and will do the deallocation. If a
72  nullptr is passed the creator is responsible for the deallocation.
73  @param min_filter Minification filter constant from OpenGL
74  @param mag_filter Magnification filter constant from OpenGL
75  @param wrapS Texture wrapping in S direction (OpenGL constant)
76  @param wrapT Texture wrapping in T direction (OpenGL constant)
77  @param target Texture target GL_TEXTURE_1D, 2D, 3D
78  */
80  SLint min_filter,
81  SLint mag_filter,
82  SLint wrapS,
83  SLint wrapT,
84  SLenum target)
85 {
86  _width = 0;
87  _height = 0;
88  _depth = 0;
89  _bytesPerPixel = 0;
90  _uvIndex = 0;
91  _min_filter = min_filter;
92  _mag_filter = mag_filter;
93  _wrap_s = wrapS;
94  _wrap_t = wrapT;
95  _target = target;
96  _texID = 0;
97  _bumpScale = 1.0f;
98  _resizeToPow2 = false;
99  _autoCalcTM3D = false;
100  _needsUpdate = false;
101  _bytesOnGPU = 0;
102  _bytesInFile = 0;
104  _deleteImageAfterBuild = false;
105 
106  // Add pointer to the global resource vectors for deallocation
107  if (assetMgr)
108  assetMgr->textures().push_back(this);
109 }
110 //-----------------------------------------------------------------------------
111 /*!
112  * Constructor for 2D texture with a passed image data pointer.
113  * Textures can be used in multiple materials. Textures can belong therefore
114  * to the global assets such as meshes (SLMesh), materials (SLMaterial),
115  * textures (SLGLTexture) and shader programs (SLGLProgram).
116  * \param assetMgr Pointer to a global asset manager. If passed the asset
117  * manager is the owner of the instance and will do the deallocation. If a
118  * nullptr is passed the creator is responsible for the deallocation.
119  * \param data Data pointer to the first top-left pixel
120  * \param width Width of the image in pixels
121  * \param height Height of the image in pixels
122  * \param cvtype OpenCV image type
123  * \param min_filter Minification filter constant from OpenGL
124  * \param mag_filter Magnification filter constant from OpenGL
125  * \param type Type of the texture
126  * \param wrapS Texture wrapping in S direction (OpenGL constant)
127  * \param wrapT Texture wrapping in T direction (OpenGL constant)
128  */
130  unsigned char* data,
131  int width,
132  int height,
133  int cvtype,
134  SLint min_filter,
135  SLint mag_filter,
136  SLTextureType type,
137  SLint wrapS,
138  SLint wrapT)
139 {
140 
141  CVImage* image = new CVImage();
142  image->load(width, height, PF_red, PF_red, data, true, false);
143  _images.push_back(image);
144 
145  _width = (SLint)image->width();
146  _height = (SLint)image->height();
147  _depth = (SLint)_images.size();
148  _uvIndex = 0;
149  _bytesPerPixel = (SLint)image->bytesPerPixel();
150  _min_filter = min_filter;
151  _mag_filter = mag_filter;
152  _wrap_s = wrapS;
153  _wrap_t = wrapT;
154  _target = GL_TEXTURE_2D;
155  _texID = 0;
156  _bumpScale = 1.0f;
157  _resizeToPow2 = false;
158  _autoCalcTM3D = false;
159  _needsUpdate = false;
160  _bytesOnGPU = 0;
161  _bytesInFile = 0;
162  _texType = type;
163  _deleteImageAfterBuild = false;
164 
165  // Add pointer to the global resource vectors for deallocation
166  if (assetMgr)
167  assetMgr->textures().push_back(this);
168 }
169 //-----------------------------------------------------------------------------
170 /*!
171  * Constructor for 2D textures from image file with internal image allocation.
172  * Textures can be used in multiple materials. Textures can belong therefore
173  * to the global assets such as meshes (SLMesh), materials (SLMaterial),
174  * textures (SLGLTexture) and shader programs (SLGLProgram).
175  * \param assetMgr Pointer to a global asset manager. If passed the asset
176  * manager is the owner of the instance and will do the deallocation. If a
177  * nullptr is passed the creator is responsible for the deallocation.
178  * \param filename Name of the texture image file. If only a filename is
179  * passed it will be search on the SLGLTexture::defaultPath.
180  * \param min_filter Minification filter constant from OpenGL
181  * \param mag_filter Magnification filter constant from OpenGL
182  * \param type Type of the texture
183  * \param wrapS Texture wrapping in S direction (OpenGL constant)
184  * \param wrapT Texture wrapping in T direction (OpenGL constant)
185  */
187  const SLstring& filename,
188  SLint min_filter,
189  SLint mag_filter,
190  SLTextureType type,
191  SLint wrapS,
192  SLint wrapT)
193  : SLObject(Utils::getFileName(filename), filename)
194 {
195  assert(!filename.empty());
196 
197  _texType = type == TT_unknown ? detectType(filename) : type;
198 
199  load(filename);
200 
201  if (!_images.empty())
202  {
203  _width = _images[0]->width();
204  _height = _images[0]->height();
205  _depth = (SLint)_images.size();
206  _bytesPerPixel = _images[0]->bytesPerPixel();
207  _bytesInFile = _images[0]->bytesInFile();
208  }
209  else if (_compressedTexture)
210  {
211 #ifdef SL_BUILD_WITH_KTX
212  // todo ktx: get properties and extract necessary
213  _width = _ktxTexture->baseWidth;
214  _height = _ktxTexture->baseHeight;
215  _depth = _ktxTexture->numDimensions == 3 ? _ktxTexture->baseDepth : 1;
216  _bytesInFile = Utils::getFileSize(filename);
217 #endif
218  }
219 
220  _min_filter = min_filter;
221  _mag_filter = mag_filter;
222  _wrap_s = wrapS;
223  _wrap_t = wrapT;
224  _target = GL_TEXTURE_2D;
225  _texID = 0;
226  _uvIndex = 0;
227  _bumpScale = 1.0f;
228  _resizeToPow2 = false;
229  _autoCalcTM3D = false;
230  _needsUpdate = false;
231  _bytesOnGPU = 0;
232  _deleteImageAfterBuild = false;
233 
234 #ifdef SL_HAS_OPTIX
235  _cudaGraphicsResource = nullptr;
236  _cudaTextureObject = 0;
237 #endif
238 
239  // Add pointer to the global resource vectors for deallocation
240  if (assetMgr)
241  assetMgr->textures().push_back(this);
242 }
243 //-----------------------------------------------------------------------------
244 /*!
245  * Constructor for 3D textures from image files with internal image allocation.
246  * Textures can be used in multiple materials. Textures can belong therefore
247  * to the global assets such as meshes (SLMesh), materials (SLMaterial),
248  * textures (SLGLTexture) and shader programs (SLGLProgram).
249  * \param assetMgr Pointer to a global asset manager. If passed the asset
250  * manager is the owner of the instance and will do the deallocation. If a
251  * nullptr is passed the creator is responsible for the deallocation.
252  * \param files Vector of texture image files. If only filenames are
253  * passed they will be searched on the SLGLTexture::defaultPath.
254  * \param min_filter Minification filter constant from OpenGL
255  * \param mag_filter Magnification filter constant from OpenGL
256  * \param wrapS Texture wrapping in S direction (OpenGL constant)
257  * \param wrapT Texture wrapping in T direction (OpenGL constant)
258  * \param name Name of the 3D texture
259  * \param loadGrayscaleIntoAlpha Flag if grayscale image should be loaded into
260  * alpha channel.
261  */
263  const SLVstring& files,
264  SLint min_filter,
265  SLint mag_filter,
266  SLint wrapS,
267  SLint wrapT,
268  const SLstring& name,
269  SLbool loadGrayscaleIntoAlpha) : SLObject(name)
270 {
271  assert(files.size() > 1);
272 
274 
275  for (const auto& filename : files)
276  load(filename, true, loadGrayscaleIntoAlpha);
277 
278  if (!_images.empty())
279  {
280  _width = _images[0]->width();
281  _height = _images[0]->height();
282  _depth = (SLint)_images.size();
283  _bytesPerPixel = _images[0]->bytesPerPixel();
284  }
285 
286  _min_filter = min_filter;
287  _mag_filter = mag_filter;
288  _wrap_s = wrapS;
289  _wrap_t = wrapT;
290  _target = GL_TEXTURE_3D;
291  _texID = 0;
292  _uvIndex = 0;
293  _bumpScale = 1.0f;
294  _resizeToPow2 = false;
295  _autoCalcTM3D = true;
296  _needsUpdate = false;
297  _bytesOnGPU = 0;
298  _deleteImageAfterBuild = false;
299 
300 #ifdef SL_HAS_OPTIX
301  _cudaGraphicsResource = nullptr;
302  _cudaTextureObject = 0;
303 #endif
304 
305  // Add pointer to the global resource vectors for deallocation
306  if (assetMgr)
307  assetMgr->textures().push_back(this);
308 }
309 //-----------------------------------------------------------------------------
310 /*!
311  * Constructor for 3D textures from single image file that is stacked depth times.
312  * Textures can be used in multiple materials. Textures can belong therefore
313  * to the global assets such as meshes (SLMesh), materials (SLMaterial),
314  * textures (SLGLTexture) and shader programs (SLGLProgram).
315  * \param assetMgr Pointer to a global asset manager. If passed the asset
316  * manager is the owner of the instance and will do the deallocation. If a
317  * nullptr is passed the creator is responsible for the deallocation.
318  * \param depth Depth of 3D texture.
319  * \param filename texture image file. If only filenames are
320  * passed they will be searched on the SLGLTexture::defaultPath.
321  * \param min_filter Minification filter constant from OpenGL
322  * \param mag_filter Magnification filter constant from OpenGL
323  * \param wrapS Texture wrapping in S direction (OpenGL constant)
324  * \param wrapT Texture wrapping in T direction (OpenGL constant)
325  * \param name Name of the 3D texture
326  * \param loadGrayscaleIntoAlpha Flag if grayscale image should be loaded into
327  * alpha channel.
328  */
330  SLint depth,
331  const SLstring& filename,
332  SLint min_filter,
333  SLint mag_filter,
334  SLint wrapS,
335  SLint wrapT,
336  const SLstring& name,
337  SLbool loadGrayscaleIntoAlpha) : SLObject(name)
338 {
339  assert(depth > 1);
340 
342 
343  for (SLint i = 0; i < depth; ++i)
344  load(filename, true, loadGrayscaleIntoAlpha);
345 
346  if (!_images.empty())
347  {
348  _width = (SLint)_images[0]->width();
349  _height = (SLint)_images[0]->height();
350  _depth = (SLint)_images.size();
352  }
353 
354  _min_filter = min_filter;
355  _mag_filter = mag_filter;
356  _wrap_s = wrapS;
357  _wrap_t = wrapT;
358  _target = GL_TEXTURE_3D;
359  _texID = 0;
360  _uvIndex = 0;
361  _bumpScale = 1.0f;
362  _resizeToPow2 = false;
363  _autoCalcTM3D = true;
364  _needsUpdate = false;
365  _bytesOnGPU = 0;
366  _deleteImageAfterBuild = false;
367 
368 #ifdef SL_HAS_OPTIX
369  _cudaGraphicsResource = nullptr;
370  _cudaTextureObject = 0;
371 #endif
372 
373  // Add pointer to the global resource vectors for deallocation
374  if (assetMgr)
375  assetMgr->textures().push_back(this);
376 }
377 //-----------------------------------------------------------------------------
378 /*!
379  * Constructor for 1D texture from a color vector.
380  * Textures can be used in multiple materials. Textures can belong therefore
381  * to the global assets such as meshes (SLMesh), materials (SLMaterial),
382  * textures (SLGLTexture) and shader programs (SLGLProgram).
383  * \param assetMgr Pointer to a global asset manager. If passed the asset
384  * manager is the owner of the instance and will do the deallocation. If a
385  * nullptr is passed the creator is responsible for the deallocation.
386  * \param colors Vector of colors
387  * \param min_filter Minification filter constant from OpenGL
388  * \param mag_filter Magnification filter constant from OpenGL
389  * \param wrapS Texture wrapping in S direction (OpenGL constant)
390  * \param name Name of the 1D texture
391  */
393  const SLVCol4f& colors,
394  SLint min_filter,
395  SLint mag_filter,
396  SLint wrapS,
397  const SLstring& name) : SLObject(name)
398 {
399  assert(colors.size() > 1);
400 
402 
403  load(colors);
404 
405  if (!_images.empty())
406  {
407  _width = (SLint)_images[0]->width();
408  _height = (SLint)_images[0]->height();
409  _depth = (SLint)_images.size();
411  }
412 
413  _min_filter = min_filter;
414  _mag_filter = mag_filter;
415  _wrap_s = wrapS;
416  _wrap_t = wrapS;
417 
418  // OpenGL ES doesn't define 1D textures. We just make a 1 pixel high 2D texture
419  _target = GL_TEXTURE_2D;
420 
421  _texID = 0;
422  _uvIndex = 0;
423  _bumpScale = 1.0f;
424  _resizeToPow2 = false;
425  _autoCalcTM3D = true;
426  _needsUpdate = false;
427  _bytesOnGPU = 0;
428  _deleteImageAfterBuild = false;
429 
430 #ifdef SL_HAS_OPTIX
431  _cudaGraphicsResource = nullptr;
432  _cudaTextureObject = 0;
433 #endif
434 
435  // Add pointer to the global resource vectors for deallocation
436  if (assetMgr)
437  assetMgr->textures().push_back(this);
438 }
439 //-----------------------------------------------------------------------------
440 /*!
441  * Constructor for a cubemap texture from 6 image files.
442  * Textures can be used in multiple materials. Textures can belong therefore
443  * to the global assets such as meshes (SLMesh), materials (SLMaterial),
444  * textures (SLGLTexture) and shader programs (SLGLProgram).
445  * \param assetMgr Pointer to a global asset manager. If passed the asset
446  * manager is the owner of the instance and will do the deallocation. If a
447  * nullptr is passed the creator is responsible for the deallocation.
448  * \param filenameXPos Filename of the cubemap image in the pos. X direction.
449  * \param filenameXNeg Filename of the cubemap image in the neg. X direction.
450  * \param filenameYPos Filename of the cubemap image in the pos. Y direction.
451  * \param filenameYNeg Filename of the cubemap image in the neg. Y direction.
452  * \param filenameZPos Filename of the cubemap image in the pos. Z direction.
453  * \param filenameZNeg Filename of the cubemap image in the neg. Z direction.
454  * \param min_filter Minification filter constant from OpenGL
455  * \param mag_filter Magnification filter constant from OpenGL
456  * \param type Texture Type
457  */
459  const SLstring& filenameXPos,
460  const SLstring& filenameXNeg,
461  const SLstring& filenameYPos,
462  const SLstring& filenameYNeg,
463  const SLstring& filenameZPos,
464  const SLstring& filenameZNeg,
465  SLint min_filter,
466  SLint mag_filter,
467  SLTextureType type) : SLObject(filenameXPos)
468 {
469  _texType = type == TT_unknown ? detectType(filenameXPos) : type;
470 
471  assert(!filenameXPos.empty());
472  assert(!filenameXNeg.empty());
473  assert(!filenameYPos.empty());
474  assert(!filenameYNeg.empty());
475  assert(!filenameZPos.empty());
476  assert(!filenameZNeg.empty());
477 
478  load(filenameXPos, false);
479  load(filenameXNeg, false);
480  load(filenameYPos, false);
481  load(filenameYNeg, false);
482  load(filenameZPos, false);
483  load(filenameZNeg, false);
484 
485  if (!_images.empty())
486  {
487  _width = (SLint)_images[0]->width();
488  _height = (SLint)_images[0]->height();
489  _depth = (SLint)_images.size();
491  }
492 
493  _min_filter = min_filter;
494  _mag_filter = mag_filter;
495  _wrap_s = GL_CLAMP_TO_EDGE; // other you will see filter artefacts on the edges
496  _wrap_t = GL_CLAMP_TO_EDGE; // other you will see filter artefacts on the edges
497  _target = GL_TEXTURE_CUBE_MAP;
498  _texID = 0;
499  _uvIndex = 0;
500  _bumpScale = 1.0f;
501  _resizeToPow2 = false;
502  _autoCalcTM3D = false;
503  _needsUpdate = false;
504  _bytesOnGPU = 0;
505  _deleteImageAfterBuild = false;
506 
507 #ifdef SL_HAS_OPTIX
508  _cudaGraphicsResource = nullptr;
509  _cudaTextureObject = 0;
510 #endif
511  if (assetMgr)
512  assetMgr->textures().push_back(this);
513 }
514 //-----------------------------------------------------------------------------
515 /*!
516  * The destructor should be called by the owner of the texture. If an asset
517  * manager was passed in the constructor it will do it after scene destruction.
518  * The destructor deletes all images in the RAM as well as the texture objects
519  * on the GPU.
520  */
522 {
523  // SL_LOG("~SLGLTexture(%s)", name().c_str());
524  deleteData(true);
525 }
526 //-----------------------------------------------------------------------------
527 //! Delete all data (CVImages and GPU textures)
528 void SLGLTexture::deleteData(SLbool deleteAlsoOnGPU)
529 {
530  deleteImages();
531 
532  // Delete date on GPU only from the main thread where OpenGL calls are allowed
533  if (deleteAlsoOnGPU)
534  deleteDataGpu();
535 
536 #ifdef SL_BUILD_WITH_KTX
537  if (deleteAlsoOnGPU && _ktxTexture)
538  ktxTexture_Destroy((ktxTexture*)_ktxTexture);
539 #endif
540 
541  _texID = 0;
543  _width = 0;
544  _height = 0;
545  _depth = 0;
546  _bytesPerPixel = 0;
547  _deleteImageAfterBuild = false;
548 }
549 //-----------------------------------------------------------------------------
550 //! Deletes the CVImages in _images. No more texture mapping in ray tracing.
552 {
553  for (auto& img : _images)
554  {
555  delete img;
556  img = nullptr;
557  }
558  _images.clear();
559 }
560 //-----------------------------------------------------------------------------
561 //! Deletes the OpenGL texture objects and releases the memory on the GPU
562 /*! Call this function only from the main thread where OpenGL calls are allowed
563  */
565 {
566  glDeleteTextures(1, &_texID);
567  _texID = 0;
569  _bytesOnGPU = 0;
571 
572 #ifdef SL_HAS_OPTIX
573  if (_cudaGraphicsResource)
574  {
575  CUDA_CHECK(cuGraphicsUnregisterResource(_cudaGraphicsResource));
576  _cudaGraphicsResource = nullptr;
577  }
578 #endif
579 }
580 //-----------------------------------------------------------------------------
581 //! Loads the texture, converts color depth & applies vertical mirroring
582 void SLGLTexture::load(const SLstring& filename,
583  SLbool flipVertical,
584  SLbool loadGrayscaleIntoAlpha)
585 {
586  if (!SLFileStorage::exists(filename, IOK_image))
587  {
588  SLstring msg = "SLGLTexture: File not found: " + filename;
589  SL_EXIT_MSG(msg.c_str());
590  }
591 
592  string ext = Utils::getFileExt(filename);
593 
594  // Check for compressed texture in KTX2 (Khronos Texture) format
595  if (ext == "ktx2")
596  {
597 #ifdef SL_BUILD_WITH_KTX
598  _ktxFileName = filename;
599  _compressedTexture = true;
600 
602  KTX_error_code error = ktxTexture_CreateFromMemory(buffer.data,
603  buffer.size,
604  KTX_TEXTURE_CREATE_NO_FLAGS,
605  (ktxTexture**)&_ktxTexture);
606  // KTX apparently takes ownership of the data, so no deallocation
607 
608  if (error != KTX_SUCCESS)
609  {
610  string errStr = "Error in SLGLTexture::load: " +
611  ktxErrorStr(error) + " in file: " + filename;
612  SL_EXIT_MSG(errStr.c_str());
613  }
614 
615 # ifdef SL_EMSCRIPTEN
616  // WebGL doesn't support generating mipmaps for compressed textures
617  _ktxTexture->generateMipmaps = false;
618 # endif
619 
620  if (ktxTexture2_NeedsTranscoding(_ktxTexture))
621  {
622 # if 0
623  // NOTE(dgj1): The following lines are for reading out supported compressed texture formats
624  // from the openGL driver. I have the suspicion that the enabled compression format (KTX_TTF_ETC2_RGBA)
625  // is not supported on the tested device and that the reason the textures are not displayed on
626  // these devices is this. However, this could not be verified.
627  GLint numCompressedTextureFormats = 0;
628  glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numCompressedTextureFormats);
629  std::vector<GLint> compressedTextureFormats(numCompressedTextureFormats, 0);
630  glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, &compressedTextureFormats[0]);
631 # endif
632 
633 # if defined(SL_OS_MACIOS)
634  _compressionFormat = KTX_TTF_PVRTC1_4_RGB;
635 # elif defined(SL_OS_ANDROID)
636  _compressionFormat = KTX_TTF_ETC2_RGBA;
637 # elif defined(SL_EMSCRIPTEN)
638  // The executable might run on desktop or on mobile, so we have to check
639  // the available compression extensions to pick the right format.
640  if (SLGLState::instance()->hasExtension("WEBGL_compressed_texture_s3tc"))
641  _compressionFormat = KTX_TTF_BC3_RGBA;
642  else if (SLGLState::instance()->hasExtension("WEBGL_compressed_texture_etc"))
643  _compressionFormat = KTX_TTF_ETC2_RGBA;
644  else
645  SL_EXIT_MSG("No valid compression format found for this WebGL context");
646 # else
647  _compressionFormat = KTX_TTF_BC3_RGBA;
648 # endif
649  error = ktxTexture2_TranscodeBasis(_ktxTexture, _compressionFormat, 0);
650 
651  if (error != KTX_SUCCESS || _ktxTexture->pData == nullptr)
652  {
653  string errStr = "Error in SLGLTexture::load: " +
654  ktxErrorStr(error) +
655  "\nwhile transcoding file: " + filename +
656  "\nto format: " + compressionFormatStr(_compressionFormat);
657  SL_EXIT_MSG(errStr.c_str());
658  }
659  }
660 #else
661  SL_EXIT_MSG("Ktx files are not supported. You have to build with SL_BUILD_WITH_KTX flag enabled.");
662 #endif
663  }
664  else
665  {
666  CVImage* image = new CVImage(filename,
667  flipVertical,
668  loadGrayscaleIntoAlpha);
669  _images.push_back(image);
670  }
671 }
672 //-----------------------------------------------------------------------------
673 //! Loads the 1D color data into an image of height 1
674 void SLGLTexture::load(const SLVCol4f& colors)
675 {
676  assert(colors.size() > 1);
677 
678  // convert to CV color vector
679  CVVVec4f col4f;
680  for (const auto& c : colors)
681  col4f.push_back(CVVec4f(c.r, c.g, c.b, c.a));
682 
683  CVImage* image = new CVImage(col4f);
684  _images.push_back(image);
685 }
686 //-----------------------------------------------------------------------------
687 //! Copies the image data from a video camera into the current video image
688 /*!
689 @brief SLGLTexture::copyVideoImage
690 @param camWidth Width in pixels of the camera image
691 @param camHeight Height in pixels of the camera image
692 @param srcFormat Pixel format according to the OpenGL pixel formats
693 @param data Pointer to the first byte of the first pixel
694 @param isContinuous Flag if the next line comes after the last byte of the prev. line
695 @param isTopLeft Flag if the data pointer points to the top left pixel
696 @return Returns true if the texture was rebuilt
697 It is important that passed pixel format is either PF_LUMINANCE, RGB or RGBA.
698 otherwise an expensive conversion must be done.
699 */
701  SLint camHeight,
702  CVPixelFormatGL srcFormat,
703  SLuchar* data,
704  SLbool isContinuous,
705  SLbool isTopLeft)
706 {
708 
709  CVPixelFormatGL pixelFormat = PF_rgb;
710 
711  // Add image for the first time
712  if (_images.empty())
713  _images.push_back(new CVImage(camWidth,
714  camHeight,
715  pixelFormat,
716  "LiveVideoImageFromMemory"));
717 
718  // load returns true if size or format changes
719  bool needsBuild = _images[0]->load(camWidth,
720  camHeight,
721  srcFormat,
722  pixelFormat,
723  data,
724  isContinuous,
725  isTopLeft);
726 
727  if (!_images.empty())
728  {
729  _width = (SLint)_images[0]->width();
730  _height = (SLint)_images[0]->height();
731  _depth = (SLint)_images.size();
733  }
734 
735  // OpenGL ES 2 only can resize non-power-of-two texture with clamp to edge
736  _wrap_s = GL_CLAMP_TO_EDGE;
737  _wrap_t = GL_CLAMP_TO_EDGE;
738 
739  if (needsBuild || _texID == 0)
740  build(0);
741 
742  _needsUpdate = true;
743  return needsBuild;
744 }
745 
747  SLint camHeight,
748  CVPixelFormatGL srcFormat,
749  CVPixelFormatGL dstFormat,
750  SLuchar* data,
751  SLbool isContinuous,
752  SLbool isTopLeft)
753 {
755 
756  // Add image for the first time
757  if (_images.empty())
758  _images.push_back(new CVImage(camWidth,
759  camHeight,
760  dstFormat,
761  "LiveVideoImageFromMemory"));
762 
763  // load returns true if size or format changes
764  bool needsBuild = _images[0]->load(camWidth,
765  camHeight,
766  srcFormat,
767  dstFormat,
768  data,
769  isContinuous,
770  isTopLeft);
771  if (!_images.empty())
772  {
773  _width = (int)_images[0]->width();
774  _height = (int)_images[0]->height();
775  _depth = (SLint)_images.size();
776  _bytesPerPixel = (int)_images[0]->bytesPerPixel();
777  }
778 
779  // OpenGL ES 2 only can resize non-power-of-two texture with clamp to edge
780  _wrap_s = GL_CLAMP_TO_EDGE;
781  _wrap_t = GL_CLAMP_TO_EDGE;
782 
783  if (needsBuild || _texID == 0)
784  build(0);
785 
786  _needsUpdate = true;
787  return needsBuild;
788 }
789 
790 //-----------------------------------------------------------------------------
791 /*!
792 Builds an OpenGL texture object with the according OpenGL commands.
793 This texture creation must be done only once when a valid OpenGL rendering
794 context is present. This function is called the first time within the enable
795 method which is called by object that uses the texture.
796 */
798 {
800 
801  assert(texUnit >= 0 && texUnit < 16);
802 
803  if (_compressedTexture)
804  {
805 #ifdef SL_BUILD_WITH_KTX
806  if (_ktxTexture->pData == nullptr)
807  {
808  string errStr = "Error in SLGLTexture::build: texture " + _ktxFileName + " contains no data";
809  SL_WARN_MSG(errStr.c_str());
810  }
811 
812  // delete texture name if it already exits
813  if (_texID)
814  {
815  glBindTexture(_target, _texID);
816  glDeleteTextures(1, &_texID);
817  glBindTexture(_target, 0);
818  _texID = 0;
820  }
821 
822  // get max texture size
823  SLint texMaxSize = 0;
824  glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texMaxSize);
825 
826  // todo ktx: compare with image size
827  // check 2D size
828  if (_target == GL_TEXTURE_2D)
829  {
830  if (_width > texMaxSize)
831  SL_EXIT_MSG("SLGLTexture::build: Texture width is too big.");
832  if (_height > texMaxSize)
833  SL_EXIT_MSG("SLGLTexture::build: Texture height is too big.");
834  }
835 
836  // todo ktx: cubemaps and 3d textures
837 
838  // todo: upload in build process
839  GLenum glerror = 0;
840  glGenTextures(1, &_texID); // Optional. GLUpload can generate a texture.
841 
842 # if 0
843  glBindTexture(_target, _texID);
844 
845  glTexParameteri(_target, GL_TEXTURE_MIN_FILTER, _min_filter);
846  GET_GL_ERROR;
847 
848  // apply magnification filter only GL_NEAREST & GL_LINEAR is allowed
849  glTexParameteri(_target, GL_TEXTURE_MAG_FILTER, _mag_filter);
850  GET_GL_ERROR;
851 
852  // apply texture wrapping modes
853  glTexParameteri(_target, GL_TEXTURE_WRAP_S, _wrap_s);
854  glTexParameteri(_target, GL_TEXTURE_WRAP_T, _wrap_t);
855  glTexParameteri(_target, GL_TEXTURE_WRAP_R, _wrap_t);
856  GET_GL_ERROR;
857 # endif
858 
859  KTX_error_code ktxErrorCode = ktxTexture_GLUpload((ktxTexture*)_ktxTexture, &_texID, &_target, &glerror);
860  GET_GL_ERROR;
861 
862  _ktxTexture->baseHeight;
863 
864  _bytesOnGPU += (SLuint)_ktxTexture->dataSize;
866 
867  // todo: destroy somewhere else
869  {
870  ktxTexture_Destroy((ktxTexture*)_ktxTexture);
871  _ktxTexture = nullptr;
872  }
873  GET_GL_ERROR;
874 #endif
875  }
876 #ifdef SL_OS_ANDROID
877  else if (_target == GL_TEXTURE_EXTERNAL_OES)
878  {
879  glGenTextures(1, &_texID);
880 
881  SLGLState* stateGL = SLGLState::instance();
882  stateGL->activeTexture(GL_TEXTURE0 + (SLuint)texUnit);
883 
884  // create binding and apply texture properties
885  stateGL->bindTexture(GL_TEXTURE_EXTERNAL_OES, _texID);
886 
887  glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
888  glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
889  // apply texture wrapping modes
890  glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, _wrap_s);
891  glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, _wrap_t);
892  // ATTENTION: setting the color to black or white does not give correct results (dont know why)
893  // colors different to black and white seem to work. Default value is {0, 0, 0, 0}.
894  float color[] = {0.00001f, 0.00001f, 0.00001f, 1.0f};
895  glTexParameterfv(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_BORDER_COLOR_OES, color);
896  GET_GL_ERROR;
897  }
898 #endif
899  else
900  {
901  if (_images.empty())
902  SL_EXIT_MSG("No images loaded in SLGLTexture::build");
903 
904  // delete texture name if it already exits
905  if (_texID)
906  {
907  glBindTexture(_target, _texID);
908  glDeleteTextures(1, &_texID);
909  SL_LOG("SLGLTexture::build: Deleted: %d, %s",
910  _texID,
911  _images[0]->name().c_str());
912  glBindTexture(_target, 0);
913  _texID = 0;
915  _bytesOnGPU = 0;
916  }
917 
918  // get max texture size
919  SLint texMaxSize = 0;
920  glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texMaxSize);
921 
922  // check if texture has to be resized
923  if (_resizeToPow2)
924  {
927  if (w2 == 0) SL_EXIT_MSG("Image can not be rescaled: width=0");
928  if (h2 == 0) SL_EXIT_MSG("Image can not be rescaled: height=0");
929  if (w2 != _images[0]->width() || h2 != _images[0]->height())
930  _images[0]->resize((SLint)w2, (SLint)h2);
931  }
932 
933  // check 2D size
934  if (_target == GL_TEXTURE_2D)
935  {
936  if (_images[0]->width() > (SLuint)texMaxSize)
937  SL_EXIT_MSG("SLGLTexture::build: Texture width is too big.");
938  if (_images[0]->height() > (SLuint)texMaxSize)
939  SL_EXIT_MSG("SLGLTexture::build: Texture height is too big.");
940  }
941 
942  // check 3D size
943  if (_target == GL_TEXTURE_3D)
944  {
945  SLint texMax3DSize = 0;
946  glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &texMax3DSize);
947  for (auto img : _images)
948  {
949  if (img->width() > (SLuint)texMax3DSize)
950  SL_EXIT_MSG("SLGLTexture::build: 3D Texture width is too big.");
951  if (img->height() > (SLuint)texMax3DSize)
952  SL_EXIT_MSG("SLGLTexture::build: 3D Texture height is too big.");
953  if (img->width() != _images[0]->width() ||
954  img->height() != _images[0]->height())
955  SL_EXIT_MSG("SLGLTexture::build: Not all images of the 3D texture have the same size.");
956  }
957  }
958 
959  // check cube mapping capability & max. cube map size
960  if (_target == GL_TEXTURE_CUBE_MAP)
961  {
962  SLint texMaxCubeSize;
963  glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &texMaxCubeSize);
964  if (_images[0]->width() > (SLuint)texMaxCubeSize)
965  SL_EXIT_MSG("SLGLTexture::build: Cube Texture width is too big.");
966  if (_images.size() != 6)
967  SL_EXIT_MSG("SLGLTexture::build: Not six images provided for cube map texture.");
968  }
969 
970  // Generate texture names
971  glGenTextures(1, &_texID);
972 
973  SLGLState* stateGL = SLGLState::instance();
974  stateGL->activeTexture(GL_TEXTURE0 + (SLuint)texUnit);
975 
976  // create binding and apply texture properties
977  stateGL->bindTexture(_target, _texID);
978 
979  // check if anisotropic texture filter extension is available
980  if (maxAnisotropy < 0.0f)
981  {
982  if (stateGL->hasExtension("GL_EXT_texture_filter_anisotropic"))
984  else
985  {
986  maxAnisotropy = 0.0f;
987  SL_LOG("GL_EXT_texture_filter_anisotropic not available.\n");
988  }
989  }
990  GET_GL_ERROR;
991 
992  // apply anisotropic or minification filter
993  if (_min_filter > GL_LINEAR_MIPMAP_LINEAR)
994  {
995  SLfloat anisotropy; // = off
997  anisotropy = maxAnisotropy;
998  else
999  anisotropy = std::min((SLfloat)(_min_filter - GL_LINEAR_MIPMAP_LINEAR),
1000  maxAnisotropy);
1001  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);
1002  }
1003  else
1004  glTexParameteri(_target, GL_TEXTURE_MIN_FILTER, _min_filter);
1005  GET_GL_ERROR;
1006 
1007  // apply magnification filter only GL_NEAREST & GL_LINEAR is allowed
1008  glTexParameteri(_target, GL_TEXTURE_MAG_FILTER, _mag_filter);
1009  GET_GL_ERROR;
1010 
1011  // apply texture wrapping modes
1012  glTexParameteri(_target, GL_TEXTURE_WRAP_S, _wrap_s);
1013  glTexParameteri(_target, GL_TEXTURE_WRAP_T, _wrap_t);
1014  glTexParameteri(_target, GL_TEXTURE_WRAP_R, _wrap_t);
1015  GET_GL_ERROR;
1016 
1017  // Handle special stupid case on iOS
1018  _internalFormat = _images[0]->format();
1019  if (_internalFormat == PF_red)
1020  _internalFormat = GL_R8;
1021 
1022  // Handle special case for realtime RT
1023  if (_images[0]->name() == "Optix Raytracer")
1024  _internalFormat = GL_RGB32F;
1025 
1026  // Handle special case for HDR textures
1027  if (_texType == TT_hdr)
1029 
1030  // Build textures
1031  if (_target == GL_TEXTURE_2D)
1032  {
1033  GLenum format = _images[0]->format();
1034 
1035  //////////////////////////////////////////////////////////////
1036  glTexImage2D(GL_TEXTURE_2D,
1037  0,
1039  (SLsizei)_images[0]->width(),
1040  (SLsizei)_images[0]->height(),
1041  0,
1042  format,
1043  _texType == TT_hdr ? SL_HDR_GL_TYPE : GL_UNSIGNED_BYTE,
1044  (GLvoid*)_images[0]->data());
1045  /////////////////////////////////////////////////////////////
1046 
1047  GET_GL_ERROR;
1048 
1049  _bytesOnGPU = _images[0]->bytesPerImage();
1050 
1051  if (_min_filter >= GL_NEAREST_MIPMAP_NEAREST)
1052  {
1053  if (stateGL->glIsES2() ||
1054  stateGL->glIsES3() ||
1055  stateGL->glVersionNOf() >= 3.0)
1056  glGenerateMipmap(GL_TEXTURE_2D);
1057  else
1058  build2DMipmaps(GL_TEXTURE_2D, 0);
1059 
1060  // Mipmaps use 1/3 more memory on GPU
1061  _bytesOnGPU = (SLuint)((SLfloat)_bytesOnGPU * 1.333333333f);
1062  GET_GL_ERROR;
1063  }
1064 
1066  }
1067  else if (_target == GL_TEXTURE_3D)
1068  {
1069  // temporary buffer for 3D image data
1070  SLVuchar buffer(_images[0]->bytesPerImage() * _images.size());
1071  SLuchar* imageData = &buffer[0];
1072 
1073  // copy each image data into temp. buffer
1074  for (CVImage* img : _images)
1075  {
1076  memcpy(imageData, img->data(), img->bytesPerImage());
1077  imageData += img->bytesPerImage();
1078  _bytesOnGPU += _images[0]->bytesPerImage();
1079  }
1080 
1081  /////////////////////////////////////////////////////
1082  glTexImage3D(GL_TEXTURE_3D,
1083  0, // Mipmap level,
1084  _internalFormat, // Internal format
1085  (SLsizei)_images[0]->width(),
1086  (SLsizei)_images[0]->height(),
1087  (SLsizei)_images.size(),
1088  0, // Border
1089  _images[0]->format(), // Format
1090  GL_UNSIGNED_BYTE, // Data type
1091  &buffer[0]);
1092  /////////////////////////////////////////////////////
1093 
1095  GET_GL_ERROR;
1096  }
1097  else if (_target == GL_TEXTURE_CUBE_MAP)
1098  {
1099  for (SLuint i = 0; i < 6; i++)
1100  {
1101  //////////////////////////////////////////////
1102  glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
1103  0,
1105  (SLsizei)_images[i]->width(),
1106  (SLsizei)_images[i]->height(),
1107  0,
1108  _images[i]->format(),
1109  GL_UNSIGNED_BYTE,
1110  (GLvoid*)_images[i]->data());
1111  //////////////////////////////////////////////
1112 
1113  _bytesOnGPU += _images[0]->bytesPerImage();
1114  GET_GL_ERROR;
1115  }
1116 
1118  if (_min_filter >= GL_NEAREST_MIPMAP_NEAREST)
1119  {
1120  glGenerateMipmap(GL_TEXTURE_2D);
1121 
1122  // Mipmaps use 1/3 more memory on GPU
1123  _bytesOnGPU = (SLuint)((SLfloat)_bytesOnGPU * (4.0f / 3.0f));
1124  }
1125  }
1126 
1127  // If the images get deleted they only are on the GPU side
1129  deleteImages();
1130  }
1131 
1132  // Check if texture name is valid only for debug purpose
1133  // if (glIsTexture(_texName))
1134  // SL_LOG("SLGLTexture::build: name: %u, unit-id: %u, Filename: %s", _texName, texUnit, _images[0]->name().c_str());
1135  // else SL_LOG("SLGLTexture::build: invalid name: %u, unit-id: %u, Filename: %s", _texName, texUnit, _images[0]->name().c_str());
1136 
1137  GET_GL_ERROR;
1138 }
1139 //-----------------------------------------------------------------------------
1140 #ifdef SL_HAS_OPTIX
1141 void SLGLTexture::buildCudaTexture()
1142 {
1143  if (!_cudaTextureObject)
1144  {
1145  CUarray texture_ptr;
1146 
1147  CUDA_CHECK(cuGraphicsMapResources(1,
1148  &_cudaGraphicsResource,
1149  SLOptix::stream));
1150  CUDA_CHECK(cuGraphicsSubResourceGetMappedArray(&texture_ptr,
1151  _cudaGraphicsResource,
1152  0,
1153  0));
1154 
1155  CUDA_RESOURCE_DESC res_desc = {};
1156 
1157  res_desc.resType = CU_RESOURCE_TYPE_ARRAY;
1158  res_desc.res.array.hArray = texture_ptr;
1159 
1160  CUDA_TEXTURE_DESC tex_desc = {};
1161  tex_desc.addressMode[0] = CU_TR_ADDRESS_MODE_WRAP;
1162  tex_desc.addressMode[1] = CU_TR_ADDRESS_MODE_WRAP;
1163  tex_desc.filterMode = CU_TR_FILTER_MODE_LINEAR;
1164  tex_desc.flags = CU_TRSF_NORMALIZED_COORDINATES;
1165  tex_desc.maxAnisotropy = (SLuint)maxAnisotropy;
1166  tex_desc.maxMipmapLevelClamp = 99;
1167  tex_desc.minMipmapLevelClamp = 0;
1168 
1169  CUDA_CHECK(cuTexObjectCreate(&_cudaTextureObject,
1170  &res_desc,
1171  &tex_desc,
1172  nullptr));
1173  CUDA_CHECK(cuGraphicsUnmapResources(1,
1174  &_cudaGraphicsResource,
1175  SLOptix::stream));
1176  }
1177 }
1178 #endif
1179 //-----------------------------------------------------------------------------
1180 /*!
1181 SLGLTexture::bindActive binds the active texture. This method must be called
1182 by the object that uses the texture every time BEFORE the its rendering.
1183 The texUnit is only used for multi texturing. Before the first time the texture
1184 is passed to OpenGL.
1185 */
1187 {
1188  assert(texUnit >= 0 && texUnit < 16);
1189 
1190  // if texture not exists build it
1191  if (!_texID)
1192  build(texUnit);
1193 
1194  if (_texID)
1195  {
1196  SLGLState* stateGL = SLGLState::instance();
1197  // SL_LOG("SLGLTexture::bindActive: activeTexture: %d, bindTexture: %u, name: %s", texUnit, _texID, _name.c_str());
1198  stateGL->activeTexture(GL_TEXTURE0 + texUnit);
1199  stateGL->bindTexture(_target, _texID);
1200 
1201  if (_needsUpdate)
1202  {
1203  fullUpdate();
1204  _needsUpdate = false;
1205  }
1206 
1207 #ifdef SL_HAS_OPTIX
1208  if (!_cudaGraphicsResource)
1209  {
1210  // Todo: Bugfix needed for Optix needs some work for newer shader models
1211  // CUDA_CHECK(
1212  cuGraphicsGLRegisterImage(&_cudaGraphicsResource,
1213  _texID,
1214  _target,
1215  CU_GRAPHICS_REGISTER_FLAGS_NONE);
1216  //);
1217  }
1218 #endif
1219  }
1220 
1221  GET_GL_ERROR;
1222 }
1223 //-----------------------------------------------------------------------------
1224 /*!
1225 Fully updates the OpenGL internal texture data by the image data
1226 */
1228 {
1229  PROFILE_FUNCTION();
1230 
1231  if (_texID &&
1232  !_images.empty() &&
1233  _images[0]->data() &&
1234  _target == GL_TEXTURE_2D)
1235  {
1236  // Do not allow MIP-Maps as they are to big
1237  if (_min_filter == GL_NEAREST || _min_filter == GL_LINEAR)
1238  {
1240 
1241  /////////////////////////////////////////////
1242  glTexSubImage2D(_target,
1243  0,
1244  0,
1245  0,
1246  (SLsizei)_images[0]->width(),
1247  (SLsizei)_images[0]->height(),
1248  _images[0]->format(),
1249  GL_UNSIGNED_BYTE,
1250  (GLvoid*)_images[0]->data());
1251  /////////////////////////////////////////////
1252 
1253  _bytesOnGPU = _images[0]->bytesPerImage();
1255  }
1256  else
1257  SL_WARN_MSG("Filtering to expensive to full update in SLGLTexture::fullupdate!");
1258  }
1259  GET_GL_ERROR;
1260 }
1261 //-----------------------------------------------------------------------------
1262 //! Draws the texture as 2D sprite with OpenGL buffers
1263 /*! Draws the texture as a flat 2D sprite with a height and a width on two
1264 triangles with zero in the bottom left corner: <br>
1265  w
1266  +-----+
1267  | /|
1268  | / |
1269  h | / |
1270  | / |
1271  |/ |
1272  0 +-----+
1273  0
1274 */
1276 {
1277  // build buffer object once
1278  if (!_vaoSprite.vaoID())
1279  {
1280  // Vertex X & Y of corners
1281  SLVVec2f P = {{x, h},
1282  {x, y},
1283  {x + w, y + h},
1284  {x + w, y}};
1285 
1286  // Texture coords of corners
1287  SLVVec2f T = {{0.0f, 1.0f},
1288  {0.0f, 0.0f},
1289  {1.0f, 1.0f},
1290  {1.0f, 0.0f}};
1291 
1292  // Indexes for a triangle strip
1293  SLVushort I = {0, 1, 2, 3};
1294 
1296  sp->useProgram();
1299  _vaoSprite.setIndices(&I, nullptr);
1300  _vaoSprite.generate(4);
1301  }
1302 
1303  bindActive(0); // Enable & build texture
1304  if (doUpdate) fullUpdate(); // Update the OpenGL texture on each draw
1305 
1306  // Draw the character triangles
1307  SLGLState* stateGL = SLGLState::instance();
1309  sp->useProgram();
1310  sp->uniformMatrix4fv("u_mMatrix", 1, (SLfloat*)&stateGL->modelMatrix);
1311  sp->uniformMatrix4fv("u_vMatrix", 1, (SLfloat*)&stateGL->viewMatrix);
1312  sp->uniformMatrix4fv("u_pMatrix", 1, (SLfloat*)&stateGL->projectionMatrix);
1313  sp->uniform1i("u_matTexture0", 0);
1314  sp->uniform1f("u_oneOverGamma", 1.0f);
1315 
1316  ////////////////////////////////////////////
1318  ////////////////////////////////////////////
1319 }
1320 //-----------------------------------------------------------------------------
1321 //! SLGLTexture::getTexelf returns a pixel color from u & v texture coordinates.
1322 /*! If the OpenGL filtering is set to GL_LINEAR a bilinear interpolated color out
1323 of four neighboring pixels is return. Otherwise the nearest pixel is returned.
1324 */
1326 {
1327  if (imgIndex < _images.size())
1328  {
1329 
1330  // transform tex coords with the texture matrix
1331  u = u * _tm.m(0) + _tm.m(12);
1332  v = v * _tm.m(5) + _tm.m(13);
1333 
1334  // Make sure the tex. coords are between 0.0 and 1.0
1335  if (u < 0.0f || u > 1.0f) u -= floor(u);
1336  if (v < 0.0f || v > 1.0f) v -= floor(v);
1337 
1338  // Bilinear interpolation
1339  if (_min_filter == GL_LINEAR || _mag_filter == GL_LINEAR)
1340  {
1341  CVVec4f c4f = _images[imgIndex]->getPixelf(u, v);
1342  return SLCol4f(c4f[0], c4f[1], c4f[2], c4f[3]);
1343  }
1344  else
1345  {
1346  CVVec4f c4f = _images[imgIndex]->getPixeli((SLint)(u * (float)_images[imgIndex]->width()),
1347  (SLint)(v * (float)_images[imgIndex]->height()));
1348  return SLCol4f(c4f[0], c4f[1], c4f[2], c4f[3]);
1349  }
1350  }
1351  else
1352  return SLCol4f::BLACK;
1353 }
1354 //-----------------------------------------------------------------------------
1355 //! SLGLTexture::getTexelf returns a pixel color at the specified cubemap direction
1357 {
1358  assert(_images.size() == 6 &&
1359  _target == GL_TEXTURE_CUBE_MAP &&
1360  "SLGLTexture::getTexelf: Not a cubemap!");
1361 
1362  SLint index = 0;
1363  SLfloat u, v;
1364 
1365  cubeXYZ2UV(cubemapDir.x, cubemapDir.y, cubemapDir.z, index, u, v);
1366 
1367  return getTexelf(u, v, (SLuint)index);
1368 }
1369 //-----------------------------------------------------------------------------
1370 /*!
1371 dudv calculates the partial derivation (gray value slope) at u,v for bump
1372 mapping either from a height map or a normal map
1373 */
1375 {
1376  SLVec2f dudv(0, 0);
1377  SLfloat du = 1.0f / (SLfloat)_images[0]->width();
1378  SLfloat dv = 1.0f / (SLfloat)_images[0]->height();
1379 
1380  if (_texType == TT_height)
1381  {
1382  dudv.x = (getTexelf(u + du, v).x - getTexelf(u - du, v).x) * -_bumpScale;
1383  dudv.y = (getTexelf(u, v + dv).x - getTexelf(u, v - dv).x) * -_bumpScale;
1384  }
1385  else if (_texType == TT_normal)
1386  {
1387  SLVec4f texel = getTexelf(u, v);
1388  dudv.x = texel.r * 2.0f - 1.0f;
1389  dudv.y = texel.g * 2.0f - 1.0f;
1390  }
1391  return dudv;
1392 }
1393 //-----------------------------------------------------------------------------
1394 //! Detects the texture type from the filename appendix (See SLTexType def.)
1396 {
1397  // Check first our own texture name encoding
1399  SLstring ext = Utils::getFileExt(filename);
1400  SLstring appendix = name.substr(name.length() - 2, 2);
1401 
1402  if (ext == "hdr") return TT_hdr;
1403  if (appendix == "_C") return TT_diffuse; // Color
1404  if (appendix == "_D") return TT_diffuse;
1405  if (appendix == "_N") return TT_normal;
1406  if (appendix == "_H") return TT_height;
1407  if (appendix == "_G") return TT_specular; // Gloss
1408  if (appendix == "_S") return TT_specular;
1409  if (appendix == "_R") return TT_roughness;
1410  if (appendix == "_M") return TT_metallic;
1411  if (appendix == "_O") return TT_occlusion; // Ambient Occlusion
1412  if (appendix == "_A") return TT_occlusion;
1413  if (appendix == "_F") return TT_font;
1414 
1415  // Now check various formats found in the past
1417 
1418  if (Utils::containsString(name, "COL") ||
1419  Utils::containsString(name, "COLOR") ||
1420  Utils::containsString(name, "BASECOLOR") ||
1421  Utils::containsString(name, "ALBEDO") ||
1422  Utils::containsString(name, "DIFFUSE") ||
1423  Utils::containsString(name, "DIFF") ||
1424  Utils::containsString(name, "DIF"))
1425  return TT_diffuse;
1426 
1427  if (Utils::containsString(name, "NRM") ||
1428  Utils::containsString(name, "NORM") ||
1429  Utils::containsString(name, "NORMAL"))
1430  return TT_normal;
1431 
1432  if (Utils::containsString(name, "DISP") ||
1433  Utils::containsString(name, "DISPL") ||
1434  Utils::containsString(name, "HEIGHT") ||
1435  Utils::containsString(name, "BUMP"))
1436  return TT_height;
1437 
1438  if (Utils::containsString(name, "GLOSS") ||
1439  Utils::containsString(name, "REFL") ||
1440  Utils::containsString(name, "SPECULAR") ||
1441  Utils::containsString(name, "SPEC"))
1442  return TT_specular;
1443 
1444  if (Utils::containsString(name, "OCCLUSIONROUGHNESSMETALLIC"))
1445  return TT_occluRoughMetal;
1446 
1447  if (Utils::containsString(name, "ROUGHNESSMETALLIC"))
1448  return TT_roughMetal;
1449 
1450  if (Utils::containsString(name, "ROUGHNESS") ||
1451  Utils::containsString(name, "RGH") ||
1452  Utils::containsString(name, "ROUGH"))
1453  return TT_roughness;
1454 
1455  if (Utils::containsString(name, "METAL") ||
1456  Utils::containsString(name, "METALLIC") ||
1457  Utils::containsString(name, "METALNESS"))
1458  return TT_metallic;
1459 
1460  if (Utils::containsString(name, "AO") ||
1461  Utils::containsString(name, "AMBIENT") ||
1462  Utils::containsString(name, "OCCLUSION") ||
1463  Utils::containsString(name, "OCCLU") ||
1464  Utils::containsString(name, "OCCL") ||
1465  Utils::containsString(name, "OCC"))
1466  return TT_occlusion;
1467 
1468  // if nothing was detected so far we interpret it as a color texture
1469  // SLstring msg = Utils::formatString("SLGLTexture::detectType: No type detected in file: %s", filename.c_str());
1470  // SL_WARN_MSG(msg.c_str());
1471 
1472  return TT_diffuse;
1473 }
1474 //-----------------------------------------------------------------------------
1476 {
1477  // Create the base level mipmap
1478  SLint level = 0;
1479  glTexImage2D((SLuint)target,
1480  level,
1481  (SLint)_images[index]->bytesPerPixel(),
1482  (SLsizei)_images[index]->width(),
1483  (SLsizei)_images[index]->height(),
1484  0,
1485  _images[index]->format(),
1486  GL_UNSIGNED_BYTE,
1487  (GLvoid*)_images[index]->data());
1488  GET_GL_ERROR;
1489 
1490  // working copy of the base mipmap
1491  CVImage img2(*_images[index]);
1492 
1493  // create half sized sub level mipmaps
1494  while (img2.width() > 1 || img2.height() > 1)
1495  {
1496  level++;
1497  img2.resize((SLint)std::max(img2.width() >> 1, (SLuint)1),
1498  (SLint)std::max(img2.height() >> 1, (SLuint)1));
1499 
1500  // SLfloat gauss[9] = {1.0f, 2.0f, 1.0f,
1501  // 2.0f, 4.0f, 2.0f,
1502  // 1.0f, 2.0f, 1.0f};
1503 
1504  // img2.convolve3x3(gauss);
1505 
1506  // Debug output
1507  // SLchar filename[255];
1508  // snprintf(filename,sizeof(filename),"%s_L%d_%dx%d.png", _name.c_str(), level, img2.width(), img2.height());
1509  // img2.savePNG(filename);
1510 
1511  glTexImage2D((SLuint)target,
1512  level,
1513  (SLint)img2.bytesPerPixel(),
1514  (SLsizei)img2.width(),
1515  (SLsizei)img2.height(),
1516  0,
1517  img2.format(),
1518  GL_UNSIGNED_BYTE,
1519  (GLvoid*)img2.data());
1520  GET_GL_ERROR;
1521  }
1522 }
1523 //-----------------------------------------------------------------------------
1524 //! Returns the texture type as string
1526 {
1527  switch (_texType)
1528  {
1529  case TT_unknown: return "TT_unknown";
1530  case TT_diffuse: return "TT_diffuse";
1531  case TT_normal: return "TT_normal";
1532  case TT_height: return "TT_height";
1533  case TT_specular: return "TT_specular";
1534  case TT_emissive: return "TT_emissive";
1535  case TT_roughness: return "TT_roughness";
1536  case TT_metallic: return "TT_metallic";
1537  case TT_occluRoughMetal: return "TT_occluRoughMetal";
1538  case TT_roughMetal: return "TT_roughMetal";
1539  case TT_occlusion: return "TT_occlusion";
1540  case TT_font: return "TT_font";
1541  case TT_hdr: return "TT_hdr";
1542  case TT_environmentCubemap: return "TT_environmentCubemap";
1543  case TT_irradianceCubemap: return "TT_irradianceCubemap";
1544  case TT_roughnessCubemap:
1545  case TT_brdfLUT: return "TT_roughnessCubemap";
1546  case TT_videoBkgd: return "TT_videoBkgd";
1547  default: return "TT_unknown";
1548  }
1549 }
1550 //-----------------------------------------------------------------------------
1551 //! Returns the texture type short
1553 {
1554  switch (_texType)
1555  {
1556  case TT_unknown: return "U";
1557  case TT_diffuse: return "D";
1558  case TT_normal: return "N";
1559  case TT_height: return "H";
1560  case TT_specular: return "S";
1561  case TT_emissive: return "E";
1562  case TT_roughness: return "R";
1563  case TT_metallic: return "M";
1564  case TT_occlusion: return "O";
1565  case TT_roughMetal: return "RM";
1566  case TT_occluRoughMetal: return "ORM";
1567  case TT_font: return "F";
1568  case TT_hdr: return "HDR";
1569  case TT_environmentCubemap: return "EnvE";
1570  case TT_irradianceCubemap: return "EnvI";
1571  case TT_roughnessCubemap: return "EnvR";
1572  case TT_brdfLUT: return "brdf";
1573  case TT_videoBkgd: return "VidBkgd";
1574  default: return "U";
1575  }
1576 }
1577 //-----------------------------------------------------------------------------
1578 //! Returns OpenGL texture filter as string
1580 {
1581  switch (glFilter)
1582  {
1583  case GL_NEAREST: return "nearest";
1584  case GL_LINEAR: return "linear";
1585  case GL_NEAREST_MIPMAP_NEAREST: return "nearest mipmap nearest";
1586  case GL_LINEAR_MIPMAP_NEAREST: return "linear mipmap linear";
1587  case GL_NEAREST_MIPMAP_LINEAR: return "nearest mipmap linear";
1588  case GL_LINEAR_MIPMAP_LINEAR: return "linear mipmap linear";
1589  case SL_ANISOTROPY_MAX: return "anisotropic max.";
1590  default: return "unknown";
1591  }
1592 }
1593 //-----------------------------------------------------------------------------
1594 /*! SLGLTexture::calc3DGradients calculates the normals based on the 3D
1595 gradient of all images and stores them in the RGB components.
1596 @param sampleRadius Distance from center to calculate the gradient
1597 @param onUpdateProgress Callback function for progress display
1598 */
1600  const function<void(int)>& onUpdateProgress)
1601 {
1602  SLint r = sampleRadius;
1603  SLint volX = (SLint)_images[0]->width();
1604  SLint volY = (SLint)_images[0]->height();
1605  SLint volZ = (SLint)_images.size();
1606  SLuint numVoxels = volX * volY * volZ;
1607  SLuint cntVoxels = 0;
1608  SLfloat oneOver255 = 1.0f / 255.0f;
1609 
1610  // check that all images in depth have the same size
1611  for (auto img : _images)
1612  if ((SLint)img->width() != volX ||
1613  (SLint)img->height() != volY ||
1614  img->format() != PF_rgba)
1615  SL_EXIT_MSG("SLGLTexture::calc3DGradients: Not all images have the same size!");
1616 
1617  for (int z = r; z < volZ - r; ++z)
1618  {
1619  for (int y = r; y < volY - r; ++y)
1620  {
1621  for (int x = r; x < volX - r; ++x)
1622  {
1623  // Calculate the min & max vectors
1624  SLVec3f min, max;
1625  min.x = (SLfloat)_images[(SLuint)z]->cvMat().at<cv::Vec4b>(y, x - r)[3] * oneOver255;
1626  max.x = (SLfloat)_images[(SLuint)z]->cvMat().at<cv::Vec4b>(y, x + r)[3] * oneOver255;
1627  min.y = (SLfloat)_images[(SLuint)z]->cvMat().at<cv::Vec4b>(y - r, x)[3] * oneOver255;
1628  max.y = (SLfloat)_images[(SLuint)z]->cvMat().at<cv::Vec4b>(y + r, x)[3] * oneOver255;
1629  min.z = (SLfloat)_images[(SLuint)z - (SLuint)r]->cvMat().at<cv::Vec4b>(y, x)[3] * oneOver255;
1630  max.z = (SLfloat)_images[(SLuint)z + (SLuint)r]->cvMat().at<cv::Vec4b>(y, x)[3] * oneOver255;
1631 
1632  // Calculate normal as the difference between max & min
1633  SLVec3f normal = max - min;
1634  SLfloat length = normal.length();
1635  if (length > 0.0001f)
1636  normal /= length;
1637  else
1638  normal.set(0, 0, 0);
1639 
1640  // Store normal in the rgb channels. Scale range from -1 - 1 to 0 - 1 to 0 - 255
1641  normal += 1.0f;
1642  _images[(SLuint)z]->cvMat().at<cv::Vec4b>(y, x)[0] = (SLuchar)(normal.x * 0.5f * 255.0f);
1643  _images[(SLuint)z]->cvMat().at<cv::Vec4b>(y, x)[1] = (SLuchar)(normal.y * 0.5f * 255.0f);
1644  _images[(SLuint)z]->cvMat().at<cv::Vec4b>(y, x)[2] = (SLuchar)(normal.z * 0.5f * 255.0f);
1645 
1646  // Calculate progress in percent
1647  cntVoxels++;
1648  if (onUpdateProgress)
1649  {
1650  SLint progress = (SLint)((SLfloat)cntVoxels / (SLfloat)numVoxels * 100.0f);
1651  onUpdateProgress(progress);
1652  }
1653  }
1654  }
1655  }
1656 
1657  // Debug check
1658  // for (auto img : _images)
1659  // img->savePNG(img->path() + "Normals_" + img->name());
1660 }
1661 //-----------------------------------------------------------------------------
1662 /*! SLGLTexture::smooth3DGradients smooths the 3D gradients in the RGB channels
1663 of all images.
1664 @param smoothRadius Soothing radius
1665 @param onUpdateProgress Callback function for progress display
1666 */
1668  function<void(int)> onUpdateProgress)
1669 {
1670  SLint r = smoothRadius;
1671  SLint volX = (SLint)_images[0]->width();
1672  SLint volY = (SLint)_images[0]->height();
1673  SLint volZ = (SLint)_images.size();
1674  SLuint numVoxels = volX * volY * volZ;
1675  SLuint cntVoxels = 0;
1676  SLfloat oneOver255 = 1.0f / 255.0f;
1677 
1678  // check that all images in depth have the same size
1679  for (auto img : _images)
1680  if ((SLint)img->width() != volX ||
1681  (SLint)img->height() != volY || img->format() != PF_rgba)
1682  SL_EXIT_MSG("SLGLTexture::calc3DGradients: Not all images have the same size3@!");
1683 
1684  //@todo This is very slow and should be implemented as separable filter
1685  for (int z = r; z < volZ - r; ++z)
1686  {
1687  for (int y = r; y < volY - r; ++y)
1688  {
1689  for (int x = r; x < volX - r; ++x)
1690  {
1691  SLVec3f filtered(0, 0, 0);
1692 
1693  // box filter (= average)
1694  SLint num = 0;
1695  for (int fz = z - r; fz <= z + r; ++fz)
1696  {
1697  for (int fy = y - r; fy <= y + r; ++fy)
1698  {
1699  for (int fx = x - r; fx <= x + r; ++fx)
1700  {
1701  filtered += SLVec3f((SLfloat)_images[(SLuint)fz]->cvMat().at<cv::Vec4b>(fy, fx)[0] * oneOver255 * 2.0f - 1.0f,
1702  (SLfloat)_images[(SLuint)fz]->cvMat().at<cv::Vec4b>(fy, fx)[1] * oneOver255 * 2.0f - 1.0f,
1703  (SLfloat)_images[(SLuint)fz]->cvMat().at<cv::Vec4b>(fy, fx)[2] * oneOver255 * 2.0f - 1.0f);
1704  num++;
1705  }
1706  }
1707  }
1708  filtered /= (SLfloat)num;
1709 
1710  // Store normal in the rgb channels. Scale range from -1 - 1 to 0 - 1 to 0 - 255
1711  filtered += 1.0f;
1712  _images[(SLuint)z]->cvMat().at<cv::Vec4b>(y, x)[0] = (SLuchar)(filtered.x * 0.5f * 255.0f);
1713  _images[(SLuint)z]->cvMat().at<cv::Vec4b>(y, x)[1] = (SLuchar)(filtered.y * 0.5f * 255.0f);
1714  _images[(SLuint)z]->cvMat().at<cv::Vec4b>(y, x)[2] = (SLuchar)(filtered.z * 0.5f * 255.0f);
1715 
1716  // Calculate progress in percent
1717  cntVoxels++;
1718 
1719  if (onUpdateProgress)
1720  {
1721  SLint progress = (SLint)((SLfloat)cntVoxels / (SLfloat)numVoxels * 100.0f);
1722  onUpdateProgress(progress);
1723  }
1724  }
1725  }
1726  }
1727 }
1728 //-----------------------------------------------------------------------------
1729 //! Computes the unnormalised vector x,y,z from tex. coords. uv with cubemap index.
1730 /*! A cube texture indexes six texture maps from 0 to 5 in order Positive X,
1731 Negative X, Positive Y, Negative Y, Positive Z, Negative Z. The images are
1732 stored with the origin at the lower left of the image. The Positive X and Y
1733 faces must reverse the Z coordinate and the Negative Z face must negate the X
1734 coordinate. If given the face, and texture coordinates (u,v), the unnormalized
1735 vector (x,y,z) are computed. Source:\n
1736 https://en.wikipedia.org/wiki/Cube_mapping
1737 */
1739  SLfloat u,
1740  SLfloat v,
1741  SLfloat& x,
1742  SLfloat& y,
1743  SLfloat& z)
1744 {
1745  assert(_images.size() == 6 &&
1746  _target == GL_TEXTURE_CUBE_MAP &&
1747  "SLGLTexture::cubeUV2XYZ: Not a cubemap!");
1748 
1749  // convert range 0 to 1 to -1 to 1
1750  SLfloat uc = 2.0f * u - 1.0f;
1751  SLfloat vc = 2.0f * v - 1.0f;
1752  switch (index)
1753  {
1754  case 0:
1755  x = 1.0f;
1756  y = vc;
1757  z = -uc;
1758  break; // POSITIVE X
1759  case 1:
1760  x = -1.0f;
1761  y = vc;
1762  z = uc;
1763  break; // NEGATIVE X
1764  case 2:
1765  x = uc;
1766  y = 1.0f;
1767  z = -vc;
1768  break; // POSITIVE Y
1769  case 3:
1770  x = uc;
1771  y = -1.0f;
1772  z = vc;
1773  break; // NEGATIVE Y
1774  case 4:
1775  x = uc;
1776  y = vc;
1777  z = 1.0f;
1778  break; // POSITIVE Z
1779  case 5:
1780  x = -uc;
1781  y = vc;
1782  z = -1.0f;
1783  break; // NEGATIVE Z
1784  default:
1785  SL_EXIT_MSG("SLGLTexture::cubeUV2XYZ: Invalid index");
1786  }
1787 }
1788 //------------------------------------------------------------------------------
1789 //! Computes the uv and cubemap image index from a unnormalised vector x,y,z.
1790 /*! See also SLGLTexture::cubeUV2XYZ. Source:\n
1791 https://en.wikipedia.org/wiki/Cube_mapping
1792 */
1794  SLfloat y,
1795  SLfloat z,
1796  SLint& index,
1797  SLfloat& u,
1798  SLfloat& v)
1799 {
1800  assert(_images.size() == 6 &&
1801  _target == GL_TEXTURE_CUBE_MAP &&
1802  "SLGLTexture::cubeXYZ2UV: Not a cubemap!");
1803 
1804  SLfloat absX = fabs(x);
1805  SLfloat absY = fabs(y);
1806  SLfloat absZ = fabs(z);
1807 
1808  SLint isXPositive = x > 0 ? 1 : 0;
1809  SLint isYPositive = y > 0 ? 1 : 0;
1810  SLint isZPositive = z > 0 ? 1 : 0;
1811 
1812  SLfloat maxAxis = 0.0f, uc = 0.0f, vc = 0.0f;
1813 
1814  // POSITIVE X
1815  if (isXPositive && absX >= absY && absX >= absZ)
1816  {
1817  // u (0 to 1) goes from +z to -z
1818  // v (0 to 1) goes from -y to +y
1819  maxAxis = absX;
1820  uc = -z;
1821  vc = y;
1822  index = 0;
1823  }
1824 
1825  // NEGATIVE X
1826  if (!isXPositive && absX >= absY && absX >= absZ)
1827  {
1828  // u (0 to 1) goes from -z to +z
1829  // v (0 to 1) goes from -y to +y
1830  maxAxis = absX;
1831  uc = z;
1832  vc = y;
1833  index = 1;
1834  }
1835 
1836  // POSITIVE Y
1837  if (isYPositive && absY >= absX && absY >= absZ)
1838  {
1839  // u (0 to 1) goes from -x to +x
1840  // v (0 to 1) goes from +z to -z
1841  maxAxis = absY;
1842  uc = x;
1843  vc = -z;
1844  index = 2;
1845  }
1846 
1847  // NEGATIVE Y
1848  if (!isYPositive && absY >= absX && absY >= absZ)
1849  {
1850  // u (0 to 1) goes from -x to +x
1851  // v (0 to 1) goes from -z to +z
1852  maxAxis = absY;
1853  uc = x;
1854  vc = z;
1855  index = 3;
1856  }
1857 
1858  // POSITIVE Z
1859  if (isZPositive && absZ >= absX && absZ >= absY)
1860  {
1861  // u (0 to 1) goes from -x to +x
1862  // v (0 to 1) goes from -y to +y
1863  maxAxis = absZ;
1864  uc = x;
1865  vc = y;
1866  index = 4;
1867  }
1868 
1869  // NEGATIVE Z
1870  if (!isZPositive && absZ >= absX && absZ >= absY)
1871  {
1872  // u (0 to 1) goes from +x to -x
1873  // v (0 to 1) goes from -y to +y
1874  maxAxis = absZ;
1875  uc = -x;
1876  vc = y;
1877  index = 5;
1878  }
1879 
1880  // Convert range from -1 to 1 to 0 to 1
1881  u = 0.5f * (uc / maxAxis + 1.0f);
1882  v = -0.5f * (vc / maxAxis + 1.0f);
1883 }
1884 #ifdef SL_BUILD_WITH_KTX
1885 //------------------------------------------------------------------------------
1886 //! Returns the KTX transcoding compression format as string
1887 string SLGLTexture::compressionFormatStr(int compressionFormat)
1888 {
1889  switch (compressionFormat)
1890  {
1891  case KTX_TTF_ETC1_RGB: return "ETC1_RGB";
1892  case KTX_TTF_ETC2_RGBA: return "ETC2_RGBA";
1893  case KTX_TTF_BC1_RGB: return "BC1_RGB";
1894  case KTX_TTF_BC3_RGBA: return "BC3_RGBA";
1895  case KTX_TTF_BC4_R: return "BC4_R";
1896  case KTX_TTF_BC5_RG: return "BC5_RG";
1897  case KTX_TTF_BC7_RGBA: return "BC7_RGBA";
1898  case KTX_TTF_PVRTC1_4_RGB: return "PVRTC1_4_RGB";
1899  case KTX_TTF_PVRTC1_4_RGBA: return "PVRTC1_4_RGBA";
1900  case KTX_TTF_ASTC_4x4_RGBA: return "ASTC_4x4_RGBA";
1901  case KTX_TTF_PVRTC2_4_RGB: return "PVRTC2_4_RGB";
1902  case KTX_TTF_PVRTC2_4_RGBA: return "PVRTC2_4_RGBA";
1903  case KTX_TTF_ETC2_EAC_R11: return "ETC2_EAC_R11";
1904  case KTX_TTF_ETC2_EAC_RG11: return "ETC2_EAC_RG11";
1905  case KTX_TTF_RGBA32: return "RGBA32";
1906  case KTX_TTF_RGB565: return "RGB565";
1907  case KTX_TTF_BGR565: return "BGR565";
1908  case KTX_TTF_RGBA4444: return "RGBA4444";
1909  case KTX_TTF_ETC: return "ETC";
1910  case KTX_TTF_BC1_OR_3: return "BC1_OR_3";
1911  default: return "NOT_COMPRESSED";
1912  }
1913 }
1914 //------------------------------------------------------------------------------
1915 string SLGLTexture::ktxErrorStr(int ktxErrorCode)
1916 {
1917  switch (ktxErrorCode)
1918  {
1919  case KTX_SUCCESS: return "KTX_SUCCESS";
1920  case KTX_FILE_DATA_ERROR: return "KTX_FILE_DATA_ERROR";
1921  case KTX_FILE_ISPIPE: return "KTX_FILE_ISPIPE";
1922  case KTX_FILE_OPEN_FAILED: return "KTX_FILE_OPEN_FAILED";
1923  case KTX_FILE_OVERFLOW: return "KTX_FILE_OVERFLOW";
1924  case KTX_FILE_READ_ERROR: return "KTX_FILE_READ_ERROR";
1925  case KTX_FILE_SEEK_ERROR: return "KTX_FILE_SEEK_ERROR";
1926  case KTX_FILE_UNEXPECTED_EOF: return "KTX_FILE_UNEXPECTED_EOF";
1927  case KTX_FILE_WRITE_ERROR: return "KTX_FILE_WRITE_ERROR";
1928  case KTX_GL_ERROR: return "KTX_GL_ERROR";
1929  case KTX_INVALID_OPERATION: return "KTX_INVALID_OPERATION";
1930  case KTX_INVALID_VALUE: return "KTX_INVALID_VALUE";
1931  case KTX_NOT_FOUND: return "KTX_NOT_FOUND";
1932  case KTX_OUT_OF_MEMORY: return "KTX_OUT_OF_MEMORY";
1933  case KTX_TRANSCODE_FAILED: return "KTX_TRANSCODE_FAILED";
1934  case KTX_UNKNOWN_FILE_FORMAT: return "KTX_UNKNOWN_FILE_FORMAT";
1935  case KTX_UNSUPPORTED_TEXTURE_TYPE: return "KTX_UNSUPPORTED_TEXTURE_TYPE";
1936  case KTX_UNSUPPORTED_FEATURE: return "KTX_UNSUPPORTED_FEATURE";
1937  case KTX_LIBRARY_NOT_LINKED: return "KTX_LIBRARY_NOT_LINKED";
1938  default: "Unknown KTX_ERROR";
1939  }
1940  return string("Unknown KTX_ERROR");
1941 }
1942 #endif
1943 //------------------------------------------------------------------------------
1944 //! Returns the internal pixel format from OpenGL
1945 /*!
1946  * Taken from https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glTexImage2D.xhtml
1947  */
1948 string SLGLTexture::internalFormatStr(int internalFormat)
1949 {
1950  switch (internalFormat)
1951  {
1952  case GL_DEPTH_COMPONENT: return "GL_DEPTH_COMPONENT";
1953  case GL_DEPTH_STENCIL: return "GL_DEPTH_STENCIL";
1954  case GL_RED: return "GL_RED";
1955  case GL_RG: return "GL_RG";
1956  case GL_RGB: return "GL_RGB";
1957  case GL_RGBA: return "GL_RGBA";
1958  case GL_R8: return "GL_R8";
1959  case GL_R8_SNORM: return "GL_R8_SNORM";
1960  // case GL_R16: return "GL_R16"; // Not available on iOS
1961  // case GL_R16_SNORM: return "GL_R16_SNORM";
1962  case GL_RG8: return "GL_RG8";
1963  case GL_RG8_SNORM: return "GL_RG8_SNORM";
1964  // case GL_RG16: return "GL_RG16";
1965  // case GL_RG16_SNORM: return "GL_RG16_SNORM";
1966  // case GL_R3_G3_B2: return "GL_R3_G3_B2";
1967  // case GL_RGB4: return "GL_RGB4";
1968  // case GL_RGB5: return "GL_RGB5";
1969  // case GL_RGB8: return "GL_RGB8";
1970  case GL_RGB8_SNORM: return "GL_RGB8_SNORM";
1971  // case GL_RGB10: return "GL_RGB10";
1972  // case GL_RGB12: return "GL_RGB12";
1973  // case GL_RGB16_SNORM: return "GL_RGB16_SNORM";
1974  // case GL_RGBA2: return "GL_RGBA2";
1975  // case GL_RGBA4: return "GL_RGBA4";
1976  // case GL_RGB5_A1: return "GL_RGB5_A1";
1977  case GL_RGBA8: return "GL_RGBA8";
1978  case GL_RGBA8_SNORM: return "GL_RGBA8_SNORM";
1979  case GL_RGB10_A2: return "GL_RGB10_A2";
1980  case GL_RGB10_A2UI: return "GL_RGB10_A2UI";
1981  // case GL_RGBA12: return "GL_RGBA12";
1982  // case GL_RGBA16: return "GL_RGBA16";
1983  case GL_SRGB8: return "GL_SRGB8";
1984  case GL_SRGB8_ALPHA8: return "GL_SRGB8_ALPHA8";
1985  case GL_R16F: return "GL_R16F";
1986  case GL_RG16F: return "GL_RG16F";
1987  case GL_RGB16F: return "GL_RGB16F";
1988  case GL_RGBA16F: return "GL_RGBA16F";
1989  case GL_R32F: return "GL_R32F";
1990  case GL_RG32F: return "GL_RG32F";
1991  case GL_RGB32F: return "GL_RGB32F";
1992  case GL_RGBA32F: return "GL_RGBA32F";
1993  case GL_R11F_G11F_B10F: return "GL_R11F_G11F_B10F";
1994  case GL_RGB9_E5: return "GL_RGB9_E5";
1995  case GL_R8I: return "GL_R8I";
1996  case GL_R8UI: return "GL_R8UI";
1997  case GL_R16I: return "GL_R16I";
1998  case GL_R16UI: return "GL_R16UI";
1999  case GL_R32I: return "GL_R32I";
2000  case GL_R32UI: return "GL_R32UI";
2001  case GL_RG8I: return "GL_RG8I";
2002  case GL_RG8UI: return "GL_RG8UI";
2003  case GL_RG16I: return "GL_RG16I";
2004  case GL_RG16UI: return "GL_RG16UI";
2005  case GL_RG32I: return "GL_RG32I";
2006  case GL_RG32UI: return "GL_RG32UI";
2007  case GL_RGB8I: return "GL_RGB8I";
2008  case GL_RGB8UI: return "GL_RGB8UI";
2009  case GL_RGB16I: return "GL_RGB16I";
2010  case GL_RGB16UI: return "GL_RGB16UI";
2011  case GL_RGB32I: return "GL_RGB32I";
2012  case GL_RGB32UI: return "GL_RGB32UI";
2013  case GL_RGBA8I: return "GL_RGBA8I";
2014  case GL_RGBA8UI: return "GL_RGBA8UI";
2015  case GL_RGBA16I: return "GL_RGBA16I";
2016  case GL_RGBA16UI: return "GL_RGBA16UI";
2017  case GL_RGBA32I: return "GL_RGBA32I";
2018  case GL_RGBA32UI: return "GL_RGBA32UI";
2019  // case GL_COMPRESSED_RED: return "GL_COMPRESSED_RED";
2020  // case GL_COMPRESSED_RG: return "GL_COMPRESSED_RG";
2021  // case GL_COMPRESSED_RGB: return "GL_COMPRESSED_RGB";
2022  // case GL_COMPRESSED_RGBA: return "GL_COMPRESSED_RGBA";
2023  // case GL_COMPRESSED_SRGB: return "GL_COMPRESSED_SRGB";
2024  // case GL_COMPRESSED_SRGB_ALPHA: return "GL_COMPRESSED_SRGB_ALPHA";
2025  // case GL_COMPRESSED_RED_RGTC1: return "GL_COMPRESSED_RED_RGTC1";
2026  // case GL_COMPRESSED_SIGNED_RED_RGTC1: return "GL_COMPRESSED_SIGNED_RED_RGTC1";
2027  // case GL_COMPRESSED_RG_RGTC2: return "GL_COMPRESSED_RG_RGTC2";
2028  // case GL_COMPRESSED_SIGNED_RG_RGTC2: return "GL_COMPRESSED_SIGNED_RG_RGTC2";
2029  // case GL_COMPRESSED_RGBA_BPTC_UNORM: return "GL_COMPRESSED_RGBA_BPTC_UNORM";
2030  // case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: return "GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM";
2031  // case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: return "GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT";
2032  // case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: return "GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT";
2033  default: return "Unknown format";
2034  }
2035 }
2036 //------------------------------------------------------------------------------
CVPixelFormatGL
Pixel format according to OpenGL pixel format defines.
Definition: CVImage.h:24
@ PF_red
Definition: CVImage.h:34
@ PF_rgb
Definition: CVImage.h:36
@ PF_rgba
Definition: CVImage.h:37
cv::Vec4f CVVec4f
Definition: CVTypedefs.h:54
vector< cv::Vec4f > CVVVec4f
Definition: CVTypedefs.h:86
#define PROFILE_FUNCTION()
Definition: Instrumentor.h:41
float SLfloat
Definition: SL.h:173
unsigned int SLenum
Definition: SL.h:176
#define SL_LOG(...)
Definition: SL.h:233
unsigned int SLuint
Definition: SL.h:171
#define SL_WARN_MSG(message)
Definition: SL.h:241
unsigned char SLuchar
Definition: SL.h:163
vector< SLuchar > SLVuchar
Definition: SL.h:193
bool SLbool
Definition: SL.h:175
vector< SLstring > SLVstring
Definition: SL.h:201
#define SL_EXIT_MSG(message)
Definition: SL.h:240
vector< SLushort > SLVushort
Definition: SL.h:195
int SLsizei
Definition: SL.h:172
string SLstring
Definition: SL.h:158
int SLint
Definition: SL.h:170
@ IOK_image
Definition: SLFileStorage.h:40
@ AT_position
Vertex position as a 2, 3 or 4 component vectors.
Definition: SLGLEnums.h:58
@ AT_uv1
Vertex 1st texture coordinate as 2 component vector.
Definition: SLGLEnums.h:60
@ PT_triangleStrip
Definition: SLGLEnums.h:36
@ SP_textureOnly
Singleton class for global render state.
#define GET_GL_ERROR
Definition: SLGLState.h:56
#define GL_TEXTURE_MAX_ANISOTROPY_EXT
Definition: SLGLTexture.h:43
SLTextureType
Texture type enumeration & their filename appendix for auto type detection.
Definition: SLGLTexture.h:76
@ TT_occluRoughMetal
Definition: SLGLTexture.h:87
@ TT_brdfLUT
Definition: SLGLTexture.h:93
@ TT_height
Definition: SLGLTexture.h:80
@ TT_videoBkgd
Definition: SLGLTexture.h:94
@ TT_metallic
Definition: SLGLTexture.h:85
@ TT_unknown
Definition: SLGLTexture.h:77
@ TT_irradianceCubemap
Definition: SLGLTexture.h:91
@ TT_environmentCubemap
Definition: SLGLTexture.h:90
@ TT_roughnessCubemap
Definition: SLGLTexture.h:92
@ TT_roughMetal
Definition: SLGLTexture.h:86
@ TT_roughness
Definition: SLGLTexture.h:84
@ TT_specular
Definition: SLGLTexture.h:81
@ TT_normal
Definition: SLGLTexture.h:79
@ TT_diffuse
Definition: SLGLTexture.h:78
@ TT_occlusion
Definition: SLGLTexture.h:83
@ TT_hdr
Definition: SLGLTexture.h:89
@ TT_emissive
Definition: SLGLTexture.h:82
@ TT_font
Definition: SLGLTexture.h:88
#define SL_HDR_GL_INTERNAL_FORMAT
Definition: SLGLTexture.h:51
#define SL_ANISOTROPY_MAX
Definition: SLGLTexture.h:34
#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
Definition: SLGLTexture.h:46
#define SL_HDR_GL_TYPE
Definition: SLGLTexture.h:53
vector< SLVec2f > SLVVec2f
Definition: SLVec2.h:143
SLVec3< SLfloat > SLVec3f
Definition: SLVec3.h:318
vector< SLCol4f > SLVCol4f
Definition: SLVec4.h:241
SLVec4< SLfloat > SLCol4f
Definition: SLVec4.h:237
OpenCV image class with the same interface as the former SLImage class.
Definition: CVImage.h:64
void resize(int width, int height)
Definition: CVImage.cpp:938
uint width()
Definition: CVImage.h:125
uchar * data()
Definition: CVImage.h:123
CVPixelFormatGL format()
Definition: CVImage.h:131
uint bytesPerPixel()
Definition: CVImage.h:127
uint height()
Definition: CVImage.h:126
void load(const string &filename, bool flipVertical=true, bool loadGrayscaleIntoAlpha=false)
Loads the image with the appropriate image loader.
Definition: CVImage.cpp:379
Toplevel holder of the assets meshes, materials, textures and shaders.
SLVGLTexture & textures()
Encapsulation of an OpenGL shader program object.
Definition: SLGLProgram.h:56
SLint uniformMatrix4fv(const SLchar *name, SLsizei count, const SLfloat *value, GLboolean transpose=false) const
Passes a 4x4 float matrix values py pointer to the uniform variable "name".
SLint uniform1f(const SLchar *name, SLfloat v0) const
Passes the float value v0 to the uniform variable "name".
void useProgram()
SLint uniform1i(const SLchar *name, SLint v0) const
Passes the int values v0 to the uniform variable "name".
static SLGLProgramGeneric * get(SLStdShaderProg id)
Get program reference for given id.
Singleton class holding all OpenGL states.
Definition: SLGLState.h:71
void activeTexture(SLenum textureUnit)
Definition: SLGLState.cpp:445
SLMat4f modelMatrix
Init all states.
Definition: SLGLState.h:89
static SLGLState * instance()
Public static instance getter for singleton pattern.
Definition: SLGLState.h:74
SLMat4f viewMatrix
matrix for the active cameras view transform
Definition: SLGLState.h:91
SLbool hasExtension(const SLstring &e)
Definition: SLGLState.h:141
SLbool glIsES3() const
Definition: SLGLState.h:136
SLfloat glVersionNOf() const
Definition: SLGLState.h:129
SLbool glIsES2() const
Definition: SLGLState.h:135
void bindTexture(SLenum target, SLuint textureID)
Definition: SLGLState.cpp:423
SLMat4f projectionMatrix
matrix for projection transform
Definition: SLGLState.h:90
SLbool _resizeToPow2
Flag if image should be resized to n^2.
Definition: SLGLTexture.h:321
SLint bytesPerPixel()
Definition: SLGLTexture.h:222
void deleteImages()
Deletes the CVImages in _images. No more texture mapping in ray tracing.
void build2DMipmaps(SLint target, SLuint index)
static string internalFormatStr(int internalFormat)
Returns the internal pixel format from OpenGL.
SLint _bytesPerPixel
Bytes per texture image pixel (images exist either in _images or on the GPU or on both)
Definition: SLGLTexture.h:310
SLint _width
Texture image width in pixels (images exist either in _images or on the GPU or on both)
Definition: SLGLTexture.h:305
SLfloat _bumpScale
Bump mapping scale factor.
Definition: SLGLTexture.h:320
SLuint height()
Definition: SLGLTexture.h:219
void cubeXYZ2UV(SLfloat x, SLfloat y, SLfloat z, SLint &index, SLfloat &u, SLfloat &v)
Computes the uv and cubemap image index from a unnormalised vector x,y,z.
SLuint _bytesOnGPU
NO. of bytes on GPU.
Definition: SLGLTexture.h:317
SLMat4f _tm
texture matrix
Definition: SLGLTexture.h:316
SLenum target() const
Definition: SLGLTexture.h:226
SLuint width()
Definition: SLGLTexture.h:218
SLint _wrap_t
Wrapping in t direction.
Definition: SLGLTexture.h:314
SLVec2f dudv(SLfloat u, SLfloat v)
SLint _min_filter
Minification filter.
Definition: SLGLTexture.h:311
void load(const SLstring &filename, SLbool flipVertical=true, SLbool loadGrayscaleIntoAlpha=false)
Loads the texture, converts color depth & applies vertical mirroring.
SLint _wrap_s
Wrapping in s direction.
Definition: SLGLTexture.h:313
static SLfloat maxAnisotropy
Returns the derivation as [s,t].
Definition: SLGLTexture.h:292
SLbool _deleteImageAfterBuild
Flag if images should be deleted after build on GPU.
Definition: SLGLTexture.h:326
SLint _height
Texture image height in pixels (images exist either in _images or on the GPU or on both)
Definition: SLGLTexture.h:306
SLTextureType _texType
See SLTextureType.
Definition: SLGLTexture.h:304
~SLGLTexture() override
void deleteData(SLbool deleteAlsoOnGPU)
Delete all data (CVImages and GPU textures)
CVVImage _images
Vector of CVImage pointers.
Definition: SLGLTexture.h:302
SLint _depth
3D Texture image depth (images exist either in _images or on the GPU or on both)
Definition: SLGLTexture.h:307
SLbyte _uvIndex
Texture coordinate index in SLMesh (0 = default)
Definition: SLGLTexture.h:308
SLstring typeShortName()
Returns the texture type short.
virtual void build(SLint texUnit)
SLenum _target
texture target
Definition: SLGLTexture.h:315
void cubeUV2XYZ(SLint index, SLfloat u, SLfloat v, SLfloat &x, SLfloat &y, SLfloat &z)
Computes the unnormalised vector x,y,z from tex. coords. uv with cubemap index.
SLstring typeName()
Returns the texture type as string.
std::atomic< bool > _needsUpdate
Flag if image needs an single update.
Definition: SLGLTexture.h:323
SLint _internalFormat
Internal OpenGL format.
Definition: SLGLTexture.h:309
static SLTextureType detectType(const SLstring &filename)
Detects the texture type from the filename appendix (See SLTexType def.)
SLGLTexture()
Default ctor for all stack instances (not created with new)
Definition: SLGLTexture.cpp:37
SLuint depth()
Definition: SLGLTexture.h:220
void calc3DGradients(SLint sampleRadius, const function< void(int)> &onUpdateProgress=nullptr)
void deleteDataGpu()
Deletes the OpenGL texture objects and releases the memory on the GPU.
SLbool _compressedTexture
True for compressed texture format on GPU.
Definition: SLGLTexture.h:327
SLuint _bytesInFile
NO. of bytes in file.
Definition: SLGLTexture.h:318
SLint _mag_filter
Magnification filter.
Definition: SLGLTexture.h:312
SLstring filterString(SLint glFilter)
Returns OpenGL texture filter as string.
void smooth3DGradients(SLint smoothRadius, function< void(int)> onUpdateProgress=nullptr)
static SLuint totalNumBytesOnGPU
Total NO. of bytes used for textures on GPU.
Definition: SLGLTexture.h:293
void fullUpdate()
void bindActive(SLuint texUnit=0)
SLbool _autoCalcTM3D
Flag if texture matrix should be calculated from AABB for 3D mapping.
Definition: SLGLTexture.h:319
SLGLVertexArray _vaoSprite
Vertex array object for sprite rendering.
Definition: SLGLTexture.h:322
void drawSprite(SLbool doUpdate, SLfloat x, SLfloat y, SLfloat w, SLfloat h)
Draws the texture as 2D sprite with OpenGL buffers.
SLbool copyVideoImage(SLint camWidth, SLint camHeight, CVPixelFormatGL glFormat, SLuchar *data, SLbool isContinuous, SLbool isTopLeft)
Copies the image data from a video camera into the current video image.
SLuint _texID
OpenGL texture ID.
Definition: SLGLTexture.h:303
SLCol4f getTexelf(SLfloat u, SLfloat v, SLuint imgIndex=0)
SLGLTexture::getTexelf returns a pixel color from u & v texture coordinates.
void clearAttribs()
Clears the attribute definition.
void drawElementsAs(SLGLPrimitiveType primitiveType, SLuint numIndexes=0, SLuint indexOffsetBytes=0)
Draws the VAO by element indices with a primitive type.
void setAttrib(SLGLAttributeType type, SLint elementSize, SLint location, void *dataPointer, SLGLBufferType dataType=BT_float)
Adds a vertex attribute with data pointer and an element size.
SLuint vaoID() const
Returns either the VAO id or the VBO id.
void setIndices(SLuint numIndicesElements, SLGLBufferType indexDataType, void *indexDataElements, SLuint numIndicesEdges=0, void *indexDataEdges=nullptr)
Adds the index array for indexed element drawing.
void generate(SLuint numVertices, SLGLBufferUsage usage=BU_static, SLbool outputInterleaved=true, SLuint divisor=0)
Generates the VA & VB objects for a NO. of vertices.
void m(int i, T val)
Definition: SLMat4.h:93
Base class for all other classes.
Definition: SLObject.h:23
const SLstring & name() const
Definition: SLObject.h:38
T y
Definition: SLVec2.h:30
T x
Definition: SLVec2.h:30
T y
Definition: SLVec3.h:43
T x
Definition: SLVec3.h:43
T length() const
Definition: SLVec3.h:122
T z
Definition: SLVec3.h:43
static SLVec4 BLACK
Definition: SLVec4.h:213
T g
Definition: SLVec4.h:33
T r
Definition: SLVec4.h:33
T x
Definition: SLVec4.h:32
SLIOBuffer readIntoBuffer(std::string path, SLIOStreamKind kind)
Reads an entire file into memory.
bool exists(std::string path, SLIOStreamKind kind)
Checks whether a given file exists.
Utils provides utilities for string & file handling, logging and math functions.
Definition: Averaged.h:22
bool containsString(const string &container, const string &search)
Returns true if container contains the search string.
Definition: Utils.cpp:345
string getFileNameWOExt(const string &pathFilename)
Returns the filename without extension.
Definition: Utils.cpp:616
unsigned int getFileSize(const string &pathfilename)
Returns the file size in bytes.
Definition: Utils.cpp:912
string getFileName(const string &pathFilename)
Returns the filename of path-filename string.
Definition: Utils.cpp:580
T floor(T a)
Definition: Utils.h:246
string toUpperString(string s)
Returns a string in upper case.
Definition: Utils.cpp:120
unsigned closestPowerOf2(unsigned num)
Returns the closest power of 2 to a passed number.
Definition: Utils.cpp:1221
string getFileExt(const string &filename)
Returns the file extension without dot in lower case.
Definition: Utils.cpp:629
Utility struct that holds a pointer and its length.
Definition: SLFileStorage.h:28
size_t size
Definition: SLFileStorage.h:30
unsigned char * data
Definition: SLFileStorage.h:29