Optimize vecr::renderer by using primitive's bbox

This commit is contained in:
Nikita Lisitsa 2023-06-19 19:11:50 +03:00
parent 2e2df09790
commit f70cdf9d8e
22 changed files with 245 additions and 16 deletions

View file

@ -2,6 +2,7 @@
#include <psemek/vecr/invert.hpp>
#include <psemek/vecr/intersect.hpp>
#include <psemek/geom/box.hpp>
namespace psemek::vecr
{
@ -14,4 +15,6 @@ namespace psemek::vecr
sdf_sample sdf(add const & s, geom::point<float, 2> const & p);
geom::box<float, 2> bbox(add const & s);
}

View file

@ -2,12 +2,52 @@
#include <psemek/vecr/sdf.hpp>
#include <psemek/geom/point.hpp>
#include <psemek/geom/box.hpp>
#include <functional>
#include <memory>
namespace psemek::vecr
{
namespace detail
{
struct any_base
{
virtual sdf_sample sdf_func(geom::point<float, 2> const & p) const = 0;
virtual geom::box<float, 2> bbox_func() const = 0;
virtual ~any_base() {}
};
template <typename Shape>
struct any_impl
: any_base
{
any_impl(Shape && shape)
: shape(std::move(shape))
{}
any_impl(Shape const & shape)
: shape(shape)
{}
Shape shape;
sdf_sample sdf_func(geom::point<float, 2> const & p) const override
{
return sdf(shape, p);
}
geom::box<float, 2> bbox_func() const override
{
return bbox(shape);
}
};
}
struct any
{
any() = default;
@ -26,26 +66,30 @@ namespace psemek::vecr
template <typename Shape>
any & operator = (Shape && shape)
{
sdf_ = [shape = std::forward<Shape>(shape)](geom::point<float, 2> const & p){
return sdf(shape, p);
};
impl_ = std::make_shared<detail::any_impl<std::decay_t<Shape>>>(std::move(shape));
return *this;
}
explicit operator bool() const
{
return static_cast<bool>(sdf_);
return static_cast<bool>(impl_);
}
friend sdf_sample sdf(any const & s, geom::point<float, 2> const & p);
friend geom::box<float, 2> bbox(any const & s);
private:
std::function<sdf_sample(geom::point<float, 2> const &)> sdf_;
std::shared_ptr<detail::any_base> impl_;
};
inline sdf_sample sdf(any const & s, geom::point<float, 2> const & p)
{
return s.sdf_ ? s.sdf_(p) : sdf_sample{};
return s.impl_ ? s.impl_->sdf_func(p) : sdf_sample{};
}
inline geom::box<float, 2> bbox(any const & s)
{
return s.impl_ ? s.impl_->bbox_func() : geom::box<float, 2>{};
}
}

View file

@ -2,6 +2,7 @@
#include <psemek/vecr/sdf.hpp>
#include <psemek/geom/point.hpp>
#include <psemek/geom/box.hpp>
namespace psemek::vecr
{
@ -24,4 +25,10 @@ namespace psemek::vecr
return result;
}
template <typename Shape>
geom::box<float, 2> bbox(border<Shape> const & s)
{
return bbox(s.shape);
}
}

View file

@ -2,6 +2,7 @@
#include <psemek/vecr/sdf.hpp>
#include <psemek/geom/point.hpp>
#include <psemek/geom/box.hpp>
namespace psemek::vecr
{
@ -14,4 +15,6 @@ namespace psemek::vecr
sdf_sample sdf(circle const & s, geom::point<float, 2> const & p);
geom::box<float, 2> bbox(circle const & s);
}

View file

@ -2,6 +2,7 @@
#include <psemek/vecr/sdf.hpp>
#include <psemek/geom/point.hpp>
#include <psemek/geom/box.hpp>
#include <optional>
@ -55,4 +56,10 @@ namespace psemek::vecr
return result;
}
template <typename Shape>
geom::box<float, 2> bbox(exact<Shape> const & s)
{
return bbox(s.shape);
}
}

View file

@ -1,6 +1,7 @@
#pragma once
#include <psemek/vecr/path.hpp>
#include <psemek/geom/box.hpp>
namespace psemek::vecr
{
@ -12,4 +13,6 @@ namespace psemek::vecr
sdf_sample sdf(fill const & s, geom::point<float, 2> const & p);
geom::box<float, 2> bbox(fill const & s);
}

View file

@ -2,6 +2,7 @@
#include <psemek/vecr/sdf.hpp>
#include <psemek/geom/point.hpp>
#include <psemek/geom/box.hpp>
namespace psemek::vecr
{
@ -21,4 +22,10 @@ namespace psemek::vecr
return result;
}
template <typename Shape>
geom::box<float, 2> bbox(grow<Shape> const & s)
{
return geom::expand(bbox(s.shape), s.distance);
}
}

View file

@ -2,6 +2,7 @@
#include <psemek/vecr/sdf.hpp>
#include <psemek/geom/point.hpp>
#include <psemek/geom/box.hpp>
namespace psemek::vecr
{
@ -17,4 +18,10 @@ namespace psemek::vecr
return {geom::dot(p - s.origin, s.normal), s.normal};
}
inline geom::box<float, 2> bbox(halfspace const &)
{
return geom::box<float, 2>::full();
}
}

View file

@ -4,6 +4,7 @@
#include <psemek/vecr/any.hpp>
#include <psemek/geom/point.hpp>
#include <psemek/geom/math.hpp>
#include <psemek/geom/box.hpp>
#include <vector>
@ -18,4 +19,6 @@ namespace psemek::vecr
sdf_sample sdf(intersect const & s, geom::point<float, 2> const & p);
geom::box<float, 2> bbox(intersect const & s);
}

View file

@ -2,6 +2,7 @@
#include <psemek/vecr/sdf.hpp>
#include <psemek/geom/point.hpp>
#include <psemek/geom/box.hpp>
namespace psemek::vecr
{
@ -21,4 +22,10 @@ namespace psemek::vecr
return result;
}
template <typename Shape>
geom::box<float, 2> bbox(invert<Shape> const &)
{
return geom::box<float, 2>::full();
}
}

View file

@ -2,6 +2,7 @@
#include <psemek/vecr/sdf.hpp>
#include <psemek/geom/point.hpp>
#include <psemek/geom/box.hpp>
namespace psemek::vecr
{
@ -34,4 +35,24 @@ namespace psemek::vecr
return result;
}
template <typename Shape>
geom::box<float, 2> bbox(mirror<Shape> const & s)
{
geom::box<float, 2> result;
auto sbox = bbox(s.shape);
for (int x = 0; x <= 1; ++x)
{
for (int y = 0; y <= 1; ++y)
{
auto p = sbox.corner(x, y);
p = p - (2.f * geom::dot(s.axis, p - s.origin)) * s.axis;
result |= p;
}
}
return result;
}
}

View file

@ -2,6 +2,7 @@
#include <psemek/vecr/sdf.hpp>
#include <psemek/geom/point.hpp>
#include <psemek/geom/box.hpp>
#include <vector>
@ -15,4 +16,6 @@ namespace psemek::vecr
sdf_sample sdf(path const & s, geom::point<float, 2> const & p, bool closed = false);
geom::box<float, 2> bbox(path const & s);
}

View file

@ -24,6 +24,7 @@ namespace psemek::vecr
geom::vector<std::size_t, 2> size() const;
std::size_t samples() const;
gfx::pixmap_rgba const & result() const;
gfx::pixmap_rgba release();
void clear(gfx::color_rgba const & color = {0, 0, 0, 0});

View file

@ -20,4 +20,10 @@ namespace psemek::vecr
return sdf(intersect{{s.shape1, invert{s.shape2}}, s.smooth}, p);
}
template <typename Shape1, typename Shape2>
geom::box<float, 2> bbox(subtract<Shape1, Shape2> const & s)
{
return bbox(s.shape1);
}
}

View file

@ -25,4 +25,10 @@ namespace psemek::vecr
return sdf(s.shape, q);
}
template <typename Shape>
geom::box<float, 2> bbox(tile<Shape> const &)
{
return geom::box<float, 2>::full();
}
}

View file

@ -5,6 +5,7 @@
#include <psemek/geom/matrix.hpp>
#include <psemek/geom/homogeneous.hpp>
#include <psemek/geom/gauss.hpp>
#include <psemek/geom/box.hpp>
namespace psemek::vecr
{
@ -45,6 +46,12 @@ namespace psemek::vecr
return sdf(s.shape, p - s.delta);
}
template <typename Shape>
geom::box<float, 2> bbox(translate<Shape> const & s)
{
return bbox(s.shape) + s.delta;
}
template <typename Shape>
sdf_sample sdf(rotate<Shape> const & s, geom::point<float, 2> const & p)
{
@ -53,6 +60,20 @@ namespace psemek::vecr
return result;
}
template <typename Shape>
geom::box<float, 2> bbox(rotate<Shape> const & s)
{
auto sbox = bbox(s.shape);
geom::box<float, 2> result;
for (int y = 0; y <= 1; ++y)
for (int x = 0; x <= 1; ++x)
result |= s.origin + geom::rotate(sbox.corner(x, y) - s.origin, s.angle);
return result;
}
template <typename Shape>
sdf_sample sdf(scale<Shape> const & s, geom::point<float, 2> const & p)
{
@ -65,6 +86,20 @@ namespace psemek::vecr
return result;
}
template <typename Shape>
geom::box<float, 2> bbox(scale<Shape> const & s)
{
auto sbox = bbox(s.shape);
geom::box<float, 2> result;
for (int y = 0; y <= 1; ++y)
for (int x = 0; x <= 1; ++x)
result |= s.origin + (sbox.corner(x, y) - s.origin) * s.factor;
return result;
}
template <typename Shape>
sdf_sample sdf(transform<Shape> const & s, geom::point<float, 2> const & p)
{
@ -89,5 +124,18 @@ namespace psemek::vecr
return result;
}
template <typename Shape>
geom::box<float, 2> bbox(transform<Shape> const & s)
{
auto sbox = bbox(s.shape);
geom::box<float, 2> result;
for (int y = 0; y <= 1; ++y)
for (int x = 0; x <= 1; ++x)
result |= geom::as_point(s.matrix * geom::homogeneous(sbox.corner(x, y)));
return result;
}
}

View file

@ -38,4 +38,12 @@ namespace psemek::vecr
return result;
}
geom::box<float, 2> bbox(add const & s)
{
geom::box<float, 2> result;
for (auto const & ss : s.shapes)
result |= bbox(ss);
return result;
}
}

View file

@ -12,4 +12,9 @@ namespace psemek::vecr
return {l - s.radius, {0.f, 0.f}};
}
geom::box<float, 2> bbox(circle const & s)
{
return geom::expand(geom::box<float, 2>::singleton(s.center), s.radius);
}
}

View file

@ -29,4 +29,9 @@ namespace psemek::vecr
return result;
}
geom::box<float, 2> bbox(fill const & s)
{
return bbox(s.border);
}
}

View file

@ -39,4 +39,12 @@ namespace psemek::vecr
return result;
}
geom::box<float, 2> bbox(intersect const & s)
{
auto result = geom::box<float, 2>::full();
for (auto const & ss : s.shapes)
result &= bbox(ss);
return result;
}
}

View file

@ -27,4 +27,14 @@ namespace psemek::vecr
return result;
}
geom::box<float, 2> bbox(path const & s)
{
geom::box<float, 2> result;
for (auto const & p : s.points)
result |= p;
return result;
}
}

View file

@ -28,6 +28,13 @@ namespace psemek::vecr
return result_;
}
gfx::pixmap_rgba renderer::release()
{
resolve();
canvas_.clear();
return std::move(result_);
}
void renderer::clear(gfx::color_rgba const & color)
{
canvas_.fill(color);
@ -39,22 +46,32 @@ namespace psemek::vecr
{
float const aa = primitive.blur / 2.f;
for (auto const & idx : canvas_.indices())
auto const box = geom::expand(bbox(primitive.mask), aa);
int xmin = std::max<int>(0, std::floor(box[0].min) * samples_);
int xmax = std::min<int>(canvas_.width() - 1, std::ceil(box[0].max) * samples_);
int ymin = std::max<int>(0, std::floor(box[1].min) * samples_);
int ymax = std::min<int>(canvas_.height() - 1, std::ceil(box[1].max) * samples_);
for (int y = ymin; y < ymax; ++y)
{
geom::point const center{(idx[0] + 0.5f) / samples_, (idx[1] + 0.5f) / samples_};
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);
auto const sample = sdf(primitive.mask, center);
if (sample.value > aa) continue;
if (sample.value > aa) continue;
float blur = 1.f;
if (sample.value > - aa)
blur = (aa - sample.value) / (2.f * aa);
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;
auto color = colorize(primitive.colorizer, center, sample);
color[3] *= blur;
canvas_(idx) = gfx::to_coloru8(primitive.blend(gfx::to_colorf(canvas_(idx)), color));
canvas_(x, y) = gfx::to_coloru8(primitive.blend(gfx::to_colorf(canvas_(x, y)), color));
}
}
need_resolve_ = true;