77 lines
2.7 KiB
C++
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);
|
|
}
|
|
}
|