UE4版本:4.24.3源码编译
Windows10 + VS2019开发环境
在先前分享的基础上,现在来梳理下App启动时默认窗口的创建流程,以及相关的类、对象之间的抽象层级:
1、窗口创建流程
Q:App启动过程中,窗口是何时创建的?
Win32 API中创建窗口使用CreateWindowXX系列函数,VS中全局搜索一下CreateWindow,如下图是想要找的地方
全局搜索时不要勾选【Match whole world】
图1:全局搜索CreateWindow系列函数的调用
图一中源码路径:Source/Runtime/ApplicationCore/Private/Windows/WindowsWindow.cpp是需要找的调用;
在项目工程属性中:Debugging->Command Arguments中,添加-game参数:
VS中运行后,以Game模式启动,而非启动编辑器界面;
可以排除Editor相关的函数调用,模拟最终游戏的启动和运行流程;
VS中断点调试,拿到的调用堆栈如下图:
图2:窗口创建时的调用堆栈
从图2中可以看到,CreateWindowEx函数的调用过程中涉及到了下面几个类:
- FEngineLoop
- FPreLoadScreenManager
- UGameEngine
- FSlateApplication
- FWindowsApplication
- FWindowsWindow
定位到UGameEngine::CreateGameWindows()函数定义处,该函数创建的对象类型其实是SWindow;
// SNew宏创建一个SWindow实例(SWindow是SWidget派生类,参看前面的SImage用法)
TSharedRef<SWindow> Window = SNew(SWindow)
该SWindow实例被添加到FSlateApplication类中,被保存在SlateWindows这个数组中:定位到FSlateApplication::AddWindow()函数处可以查看
FSlateApplication::Get().AddWindow( Window, bShowImmediately );
FSlateApplication::AddWindow(...)函数内部,除了保存SWindow实例外,还会调用FSlateApplication::MakeWindow(...)创建一个FGenericWindow对象;
稍微追一下代码,会发现:
- 该FGenericWindow对象的实际类型是FWindowsWindow;
- FSlateApplication::MakeWindow(...)函数中出现的那个PlatformApplication实例,其类型为FWindowsApplication
关于PlatformApplication这个实例,参考FSlateApplication::Create(...)函数;
回到UGameEngine::CreateGameWindow()函数定义处:
SWindow实例会调用ShowWindow()函数,函数内部会调用到FWindowsWindow实例的Show()方法:该方法内部针对先前CreateWindowEx(...)函数创建的Win32窗口句柄做显示动作;
这部分分析过程中,会涉及到下面这些新出现的类:
- FGenericWindow
- FGenericApplication
- FGenericAcpplicationMisc
- FWindowsPlatformApplicationMisc
- FPlatformApplicationMisc 该类是一个typedef,指向具体平台的FXXXPlatformApplicationMisc类
- FSlateApplicationBase
以上整个UGameEngine::CreateGameWindow(...)函数调用的过程,就是窗口创建的过程;
2、类、对象的分析
类FSlateApplication继承自FSlateApplicationBase类;单例形式,管理并驱动整个Slate SWidget的渲染和事件派发等重要任务;
SWindow类抽象并封装平台Window对象;
FGenericApplication、FGenericWindow类是多平台对应类的基类,具体平台的逻辑操作在派生类中执行,实现各平台Api的封装;
3、总结、扩展
这次主要是追一下UE4引擎源码中,在Windows平台下,最基础的窗口是如何创建的;
对于其中涉及到的一些类和彼此之间的抽象关系做一个粗粒度的感性认识;
对于游戏引擎,各图形单元的渲染使用DirectX、OpenGL、Metal等底层硬件加速Api,并不依赖平台自身开发框架提供的Native控件;
窗口创建后,一般都会需要一个Content上下文初始化的工作,这块涉及到具体游戏引擎的渲染模块,以后有机会在来分享;
起始的窗口大小:
在项目工程属性中:Debugging->Command Arguments中,添加ResX=1280 ResY=720参数
ResX=1280 ResY=720参数设定窗口的启动大小:相关的代码可以参考:
static void UGameEngine::ConditionallyOverrideSettings(...);
static void UGameEngine::DetermineGameWindowResolution(...);
另外:上面全局搜索CreateWindo函数调用时,搜索结果中有出现一个WindowsPlatformSplash.cpp文件;
当中也有调用到CreateWindowEx(...)函数
这里其实就是引擎、或者VS中直接带-game参数启动时那个黑色的类似一个Loading界面的窗口
对应的图片资源在引擎Engine\Content\Splash目录下,有兴趣可以翻一下WindowsPlatformSplash.cpp源码