CTexture.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. #include "CTexture.h"
  2. #include "WallpaperEngine/Logging/Log.h"
  3. #include <cstring>
  4. #include <lz4.h>
  5. #include <string>
  6. #define STB_IMAGE_IMPLEMENTATION
  7. #include <stb_image.h>
  8. using namespace WallpaperEngine::Render;
  9. CTexture::CTexture (TextureUniquePtr header) : m_header (std::move(header)) {
  10. // ensure the header is parsed
  11. this->setupResolution ();
  12. const GLint internalFormat = this->setupInternalFormat();
  13. // allocate texture ids list
  14. this->m_textureID = new GLuint [this->m_header->imageCount];
  15. // ask opengl for the correct amount of textures
  16. glGenTextures (this->m_header->imageCount, this->m_textureID);
  17. for (const auto& [index, mipmaps] : this->m_header->images) {
  18. this->setupOpenGLParameters (index);
  19. int level = 0;
  20. for (const auto& mipmap : mipmaps) {
  21. stbi_uc* handle = nullptr;
  22. const void* dataptr = mipmap->uncompressedData.get ();
  23. int width = mipmap->width;
  24. int height = mipmap->height;
  25. const uint32_t bufferSize = mipmap->uncompressedSize;
  26. GLenum textureFormat = GL_RGBA;
  27. if (this->m_header->freeImageFormat != FIF_UNKNOWN) {
  28. int fileChannels;
  29. dataptr = handle = stbi_load_from_memory (
  30. reinterpret_cast <unsigned char*> (mipmap->uncompressedData.get ()),
  31. mipmap->uncompressedSize,
  32. &width,
  33. &height,
  34. &fileChannels,
  35. 4);
  36. } else {
  37. if (this->m_header->format == TextureFormat_R8) {
  38. // red textures are 1-byte-per-pixel, so it's alignment has to be set manually
  39. glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
  40. textureFormat = GL_RED;
  41. } else if (this->m_header->format == TextureFormat_RG88) {
  42. textureFormat = GL_RG;
  43. }
  44. }
  45. switch (internalFormat) {
  46. case GL_RGBA8:
  47. case GL_RG8:
  48. case GL_R8:
  49. glTexImage2D (
  50. GL_TEXTURE_2D, level, internalFormat, width, height, 0, textureFormat,
  51. GL_UNSIGNED_BYTE, dataptr);
  52. break;
  53. case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
  54. case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
  55. case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
  56. glCompressedTexImage2D (
  57. GL_TEXTURE_2D, level, internalFormat, width, height, 0, bufferSize,
  58. dataptr);
  59. break;
  60. default: sLog.exception ("Cannot load texture, unknown format", this->m_header->format);
  61. }
  62. // stbi_image buffer won't be used anymore, so free memory
  63. if (this->m_header->freeImageFormat != FIF_UNKNOWN) {
  64. stbi_image_free (handle);
  65. }
  66. level ++;
  67. }
  68. }
  69. }
  70. void CTexture::setupResolution () {
  71. if (this->isAnimated ()) {
  72. this->m_resolution = {
  73. this->m_header->textureWidth, this->m_header->textureHeight,
  74. this->m_header->gifWidth, this->m_header->gifHeight
  75. };
  76. } else {
  77. if (this->m_header->freeImageFormat != FIF_UNKNOWN) {
  78. // wpengine-texture format always has one mipmap
  79. // get first image size
  80. const auto element = this->m_header->images.find (0)->second.begin ();
  81. // set the texture resolution
  82. this->m_resolution = {
  83. (*element)->width, (*element)->height,
  84. this->m_header->width, this->m_header->height
  85. };
  86. } else {
  87. // set the texture resolution
  88. this->m_resolution = {
  89. this->m_header->textureWidth, this->m_header->textureHeight,
  90. this->m_header->width, this->m_header->height
  91. };
  92. }
  93. }
  94. }
  95. GLint CTexture::setupInternalFormat () const {
  96. if (this->m_header->freeImageFormat != FIF_UNKNOWN) {
  97. return GL_RGBA8;
  98. }
  99. // detect the image format and hand it to openGL to be used
  100. switch (this->m_header->format) {
  101. case TextureFormat_DXT5:
  102. return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
  103. case TextureFormat_DXT3:
  104. return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
  105. case TextureFormat_DXT1:
  106. return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
  107. case TextureFormat_ARGB8888:
  108. return GL_RGBA8;
  109. case TextureFormat_R8:
  110. return GL_R8;
  111. case TextureFormat_RG88:
  112. return GL_RG8;
  113. default:
  114. sLog.exception ("Cannot determine texture format");
  115. }
  116. }
  117. void CTexture::setupOpenGLParameters (const uint32_t textureID) const {
  118. // bind the texture to assign information to it
  119. glBindTexture (GL_TEXTURE_2D, this->m_textureID [textureID]);
  120. // set mipmap levels
  121. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
  122. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, this->m_header->images [textureID].size () - 1);
  123. // setup texture wrapping and filtering
  124. if (this->m_header->flags & TextureFlags_ClampUVs) {
  125. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  126. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  127. } else {
  128. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  129. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  130. }
  131. if (this->m_header->flags & TextureFlags_NoInterpolation) {
  132. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  133. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
  134. } else {
  135. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  136. glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  137. }
  138. glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, 8.0f);
  139. }
  140. GLuint CTexture::getTextureID (const uint32_t imageIndex) const {
  141. // ensure we do not go out of bounds
  142. if (imageIndex >= this->m_header->imageCount)
  143. return this->m_textureID [0];
  144. return this->m_textureID [imageIndex];
  145. }
  146. uint32_t CTexture::getTextureWidth (const uint32_t imageIndex) const {
  147. if (imageIndex >= this->m_header->imageCount)
  148. return this->getHeader ().textureWidth;
  149. return (*this->m_header->images [imageIndex].begin ())->width;
  150. }
  151. uint32_t CTexture::getTextureHeight (const uint32_t imageIndex) const {
  152. if (imageIndex >= this->m_header->imageCount)
  153. return this->getHeader ().textureHeight;
  154. return (*this->m_header->images [imageIndex].begin ())->height;
  155. }
  156. uint32_t CTexture::getRealWidth () const {
  157. return this->isAnimated () ? this->getHeader ().gifWidth : this->getHeader ().width;
  158. }
  159. uint32_t CTexture::getRealHeight () const {
  160. return this->isAnimated () ? this->getHeader ().gifHeight : this->getHeader ().height;
  161. }
  162. TextureFormat CTexture::getFormat () const {
  163. return this->getHeader ().format;
  164. }
  165. uint32_t CTexture::getFlags () const {
  166. return this->getHeader ().flags;
  167. }
  168. const Texture& CTexture::getHeader () const {
  169. return *this->m_header;
  170. }
  171. const glm::vec4* CTexture::getResolution () const {
  172. return &this->m_resolution;
  173. }
  174. const std::vector<FrameSharedPtr>& CTexture::getFrames () const {
  175. return this->getHeader ().frames;
  176. }
  177. bool CTexture::isAnimated () const {
  178. return this->getHeader ().isAnimated ();
  179. }
  180. uint32_t CTexture::getSpritesheetCols () const {
  181. return this->getHeader ().spritesheetCols;
  182. }
  183. uint32_t CTexture::getSpritesheetRows () const {
  184. return this->getHeader ().spritesheetRows;
  185. }
  186. uint32_t CTexture::getSpritesheetFrames () const {
  187. return this->getHeader ().spritesheetFrames;
  188. }
  189. float CTexture::getSpritesheetDuration () const {
  190. return this->getHeader ().spritesheetDuration;
  191. }