📄 chapter10.cpp
字号:
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 + -