// 数据结构大作业,池塘夜雨
// 这是主窗口cpp,参考nehe opengl教程的主窗口创建方式,原因是对各类的异常都分析的很完善
// 使用opengl实现动画,采用数组的形式存放每一个雨点
// openGL.cpp
#include <windows.h> // Windows头文件
#include "Rain.h" //自定义的Rain头文件
HDC hDC=NULL; // opengl的渲染描述表句柄
HGLRC hRC=NULL; // 窗口的着色描述表句柄
HWND hWnd=NULL; // 用于保存自己的窗口句柄
HINSTANCE hInstance; // 实例程序的句柄
bool keys[256]; // 保存键盘按键的数组
bool active=TRUE; // 窗口的活动标志,默认为true
bool fullscreen=TRUE; // 窗口的全屏标志,默认为true
const int num=150; // Rain数组的大小,设为常数
const int speed=0; // 下一个雨滴下落的时间
int loop; // 对Rain数组进行操作的下标
int count=0; // 控制下一次雨滴下落时间的计数量
GLfloat zoom=-16.0f; // 窗口坐标在z轴方向移动的值,即镜头的移出和移入
Rain rains[num]; // 创建一个Rain数组
GLuint texture[1]; // 存储一个纹理
AUX_RGBImageRec *LoadBMP(char *Filename){ // 载入位图图象
FILE *File=NULL; // 文件句柄
if (!Filename) // 确保文件名已提供
{
return NULL; // 如果没提供,返回 NULL
}
File=fopen(Filename,"r"); // 尝试打开文件
if (File) // 文件存在么?
{
fclose(File); // 关闭句柄
return auxDIBImageLoad(Filename); // 载入位图并返回指针
}
return NULL; // 如果载入失败,返回 NULL
}
int LoadGLTextures(){ // 载入位图(调用上面的代码)并转换成纹理
int Status=FALSE; // 状态指示器
AUX_RGBImageRec *TextureImage[1]; // 创建纹理的存储空间
memset(TextureImage,0,sizeof(void *)*1); // 将指针设为 NULL
// 载入位图,检查有无错误,如果位图没找到则退出
if (TextureImage[0]=LoadBMP("Data/background.bmp")){
Status=TRUE; // 将 Status 设为 TRUE
glGenTextures(1, &texture[0]); // 创建纹理
// 使用来自位图数据生成 的典型纹理
glBindTexture(GL_TEXTURE_2D, texture[0]);
// 生成纹理
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // 线形滤波
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // 线形滤波
}
// 释放位图数据的内存
if (TextureImage[0]) // 纹理是否存在
{
if (TextureImage[0]->data) // 纹理图像是否存在
{
free(TextureImage[0]->data); // 释放纹理图像占用的内存
}
free(TextureImage[0]); // 释放图像结构
}
return Status; // 返回 Status
}
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // 由于下面的CreatGLWindow()要用到,所以先定义WndProc(),之后再写起具体函数
GLvoid ReSizeGLScene(GLsizei width, GLsizei height){ // 为了方便画图,重置opengl的窗口大小
if (height==0) // 防止被零除
{
height=1; // 如果是0,将高度设为1
}
glViewport(0,0,width,height); // 重设当前窗口的视点
// 以下几行代码是为透视图设置图层,即越远的东西看起来越小
glMatrixMode(GL_PROJECTION); // 选择投影矩阵
glLoadIdentity(); // 重置投影矩阵
// 设置窗口的大小
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW); // 选择模型观察矩阵
glLoadIdentity(); // 重置模型观察矩阵
}
int InitGL(GLvoid){ // 对opengl进行所有的设置
if (!LoadGLTextures()) // 调用纹理载入子例程
{
return FALSE; // 如果未能载入,返回FALSE
}
glEnable(GL_TEXTURE_2D); // 启用纹理映射
glClearColor(0.5f,0.5f,0.5f,1.0f); // 设置背景的颜色为雾气的颜色
glShadeModel(GL_SMOOTH); // 启用阴影平滑
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // 设置清屏幕颜色为黑色
glClearDepth(1.0f); // 设置深度缓存
glEnable(GL_DEPTH_TEST); // 启用深度缓存测试
glDepthFunc(GL_LEQUAL); // 选择所用深度缓存的类型
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 告诉系统透视进行修正
return TRUE; // 初始化成功后,返回true
}
int DrawGLScene(GLvoid){ // 这部分是做所有绘制的部分
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 首先,清除屏幕和深度缓存
glLoadIdentity(); // 重置当前的模型观察矩阵
// 绘制背景
glTranslatef(0.0f,0.0f,-16.0f); // 移入屏幕 16.0
glColor3f(1.0f,1.0f,1.0f); // 选择颜色为白色
glBindTexture(GL_TEXTURE_2D, texture[0]); // 选择纹理
glBegin(GL_QUADS); // 绘制正方形
glTexCoord2f(0.0f, 1.0f); glVertex3f(-9.0f, 6.7f, 0.0f); // 左上
glTexCoord2f(1.0f, 1.0f); glVertex3f( 9.0f, 6.7f, 0.0f); // 右上
glTexCoord2f(1.0f, 0.0f); glVertex3f( 9.0f,-6.7f, 0.0f); // 左下
glTexCoord2f(0.0f, 0.0f); glVertex3f(-9.0f,-6.7f, 0.0f); // 右下
glEnd(); // 正方形绘制结束
// 绘制下雨过程
for(loop=0;loop<num;){ // 使用循环,对rains数组进行遍历
count++;
rains[loop].Display(zoom); // Display()函数是对下雨进行绘制
if(rains[loop].isOver()){ // rains的一个成员是否绘制结束
rains[loop].renew(); // 使用这个成员空间,存储新的数据
}
if(count>speed){
loop++;
count=0;
}
}
if(loop>=num-1){ // 如果loop到达循环条件,重置loop
loop=0;
}
return TRUE; // 所有绘制成功后,返回true
}
GLvoid KillGLWindow(GLvoid) // 删除窗口
{
if (fullscreen) { // 判断是否全屏状态
ChangeDisplaySettings(NULL,0); // 如果是全屏,切换回桌面
ShowCursor(TRUE); // 显示鼠标指针
}
if (hRC){ // 是否拥有opengl渲染描述表
if (!wglMakeCurrent(NULL,NULL)){ // 能否释放DC和RC
//释放错误消息
MessageBox(NULL,"DC和RC释放失败。","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
}
if (!wglDeleteContext(hRC)){ // 能否删除RC
//RC删除错误消息
MessageBox(NULL,"目录释放失败。","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
}
hRC=NULL; // 设置RC为空
}
if (hDC && !ReleaseDC(hWnd,hDC)){ // 能否释放DC
//释放错误消息
MessageBox(NULL,"设备目录释放失败","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
hDC=NULL; // 设置DC为空
}
if (hWnd && !DestroyWindow(hWnd)){ // 能否销毁窗口
//销毁错误消息
MessageBox(NULL,"不能释放hWnd。","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
hWnd=NULL; // 设置窗口描述表为空
}
if (!UnregisterClass("OpenGL",hInstance)){ // 能否注销类
//注销错误消息
MessageBox(NULL,"不能注销类。","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
hInstance=NULL; // 设置实例描述表为空
}
}
// 创建一个容易定制的友好的窗口,但需要大量的代码
BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag){
GLuint PixelFormat; // 保存查找匹配的结果
WNDCLASS wc; // 窗口类结构
DWORD dwExStyle; // 扩展窗口风格
DWORD dwStyle; // 窗口风格
RECT WindowRect; // 取得矩阵左上角和右下角的坐标值
WindowRect.left=(long)0; // 设置left为0
WindowRect.right=(long)width; // 设置right为要求的宽度
WindowRect.top=(long)0; // 设置top为0
WindowRect.bottom=(long)height; // 设置bottom为要求的高度
fullscreen=fullscreenflag; // 设置全局全屏状态
hInstance = GetModuleHandle(NULL); // 取得窗口实例
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // 移动时重画,并取得DC
wc.lpfnWndProc = (WNDPROC) WndProc; // WndProc处理消息
wc.cbClsExtra = 0; // 没有额外的窗口数据
wc.cbWndExtra = 0; // 没有额外的窗口数据
wc.hInstance = hInstance;
- 1
- 2
前往页