The Battle for Wesnoth  1.17.12+dev
video.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2022
3  by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "video.hpp"
17 
18 #include "display.hpp"
19 #include "draw_manager.hpp"
20 #include "floating_label.hpp"
21 #include "font/sdl_ttf_compat.hpp"
22 #include "font/text.hpp"
23 #include "log.hpp"
24 #include "picture.hpp"
25 #include "preferences/general.hpp"
26 #include "sdl/input.hpp"
27 #include "sdl/point.hpp"
28 #include "sdl/texture.hpp"
29 #include "sdl/userevent.hpp"
30 #include "sdl/utils.hpp"
31 #include "sdl/window.hpp"
32 #include "widgets/menu.hpp" // for bluebg_style.unload_images
33 
34 #ifdef TARGET_OS_OSX
35 #include "desktop/apple_video.hpp"
36 #include "game_version.hpp"
37 #endif
38 
39 #include <SDL2/SDL_render.h> // SDL_Texture
40 
41 #include <cassert>
42 #include <vector>
43 
44 static lg::log_domain log_display("display");
45 #define LOG_DP LOG_STREAM(info, log_display)
46 #define ERR_DP LOG_STREAM(err, log_display)
47 #define WRN_DP LOG_STREAM(warn, log_display)
48 #define DBG_DP LOG_STREAM(debug, log_display)
49 
50 namespace
51 {
52 /** The SDL window object. Will be null only if headless_. */
53 std::unique_ptr<sdl::window> window;
54 
55 /** The main offscreen render target. */
56 texture render_texture_ = {};
57 
58 /** The current offscreen render target. */
59 texture current_render_target_ = {};
60 
61 bool headless_ = false; /**< running with no window at all */
62 bool testing_ = false; /**< running unit tests */
63 point test_resolution_ = {1024, 768}; /**< resolution for unit tests */
64 int refresh_rate_ = 0;
65 point game_canvas_size_ = {0, 0};
66 int pixel_scale_ = 1;
67 rect input_area_ = {};
68 
69 } // anon namespace
70 
71 namespace video
72 {
73 
74 // Non-public interface
75 void render_screen(); // exposed and used only in draw_manager.cpp
76 
77 // Internal functions
78 static void init_window();
79 static void init_test_window();
80 static void init_fake();
81 static void init_test();
82 static bool update_framebuffer();
83 static bool update_test_framebuffer();
84 static point draw_offset();
85 
86 
87 void init(fake type)
88 {
89  LOG_DP << "initializing video";
90  if(SDL_WasInit(SDL_INIT_VIDEO)) {
91  throw error("video subsystem already initialized");
92  }
93  if(SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
94  ERR_DP << "Could not initialize SDL_video: " << SDL_GetError();
95  throw error("Video initialization failed");
96  }
97 
98  switch(type) {
99  case fake::none:
100  init_window();
101  break;
102  case fake::window:
103  init_fake();
104  break;
105  case fake::draw:
106  init_test();
107  break;
108  default:
109  throw error("unrecognized fake type passed to video::init");
110  }
111 }
112 
113 void deinit()
114 {
115  LOG_DP << "deinitializing video";
116 
117  // SDL_INIT_TIMER is always initialized at program start.
118  // If it is not initialized here, there is a problem.
119  assert(SDL_WasInit(SDL_INIT_TIMER));
120 
121  // Clear any static texture caches,
122  // lest they try to delete textures after SDL_Quit.
125  render_texture_.reset();
126  current_render_target_.reset();
128 
129  // Destroy the window, and thus also the renderer.
130  window.reset();
131 
132  // Close the video subsystem.
133  if(SDL_WasInit(SDL_INIT_VIDEO)) {
134  LOG_DP << "quitting SDL video subsystem";
135  SDL_QuitSubSystem(SDL_INIT_VIDEO);
136  }
137  if(SDL_WasInit(SDL_INIT_VIDEO)) {
138  // This should not have been initialized multiple times
139  throw error("video subsystem still initialized after deinit");
140  }
141 }
142 
143 bool headless()
144 {
145  return headless_;
146 }
147 
148 bool testing()
149 {
150  return testing_;
151 }
152 
153 void init_fake()
154 {
155  headless_ = true;
156  refresh_rate_ = 1;
157  game_canvas_size_ = {800,600};
158 }
159 
160 void init_test()
161 {
162  testing_ = true;
163  refresh_rate_ = 1;
165 }
166 
167 /** Returns true if the buffer was changed */
169 {
170  if (!window) {
171  throw("trying to update test framebuffer with no window");
172  }
173 
174  bool changed = false;
175 
176  // TODO: code unduplication
177  // Build or update the current render texture.
178  if (render_texture_) {
179  int w, h;
180  SDL_QueryTexture(render_texture_, nullptr, nullptr, &w, &h);
181  if (w != test_resolution_.x || h != test_resolution_.y) {
182  // Delete it and let it be recreated.
183  LOG_DP << "destroying old render texture";
184  render_texture_.reset();
185  }
186  }
187  if (!render_texture_) {
188  LOG_DP << "creating offscreen render texture";
189  render_texture_.assign(SDL_CreateTexture(
190  *window,
191  window->pixel_format(),
192  SDL_TEXTUREACCESS_TARGET,
193  test_resolution_.x, test_resolution_.y
194  ));
195  LOG_DP << "updated render target to " << test_resolution_.x
196  << "x" << test_resolution_.y;
197  changed = true;
198  }
199 
200  pixel_scale_ = 1;
201  game_canvas_size_ = test_resolution_;
202  input_area_ = {{}, test_resolution_};
203 
204  // The render texture is always the render target in this case.
205  force_render_target(render_texture_);
206 
207  return changed;
208 }
209 
211 {
212  if (!window) {
213  throw error("trying to update framebuffer with no window");
214  }
215 
216  if (testing_) {
217  return update_test_framebuffer();
218  }
219 
220  bool changed = false;
221 
222  // Make sure we're getting values from the native window.
223  SDL_SetRenderTarget(*window, nullptr);
224 
225  // Non-integer scales are not currently supported.
226  // This option makes things neater when window size is not a perfect
227  // multiple of logical size, which can happen when manually resizing.
228  SDL_RenderSetIntegerScale(*window, SDL_TRUE);
229 
230  // Find max valid pixel scale at current output size.
231  point osize(window->get_output_size());
232  int max_scale = std::min(
235  max_scale = std::min(max_scale, preferences::max_pixel_scale);
236 
237  // Determine best pixel scale according to preference and window size
238  int scale = 1;
240  // Try to match the default size (1280x720) but do not reduce below
241  int def_scale = std::min(
244  scale = std::min(max_scale, def_scale);
245  // Otherwise reduce to keep below the max window size (1920x1080).
246  int min_scale = std::min(
247  osize.x / (preferences::max_window_width+1) + 1,
248  osize.y / (preferences::max_window_height+1) + 1);
249  scale = std::max(scale, min_scale);
250  } else {
251  scale = std::min(max_scale, preferences::pixel_scale());
252  }
253  // Cache it for easy access.
254  if (pixel_scale_ != scale) {
255  pixel_scale_ = scale;
256  changed = true;
257  }
258 
259  // Update logical size if it doesn't match the current resolution and scale.
260  point lsize(window->get_logical_size());
261  point wsize(window->get_size());
262  if (lsize.x != osize.x / scale || lsize.y != osize.y / scale) {
264  LOG_DP << "reducing pixel scale from desired "
265  << preferences::pixel_scale() << " to maximum allowable "
266  << scale;
267  }
268  LOG_DP << "pixel scale: " << scale;
269  LOG_DP << "overriding logical size";
270  LOG_DP << " old lsize: " << lsize;
271  LOG_DP << " old wsize: " << wsize;
272  LOG_DP << " old osize: " << osize;
273  window->set_logical_size(osize.x / scale, osize.y / scale);
274  lsize = window->get_logical_size();
275  wsize = window->get_size();
276  osize = window->get_output_size();
277  LOG_DP << " new lsize: " << lsize;
278  LOG_DP << " new wsize: " << wsize;
279  LOG_DP << " new osize: " << osize;
280  float sx, sy;
281  SDL_RenderGetScale(*window, &sx, &sy);
282  LOG_DP << " render scale: " << sx << ", " << sy;
283  }
284  // Cache it for easy access
285  game_canvas_size_ = lsize;
286 
287  // Build or update the current render texture.
288  if (render_texture_) {
289  int w, h;
290  SDL_QueryTexture(render_texture_, nullptr, nullptr, &w, &h);
291  if (w != osize.x || h != osize.y) {
292  // Delete it and let it be recreated.
293  LOG_DP << "destroying old render texture";
294  render_texture_.reset();
295  }
296  }
297  if (!render_texture_) {
298  LOG_DP << "creating offscreen render texture";
299  render_texture_.assign(SDL_CreateTexture(
300  *window,
301  window->pixel_format(),
302  SDL_TEXTUREACCESS_TARGET,
303  osize.x, osize.y
304  ));
305  // This isn't really necessary, but might be nice to have attached
306  render_texture_.set_draw_size(lsize);
307  changed = true;
308  }
309 
310  // Assign the render texture now. It will be used for all drawing.
311  force_render_target(render_texture_);
312 
313  // By default input area is the same as the window area.
314  input_area_ = {{}, wsize};
315 
316  rect active_area = to_output(draw_area());
317  if (active_area.size() != osize) {
318  LOG_DP << "render target offset: LT " << active_area.pos() << " RB "
319  << osize - active_area.size() - active_area.pos();
320  // Translate active_area into display coordinates as input_area_
321  input_area_ = {
322  (active_area.pos() * wsize) / osize,
323  (active_area.size() * wsize) / osize
324  };
325  LOG_DP << "input area: " << input_area_;
326  }
327 
328  return changed;
329 }
330 
332 {
333  LOG_DP << "creating test window " << test_resolution_.x
334  << "x" << test_resolution_.y;
335 
336  uint32_t window_flags = 0;
337  window_flags |= SDL_WINDOW_HIDDEN;
338  // The actual window won't be used, as we'll be rendering to texture.
339 
340  uint32_t renderer_flags = 0;
341  renderer_flags |= SDL_RENDERER_TARGETTEXTURE;
342  // All we need is to be able to render to texture.
343 
344  window.reset(new sdl::window(
345  "", 0, 0, test_resolution_.x, test_resolution_.y,
346  window_flags, renderer_flags
347  ));
348 
350 }
351 
353 {
354  // Position
355  const int x = preferences::fullscreen() ? SDL_WINDOWPOS_UNDEFINED : SDL_WINDOWPOS_CENTERED;
356  const int y = preferences::fullscreen() ? SDL_WINDOWPOS_UNDEFINED : SDL_WINDOWPOS_CENTERED;
357 
358  // Dimensions
359  const point res = preferences::resolution();
360  const int w = res.x;
361  const int h = res.y;
362 
363  uint32_t window_flags = 0;
364 
365  // Add any more default flags here
366  window_flags |= SDL_WINDOW_RESIZABLE;
367  window_flags |= SDL_WINDOW_ALLOW_HIGHDPI;
368 
370  window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
371  } else if(preferences::maximized()) {
372  window_flags |= SDL_WINDOW_MAXIMIZED;
373  }
374 
375  uint32_t renderer_flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE;
376 
377  if(preferences::vsync()) {
378  LOG_DP << "VSYNC on";
379  renderer_flags |= SDL_RENDERER_PRESENTVSYNC;
380  }
381 
382  // Initialize window
383  window.reset(new sdl::window("", x, y, w, h, window_flags, renderer_flags));
384 
385  // It is assumed that this function is only ever called once.
386  // If that is no longer true, then you should clean things up.
387  assert(!render_texture_);
388 
389  PLAIN_LOG << "Setting mode to " << w << "x" << h;
390 
392 
393  SDL_DisplayMode currentDisplayMode;
394  SDL_GetCurrentDisplayMode(window->get_display_index(), &currentDisplayMode);
395  refresh_rate_ = currentDisplayMode.refresh_rate != 0 ? currentDisplayMode.refresh_rate : 60;
396 
398 }
399 
401 {
402  return bool(window);
403 }
404 
406 {
407  if (testing_) {
408  return test_resolution_;
409  }
410  // As we are rendering via an abstraction, we should never need this.
411  return window->get_output_size();
412 }
413 
415 {
416  if (testing_) {
417  return test_resolution_;
418  }
419  return window->get_size();
420 }
421 
423 {
424  return {0, 0, game_canvas_size_.x, game_canvas_size_.y};
425 }
426 
428 {
429  return game_canvas_size_;
430 }
431 
433 {
434  return current_render_target_.draw_size();
435 }
436 
438 {
439  return {0, 0, current_render_target_.w(), current_render_target_.h()};
440 }
441 
443 {
444  // As we are using SDL_RenderSetIntegerScale, there may be a slight
445  // offset of the drawable area on the render target if the target size
446  // is not perfectly divisble by the scale.
447  // SDL doesn't provide any way of retrieving this offset,
448  // so we just have to base our calculation on the known behaviour.
449  point osize = output_size();
450  point dsize = draw_size();
451  point scale = osize / dsize;
452  return (osize - (scale * dsize)) / 2;
453 }
454 
456 {
457  point p = output_size();
458  return {0, 0, p.x, p.y};
459 }
460 
461 rect to_output(const rect& r)
462 {
463  // Multiply r by integer scale, adding draw_offset to the position.
464  point dsize = current_render_target_.draw_size();
465  point osize = current_render_target_.get_raw_size();
466  point pos = (r.pos() * (osize / dsize)) + draw_offset();
467  point size = r.size() * (osize / dsize);
468  return {pos, size};
469 }
470 
472 {
473  return input_area_;
474 }
475 
477 {
478  return pixel_scale_;
479 }
480 
482 {
483  // TODO: this should be more clever, depending on usage
484  return refresh_rate_;
485 }
486 
488 {
489  if (SDL_SetRenderTarget(get_renderer(), t)) {
490  ERR_DP << "failed to set render target to "
491  << static_cast<void*>(t.get()) << ' '
492  << t.draw_size() << " / " << t.get_raw_size();
493  ERR_DP << "last SDL error: " << SDL_GetError();
494  throw error("failed to set render target");
495  }
496  current_render_target_ = t;
497 
498  if (testing_) {
499  return;
500  }
501 
502  // The scale factor gets reset when the render target changes,
503  // so make sure it gets set back appropriately.
504  if (!t) {
505  DBG_DP << "rendering to window / screen";
506  window->set_logical_size(game_canvas_size_);
507  } else if (t == render_texture_) {
508  DBG_DP << "rendering to primary buffer";
509  window->set_logical_size(game_canvas_size_);
510  } else {
511  DBG_DP << "rendering to custom target "
512  << static_cast<void*>(t.get()) << ' '
513  << t.draw_size() << " / " << t.get_raw_size();
514  window->set_logical_size(t.w(), t.h());
515  }
516 }
517 
519 {
521 }
522 
524 {
525  // This should always be up-to-date, but assert for sanity.
526  assert(current_render_target_ == SDL_GetRenderTarget(get_renderer()));
527  return current_render_target_;
528 }
529 
530 // Note: this is not thread-safe.
531 // Drawing functions should not be called while this is active.
532 // SDL renderer usage is not thread-safe anyway, so this is fine.
534 {
535  if(headless_ || testing_) {
536  // No need to present anything in this case
537  return;
538  }
539 
540  if(!window) {
541  WRN_DP << "trying to render with no window";
542  return;
543  }
544 
545  // This should only ever be called when the main render texture is the
546  // current render target. It could be adapted otherwise... but let's not.
547  if(SDL_GetRenderTarget(*window) != render_texture_) {
548  ERR_DP << "trying to render screen, but current render texture is "
549  << static_cast<void*>(SDL_GetRenderTarget(*window))
550  << " | " << static_cast<void*>(current_render_target_.get())
551  << ". It should be " << static_cast<void*>(render_texture_.get());
552  throw error("tried to render screen from wrong render target");
553  }
554 
555  // Clear the render target so we're drawing to the window.
557 
558  // Copy the render texture to the window.
559  SDL_RenderCopy(*window, render_texture_, nullptr, nullptr);
560 
561  // Finalize and display the frame.
562  SDL_RenderPresent(*window);
563 
564  // Reset the render target to the render texture.
565  force_render_target(render_texture_);
566 }
567 
568 surface read_pixels(SDL_Rect* r)
569 {
570  if (!window) {
571  WRN_DP << "trying to read pixels with no window";
572  return surface();
573  }
574 
575  // This should be what we want to read from.
576  texture& target = current_render_target_;
577 
578  // Make doubly sure.
579  if (target != SDL_GetRenderTarget(*window)) {
580  SDL_Texture* t = SDL_GetRenderTarget(*window);
581  ERR_DP << "render target " << static_cast<void*>(target.get())
582  << ' ' << target.draw_size() << " / " << target.get_raw_size()
583  << " doesn't match window render target "
584  << static_cast<void*>(t);
585  throw error("unexpected render target while reading pixels");
586  }
587 
588  // Intersect the draw area with the given rect.
589  rect r_clipped = draw_area();
590  if (r) {
591  r_clipped.clip(*r);
592  if (r_clipped != *r) {
593  DBG_DP << "modifying pixel read area from " << *r
594  << " to " << r_clipped;
595  *r = r_clipped;
596  }
597  }
598 
599  // Convert the rect to output coordinates, if necessary.
600  rect o = to_output(r_clipped);
601 
602  // Create surface and read pixels
603  surface s(o.w, o.h);
604  SDL_RenderReadPixels(*window, &o, s->format->format, s->pixels, s->pitch);
605  return s;
606 }
607 
609 {
610  if(!window) {
611  WRN_DP << "trying to read pixels with no window";
612  return surface();
613  }
614  surface s = read_pixels(r);
615  if(r) {
616  return scale_surface(s, r->w, r->h);
617  } else {
618  return scale_surface(s, draw_size().x, draw_size().y);
619  }
620 }
621 
622 void set_window_title(const std::string& title)
623 {
624  assert(window);
625  window->set_title(title);
626 }
627 
629 {
630  assert(window);
631  window->set_icon(icon);
632 }
633 
634 SDL_Renderer* get_renderer()
635 {
636  if(window) {
637  return *window;
638  } else {
639  return nullptr;
640  }
641 }
642 
643 SDL_Window* get_window()
644 {
645  return *window;
646 }
647 
648 std::string current_driver()
649 {
650  const char* const drvname = SDL_GetCurrentVideoDriver();
651  return drvname ? drvname : "<not initialized>";
652 }
653 
654 std::vector<std::string> enumerate_drivers()
655 {
656  std::vector<std::string> res;
657  int num_drivers = SDL_GetNumVideoDrivers();
658 
659  for(int n = 0; n < num_drivers; ++n) {
660  const char* drvname = SDL_GetVideoDriver(n);
661  res.emplace_back(drvname ? drvname : "<invalid driver>");
662  }
663 
664  return res;
665 }
666 
667 /**
668  * Tests whether the given flags are currently set on the SDL window.
669  *
670  * @param flags The flags to test, OR'd together.
671  */
672 static bool window_has_flags(uint32_t flags)
673 {
674  return window && (window->get_flags() & flags) != 0;
675 }
676 
678 {
679  return window_has_flags(SDL_WINDOW_SHOWN);
680 }
681 
683 {
684  return window_has_flags(SDL_WINDOW_MOUSE_FOCUS | SDL_WINDOW_INPUT_FOCUS);
685 }
686 
688 {
689  return window_has_flags(SDL_WINDOW_MOUSE_FOCUS);
690 }
691 
692 std::vector<point> get_available_resolutions(const bool include_current)
693 {
694  std::vector<point> result;
695 
696  if(!window) {
697  return result;
698  }
699 
700  const int display_index = window->get_display_index();
701 
702  const int modes = SDL_GetNumDisplayModes(display_index);
703  if(modes <= 0) {
704  PLAIN_LOG << "No modes supported";
705  return result;
706  }
707 
709 
710  // The maximum size to which this window can be set. For some reason this won't
711  // pop up as a display mode of its own.
712  SDL_Rect bounds;
713  SDL_GetDisplayBounds(display_index, &bounds);
714 
715  SDL_DisplayMode mode;
716 
717  for(int i = 0; i < modes; ++i) {
718  if(SDL_GetDisplayMode(display_index, i, &mode) == 0) {
719  // Exclude any results outside the range of the current DPI.
720  if(mode.w > bounds.w && mode.h > bounds.h) {
721  continue;
722  }
723 
724  if(mode.w >= min_res.x && mode.h >= min_res.y) {
725  result.emplace_back(mode.w, mode.h);
726  }
727  }
728  }
729 
730  if(std::find(result.begin(), result.end(), min_res) == result.end()) {
731  result.push_back(min_res);
732  }
733 
734  if(include_current) {
735  result.push_back(current_resolution());
736  }
737 
738  std::sort(result.begin(), result.end());
739  result.erase(std::unique(result.begin(), result.end()), result.end());
740 
741  return result;
742 }
743 
745 {
746  if (testing_) {
747  return test_resolution_;
748  }
749  return point(window->get_size()); // Convert from plain SDL_Point
750 }
751 
753 {
754  if (testing_) {
755  return true;
756  }
757  return (window->get_flags() & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
758 }
759 
761 {
762  if (headless_ || testing_) {
763  return;
764  }
765 
766  // Only do anything if the current value differs from the desired value
767  if (window && is_fullscreen() != fullscreen) {
768  if (fullscreen) {
769  window->full_screen();
770  } else if (preferences::maximized()) {
771  window->to_window();
772  window->maximize();
773  } else {
774  window->to_window();
775  window->restore();
776  }
777  update_buffers();
778  }
779 
780  // Update the config value in any case.
781  preferences::_set_fullscreen(fullscreen);
782 }
783 
785 {
787 }
788 
790 {
791  if(resolution == current_resolution()) {
792  return false;
793  }
794 
795  if(!window) {
796  throw error("tried to set resolution with no window");
797  }
798 
799  if(testing_) {
800  LOG_DP << "resizing test resolution to " << resolution;
801  test_resolution_ = resolution;
802  return update_test_framebuffer();
803  }
804 
805  window->restore();
806  window->set_size(resolution.x, resolution.y);
807  window->center();
808 
809  update_buffers();
810 
811  // Change the saved values in preferences.
812  LOG_DP << "updating resolution to " << resolution;
813  preferences::_set_resolution(resolution);
815 
816  return true;
817 }
818 
819 void update_buffers(bool autoupdate)
820 {
821  if(headless_) {
822  return;
823  }
824 
825  LOG_DP << "updating video buffers";
826  if(update_framebuffer() && autoupdate) {
828  }
829 }
830 
831 std::pair<float, float> get_dpi()
832 {
833  float hdpi = 0.0f, vdpi = 0.0f;
834  if(window && SDL_GetDisplayDPI(window->get_display_index(), nullptr, &hdpi, &vdpi) == 0) {
835 #ifdef TARGET_OS_OSX
836  // SDL 2.0.12 changes SDL_GetDisplayDPI. Function now returns DPI
837  // multiplied by screen's scale factor. This part of code reverts
838  // this multiplication.
839  //
840  // For more info see issue: https://github.com/wesnoth/wesnoth/issues/5019
841  if(sdl::get_version() >= version_info{2, 0, 12}) {
842  float scale_factor = desktop::apple::get_scale_factor(window->get_display_index());
843  hdpi /= scale_factor;
844  vdpi /= scale_factor;
845  }
846 #endif
847  }
848  return { hdpi, vdpi };
849 }
850 
851 std::vector<std::pair<std::string, std::string>> renderer_report()
852 {
853  std::vector<std::pair<std::string, std::string>> res;
854  SDL_Renderer* rnd;
855  SDL_RendererInfo ri;
856 
857  if(window && (rnd = *window) && SDL_GetRendererInfo(rnd, &ri) == 0) {
858  std::string renderer_name = ri.name ? ri.name : "<unknown>";
859 
860  if(ri.flags & SDL_RENDERER_SOFTWARE) {
861  renderer_name += " (sw)";
862  }
863 
864  if(ri.flags & SDL_RENDERER_ACCELERATED) {
865  renderer_name += " (hw)";
866  }
867 
868  std::string renderer_max = std::to_string(ri.max_texture_width) +
869  'x' +
870  std::to_string(ri.max_texture_height);
871 
872  res.emplace_back("Renderer", renderer_name);
873  res.emplace_back("Maximum texture size", renderer_max);
874  res.emplace_back("VSync", ri.flags & SDL_RENDERER_PRESENTVSYNC ? "on" : "off");
875  }
876 
877  return res;
878 }
879 
880 } // namespace video
void init(fake type)
Initialize the video subsystem.
Definition: video.cpp:87
void _set_fullscreen(bool ison)
Definition: general.cpp:455
#define PLAIN_LOG
Definition: log.hpp:258
#define DBG_DP
Definition: video.cpp:48
const int min_window_height
Definition: general.cpp:67
std::vector< point > get_available_resolutions(const bool include_current)
Returns the list of available screen resolutions.
Definition: video.cpp:692
surface read_pixels(SDL_Rect *r)
Copy back a portion of the render target that is already drawn.
Definition: video.cpp:568
int get_pixel_scale()
Get the current active pixel scale multiplier.
Definition: video.cpp:476
SDL_Renderer * get_renderer()
Definition: video.cpp:634
void _set_maximized(bool ison)
Definition: general.cpp:450
Interfaces for manipulating version numbers of engine, add-ons, etc.
int w() const
The draw-space width of the texture, in pixels.
Definition: texture.hpp:105
std::string current_driver()
The current video driver in use, or else "<not initialized>".
Definition: video.cpp:648
void render_screen()
Definition: video.cpp:533
An error specifically indicating video subsystem problems.
Definition: video.hpp:306
void set_window_title(const std::string &title)
Sets the title of the main window.
Definition: video.cpp:622
#define ERR_DP
Definition: video.cpp:46
rect output_area()
{0, 0, output_size().x, output_size().y}
Definition: video.cpp:455
bool is_fullscreen()
Whether we are currently in fullscreen mode.
Definition: video.cpp:752
#define WRN_DP
Definition: video.cpp:47
#define LOG_DP
Definition: video.cpp:45
bool window_has_focus()
True iff the window has mouse or input focus.
Definition: video.cpp:682
static bool update_test_framebuffer()
Returns true if the buffer was changed.
Definition: video.cpp:168
const int min_window_width
Definition: general.cpp:66
int h() const
The draw-space height of the texture, in pixels.
Definition: texture.hpp:114
point get_raw_size() const
The raw internal texture size.
Definition: texture.cpp:112
const int max_window_width
Definition: general.cpp:72
rect to_output(const rect &r)
Convert coordinates in draw space to coordinates in render space.
Definition: video.cpp:461
int current_refresh_rate()
The refresh rate of the screen.
Definition: video.cpp:481
bool vsync()
Definition: general.cpp:439
void _set_resolution(const point &res)
Definition: general.cpp:444
void deinit()
Deinitialize the video subsystem.
Definition: video.cpp:113
static void init_window()
Definition: video.cpp:352
void set_fullscreen(bool fullscreen)
Set the fullscreen state.
Definition: video.cpp:760
std::vector< std::pair< std::string, std::string > > renderer_report()
Provides diagnostic information about the current renderer for the build_info API.
Definition: video.cpp:851
constexpr point pos() const
Definition: rect.hpp:64
#define h
bool testing()
The game is running unit tests.
Definition: video.cpp:148
surface scale_surface(const surface &surf, int w, int h)
Scale a surface using alpha-weighted modified bilinear filtering Note: causes artifacts with alpha gr...
Definition: utils.cpp:129
static point draw_offset()
Definition: video.cpp:442
texture get_render_target()
Get the current render target.
Definition: video.cpp:523
static bool window_has_flags(uint32_t flags)
Tests whether the given flags are currently set on the SDL window.
Definition: video.cpp:672
std::vector< std::string > enumerate_drivers()
A list of available video drivers.
Definition: video.cpp:654
static bool update_framebuffer()
Definition: video.cpp:210
static imgsel_style bluebg_style
Definition: menu.hpp:96
Contains functions for cleanly handling SDL input.
Wrapper class to encapsulate creation and management of an SDL_Texture.
Definition: texture.hpp:32
bool maximized()
Definition: general.cpp:429
void invalidate_all()
Mark the entire screen as requiring redraw.
bool set_resolution(const point &resolution)
Set the window resolution.
Definition: video.cpp:789
void flush_cache()
Purges all image caches.
Definition: picture.cpp:234
void update_buffers(bool autoupdate)
Update buffers to match current resolution and pixel scale settings.
Definition: video.cpp:819
point current_resolution()
The current window size in desktop coordinates.
Definition: video.cpp:744
static void init_fake()
Definition: video.cpp:153
rect game_canvas()
The game canvas area, in drawing coordinates.
Definition: video.cpp:422
point draw_size() const
The size of the texture in draw-space.
Definition: texture.hpp:122
version_info get_version()
Returns the runtime SDL version.
Definition: utils.cpp:34
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:87
The wrapper class for the SDL_Window class.
Definition: window.hpp:47
void scale(size_t factor, const uint32_t *src, uint32_t *trg, int srcWidth, int srcHeight, const ScalerCfg &cfg=ScalerCfg(), int yFirst=0, int yLast=std::numeric_limits< int >::max())
Definition: xbrz.cpp:1190
point output_size()
Returns the size of the final render target.
Definition: video.cpp:405
bool fullscreen()
Definition: general.cpp:434
static lg::log_domain log_display("display")
void clip(const SDL_Rect &r)
Clip this rectangle by the given rectangle.
Definition: rect.cpp:101
rect draw_area()
The current drawable area.
Definition: video.cpp:437
bool headless()
The game is running headless.
Definition: video.cpp:143
map_display and display: classes which take care of displaying the map and game-data on the screen...
const int max_pixel_scale
Definition: general.cpp:79
constexpr point size() const
Definition: rect.hpp:65
int pixel_scale()
Definition: general.cpp:408
void set_window_icon(surface &icon)
Sets the icon of the main window.
Definition: video.cpp:628
std::pair< float, float > get_dpi()
Retrieves the current game screen DPI for the build_info API.
Definition: video.cpp:831
CGFloat get_scale_factor(int display_index)
const int def_window_width
Definition: general.cpp:69
std::size_t i
Definition: function.cpp:968
mock_party p
static map_location::DIRECTION s
void force_render_target(const texture &t)
Set the render target, without any provided way of setting it back.
Definition: video.cpp:487
fake
For describing the type of faked display, if any.
Definition: video.hpp:44
point game_canvas_size()
The size of the game canvas, in drawing coordinates / game pixels.
Definition: video.cpp:427
An abstract description of a rectangle with integer coordinates.
Definition: rect.hpp:46
static void init_test_window()
Definition: video.cpp:331
Holds a 2D point.
Definition: point.hpp:24
void flush_texture_cache()
Flush the rendered text cache.
Definition: text.cpp:65
int w
bool has_window()
Whether the game has set up a window to render into.
Definition: video.cpp:400
bool window_has_mouse_focus()
True iff the window has mouse focus.
Definition: video.cpp:687
Represents version numbers.
point draw_size()
The size of the current render target in drawing coordinates.
Definition: video.cpp:432
bool window_is_visible()
True iff the window is not hidden.
Definition: video.cpp:677
void toggle_fullscreen()
Toggle fullscreen mode.
Definition: video.cpp:784
const int def_window_height
Definition: general.cpp:70
SDL_Texture * get() const
Definition: texture.hpp:196
surface read_pixels_low_res(SDL_Rect *r)
The same as read_pixels, but returns a low-resolution surface suitable for use with the old drawing s...
Definition: video.cpp:608
SDL_Window * get_window()
Definition: video.cpp:643
double t
Definition: astarsearch.cpp:65
Standard logging facilities (interface).
point window_size()
Returns the size of the window in display units / screen coordinates.
Definition: video.cpp:414
rect input_area()
Returns the input area of the window, in display coordinates.
Definition: video.cpp:471
Contains a wrapper class for the SDL_Window class.
void point(int x, int y)
Draw a single point.
Definition: draw.cpp:193
point resolution()
Definition: general.cpp:392
static map_location::DIRECTION n
Transitional API for porting SDL_ttf-based code to Pango.
const int max_window_height
Definition: general.cpp:73
bool auto_pixel_scale()
Definition: general.cpp:419
void clear_render_target()
Reset the render target to the main window / screen.
Definition: video.cpp:518
static void init_test()
Definition: video.cpp:160