---------Updated---------
I am trying to create a Window class, which can take care of creating a window with basic functionalities such as toggling full screen and binding ESC to close the window and window resize.
I am able to exit with ESC, but when I press F11, I keep getting access Exception thrown at 0x001D6F6B in IDK.exe: 0xC0000005: Access violation reading location 0xCCCCCF78. at line 16 in Window.cpp, not sure why this is happening.
I have tried adding print statements before the toggel function is called, and i see valid values, but as soon as the glfwGetWindowPos(_window, &_windowedMode.xpos, &_windowedMode.ypos); is reached I keep getting the same error, and I am stuck.
Window.h
#pragma once
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
struct WindowProperties
{
int xpos, ypos;
int width, height;
};
class Window
{
private:
std::string _title;
bool _fullscreen;
GLFWwindow* _window;
float _aspectRatio;
WindowProperties _windowedMode;
static void framebufferSizeCallback(GLFWwindow* window, int width, int height)
{
Window* windowInstance = static_cast<Window*>(glfwGetWindowUserPointer(window));
if (windowInstance)
{
windowInstance->handleFramebufferResize(width, height);
}
}
static void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
Window* windowInstance = static_cast<Window*>(glfwGetWindowUserPointer(window));
if (windowInstance)
{
windowInstance->handleKeyPress(key, scancode, action, mods);
}
}
public:
Window(const std::string& title, WindowProperties winProp, bool fullscreen = false)
: _title(title)
, _windowedMode(winProp)
, _fullscreen(fullscreen)
, _window(nullptr)
, _aspectRatio(static_cast<float>(_windowedMode.width) / static_cast<float>(_windowedMode.height)) {}
void toggleFullscreen()
{
_fullscreen = !_fullscreen;
if (_fullscreen)
{
glfwGetWindowPos(_window, &_windowedMode.xpos, &_windowedMode.ypos);
glfwGetWindowSize(_window, &_windowedMode.width, &_windowedMode.height);
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
glfwSetWindowMonitor(_window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate);
}
else
{
// Return to windowed mode with previous position and size
glfwSetWindowMonitor(_window, nullptr,
_windowedMode.xpos, _windowedMode.ypos,
_windowedMode.width, _windowedMode.height,
0);
}
}
void handleFramebufferResize(int width, int height)
{
_windowedMode.width = width;
_windowedMode.height = height;
_aspectRatio = static_cast<float>(width) / static_cast<float>(height);
glViewport(0, 0, width, height);
}
void handleKeyPress(int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
{
glfwSetWindowShouldClose(_window, true);
}
else if (key == GLFW_KEY_F11 && action == GLFW_PRESS)
{
toggleFullscreen();
}
}
bool init()
{
if (!glfwInit())
{
std::cerr << "Failed to initialize GLFW!" << std::endl;
return false;
}
_window = glfwCreateWindow(_windowedMode.width, _windowedMode.height, _title.c_str(),
_fullscreen ? glfwGetPrimaryMonitor() : nullptr, nullptr);
if (!_window)
{
std::cerr << "Failed to create GLFW window!" << std::endl;
glfwTerminate();
return false;
}
glfwMakeContextCurrent(_window);
glfwSwapInterval(1);
glfwSetWindowUserPointer(_window, this);
// Use lambda functions to bind the instance
glfwSetFramebufferSizeCallback(_window, [](GLFWwindow* window, int width, int height)
{
Window* windowInstance = static_cast<Window*>(glfwGetWindowUserPointer(window));
if (windowInstance)
{
windowInstance->handleFramebufferResize(width, height);
}
});
glfwSetKeyCallback(_window, [](GLFWwindow* window, int key, int scancode, int action, int mods) {
Window* windowInstance = static_cast<Window*>(glfwGetWindowUserPointer(window));
if (windowInstance)
{
windowInstance->handleKeyPress(key, scancode, action, mods);
}
});
if (glewInit() != GLEW_OK)
{
std::cerr << "Failed to initialize GLEW!" << std::endl;
glfwTerminate();
return false;
}
glEnable(GL_DEPTH_TEST);
return true;
}
float getAspectRatio() const { return _aspectRatio; }
GLFWwindow* getWindow() const { return _window; }
void setKeyCallback(GLFWkeyfun callback) { glfwSetKeyCallback(_window, callback); }
void setScrollCallback(GLFWscrollfun callback) { glfwSetScrollCallback(_window, callback); }
void setCursorPositionCallback(GLFWcursorposfun callback) { glfwSetCursorPosCallback(_window, callback); }
~Window()
{
if (_window)
{
glfwDestroyWindow(_window);
_window = nullptr;
}
glfwTerminate();
}
};
The code works fine with below example:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "Window.h"
#define PI 3.14159265358979
WindowProperties windowedMode(100, 100, 920, 900);
float deltaTime = 0.0f;
float lastFrame = 0.0f;
int main()
{
Window window("IDK Window", windowedMode, false);
if (!window.init())
{
return -1;
}
float vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f,
0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f
};
// Create and bind VAO/VBO
GLuint VAO, VBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Configure vertex attributes
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// Unbind to avoid accidental modification
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glLineWidth(2.0f);
while (!glfwWindowShouldClose(window.getWindow()))
{
float currentTime = static_cast<float>(glfwGetTime());
deltaTime = currentTime - lastFrame;
lastFrame = currentTime;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Draw lines
glBindVertexArray(VAO);
glDrawArrays(GL_LINES, 0, 8);
glfwSwapBuffers(window.getWindow());
glfwPollEvents();
}
glfwTerminate();
return 0;
}
However, as soon as I get Camera.h into the picture, its crashes with same issue.
Camera.h
#pragma once
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
enum Camera_Movement
{
FORWARD,
BACKWARD,
LEFT,
RIGHT,
UP,
DOWN
};
// Default camera values
const float YAW = -90.0f;
const float PITCH = 0.0f;
const float SPEED = 2.5f;
const float SENSITIVITY = 0.1f;
const float ZOOM = 45.0f;
class Camera
{
public:
glm::vec3 Position;
glm::vec3 Front;
glm::vec3 Up;
glm::vec3 Right;
glm::vec3 WorldUp;
// euler Angles
float Yaw;
float Pitch;
// camera options
float MovementSpeed;
float MouseSensitivity;
float Zoom;
// constructor with vectors
Camera( glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f),glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH)
: Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Zoom(ZOOM)
{
Position = position;
WorldUp = up;
Yaw = yaw;
Pitch = pitch;
updateCameraVectors();
}
// constructor with scalar values
Camera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch)
: Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Zoom(ZOOM)
{
Position = glm::vec3(posX, posY, posZ);
WorldUp = glm::vec3(upX, upY, upZ);
Yaw = yaw;
Pitch = pitch;
updateCameraVectors();
}
// Camera movement methods
glm::mat4 GetViewMatrix();
void ProcessKeyboard(Camera_Movement direction, float deltaTime);
void ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch = true);
void ProcessMouseScroll(float yoffset);
private:
void updateCameraVectors();
};
Camera.cpp
#include "Camera.h"
#include <iostream>
glm::mat4 Camera::GetViewMatrix()
{
return glm::lookAt(Position, Position + Front, Up);
}
// processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems)
void Camera::ProcessKeyboard(Camera_Movement direction, float deltaTime)
{
float velocity = MovementSpeed * deltaTime;
if (direction == FORWARD)
Position += Front * velocity;
if (direction == BACKWARD)
Position -= Front * velocity;
if (direction == LEFT)
Position -= Right * velocity;
if (direction == RIGHT)
Position += Right * velocity;
if (direction == UP)
Position += Up * velocity;
if (direction == DOWN)
Position -= Up * velocity;
}
// processes input received from a mouse input system. Expects the offset value in both the x and y direction.
void Camera::ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch)
{
xoffset *= MouseSensitivity;
yoffset *= MouseSensitivity;
Yaw += xoffset;
Pitch += yoffset;
// make sure that when pitch is out of bounds, screen doesn't get flipped
if (constrainPitch)
{
if (Pitch > 89.0f)
Pitch = 89.0f;
if (Pitch < -89.0f)
Pitch = -89.0f;
}
// update Front, Right and Up Vectors using the updated Euler angles
updateCameraVectors();
}
// processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis
void Camera::ProcessMouseScroll(float yoffset)
{
Zoom -= (float)yoffset;
if (Zoom < 1.0f)
Zoom = 1.0f;
if (Zoom > 45.0f)
Zoom = 45.0f;
}
void Camera::updateCameraVectors()
{
// calculate the new Front vector
glm::vec3 front;
front.x = cos(glm::radians(Yaw)) * cos(glm::radians(Pitch));
front.y = sin(glm::radians(Pitch));
front.z = sin(glm::radians(Yaw)) * cos(glm::radians(Pitch));
Front = glm::normalize(front);
// also re-calculate the Right and Up vector
Right = glm::normalize(glm::cross(Front, WorldUp)); // normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement.
Up = glm::normalize(glm::cross(Right, Front));
}
CameraController:
#include "CameraController.h"
CameraController::CameraController(GLFWwindow* window, Camera& camera)
: m_window(window)
, m_camera(camera)
, m_lastX(0.0f)
, m_lastY(0.0f)
, m_firstMouse(true)
, m_enabled(true)
{
// Store window dimensions for initial aspect ratio
int width, height;
glfwGetWindowSize(window, &width, &height);
m_aspectRatio = static_cast<float>(width) / static_cast<float>(height);
// Store previous callbacks
m_previousMouseCallback = glfwSetCursorPosCallback(window, MouseCallback);
m_previousScrollCallback = glfwSetScrollCallback(window, ScrollCallback);
// Set window user pointer to this instance
glfwSetWindowUserPointer(window, this);
// Set initial cursor state
//glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
}
CameraController::~CameraController()
{
// Restore previous callbacks
glfwSetCursorPosCallback(m_window, m_previousMouseCallback);
glfwSetScrollCallback(m_window, m_previousScrollCallback);
}
void CameraController::Update(float deltaTime)
{
if (!m_enabled) return;
ProcessKeyboardInput(deltaTime);
}
void CameraController::ProcessKeyboardInput(float deltaTime)
{
if (glfwGetKey(m_window, GLFW_KEY_W) == GLFW_PRESS)
m_camera.ProcessKeyboard(FORWARD, deltaTime);
if (glfwGetKey(m_window, GLFW_KEY_S) == GLFW_PRESS)
m_camera.ProcessKeyboard(BACKWARD, deltaTime);
if (glfwGetKey(m_window, GLFW_KEY_A) == GLFW_PRESS)
m_camera.ProcessKeyboard(LEFT, deltaTime);
if (glfwGetKey(m_window, GLFW_KEY_D) == GLFW_PRESS)
m_camera.ProcessKeyboard(RIGHT, deltaTime);
if (glfwGetKey(m_window, GLFW_KEY_SPACE) == GLFW_PRESS)
m_camera.ProcessKeyboard(UP, deltaTime);
if (glfwGetKey(m_window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS)
m_camera.ProcessKeyboard(DOWN, deltaTime);
}
void CameraController::ProcessMouseMovement(double xpos, double ypos)
{
if (!m_enabled) return;
if (m_firstMouse)
{
m_lastX = xpos;
m_lastY = ypos;
m_firstMouse = false;
}
float xoffset = xpos - m_lastX;
float yoffset = m_lastY - ypos;
m_lastX = xpos;
m_lastY = ypos;
m_camera.ProcessMouseMovement(xoffset, yoffset);
}
void CameraController::ProcessMouseScroll(double yoffset)
{
if (!m_enabled) return;
m_camera.ProcessMouseScroll(static_cast<float>(yoffset));
}
// Static callback implementations
void CameraController::MouseCallback(GLFWwindow* window, double xpos, double ypos)
{
auto* controller = static_cast<CameraController*>(glfwGetWindowUserPointer(window));
if (controller) {
controller->ProcessMouseMovement(xpos, ypos);
}
}
void CameraController::ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
{
auto* controller = static_cast<CameraController*>(glfwGetWindowUserPointer(window));
if (controller) {
controller->ProcessMouseScroll(yoffset);
}
}
Crashing app:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <iostream>
#include <vector>
#include <cmath>
#include "Shader.h"
#include "Camera.h"
#include "Window.h"
#include "CameraController.h"
#define PI 3.14159265358979
WindowProperties windowedMode(100, 100, 920, 900);
float deltaTime = 0.0f;
float lastFrame = 0.0f;
float aspectRatio;
int main()
{
Window window("IDK Window", windowedMode, false);
if (!window.init())
{
return -1;
}
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
CameraController cameraController(window.getWindow(), camera);
Shader shaderID("Shaders/BasicVertexShader.glsl", "Shaders/BasicFragmentShader.glsl");
aspectRatio = (float)windowedMode.width / (float)windowedMode.height;
float vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f,
0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f
};
// Create and bind VAO/VBO
GLuint VAO, VBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Configure vertex attributes
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// Unbind to avoid accidental modification
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glLineWidth(2.0f);
while (!glfwWindowShouldClose(window.getWindow()))
{
float currentTime = static_cast<float>(glfwGetTime());
deltaTime = currentTime - lastFrame;
lastFrame = currentTime;
cameraController.Update(deltaTime);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shaderID.use();
glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), aspectRatio, 0.1f, 100.0f);
glm::mat4 view = camera.GetViewMatrix();
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, glm::vec3(0.0f, 0.0f, -2.0f));
shaderID.setMat4("projection", projection);
shaderID.setMat4("view", view);
shaderID.setMat4("model", model);
// Draw lines
glBindVertexArray(VAO);
glDrawArrays(GL_LINES, 0, 8);
glfwSwapBuffers(window.getWindow());
glfwPollEvents();
}
glfwTerminate();
return 0;
}