⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chapter1.cpp

📁 一本关于OPenGL的很好的电子书
💻 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 + -