Related
How to draw Two Cubic Bezier Curve using 8 Points
The last point of the first curve will be the starting point of second curve
What I am doing wrong ??
Please Help me solve this issue .
#include <array>
#include <fstream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <iostream>
#include <math.h>
#include <string>
#include <vector>
using namespace std;
std::vector<glm::vec3> pointToDraw;
std::vector<glm::vec3> myControlPoints = {
glm::vec3(-0.5f, -0.5f, 0.0f),
glm::vec3(-0.5f, 0.5f, 0.0f),
glm::vec3( 0.5f, -0.5f, 0.0f),
glm::vec3( 0.5f, 0.0f, 0.0f),
};
#define numVBOs 1
#define numVAOs 1
GLuint VBO[numVBOs];
GLuint VAO[numVAOs];
GLuint renderingProgram;
bool checkOpenGLError() {
bool foundError = false;
int glErr = glGetError();
while (glErr != GL_NO_ERROR) {
cout << "glError: " << glErr << endl;
foundError = true;
glErr = glGetError();
}
return foundError;
}
void printShaderLog(GLuint shader) {
int len = 0;
int chWrittn = 0;
char* log;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
if (len > 0) {
log = (char*)malloc(len);
glGetShaderInfoLog(shader, len, &chWrittn, log);
cout << "Shader Info Log: " << log << endl;
free(log);
}
}
void printProgramLog(int prog) {
int len = 0;
int chWrittn = 0;
char* log;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &len);
if (len > 0) {
log = (char*)malloc(len);
glGetProgramInfoLog(prog, len, &chWrittn, log);
cout << "Program Info Log: " << log << endl;
free(log);
}
}
string readShaderSource(const char* filePath) {
string content;
ifstream fileStream(filePath, ios::in);
string line = "";
while (!fileStream.eof()) {
getline(fileStream, line);
content.append(line + "\n");
}
fileStream.close();
return content;
}
GLuint createShaderProgram()
{
GLint vertCompiled;
GLint fragCompiled;
GLint linked;
string vertShaderStr = readShaderSource("vertexShader.glsl");
string fragShaderStr = readShaderSource("fragmentShader.glsl");
GLuint vShader = glCreateShader(GL_VERTEX_SHADER);
GLuint fShader = glCreateShader(GL_FRAGMENT_SHADER);
const char* vertShaderSrc = vertShaderStr.c_str();
const char* fragShaderSrc = fragShaderStr.c_str();
glShaderSource(vShader, 1, &vertShaderSrc, NULL);
glShaderSource(fShader, 1, &fragShaderSrc, NULL);
glCompileShader(vShader);
checkOpenGLError();
glGetShaderiv(vShader, GL_COMPILE_STATUS, &vertCompiled);
if (vertCompiled != 1) {
cout << "vertex compilation failed" << endl;
printShaderLog(vShader);
}
glCompileShader(fShader);
checkOpenGLError();
glGetShaderiv(vShader, GL_COMPILE_STATUS, &fragCompiled);
if (fragCompiled != 1) {
cout << "fragment compilation failed" << endl;
printShaderLog(fShader);
}
// Shader program objektum létrehozása. Eltároljuk az ID értéket.
GLuint vfProgram = glCreateProgram();
glAttachShader(vfProgram, vShader);
glAttachShader(vfProgram, fShader);
glLinkProgram(vfProgram);
checkOpenGLError();
glGetProgramiv(vfProgram, GL_LINK_STATUS, &linked);
if (linked != 1) {
cout << "linking failed" << endl;
printProgramLog(vfProgram);
}
glDeleteShader(vShader);
glDeleteShader(fShader);
return vfProgram;
}
int NCR(int n, int r) {
if (r == 0) return 1;
if (r > n / 2) return NCR(n, n - r);
long res = 1;
for (int k = 1; k <= r; ++k) {
res *= n - k + 1;
res /= k;
}
return res;
}
GLfloat blending(GLint n, GLint i, GLfloat t) {
return NCR(n, i) * pow(t, i) * pow(1.0f - t, n - i);
}
void drawBezierCurve(std::vector<glm::vec3> controlPoints) {
glm::vec3 nextPoint;
GLfloat t = 0.0f, B;
GLfloat increment = 1.0f / 100.0f;
while (t <= 1.0f) {
nextPoint = glm::vec3(0.0f, 0.0f, 0.0f);
for (int i = 0; i < controlPoints.size(); i++) {
B = blending(controlPoints.size() - 1, i, t);
nextPoint.x += B * controlPoints.at(i).x;
nextPoint.y += B * controlPoints.at(i).y;
nextPoint.z += B * controlPoints.at(i).z;
}
pointToDraw.push_back(nextPoint);
t += increment;
}
}
void init(GLFWwindow* window) {
renderingProgram = createShaderProgram();
drawBezierCurve(myControlPoints);
glGenBuffers(numVBOs, VBO);
glGenVertexArrays(numVAOs, VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glBufferData(GL_ARRAY_BUFFER, pointToDraw.size() * sizeof(glm::vec3), pointToDraw.data(), GL_STATIC_DRAW);
glBindVertexArray(VAO[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(renderingProgram);
glClearColor(0.0, 0.0, 0.0, 1.0);
}
void display(GLFWwindow* window, double currentTime) {
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(VAO[0]);
glLineWidth(2.0f);
glDrawArrays(GL_LINE_STRIP, 0, pointToDraw.size());
glBindVertexArray(0);
}
I want to join two cubic Bezier curve
Two Cubic Bezier Curve Sample
Second curve is starting from the end of first cubic Bezier curve
I am trying to render a cylinder in OpenGL, by first starting to render top and lower caps using TRIANGLE_FAN. I store all the vertex data in one VBO and create two index buffers one for each cap. The top cap gets rendered correctly however the low cap does not get rendered at all, you can see it in the snapshot.
Here is my client application.
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/vec3.hpp> // glm::vec3
#include <glm/vec4.hpp> // glm::vec4
#include <glm/mat4x4.hpp> // glm::mat4
#include <glm/gtc/matrix_transform.hpp> // glm::translate, glm::rotate, glm::scale, glm::perspective
using namespace std;
#define PI 3.14159265359
static string ParseShader(string filepath) {
ifstream stream(filepath);
string line;
stringstream stringStream;
while (getline(stream, line))
{
stringStream << line << '\n';
}
return stringStream.str();
}
static unsigned int CompileShader(unsigned int type, const string& source) {
unsigned int id = glCreateShader(type);
const char* src = source.c_str(); // this returns a pointer to data inside the string, the first character
glShaderSource(id, 1, &src, nullptr); // shader id, count of source codes, a pointer to the array that holds the strings
glCompileShader(id);
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE) {
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
char* message = (char*)alloca(length * sizeof(char));
glGetShaderInfoLog(id, length, &length, message);
cout << type << endl;
cout << message << endl;
glDeleteShader(id);
return 0;
}
return id;
}
// takes the shader codes as a string parameters
static unsigned int CreateShader(const string& vertexShader, const string& fragmentShader)
{
GLuint program = glCreateProgram();
unsigned int vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glValidateProgram(program); // validate if the program is valid and can be run in the current state of opengl
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
std::vector<float> GenerateVertexData(float radius, float cylinderHeight, int vertexCount) {
int bufferSize = 3 * vertexCount;
std::vector<float> result(3 * vertexCount);
result[0] = 0;
result[1] = 0;
result[2] = cylinderHeight / 2;
float angleDelta = (360 / (vertexCount - 1)) * PI / 180;
float currentAngle = 0;
for (int i = 1; i < vertexCount; ++i) {
result[ 3 * i ] = cos(currentAngle) * radius;
result[3 * i + 1] = sin(currentAngle) * radius;
result[3 * i + 2] = cylinderHeight / 2;
currentAngle += angleDelta;
}
for (int i = 0; i < bufferSize; ++i) {
std::cout << "Result [ " << i << " ]" << result[i] << std::endl;
}
return result;
}
std::vector<GLuint> GenerateIndexData(int vertexCount) {
std::vector<GLuint> result(vertexCount + 1);
for (int i = 0; i < vertexCount; ++i) {
result[i] = i;
}
result[vertexCount] = 1;
return result;
}
std::vector<GLuint> GenerateLowCapIndexData(int vertexCount) {
std::vector<GLuint> result(vertexCount + 1);
for (int i = 0; i < vertexCount; ++i) {
result[i] = i + vertexCount;
std::cout << "Index [ " << i << " ]" << result[i] << std::endl;
}
result[vertexCount] = 1 + vertexCount;
std::cout << "Index [ " << result.size() << " ]" << result.back() << std::endl;
return result;
}
std::vector<GLuint> generateBodyIndexData(int verticalSegments) {
std::vector<GLuint> result(2 * (verticalSegments + 1));
for (int i = 0; i < verticalSegments; ++i) {
result[ 2 * i ] = i;
result[2 * i + 1] = i + verticalSegments;
}
result[result.size() - 2] = result.front();
result.back() = result[1];
return result;
}
int main(int argc, char* argv[]) {
float radius = std::stof(argv[1]);
float cylinderHeight = std::stof(argv[2]);
int verticalSegments = std::stoi(argv[3]);
std::cout << "Vertical segments : " << verticalSegments << std::endl;
int totalVertexCount = verticalSegments + 1;
const int vertexCoordinateCount = 3;
std::vector<float> vertexData = GenerateVertexData(radius, cylinderHeight, totalVertexCount);
std::vector<float> vertexDataLowerHalf = GenerateVertexData(radius, -cylinderHeight, totalVertexCount);
appendVec(vertexData, vertexDataLowerHalf);
std::vector<GLuint> topCapIndexData = GenerateIndexData(totalVertexCount);
std::vector<GLuint> lowCapIndexData = GenerateLowCapIndexData(totalVertexCount);
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
window = glfwCreateWindow(640, 480, "HW3", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
if (glfwRawMouseMotionSupported())
glfwSetInputMode(window, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE);
glfwMakeContextCurrent(window);
GLenum err = glewInit();
if (GLEW_OK != err)
{
/* Problem: glewInit failed, something is seriously wrong. */
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
}
//Positions
GLuint positionBufferHandle;
glGenBuffers(1, &positionBufferHandle);
glBindBuffer(GL_ARRAY_BUFFER, positionBufferHandle);
glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(float), vertexData.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, vertexCoordinateCount, GL_FLOAT, GL_FALSE, sizeof(float) * vertexCoordinateCount, 0);
glEnableVertexAttribArray(0);
//TopCap Indices
GLuint indexBufferHandle;
glGenBuffers(1, &indexBufferHandle);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferHandle);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, topCapIndexData.size() * sizeof(GLuint), topCapIndexData.data(), GL_STATIC_DRAW);
//LowCap Indices
GLuint lowCapIndexBufferHandle;
glGenBuffers(1, &lowCapIndexBufferHandle);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, lowCapIndexBufferHandle);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, lowCapIndexData.size() * sizeof(GLuint), lowCapIndexData.data(), GL_STATIC_DRAW);
string vertexSource = ParseShader("vertex.shader");
string fragmentSource = ParseShader("fragment.shader");
unsigned int program = CreateShader(vertexSource, fragmentSource);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
// Render here
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(program);
glDrawElements(GL_TRIANGLE_FAN, topCapIndexData.size() + lowCapIndexData.size(), GL_UNSIGNED_INT, nullptr);
//Swap front and back buffers
glfwSwapBuffers(window);
// Poll for and process events
glfwPollEvents();
}
glDeleteProgram(program);
glfwTerminate();
return 0;
}
I have checked my vertex data generating functions and they are correct.
Here is the snapshot of my result.
Only 1 index buffer can be bound at a time. You need 2 draw calls and must bind the index buffer before the draw call:
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferHandle);
glDrawElements(GL_TRIANGLE_FAN, topCapIndexData.size(), GL_UNSIGNED_INT, nullptr);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, lowCapIndexBufferHandle);
glDrawElements(GL_TRIANGLE_FAN, lowCapIndexData.size(), GL_UNSIGNED_INT, nullptr);
Alternatively you can put the list of indices in 1 buffer and separate them with a Primitive Restart index.
GLuint restartIndex = 0xffffffff;
std::vector<GLuint> indices = topCapIndexData;
indices.push_back(restartIndex);
indices.insert(indices.end(), lowCapIndexBufferHandle.begin(), lowCapIndexBufferHandle.end();
GLuint indexBufferHandle;
glGenBuffers(1, &indexBufferHandle);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferHandle);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLuint), indices.data(), GL_STATIC_DRAW);
glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(restartIndex);
glDrawElements(GL_TRIANGLE_FAN, indices.size(), GL_UNSIGNED_INT, nullptr);
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
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).
EDIT:
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++;
}
}
Assuming ConvertToFloat::format takes a pointer and a length, here is your problem:
conversion->format(vertices, numVertices * 8 * sizeof(float));
vertices only has numVertices * 8 elements and you are multiplying that by sizeof(float). So that function will happily corrupt lots of memory after the vertices buffer.
The immediate fix is trivial: lose the * sizeof(float), but I implore you to stop using raw memory and pointers and embrace std::vector.
If you declare std::vector<float> vertices you can simply pass that to ConvertToFloat::format and it will automatically a) know the size and b) alert if you do an out-of-bounds access.
You can always get a pointer to the backing array back by calling vertices.data().
Also, if you define a
struct Vertex { float position[3]; float color[3]; float texcoord[2]; }
you can document your VBO format and greatly clear up your attribute assignment code:
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);
Ideally vertices would just be a std::vector<Vertex>, but I can imagine that does not immediately fit your loading code.
I have been working to create a circle based on a shader that changes color periodically. My code prints out a blank window. I decided to set-up some methods to check for errors using GL_LINK_STATUS and it seems that my code is encountering an issue linking the program and the shader.
I did some research into similar issues that people have had but they don't seem to have similar causes.
I have posted my shader code, the driver program(named Priomary) and the Shader Program below.
Vertex Shader
#version 330 core
layout (location = 0) in vec3 pos;
uniform vec2 posOffset;
void main()
{
gl_Position = vec4(pos.x + posOffset.x, pos.y + posOffset.y, pos.z, 1.0);
}
Fragment Shader
#version 330 core
uniform vec4 vertColor;
out vec4 frag_color;
void main()
{
frag_color = vertColor;
}
Shader Program
#include "ShaderProgram.h"
#include <fstream>
#include <iostream>
#include <sstream>
ShaderProgram::ShaderProgram()
: mProgram(0){
}
ShaderProgram::~ShaderProgram()
{
glDeleteProgram(mProgram);
}
bool ShaderProgram::assignShaders(const char* vertFileName, const char* fragFileName)
{
//Shaders output objects called programs that define their relationship and lead to .exe functionality
//assigning pointer to the shader
string vsString = readFile(vertFileName);
string fsString = readFile(fragFileName);
// c_str returns a const char* that points to a null-terminated string (i.e. a C-style string). It is useful when you want to pass the "contents"¹ of an std::string to a function that expects to work with a C-style string.
const GLchar* vsSourcePtr = vsString.c_str();
const GLchar* fsSourcePtr = fsString.c_str();
//creating vertex shader(vs) shader object
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
//assigning shader source using address. Replaces the source code in a shader object //#arg (shader, count Strings, pointer to const File ,size)
glShaderSource(vs, 1, &vsSourcePtr, NULL);
glShaderSource(fs, 1, &fsSourcePtr, NULL);
glCompileShader(vs);
testShaderCompile(vs);
glCompileShader(fs);
testShaderCompile(fs);
//createProgram returns GLUint which is basically an unsigned int... we will use This Handler to create a program object
mProgram = glCreateProgram();
if (mProgram == 0)
{
std::cerr << "Shader cannot be created" << std::endl;
return false;
}
//assign the program object(mProgram) to the Shader
glAttachShader(mProgram, vs);
glAttachShader(mProgram, fs);
//this method accepts a GLuint "program" . If its an object of type GL_VERTEX_SHADER,
//itll create a .exe that runs on the programmable vertex processor. same goes for geometric and fragment shaders if they were included
//it will also bind all user defined uniform variables and attributes to the program
//The program can then be made part of a defined state by calling useProgram
glLinkProgram(mProgram);
testProgramCompile();
//cleaning up the elements we already used
glDeleteShader(vs);
glDeleteShader(fs);
//clear the identifier lookup map(in this case, there's only one)
mUniformIdentifiers.clear();
return true;
}//end main
//Read the shaderFile. strngstream for reading multiple lines
string ShaderProgram:: readFile(const string& filename) {
std::stringstream strgstream;
std::ifstream file;
try
{
file.open(filename, std::ios::in);
if (!file.fail())
{
strgstream << file.rdbuf();
}
file.close();
}
catch (std::exception ex)
{
std::cerr << "Error: File or File Name Issues" << std::endl;
}
return strgstream.str();
}
//use the Program Object we created in this current state(color)
void ShaderProgram::use()
{
//check if it is not null
if (mProgram > 0)
glUseProgram(mProgram);
}
void ShaderProgram::dumpShaderLog(bool is_shader, GLuint obj)
{
int maxlen = 0;
if (is_shader) glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &maxlen);
else glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &maxlen);
if (maxlen > 0)
{
char *log = new char[maxlen];
int len;
if (is_shader) glGetShaderInfoLog(obj, maxlen, &len, log);
else glGetProgramInfoLog(obj, maxlen, &len, log);
if (len > 0 && log[0] != '\0')
fprintf(stderr, "%s\n", log);
delete[] log;
}
}
void ShaderProgram::testProgramCompile() {
int status = 0;
GLuint program = mProgram;
// ///CHECKING GL_LINK_STATUS to see if Program Link was successul. Link Status will return GL_TRUE if it was
glGetProgramiv( mProgram, GL_LINK_STATUS, &status); //requesting the status
if (status == GL_FALSE)
{
GLint length = 0;
glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &length);
string errorLog(length, ' '); // Resize and fill with space character
glGetProgramInfoLog(mProgram, length, &length, &errorLog[0]);
dumpShaderLog(false, mProgram);
std::cerr << "Linking Error with Program and Shader" << std::endl;
}
}
void ShaderProgram :: testShaderCompile(GLuint shader) {
int status = 0;
// ///CHECKING GL_LINK_STATUS to see if Program Link was successul. Link Status will return GL_TRUE if it was
glGetShaderiv (shader, GL_COMPILE_STATUS, &status);//requesting the status
if (status == GL_FALSE)
{
GLint length = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
string errorLog(length, ' '); // Resize and fill with space character
glGetShaderInfoLog(shader, length, &length, &errorLog[0]);
std::cerr << "SHADER COMPILE TEST ERROR " << std::endl;
}
}
////GETTERS AND SETTERS
GLuint ShaderProgram::getProgram() const
{
return mProgram;
}
void ShaderProgram::setUniform(const GLchar* name, const glm::vec2& v)
{
GLint address = getUniformIdentifier(name);
glUniform2f(address, v.x, v.y);
}
void ShaderProgram::setUniform(const GLchar* name, const glm::vec3& v)
{
GLint address = getUniformIdentifier(name);
glUniform3f(address, v.x, v.y, v.z);
}
void ShaderProgram:: setUniform(const GLchar* name, const glm::vec4& v) {
GLint address = getUniformIdentifier(name);
glUniform4f(address, v.x, v.y, v.z, v.w);
}
//Maybe need to switch places with setUniform
GLint ShaderProgram :: getUniformIdentifier(const GLchar* name) {
std::map<std::string, GLint>::iterator it;
it = mUniformIdentifiers.find(name);
//std::map<std::string, GLint>
// Only need to query the shader program IF it doesn't already exist.
if (it == mUniformIdentifiers.end())
{
// Find it and add it to the map
mUniformIdentifiers[name] = glGetUniformLocation(mProgram, name);
}
// Return it
return mUniformIdentifiers[name];
}
Primary Program
#include <iostream>
#include <vector>
#include <sstream>
#define GLEW_STATIC
//always GLEW before GLFW
#include "GL/glew.h"
#include "GLFW/glfw3.h"
#include "glm/glm.hpp"
#include "ShaderProgram.h"
#ifndef M_PI
# define M_PI 3.141592653
#endif
/////gLOBAL
GLFWwindow* w = NULL;
const int wWidth = 800;
const int wHeight = 600;
std::vector<glm::vec3> vertices;
std::vector<unsigned int> indices;
GLfloat Radius = 6;
GLfloat Stacks = 5;
GLfloat Slices = 5;
void key_callback(GLFWwindow *w, int key, int scancode, int action, int mode);
//update colors based on average framerate
void averageFPS(GLFWwindow* window);
//screen resizing
void glfw_onFramebufferSize(GLFWwindow* window, int width, int height);
bool initOpenGL();
static void error(int error, const char *desc)
{
fputs(desc, stderr);
}
//setting up values for keys
int main() {
//pointing to GLFW window
//GLFWwindow *w; //may want to initialize as null outside before main
if (!initOpenGL()) ///5IMPR
{
// An error occured
std::cerr << "GLFW not initialized" << std::endl;
return -1;
}
glfwSetErrorCallback(error);
///TEMP CIRCLE VERTICES
// Calc The Vertices
for (int i = 0; i <= Stacks; ++i) {
float V = i / (float)Stacks;
float phi = V * M_PI; //change to glm:: pi
// Loop Through Slices
for (int j = 0; j <= Slices; ++j) {
float U = j / (float)Slices;
float theta = U * (M_PI * 2);
// Calc The Vertex Positions
float x = cosf(theta) * sinf(phi);
float y = cosf(phi);
float z = sinf(theta) * sinf(phi);
// Push Back Vertex Data //push_back is a standard vector function which adds a parameter to the end of the vector
//std::vector<glm::vec3> vertices; //moved to global variables at top
vertices.push_back(glm::vec3(x, y, z) * Radius);
}
}
// Calc The Index Positions
for (int i = 0; i < Slices * Stacks + Slices; ++i) {
indices.push_back(i);
indices.push_back(i + Slices + 1);
indices.push_back(i + Slices);
indices.push_back(i + Slices + 1);
indices.push_back(i);
indices.push_back(i + 1);
}
////TEMP CIRCLE VERTICES END
// 2. Set up buffers on the GPU
GLuint vbo, ibo, vao; ///5IMPROVEdown
glGenBuffers(1, &vbo); // Generate an empty vertex buffer on the GPU
glBindBuffer(GL_ARRAY_BUFFER, vbo); // "bind" or set as the current buffer we are working with
//3rd argument of glBufferData needs a pointer to the std:vector data...A pointer to the data can be obtained by vertices.data() accrding to std: ector docs...
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), vertices.data(), GL_STATIC_DRAW);// copy the data from CPU to GPU
glGenVertexArrays(1, &vao); // Tell OpenGL to create new Vertex Array Object
glBindVertexArray(vao); // Make it the current one
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL); // Define a layout for the first vertex buffer "0"
glEnableVertexAttribArray(0); // Enable the first attribute or attribute "0"
// Set up index buffer
glGenBuffers(1, &ibo); // Create buffer space on the GPU for the index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW);
// glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); - REPLACED
glBindVertexArray(0); // unbind to make sure other code doesn't change it
ShaderProgram shaderProgram; ///5ADD
shaderProgram.assignShaders("shaders\\ColorShader.vert", "shaders\\ColorShader.frag"); ///5ADD
////////SETUP RENDERING
while (!glfwWindowShouldClose(w))
{
averageFPS(w);
//process events
glfwPollEvents();
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT);
shaderProgram.use(); ///5ADD
GLfloat time = (GLfloat)glfwGetTime(); ///5ADD
GLfloat blueSetting = (sin(time) / 2) + 0.5f; ///5ADD
glm::vec2 pos;
pos.x = sin(time) / 2;
pos.y = cos(time) / 2;
shaderProgram.setUniform("vertColor", glm::vec4(0.0f, 0.0f, blueSetting, 1.0f)); ///5ADD
shaderProgram.setUniform("posOffset", pos);
glBindVertexArray(vao);
//og for quad
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
//glDrawElements(GL_LINE_LOOP, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
// Swap buffers and look for events
glfwSwapBuffers(w);
}
//clean up
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
glDeleteBuffers(1, &ibo);
//glfwDestroyWindow(w);
glfwTerminate();
return 0;
}
///////START Initializing glfw glew etc
bool initOpenGL(){
//this method will exit on these conditions
GLuint error = glfwInit();
if (!error)
return false;
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
w = glfwCreateWindow(wWidth, wHeight, "Exercise", NULL, NULL);
if (w== NULL)
{
std::cerr << "glfw window not created" << std::endl;
glfwTerminate();
return false;
}
//update context
glfwMakeContextCurrent(w);
// Initialize GLEWunifor
glewExperimental = GL_TRUE;
GLuint err = glewInit();
if (err != GLEW_OK)
{
std::cerr << "initialize GLEW Failed" << std::endl;
return false;
}
//setup key callbacks
glfwSetKeyCallback(w, key_callback);
glfwSetFramebufferSizeCallback(w, glfw_onFramebufferSize);
glClearColor(0.23f, 0.38f, 0.47f, 1.0f); ///5ADD
// Define the viewport dimensions
glViewport(0, 0, wWidth, wHeight); //necessary?
return true;
}
void key_callback(GLFWwindow *w, int key, int scancode, int action, int mode)
{
// See http://www.glfw.org/docs/latest/group__keys.html
if ((key == GLFW_KEY_ESCAPE || key == GLFW_KEY_Q) && action == GLFW_PRESS)
glfwSetWindowShouldClose(w, GL_TRUE);
if (key == GLFW_KEY_W && action == GLFW_PRESS)
{
bool showWires = false;
if (showWires)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
else
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
}
//whever window resizes, do this
void glfw_onFramebufferSize(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
void averageFPS(GLFWwindow* window) ///5ADDdown
{
static double previousSeconds = 0.0;
static int frameCount = 0;
double passedSeconds;
double currentSeconds = glfwGetTime(); //seconds since GLFW started
passedSeconds = currentSeconds - previousSeconds;
// Limit time updates to 4 times per second
if (passedSeconds > 0.25)
{
previousSeconds = currentSeconds;
double fps = (double)frameCount / passedSeconds;
// double frameInMilSecs = 1000.0 / fps;
frameCount = 0;}
frameCount++;
}
While glGetShaderiv returns a parameter from a shader object, glGetProgramiv returns a parameter from a program object.
This means you have to change your code like this:
// glGetProgramiv(shader, GL_COMPILE_STATUS, &status); <--- delete
glGetShaderiv (shader, GL_COMPILE_STATUS, &status);
Ensure that the shader files are correctly loaded and trace them for debug reasons:
glShaderSource(vs, 1, &vsSourcePtr, NULL);
glShaderSource(fs, 1, &fsSourcePtr, NULL);
std::cout << "VERTEX SHADER:" << std::endl << vsSourcePtr << std::endl << std::endl;
glCompileShader(vs);
testShaderCompile(vs);
std::cout << "FRAGMENT SHADER:" << std::endl << fsSourcePtr << std::endl << std::endl;
glCompileShader(fs);
testShaderCompile(fs);
Since you don't set any matrices, you have to set up all the vertex coordinates in normalized device space, which is in [-1.0, 1.0].
To make the mesh proper "visible" on the viewport set the radius of the sphere to 0.5:
GLfloat Radius = 0.5f;
and draw all the primitives:
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
I'm beggining at modern OpenGL.
But I am front of a strange memory leak with VBO and VAO.
Here is my code ( the important part ) :
#include "OpenGlScene.h"
#include "Block.h"
#include <iostream>
#include "Shader.h"
#include "Camera2D.h"
#include "Input.h"
#include "Container.h"
#include "Texture.h"
OpenGlScene::OpenGlScene(void) {
this->width = 1280;
this->height = 720;
this->initWindow();
this->initOpenGl();
this->loop();
}
OpenGlScene::~OpenGlScene(void)
{
}
void OpenGlScene::loop() {
bool mustFinish = false;
unsigned int frameRate = ( 1000 / 60 );
int startTime, endTime, elapsedTime = 0;
Container* cContainer = new Container();
Input *iInput = new Input();
cContainer->setInput(iInput);
iInput->setContainer(cContainer);
Camera2D *cCamera = new Camera2D();
cContainer->setCamera(cCamera);
cCamera->setContainer(cContainer);
cCamera->init(this->width, this->height);
glm::mat4 cameraMatrix;
Block *bBlock = new Block(0,0);
bBlock->setContainer(cContainer);
bBlock->init();
Block *aBlock = new Block(-100, -100);
aBlock->setContainer(cContainer);
aBlock->init();
Block *cBlock = new Block(-200, -100);
cBlock->setContainer(cContainer);
cBlock->init();
//bBlock->load();
while(!mustFinish) {
startTime = SDL_GetTicks();
cCamera->update();
iInput->update();
bBlock->update();
cameraMatrix = cCamera->getCameraMatrix();
bBlock->render();
aBlock->render();
cBlock->render();
SDL_GL_SwapWindow(this->Window);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ;
glClearColor(119/255.0f,181/255.0f,254/255.0f,1);
endTime = SDL_GetTicks();
elapsedTime = endTime - startTime;
if(elapsedTime < frameRate) {
SDL_Delay(frameRate - elapsedTime);
}
}
}
bool OpenGlScene::initOpenGl() {
GLenum glewInit( glewInit() );
if(glewInit != GLEW_OK)
{
std::cout << "Erreur d'initialisation de GLEW : " << glewGetErrorString(glewInit) << std::endl;
SDL_GL_DeleteContext(this->OpenGlContext);
SDL_DestroyWindow(this->Window);
SDL_Quit();
return false;
}
glEnable(GL_DEPTH_TEST);
return true;
}
bool OpenGlScene::initWindow() {
if(SDL_Init(SDL_INIT_VIDEO) < 0)
{
std::cout << "Erreur lors de l'initialisation de la SDL : " << SDL_GetError() << std::endl;
SDL_Quit();
return false;
}
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
this->Window = SDL_CreateWindow("OpenGL Scene", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, this->width, this->height, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);
if(this->Window == 0) {
std::cout << "Erreur lors de la creation de la fenetre : " << SDL_GetError() << std::endl;
SDL_Quit();
return false;
}
SDL_GLContext context = SDL_GL_CreateContext(this->Window);
this->OpenGlContext = &context;
if((*this->OpenGlContext) == 0) {
std::cout << SDL_GetError() << std::endl;
SDL_DestroyWindow(this->Window);
SDL_Quit();
return false;
}
return true;
}
The leak comes from the loop method inside the while.
It mostly comes from when I render Blocks.
#include "Block.h"
Block::Block(float x, float y){
this->time = 0.0f;
this->x = x;
this->y = y;
this->size = 200.0f;
this->sSprite = nullptr;
}
Block::~Block(void){
if(this->sSprite) {
delete this->sSprite;
}
}
void Block::init() {
this->sSprite = new SpriteRect(x, y, size, size, "textures/grass.png", 1.0f, 1.0f, 1.0f, 1.0f);
this->sSprite->setContainer(this->cContainer);
this->sSprite->load();
}
void Block::update() {
this->time += 0.5f;
this->x += 0.5f;
//this->sSprite->update(this->x, this->y);
}
void Block::render() {
this->sSprite->render();
}
And the most important, SpriteRect.cpp :
#include "SpriteRect.h"
#include <string>
#include "Texture.h"
#include "Shader.h"
#include "Container.h"
#include "Camera2D.h"
SpriteRect::SpriteRect(float x, float y, float width, float height, std::string textureFile, float r, float g, float b, float a) {
this->x = x;
this->y = y;
this->width = width;
this->height = height;
this->vaoId = 0;
this->vboId = 0;
this->tTexture = new Texture(textureFile);
this->tTexture->load();
this->cColor = new Color();
this->cColor->a = a;
this->cColor->r = r;
this->cColor->g = g;
this->cColor->b = b;
float textureCoordsTmp[] = {0.0f, 1, 1,1, 0.0f,0.0f,
0.0f,0.0f, 1,1, 1,0.0f};
float colorCoordsTmp[] = {this->cColor->r,this->cColor->g,this->cColor->b,this->cColor->a, this->cColor->r,this->cColor->g,this->cColor->b,this->cColor->a, this->cColor->r,this->cColor->g,this->cColor->b,this->cColor->a,
this->cColor->r,this->cColor->g,this->cColor->b,this->cColor->a, this->cColor->r,this->cColor->g,this->cColor->b,this->cColor->a, this->cColor->r,this->cColor->g,this->cColor->b,this->cColor->a};
for(int i = 0; i<12; i++) {
this->textureCoords[i] = textureCoordsTmp[i];
}
for(int i= 0; i<24;i++) {
this->colors[i] = colorCoordsTmp[i];
}
this->setVerticesFromCoords();
this->colorsSizeBytes = (24*sizeof(float));
this->textureCoordsSizeBytes = (12*sizeof(float));
this->verticesSizeBytes = (12*sizeof(float));
this->sShader = new Shader("Shaders/classic2D.vert", "Shaders/classic2D.frag");
this->sShader->charger();
}
SpriteRect::~SpriteRect() {
delete this->tTexture;
delete this->cColor;
delete this->sShader;
glDeleteBuffers(1, &vboId);
glDeleteVertexArrays(1, &vaoId);
}
void SpriteRect::setVerticesFromCoords() {
float verticesTmp[] = {x, y, x+width, y, x, y+height,
x, y+height, x+width, y, x+width, y+height};
for(int i=0;i<12;i++) {
this->vertices[i] = verticesTmp[i];
}
if(glIsBuffer(vboId) == GL_TRUE) {
this->updateVbo(this->vertices, 12*sizeof(float), 0);
}
}
void SpriteRect::load() {
if(glIsBuffer(vboId) == GL_TRUE) {
glDeleteBuffers(1, &vboId);
}
glGenBuffers(1, &vboId);
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, (this->verticesSizeBytes + this->colorsSizeBytes + this->textureCoordsSizeBytes), 0, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, this->verticesSizeBytes, this->vertices);
glBufferSubData(GL_ARRAY_BUFFER, this->verticesSizeBytes, this->colorsSizeBytes, this->colors);
glBufferSubData(GL_ARRAY_BUFFER, this->verticesSizeBytes+this->colorsSizeBytes, this->textureCoordsSizeBytes, this->textureCoords);
glBindBuffer(GL_ARRAY_BUFFER, 0);
if(glIsVertexArray(vaoId)) {
glDeleteVertexArrays(1, &vaoId);
}
glGenVertexArrays(1, &vaoId);
glBindVertexArray(vaoId);
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(this->verticesSizeBytes));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(this->verticesSizeBytes+this->colorsSizeBytes));
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void SpriteRect::update(float x, float y) {
if(x != this->x || y != this->y) {
this->x = x;
this->y = y;
this->setVerticesFromCoords();
}
this->update();
}
void SpriteRect::update() {
}
void SpriteRect::updateVbo(void *datas, int sizeBytes, int offset)
{
// Verrouillage du VBO
glBindBuffer(GL_ARRAY_BUFFER,vboId);
// Récupération de l'adresse du VBO
void *vboAdress = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
// Si l'adresse retournée est nulle alors on arrête le transfert
if(vboAdress == NULL)
{
std::cout << "Erreur au niveau de la récupération du VBO" << std::endl;
glBindBuffer(GL_ARRAY_BUFFER, 0);
return;
}
// Mise à jour des données
memcpy((char*)vboAdress + offset, datas, sizeBytes);
// Annulation du pointeur
glUnmapBuffer(GL_ARRAY_BUFFER);
vboAdress = 0;
// Déverrouillage du VBO
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void SpriteRect::render() {
glUseProgram(this->sShader->getProgramID());
glBindVertexArray(vaoId);
glUniformMatrix4fv(glGetUniformLocation(this->sShader->getProgramID(), "cameraMatrix"), 1, GL_FALSE, glm::value_ptr(this->cContainer->getCamera()->getCameraMatrix()));
glBindTexture(GL_TEXTURE_2D, this->tTexture->getId());
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindTexture(GL_TEXTURE_2D, 0);
glBindVertexArray(0);
glUseProgram(0);
}
Then when I comment out the [BlockObject]->render(); There is no more leak.
Actually the leak is about 30Kb/sec. I saw that when using updateVbo() method of SpriteRect there is a leak to.
Sorry comments are french but the code is easy ;)
Any ideas ?
For every new you do, there must be a corresponding delete. Your loop method does a lot of new into local variables, but no single delete.