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

211 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 "rasterizer/texture-2d.hpp"
  20. #include "rasterizer/texture-wrapping.hpp"
  21. #include "rasterizer/texture-filter.hpp"
  22. #include <glad/glad.h>
  23. #include <algorithm>
  24. static constexpr GLenum pixel_format_lut[] =
  25. {
  26. GL_DEPTH_COMPONENT,
  27. GL_DEPTH_STENCIL,
  28. GL_RED,
  29. GL_RG,
  30. GL_RGB,
  31. GL_BGR,
  32. GL_RGBA,
  33. GL_BGRA
  34. };
  35. static constexpr GLenum pixel_type_lut[] =
  36. {
  37. GL_BYTE,
  38. GL_UNSIGNED_BYTE,
  39. GL_SHORT,
  40. GL_UNSIGNED_SHORT,
  41. GL_INT,
  42. GL_UNSIGNED_INT,
  43. GL_HALF_FLOAT,
  44. GL_FLOAT
  45. };
  46. static constexpr GLenum linear_internal_format_lut[][8] =
  47. {
  48. {GL_NONE, GL_NONE, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT32, GL_NONE, GL_DEPTH_COMPONENT32F},
  49. // Note: GL_DEPTH32F_STENCIL8 is actually a 64-bit format, 32 depth bits, 8 stencil bits, and 24 alignment bits.
  50. {GL_NONE, GL_NONE, GL_NONE, GL_NONE, GL_DEPTH24_STENCIL8, GL_DEPTH24_STENCIL8, GL_NONE, GL_DEPTH32F_STENCIL8},
  51. {GL_R8, GL_R8, GL_R16, GL_R16, GL_R32F, GL_R32F, GL_R16F, GL_R32F},
  52. {GL_RG8, GL_RG8, GL_RG16, GL_RG16, GL_RG32F, GL_RG32F, GL_RG16F, GL_RG32F},
  53. {GL_RGB8, GL_RGB8, GL_RGB16, GL_RGB16, GL_RGB32F, GL_RGB32F, GL_RGB16F, GL_RGB32F},
  54. {GL_RGB8, GL_RGB8, GL_RGB16, GL_RGB16, GL_RGB32F, GL_RGB32F, GL_RGB16F, GL_RGB32F},
  55. {GL_RGBA8, GL_RGBA8, GL_RGBA16, GL_RGBA16, GL_RGBA32F, GL_RGBA32F, GL_RGBA16F, GL_RGBA32F},
  56. {GL_RGBA8, GL_RGBA8, GL_RGBA16, GL_RGBA16, GL_RGBA32F, GL_RGBA32F, GL_RGBA16F, GL_RGBA32F}
  57. };
  58. static constexpr GLenum srgb_internal_format_lut[][8] =
  59. {
  60. {GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8, GL_SRGB8},
  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_ALPHA8, GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8, GL_SRGB8_ALPHA8},
  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. };
  69. static constexpr GLint swizzle_mask_lut[][4] =
  70. {
  71. {GL_RED, GL_RED, GL_RED, GL_ONE},
  72. {GL_RED, GL_GREEN, GL_ZERO, GL_ONE},
  73. {GL_RED, GL_RED, GL_RED, GL_ONE},
  74. {GL_RED, GL_RED, GL_RED, GL_GREEN},
  75. {GL_RED, GL_GREEN, GL_BLUE, GL_ONE},
  76. {GL_RED, GL_GREEN, GL_BLUE, GL_ONE},
  77. {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA},
  78. {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}
  79. };
  80. static constexpr GLenum wrapping_lut[] =
  81. {
  82. GL_CLAMP_TO_EDGE,
  83. GL_REPEAT,
  84. GL_MIRRORED_REPEAT
  85. };
  86. static constexpr GLenum min_filter_lut[] =
  87. {
  88. GL_NEAREST,
  89. GL_LINEAR,
  90. GL_NEAREST_MIPMAP_NEAREST,
  91. GL_LINEAR_MIPMAP_NEAREST,
  92. GL_NEAREST_MIPMAP_LINEAR,
  93. GL_LINEAR_MIPMAP_LINEAR
  94. };
  95. static constexpr GLenum mag_filter_lut[] =
  96. {
  97. GL_NEAREST,
  98. GL_LINEAR
  99. };
  100. texture_2d::texture_2d(int width, int height, ::pixel_type type, ::pixel_format format, ::color_space color_space, const void* data):
  101. gl_texture_id(0),
  102. dimensions({0, 0}),
  103. wrapping({texture_wrapping::repeat, texture_wrapping::repeat}),
  104. filters({texture_min_filter::linear_mipmap_linear, texture_mag_filter::linear}),
  105. max_anisotropy(0.0f)
  106. {
  107. glGenTextures(1, &gl_texture_id);
  108. resize(width, height, type, format, color_space, data);
  109. set_wrapping(std::get<0>(wrapping), std::get<1>(wrapping));
  110. set_filters(std::get<0>(filters), std::get<1>(filters));
  111. set_max_anisotropy(max_anisotropy);
  112. }
  113. texture_2d::~texture_2d()
  114. {
  115. glDeleteTextures(1, &gl_texture_id);
  116. }
  117. void texture_2d::resize(int width, int height, ::pixel_type type, ::pixel_format format, ::color_space color_space, const void* data)
  118. {
  119. dimensions = {width, height};
  120. pixel_type = type;
  121. pixel_format = format;
  122. this->color_space = color_space;
  123. GLenum gl_internal_format;
  124. if (color_space == ::color_space::srgb)
  125. {
  126. gl_internal_format = srgb_internal_format_lut[static_cast<std::size_t>(format)][static_cast<std::size_t>(type)];
  127. }
  128. else
  129. {
  130. gl_internal_format = linear_internal_format_lut[static_cast<std::size_t>(format)][static_cast<std::size_t>(type)];
  131. }
  132. GLenum gl_format = pixel_format_lut[static_cast<std::size_t>(format)];
  133. const GLint* gl_swizzle_mask = swizzle_mask_lut[static_cast<std::size_t>(format)];
  134. GLenum gl_type = pixel_type_lut[static_cast<std::size_t>(type)];
  135. // Special cases for depth + stencil pixel formats
  136. if (gl_internal_format == GL_DEPTH24_STENCIL8)
  137. gl_type = GL_UNSIGNED_INT_24_8;
  138. else if (gl_internal_format == GL_DEPTH32F_STENCIL8)
  139. gl_type = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
  140. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  141. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  142. glBindTexture(GL_TEXTURE_2D, gl_texture_id);
  143. glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type, data);
  144. glGenerateMipmap(GL_TEXTURE_2D);
  145. glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, gl_swizzle_mask);
  146. /// TODO: remove this
  147. if (format == pixel_format::d)
  148. {
  149. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
  150. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
  151. }
  152. }
  153. void texture_2d::set_wrapping(texture_wrapping wrap_s, texture_wrapping wrap_t)
  154. {
  155. wrapping = {wrap_s, wrap_t};
  156. GLenum gl_wrap_s = wrapping_lut[static_cast<std::size_t>(wrap_s)];
  157. GLenum gl_wrap_t = wrapping_lut[static_cast<std::size_t>(wrap_t)];
  158. glBindTexture(GL_TEXTURE_2D, gl_texture_id);
  159. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl_wrap_s);
  160. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl_wrap_t);
  161. }
  162. void texture_2d::set_filters(texture_min_filter min_filter, texture_mag_filter mag_filter)
  163. {
  164. filters = {min_filter, mag_filter};
  165. GLenum gl_min_filter = min_filter_lut[static_cast<std::size_t>(min_filter)];
  166. GLenum gl_mag_filter = mag_filter_lut[static_cast<std::size_t>(mag_filter)];
  167. glBindTexture(GL_TEXTURE_2D, gl_texture_id);
  168. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_min_filter);
  169. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_mag_filter);
  170. }
  171. void texture_2d::set_max_anisotropy(float anisotropy)
  172. {
  173. this->max_anisotropy = std::max<float>(0.0f, std::min<float>(1.0f, anisotropy));
  174. // Lerp between 1.0f and GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
  175. float gl_max_texture_max_anisotropy;
  176. glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gl_max_texture_max_anisotropy);
  177. float gl_max_anisotropy = 1.0f + this->max_anisotropy * (gl_max_texture_max_anisotropy - 1.0f);
  178. glBindTexture(GL_TEXTURE_2D, gl_texture_id);
  179. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_max_anisotropy);
  180. }