💿🐜 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.

215 lines
7.3 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-2d.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_2d::texture_2d(int width, int height, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const void* data):
  103. gl_texture_id(0),
  104. dimensions({0, 0}),
  105. wrapping({texture_wrapping::repeat, texture_wrapping::repeat}),
  106. filters({texture_min_filter::linear_mipmap_linear, texture_mag_filter::linear}),
  107. max_anisotropy(0.0f)
  108. {
  109. glGenTextures(1, &gl_texture_id);
  110. resize(width, height, type, format, color_space, data);
  111. set_wrapping(std::get<0>(wrapping), std::get<1>(wrapping));
  112. set_filters(std::get<0>(filters), std::get<1>(filters));
  113. set_max_anisotropy(max_anisotropy);
  114. }
  115. texture_2d::~texture_2d()
  116. {
  117. glDeleteTextures(1, &gl_texture_id);
  118. }
  119. void texture_2d::resize(int width, int height, gl::pixel_type type, gl::pixel_format format, gl::color_space color_space, const void* data)
  120. {
  121. dimensions = {width, height};
  122. pixel_type = type;
  123. pixel_format = format;
  124. this->color_space = color_space;
  125. GLenum gl_internal_format;
  126. if (color_space == gl::color_space::srgb)
  127. {
  128. gl_internal_format = srgb_internal_format_lut[static_cast<std::size_t>(format)][static_cast<std::size_t>(type)];
  129. }
  130. else
  131. {
  132. gl_internal_format = linear_internal_format_lut[static_cast<std::size_t>(format)][static_cast<std::size_t>(type)];
  133. }
  134. GLenum gl_format = pixel_format_lut[static_cast<std::size_t>(format)];
  135. const GLint* gl_swizzle_mask = swizzle_mask_lut[static_cast<std::size_t>(format)];
  136. GLenum gl_type = pixel_type_lut[static_cast<std::size_t>(type)];
  137. // Special cases for depth + stencil pixel formats
  138. if (gl_internal_format == GL_DEPTH24_STENCIL8)
  139. gl_type = GL_UNSIGNED_INT_24_8;
  140. else if (gl_internal_format == GL_DEPTH32F_STENCIL8)
  141. gl_type = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
  142. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  143. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  144. glBindTexture(GL_TEXTURE_2D, gl_texture_id);
  145. glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type, data);
  146. glGenerateMipmap(GL_TEXTURE_2D);
  147. glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, gl_swizzle_mask);
  148. /// TODO: remove this
  149. if (format == pixel_format::d)
  150. {
  151. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
  152. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
  153. }
  154. }
  155. void texture_2d::set_wrapping(gl::texture_wrapping wrap_s, texture_wrapping wrap_t)
  156. {
  157. wrapping = {wrap_s, wrap_t};
  158. GLenum gl_wrap_s = wrapping_lut[static_cast<std::size_t>(wrap_s)];
  159. GLenum gl_wrap_t = wrapping_lut[static_cast<std::size_t>(wrap_t)];
  160. glBindTexture(GL_TEXTURE_2D, gl_texture_id);
  161. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl_wrap_s);
  162. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl_wrap_t);
  163. }
  164. void texture_2d::set_filters(texture_min_filter min_filter, texture_mag_filter mag_filter)
  165. {
  166. filters = {min_filter, mag_filter};
  167. GLenum gl_min_filter = min_filter_lut[static_cast<std::size_t>(min_filter)];
  168. GLenum gl_mag_filter = mag_filter_lut[static_cast<std::size_t>(mag_filter)];
  169. glBindTexture(GL_TEXTURE_2D, gl_texture_id);
  170. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_min_filter);
  171. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_mag_filter);
  172. }
  173. void texture_2d::set_max_anisotropy(float anisotropy)
  174. {
  175. this->max_anisotropy = std::max<float>(0.0f, std::min<float>(1.0f, anisotropy));
  176. // Lerp between 1.0f and GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
  177. float gl_max_texture_max_anisotropy;
  178. glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gl_max_texture_max_anisotropy);
  179. float gl_max_anisotropy = 1.0f + this->max_anisotropy * (gl_max_texture_max_anisotropy - 1.0f);
  180. glBindTexture(GL_TEXTURE_2D, gl_texture_id);
  181. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_max_anisotropy);
  182. }
  183. } // namespace gl