File: lightmap.c

/****************************************************/
/* Light mapping                                    */
/* An OpenGL demo by A.P.Gardner                    */
/* Ported to Cpw by Jim Mathies                     */
/****************************************************/

/* 
  Cpw link options:

  #define CPW_EXTERN        - link to the static lib
  #define CPWDLL_EXTERN     - link to the release dll's stub
  #define CPWDLLDBG_EXTERN  - link to the debug dll's stub
  #define CPWEXTDLL_EXTERN  - link to the release dll with cpw addons 
*/

#define CPWDLL_EXTERN

#include <cpw.h>
#include "../../library/addons/glextensions/cpwext_glextensions.h"

/* extension support info */

static GLExtensionSupport glExtInfo;

/* store of texture references */

static GLuint texName[2];
static CpwImage images[2];
static double rot = 0;

/****************************************************/
/*  Load texture function                           */
/****************************************************/

bool registerTexture( pCpw cpw, char * filename, uint_32 id )
{
    /* load the bitmap */

    if ( !cpwLoadImage( cpw, &images[id], CPW_IMAGEFORMAT_BMP, filename, true ) ) {
        printf( "File not found: %s\n", filename );
        return false;
    }

    /* create texture object */

    glBindTexture( GL_TEXTURE_2D, texName[id] );

    /* set up wrap & filter params */

    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_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );

    /* load the texture into gl */

    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, images[id].width, images[id].height,
			     0, GL_RGB, GL_UNSIGNED_BYTE, images[id].data );

    return true;
}

/****************************************************/
/*  Init                                            */
/****************************************************/

bool init(pCpw cpw)
{
    /* set background colour */

    glClearColor(0.0, 0.0, 0.0, 0.0);

    /* initialise viewing parameters */

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.1, 0.9, 0.1, 0.9, -1.0, 1.0);

    /* generate texture names */

    texName[0] = 0;
    texName[1] = 0;
    glGenTextures( 2, texName );

    /* load textures */

    if ( !registerTexture( cpw, "textures/light.bmp", 0 ) ) return false;

    if ( !registerTexture( cpw, "textures/wall2.bmp", 1 ) ) return false;

    /* enable texturing & set texturing function */

    glEnable(GL_TEXTURE_2D);

    /* init gl extensions we might use if they exists */

    cpwextInitOpenGLExtensions( cpw, &glExtInfo );

    if ( glExtInfo.ARB_multitexture ) {

        printf( "Using ARB_multitexture extension.\n" );

    } else {

        printf( "No ARB_multitexture support, using multipass rendering.\n" );

    }

    return true;
}

/****************************************************/
/*  Cleanup texture memory                          */
/****************************************************/

void cleanup(void)
{
    /* delete texture objects */

    glDeleteTextures(2, texName);
}

/****************************************************/
/*  Timer Event callback                            */
/****************************************************/

void timer( pCpw cpw, uint_32 id )
{
    rot = rot + .1;
    cpwPostWindowRedisplay( cpw, 1 );
}

void display_arbmultitexture( void )
{
    /* move the lightmap texture around in a circle */

    glActiveTextureARB( GL_TEXTURE0_ARB ); 
    glBindTexture( GL_TEXTURE_2D, texName[0] ); 
    glEnable( GL_TEXTURE_2D ); 

    glMatrixMode( GL_TEXTURE );
    glLoadIdentity();

    glTranslated( sin(rot)*.05, cos(rot)*.05, 0 ); 

    glActiveTextureARB( GL_TEXTURE1_ARB ); 
    glBindTexture( GL_TEXTURE_2D, texName[1] ); 
    glEnable( GL_TEXTURE_2D );

    /* just draw the wall texture - no movement */

    glMatrixMode( GL_MODELVIEW );

    /* draw both the lightmap and the wall at the same time */

    /* The ARB_multitexture extension does not add any new texture 
    blending modes. The standard OpenGL 1.1 blending modes are supported 
    in a pipelined manner; the result of the first texture environment 
    feeds into the second texture environment as the fragment color. */

    glBegin( GL_QUADS );

    glMultiTexCoord2fARB( GL_TEXTURE0_ARB, 0.0, 0.0 );
    glMultiTexCoord2fARB( GL_TEXTURE1_ARB, 0.0, 0.0 );
    glVertex3d(0.0, 0.0, 0.0);

    glMultiTexCoord2fARB( GL_TEXTURE0_ARB, 1.0, 0.0 );
    glMultiTexCoord2fARB( GL_TEXTURE1_ARB, 1.0, 0.0 );
    glVertex3d(1.0, 0.0, 0.0);

    glMultiTexCoord2fARB( GL_TEXTURE0_ARB, 1.0, 1.0 );
    glMultiTexCoord2fARB( GL_TEXTURE1_ARB, 1.0, 1.0 );
    glVertex3d(1.0, 1.0, 0.0);

    glMultiTexCoord2fARB( GL_TEXTURE0_ARB, 0.0, 1.0 );
    glMultiTexCoord2fARB( GL_TEXTURE1_ARB, 0.0, 1.0 );
    glVertex3d(0.0, 1.0, 0.0);
   
    glEnd();

}

void display_standardpipeline( void )
{
    /* bind light map texture */

    glBindTexture(GL_TEXTURE_2D, texName[0]);

    glMatrixMode( GL_TEXTURE );
    glLoadIdentity();

    glTranslated( sin(rot)*.05, cos(rot)*.05, 0 ); 

    /* draw the light map quad */

    glBegin(GL_QUADS);
	    glTexCoord2d(0.0, 0.0);
	    glVertex3d(0.0, 0.0, 0.0);
	    glTexCoord2d(1.0, 0.0);
	    glVertex3d(1.0, 0.0, 0.0);
	    glTexCoord2d(1.0, 1.0);
	    glVertex3d(1.0, 1.0, 0.0);
	    glTexCoord2d(0.0, 1.0);
	    glVertex3d(0.0, 1.0, 0.0);
    glEnd();

    glMatrixMode( GL_MODELVIEW );

    /* enable blending */

    glEnable(GL_BLEND);

    /* set blend function to multiply SRC & DST colours */

    glBlendFunc(GL_ZERO, GL_SRC_COLOR);

    /* bind wall texture */

    glBindTexture(GL_TEXTURE_2D, texName[1]);

    glMatrixMode( GL_TEXTURE );
    glLoadIdentity();
    glMatrixMode( GL_MODELVIEW );

    /* draw the wall quad */

    glBegin(GL_QUADS);
	    glTexCoord2d(0.0, 0.0);
	    glVertex3d(0.0, 0.0, 0.0);
	    glTexCoord2d(1.0, 0.0);
	    glVertex3d(1.0, 0.0, 0.0);
	    glTexCoord2d(1.0, 1.0);
	    glVertex3d(1.0, 1.0, 0.0);
	    glTexCoord2d(0.0, 1.0);
	    glVertex3d(0.0, 1.0, 0.0);
    glEnd();

    /* disable blending */

    glDisable(GL_BLEND);
}

/****************************************************/
/*  Window Draw Event callback                      */
/****************************************************/

void display( pCpw cpw, uint_32 winid )
{
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    /* clear all pixels in colour buffer */

    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    /* display */

    if ( glExtInfo.ARB_multitexture ) {

      display_arbmultitexture();

    } else {

      display_standardpipeline();

    }

    cpwFpsDraw( cpw, true );

    cpwSwapWindowBuffers( cpw, winid );
}

/****************************************************/
/*  Window Resize Event callback                    */
/****************************************************/

void reshape( pCpw cpw, uint_32 winid, uint_32 width, uint_32 height )
{
	  glMatrixMode(GL_PROJECTION);
	  glLoadIdentity();
	  glOrtho(0.1, 0.9, 0.1, 0.9, -1.0, 1.0);
    glViewport( 0, 0, width, height );
}

/****************************************************/
/*  Main                                            */
/****************************************************/

#ifdef _WINDOWS
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
#elif  _CONSOLE
int main(int argc, char* argv[])
#endif
{
    pCpw cpw = null;
    cpwInitContext( &cpw );
    cpwInitDisplayMode( cpw, CPW_SURFACE_DOUBLE | CPW_SURFACE_RGB );
    cpwInitWindowProperty( cpw, CPW_WINDOWPROP_POSITION, 100, 100 );
    cpwInitWindowProperty( cpw, CPW_WINDOWPROP_SIZE, 200, 200 );
    cpwCreateWindow(cpw,"OpenGL Demo - Light Mapping (Multipass)");

    if ( !init(cpw) ) {
        cpwFreeContext( &cpw );
        return false;
    }

    cpwReshapeCallback( cpw, reshape );
    cpwDisplayCallback(cpw,display);
    cpwTimerCallback(cpw,1,1,true,timer);
    cpwFpsInit(cpw);
    cpwMainLoop(cpw);
    cleanup();

    return 0;