ASW Lib
A.D.S. Games SDL Wrapper Library. A library targeted at Allegro4 users who want to switch to SDL3 and use modern c++.
Loading...
Searching...
No Matches
display.cpp
Go to the documentation of this file.
2
3#include <SDL3/SDL.h>
4#include <SDL3_image/SDL_image.h>
5#include <algorithm>
6#include <optional>
7#include <string>
8
10#include "./asw/modules/draw.h"
11#include "./asw/modules/log.h"
12#include "./asw/modules/types.h"
13#include "./asw/modules/util.h"
14
15namespace {
18SDL_GLContext gl_context = nullptr;
19
20// Logical size of the screen. Kept here because SDL reports the logical
21// presentation of the current render target, which is 0 for textures.
23
24// Settings from the config. They win over what the game asks for
25std::optional<bool> fullscreen_override;
26std::optional<bool> vsync_override;
27std::optional<int> scale_override;
28
29constexpr int MAX_SCALE = 16;
30
32{
33 fullscreen_override = asw::config::get_bool("display.fullscreen");
34 vsync_override = asw::config::get_bool("display.vsync");
35 scale_override = asw::config::get_int("display.scale");
36
39 "Ignoring config display.scale = {}, use 1 to {}", *scale_override, MAX_SCALE);
40 scale_override.reset();
41 }
42}
43
44// Window flags and scale, with the overrides applied
45SDL_WindowFlags apply_overrides(SDL_WindowFlags flags, int& scale)
46{
47 if (scale_override) {
48 scale = *scale_override;
49 }
50
51 if (fullscreen_override.value_or(false)) {
52 flags |= SDL_WINDOW_FULLSCREEN;
53 }
54
55 return flags;
56}
57} // namespace
58
59void asw::display::_init(int width, int height, int scale)
60{
62
63 // High pixel density gives the canvas one pixel per device pixel in the
64 // browser. Without it the scene is drawn at CSS size and the browser
65 // stretches it, which blurs it on high density screens
66 SDL_WindowFlags flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY;
67
68#ifdef __EMSCRIPTEN__
69 // The WebGL renderer recreates a window that is not OpenGL. That resets
70 // the canvas CSS size, so the page's CSS no longer sizes the canvas
71 flags |= SDL_WINDOW_OPENGL;
72#endif
73
74 flags = apply_overrides(flags, scale);
75 window = SDL_CreateWindow("", width * scale, height * scale, flags);
76 if (window == nullptr) {
78 }
79
80 SDL_SetHint(SDL_HINT_RENDER_VSYNC, vsync_override.value_or(true) ? "1" : "0");
81
82 renderer = SDL_CreateRenderer(window, nullptr);
83
84 // SDL defaults to no blending, which makes see through primitives opaque
85 SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
86
87 SDL_SetRenderLogicalPresentation(renderer, width, height, SDL_LOGICAL_PRESENTATION_LETTERBOX);
88 logical_size = asw::Vec2<int>(width, height);
89}
90
91void asw::display::_init_opengl(int width, int height, int scale)
92{
94
95 const SDL_WindowFlags flags = apply_overrides(
96 SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY, scale);
97 window = SDL_CreateWindow("", width * scale, height * scale, flags);
98 if (window == nullptr) {
100 }
101
102 gl_context = SDL_GL_CreateContext(window);
103 if (gl_context == nullptr) {
104 asw::util::abort_on_error("SDL_GL_CreateContext");
105 }
106
107 if (!SDL_GL_MakeCurrent(window, gl_context)) {
108 asw::util::abort_on_error("SDL_GL_MakeCurrent");
109 }
110
111 if (vsync_override) {
112 SDL_GL_SetSwapInterval(*vsync_override ? 1 : 0);
113 }
114}
115
117{
118 // Release cached text textures while their renderer is still alive.
120
121 auto* r = renderer;
122 renderer = nullptr;
123 if (r != nullptr) {
124 SDL_DestroyRenderer(r);
125 }
126
127 if (gl_context != nullptr) {
128 SDL_GL_DestroyContext(gl_context);
129 gl_context = nullptr;
130 }
131
132 auto* w = window;
133 window = nullptr;
134 if (w != nullptr) {
135 SDL_DestroyWindow(w);
136 }
137}
138
143
148
149void asw::display::set_title(const std::string& title)
150{
151 SDL_SetWindowTitle(window, title.c_str());
152}
153
154void asw::display::set_icon(const std::string& path)
155{
156 SDL_Surface* icon = IMG_Load(path.c_str());
157
158 if (icon == nullptr) {
159 return;
160 }
161
162 SDL_SetWindowIcon(window, icon);
163 SDL_DestroySurface(icon);
164}
165
166void asw::display::set_fullscreen(bool fullscreen)
167{
168 SDL_SetWindowFullscreen(window, fullscreen_override.value_or(fullscreen));
169 SDL_SyncWindow(window);
170}
171
173{
174 if (window == nullptr) {
175 return false;
176 }
177
178 return (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) != 0;
179}
180
182{
183 SDL_SetWindowSize(window, w, h);
184}
185
186void asw::display::set_resizable(bool resizable)
187{
188 SDL_SetWindowResizable(window, resizable);
189}
190
192{
193 asw::Vec2<int> size;
194 SDL_GetWindowSize(window, &size.x, &size.y);
195 return size;
196}
197
199{
200 if (renderer == nullptr) {
201 return { };
202 }
203
204 return logical_size;
205}
206
208{
209 asw::Vec2<float> scale(1.0F, 1.0F);
210
211 if (renderer == nullptr || logical_size.x <= 0 || logical_size.y <= 0) {
212 return scale;
213 }
214
215 // Letterboxing keeps the aspect ratio, so both axes use the same scale
216 int out_w = 0;
217 int out_h = 0;
218 SDL_GetRenderOutputSize(renderer, &out_w, &out_h);
219 const float s = std::min(static_cast<float>(out_w) / static_cast<float>(logical_size.x),
220 static_cast<float>(out_h) / static_cast<float>(logical_size.y));
221 return { s, s };
222}
223
225{
226 if (renderer == nullptr) {
227 return;
228 }
229
230 SDL_SetRenderTarget(renderer, texture.get());
231}
232
234{
235 if (renderer == nullptr) {
236 return;
237 }
238
239 SDL_SetRenderTarget(renderer, nullptr);
240}
241
243{
244 if (renderer == nullptr) {
245 return;
246 }
247
248 // Draw calls leave their colour set, so pick one rather than clearing to
249 // whatever was drawn last
250 SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
251 SDL_RenderClear(renderer);
252}
253
255{
256 if (renderer == nullptr) {
257 return;
258 }
259
260 SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
261 SDL_RenderClear(renderer);
262}
263
265{
266 if (renderer == nullptr) {
267 return;
268 }
269
270 SDL_RenderPresent(renderer);
271}
272
274{
275 SDL_SetRenderDrawBlendMode(renderer, static_cast<SDL_BlendMode>(mode));
276}
277
278void asw::display::warp_mouse(float x, float y)
279{
280 SDL_WarpMouseInWindow(window, x, y);
281}
282
284{
285 SDL_GL_SwapWindow(window);
286}
287
288bool asw::display::screenshot(const std::string& path)
289{
290 if (renderer == nullptr) {
291 return false;
292 }
293
294 SDL_Surface* surface = SDL_RenderReadPixels(renderer, nullptr);
295 if (surface == nullptr) {
296 return false;
297 }
298
299 const bool saved = IMG_SavePNG(surface, path.c_str());
300 SDL_DestroySurface(surface);
301 return saved;
302}
A 2D vector in space.
Definition geometry.h:27
T y
The y component of the vector.
Definition geometry.h:280
T x
The x component of the vector.
Definition geometry.h:277
Settings from a config file, set by whoever runs the game.
Display and window routines for the ASW library.
Routines for drawing sprites and primitives to the screen.
Structured logging system.
std::optional< bool > vsync_override
Definition display.cpp:26
SDL_WindowFlags apply_overrides(SDL_WindowFlags flags, int &scale)
Definition display.cpp:45
std::optional< int > scale_override
Definition display.cpp:27
std::optional< bool > fullscreen_override
Definition display.cpp:25
asw::Vec2< int > logical_size
Definition display.cpp:22
std::optional< int > get_int(const std::string &key)
Get a setting as a whole number.
Definition config.cpp:127
std::optional< bool > get_bool(const std::string &key)
Get a setting as true or false. 1, true, yes and on are true. 0, false, no and off are false....
Definition config.cpp:108
void set_icon(const std::string &path)
Set the icon to display on the window. If it does not exist, this will silently fail.
Definition display.cpp:154
bool screenshot(const std::string &path)
Save what has been drawn this frame to a PNG file. Call after drawing and before the frame is present...
Definition display.cpp:288
asw::Vec2< float > get_scale()
Get how many output pixels one logical pixel covers, after letterboxing. 2.0 means the game is drawn ...
Definition display.cpp:207
void set_fullscreen(bool fullscreen)
Set the window to fullscreen or windowed.
Definition display.cpp:166
asw::Vec2< int > get_logical_size()
Get the logical size of the window. This may differ from the actual size if scaling is enabled.
Definition display.cpp:198
void _init_opengl(int width, int height, int scale)
Initialize the display module with OpenGL support. Called by asw::core::init().
Definition display.cpp:91
void set_blend_mode(asw::BlendMode mode)
Set the blend mode used to draw primitives such as rectangles, lines and circles. Defaults to Blend,...
Definition display.cpp:273
bool is_fullscreen()
Check if the window is fullscreen.
Definition display.cpp:172
void reset_render_target()
Reset the render target to the default.
Definition display.cpp:233
asw::Vec2< int > get_size()
Get the size of the window.
Definition display.cpp:191
void swap_window()
Swap window (gl)
Definition display.cpp:283
void present()
Present the window.
Definition display.cpp:264
void set_render_target(const asw::Texture &texture)
Set the render target to the window.
Definition display.cpp:224
void clear()
Clear the window to black.
Definition display.cpp:242
void _shutdown()
Shut down the display module. Called by asw::core::shutdown(). Nulls the renderer and window pointers...
Definition display.cpp:116
void warp_mouse(float x, float y)
Warp mouse in window.
Definition display.cpp:278
asw::Renderer * get_renderer()
Get the SDL renderer.
Definition display.cpp:139
asw::Window * get_window()
Get the SDL window.
Definition display.cpp:144
void _init(int width, int height, int scale)
Initialize the display module. Called by asw::core::init().
Definition display.cpp:59
void set_title(const std::string &title)
Set the title of the window.
Definition display.cpp:149
void set_resolution(int w, int h)
Set the resolution of the window.
Definition display.cpp:181
void set_resizable(bool resizable)
Set resizable flag of the window.
Definition display.cpp:186
void clear_text_cache()
Clear cached rendered text textures.
Definition draw.cpp:475
void warn(const std::string &message)
Log a warning message.
Definition log.cpp:191
void abort_on_error(const std::string &message)
Abort program and display error message.
Definition util.cpp:67
std::shared_ptr< SDL_Texture > Texture
Alias for a shared pointer to an SDL_Texture.
Definition types.h:76
BlendMode
Mappings from SDL_BLENDMODE to ASW BlendMode.
Definition types.h:26
SDL_Window Window
Alias for a shared pointer to an SDL_Window.
Definition types.h:91
SDL_Renderer Renderer
Alias for a shared pointer to an SDL_Renderer.
Definition types.h:88
RGBA color struct with 8-bit channels.
Definition color.h:18
uint8_t b
Definition color.h:32
uint8_t r
Definition color.h:30
uint8_t g
Definition color.h:31
uint8_t a
Definition color.h:33
Types used throughout the ASW library.
General utility functions.