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