<2021SC@SDUSC>开源游戏引擎Overload代码分析四:OvEditor——Utils,Settings,Resources

2021SC@SDUSC

前言

这是Overload引擎相关的第六篇文章,同时也是OvEditor分析的第一篇。Overload引擎的Github主页在这里。

本篇文章主要会介绍OvEditor中三个文件夹所包含的h和cpp文件,分别是Utils,Settings和Resources文件夹。其中,前两个文件夹包含的内容较少,而Resources文件夹中因为有默认shader的缘故,内容会比较多。

一、Utils

ActorCreationMenu.h

#include <functional>

namespace OvUI::Widgets::Menu
{
    class MenuList;
}

namespace OvCore::ECS
{
    class Actor;
}

namespace OvEditor::Utils
{
    /**
    * Class exposing tools to generate an actor creation menu
    */
    class ActorCreationMenu
    {
    public:
        /**
        * Disabled constructor
        */
        ActorCreationMenu() = delete;

        /**
        * Generates an actor creation menu under the given MenuList item.
        * Also handles custom additionnal OnClick callback
        * @param p_menuList
        * @param p_parent
        * @param p_onItemClicked
        */
        static void GenerateActorCreationMenu(OvUI::Widgets::Menu::MenuList& p_menuList, OvCore::ECS::Actor* p_parent = nullptr, std::optional<std::function<void()>> p_onItemClicked = {});
    };
}

头文件很简短,引入了其他命名空间来定义类ActorCreationMenu,不过并没有启用构造函数,下个函数的具体内容在cpp文件中再讲。

ActorCreationMenu.cpp

std::function<void()> Combine(std::function<void()> p_a, std::optional<std::function<void()>> p_b)
{
    if (p_b.has_value())
    {
        return [=]()
        {
            p_a();
            p_b.value()();
        };
    }

    return p_a;
}

template<class T>
std::function<void()> ActorWithComponentCreationHandler(OvCore::ECS::Actor* p_parent, std::optional<std::function<void()>> p_onItemClicked)
{
    return Combine(EDITOR_BIND(CreateMonoComponentActor<T>, true, p_parent), p_onItemClicked);
}

std::function<void()> ActorWithModelComponentCreationHandler(OvCore::ECS::Actor* p_parent, const std::string& p_modelName, std::optional<std::function<void()>> p_onItemClicked)
{
    return Combine(EDITOR_BIND(CreateActorWithModel, ":Models\\" + p_modelName + ".fbx", true, p_parent, p_modelName), p_onItemClicked);
}

void OvEditor::Utils::ActorCreationMenu::GenerateActorCreationMenu(OvUI::Widgets::Menu::MenuList& p_menuList, OvCore::ECS::Actor* p_parent, std::optional<std::function<void()>> p_onItemClicked)
{
    using namespace OvUI::Widgets::Menu;
    using namespace OvCore::ECS::Components;

    p_menuList.CreateWidget<MenuItem>("Create Empty").ClickedEvent += Combine(EDITOR_BIND(CreateEmptyActor, true, p_parent, ""), p_onItemClicked);

    auto& primitives = p_menuList.CreateWidget<MenuList>("Primitives");
    auto& physicals = p_menuList.CreateWidget<MenuList>("Physicals");
    auto& lights = p_menuList.CreateWidget<MenuList>("Lights");
    auto& audio = p_menuList.CreateWidget<MenuList>("Audio");
    auto& others = p_menuList.CreateWidget<MenuList>("Others");

    primitives.CreateWidget<MenuItem>("Cube").ClickedEvent              += ActorWithModelComponentCreationHandler(p_parent, "Cube", p_onItemClicked);
    primitives.CreateWidget<MenuItem>("Sphere").ClickedEvent            += ActorWithModelComponentCreationHandler(p_parent, "Sphere", p_onItemClicked);
    primitives.CreateWidget<MenuItem>("Cone").ClickedEvent              += ActorWithModelComponentCreationHandler(p_parent, "Cone", p_onItemClicked);
    primitives.CreateWidget<MenuItem>("Cylinder").ClickedEvent          += ActorWithModelComponentCreationHandler(p_parent, "Cylinder", p_onItemClicked);
    primitives.CreateWidget<MenuItem>("Plane").ClickedEvent             += ActorWithModelComponentCreationHandler(p_parent, "Plane", p_onItemClicked);
    primitives.CreateWidget<MenuItem>("Gear").ClickedEvent              += ActorWithModelComponentCreationHandler(p_parent, "Gear", p_onItemClicked);
    primitives.CreateWidget<MenuItem>("Helix").ClickedEvent             += ActorWithModelComponentCreationHandler(p_parent, "Helix", p_onItemClicked);
    primitives.CreateWidget<MenuItem>("Pipe").ClickedEvent              += ActorWithModelComponentCreationHandler(p_parent, "Pipe", p_onItemClicked);
    primitives.CreateWidget<MenuItem>("Pyramid").ClickedEvent           += ActorWithModelComponentCreationHandler(p_parent, "Pyramid", p_onItemClicked);
    primitives.CreateWidget<MenuItem>("Torus").ClickedEvent             += ActorWithModelComponentCreationHandler(p_parent, "Torus", p_onItemClicked);
    physicals.CreateWidget<MenuItem>("Physical Box").ClickedEvent       += ActorWithComponentCreationHandler<CPhysicalBox>(p_parent, p_onItemClicked);
    physicals.CreateWidget<MenuItem>("Physical Sphere").ClickedEvent    += ActorWithComponentCreationHandler<CPhysicalSphere>(p_parent, p_onItemClicked);
    physicals.CreateWidget<MenuItem>("Physical Capsule").ClickedEvent   += ActorWithComponentCreationHandler<CPhysicalCapsule>(p_parent, p_onItemClicked);
    lights.CreateWidget<MenuItem>("Point").ClickedEvent                 += ActorWithComponentCreationHandler<CPointLight>(p_parent, p_onItemClicked);
    lights.CreateWidget<MenuItem>("Directional").ClickedEvent           += ActorWithComponentCreationHandler<CDirectionalLight>(p_parent, p_onItemClicked);
    lights.CreateWidget<MenuItem>("Spot").ClickedEvent                  += ActorWithComponentCreationHandler<CSpotLight>(p_parent, p_onItemClicked);
    lights.CreateWidget<MenuItem>("Ambient Box").ClickedEvent           += ActorWithComponentCreationHandler<CAmbientBoxLight>(p_parent, p_onItemClicked);
    lights.CreateWidget<MenuItem>("Ambient Sphere").ClickedEvent        += ActorWithComponentCreationHandler<CAmbientSphereLight>(p_parent, p_onItemClicked);
    audio.CreateWidget<MenuItem>("Audio Source").ClickedEvent           += ActorWithComponentCreationHandler<CAudioSource>(p_parent, p_onItemClicked);
    audio.CreateWidget<MenuItem>("Audio Listener").ClickedEvent         += ActorWithComponentCreationHandler<CAudioListener>(p_parent, p_onItemClicked);
    others.CreateWidget<MenuItem>("Camera").ClickedEvent                += ActorWithComponentCreationHandler<CCamera>(p_parent, p_onItemClicked);
}

这里定义了三个函数用于辅助当前函数,Combine()函数用到了许多C++现代特性。首先是function类模板,使用它可以让函数声明变得简单,但我们在此并不着重于介绍C++特性,所以有兴趣的可以查阅相关文章然后像是lambda表达式,可以让函数使用更直接快捷,具体可看这里还有std::optional类型,实际上就是对编程中常见的初始空值的代替,介绍可以看这里。有了以上的基础,这个Combine()函数就不是很难理解了,具体实现就是先判断p_b是否非空,如果是,那就执行p_a()函数和p_b内部所含的函数;如果为空值,就返回p_a()函数。
剩下的两个辅助用的函数ActorWithComponentCreationHandler()和ActorWithModelComponentCreationHandler(),就是Combine()函数具体使用的又一层封装。p_a是把属性或者模型和对应的变量绑定,p_b是鼠标点击。
最后的GenerateActorCreationMenu(),下面一句是用给定menulist生成了物体创建菜单:

p_menuList.CreateWidget<MenuItem>("Create Empty").ClickedEvent += Combine(EDITOR_BIND(CreateEmptyActor, true, p_parent, ""), p_onItemClicked);

而接下来的又一大串则是充当回调函数的作用,类型是看由谁调用:

    primitives.CreateWidget<MenuItem>("Cube").ClickedEvent              += ActorWithModelComponentCreationHandler(p_parent, "Cube", p_onItemClicked);
    primitives.CreateWidget<MenuItem>("Sphere").ClickedEvent            += ActorWithModelComponentCreationHandler(p_parent, "Sphere", p_onItemClicked);
    primitives.CreateWidget<MenuItem>("Cone").ClickedEvent              += ActorWithModelComponentCreationHandler(p_parent, "Cone", p_onItemClicked);
    primitives.CreateWidget<MenuItem>("Cylinder").ClickedEvent          += ActorWithModelComponentCreationHandler(p_parent, "Cylinder", p_onItemClicked);
    primitives.CreateWidget<MenuItem>("Plane").ClickedEvent             += ActorWithModelComponentCreationHandler(p_parent, "Plane", p_onItemClicked);
    primitives.CreateWidget<MenuItem>("Gear").ClickedEvent              += ActorWithModelComponentCreationHandler(p_parent, "Gear", p_onItemClicked);
    primitives.CreateWidget<MenuItem>("Helix").ClickedEvent             += ActorWithModelComponentCreationHandler(p_parent, "Helix", p_onItemClicked);
    primitives.CreateWidget<MenuItem>("Pipe").ClickedEvent              += ActorWithModelComponentCreationHandler(p_parent, "Pipe", p_onItemClicked);
    primitives.CreateWidget<MenuItem>("Pyramid").ClickedEvent           += ActorWithModelComponentCreationHandler(p_parent, "Pyramid", p_onItemClicked);
    primitives.CreateWidget<MenuItem>("Torus").ClickedEvent             += ActorWithModelComponentCreationHandler(p_parent, "Torus", p_onItemClicked);
    physicals.CreateWidget<MenuItem>("Physical Box").ClickedEvent       += ActorWithComponentCreationHandler<CPhysicalBox>(p_parent, p_onItemClicked);
    physicals.CreateWidget<MenuItem>("Physical Sphere").ClickedEvent    += ActorWithComponentCreationHandler<CPhysicalSphere>(p_parent, p_onItemClicked);
    physicals.CreateWidget<MenuItem>("Physical Capsule").ClickedEvent   += ActorWithComponentCreationHandler<CPhysicalCapsule>(p_parent, p_onItemClicked);
    lights.CreateWidget<MenuItem>("Point").ClickedEvent                 += ActorWithComponentCreationHandler<CPointLight>(p_parent, p_onItemClicked);
    lights.CreateWidget<MenuItem>("Directional").ClickedEvent           += ActorWithComponentCreationHandler<CDirectionalLight>(p_parent, p_onItemClicked);
    lights.CreateWidget<MenuItem>("Spot").ClickedEvent                  += ActorWithComponentCreationHandler<CSpotLight>(p_parent, p_onItemClicked);
    lights.CreateWidget<MenuItem>("Ambient Box").ClickedEvent           += ActorWithComponentCreationHandler<CAmbientBoxLight>(p_parent, p_onItemClicked);
    lights.CreateWidget<MenuItem>("Ambient Sphere").ClickedEvent        += ActorWithComponentCreationHandler<CAmbientSphereLight>(p_parent, p_onItemClicked);
    audio.CreateWidget<MenuItem>("Audio Source").ClickedEvent           += ActorWithComponentCreationHandler<CAudioSource>(p_parent, p_onItemClicked);
    audio.CreateWidget<MenuItem>("Audio Listener").ClickedEvent         += ActorWithComponentCreationHandler<CAudioListener>(p_parent, p_onItemClicked);
    others.CreateWidget<MenuItem>("Camera").ClickedEvent                += ActorWithComponentCreationHandler<CCamera>(p_parent, p_onItemClicked);

二、Settings

EditorSettings.cpp

#include "OvEditor/Settings/EditorSettings.h"

这个cpp文件的作用只是包含头文件,所以咱们就讲讲头文件。

EditorSettings.h

namespace OvEditor::Settings
{
	/**
	* Accessible from anywhere editor settings
	*/
	class EditorSettings
	{
	public:
		template<typename T>
		class Property
		{
		public:
			/**
			* Creates the property with a default value
			* @param p_value
			*/
			Property(T p_value) : m_value(p_value) {}

			/**
			* Event called when the property value changes
			*/
			OvTools::Eventing::Event<T> OnValueChanged;

			/**
			* Assign a new value to the property
			* @param p_value
			*/
			inline T& operator=(T p_value)
			{
				Set(p_value);
				return m_value;
			}

			/**
			* Assign a new valeu to the property
			* @param p_value
			*/
			inline void Set(T p_value)
			{
				m_value = p_value;
				OnValueChanged.Invoke(m_value);
			}

			inline operator T()
			{
				return m_value;
			}

			/**
			* Returns the value of the property
			*/
			inline T Get() const
			{
				return m_value;
			}

		private:
			T m_value;
		};

		/**
		* No construction possible
		*/
		EditorSettings() = delete;

		inline static Property<bool> ShowGeometryBounds = { false };
		inline static Property<bool> ShowLightBounds = { false };
		inline static Property<bool> ShowGeometryFrustumCullingInSceneView = { false };
		inline static Property<bool> ShowLightFrustumCullingInSceneView = { false };
		inline static Property<float> LightBillboardScale = { 0.5f };
		inline static Property<float> TranslationSnapUnit = { 1.0f };
		inline static Property<float> RotationSnapUnit = { 15.0f };
		inline static Property<float> ScalingSnapUnit = { 1.0f };
	};
}

在EditorSettings类中还有Property类,Property内的定义很简单,维护了一个模板类型值;构造函数是赋默认值;有在改变数值时的事件,重载了“=”和“()”运算符,和set()以及get()函数一样,都是赋值和读值;至于EditorSettings类,则没有构造函数,同时只定义了一些默认属性。

三、Resources

RawTextures.h

#define BUTTON_PLAY		
#define BUTTON_PAUSE	
#define BUTTON_STOP		
#define BUTTON_NEXT		
#define BUTTON_REFRESH	
#define ICON_FILE		
#define ICON_TEXTURE	
#define ICON_SOUND		
#define ICON_SHADER		
#define ICON_SCRIPT		
#define ICON_SCENE		
#define ICON_MODEL		
#define ICON_FONT		
#define ICON_FOLDER		
#define ICON_MATERIAL	
#define EMPTY_TEXTURE	
#define BILL_PLIGHT		
#define BILL_ASLIGHT	
#define BILL_ABLIGHT	
#define BILL_SLIGHT		
#define BILL_DLIGHT		

这段代码不复杂,但实在是太长了,所以在这里并没有放全部,只是把名称放了进来。从这个头文件的名字就可以看出,这其实是定义了一些默认图片,由于需要给出每个像素的灰度值,所以才会特别的长,具体其实没有什么好说的。

RawShaders.h

namespace OvEditor::Resources
{
	/**
	* Defines some editor shaders
	*/
	class RawShaders
	{
	public:
		/**
		* Returns the grid shader
		*/
		static std::pair<std::string, std::string> GetGrid();

		/**
		* Returns the gizmo shader
		*/
		static std::pair<std::string, std::string> GetGizmo();

		/**
		* Returns the billboard shader
		*/
		static std::pair<std::string, std::string> GetBillboard();
	};
}

定义了RawShaders类,事实上就是三个shader,具体留待cpp中讲解。

RawShaders.cpp

我本打算在这篇文章中写完cpp,但因为shader使用的hlsl和正常的c++还不太一样,所以我决定新开一篇文章专门用于介绍此文件,在此就不说了。

总结

这篇文章介绍的都是一些比较简单的辅助文件,接下来要介绍的shader会比较不一样,它被包含在RawShaders.cpp中,并且是预定义好的,需要花费一些篇幅。

Diana

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值