bwidgets/src/core/draw.cpp

77 lines
2.7 KiB
C++

#include <algorithm>
#include <cmath>
#include <vector>
#include <SDL_render.h>
#include <basic_widgets/core/draw.hpp>
#include <basic_widgets/core/math.hpp>
#include <basic_widgets/core/texture.hpp>
namespace bwidgets
{
auto aa(const Color base_color, const int aa_pixels, const float d) noexcept -> Color
{
Color c = [aa_pixels, base_color, d]() -> Color {
const auto [r, g, b, a] = base_color();
// AA disabled, returns fully opaque or fully transparent colors
if (aa_pixels == 0) {
if (d > 0) return {r, g, b, 0};
return {r, g, b, a};
}
const auto factor = 1.0 - smoothstep<float>(d, (float)-aa_pixels, 0.);
return {r, g, b, (uint8_t)((float)base_color().a * factor)};
}();
return c;
}
auto filled_circle(const Color c, const int resolution, const Renderer& r,
const int aa_pixels) -> std::shared_ptr<Texture>
{
// clang-format off
auto texture {std::make_shared<Texture>(
r,
SDL_PIXELFORMAT_RGBA32,
SDL_TEXTUREACCESS_STATIC,
resolution,
resolution)};
// clang-format on
const auto radius {resolution / 2};
const SDL_Point center {radius, radius};
set_pixels_color(texture.get(),
[aa_pixels, c, center, radius](
SDL_Point p, const SDL_PixelFormat& format) -> uint32_t {
const auto d_delta = distance(center, p) - (float)radius;
const auto aa_color = aa(c, aa_pixels, d_delta);
return SDL_MapRGBA(&format, aa_color().r, aa_color().g,
aa_color().b, aa_color().a);
});
texture->blend_mode(SDL_BLENDMODE_BLEND);
texture->scale_mode(SDL_ScaleModeNearest);
return texture;
}
void set_pixels_color(
Texture& t,
const std::function<uint32_t(SDL_Point, const SDL_PixelFormat&)>& pixel_color)
{
auto attr = t.attributes();
auto pitch = attr.w * attr.format->BytesPerPixel;
std::vector<uint32_t> pixels;
pixels.reserve(attr.h * (std::vector<uint32_t>::size_type)pitch);
// TODO parallel algo
for (auto y = 0; y < attr.h; y++) {
for (auto x = 0; x < attr.w; x++) {
pixels.emplace_back(pixel_color({x, y}, *attr.format));
}
}
t.update(nullptr, (const void*)pixels.data(), pitch);
}
}