Sampler.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. /*
  2. * Copyright (c) 2021, Stephan Unverwerth <s.unverwerth@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibSoftGPU/Config.h>
  7. #include <LibSoftGPU/Image.h>
  8. #include <LibSoftGPU/Sampler.h>
  9. #include <math.h>
  10. namespace SoftGPU {
  11. static constexpr float fracf(float value)
  12. {
  13. return value - floorf(value);
  14. }
  15. static constexpr float wrap_repeat(float value)
  16. {
  17. return fracf(value);
  18. }
  19. [[maybe_unused]] static constexpr float wrap_clamp(float value)
  20. {
  21. return clamp(value, 0.0f, 1.0f);
  22. }
  23. static constexpr float wrap_clamp_to_edge(float value, unsigned num_texels)
  24. {
  25. float const clamp_limit = 1.f / (2 * num_texels);
  26. return clamp(value, clamp_limit, 1.0f - clamp_limit);
  27. }
  28. static constexpr float wrap_mirrored_repeat(float value, unsigned num_texels)
  29. {
  30. float integer = floorf(value);
  31. float frac = value - integer;
  32. bool iseven = fmodf(integer, 2.0f) == 0.0f;
  33. return wrap_clamp_to_edge(iseven ? frac : 1 - frac, num_texels);
  34. }
  35. static constexpr float wrap(float value, TextureWrapMode mode, unsigned num_texels)
  36. {
  37. switch (mode) {
  38. case TextureWrapMode::Repeat:
  39. return wrap_repeat(value);
  40. case TextureWrapMode::MirroredRepeat:
  41. return wrap_mirrored_repeat(value, num_texels);
  42. case TextureWrapMode::Clamp:
  43. if constexpr (CLAMP_DEPRECATED_BEHAVIOR) {
  44. return wrap_clamp(value);
  45. }
  46. return wrap_clamp_to_edge(value, num_texels);
  47. case TextureWrapMode::ClampToBorder:
  48. case TextureWrapMode::ClampToEdge:
  49. return wrap_clamp_to_edge(value, num_texels);
  50. default:
  51. VERIFY_NOT_REACHED();
  52. }
  53. }
  54. FloatVector4 Sampler::sample_2d(FloatVector2 const& uv) const
  55. {
  56. if (m_config.bound_image.is_null())
  57. return { 0, 0, 0, 1 };
  58. auto const& image = *m_config.bound_image;
  59. unsigned const layer = 0;
  60. // FIXME: calculate actual mipmap level to use
  61. unsigned const level = 0;
  62. unsigned width = image.level_width(level);
  63. unsigned height = image.level_height(level);
  64. float s = wrap(uv.x(), m_config.texture_wrap_u, width);
  65. float t = wrap(uv.y(), m_config.texture_wrap_v, height);
  66. float u = s * width;
  67. float v = t * height;
  68. if (m_config.texture_mag_filter == TextureFilter::Nearest) {
  69. unsigned i = min(static_cast<unsigned>(u), width - 1);
  70. unsigned j = min(static_cast<unsigned>(v), height - 1);
  71. return image.texel(layer, level, i, j, 0);
  72. }
  73. int i0 = m_config.texture_wrap_u == TextureWrapMode::Repeat ? static_cast<unsigned>(floorf(u - 0.5f)) % width : floorf(u - 0.5f);
  74. int j0 = m_config.texture_wrap_v == TextureWrapMode::Repeat ? static_cast<unsigned>(floorf(v - 0.5f)) % height : floorf(v - 0.5f);
  75. int i1 = m_config.texture_wrap_u == TextureWrapMode::Repeat ? (i0 + 1) % width : i0 + 1;
  76. int j1 = m_config.texture_wrap_v == TextureWrapMode::Repeat ? (j0 + 1) % height : j0 + 1;
  77. FloatVector4 t0, t1, t2, t3;
  78. if (m_config.texture_wrap_u == TextureWrapMode::Repeat && m_config.texture_wrap_v == TextureWrapMode::Repeat) {
  79. t0 = image.texel(layer, level, i0, j0, 0);
  80. t1 = image.texel(layer, level, i1, j0, 0);
  81. t2 = image.texel(layer, level, i0, j1, 0);
  82. t3 = image.texel(layer, level, i1, j1, 0);
  83. } else {
  84. int w = static_cast<int>(width);
  85. int h = static_cast<int>(height);
  86. t0 = (i0 < 0 || i0 >= w || j0 < 0 || j0 >= h) ? m_config.border_color : image.texel(layer, level, i0, j0, 0);
  87. t1 = (i1 < 0 || i1 >= w || j0 < 0 || j0 >= h) ? m_config.border_color : image.texel(layer, level, i1, j0, 0);
  88. t2 = (i0 < 0 || i0 >= w || j1 < 0 || j1 >= h) ? m_config.border_color : image.texel(layer, level, i0, j1, 0);
  89. t3 = (i1 < 0 || i1 >= w || j1 < 0 || j1 >= h) ? m_config.border_color : image.texel(layer, level, i1, j1, 0);
  90. }
  91. float const alpha = fracf(u - 0.5f);
  92. float const beta = fracf(v - 0.5f);
  93. auto const lerp_0 = mix(t0, t1, alpha);
  94. auto const lerp_1 = mix(t2, t3, alpha);
  95. return mix(lerp_0, lerp_1, beta);
  96. }
  97. }