---------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;
}
---------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;
}
Share
Improve this question
edited Jan 29 at 9:52
Mark Rotteveel
109k226 gold badges155 silver badges219 bronze badges
asked Jan 28 at 12:50
ZoroZoro
14 bronze badges
18
- 1 Attach a debugger to your program. When it crashes, which field in which variable is it trying to access? – Botje Commented Jan 28 at 12:57
- 1 That address (0xCCCCCF78) looks like a field access of an invalid pointer. The Wikipedia list of Magic numbers says that 0xCCCCCCCC is Used by Microsoft's C++ debugging runtime library and many DOS environments to mark uninitialized stack memory. CC is the opcode of the INT 3 debug breakpoint interrupt on x86 processors. – Botje Commented Jan 28 at 13:00
- 2 Is the program trying to construct the Window (i.e. instantiate the Window class) before init() is called and GLFW and Glew are initialized? – Yun Commented Jan 28 at 13:04
- 1 Please don't post images of text, but just copy/paste the text. The code as is just seems to create a window and close it immediately (without errors), please create a minimal reproducible example. – Yun Commented Jan 28 at 16:41
- 2 This was not obvious from the start because you left out the code that contained the problem. Please help us help you by including a minimal reproducible example in your future questions. We take the "minimal" bit quite serious, and often you discover the problem yourself in the process of minimizing. – Botje Commented Jan 29 at 9:29
1 Answer
Reset to default 0When you're getting an error accessing an address in memory, the issue might not be anwhere near the line triggering it, since something else entirely could interfere with the memory that line was trying to access. Since you're getting an error after you add in the Camera class, we know to look in there. Since the issue is coming from a glfw function, we look through all the glfw functions in your Camera class code and the issue is that you're setting new glfw callbacks in the Camera class when you previously set them in the Window class. This explains the source of the issue, and why you're getting a glfw issue back in the Window class after you've set new callbacks in the Camera class.
m_previousMouseCallback = glfwSetCursorPosCallback(window, MouseCallback); m_previousScrollCallback = glfwSetScrollCallback(window, ScrollCallback);
To fix this you should only handle any glfwSet functions inside of one class (Window class or make a broader Context class to manage glfw functions). In OpenGL and GLFW, everything is managed via one active context per window. So your idea was seemingly to set multiple callbacks in two different classes, and then GLFW will manage this by remembering both callbacks and calling both (sounds like a fun thing to try an implement yourself), however that does not work. One context per window, one callback per callback type (while not absolutely necessary to only make glfwSet calls in one class, I highly recommend it to avoid the separate classes stepping on each others toes). My final advice is to use a debugger to step through your code and view the variables and call stack at each step of the way, especially working with OpenGL in C/C++.