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

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