I am building the game Snake using OpenGL in VS. I have my class that handles the models, VertexData
, and then the rest of the game in Main
. Whenever I create the first object by calling createModel()
, everything works fine. However whenever I call createModel()
the second time, like to create the apple, there is about a 40% chance of Visual Studio triggering a breakpoint. everytime I call createModel()
after that, like to create another body segment, the chances of it triggering a breakpoint increases. Is it due to where I am creating the object, or is there something else wrong? I saw that adding a copy constructor to the VertexData
class would stop the crashing but it did not.
Main.cpp:
//includes
#include "convertToFloat.h"
#include "vertexData.h"
#include <iostream>
#include <vector>
#include <time.h>
//function prototypes
static void error_callback(int error, const char* description);
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void initWindow();
void destroy();
void changeLocation();
void update();
void render();
void loadModels();
void onStartUp();
void onCollect();
void createModel();
int roundUp(int numToRound, int multiple);
int roundDown(int numToRound, int multiple);
//object declerations
GLFWwindow* window;
//variables
int x = 200;
int y = 200;
int appleLoc[2] = { x,y };
int direction = 0;
int stepSize = 20;
bool start = false;
static double limitFPS = 1.0 / 15.0;
double lastTime = glfwGetTime(), timer = lastTime;
double deltaTime = 0, nowTime = 0;
int frames = 0, updates = 0;
std::vector<std::shared_ptr<VertexData>> models;
int main(void)
{
initWindow();
loadModels();
onStartUp();
while (!glfwWindowShouldClose(window))
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
nowTime = glfwGetTime();
deltaTime += (nowTime - lastTime) / limitFPS;
lastTime = nowTime;
while (deltaTime >= 1.0) {
update();
updates++;
deltaTime--;
}
render();
frames++;
if (glfwGetTime() - timer > 1.0) {
timer++;
updates = 0, frames = 0;
}
glfwSwapBuffers(window);
glfwPollEvents();
}
destroy();
}
void onCollect() {
appleLoc[0] = roundUp(rand() % 620, 20);
appleLoc[1] = roundUp(rand() % 460, 20);
//models.at(1)->move(appleLoc[0], appleLoc[1]);
//createModel();
}
void onStartUp() {
srand(time(0));
onCollect();
}
void createModel() {
std::shared_ptr<VertexData> model{ new VertexData("models/snakeHead.md",640,480) };
models.push_back(model);
}
void loadModels() {
createModel();
createModel();
}
void changeLocation() {
switch (direction) {
case(0):
if(y<460)
y += stepSize;
break;
case(1):
if (x < 620)
x += stepSize;
break;
case(2):
if (y > 0)
y -= stepSize;
break;
case(3):
if (x > 0)
x -= stepSize;
break;
}
std::cout << x << " " << y << std::endl;
std::cout << appleLoc[0] << " " << appleLoc[1] << std::endl;
}
void render() {
for(int i=0; i<models.size();i++)
models.at(i)->render();
}
void update() {
if (start)
changeLocation();
models.at(0)->move(x, y);
if (x == appleLoc[0] && y == appleLoc[1]) {
onCollect();
}
}
void initWindow() {
if (!glfwInit())
exit(EXIT_FAILURE);
window = glfwCreateWindow(640, 480, "Snek", NULL, NULL);
if (!window)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(window);
gladLoadGL(glfwGetProcAddress); //important
glfwSwapInterval(1);
glfwSetErrorCallback(error_callback);
glfwSetKeyCallback(window, key_callback);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
}
static void error_callback(int error, const char* description)
{
fprintf(stderr, "Error: %s\n", description);
}
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GLFW_TRUE);
if (key == GLFW_KEY_W && action == GLFW_PRESS) {
direction = 0;
start = true;
}
if (key == GLFW_KEY_S && action == GLFW_PRESS){
direction = 2;
start = true;
}
if (key == GLFW_KEY_A && action == GLFW_PRESS){
direction = 3;
start = true;
}
if (key == GLFW_KEY_D && action == GLFW_PRESS){
direction = 1;
start = true;
}
}
int roundUp(int numToRound, int multiple)
{
if (multiple == 0)
return numToRound;
int remainder = numToRound % multiple;
if (remainder == 0)
return numToRound;
return numToRound + multiple - remainder;
}
int roundDown(int numToRound, int multiple)
{
if (multiple == 0)
return numToRound;
int remainderInverseSorta = multiple-(numToRound % multiple);
if (remainderInverseSorta == 0)
return numToRound;
return numToRound - multiple + remainderInverseSorta;
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
void destroy() {
for (int i = 0; i < models.size(); i++)
models.at(i)->destroy();
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}
vertexdata.h:
#ifndef vertextData
#define vertexData
#define GLFW_INCLUDE_NONE
#include "loadFile.h"
#include "convertToFloat.h"
#include "shaderLoader.h"
#include <GLFW/glfw3.h>
#include <glad/gl.h> // include glad to get all the required OpenGL headers
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
class VertexData {
private:
unsigned int VAO,VBO,EBO;
int width = 0;
int height = 0;
std::unique_ptr <Shader> shader{ new Shader("Shaders/3.3.shader.vs", "Shaders/3.3.shader.fs") }; //add shader path to constructor
glm::mat4 trans = glm::mat4(1.0f);
public:
VertexData(const char* modelPath,int width,int height);
VertexData(const VertexData& data);
void render();
void move(int x, int y);
void rotate(int deg);
void destroy();
};
#endif
vertexData.cpp:
#include "vertexData.h"
VertexData::VertexData(const char* modelPath, int width, int height) {
this->width = width;
this->height = height;
std::unique_ptr<ConvertToFloat> conversion{ new ConvertToFloat(width, height) };
std::unique_ptr<LoadFile> file{ new LoadFile() };
std::stringstream modelStream;
std::string substr;
modelStream = file->load(modelPath);
std::getline(modelStream, substr, ',');
int numVertices = stoi(substr);
float* vertices = new float[numVertices*8];
std::getline(modelStream, substr, '\n');
int numIndices = stoi(substr);
int* indices = new int[numIndices];
int step = 0;
for (int i = 0; i < numVertices * 8; i++) {
if(step!=7)
std::getline(modelStream, substr, ',');
else
std::getline(modelStream, substr, '\n');
vertices[i] = stof(substr);
if (step == 7)
step = 0;
else
step++;
}
step = 0;
for (int i = 0; i < numIndices; i++) {
if (step == 2) {
std::getline(modelStream, substr, '\n');
step = 0;
}
else {
std::getline(modelStream, substr, ',');
step++;
}
indices[i] = stoi(substr);
}
conversion->format(vertices, numVertices * 8 * sizeof(float));
//binds id
glGenBuffers(1, &VBO);
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, numVertices*8*sizeof(float), vertices, GL_STATIC_DRAW);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, numIndices*4, indices, GL_STATIC_DRAW);
//texture
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
VertexData::VertexData(const VertexData& data) {
VAO = data.VAO;
VBO = data.VBO;
EBO = data.EBO;
width = data.width;
height = data.height;
trans = data.trans;
}
void VertexData::render() {
shader->use();
unsigned int transformLoc = glGetUniformLocation(shader->ID, "location");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
void VertexData::move(int x, int y) {
float coor[2] = { float(x),float(y) };
std::unique_ptr<ConvertToFloat> conversion{ new ConvertToFloat(width,height) };
conversion->convertToGlobal(coor);
glm::mat4 temp = glm::mat4(1.0f);
temp = glm::translate(temp, glm::vec3(coor[0],coor[1], 0.0f));
trans = temp;
}
void VertexData::rotate(int deg) {
}
void VertexData::destroy() {
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
}
loadFile.h:
#pragma once
#ifndef loadFileH
#define loadFileH
#include <fstream>
#include <sstream>
#include <iostream>
class LoadFile {
private:
public:
LoadFile() {}
std::stringstream load(const char* path) {
std::ifstream file;
std::stringstream stream;
file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
file.open(path);
stream << file.rdbuf();
// close file handlers
file.close();
return stream;
}
catch (std::ifstream::failure e)
{
std::cout << "ERROR::FILE_NOT_SUCCESFULLY_READ" << std::endl;
return stream;
}
}
};
#endif
shaderLoader.h:
#ifndef SHADER_H
#define SHADER_H
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <glad/gl.h> // include glad to get all the required OpenGL headers
#include "loadFile.h"
#include <string>
class Shader
{
public:
// the program ID
unsigned int ID;
// constructor reads and builds the shader
Shader(const char* vertexPath, const char* fragmentPath) {
std::unique_ptr<LoadFile> fragFile{ new LoadFile() };
std::unique_ptr<LoadFile> vertexFile{ new LoadFile() };
std::string vertexCode;
std::string fragmentCode;
vertexCode = vertexFile->load(vertexPath).str();
fragmentCode = fragFile->load(fragmentPath).str();
const char* vShaderCode = vertexCode.c_str();
const char* fShaderCode = fragmentCode.c_str();
// 2. compile shaders
unsigned int vertex, fragment;
int success;
char infoLog[512];
// vertex Shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
// print compile errors if any
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertex, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
};
// similiar for Fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
// print compile errors if any
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragment, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
};
// shader Program
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
glLinkProgram(ID);
// print linking errors if any
glGetProgramiv(ID, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(ID, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
// delete the shaders as they're linked into our program now and no longer necessary
glDeleteShader(vertex);
glDeleteShader(fragment);
}
// use/activate the shader
void use(){
glUseProgram(ID);
}
};
#endif
The areas that the breakpoint are triggered according to VS are: line 19 of loadFile.h stream << file.rdbuf();
, line 27 of shaderLoader.h const char* vShaderCode = vertexCode.c_str();
, and line 75 of vertexData.cpp }
which is just a closing bracket. If I click continue after the breakpoint, I get the error Unhandled exception at 0x7727FA1D (ntdll.dll) in snek.exe: 0xC0000374: A heap has been corrupted (parameters: 0x772BB960).