Application

Application Structure

All applications in Force holds by Force::Application class. Application is base class of Force Engine, it holds all user applications, initialize other engines, managers, load libraries defined by Force::ApplicationSpecification. To create a application we need create single executable file, in our case in will be ExampleApplication.cpp.

Any Application accept the ApplicationSpecification structure in their base constructor. About the specifications we will talk later.

// Defenition of Application constructor.
Application(const ApplicationSpecification& spec);

Modules

Each Force Core module is divided by different folders and stored in separate namespaces. Here list with all supported at this moment Force modules.

Module
Folder
Namespace

Core

Force/Core

Force::Core

IO

Force/IO

Force::IO

Graphics

Force/Graphics

Force::Graphics

Audio

Force/Audio

Force::Audio

Platform

Force/Platform

Force::Platform

Physics

Force/Physics

Force::Physics

Math

Force/Math

Force::Math

Animation

Force/Animation

Force::Animations

Assets

Force/Assets

Force::Assets

Project

Force/ProjectManagment

Force::ProjectManagment

Scene Managment

Force/SceneManagment

Force::SceneManagment

Scripting

Force/Scripting

Force::Scripting

Serialization

Force/Serialization

Force::Serialization

Networking

Force/Network

Force::Networking

Localization

Force/Localization

Force::Localization

UI

Force/UI

Force::UI

Utils

Force/Utils

Force::Utils

Entry point

Each application should have its entry point. Entry point is entry of any program in general. In Force entry point defined in Main.cpp file. Without it, you won't be able to compile and launch the application. This file need to be included once per application project.

So to quickly setup entry point, and other properties, lets define and setup Main.h, that you can copy from engine Force/Main.h with all description about each define.

In this file we can choose witch runtime Force API's we should use, for example in ManagedInitializeCore() for CoreSpecification we can choose to disable executing of Scripting Engine, because for our application it not needed. But main include there is Force/Main.cpp, because it define application entry point and include Main() function to make our application executable.

Now how our ExampleApplication.cpp file should looks like:

Before launching application we need to create implementation of Force::CreateApplication() function.

As you can see all information here that passed into Application via ApplicationSpecification is trivial, only one little new note that i wanna take of: FE_DEV_LOCATION macro is point to "C:/ForceDev", witch is default, constant location on drive where all Force Engine development branch are stored.

And that's it! Now you can just press F5 and build and run your own application written in Force.

If you have some problems with compiling or linking Force, please take a look on the latest two chapters below.

Application Specifications

Now Applications use the specifications like ApplicationSpecification, ApplicationUserSpecification, ApplicationWindowSpecification, and ApplicationBootSpecification instead old GetParam API.

When you first configure and run the engine you will have by default are the default settings of window and so on. If you want to add or change your app's settings you will need to use Force::ApplicationSpecification struct to configurate custom application. Its contains the bunch options that you can apply on application.

ApplicationSpecification

As you can see ApplicationSpecification contains basic, parameter as name or version of your application, but also contains other application sub-specifications.

ApplicationUserSpecification

User specification contains information about user per application. Some of options can be independent of each application, like startProjectPath or newUser.

But other options is specific for each application.

ApplicationWindowSpecification

Window specification contains application window info.

ApplicationBootSpecification

Contains information about boot/start data that comes from Core and Entry Point.

This Application specification you should implement in your CreateApplication function. For example:

Element System

To access to engine main update loop and hold our code properly we use Elements.

Include the Force/Core/Element.h from Force::Core namespace. Next creates new file and class ExampleElement.h somewhere in folder Elements and inherent it from Element.

Element has pack events that called in some time by application and controls by Force::ElementEngine. This are basic from this list:

Element Events
Description

OnCreate()

Calls when all application engines was initialized. You can threat this event as Element constructor.

OnEvent()

Calls by application when any event inherited from Event is invokes.

OnUpdate()

Calls by application in engine main update loop every frame, with passing the delta time variable.

OnRender()

Calls by application in in engine main update loop every frame with purpose for rendering.

OnDestroy()

Calls when application exiting from main engine update loop. You can threat this event as Element destructor.

Also exist are few additional events that also can be called by application, order is matter here:

Element Events
Description

OnCreateWND()

Calls when application creates platform and window, but before the OnCreate(), and OnCreatePost(). Prefer using this for setting custom title. Not use rendering, audio, physics, scripting code here because contexts of it was not created at this point.

OnCreateGUI()

Calls right after OnCreate(), and OnCreateWND() during Dear's ImGui context creation, and before OnCreatePost(). This function will not be executed if application disable support ImGui. Main usage of this function is customize the ImGui global settings during creation for each application.

OnCreateGPU()

Calls every time when application is reloading all GPU descriptors and resources, such a Textures, Shaders, Framebuffers, VertexBuffers, IndexBuffers, and purpuse for its initialization. However this event will not be called automatically on the start, or at OnCreate() time, you need to call it manially. Reason for that sometimes, some Graphics APIs can detect GPU device as suspended, removed, ot hung due to driver/OS error or state change, and that way Force can reload all this resources automatically.

OnCreatePost()

Calls after OnCreate(), OnCreateGUI(), and OnCreateWND(). This event usally called after main window is full created, initialized and showed.

OnRenderGUI()

Calls after main rendering, when Dear's ImGui begin their rendering frame. This function will not be called if application disable support of Dear's ImGui.

OnDestroyGPU()

Calls every time when application is reloading all GPU descriptors and resources, such a Textures, Shaders, Framebuffers, VertexBuffers, IndexBuffers, and purpuse for its destruction. However this event will not be called on the end, or at OnDestroy() time, you need to call it manially. Reason for that sometimes, some Graphics APIs can detect GPU device as suspended, removed, ot hung due to driver/OS error or state change, and that way Force can reload all this resources automatically.

OnFrameOver()

Calls when current frame is over, usefull when need to Application::PresentFrame() immediatly. Nowdays using for processing operations, that should happen after frame is over, but before new frame.

OnNextFrame()

Calls on next frame, i.e after GPU redraws all drawable surface and application logic (execute SwapChain::Present()), and complete logic. You can skip few frames by passing 'frames' count and then execute. This function will be called right up when new frame is started, so here you cannot use renderers, only logic.

Rendering using Elements

This example will implement Element as basic test for Force Renderer.

Next create the implementation file ExampleElement.cpp, and include ExampleElement.h.

In OnCreate() event we setting up the perspective camera, and in OnCreateGPU() we create all GPU resources, for advanced usage you can create it everywhere, but for basic usage, to let Force reload all resources in case of driver lost/hung.

In OnUpdate() event we implement basic every frame update logic, like camera movement or object transformations.

In OnRender() event we call commands from RenderPass from Force::Graphics to start main screen pass, which will perfom clearing main screen buffer with new color and clear depth/depth-stencil buffers which was defined in RenderPassSpecification or like in example dynamic clear property.

Before we can render anything we need to call Begin() and End() from specified renderer which will begin renderer's pipeline, set to it Camera and RenderPass throw witch rendering happens.

Today Force 2D Renderer support few types of primitive:

  • Points

  • Lines

  • Quads

  • Quads Textured

  • Circles

  • Sprites

  • AABB's

If you want you can add few more example primitives:

The RenderSprite() use the ECS components, one for Transform and another for Sprite. C++ API is almost identical to C#, so you can find more information in this section.

The RenderQuadTextured() accept the texture parameter. To create and load a texture use Texture2D from Force::Graphics namespace. Also its accepts Transform instead of Rect because we pass rotationZ value to have opportunity to rotate the rect.

We have finished creating your own rendering element, now you just need to add element to application in Force::CreateApplication().

You can use two ways to do this by AddElementLast() to add element to end of container, and AddElement() to add scene to begin of container. And after that you can run your app with peace of mind.

Examples\ExampleApplication

Check Example\ExampleApplication for full example in ForceDev repository for details.

Console Applications

Force also allows to create a console applications, and cut off a lot of unnecessary API's, such a main window, rendering, assets, languages, IO, and display only console that you can write, read or test or maybe even create a server (even if Force not have this API yet.).

To create a console application all that you need to do is in you CreateApplication function set consoleApp to FE_TRUE:

Also you can disable debug logger that you Force and use specific release logger, that will log only your message to console. To do this set this in you config file inside ManagedInitializeCore function:

Examples\ConsoleApplication

Check Example\ConsoleApplication for full example in ForceDev repository for details.

Solution and project configuration

Projects and solution we can configure using Premake that written on Lua. Lua is easy to learn scripting language, with minimum dependences and code. Each premake file stores on each of project directories. Main premake file is ForceEngine.lua stored in root of ForceDev. It contains utility functions to work with projects and solution itself. For reference you can check Lua arrow-up-rightand Premake arrow-up-rightdocumentation.

Force Linking

In the variable LinkForce we can specify how Force wil be linked and build: "Dynamic" to ".dll" or "Static to ".lib". Force from 23 commit (993651b) of dev using Static linking and to migrate to dynamic requested rewrite hole a bunch of code.

So for now Force supports only static linking and look like this:

Force Projects

Projects in Force separates by few groups: Core, Examples and Libraries and in that order displays in Visual Studio. About libraries we talk about later. Force project list available at this moment is:

If you dont need them to exist you can just turn it off by setting to false.

Each of this project and libraries defined as Libraries has its Project Directory ProjDir relative to ForceDir. Some of this projects - libraries that stored either relative to Force/Libraries or some of them relative to vckpg/packages .

All of this libraries has BinaryDir depending on build configuration (Debug, Release) where all binaries files stored for that library, then IncludeDir where all header files stored, and Library itself thats directly points to static library (.lib) witch you can link to Projects.Core.Force library.

Force Engine Solution

The code for solution looks like this:

Its basic premake script workspace with two configurations and some flags. Basically here all what you need for solution so dont recommended it to change.

Force Project

Go to Force and open Force.lua premake file. This is file that contains definition of the main project, basically all other projects are structured this way.

The most important here is targetdir and objdir where project will store when build project. By default it will be Bin/*BuildDir/*ProjectName/Lib and Bin/*BuildDir/*ProjectName/Obj

Then goes files and include directories (includedir) witch project will be included and use, and links list and already configured for each library of libraries that will be linked to Force.

Defines (defines) that contains list of predefined FE_LIBRARY_* macross and other platform libraries.

And the goes that same for each platform and configuration.

Application and Libraries

Enable and disable libraries

When you write applications, you can disable some libraries and especially its linking if you dont use them to decrease size of the your executable. Now it totally achievable. To do that please go to ForceEngine.lua and find libraries list:

Just set you library to false and you ready to go. Its disable library linking for static libraries, for dynamic libraries its disable copying its .dll file in to executable directory, and sets it proper macros FE_LIBRARY_XXX to 0. After this you need to fully rebuild the solution for Debug and Release configuration.

Libraries that now can be disables:

For other libraries its not tested, and basically other libraries its tiny and all static linked so you dont have any .dll file requested and dont need to disable.

Missing Mono .NET Framework

When you linked Mono and Mono Runtime in to Force you can not have Mono folder with all Runtime .Net Framework. If that happens means you forgot copy proper version of you .Net Framework from MonoSDK. To do that please go to C:\_YourMonoSDKPath_\lib\mono and select you version of .NET Framework and copy it Mono folder to you working or executable directory or just download this archivearrow-up-right.

Last updated