这个引擎是基于win32架构写的, Platform可以理解成是整个引擎的入口。控制着引擎的整个生命周期,内部主要完成了openGL、win32窗口句柄的初始化;键盘鼠标事件分发;主循环控制。关闭程序的处理。
1.首先是执行了Platform中的静态函数SetWindowSize,设置了Win32窗口的初始化xy位置,以及窗口大小。
void CPlateForm::setWindowSize(int x, int y, int wid, int hei) { window_x = x; window_y = y; windows_width = wid; windows_height = hei; }
2.接着是构造Platform的单例类(当时代码有些不规范,Platform已经是单例类了,直接在Init的时候传递x、y、w、h,然后在Init函数里执行原本构造函数里的这些代码就好了。没有必要再写一个静态类专门来Save一下x、y、w、h这四个参数了)
CPlateForm::CPlateForm() { hRC = NULL; hDC = NULL; hWnd = NULL; hInst = NULL; isPause = false; gameMode = PLAYING; ShowWindow(hWnd, SW_SHOWDEFAULT); UpdateWindow(hWnd); MyRegisterClass();// 执行应用程序初始化: if (!InitInstance()) { MessageBox(NULL, L"不能成功初始化", L"错误", MB_OK | MB_ICONEXCLAMATION); } HACCEL hAccelTable = LoadAccelerators(hInst, MAKEINTRESOURCE(NULL)); memset(&msg, 0, sizeof(MSG)); m_Audio.Initialize(hWnd); }
2.1.接着会调用MyRegisterClass对Win32窗口的大小、icon、光标、窗口风格进行设置,然后调用系统API把我们设置好的参数传递给操作系统。
ATOM CPlateForm::MyRegisterClass() { WNDCLASSEXW wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInst; wcex.hIcon = LoadIcon(hInst,NULL);//托盘上的ICO图标 wcex.hCursor = LoadCursorFromFileA("res/color/0081.ani"); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = NULL; wcex.lpszClassName = L"myClass"; wcex.hIconSm = LoadIcon(wcex.hInstance,NULL);//窗口上的ICO图标 return RegisterClassExW(&wcex); }
2.2 配置完成窗口配置后,会在这个函数里真正的创建一个Win32窗口,并返回一个窗口句柄(其实可以理解成系统给我们分配的一个窗口Id),接着初始化OpenGL。
BOOL CPlateForm::InitInstance() { //hInst = hInstance; // 将实例句柄存储在全局变量中 int nX = GetSystemMetrics(SM_CXFRAME) * 4; int nY = GetSystemMetrics(SM_CYFRAME) * 4 + GetSystemMetrics(SM_CYCAPTION);//+ GetSystemMetrics(SM_CYMENU); //创建Win32窗口,返回窗口句柄 hWnd = CreateWindowW(L"myClass", L"荒岛求生_V1.1", WS_OVERLAPPEDWINDOW, window_x, window_y, windows_width + nX, windows_height + nY, nullptr, nullptr, NULL, nullptr); if (!hWnd) { return FALSE; } //初始化OpenGL配置 InitGL(); //初始化硬件获取纹理通道 glewInit(); //操作系统API,显示这个窗口 ShowWindow(hWnd, true); //立即刷新窗口 UpdateWindow(hWnd); //顶点缓存上的,没有用到 //使用VBO查询字符串为 //#ifndef NO_VBOS // g_fVBOSupported = IsExtensionSupported("GL_ARB_vertex_buffer_object"); // //返回1为支持. // //下面声明VBO扩展函数 // // VBO Extension Function Pointers // PFNGLGENBUFFERSARBPROC glGenBuffersARB = NULL; // VBO Name Generation Procedure // PFNGLBINDBUFFERARBPROC glBindBufferARB = NULL; // VBO Bind Procedure // PFNGLBUFFERDATAARBPROC glBufferDataARB = NULL; // VBO Data Loading Procedure // PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB = NULL; // VBO Deletion Procedure // // if (g_fVBOSupported) //获取函数地址 // { // // 获得函数的指针 // glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)wglGetProcAddress("glGenBuffersARB"); // glBindBufferARB = (PFNGLBINDBUFFERARBPROC)wglGetProcAddress("glBindBufferARB"); // glBufferDataARB = (PFNGLBUFFERDATAARBPROC)wglGetProcAddress("glBufferDataARB"); // glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)wglGetProcAddress("glDeleteBuffersARB"); // } //#else // g_fVBOSupported = false; //#endif return TRUE; }
2.3 这个函数比较长,其实主要干的事儿就是给OpenGL传递参数开启或者关闭开关,对OpenGL进行初始化,因为OpenGL需要设置的参数实在是太多了,具体备注代码上都有,大家直接看代码吧!
// 此处开始对OpenGL进行所有设置 GLboolean CPlateForm::InitGL(GLvoid) { static PIXELFORMATDESCRIPTOR pfd = // /pfd 告诉窗口我们所希望的东东,即窗口使用的像素格式 { sizeof(PIXELFORMATDESCRIPTOR), // 上述格式描述符的大小 1, // 版本号 PFD_DRAW_TO_WINDOW | // 格式支持窗口 PFD_SUPPORT_OPENGL | // 格式必须支持OpenGL PFD_DOUBLEBUFFER, // 必须支持双缓冲 PFD_TYPE_RGBA, // 申请 RGBA 格式 24, // 选定色彩深度 0, 0, 0, 0, 0, 0, // 忽略的色彩位 0, // 无Alpha缓存 0, // 忽略Shift Bit 0, // 无累加缓存 0, 0, 0, 0, // 忽略聚集位 16, // 16位 Z-缓存 (深度缓存) 1, // 无蒙板缓存 0, // 无辅助缓存 PFD_MAIN_PLANE, // 主绘图层 0, // Reserved 0, 0, 0 // 忽略层遮罩 }; if (!(hDC = GetDC(hWnd))) // 取得设备描述表了么? { KillGLWindow(); // 重置显示区 MessageBox(NULL, L"不能创建一种相匹配的像素格式", L"错误", MB_OK | MB_ICONEXCLAMATION); return FALSE; // 返回 FALSE } GLuint PixelFormat = ChoosePixelFormat(hDC, &pfd); // Windows 找到相应的象素格式了吗? if (!SetPixelFormat(hDC, PixelFormat, &pfd)) // 能够设置象素格式么? return false; // 能否取得着色描述表? if (!(hRC = wglCreateContext(hDC))) return false; // 尝试激活着色描述表 if (!wglMakeCurrent(hDC, hRC)) return false; // Windows 找到相应的象素格式了吗? if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd))) { KillGLWindow(); // 重置显示区 MessageBox(NULL, L"不能设置像素格式", L"错误", MB_OK | MB_ICONEXCLAMATION); return FALSE; // 返回 FALSE } if (!SetPixelFormat(hDC, PixelFormat, &pfd)) // 能够设置象素格式么? { KillGLWindow(); // 重置显示区 MessageBox(NULL, L"不能设置像素格式", L"错误", MB_OK | MB_ICONEXCLAMATION); return FALSE; // 返回 FALSE } if (!(hRC = wglCreateContext(hDC))) // 能否取得着色描述表? { KillGLWindow(); // 重置显示区 MessageBox(NULL, L"不能创建OpenGL渲染描述表", L"错误", MB_OK | MB_ICONEXCLAMATION); return FALSE; // 返回 FALSE } if (!wglMakeCurrent(hDC, hRC)) // 尝试激活着色描述表 { KillGLWindow(); // 重置显示区 MessageBox(NULL, L"不能激活当前的OpenGL渲然描述表", L"错误", MB_OK | MB_ICONEXCLAMATION); return FALSE; // 返回 FALSE } glStencilMask(0); //蒙版缓冲区置为0 glShadeModel(GL_SMOOTH); // 启用阴影平滑 glClearColor(0.0f,0.0f, 0.0f,1.0f); // 背景 glClearDepth(1.0f); // 设置深度缓存 glEnable(GL_DEPTH_TEST); // 启用深度测试 glDepthFunc(GL_LEQUAL); // 所作深度测试的类型 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 真正精细的透视修正,告诉系统对透视进行修正 glFrontFace(GL_CCW); //多边形逆时针方向为正面 glClearStencil(0); glEnable(GL_CULL_FACE); //只显示正面 ReSizeGLScene(windows_width, windows_height); //设置openGL窗口大小 InitGeometry(); return TRUE; // 初始化 OK }
2.4 InitGeometry 是初始化操作的最后一个函数,函数里面干的事儿主要就是设置光源位置,设置环境光、漫反射、高光的颜色。开启了范围雾、设置了雾的开始Z值 和 结束Z值,其实这些代码也能放到InitGL函数里面,但是考虑到InitGL函数太长了,这些代码干的事儿主要是初始化光源和雾气配置,所以细分了一下函数,就给拆出来了。
void CPlateForm::InitGeometry() { glEnable(GL_NORMALIZE); GLfloat LightPos[] = { 0.0f,0.0f,5.0f,1.0f }; GLfloat LightAmb[] = { 0.5f,0.5f,0.5f,1.0f }; GLfloat LightDif[] = { 0.8f,0.8f,0.8f,1.0f }; GLfloat LightSpe[] = { 0.8f,0.8f,0.8f,1.0f }; glLightfv(GL_LIGHT0, GL_POSITION, LightPos); glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmb); glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDif); glLightfv(GL_LIGHT0, GL_SPECULAR, LightSpe); GLuint fogMode[] = { GL_EXP, GL_EXP2, GL_LINEAR }; // 雾气的模式 GLfloat fogColor[4] = { 0.5f, 0.5f, 0.5f, 1.0f }; // 雾的颜色设为灰色 glFogi(GL_FOG_MODE, GL_LINEAR); // 设置雾气的模式 glFogfv(GL_FOG_COLOR, fogColor); // 设置雾的颜色 glFogf(GL_FOG_DENSITY,0.05f); // 设置雾的密度 glHint(GL_FOG_HINT, GL_DONT_CARE); // 设置系统如何计算雾气 glFogf(GL_FOG_START,2000.0f); // 雾气的开始位置 glFogf(GL_FOG_END,4000.0f); // 雾气的结束位置 }