download original
// ----------------------
// OpenGL cube demo.
//
// Written by Chris Halsall (chalsall@chalsall.com) for the
// O'Reilly Network on Linux.com (oreilly.linux.com).
// May 2000.
//
// Released into the Public Domain; do with it as you wish.
// We would like to hear about interesting uses.
//
// Coded to the groovy tunes of Yello: Pocket Universe.
#define PROGRAM_TITLE "O'Reilly Net: OpenGL Demo -- C.Halsall"
#include <stdio.h> // Always a good idea.
#include <time.h> // For our FPS stats.
#include <GL/gl.h> // OpenGL itself.
#include <GL/glu.h> // GLU support library.
#include <GL/glut.h> // GLUT support library.
// Some global variables.
// Window and texture IDs, window width and height.
int Texture_ID;
int Window_ID;
int Window_Width = 300;
int Window_Height = 300;
// Our display mode settings.
int Light_On = 0;
int Blend_On = 0;
int Texture_On = 0;
int Filtering_On = 0;
int Alpha_Add = 0;
int Curr_TexMode = 0;
char *TexModesStr[] = {"GL_DECAL","GL_MODULATE","GL_BLEND","GL_REPLACE"};
GLint TexModes[] = {GL_DECAL,GL_MODULATE,GL_BLEND,GL_REPLACE};
// Object and scene global variables.
// Cube position and rotation speed variables.
float X_Rot = 0.9f;
float Y_Rot = 0.0f;
float X_Speed = 0.0f;
float Y_Speed = 0.5f;
float Z_Off =-5.0f;
// Settings for our light. Try playing with these (or add more lights).
float Light_Ambient[]= { 0.1f, 0.1f, 0.1f, 1.0f };
float Light_Diffuse[]= { 1.2f, 1.2f, 1.2f, 1.0f };
float Light_Position[]= { 2.0f, 2.0f, 0.0f, 1.0f };
// ------
// Frames per second (FPS) statistic variables and routine.
#define FRAME_RATE_SAMPLES 50
int FrameCount=0;
float FrameRate=0;
static void ourDoFPS(
)
{
static clock_t last=0;
clock_t now;
float delta;
if (++FrameCount >= FRAME_RATE_SAMPLES) {
now = clock();
delta= (now - last) / (float) CLOCKS_PER_SEC;
last = now;
FrameRate = FRAME_RATE_SAMPLES / delta;
FrameCount = 0;
}
}
// ------
// String rendering routine; leverages on GLUT routine.
static void ourPrintString(
void *font,
char *str
)
{
int i,l=strlen(str);
for(i=0;i<l;i++)
glutBitmapCharacter(font,*str++);
}
// ------
// Routine which actually does the drawing
void cbRenderScene(
void
)
{
char buf[80]; // For our strings.
// Enables, disables or otherwise adjusts as
// appropriate for our current settings.
if (Texture_On)
glEnable(GL_TEXTURE_2D);
else
glDisable(GL_TEXTURE_2D);
if (Light_On)
glEnable(GL_LIGHTING);
else
glDisable(GL_LIGHTING);
if (Alpha_Add)
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
else
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
// If we're blending, we don't want z-buffering.
if (Blend_On)
glDisable(GL_DEPTH_TEST);
else
glEnable(GL_DEPTH_TEST);
if (Filtering_On) {
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_LINEAR);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
} else {
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,
GL_NEAREST_MIPMAP_NEAREST);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
}
// Need to manipulate the ModelView matrix to move our model around.
glMatrixMode(GL_MODELVIEW);
// Reset to 0,0,0; no rotation, no scaling.
glLoadIdentity();
// Move the object back from the screen.
glTranslatef(0.0f,0.0f,Z_Off);
// Rotate the calculated amount.
glRotatef(X_Rot,1.0f,0.0f,0.0f);
glRotatef(Y_Rot,0.0f,1.0f,0.0f);
// Clear the color and depth buffers.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// OK, let's start drawing our planer quads.
glBegin(GL_QUADS);
// Bottom Face. Red, 75% opaque, magnified texture
glNormal3f( 0.0f, -1.0f, 0.0f); // Needed for lighting
glColor4f(0.9,0.2,0.2,.75); // Basic polygon color
glTexCoord2f(0.800f, 0.800f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.200f, 0.800f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(0.200f, 0.200f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(0.800f, 0.200f); glVertex3f(-1.0f, -1.0f, 1.0f);
// Top face; offset. White, 50% opaque.
glNormal3f( 0.0f, 1.0f, 0.0f); glColor4f(0.5,0.5,0.5,.5);
glTexCoord2f(0.005f, 1.995f); glVertex3f(-1.0f, 1.3f, -1.0f);
glTexCoord2f(0.005f, 0.005f); glVertex3f(-1.0f, 1.3f, 1.0f);
glTexCoord2f(1.995f, 0.005f); glVertex3f( 1.0f, 1.3f, 1.0f);
glTexCoord2f(1.995f, 1.995f); glVertex3f( 1.0f, 1.3f, -1.0f);
// Far face. Green, 50% opaque, non-uniform texture cooridinates.
glNormal3f( 0.0f, 0.0f,-1.0f); glColor4f(0.2,0.9,0.2,.5);
glTexCoord2f(0.995f, 0.005f); glVertex3f(-1.0f, -1.0f, -1.3f);
glTexCoord2f(2.995f, 2.995f); glVertex3f(-1.0f, 1.0f, -1.3f);
glTexCoord2f(0.005f, 0.995f); glVertex3f( 1.0f, 1.0f, -1.3f);
glTexCoord2f(0.005f, 0.005f); glVertex3f( 1.0f, -1.0f, -1.3f);
// Right face. Blue; 25% opaque
glNormal3f( 1.0f, 0.0f, 0.0f); glColor4f(0.2,0.2,0.9,.25);
glTexCoord2f(0.995f, 0.005f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(0.995f, 0.995f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.005f, 0.995f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.005f, 0.005f); glVertex3f( 1.0f, -1.0f, 1.0f);
// Front face; offset. Multi-colored, 50% opaque.
glNormal3f( 0.0f, 0.0f, 1.0f);
glColor4f( 0.9f, 0.2f, 0.2f, 0.5f);
glTexCoord2f( 0.005f, 0.005f); glVertex3f(-1.0f, -1.0f, 1.3f);
glColor4f( 0.2f, 0.9f, 0.2f, 0.5f);
glTexCoord2f( 0.995f, 0.005f); glVertex3f( 1.0f, -1.0f, 1.3f);
glColor4f( 0.2f, 0.2f, 0.9f, 0.5f);
glTexCoord2f( 0.995f, 0.995f); glVertex3f( 1.0f, 1.0f, 1.3f);
glColor4f( 0.1f, 0.1f, 0.1f, 0.5f);
glTexCoord2f( 0.005f, 0.995f); glVertex3f(-1.0f, 1.0f, 1.3f);
// Left Face; offset. Yellow, varying levels of opaque.
glNormal3f(-1.0f, 0.0f, 0.0f);
glColor4f(0.9,0.9,0.2,0.0);
glTexCoord2f(0.005f, 0.005f); glVertex3f(-1.3f, -1.0f, -1.0f);
glColor4f(0.9,0.9,0.2,0.66);
glTexCoord2f(0.995f, 0.005f); glVertex3f(-1.3f, -1.0f, 1.0f);
glColor4f(0.9,0.9,0.2,1.0);
glTexCoord2f(0.995f, 0.995f); glVertex3f(-1.3f, 1.0f, 1.0f);
glColor4f(0.9,0.9,0.2,0.33);
glTexCoord2f(0.005f, 0.995f); glVertex3f(-1.3f, 1.0f, -1.0f);
// All polygons have been drawn.
glEnd();
// Move back to the origin (for the text, below).
glLoadIdentity();
// We need to change the projection matrix for the text rendering.
glMatrixMode(GL_PROJECTION);
// But we like our current view too; so we save it here.
glPushMatrix();
// Now we set up a new projection for the text.
glLoadIdentity();
glOrtho(0,Window_Width,0,Window_Height,-1.0,1.0);
// Lit or textured text looks awful.
glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
// We don't want depth-testing either.
glDisable(GL_DEPTH_TEST);
// But, for fun, let's make the text partially transparent too.
glColor4f(0.6,1.0,0.6,.75);
// Render our various display mode settings.
sprintf(buf,"Mode: %s", TexModesStr[Curr_TexMode]);
glRasterPos2i(2,2); ourPrintString(GLUT_BITMAP_HELVETICA_12,buf);
sprintf(buf,"AAdd: %d", Alpha_Add);
glRasterPos2i(2,14); ourPrintString(GLUT_BITMAP_HELVETICA_12,buf);
sprintf(buf,"Blend: %d", Blend_On);
glRasterPos2i(2,26); ourPrintString(GLUT_BITMAP_HELVETICA_12,buf);
sprintf(buf,"Light: %d", Light_On);
glRasterPos2i(2,38); ourPrintString(GLUT_BITMAP_HELVETICA_12,buf);
sprintf(buf,"Tex: %d", Texture_On);
glRasterPos2i(2,50); ourPrintString(GLUT_BITMAP_HELVETICA_12,buf);
sprintf(buf,"Filt: %d", Filtering_On);
glRasterPos2i(2,62); ourPrintString(GLUT_BITMAP_HELVETICA_12,buf);
// Now we want to render the calulated FPS at the top.
// To ease, simply translate up. Note we're working in screen
// pixels in this projection.
glTranslatef(6.0f,Window_Height - 14,0.0f);
// Make sure we can read the FPS section by first placing a
// dark, mostly opaque backdrop rectangle.
glColor4f(0.2,0.2,0.2,0.75);
glBegin(GL_QUADS);
glVertex3f( 0.0f, -2.0f, 0.0f);
glVertex3f( 0.0f, 12.0f, 0.0f);
glVertex3f(140.0f, 12.0f, 0.0f);
glVertex3f(140.0f, -2.0f, 0.0f);
glEnd();
glColor4f(0.9,0.2,0.2,.75);
sprintf(buf,"FPS: %f F: %2d", FrameRate, FrameCount);
glRasterPos2i(6,0);
ourPrintString(GLUT_BITMAP_HELVETICA_12,buf);
// Done with this special projection matrix. Throw it away.
glPopMatrix();
// All done drawing. Let's show it.
glutSwapBuffers();
// Now let's do the motion calculations.
X_Rot+=X_Speed;
Y_Rot+=Y_Speed;
// And collect our statistics.
ourDoFPS();
}
// ------
// Callback function called when a normal key is pressed.
void cbKeyPressed(
unsigned char key,
int x, int y
)
{
switch (key) {
case 113: case 81: case 27: // Q (Escape) - We're outta here.
glutDestroyWindow(Window_ID);
exit(1);
break; // exit doesn't return, but anyway...
case 130: case 98: // B - Blending.
Blend_On = Blend_On ? 0 : 1;
if (!Blend_On)
glDisable(GL_BLEND);
else
glEnable(GL_BLEND);
break;
case 108: case 76: // L - Lighting
Light_On = Light_On ? 0 : 1;
break;
case 109: case 77: // M - Mode of Blending
if ( ++ Curr_TexMode > 3 )
Curr_TexMode=0;
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,TexModes[Curr_TexMode]);
break;
case 116: case 84: // T - Texturing.
Texture_On = Texture_On ? 0 : 1;
break;
case 97: case 65: // A - Alpha-blending hack.
Alpha_Add = Alpha_Add ? 0 : 1;
break;
case 102: case 70: // F - Filtering.
Filtering_On = Filtering_On ? 0 : 1;
break;
case 115: case 83: case 32: // F (Space) - Freeze!
X_Speed=Y_Speed=0;
break;
case 114: case 82: // R - Reverse.
X_Speed=-X_Speed;
Y_Speed=-Y_Speed;
break;
default:
printf ("KP: No action for %d.\n", key);
break;
}
}
// ------
// Callback Function called when a special key is pressed.
void cbSpecialKeyPressed(
int key,
int x,
int y
)
{
switch (key) {
case GLUT_KEY_PAGE_UP: // move the cube into the distance.
Z_Off -= 0.05f;
break;
case GLUT_KEY_PAGE_DOWN: // move the cube closer.
Z_Off += 0.05f;
break;
case GLUT_KEY_UP: // decrease x rotation speed;
X_Speed -= 0.01f;
break;
case GLUT_KEY_DOWN: // increase x rotation speed;
X_Speed += 0.01f;
break;
case GLUT_KEY_LEFT: // decrease y rotation speed;
Y_Speed -= 0.01f;
break;
case GLUT_KEY_RIGHT: // increase y rotation speed;
Y_Speed += 0.01f;
break;
default:
printf ("SKP: No action for %d.\n", key);
break;
}
}
// ------
// Function to build a simple full-color texture with alpha channel,
// and then create mipmaps. This could instead load textures from
// graphics files from disk, or render textures based on external
// input.
void ourBuildTextures(
void
)
{
GLenum gluerr;
GLubyte tex[128][128][4];
int x,y,t;
int hole_size = 3300; // ~ == 57.45 ^ 2.
// Generate a texture index, then bind it for future operations.
glGenTextures(1,&Texture_ID);
glBindTexture(GL_TEXTURE_2D,Texture_ID);
// Iterate across the texture array.
for(y=0;y<128;y++) {
for(x=0;x<128;x++) {
// A simple repeating squares pattern.
// Dark blue on white.
if ( ( (x+4)%32 < 8 ) && ( (y+4)%32 < 8)) {
tex[x][y][0]=tex[x][y][1]=0; tex[x][y][2]=120;
} else {
tex[x][y][0]=tex[x][y][1]=tex[x][y][2]=240;
}
// Make a round dot in the texture's alpha-channel.
// Calculate distance to center (squared).
t = (x-64)*(x-64) + (y-64)*(y-64) ;
if ( t < hole_size) // Don't take square root; compare squared.
tex[x][y][3]=255; // The dot itself is opaque.
else if (t < hole_size + 100)
tex[x][y][3]=128; // Give our dot an anti-aliased edge.
else
tex[x][y][3]=0; // Outside of the dot, it's transparent.
}
}
// The GLU library helps us build MipMaps for our texture.
if ((gluerr=gluBuild2DMipmaps(GL_TEXTURE_2D, 4, 128, 128, GL_RGBA,
GL_UNSIGNED_BYTE, (void *)tex))) {
fprintf(stderr,"GLULib%s\n",gluErrorString(gluerr));
exit(-1);
}
// Some pretty standard settings for wrapping and filtering.
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
// We start with GL_DECAL mode.
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
}
// ------
// Callback routine executed whenever our window is resized. Lets us
// request the newly appropriate perspective projection matrix for
// our needs. Try removing the gluPerspective() call to see what happens.
void cbResizeScene(
int Width,
int Height
)
{
// Let's not core dump, no matter what.
if (Height == 0)
Height = 1;
glViewport(0, 0, Width, Height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW);
Window_Width = Width;
Window_Height = Height;
}
// ------
// Does everything needed before losing control to the main
// OpenGL event loop.
void ourInit(
int Width,
int Height
)
{
ourBuildTextures();
// Color to clear color buffer to.
glClearColor(0.1f, 0.1f, 0.1f, 0.0f);
// Depth to clear depth buffer to; type of test.
glClearDepth(1.0);
glDepthFunc(GL_LESS);
// Enables Smooth Color Shading; try GL_FLAT for (lack of) fun.
glShadeModel(GL_SMOOTH);
// Load up the correct perspective matrix; using a callback directly.
cbResizeScene(Width,Height);
// Set up a light, turn it on.
glLightfv(GL_LIGHT1, GL_POSITION, Light_Position);
glLightfv(GL_LIGHT1, GL_AMBIENT, Light_Ambient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, Light_Diffuse);
glEnable (GL_LIGHT1);
// A handy trick -- have surface material mirror the color.
glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
}
// ------
// The main() function. Inits OpenGL. Calls our own init function,
// then passes control onto OpenGL.
int main(
int argc,
char **argv
)
{
glutInit(&argc, argv);
// To see OpenGL drawing, take out the GLUT_DOUBLE request.
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
//glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(Window_Width, Window_Height);
// Open a window
Window_ID = glutCreateWindow( PROGRAM_TITLE );
// Register the callback function to do the drawing.
glutDisplayFunc(&cbRenderScene);
// If there's nothing to do, draw.
glutIdleFunc(&cbRenderScene);
// It's a good idea to know when our window's resized.
glutReshapeFunc(&cbResizeScene);
// And let's get some keyboard input.
glutKeyboardFunc(&cbKeyPressed);
glutSpecialFunc(&cbSpecialKeyPressed);
// OK, OpenGL's ready to go. Let's call our own init function.
ourInit(Window_Width, Window_Height);
// Print out a bit of help dialog.
printf("\n" PROGRAM_TITLE "\n\n\
Use arrow keys to rotate, 'R' to reverse, 'S' to stop.\n\
Page up/down will move cube away from/towards camera.\n\n\
Use first letter of shown display mode settings to alter.\n\n\
Q or [Esc] to quit; OpenGL window must have focus for input.\n");
// Pass off control to OpenGL.
// Above functions are called as appropriate.
glutMainLoop();
return 1;
}
back to cube
(C) 1998-2017 Olaf Klischat <olaf.klischat@gmail.com>