Add generator & pixmap mapping functions

This commit is contained in:
Nikita Lisitsa 2020-09-13 11:05:24 +03:00
parent 395df40793
commit da7b71b504

View file

@ -0,0 +1,120 @@
#pragma once
#include <psemek/gfx/pixmap.hpp>
#include <psemek/pcg/seamless.hpp>
#include <vector>
#include <type_traits>
namespace psemek::pcg
{
// TODO: return a proper generator instead of a lambda
template <typename Gen, typename F>
auto map_(Gen && gen, F && f)
{
return [gen = std::forward<Gen>(gen), f = std::forward<F>(f)](float x, float y)
{
return f(gen(x, y));
};
}
template <typename T, typename F, typename R = decltype(std::declval<F>()(std::declval<T>())),
typename = std::enable_if_t<std::is_same_v<T, R>>>
auto map(gfx::basic_pixmap<T> p, F && f)
{
for (std::size_t j = 0; j < p.height(); ++j)
{
for (std::size_t i = 0; i < p.width(); ++i)
{
p(i, j) = f(p(i, j));
}
}
return p;
}
template <typename T, typename F, typename R = decltype(std::declval<F>()(std::declval<T>())),
typename = std::enable_if_t<!std::is_same_v<T, R>>>
auto map(gfx::basic_pixmap<T> const & p, F && f)
{
gfx::basic_pixmap<R> result({p.width(), p.height()});
for (std::size_t j = 0; j < p.height(); ++j)
{
for (std::size_t i = 0; i < p.width(); ++i)
{
result(i, j) = f(p(i, j));
}
}
return result;
}
template <typename T, typename F>
auto map_neumann(gfx::basic_pixmap<T> const & pixmap, F && f, seamless_tag)
{
std::vector<T> n;
n.reserve(4);
using R = decltype(f(pixmap(0, 0), n));
std::size_t const w = pixmap.width();
std::size_t const h = pixmap.height();
gfx::basic_pixmap<R> result({w, h});
for (std::size_t j = 0; j < h; ++j)
{
for (std::size_t i = 0; i < w; ++i)
{
n.push_back(pixmap((i + 1) % w, j));
n.push_back(pixmap((i + w - 1) % w, j));
n.push_back(pixmap(i, (j + 1) % h));
n.push_back(pixmap(i, (j + h - 1) % h));
result(i, j) = f(pixmap(i, j), n);
n.clear();
}
}
return result;
}
template <typename T, typename F>
auto map_moore(gfx::basic_pixmap<T> const & pixmap, F && f, seamless_tag)
{
std::vector<T> n;
n.reserve(8);
using R = decltype(f(pixmap(0, 0), n));
std::size_t const w = pixmap.width();
std::size_t const h = pixmap.height();
gfx::basic_pixmap<R> result({w, h});
for (std::size_t j = 0; j < h; ++j)
{
for (std::size_t i = 0; i < w; ++i)
{
n.push_back(pixmap((i + 1) % w, j));
n.push_back(pixmap((i + 1) % w, (j + 1) % h));
n.push_back(pixmap(i, (j + 1) % h));
n.push_back(pixmap((i + w - 1) % w, (j + 1) % h));
n.push_back(pixmap((i + w - 1) % w, j));
n.push_back(pixmap((i + w - 1) % w, (j + h - 1) % h));
n.push_back(pixmap(i, (j + h - 1) % h));
n.push_back(pixmap((i + 1) % w, (j + h - 1) % h));
result(i, j) = f(pixmap(i, j), n);
n.clear();
}
}
return result;
}
}