0
votes

On my windows computer using opengl 4.5 and I cannot seem to get my texture to appear on screen. All I receive is a black screen. For my code, I first developed a small Vector class to house all vertex attribute information:

Vector3D.h

struct Position
{
    Position();
    Position(float x, float y, float z);
    float x;
    float y;
    float z;
};

Position::Position()
{}

Position::Position(float x, float y, float z) :
    x(x), y(y), z(z)
{}

struct Color
{
    GLubyte r;
    GLubyte g;
    GLubyte b;
    GLubyte a;
};

struct TextureCoordinate
{
    float u;
    float v;
};

struct Vector3D
{
    Vector3D();
    Vector3D(float x, float y, float z);

    Position position;
    Color color;
    TextureCoordinate textCoordinate;

    void setUV(float u, float v);
};

Vector3D::Vector3D()
{}

Vector3D::Vector3D(float x, float y, float z) :
    position(x, y, z)
{}

void Vector3D::setUV(float u, float v)
{
    this->textCoordinate.u = u;
    this->textCoordinate.v = v;
}

I then have a sprite class, through which I Initialize vertex attributes using Init() function:

Sprite.cpp

void Sprite::Init(float x, float y, float width, float height)
{
    this->x = x;
    this->y = y;
    this->width = width;
    this->height = height;

    if (vboID == 0)
        glGenBuffers(1, &vboID);

    Vector3D vertexData[6]{
        Vector3D {x + width, y + height, 1.0f},
        Vector3D {x, y + height, 1.0f },
        Vector3D {x, y, 1.0f},
        Vector3D {x, y, 1.0f},
        Vector3D {x + width, y, 1.0f},
        Vector3D {x + width, y + height, 1.0f},
    };

    for (int i = 0; i < 6; ++i)
    {
        vertexData[i].color.r = 0;
        vertexData[i].color.g = 155;
        vertexData[i].color.b = 200;
    };

    vertexData[0].setUV(1.0f, 1.0f);
    vertexData[1].setUV(0.0f, 1.0f);
    vertexData[2].setUV(0.0f, 0.0f);
    vertexData[3].setUV(0.0f, 0.0f);
    vertexData[4].setUV(1.0f, 0.0f);
    vertexData[5].setUV(1.0f, 1.0f);

    glBindBuffer(GL_ARRAY_BUFFER, vboID);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

I then have the draw function in sprite class which obviously rebinds to correct VBO and draws image:

Sprite.cpp

void Sprite::Draw()
{
    glBindBuffer(GL_ARRAY_BUFFER, 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, textCoordinate));

    glDrawArrays(GL_TRIANGLES, 0, 6);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

Finally, I call everything above within my main function here (I'm also using SDL and the image loading library stb):

main.cpp

int main(int agrc, char** argv)
{
    window.Initialize();
    playerSprite.Init(-1.0f, -1.0f, 1.0f, 1.0f);

    GameState gamestate{ GameState::PLAY };

    SDL_Event evnt;

    int32 x, y, currentChannels;
    int32 forceChannels = 4;
    uchar8* imageData = 0;
    imageData = stbi_load("CharImage.png", &x, &y, &currentChannels, forceChannels);

    if (imageData == nullptr)
    {
        LOG("ERROR: Could not load image file!");
    };

    GLuint texture;
    glGenTextures(1, &texture);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
    glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);


    Blz::OpenGL::ShaderProgram colorShaderProgram;
    colorShaderProgram.Compile();
    colorShaderProgram.Link();
    colorShaderProgram.Bind();

    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);

    while (gamestate != GameState::EXIT)
    {
        unsigned int startTime = SDL_GetTicks();

        //Game Logic Update
        while (SDL_PollEvent(&evnt))
        {
            switch (evnt.type)
            {
            case SDL_QUIT:
                gamestate = GameState::EXIT;

            default:
                break;
            }
        }

        window.ClearBuffers();

        playerSprite.Draw();

        window.SwapBuffers();
    }

    return 0;
}

Also, here are my shaders:

Vertex Shader

#version 430

layout(location=0) in vec3 vertexPosition;
layout(location=1) in vec2 textCoord;

out vec2 TextureCoord;

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

Fragment Shader

#version 430

out vec4 daColor;
in vec2 TextureCoord;

uniform sampler2D basicTexture;

void main()
{
    vec4 texel = texture(basicTexture, TextureCoord);
    daColor = texel;
};
1
Review that wrong number sizeof(vertexData)used at glBufferData(). It must be the size in bytes of data passed to glBufferData. - Ripi2
While sizeof(vertexData) returns 144 which is the number of bytes within the array correct? - Jason
144 is the size of the struct, not the whole array of data. GL knows nothing about your structures, glBufferData gets only bytes. It's up to you to compute the sizes depending on your data layout. Also, in the same matter, review how to you read buffers (glVertexAttribPointer) - Ripi2
@Ripi2 struct Vector3D has 6 floats which gives 6*4 = 24 bytes of length. Using a vector of 6 elements, we have a total of 144 bytes - Amadeus
Well I will say that previously I had sent down my vertex positions with color color data to opengl using the same code above and got a square to appear with the correct color displaying. That makes me think glbufferdata and glvertexattribpointer were setup correctly? - Jason

1 Answers

-1
votes

Its times like these that I wish there was a better alternative to cross platform graphics programming as openGL really is a mess. The reason my image wasn't showing up was because I was setting my parameters with:

glTextureParameteri()

instead of the apparently correct:

glTexParameteri()

..................