c++opengltexturestexturing

Unable to render a texture on a quad


I am trying to program a simple game in C++ using OpenGL for graphics. In my game, I have objects that are rendered onscreen as a white square. I would like to be able to bind an image as a texture to these objects, so that I can render an image onscreen instead of the white square. There's no restriction on the format of the image, though I've been using .png or .bmp for testing.

One of my object classes, Character.h, stores a GLuint* member variable called _texture and an unsigned char* member variable called _data (as an image handle and pixel data, respectively). Within Character.h is this function meant to bind the image as a texture to the Character object:

void loadTexture(const char* fileName)
    {
        /* read pixel data */
        FILE* file;
        file = fopen(fileName, "rb");
        if (file == NULL) {cout << "ERROR: Image file not found!" << endl;}
        _data = (unsigned char*)malloc(_dimension * _dimension * 3);
        fread(_data, _dimension * _dimension * 3, 1, file);
        fclose(file);
        /* bind texture */
        glGenTextures(1, &_texture); // _texture is a member variable of type GLuint
        glBindTexture(GL_TEXTURE_2D, _texture);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _dimension, _dimension, 0, GL_RGB, GL_UNSIGNED_BYTE, _data); // _dimension = 64.0f.
    }

Once the image is bound, I then attempt to render the Character object with this function (which is a static function found in a separate class):

static void drawTexturedRectangle(float x, float y, float w, float h, GLuint texture, unsigned char* data)
    {
        /* fractions are calculated to determine the position onscreen that the object is drawn at */
        float xFraction = (x / GlobalConstants::SCREEN_WIDTH) * 2;
        float yFraction = (y / GlobalConstants::SCREEN_HEIGHT) * 2;
        float wFraction = (w / GlobalConstants::SCREEN_WIDTH) * 2;
        float hFraction = (h / GlobalConstants::SCREEN_HEIGHT) * 2;
        glEnable(GL_TEXTURE_2D);
        glClear(GL_COLOR_BUFFER_BIT);
        glBindTexture(GL_TEXTURE_2D, texture);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
        glPushMatrix();
        glEnable(GL_BLEND);
        glBegin(GL_QUADS);
        glTexCoord2f(0.0f, 0.0f); glVertex2f(xFraction, yFraction); // bottom left corner
        glTexCoord2f(0.0f, 1.0f); glVertex2f(xFraction, yFraction + hFraction); // top left corner
        glTexCoord2f(1.0f, 1.0f); glVertex2f(xFraction + wFraction, yFraction + hFraction); // top right corner
        glTexCoord2f(1.0f, 0.0f); glVertex2f(xFraction + wFraction, yFraction); // bottom right corner
        glEnd();
        glDisable(GL_BLEND);
        glPopMatrix();
    }

No matter how much I mess around with this, I cannot seem to get my program to do anything other than render a plain white square with no texture on it. I have checked to ensure that variables file, _texture, _dimension, and _data all contain values. Can anybody spot what I might be doing wrong?


Solution

  • i dont think you can just input a raw file to glTexImage2D, except if you store texture files in that format (which you probably dont). glTexImage2D expects a huge array bytes (representing texel colors), but file formats typically dont store images like that. Even bmp has some header information in it.

    Use a 3rd party image loader library like DevIL or SOIL to load your textures! These libraries can convert most common image file formats (png, jpg, tga, ...) into a byte stream that you can input to OpenGL!

    On a side note: After you call glTexImage2D(..., data), the content of data is copied into the GPU memory (VRAM). From this point you only have to bind the texture using it's id, as it is already in the VRAM. Calling glTexImage2D() in each frame will reupload the whole texture in each frame into the vram, causing a big performance penalty.