The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
video.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2003 - 2025
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 "draw_manager.hpp"
19#include "font/text.hpp"
20#include "log.hpp"
21#include "picture.hpp"
23#include "sdl/point.hpp"
24#include "sdl/texture.hpp"
25#include "sdl/utils.hpp"
26#include "sdl/window.hpp"
27#include "utils/general.hpp"
28
29#ifdef __APPLE__
30#include <TargetConditionals.h>
32#if TARGET_OS_OSX
33#include "game_version.hpp"
34#endif
35#endif
36
37#include <SDL3/SDL_init.h>
38#include <SDL3/SDL_render.h> // SDL_Texture
39
40#include <cassert>
41#include <vector>
42
43#ifdef __ANDROID__
44extern "C" {
45 SDL_Surface* Android_AP_getFrameBuffer();
46}
47#endif
48
49static lg::log_domain log_display("display");
50#define LOG_DP LOG_STREAM(info, log_display)
51#define ERR_DP LOG_STREAM(err, log_display)
52#define WRN_DP LOG_STREAM(warn, log_display)
53#define DBG_DP LOG_STREAM(debug, log_display)
54
55namespace
56{
57/** The SDL window object. Will be null only if headless_. */
58std::unique_ptr<sdl::window> window;
59
60/** The main offscreen render target. */
61texture render_texture_ = {};
62
63/** The current offscreen render target. */
64texture current_render_target_ = {};
65
66bool headless_ = false; /**< running with no window at all */
67bool testing_ = false; /**< running unit tests */
68point test_resolution_ = {1024, 768}; /**< resolution for unit tests */
69int refresh_rate_ = 0;
70point game_canvas_size_ = {0, 0};
71int pixel_scale_ = 1;
72int max_scale_ = 1;
73rect input_area_ = {};
74
75} // anon namespace
76
77namespace video
78{
79
80// Non-public interface
81void render_screen(); // exposed and used only in draw_manager.cpp
82
83// Internal functions
84static void init_window(bool hidden=false);
85static void init_test_window();
86static void init_fake();
87static void init_test();
88static bool update_framebuffer();
89static bool update_test_framebuffer();
90static point draw_offset();
91
92
93void init(fake type)
94{
95 LOG_DP << "initializing video";
96 if(SDL_WasInit(SDL_INIT_VIDEO)) {
97 throw error("video subsystem already initialized");
98 }
99 if(!SDL_InitSubSystem(SDL_INIT_VIDEO)) {
100 ERR_DP << "Could not initialize SDL_video: " << SDL_GetError();
101 throw error("Video initialization failed");
102 }
103
104 switch(type) {
105 case fake::none:
106 init_window();
107 break;
108 case fake::no_window:
109 init_fake();
110 break;
111 case fake::no_draw:
112 init_test();
113 break;
115 init_window(true);
116 break;
117 default:
118 throw error("unrecognized fake type passed to video::init");
119 }
120}
121
122void deinit()
123{
124 LOG_DP << "deinitializing video";
125
126 // Clear any static texture caches,
127 // lest they try to delete textures after SDL_Quit.
129 render_texture_.reset();
130 current_render_target_.reset();
131
132 // Destroy the window, and thus also the renderer.
133 window.reset();
134
135 // Close the video subsystem.
136 if(SDL_WasInit(SDL_INIT_VIDEO)) {
137 LOG_DP << "quitting SDL video subsystem";
138 SDL_QuitSubSystem(SDL_INIT_VIDEO);
139 }
140 if(SDL_WasInit(SDL_INIT_VIDEO)) {
141 // This should not have been initialized multiple times
142 throw error("video subsystem still initialized after deinit");
143 }
144}
145
147{
148 return headless_;
149}
150
152{
153 return testing_;
154}
155
157{
158 LOG_DP << "running headless";
159 headless_ = true;
160 refresh_rate_ = 1;
161 game_canvas_size_ = {800,600};
162}
163
165{
166 testing_ = true;
167 refresh_rate_ = 1;
169}
170
171/** Returns true if the buffer was changed */
173{
174 if (!window) {
175 throw("trying to update test framebuffer with no window");
176 }
177
178 bool changed = false;
179
180 // TODO: code unduplication
181 // Build or update the current render texture.
182 if (render_texture_) {
183 SDL_PropertiesID props = SDL_GetTextureProperties(render_texture_.get());
184 int w = SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_WIDTH_NUMBER, 0);
185 int h = SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_HEIGHT_NUMBER, 0);
186 if (w != test_resolution_.x || h != test_resolution_.y) {
187 // Delete it and let it be recreated.
188 LOG_DP << "destroying old render texture";
189 render_texture_.reset();
190 }
191 }
192 if (!render_texture_) {
193 LOG_DP << "creating offscreen render texture";
194 render_texture_.assign(SDL_CreateTexture(
195 *window,
196 SDL_PIXELFORMAT_ARGB8888,
197 SDL_TEXTUREACCESS_TARGET,
198 test_resolution_.x, test_resolution_.y
199 ));
200 LOG_DP << "updated render target to " << test_resolution_.x
201 << "x" << test_resolution_.y;
202 changed = true;
203 }
204
205 pixel_scale_ = 1;
206 game_canvas_size_ = test_resolution_;
207 input_area_ = {{}, test_resolution_};
208
209 // The render texture is always the render target in this case.
210 force_render_target(render_texture_);
211
212 return changed;
213}
214
216{
217 if (!window) {
218 throw error("trying to update framebuffer with no window");
219 }
220
221 if (testing_) {
223 }
224
225 bool changed = false;
226
227 // Make sure we're getting values from the native window.
228 SDL_SetRenderTarget(*window, nullptr);
229
230 // Find max valid pixel scale at current output size.
231 point osize(window->get_output_size());
232 max_scale_ = std::min(
235 max_scale_ = std::clamp(max_scale_, 1, pref_constants::max_pixel_scale);
236
237 // Determine best pixel scale according to preference and window size
238 int scale = 1;
239 if (prefs::get().auto_pixel_scale()) {
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 / (pref_constants::max_window_width+1) + 1,
248 osize.y / (pref_constants::max_window_height+1) + 1);
249 scale = std::max(scale, min_scale);
250 } else {
251 scale = std::min(max_scale_, prefs::get().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) {
263 if (!prefs::get().auto_pixel_scale() && scale < prefs::get().pixel_scale()) {
264 LOG_DP << "reducing pixel scale from desired "
265 << prefs::get().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_GetRenderScale(*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 SDL_PropertiesID props = SDL_GetTextureProperties(render_texture_.get());
290 int w = SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_WIDTH_NUMBER, 0);
291 int h = SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_HEIGHT_NUMBER, 0);
292 if (w != osize.x || h != osize.y) {
293 // Delete it and let it be recreated.
294 LOG_DP << "destroying old render texture";
295 render_texture_.reset();
296 } else {
297 // This isn't currently used, but ensure it's accurate anyway.
298 render_texture_.set_draw_size(lsize);
299 }
300 }
301 if (!render_texture_) {
302 LOG_DP << "creating offscreen render texture";
303 render_texture_.assign(SDL_CreateTexture(
304 *window,
305 SDL_PIXELFORMAT_ARGB8888,
306 SDL_TEXTUREACCESS_TARGET,
307 osize.x, osize.y
308 ));
309 // This isn't really necessary, but might be nice to have attached
310 render_texture_.set_draw_size(lsize);
311 changed = true;
312 }
313
314 // Assign the render texture now. It will be used for all drawing.
315 force_render_target(render_texture_);
316
317 // By default input area is the same as the window area.
318 input_area_ = {{}, wsize};
319
320 rect active_area = to_output(draw_area());
321 if (active_area.size() != osize) {
322 LOG_DP << "render target offset: LT " << active_area.origin() << " RB "
323 << osize - active_area.size() - active_area.origin();
324 // Translate active_area into display coordinates as input_area_
325 input_area_ = {
326 (active_area.origin() * wsize) / osize,
327 (active_area.size() * wsize) / osize
328 };
329 LOG_DP << "input area: " << input_area_;
330 }
331
332 return changed;
333}
334
336{
337 LOG_DP << "creating test window " << test_resolution_.x
338 << "x" << test_resolution_.y;
339
340 uint32_t window_flags = 0;
341 window_flags |= SDL_WINDOW_HIDDEN;
342 // The actual window won't be used, as we'll be rendering to texture.
343
344 window.reset(new sdl::window(
345 "", test_resolution_.x, test_resolution_.y,
346 window_flags
347 ));
348
350}
351
352void init_window(bool hidden)
353{
354#ifdef __ANDROID__
355 prefs::get().set_fullscreen(true);
356#endif
357#if defined(__APPLE__) && TARGET_OS_IPHONE
359#endif
360 // Dimensions
361 const point res = prefs::get().resolution();
362 const int w = res.x;
363 const int h = res.y;
364
365 uint32_t window_flags = 0;
366
367 // Add any more default flags here
368 window_flags |= SDL_WINDOW_RESIZABLE;
369 window_flags |= SDL_WINDOW_HIGH_PIXEL_DENSITY;
370
371 if(prefs::get().fullscreen()) {
372 window_flags |= SDL_WINDOW_FULLSCREEN;
373 }
374
375 if(prefs::get().maximized()) {
376 window_flags |= SDL_WINDOW_MAXIMIZED;
377 }
378
379 if(hidden) {
380 LOG_DP << "hiding main window";
381 window_flags |= SDL_WINDOW_HIDDEN;
382 }
383
384 // Initialize window
385 window.reset(new sdl::window("", w, h, window_flags));
386
387 // It is assumed that this function is only ever called once.
388 // If that is no longer true, then you should clean things up.
389 assert(!render_texture_);
390
391 PLAIN_LOG << "Setting mode to " << w << "x" << h;
392
394
395 const SDL_DisplayMode* currentDisplayMode = SDL_GetCurrentDisplayMode(window->get_display_index());
396 refresh_rate_ = currentDisplayMode->refresh_rate != 0 ? currentDisplayMode->refresh_rate : 60;
397
398#ifdef __ANDROID__
399 window->set_size(w, h);
400#endif
401
403}
404
406{
407 return bool(window);
408}
409
411{
412 if (testing_) {
413 return test_resolution_;
414 }
415 // As we are rendering via an abstraction, we should never need this.
416 return window->get_output_size();
417}
418
420{
421 if (testing_) {
422 return test_resolution_;
423 }
424 return window->get_size();
425}
426
428{
429 return {point{}, game_canvas_size_};
430}
431
433{
434 return game_canvas_size_;
435}
436
438{
439 return current_render_target_.draw_size();
440}
441
443{
444 return {point{}, draw_size()};
445}
446
448{
449 // As we are using SDL_RenderSetIntegerScale, there may be a slight
450 // offset of the drawable area on the render target if the target size
451 // is not perfectly divisble by the scale.
452 // SDL doesn't provide any way of retrieving this offset,
453 // so we just have to base our calculation on the known behaviour.
454 point osize = output_size();
455 point dsize = draw_size();
456 point scale = osize / dsize;
457 return (osize - (scale * dsize)) / 2;
458}
459
461{
462 return {point{}, output_size()};
463}
464
466{
467 // Multiply r by integer scale, adding draw_offset to the position.
468 point dsize = current_render_target_.draw_size();
469 point osize = current_render_target_.get_raw_size();
470 point pos = (r.origin() * (osize / dsize)) + draw_offset();
471 point size = r.size() * (osize / dsize);
472 return {pos, size};
473}
474
476{
477 return input_area_;
478}
479
481{
482 return pixel_scale_;
483}
484
486{
487 return max_scale_;
488}
489
491{
492 return refresh_rate_;
493}
494
496{
497 // TODO: this should be more clever, depending on usage
498 if(auto preferred = prefs::get().refresh_rate(); preferred > 0) {
499 return std::min(preferred, refresh_rate_);
500 } else {
501 return refresh_rate_;
502 }
503}
504
506{
507 SDL_DisplayID id = SDL_GetDisplayForWindow(*window);
508 if(id != 0) {
509 return SDL_GetDisplayContentScale(id);
510 }
511 return 0.0f;
512}
514{
515 return SDL_GetWindowPixelDensity(*window);
516}
518{
519 return SDL_GetWindowDisplayScale(*window);
520}
521
523{
524 if (!SDL_SetRenderTarget(get_renderer(), t)) {
525 ERR_DP << "failed to set render target to "
526 << static_cast<void*>(t.get()) << ' '
527 << t.draw_size() << " / " << t.get_raw_size();
528 ERR_DP << "last SDL error: " << SDL_GetError();
529 throw error("failed to set render target");
530 }
531 current_render_target_ = t;
532
533 if (testing_) {
534 return;
535 }
536
537 // The scale factor gets reset when the render target changes,
538 // so make sure it gets set back appropriately.
539 if (!t) {
540 DBG_DP << "rendering to window / screen";
541 window->set_logical_size(game_canvas_size_);
542 } else if (t == render_texture_) {
543 DBG_DP << "rendering to primary buffer";
544 window->set_logical_size(game_canvas_size_);
545 } else {
546 DBG_DP << "rendering to custom target "
547 << static_cast<void*>(t.get()) << ' '
548 << t.draw_size() << " / " << t.get_raw_size();
549 window->set_logical_size(t.w(), t.h());
550 }
551}
552
554{
556}
557
559{
560 force_render_target(render_texture_);
561}
562
564{
565#ifndef __ANDROID__
566 // This should always be up-to-date, but assert for sanity.
567 assert(current_render_target_ == SDL_GetRenderTarget(get_renderer()));
568#endif
569 return current_render_target_;
570}
571
572// Note: this is not thread-safe.
573// Drawing functions should not be called while this is active.
574// SDL renderer usage is not thread-safe anyway, so this is fine.
576{
577 if(headless_ || testing_) {
578 // No need to present anything in this case
579 return;
580 }
581
582 if(!window) {
583 WRN_DP << "trying to render with no window";
584 return;
585 }
586
587 // This should only ever be called when the main render texture is the
588 // current render target. It could be adapted otherwise... but let's not.
589 if(SDL_GetRenderTarget(*window) != render_texture_) {
590 ERR_DP << "trying to render screen, but current render texture is "
591 << static_cast<void*>(SDL_GetRenderTarget(*window))
592 << " | " << static_cast<void*>(current_render_target_.get())
593 << ". It should be " << static_cast<void*>(render_texture_.get());
594 throw error("tried to render screen from wrong render target");
595 }
596
597 // Clear the render target so we're drawing to the window.
599
600 // force_render_target() only changes the render target, not the
601 // viewport, and this call bypasses draw::render_target_setter (which
602 // is the only place that saves/restores the viewport). So whatever
603 // viewport a nested widget draw last left active could still be
604 // narrower than the full window here. Reset it, since clearing and
605 // presenting the whole frame should never be constrained to a
606 // leftover partial viewport.
607 SDL_SetRenderViewport(*window, nullptr);
608
609 // Use fully transparent black to clear the window backbuffer
610 SDL_SetRenderDrawColor(*window, 0u, 0u, 0u, 0u);
611
612 // Clear the window backbuffer before rendering the render texture.
613 SDL_RenderClear(*window);
614
615 // Copy the render texture to the window.
616 SDL_RenderTexture(*window, render_texture_, nullptr, nullptr);
617
618 // Finalize and display the frame.
619 SDL_RenderPresent(*window);
620
621 // Reset the render target to the render texture.
623}
624
626{
627 if (!window) {
628 WRN_DP << "trying to read pixels with no window";
629 return surface();
630 }
631
632 // This should be what we want to read from.
633 texture& target = current_render_target_;
634
635 // Make doubly sure.
636 if (target != SDL_GetRenderTarget(*window)) {
637 SDL_Texture* t = SDL_GetRenderTarget(*window);
638 ERR_DP << "render target " << static_cast<void*>(target.get())
639 << ' ' << target.draw_size() << " / " << target.get_raw_size()
640 << " doesn't match window render target "
641 << static_cast<void*>(t);
642 throw error("unexpected render target while reading pixels");
643 }
644
645 // Intersect the draw area with the given rect.
646 rect r_clipped = draw_area();
647 if (r) {
648 r_clipped.clip(*r);
649 if (r_clipped != *r) {
650 DBG_DP << "modifying pixel read area from " << *r
651 << " to " << r_clipped;
652 *r = r_clipped;
653 }
654 }
655
656 // Convert the rect to output coordinates, if necessary.
657 rect o = to_output(r_clipped);
658
659 // SDL_RenderReadPixels reads relative to the current viewport rather
660 // than the full render target. Callers may invoke read_pixels() while
661 // a narrower, widget-local viewport is still active (for example, the
662 // background-blur code reads pixels while its own widget's viewport
663 // is in effect), which would make the output-space rect computed
664 // above fall outside it. Reset to the full target for the read.
665 rect old_viewport;
666 SDL_GetRenderViewport(*window, &old_viewport);
667 SDL_SetRenderViewport(*window, nullptr);
668
669 // Create surface and read pixels
670 surface s = SDL_RenderReadPixels(*window, &o);
671
672 SDL_SetRenderViewport(*window, &old_viewport);
673
674 return s;
675}
676
678{
679 if(!window) {
680 WRN_DP << "trying to read pixels with no window";
681 return surface();
682 }
683 surface s = read_pixels(r);
684 if(r) {
685 return scale_surface(s, r->w, r->h);
686 } else {
687 return scale_surface(s, draw_size().x, draw_size().y);
688 }
689}
690
691void set_window_title(const std::string& title)
692{
693 assert(window);
694 window->set_title(title);
695}
696
698{
699 assert(window);
700 window->set_icon(icon);
701}
702
703SDL_Renderer* get_renderer()
704{
705 if(window) {
706 return *window;
707 } else {
708 return nullptr;
709 }
710}
711
712SDL_Window* get_window()
713{
714 if(window) {
715 return *window;
716 } else {
717 return nullptr;
718 }
719}
720
721std::string current_driver()
722{
723 const char* const drvname = SDL_GetCurrentVideoDriver();
724 return drvname ? drvname : "<not initialized>";
725}
726
727std::vector<std::string> enumerate_drivers()
728{
729 std::vector<std::string> res;
730 int num_drivers = SDL_GetNumVideoDrivers();
731
732 for(int n = 0; n < num_drivers; ++n) {
733 const char* drvname = SDL_GetVideoDriver(n);
734 res.emplace_back(drvname ? drvname : "<invalid driver>");
735 }
736
737 return res;
738}
739
740/**
741 * Tests whether the given flags are currently set on the SDL window.
742 *
743 * @param flags The flags to test, OR'd together.
744 */
745static bool window_has_flags(uint32_t flags)
746{
747 return window && (window->get_flags() & flags) != 0;
748}
749
751{
752 return !window_has_flags(SDL_WINDOW_HIDDEN);
753}
754
756{
757 return window_has_flags(SDL_WINDOW_MOUSE_FOCUS | SDL_WINDOW_INPUT_FOCUS);
758}
759
761{
762 return window_has_flags(SDL_WINDOW_MOUSE_FOCUS);
763}
764
765std::vector<point> get_available_resolutions(const bool include_current)
766{
767 std::vector<point> result;
768
769#ifdef __ANDROID__
770 result.push_back(prefs::get().resolution());
771 return result;
772#endif
773
774 if(!window) {
775 return result;
776 }
777
778 const int display_index = window->get_display_index();
779
780 int mode_count = 0;
781 SDL_DisplayMode** modes = SDL_GetFullscreenDisplayModes(display_index, &mode_count);
782 if(mode_count <= 0 || !modes) {
783 PLAIN_LOG << "No modes supported";
784 return result;
785 }
786
788
789 // The maximum size to which this window can be set. For some reason this won't
790 // pop up as a display mode of its own.
791 rect bounds;
792 SDL_GetDisplayBounds(display_index, &bounds);
793
794 for(SDL_DisplayMode* mode : utils::span(modes, mode_count)) {
795 assert(mode);
796 point size{mode->w, mode->h};
797
798 if(min_res <= size && size <= bounds.size()) {
799 result.push_back(size);
800 }
801 }
802
803 SDL_free(modes);
804
805 if(!utils::contains(result, min_res)) {
806 result.push_back(min_res);
807 }
808
809 if(include_current) {
810 result.push_back(current_resolution());
811 }
812
813 std::sort(result.begin(), result.end());
814 result.erase(std::unique(result.begin(), result.end()), result.end());
815
816 return result;
817}
818
820{
821 if (testing_) {
822 return test_resolution_;
823 }
824 return window->get_size();
825}
826
827void set_fullscreen(bool fullscreen)
828{
829 if (headless_ || testing_) {
830 return;
831 }
832
833 if (fullscreen) {
834 window->full_screen();
835 } else if (prefs::get().maximized()) {
836 window->to_window();
837 window->maximize();
838 } else {
839 window->to_window();
840 window->restore();
841 }
842
843 // Update the config value in any case.
844 prefs::get().set_fullscreen(fullscreen);
845}
846
848{
849 set_fullscreen(!prefs::get().fullscreen());
850}
851
852bool set_resolution(const point& resolution)
853{
854 if(resolution == current_resolution()) {
855 return false;
856 }
857
858 if(!window) {
859 throw error("tried to set resolution with no window");
860 }
861
862 if(testing_) {
863 LOG_DP << "resizing test resolution to " << resolution;
864 test_resolution_ = resolution;
866 }
867
868 window->restore();
869 window->set_size(resolution.x, resolution.y);
870 window->center();
871
873
874 // Change the saved values in preferences.
875 LOG_DP << "updating resolution to " << resolution;
876 prefs::get().set_resolution(resolution);
877 prefs::get().set_maximized(false);
878
879 return true;
880}
881
882void update_buffers(bool autoupdate)
883{
884 if(headless_) {
885 return;
886 }
887
888 LOG_DP << "updating video buffers";
889 if(update_framebuffer() && autoupdate) {
891 }
892}
893
894std::vector<std::string> get_available_renderers()
895{
896 std::vector<std::string> renderers;
897
898 int renderer_count = SDL_GetNumRenderDrivers();
899 for(int i = 0; i < renderer_count; i++) {
900 renderers.emplace_back(SDL_GetRenderDriver(i));
901 }
902
903 return renderers;
904}
905
906std::vector<std::pair<std::string, std::string>> renderer_report()
907{
908 std::vector<std::pair<std::string, std::string>> res;
909 SDL_Renderer* rnd = get_renderer();
910
911 if(rnd) {
912 std::string renderer_name = SDL_GetRendererName(rnd) ? SDL_GetRendererName(rnd) : "<unknown>";
913 SDL_PropertiesID props = SDL_GetRendererProperties(rnd);
914
915 res.emplace_back("Renderer", renderer_name);
916 res.emplace_back("VSync", SDL_GetNumberProperty(props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, 0) != 0 ? "on" : "off");
917 }
918
919 return res;
920}
921
922} // namespace video
#define LOG_DP
double t
static prefs & get()
int pixel_scale()
void set_resolution(const point &res)
point resolution()
The wrapper class for the SDL_Window class.
Definition window.hpp:48
Wrapper class to encapsulate creation and management of an SDL_Texture.
Definition texture.hpp:33
SDL_Texture * get() const
Definition texture.hpp:194
point draw_size() const
The size of the texture in draw-space.
Definition texture.hpp:120
point get_raw_size() const
The raw internal texture size.
Definition texture.cpp:109
#define ERR_DP
#define WRN_DP
Definition display.cpp:77
#define DBG_DP
Definition display.cpp:79
Interfaces for manipulating version numbers of engine, add-ons, etc.
Standard logging facilities (interface).
#define PLAIN_LOG
Definition log.hpp:296
void install_keyboard_dismiss_toolbar()
void invalidate_all()
Mark the entire screen as requiring redraw.
void flush_cache()
Purges all image caches.
Definition picture.cpp:210
const int min_window_height
const int max_pixel_scale
const int def_window_width
const int min_window_width
const int max_window_height
const int max_window_width
const int def_window_height
bool contains(const Container &container, const Value &value)
Returns true iff value is found in container.
Definition general.hpp:88
bool window_has_mouse_focus()
True iff the window has mouse focus.
Definition video.cpp:760
float pixel_density()
Definition video.cpp:513
bool headless()
The game is running headless.
Definition video.cpp:146
rect draw_area()
The current drawable area.
Definition video.cpp:442
rect output_area()
{0, 0, output_size().x, output_size().y}
Definition video.cpp:460
void set_window_title(const std::string &title)
Sets the title of the main window.
Definition video.cpp:691
static void init_fake()
Definition video.cpp:156
void clear_render_target()
Reset the render target to the main window / screen.
Definition video.cpp:553
rect to_output(const rect &r)
Convert coordinates in draw space to coordinates in render space.
Definition video.cpp:465
void render_screen()
Definition video.cpp:575
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:906
static bool window_has_flags(uint32_t flags)
Tests whether the given flags are currently set on the SDL window.
Definition video.cpp:745
static bool update_framebuffer()
Definition video.cpp:215
void reset_render_target()
Reset the render target to the primary render buffer.
Definition video.cpp:558
float content_scaling()
Definition video.cpp:505
point output_size()
Returns the size of the final render target.
Definition video.cpp:410
std::vector< point > get_available_resolutions(const bool include_current)
Returns the list of available screen resolutions.
Definition video.cpp:765
static bool update_test_framebuffer()
Returns true if the buffer was changed.
Definition video.cpp:172
void set_window_icon(surface &icon)
Sets the icon of the main window.
Definition video.cpp:697
int get_max_pixel_scale()
Definition video.cpp:485
bool window_is_visible()
True iff the window is not hidden.
Definition video.cpp:750
void force_render_target(const texture &t)
Set the render target, without any provided way of setting it back.
Definition video.cpp:522
point game_canvas_size()
The size of the game canvas, in drawing coordinates / game pixels.
Definition video.cpp:432
SDL_Window * get_window()
Definition video.cpp:712
bool window_has_focus()
True iff the window has mouse or input focus.
Definition video.cpp:755
point window_size()
Returns the size of the window in display units / screen coordinates.
Definition video.cpp:419
bool has_window()
Whether the game has set up a window to render into.
Definition video.cpp:405
bool testing()
The game is running unit tests.
Definition video.cpp:151
std::vector< std::string > enumerate_drivers()
A list of available video drivers.
Definition video.cpp:727
rect game_canvas()
The game canvas area, in drawing coordinates.
Definition video.cpp:427
static point draw_offset()
Definition video.cpp:447
int get_pixel_scale()
Get the current active pixel scale multiplier.
Definition video.cpp:480
static void init_window(bool hidden=false)
Definition video.cpp:352
std::vector< std::string > get_available_renderers()
Returns a list of all available renderers.
Definition video.cpp:894
point current_resolution()
The current window size in desktop coordinates.
Definition video.cpp:819
int native_refresh_rate()
The native refresh rate of display, not taking any user preferences into account.
Definition video.cpp:490
void init(fake type)
Initialize the video subsystem.
Definition video.cpp:93
void set_fullscreen(bool fullscreen)
Set the fullscreen state.
Definition video.cpp:827
void deinit()
Deinitialize the video subsystem.
Definition video.cpp:122
bool set_resolution(const point &resolution)
Set the window resolution.
Definition video.cpp:852
int current_refresh_rate()
The refresh rate of the screen.
Definition video.cpp:495
surface read_pixels_low_res(rect *r)
The same as read_pixels, but returns a low-resolution surface suitable for use with the old drawing s...
Definition video.cpp:677
std::string current_driver()
The current video driver in use, or else "<not initialized>".
Definition video.cpp:721
surface read_pixels(rect *r)
Copy back a portion of the render target that is already drawn.
Definition video.cpp:625
void toggle_fullscreen()
Toggle fullscreen mode.
Definition video.cpp:847
SDL_Renderer * get_renderer()
Definition video.cpp:703
void update_buffers(bool autoupdate)
Update buffers to match current resolution and pixel scale settings.
Definition video.cpp:882
texture get_render_target()
Get the current render target.
Definition video.cpp:563
static void init_test()
Definition video.cpp:164
fake
For describing the type of faked display, if any.
Definition video.hpp:44
static void init_test_window()
Definition video.cpp:335
point draw_size()
The size of the current render target in drawing coordinates.
Definition video.cpp:437
rect input_area()
Returns the input area of the window, in display coordinates.
Definition video.cpp:475
float display_scaling()
Definition video.cpp:517
int w
Definition pathfind.cpp:188
Contains a wrapper class for the SDL_Window class.
Holds a 2D point.
Definition point.hpp:25
An abstract description of a rectangle with integer coordinates.
Definition rect.hpp:49
void clip(const rect &r)
Clip this rectangle by the given rectangle.
Definition rect.cpp:101
constexpr point origin() const
Definition rect.hpp:66
constexpr point size() const
Definition rect.hpp:67
An error specifically indicating video subsystem problems.
Definition video.hpp:321
static map_location::direction n
static map_location::direction s
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:99
static lg::log_domain log_display("display")
#define i
#define h