Search code examples
c++opengltexturesglut

OpenGL - Load mutliple texures in one function


I've already constructed a 15x15 grid of cubes with glutSolidCube(). Then i have a menu handler in which when I click "Start Game", loads the texture I used to all of the cubes, calling a custom glutSolidCube and having glTexCoord2d before each declaration of vertices, cause we can't have textures on the latter I think. For uploading the texture from an image, I'm using a STB_IMAGE_IMPLEMENTATION implementation having also a header file included. The function loadTextureFromFile(const char *filename) does the loading part.

How can I upload more textures (I want 2 more, in the same loadTextureFromFile() function preferably) and how to handle each texture with the glTexCoord2d()?

Here's my entire code:

#include<iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/gl.h>     // openGL header
#include <GL/glu.h>   // glut header
#include <GL/glut.h>   // glut header
#define STB_IMAGE_IMPLEMENTATION


/////////////////////////////////////Textures==============================================/////////////////////////////////////
#include "stb_image.h"
GLuint texture; //the array for our texture


void loadTextureFromFile(const char *filename)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    //glShadeModel(GL_FLAT);
    //glEnable(GL_DEPTH_TEST);

    unsigned int texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    // set the texture wrapping/filtering options (on the currently bound texture object)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    // load and generate the texture
    int width, height, nrChannels;
    unsigned char *data = stbi_load("paper.bmp", &width, &height, &nrChannels, 0);
    if (data)
    {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
        //glGenerateMipmap(GL_TEXTURE_2D);
    }
    else
    {
        std::cout << "Failed to load texture" << std::endl;
    }
    stbi_image_free(data);
}

void FreeTexture(GLuint texture)
{
    glDeleteTextures(1, &texture);
}



/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


static void
drawBox(GLfloat size, GLenum type)
{
    static GLfloat n[6][3] =
    {
        {-1.0, 0.0, 0.0},
        {0.0, 1.0, 0.0},
        {1.0, 0.0, 0.0},
        {0.0, -1.0, 0.0},
        {0.0, 0.0, 1.0},
        {0.0, 0.0, -1.0}
        };

    static GLint faces[6][4] =
    {
        {0, 1, 2, 3},
            {3, 2, 6, 7},
            {7, 6, 5, 4},
        {4, 5, 1, 0},
        {5, 6, 2, 1},
        {7, 4, 0, 3}
    };
    GLfloat v[8][3];
    GLint i;

    v[0][0] = v[1][0] = v[2][0] = v[3][0] = -size / 2;
    v[4][0] = v[5][0] = v[6][0] = v[7][0] = size / 2;
    v[0][1] = v[1][1] = v[4][1] = v[5][1] = -size / 2;
    v[2][1] = v[3][1] = v[6][1] = v[7][1] = size / 2;
    v[0][2] = v[3][2] = v[4][2] = v[7][2] = -size / 2;
    v[1][2] = v[2][2] = v[5][2] = v[6][2] = size / 2;

    for (i = 5; i >= 0; i--) {
        glBegin(type);
            glNormal3fv(&n[i][0]);

        glTexCoord2d(0.0,0.0);
            glVertex3fv(&v[faces[i][0]][0]);
        glTexCoord2d(0.0,1.0);
            glVertex3fv(&v[faces[i][1]][0]);
        glTexCoord2d(1.0,1.0);
            glVertex3fv(&v[faces[i][2]][0]);
        glTexCoord2d(1.0,0.0);
            glVertex3fv(&v[faces[i][3]][0]);
            glEnd();
    }
}

void APIENTRY
myglutSolidCube(GLdouble size)
{
  drawBox(size, GL_QUADS);
}

//int red_color[]={255,0,0};
//int blue_colot[]={0,0,255};


//////////////////////////////=========MENU============/////////////
enum MENU_TYPE //menu options-values
{
        MENU_START,
        MENU_EXIT,

};

//create the menu - Prototype
void my_createmenu(void);
// Menu handling function declaration - Prototype
void menu(int);



void init()
{       //for 3d lighting
    glEnable(GL_DEPTH_TEST); //depth test
    glEnable(GL_LIGHTING); //enable light from a single source
    glEnable(GL_LIGHT0); //enable white light , diffuse and specular components
    glEnable(GL_COLOR_MATERIAL); //track the current color

}


void display()
{




    glClearColor(0.0f, 0.0f, 0.0f, 1.0f); //Black and opaque
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //define the projection matrix just once and use the modelview matrix all other times


    glMatrixMode(GL_PROJECTION);  //Applies subsequent matrix operations to the projection matrix stack
    glLoadIdentity();//Reset

    GLint viewport[4];
    glGetIntegerv(GL_VIEWPORT, viewport); //The params parameter returns four values: the x and y window coordinates of the viewport, followed by its width and height
    double aspect = (double)viewport[2] / (double)viewport[3]; // y/width would be 1.0

    gluPerspective(60,aspect, 1, 100); //using perspective projection
    //gluOrtho2D(0.0,600.0,-60.0,600.0);  


    glMatrixMode(GL_MODELVIEW); //for trasformations - Applies subsequent matrix operations to the texture matrix stack
    glLoadIdentity();

    // move back a bit for viewer  , cause of gluPerspective
    glTranslatef( 0, 0, -35 );


    float e=0,f=0;

    //construct the grid with reference the central cube  
    for(int i=0;i<8;i++) {
        for(int j=0;j<8;j++) {      
            glPushMatrix();
                glTranslatef(0.0f+e,0.0f+f,0.0f); //right and below
                glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
                    glColor3ub(245, 245, 220); //Beige
                    glutSolidCube(2.25);
                glPopMatrix();

            glPushMatrix();
                glTranslatef(0.0f-e,0.0f+f,0.0f); //left and below
                glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
                    glColor3ub(245, 245, 220); //Beige
                    glutSolidCube(2.25);
                glPopMatrix();

            glPushMatrix();
                glTranslatef(0.0f+e,0.0f-f,0.0f); //right and up
                glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
                    glColor3ub(245, 245, 220); //Beige
                    glutSolidCube(2.25);
                glPopMatrix();

            glPushMatrix();
                glTranslatef(0.0f-e,0.0f-f,0.0f); //left and up
                glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
                    glColor3ub(245, 245, 220); //Beige
                    glutSolidCube(2.25);
                glPopMatrix();


                f += -2.63;
            }
            f=0;
            e+=2.63;
        }





    glutSwapBuffers(); //implicit   glFlush



}

//for the second part of program 
void display_game()
{




    glClearColor(0.0f, 0.0f, 0.0f, 1.0f); //Black and opaque
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //define the projection matrix just once and use the modelview matrix all other times

    glMatrixMode(GL_PROJECTION);  //Applies subsequent matrix operations to the projection matrix stack
    glLoadIdentity();//Reset

    GLint viewport[4];
    glGetIntegerv(GL_VIEWPORT, viewport); //The params parameter returns four values: the x and y window coordinates of the viewport, followed by its width and height
    double aspect = (double)viewport[2] / (double)viewport[3]; // y/width would be 1.0


    gluPerspective(60,aspect, 1, 100); //using perspective projection
    //glOrtho(0.0f, 600.0f, 600.0f, 0.0f, 0.0f, 1.0f);


    glMatrixMode(GL_MODELVIEW); //for trasformations - Applies subsequent matrix operations to the texture matrix stack
    glLoadIdentity();

    // move back a bit for viewer  , cause of gluPerspective
    glTranslatef( 0, 0, -35 );


    float e=0,f=0;



    glEnable(GL_TEXTURE_2D);

    //construct the grid with reference the central cube  
    for(int i=0;i<8;i++) {
        for(int j=0;j<8;j++) {      
            glPushMatrix();
                glTranslatef(0.0f+e,0.0f+f,0.0f); //right and below
                glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
                    //glColor3ub(245, 245, 220); //Beige
                //glColor3ub( rand()%255,rand()%255, rand()%255 );
                    myglutSolidCube(2.25);
                glPopMatrix();

            glPushMatrix();
                glTranslatef(0.0f-e,0.0f+f,0.0f); //left and below
                glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
                    //glColor3ub( rand()%255,rand()%255, rand()%255 );
                    myglutSolidCube(2.25);
                glPopMatrix();

            glPushMatrix();
                glTranslatef(0.0f+e,0.0f-f,0.0f); //right and up
                glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
                    myglutSolidCube(2.25);
                glPopMatrix();

            glPushMatrix();
                glTranslatef(0.0f-e,0.0f-f,0.0f); //left and up
                glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
                    myglutSolidCube(2.25);
                glPopMatrix();


                f += -2.63;
            }
            f=0;
            e+=2.63;
        }


    //SEED to some constant value for 2nd part of the program. If it is not used , cubes would change color in runtime
    //srand(0x98765432); 


    glutSwapBuffers(); //implicit   glFlush


    glDisable(GL_TEXTURE_2D);
}

void reshape(GLsizei width, GLsizei height) { 

    // GLsizei for non-negative integer // Compute aspect ratio of the new window

    if (height == 0) height = 1; // To prevent divide by 0 
    GLfloat aspect = (GLfloat)width / (GLfloat)height; // Set the viewport to cover the new window 
    glViewport(0, 0, width, height); // Set the aspect ratio of the clipping volume                 glMatrixMode(GL_PROJECTION); // To operate on the Projection matrix 
    glLoadIdentity(); // Reset // Enable perspective projection with fovy, aspect, zNear and zFar 
    gluPerspective(45.0f, aspect, 0.1f, 100.0f); 

} 

void timer(int extra)
{
    glutPostRedisplay();
    glutTimerFunc(16, timer, 0);
}


void mouseEscape( int button, int state, int x, int y )
{
    if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN &&button==MENU_EXIT)

    {
        int windowID = glutCreateWindow("CUBES");
        glutDestroyWindow(windowID);
        exit(0);
    }

            glutPostRedisplay();

}

//for loading the texture
const char* filename = "salt_on_spoon.bmp";
int main(int argc, char **argv)
{
    glutInit(&argc, argv);
        glutInitWindowSize(600,600);
        glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE| GLUT_MULTISAMPLE);
        glEnable(GL_MULTISAMPLE); //anti-alliasing  
    glutCreateWindow("CUBES");



    //create and handle the menu
    my_createmenu();

    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutTimerFunc(0, timer, 0);


        init();
    //glEnable(GL_TEXTURE_2D); //for texture
    //glutMouseFunc(mouseEscape);
    //glutKeyboardFunc(keyEscape);

    //Load our texture
    //loadTextureFromFile(filename);



    glutMainLoop();

    //Free our texture
    //FreeTexture(texture);

    return 0;
}

//create the menu-entries
void my_createmenu(void) {

    // Create a menu
        glutCreateMenu(menu);

        // Add menu items
        glutAddMenuEntry("Start Game", MENU_START);
        glutAddMenuEntry("Exit", MENU_EXIT);

        // Associate a mouse button with menu
        glutAttachMenu(GLUT_RIGHT_BUTTON);


}

// Menu handling function-what to do in each value
void menu(int item)
{
        switch (item)
        {
        case MENU_START: {

        //glEnable(GL_TEXTURE_2D); //for texture

        //Load our texture
        loadTextureFromFile(filename);

        glutDisplayFunc(display_game);
        }
        break;
        case MENU_EXIT: 
        {
        int windowID = glutCreateWindow("CUBES"); //exit game
        glutDestroyWindow(windowID);
        exit(0);                
            }
                break;  
        default:
                {       /* Nothing */       }
                break;
        }

        glutPostRedisplay();

        return;
}

I'm doing the texture loading part in the menu function. How will I be able to handle three textures? The ultimate goal is to make a rand call also for the three textures to be rendered on the cubes.

I also have two pictures: 1st: when the program begins:

2nd: after clicking "Star Game" where you can see the texture rendered in all of the cubes:

The goal is for more 2 types of textures and all of them render in random cubes.


Solution

  • You can create more than 1 texture object. glBindTexture binds a named texture to a texturing target, that is a global state. glTexImage2D specify a two-dimensional texture image for the texture, which is currently bound to the specified target. glTexParameter set parameter to the texture object.

    I recommend to write a function which loads a texture form a file to a given texture object (name id):

    void loadTextureFromFile(const char *filename, unsigned int texture)
    {
        glBindTexture(GL_TEXTURE_2D, texture);
    
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        // load and generate the texture
        int width, height, nrChannels;
        unsigned char *data = stbi_load(filename, &width, &height, &nrChannels, 0);
        if (data)
        {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
                         GL_RGB, GL_UNSIGNED_BYTE, data);
            //glGenerateMipmap(GL_TEXTURE_2D);
        }
        else
        {
            std::cout << "Failed to load texture" << std::endl;
        }
        stbi_image_free(data);
    }
    
    const char* filename1 = "salt_on_spoon.bmp";
    const char* filename2 = ...;
    const char* filename3 = ...;
    unsigned int tob[3];
    
    int main(int argc, char **argv)
    {
        // [...]
    
        glGenTextures(3, &tob[0]);
    
        loadTextureFromFile(filename1, tob[0]);
        loadTextureFromFile(filename2, tob[1]);
        loadTextureFromFile(filename3, tob[2]);
    
        // [...]
    }
    

    When two-dimensional texturing is enabled, then the image of the texture object, which is currently bound to the target GL_TEXTURE_2D is wrapped on the mesh.

    You've to bind the proper texture object, before you draw the geometry. e.g:

    for(int i=0;i<8;i++) {
        for(int j=0;j<8;j++) {
    
            glBindTexture(GL_TEXTURE_2D, tob[0]);
            glPushMatrix();
                glTranslatef(0.0f+e,0.0f+f,0.0f); //right and below
                glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
                    myglutSolidCube(2.25);
            glPopMatrix();
    
            glBindTexture(GL_TEXTURE_2D, tob[1]);
            glPushMatrix();
                glTranslatef(0.0f-e,0.0f+f,0.0f); //left and below
                glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
                    myglutSolidCube(2.25);
            glPopMatrix();
    
            glBindTexture(GL_TEXTURE_2D, tob[2]);
            glPushMatrix();
                glTranslatef(0.0f+e,0.0f-f,0.0f); //right and up
                glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
                    myglutSolidCube(2.25);
            glPopMatrix();
    
            glBindTexture(GL_TEXTURE_2D, tob[0]);
            glPushMatrix();
                glTranslatef(0.0f-e,0.0f-f,0.0f); //left and up
                glRotatef(20.0f,1.0f,-2.0f,0.0f); //looking 3d
                    myglutSolidCube(2.25);
            glPopMatrix();
    
            f += -2.63;
        }
        f=0;
        e+=2.63;
    }
    

    Note, the distribution of the textures is just an example. You've to ensure that unsigned int tob[3]; is declared before, in global namespace.