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

📄 chapter10.cpp

📁 一个OpenGL的地形算法
💻 CPP
📖 第 1 页 / 共 2 页
字号:
  GLuint  pixelFormat;

  // choose best matching pixel format
  if (!(pixelFormat = ChoosePixelFormat(g_hdc, &pfd)))
  {
    MessageBox(NULL, "Can't find an appropriate pixel format", "Error", MB_OK | MB_ICONEXCLAMATION);
    return FALSE;
  }

  // set pixel format to device context
  if(!SetPixelFormat(g_hdc, pixelFormat,&pfd))
  {
    MessageBox(NULL, "Unable to set pixel format", "Error", MB_OK | MB_ICONEXCLAMATION);
    return FALSE;
  }

  // create the OpenGL rendering context
  if (!(g_hrc = wglCreateContext(g_hdc)))
  {
    MessageBox(NULL, "Unable to create OpenGL rendering context", "Error",MB_OK | MB_ICONEXCLAMATION);
    return FALSE;
  }

  // now make the rendering context the active one
  if(!wglMakeCurrent(g_hdc, g_hrc))
  {
    MessageBox(NULL,"Unable to activate OpenGL rendering context", "ERROR", MB_OK | MB_ICONEXCLAMATION);
    return FALSE;
  }

  // show the window in the forground, and set the keyboard focus to it
  ShowWindow(g_hwnd, SW_SHOW);
  SetForegroundWindow(g_hwnd);
  SetFocus(g_hwnd);

  // set up the perspective for the current screen size
  ResizeScene(width, height);

  // do one-time initialization
  if (!InitializeScene())
  {
    MessageBox(NULL, "Initialization failed", "Error", MB_OK | MB_ICONEXCLAMATION);
    return FALSE;
  }

  return TRUE;
} // end SetupWindow()


/*****************************************************************************
 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(54.0f, (GLfloat)width/(GLfloat)height, 1.0f, 1000.0f);

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


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

 Performs one-time application-specific setup. Returns FALSE on any failure.
*****************************************************************************/
BOOL InitializeScene()
{
  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);   // clear to black
  
  glShadeModel(GL_SMOOTH);        // use smooth shading
  glEnable(GL_DEPTH_TEST);        // hidden surface removal
  glEnable(GL_CULL_FACE);         // do not calculate inside of polys
  glFrontFace(GL_CCW);            // counter clock-wise polygons are out

  glEnable(GL_TEXTURE_2D);        // enable 2D texturing

  g_imageData = LoadBitmapFile("terrain2.bmp", &g_bitmapInfoHeader);

  // initialize the terrain data and load the textures
  InitializeTerrain();
  LoadTextures();

  // load terrain data into the arrays
  InitializeArrays();

  // 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");
  }

  // if the compiled arrays extension is available, lock the arrays
  if (glLockArraysEXT)
    glLockArraysEXT(0, MAP_X * MAP_Z);

  return TRUE;
} // end InitializeScene()


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

 The work of the application is done here. This is called every frame, and
 handles the actual rendering of the scene.
*****************************************************************************/
BOOL DisplayScene()
{
  static float waterHeight = 154.0f;   // height of water
  static bool  waterDir = true;        // used to animate water; true = up, false = down

  float radians =  float(PI*(g_angle-90.0f)/180.0f);

  // calculate the camera's position
  g_cameraPos[0] = g_lookAt[0] + (float)sin(radians) * g_mouseY;  // multiplying by mouseY makes the
  g_cameraPos[2] = g_lookAt[2] + (float)cos(radians) * g_mouseY;  // camera get closer/farther away with mouseY
  g_cameraPos[1] = g_lookAt[1] + g_mouseY / 2.0f;

  // calculate the camera look-at coordinates as the center of the terrain map
  g_lookAt[0] = (MAP_X*MAP_SCALE)/2.0f;
  g_lookAt[1] = 150.0f;
  g_lookAt[2] = -(MAP_Z*MAP_SCALE)/2.0f;

  // clear screen and depth buffer
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glLoadIdentity();

  // set the camera position
  gluLookAt(g_cameraPos[0], g_cameraPos[1], g_cameraPos[2],
    g_lookAt[0], g_lookAt[1], g_lookAt[2],
    0.0, 1.0, 0.0);
  
  // set the current texture to the land texture
  glBindTexture(GL_TEXTURE_2D, g_land);
  
  // 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]);
  }

  // enable blending
  glEnable(GL_BLEND);

  // enable read-only depth buffer
  glDepthMask(GL_FALSE);

  // set the blend function to what we use for transparency
  glBlendFunc(GL_SRC_ALPHA, GL_ONE);

  glColor4f(0.5f, 0.5f, 1.0f, 0.7f);      // set color to a transparent blue
  glBindTexture(GL_TEXTURE_2D, g_water);  // set texture to the water texture

  // draw water as one large quad surface
  glBegin(GL_QUADS);
    glTexCoord2f(0.0f, 0.0f);     // lower left corner
    glVertex3f(g_terrain[0][0], waterHeight, g_terrain[0][2]);

    glTexCoord2f(10.0f, 0.0f);    // lower right corner
    glVertex3f(g_terrain[MAP_X-1][0], waterHeight, g_terrain[MAP_X-1][2]);

    glTexCoord2f(10.0f, 10.0f);   // upper right corner
    glVertex3f(g_terrain[MAP_X-1 + MAP_X * (MAP_Z-1)][0], waterHeight, g_terrain[MAP_X-1 + MAP_X * (MAP_Z-1)][2]);

    glTexCoord2f(0.0f, 10.0f);    // upper left corner
    glVertex3f(g_terrain[MAP_X * (MAP_Z-1)][0], waterHeight, g_terrain[MAP_X * (MAP_Z-1)][2]);
  glEnd();

  // set back to normal depth buffer mode (writable)
  glDepthMask(GL_TRUE);

  // disable blending
  glDisable(GL_BLEND);

  // animate the water
  if (waterHeight > 155.0f)
    waterDir = false;
  else if (waterHeight < 154.0f)
    waterDir = true;

  if (waterDir)
    waterHeight += 0.01f;
  else
    waterHeight -= 0.01f;

  return TRUE;
} // end DisplayScene()


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

 Called at the end of successful program execution.
*****************************************************************************/
BOOL Cleanup()
{
  glDisableClientState(GL_VERTEX_ARRAY);
  glDisableClientState(GL_COLOR_ARRAY);
  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  free(g_imageData);

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

  return TRUE;
} // end Cleanup()


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

 Initializes the heightfield terrain data
*****************************************************************************/
void InitializeTerrain()
{
  // loop through all of the heightfield points, calculating
  // the coordinates for each point
  for (int z = 0; z < MAP_Z; z++)
  {
    for (int x = 0; x < MAP_X; x++)
    {
      g_terrain[x + MAP_X * z][0] = float(x)*MAP_SCALE;
      g_terrain[x + MAP_X * z][1] = (float)g_imageData[(z*MAP_Z+x)*3];
      g_terrain[x + MAP_X * z][2] = -float(z)*MAP_SCALE;
    }
  }
} // end InitializeTerrain()


/*****************************************************************************
 LoadTextures()

 Loads the data for the water and land textures and stores them in texture
 objects
*****************************************************************************/
bool LoadTextures()
{
  BITMAPINFOHEADER  landInfo;       // land texture info header
  BITMAPINFOHEADER  waterInfo;      // water texture info header
  unsigned char    *landTexture;    // land texture data
  unsigned char    *waterTexture;   // water texture data
  
  // load the land texture data
  landTexture = LoadBitmapFile("green.bmp", &landInfo);
  if (!landTexture)
    return false;

  // load the water texture data
  waterTexture = LoadBitmapFile("water.bmp", &waterInfo);
  if (!waterTexture)
  {
    free(landTexture);
    return false;
  }

  // generate the land texture as a mipmap
  glGenTextures(1, &g_land);
  glBindTexture(GL_TEXTURE_2D, g_land);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, landInfo.biWidth, landInfo.biHeight, GL_RGB, GL_UNSIGNED_BYTE, landTexture);
  
  // generate the water texture as a mipmap
  glGenTextures(1, &g_water);
  glBindTexture(GL_TEXTURE_2D, g_water);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, waterInfo.biWidth, waterInfo.biHeight, GL_RGB, GL_UNSIGNED_BYTE, waterTexture);

  free(landTexture);
  free(waterTexture);

  return true;
} // end LoadTextures()


/*****************************************************************************
 InitializeArrays()

 Loads the terrain data into 3 vertex arrays (vertex, color, and tex coord),
 as well as creating an index array.
*****************************************************************************/
void InitializeArrays()
{
  // used to track current entry in the index array
  int index = 0;
  int currentVertex;

  // loop over all vertices in the terrain map
  for (int z = 0; z < MAP_Z; z++)
  {
    for (int x = 0; x < MAP_X; x++)
    {
      // 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 + MAP_X * z][1]/255.0f;

      // 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;
    }
  }

  for (z = 0; z < MAP_Z - 1; z++)
  {
    for (int x = 0; x < MAP_X; x++)
    {
      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()

⌨️ 快捷键说明

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