#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include <gl\glaux.h>
#define MAP_SIZE 1024 // .raw高程映射文件的大小
#define STEP_SIZE 16 // 每个三角形网格的宽度和高度
#define HEIGHT_RATIO 1.5f // This is the ratio that the Y is scaled according to the X and Z
#define MAX_TEXTURES 1000 // 最大的纹理数目
#define SCREEN_WIDTH 1000
#define SCREEN_HEIGHT 500 // 700
#define SCREEN_DEPTH 16
// glInterface.cpp --- opengl 简洁界面
#define eInfo(a) { DWORD er=GetLastError(); LPTSTR psz; \
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER,0,er,0,(LPTSTR)&psz,0,0); \
MessageBox(0,psz,a,0); LocalFree(psz); }
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
void InitApp(HWND hWnd); // 初始化整个程序
void clearApp(); // 释放程序占用的内存空间
void RenderScene(); // 渲染场景
#include <math.h>
#define PI 3.14159265358979323846
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "glaux.lib")
#include <d3dx.h>
#pragma comment(lib, "d3dx.lib")
#pragma comment(lib, "Winmm.lib") //for timeGetTime
HWND g_hWnd;
HDC g_hDC;
HGLRC g_hRC;
bool g_bRenderMode = true; // 渲染模式
UINT g_Texture[MAX_TEXTURES] = {0};
// 各位置的纹理ID
#define BACK_ID 1
#define FRONT_ID 2
#define BOTTOM_ID 3
#define TOP_ID 4
#define LEFT_ID 5
#define RIGHT_ID 6
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, int){
WNDCLASS wc={ CS_HREDRAW | CS_VREDRAW, WndProc, 0,0, hInstance,
LoadIcon(NULL, IDI_APPLICATION),LoadCursor(NULL, IDC_ARROW),
(HBRUSH) (COLOR_WINDOW+1), 0, "GameTutorials", };
RegisterClass(&wc);
DWORD dwStyle=0;
if(!dwStyle) dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
int width=SCREEN_WIDTH, height=SCREEN_HEIGHT;
RECT rcw={0,0,width,height,}; AdjustWindowRect( &rcw, dwStyle, false);
HWND hWnd = CreateWindow("GameTutorials", " 地形模拟 ", dwStyle, 200, 20, rcw.right-rcw.left, rcw.bottom-rcw.top,0, 0, hInstance, 0);
if(!hWnd) return true;
ShowWindow(hWnd, SW_SHOWNORMAL); UpdateWindow(hWnd); // SetFocus(hWnd);
InitApp(hWnd); // 初始化OpenGL
MSG msg; // MainLoop();
while(1){
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){
if(msg.message == WM_QUIT) break;
TranslateMessage(&msg); DispatchMessage(&msg);
}else{ RenderScene(); }
} // while
clearApp();
UnregisterClass("GameTutorials", hInstance);
return(msg.wParam);
}
bool setPixelFormat(HDC hdc){
PIXELFORMATDESCRIPTOR pfd={sizeof(pfd),1, PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER, // | PFD_SUPPORT_OPENGL
PFD_TYPE_RGBA,SCREEN_DEPTH, 0, };
int pf; if ( (pf = ChoosePixelFormat(hdc, &pfd)) == FALSE ){ eInfo("ChoosePixelFormat"); return FALSE; }
if (SetPixelFormat(hdc, pf, &pfd) == FALSE) { eInfo("SetPixelFormat"); return FALSE; }
return TRUE;
}
void glView(int w, int h){
if (h==0) h=1;
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f,(float)w/h, 4 ,4000.0f);
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
}
void glInit(int w, int h) {
g_hDC = GetDC(g_hWnd); if (!setPixelFormat(g_hDC)) PostQuitMessage (0);
g_hRC = wglCreateContext(g_hDC); wglMakeCurrent(g_hDC, g_hRC);
glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST);
glView(w, h);
}
void clearApp(){
if (g_hRC){ wglMakeCurrent(0, 0); wglDeleteContext(g_hRC); }
if (g_hDC) ReleaseDC(g_hWnd, g_hDC);
PostQuitMessage (0);
}
//.................. Textures ..................//
bool CreateTexture(UINT &texture, LPSTR strFileName){ if(!strFileName) return false;
FILE *pFile = NULL;
if((pFile = fopen(strFileName, "rb")) == NULL) { // 以只读模式打开文件
MessageBox(g_hWnd, "Unable to load BMP File!", "Error", MB_OK); // 如果文件无法打开,则显示错误信息
return NULL; }
AUX_RGBImageRec *pImage = auxDIBImageLoad(strFileName); // 装入位图
if(pImage == NULL) return false; // 确保位图数据已经装入
glGenTextures(1, &texture); // 生成纹理
glPixelStorei (GL_UNPACK_ALIGNMENT, 1); // 设置像素格式
glBindTexture(GL_TEXTURE_2D, texture); // 捆绑纹理
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, pImage->sizeX, pImage->sizeY, GL_RGB, GL_UNSIGNED_BYTE, pImage->data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
// 释放位图数据占据的内存资源
if(pImage){ if(pImage->data) free(pImage->data);
free(pImage); }
return true;
}
//------------------ Textures ------------------//
#define texUV(x,z) glTexCoord2f( (float)x/ MAP_SIZE, - (float)z/MAP_SIZE )
void InitApp(HWND hWnd){
g_hWnd = hWnd;
RECT g_rRect; GetClientRect(g_hWnd, &g_rRect);
glInit(g_rRect.right, g_rRect.bottom);
// 读入"Terrain.raw"文件,作为高程数据
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
// glEnable(GL_CULL_FACE);
glShadeModel(GL_SMOOTH);
CreateTexture(g_Texture[0], "wall.bmp");
CreateTexture(g_Texture[1], "wall1.bmp");
}
// getFPS, 计算帧率, 每 1 秒内显示帧的个数.
// fi, frame interval, 若非空, 则记录当前帧与前一帧之间的时间间隔(秒).
float getFPS(float*fi){
static float fps = 0.0f; // 帧率, 每 1 秒内显示帧的个数, framesPerSecond.
static float lastSecond = 0.0f; // 前一秒的标记时刻, 每秒更新一次.
static float lastTime = 0.0f; // 前一帧时刻, 每帧(的秒数)更新一次
static float currentTime=timeGetTime() * 0.001f; // 当前帧时刻
// static char strFrameRate[50] = {0};
currentTime= timeGetTime() * 0.001f; // 当前帧时刻 : milliseconds -- /1000 --> seconds
if(fi)*fi= currentTime - lastTime; // static float m_FrameInterval; m_FrameInterval = currentTime - lastTime; // 两帧之间的时间间隔
lastTime = currentTime;
++fps; // 帧计数器递增
if( currentTime - lastSecond > 1.0f ){
lastSecond = currentTime; // sprintf(strFrameRate, "地形模拟 当前帧率:每秒 %d 帧", int(fps)); SetWindowText(g_hWnd, strFrameRate);
fps = 0; // 帧计数器复位
} // if(...)
return fps;
}
// RotateAxis, 将vIn 绕vAixs 旋转角度 a, 公式:
// x'=(x*n)n(1-cosθ) + cosθx + sinθn×x
D3DXVECTOR3* D3DXVec3RotateAxis(D3DXVECTOR3*vOut, const D3DXVECTOR3*vIn, float a, const D3DXVECTOR3*vAxis){
if(!vOut || !vIn || !vAxis) return 0L;
D3DXVECTOR3 xv, x=*vIn, n=*vAxis; D3DXVec3Normalize(&n,&n);
float p=D3DXVec3Dot(&x,&n); // p=x*n
float ca = cos(a), sa = sin(a);
D3DXVec3Cross(&xv,&n,&x);
*vOut=p*(1-ca)*n+ca*x+sa*xv;
return vOut;
}
#define kSpeed 180.0f // in Camera.h
// aimCamera, 实时调整摄像机位置. 关键调用: gluLookAt( ... );
void aimCamera(){
// 摄像机基本参数: // g_Camera.PositionCamera( 280, 35, 225, 281, 35, 225, 0, 1, 0);
static D3DXVECTOR3 g_vLookat(700,0,800); //280, 35, -225 m_vPosition
static D3DXVECTOR3 g_vEye(600,35*3,-800); // m_vView
static D3DXVECTOR3 g_vUp(0,1,0); // m_vUpVector 摄像机初始参数: 0--x, 1--y, 2--z
// 摄像机辅助参数:
static D3DXVECTOR3 g_vRight(1,0,0), g_vLook(0,-1,-0.5); // 摄像机方向
g_vLook = g_vLookat-g_vEye; // D3DXVec3Normalize(&g_vLook,&g_vLook);
D3DXVec3Cross(&g_vRight, &g_vLook, &g_vUp); D3DXVec3Normalize(&g_vRight,&g_vRight);
glLoadIdentity(); \
gluLookAt(g_vEye.x, g_vEye.y, g_vEye.z, g_vLookat.x, g_vLookat.y, g_vLookat.z, g_vUp.x, g_vUp.y, g_vUp.z); \
// g_Camera.Update(); ...... CheckForMovement();
static float v; getFPS(&v); v= kSpeed * v; // v: 每秒位移量 ----> 每帧位移量
g_vLook = g_vLookat-g_vEye; D3DXVec3Normalize(&g_vLook,&g_vLook);
D3DXVec3Cross(&g_vRight, &g_vLook, &g_vUp); D3DXVec3Normalize(&g_vRight,&g_vRight);
if( GetKeyState(VK_UP) & 0x80 ) {
g_vLookat.y--; g_vEye.y--;
}else if( GetKeyState(VK_DOWN) & 0x80){
g_vLookat.y++; g_vEye.y++;
}else if( GetKeyState('W') & 0x80 ) { // 移动摄像机: MoveCamera(speed);
g_vLookat+=g_vLook*v; g_vEye+=g_vLook*v; // 改变摄像机的位置
}else if( GetKeyState('S') & 0x80 ){
g_vLookat+=-g_vLook*v; g_vEye+=-g_vLook*v;
}else if( GetKeyState(VK_LEFT) & 0x80 || GetKeyState('A') & 0x80 ){
g_vLookat+=g_vRight*v; // .y分量不加...
g_vEye+=g_vRight*v;
}else if( GetKeyState(VK_RIGHT) & 0x80 || GetKeyState('D') & 0x80 ){
g_vLookat+=-g_vRight*v; // .y分量不加...
g_vEye+=-g_vRight*v;
} // if ... else ...
} // aimCamera
// glSquare, 以三角形面片的形式渲染四边形 ......
void glSquare(int w,int h, int iTex=-1, float*pm=0L){
// glShadeModel(GL_SMOOTH);
glMatrixMode(GL_TEXTURE_MATRIX); glPushMatrix();
static float H; H+=0.1; // if(iTex>=0) // 对于使用纹理的矩形, 施行世界坐标变换.
if(pm){ glTranslatef(0,0,w/3.); glMultMatrixf(pm); }
// 0, 1, 2, 3
float vso[]={0,0,0, w,0,0, 0,0,h, w,0,h, };
float co[]={0xFF,0,0, 0,0xFF,0, 0,0,0xFF, 0xFF,0xFF,0xFF, }; // 最后指定白色
D3DXVECTOR3*vs=(D3DXVECTOR3*)vso;
D3DXVECTOR3*vo=(D3DXVECTOR3*)co;
if(iTex>=0) glBindTexture(GL_TEXTURE_2D, g_Texture[iTex]); // 捆绑纹理
glBegin( GL_TRIANGLE_STRIP ); // 以三角形面片的形式绘制地形
static float x,y,z;
for(int i=0; i<4; i++){ // CULL
x=vs[i].x,y=vs[i].y, z=vs[i].z; // x*=100, y*=100,z*=100;
if(iTex>=0) glTexCoord2f( x/ w, -z/h ); // 使用纹理坐标
else glColor4f(vo[i].x,vo[i].y,vo[i].z,1); // 使用颜色
glVertex3i(x,y,z);
} // for
glEnd(); // 绘制完成
glPopMatrix();
}
// glCircle, 以GL_LINE_STRIP 形式渲染圆 ......
void glCircle(float r=10){ // glShadeModel(GL_SMOOTH);
glMatrixMode(GL_TEXTURE_MATRIX); glPushMatrix();
static float a=20, da=-0.05;
static float pm[16+2]={ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1, };
pm[0]=cos(-a); pm[1]=sin(-a); pm[4]=-sin(-a); pm[5]=cos(-a);
glTranslatef(a*r,r,0);
glMultMatrixf(pm);
a+=da; if(a*r<=r) da=+0.05; else if(a>=20) da=-0.05;
float co[]={0xFF,0,0, 0,0xFF,0, 0,0,0xFF, 0xFF,0xFF,0, 0xFF,0,0xFF, 0,0xFF,0xFF, 0xFF,0xFF,0xFF, }; // 最后指定白色
D3DXVECTOR3*vo=(D3DXVECTOR3*)co;
glBegin( GL_LINE_STRIP );
static float x,y,z, c, dc=PI/12;
static int N=24; c=0; z=256;
for(int i=0; i<N; i++){ // CULL
x=r*cos(c), y=r*sin(c); // x*=100, y*=100,z*=100;
glColor4f(vo[i%7].x,vo[i%7].y,vo[i%7].z,1); // 使用颜色
glVertex3i(x,y,z);
c+=dc;
} // for
glEnd(); // 绘制完成
glPopMatrix();
}
// RenderScene, 绘制场景
void RenderScene(){
aimCamera();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.2f,0.2f,0.8f,1.0f);
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
static float a=PI/2; static float b=0;
static float pm[16]={ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1, };
pm[0]=cos(a); pm[1]=sin(a); pm[4]=-sin(a); pm[5]=cos(a);
glSquare(MAP_SIZE,MAP_SIZE);
glSquare(MAP_SIZE/4.,MAP_SIZE/2.,0,pm); // /STEP_SIZE
static float qm[16]={ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1, };
qm[0]=cos(a); qm[1]=sin(a); qm[4]=-sin(a); qm[5]=cos(a);
qm[12]=MAP_SIZE;
glSquare(MAP_SIZE/4.,MAP_SIZE/2.,1,qm);
glCircle(50.);
SwapBuffers(g_hDC); // 交换缓冲区
}
LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam){
switch (uMsg){
case WM_SIZE:{ glView(LOWORD(lParam),HIWORD(lParam));
}break;
case WM_LBUTTONDOWN:
g_bRenderMode = !g_bRenderMode; // 改变渲染模式
if(g_bRenderMode) { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // 纹理模式
}else{ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); } // 线框模式
break;
case WM_KEYDOWN: switch(wParam) {
case VK_ESCAPE:PostQuitMessage(0); break;
case 'Z': g_bRenderMode = !g_bRenderMode; // 改变渲染模式
if(g_bRenderMode) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // 纹理模式
else glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // 线框模式
break;
default: break;
}break;
case WM_CLOSE: PostQuitMessage(0); break;
} // switch (uMsg)
return DefWindowProc (hWnd, uMsg, wParam, lParam);
}