25 vec2i{0, image.height},
48 for(
int y = bottom;
y < top; ++
y)
50 if(y < 0 || y >= image->height)
54 for(
int x = left;
x < right; ++
x)
56 if(x < 0 || x >= image->width)
60 image->set_pixel(
x,
y, color);
83 calculate_bounding_rect(
const std::vector<vec2f>& poly)
85 const auto [
min,
max] = find_min_max<vec2f>
88 [](
const auto& lhs,
const auto& rhs)
96 [](
const auto& lhs,
const auto& rhs)
110 does_ray_intersect_segment(
const vec2f& u,
const vec2f& a,
const vec2f& b)
114 (
a.y >
u.y) != (
b.y >
u.y) &&
115 u.x < (
b.x -
a.x) * (
u.y -
a.y) / (
b.y -
a.y) +
a.x
120 point_is_in_poly(
const vec2f& p,
const std::vector<vec2f>& poly)
128 auto previous_point = poly[0];
129 auto in = does_ray_intersect_segment(p, *poly.rbegin(), previous_point);
131 for(
auto poly_iterator = poly.begin() + 1; poly_iterator != poly.end(); ++poly_iterator)
133 const auto current_point = *poly_iterator;
134 if(does_ray_intersect_segment(p, previous_point, current_point))
138 previous_point = current_point;
150 const auto rect = calculate_bounding_rect(poly);
158 for(
int y = bottom;
y < top; ++
y)
160 if(y < 0 || y >= image->height) {
continue; }
161 for(
int x = left;
x < right; ++
x)
163 if(x < 0 || x >= image->width) {
continue; }
167 image->set_pixel(
x,
y, color);
201 for(
int y = top;
y < bottom; ++
y)
203 for(
int x = left;
x < right; ++
x)
208 vec2f{
static_cast<float>(
x),
static_cast<float>(
y)},
212 float blend_factor = 1.0f;
214 const auto a =
make_range(inner - softness, inner);
215 const auto b =
make_range(radius, radius + softness);
219 blend_factor =
to01(
a, sq);
224 blend_factor = 1.0f -
to01(
b, sq);
247 image->set_pixel(
x,
y,
Rgbai{paint_color});
266 auto plot = [&](
int x,
int y)
268 image->set_pixel(
x,
y, color);
271 auto plot_line_low = [&](
int x0,
int y0,
int x1,
int y1)
286 for(
int x=x0;
x<
x1;
x+=1)
298 auto plot_line_high = [&](
int x0,
int y0,
int x1,
int y1)
311 for(
int y=y0;
y<y1;
y+=1)
323 const auto x0 = from.
x;
324 const auto y0 = from.
y;
325 const auto x1 = to.
x;
326 const auto y1 = to.
y;
329 if(x0 >
x1) { plot_line_low(
x1, y1, x0, y0); }
330 else { plot_line_low(x0, y0,
x1, y1); }
334 if(y0 > y1) { plot_line_high(
x1, y1, x0, y0); }
335 else { plot_line_high(x0, y0,
x1, y1); }
373 auto round = [&](
float x) ->
int {
return ipart(
x + 0.5f); };
374 auto fpart = [&](
float x) ->
float {
return x -
std::floor(
x); };
375 auto rfpart = [&](
float x) ->
float {
return 1.0f - fpart(
x); };
377 auto plot = [&](
int x,
int y,
float c)
382 if(valid_x && valid_y)
390 image->set_pixel(
x,
y,
Rgbai{paint_color});
403 auto steep =
abs(y1 - y0) >
abs(
x1 - x0);
418 float gradient = dy / dx;
425 auto xend =
round(x0);
427 auto xgap = rfpart(x0 + 0.5f);
429 auto ypxl1 = ipart(yend);
432 plot(ypxl1, xpxl1, rfpart(yend) * xgap);
433 plot(ypxl1+1, xpxl1, fpart(yend) * xgap);
437 plot(xpxl1, ypxl1 , rfpart(yend) * xgap);
438 plot(xpxl1, ypxl1+1, fpart(yend) * xgap);
440 auto intery = yend + gradient;
445 xgap = fpart(
x1 + 0.5f);
447 auto ypxl2 = ipart(yend);
451 plot(ypxl2 , xpxl2, rfpart(yend) * xgap);
452 plot(ypxl2+1, xpxl2, fpart(yend) * xgap);
456 plot(xpxl2, ypxl2, rfpart(yend) * xgap);
457 plot(xpxl2, ypxl2+1, fpart(yend) * xgap);
463 for(
auto x=xpxl1 + 1;
x<=xpxl2 - 1;
x+=1)
465 plot(ipart(intery) ,
x, rfpart(intery));
466 plot(ipart(intery)+1,
x, fpart(intery));
467 intery = intery + gradient;
472 for(
auto x = xpxl1 + 1;
x<xpxl2 - 1;
x+=1)
474 plot(
x, ipart(intery), rfpart(intery));
475 plot(
x, ipart(intery)+1, fpart(intery));
476 intery = intery + gradient;
483 return {{
c.r * tint.
r,
c.g * tint.
g,
c.b * tint.
b},
c.a};
504 const auto dx =
p.x +
x;
505 const auto dy =
p.y +
y;
506 if(dx >= dst->
width) {
continue; }
507 if(dy >= dst->
height) {
continue; }
508 const auto dst_color = dst->
get_pixel(dx, dy);
510 const auto tinted_color =
tint_color(src_color, tint);
511 const auto result_color =
blend(tinted_color, dst_color);
521 const vec2i& start_pos,
522 const std::string& text,
529 vec2i pos = start_pos;
543 const auto& glyph = glyph_found->second;
544 blend_image(image, pos, glyph.image, color);
545 pos.x += glyph.advance;
555 const vec2i& position,
556 const Image& source_image,
563 for(
int y = 0;
y < source_image.
height; ++
y)
565 for(
int x = 0;
x < source_image.
width; ++
x)
567 const auto dest_x = position.
x +
x;
568 const auto dest_y = position.
y +
y;
580 const auto bottom = dest_image->
get_pixel(dest_x, dest_y);
581 const auto color =
blend(top, bottom, blend_mode);
582 dest_image->
set_pixel(dest_x, dest_y, color);
599 const auto [minf, maxf] = find_min_max<vec2f, std::vector<vec2f> >
612 const auto min = minf.to_i();
613 const auto max = maxf.to_i();
621 0,
x, image->width - 1
625 0,
y, image->height - 1
627 if(valid_x && valid_y)
634 vec2f{
static_cast<float>(
x),
static_cast<float>(
y)}
638 image->set_pixel(
x,
y, color);
660 const vec2f arrow_point = to;
665 const auto arrow_angle =
atan2(
abs(from.
y - to.
y),
abs(from.
x - to.
x));
666 const auto angle_b =
atan2((3 * size), (arrow_length - (3 * size)));
667 const auto secondary_length = (3 * size) /
sin(angle_b);
670 const auto arrow_point_left_x = from.
x > to.
x
671 ? from.
x - (
sin(angle_c) * secondary_length)
672 : (
sin(angle_c) * secondary_length) + from.
x
674 const auto arrow_point_left_y = from.
y > to.
y
675 ? from.
y - (
cos(angle_c) * secondary_length)
676 : (
cos(angle_c) * secondary_length) + from.
y
678 const auto arrow_point_left =
vec2f
685 angle_c = arrow_angle - angle_b;
687 const auto arrow_point_right_x = from.
x > to.x
688 ? from.x - (
cos(angle_c) * secondary_length)
689 : (
cos(angle_c) * secondary_length) + from.x
691 const auto arrow_point_right_y = from.y > to.y
692 ? from.y - (
sin(angle_c) * secondary_length)
693 : (
sin(angle_c) * secondary_length) + from.y
695 const auto arrow_point_right =
vec2f
Rgb blend(const Rgb &top, const Rgb &bottom, BlendMode mode)
void fill_triangle(Image *image, const vec2f &a, const vec2f &b, const vec2f &c, const Rgbai &color)
void draw_line_antialiased(Image *image, const Rgb &color, const vec2f &from, const vec2f &to)
void clear(Image *image, const Rgbai &color)
void draw_text(Image *image, const vec2i &start_pos, const std::string &text, const Rgbai &color, const LoadedFont &font)
void draw_circle(Image *image, const Rgb &color, const vec2i ¢er, float radius, float softness, float inner)
void draw_arrow(Image *image, const vec2f &from, const vec2f &to, const Rgbai &color, float size)
void blend_image(Image *dst, const vec2i &p, const Image &src, const Rgbai &tint)
void fill_poly(Image *image, const Rgbai &color, const std::vector< vec2f > &poly)
bool calc_utf8_to_codepoints(const TString &string, TOnCodepointFunc on_codepoint)
void draw_line_fast(Image *image, const Rgbai &color, const vec2i &from, const vec2i &to)
Recti on_whole_image(const Image &image)
Rgba tint_color(const Rgba &c, const Rgb &tint)
bool is_point_in_triangle(const vec2f &a, const vec2f &b, const vec2f &c, const vec2f &p)
void draw_line_antialiased(Image *image, const Rgb &color, const vec2i &from, const vec2i &to)
void draw_square(Image *image, const Rgbai &color, int x, int y, int size)
void paste_image(Image *dest_image, const vec2i &position, const Image &source_image, BlendMode blend_mode, PixelsOutside clip)
void draw_rect(Image *image, const Rgbai &color, const Recti &rect)
constexpr ShaderAttribute color
Rgbai to_rgbai(const Rgba &c)
Angle atan2(float y, float x)
constexpr int c_float_to_int(float f)
bool is_within_inclusive_as_int(int min, int c, int max)
float to01(const Range< T > &range, T value)
Range< T > make_range(T min, T max)
Rgb to_rgb(const Rgbi &c)
constexpr float abs(float r)
float round(float num, float gran)
Rounds a value to the nearest nice value.
constexpr float c_int_to_float(int i)
float cos(const Angle &ang)
size2f min(const size2f lhs, const size2f rhs)
Rgba to_rgba(const Rgbai &c)
Rgb lerp_rgb(const Rgb &from, float v, const Rgb &to)
float sin(const Angle &ang)
bool is_within(const Range< T > &range, T value)
size2f max(const size2f lhs, const size2f rhs)
int floor_to_int(float v)
constexpr static Angle from_degrees(float degrees)
static Rectf from_left_right_bottom_top(float left_side, float right_side, float bottom_side, float top_side)
vec2i get_top_right() const
vec2i get_bottom_left() const
vec2i get_top_left() const
static Recti from_top_left_width_height(const vec2i &topleft, int width, int height)
Recti get_indices() const
void set_pixel(int x, int y, const Rgbai &color)
Rgbai get_pixel(int x, int y) const
std::map< int, LoadedGlyph > codepoint_to_glyph
static vec2f from_to(const vec2f &from, const vec2f &to)