📄 chapter1.cpp
字号:
/****************************************************************************
chapter1.cpp
A simple OpenGL/GLUT demonstration showing a texture mapped, lit, spinning
cube reflecting in a surface.
This demo should give you a general idea of what GLUT is. For more
information, visit the official GLUT page at:
http://reality.sgi.com/opengl/glut3/glut3.html
Author : Dave Astle
Date : 8/23/2000
Written for OpenGL Game Programming
*****************************************************************************/
/********************************* Includes *********************************/
#include <gl\glaux.h>
#include <gl\glut.h>
#include <iostream.h>
#include "HiResTimer.h"
/*************************** Macros and constants ***************************/
enum rendermode_t {
RENDER_REFLECTED,
RENDER_SHADOW,
RENDER_NORMAL
};
const GLfloat DEGREES_PER_SECOND = 60.0f;
/******************************** Prototypes ********************************/
void Initialize();
void MouseHandler(int button, int state, int x, int y);
void KeyboardHandler(unsigned char key, int x, int y);
void MainMenuHandler(int option);
void Animate();
void Reshape(int width, int height);
void Display();
void LoadTexture(char *filename, GLuint &texture);
void DrawScene(rendermode_t mode);
void DrawCube();
void DrawSurface();
/********************************* Globals **********************************/
// index for the texture we'll load for the cube
GLuint g_cubeTexture;
// how much to rotate the cube around an axis
GLfloat g_rotationAngle = 0.0;
CHiResTimer g_timer;
/****************************************************************************
main()
Setup GLUT and OpenGL, drop into the event loop
*****************************************************************************/
int main(int argc, char **argv)
{
// Setup the basic GLUT stuff
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH | GLUT_STENCIL);
// Create the window
glutInitWindowSize(512, 512);
glutInitWindowPosition(400, 350);
glutCreateWindow("Chapter 1");
Initialize();
// Register the event callback functions
glutDisplayFunc(Display);
glutReshapeFunc(Reshape);
glutMouseFunc(MouseHandler);
glutKeyboardFunc(KeyboardHandler);
glutIdleFunc(Animate);
// At this point, control is relinquished to the GLUT event handler.
// Control is returned as events occur, via the callback functions.
glutMainLoop();
return 0;
} // end main()
/****************************************************************************
Initialize()
One time setup, including creating menus, creating a light, setting the
shading mode and clear color, and loading textures.
*****************************************************************************/
void Initialize()
{
// set up the only meny
int mainMenu;
mainMenu = glutCreateMenu(MainMenuHandler);
glutSetMenu(mainMenu);
glutAddMenuEntry("Exit", 0);
glutAttachMenu(GLUT_RIGHT_BUTTON);
g_timer.Init();
// set the background color
glClearColor(0.0, 0.0, 0.0, 0.0);
// set the shading model
glShadeModel(GL_SMOOTH);
// set up a single white light
GLfloat lightColor[] = { 1.0f, 1.0f, 1.0f, 1.0 };
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor);
glLightfv(GL_LIGHT0, GL_SPECULAR, lightColor);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
// load the texture for the cube
LoadTexture("opengl.bmp", g_cubeTexture);
// make the modelview matrix active, and initialize it
glMatrixMode(GL_MODELVIEW);
} // end Initialize()
/****************************************************************************
MouseHandler()
Handle mouse events. For this simple demo, just exit on a left click.
*****************************************************************************/
void MouseHandler(int button, int state, int x, int y)
{
switch (button)
{
case GLUT_LEFT_BUTTON:
{
exit(0);
} break;
default:
break;
}
// force a screen redraw
glutPostRedisplay();
} // end MouseHandler()
/****************************************************************************
KeyboardHandler()
Keyboard handler. Again, we'll just exit when q is pressed.
*****************************************************************************/
void KeyboardHandler(unsigned char key, int x, int y)
{
switch (key)
{
case 'q': // exit
{
exit(0);
} break;
default:
{
} break;
}
glutPostRedisplay();
} // end KeyboardHandler()
/****************************************************************************
MainMenuHandler()
Main menu callback.
*****************************************************************************/
void MainMenuHandler(int option)
{
switch(option)
{
case 0:
{
exit(0);
} break;
default:
break;
}
glutPostRedisplay();
} // end MainMenuHandler()
/****************************************************************************
Animate()
Rotate the cube by 4 degrees and force a redisplay.
*****************************************************************************/
void Animate()
{
glutPostRedisplay();
} // end Animate()
/****************************************************************************
Reshape()
Reset the viewport for window changes
*****************************************************************************/
void Reshape(int width, int height)
{
if (height == 0)
return;
glViewport(0, 0, (GLsizei) width, (GLsizei) height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90.0, width/height, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
} // end Reshape
/****************************************************************************
Display()
Clear and redraw the scene.
*****************************************************************************/
void Display()
{
g_rotationAngle += (DEGREES_PER_SECOND * g_timer.GetElapsedSeconds());
static int s_frames = 0;
if (++s_frames > 100)
{
cout << g_timer.GetFPS(100) << endl;
s_frames = 0;
}
// set up the view orientation looking at the origin from slightly above
// and to the left
glLoadIdentity();
gluLookAt(0.0, 1.0, 6.0,
0.0, 0.0, 0.0,
0.0, 1.0, 0.0);
// clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glRotatef(-g_rotationAngle/8.0, 0.0, 1.0, 0.0);
// draw the reflected cube first, with fog enable for a more realistic
// effect
glEnable(GL_FOG);
glFogf(GL_FOG_END, 5.0);
glFogf(GL_FOG_DENSITY, 0.4);
DrawScene(RENDER_REFLECTED);
glDisable(GL_FOG);
// now draw the scene with the shadow
DrawScene(RENDER_SHADOW);
// now draw the real cube
DrawScene(RENDER_NORMAL);
// draw everything and swap the display buffer
glFlush();
glutSwapBuffers();
} // end Display()
/****************************************************************************
LoadTexture()
Loads the texture from the specified file and stores it in iTexture. Note
that we're using the GLAUX library here, which is generally discouraged,
but in this case spares us having to write a bitmap loading routine.
*****************************************************************************/
void LoadTexture(char *filename, GLuint &texture)
{
AUX_RGBImageRec *image[1];
memset(image, 0, sizeof(void *));
// if the file can be read, load the texture
if (image[0] = auxDIBImageLoad(filename))
{
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
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);
glTexImage2D(GL_TEXTURE_2D, 0, 3, image[0]->sizeX, image[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image[0]->data);
}
// free memory if we need to
if (image[0])
{
if (image[0]->data)
{
free(image[0]->data);
}
free(image[0]);
}
} // end LoadTexture()
/****************************************************************************
DrawScene()
Renders the texture mapped cube at the proper location and rotation. If
isMirrored is true, the reflected version will be drawn.
*****************************************************************************/
void DrawScene(rendermode_t mode)
{
glPushMatrix();
switch (mode)
{
case RENDER_REFLECTED:
{
// since the user can move the view, and we know that the cube is
// completely reflected in the surface, we can get cheap reflection
// by merely flipping the cube and light around the xz plane
GLfloat lightPos[4] = {3.0, -10.0, 3.0, 1.0};
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
glScalef(1.0, -1.0, 1.0);
DrawCube();
} break;
case RENDER_SHADOW:
{
// set up a projective shadow
GLfloat lightPos[4] = {3.0, 10.0, 3.0, 1.0};
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
// since the scene is static and the plane we're projecting the
// shadow on is y=0, we can use a simplified matrix
GLfloat shadowMatrix[16] = {
lightPos[1], 0.0, 0.0, 0.0,
-lightPos[0], 0.0, -lightPos[2], -1.0,
0.0, 0.0, lightPos[1], 0.0,
0.0, 0.0, 0.0, lightPos[1]
};
// set up the stencil buffer so that we only draw the shadow
// on the reflecting surface
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 3, 0xFFFFFFFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
DrawSurface();
glStencilFunc(GL_LESS, 2, 0xFFFFFFFF);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
glEnable(GL_POLYGON_OFFSET_FILL);
// draw the shadow as half-blended black
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_LIGHTING);
glColor4f(0.0, 0.0, 0.0, 0.5);
// project the cube through the shadow matrix
glMultMatrixf(shadowMatrix);
DrawCube();
glDisable(GL_BLEND);
glEnable(GL_LIGHTING);
glDisable(GL_POLYGON_OFFSET_FILL);
glDisable(GL_STENCIL_TEST);
} break;
case RENDER_NORMAL:
{
GLfloat lightPos[4] = {3.0, 10.0, 3.0, 1.0};
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
DrawCube();
} break;
default:
break;
};
glPopMatrix();
} // end DrawCube()
/****************************************************************************
DrawCube()
Draws the rotating cube
*****************************************************************************/
void DrawCube()
{
// set the color of the cube's surface
GLfloat cubeColor[] = { 1.0f, 1.0f, 1.0f, 1.0 };
glMaterialfv(GL_FRONT, GL_SPECULAR, cubeColor);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cubeColor);
glMaterialf(GL_FRONT, GL_SHININESS, 50.0);
glTranslatef(0.0, 2.0, 0.0);
glRotatef(g_rotationAngle, 1.0, 0.5, 1.0);
// set up the cube's texture
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBindTexture(GL_TEXTURE_2D, g_cubeTexture);
// the cube will just be drawn as six quads for the sake of simplicity
// for each face, we specify the quad's normal (for lighting), then
// specify the quad's 4 vertices and associated texture coordinates
glBegin(GL_QUADS);
// front
glNormal3f(0.0, 0.0, 1.0);
glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0, 1.0);
glTexCoord2f(1.0, 0.0); glVertex3f(1.0, -1.0, 1.0);
glTexCoord2f(1.0, 1.0); glVertex3f(1.0, 1.0, 1.0);
glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, 1.0);
// back
glNormal3f(0.0, 0.0, -1.0);
glTexCoord2f(0.0, 0.0); glVertex3f(1.0, -1.0, -1.0);
glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, -1.0, -1.0);
glTexCoord2f(1.0, 1.0); glVertex3f(-1.0, 1.0, -1.0);
glTexCoord2f(0.0, 1.0); glVertex3f(1.0, 1.0, -1.0);
// top
glNormal3f(0.0, 1.0, 0.0);
glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, 1.0, 1.0);
glTexCoord2f(1.0, 0.0); glVertex3f(1.0, 1.0, 1.0);
glTexCoord2f(1.0, 1.0); glVertex3f(1.0, 1.0, -1.0);
glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, -1.0);
// bottom
glNormal3f(0.0, -1.0, 0.0);
glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0, -1.0);
glTexCoord2f(1.0, 0.0); glVertex3f(1.0, -1.0, -1.0);
glTexCoord2f(1.0, 1.0); glVertex3f(1.0, -1.0, 1.0);
glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, -1.0, 1.0);
// left
glNormal3f(-1.0, 0.0, 0.0);
glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0, -1.0);
glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, -1.0, 1.0);
glTexCoord2f(1.0, 1.0); glVertex3f(-1.0, 1.0, 1.0);
glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, -1.0);
// right
glNormal3f(1.0, 0.0, 0.0);
glTexCoord2f(0.0, 0.0); glVertex3f(1.0, -1.0, 1.0);
glTexCoord2f(1.0, 0.0); glVertex3f(1.0, -1.0, -1.0);
glTexCoord2f(1.0, 1.0); glVertex3f(1.0, 1.0, -1.0);
glTexCoord2f(0.0, 1.0); glVertex3f(1.0, 1.0, 1.0);
glEnd();
glDisable(GL_TEXTURE_2D);
} // end DrawCube()
/****************************************************************************
DrawSurface()
Draws a simple plane to provide a reflection surface.
*****************************************************************************/
void DrawSurface()
{
// make sure the light is positioned correctly
GLfloat lightPos[4] = {3.0, 3.0, 3.0, 1.0};
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
// set up the surface's color
GLfloat surfaceColor[] = { 0.2f, 0.4f, 0.2f, 0.5 };
glMaterialfv(GL_FRONT, GL_SPECULAR, surfaceColor);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, surfaceColor);
glMaterialf(GL_FRONT, GL_SHININESS, 200.0);
// set up blending so we can see the reflected cube through the
// surface, and thus create the illusion of reflection
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBegin(GL_QUADS);
glNormal3f(0.0, 1.0, 0.0);
// to have lighting effects show up at all, we need to draw the
// surface as a lot of quads, not just one
GLfloat x = -5.0, z = -5.0;
for (GLint i = 0; i < 10; i++, x += 1)
{
for (GLint j = 0; j < 10; j++, z += 1)
{
// draw the plane slightly offset so the shadow shows up
glVertex3f(x, -0.1, z);
glVertex3f(x + 1.0, -0.1, z);
glVertex3f(x + 1.0, -0.1, z + 1.0);
glVertex3f(x, -0.1, z + 1.0);
}
z = -5.0;
}
glEnd();
glDisable(GL_BLEND);
} // end DrawSurface()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -