The Battle for Wesnoth  1.17.17+dev
draw.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2022 - 2023
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include "draw.hpp"
16 
17 #include "color.hpp"
18 #include "log.hpp"
19 #include "sdl/rect.hpp"
20 #include "sdl/surface.hpp"
21 #include "sdl/texture.hpp"
22 #include "sdl/utils.hpp" // sdl::runtime_at_least
23 #include "video.hpp"
24 
25 #include <SDL2/SDL_rect.h>
26 #include <SDL2/SDL_render.h>
27 
28 static lg::log_domain log_draw("draw");
29 #define DBG_D LOG_STREAM(debug, log_draw)
30 #define WRN_D LOG_STREAM(warn, log_draw)
31 
32 static SDL_Renderer* renderer()
33 {
34  return video::get_renderer();
35 }
36 
37 /**************************************/
38 /* basic drawing and pixel primatives */
39 /**************************************/
40 
42  const SDL_Rect& area,
43  uint8_t r, uint8_t g, uint8_t b, uint8_t a)
44 {
45  DBG_D << "fill " << area << ' ' << color_t{r,g,b,a};
46  SDL_SetRenderDrawColor(renderer(), r, g, b, a);
47  SDL_RenderFillRect(renderer(), &area);
48 }
49 
51  const SDL_Rect& area,
52  uint8_t r, uint8_t g, uint8_t b)
53 {
54  draw::fill(area, r, g, b, SDL_ALPHA_OPAQUE);
55 }
56 
57 void draw::fill(const SDL_Rect& area, const color_t& c)
58 {
59  draw::fill(area, c.r, c.g, c.b, c.a);
60 }
61 
62 void draw::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
63 {
64  DBG_D << "fill " << color_t{r,g,b,a};
65  SDL_SetRenderDrawColor(renderer(), r, g, b, a);
66  SDL_RenderFillRect(renderer(), nullptr);
67 }
68 
69 void draw::fill(uint8_t r, uint8_t g, uint8_t b)
70 {
71  draw::fill(r, g, b, SDL_ALPHA_OPAQUE);
72 }
73 
74 void draw::fill(const color_t& c)
75 {
76  draw::fill(c.r, c.g, c.b, c.a);
77 }
78 
79 void draw::fill(const SDL_Rect& area)
80 {
81  DBG_D << "fill " << area;
82  SDL_RenderFillRect(renderer(), &area);
83 }
84 
85 void draw::fill()
86 {
87  DBG_D << "fill";
88  SDL_RenderFillRect(renderer(), nullptr);
89 }
90 
91 void draw::set_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
92 {
93  DBG_D << "set color " << color_t{r,g,b,a};
94  SDL_SetRenderDrawColor(renderer(), r, g, b, a);
95 }
96 
97 void draw::set_color(uint8_t r, uint8_t g, uint8_t b)
98 {
99  DBG_D << "set color " << color_t{r,g,b};
100  SDL_SetRenderDrawColor(renderer(), r, g, b, SDL_ALPHA_OPAQUE);
101 }
102 
104 {
105  DBG_D << "set color " << c;
106  SDL_SetRenderDrawColor(renderer(), c.r, c.g, c.b, c.a);
107 }
108 
109 void draw::set_blend_mode(SDL_BlendMode b)
110 {
111  SDL_SetRenderDrawBlendMode(renderer(), b);
112 }
113 
114 /** Some versions of SDL have a bad rectangle drawing implementation. */
115 static bool sdl_bad_at_rects()
116 {
117  // This could be done once at program start and cached,
118  // but it isn't all that heavy.
119  if (sdl::runtime_at_least(2,0,15) && !sdl::runtime_at_least(2,0,18)) {
120  return true;
121  }
122  return false;
123 }
124 
125 /** For some SDL versions, draw rectangles as lines. */
126 static void draw_rect_as_lines(const SDL_Rect& rect)
127 {
128  // w and h indicate the final pixel width/height of the box.
129  // This is 1 greater than the difference in corner coordinates.
130  if (rect.w <= 0 || rect.h <= 0) {
131  return;
132  }
133  int x2 = rect.x + rect.w - 1;
134  int y2 = rect.y + rect.h - 1;
135  draw::line(rect.x, rect.y, x2, rect.y);
136  draw::line(rect.x, rect.y, rect.x, y2);
137  draw::line(x2, rect.y, x2, y2);
138  draw::line(rect.x, y2, x2, y2);
139 }
140 
141 void draw::rect(const SDL_Rect& rect)
142 {
143  DBG_D << "rect " << rect;
144  if (sdl_bad_at_rects()) {
145  return draw_rect_as_lines(rect);
146  }
147  SDL_RenderDrawRect(renderer(), &rect);
148 }
149 
150 void draw::rect(const SDL_Rect& rect,
151  uint8_t r, uint8_t g, uint8_t b, uint8_t a)
152 {
153  DBG_D << "rect " << rect << ' ' << color_t{r,g,b,a};
154  SDL_SetRenderDrawColor(renderer(), r, g, b, a);
155  if (sdl_bad_at_rects()) {
156  return draw_rect_as_lines(rect);
157  }
158  SDL_RenderDrawRect(renderer(), &rect);
159 }
160 
161 void draw::rect(const SDL_Rect& rect, uint8_t r, uint8_t g, uint8_t b)
162 {
163  draw::rect(rect, r, g, b, SDL_ALPHA_OPAQUE);
164 }
165 
166 void draw::rect(const SDL_Rect& rect, const color_t& c)
167 {
168  draw::rect(rect, c.r, c.g, c.b, c.a);
169 }
170 
171 void draw::line(int from_x, int from_y, int to_x, int to_y)
172 {
173  DBG_D << "line from (" << from_x << ',' << from_y
174  << ") to (" << to_x << ',' << to_y << ')';
175  SDL_RenderDrawLine(renderer(), from_x, from_y, to_x, to_y);
176 }
177 
178 void draw::line(int from_x, int from_y, int to_x, int to_y, const color_t& c)
179 {
180  DBG_D << "line from (" << from_x << ',' << from_y
181  << ") to (" << to_x << ',' << to_y
182  << ") with colour " << c;
183  SDL_SetRenderDrawColor(renderer(), c.r, c.g, c.b, c.a);
184  SDL_RenderDrawLine(renderer(), from_x, from_y, to_x, to_y);
185 }
186 
187 void draw::points(const std::vector<SDL_Point>& points)
188 {
189  DBG_D << points.size() << " points";
190  SDL_RenderDrawPoints(renderer(), points.data(), points.size());
191 }
192 
193 void draw::point(int x, int y)
194 {
195  DBG_D << "point (" << x << ',' << y << ')';
196  SDL_RenderDrawPoint(renderer(), x, y);
197 }
198 
199 void draw::circle(int cx, int cy, int r, const color_t& c, uint8_t octants)
200 {
202  draw::circle(cx, cy, r, octants);
203 }
204 
205 void draw::circle(int cx, int cy, int r, uint8_t octants)
206 {
207  DBG_D << "circle (" << cx << ',' << cy
208  << ") -> " << r << ", oct " << int(octants);
209 
210  // Algorithm based on
211  // http://de.wikipedia.org/wiki/Rasterung_von_Kreisen#Methode_von_Horn
212  // version of 2011.02.07.
213  int d = -r;
214  int x = r;
215  int y = 0;
216 
217  std::vector<SDL_Point> points;
218 
219  while(!(y > x)) {
220  if(octants & 0x04) points.push_back({cx + x, cy + y});
221  if(octants & 0x02) points.push_back({cx + x, cy - y});
222  if(octants & 0x20) points.push_back({cx - x, cy + y});
223  if(octants & 0x40) points.push_back({cx - x, cy - y});
224 
225  if(octants & 0x08) points.push_back({cx + y, cy + x});
226  if(octants & 0x01) points.push_back({cx + y, cy - x});
227  if(octants & 0x10) points.push_back({cx - y, cy + x});
228  if(octants & 0x80) points.push_back({cx - y, cy - x});
229 
230  d += 2 * y + 1;
231  ++y;
232  if(d > 0) {
233  d += -2 * x + 2;
234  --x;
235  }
236  }
237 
239 }
240 
241 void draw::disc(int cx, int cy, int r, const color_t& c, uint8_t octants)
242 {
244  draw::disc(cx, cy, r, octants);
245 }
246 
247 void draw::disc(int cx, int cy, int r, uint8_t octants)
248 {
249  DBG_D << "disc (" << cx << ',' << cy
250  << ") -> " << r << ", oct " << int(octants);
251 
252  int d = -r;
253  int x = r;
254  int y = 0;
255 
256  while(!(y > x)) {
257  // I use the formula of Bresenham's line algorithm
258  // to determine the boundaries of a segment.
259  // The slope of the line is always 1 or -1 in this case.
260  if(octants & 0x04)
261  // x2 - 1 = y2 - (cy + 1) + cx
262  draw::line(cx + x, cy + y + 1, cx + y + 1, cy + y + 1);
263  if(octants & 0x02)
264  // x2 - 1 = cy - y2 + cx
265  draw::line(cx + x, cy - y, cx + y + 1, cy - y);
266  if(octants & 0x20)
267  // x2 + 1 = (cy + 1) - y2 + (cx - 1)
268  draw::line(cx - x - 1, cy + y + 1, cx - y - 2, cy + y + 1);
269  if(octants & 0x40)
270  // x2 + 1 = y2 - cy + (cx - 1)
271  draw::line(cx - x - 1, cy - y, cx - y - 2, cy - y);
272 
273  if(octants & 0x08)
274  // y2 = x2 - cx + (cy + 1)
275  draw::line(cx + y, cy + x + 1, cx + y, cy + y + 1);
276  if(octants & 0x01)
277  // y2 = cx - x2 + cy
278  draw::line(cx + y, cy - x, cx + y, cy - y);
279  if(octants & 0x10)
280  // y2 = (cx - 1) - x2 + (cy + 1)
281  draw::line(cx - y - 1, cy + x + 1, cx - y - 1, cy + y + 1);
282  if(octants & 0x80)
283  // y2 = x2 - (cx - 1) + cy
284  draw::line(cx - y - 1, cy - x, cx - y - 1, cy - y);
285 
286  d += 2 * y + 1;
287  ++y;
288  if(d > 0) {
289  d += -2 * x + 2;
290  --x;
291  }
292  }
293 }
294 
295 
296 /*******************/
297 /* texture drawing */
298 /*******************/
299 
300 
301 void draw::blit(const texture& tex, const SDL_Rect& dst)
302 {
303  if (dst == sdl::empty_rect) {
304  return draw::blit(tex);
305  }
306 
307  if (!tex) { DBG_D << "null blit"; return; }
308  DBG_D << "blit " << dst;
309 
310  SDL_RenderCopy(renderer(), tex, tex.src(), &dst);
311 }
312 
313 void draw::blit(const texture& tex)
314 {
315  if (!tex) { DBG_D << "null blit"; return; }
316  DBG_D << "blit";
317 
318  SDL_RenderCopy(renderer(), tex, tex.src(), nullptr);
319 }
320 
321 
322 static SDL_RendererFlip get_flip(bool flip_h, bool flip_v)
323 {
324  // This should be easier than it is.
325  return static_cast<SDL_RendererFlip>(
326  static_cast<int>(flip_h ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE)
327  | static_cast<int>(flip_v ? SDL_FLIP_VERTICAL : SDL_FLIP_NONE)
328  );
329 }
330 
332  const texture& tex,
333  const SDL_Rect& dst,
334  bool flip_h,
335  bool flip_v)
336 {
337  if (dst == sdl::empty_rect) {
338  return draw::flipped(tex, flip_h, flip_v);
339  }
340 
341  if (!tex) { DBG_D << "null flipped"; return; }
342  DBG_D << "flipped (" << flip_h << '|' << flip_v
343  << ") to " << dst;
344 
345  SDL_RendererFlip flip = get_flip(flip_h, flip_v);
346  SDL_RenderCopyEx(renderer(), tex, tex.src(), &dst, 0.0, nullptr, flip);
347 }
348 
349 void draw::flipped(const texture& tex, bool flip_h, bool flip_v)
350 {
351  if (!tex) { DBG_D << "null flipped"; return; }
352  DBG_D << "flipped (" << flip_h << '|' << flip_v << ')';
353 
354  SDL_RendererFlip flip = get_flip(flip_h, flip_v);
355  SDL_RenderCopyEx(renderer(), tex, tex.src(), nullptr, 0.0, nullptr, flip);
356 }
357 
358 
359 // TODO: highdpi - maybe expose this mirrored mode to WML somehow
360 void draw::tiled(const texture& tex, const SDL_Rect& dst, bool centered,
361  bool mirrored)
362 {
363  if (!tex) { DBG_D << "null tiled"; return; }
364  DBG_D << "tiled (" << centered << '|' << mirrored
365  << ") " << dst;
366 
367  // Reduce clip to dst.
368  auto clipper = draw::reduce_clip(dst);
369 
370  const int xoff = centered ? (dst.w - tex.w()) / 2 : 0;
371  const int yoff = centered ? (dst.h - tex.h()) / 2 : 0;
372 
373  // Just blit the image however many times is necessary.
374  bool vf = false;
375  SDL_Rect t{dst.x - xoff, dst.y - yoff, tex.w(), tex.h()};
376  for (; t.y < dst.y + dst.h; t.y += t.h, vf = !vf) {
377  bool hf = false;
378  for (t.x = dst.x - xoff; t.x < dst.x + dst.w; t.x += t.w, hf = !hf) {
379  if (mirrored) {
380  draw::flipped(tex, t, hf, vf);
381  } else {
382  draw::blit(tex, t);
383  }
384  }
385  }
386 }
387 
388 void draw::tiled_highres(const texture& tex, const SDL_Rect& dst,
389  bool centered, bool mirrored)
390 {
391  if (!tex) { DBG_D << "null tiled_highres"; return; }
392  DBG_D << "tiled_highres (" << centered << '|' << mirrored
393  << ") " << dst;
394 
395  const int pixel_scale = video::get_pixel_scale();
396 
397  // Reduce clip to dst.
398  auto clipper = draw::reduce_clip(dst);
399 
401  const float w = float(size.x) / float(pixel_scale);
402  const float h = float(size.y) / float(pixel_scale);
403  const float xoff = centered ? (dst.w - w) / 2 : 0.0f;
404  const float yoff = centered ? (dst.h - h) / 2 : 0.0f;
405 
406  // Just blit the image however many times is necessary.
407  bool vf = false;
408  SDL_FRect t{dst.x - xoff, dst.y - yoff, w, h};
409  for (; t.y < dst.y + dst.h; t.y += t.h, vf = !vf) {
410  bool hf = false;
411  for (t.x = dst.x - xoff; t.x < dst.x + dst.w; t.x += t.w, hf = !hf) {
412  if (mirrored) {
413  SDL_RendererFlip flip = get_flip(hf, vf);
414  SDL_RenderCopyExF(renderer(), tex, nullptr, &t, 0.0, nullptr, flip);
415  } else {
416  SDL_RenderCopyF(renderer(), tex, nullptr, &t);
417  }
418  }
419  }
420 }
421 
422 
423 /***************************/
424 /* RAII state manipulation */
425 /***************************/
426 
427 
428 draw::clip_setter::clip_setter(const SDL_Rect& clip)
429  : c_(draw::get_clip()), clip_enabled_(draw::clip_enabled())
430 {
431  draw::force_clip(clip);
432 }
433 
435 {
436  if (clip_enabled_) {
437  draw::force_clip(c_);
438  } else {
440  }
441 }
442 
444 {
445  return draw::clip_setter(clip);
446 }
447 
449 {
450  if (!draw::clip_enabled()) {
451  return draw::clip_setter(clip);
452  }
453  return draw::clip_setter(draw::get_clip().intersect(clip));
454 }
455 
456 void draw::force_clip(const SDL_Rect& clip)
457 {
458  // TODO: highdpi - fix whatever reason there is for this guard (CI fail)
459  if (!renderer()) {
460  WRN_D << "trying to force clip will null renderer";
461  return;
462  }
463  DBG_D << "forcing clip to " << clip;
464 
465  SDL_RenderSetClipRect(renderer(), &clip);
466 }
467 
469 {
470  // TODO: highdpi - fix whatever reason there is for this guard (CI fail)
471  if (!renderer()) {
472  return sdl::empty_rect;
473  }
474 
475  if (!SDL_RenderIsClipEnabled(renderer())) {
476  return draw::get_viewport();
477  }
478 
479  ::rect clip;
480  SDL_RenderGetClipRect(renderer(), &clip);
481  return clip;
482 }
483 
485 {
486  if (!renderer()) {
487  return false;
488  }
489  return SDL_RenderIsClipEnabled(renderer());
490 }
491 
493 {
494  if (!renderer()) {
495  return;
496  }
497  SDL_RenderSetClipRect(renderer(), nullptr);
498  DBG_D << "clip disabled";
499 }
500 
502 {
503  if (!renderer()) {
504  return true;
505  }
506  if (!SDL_RenderIsClipEnabled(renderer())) {
507  return false;
508  }
509  SDL_Rect clip;
510  SDL_RenderGetClipRect(renderer(), &clip);
511  return clip.w <= 0 || clip.h <= 0;
512 }
513 
514 
516  : v_(), c_(), clip_enabled_(draw::clip_enabled())
517 {
519  draw::force_viewport(view);
520  if (clip_enabled_) {
521  c_ = draw::get_clip();
522  // adjust clip for difference in viewport position
523  SDL_Rect c_view = {
524  c_.x + v_.x - view.x,
525  c_.y + v_.y - view.y,
526  c_.w, c_.h
527  };
528  draw::force_clip(c_view);
529  }
530 }
531 
533 {
535  if (clip_enabled_) {
536  draw::force_clip(c_);
537  } else {
539  }
540 }
541 
542 draw::viewport_setter draw::set_viewport(const SDL_Rect& viewport)
543 {
544  return draw::viewport_setter(viewport);
545 }
546 
547 void draw::force_viewport(const SDL_Rect& viewport)
548 {
549  if (!renderer()) {
550  WRN_D << "trying to force viewport will null renderer";
551  return;
552  }
553  DBG_D << "forcing viewport to " << viewport;
554 
555  SDL_RenderSetViewport(renderer(), &viewport);
556 }
557 
559 {
560  if (!renderer()) {
561  WRN_D << "no renderer available to get viewport";
562  return sdl::empty_rect;
563  }
564 
565  SDL_Rect viewport;
566  SDL_RenderGetViewport(renderer(), &viewport);
567 
568  if (viewport == sdl::empty_rect) {
569  return video::draw_area();
570  }
571  return viewport;
572 }
573 
574 
576  : target_()
577  , viewport_()
578 {
579  // Validate we can render to this texture.
580  assert(t.get_access() == SDL_TEXTUREACCESS_TARGET);
581 
582  if (!renderer()) {
583  WRN_D << "can't set render target with null renderer";
584  return;
585  }
586 
588  SDL_RenderGetViewport(renderer(), &viewport_);
589 
591 }
592 
594 {
595  if (!renderer()) {
596  WRN_D << "can't reset render target with null renderer";
597  return;
598  }
600  SDL_RenderSetViewport(renderer(), &viewport_);
601 }
602 
604 {
605  DBG_D << "setting render target to "
606  << t.w() << 'x' << t.h() << " texture";
608 }
double t
Definition: astarsearch.cpp:65
double g
Definition: astarsearch.cpp:65
A class to manage automatic restoration of the clipping region.
Definition: draw.hpp:293
clip_setter(const SDL_Rect &clip)
Definition: draw.cpp:428
A class to manage automatic restoration of the render target.
Definition: draw.hpp:425
render_target_setter(const texture &t)
Definition: draw.cpp:575
A class to manage automatic restoration of the viewport region.
Definition: draw.hpp:365
viewport_setter(const SDL_Rect &viewport)
Definition: draw.cpp:515
Wrapper class to encapsulate creation and management of an SDL_Texture.
Definition: texture.hpp:33
int w() const
The draw-space width of the texture, in pixels.
Definition: texture.hpp:105
point get_raw_size() const
The raw internal texture size.
Definition: texture.cpp:112
const rect * src() const
A pointer to a rect indicating the source region of the underlying SDL_Texture to be used when drawin...
Definition: texture.hpp:148
int h() const
The draw-space height of the texture, in pixels.
Definition: texture.hpp:114
static lg::log_domain log_draw("draw")
static bool sdl_bad_at_rects()
Some versions of SDL have a bad rectangle drawing implementation.
Definition: draw.cpp:115
static SDL_Renderer * renderer()
Definition: draw.cpp:32
static void draw_rect_as_lines(const SDL_Rect &rect)
For some SDL versions, draw rectangles as lines.
Definition: draw.cpp:126
#define WRN_D
Definition: draw.cpp:30
static SDL_RendererFlip get_flip(bool flip_h, bool flip_v)
Definition: draw.cpp:322
#define DBG_D
Definition: draw.cpp:29
Drawing functions, for drawing things on the screen.
int w
Standard logging facilities (interface).
Definition: draw.hpp:43
viewport_setter set_viewport(const SDL_Rect &viewport)
Set the viewport.
Definition: draw.cpp:542
void force_viewport(const SDL_Rect &viewport)
Set the viewport, without any provided way of setting it back.
Definition: draw.cpp:547
render_target_setter set_render_target(const texture &t)
Set the given texture as the active render target.
Definition: draw.cpp:603
clip_setter override_clip(const SDL_Rect &clip)
Override the clipping area.
Definition: draw.cpp:443
void circle(int x, int y, int r, const color_t &c, uint8_t octants=0xff)
Draw a circle of the given colour.
Definition: draw.cpp:199
void points(const std::vector< SDL_Point > &points)
Draw a set of points.
Definition: draw.cpp:187
void force_clip(const SDL_Rect &clip)
Set the clipping area, without any provided way of setting it back.
Definition: draw.cpp:456
SDL_Rect get_viewport()
Get the current viewport.
Definition: draw.cpp:558
bool null_clip()
Whether the current clipping region will disallow drawing.
Definition: draw.cpp:501
clip_setter reduce_clip(const SDL_Rect &clip)
Set the clipping area to the intersection of the current clipping area and the given rectangle.
Definition: draw.cpp:448
bool clip_enabled()
Whether clipping is enabled.
Definition: draw.cpp:484
void tiled(const texture &tex, const SDL_Rect &dst, bool centered=false, bool mirrored=false)
Tile a texture to fill a region.
Definition: draw.cpp:360
void disc(int x, int y, int r, const color_t &c, uint8_t octants=0xff)
Draw a solid disc of the given colour.
Definition: draw.cpp:241
void set_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Set the drawing colour.
Definition: draw.cpp:91
void flipped(const texture &tex, const SDL_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...
Definition: draw.cpp:331
void fill(const SDL_Rect &rect, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Fill an area with the given colour.
Definition: draw.cpp:41
void point(int x, int y)
Draw a single point.
Definition: draw.cpp:193
void set_blend_mode(SDL_BlendMode b)
Set the blend mode used for drawing operations such as fill() and line().
Definition: draw.cpp:109
void blit(const texture &tex, const SDL_Rect &dst)
Draws a texture, or part of a texture, at the given location.
Definition: draw.cpp:301
void tiled_highres(const texture &tex, const SDL_Rect &dst, bool centered=false, bool mirrored=false)
Tile a texture to fill a region.
Definition: draw.cpp:388
::rect get_clip()
Get the current clipping area, in draw coordinates.
Definition: draw.cpp:468
void rect(const SDL_Rect &rect)
Draw a rectangle.
Definition: draw.cpp:141
void disable_clip()
Disable clipping.
Definition: draw.cpp:492
void line(int from_x, int from_y, int to_x, int to_y)
Draw a line.
Definition: draw.cpp:171
int pixel_scale()
Definition: general.cpp:408
constexpr const SDL_Rect empty_rect
Definition: rect.hpp:30
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,...
Definition: utils.cpp:41
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:87
rect draw_area()
The current drawable area.
Definition: video.cpp:436
void force_render_target(const texture &t)
Set the render target, without any provided way of setting it back.
Definition: video.cpp:486
int get_pixel_scale()
Get the current active pixel scale multiplier.
Definition: video.cpp:475
SDL_Renderer * get_renderer()
Definition: video.cpp:633
texture get_render_target()
Get the current render target.
Definition: video.cpp:522
Contains the SDL_Rect helper code.
The basic class for representing 8-bit RGB or RGBA colour values.
Definition: color.hpp:59
An abstract description of a rectangle with integer coordinates.
Definition: rect.hpp:47
mock_char c
#define d
#define h
#define a
#define b