115 lines
2.6 KiB
C++
115 lines
2.6 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_;
|
|
}
|
|
|
|
gfx::pixmap_rgba renderer::release()
|
|
{
|
|
resolve();
|
|
canvas_.clear();
|
|
return std::move(result_);
|
|
}
|
|
|
|
gfx::pixmap_rgba const & renderer::canvas() const
|
|
{
|
|
return canvas_;
|
|
}
|
|
|
|
gfx::pixmap_rgba renderer::release_canvas()
|
|
{
|
|
result_.clear();
|
|
need_resolve_ = false;
|
|
return std::move(canvas_);
|
|
}
|
|
|
|
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;
|
|
|
|
auto const box = geom::expand(bbox(primitive.mask), aa);
|
|
|
|
int xmin = std::floor(std::max(0.f, box[0].min * samples_));
|
|
int xmax = std::floor(std::min(canvas_.width() - 1.f, box[0].max * samples_));
|
|
int ymin = std::floor(std::max(0.f, box[1].min * samples_));
|
|
int ymax = std::floor(std::min(canvas_.height() - 1.f, box[1].max * samples_));
|
|
|
|
for (int y = ymin; y <= ymax; ++y)
|
|
{
|
|
for (int x = xmin; x <= xmax; ++x)
|
|
{
|
|
geom::point const center{(x + 0.5f) / samples_, (y + 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;
|
|
color[3] *= primitive.alpha;
|
|
|
|
canvas_(x, y) = gfx::to_coloru8(primitive.blend(gfx::to_colorf(canvas_(x, y)), 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;
|
|
}
|
|
|
|
}
|