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

190 lines
6.1 KiB

  1. /*
  2. * Copyright (C) 2020 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 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 GLint swizzle_mask_lut[][4] =
  59. {
  60. {GL_RED, GL_RED, GL_RED, GL_ONE},
  61. {GL_RED, GL_GREEN, GL_ZERO, GL_ONE},
  62. {GL_RED, GL_RED, GL_RED, GL_ONE},
  63. {GL_RED, GL_RED, GL_RED, GL_GREEN},
  64. {GL_RED, GL_GREEN, GL_BLUE, GL_ONE},
  65. {GL_RED, GL_GREEN, GL_BLUE, GL_ONE},
  66. {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA},
  67. {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}
  68. };
  69. static constexpr GLenum wrapping_lut[] =
  70. {
  71. GL_CLAMP_TO_EDGE,
  72. GL_REPEAT,
  73. GL_MIRRORED_REPEAT
  74. };
  75. static constexpr GLenum min_filter_lut[] =
  76. {
  77. GL_NEAREST,
  78. GL_LINEAR,
  79. GL_NEAREST_MIPMAP_NEAREST,
  80. GL_LINEAR_MIPMAP_NEAREST,
  81. GL_NEAREST_MIPMAP_LINEAR,
  82. GL_LINEAR_MIPMAP_LINEAR
  83. };
  84. static constexpr GLenum mag_filter_lut[] =
  85. {
  86. GL_NEAREST,
  87. GL_LINEAR
  88. };
  89. texture_2d::texture_2d(int width, int height, ::pixel_type type, ::pixel_format format, const void* data):
  90. gl_texture_id(0),
  91. dimensions({0, 0}),
  92. wrapping({texture_wrapping::repeat, texture_wrapping::repeat}),
  93. filters({texture_min_filter::linear_mipmap_linear, texture_mag_filter::linear}),
  94. max_anisotropy(0.0f)
  95. {
  96. glGenTextures(1, &gl_texture_id);
  97. resize(width, height, type, format, data);
  98. set_wrapping(std::get<0>(wrapping), std::get<1>(wrapping));
  99. set_filters(std::get<0>(filters), std::get<1>(filters));
  100. set_max_anisotropy(max_anisotropy);
  101. }
  102. texture_2d::~texture_2d()
  103. {
  104. glDeleteTextures(1, &gl_texture_id);
  105. }
  106. void texture_2d::resize(int width, int height, ::pixel_type type, ::pixel_format format, const void* data)
  107. {
  108. dimensions = {width, height};
  109. pixel_type = type;
  110. pixel_format = format;
  111. GLenum gl_internal_format = internal_format_lut[static_cast<std::size_t>(format)][static_cast<std::size_t>(type)];
  112. GLenum gl_format = pixel_format_lut[static_cast<std::size_t>(format)];
  113. const GLint* gl_swizzle_mask = swizzle_mask_lut[static_cast<std::size_t>(format)];
  114. GLenum gl_type = pixel_type_lut[static_cast<std::size_t>(type)];
  115. // Special cases for depth + stencil pixel formats
  116. if (gl_internal_format == GL_DEPTH24_STENCIL8)
  117. gl_type = GL_UNSIGNED_INT_24_8;
  118. else if (gl_internal_format == GL_DEPTH32F_STENCIL8)
  119. gl_type = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
  120. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  121. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  122. glBindTexture(GL_TEXTURE_2D, gl_texture_id);
  123. glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, width, height, 0, gl_format, gl_type, data);
  124. glGenerateMipmap(GL_TEXTURE_2D);
  125. glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, gl_swizzle_mask);
  126. /// TODO: remove this
  127. if (format == pixel_format::d)
  128. {
  129. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
  130. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
  131. }
  132. }
  133. void texture_2d::set_wrapping(texture_wrapping wrap_s, texture_wrapping wrap_t)
  134. {
  135. wrapping = {wrap_s, wrap_t};
  136. GLenum gl_wrap_s = wrapping_lut[static_cast<std::size_t>(wrap_s)];
  137. GLenum gl_wrap_t = wrapping_lut[static_cast<std::size_t>(wrap_t)];
  138. glBindTexture(GL_TEXTURE_2D, gl_texture_id);
  139. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl_wrap_s);
  140. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl_wrap_t);
  141. }
  142. void texture_2d::set_filters(texture_min_filter min_filter, texture_mag_filter mag_filter)
  143. {
  144. filters = {min_filter, mag_filter};
  145. GLenum gl_min_filter = min_filter_lut[static_cast<std::size_t>(min_filter)];
  146. GLenum gl_mag_filter = mag_filter_lut[static_cast<std::size_t>(mag_filter)];
  147. glBindTexture(GL_TEXTURE_2D, gl_texture_id);
  148. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_min_filter);
  149. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_mag_filter);
  150. }
  151. void texture_2d::set_max_anisotropy(float anisotropy)
  152. {
  153. this->max_anisotropy = std::max<float>(0.0f, std::min<float>(1.0f, anisotropy));
  154. // Lerp between 1.0f and GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
  155. float gl_max_texture_max_anisotropy;
  156. glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gl_max_texture_max_anisotropy);
  157. float gl_max_anisotropy = 1.0f + this->max_anisotropy * (gl_max_texture_max_anisotropy - 1.0f);
  158. glBindTexture(GL_TEXTURE_2D, gl_texture_id);
  159. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_max_anisotropy);
  160. }