Skip to content

Commit 5586b68

Browse files
committed
Window improvements.
Added handling for content scaling changes to update UI. Refactored Window constructed in windowed mode to begin in the middle of the screen at half its size. Fixed bad state sync for size and position via set_size and set_position by adding on_x_callback.
1 parent 380f8a3 commit 5586b68

File tree

7 files changed

+109
-80
lines changed

7 files changed

+109
-80
lines changed

source/Application.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ int main(int argc, char* argv[])
194194
Platform::Core::initialise_directories();
195195
Platform::Core::initialise_GLFW();
196196
Platform::Input input = Platform::Input();
197-
Platform::Window window = Platform::Window(1920, 1080, input);
197+
Platform::Window window = Platform::Window(glm::vec2{0.5f, 0.5f}, input);
198198
Platform::Core::initialise_OpenGL();
199199
OpenGL::DebugRenderer::init();
200200
Platform::Core::initialise_ImGui(window);

source/External/ImGuiUser/imgui_user.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
// Add extra functions within the ImGui:: namespace here.
2020
namespace ImGui
2121
{
22+
inline bool IsInitialised()
23+
{
24+
return GetCurrentContext() != nullptr;
25+
}
2226
inline void Text_Manual(const char* fmt, ...)
2327
{
2428
va_list args;

source/Platform/Core.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,14 @@ namespace Platform
111111
{
112112
IMGUI_CHECKVERSION();
113113
ImGui::CreateContext();
114-
ImGuiIO& io = ImGui::GetIO();
115-
(void)io;
116-
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable docking
117114
ImGui_ImplGlfw_InitForOpenGL(p_window.m_handle, true);
118115
ImGui_ImplOpenGL3_Init(Config::GLSL_Version_String);
119-
glm::uvec2 size = p_window.size();
120-
io.DisplaySize = ImVec2(static_cast<float>(size.x), static_cast<float>(size.y));
116+
117+
ImGuiIO& io = ImGui::GetIO();
118+
io.FontGlobalScale = p_window.content_scale();
119+
glm::uvec2 size = p_window.size();
120+
io.DisplaySize = ImVec2(static_cast<float>(size.x), static_cast<float>(size.y));
121+
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
121122

122123
LOG("[INIT] Initialised ImGui");
123124
}

source/Platform/Window.cpp

Lines changed: 77 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,19 @@
77
#include "Utility/Utility.hpp"
88
#include "Utility/Config.hpp"
99

10-
#ifdef _WIN32
11-
#include <Windows.h> // MSVC requires Windows.h to be included before glfw headers
12-
#endif
1310
#include "GLFW/glfw3.h"
1411
#include "backends/imgui_impl_glfw.h"
1512
#include "backends/imgui_impl_opengl3.h"
1613
#include "imgui.h"
1714
#include "imgui_internal.h"
1815
#include "ImGuizmo.h"
1916

20-
#include <iostream>
21-
2217
namespace Platform
2318
{
24-
Window::Window(const int& p_width, const int& p_height, Input& p_input_state) noexcept
25-
: m_size_fullscreen{get_max_resolution()}
26-
, m_position_fullscreen{0, 0}
27-
, m_size_windowed{p_width, p_height}
28-
, m_position_windowed{0, get_window_title_bar_height()} // Offset starting position by height of title bar.
19+
Window::Window(const glm::vec2& p_screen_factor, Input& p_input_state) noexcept
20+
: m_last_position_windowed{0, 0} // init in body via set_position
21+
, m_last_size_windowed{0, 0} // init in body
2922
, m_fullscreen{false}
30-
, m_aspect_ratio{m_fullscreen ? static_cast<float>(m_size_fullscreen.x) / static_cast<float>(m_size_fullscreen.y) : static_cast<float>(m_size_windowed.x) / static_cast<float>(m_size_windowed.y)}
3123
, m_VSync{true}
3224
, m_close_requested{false}
3325
, m_handle{nullptr}
@@ -36,23 +28,30 @@ namespace Platform
3628
{
3729
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);
3830
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
39-
const auto window_size = size();
40-
const auto window_position = position();
41-
m_handle = glfwCreateWindow(window_size.x, window_size.y, Config::Is_Debug ? "Spirit - Debug" : "Spirit", m_fullscreen ? glfwGetPrimaryMonitor() : NULL, NULL);
31+
32+
auto monitor = glfwGetPrimaryMonitor();
33+
int wa_xpos, wa_ypos, wa_width, wa_height;
34+
glfwGetMonitorWorkarea(monitor, &wa_xpos, &wa_ypos, &wa_width, &wa_height);
35+
const glm::ivec2 desired_size_windowed = {wa_width * p_screen_factor.x, wa_height * p_screen_factor.y};
36+
37+
ASSERT(!m_fullscreen, "[WINDOW] Fullscreen construction not implemented. Add glfwCreateWindow call for fullscreen.");
38+
m_handle = glfwCreateWindow(desired_size_windowed.x, desired_size_windowed.y, Config::Is_Debug ? "Spirit - Debug" : "Spirit", NULL, NULL);
4239
ASSERT(m_handle != nullptr, "[WINDOW] Failed to construct Window");
4340

44-
glfwMakeContextCurrent(m_handle); // Set this window as the context for GL render calls.
45-
glfwSetWindowPos(m_handle, window_position.x, window_position.y);
46-
glfwSetWindowSize(m_handle, window_size.x, window_size.y); // glfwCreateWindow size requests are not hard constraints. Have to ensure size was set by calling glfwSetWindowSize.
41+
m_last_size_windowed = size(); // Get the actual size of the window after creation. Per GLFW docs, this may not be the same as the requested size.
42+
const glm::ivec2 desired_position_windowed = {wa_xpos + (wa_width - m_last_size_windowed.x) * 0.5f, wa_ypos + (wa_height - m_last_size_windowed.y) * 0.5f};
43+
set_position(desired_position_windowed);
4744
set_VSync(m_VSync);
45+
glfwMakeContextCurrent(m_handle); // Set this window as the context for GL render calls.
4846

4947
{ // Set the GLFW callbacks.
5048
// GLFW is a C library requiring static || global functions for callbacks.
5149
// We use the glfwSetWindowUserPointer and glfwGetWindowUserPointer to retrieve this instance of Window from the library and call the member functions.
5250
glfwSetWindowUserPointer(m_handle, this);
53-
glfwSetWindowCloseCallback(m_handle, [](GLFWwindow* p_handle){((Window*)glfwGetWindowUserPointer(p_handle))->request_close();});
54-
glfwSetWindowSizeCallback(m_handle, [](GLFWwindow* p_handle, int p_size_x, int p_size_y){((Window*)glfwGetWindowUserPointer(p_handle))->set_size({p_size_x, p_size_y});});
55-
glfwSetWindowPosCallback(m_handle, [](GLFWwindow* p_handle, int p_pos_x, int p_pos_y){((Window*)glfwGetWindowUserPointer(p_handle))->set_position({p_pos_x, p_pos_y});});
51+
glfwSetWindowCloseCallback(m_handle, [](GLFWwindow* p_handle){((Window*)glfwGetWindowUserPointer(p_handle))->request_close();});
52+
glfwSetWindowSizeCallback(m_handle, [](GLFWwindow* p_handle, int p_size_x, int p_size_y){((Window*)glfwGetWindowUserPointer(p_handle))->on_size_callback({p_size_x, p_size_y});});
53+
glfwSetWindowPosCallback(m_handle, [](GLFWwindow* p_handle, int p_pos_x, int p_pos_y){((Window*)glfwGetWindowUserPointer(p_handle))->on_position_callback({p_pos_x, p_pos_y});});
54+
glfwSetWindowContentScaleCallback(m_handle, [](GLFWwindow* p_handle, float p_scale_x, float p_scale_y){((Window*)glfwGetWindowUserPointer(p_handle))->on_content_scale_callback((p_scale_x + p_scale_y) * 0.5f);});
5655

5756
{ // INPUT CALLBACKS - Because we only have access to the WindowUserPointer via GLFW, we have to access the Input and set it from the window.
5857
glfwSetKeyCallback(m_handle, [](GLFWwindow* p_handle, int p_key, int p_scancode, int p_action, int p_mode){((Window*)glfwGetWindowUserPointer(p_handle))->m_input.glfw_key_press(p_key, p_scancode, p_action, p_mode);});
@@ -76,6 +75,7 @@ namespace Platform
7675
icon.height = icon_image.height;
7776
glfwSetWindowIcon(m_handle, 1, &icon);
7877
}
78+
7979
LOG("[WINDOW] Created Window with resolution {}x{}", size().x, size().y);
8080
}
8181
Window::~Window() noexcept
@@ -85,46 +85,63 @@ namespace Platform
8585
LOG("[WINDOW] Closed window");
8686
}
8787

88-
void Window::set_size(glm::uvec2 p_new_size)
88+
glm::uvec2 Window::size() const
8989
{
90-
if (p_new_size.x == 0 || p_new_size.y == 0) // When the window is minimised the size can be 0. Ignore and keep original size data.
91-
return;
90+
int size_x, size_y;
91+
glfwGetWindowSize(m_handle, &size_x, &size_y);
9292

93-
ImGuiIO& io = ImGui::GetIO();
94-
io.FontGlobalScale = std::round(ImGui::GetMainViewport()->DpiScale);
95-
96-
if (m_fullscreen)
97-
{
98-
m_size_fullscreen = p_new_size;
99-
m_aspect_ratio = static_cast<float>(m_size_fullscreen.x) / static_cast<float>(m_size_fullscreen.y);
100-
io.DisplaySize = ImVec2(static_cast<float>(m_size_fullscreen.x), static_cast<float>(m_size_fullscreen.y));
101-
}
93+
if (size_x == 0 || size_y == 0) // When the window is minimised the size can be 0.
94+
return {1, 1};
10295
else
103-
{
104-
m_size_windowed = p_new_size;
105-
m_aspect_ratio = static_cast<float>(m_size_windowed.x) / static_cast<float>(m_size_windowed.y);
106-
io.DisplaySize = ImVec2(static_cast<float>(m_size_windowed.x), static_cast<float>(m_size_windowed.y));
107-
}
96+
return {static_cast<unsigned int>(size_x), static_cast<unsigned int>(size_y)};
97+
}
98+
99+
void Window::on_size_callback(const glm::uvec2& p_new_size)
100+
{
101+
if (p_new_size.x == 0 || p_new_size.y == 0)
102+
return;
103+
104+
if (!m_fullscreen)
105+
m_last_size_windowed = p_new_size;
108106

109-
//mWindowResizeEvent.dispatch(new_size.x, new_size.y);
107+
if (ImGui::IsInitialised())
108+
ImGui::GetIO().DisplaySize = ImVec2(static_cast<float>(p_new_size.x), static_cast<float>(p_new_size.y));
110109

111110
LOG("[WINDOW] Resized to {}x{} aspect: {}", size().x, size().y, aspect_ratio());
112111
}
113-
void Window::set_position(glm::uvec2 p_new_position)
112+
void Window::set_size(const glm::uvec2& p_new_size)
114113
{
115-
if (m_fullscreen)
116-
m_position_fullscreen = p_new_position;
117-
else
118-
m_position_windowed = p_new_position;
119-
120-
LOG("[WINDOW] Moved to {}, {}", position().x, position().y, aspect_ratio());
114+
glfwSetWindowSize(m_handle, p_new_size.x, p_new_size.y);
115+
on_size_callback(size()); // Actual size may not be the same as requested call size to get the actual size.
116+
}
117+
glm::uvec2 Window::position() const
118+
{
119+
int pos_x, pos_y;
120+
glfwGetWindowPos(m_handle, &pos_x, &pos_y);
121+
return {static_cast<unsigned int>(pos_x), static_cast<unsigned int>(pos_y)};
122+
}
123+
void Window::on_position_callback(const glm::uvec2& new_position)
124+
{
125+
if (!m_fullscreen)
126+
m_last_position_windowed = new_position;
127+
LOG("[WINDOW] Moved to {}, {}", new_position.x, new_position.y, aspect_ratio());
128+
}
129+
void Window::set_position(const glm::uvec2& p_new_position)
130+
{
131+
glfwSetWindowPos(m_handle, p_new_position.x, p_new_position.y);
132+
on_position_callback(position());// Actual position may not be the same as requested call position to get the actual position.
121133
}
122134

123135
void Window::request_close()
124136
{
125137
glfwSetWindowShouldClose(m_handle, GL_TRUE); // Ask GLFW to close this window
126138
m_close_requested = true;
127139
}
140+
float Window::aspect_ratio() const
141+
{
142+
const auto curr_size = size();
143+
return static_cast<float>(curr_size.x) / static_cast<float>(curr_size.y);
144+
}
128145
void Window::set_VSync(bool p_enabled)
129146
{
130147
glfwMakeContextCurrent(m_handle);
@@ -142,15 +159,14 @@ namespace Platform
142159
{
143160
const auto max_res = get_max_resolution();
144161
glfwSetWindowMonitor(m_handle, glfwGetPrimaryMonitor(), 0, 0, max_res.x, max_res.y, GLFW_DONT_CARE);
145-
set_position({0, 0});
146-
set_size(max_res);
147-
LOG("[WINDOW] Set to fullscreen. Position: {},{} Resolution: {}x{} Aspect ratio: {}", 0, 0, m_size_fullscreen.x, m_size_fullscreen.y, m_aspect_ratio);
148162
}
149163
else // Windowed mode. Reuse the old size and position
150-
{
151-
glfwSetWindowMonitor(m_handle, NULL, m_position_windowed.x, m_position_windowed.y, m_size_windowed.x, m_size_windowed.y, GLFW_DONT_CARE);
152-
LOG("[WINDOW] Set to windowed mode. Position: {},{} Resolution: {}x{} Aspect ratio: {}", 0, 0, m_size_windowed.x, m_size_windowed.y, m_aspect_ratio);
153-
}
164+
glfwSetWindowMonitor(m_handle, NULL, m_last_position_windowed.x, m_last_position_windowed.y, m_last_size_windowed.x, m_last_size_windowed.y, GLFW_DONT_CARE);
165+
166+
on_position_callback(position());
167+
on_size_callback(size());
168+
169+
LOG("[WINDOW] Set to fullscreen. Position: {},{} Resolution: {}x{} Aspect ratio: {}", position().x, position().y, size().x, size().y, aspect_ratio());
154170
}
155171

156172
void Window::swap_buffers()
@@ -217,14 +233,16 @@ namespace Platform
217233
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
218234
}
219235

220-
int Window::get_window_title_bar_height()
236+
void Window::on_content_scale_callback(float new_scale)
237+
{
238+
if (ImGui::IsInitialised())
239+
ImGui::GetIO().FontGlobalScale = new_scale;
240+
}
241+
float Window::content_scale() const
221242
{
222-
#ifdef _WIN32
223-
return (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CXPADDEDBORDER));
224-
#else
225-
// Not implemented get_taskbar_height for this platform
226-
return 0;
227-
#endif
243+
float xscale, yscale;
244+
glfwGetWindowContentScale(m_handle, &xscale, &yscale);
245+
return (xscale + yscale) * 0.5f;
228246
}
229247

230248
glm::uvec2 Window::get_max_resolution()

source/Platform/Window.hpp

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,10 @@ namespace Platform
1111
class Window
1212
{
1313
friend class Core; // Core::initialise_imgui requires access to m_handle.
14-
glm::uvec2 m_size_fullscreen; // the most up-to-date size of the window in fullscreen.
15-
glm::uvec2 m_position_fullscreen; // the most up-to-date position of the window in fullscreen.
16-
glm::uvec2 m_size_windowed; // the most up-to-date size of the window in windowed.
17-
glm::uvec2 m_position_windowed; // the most up-to-date position of the window in windowed.
14+
glm::uvec2 m_last_position_windowed; // the most up-to-date position of the window in windowed.
15+
glm::uvec2 m_last_size_windowed; // the most up-to-date size of the window in windowed.
1816

1917
bool m_fullscreen;
20-
float m_aspect_ratio;
2118
bool m_VSync; // Whether VSync is on for the window.
2219
bool m_close_requested;
2320
GLFWwindow* m_handle;
@@ -27,28 +24,31 @@ namespace Platform
2724
// Creates a OS window of p_width and p_height.
2825
// Takes an Input and sets its GLFW callback functions. Input depends on a Window.
2926
// Window construction requires GLFW and ImGui to be initialised before.
30-
Window(const int& p_width, const int& p_height, Input& p_input_state) noexcept;
27+
Window(const glm::vec2& p_screen_factor, Input& p_input_state) noexcept;
3128
~Window() noexcept;
3229

3330
void set_VSync(bool p_enabled);
3431
bool get_VSync() const { return m_VSync; };
3532

36-
glm::uvec2 size() const { return m_fullscreen ? m_size_fullscreen : m_size_windowed; };
37-
void set_size(glm::uvec2 p_new_size);
33+
glm::uvec2 size() const;
34+
void on_size_callback(const glm::uvec2& p_new_size);
35+
void set_size(const glm::uvec2& p_new_size);
3836

39-
glm::uvec2 position() const { return m_fullscreen ? m_position_fullscreen : m_position_windowed; };
40-
void set_position(glm::uvec2 p_new_position);
37+
glm::uvec2 position() const;
38+
void on_position_callback(const glm::uvec2& p_new_position);
39+
void set_position(const glm::uvec2& p_new_position);
4140

4241
void toggle_fullscreen();
4342
void swap_buffers();
4443
void start_ImGui_frame();
4544
void end_ImGui_frame();
4645
void request_close();
4746
bool close_requested() const { return m_close_requested; };
48-
float aspect_ratio() const { return m_aspect_ratio; };
47+
float aspect_ratio() const;
48+
49+
void on_content_scale_callback(float new_scale);
50+
float content_scale() const;
4951

50-
// Returns the hight of the window title bar in pixels.
51-
static int get_window_title_bar_height();
5252
// Get the max resolution of the primary monitor.
5353
static glm::uvec2 get_max_resolution();
5454

source/Test/Tests/GraphicsTester.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace Test
1616
Platform::Core::initialise_directories();
1717
Platform::Core::initialise_GLFW();
1818
Platform::Input input = Platform::Input();
19-
Platform::Window window = Platform::Window(1920, 1080, input);
19+
Platform::Window window = Platform::Window({0.5, 0.5}, input);
2020
Platform::Core::initialise_OpenGL();
2121

2222

source/UI/Editor.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,13 @@ namespace UI
259259

260260
break;
261261
}
262-
case Platform::Key::F11: m_window.toggle_fullscreen(); break;
262+
case Platform::Key::F11:
263+
{
264+
if (p_action == Platform::Action::Release)
265+
m_window.toggle_fullscreen();
266+
267+
break;
268+
}
263269
default: break;
264270
}
265271
}

0 commit comments

Comments
 (0)