[toc]
# Pilot 引擎 Github 与课程地址
课程: https://www.bilibili.com/video/BV14r4y1p7tt?spm_id_from=333.337.search-card.all.click
Pilot 引擎 Github: https://github.com/BoomingTech/Pilot
# 大体逻辑
先通过 reflection 和 serializer 中定义的宏在对应需要反射的类中声明反射的 Operator
类
REFLECTION_TYPE(Quaternion)
CLASS(Quaternion, Fields)
{
REFLECTION_BODY(Quaternion);
}
上面三个宏分别是:
#define REFLECTION_BODY(class_name) \
friend class Reflection::TypeFieldReflectionOparator::Type##class_name##Operator; \
friend class PSerializer;
// public: virtual std::string getTypeName() override {return #class_name;}
#define REFLECTION_TYPE(class_name) \
namespace Reflection \
{ \
namespace TypeFieldReflectionOparator \
{ \
class Type##class_name##Operator; \
} \
};
#define CLASS(class_name, …) class class_name
可以看,声明了 Type##class_name##Operator
对象,并且设置为友联,但是没有实现
实现是放在了预编译阶段生成的代码中了
比如 Quaternion.h
就会生成 quaternion.reflection.gen.h
, 在生成的 all_reflection.h
中
那么这些代码在哪生成的呢?
在项目的 Pilot/engine/bin
目录下有三个子目录,Linux/macOS/Windows, 以 Windows 为例,Windos 目录下有一个文件 meta_parser.exe
这个文件就是用来生成 quaternion.reflection.gen.h
的,目录中还有一个文件, precompile.json
, 记录的是需要检查的文件列表
我们知道 C 程序需要使用 cmake 来生成 VS 工程方便后续的代码,命令都放在 cmakeLists.txt
中,其中最外层的 CmakeLists.txt
最后几段有这样一段命令
set(CODEGEN_TARGET “PilotPreCompile”)
include(source/precompile/precompile.cmake)
可以看到引用到了 source/precompile/precompile.cmake
在实际的 precompile.cmake 文件中的最后几段有实际的生成反射需要的文件的命令
COMMAND
${CMAKE_COMMAND} -E echo "************************************************************* "
COMMAND
${CMAKE_COMMAND} -E echo "**** [Precompile] BEGIN "
COMMAND
${CMAKE_COMMAND} -E echo "************************************************************* "
COMMAND
{PILOT_PRECOMPILE_PARAMS_PATH}" “{ENGINE_ROOT_DIR}/source” ${sys_include} “Pilot” S 0 0 0
# BUILDING ====================================================================================
COMMAND
${CMAKE_COMMAND} -E echo “+++ Precompile finished +++”
实际有用的是倒数第二条指令,其中这条指令中的每个参数都是在上文中得到的,都是绝对路径,在我的电脑环境中分别代表:
- PRECOMPILE_PARSER : C:\G\GithubRepo\PilotTest\engine\bin\Windows\x64\meta_parser.exe
- PILOT_PRECOMPILE_PARAMS_PATH : “C:\G\GithubRepo\PilotTest\engine\bin\precompile.json”
- PARSER_INPUT : “parserHeader.h”
- ${ENGINE_ROOT_DIR}/source : “C:\G\GithubRepo\PilotTest\engine\source”
- sys_include : “*”
其中 PARSER_INPUT
代表的是根据之前的 PILOT_PRECOMPILE_PARAMS_PATH
json 文件中所有需要引用到的文件的合并 #include
这些命令执行完成后,就会生成所有的反射和序列化代码,这些代码放在 source/_generated/
目录下
然后后续对这些类的反射实际上都已经在编译期完成了.
# 反射的初始化
pilot 引擎会进入 PilotEditor 项目中的 main, 通过 main 函数会调用引擎内核 PilotEngine
类中的 startEngine
方法
在 startEngine
方法中的第一行就是每个类型的反射操作类 Type##className##Oprator
的注册
void PilotEngine::startEngine(const EngineInitParams& param)
{
Reflection::TypeMetaRegister::Register();
}
这个 Register 方法进入的是之前生成的文件中的一个整合的 .h
文件,即 all_reflection.h
这个类中的一部分如下:
void TypeMetaRegister::Register(){
TypeWrappersRegister::Quaternion();
TypeWrappersRegister::AnimNodeMap();
TypeWrappersRegister::AnimationAsset();
TypeWrappersRegister::AnimationChannel();
TypeWrappersRegister::AnimationClip();
TypeWrappersRegister::Vector3();
TypeWrappersRegister::RawBone();
}
至此,Pilot 的反射注册完毕,可以正常使用,但是实际上对反射类型的操作还是需要继续学习框架内的内容