openglsdlbump-mapping

SDL OpenGL Normal mapping


What is the simplest way of applying a normal map to a textured four vertex polygon in SDL? Do you have to create a shader or is there a simpler way? I have here my code that creates a textured rotating cube, with a rotating satellite light.

What additions to my code do I need to do if I want to use the generated texture (tex_Norm = generateTexture()) as a normal map also?

#include <windows.h>
#include <SDL.h>

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <GL/glext.h>

#include <math.h>

void            initAll();
void            setupBox();
void            mainloop();
unsigned int    generateTexture();
void            handle_inputs();
void            updateScreen();
void            clean_up();

int             scrWidth, scrHeight, flags;
bool            bQuit = false;
float           angle = 0.0f;

GLuint          tex_Box, tex_Norm;

struct sVert
{
    float x;
    float y;
    float z;
};

class cPolygon
{
public:
    int v[4];

    void fillverts(int v1, int v2, int v3, int v4) {
        v[0] = v1;
        v[1] = v2;
        v[2] = v3;
        v[3] = v4;
    }
} p[6];

sVert pv[8];

int main(int argc, char *argv[])
{
    initAll();
    mainloop();
    clean_up();
    return 0;
}

void initAll()
{
    scrWidth = 800;
    scrHeight = 600;

    SDL_InitSubSystem(SDL_INIT_VIDEO);
    SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
    SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
    SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
    SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
    SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
    SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );

    flags = SDL_OPENGL | SDL_ANYFORMAT ;

    SDL_SetVideoMode(scrWidth, scrHeight, 16, flags);
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity( );
    gluPerspective( 45.0f, (GLfloat)scrWidth/(GLfloat)scrHeight, 1.0f, 500.0f );
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity( );

    glEnable (GL_DEPTH_TEST);
    glEnable (GL_LIGHTING);
    glEnable (GL_LIGHT0);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_ALPHA);

    SDL_WM_SetCaption( "Normal Mapping", NULL );

    tex_Box = generateTexture();
    tex_Norm = generateTexture();

    setupBox();
}

void setupBox()
{

    for (int z=0;z<2;z++)
    for (int y=0;y<2;y++)
    for (int x=0;x<2;x++)
    {
        pv[x+y*2+z*4].x = -1.0+x;
        pv[x+y*2+z*4].y = -1.0+y;
        pv[x+y*2+z*4].z = -1.0+z;
    }

    // Box object
    p[0].fillverts (0, 1, 3, 2);    // above
    p[1].fillverts (4, 5, 1, 0);    // behind
    p[2].fillverts (6, 7, 3, 2);    // in front
    p[3].fillverts (5, 7, 3, 1);    // right
    p[4].fillverts (0, 2, 6, 4);    // left
    p[5].fillverts (7, 6, 4, 5);    // below
}

unsigned int generateTexture()
{
    BYTE    data[128*128*3];
    unsigned int id;

    for (int x=0;x<128;x++)
        for (int y=0;y<128;y++)
        {
            data[y*128*3+x*3+0] = x;        // Red
            data[y*128*3+x*3+1] = y;        // Green
            data[y*128*3+x*3+2] = 128-(abs(64-x)+abs(64-y));    // Blue
        }

    glGenTextures(1, &id); 
    glBindTexture(GL_TEXTURE_2D, id); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 128, 128, 0, GL_RGB, GL_BYTE, data);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 

    return id;
}

void mainloop()
{
    while(bQuit == false)
    {
        handle_inputs();
        updateScreen();
        angle += 1.5f;
        Sleep(50);
    }
}

void handle_inputs()
{
    SDL_PumpEvents();
    Uint8 * keystate = SDL_GetKeyState(NULL);
    if(keystate[SDLK_ESCAPE]) bQuit = true;
}

void updateScreen()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    glPushMatrix();

    glTranslatef(0.0f, 0.0f, -3.0f);        
    glRotatef(-angle*2.0, 1.0f, 1.0f, 1.0f);

    // Setup a light source
    float lpos[] = {0.0, 0.0, 2.0, 1.0};    // position
    float ldif[] = {1.0, 1.0, 1.0, 1.0};    // diffuse 
    float lamb[] = {0.3, 0.3, 0.2, 1.0};    // ambient 

    glLightfv(GL_LIGHT0, GL_POSITION, lpos);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, ldif);
    glLightfv(GL_LIGHT0, GL_AMBIENT, lamb);

    glPopMatrix();
    glPushMatrix();

    glTranslatef(0.5f, 0.5f, -3.0f);        
    glRotatef(angle, 1.0f, 1.0f, 1.0f); 

    // Draw box object
    glBindTexture(GL_TEXTURE_2D, tex_Box);
    glEnable(GL_TEXTURE_2D);
    glBegin(GL_QUADS);

    for(int pi=0; pi<6; pi++)
        for(int vi=0; vi<4; vi++)
        {
            switch(vi) {
            case 0: glTexCoord2d(0.0,2.0); break;
            case 1: glTexCoord2d(0.0,0.0); break;
            case 2: glTexCoord2d(2.0,0.0); break;
            case 3: glTexCoord2d(2.0,2.0); break; };

            glVertex3f( pv[ p[pi].v[vi] ].x, 
                        pv[ p[pi].v[vi] ].y, 
                        pv[ p[pi].v[vi] ].z );

        };

    glEnd();
    glDisable(GL_TEXTURE_2D);
    glPopMatrix();

    glFinish();
    SDL_GL_SwapBuffers();
}

void clean_up()
{
    SDL_QuitSubSystem(SDL_INIT_VIDEO);
    glDeleteTextures(1, &tex_Box);
    glDeleteTextures(1, &tex_Norm);
    SDL_Quit();
}

Solution

  • Sorry, but if you want to use modern OpenGL features, you need modern OpenGL, which means shaders. :( That also means all your lighting needs to be done manually in the shader, so your program is going to get quite a bit more complicated, but that's the price you pay for cool images.

    Explaining in detail how to do normal mapping wouldn't fit here, but there are very nice tutorials out there, for example http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-13-normal-mapping/.

    Good luck!