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

Razakhel / RaZ / 16746843640

05 Aug 2025 09:54AM UTC coverage: 74.293% (-0.3%) from 74.615%
16746843640

push

github

Razakhel
[Render/Renderer] Added sampler functions

- Renamed activateTexture() to setActiveTexture(), and TextureParam* enums to TextureParameter*

- Added several noexcept specifications

- Removed single dots at the end of message strings

66 of 170 new or added lines in 28 files covered. (38.82%)

8326 of 11207 relevant lines covered (74.29%)

1745.43 hits per line

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

61.78
/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] " + std::string(description) + " (error code " + std::to_string(errorCode) + ')');
11✔
42
  });
11✔
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 " + std::to_string(major) + '.' + std::to_string(minor) + " unsupported; attempting to fallback to a lower version");
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
  if (glfwGetCurrentContext() == nullptr)
11✔
115
    glfwMakeContextCurrent(m_windowHandle);
2✔
116

117
  Renderer::initialize();
11✔
118
  setClearColor(0.15f, 0.15f, 0.15f);
11✔
119

120
  glfwSetFramebufferSizeCallback(m_windowHandle, [] (GLFWwindow* windowHandle, int newWidth, int newHeight) {
11✔
121
    static_cast<const Window*>(glfwGetWindowUserPointer(windowHandle))->m_renderSystem->resizeViewport(static_cast<unsigned int>(newWidth),
1✔
122
                                                                                                       static_cast<unsigned int>(newHeight));
123
  });
1✔
124

125
#if !defined(RAZ_NO_OVERLAY)
126
  Overlay::initialize(m_windowHandle);
11✔
127
#endif
128

129
  ++s_refCounter;
11✔
130

131
  Logger::debug("[Window] Initialized");
11✔
132
}
11✔
133

134
void Window::setClearColor(const Color& color, float alpha) const {
15✔
135
  Renderer::clearColor(color.red(), color.green(), color.blue(), alpha);
15✔
136
}
15✔
137

138
void Window::setTitle(const std::string& title) const {
1✔
139
  glfwSetWindowTitle(m_windowHandle, title.c_str());
1✔
140
}
1✔
141

142
void Window::setIcon(const Image& img) const {
1✔
143
  if (img.isEmpty()) {
1✔
NEW
144
    Logger::error("[Window] Empty image given as window icon");
×
145
    return;
×
146
  }
147

148
  if (img.getColorspace() != ImageColorspace::RGBA) {
1✔
NEW
149
    Logger::error("[Window] The window icon can only be created from an image having an RGBA colorspace");
×
150
    return;
×
151
  }
152

153
  if (img.getDataType() != ImageDataType::BYTE) {
1✔
NEW
154
    Logger::error("[Window] The window icon can only be created from an image having byte data");
×
155
    return;
×
156
  }
157

158
  const GLFWimage icon = { static_cast<int>(img.getWidth()),
1✔
159
                           static_cast<int>(img.getHeight()),
2✔
160
                           const_cast<unsigned char*>(static_cast<const uint8_t*>(img.getDataPtr())) };
1✔
161
  glfwSetWindowIcon(m_windowHandle, 1, &icon);
1✔
162
}
163

164
void Window::resize(unsigned int width, unsigned int height) {
1✔
165
  glfwSetWindowSize(m_windowHandle, static_cast<int>(width), static_cast<int>(height));
1✔
166
  glfwGetWindowSize(m_windowHandle, &m_width, &m_height);
1✔
167
}
1✔
168

169
void Window::makeFullscreen() {
×
170
  glfwGetWindowSize(m_windowHandle, &m_width, &m_height);
×
171
  glfwGetWindowPos(m_windowHandle, &m_posX, &m_posY);
×
172

173
  GLFWmonitor* monitor    = glfwGetPrimaryMonitor();
×
174
  const GLFWvidmode* mode = glfwGetVideoMode(monitor);
×
175

176
  glfwSetWindowMonitor(m_windowHandle, monitor, 0, 0, mode->width, mode->height, mode->refreshRate);
×
177
}
×
178

179
void Window::makeWindowed() {
1✔
180
  glfwSetWindowMonitor(m_windowHandle, nullptr, m_posX, m_posY, m_width, m_height, GLFW_DONT_CARE);
1✔
181
}
1✔
182

183
void Window::enableFaceCulling(bool value) const {
3✔
184
  if (value)
3✔
185
    Renderer::enable(Capability::CULL);
2✔
186
  else
187
    Renderer::disable(Capability::CULL);
1✔
188
}
3✔
189

190
bool Window::recoverVerticalSyncState() const {
×
191
  ZoneScopedN("Window::recoverVerticalSyncState");
192

193
#if defined(RAZ_PLATFORM_WINDOWS)
194
  if (wglGetExtensionsStringEXT())
195
    return static_cast<bool>(wglGetSwapIntervalEXT());
196

197
  return true;
198
#elif defined(RAZ_PLATFORM_LINUX)
199
  if (glXQueryExtensionsString(glXGetCurrentDisplay(), 0)) {
×
200
    unsigned int interval {};
×
201
    glXQueryDrawable(glXGetCurrentDisplay(), glXGetCurrentDrawable(), GLX_SWAP_INTERVAL_EXT, &interval);
×
202

203
    return static_cast<bool>(interval);
×
204
  }
205

206
  return true;
×
207
#elif defined(RAZ_PLATFORM_MAC)
208
  return true;
209
#else
210
  Logger::warn("Vertical synchronization unsupported");
211
  return false;
212
#endif
213
}
214

215
void Window::enableVerticalSync([[maybe_unused]] bool value) const {
3✔
216
  ZoneScopedN("Window::enableVerticalSync");
217

218
#if defined(RAZ_PLATFORM_WINDOWS)
219
  if (wglGetExtensionsStringEXT()) {
220
    wglSwapIntervalEXT(static_cast<int>(value));
221
    return;
222
  }
223
#elif defined(RAZ_PLATFORM_LINUX)
224
  if (glXQueryExtensionsString(glXGetCurrentDisplay(), 0)) {
3✔
225
    glXSwapIntervalEXT(glXGetCurrentDisplay(), glXGetCurrentDrawable(), value);
3✔
226
    glXSwapIntervalMESA(static_cast<unsigned int>(value));
3✔
227
    return;
3✔
228
  }
229
#elif defined(RAZ_PLATFORM_MAC)
230
  glfwSwapInterval(value);
231
#else
232
  Logger::warn("Vertical synchronization unsupported");
233
#endif
234
}
235

236
void Window::setCursorState(Cursor::State state) const {
3✔
237
  glfwSetInputMode(m_windowHandle, GLFW_CURSOR, state);
3✔
238
}
3✔
239

240
void Window::addKeyCallback(Keyboard::Key key, std::function<void(float)> actionPress,
3✔
241
                                               Input::ActionTrigger frequency,
242
                                               std::function<void()> actionRelease) {
243
  std::get<0>(m_callbacks).emplace_back(key, std::move(actionPress), frequency, std::move(actionRelease));
3✔
244
  updateCallbacks();
3✔
245
}
3✔
246

247
void Window::addMouseButtonCallback(Mouse::Button button, std::function<void(float)> actionPress,
3✔
248
                                                          Input::ActionTrigger frequency,
249
                                                          std::function<void()> actionRelease) {
250
  std::get<1>(m_callbacks).emplace_back(button, std::move(actionPress), frequency, std::move(actionRelease));
3✔
251
  updateCallbacks();
3✔
252
}
3✔
253

254
void Window::setMouseScrollCallback(std::function<void(double, double)> func) {
1✔
255
  std::get<2>(m_callbacks) = std::move(func);
1✔
256
  updateCallbacks();
1✔
257
}
1✔
258

259
void Window::setMouseMoveCallback(std::function<void(double, double)> func) {
1✔
260
  std::get<3>(m_callbacks) = std::make_tuple(m_width / 2, m_height / 2, std::move(func));
1✔
261
  updateCallbacks();
1✔
262
}
1✔
263

264
void Window::setCloseCallback(std::function<void()> func) {
1✔
265
  m_closeCallback = std::move(func);
1✔
266

267
  glfwSetWindowCloseCallback(m_windowHandle, [] (GLFWwindow* windowHandle) {
1✔
268
    static_cast<const Window*>(glfwGetWindowUserPointer(windowHandle))->m_closeCallback();
×
269
  });
×
270
}
1✔
271

272
void Window::updateCallbacks() const {
9✔
273
  ZoneScopedN("Window::updateCallbacks");
274

275
#if !defined(RAZ_NO_OVERLAY)
276
  // Monitor events
277
  glfwSetMonitorCallback([] (GLFWmonitor* monitorHandle, int event) {
9✔
278
    ImGui_ImplGlfw_MonitorCallback(monitorHandle, event);
×
279
  });
×
280
#endif
281

282
#if !defined(RAZ_NO_OVERLAY)
283
  // Window focus
284
  glfwSetWindowFocusCallback(m_windowHandle, [] (GLFWwindow* windowHandle, int focused) {
9✔
285
    ImGui_ImplGlfw_WindowFocusCallback(windowHandle, focused);
×
286
  });
×
287
#endif
288

289
  // Keyboard inputs
290
  if (!std::get<0>(m_callbacks).empty()) {
9✔
291
    glfwSetKeyCallback(m_windowHandle, [] (GLFWwindow* windowHandle, int key, int scancode, int action, int mods) {
9✔
292
#if !defined(RAZ_NO_OVERLAY)
293
      ImGui_ImplGlfw_KeyCallback(windowHandle, key, scancode, action, mods);
×
294

295
      // Key callbacks should not be executed if the overlay requested keyboard focus
296
      if (ImGui::GetIO().WantCaptureKeyboard)
×
297
        return;
×
298
#endif
299

300
      InputCallbacks& callbacks = static_cast<Window*>(glfwGetWindowUserPointer(windowHandle))->m_callbacks;
×
301
      const auto& keyCallbacks  = std::get<0>(callbacks);
×
302

303
      for (const auto& callback : keyCallbacks) {
×
304
        if (key != std::get<0>(callback))
×
305
          continue;
×
306

307
        auto& actions = std::get<InputActions>(callbacks);
×
308

309
        if (action == GLFW_PRESS) {
×
310
          actions.emplace(key, std::make_pair(std::get<1>(callback), std::get<2>(callback)));
×
311
        } else if (action == GLFW_RELEASE) {
×
312
          actions.erase(key);
×
313

314
          const auto& actionRelease = std::get<3>(callback);
×
315

316
          if (actionRelease)
×
317
            actionRelease();
×
318
        }
319
      }
320
    });
321
  }
322

323
#if !defined(RAZ_NO_OVERLAY)
324
  // Unicode character inputs
325
  glfwSetCharCallback(m_windowHandle, [] (GLFWwindow* windowHandle, unsigned int codePoint) {
9✔
326
    ImGui_ImplGlfw_CharCallback(windowHandle, codePoint);
×
327
  });
×
328
#endif
329

330
#if !defined(RAZ_NO_OVERLAY)
331
  // Cursor enter event
332
  glfwSetCursorEnterCallback(m_windowHandle, [] (GLFWwindow* windowHandle, int entered) {
9✔
333
    ImGui_ImplGlfw_CursorEnterCallback(windowHandle, entered);
×
334
  });
×
335
#endif
336

337
  // Mouse buttons inputs
338
  if (!std::get<1>(m_callbacks).empty()) {
9✔
339
    glfwSetMouseButtonCallback(m_windowHandle, [] (GLFWwindow* windowHandle, int button, int action, int mods) {
6✔
340
#if !defined(RAZ_NO_OVERLAY)
341
      ImGui_ImplGlfw_MouseButtonCallback(windowHandle, button, action, mods);
×
342

343
      // Mouse buttons callbacks should not be executed if the overlay requested mouse focus
344
      if (ImGui::GetIO().WantCaptureMouse)
×
345
        return;
×
346
#endif
347

348
      InputCallbacks& callbacks  = static_cast<Window*>(glfwGetWindowUserPointer(windowHandle))->m_callbacks;
×
349
      const auto& mouseCallbacks = std::get<1>(callbacks);
×
350

351
      for (const auto& callback : mouseCallbacks) {
×
352
        if (button != std::get<0>(callback))
×
353
          continue;
×
354

355
        auto& actions = std::get<InputActions>(callbacks);
×
356

357
        if (action == GLFW_PRESS) {
×
358
          actions.emplace(button, std::make_pair(std::get<1>(callback), std::get<2>(callback)));
×
359
        } else if (action == GLFW_RELEASE) {
×
360
          actions.erase(button);
×
361

362
          const auto& actionRelease = std::get<3>(callback);
×
363

364
          if (actionRelease)
×
365
            actionRelease();
×
366
        }
367
      }
368
    });
369
  }
370

371
  // Mouse scroll input
372
  if (std::get<2>(m_callbacks)) {
9✔
373
    glfwSetScrollCallback(m_windowHandle, [] (GLFWwindow* windowHandle, double xOffset, double yOffset) {
3✔
374
#if !defined(RAZ_NO_OVERLAY)
375
      ImGui_ImplGlfw_ScrollCallback(windowHandle, xOffset, yOffset);
×
376

377
      // Scroll callback should not be executed if the overlay requested mouse focus
378
      if (ImGui::GetIO().WantCaptureMouse)
×
379
        return;
×
380
#endif
381

382
      const auto& scrollCallback = std::get<2>(static_cast<Window*>(glfwGetWindowUserPointer(windowHandle))->m_callbacks);
×
383
      scrollCallback(xOffset, yOffset);
×
384
    });
385
  }
386

387
  // Mouse move input
388
  if (std::get<2>(std::get<3>(m_callbacks))) {
9✔
389
    glfwSetCursorPosCallback(m_windowHandle, [] (GLFWwindow* windowHandle, double xPosition, double yPosition) {
2✔
390
      MouseMoveCallback& moveCallback = std::get<3>(static_cast<Window*>(glfwGetWindowUserPointer(windowHandle))->m_callbacks);
×
391

392
      double& xPrevPos = std::get<0>(moveCallback);
×
393
      double& yPrevPos = std::get<1>(moveCallback);
×
394

395
      std::get<2>(moveCallback)(xPosition - xPrevPos, yPosition - yPrevPos);
×
396

397
      xPrevPos = xPosition;
×
398
      yPrevPos = yPosition;
×
399
    });
×
400
  }
401
}
9✔
402

403
bool Window::run(float deltaTime) {
9✔
404
  ZoneScopedN("Window::run");
405

406
  if (glfwWindowShouldClose(m_windowHandle))
9✔
407
    return false;
×
408

409
  processInputs(deltaTime);
9✔
410

411
#if !defined(RAZ_NO_OVERLAY)
412
  if (m_isOverlayEnabled && !m_overlay.isEmpty())
9✔
413
    m_overlay.render();
4✔
414
#endif
415

416
  {
417
    ZoneScopedN("glfwSwapBuffers");
418
    TracyGpuZone("SwapBuffers")
419
    glfwSwapBuffers(m_windowHandle);
9✔
420
  }
421

422
#if defined(RAZ_PLATFORM_EMSCRIPTEN)
423
  emscripten_webgl_commit_frame();
424
#endif
425

426
  {
427
    TracyGpuZone("TracyGpuCollect")
428
    TracyGpuCollect
429
  }
430

431
  return true;
9✔
432
}
433

434
Vec2f Window::recoverMousePosition() const {
1✔
435
  double xPos {};
1✔
436
  double yPos {};
1✔
437
  glfwGetCursorPos(m_windowHandle, &xPos, &yPos);
1✔
438

439
  return Vec2f(static_cast<float>(xPos), static_cast<float>(yPos));
1✔
440
}
441

442
void Window::processInputs(float deltaTime) {
9✔
443
  ZoneScopedN("Window::processInputs");
444

445
  {
446
    ZoneScopedN("glfwPollEvents");
447
    glfwPollEvents();
9✔
448
  }
449

450
  auto& actions   = std::get<InputActions>(m_callbacks);
9✔
451
  auto actionIter = actions.cbegin();
9✔
452

453
  while (actionIter != actions.cend()) {
9✔
454
    const auto& action = actionIter->second;
×
455

456
    // An action consists of two parts:
457
    // - A callback associated to the triggered key or button
458
    // - A value indicating if it should be executed only once or every frame
459

460
    action.first(deltaTime);
×
461

462
    // Removing the current action if ONCE is given, or simply increment the iterator
463
    if (action.second == Input::ONCE)
×
464
      actionIter = actions.erase(actionIter); // std::unordered_map::erase(iter) returns an iterator on the next element
×
465
    else
466
      ++actionIter;
×
467
  }
468
}
9✔
469

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

474
void Window::close() {
11✔
475
  ZoneScopedN("Window::close");
476

477
  if (!m_windowHandle.isValid())
11✔
478
    return;
×
479

480
  Logger::debug("[Window] Closing...");
11✔
481

482
  --s_refCounter;
11✔
483

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

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

496
  Logger::debug("[Window] Closed");
11✔
497
}
498

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

© 2026 Coveralls, Inc