25 #include <boost/math/constants/constants.hpp>
26 #include <SDL3/SDL_rect.h>
27 #include <SDL3/SDL_render.h>
30 #define DBG_D LOG_STREAM(debug, log_draw)
31 #define WRN_D LOG_STREAM(warn, log_draw)
56 SDL_GetRenderDrawBlendMode(
renderer(), &
b);
57 SDL_SetRenderDrawBlendMode(
renderer(), SDL_BLENDMODE_NONE);
59 SDL_SetRenderDrawBlendMode(
renderer(),
b);
64 uint8_t r, uint8_t
g, uint8_t
b, uint8_t a)
67 SDL_SetRenderDrawColor(
renderer(), r,
g,
b, a);
69 SDL_RenderFillRect(
renderer(), &frect);
74 uint8_t r, uint8_t
g, uint8_t
b)
87 SDL_SetRenderDrawColor(
renderer(), r,
g,
b, a);
88 SDL_RenderFillRect(
renderer(),
nullptr);
103 DBG_D <<
"sub-pixel fill";
110 DBG_D <<
"fill " << area;
112 SDL_RenderFillRect(
renderer(), &frect);
118 SDL_RenderFillRect(
renderer(),
nullptr);
124 SDL_SetRenderDrawColor(
renderer(), r,
g,
b, a);
130 SDL_SetRenderDrawColor(
renderer(), r,
g,
b, SDL_ALPHA_OPAQUE);
135 DBG_D <<
"set color " <<
c;
141 SDL_SetRenderDrawBlendMode(
renderer(),
b);
182 uint8_t r, uint8_t
g, uint8_t
b, uint8_t a)
185 SDL_SetRenderDrawColor(
renderer(), r,
g,
b, a);
205 DBG_D <<
"line from (" << from_x <<
',' << from_y
206 <<
") to (" << to_x <<
',' << to_y <<
')';
207 SDL_RenderLine(
renderer(), from_x, from_y, to_x, to_y);
212 DBG_D <<
"line from (" << from_x <<
',' << from_y
213 <<
") to (" << to_x <<
',' << to_y
214 <<
") with colour " <<
c;
216 SDL_RenderLine(
renderer(), from_x, from_y, to_x, to_y);
222 static_assert(
sizeof(::
point) ==
sizeof(SDL_Point));
230 DBG_D <<
"point (" << x <<
',' << y <<
')';
242 DBG_D <<
"circle (" << cx <<
',' << cy
243 <<
") -> " << r <<
", oct " << int(octants);
252 std::vector<SDL_FPoint>
points;
255 points.push_back({
static_cast<float>(cx + y),
static_cast<float>(cy + x)});
258 points.push_back({
static_cast<float>(cx + y),
static_cast<float>(cy - x)});
261 points.push_back({
static_cast<float>(cx - y),
static_cast<float>(cy + x)});
264 points.push_back({
static_cast<float>(cx - y),
static_cast<float>(cy - x)});
285 DBG_D <<
"disc (" << cx <<
',' << cy
286 <<
") -> " << r <<
", oct " << int(octants);
298 draw::line(cx + x, cy + y + 1, cx + y + 1, cy + y + 1);
301 draw::line(cx + x, cy - y, cx + y + 1, cy - y);
304 draw::line(cx - x - 1, cy + y + 1, cx - y - 2, cy + y + 1);
307 draw::line(cx - x - 1, cy - y, cx - y - 2, cy - y);
311 draw::line(cx + y, cy + x + 1, cx + y, cy + y + 1);
317 draw::line(cx - y - 1, cy + x + 1, cx - y - 1, cy + y + 1);
320 draw::line(cx - y - 1, cy - x, cx - y - 1, cy - y);
343 int render_size =
draw_size * pixel_scale;
345 surface sdl_surf(render_size, render_size);
347 reinterpret_cast<uint8_t*
>(sdl_surf->pixels), ::
point(sdl_surf->w, sdl_surf->h));
350 cairo_t* ctx = cairo_context.get();
351 cairo_scale(ctx, pixel_scale, pixel_scale);
353 cairo_set_antialias(ctx, CAIRO_ANTIALIAS_BEST);
354 cairo_set_source_rgba(ctx, 0.0, 0.0, 0.0, 0.0);
357 cairo_set_line_width(ctx, thickness);
358 cairo_set_source_rgba(ctx,
366 double half_thickness = 1.0 * thickness / 2;
367 cairo_arc(ctx, r, r, r - half_thickness, 0, 2 * boost::math::constants::pi<double>());
381 int render_size =
draw_size * pixel_scale;
383 surface sdl_surf(render_size, render_size);
385 reinterpret_cast<uint8_t*
>(sdl_surf->pixels), ::
point(sdl_surf->w, sdl_surf->h));
388 cairo_t* ctx = cairo_context.get();
389 cairo_scale(ctx, pixel_scale, pixel_scale);
391 cairo_set_antialias(ctx, CAIRO_ANTIALIAS_BEST);
392 cairo_set_source_rgba(ctx,
398 cairo_arc(ctx, r, r, r, 0, 2 * boost::math::constants::pi<double>());
415 if (!tex) {
DBG_D <<
"null blit";
return; }
418 const SDL_Rect*
rect = tex.
src();
422 SDL_RenderTexture(
renderer(), tex, &frect, &fdst);
424 SDL_RenderTexture(
renderer(), tex,
nullptr, &fdst);
430 if (!tex) {
DBG_D <<
"null blit";
return; }
433 const SDL_Rect*
rect = tex.
src();
436 SDL_RenderTexture(
renderer(), tex, &frect,
nullptr);
438 SDL_RenderTexture(
renderer(), tex,
nullptr,
nullptr);
443 static SDL_FlipMode
get_flip(
bool flip_h,
bool flip_v)
446 return static_cast<SDL_FlipMode
>(
447 static_cast<int>(flip_h ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE)
448 |
static_cast<int>(flip_v ? SDL_FLIP_VERTICAL : SDL_FLIP_NONE)
462 if (!tex) {
DBG_D <<
"null flipped";
return; }
463 DBG_D <<
"flipped (" << flip_h <<
'|' << flip_v
466 SDL_FlipMode flip =
get_flip(flip_h, flip_v);
467 const SDL_Rect*
rect = tex.
src();
471 SDL_RenderTextureRotated(
renderer(), tex, &frect, &fdst, 0.0,
nullptr, flip);
473 SDL_RenderTextureRotated(
renderer(), tex,
nullptr, &fdst, 0.0,
nullptr, flip);
479 if (!tex) {
DBG_D <<
"null flipped";
return; }
480 DBG_D <<
"flipped (" << flip_h <<
'|' << flip_v <<
')';
482 SDL_FlipMode flip =
get_flip(flip_h, flip_v);
483 const SDL_Rect*
rect = tex.
src();
486 SDL_RenderTextureRotated(
renderer(), tex, &frect,
nullptr, 0.0,
nullptr, flip);
488 SDL_RenderTextureRotated(
renderer(), tex,
nullptr,
nullptr, 0.0,
nullptr, flip);
497 if (!tex) {
DBG_D <<
"null tiled";
return; }
498 DBG_D <<
"tiled (" << centered <<
'|' << mirrored
504 const int xoff = centered ? (
dst.w - tex.
w()) / 2 : 0;
505 const int yoff = centered ? (
dst.h - tex.
h()) / 2 : 0;
510 for (;
t.y <
dst.y +
dst.h;
t.y +=
t.h, vf = !vf) {
512 for (
t.x =
dst.x - xoff;
t.x <
dst.x +
dst.w;
t.x +=
t.w, hf = !hf) {
523 bool centered,
bool mirrored)
525 if (!tex) {
DBG_D <<
"null tiled_highres";
return; }
526 DBG_D <<
"tiled_highres (" << centered <<
'|' << mirrored
535 const float w = float(
size.x) / float(pixel_scale);
536 const float h = float(
size.y) / float(pixel_scale);
537 const float xoff = centered ? (
dst.w -
w) / 2 : 0.0f;
538 const float yoff = centered ? (
dst.h -
h) / 2 : 0.0f;
542 SDL_FRect
t{
dst.x - xoff,
dst.y - yoff,
w,
h};
543 for (;
t.y <
dst.y +
dst.h;
t.y +=
t.h, vf = !vf) {
545 for (
t.x =
dst.x - xoff;
t.x <
dst.x +
dst.w;
t.x +=
t.w, hf = !hf) {
547 SDL_FlipMode flip =
get_flip(hf, vf);
548 SDL_RenderTextureRotated(
renderer(), tex,
nullptr, &
t, 0.0,
nullptr, flip);
550 SDL_RenderTexture(
renderer(), tex,
nullptr, &
t);
557 const std::array<SDL_Vertex, 4>& verts)
559 DBG_D <<
"smooth shade, verts:";
560 for (
const SDL_Vertex& v : verts) {
561 DBG_D <<
" {(" << v.position.x <<
',' << v.position.y <<
") "
562 << v.color.r <<
"," << v.color.g <<
"," << v.color.b <<
"," << v.color.a
563 <<
" (" << v.tex_coord.x <<
',' << v.tex_coord.y
566 int indices[6] = {0, 1, 2, 2, 1, 3};
567 SDL_RenderGeometry(
renderer(), tex, &verts[0], 4, indices, 6);
607 WRN_D <<
"trying to force clip will null renderer";
610 DBG_D <<
"forcing clip to " << clip;
612 SDL_SetRenderClipRect(
renderer(), &clip);
622 if (!SDL_RenderClipEnabled(
renderer())) {
627 SDL_GetRenderClipRect(
renderer(), &clip);
636 return SDL_RenderClipEnabled(
renderer());
644 SDL_SetRenderClipRect(
renderer(),
nullptr);
645 DBG_D <<
"clip disabled";
653 if (!SDL_RenderClipEnabled(
renderer())) {
657 SDL_GetRenderClipRect(
renderer(), &clip);
658 return clip.w <= 0 || clip.h <= 0;
671 c_.x +
v_.x - view.x,
672 c_.y +
v_.y - view.y,
697 WRN_D <<
"trying to force viewport will null renderer";
700 DBG_D <<
"forcing viewport to " << viewport;
702 SDL_SetRenderViewport(
renderer(), &viewport);
708 WRN_D <<
"no renderer available to get viewport";
713 SDL_GetRenderViewport(
renderer(), &viewport);
727 assert(!
t ||
t.get_access() == SDL_TEXTUREACCESS_TARGET);
730 WRN_D <<
"can't set render target with null renderer";
748 WRN_D <<
"can't reset render target with null renderer";
752 SDL_SetRenderViewport(
renderer(), &viewport_);
754 SDL_SetRenderClipRect(
renderer(), &clip_);
760 DBG_D <<
"setting render target to "
761 <<
t.w() <<
'x' <<
t.h() <<
" texture";
763 DBG_D <<
"setting render target to main render buffer";
A class to manage automatic restoration of the clipping region.
clip_setter(const ::rect &clip)
A class to manage automatic restoration of the render target.
render_target_setter(const texture &t)
A class to manage automatic restoration of the viewport region.
viewport_setter(const ::rect &viewport)
Wrapper class to encapsulate creation and management of an SDL_Texture.
int w() const
The draw-space width of the texture, in pixels.
point get_raw_size() const
The raw internal texture size.
const rect * src() const
A pointer to a rect indicating the source region of the underlying SDL_Texture to be used when drawin...
int h() const
The draw-space height of the texture, in pixels.
static lg::log_domain log_draw("draw")
static bool sdl_bad_at_rects()
Some versions of SDL have a bad rectangle drawing implementation.
static SDL_Renderer * renderer()
static void draw_rect_as_lines(const rect &rect)
For some SDL versions, draw rectangles as lines.
static SDL_FlipMode get_flip(bool flip_h, bool flip_v)
SDL_FRect rect_to_frect(const SDL_Rect &rect)
Drawing functions, for drawing things on the screen.
const gui2::tracked_drawable & target_
The drawable whose render calls we are tracking.
Standard logging facilities (interface).
context_ptr create_context(const surface_ptr &surf)
surface_ptr create_surface(uint8_t *buffer, const point &size)
void force_viewport(const ::rect &viewport)
Set the viewport, without any provided way of setting it back.
void tiled_highres(const texture &tex, const ::rect &dst, bool centered=false, bool mirrored=false)
Tile a texture to fill a region.
render_target_setter set_render_target(const texture &t)
Set the given texture as the active render target.
void circle(int x, int y, int r, const color_t &c, uint8_t octants=0xff)
Draw a circle of the given colour.
void tiled(const texture &tex, const ::rect &dst, bool centered=false, bool mirrored=false)
Tile a texture to fill a region.
void points(const std::vector< SDL_FPoint > &points)
Draw a set of points.
void rect(const ::rect &rect)
Draw a rectangle.
void cairo_disc(int cx, int cy, int r, const color_t &c)
Draw filled circle using Cairo.
bool null_clip()
Whether the current clipping region will disallow drawing.
bool clip_enabled()
Whether clipping is enabled.
clip_setter reduce_clip(const ::rect &clip)
Set the clipping area to the intersection of the current clipping area and the given rectangle.
void flipped(const texture &tex, const ::rect &dst, bool flip_h=true, bool flip_v=false)
Draws a texture, or part of a texture, at the given location, also mirroring/flipping the texture hor...
void cairo_circle(int cx, int cy, int r, const color_t &c, int thickness)
Draw outline of circle using Cairo.
void disc(int x, int y, int r, const color_t &c, uint8_t octants=0xff)
Draw a solid disc of the given colour.
void set_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Set the drawing colour.
clip_setter override_clip(const ::rect &clip)
Override the clipping area.
void point(int x, int y)
Draw a single point.
void clear()
Clear the current render target.
void smooth_shaded(const texture &tex, const std::array< SDL_Vertex, 4 > &verts)
Draw a texture with smoothly varying colour and alpha modification, specified at the four corners of ...
void set_blend_mode(SDL_BlendMode b)
Set the blend mode used for drawing operations such as fill() and line().
void force_clip(const ::rect &clip)
Set the clipping area, without any provided way of setting it back.
viewport_setter set_viewport(const ::rect &viewport)
Set the viewport.
void fill(const ::rect &rect, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Fill an area with the given colour.
::rect get_viewport()
Get the current viewport.
::rect get_clip()
Get the current clipping area, in draw coordinates.
void disable_clip()
Disable clipping.
void blit(const texture &tex, const ::rect &dst)
Draws a texture, or part of a texture, at the given location.
void line(int from_x, int from_y, int to_x, int to_y)
Draw a line.
constexpr const SDL_Rect empty_rect
bool runtime_at_least(uint8_t major, uint8_t minor=0, uint8_t patch=0)
Returns true if the runtime SDL version is at or greater than the specified version,...
std::size_t size(std::string_view str)
Length in characters of a UTF-8 string.
rect draw_area()
The current drawable area.
void reset_render_target()
Reset the render target to the primary render buffer.
void force_render_target(const texture &t)
Set the render target, without any provided way of setting it back.
int get_pixel_scale()
Get the current active pixel scale multiplier.
SDL_Renderer * get_renderer()
texture get_render_target()
Get the current render target.
point draw_size()
The size of the current render target in drawing coordinates.
Contains the SDL_Rect helper code.
rect dst
Location on the final composed sheet.
The basic class for representing 8-bit RGB or RGBA colour values.
An abstract description of a rectangle with integer coordinates.