| #ifndef IMAGE_SAMPLER |
| #define IMAGE_SAMPLER |
| |
| #include <stdint.h> |
| |
| namespace rive |
| { |
| enum class ImageFilter : uint8_t |
| { |
| // High fidelity linear filter in all 2 directions: x, y |
| bilinear = 0, |
| // Sample with low fidelity, good for things like pixel art. |
| nearest = 1, |
| }; |
| |
| constexpr size_t NUM_IMAGE_FILTERS = 2; |
| |
| enum class ImageWrap : uint8_t |
| { |
| // Clamp to the color of the nearest edge when a texture sample falls |
| // outside 0..1. |
| clamp = 0, |
| // Repeat when a texture sample falls outside 0..1 (e.g., fmod(coord, 1)). |
| repeat = 1, |
| // Similar to repeat, but also mirror the coordinate with each repeat. |
| mirror = 2, |
| }; |
| |
| constexpr size_t NUM_IMAGE_WRAP = 3; |
| |
| struct ImageSampler |
| { |
| static constexpr ImageSampler LinearClamp() { return {}; } |
| |
| constexpr static uint8_t LINEAR_CLAMP_SAMPLER_KEY = 0; |
| |
| ImageWrap wrapX = ImageWrap::clamp; |
| ImageWrap wrapY = ImageWrap::clamp; |
| // How to sample the texture, this will be for both MIN and MAG filtering. |
| ImageFilter filter = ImageFilter::bilinear; |
| |
| bool operator==(const ImageSampler other) const |
| { |
| return other.wrapX == wrapX && other.wrapY == wrapY && |
| other.filter == filter; |
| } |
| |
| bool operator!=(const ImageSampler other) const |
| { |
| return !(*this == other); |
| } |
| |
| // The maximum number of possible combinations of sampler options. Used for |
| // array length in implementations. |
| static constexpr size_t MAX_SAMPLER_PERMUTATIONS = |
| NUM_IMAGE_FILTERS * NUM_IMAGE_WRAP * NUM_IMAGE_WRAP; |
| |
| // Convert struct to a key that can be used to index an array to get a |
| // unique sampler that represents these options. |
| const uint8_t asKey() const |
| { |
| return static_cast<int>(wrapX) + |
| (static_cast<int>(wrapY) * NUM_IMAGE_WRAP) + |
| (static_cast<int>(filter) * NUM_IMAGE_WRAP * NUM_IMAGE_WRAP); |
| } |
| |
| static ImageSampler SamplerFromKey(uint8_t key) |
| { |
| // Android wouldn't compile with {} style initialization so do it this |
| // way instead. |
| ImageSampler sampler; |
| |
| sampler.wrapX = GetWrapXOptionFromKey(key); |
| sampler.wrapY = GetWrapYOptionFromKey(key); |
| sampler.filter = GetFilterOptionFromKey(key); |
| |
| return sampler; |
| } |
| |
| static ImageWrap GetWrapXOptionFromKey(uint8_t key) |
| { |
| return static_cast<ImageWrap>(key % NUM_IMAGE_WRAP); |
| } |
| |
| static ImageWrap GetWrapYOptionFromKey(uint8_t key) |
| { |
| return static_cast<ImageWrap>((key / NUM_IMAGE_WRAP) % NUM_IMAGE_WRAP); |
| } |
| |
| static ImageFilter GetFilterOptionFromKey(uint8_t key) |
| { |
| return static_cast<ImageFilter>(key / |
| (NUM_IMAGE_WRAP * NUM_IMAGE_WRAP)); |
| } |
| }; |
| } // namespace rive |
| #endif |