File: volfog.c/****************************************************/
/* Volumetric fog */
/* 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;
/* definitions */
#define NUM_PANELS 16 /* number of panels in scene */
/* vertex data */
typedef struct
{
float x;
float y;
float z;
} world_vector;
/* vertex data for the panels */
world_vector vertices[NUM_PANELS*4] = {
{-15.0, 10.0, 0.0},{-5.0, 10.0, 0.0},{-5.0, 20.0, 0.0},{-15.0, 20.0, 0.0}, /* back wall */
{-5.0, 10.0, 0.0},{5.0, 10.0, 0.0},{5.0, 20.0, 0.0},{-5.0, 20.0, 0.0},
{5.0, 10.0, 0.0},{15.0, 10.0, 0.0},{15.0, 20.0, 0.0},{5.0, 20.0, 0.0},
{-15.0, 0.0, 0.0},{-5.0, 0.0, 0.0},{-5.0, 10.0, 0.0},{-15.0, 10.0, 0.0},
{-5.0, 0.0, 0.0},{5.0, 0.0, 0.0},{5.0, 10.0, 0.0},{-5.0, 10.0, 0.0},
{5.0, 0.0, 0.0},{15.0, 0.0, 0.0},{15.0, 10.0, 0.0},{5.0, 10.0, 0.0},
{-5.0, -10.0, 0.0},{5.0, -10.0, 0.0},{5.0, 0.0, 0.0},{-5.0, 0.0, 0.0}, /* foggy bit */
{-5.0, -10.0, 10.0},{-5.0, -10.0, 0.0},{-5.0, 0.0, 0.0},{-5.0, 0.0, 10.0},
{-5.0, -10.0, 20.0},{-5.0, -10.0, 10.0},{-5.0, 0.0, 10.0},{-5.0, 0.0, 20.0},
{5.0, -10.0, 0.0},{5.0, -10.0, 10.0},{5.0, 0.0, 10.0},{5.0, 0.0, 0.0},
{5.0, -10.0, 10.0},{5.0, -10.0, 20.0},{5.0, 0.0, 20.0},{5.0, 0.0, 10.0},
{-5.0, -10.0, 10.0},{5.0, -10.0, 10.0},{5.0, -10.0, 0.0},{-5.0, -10.0, 0.0},
{-15.0, 0.0, 10.0},{-5.0, 0.0, 10.0},{-5.0, 0.0, 0.0},{-15.0, 0.0, 0.0}, /* floor */
{5.0, 0.0, 10.0},{15.0, 0.0, 10.0},{15.0, 0.0, 0.0},{5.0, 0.0, 0.0},
{-15.0, 0.0, 20.0},{-5.0, 0.0, 20.0},{-5.0, 0.0, 10.0},{-15.0, 0.0, 10.0},
{5.0, 0.0, 20.0},{15.0, 0.0, 20.0},{15.0, 0.0, 10.0},{5.0, 0.0, 10.0}
};
/* texture references for the panels */
int panel_texture[NUM_PANELS] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
/* area references for the panels */
int fog_area[NUM_PANELS] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0};
/* mode flag */
static int fog = 1;
/* fog color */
static float red = (float)0.6;
static float green = (float)0.25;
/* store of texture references */
static GLuint texName[2];
static CpwImage images[2];
/****************************************************/
/* 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);
/* 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)
{
GLfloat fogColor[4] = {red, green, 0.0, 1.0};
/* set background colour */
glClearColor(0.0, 0.0, 0.0, 0.0);
/* initialise viewing parameters */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(50, 1.0, 0.2, 40);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
/* generate texture names */
texName[0] = 0;
texName[1] = 0;
glGenTextures( 2, texName );
/* load textures */
if ( !registerTexture( cpw, "textures/floor.bmp", 0 ) ) return false;
if ( !registerTexture( cpw, "textures/wall2.bmp", 1 ) ) return false;
/* enable texturing & set texturing function */
glEnable(GL_TEXTURE_2D);
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
/* init gl extensions we might use if they exists */
cpwextInitOpenGLExtensions( cpw, &glExtInfo );
if ( glExtInfo.EXT_fog_coord ) {
printf( "Using EXT_fog_coord extension with OpenGL fog.\n" );
glEnable( GL_FOG );
glFogi( GL_FOG_MODE, GL_LINEAR );
glFogfv( GL_FOG_COLOR, fogColor );
glFogf( GL_FOG_START, 0.0 );
glFogf( GL_FOG_END, 10.0 );
glFogi( GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT );
} else {
printf( "No EXT_fog_coord support, using alpha fog.\n" );
}
return true;
}
/****************************************************/
/* Cleanup texture memory */
/****************************************************/
void cleanup(void)
{
/* delete texture objects */
glDeleteTextures(2, texName);
}
/****************************************************/
/* Fog color per vertex */
/****************************************************/
void set_fog_color_ext(int p, int v)
{
float z; /* distance of vertex from edge of fog volume */
/* calculate depth through fog */
if (fog_area[p]) {
z = (float)0.0 - vertices[v].y;
} else {
z = 0.0;
}
/* set depth for this coord */
glFogCoordfEXT(z);
}
void set_fog_color_alpha(int v)
{
float z; /* distance of vertex from edge of fog volume */
float f; /* fog factor */
z = (float)0.0 - vertices[v].y;
/* linear fog: f = (end - z)/(end - start) */
f = ((float)10.0 - z) / ((float)10.0 - (float)0.0);
if ( fog == 2 ) glColor4f( red, green, 0.0, 1.0 );
else glColor4f( red, green, 0.0, f );
}
/****************************************************/
/* Draw a panel */
/****************************************************/
void draw_panel_ext(int ref)
{
int v; /* store of next vertex ref */
/* bind texture */
glBindTexture(GL_TEXTURE_2D, texName[panel_texture[ref]]);
/* draw panel */
v = ref * 4;
glBegin(GL_QUADS);
set_fog_color_ext(ref, v);
glTexCoord2f(0.0, 0.0);
glVertex3f(vertices[v].x, vertices[v].y, vertices[v].z); v++;
set_fog_color_ext(ref, v);
glTexCoord2f(1.0, 0.0);
glVertex3f(vertices[v].x, vertices[v].y, vertices[v].z); v++;
set_fog_color_ext(ref, v);
glTexCoord2f(1.0, 1.0);
glVertex3f(vertices[v].x, vertices[v].y, vertices[v].z); v++;
set_fog_color_ext(ref, v);
glTexCoord2f(0.0, 1.0);
glVertex3f(vertices[v].x, vertices[v].y, vertices[v].z);
glEnd();
}
void draw_panel_alpha(int ref)
{
int v; /* store of next vertex ref */
/* disable writes to z buffer (if fog area) */
if (fog_area[ref])
{
glDepthMask(GL_FALSE);
}
/* bind texture */
glBindTexture(GL_TEXTURE_2D, texName[panel_texture[ref]]);
/* draw the panel */
v = ref * 4;
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0);
glVertex3f(vertices[v].x, vertices[v].y, vertices[v].z); v++;
glTexCoord2f(1.0, 0.0);
glVertex3f(vertices[v].x, vertices[v].y, vertices[v].z); v++;
glTexCoord2f(1.0, 1.0);
glVertex3f(vertices[v].x, vertices[v].y, vertices[v].z); v++;
glTexCoord2f(0.0, 1.0);
glVertex3f(vertices[v].x, vertices[v].y, vertices[v].z);
glEnd();
/* perform rendering pass for fog if required */
if (fog_area[ref])
{
/* restore z buffer writes, set blend params & disable texturing */
glDepthMask(GL_TRUE);
glEnable(GL_BLEND);
if ( fog == 1 )
glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
else if ( fog == 2 )
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
else if ( fog == 3 )
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_TEXTURE_2D);
/* draw the fog panel */
v = ref * 4;
glBegin(GL_QUADS);
set_fog_color_alpha(v);
glVertex3f(vertices[v].x, vertices[v].y, vertices[v].z); v++;
set_fog_color_alpha(v);
glVertex3f(vertices[v].x, vertices[v].y, vertices[v].z); v++;
set_fog_color_alpha(v);
glVertex3f(vertices[v].x, vertices[v].y, vertices[v].z); v++;
set_fog_color_alpha(v);
glVertex3f(vertices[v].x, vertices[v].y, vertices[v].z);
glEnd();
/* restore rendering state */
glEnable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
}
}
/****************************************************/
/* Window Draw Event callback */
/****************************************************/
void display( pCpw cpw, uint_32 winid )
{
int n; /* counter */
/* clear all pixels in colour buffer */
glClear( GL_COLOR_BUFFER_BIT );
/* position viewer */
glLoadIdentity();
glTranslatef(0.0, -3.0, -32.0);
glRotatef(10.0, 1.0, 0.0, 0.0);
/* draw the panels */
for (n=0; n<NUM_PANELS; n++) {
if ( glExtInfo.EXT_fog_coord )
draw_panel_ext(n);
else
draw_panel_alpha(n);
}
cpwSwapWindowBuffers( cpw, winid );
}
/****************************************************/
/* Window Resize Event callback */
/****************************************************/
void reshape( pCpw cpw, uint_32 winid, uint_32 width, uint_32 height )
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(50, 1.0, 0.2, 40);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport( 0, 0, width, height );
}
/****************************************************/
/* Keyboard Event callback */
/****************************************************/
void keyboard( pCpw cpw, uint_32 id, uint_32 key, uint_32 state, uint_32 x, uint_32 y )
{
if ( state == CPW_KEYMOD_UP ) return;
if ( key == 'f' || key == 'F' ) fog++;
if ( fog == 4 ) fog = 1;
cpwPostRedisplay( cpw );
}
/****************************************************/
/* 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_RGBA );
cpwInitWindowProperty( cpw, CPW_WINDOWPROP_POSITION, 100, 100 );
cpwInitWindowProperty( cpw, CPW_WINDOWPROP_SIZE, 200, 200 );
cpwCreateWindow(cpw,"OpenGL Demo - Volumetric Fog");
glEnable( GL_CULL_FACE );
if ( !init(cpw) ) {
cpwFreeContext( &cpw );
return false;
}
cpwReshapeCallback( cpw, reshape );
cpwDisplayCallback(cpw,display);
cpwKeyboardCallback( cpw, keyboard );
cpwMainLoop(cpw);
cleanup();
return 0;