💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

267 lines
9.6 KiB

  1. /*
  2. * Copyright (C) 2021 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "gl/texture.hpp"
  20. #include "gl/texture-wrapping.hpp"
  21. #include "gl/texture-filter.hpp"
  22. #include <glad/glad.h>
  23. #include <algorithm>
  24. namespace gl {
  25. static constexpr GLenum pixel_format_lut[] =
  26. {
  27. GL_DEPTH_COMPONENT,
  28. GL_DEPTH_STENCIL,
  29. GL_RED,
  30. GL_RG,
  31. GL_RGB,
  32. GL_BGR,
  33. GL_RGBA,
  34. GL_BGRA
  35. };
  36. static constexpr GLenum pixel_type_lut[] =
  37. {
  38. GL_BYTE,
  39. GL_UNSIGNED_BYTE,
  40. GL_SHORT,
  41. GL_UNSIGNED_SHORT,
  42. GL_INT,
  43. GL_UNSIGNED_INT,
  44. GL_HALF_FLOAT,
  45. GL_FLOAT
  46. };
  47. static constexpr GLenum linear_internal_format_lut[][8] =
  48. {
  49. {GL_NONE, GL_NONE, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT32, GL_NONE, GL_DEPTH_COMPONENT32F},
  50. // Note: GL_DEPTH32F_STENCIL8 is actually a 64-bit format, 32 depth bits, 8 stencil bits, and 24 alignment bits.
  51. {GL_NONE, GL_NONE, GL_NONE, GL_NONE, GL_DEPTH24_STENCIL8, GL_DEPTH24_STENCIL8, GL_NONE, GL_DEPTH32F_STENCIL8},
  52. {GL_R8, GL_R8, GL_R16, GL_R16, GL_R32F, GL_R32F, GL_R16F, GL_R32F},
  53. {GL_RG8, GL_RG8, GL_RG16, GL_RG16, GL_RG32F, GL_RG32F, GL_RG16F, GL_RG32F},
  54. {GL_RGB8, GL_RGB8, GL_RGB16, GL_RGB16, GL_RGB32F, GL_RGB32F, GL_RGB16F, GL_RGB32F},
  55. {GL_RGB8, GL_RGB8, GL_RGB16, GL_RGB16, GL_RGB32F, GL_RGB32F, GL_RGB16F, GL_RGB32F},
  56. {GL_RGBA8, GL_RGBA8, GL_RGBA16, GL_RGBA16, GL_RGBA32F, GL_RGBA32F, GL_RGBA16F, GL_RGBA32F},
  57. {GL_RGBA8, GL_RGBA8, GL_RGBA16, GL_RGBA16, GL_RGBA32F, GL_RGBA32F, GL_RGBA16F, GL_RGBA32F}
  58. };
  59. static constexpr GLenum srgb_internal_format_lut[][8] =
  60. {
  61. {GL_NONE, GL_NONE, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT32, GL_NONE, GL_DEPTH_COMPONENT32F},
  62. {GL_NONE, GL_NONE, GL_NONE, GL_NONE, GL_DEPTH24_STENCIL8, GL_DEPTH24_STENCIL8, GL_NONE, GL_DEPTH32F_STENCIL8},
  63. {GL_SRGB8, GL_SRGB8, GL_R16, GL_R16, GL_R32F, GL_R32F, GL_R16F, GL_R32F},
  64. {GL_SRGB8, GL_SRGB8, GL_RG16, GL_RG16, GL_RG32F, GL_RG32F, GL_RG16F, GL_RG32F},
  65. {GL_SRGB8, GL_SRGB8, GL_RGB16, GL_RGB16, GL_RGB32F, GL_RGB32F, GL_RGB16F, GL_RGB32F},
  66. {GL_SRGB8, GL_SRGB8, GL_RGB16, GL_RGB16, GL_RGB32F, GL_RGB32F, GL_RGB16F, GL_RGB32F},
  67. {GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_RGBA16, GL_RGBA16, GL_RGBA32F, GL_RGBA32F, GL_RGBA16F, GL_RGBA32F},
  68. {GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_RGBA16, GL_RGBA16, GL_RGBA32F, GL_RGBA32F, GL_RGBA16F, GL_RGBA32F}
  69. };
  70. static constexpr GLint swizzle_mask_lut[][4] =
  71. {
  72. {GL_RED, GL_RED, GL_RED, GL_ONE},
  73. {GL_RED, GL_GREEN, GL_ZERO, GL_ONE},
  74. {GL_RED, GL_RED, GL_RED, GL_ONE},
  75. {GL_RED, GL_RED, GL_RED, GL_GREEN},
  76. {GL_RED, GL_GREEN, GL_BLUE, GL_ONE},
  77. {GL_RED, GL_GREEN, GL_BLUE, GL_ONE},
  78. {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA},
  79. {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}
  80. };
  81. static constexpr GLenum wrapping_lut[] =
  82. {
  83. GL_CLAMP_TO_BORDER,
  84. GL_CLAMP_TO_EDGE,
  85. GL_REPEAT,
  86. GL_MIRRORED_REPEAT
  87. };
  88. static constexpr GLenum min_filter_lut[] =
  89. {
  90. GL_NEAREST,
  91. GL_LINEAR,
  92. GL_NEAREST_MIPMAP_NEAREST,
  93. GL_LINEAR_MIPMAP_NEAREST,
  94. GL_NEAREST_MIPMAP_LINEAR,
  95. GL_LINEAR_MIPMAP_LINEAR
  96. };
  97. static constexpr GLenum mag_filter_lut[] =
  98. {
  99. GL_NEAREST,
  100. GL_LINEAR
  101. };
  102. texture::texture(std::uint16_t width, std::uint16_t height, std::uint16_t depth, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const void* data):
  103. gl_texture_target((depth) ? GL_TEXTURE_3D : (height) ? GL_TEXTURE_2D : GL_TEXTURE_1D),
  104. gl_texture_id(0),
  105. dimensions({0, 0, 0}),
  106. wrapping({texture_wrapping::repeat, texture_wrapping::repeat, texture_wrapping::repeat}),
  107. filters({texture_min_filter::linear_mipmap_linear, texture_mag_filter::linear}),
  108. max_anisotropy(0.0f)
  109. {
  110. glGenTextures(1, &gl_texture_id);
  111. resize(width, height, depth, type, format, color_space, data);
  112. set_wrapping(wrapping[0], wrapping[1], wrapping[2]);
  113. set_filters(std::get<0>(filters), std::get<1>(filters));
  114. set_max_anisotropy(max_anisotropy);
  115. }
  116. texture::texture(std::uint16_t width, std::uint16_t height, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const void* data):
  117. texture(width, height, 0, type, format, color_space, data)
  118. {}
  119. texture::texture(std::uint16_t width, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const void* data):
  120. texture(width, 0, 0, type, format, color_space, data)
  121. {}
  122. texture::~texture()
  123. {
  124. glDeleteTextures(1, &gl_texture_id);
  125. }
  126. void texture::set_filters(texture_min_filter min_filter, texture_mag_filter mag_filter)
  127. {
  128. filters = {min_filter, mag_filter};
  129. GLenum gl_min_filter = min_filter_lut[static_cast<std::size_t>(min_filter)];
  130. GLenum gl_mag_filter = mag_filter_lut[static_cast<std::size_t>(mag_filter)];
  131. glBindTexture(gl_texture_target, gl_texture_id);
  132. glTexParameteri(gl_texture_target, GL_TEXTURE_MIN_FILTER, gl_min_filter);
  133. glTexParameteri(gl_texture_target, GL_TEXTURE_MAG_FILTER, gl_mag_filter);
  134. }
  135. void texture::set_max_anisotropy(float anisotropy)
  136. {
  137. max_anisotropy = std::max<float>(0.0f, std::min<float>(1.0f, anisotropy));
  138. // Get the maximum supported anisotropy value
  139. float gl_max_texture_max_anisotropy;
  140. glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gl_max_texture_max_anisotropy);
  141. // Lerp between 1.0 and GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
  142. float gl_max_anisotropy = 1.0f + max_anisotropy * (gl_max_texture_max_anisotropy - 1.0f);
  143. glBindTexture(gl_texture_target, gl_texture_id);
  144. glTexParameterf(gl_texture_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_max_anisotropy);
  145. }
  146. void texture::set_wrapping(gl::texture_wrapping wrap_s, gl::texture_wrapping wrap_t, gl::texture_wrapping wrap_r)
  147. {
  148. wrapping = {wrap_s, wrap_t, wrap_r};
  149. GLenum gl_wrap_s = wrapping_lut[static_cast<std::size_t>(wrap_s)];
  150. GLenum gl_wrap_t = wrapping_lut[static_cast<std::size_t>(wrap_t)];
  151. GLenum gl_wrap_r = wrapping_lut[static_cast<std::size_t>(wrap_r)];
  152. glBindTexture(gl_texture_target, gl_texture_id);
  153. glTexParameteri(gl_texture_target, GL_TEXTURE_WRAP_S, gl_wrap_s);
  154. glTexParameteri(gl_texture_target, GL_TEXTURE_WRAP_T, gl_wrap_t);
  155. glTexParameteri(gl_texture_target, GL_TEXTURE_WRAP_R, gl_wrap_r);
  156. }
  157. void texture::set_wrapping(gl::texture_wrapping wrap_s, gl::texture_wrapping wrap_t)
  158. {
  159. std::get<0>(wrapping) = wrap_s;
  160. std::get<1>(wrapping) = wrap_t;
  161. GLenum gl_wrap_s = wrapping_lut[static_cast<std::size_t>(wrap_s)];
  162. GLenum gl_wrap_t = wrapping_lut[static_cast<std::size_t>(wrap_t)];
  163. glBindTexture(gl_texture_target, gl_texture_id);
  164. glTexParameteri(gl_texture_target, GL_TEXTURE_WRAP_S, gl_wrap_s);
  165. glTexParameteri(gl_texture_target, GL_TEXTURE_WRAP_T, gl_wrap_t);
  166. }
  167. void texture::set_wrapping(gl::texture_wrapping wrap_s)
  168. {
  169. std::get<0>(wrapping) = wrap_s;
  170. GLenum gl_wrap_s = wrapping_lut[static_cast<std::size_t>(wrap_s)];
  171. glBindTexture(gl_texture_target, gl_texture_id);
  172. glTexParameteri(gl_texture_target, GL_TEXTURE_WRAP_S, gl_wrap_s);
  173. }
  174. void texture::resize(std::uint16_t width, std::uint16_t height, std::uint16_t depth, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const void* data)
  175. {
  176. dimensions = {width, height, depth};
  177. pixel_type = type;
  178. pixel_format = format;
  179. this->color_space = color_space;
  180. GLenum gl_internal_format;
  181. if (color_space == gl::color_space::srgb)
  182. {
  183. gl_internal_format = srgb_internal_format_lut[static_cast<std::size_t>(format)][static_cast<std::size_t>(type)];
  184. }
  185. else
  186. {
  187. gl_internal_format = linear_internal_format_lut[static_cast<std::size_t>(format)][static_cast<std::size_t>(type)];
  188. }
  189. GLenum gl_format = pixel_format_lut[static_cast<std::size_t>(format)];
  190. const GLint* gl_swizzle_mask = swizzle_mask_lut[static_cast<std::size_t>(format)];
  191. GLenum gl_type = pixel_type_lut[static_cast<std::size_t>(type)];
  192. // Special cases for depth + stencil pixel formats
  193. if (gl_internal_format == GL_DEPTH24_STENCIL8)
  194. gl_type = GL_UNSIGNED_INT_24_8;
  195. else if (gl_internal_format == GL_DEPTH32F_STENCIL8)
  196. gl_type = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
  197. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  198. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  199. glBindTexture(gl_texture_target, gl_texture_id);
  200. if (depth)
  201. glTexImage3D(gl_texture_target, 0, gl_internal_format, width, height, depth, 0, gl_format, gl_type, data);
  202. else if (height)
  203. glTexImage2D(gl_texture_target, 0, gl_internal_format, width, height, 0, gl_format, gl_type, data);
  204. else if (width)
  205. glTexImage1D(gl_texture_target, 0, gl_internal_format, width, 0, gl_format, gl_type, data);
  206. glGenerateMipmap(gl_texture_target);
  207. glTexParameteriv(gl_texture_target, GL_TEXTURE_SWIZZLE_RGBA, gl_swizzle_mask);
  208. /// TODO: remove this
  209. if (format == pixel_format::d)
  210. {
  211. glTexParameteri(gl_texture_target, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
  212. glTexParameteri(gl_texture_target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
  213. }
  214. }
  215. void texture::resize(std::uint16_t width, std::uint16_t height, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const void* data)
  216. {
  217. resize(width, height, 0, type, format, color_space, data);
  218. }
  219. void texture::resize(std::uint16_t width, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const void* data)
  220. {
  221. resize(width, 0, 0, type, format, color_space, data);
  222. }
  223. } // namespace gl