// WinMain.cpp : 定义应用程序的入口点。
//
#pragma region 头文件,宏定义
//include
#include "stdafx.h"
#include "WinMain.h"
#include
#include
#include
#include
#include
#include
#include
#include "bitmap.h"
//define
#define MAX_LOADSTRING 100
#define BITMAP_ID 0X4D42 //位图标识ID
// 全局变量:
HDC g_HDC;
bool fullScreen = false;
//鼠标,视点变量
int mouseX, mouseY; //鼠标坐标
float cameraX, cameraY, cameraZ; //视点坐标
//变量定义
typedef struct
{
int width;
int height;
unsigned int texID;
unsigned char *data;
}texture_t;
float angle = 0.0f; //圆环旋转角度
texture_t *envTex;
texture_t *skyTex;
texture_t *LoadTextureFile(char *filename)
{
BITMAPINFOHEADER texInfo;
texture_t *thisTex;
//为纹理数据结构分配内存
thisTex = (texture_t*)malloc(sizeof(texture_t));
if(thisTex == NULL)
return NULL;
//载入纹理数据并检查其有效性
thisTex->data = LoadBitmapFile(filename, &texInfo);
if (thisTex->data == NULL)
{
free(thisTex);
return NULL;
}
//为纹理设置相应的宽度和高度信息
thisTex->width = texInfo.biWidth;
thisTex->height = texInfo.biHeight;
//为此纹理生成相应的纹理对象
glGenTextures(1,&thisTex->texID);
return thisTex;
}
bool loadAllTextures()
{
//载入环境纹理数据
envTex = LoadTextureFile("darksky-sphere.bmp");
if(envTex == NULL)
return false;
skyTex = LoadTextureFile("darksky.bmp");
if(skyTex == NULL)
return false;
//将环境纹理设置为进行双线性插值过滤处理的mipmap
glBindTexture(GL_TEXTURE_2D , envTex->texID);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
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, envTex->width, envTex->height,GL_RGB,GL_UNSIGNED_BYTE,envTex->data);
//设置天空背景纹理
glBindTexture(GL_TEXTURE_2D, skyTex->texID);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
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, skyTex->width, skyTex->height,GL_RGB,GL_UNSIGNED_BYTE,skyTex->data);
}
void Render()
{
if (angle > 360.0f)
{
angle = .0f;
}
angle += 0.2f;
//清理屏幕和深度缓存
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
//绘制天空背景纹理
glBindTexture(GL_TEXTURE_2D, skyTex->texID);
glBegin(GL_QUADS);
glTexCoord2f(.0f, .0f);
glVertex3f(-200.0f , -200.0f , -120.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(200.0f, -200.0f , -120.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(200.0f, 200.0f, -120.0f);
glTexCoord2f(.0f, 1.0f);
glVertex3f(-200.0f, 200.0f, -120.0f);
glEnd();
//后移物体并绕着三个轴旋转
glTranslatef(.0f, .0f, -100.0f);
glRotatef(angle, 1.0f, .0f, .0f);
glRotatef(angle, .0f, 1.0f, .0f);
glRotatef(angle , .0f, .0f, 1.0f);
//设置环境映射,主要就是这几句,注意是sphere
glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
//绑定纹理映射
glBindTexture(GL_TEXTURE_2D,envTex->texID);
//实体圆环:内径10,外径20
//auxSolidTeapot(5.0);
auxSolidTorus(10.0f, 20.0f);
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纹理
// InitializeTerrain();
loadAllTextures();
}
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);
}
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_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;
}