The Battle for Wesnoth  1.19.10+dev
draw.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2022 - 2025
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 "font/cairo.hpp"
19 #include "log.hpp"
20 #include "sdl/rect.hpp"
21 #include "sdl/texture.hpp"
22 #include "sdl/utils.hpp" // sdl::runtime_at_least
23 #include "video.hpp"
24 
25 #include <boost/math/constants/constants.hpp>
26 #include <SDL2/SDL_rect.h>
27 #include <SDL2/SDL_render.h>
28 
29 static lg::log_domain log_draw("draw");
30 #define DBG_D LOG_STREAM(debug, log_draw)
31 #define WRN_D LOG_STREAM(warn, log_draw)
32 
33 static SDL_Renderer* renderer()
34 {
35  return video::get_renderer();
36 }
37 
38 /**************************************/
39 /* basic drawing and pixel primatives */
40 /**************************************/
41 
43 {
44  DBG_D << "clear";
45  SDL_BlendMode b;
46  SDL_GetRenderDrawBlendMode(renderer(), &b);
47  SDL_SetRenderDrawBlendMode(renderer(), SDL_BLENDMODE_NONE);
48  fill(0, 0, 0, 0);
49  SDL_SetRenderDrawBlendMode(renderer(), b);
50 }
51 
53  const SDL_Rect& area,
54  uint8_t r, uint8_t g, uint8_t b, uint8_t a)
55 {
56  DBG_D << "fill " << area << ' ' << color_t{r,g,b,a};
57  SDL_SetRenderDrawColor(renderer(), r, g, b, a);
58  SDL_RenderFillRect(renderer(), &area);
59 }
60 
62  const SDL_Rect& area,
63  uint8_t r, uint8_t g, uint8_t b)
64 {
65  draw::fill(area, r, g, b, SDL_ALPHA_OPAQUE);
66 }
67 
68 void draw::fill(const SDL_Rect& area, const color_t& c)
69 {
70  draw::fill(area, c.r, c.g, c.b, c.a);
71 }
72 
73 void draw::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
74 {
75  DBG_D << "fill " << color_t{r,g,b,a};
76  SDL_SetRenderDrawColor(renderer(), r, g, b, a);
77  SDL_RenderFillRect(renderer(), nullptr);
78 }
79 
80 void draw::fill(uint8_t r, uint8_t g, uint8_t b)
81 {
82  draw::fill(r, g, b, SDL_ALPHA_OPAQUE);
83 }
84 
85 void draw::fill(const color_t& c)
86 {
87  draw::fill(c.r, c.g, c.b, c.a);
88 }
89 
90 void draw::fill(const SDL_FRect& rect, const color_t& c)
91 {
92  DBG_D << "sub-pixel fill";
93  SDL_SetRenderDrawColor(renderer(), c.r, c.g, c.b, c.a);
94  SDL_RenderFillRectF(renderer(), &rect);
95 }
96 
97 void draw::fill(const SDL_Rect& area)
98 {
99  DBG_D << "fill " << area;
100  SDL_RenderFillRect(renderer(), &area);
101 }
102 
104 {
105  DBG_D << "fill";
106  SDL_RenderFillRect(renderer(), nullptr);
107 }
108 
109 void draw::set_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
110 {
111  DBG_D << "set color " << color_t{r,g,b,a};
112  SDL_SetRenderDrawColor(renderer(), r, g, b, a);
113 }
114 
115 void draw::set_color(uint8_t r, uint8_t g, uint8_t b)
116 {
117  DBG_D << "set color " << color_t{r,g,b};
118  SDL_SetRenderDrawColor(renderer(), r, g, b, SDL_ALPHA_OPAQUE);
119 }
120 
122 {
123  DBG_D << "set color " << c;
124  SDL_SetRenderDrawColor(renderer(), c.r, c.g, c.b, c.a);
125 }
126 
127 void draw::set_blend_mode(SDL_BlendMode b)
128 {
129  SDL_SetRenderDrawBlendMode(renderer(), b);
130 }
131 
132 /** Some versions of SDL have a bad rectangle drawing implementation. */
133 static bool sdl_bad_at_rects()
134 {
135  // This could be done once at program start and cached,
136  // but it isn't all that heavy.
137  if (sdl::runtime_at_least(2,0,15) && !sdl::runtime_at_least(2,0,18)) {
138  return true;
139  }
140  return false;
141 }
142 
143 /** For some SDL versions, draw rectangles as lines. */
144 static void draw_rect_as_lines(const SDL_Rect& rect)
145 {
146  // w and h indicate the final pixel width/height of the box.
147  // This is 1 greater than the difference in corner coordinates.
148  if (rect.w <= 0 || rect.h <= 0) {
149  return;
150  }
151  int x2 = rect.x + rect.w - 1;
152  int y2 = rect.y + rect.h - 1;
153  draw::line(rect.x, rect.y, x2, rect.y);
154  draw::line(rect.x, rect.y, rect.x, y2);
155  draw::line(x2, rect.y, x2, y2);
156  draw::line(rect.x, y2, x2, y2);
157 }
158 
159 void draw::rect(const SDL_Rect& rect)
160 {
161  DBG_D << "rect " << rect;
162  if (sdl_bad_at_rects()) {
163  return draw_rect_as_lines(rect);
164  }
165  SDL_RenderDrawRect(renderer(), &rect);
166 }
167 
168 void draw::rect(const SDL_Rect& rect,
169  uint8_t r, uint8_t g, uint8_t b, uint8_t a)
170 {
171  DBG_D << "rect " << rect << ' ' << color_t{r,g,b,a};
172  SDL_SetRenderDrawColor(renderer(), r, g, b, a);
173  if (sdl_bad_at_rects()) {
174  return draw_rect_as_lines(rect);
175  }
176  SDL_RenderDrawRect(renderer(), &rect);
177 }
178 
179 void draw::rect(const SDL_Rect& rect, uint8_t r, uint8_t g, uint8_t b)
180 {
181  draw::rect(rect, r, g, b, SDL_ALPHA_OPAQUE);
182 }
183 
184 void draw::rect(const SDL_Rect& rect, const color_t& c)
185 {
186  draw::rect(rect, c.r, c.g, c.b, c.a);
187 }
188 
189 void draw::line(int from_x, int from_y, int to_x, int to_y)
190 {
191  DBG_D << "line from (" << from_x << ',' << from_y
192  << ") to (" << to_x << ',' << to_y << ')';
193  SDL_RenderDrawLine(renderer(), from_x, from_y, to_x, to_y);
194 }
195 
196 void draw::line(int from_x, int from_y, int to_x, int to_y, const color_t& c)
197 {
198  DBG_D << "line from (" << from_x << ',' << from_y
199  << ") to (" << to_x << ',' << to_y
200  << ") with colour " << c;
201  SDL_SetRenderDrawColor(renderer(), c.r, c.g, c.b, c.a);
202  SDL_RenderDrawLine(renderer(), from_x, from_y, to_x, to_y);
203 }
204 
205 void draw::points(const std::vector<SDL_Point>& points)
206 {
207  DBG_D << points.size() << " points";
208  SDL_RenderDrawPoints(renderer(), points.data(), points.size());
209 }
210 
211 void draw::point(int x, int y)
212 {
213  DBG_D << "point (" << x << ',' << y << ')';
214  SDL_RenderDrawPoint(renderer(), x, y);
215 }
216 
217 void draw::circle(int cx, int cy, int r, const color_t& c, uint8_t octants)
218 {
220  draw::circle(cx, cy, r, octants);
221 }
222 
223 void draw::circle(int cx, int cy, int r, uint8_t octants)
224 {
225  DBG_D << "circle (" << cx << ',' << cy
226  << ") -> " << r << ", oct " << int(octants);
227 
228  // Algorithm based on
229  // http://de.wikipedia.org/wiki/Rasterung_von_Kreisen#Methode_von_Horn
230  // version of 2011.02.07.
231  int d = -r;
232  int x = r;
233  int y = 0;
234 
235  std::vector<SDL_Point> points;
236 
237  while(!(y > x)) {
238  if(octants & 0x04) points.push_back({cx + x, cy + y});
239  if(octants & 0x02) points.push_back({cx + x, cy - y});
240  if(octants & 0x20) points.push_back({cx - x, cy + y});
241  if(octants & 0x40) points.push_back({cx - x, cy - y});
242 
243  if(octants & 0x08) points.push_back({cx + y, cy + x});
244  if(octants & 0x01) points.push_back({cx + y, cy - x});
245  if(octants & 0x10) points.push_back({cx - y, cy + x});
246  if(octants & 0x80) points.push_back({cx - y, cy - x});
247 
248  d += 2 * y + 1;
249  ++y;
250  if(d > 0) {
251  d += -2 * x + 2;
252  --x;
253  }
254  }
255 
257 }
258 
259 void draw::disc(int cx, int cy, int r, const color_t& c, uint8_t octants)
260 {
262  draw::disc(cx, cy, r, octants);
263 }
264 
265 void draw::disc(int cx, int cy, int r, uint8_t octants)
266 {
267  DBG_D << "disc (" << cx << ',' << cy
268  << ") -> " << r << ", oct " << int(octants);
269 
270  int d = -r;
271  int x = r;
272  int y = 0;
273 
274  while(!(y > x)) {
275  // I use the formula of Bresenham's line algorithm
276  // to determine the boundaries of a segment.
277  // The slope of the line is always 1 or -1 in this case.
278  if(octants & 0x04)
279  // x2 - 1 = y2 - (cy + 1) + cx
280  draw::line(cx + x, cy + y + 1, cx + y + 1, cy + y + 1);
281  if(octants & 0x02)
282  // x2 - 1 = cy - y2 + cx
283  draw::line(cx + x, cy - y, cx + y + 1, cy - y);
284  if(octants & 0x20)
285  // x2 + 1 = (cy + 1) - y2 + (cx - 1)
286  draw::line(cx - x - 1, cy + y + 1, cx - y - 2, cy + y + 1);
287  if(octants & 0x40)
288  // x2 + 1 = y2 - cy + (cx - 1)
289  draw::line(cx - x - 1, cy - y, cx - y - 2, cy - y);
290 
291  if(octants & 0x08)
292  // y2 = x2 - cx + (cy + 1)
293  draw::line(cx + y, cy + x + 1, cx + y, cy + y + 1);
294  if(octants & 0x01)
295  // y2 = cx - x2 + cy
296  draw::line(cx + y, cy - x, cx + y, cy - y);
297  if(octants & 0x10)
298  // y2 = (cx - 1) - x2 + (cy + 1)
299  draw::line(cx - y - 1, cy + x + 1, cx - y - 1, cy + y + 1);
300  if(octants & 0x80)
301  // y2 = x2 - (cx - 1) + cy
302  draw::line(cx - y - 1, cy - x, cx - y - 1, cy - y);
303 
304  d += 2 * y + 1;
305  ++y;
306  if(d > 0) {
307  d += -2 * x + 2;
308  --x;
309  }
310  }
311 }
312 
313 /********************/
314 /* Cairo primitives */
315 /********************/
316 
317 void draw::cairo_circle(int cx, int cy, int r, const color_t& c, int thickness)
318 {
319  if (r <= 0) {
320  return;
321  }
322 
323  int size = 2*r;
324  surface sdl_surf(size, size);
325  auto cairo_surface = cairo::create_surface(
326  reinterpret_cast<uint8_t*>(sdl_surf->pixels), ::point(sdl_surf->w, sdl_surf->h));
327  auto cairo_context = cairo::create_context(cairo_surface);
328  cairo_t* ctx = cairo_context.get();
329 
330  cairo_set_antialias(ctx, CAIRO_ANTIALIAS_BEST);
331 
332  cairo_set_source_rgba(ctx, 0.0, 0.0, 0.0, 0.0);
333  cairo_paint(ctx);
334 
335  cairo_set_line_width(ctx, thickness);
336  cairo_set_source_rgba(ctx,
337  c.r / 255.0,
338  c.g / 255.0,
339  c.b / 255.0,
340  c.a / 255.0
341  );
342  cairo_arc(ctx, r, r, r-thickness, 0, 2*boost::math::constants::pi<double>());
343  cairo_stroke(ctx);
344 
345  draw::blit(texture(sdl_surf), ::rect(cx-r, cy-r, size, size));
346 }
347 
348 void draw::cairo_disc(int cx, int cy, int r, const color_t& c)
349 {
350  if (r <= 0) {
351  return;
352  }
353 
354  int size = 2*r;
355  surface sdl_surf(size, size);
356  auto cairo_surface = cairo::create_surface(
357  reinterpret_cast<uint8_t*>(sdl_surf->pixels), ::point(sdl_surf->w, sdl_surf->h));
358  auto cairo_context = cairo::create_context(cairo_surface);
359  cairo_t* ctx = cairo_context.get();
360 
361  cairo_set_antialias(ctx, CAIRO_ANTIALIAS_BEST);
362 
363  cairo_set_source_rgba(ctx,
364  c.r / 255.0,
365  c.g / 255.0,
366  c.b / 255.0,
367  c.a / 255.0
368  );
369  cairo_arc(ctx, r, r, r, 0, 2*2*boost::math::constants::pi<double>());
370  cairo_fill(ctx);
371 
372  draw::blit(texture(sdl_surf), ::rect(cx-r, cy-r, size, size));
373 }
374 
375 /*******************/
376 /* texture drawing */
377 /*******************/
378 
379 
380 void draw::blit(const texture& tex, const SDL_Rect& dst)
381 {
382  if (dst == sdl::empty_rect) {
383  return draw::blit(tex);
384  }
385 
386  if (!tex) { DBG_D << "null blit"; return; }
387  DBG_D << "blit " << dst;
388 
389  SDL_RenderCopy(renderer(), tex, tex.src(), &dst);
390 }
391 
392 void draw::blit(const texture& tex)
393 {
394  if (!tex) { DBG_D << "null blit"; return; }
395  DBG_D << "blit";
396 
397  SDL_RenderCopy(renderer(), tex, tex.src(), nullptr);
398 }
399 
400 
401 static SDL_RendererFlip get_flip(bool flip_h, bool flip_v)
402 {
403  // This should be easier than it is.
404  return static_cast<SDL_RendererFlip>(
405  static_cast<int>(flip_h ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE)
406  | static_cast<int>(flip_v ? SDL_FLIP_VERTICAL : SDL_FLIP_NONE)
407  );
408 }
409 
411  const texture& tex,
412  const SDL_Rect& dst,
413  bool flip_h,
414  bool flip_v)
415 {
416  if (dst == sdl::empty_rect) {
417  return draw::flipped(tex, flip_h, flip_v);
418  }
419 
420  if (!tex) { DBG_D << "null flipped"; return; }
421  DBG_D << "flipped (" << flip_h << '|' << flip_v
422  << ") to " << dst;
423 
424  SDL_RendererFlip flip = get_flip(flip_h, flip_v);
425  SDL_RenderCopyEx(renderer(), tex, tex.src(), &dst, 0.0, nullptr, flip);
426 }
427 
428 void draw::flipped(const texture& tex, bool flip_h, bool flip_v)
429 {
430  if (!tex) { DBG_D << "null flipped"; return; }
431  DBG_D << "flipped (" << flip_h << '|' << flip_v << ')';
432 
433  SDL_RendererFlip flip = get_flip(flip_h, flip_v);
434  SDL_RenderCopyEx(renderer(), tex, tex.src(), nullptr, 0.0, nullptr, flip);
435 }
436 
437 
438 // TODO: highdpi - maybe expose this mirrored mode to WML somehow
439 void draw::tiled(const texture& tex, const SDL_Rect& dst, bool centered,
440  bool mirrored)
441 {
442  if (!tex) { DBG_D << "null tiled"; return; }
443  DBG_D << "tiled (" << centered << '|' << mirrored
444  << ") " << dst;
445 
446  // Reduce clip to dst.
447  auto clipper = draw::reduce_clip(dst);
448 
449  const int xoff = centered ? (dst.w - tex.w()) / 2 : 0;
450  const int yoff = centered ? (dst.h - tex.h()) / 2 : 0;
451 
452  // Just blit the image however many times is necessary.
453  bool vf = false;
454  SDL_Rect t{dst.x - xoff, dst.y - yoff, tex.w(), tex.h()};
455  for (; t.y < dst.y + dst.h; t.y += t.h, vf = !vf) {
456  bool hf = false;
457  for (t.x = dst.x - xoff; t.x < dst.x + dst.w; t.x += t.w, hf = !hf) {
458  if (mirrored) {
459  draw::flipped(tex, t, hf, vf);
460  } else {
461  draw::blit(tex, t);
462  }
463  }
464  }
465 }
466 
467 void draw::tiled_highres(const texture& tex, const SDL_Rect& dst,
468  bool centered, bool mirrored)
469 {
470  if (!tex) { DBG_D << "null tiled_highres"; return; }
471  DBG_D << "tiled_highres (" << centered << '|' << mirrored
472  << ") " << dst;
473 
474  const int pixel_scale = video::get_pixel_scale();
475 
476  // Reduce clip to dst.
477  auto clipper = draw::reduce_clip(dst);
478 
480  const float w = float(size.x) / float(pixel_scale);
481  const float h = float(size.y) / float(pixel_scale);
482  const float xoff = centered ? (dst.w - w) / 2 : 0.0f;
483  const float yoff = centered ? (dst.h - h) / 2 : 0.0f;
484 
485  // Just blit the image however many times is necessary.
486  bool vf = false;
487  SDL_FRect t{dst.x - xoff, dst.y - yoff, w, h};
488  for (; t.y < dst.y + dst.h; t.y += t.h, vf = !vf) {
489  bool hf = false;
490  for (t.x = dst.x - xoff; t.x < dst.x + dst.w; t.x += t.w, hf = !hf) {
491  if (mirrored) {
492  SDL_RendererFlip flip = get_flip(hf, vf);
493  SDL_RenderCopyExF(renderer(), tex, nullptr, &t, 0.0, nullptr, flip);
494  } else {
495  SDL_RenderCopyF(renderer(), tex, nullptr, &t);
496  }
497  }
498  }
499 }
500 
501 void draw::smooth_shaded(const texture& tex, const SDL_Rect& dst,
502  const SDL_Color& cTL, const SDL_Color& cTR,
503  const SDL_Color& cBL, const SDL_Color& cBR,
504  const SDL_FPoint& uvTL, const SDL_FPoint& uvTR,
505  const SDL_FPoint& uvBL, const SDL_FPoint& uvBR)
506 {
507  const SDL_FPoint pTL{float(dst.x), float(dst.y)};
508  const SDL_FPoint pTR{float(dst.x + dst.w), float(dst.y)};
509  const SDL_FPoint pBL{float(dst.x), float(dst.y + dst.h)};
510  const SDL_FPoint pBR{float(dst.x + dst.w), float(dst.y + dst.h)};
511  std::array<SDL_Vertex,4> verts {
512  SDL_Vertex{pTL, cTL, uvTL},
513  SDL_Vertex{pTR, cTR, uvTR},
514  SDL_Vertex{pBL, cBL, uvBL},
515  SDL_Vertex{pBR, cBR, uvBR},
516  };
517  draw::smooth_shaded(tex, verts);
518 }
519 
520 void draw::smooth_shaded(const texture& tex, const SDL_Rect& dst,
521  const SDL_Color& cTL, const SDL_Color& cTR,
522  const SDL_Color& cBL, const SDL_Color& cBR)
523 {
524  SDL_FPoint uv[4] = {
525  {0.f, 0.f}, // top left
526  {1.f, 0.f}, // top right
527  {0.f, 1.f}, // bottom left
528  {1.f, 1.f}, // bottom right
529  };
530  draw::smooth_shaded(tex, dst, cTL, cTR, cBL, cBR,
531  uv[0], uv[1], uv[2], uv[3]);
532 }
533 
534 void draw::smooth_shaded(const texture& tex,
535  const std::array<SDL_Vertex, 4>& verts)
536 {
537  DBG_D << "smooth shade, verts:";
538  for (const SDL_Vertex& v : verts) {
539  DBG_D << " {(" << v.position.x << ',' << v.position.y << ") "
540  << v.color << " (" << v.tex_coord.x << ',' << v.tex_coord.y
541  << ")}";
542  }
543  int indices[6] = {0, 1, 2, 2, 1, 3};
544  SDL_RenderGeometry(renderer(), tex, &verts[0], 4, indices, 6);
545 }
546 
547 /***************************/
548 /* RAII state manipulation */
549 /***************************/
550 
551 
552 draw::clip_setter::clip_setter(const SDL_Rect& clip)
553  : c_(draw::get_clip()), clip_enabled_(draw::clip_enabled())
554 {
555  draw::force_clip(clip);
556 }
557 
559 {
560  if (clip_enabled_) {
561  draw::force_clip(c_);
562  } else {
564  }
565 }
566 
568 {
569  return draw::clip_setter(clip);
570 }
571 
573 {
574  if (!draw::clip_enabled()) {
575  return draw::clip_setter(clip);
576  }
577  return draw::clip_setter(draw::get_clip().intersect(clip));
578 }
579 
580 void draw::force_clip(const SDL_Rect& clip)
581 {
582  // TODO: highdpi - fix whatever reason there is for this guard (CI fail)
583  if (!renderer()) {
584  WRN_D << "trying to force clip will null renderer";
585  return;
586  }
587  DBG_D << "forcing clip to " << clip;
588 
589  SDL_RenderSetClipRect(renderer(), &clip);
590 }
591 
593 {
594  // TODO: highdpi - fix whatever reason there is for this guard (CI fail)
595  if (!renderer()) {
596  return sdl::empty_rect;
597  }
598 
599  if (!SDL_RenderIsClipEnabled(renderer())) {
600  return draw::get_viewport();
601  }
602 
603  ::rect clip;
604  SDL_RenderGetClipRect(renderer(), &clip);
605  return clip;
606 }
607 
609 {
610  if (!renderer()) {
611  return false;
612  }
613  return SDL_RenderIsClipEnabled(renderer());
614 }
615 
617 {
618  if (!renderer()) {
619  return;
620  }
621  SDL_RenderSetClipRect(renderer(), nullptr);
622  DBG_D << "clip disabled";
623 }
624 
626 {
627  if (!renderer()) {
628  return true;
629  }
630  if (!SDL_RenderIsClipEnabled(renderer())) {
631  return false;
632  }
633  SDL_Rect clip;
634  SDL_RenderGetClipRect(renderer(), &clip);
635  return clip.w <= 0 || clip.h <= 0;
636 }
637 
638 
640  : v_(), c_(), clip_enabled_(draw::clip_enabled())
641 {
643  draw::force_viewport(view);
644  if (clip_enabled_) {
645  c_ = draw::get_clip();
646  // adjust clip for difference in viewport position
647  SDL_Rect c_view = {
648  c_.x + v_.x - view.x,
649  c_.y + v_.y - view.y,
650  c_.w, c_.h
651  };
652  draw::force_clip(c_view);
653  }
654 }
655 
657 {
659  if (clip_enabled_) {
660  draw::force_clip(c_);
661  } else {
663  }
664 }
665 
666 draw::viewport_setter draw::set_viewport(const SDL_Rect& viewport)
667 {
668  return draw::viewport_setter(viewport);
669 }
670 
671 void draw::force_viewport(const SDL_Rect& viewport)
672 {
673  if (!renderer()) {
674  WRN_D << "trying to force viewport will null renderer";
675  return;
676  }
677  DBG_D << "forcing viewport to " << viewport;
678 
679  SDL_RenderSetViewport(renderer(), &viewport);
680 }
681 
683 {
684  if (!renderer()) {
685  WRN_D << "no renderer available to get viewport";
686  return sdl::empty_rect;
687  }
688 
689  SDL_Rect viewport;
690  SDL_RenderGetViewport(renderer(), &viewport);
691 
692  if (viewport == sdl::empty_rect) {
693  return video::draw_area();
694  }
695  return viewport;
696 }
697 
699  : target_()
700  , viewport_()
701  , clip_()
702 {
703  // Validate we can render to this texture.
704  assert(!t || t.get_access() == SDL_TEXTUREACCESS_TARGET);
705 
706  if (!renderer()) {
707  WRN_D << "can't set render target with null renderer";
708  return;
709  }
710 
712  SDL_RenderGetViewport(renderer(), &viewport_);
713  SDL_RenderGetClipRect(renderer(), &clip_);
714 
715  if (t) {
717  } else {
719  }
720 }
721 
723 {
724  if (!renderer()) {
725  WRN_D << "can't reset render target with null renderer";
726  return;
727  }
729  SDL_RenderSetViewport(renderer(), &viewport_);
730  if(clip_ == sdl::empty_rect) return;
731  SDL_RenderSetClipRect(renderer(), &clip_);
732 }
733 
735 {
736  if (t) {
737  DBG_D << "setting render target to "
738  << t.w() << 'x' << t.h() << " texture";
739  } else {
740  DBG_D << "setting render target to main render buffer";
741  }
743 }
double t
Definition: astarsearch.cpp:63
double g
Definition: astarsearch.cpp:63
A class to manage automatic restoration of the clipping region.
Definition: draw.hpp:346
clip_setter(const SDL_Rect &clip)
Definition: draw.cpp:552
A class to manage automatic restoration of the render target.
Definition: draw.hpp:478
render_target_setter(const texture &t)
Definition: draw.cpp:698
A class to manage automatic restoration of the viewport region.
Definition: draw.hpp:418
viewport_setter(const SDL_Rect &viewport)
Definition: draw.cpp:639
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:103
point get_raw_size() const
The raw internal texture size.
Definition: texture.cpp:99
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:146
int h() const
The draw-space height of the texture, in pixels.
Definition: texture.hpp:112
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:133
static SDL_Renderer * renderer()
Definition: draw.cpp:33
static void draw_rect_as_lines(const SDL_Rect &rect)
For some SDL versions, draw rectangles as lines.
Definition: draw.cpp:144
#define WRN_D
Definition: draw.cpp:31
static SDL_RendererFlip get_flip(bool flip_h, bool flip_v)
Definition: draw.cpp:401
#define DBG_D
Definition: draw.cpp:30
Drawing functions, for drawing things on the screen.
const gui2::tracked_drawable & target_
The drawable whose render calls we are tracking.
Definition: fps_report.cpp:53
int w
Standard logging facilities (interface).
context_ptr create_context(const surface_ptr &surf)
Definition: cairo.hpp:41
surface_ptr create_surface(uint8_t *buffer, const point &size)
Definition: cairo.hpp:30
Definition: draw.hpp:43
viewport_setter set_viewport(const SDL_Rect &viewport)
Set the viewport.
Definition: draw.cpp:666
void force_viewport(const SDL_Rect &viewport)
Set the viewport, without any provided way of setting it back.
Definition: draw.cpp:671
render_target_setter set_render_target(const texture &t)
Set the given texture as the active render target.
Definition: draw.cpp:734
clip_setter override_clip(const SDL_Rect &clip)
Override the clipping area.
Definition: draw.cpp:567
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:217
void points(const std::vector< SDL_Point > &points)
Draw a set of points.
Definition: draw.cpp:205
void force_clip(const SDL_Rect &clip)
Set the clipping area, without any provided way of setting it back.
Definition: draw.cpp:580
SDL_Rect get_viewport()
Get the current viewport.
Definition: draw.cpp:682
void cairo_disc(int cx, int cy, int r, const color_t &c)
Draw filled circle using Cairo.
Definition: draw.cpp:348
bool null_clip()
Whether the current clipping region will disallow drawing.
Definition: draw.cpp:625
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:572
bool clip_enabled()
Whether clipping is enabled.
Definition: draw.cpp:608
void cairo_circle(int cx, int cy, int r, const color_t &c, int thickness)
Draw outline of circle using Cairo.
Definition: draw.cpp:317
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:439
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:259
void set_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Set the drawing colour.
Definition: draw.cpp:109
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:410
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:52
void point(int x, int y)
Draw a single point.
Definition: draw.cpp:211
void clear()
Clear the current render target.
Definition: draw.cpp:42
void set_blend_mode(SDL_BlendMode b)
Set the blend mode used for drawing operations such as fill() and line().
Definition: draw.cpp:127
void blit(const texture &tex, const SDL_Rect &dst)
Draws a texture, or part of a texture, at the given location.
Definition: draw.cpp:380
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:467
::rect get_clip()
Get the current clipping area, in draw coordinates.
Definition: draw.cpp:592
void rect(const SDL_Rect &rect)
Draw a rectangle.
Definition: draw.cpp:159
void disable_clip()
Disable clipping.
Definition: draw.cpp:616
void line(int from_x, int from_y, int to_x, int to_y)
Draw a line.
Definition: draw.cpp:189
void smooth_shaded(const texture &tex, const SDL_Rect &dst, const SDL_Color &cTL, const SDL_Color &cTR, const SDL_Color &cBL, const SDL_Color &cBR, const SDL_FPoint &uvTL, const SDL_FPoint &uvTR, const SDL_FPoint &uvBL, const SDL_FPoint &uvBR)
Draw a texture with smoothly varying colour and alpha modification, specified at the four corners of ...
Definition: draw.cpp:501
constexpr const SDL_Rect empty_rect
Definition: rect.hpp:32
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:47
std::size_t size(std::string_view str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:85
rect draw_area()
The current drawable area.
Definition: video.cpp:442
void reset_render_target()
Reset the render target to the primary render buffer.
Definition: video.cpp:537
void force_render_target(const texture &t)
Set the render target, without any provided way of setting it back.
Definition: video.cpp:501
int get_pixel_scale()
Get the current active pixel scale multiplier.
Definition: video.cpp:481
SDL_Renderer * get_renderer()
Definition: video.cpp:659
texture get_render_target()
Get the current render target.
Definition: video.cpp:542
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.
Definition: color.hpp:61
Holds a 2D point.
Definition: point.hpp:25
An abstract description of a rectangle with integer coordinates.
Definition: rect.hpp:49
mock_char c
#define d
#define h
#define b