Search code examples
c++openglgluttexture-mappingfreeglut

Mapping a texture in OpenGL


I am trying to map a texture to a simple quad for the first time, but all it won't render. I am using freeglut for the implementation, and the stb_image.h header to load the texture. The code:

#include <GL/glut.h>   
#include <stb_image.h>
#include <iostream>
int ww = 500, wh = 500;

void display()
{
    glClearColor(1.0, 1.0, 0.7, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_QUADS);
    glEnable(GL_TEXTURE_2D);
    glTexCoord2f(0.0, 0.0); glVertex3f(10,10,0);
    glTexCoord2f(0.0, 1.0); glVertex3f(10,wh-10,0);
    glTexCoord2f(1.0, 1.0); glVertex3f(ww-10,wh,0);
    glTexCoord2f(1.0, 0.0); glVertex3f(ww-10,10,0);
    glDisable(GL_TEXTURE_2D);
    glEnd();
    glFlush();
}


void myinit()
{   
    glViewport(0, 0, ww, wh);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0, (GLdouble)ww, 0.0, (GLdouble)wh);
    glMatrixMode(GL_MODELVIEW);

    unsigned int texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    int width, height, nrChannels;
    unsigned char* data = stbi_load("container.jpg", &width, &height, &nrChannels, 0);
    if (data)
    {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
    }
    else
    {
        std::cout << "Failed to load texture" << std::endl;
    }
    stbi_image_free(data);
}
int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
    glutInitWindowSize(ww, wh);
    glutCreateWindow("texture-try");
    glutDisplayFunc(display);
    myinit();
    glutMainLoop();
    return 0;
}

It successfully loads the texture, but the quad appears just white. What am I missing?

Edit:

I moved the glBegin(GL_QUADS); and glEnd(); inside the glEnable(GL_TEXTURE_2D); and glDisable(GL_TEXTURE_2D); commands as was suggested, but it still won't render the texture.

I also checked the glGetError command, but it returns GL_NO_ERROR.


Solution

  • Several things:

    • The aforementioned "don't use prohibited functions within a glBegin()/glEnd() pair" issue; as of posting this hasn't been fixed in the question code.
    • GL_LINEAR_MIPMAP_LINEAR is being used without providing any mipmaps. Drop to GL_LINEAR or provide some mipmaps.
    • Pass 3 to stbi_load()'s desired_channels parameter (instead of the current 0) to guarantee you get 3-channel image data instead of just assuming nrChannels is 3 for all input images.
    • Using GL_RGB with the default GL_UNPACK_ALIGNMENT of 4 can result in wonky display if your image width isn't a nice multiple of 4 so drop that down to 1 via glPixelStorei(GL_UNPACK_ALIGNMENT, 1) before calling glTexImage2D().
    • Switch to GLUT_DOUBLE & glutSwapBuffers() instead of using GLUT_SINGLE and glFlush().

    All together:

    #include <GL/glut.h>   
    #define STB_IMAGE_IMPLEMENTATION
    #include <stb_image.h>
    #include <iostream>
    int ww = 500, wh = 500;
    
    void display()
    {
        glClearColor(1.0, 1.0, 0.7, 1.0);
        glClear(GL_COLOR_BUFFER_BIT);
        glEnable(GL_TEXTURE_2D);
        glBegin(GL_QUADS);
        glTexCoord2f(0.0, 0.0); glVertex3f(10,10,0);
        glTexCoord2f(0.0, 1.0); glVertex3f(10,wh-10,0);
        glTexCoord2f(1.0, 1.0); glVertex3f(ww-10,wh,0);
        glTexCoord2f(1.0, 0.0); glVertex3f(ww-10,10,0);
        glEnd();
        glDisable(GL_TEXTURE_2D);
        glutSwapBuffers();
    }
    
    
    void myinit()
    {   
        glViewport(0, 0, ww, wh);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluOrtho2D(0.0, (GLdouble)ww, 0.0, (GLdouble)wh);
        glMatrixMode(GL_MODELVIEW);
    
        unsigned int texture;
        glGenTextures(1, &texture);
        glBindTexture(GL_TEXTURE_2D, texture);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        int width, height, nrChannels;
        // https://commons.wikimedia.org/wiki/File:Container.JPG
        unsigned char* data = stbi_load("container.jpg", &width, &height, &nrChannels, 3);
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        if (data)
        {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
        }
        else
        {
            std::cout << "Failed to load texture" << std::endl;
        }
        stbi_image_free(data);
    }
    int main(int argc, char** argv)
    {
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
        glutInitWindowSize(ww, wh);
        glutCreateWindow("texture-try");
        glutDisplayFunc(display);
        myinit();
        glutMainLoop();
        return 0;
    }
    

    screenshot