创建第二个 object 后堆损坏
Heap corruption after creation of 2nd object
我正在 VS 中使用 OpenGL 构建贪吃蛇游戏。我有我的 class 处理模型,VertexData
,然后 Main
处理游戏的其余部分。每当我通过调用 createModel()
创建第一个 object 时,一切正常。但是每当我第二次调用 createModel()
时,比如创建苹果,Visual Studio 有大约 40% 的机会触发断点。每次我在那之后调用 createModel()
,比如创建另一个 body 段,它触发断点的机会就会增加。是因为我在哪里创建 object,还是有其他问题?我看到向 VertexData
class 添加一个复制构造函数会阻止崩溃,但事实并非如此。
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
根据VS触发断点的区域为:loadFile.h第19行stream << file.rdbuf();
、shaderLoader.h第27行const char* vShaderCode = vertexCode.c_str();
、[=75行vertexData.cpp }
这只是一个右括号。
如果我在断点后单击继续,我会收到错误 Unhandled exception at 0x7727FA1D (ntdll.dll) in snek.exe: 0xC0000374: A heap has been corrupted (parameters: 0x772BB960).
编辑:
convertToFloat.h:
#ifndef convertToFloat
#define convertToFloat
class ConvertToFloat {
public:
ConvertToFloat(int width, int height);
ConvertToFloat();
void convertToGlobal(float* input);
void convertFromRGB(float* input, const int size);
void format(float* input, const int size);
private:
int width = 0;
int height = 0;
};
#endif
convertToFloat.cpp
#include "convertToFloat.h"
ConvertToFloat::ConvertToFloat(int width, int height) {
this->width = width;
this->height = height;
}
ConvertToFloat::ConvertToFloat() {
}
void ConvertToFloat::convertToGlobal(float* input) {
input[0] = 2.0*input[0] / width;
input[1] = 2.0*input[1] / height;
}
void ConvertToFloat::convertFromRGB(float* input, const int size) {
for (int i = 0; i < size; i++)
input[i] = input[i] / 255;
}
void ConvertToFloat::format(float* input, const int size) {
int step = 0;
for (int i = 0; i < size; i++) {
if (step < 3) {
if (step == 1)
input[i] = ((input[i] * 2) / height) - 1;
else
input[i] = ((input[i] * 2) / width) - 1;
}
else if (step < 6) {
input[i] = input[i] / 255;
}
if (step == 7)
step = 0;
else
step++;
}
}
假设 ConvertToFloat::format
有一个指针和一个长度,这就是你的问题:
conversion->format(vertices, numVertices * 8 * sizeof(float));
vertices
只有 numVertices * 8
个元素,您要将其乘以 sizeof(float)
。因此该函数将愉快地破坏 vertices
缓冲区后的大量内存。
立即修复是微不足道的:失去 * sizeof(float)
,但我恳请您停止使用原始内存和指针并拥抱 std::vector
。
如果您声明 std::vector<float> vertices
,您只需将其传递给 ConvertToFloat::format
,它会自动 a) 知道大小和 b) 如果您进行越界访问,则发出警报。
您始终可以通过调用 vertices.data()
.
获取指向后备数组的指针
此外,如果您定义一个
struct Vertex { float position[3]; float color[3]; float texcoord[2]; }
您可以记录您的 VBO 格式并大大清理您的属性分配代码:
glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(float), vertices.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, color));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texcoord));
glEnableVertexAttribArray(2);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size()*sizeof(int), indices.data(), GL_STATIC_DRAW);
理想情况下 vertices
只是一个 std::vector<Vertex>
,但我可以想象它不会立即适合您的加载代码。
我正在 VS 中使用 OpenGL 构建贪吃蛇游戏。我有我的 class 处理模型,VertexData
,然后 Main
处理游戏的其余部分。每当我通过调用 createModel()
创建第一个 object 时,一切正常。但是每当我第二次调用 createModel()
时,比如创建苹果,Visual Studio 有大约 40% 的机会触发断点。每次我在那之后调用 createModel()
,比如创建另一个 body 段,它触发断点的机会就会增加。是因为我在哪里创建 object,还是有其他问题?我看到向 VertexData
class 添加一个复制构造函数会阻止崩溃,但事实并非如此。
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
根据VS触发断点的区域为:loadFile.h第19行stream << file.rdbuf();
、shaderLoader.h第27行const char* vShaderCode = vertexCode.c_str();
、[=75行vertexData.cpp }
这只是一个右括号。
如果我在断点后单击继续,我会收到错误 Unhandled exception at 0x7727FA1D (ntdll.dll) in snek.exe: 0xC0000374: A heap has been corrupted (parameters: 0x772BB960).
编辑: convertToFloat.h:
#ifndef convertToFloat
#define convertToFloat
class ConvertToFloat {
public:
ConvertToFloat(int width, int height);
ConvertToFloat();
void convertToGlobal(float* input);
void convertFromRGB(float* input, const int size);
void format(float* input, const int size);
private:
int width = 0;
int height = 0;
};
#endif
convertToFloat.cpp
#include "convertToFloat.h"
ConvertToFloat::ConvertToFloat(int width, int height) {
this->width = width;
this->height = height;
}
ConvertToFloat::ConvertToFloat() {
}
void ConvertToFloat::convertToGlobal(float* input) {
input[0] = 2.0*input[0] / width;
input[1] = 2.0*input[1] / height;
}
void ConvertToFloat::convertFromRGB(float* input, const int size) {
for (int i = 0; i < size; i++)
input[i] = input[i] / 255;
}
void ConvertToFloat::format(float* input, const int size) {
int step = 0;
for (int i = 0; i < size; i++) {
if (step < 3) {
if (step == 1)
input[i] = ((input[i] * 2) / height) - 1;
else
input[i] = ((input[i] * 2) / width) - 1;
}
else if (step < 6) {
input[i] = input[i] / 255;
}
if (step == 7)
step = 0;
else
step++;
}
}
假设 ConvertToFloat::format
有一个指针和一个长度,这就是你的问题:
conversion->format(vertices, numVertices * 8 * sizeof(float));
vertices
只有 numVertices * 8
个元素,您要将其乘以 sizeof(float)
。因此该函数将愉快地破坏 vertices
缓冲区后的大量内存。
立即修复是微不足道的:失去 * sizeof(float)
,但我恳请您停止使用原始内存和指针并拥抱 std::vector
。
如果您声明 std::vector<float> vertices
,您只需将其传递给 ConvertToFloat::format
,它会自动 a) 知道大小和 b) 如果您进行越界访问,则发出警报。
您始终可以通过调用 vertices.data()
.
此外,如果您定义一个
struct Vertex { float position[3]; float color[3]; float texcoord[2]; }
您可以记录您的 VBO 格式并大大清理您的属性分配代码:
glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(float), vertices.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, color));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texcoord));
glEnableVertexAttribArray(2);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size()*sizeof(int), indices.data(), GL_STATIC_DRAW);
理想情况下 vertices
只是一个 std::vector<Vertex>
,但我可以想象它不会立即适合您的加载代码。