引擎的入口点

模块调整

应用程序启动的时候会发生什么?任何软件总会有一个程序的入口点,启动之后那些代码会开始运行,这就是程序的入口点。实现该方法的思路也很多,比如我们这里的Hazel就是一个dll文件,dll文件也有主函数,我们可以附件或分离dll进程的时候调用特定代码,换句话说也就是我们的应用程序加载或卸载dll时,我们可以对这些事件进行抓取。

首先我们删除掉Test.h和Test.cpp,这些只是测试用的类。在Hazel下的src文件夹创建Hazel文件夹,我们将在这里放核心的类,创建一个Core.h和Application.h,Application.cpp

Application.h

#pragma once
namespace Hazel
{
        class Application
        {
        public:
                Application();
                ~Application();

                void Run();
        };

}

Application.cpp

#include "Application.h"

namespace Hazel
{
        Application::Application()
        {
        }

        Application::~Application()
        {
        }
        
        void Application::Run()
        {
                while(true);
        }
}

这样我们就构建了一个能够无限运行的Run()方法,此时结构如下:

tips:__declspec(dllexport)和__declspec(dllimport)可以从dll文件中导出和导入相关的内容

考虑到这是我们自己的应用程序,因此可以用宏去简化一些操作,让我们更加方便。从根本上说,我们需要找到一个宏,它要么是用作dll导入,要么就是dll导出,具体取决于我们是否在构建这个dll文件

我们拆解一下需求,首先dll相关的内容都是仅限windows的内容,所以第一步是确定Hazel(下面缩写为HZ)是否是针对windows平台的。第二步是判断是否是要编译dll,是的话就export,不是就说明是import到实际项目。最后就是如果错误做一个报错处理。

Core.h

#pragma once
#ifdef HZ_PLATFORM_WINDOWS
        #ifdef HZ_BUILD_DLL
                #define HAZEL_API __declspec(dllexport)
        #else
                #define HAZEL_API __declspec(dllimport)
        #endif
#else
        #error Hazel only supports Windows!
#endif

随后打开Hazel和Sandbox的属性,在C/C++预处理器部分,预处理器定义(全部)分别修改添加:

HZ_PLATFORM_WINDOWS;HZ_BUILD_DLL;_WINDLL;%(PreprocessorDefinitions) HZ_PLATFORM_WINDOWS;_MBCS;%(PreprocessorDefinitions) 不知道这里会不会出问题,先这样改,本来DEBUG和Release长这样: _DEBUG;_CONSOLE;%(PreprocessorDefinitions) NDEBUG;_CONSOLE;%(PreprocessorDefinitions)

随后我们打开Hazel中的Application.h,导入Core.h后,就可以将原本的__declspec(dllexport)修改为HAZEL_API了。

Application.h

#pragma once

#include "Core.h"

namespace Hazel
{
        class HAZEL_API Application
        {
        public:
                Application();
                virtual ~Application();

                void Run();
        };
}

此时由于Hazel和Sandbox都有Application.cpp。所以我们将Sandbox中的Application.cpp更名为SandboxApp.cpp。

此时如果要编译,我们得使用#include<Hazel/App>这类的方式,不太方便,我们所期待的比较好的方法其实是用#include<Hazel.h>,对于该方法我们就要创建一个Hazel.h。这将是一个只给客户端应用程序包含的头文件供客户端使用,放在src文件夹内,Hazel文件夹外,这是一个供Hazel应用程序使用的头文件。

在Sandbox的属性中附加包含该目录,这样我们也可以使用#include”Hazel.h”了

#include <Hazel.h>

class Sandbox : public Hazel::Application
{
public:
        Sandbox()
        {

        }

        ~Sandbox()
        {

        }
};

void main()
{
        Sandbox* sandbox = new Sandbox();
        sandbox->Run();
        delete sandbox;
}

此时运行程序,会出现报错:

原因是我们没有更新动态链接库dll,而他现在包含了其他内容,由于我们还没有做后续的自动化,所以手动从目录中将之前的Hazel.dll再拖入sandbox中。此时即可正常运行。

入口函数EntryPoint

在Hazel文件夹下新增头文件EntryPoint.h,最开始先写成以下格式,确定一下这个头文件要做什么:

EntryPoint.h

#pragma once

#ifdef HZ_PLATFORM_WINDOWS

extern Hazel::Application* Hazel::CreateApplication();

int main(int argc, char** argv)
{
        Sandbox* sandbox = new Sandbox();
        sandbox->Run();
        delete sandbox;
}
#endif

以上代码将sandbox里面运行开始的地方搬过来了,意味着这是一个启动程序要做的事情,同时给了两个参数argc和argv,与Windows的WinMain有关(因为我们可能保留与程序运行方式相关的一些信息)。并且有一个返回某种数据的功能,Hazel应用程序指针,

Application.h

#pragma once

#include "Core.h"

namespace Hazel
{
    class HAZEL_API Application
    {
    public:
        Application();
        virtual ~Application();

        void Run();
    };

    //去定义在客户端中
    Application* CreateApplication();
}

SandboxApp.cpp

#include <Hazel.h>

class Sandbox : public Hazel::Application
{
public:
    Sandbox()
    {

    }

    ~Sandbox()
    {

    }
};

Hazel::Application* Hazel::CreateApplication()
{
    return new Sandbox();
}

此时我们将其添加到Application.h和SandboxApp.cpp中,就可以用这样的方式来返回这样的一个应用程序。(创建应用程序就是我们将在客户端实现的操作,Sandbox是我们要创建的应用程序)。

最后将其修改:

EntryPoint.h

#pragma once

#ifdef HZ_PLATFORM_WINDOWS

extern Hazel::Application* Hazel::CreateApplication();

int main(int argc, char** argv)
{
        auto app = Hazel::CreateApplication();
        app->Run();
        delete app;
}
#endif

Hazel.h

#pragma once

//For use by Hazel application

#include "Hazel/Application.h"

//------EntryPoint---------------------
#include "Hazel/EntryPoint.h"
//-------------------------------------

这里是为了方便模块细分,所以分开,此时我们的程序已经可以运行了。

功能细分

如果我们在尝试在EntryPoint.h中添加其他的东西比如:

int main(int argc, char** argv)
{
        printf("Hazel Engine\n");
        auto app = Hazel::CreateApplication();
        app->Run();
        delete app;
}

此时运行就会报错,因为缺少相关的库,在Hazel.h这里添加即可。

Hazel.h

#pragma once

//For use by Hazel application

#include <stdio.h>
#include "Hazel/Application.h"

//------EntryPoint---------------------
#include "Hazel/EntryPoint.h"
//-------------------------------------

这只是一个测试,我们还是将这一部分的代码去掉(