views:

165

answers:

5

Hi,

Recently I have been looking into OpenGL, and I've got up to the stage were I want to texture things. I thought I would start with texturing a simple cube. I currently have this code, and understand fully how it works:

#include <glut.h>

#define WINDOW_WIDTH 400
#define WINDOW_HEIGHT 400


float angle = 30.0f;

void Draw() {

glLoadIdentity(); //Reset the drawing perspective
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Clears the buffers

//Add positioned light
GLfloat lightColor0[] = {0.5f, 0.5f, 0.5f, 1.0f}; //Color intensity
GLfloat lightPos0[] = {0.0f, 0.0f, 0.0f, 1.0f}; //Positioned at..
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor0); //Set our light colour
glLightfv(GL_LIGHT0, GL_POSITION, lightPos0); //Set our light position

glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 200);

glRotatef(angle,1.0f,1.0f,1.0f); //Rotate around the origin
glScalef(0.4f, 0.4f, 0.4f); //Scale the shape down
glBegin(GL_QUADS); //Start drawing a Quad
glColor3f(1.0f,0.0f,0.0f); //Set the colour to Red
glVertex3f( 1.0f, 1.0f,-1.0f); //Top right of the quad (Top Face)
glVertex3f(-1.0f, 1.0f,-1.0f); //Top left of the quad (Top Face)
glVertex3f(-1.0f, 1.0f, 1.0f); //Bottom left of the quad (Top Face)
glVertex3f( 1.0f, 1.0f, 1.0f); //Bottom right of the quad (Top Face)
glVertex3f( 1.0f,-1.0f, 1.0f); //Top right of the quad (Bottom Face)
glVertex3f(-1.0f,-1.0f, 1.0f); //Top left of the quad (Bottom Face)
glVertex3f(-1.0f,-1.0f,-1.0f); //Bottom left of the quad (Bottom Face)
glVertex3f( 1.0f,-1.0f,-1.0f); //Bottom right of the quad (Bottom Face)
glVertex3f( 1.0f, 1.0f, 1.0f); //Top right of the quad (Front Face)
glVertex3f(-1.0f, 1.0f, 1.0f); //Top left of the quad (Front Face)
glVertex3f(-1.0f,-1.0f, 1.0f); //Bottom left of the quad (Front Face)
glVertex3f( 1.0f,-1.0f, 1.0f); //Bottom right of the quad (Front Face)
glVertex3f( 1.0f,-1.0f,-1.0f); //Top right of the quad (Back Face)
glVertex3f(-1.0f,-1.0f,-1.0f); //Top left of the quad (Back Face)
glVertex3f(-1.0f, 1.0f,-1.0f); //Bottom left of the quad (Back Face)
glVertex3f( 1.0f, 1.0f,-1.0f); //Bottom right of the quad (Back Face)
glVertex3f(-1.0f, 1.0f, 1.0f); //Top right of the quad (Left Face)
glVertex3f(-1.0f, 1.0f,-1.0f); //Top left of the quad (Left Face)
glVertex3f(-1.0f,-1.0f,-1.0f); //Bottom left of the quad (Left Face)
glVertex3f(-1.0f,-1.0f, 1.0f); //Bottom right of the quad (Left Face)
glVertex3f( 1.0f, 1.0f,-1.0f); //Top right of the quad (Right Face)
glVertex3f( 1.0f, 1.0f, 1.0f); //Top left of the quad (Right Face)
glVertex3f( 1.0f,-1.0f, 1.0f); //Bottom left of the quad (Right Face)
glVertex3f( 1.0f,-1.0f,-1.0f); //Bottom right of the quad (Right Face)
glEnd(); //Finished Drawing The Quad
glutSwapBuffers(); //Send the 3D scene to the screen
}

void Update(int value){ //Our update function
angle+=0.5f; //Increase the angle by 5

if(angle>360){ //If the angle is greater than 360
angle=0; //Set the angle to 0
}

glutPostRedisplay(); //Tell it that the scene has changed
glutTimerFunc(25,Update,0); //Call "Update" again in another 25ms
}

void Initialize() {
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHTING); //Enable lighting
glEnable(GL_LIGHT0); //Enable light No. 0
glEnable(GL_NORMALIZE); //Automatically "normalize" normals
glShadeModel(GL_SMOOTH); //Enable smooth shading (nice effect)


glClearColor(0.0, 0.0, 0.0, 0.0); //Background RGBA
glMatrixMode(GL_MODELVIEW); //MODELVIEW view
glLoadIdentity(); //Start at origin
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); //Set the scale
//X axis = 0 to 1. Y = 0 to 1. Z = -1 to 1.
}

int main() {
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); //The display mode
glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT); //Window Size
glutInitWindowPosition(200, 200); //Window Position
glutCreateWindow("Lighting!"); //Creates a window with the name "Lighting!"
Initialize(); //Call our initialize function.
glutDisplayFunc(Draw); //"Draw" then refresh the window
glutTimerFunc(25,Update,0); //Call "Update" 25ms after program starts
glutMainLoop(); //Process events etc. Also keeps the window open.
return 0; //End the program
}

However after reading many, MANY texturing tutorials (I mean literally all of the ones I could find on the web); I'm still confused about how I would add it to this program. I know that I have to load the texture (somehow) and then bind it using the glBindTexture function before I draw the cube, but I think there is something else I need to do in-between (and I don't know how to load the image properly either).

Please Help,

Thanks In Advance,

Joe

+2  A: 

I recommend looking at SOIL, an OpenGL image loading library - its what I use.

As far as getting a texture working, its pretty much:

Unsigned int texture = SOIL_load_OGL_texture(imagePath.c_str(), SOIL_CREATE_NEW_ID, SOIL_LOAD_AUTO, SOIL_FLAG_MIPMAPS);

glBindTexture(texture);

You do however have to use texture co-ordinates so that opengl knows how to wrap your texture. Heres some sample calls that render cube.

    int size = 1;

    // Begin Rending
    glBegin(GL_QUADS);

    {
        // Face 1

        glNormal3f( 0.0f, 0.0f, 1.0f);  

        glTexCoord2f(0.0f, 0.0f);
        glVertex3f( m_size, m_size,-m_size);

        glTexCoord2f(1.0f, 0.0f);
        glVertex3f(-m_size, m_size,-m_size);

        glTexCoord2f(1.0f, 1.0f);
        glVertex3f(-m_size, m_size, m_size);

        glTexCoord2f(0.0f, 1.0f);
        glVertex3f( m_size, m_size, m_size);    

        // Face 2

        glNormal3f( 0.0f, 0.0f,-1.0f);

        glTexCoord2f(0.0f, 0.0f);
        glVertex3f( m_size,-m_size, m_size);    

        glTexCoord2f(1.0f, 0.0f);
        glVertex3f(-m_size,-m_size, m_size);

        glTexCoord2f(1.0f, 1.0f);
        glVertex3f(-m_size,-m_size,-m_size);

        glTexCoord2f(0.0f, 1.0f);
        glVertex3f( m_size,-m_size,-m_size);

        // Face 3


        glTexCoord2f(0.0f, 0.0f);
        glVertex3f( m_size, m_size, m_size);    

        glTexCoord2f(1.0f, 0.0f);
        glVertex3f(-m_size, m_size, m_size);

        glTexCoord2f(1.0f, 1.0f);
        glVertex3f(-m_size,-m_size, m_size);    

        glTexCoord2f(0.0f, 1.0f);
        glVertex3f( m_size,-m_size, m_size);

        // Face 4

        glNormal3f( 0.0f,-1.0f, 0.0f);  

        glTexCoord2f(0.0f, 0.0f);
        glVertex3f( m_size,-m_size,-m_size);

        glTexCoord2f(1.0f, 0.0f);
        glVertex3f(-m_size,-m_size,-m_size);

        glTexCoord2f(1.0f, 1.0f);
        glVertex3f(-m_size, m_size,-m_size);

        glTexCoord2f(0.0f, 1.0f);
        glVertex3f( m_size, m_size,-m_size);

        // Face 5

        glNormal3f( 1.0f, 0.0f, 0.0f);

        glTexCoord2f(0.0f, 0.0f);
        glVertex3f(-m_size, m_size, m_size);    

        glTexCoord2f(1.0f, 0.0f);
        glVertex3f(-m_size, m_size,-m_size);    

        glTexCoord2f(1.0f, 1.0f);
        glVertex3f(-m_size,-m_size,-m_size);

        glTexCoord2f(0.0f, 1.0f);
        glVertex3f(-m_size,-m_size, m_size);

        // Face 6

        glNormal3f( 1.0f, 0.0f, 0.0f);

        glTexCoord2f(0.0f, 0.0f);
        glVertex3f( m_size, m_size,-m_size);

        glTexCoord2f(1.0f, 0.0f);
        glVertex3f( m_size, m_size, m_size);

        glTexCoord2f(1.0f, 1.0f);
        glVertex3f( m_size,-m_size, m_size);

        glTexCoord2f(0.0f, 1.0f);
        glVertex3f( m_size,-m_size,-m_size);    
    }

    glEnd();
Tomas Cokis
imagePath is an std::string, just to be clear
Tomas Cokis
So would something like this work?[code]const string imagePath="texture.bmp";unsigned int texture = SOIL_load_OGL_texture(imagePath.c_str(), SOIL_CREATE_NEW_ID, SOIL_LOAD_AUTO, SOIL_FLAG_MIPMAPS); void Draw(){int size = 1; glBindTexture(texture); //Insert the other bit of code you had in the main post here.}[/code]
Joesavage1
A: 

For image loading you can also use the SDL-image Library:

http://www.libsdl.org/projects/SDL_image/

It is very handy.

Quonux
I thought that library was for SDL's built in rendering only?
Tomas Cokis
nope, it is an extendtion to whatever you want, sure, it needs maybe sdl (i dunno) but u can use it anywhere
Quonux
+1  A: 

I think the part your missing is the concept of texture coordinates.

Textures are 2d right? So, when you're pushing the 3d points of your object to the graphics card, if you want it textured you also need to associate that 3d point with a position in a texture image which you do with a pair of texture coordinates (pair because textures are 2d)... Take a look at glTexCoord2f()... If you make a call to that right before a call to glVertex3f() you'll associate that 3d point with a point in the image... If you do that for all the points that make up a primitive opengl can interpolate for all the points in between...

dicroce
So I have to create the cube (using the draw code I already have in my program), and then map the texture on using the majority of the code in the post my Tomas Cokis?
Joesavage1
Yup. You create a texture, you load an image into it (with glTexSubImage2d() I think), then you glBindTexture() so openGL knows what texture your talking about, then when you're pushing geometry, you push texture coordinates as well (with glTexCoord2f()).
dicroce
Ok, I think I get it. But you're saying to load the image with hlTexSubImage2d(), however according to a quick search there isn't a file path parameter for the function; so how do I actually load the image? (I know that I could use SOIL, but I generally don't like extra pre-created headers, and I would prefer to do it in a pure OpenGL way if possible).
Joesavage1
Yeah, glTexSubImage2d() doesn't know about image files... You have to provide it with a pointer to a buffer full of the pixels...
dicroce
Ah ok. Is there a way that only uses OpenGL to load these images (and get them into the format I need for glTexSubImage2d()) or will I need to look around different extenal headers? (I hate downloading headers generally.. I just feel like I'm copying code, and I hate just copying; I need to know how it all works).
Joesavage1
None of OpenGL knows anything about files.
Ben Voigt
OpenGL requires the pixel data of your texture. Reading the pixel data from an image file is outside the scope of OpenGL, you'll need to use another library for that. If your goal is to learn about OpenGL, I recommend against writing your own image loader.
Joe Gauterin
+1  A: 

For loading texture files (png, jpg...) use this: (don't forget to install SDL and SDL_image libraries)

#include <SDL/SDL.h>
#include <SDL/SDL_image.h>

GLuint texture_alloc(const char  *tex_name, int alpha)
{
    GLuint tex_num;

    SDL_Surface *tex_img;
    glGenTextures(1, &tex_num);

    if(tex_img = (SDL_Surface *) IMG_Load(tex_name)) {

        glBindTexture(GL_TEXTURE_2D, tex_num);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);

        if (alpha==1)
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_img->w, tex_img->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex_img->pixels);
        else
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_img->w, tex_img->h, 0, GL_RGB, GL_UNSIGNED_BYTE, tex_img->pixels);
        SDL_FreeSurface (tex_img);
    }

    return tex_num;

}

For setting texture coordinates use glTexCoord function:

glTexCoord2f(0.0f, 0.0f);
glVertex3f( 1.0f, 1.0f,-1.0f); 
glTexCoord2f(1.0f, 0.0f);
glVertex3f(-1.0f, 1.0f,-1.0f);
.
.
.
Kuscsikp
Wow, blew my brains at first; then I realised it was just a simple function (hadn't seen the data type before :P). Where does it get the image path from? Is that the tex_name?I think I'm finally beginning to understand it!
Joesavage1
+ you can replace (alpha==1) with (tex_img->format->BitsPerPixel==32) /RGBA/
Kuscsikp
A: 

You can use the glaux code from the http://nehe.gamedeve.net/ this also is pretty simple.

AUX_RGBImageRec* LoadBMP(char* Filename)
{
    FILE *File = NULL;

    if ( !Filename )
        return NULL;

    File = fopen(Filename,"r");

    if ( !Filename )
        return NULL;

    fclose(File);
    return auxDIBImageLoad(Filename);
}

int LoadTextures()
{
    int Status = FALSE;
    AUX_RGBImageRec *TextureImage[1];
    memset(TextureImage,0,sizeof(void*)*1);

    if ( TextureImage[0] = LoadBMP("GoneFishing.bmp") )
    {
        Status = true;
        if(texture[0] == -1)
            glGenTextures(1,&texture[0]);
        glBindTexture(GL_TEXTURE_2D,texture[0]);
        // Generate The Texture
        glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // Linear Filtering
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering
    }

    if (TextureImage[0])                            // If Texture Exists
    {
        if (TextureImage[0]->data)                  // If Texture Image Exists
        {
            free(TextureImage[0]->data);                // Free The Texture Image Memory
        }

        free(TextureImage[0]);                      // Free The Image Structure
    }

    return Status;
}
ferosekhanj