高程纹理地形


// WinMain.cpp : 定义应用程序的入口点。
//
#pragma region 头文件,宏定义
//include
#include "stdafx.h"
#include "WinMain.h"
#include <GL/glew.h>

#include <gl/GL.h>
#include <gl/GLU.h>

#include <GL/GLAUX.H>
#include <gl/glut.h>
#include <math.h>
#include <stdlib.h>
#include "bitmap.h"
//define
#define MAX_LOADSTRING 100
#define  BITMAP_ID 0X4D42		//位图标识ID
#define MAP_X  32	//地图X轴的尺寸
#define MAP_Z  32 
#define MAP_SCALE 20.0f
#define PI 3.14159

#pragma endregion over

#pragma region 变量定义
// 全局变量:
HDC g_HDC;
bool fullScreen = false;
bool keyPressd[256];			//被按下的键,其值为true
float angle = 0.0f;				//视点角度
float radians = 0.0f;			//以弧度表示的视点角度
float waterHeight = 154.0f; //水面高度
bool waterDir = true;			//用于水的动画,true-向上,false-向下
//鼠标,视点变量
int mouseX, mouseY;		//鼠标坐标
float cameraX, cameraY, cameraZ; //视点坐标
float lookX, lookY, lookZ	;	//观察点坐标
//纹理信息
BITMAPINFOHEADER bitmapInfoHeader;		//临时位图信息头
BITMAPINFOHEADER landInfo;	//陆地纹理信息头
BITMAPINFOHEADER waterInfo;	//水纹理信息头

unsigned char* imageData;	//地形图图像数据
unsigned char* landTexture;//陆地纹理数据
unsigned char* waterTexture;//水纹理数据
unsigned int land;	//陆地纹理对象,使用纹理对象,加速纹理的处理过程
unsigned int water;	//水纹理对象

//地形数据
float terrain[MAP_X][MAP_Z][3];	//高程地形数据

#pragma  endregion 变量定义完毕
#pragma region old code
#pragma endregion old over
void GLInitialize()
{

	glEnable(GL_DEPTH_TEST);//被遮挡的表面剔除掉
	glEnable(GL_SMOOTH);
	glEnable(GL_POINT_SMOOTH);
	glEnable(GL_LINE_SMOOTH);

	glEnable(GL_CULL_FACE);	//不计算多边形背面
	glFrontFace(GL_CCW);//多边形逆时针方向为正面
	glEnable(GL_LIGHTING);	//启用光照
	将背景清理为黑色
	glClearColor(.0f,.0f,.0f,.0f);	
	glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST);
	glEnable (GL_BLEND);
	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	
}
void InitializeTerrain()
{
	//遍历所有的高程点,并为每个点计算坐标
	for (int z = 0; z < MAP_Z ; z++)
	{
		for (int x = 0; x < MAP_X; x++)
		{
			terrain[x][z][0] = float(x) * MAP_SCALE;
			terrain[x][z][1] = (float)imageData[(z*MAP_Z + x ) * 3];
			terrain[x][z][2] = -float(z) * MAP_SCALE;

		}
	}
}
bool LoadTextures()
{
	//载入地形纹理数据
	landTexture = LoadBitmapFile("green.bmp",&landInfo);
	if (!landTexture)
	{
		return false;
	}
	//载入水纹理数据
	waterTexture = LoadBitmapFile("water.bmp",&waterInfo);
	if (! waterTexture)
	{
		return false;
	}
	//生成陆地纹理为mipmap
	glGenTextures(1,&land);
	glBindTexture(GL_TEXTURE_2D,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);
	//生成水纹理为mipmap
	glGenTextures(1,&water);
	glBindTexture(GL_TEXTURE_2D, 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);
	return true;
}
void Render()
{
	radians = float(PI * (angle - 90.0f) / 180.0f);
	//计算视点位置
	cameraX = lookX + sin(radians) * mouseY;
	cameraZ = lookZ + cos(radians) * mouseY;
	cameraY = lookY + mouseY / 2.0f;
	//将视点的观察点设为地形图的中央
	lookX = (MAP_X * MAP_SCALE) / 2.0F;
	lookY = 150.0f;
	lookZ = -(MAP_Z * MAP_SCALE) / 2.0F;
	//清理屏幕和深度缓存
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	//设置视点位置
	gluLookAt(cameraX,cameraY,cameraZ,
					lookX,  lookY,  lookZ,
					0.0f, 1.0f, 0.0f);
	//将当前纹理设为陆地纹理
	glBindTexture(GL_TEXTURE_2D, land);
	//虽然我们将遍历所有的地形数据点
	//但是我们只会为沿着x轴的每一行数据点绘制一条三角形带
	for (int z = 0; z < MAP_Z - 1; z++)
	{
		glBegin(GL_TRIANGLE_STRIP);
		for (int x = 0; x < MAP_X - 1; x++)
		{
			//对于每个顶点,我们为其计算灰度颜色
			//设置纹理坐标绘制顶点
			//蛇形绘制顺序
			//绘制顶点0
			glColor3f( terrain[x][z][1] / 255.0f, terrain[x][z][1] / 255.0f, terrain[x][z][1] / 255.0f);
			glTexCoord2f(0.0f,1.0f);
			glVertex3f(  terrain[x][z][0],  terrain[x][z][1],  terrain[x][z][2] );
			//绘制顶点1
			glTexCoord2f(1.0f, 1.0f);
			glColor3f(  terrain[x + 1][z][1] / 255.0f, terrain[x + 1][z][1] / 255.0f, terrain[x + 1][z][1] / 255.0f);
			glVertex3f(  terrain[x + 1][z][0],  terrain[x + 1][z][1],  terrain[x + 1][z][2] );
			//绘制顶点2
			glTexCoord2f(0.0f, 0.0f);
			glColor3f( terrain[x][z + 1][1] / 255.0f, terrain[x][z + 1][1] / 255.0f, terrain[x][z + 1][1] / 255.0f);
			glVertex3f(  terrain[x][z + 1][0],  terrain[x][z + 1][1],  terrain[x][z + 1][2] );
			//绘制顶点3
			glTexCoord2f(0.0f, 1.0f);
			glColor3f( terrain[x + 1][z + 1][1] / 255.0f, terrain[x + 1][z + 1][1] / 255.0f, terrain[x + 1][z + 1][1] / 255.0f);
			glTexCoord2f(1.0f, .0f);
			glVertex3f(  terrain[x + 1][z + 1][0],  terrain[x + 1][z + 1][1],  terrain[x + 1][z + 1][2] );
		}
		glEnd();
	}
	//启用混合
	glEnable(GL_BLEND);
	//将深度缓存设为只读状态
	glDepthMask(GL_FALSE);
	//设置用于透明效果的混合因子
	glBlendFunc(GL_SRC_ALPHA,GL_ONE);
	//将颜色设置为透明的蓝色
	glColor4f(0.5f,0.5f,1.0f,0.7f);

	glBindTexture(GL_TEXTURE_2D,water);
	//将一个大的四边形表面绘制水,该四边形就是最下面的地,然后因为地有高低,所以水比地低的地方因为被遮挡,所以就看不到了。
	glBegin(GL_QUADS);
		//左下角
		glTexCoord2f(.0f, .0f);	
		glVertex3f(terrain[0][0][0] , waterHeight, terrain[0][0][2]);
		//右下角
		glTexCoord2f(10.0f, .0f);	
		glVertex3f(terrain[MAP_X - 1][0][0] , waterHeight, terrain[MAP_X - 1][0][2]);
		//右上角
		glTexCoord2f(10.0f, 10.0f);	
		glVertex3f(terrain[MAP_X - 1][MAP_Z - 1][0] , waterHeight, terrain[MAP_X - 1][MAP_Z - 1][2]);
		//左上角
		glTexCoord2f(.0f, 10.0f);	
		glVertex3f(terrain[0][ MAP_Z - 1 ][0] , waterHeight, terrain[0][ MAP_Z - 1 ][2]);
	glEnd();
	//将深度缓存设置回正常的模式
	glDepthMask(GL_TRUE);
	//禁用混合
	glDisable(GL_BLEND);
	//动画水
	if (waterHeight > 155.0f)
	{
		waterDir = false;
	} 
	else if(waterHeight < 154.0f)
	{
		waterDir = true;
	}
	if(waterDir)
		waterHeight += 0.01f;
	else 
		waterHeight -= 0.01f;
	glFlush();
	SwapBuffers(g_HDC);//交换前后缓存

}
// 此代码模块中包含的函数的前向声明:
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
//此函数用于应用程序的初始化和设置
void Initilize()
{
	glClearColor(.0f,.0f,.0f,.0f);		//背景色清理为黑色
	glShadeModel(GL_SMOOTH);	//使用平滑底纹
	glEnable(GL_DEPTH_TEST);	
	glEnable(GL_CULL_FACE);
	glFrontFace(GL_CCW);	//多边形逆时针方向为正面
	// glPolygonMode(GL_FRONT_AND_BACK ,GL_LINE );
	glEnable(GL_TEXTURE_2D);//启用2D纹理
	imageData = LoadBitmapFile("terrain2.bmp", &bitmapInfoHeader);
	//初始化地形数据载入纹理
	InitializeTerrain();
	LoadTextures();
}
void SetupPixelFormat(HDC hDC)
{
	int nPixelFormat;	//像素格式变量
	static PIXELFORMATDESCRIPTOR pfd = 
	{
		sizeof(PIXELFORMATDESCRIPTOR),
		1,		//版本号,总为1
		PFD_DRAW_TO_WINDOW |
		PFD_SUPPORT_OPENGL	   |
		PFD_DOUBLEBUFFER,
		PFD_TYPE_RGBA,
		32,
		0,0,0,0,0,0,
		0,
		0,
		0,
		0,0,0,0,
		16,
		0,
		0,
		PFD_MAIN_PLANE,
		0,
		0,0,0
	};
	//选择最匹配的像素格式,返回索引值
	nPixelFormat = ChoosePixelFormat(hDC,&pfd);
	//设置设备环境的像素格式
	SetPixelFormat(hDC,nPixelFormat,&pfd);
}
//
//  函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的: 处理主窗口的消息。
//
//  WM_COMMAND	- 处理应用程序菜单
//  WM_PAINT	    - 绘制主窗口
//  WM_DESTROY	- 发送退出消息并返回
//
//第三和第四个参数实际是第二个参数的扩展,它们提供message无法提供的更多的信息细节

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HGLRC hRC;				//绘制环境
	static HDC hDC;					//设备环境
	int width,height;					//窗口宽高
	int oldMouseX, oldMouseY;	//旧的鼠标坐标
	switch (message)
	{
	case WM_CREATE:		//创建窗口
		hDC = GetDC(hwnd);
		g_HDC = hDC;
		SetupPixelFormat(hDC);
		//创建绘制环境,并将其设置为当前绘制环境
		hRC = wglCreateContext(hDC);
		wglMakeCurrent(hDC,hRC);
		return 0;
		break;
	case WM_CLOSE:
		//取消对绘图环境的选定并将其删除
		wglMakeCurrent(hDC,NULL);
		wglDeleteContext(hRC);
		//发送消息到消息队列
		PostQuitMessage(0);
		return 0;
		break;
	case WM_SIZE:
		height = HIWORD(lParam);		//得到窗口宽度和高度
		width = LOWORD(lParam);
		if (height == 0)
		{
			height = 1;
		}
		//重置窗口尺寸
		glViewport(0,0,width,height);
		glMatrixMode(GL_PROJECTION);	//设定投影矩阵
		glLoadIdentity();							//复位投影矩阵
		//计算窗口尺寸比例
		gluPerspective(54.0f,(GLfloat)width/(GLfloat)height,1.0f,1000.0f);
		glMatrixMode(GL_MODELVIEW);	//设定模型视图矩阵
		glLoadIdentity();	//复位模型视图矩阵
		return 0;
		break;
	case WM_KEYDOWN:
		keyPressd[wParam] = true;
		return 0;
		break;
	case WM_KEYUP:
		keyPressd[wParam] = false;
		return 0 ;
		break;
	case WM_MOUSEMOVE:
		oldMouseX = mouseX;
		oldMouseY = mouseY;
		//从windows系统得到鼠标坐标
		mouseX = LOWORD(lParam);
		mouseY = HIWORD(lParam);
		//限定视点的活动范围
		if(mouseY < 200)
			mouseY = 200;
		if (mouseY > 450)
		{
			mouseY = 450;
		}
		//鼠标向右移动
		if ( ( mouseX - oldMouseX) > 0)
		{
			angle += 3.0f;
		}
		else if(  ( mouseX - oldMouseX) < 0 )
			angle -= 3.0f;
		return 0;
		break;
	
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		break;
	}
	return DefWindowProc(hwnd, message, wParam, lParam);
	//return 0;
}
//计算三个点形成的面的法向量
//入口函数
int APIENTRY _tWinMain(
					 HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow
									)
{
	MSG msg;
	//HACCEL hAccelTable;
	bool done;	//应用程序退出标记
	HWND hWnd;
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINMAIN));
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	=NULL;// (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= NULL;//MAKEINTRESOURCE(IDC_WINMAIN);
	wcex.lpszClassName	= "MyClass";//szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	if (!RegisterClassEx(&wcex))
	{
		return 0;
	}
	// 初始化全局字符串
//	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
//	LoadString(hInstance, IDC_WINMAIN, szWindowClass, MAX_LOADSTRING);
	
    hWnd = CreateWindowEx
		(
			NULL,
			"MyClass",
			"The OpenGL Game",
			WS_OVERLAPPEDWINDOW,
			100,100,
			800,800,
			NULL,
			NULL,
			hInstance,
			NULL
		);
	if (!hWnd)
	{
		MessageBox(NULL,"create error","Game",NULL);
		return FALSE;//创建窗口失败
	}

   ShowWindow(hWnd, SW_SHOW);
   UpdateWindow(hWnd);
	// 执行应用程序初始化:
	// 主消息循环:
	//这里最好还是用peekmessage函数。该函数虽然与getmessage功能相似,但是更适合于游戏程序 
	//如果只是消息队列中没有消息,getmessage函数会使应用程序挂起直到出现一个消息。而使用运行时函数peekmessage时,即使
	//消息队列中没有消息,也会让应用程序继续运行。这对于游戏程序来说很有用。
	done = false;
	Initilize();
	while( !done )
	{
		PeekMessage(&msg,hWnd,NULL,NULL,PM_REMOVE);
		if (msg.message == WM_QUIT)
		{
			done = true;
		}
		else
		{
			Render();
			TranslateMessage(&msg);	//翻译消息并分发到事件队列中
			DispatchMessage(&msg);
		}
	}
	return (int) msg.wParam;
}



  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值