psemek/libs/vecr/source/renderer.cpp

85 lines
1.8 KiB
C++

#include <psemek/vecr/renderer.hpp>
#include <psemek/geom/swizzle.hpp>
namespace psemek::vecr
{
void renderer::reset(geom::vector<std::size_t, 2> const & size, std::size_t samples, gfx::color_rgba const & color)
{
samples_ = samples;
canvas_.assign({size[0] * samples, size[1] * samples}, color);
result_.assign({size[0], size[1]}, color);
need_resolve_ = false;
}
geom::vector<std::size_t, 2> renderer::size() const
{
return {result_.width(), result_.height()};
}
std::size_t renderer::samples() const
{
return samples_;
}
gfx::pixmap_rgba const & renderer::result() const
{
resolve();
return result_;
}
void renderer::clear(gfx::color_rgba const & color)
{
canvas_.fill(color);
result_.fill(color);
need_resolve_ = false;
}
void renderer::draw(primitive const & primitive)
{
float const aa = primitive.blur / 2.f;
for (auto const & idx : canvas_.indices())
{
geom::point const center{(idx[0] + 0.5f) / samples_, (idx[1] + 0.5f) / samples_};
auto const sample = sdf(primitive.mask, center);
if (sample.value > aa) continue;
float blur = 1.f;
if (sample.value > - aa)
blur = (aa - sample.value) / (2.f * aa);
auto color = colorize(primitive.colorizer, center, sample);
color[3] *= blur;
canvas_(idx) = gfx::to_coloru8(primitive.blend(gfx::to_colorf(canvas_(idx)), color));
}
need_resolve_ = true;
}
void renderer::resolve() const
{
if (!need_resolve_) return;
for (auto const & idx : result_.indices())
{
gfx::color_4f sum{0.f, 0.f, 0.f, 0.f};
for (std::size_t y = 0; y < samples_; ++y)
{
for (std::size_t x = 0; x < samples_; ++x)
{
sum += gfx::premult(gfx::to_colorf(canvas_({idx[0] * samples_ + x, idx[1] * samples_ + y})));
}
}
result_(idx) = gfx::to_coloru8(gfx::unpremult(sum / (1.f * samples_ * samples_)));
}
need_resolve_ = false;
}
}