| /* |
| * Copyright 2022 Rive |
| */ |
| |
| #include "gm.hpp" |
| #include "gmutils.hpp" |
| #include "common/write_png_file.hpp" |
| #include <vector> |
| |
| constexpr int imgW = 512; |
| constexpr int imgH = 512; |
| |
| // sRGB encoding function |
| uint8_t linearToSrgb(float linear) |
| { |
| if (linear <= 0.0031308f) |
| return static_cast<uint8_t>(std::round(255.0f * (12.92f * linear))); |
| else |
| return static_cast<uint8_t>(std::round( |
| 255.0f * (1.055f * std::pow(linear, 1.0f / 2.4f) - 0.055f))); |
| } |
| |
| // Pack ARGB pixel |
| uint32_t packARGB(uint8_t r, uint8_t g, uint8_t b) |
| { |
| return (255u << 24) | (r << 16) | (g << 8) | b; |
| } |
| |
| std::vector<uint32_t> generateTexture() |
| { |
| std::vector<uint32_t> pixels(imgW * imgH); |
| |
| for (int y = 0; y < imgH; ++y) |
| { |
| for (int x = 0; x < imgW; ++x) |
| { |
| uint8_t val = 0; |
| |
| if (y < 64) |
| { |
| // sRGB ramp |
| float linear = static_cast<float>(x) / (imgW - 1); |
| val = linearToSrgb(linear); |
| } |
| else if (y < 128) |
| { |
| // linear ramp |
| val = static_cast<uint8_t>(std::round(255.0f * x / (imgW - 1))); |
| } |
| else if (y < 192) |
| { |
| // 8 sRGB squares |
| int i = x / (imgW / 8); |
| float linear = static_cast<float>(i) / 7.0f; |
| val = linearToSrgb(linear); |
| } |
| else if (y < 256) |
| { |
| // 8 linear squares |
| int i = x / (imgW / 8); |
| val = static_cast<uint8_t>(std::round(255.0f * i / 7.0f)); |
| } |
| else |
| { |
| if (x < imgW / 2) |
| { |
| // checkerboard |
| val = ((x + y) % 2 == 0) ? 255 : 0; |
| } |
| else |
| { |
| // right half blocks |
| val = (y < 256 + 128) ? 127 : linearToSrgb(0.5f); // ≈ 187 |
| } |
| } |
| |
| int yD = (imgH - 1) - y; |
| pixels[yD * imgW + x] = packARGB(val, val, val); |
| } |
| } |
| |
| return pixels; |
| } |
| |
| using namespace rivegm; |
| |
| class GammaTextureGM : public GM |
| { |
| public: |
| GammaTextureGM() : GM(512, 768) {} |
| |
| void onDraw(rive::Renderer* renderer) override |
| { |
| auto pixData = generateTexture(); |
| std::vector<uint8_t> encodedData = |
| EncodePNGToBuffer(imgW, |
| imgH, |
| (uint8_t*)pixData.data(), |
| PNGCompression::fast_rle); |
| auto img = LoadImage(rive::Span<uint8_t>(encodedData)); |
| if (img == nullptr) |
| { |
| return; |
| } |
| |
| // Full size image |
| rive::AABB r = {0, 0, 512, 512}; |
| renderer->save(); |
| renderer->translate(0, 0); |
| draw_image(renderer, img.get(), r); |
| renderer->restore(); |
| |
| // Below is 1/4 (1/2 * 1/2) version |
| renderer->save(); |
| renderer->translate(0, 512); |
| renderer->scale(.5, .5); |
| draw_image(renderer, img.get(), r); |
| renderer->restore(); |
| |
| // Bottom right is 1/16 (1/4 * 1/4) version |
| renderer->save(); |
| renderer->translate(256, 512); |
| renderer->scale(.25, .25); |
| draw_image(renderer, img.get(), r); |
| renderer->restore(); |
| } |
| }; |
| GMREGISTER(gamma_texture, return new GammaTextureGM) |