Search code examples
c++openglgraphics2d

opengl 2d game only drawing second sprite texture and not first


I'm currently creating a 2d fighting game utilizing OpenGL and I have run into a problem where OpenGL is only drawing at my last initialized sprite position, regardless of how many sprites I initialize and try and draw. Even when I initialize a sprite1 and sprite2 but only draw sprite1, sprite is what will still be drawn. It starts with my sprite class where I initialize where on the screen I want my image as well as what image to use:

Sprite.cpp

 Init(int screenCoordinateX, int screenCoordinateY, uint imageWidth, unsigned int imageHeight, std::string imageFilePath)
{
    //casting to float since GLSL shader variables vec2,3,4 require vertex data to be in floats
    this->x = static_cast<float>(x);
    this->y = static_cast<float>(y);
    this->width = static_cast<float>(width);
    this->height = static_cast<float>(height);

    glGenBuffers(1, &vboID);

    Blz::Graphics::GLTexture texture(imageFilePath);
    this->texture = texture;

    float halfWidth = this->width / 2;

    //Setting sprite origin at bottom middle of image by subtracting half width 
    this->vertexData.at(0).SetPosition(glm::vec3{ this->x + (this->width - halfWidth), this->y + this->height, 0.0f });//Top right corner
    this->vertexData.at(1).SetPosition(glm::vec3{ this->x - halfWidth, this->y + height, 0.0f });//Top left corner
    this->vertexData.at(2).SetPosition(glm::vec3{ this->x - halfWidth, this->y, 0.0f });//Bottom left corner
    this->vertexData.at(3).SetPosition(glm::vec3{ this->x - halfWidth, this->y, 0.0f });//Bottom left corner
    this->vertexData.at(4).SetPosition(glm::vec3{ this->x + (this->width - halfWidth), this->y, 0.0f });//Bottom right corner
    this->vertexData.at(5).SetPosition(glm::vec3{ this->x + (this->width - halfWidth), this->y + this->height, 0.0f });//Top right corner

    this->vertexData.at(0).SetUV(glm::vec2{ 1.0f, 1.0f });
    this->vertexData.at(1).SetUV(glm::vec2{ 0.0f, 1.0f });
    this->vertexData.at(2).SetUV(glm::vec2{ 0.0f, 0.0f });
    this->vertexData.at(3).SetUV(glm::vec2{ 0.0f, 0.0f });
    this->vertexData.at(4).SetUV(glm::vec2{ 1.0f, 0.0f });
    this->vertexData.at(5).SetUV(glm::vec2{ 1.0f, 1.0f });

    glBindBuffer(GL_ARRAY_BUFFER, vboID);
    glBufferData(GL_ARRAY_BUFFER, (sizeof(Vector3D) * this->vertexData.size()), &this->vertexData.front(), GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3D), (void*)offsetof(Vector3D, position));
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vector3D), (void*)offsetof(Vector3D, textureCoordinates));

    //Unbind 
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

I then try and render sprites passed in to renderer like so:

Renderer.cpp

void Renderer::Draw(Sprite& sprite)
{
    glm::mat4 orthoProjection = glm::ortho(0.0f, static_cast<sfloat>(1024), 0.0f, static_cast<sfloat>(768));
    GLuint transformationMatrixUniformLocation = this->shaderProgram.GetUniformLocation("transformationMatrix");

    glUniformMatrix4fv(transformationMatrixUniformLocation, 1, GL_FALSE, &(orthoProjection[0][0]));

    glBindTexture(GL_TEXTURE_2D, sprite.texture.id);
    glBindBuffer(GL_ARRAY_BUFFER, sprite.vboID);

    glDrawArrays(GL_TRIANGLES, 0, 6);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

I here is my main.cpp where I begin to call everything:

int main() 
{
    Blz::Graphics::Renderer renderer;
    Blz::Window window;
    Blz::Input input;
    Scene scene;

    window.Initialize();
    renderer.Init();

    Sprite sprite1;
    sprite.Init(900, 300, 200, 200, "CharImage.png");

    Sprite sprite2;
    sprite2.Init(100, 100, 200, 200, "CharImage.png");

    while (!input.IsKeyPressed(SDLK_ESCAPE))
    {
        window.ClearBuffers();

        renderer.Draw(sprite1);

        window.SwapBuffers();
    }

    return 0;
}

So even though I ask for sprite1 to be drawn, only sprite2's position at 100x 100y gets drawn to the screen. Even if I manually try and enter a vboID of 1 (which is the vboID of sprite1) within renderer.cpp, it still draws sprite2's position. What am I doing wrong?

Here are my Shaders if necessary:

VertexShader.glsl

#version 430

in vec3 vertexPosition;
in vec2 textCoord;

out vec2 TextureCoord;

uniform mat4 transformationMatrix;

void main()
{
    vec4 position = vec4(vertexPosition, 1.0f);
    gl_Position = transformationMatrix * position;
    TextureCoord = textCoord;
};

FragmentShader.glsl

#version 430

out vec4 daColor;
in vec2 TextureCoord;

uniform sampler2D basicTexture;

void main()
{
    vec4 texel = texture(basicTexture, TextureCoord);
    daColor = texel;
};

Solution

  • So I guess this is a lesson for anyone aspiring to learn and use OpenGL. Anytime you are using VBOs and vbo ids to bind an OpenGL buffer to you also need to again specify your vertexattribpointers before drawing. So my new renderer.cpp file looks like this:

    void Renderer::Draw(Sprite& sprite)
    {
        glm::mat4 orthoProjection = glm::ortho(0.0f, static_cast<sfloat>(1024), 0.0f, static_cast<sfloat>(768));
        GLuint transformationMatrixUniformLocation = this->shaderProgram.GetUniformLocation("transformationMatrix");
    
        glUniformMatrix4fv(transformationMatrixUniformLocation, 1, GL_FALSE, &(orthoProjection[0][0]));
    
        glBindTexture(GL_TEXTURE_2D, sprite.texture.id);
        glBindBuffer(GL_ARRAY_BUFFER, sprite.vboID);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3D), (void*)offsetof(Vector3D, position));
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vector3D), (void*)offsetof(Vector3D, textureCoordinates));
    
        glDrawArrays(GL_TRIANGLES, 0, 6);
    
        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }
    

    This other SO answer gives a reason as to why: is VertexAttribPointer needed after each BindBuffer?. To avoid this, you would use the newer VAO's which store vertex attribute info so you don't have to specify vertexattribpointer functions everytime.