blob: e8628384083073017b4c424334ae1bf2346db4c3 [file] [log] [blame]
/*
* 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)