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

📄 cacti.cpp

📁 一本关于OPenGL的很好的电子书
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*****************************************************************************
 KillWindow()

 Deletes the DC, RC, and Window, and restores the original display.
*****************************************************************************/
BOOL KillWindow()
{
  // restore the original display if we're in fullscreen mode
  if (g_isFullscreen)
  {
    ChangeDisplaySettings(NULL, 0);
    ShowCursor(TRUE);
  }

  // if we have an RC, release it
  if (g_hrc)
  {
    // release the RC
    if (!wglMakeCurrent(NULL,NULL))
    {
      MessageBox(NULL, "Unable to release rendering context", "Error", MB_OK | MB_ICONINFORMATION);
    }

    // delete the RC
    if (!wglDeleteContext(g_hrc))
    {
      MessageBox(NULL, "Unable to delete rendering context", "Error", MB_OK | MB_ICONINFORMATION);
    }

    g_hrc = NULL;
  }

  // release the DC if we have one
  if (g_hdc && !ReleaseDC(g_hwnd, g_hdc))
  {
    MessageBox(NULL, "Unable to release device context", "Error", MB_OK | MB_ICONINFORMATION);
    g_hdc = NULL;
  }

  // destroy the window if we have a valid handle
  if (g_hwnd && !DestroyWindow(g_hwnd))
  {
    MessageBox(NULL, "Unable to destroy window", "Error", MB_OK | MB_ICONINFORMATION);
    g_hwnd = NULL;
  }

  // unregister our class so we can create a new one if we need to
  if (!UnregisterClass(WND_CLASS_NAME, g_hInstance))
  {
    MessageBox(NULL, "Unable to unregister window class", "Error", MB_OK | MB_ICONINFORMATION);
    g_hInstance = NULL;
  }

  return TRUE;
} // end KillWindow()


/*****************************************************************************
 ResizeScene()

 Called once when the application starts and again every time the window is
 resized by the user.
*****************************************************************************/
GLvoid ResizeScene(GLsizei width, GLsizei height)
{
  // avoid divide by zero
  if (height==0)  
  {
    height=1;
  }

  // set the viewport to the new dimensions
  glViewport(0, 0, width, height);

  // select the projection matrix and clear it out
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  // set the perspective with the appropriate aspect ratio
  gluPerspective(45.0f, (GLfloat)width/(GLfloat)height, 0.1f, 1000.0f);

  // select modelview matrix
  glMatrixMode(GL_MODELVIEW);
} // end ResizeScene()


/*****************************************************************************
 InitializeScene()

 Performs one-time application-specific setup. Returns FALSE on any failure.
*****************************************************************************/
BOOL InitializeScene()
{
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_TEXTURE_2D);
  glEnable(GL_CULL_FACE);
  glCullFace(GL_CCW);

  LoadTexture("cactus.bmp", g_cactus);
  LoadTexture("sand.bmp", g_sand);

  // make the background look like the sky
  float blue[4] = { 0.5, 0.5, 1.0, 0.0 };
  glClearColor(0.5, 0.5, 1.0, 0.0);

  // use a distant fog for a haze effect
  glEnable(GL_FOG);
  glFogfv(GL_FOG_COLOR, blue);
  glFogf(GL_FOG_MODE, GL_EXP2);
  glFogf(GL_FOG_START, 200);
  glFogf(GL_FOG_END, 1000);
  glFogf(GL_FOG_DENSITY, 0.002f);

  // load terrain arrays
  InitializeTerrain();

  // check for the compiled array extensions
  char *extList = (char *) glGetString(GL_EXTENSIONS);

  if (extList && strstr(extList, "GL_EXT_compiled_vertex_array"))
  {
    // get the address of the compiled array extensions
    glLockArraysEXT = (PFNGLLOCKARRAYSEXTPROC) wglGetProcAddress("glLockArraysEXT");
    glUnlockArraysEXT = (PFNGLUNLOCKARRAYSEXTPROC) wglGetProcAddress("glUnlockArraysEXT");
  }

  return TRUE;
} // end InitializeScene()


/*****************************************************************************
 InitializeTerrain()

 Create vertex arrays containing terrain data
*****************************************************************************/
void InitializeTerrain()
{
  // used to track current entry in the index array
  int index = 0;
  int currentVertex;

  // loop through all of the heightfield points, randomly generating height values
  for (int z = 0; z < MAP_Z; z++)
  {
    for (int x = 0; x < MAP_X; x++)
    {
      // set the world coordinates of this point
      g_terrain[x + z * MAP_X][0] = float(x)*MAP_SCALE;
      g_terrain[x + z * MAP_X][1] = 5.0f + FRAND * 5.0f;
      g_terrain[x + z * MAP_X][2] = -float(z)*MAP_SCALE;

      // vertices are numbered left to right, top to bottom
      currentVertex = z * MAP_X + x;

      // set the values in the color array
      g_colorArray[currentVertex][0] = g_colorArray[currentVertex][1] =
        g_colorArray[currentVertex][2] = g_terrain[x + z * MAP_X][1] / 20.0f + 0.5f;

      // set the values in the texture coordinate array. since the texture
      // is tiled over each "square", we can use texture wrapping
      g_texcoordArray[currentVertex][0] = (float) x;
      g_texcoordArray[currentVertex][1] = (float) z;

    }
  }

  // loop over all vertices in the terrain map
  for (z = 0; z < MAP_Z-1; z++)
  {
    for (int x = 0; x < MAP_X; x++)
    {
      // add next two elements to the triangle strip
      currentVertex = z * MAP_X + x;
      g_indexArray[index++] = currentVertex + MAP_X;
      g_indexArray[index++] = currentVertex;
    }
  }

  // enable the vertex arrays being used
  glEnableClientState(GL_VERTEX_ARRAY);
  glEnableClientState(GL_COLOR_ARRAY);
  glEnableClientState(GL_TEXTURE_COORD_ARRAY);

  // pass the pointers to OpenGL
  glVertexPointer(3, GL_FLOAT, 0, g_terrain);
  glColorPointer(3, GL_FLOAT, 0, g_colorArray);
  glTexCoordPointer(2, GL_FLOAT, 0, g_texcoordArray);
} // end InitializeArrays()


/*****************************************************************************
 DisplayScene()

 The work of the application is done here. This is called every frame, and
 handles the actual rendering of the scene.
*****************************************************************************/
BOOL DisplayScene()
{
  // used to track the orientation of the viewer
  static GLfloat s_eye[] = { MAP_X * MAP_SCALE * 0.5, 8.0, -MAP_Z * MAP_SCALE * 0.5};
  static GLfloat s_at[]  = { 0.0, 0.0, 0.0 };
  static GLfloat s_angle = -90.0;
  float speed = 0.3f;

  // check for rotation
  if (g_keys[VK_LEFT])
  {
    s_angle -= 2.0;
  }
  if (g_keys[VK_RIGHT])
  {
    s_angle += 2.0;
  }

  // run if the shift key is pressed
  if (KEY_DOWN(VK_SHIFT))
    speed = speed * 2;

  float rad =  float(PI*s_angle/180.0f);

  // check for forward and backward motion
  if (g_keys[VK_UP])
  {
    s_eye[2] += (float)sin(rad) * speed;
    s_eye[0] += (float)cos(rad) * speed;
  }
  if (g_keys[VK_DOWN])
  {
    s_eye[2] -= (float)sin(rad) * speed;
    s_eye[0] -= (float)cos(rad) * speed;
  }

  // do bound's checking to make sure they don't leave the map
  if (s_eye[0] < MAP_SCALE)
    s_eye[0] = MAP_SCALE;
  if (s_eye[0] > (MAP_X - 2) * MAP_SCALE)
    s_eye[0] = (MAP_X - 2) * MAP_SCALE;
  if (s_eye[2] < -(MAP_Z - 2) * MAP_SCALE)
    s_eye[2] = -(MAP_Z - 2) * MAP_SCALE;
  if (s_eye[2] > - MAP_SCALE)
    s_eye[2] = -MAP_SCALE;

  // set the eye position in relation to the ground
  s_eye[1] = GetHeight(s_eye[0], s_eye[2]) + 2.0f;

  //set the look at point to be at eye level in the direction the viewer is headed
  s_at[0] = float(s_eye[0] + 100*cos(rad));
  s_at[2] = float(s_eye[2] + 100*sin(rad));
  s_at[1] = s_eye[1];

  // set up the modelview matrix according to this viewer orientation
  glLoadIdentity();
  gluLookAt(s_eye[0], s_eye[1], s_eye[2],
    s_at[0], s_at[1], s_at[2],
    0.0, 1.0, 0.0
    );

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  DrawSand();
  DrawCacti();

  return TRUE;
} // end DisplayScene()


/*****************************************************************************
 Cleanup()

 Called at the end of successful program execution.
*****************************************************************************/
BOOL Cleanup()
{
  if (g_sand)
    glDeleteTextures(1, &g_sand);
  if (g_cactus)
    glDeleteTextures(1, &g_cactus);

  return TRUE;
} // end Cleanup()


/*****************************************************************************
 DrawCacti()

 Draw cacti as billboarded quads.
*****************************************************************************/
void DrawCacti()
{
  // make sure the random numbers we generate are the same every time
  srand(100);

  // make sure the transparent part of the texture isn't drawn
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glEnable(GL_ALPHA_TEST);
  glAlphaFunc(GL_GREATER, 0);

  // get the modelview matrix
  float mat[16];
  glGetFloatv(GL_MODELVIEW_MATRIX, mat);

  // get the right and up vectors
  vector3_t right(mat[0], mat[4], mat[8]);
  vector3_t up(mat[1], mat[5], mat[9]);

  // select the cactus texture
  glBindTexture(GL_TEXTURE_2D, g_cactus);
  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

  // draw all cacti
  glBegin(GL_QUADS);
  for (int n = 0; n < NUM_CACTI; n++)
  {
    // randomly size the cactus
    float size = 5.0f + FRAND + 3.0f;

    // pick a random position on the map 
    vector3_t pos(RAND_COORD((MAP_X - 1) * MAP_SCALE), 0.0, -RAND_COORD((MAP_Z - 1) * MAP_SCALE));
    pos.y = GetHeight(pos.x, pos.z) + size - 0.5f;

    // bottom left corner
    glTexCoord2f(0.0, 0.0); glVertex3fv((pos + (right + up) * -size).v);
    // bottom right corner
    glTexCoord2f(1.0, 0.0); glVertex3fv((pos + (right - up) * size).v);
    // top right corner
    glTexCoord2f(1.0, 1.0); glVertex3fv((pos + (right + up) * size).v);
    // top left corner
    glTexCoord2f(0.0, 1.0); glVertex3fv((pos + (up - right) * size).v);
  }
  glEnd();
  glDisable(GL_ALPHA);
  glDisable(GL_BLEND);
} // end DrawCacti()


/****************************************************************************
 DrawSand()

 Draw the terrain
*****************************************************************************/
void DrawSand()
{
  // select the sand texture
  glBindTexture(GL_TEXTURE_2D, g_sand);
  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  if (glLockArraysEXT)
    glLockArraysEXT(0, MAP_X * MAP_Z * 6);

  // loop through all the triangle strips
  for (int z = 0; z < MAP_Z-1; z++)
  {
    // draw the triangles in this strip
    glDrawElements(GL_TRIANGLE_STRIP, MAP_X * 2, GL_UNSIGNED_INT, &g_indexArray[z * MAP_X * 2]);
  }

  // if the compiled arrays extension is available, unlock the arrays
  if (glUnlockArraysEXT)
    glUnlockArraysEXT();
} // end DrawSand()


/****************************************************************************
 LoadTexture()

 Loads the texture from the specified file and stores it in iTexture.
*****************************************************************************/
void LoadTexture(char *filename, GLuint &texture)
{
  // get a texture object
  glGenTextures(1, &texture);
  glBindTexture(GL_TEXTURE_2D, texture);

  // load the bitmap
  BITMAPINFOHEADER bitmapInfoHeader;
  unsigned char *buffer = LoadBitmapFileWithAlpha(filename, &bitmapInfoHeader);

  // set up the 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_MIPMAP_NEAREST);
  glTexImage2D(GL_TEXTURE_2D, 0, 4, bitmapInfoHeader.biWidth, bitmapInfoHeader.biHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
  gluBuild2DMipmaps(GL_TEXTURE_2D, 4, bitmapInfoHeader.biWidth, bitmapInfoHeader.biHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

  // we're done with the bitmap data
  free(buffer);
} // end LoadTexture()


/*****************************************************************************
 GetHeight()

 Returns the height of the terrain at (x, z)
*****************************************************************************/
float GetHeight(float x, float z)
{
  // divide by the grid-spacing if it is not 1
  float projCameraX = x / MAP_SCALE;
  float projCameraZ = -z / MAP_SCALE;

	// compute the height field coordinates (hflCol0, hflRow0) and
  // (hflCol1, hflRow1) that identify the height field cell directly below the camera.
	int hflCol0 = int(projCameraX);
	int hflRow0 = int(projCameraZ);
	int hflCol1 = hflCol0 + 1;
	int hflRow1 = hflRow0 + 1;

	// get the four corner heights of the cell from the height field
	float h00 = g_terrain[hflCol0 + hflRow0*MAP_X][1];
	float h01 = g_terrain[hflCol1 + hflRow0*MAP_X][1];
	float h11 = g_terrain[hflCol1 + hflRow1*MAP_X][1];
	float h10 = g_terrain[hflCol0 + hflRow1*MAP_X][1];

	// calculate the position of the camera relative to the cell.
	// note, that 0 <= tx, ty <= 1.
	float tx = projCameraX - float(hflCol0);
	float ty = projCameraZ - float(hflRow0);

	// the next step is to perform a bilinear interpolation to compute the height
  // of the terrain directly below the object.
	float txty = tx * ty;

	return h00 * (1.0f - ty - tx + txty)
					+ h01 * (tx - txty)
					+ h11 * txty
					+ h10 * (ty - txty);
} // end GetHeight()

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -