从0开发游戏引擎之引擎Win32平台的Platform类实现

简介: 首先是执行了Platform中的静态函数SetWindowSize,设置了Win32窗口的初始化xy位置,以及窗口大小。

这个引擎是基于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);       // 雾气的结束位置
}


相关文章
|
5月前
|
编译器 C# Android开发
Uno Platform 是一个用于构建跨平台应用程序的强大框架,它允许开发者使用 C# 和 XAML 来创建适用于多个平台的应用
Uno Platform 是一个用于构建跨平台应用程序的强大框架,它允许开发者使用 C# 和 XAML 来创建适用于多个平台的应用
444 8
|
6月前
|
开发者 iOS开发 C#
Uno Platform 入门超详细指南:从零开始教你打造兼容 Web、Windows、iOS 和 Android 的跨平台应用,轻松掌握 XAML 与 C# 开发技巧,快速上手示例代码助你迈出第一步
【8月更文挑战第31天】Uno Platform 是一个基于 Microsoft .NET 的开源框架,支持使用 C# 和 XAML 构建跨平台应用,适用于 Web(WebAssembly)、Windows、Linux、macOS、iOS 和 Android。它允许开发者共享几乎全部的业务逻辑和 UI 代码,同时保持原生性能。选择 Uno Platform 可以统一开发体验,减少代码重复,降低开发成本。安装时需先配置好 Visual Studio 或 Visual Studio for Mac,并通过 NuGet 或官网下载工具包。
626 0
|
6月前
|
Android开发 iOS开发 C#
Xamarin.Forms:从零开始的快速入门指南——打造你的首个跨平台移动应用,轻松学会用C#和XAML构建iOS与Android通用界面的每一个步骤
【8月更文挑战第31天】Xamarin.Forms 是一个强大的框架,让开发者通过单一共享代码库构建跨平台移动应用,支持 iOS、Android 和 Windows。使用 C# 和 XAML,它简化了多平台开发流程并保持一致的用户体验。本指南通过创建一个简单的 “HelloXamarin” 应用演示了 Xamarin.Forms 的基本功能和工作原理。
151 0
|
6月前
|
iOS开发 Android开发 MacOS
从零到全能开发者:解锁Uno Platform,一键跨越多平台应用开发的神奇之旅,让你的代码飞遍Windows、iOS、Android、macOS及Web,技术小白也能秒变跨平台大神!
【8月更文挑战第31天】从零开始,踏上使用Uno Platform开发跨平台应用的旅程。只需编写一次代码,即可轻松部署到Windows、iOS、macOS、Android及Web(通过WASM)等多个平台。Uno Platform为.NET生态带来前所未有的灵活性和效率,简化跨平台开发。首先确保安装了Visual Studio或VS Code及.NET SDK,然后选择合适的项目模板创建新项目。项目结构类似传统.NET MAUI或WPF项目,包含核心NuGet包。通过简单的按钮示例,你可以快速上手并构建应用。Uno Platform让你的技术探索之旅充满无限可能。
160 0
从0开发游戏引擎之引擎Win32平台的Platform类实现
WndProc函数是注册进操作系统的回调,监听了用户的鼠标键盘响应事件,收到后丢给场景管理器去处理了系统传过来的事件。
|
编解码 数据管理 内存技术
嵌入式实践教程--ASOC之Platform
嵌入式实践教程--ASOC之Platform
|
IDE 开发工具 C#
Visual Studio 2022 Preview 2 发布:扩展跨平台功能,支持实时预览,debug 更高效
Visual Studio 2022 Preview 2 发布:扩展跨平台功能,支持实时预览,debug 更高效
1058 0
Visual Studio 2022 Preview 2 发布:扩展跨平台功能,支持实时预览,debug 更高效
|
开发工具 iOS开发
iOS中制作可复用的框架Framework(一)
iOS中制作可复用的框架Framework
159 0
iOS中制作可复用的框架Framework(一)
|
iOS开发
iOS中制作可复用的框架Framework(二)
iOS中制作可复用的框架Framework
155 0
iOS中制作可复用的框架Framework(二)
iOS8新特性扩展(Extension)应用之四——自定义键盘控件
iOS8新特性扩展(Extension)应用之四——自定义键盘控件
539 0
iOS8新特性扩展(Extension)应用之四——自定义键盘控件