1 /* 2 Copyright (C) 2003 - 2018 by David White <dave@whitevine.net> 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 #pragma once 16 17 #include "events.hpp" 18 #include "exceptions.hpp" 19 #include "lua_jailbreak_exception.hpp" 20 21 #include <memory> 22 23 class surface; 24 struct point; 25 26 namespace sdl 27 { 28 class window; 29 } 30 31 class CVideo 32 { 33 public: 34 CVideo(const CVideo&) = delete; 35 CVideo& operator=(const CVideo&) = delete; 36 37 enum FAKE_TYPES { NO_FAKE, FAKE, FAKE_TEST }; 38 39 CVideo(FAKE_TYPES type = NO_FAKE); 40 41 ~CVideo(); 42 get_singleton()43 static CVideo& get_singleton() 44 { 45 return *singleton_; 46 } 47 48 static std::string video_settings_report(); 49 50 /***** ***** ***** ***** Unit test-related functions ***** ***** ****** *****/ 51 52 void make_fake(); 53 54 /** 55 * Creates a fake frame buffer for the unit tests. 56 * 57 * @param width The width of the buffer. 58 * @param height The height of the buffer. 59 */ 60 void make_test_fake(const unsigned width = 1024, const unsigned height = 768); 61 faked() const62 bool faked() const 63 { 64 return fake_screen_; 65 } 66 67 bool non_interactive() const; 68 69 /***** ***** ***** ***** Window-related functions ***** ***** ****** *****/ 70 71 /** Initializes a new SDL window instance, taking into account any preiously saved states. */ 72 void init_window(); 73 74 /** Returns a pointer to the underlying SDL window. */ 75 sdl::window* get_window(); 76 77 private: 78 enum MODE_EVENT { TO_RES, TO_FULLSCREEN, TO_WINDOWED, TO_MAXIMIZED_WINDOW }; 79 80 /** 81 * Sets the window's mode - ie, changing it to fullscreen, maximizing, etc. 82 * 83 * @param mode The action to perform. 84 * @param size The new window size. Utilized if @a mode is TO_RES. 85 */ 86 void set_window_mode(const MODE_EVENT mode, const point& size); 87 88 public: 89 void set_fullscreen(bool ison); 90 91 void toggle_fullscreen(); 92 93 bool is_fullscreen() const; 94 95 bool set_resolution(const unsigned width, const unsigned height); 96 97 /** 98 * Set the window resolution. 99 * 100 * @param resolution The new width and height. 101 * 102 * @returns Whether the resolution was successfully changed. 103 */ 104 bool set_resolution(const point& resolution); 105 106 point current_resolution(); 107 108 /** Returns the list of available screen resolutions. */ 109 std::vector<point> get_available_resolutions(const bool include_current = false); 110 111 /** 112 * Returns the current window renderer area, either in pixels or screen coordinates. 113 * 114 * @param as_pixels Whether to return the area in pixels (default true) or 115 * DPI-independent (DIP) screen coordinates. 116 */ 117 SDL_Rect screen_area(bool as_pixels = true) const; 118 119 /** Returns the window renderer width in pixels or screen coordinates. */ 120 int get_width(bool as_pixels = true) const; 121 122 /** Returns the window renderer height in pixels or in screen coordinates. */ 123 int get_height(bool as_pixels = true) const; 124 125 /** The current scale factor on High-DPI screens. */ 126 std::pair<float, float> get_dpi_scale_factor() const; 127 128 /** 129 * Tests whether the given flags are currently set on the SDL window. 130 * 131 * @param flags The flags to test, OR'd together. 132 */ 133 bool window_has_flags(uint32_t flags) const; 134 135 /** 136 * Sets the title of the main window. 137 * 138 * @param title The new title for the window. 139 */ 140 void set_window_title(const std::string& title); 141 142 /** 143 * Sets the icon of the main window. 144 * 145 * @param icon The new icon for the window. 146 */ 147 void set_window_icon(surface& icon); 148 current_refresh_rate() const149 int current_refresh_rate() const 150 { 151 return refresh_rate_; 152 } 153 154 /***** ***** ***** ***** Drawing functions ***** ***** ****** *****/ 155 156 /** 157 * Draws a surface directly onto the screen framebuffer. 158 * 159 * @param x The x coordinate at which to draw. 160 * @param y The y coordinate at which to draw. 161 * @param surf The surface to draw. 162 * @param srcrect The area of the surface to draw. This defaults to nullptr, 163 * which implies the entire thing. 164 * @param clip_rect The clippin rect. If not null, the surface will only be drawn 165 * within the bounds of the given rectangle. 166 */ 167 void blit_surface(int x, int y, surface surf, SDL_Rect* srcrect = nullptr, SDL_Rect* clip_rect = nullptr); 168 169 /** Renders the screen. Should normally not be called directly! */ 170 void flip(); 171 172 /** 173 * Updates and ensures the framebuffer surface is valid. 174 * This needs to be invoked immediately after a resize event or the game will crash. 175 */ 176 void update_framebuffer(); 177 178 /** Clear the screen contents */ 179 void clear_screen(); 180 181 /** Returns a reference to the framebuffer. */ 182 surface& getSurface(); 183 184 /** 185 * Stop the screen being redrawn. Anything that happens while the updates are locked will 186 * be hidden from the user's view. 187 * 188 * Note that this function is re-entrant, meaning that if lock_updates(true) is called twice, 189 * lock_updates(false) must be called twice to unlock updates. 190 */ 191 void lock_updates(bool value); 192 193 /** Whether the screen has been 'locked' or not. */ 194 bool update_locked() const; 195 196 void lock_flips(bool); 197 198 /***** ***** ***** ***** Help string functions ***** ***** ****** *****/ 199 200 /** 201 * Displays a help string with the given text. A 'help string' is like a tooltip, 202 * but appears at the bottom of the screen so as to not be intrusive. 203 * 204 * @param str The text to display. 205 * 206 * @returns The handle id of the new help string. 207 */ 208 int set_help_string(const std::string& str); 209 210 /** Removes the help string with the given handle. */ 211 void clear_help_string(int handle); 212 213 /** Removes all help strings. */ 214 void clear_all_help_strings(); 215 216 /***** ***** ***** ***** General utils ***** ***** ****** *****/ 217 218 /** Waits a given number of milliseconds before returning. */ 219 static void delay(unsigned int milliseconds); 220 221 struct error : public game::error 222 { errorCVideo::error223 error() 224 : game::error("Video initialization failed") 225 { 226 } 227 }; 228 229 /** Type that can be thrown as an exception to quit to desktop. */ 230 class quit : public lua_jailbreak_exception 231 { 232 public: quit()233 quit() 234 : lua_jailbreak_exception() 235 { 236 } 237 238 private: 239 IMPLEMENT_LUA_JAILBREAK_EXCEPTION(quit) 240 }; 241 242 private: 243 static CVideo* singleton_; 244 245 /** The SDL window object. */ 246 std::unique_ptr<sdl::window> window; 247 248 /** Initializes the SDL video subsystem. */ 249 void initSDL(); 250 251 // if there is no display at all, but we 'fake' it for clients 252 bool fake_screen_; 253 254 /** Helper class to manage SDL events. */ 255 class video_event_handler : public events::sdl_handler 256 { 257 public: handle_event(const SDL_Event &)258 virtual void handle_event(const SDL_Event&) 259 { 260 } 261 262 virtual void handle_window_event(const SDL_Event& event); 263 video_event_handler()264 video_event_handler() 265 : sdl_handler(false) 266 { 267 } 268 }; 269 270 video_event_handler event_handler_; 271 272 /** Curent ID of the help string. */ 273 int help_string_; 274 275 int updated_locked_; 276 int flip_locked_; 277 int refresh_rate_; 278 }; 279 280 /** An object which will lock the display for the duration of its lifetime. */ 281 struct update_locker 282 { update_lockerupdate_locker283 update_locker(CVideo& v, bool lock = true) 284 : video(v) 285 , unlock(lock) 286 { 287 if(lock) { 288 video.lock_updates(true); 289 } 290 } 291 ~update_lockerupdate_locker292 ~update_locker() 293 { 294 unlock_update(); 295 } 296 unlock_updateupdate_locker297 void unlock_update() 298 { 299 if(unlock) { 300 video.lock_updates(false); 301 unlock = false; 302 } 303 } 304 305 private: 306 CVideo& video; 307 bool unlock; 308 }; 309 310 class flip_locker 311 { 312 public: flip_locker(CVideo & video)313 flip_locker(CVideo& video) 314 : video_(video) 315 { 316 video_.lock_flips(true); 317 } 318 ~flip_locker()319 ~flip_locker() 320 { 321 video_.lock_flips(false); 322 } 323 324 private: 325 CVideo& video_; 326 }; 327 328 namespace video2 329 { 330 class draw_layering : public events::sdl_handler 331 { 332 protected: 333 draw_layering(const bool auto_join = true); 334 virtual ~draw_layering(); 335 }; 336 337 void trigger_full_redraw(); 338 } 339