| 900 | } |
| 901 | |
| 902 | [[nodiscard]] glm::vec4 sampleTextureBilinear(const lfs::core::TextureImage& image, |
| 903 | float u, |
| 904 | float v) { |
| 905 | if (image.width <= 0 || image.height <= 0 || image.channels <= 0 || image.pixels.empty()) { |
| 906 | return glm::vec4(1.0f); |
| 907 | } |
| 908 | |
| 909 | u -= std::floor(u); |
| 910 | v -= std::floor(v); |
| 911 | |
| 912 | const float x = u * static_cast<float>(image.width - 1); |
| 913 | const float y = v * static_cast<float>(image.height - 1); |
| 914 | const int x0 = std::clamp(static_cast<int>(std::floor(x)), 0, image.width - 1); |
| 915 | const int y0 = std::clamp(static_cast<int>(std::floor(y)), 0, image.height - 1); |
| 916 | const int x1 = (x0 + 1) % image.width; |
| 917 | const int y1 = (y0 + 1) % image.height; |
| 918 | const float tx = x - static_cast<float>(x0); |
| 919 | const float ty = y - static_cast<float>(y0); |
| 920 | |
| 921 | const glm::vec4 top = glm::mix(fetchTexel(image, x0, y0), fetchTexel(image, x1, y0), tx); |
| 922 | const glm::vec4 bottom = glm::mix(fetchTexel(image, x0, y1), fetchTexel(image, x1, y1), tx); |
| 923 | return glm::mix(top, bottom, ty); |
| 924 | } |
| 925 | |
| 926 | [[nodiscard]] const lfs::core::Material& meshMaterialOrDefault( |
| 927 | const lfs::core::MeshData& mesh, |
no test coverage detected