• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Razakhel / RaZ / 23015809894

12 Mar 2026 05:43PM UTC coverage: 74.471%. Remained the same
23015809894

push

github

Razakhel
[Render/Window] Resize operations properly propagate the dimensions

- Dimensions are now properly propagated when maximizing, making fullscreen, or their respective opposite operations

- Added a unit test file for Window, with a test checking resize operations

6 of 9 new or added lines in 2 files covered. (66.67%)

1 existing line in 1 file now uncovered.

8629 of 11587 relevant lines covered (74.47%)

1706.42 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

62.45
/src/RaZ/Render/Window.cpp
1
#include "RaZ/Data/Image.hpp"
2
#include "RaZ/Render/Renderer.hpp"
3
#include "RaZ/Render/RenderSystem.hpp"
4
#include "RaZ/Render/Window.hpp"
5
#include "RaZ/Utils/Logger.hpp"
6

7
// GLEW is needed for V-sync management
8
#include "GL/glew.h"
9
#if defined(RAZ_PLATFORM_WINDOWS)
10
#include "GL/wglew.h"
11
#elif defined(RAZ_PLATFORM_LINUX)
12
#include "GL/glxew.h"
13
#endif
14

15
#include "GLFW/glfw3.h"
16

17
#if !defined(RAZ_NO_OVERLAY)
18
// Needed to set ImGui's callbacks
19
#include "imgui_impl_glfw.h"
20
#endif
21

22
#include "tracy/Tracy.hpp"
23
#include "tracy/TracyOpenGL.hpp"
24

25
#if defined(RAZ_PLATFORM_EMSCRIPTEN)
26
#include <emscripten/html5.h>
27
#endif
28

29
namespace Raz {
30

31
Window::Window(RenderSystem& renderSystem,
11✔
32
               unsigned int width, unsigned int height,
33
               const std::string& title,
34
               WindowSetting settings,
35
               uint8_t antiAliasingSampleCount) : m_renderSystem{ &renderSystem } {
11✔
36
  ZoneScopedN("Window::Window");
37

38
  Logger::debug("[Window] Initializing...");
11✔
39

40
  glfwSetErrorCallback([] (int errorCode, const char* description) {
11✔
41
    Logger::error("[GLFW] {} (error code {})", description, errorCode);
12✔
42
  });
12✔
43

44
  if (!glfwInit())
11✔
45
    throw std::runtime_error("Error: Failed to initialize GLFW");
×
46

47
#if !defined(USE_OPENGL_ES)
48
  glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
11✔
49
  glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
11✔
50
#else
51
  glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
52
#endif
53

54
#if defined(RAZ_CONFIG_DEBUG)
55
  glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, true);
11✔
56
#endif
57

58
#if defined(RAZ_PLATFORM_MAC) // Setting the OpenGL forward compatibility is required on macOS
59
  glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, true);
60
#endif
61

62
  glfwWindowHint(GLFW_FOCUSED, static_cast<int>(settings & WindowSetting::FOCUSED));
11✔
63
  glfwWindowHint(GLFW_RESIZABLE, static_cast<int>(settings & WindowSetting::RESIZABLE));
11✔
64
  glfwWindowHint(GLFW_VISIBLE, static_cast<int>(settings & WindowSetting::VISIBLE));
11✔
65
  glfwWindowHint(GLFW_DECORATED, static_cast<int>(settings & WindowSetting::DECORATED));
11✔
66
  glfwWindowHint(GLFW_AUTO_ICONIFY, static_cast<int>(settings & WindowSetting::AUTO_MINIMIZE));
11✔
67
  glfwWindowHint(GLFW_FLOATING, static_cast<int>(settings & WindowSetting::ALWAYS_ON_TOP));
11✔
68
  glfwWindowHint(GLFW_MAXIMIZED, static_cast<int>(settings & WindowSetting::MAXIMIZED));
11✔
69
#if !defined(RAZ_PLATFORM_EMSCRIPTEN)
70
  glfwWindowHint(GLFW_CENTER_CURSOR, static_cast<int>(settings & WindowSetting::CENTER_CURSOR));
11✔
71
  glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, static_cast<int>(settings & WindowSetting::TRANSPARENT_FB));
11✔
72
  glfwWindowHint(GLFW_FOCUS_ON_SHOW, static_cast<int>(settings & WindowSetting::AUTOFOCUS));
11✔
73
#endif
74

75
  glfwWindowHint(GLFW_SAMPLES, antiAliasingSampleCount);
11✔
76

77
#if !defined(RAZ_PLATFORM_EMSCRIPTEN)
78
  static constexpr std::array<std::pair<int, int>, 8> glVersions = {{
79
    { 4, 6 },
80
    { 4, 5 },
81
    { 4, 4 },
82
    { 4, 3 },
83
    { 4, 2 },
84
    { 4, 1 },
85
    { 4, 0 },
86
    { 3, 3 }
87
  }};
88

89
  for (auto [major, minor] : glVersions) {
22✔
90
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, major);
22✔
91
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, minor);
22✔
92

93
    m_windowHandle = glfwCreateWindow(static_cast<int>(width), static_cast<int>(height), title.c_str(), nullptr, glfwGetCurrentContext());
22✔
94

95
    if (m_windowHandle)
22✔
96
      break;
11✔
97

98
    if (glfwGetError(nullptr) == GLFW_VERSION_UNAVAILABLE) {
11✔
99
      Logger::error("[Window] OpenGL {}.{} unsupported; attempting to fallback to a lower version", major, minor);
11✔
100
      continue;
11✔
101
    }
102

103
    close();
×
104
    throw std::runtime_error("Error: Failed to create GLFW Window");
×
105
  }
106
#else
107
  m_windowHandle = glfwCreateWindow(static_cast<int>(width), static_cast<int>(height), title.c_str(), nullptr, glfwGetCurrentContext());
108
#endif
109

110
  glfwSetWindowUserPointer(m_windowHandle, this);
11✔
111
  glfwGetWindowSize(m_windowHandle, &m_width, &m_height);
11✔
112
  glfwGetWindowPos(m_windowHandle, &m_posX, &m_posY);
11✔
113

114
  glfwSetWindowSizeCallback(m_windowHandle, [] (GLFWwindow* windowHandle, int newWidth, int newHeight) {
11✔
115
    static_cast<Window*>(glfwGetWindowUserPointer(windowHandle))->resize(newWidth, newHeight);
1✔
116
  });
1✔
117

118
  if (glfwGetCurrentContext() == nullptr)
11✔
119
    glfwMakeContextCurrent(m_windowHandle);
2✔
120

121
  Renderer::initialize();
11✔
122
  setClearColor(0.15f, 0.15f, 0.15f);
11✔
123

124
  glfwSetFramebufferSizeCallback(m_windowHandle, [] (GLFWwindow* windowHandle, int newWidth, int newHeight) {
11✔
125
    const auto* window = static_cast<const Window*>(glfwGetWindowUserPointer(windowHandle));
1✔
126
    window->m_renderSystem->resizeViewport(static_cast<unsigned int>(newWidth), static_cast<unsigned int>(newHeight));
1✔
127
  });
1✔
128

129
#if !defined(RAZ_NO_OVERLAY)
130
  Overlay::initialize(m_windowHandle);
11✔
131

132
  glfwSetWindowContentScaleCallback(m_windowHandle, [] (GLFWwindow*, float horizScale, float /* vertScale */) {
11✔
133
    Overlay::rescale(horizScale);
×
134
  });
×
135

136
#if !defined(RAZ_PLATFORM_EMSCRIPTEN) // glfwGetWindowContentScale() isn't available with Emscripten
137
  float windowHorizScale {};
11✔
138
  glfwGetWindowContentScale(m_windowHandle, &windowHorizScale, nullptr);
11✔
139

140
  if (windowHorizScale != 0.f)
11✔
141
    Overlay::rescale(windowHorizScale);
11✔
142
#endif // RAZ_PLATFORM_EMSCRIPTEN
143
#endif // RAZ_NO_OVERLAY
144

145
  ++s_refCounter;
11✔
146

147
  Logger::debug("[Window] Initialized");
11✔
148
}
11✔
149

150
void Window::setClearColor(const Color& color, float alpha) const {
15✔
151
  Renderer::clearColor(color.red(), color.green(), color.blue(), alpha);
15✔
152
}
15✔
153

154
void Window::setTitle(const std::string& title) const {
1✔
155
  glfwSetWindowTitle(m_windowHandle, title.c_str());
1✔
156
}
1✔
157

158
void Window::setIcon(const Image& img) const {
1✔
159
  if (img.isEmpty()) {
1✔
160
    Logger::error("[Window] Empty image given as window icon");
×
161
    return;
×
162
  }
163

164
  if (img.getColorspace() != ImageColorspace::RGBA) {
1✔
165
    Logger::error("[Window] The window icon can only be created from an image having an RGBA colorspace");
×
166
    return;
×
167
  }
168

169
  if (img.getDataType() != ImageDataType::BYTE) {
1✔
170
    Logger::error("[Window] The window icon can only be created from an image having byte data");
×
171
    return;
×
172
  }
173

174
  const GLFWimage icon = { static_cast<int>(img.getWidth()),
1✔
175
                           static_cast<int>(img.getHeight()),
2✔
176
                           const_cast<unsigned char*>(static_cast<const uint8_t*>(img.getDataPtr())) };
1✔
177
  glfwSetWindowIcon(m_windowHandle, 1, &icon);
1✔
178
}
179

180
void Window::resize(unsigned int width, unsigned int height) {
2✔
181
  glfwSetWindowSize(m_windowHandle, static_cast<int>(width), static_cast<int>(height));
2✔
182
  glfwGetWindowSize(m_windowHandle, &m_width, &m_height);
2✔
183
}
2✔
184

185
void Window::makeFullscreen() {
×
NEW
186
  m_windowedWidth  = m_width;
×
NEW
187
  m_windowedHeight = m_height;
×
UNCOV
188
  glfwGetWindowPos(m_windowHandle, &m_posX, &m_posY);
×
189

190
  GLFWmonitor* monitor    = glfwGetPrimaryMonitor();
×
191
  const GLFWvidmode* mode = glfwGetVideoMode(monitor);
×
192

193
  glfwSetWindowMonitor(m_windowHandle, monitor, 0, 0, mode->width, mode->height, mode->refreshRate);
×
194
}
×
195

196
void Window::makeWindowed() {
1✔
197
  glfwSetWindowMonitor(m_windowHandle, nullptr, m_posX, m_posY, m_windowedWidth, m_windowedHeight, GLFW_DONT_CARE);
1✔
198
}
1✔
199

200
void Window::enableFaceCulling(bool value) const {
3✔
201
  if (value)
3✔
202
    Renderer::enable(Capability::CULL);
2✔
203
  else
204
    Renderer::disable(Capability::CULL);
1✔
205
}
3✔
206

207
bool Window::recoverVerticalSyncState() const {
×
208
  ZoneScopedN("Window::recoverVerticalSyncState");
209

210
#if defined(RAZ_PLATFORM_WINDOWS)
211
  if (wglGetExtensionsStringEXT())
212
    return static_cast<bool>(wglGetSwapIntervalEXT());
213

214
  return true;
215
#elif defined(RAZ_PLATFORM_LINUX)
216
  if (glXQueryExtensionsString(glXGetCurrentDisplay(), 0)) {
×
217
    unsigned int interval {};
×
218
    glXQueryDrawable(glXGetCurrentDisplay(), glXGetCurrentDrawable(), GLX_SWAP_INTERVAL_EXT, &interval);
×
219

220
    return static_cast<bool>(interval);
×
221
  }
222

223
  return true;
×
224
#elif defined(RAZ_PLATFORM_MAC)
225
  return true;
226
#else
227
  Logger::warn("Vertical synchronization unsupported");
228
  return false;
229
#endif
230
}
231

232
void Window::enableVerticalSync([[maybe_unused]] bool value) const {
3✔
233
  ZoneScopedN("Window::enableVerticalSync");
234

235
#if defined(RAZ_PLATFORM_WINDOWS)
236
  if (wglGetExtensionsStringEXT()) {
237
    wglSwapIntervalEXT(static_cast<int>(value));
238
    return;
239
  }
240
#elif defined(RAZ_PLATFORM_LINUX)
241
  if (glXQueryExtensionsString(glXGetCurrentDisplay(), 0)) {
3✔
242
    glXSwapIntervalEXT(glXGetCurrentDisplay(), glXGetCurrentDrawable(), value);
3✔
243
    glXSwapIntervalMESA(static_cast<unsigned int>(value));
3✔
244
    return;
3✔
245
  }
246
#elif defined(RAZ_PLATFORM_MAC)
247
  glfwSwapInterval(value);
248
#else
249
  Logger::warn("Vertical synchronization unsupported");
250
#endif
251
}
252

253
void Window::setCursorState(Cursor::State state) const {
3✔
254
  glfwSetInputMode(m_windowHandle, GLFW_CURSOR, state);
3✔
255
}
3✔
256

257
void Window::addKeyCallback(Keyboard::Key key, std::function<void(float)> actionPress,
3✔
258
                                               Input::ActionTrigger frequency,
259
                                               std::function<void()> actionRelease) {
260
  m_keyboardCallbacks.emplace_back(key, std::move(actionPress), frequency, std::move(actionRelease));
3✔
261
  updateCallbacks();
3✔
262
}
3✔
263

264
void Window::addMouseButtonCallback(Mouse::Button button, std::function<void(float)> actionPress,
3✔
265
                                                          Input::ActionTrigger frequency,
266
                                                          std::function<void()> actionRelease) {
267
  m_mouseButtonCallbacks.emplace_back(button, std::move(actionPress), frequency, std::move(actionRelease));
3✔
268
  updateCallbacks();
3✔
269
}
3✔
270

271
void Window::setMouseScrollCallback(std::function<void(double, double)> func) {
1✔
272
  m_mouseScrollCallback = std::move(func);
1✔
273
  updateCallbacks();
1✔
274
}
1✔
275

276
void Window::setMouseMoveCallback(std::function<void(double, double)> func) {
1✔
277
  m_mouseMoveCallback = { m_width * 0.5, m_height * 0.5, std::move(func) };
1✔
278
  updateCallbacks();
1✔
279
}
1✔
280

281
void Window::setCloseCallback(std::function<void()> func) {
1✔
282
  m_closeCallback = std::move(func);
1✔
283

284
  glfwSetWindowCloseCallback(m_windowHandle, [] (GLFWwindow* windowHandle) {
1✔
285
    static_cast<const Window*>(glfwGetWindowUserPointer(windowHandle))->m_closeCallback();
×
286
  });
×
287
}
1✔
288

289
void Window::updateCallbacks() const {
9✔
290
  ZoneScopedN("Window::updateCallbacks");
291

292
#if !defined(RAZ_NO_OVERLAY)
293
  // Monitor events
294
  glfwSetMonitorCallback([] (GLFWmonitor* monitorHandle, int event) {
9✔
295
    ImGui_ImplGlfw_MonitorCallback(monitorHandle, event);
×
296
  });
×
297
#endif
298

299
#if !defined(RAZ_NO_OVERLAY)
300
  // Window focus
301
  glfwSetWindowFocusCallback(m_windowHandle, [] (GLFWwindow* windowHandle, int focused) {
9✔
302
    ImGui_ImplGlfw_WindowFocusCallback(windowHandle, focused);
×
303
  });
×
304
#endif
305

306
  // Keyboard inputs
307
  glfwSetKeyCallback(m_windowHandle, [] (GLFWwindow* windowHandle, int key, int scancode, int action, int mods) {
9✔
308
#if !defined(RAZ_NO_OVERLAY)
309
    ImGui_ImplGlfw_KeyCallback(windowHandle, key, scancode, action, mods);
×
310

311
    // Key callbacks shouldn't be executed if the overlay requested keyboard focus
312
    if (ImGui::GetIO().WantCaptureKeyboard)
×
313
      return;
×
314
#endif
315

316
    Window& window = *static_cast<Window*>(glfwGetWindowUserPointer(windowHandle));
×
317

318
    for (const auto& callback : window.m_keyboardCallbacks) {
×
319
      if (key != callback.key)
×
320
        continue;
×
321

322
      auto& actions = window.m_inputActions;
×
323

324
      if (action == GLFW_PRESS) {
×
325
        actions.emplace(key, InputAction{ callback.actionPress, callback.frequency });
×
326
      } else if (action == GLFW_RELEASE) {
×
327
        actions.erase(key);
×
328

329
        if (const auto& actionRelease = callback.actionRelease)
×
330
          actionRelease();
×
331
      }
332
    }
333
  });
334

335
#if !defined(RAZ_NO_OVERLAY)
336
  // Unicode character inputs
337
  glfwSetCharCallback(m_windowHandle, [] (GLFWwindow* windowHandle, unsigned int codePoint) {
9✔
338
    ImGui_ImplGlfw_CharCallback(windowHandle, codePoint);
×
339
  });
×
340
#endif
341

342
#if !defined(RAZ_NO_OVERLAY)
343
  // Cursor enter event
344
  glfwSetCursorEnterCallback(m_windowHandle, [] (GLFWwindow* windowHandle, int entered) {
9✔
345
    ImGui_ImplGlfw_CursorEnterCallback(windowHandle, entered);
×
346
  });
×
347
#endif
348

349
  // Mouse buttons inputs
350
  glfwSetMouseButtonCallback(m_windowHandle, [] (GLFWwindow* windowHandle, int button, int action, int mods) {
9✔
351
#if !defined(RAZ_NO_OVERLAY)
352
    ImGui_ImplGlfw_MouseButtonCallback(windowHandle, button, action, mods);
×
353

354
    // Mouse buttons callbacks shouldn't be executed if the overlay requested mouse focus
355
    if (ImGui::GetIO().WantCaptureMouse)
×
356
      return;
×
357
#endif
358

359
    Window& window = *static_cast<Window*>(glfwGetWindowUserPointer(windowHandle));
×
360

361
    for (const auto& callback : window.m_mouseButtonCallbacks) {
×
362
      if (button != callback.button)
×
363
        continue;
×
364

365
      if (action == GLFW_PRESS) {
×
366
        window.m_inputActions.emplace(button, InputAction{ callback.actionPress, callback.frequency });
×
367
      } else if (action == GLFW_RELEASE) {
×
368
        window.m_inputActions.erase(button);
×
369

370
        if (const auto& actionRelease = callback.actionRelease)
×
371
          actionRelease();
×
372
      }
373
    }
374
  });
375

376
  // Mouse scroll input
377
  glfwSetScrollCallback(m_windowHandle, [] (GLFWwindow* windowHandle, double xOffset, double yOffset) {
9✔
378
#if !defined(RAZ_NO_OVERLAY)
379
    ImGui_ImplGlfw_ScrollCallback(windowHandle, xOffset, yOffset);
×
380

381
    // Scroll callback shouldn't be executed if the overlay requested mouse focus
382
    if (ImGui::GetIO().WantCaptureMouse)
×
383
      return;
×
384
#endif
385

386
    if (const auto& scrollCallback = static_cast<Window*>(glfwGetWindowUserPointer(windowHandle))->m_mouseScrollCallback)
×
387
      scrollCallback(xOffset, yOffset);
×
388
  });
389

390
  // Mouse move input
391
  glfwSetCursorPosCallback(m_windowHandle, [] (GLFWwindow* windowHandle, double xPosition, double yPosition) {
9✔
392
#if !defined(RAZ_NO_OVERLAY)
393
    ImGui_ImplGlfw_CursorPosCallback(windowHandle, xPosition, yPosition);
×
394

395
    if (ImGui::GetIO().WantCaptureMouse)
×
396
      return;
×
397
#endif
398

399
    auto& [xPrevPos, yPrevPos, action] = static_cast<Window*>(glfwGetWindowUserPointer(windowHandle))->m_mouseMoveCallback;
×
400

401
    if (action == nullptr)
×
402
      return;
×
403

404
    action(xPosition - xPrevPos, yPosition - yPrevPos);
×
405
    xPrevPos = xPosition;
×
406
    yPrevPos = yPosition;
×
407
  });
408
}
9✔
409

410
bool Window::run(float deltaTime) {
9✔
411
  ZoneScopedN("Window::run");
412

413
  if (glfwWindowShouldClose(m_windowHandle))
9✔
414
    return false;
×
415

416
  processInputs(deltaTime);
9✔
417

418
#if !defined(RAZ_NO_OVERLAY)
419
  if (m_isOverlayEnabled && !m_overlay.isEmpty())
9✔
420
    m_overlay.render();
4✔
421
#endif
422

423
  {
424
    ZoneScopedN("glfwSwapBuffers");
425
    TracyGpuZone("SwapBuffers")
426
    glfwSwapBuffers(m_windowHandle);
9✔
427
  }
428

429
#if defined(RAZ_PLATFORM_EMSCRIPTEN)
430
  emscripten_webgl_commit_frame();
431
#endif
432

433
  {
434
    TracyGpuZone("TracyGpuCollect")
435
    TracyGpuCollect
436
  }
437

438
  return true;
9✔
439
}
440

441
Vec2f Window::recoverMousePosition() const {
1✔
442
  double xPos {};
1✔
443
  double yPos {};
1✔
444
  glfwGetCursorPos(m_windowHandle, &xPos, &yPos);
1✔
445

446
  return Vec2f(static_cast<float>(xPos), static_cast<float>(yPos));
1✔
447
}
448

449
void Window::processInputs(float deltaTime) {
9✔
450
  ZoneScopedN("Window::processInputs");
451

452
  {
453
    ZoneScopedN("glfwPollEvents");
454
    glfwPollEvents();
9✔
455
  }
456

457
  auto actionIter = m_inputActions.cbegin();
9✔
458

459
  while (actionIter != m_inputActions.cend()) {
9✔
460
    const auto& [action, frequency] = actionIter->second;
×
461

462
    action(deltaTime);
×
463

464
    // Removing the current action if it should be executed only once, or simply increment the iterator
465
    if (frequency == Input::ONCE)
×
466
      actionIter = m_inputActions.erase(actionIter); // std::unordered_map::erase(iter) returns an iterator on the next element
×
467
    else
468
      ++actionIter;
×
469
  }
470
}
9✔
471

472
void Window::setShouldClose() const {
×
473
  glfwSetWindowShouldClose(m_windowHandle, true);
×
474
}
×
475

476
void Window::close() {
11✔
477
  ZoneScopedN("Window::close");
478

479
  if (!m_windowHandle.isValid())
11✔
480
    return;
×
481

482
  Logger::debug("[Window] Closing...");
11✔
483

484
  --s_refCounter;
11✔
485

486
  if (s_refCounter == 0) {
11✔
487
#if !defined(RAZ_NO_OVERLAY)
488
    Overlay::destroy();
2✔
489
#endif
490

491
    {
492
      ZoneScopedN("glfwTerminate");
493
      glfwTerminate();
2✔
494
    }
495
    m_windowHandle = nullptr;
2✔
496
  }
497

498
  Logger::debug("[Window] Closed");
22✔
499
}
500

501
} // namespace Raz
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc