The Battle for Wesnoth  1.19.14+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 
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 ::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 ::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 ::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 
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 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 
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 
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 ::rect& rect, uint8_t r, uint8_t g, uint8_t b)
180 {
181  draw::rect(rect, r, g, b, SDL_ALPHA_OPAQUE);
182 }
183 
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<::point>& points)
206 {
207  // We cannot decay vector<point> to SDL_Point* unless the two types are the same size.
208  static_assert(sizeof(::point) == sizeof(SDL_Point));
209 
210  DBG_D << points.size() << " points";
211  SDL_RenderDrawPoints(renderer(), points.data(), points.size());
212 }
213 
214 void draw::point(int x, int y)
215 {
216  DBG_D << "point (" << x << ',' << y << ')';
217  SDL_RenderDrawPoint(renderer(), x, y);
218 }
219 
220 void draw::circle(int cx, int cy, int r, const color_t& c, uint8_t octants)
221 {
223  draw::circle(cx, cy, r, octants);
224 }
225 
226 void draw::circle(int cx, int cy, int r, uint8_t octants)
227 {
228  DBG_D << "circle (" << cx << ',' << cy
229  << ") -> " << r << ", oct " << int(octants);
230 
231  // Algorithm based on
232  // http://de.wikipedia.org/wiki/Rasterung_von_Kreisen#Methode_von_Horn
233  // version of 2011.02.07.
234  int d = -r;
235  int x = r;
236  int y = 0;
237 
238  std::vector<::point> points;
239 
240  while(!(y > x)) {
241  if(octants & 0x04) points.push_back({cx + x, cy + y});
242  if(octants & 0x02) points.push_back({cx + x, cy - y});
243  if(octants & 0x20) points.push_back({cx - x, cy + y});
244  if(octants & 0x40) points.push_back({cx - x, cy - y});
245 
246  if(octants & 0x08) points.push_back({cx + y, cy + x});
247  if(octants & 0x01) points.push_back({cx + y, cy - x});
248  if(octants & 0x10) points.push_back({cx - y, cy + x});
249  if(octants & 0x80) points.push_back({cx - y, cy - x});
250 
251  d += 2 * y + 1;
252  ++y;
253  if(d > 0) {
254  d += -2 * x + 2;
255  --x;
256  }
257  }
258 
260 }
261 
262 void draw::disc(int cx, int cy, int r, const color_t& c, uint8_t octants)
263 {
265  draw::disc(cx, cy, r, octants);
266 }
267 
268 void draw::disc(int cx, int cy, int r, uint8_t octants)
269 {
270  DBG_D << "disc (" << cx << ',' << cy
271  << ") -> " << r << ", oct " << int(octants);
272 
273  int d = -r;
274  int x = r;
275  int y = 0;
276 
277  while(!(y > x)) {
278  // I use the formula of Bresenham's line algorithm
279  // to determine the boundaries of a segment.
280  // The slope of the line is always 1 or -1 in this case.
281  if(octants & 0x04)
282  // x2 - 1 = y2 - (cy + 1) + cx
283  draw::line(cx + x, cy + y + 1, cx + y + 1, cy + y + 1);
284  if(octants & 0x02)
285  // x2 - 1 = cy - y2 + cx
286  draw::line(cx + x, cy - y, cx + y + 1, cy - y);
287  if(octants & 0x20)
288  // x2 + 1 = (cy + 1) - y2 + (cx - 1)
289  draw::line(cx - x - 1, cy + y + 1, cx - y - 2, cy + y + 1);
290  if(octants & 0x40)
291  // x2 + 1 = y2 - cy + (cx - 1)
292  draw::line(cx - x - 1, cy - y, cx - y - 2, cy - y);
293 
294  if(octants & 0x08)
295  // y2 = x2 - cx + (cy + 1)
296  draw::line(cx + y, cy + x + 1, cx + y, cy + y + 1);
297  if(octants & 0x01)
298  // y2 = cx - x2 + cy
299  draw::line(cx + y, cy - x, cx + y, cy - y);
300  if(octants & 0x10)
301  // y2 = (cx - 1) - x2 + (cy + 1)
302  draw::line(cx - y - 1, cy + x + 1, cx - y - 1, cy + y + 1);
303  if(octants & 0x80)
304  // y2 = x2 - (cx - 1) + cy
305  draw::line(cx - y - 1, cy - x, cx - y - 1, cy - y);
306 
307  d += 2 * y + 1;
308  ++y;
309  if(d > 0) {
310  d += -2 * x + 2;
311  --x;
312  }
313  }
314 }
315 
316 /********************/
317 /* Cairo primitives */
318 /********************/
319 
320 void draw::cairo_circle(int cx, int cy, int r, const color_t& c, int thickness)
321 {
322  if (r <= 0) {
323  return;
324  }
325 
326  int draw_size = 2 * r;
327  int pixel_scale = video::get_pixel_scale();
328  int render_size = draw_size * pixel_scale;
329 
330  surface sdl_surf(render_size, render_size);
331  auto cairo_surface = cairo::create_surface(
332  reinterpret_cast<uint8_t*>(sdl_surf->pixels), ::point(sdl_surf->w, sdl_surf->h));
333 
334  auto cairo_context = cairo::create_context(cairo_surface);
335  cairo_t* ctx = cairo_context.get();
336  cairo_scale(ctx, pixel_scale, pixel_scale);
337 
338  cairo_set_antialias(ctx, CAIRO_ANTIALIAS_BEST);
339  cairo_set_source_rgba(ctx, 0.0, 0.0, 0.0, 0.0);
340  cairo_paint(ctx);
341 
342  cairo_set_line_width(ctx, thickness);
343  cairo_set_source_rgba(ctx,
344  c.r / 255.0,
345  c.g / 255.0,
346  c.b / 255.0,
347  c.a / 255.0
348  );
349 
350  // Reduce the arc radius by half the stroke width so the border stays within the circle
351  double half_thickness = 1.0 * thickness / 2;
352  cairo_arc(ctx, r, r, r - half_thickness, 0, 2 * boost::math::constants::pi<double>());
353  cairo_stroke(ctx);
354 
355  draw::blit(texture(sdl_surf), ::rect(cx - r, cy - r, draw_size, draw_size));
356 }
357 
358 void draw::cairo_disc(int cx, int cy, int r, const color_t& c)
359 {
360  if (r <= 0) {
361  return;
362  }
363 
364  int draw_size = 2 * r;
365  int pixel_scale = video::get_pixel_scale();
366  int render_size = draw_size * pixel_scale;
367 
368  surface sdl_surf(render_size, render_size);
369  auto cairo_surface = cairo::create_surface(
370  reinterpret_cast<uint8_t*>(sdl_surf->pixels), ::point(sdl_surf->w, sdl_surf->h));
371 
372  auto cairo_context = cairo::create_context(cairo_surface);
373  cairo_t* ctx = cairo_context.get();
374  cairo_scale(ctx, pixel_scale, pixel_scale);
375 
376  cairo_set_antialias(ctx, CAIRO_ANTIALIAS_BEST);
377  cairo_set_source_rgba(ctx,
378  c.r / 255.0,
379  c.g / 255.0,
380  c.b / 255.0,
381  c.a / 255.0
382  );
383  cairo_arc(ctx, r, r, r, 0, 2 * boost::math::constants::pi<double>());
384  cairo_fill(ctx);
385 
386  draw::blit(texture(sdl_surf), ::rect(cx - r, cy - r, draw_size, draw_size));
387 }
388 
389 /*******************/
390 /* texture drawing */
391 /*******************/
392 
393 
394 void draw::blit(const texture& tex, const ::rect& dst)
395 {
396  if (dst == sdl::empty_rect) {
397  return draw::blit(tex);
398  }
399 
400  if (!tex) { DBG_D << "null blit"; return; }
401  DBG_D << "blit " << dst;
402 
403  SDL_RenderCopy(renderer(), tex, tex.src(), &dst);
404 }
405 
406 void draw::blit(const texture& tex)
407 {
408  if (!tex) { DBG_D << "null blit"; return; }
409  DBG_D << "blit";
410 
411  SDL_RenderCopy(renderer(), tex, tex.src(), nullptr);
412 }
413 
414 
415 static SDL_RendererFlip get_flip(bool flip_h, bool flip_v)
416 {
417  // This should be easier than it is.
418  return static_cast<SDL_RendererFlip>(
419  static_cast<int>(flip_h ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE)
420  | static_cast<int>(flip_v ? SDL_FLIP_VERTICAL : SDL_FLIP_NONE)
421  );
422 }
423 
425  const texture& tex,
426  const ::rect& dst,
427  bool flip_h,
428  bool flip_v)
429 {
430  if (dst == sdl::empty_rect) {
431  return draw::flipped(tex, flip_h, flip_v);
432  }
433 
434  if (!tex) { DBG_D << "null flipped"; return; }
435  DBG_D << "flipped (" << flip_h << '|' << flip_v
436  << ") to " << dst;
437 
438  SDL_RendererFlip flip = get_flip(flip_h, flip_v);
439  SDL_RenderCopyEx(renderer(), tex, tex.src(), &dst, 0.0, nullptr, flip);
440 }
441 
442 void draw::flipped(const texture& tex, bool flip_h, bool flip_v)
443 {
444  if (!tex) { DBG_D << "null flipped"; return; }
445  DBG_D << "flipped (" << flip_h << '|' << flip_v << ')';
446 
447  SDL_RendererFlip flip = get_flip(flip_h, flip_v);
448  SDL_RenderCopyEx(renderer(), tex, tex.src(), nullptr, 0.0, nullptr, flip);
449 }
450 
451 
452 // TODO: highdpi - maybe expose this mirrored mode to WML somehow
453 void draw::tiled(const texture& tex, const ::rect& dst, bool centered,
454  bool mirrored)
455 {
456  if (!tex) { DBG_D << "null tiled"; return; }
457  DBG_D << "tiled (" << centered << '|' << mirrored
458  << ") " << dst;
459 
460  // Reduce clip to dst.
461  auto clipper = draw::reduce_clip(dst);
462 
463  const int xoff = centered ? (dst.w - tex.w()) / 2 : 0;
464  const int yoff = centered ? (dst.h - tex.h()) / 2 : 0;
465 
466  // Just blit the image however many times is necessary.
467  bool vf = false;
468  ::rect t{dst.x - xoff, dst.y - yoff, tex.w(), tex.h()};
469  for (; t.y < dst.y + dst.h; t.y += t.h, vf = !vf) {
470  bool hf = false;
471  for (t.x = dst.x - xoff; t.x < dst.x + dst.w; t.x += t.w, hf = !hf) {
472  if (mirrored) {
473  draw::flipped(tex, t, hf, vf);
474  } else {
475  draw::blit(tex, t);
476  }
477  }
478  }
479 }
480 
482  bool centered, bool mirrored)
483 {
484  if (!tex) { DBG_D << "null tiled_highres"; return; }
485  DBG_D << "tiled_highres (" << centered << '|' << mirrored
486  << ") " << dst;
487 
488  const int pixel_scale = video::get_pixel_scale();
489 
490  // Reduce clip to dst.
491  auto clipper = draw::reduce_clip(dst);
492 
494  const float w = float(size.x) / float(pixel_scale);
495  const float h = float(size.y) / float(pixel_scale);
496  const float xoff = centered ? (dst.w - w) / 2 : 0.0f;
497  const float yoff = centered ? (dst.h - h) / 2 : 0.0f;
498 
499  // Just blit the image however many times is necessary.
500  bool vf = false;
501  SDL_FRect t{dst.x - xoff, dst.y - yoff, w, h};
502  for (; t.y < dst.y + dst.h; t.y += t.h, vf = !vf) {
503  bool hf = false;
504  for (t.x = dst.x - xoff; t.x < dst.x + dst.w; t.x += t.w, hf = !hf) {
505  if (mirrored) {
506  SDL_RendererFlip flip = get_flip(hf, vf);
507  SDL_RenderCopyExF(renderer(), tex, nullptr, &t, 0.0, nullptr, flip);
508  } else {
509  SDL_RenderCopyF(renderer(), tex, nullptr, &t);
510  }
511  }
512  }
513 }
514 
516  const SDL_Color& cTL, const SDL_Color& cTR,
517  const SDL_Color& cBL, const SDL_Color& cBR,
518  const SDL_FPoint& uvTL, const SDL_FPoint& uvTR,
519  const SDL_FPoint& uvBL, const SDL_FPoint& uvBR)
520 {
521  const SDL_FPoint pTL{float(dst.x), float(dst.y)};
522  const SDL_FPoint pTR{float(dst.x + dst.w), float(dst.y)};
523  const SDL_FPoint pBL{float(dst.x), float(dst.y + dst.h)};
524  const SDL_FPoint pBR{float(dst.x + dst.w), float(dst.y + dst.h)};
525  std::array<SDL_Vertex,4> verts {
526  SDL_Vertex{pTL, cTL, uvTL},
527  SDL_Vertex{pTR, cTR, uvTR},
528  SDL_Vertex{pBL, cBL, uvBL},
529  SDL_Vertex{pBR, cBR, uvBR},
530  };
531  draw::smooth_shaded(tex, verts);
532 }
533 
535  const SDL_Color& cTL, const SDL_Color& cTR,
536  const SDL_Color& cBL, const SDL_Color& cBR)
537 {
538  SDL_FPoint uv[4] = {
539  {0.f, 0.f}, // top left
540  {1.f, 0.f}, // top right
541  {0.f, 1.f}, // bottom left
542  {1.f, 1.f}, // bottom right
543  };
544  draw::smooth_shaded(tex, dst, cTL, cTR, cBL, cBR,
545  uv[0], uv[1], uv[2], uv[3]);
546 }
547 
548 void draw::smooth_shaded(const texture& tex,
549  const std::array<SDL_Vertex, 4>& verts)
550 {
551  DBG_D << "smooth shade, verts:";
552  for (const SDL_Vertex& v : verts) {
553  DBG_D << " {(" << v.position.x << ',' << v.position.y << ") "
554  << v.color << " (" << v.tex_coord.x << ',' << v.tex_coord.y
555  << ")}";
556  }
557  int indices[6] = {0, 1, 2, 2, 1, 3};
558  SDL_RenderGeometry(renderer(), tex, &verts[0], 4, indices, 6);
559 }
560 
561 /***************************/
562 /* RAII state manipulation */
563 /***************************/
564 
565 
567  : c_(draw::get_clip()), clip_enabled_(draw::clip_enabled())
568 {
569  draw::force_clip(clip);
570 }
571 
573 {
574  if (clip_enabled_) {
575  draw::force_clip(c_);
576  } else {
578  }
579 }
580 
582 {
583  return draw::clip_setter(clip);
584 }
585 
587 {
588  if (!draw::clip_enabled()) {
589  return draw::clip_setter(clip);
590  }
591  return draw::clip_setter(draw::get_clip().intersect(clip));
592 }
593 
595 {
596  // TODO: highdpi - fix whatever reason there is for this guard (CI fail)
597  if (!renderer()) {
598  WRN_D << "trying to force clip will null renderer";
599  return;
600  }
601  DBG_D << "forcing clip to " << clip;
602 
603  SDL_RenderSetClipRect(renderer(), &clip);
604 }
605 
607 {
608  // TODO: highdpi - fix whatever reason there is for this guard (CI fail)
609  if (!renderer()) {
610  return {};
611  }
612 
613  if (!SDL_RenderIsClipEnabled(renderer())) {
614  return draw::get_viewport();
615  }
616 
617  ::rect clip;
618  SDL_RenderGetClipRect(renderer(), &clip);
619  return clip;
620 }
621 
623 {
624  if (!renderer()) {
625  return false;
626  }
627  return SDL_RenderIsClipEnabled(renderer());
628 }
629 
631 {
632  if (!renderer()) {
633  return;
634  }
635  SDL_RenderSetClipRect(renderer(), nullptr);
636  DBG_D << "clip disabled";
637 }
638 
640 {
641  if (!renderer()) {
642  return true;
643  }
644  if (!SDL_RenderIsClipEnabled(renderer())) {
645  return false;
646  }
647  ::rect clip;
648  SDL_RenderGetClipRect(renderer(), &clip);
649  return clip.w <= 0 || clip.h <= 0;
650 }
651 
652 
654  : v_(), c_(), clip_enabled_(draw::clip_enabled())
655 {
657  draw::force_viewport(view);
658  if (clip_enabled_) {
659  c_ = draw::get_clip();
660  // adjust clip for difference in viewport position
661  ::rect c_view = {
662  c_.x + v_.x - view.x,
663  c_.y + v_.y - view.y,
664  c_.w, c_.h
665  };
666  draw::force_clip(c_view);
667  }
668 }
669 
671 {
673  if (clip_enabled_) {
674  draw::force_clip(c_);
675  } else {
677  }
678 }
679 
681 {
682  return draw::viewport_setter(viewport);
683 }
684 
686 {
687  if (!renderer()) {
688  WRN_D << "trying to force viewport will null renderer";
689  return;
690  }
691  DBG_D << "forcing viewport to " << viewport;
692 
693  SDL_RenderSetViewport(renderer(), &viewport);
694 }
695 
697 {
698  if (!renderer()) {
699  WRN_D << "no renderer available to get viewport";
700  return {};
701  }
702 
703  ::rect viewport;
704  SDL_RenderGetViewport(renderer(), &viewport);
705 
706  if (viewport == sdl::empty_rect) {
707  return video::draw_area();
708  }
709  return viewport;
710 }
711 
713  : target_()
714  , viewport_()
715  , clip_()
716 {
717  // Validate we can render to this texture.
718  assert(!t || t.get_access() == SDL_TEXTUREACCESS_TARGET);
719 
720  if (!renderer()) {
721  WRN_D << "can't set render target with null renderer";
722  return;
723  }
724 
726  SDL_RenderGetViewport(renderer(), &viewport_);
727  SDL_RenderGetClipRect(renderer(), &clip_);
728 
729  if (t) {
731  } else {
733  }
734 }
735 
737 {
738  if (!renderer()) {
739  WRN_D << "can't reset render target with null renderer";
740  return;
741  }
743  SDL_RenderSetViewport(renderer(), &viewport_);
744  if(clip_ == sdl::empty_rect) return;
745  SDL_RenderSetClipRect(renderer(), &clip_);
746 }
747 
749 {
750  if (t) {
751  DBG_D << "setting render target to "
752  << t.w() << 'x' << t.h() << " texture";
753  } else {
754  DBG_D << "setting render target to main render buffer";
755  }
757 }
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 ::rect &clip)
Definition: draw.cpp:566
A class to manage automatic restoration of the render target.
Definition: draw.hpp:478
render_target_setter(const texture &t)
Definition: draw.cpp:712
A class to manage automatic restoration of the viewport region.
Definition: draw.hpp:418
viewport_setter(const ::rect &viewport)
Definition: draw.cpp:653
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 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:415
#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:685
void smooth_shaded(const texture &tex, const ::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:515
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:481
render_target_setter set_render_target(const texture &t)
Set the given texture as the active render target.
Definition: draw.cpp:748
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:220
void tiled(const texture &tex, const ::rect &dst, bool centered=false, bool mirrored=false)
Tile a texture to fill a region.
Definition: draw.cpp:453
void rect(const ::rect &rect)
Draw a rectangle.
Definition: draw.cpp:159
void cairo_disc(int cx, int cy, int r, const color_t &c)
Draw filled circle using Cairo.
Definition: draw.cpp:358
bool null_clip()
Whether the current clipping region will disallow drawing.
Definition: draw.cpp:639
void points(const std::vector<::point > &points)
Draw a set of points.
Definition: draw.cpp:205
bool clip_enabled()
Whether clipping is enabled.
Definition: draw.cpp:622
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:586
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:424
void cairo_circle(int cx, int cy, int r, const color_t &c, int thickness)
Draw outline of circle using Cairo.
Definition: draw.cpp:320
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:262
void set_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Set the drawing colour.
Definition: draw.cpp:109
clip_setter override_clip(const ::rect &clip)
Override the clipping area.
Definition: draw.cpp:581
void point(int x, int y)
Draw a single point.
Definition: draw.cpp:214
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 force_clip(const ::rect &clip)
Set the clipping area, without any provided way of setting it back.
Definition: draw.cpp:594
viewport_setter set_viewport(const ::rect &viewport)
Set the viewport.
Definition: draw.cpp:680
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:52
::rect get_viewport()
Get the current viewport.
Definition: draw.cpp:696
::rect get_clip()
Get the current clipping area, in draw coordinates.
Definition: draw.cpp:606
void disable_clip()
Disable clipping.
Definition: draw.cpp:630
void blit(const texture &tex, const ::rect &dst)
Draws a texture, or part of a texture, at the given location.
Definition: draw.cpp:394
void line(int from_x, int from_y, int to_x, int to_y)
Draw a line.
Definition: draw.cpp:189
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:459
void reset_render_target()
Reset the render target to the primary render buffer.
Definition: video.cpp:559
void force_render_target(const texture &t)
Set the render target, without any provided way of setting it back.
Definition: video.cpp:523
int get_pixel_scale()
Get the current active pixel scale multiplier.
Definition: video.cpp:498
SDL_Renderer * get_renderer()
Definition: video.cpp:683
texture get_render_target()
Get the current render target.
Definition: video.cpp:564
point draw_size()
The size of the current render target in drawing coordinates.
Definition: video.cpp:454
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: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