bwidgets/src/core/draw.cpp

69 lines
2.2 KiB
C++

#include <algorithm>
#include <cmath>
#include <vector>
#include <SDL2/SDL_render.h>
#include <basic_widgets/core/draw.hpp>
#include <basic_widgets/core/math.hpp>
#include <basic_widgets/core/texture.hpp>
namespace bwidgets::core
{
auto aa(const SDL_Color& base_color, const int aa_pixels, const float d) noexcept
-> SDL_Color
{
SDL_Color c {base_color};
if (aa_pixels == 0) {
if (d > 0) c.a = 0;
}
else {
const auto factor = 1.0 - smoothstep<float>(d, (float)-aa_pixels, 0.);
c.a = (uint8_t)((float)c.a * factor);
}
return c;
}
auto filled_circle(const SDL_Color& c, const int resolution, core::Renderer* r,
const int aa_pixels) -> core::Texture*
{
auto* texture {new core::Texture(
r, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, resolution, resolution)};
const auto radius {resolution / 2};
const SDL_Point center {radius, radius};
set_pixels_color(
texture,
[aa_pixels, c, center, radius](const SDL_Point& p,
const SDL_PixelFormat* format) -> uint32_t {
const auto d_delta = core::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(
core::Texture* t,
const std::function<Uint32(const 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);
for (auto y = 0; y < attr.h; y++) {
for (auto x = 0; x < attr.w; x++) {
pixels.push_back(pixel_color({x, y}, attr.format));
}
}
t->update(nullptr, (const void*)pixels.data(), pitch);
}
}