Divide Framework 0.1
A free and open-source 3D Framework under heavy development
Loading...
Searching...
No Matches
DisplayWindow.cpp
Go to the documentation of this file.
1
2
4
11
12#include <SDL2/SDL_vulkan.h>
13
14namespace Divide {
15
18 , _windowID(U32_MAX)
19 , _clearColour(DefaultColours::BLACK)
20 , _parent(parent)
21{
22 _prevDimensions.set(1u, 1u);
23 _drawableSize.set(0u, 0u);
24}
25
27{
29
30 for ( U8 i = 0u; i < Config::MAX_FRAMES_IN_FLIGHT; ++i )
31 {
32 DIVIDE_ASSERT(_commandBufferQueues[i]._commandBuffers.empty());
33 }
34}
35
37{
38 if (_type != WindowType::COUNT && _sdlWindow != nullptr)
39 {
40 if (_destroyCbk) {
42 }
43
45 SDL_DestroyWindow(_sdlWindow);
46 _sdlWindow = nullptr;
47 }
48
49 return ErrorCode::NO_ERR;
50}
51
53 const WindowType initialType,
54 const WindowDescriptor& descriptor)
55{
56 _parentWindow = descriptor.parentWindow;
57
58 const bool vsync = descriptor.flags & to_base(WindowDescriptor::Flags::VSYNC);
59
60 if (vsync)
61 {
62 _flags |= to_base( WindowFlags::VSYNC );
63 }
64 else
65 {
66 _flags &= ~to_base( WindowFlags::VSYNC );
67 }
68
69 _previousType = _type = initialType;
70
71 vec2<I32> position(descriptor.position);
72
73 _initialDisplay = descriptor.targetDisplay;
74
75 if (position.x == -1)
76 {
77 position.x = SDL_WINDOWPOS_CENTERED_DISPLAY(descriptor.targetDisplay);
78 }
79 if (position.y == -1)
80 {
81 position.y = SDL_WINDOWPOS_CENTERED_DISPLAY(descriptor.targetDisplay);
82 }
83
84 _sdlWindow = SDL_CreateWindow( descriptor.title.c_str(),
85 position.x,
86 position.y,
87 descriptor.dimensions.width,
88 descriptor.dimensions.height,
89 windowFlags);
90 // Check if we have a valid window
91 if (_sdlWindow == nullptr)
92 {
93 Console::errorfn(LOCALE_STR("ERROR_GFX_DEVICE"),
94 Util::StringFormat(LOCALE_STR("ERROR_SDL_WINDOW"), SDL_GetError()).c_str());
95 Console::printfn(LOCALE_STR("WARN_APPLICATION_CLOSE"));
97 }
98
99 _windowID = SDL_GetWindowID(_sdlWindow);
100 _drawableSize = descriptor.dimensions;
101
102 return ErrorCode::NO_ERR;
103}
104
106 // Varies from OS to OS
107 WindowHandle handle = {};
109 return handle;
110}
111
113 switch (event) {
122 default:
123 break;
124 }
125
126 for (const auto& listener : _eventListeners[to_base(event)]) {
127 if (!listener(args)) {
128 return;
129 }
130 }
131}
132
133bool DisplayWindow::onSDLEvent(const SDL_Event event) {
134 if (event.type != SDL_WINDOWEVENT) {
135 return false;
136 }
137
138 if (_windowID != event.window.windowID) {
139 return false;
140 }
141
142 WindowEventArgs args = {};
143 args._windowGUID = getGUID();
144
146
147 if (fullscreen()) {
150 } else {
151 args.x = event.window.data1;
152 args.y = event.window.data2;
153 }
154
155 switch (event.window.event) {
156 case SDL_WINDOWEVENT_CLOSE: {
157 args.x = event.quit.type;
158 args.y = event.quit.timestamp;
160 return true;
161 };
162 case SDL_WINDOWEVENT_ENTER: {
163 _flags |= to_base( WindowFlags::IS_HOVERED );
165 return true;
166 };
167 case SDL_WINDOWEVENT_LEAVE: {
168 _flags &= to_base( WindowFlags::IS_HOVERED );
170 return true;
171 };
172 case SDL_WINDOWEVENT_FOCUS_GAINED: {
173 _flags |= to_base( WindowFlags::HAS_FOCUS );
175 return true;
176 };
177 case SDL_WINDOWEVENT_FOCUS_LOST: {
178 _flags &= to_base( WindowFlags::HAS_FOCUS );
180 return true;
181 };
182 case SDL_WINDOWEVENT_RESIZED: {
184 const U16 width = to_U16(event.window.data1);
185 const U16 height = to_U16(event.window.data2);
186 if (!setDimensions(width, height)) {
187 NOP();
188 }
189 }
190 args._flag = fullscreen();
192 _internalResizeEvent = false;
193
194 return true;
195 };
196 case SDL_WINDOWEVENT_SIZE_CHANGED: {
197 args._flag = fullscreen();
199
200 return true;
201 };
202 case SDL_WINDOWEVENT_MOVED: {
204 if (!_internalMoveEvent) {
205 setPosition(event.window.data1,
206 event.window.data2);
207 _internalMoveEvent = false;
208 }
209 return true;
210 };
211 case SDL_WINDOWEVENT_SHOWN: {
212 _flags &= to_base( WindowFlags::HIDDEN );
214
215 return true;
216 };
217 case SDL_WINDOWEVENT_HIDDEN: {
218 _flags |= to_base( WindowFlags::HIDDEN);
220
221 return true;
222 };
223 case SDL_WINDOWEVENT_MINIMIZED: {
225 minimized(true);
226 return true;
227 };
228 case SDL_WINDOWEVENT_MAXIMIZED: {
230 minimized(false);
231 return true;
232 };
233 case SDL_WINDOWEVENT_RESTORED: {
235 minimized(false);
236 return true;
237 };
238 default: break;
239 };
240
241 return false;
242}
243
245 const I32 displayIndex = SDL_GetWindowDisplayIndex(_sdlWindow);
246 assert(displayIndex != -1);
247 return displayIndex;
248}
249
251 I32 top = 0, left = 0, bottom = 0, right = 0;
252 if (SDL_GetWindowBordersSize(_sdlWindow, &top, &left, &bottom, &right) != -1) {
253 return { top, left, bottom, right };
254 }
255
256 return {};
257}
258
260{
261 return _drawableSize;
262}
263
265{
267 {
269 }
270 else
271 {
272 switch ( _context.gfx().renderAPI() )
273 {
274 default: DIVIDE_UNEXPECTED_CALL(); break;
275 case RenderAPI::None:
276 {
277 _drawableSize = { 1u, 1u };
278 } break;
280 {
281 int w = 1, h = 1;
282 SDL_Vulkan_GetDrawableSize( _sdlWindow, &w, &h );
283 if ( w > 0 && h > 0 )
284 {
285 _drawableSize.set( w, h );
286 }
287 } break;
289 {
290 int w = 1, h = 1;
291 SDL_GL_GetDrawableSize( _sdlWindow, &w, &h );
292 if ( w > 0 && h > 0 )
293 {
294 _drawableSize.set( w, h );
295 }
296 } break;
297 }
298 }
299
300}
301void DisplayWindow::opacity(const U8 opacity) noexcept {
302 if (SDL_SetWindowOpacity(_sdlWindow, to_F32(opacity) / 255) != -1) {
303 _prevOpacity = _opacity;
304 _opacity = opacity;
305 }
306}
307
309void DisplayWindow::setPosition(I32 x, I32 y, const bool global, const bool offset) {
310 _internalMoveEvent = true;
311
312 const I32 displayIndex = currentDisplayIndex();
313 if (x == -1) {
314 x = SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex);
315 } else if (!global && offset) {
316 x += _parent.monitorData()[displayIndex].viewport.x;
317 }
318 if (y == -1) {
319 y = SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex);
320 } else if (!global && offset) {
321 y += _parent.monitorData()[displayIndex].viewport.y;
322 }
323
324 SDL_SetWindowPosition(_sdlWindow, x, y);
325}
326
327vec2<I32> DisplayWindow::getPosition(const bool global, const bool offset) const {
328 vec2<I32> ret;
329 SDL_GetWindowPosition(_sdlWindow, &ret.x, &ret.y);
330
331 if (!global && offset) {
332 const vec2<I32> pOffset = _parent.monitorData()[currentDisplayIndex()].viewport.xy;
333 ret -= pOffset;
334 }
335
336 return ret;
337}
338
339void DisplayWindow::bringToFront() const noexcept {
340 SDL_RaiseWindow(_sdlWindow);
341}
342
345 setPosition(-1, -1);
346}
347
348void DisplayWindow::decorated(const bool state) noexcept {
349 // documentation states that this is a no-op on redundant state, so no need to bother checking
350 SDL_SetWindowBordered(_sdlWindow, state ? SDL_TRUE : SDL_FALSE);
351
352 state ? _flags |= to_base( WindowFlags::DECORATED ) : _flags &= to_base( WindowFlags::DECORATED );
353}
354
355void DisplayWindow::hidden(const bool state) noexcept {
356 if (((SDL_GetWindowFlags(_sdlWindow) & to_U32(SDL_WINDOW_SHOWN)) != 0u) == state)
357 {
358 if (state)
359 {
360 SDL_HideWindow(_sdlWindow);
361 }
362 else
363 {
364 SDL_ShowWindow(_sdlWindow);
365 }
366 }
367
368 state ? _flags |= to_base( WindowFlags::HIDDEN ) : _flags &= to_base( WindowFlags::HIDDEN );
369}
370
371void DisplayWindow::restore() noexcept {
372 SDL_RestoreWindow(_sdlWindow);
373
374 _flags &= ~to_base(WindowFlags::MAXIMIZED);
375 _flags &= ~to_base(WindowFlags::MINIMIZED);
376}
377
378void DisplayWindow::minimized(const bool state) noexcept {
379 if (((SDL_GetWindowFlags(_sdlWindow) & to_U32(SDL_WINDOW_MINIMIZED)) != 0u) != state)
380 {
381 if (state)
382 {
383 SDL_MinimizeWindow(_sdlWindow);
384 }
385 else
386 {
387 restore();
388 }
389 }
390
391 state ? _flags |= to_base( WindowFlags::MINIMIZED ) : _flags &= to_base( WindowFlags::MINIMIZED );
392}
393
394void DisplayWindow::maximized(const bool state) noexcept {
395 if (((SDL_GetWindowFlags(_sdlWindow) & to_U32(SDL_WINDOW_MAXIMIZED)) != 0u) != state)
396 {
397 if (state)
398 {
399 SDL_MaximizeWindow(_sdlWindow);
400 }
401 else
402 {
403 restore();
404 }
405 }
406
407 state ? _flags |= to_base( WindowFlags::MAXIMIZED ) : _flags &= to_base( WindowFlags::MAXIMIZED );
408}
409
410bool DisplayWindow::grabState() const noexcept {
411 return SDL_GetWindowGrab(_sdlWindow) == SDL_TRUE;
412}
413
414void DisplayWindow::grabState(const bool state) const noexcept {
415 SDL_SetWindowGrab(_sdlWindow, state ? SDL_TRUE : SDL_FALSE);
416}
417
419 if (_type == newWindowType) {
420 return;
421 }
422
423 _previousType = _type;
424 _type = newWindowType;
425 I32 switchState = -1;
426
427 grabState(false);
428 switch (newWindowType) {
429 case WindowType::WINDOW: {
430 switchState = SDL_SetWindowFullscreen(_sdlWindow, 0);
431 assert(switchState >= 0);
432 decorated(true);
433 } break;
435 switchState = SDL_SetWindowFullscreen(_sdlWindow, SDL_WINDOW_FULLSCREEN_DESKTOP);
436 assert(switchState >= 0);
437 decorated(false);
439 } break;
441 switchState = SDL_SetWindowFullscreen(_sdlWindow, SDL_WINDOW_FULLSCREEN);
442 assert(switchState >= 0);
443 decorated(false);
444 grabState(true);
446 } break;
447 default: break;
448 };
449
451}
452
454 if (fullscreen()) {
456 }
457 return _prevDimensions;
458}
459
461 const vec2<U16> dim = getDimensions();
462 if (dim == vec2<U16>(width, height)) {
463 return true;
464 }
465
467
468 I32 newW = to_I32(width);
469 I32 newH = to_I32(height);
470 switch(_type) {
472 // Find a decent resolution close to our dragged dimensions
473 SDL_DisplayMode mode = {}, closestMode = {};
474 SDL_GetCurrentDisplayMode(currentDisplayIndex(), &mode);
475 mode.w = width;
476 mode.h = height;
477 SDL_GetClosestDisplayMode(currentDisplayIndex(), &mode, &closestMode);
478 width = to_U16(closestMode.w);
479 height = to_U16(closestMode.h);
480 SDL_SetWindowDisplayMode(_sdlWindow, &closestMode);
481 } break;
482 case WindowType::FULLSCREEN_WINDOWED: //fall-through
484 case WindowType::WINDOW: [[fallthrough]];
485 default:
486 {
487 maximized(false);
488 SDL_SetWindowSize(_sdlWindow, newW, newH);
489 SDL_GetWindowSize(_sdlWindow, &newW, &newH);
490 } break;
491 }
492
494
495 if (newW == width && newH == height) {
496 _prevDimensions.set(dim);
497 return true;
498 }
499
500 return false;
501}
502
504 return setDimensions(dimensions.x, dimensions.y);
505}
506
508 I32 width = -1, height = -1;
509 SDL_GetWindowSize(_sdlWindow, &width, &height);
510
511 return vec2<U16>(width, height);
512}
513
514void DisplayWindow::renderingViewport(const Rect<I32>& viewport) noexcept {
515 _renderingViewport.set(viewport);
516}
517
519{
521}
522
523} //namespace Divide
#define LOCALE_STR(X)
Definition: Localization.h:91
#define DIVIDE_ASSERT(...)
#define DIVIDE_UNEXPECTED_CALL()
#define NOP()
vec2< I32 > getPosition(bool global=false, bool offset=false) const
void bringToFront() const noexcept
vec2< U16 > getDrawableSize() const noexcept
bool _internalMoveEvent
Did we generate the window move event?
void updateDrawableSize() noexcept
void handleChangeWindowType(WindowType newWindowType)
bool hidden() const noexcept
bool maximized() const noexcept
bool minimized() const noexcept
WindowHandle handle() const noexcept
virtual ~DisplayWindow() override
std::array< GFX::CommandBufferQueue, Config::MAX_FRAMES_IN_FLIGHT > _commandBufferQueues
SDL_Window * _sdlWindow
GFX::CommandBufferQueue & getCurrentCommandBufferQueue()
bool onSDLEvent(SDL_Event event) override
std::array< EventListeners, to_base(WindowEvent::COUNT)> _eventListeners
const Rect< I32 > & renderingViewport() const noexcept
bool decorated() const noexcept
void centerWindowPosition()
Centering is also easier via SDL.
vec2< U16 > _prevDimensions
void setPosition(I32 x, I32 y, bool global=false, bool offset=false)
Window positioning is handled by SDL.
void restore() noexcept
DELEGATE< void > _destroyCbk
DisplayWindow(WindowManager &parent, PlatformContext &context)
bool setDimensions(U16 width, U16 height)
width and height get adjusted to the closest supported value
bool fullscreen() const noexcept
vec2< U16 > _drawableSize
WindowManager & _parent
I32 currentDisplayIndex() const noexcept
vec2< U16 > getDimensions() const noexcept
void opacity(U8 opacity) noexcept
Rect< I32 > getBorderSizes() const noexcept
void changeType(WindowType newType)
void notifyListeners(WindowEvent event, const WindowEventArgs &args)
bool grabState() const noexcept
ErrorCode init(U32 windowFlags, WindowType initialType, const WindowDescriptor &descriptor)
vec2< U16 > getPreviousDimensions() const noexcept
static U64 FrameCount() noexcept
Definition: GFXDevice.h:340
FORCE_INLINE I64 getGUID() const noexcept
Definition: GUIDWrapper.h:51
GFXDevice & gfx() noexcept
static vec2< U16 > GetFullscreenResolution() noexcept
static void DestroyAPISettings(DisplayWindow *window) noexcept
const vector< MonitorData > & monitorData() const noexcept
void set(const T *v) noexcept
set the 2 components of the vector manually using a source pointer to a (large enough) array
Definition: MathVectors.h:335
void set(const T *v) noexcept
set the 4 components of the vector manually using a source pointer to a (large enough) array
Definition: MathVectors.h:1241
constexpr U8 MAX_FRAMES_IN_FLIGHT
Maximum number of active frames until we start waiting on a fence/sync.
Definition: config.h:100
Str StringFormat(const char *fmt, Args &&...args)
Handle console commands that start with a forward slash.
Definition: AIProcessor.cpp:7
void GetWindowHandle(void *window, WindowHandle &handleOut) noexcept
constexpr U32 to_U32(const T value)
constexpr U16 to_U16(const T value)
int32_t I32
uint8_t U8
constexpr F32 to_F32(const T value)
Project & parent
Definition: DefaultScene.h:41
uint16_t U16
@ Vulkan
not supported yet
@ None
No rendering. Used for testing or server code.
constexpr U32 U32_MAX
constexpr I32 to_I32(const T value)
uint32_t U32
constexpr auto to_base(const Type value) -> Type
static NO_INLINE void errorfn(const char *format, T &&... args)
static NO_INLINE void printfn(const char *format, T &&... args)
DisplayWindow * parentWindow