AlGrande
AlGrande

Reputation: 187

C++ OpenGL memory leak

First of all, I'm a beginner in c++. I'm writing my own game engine. Code is below.

Sprite.cpp

#include "Sprite.h"


Sprite::Sprite(GLfloat x, GLfloat y, GLfloat width, GLfloat height, Shader& shader, char *texturePath)
{
    init(x, y, width, height, shader, texturePath, STBI_rgb_alpha);
}

Sprite::Sprite(GLfloat x, GLfloat y, GLfloat width, GLfloat height, Shader& shader, char *texturePath, int reg_comp)
{
    init(x, y, width, height, shader, texturePath, reg_comp);
}
void Sprite::init(GLfloat x, GLfloat y, GLfloat width, GLfloat height, Shader& shader, char *texturePath, int reg_comp)
{
    this->shader = &shader;
    GLfloat vertices[] = {
        width/2+x,  height/2+y, 0.0f,  /* Top Right */                  1.0f, 1.0f,
        width/2 + x, -height / 2 + y, 0.0f,  /* Bottom Right*/          1.0f, 0.0f,
        -width/2 + x, -height / 2 + y, 0.0f,  /* Bottom Left*/          0.0f, 0.0f,
        -width / 2 + x,  height / 2 + y, 0.0f,   /* Top Left */         0.0f, 1.0f
    };
    GLuint indices[] = {
        0, 1, 3,  // 1
        1, 2, 3   // 2
    };
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    //Position
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    // TexCoord
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
    texture = new Texture(texturePath, reg_comp);
    transformShaderLocation = glGetUniformLocation(shader.program, "transform");
    glProgramUniform4fv(shader.program, transformShaderLocation, 1, transform);

}


Sprite::~Sprite()
{
    delete texture;
}


void Sprite::Draw() {
    glBindTexture(GL_TEXTURE_2D, texture->texture); //?
    //glUniform1i(glGetUniformLocation(shader->program, "ourTexture"), 0); //?
    shader->Use();
    glBindVertexArray(VAO);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
}


void Sprite::Transform(int x, int y) {
    glProgramUniform4fv(shader->program, transformShaderLocation, 1, transform);
}

void Sprite::setTexture(Texture *texture) {
    delete this->texture;
    this->texture = texture;
}

Sprite.h

#pragma once
#include <GL/glew.h>
#include "Shader.h"
#include <glm/glm.hpp>
#include "Texture.h"
#include <stb_image.h>



class Sprite
{
public:
    Sprite(GLfloat x, GLfloat y, GLfloat width, GLfloat height, Shader& shader, char *texturePath);
    Sprite(GLfloat x, GLfloat y, GLfloat width, GLfloat height, Shader& shader, char *texturePath, int reg_comp);

    ~Sprite();
    void Draw();
    void Transform(int x, int y);
    void setTexture(Texture *texture);

private:
    void init(GLfloat x, GLfloat y, GLfloat width, GLfloat height, Shader& shader, char *texturePath, int reg_comp);
    GLuint VBO = 0, VAO = 0, EBO = 0;
    GLint transformShaderLocation;
    Shader* shader;
    GLfloat transform[4] = {
        1.f, 1.f, 1.f, 1.f
    };
    Texture *texture;

};

Texture.cpp

#include "Texture.h"


Texture::Texture(char *texturePath, int reg_comp)
{
    glGenTextures(1, &texture);

    int _width, _height, _ImageComponents;

    unsigned char *image = stbi_load(texturePath, &_width, &_height, &_ImageComponents, reg_comp);
    if (image == nullptr) {
        std::cout << "error loading image" << std::endl;
    }


    glBindTexture(GL_TEXTURE_2D, texture);


    // Set our texture parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);   
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    // Set texture filtering
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _width, _height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);

    if (_ImageComponents == 3)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _width, _height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
    else if (_ImageComponents == 4)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _width, _height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); //RGBA8?


    glGenerateMipmap(GL_TEXTURE_2D);

    glBindTexture(GL_TEXTURE_2D, 0);
    stbi_image_free(image);
}


Texture::~Texture()
{
}

Texture.h

#pragma once
#include <GL/glew.h>
#include <iostream>
#include <stb_image.h>


class Texture
{
public:
    Texture(char *texturePath, int reg_comp);
    ~Texture();
    GLuint texture = 0;
};

main.cpp

#include "main.h"
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>




int main(int argc, char* argv[]) {
    Main main;
    return main.init();
}
int Main::init() {

    display = new Display( 800, 600, "OpenGL" );
    shader = new Shader("Shaders/default.vert", "Shaders/default.frag");

    sprite = new Sprite(-0.5f, -0.5f, 1.0f, 1.0f, *shader, "Textures/texture1.png");
    sprite2 = new Sprite(0.5f, 0.5f, 1.0f, 1.0f, *shader, "Textures/texture2.png", STBI_rgb);



    while (!display->isClosed()) {
        update();
    }
    delete display;
    delete shader;
    delete sprite;
    delete sprite2;
    return 0;
}

void Main::update() {

    draw();
    display->Update();

    if (debug == 0) {
        texture->setTexture(new Texture("Textures/texture1.png", STBI_rgb_alpha));
        debug = 1;
    }
    else if (debug == 1) {
        texture->setTexture(new Texture("Textures/texture2.png", STBI_rgb));
        debug = 0;
    }

}

void Main::draw() {
    glClearColor(0.0f, 0.3f, 0.5f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);;
    sprite->Draw();
    sprite->Draw();
}

main.h:

#pragma once
#include <iostream>
#include "Display.h"
#include "Shader.h"
#include "Triangle.h"
#include "Sprite.h"



class Main {
public:
    int init();

private:
    void draw();
    void update();
    Display *display;
    Shader *shader;
    Triangle *triangle, *triangle2;
    Sprite *sprite, *sprite2;
    int debug = 0;
};

You see, everytime a new texture is created, the last texture is deleted. However, if I open the task manager the memory usage goes up and up. Why is that so? (If I remove setTexture(new...) everything is fine, so this is the problem.

Upvotes: 0

Views: 4485

Answers (2)

OutOfBound
OutOfBound

Reputation: 2004

When I am programming OpenGL stuff, i now use wrapper around all handles. If you use GLuint it is very likely to forget some setup or deletion code. Depending on your coding skills, these wrappers can be very generic or you can use the shared pointer for this purpose.

Upvotes: 1

datenwolf
datenwolf

Reputation: 162164

Where are your glDelete… calls? (glDeleteTextures, glDeleteBuffers). Deallocating your class instances with the delete operator will not magically do the proper deletion steps with OpenGL unless you do it explicitly in the destructor.

Upvotes: 6

Related Questions