
R.O.S.E. Game Engine
2024-2025
Specifications
Language: C++
Libraries: DirectX11, ImGui, PhysX, FMOD, …
Editor: Unreal
Screenshots to the left are taken from games made in the engine.
Introduction
R.O.S.E. is the name of the in-house engine developed at The Game Assembly in our group, Ink Inc. The engine is originally derived from a graphics engine that I developed from the Applied Graphics Programming course. Before the project got underway, there were already support for rendering meshes, deferred rendering, shadow mapping, and more goodies. What was missing initially were several common engine systems that are important to develop games, e.g., robust component system, collisions, audio, and NavMesh.
Unreal is used as an editor to the engine simply due to time-constraints, since it would otherwise require creating a practical level editor. While I would love to do it, I already had too much responsibility in other areas. To export a level in Unreal to our engine, the user has to manually export the level, which outputs its contents into a JSON file. For example, position of an actor, name of the mesh, what textures it has, what children do it have, and so on.
If you wish to see some specific section of code in the engine that relates to my contribution that isn't shown here, I will be happy to provide it upon request via mail or message on LinkedIn.
You can furthermore read about other utilities and data structures I've applied in the R.O.S.E. engine here.
Contribution
Details
Component System & EntityAdmin
The component system can be seen as the central system that simplifies or enables communication from the game to other modules of the engine. My goal with the component system is for it to be easy to use, understand, robust, and performant, because us programmers in the group are going to be using it actively to make games (and hopefully not break them). To achieve this, I attempted to make it have a familiar interface and functionality with Unity's own component system, something we in the group are all familiar with.
I placed significant value in listening to feedback from the other programmers and quickly fixing bugs that are found so that development can continue. For example, from a request, I added the ability to duplicate an entity such that enemies can easily be spawned in during the final boss battle in Spite.
As for the implementation, it all starts with the EntityAdmin where entities live, which in turn live in a Scene, which in turn live in the World. Each entity has a name that the developer may specify, a EntityID, a local & global transform, references to their components, and other stuff.
The EntityID is generated using an incrementing index combined with a version so that IDs may be reused, but with only the version incremented to prevent conflict on older IDs. Whenever an entity is removed, its ID is put into a queue so that it can be reused when a new one is created.
A component is any class that inherits from the base class with the same name. A component can override these functions, for example:
-
Init | Called immediately when added to an Entity
-
Awake | When added to an Entity, called the next frame once
-
Start | When added to an Entity, called the next frame once after Awake
-
PreUpdate | Called every frame before FixedUpdate
-
FixedUpdate | Called at a fixed rate of 60 times per second
-
Update | Called every frame after FixedUpdate
-
LateUpdate | Called every frame after Update
-
Render | Called for every active camera after LateUpdate
-
OnDestroy | Called when component is removed from an Entity
-
OnEnable | Called immediately when component is enabled
-
OnDisable | Called immediately when component is disabled
-
Debug | Called every frame only in debug mode
-
OnDuplicate | Called when entity is duplicated, used to copy over previous values to new
Components can be received, added, or removed through an Entity. However, an Entity does not actually hold the component, but only a reference to the component called ComRef. All components instead live in cache-based pools inside the ComponentManager.
A ComponentPool is essentially a FreeVector that contains all components of a specific type and is iterated through when, for example, Update is called. Using such a data structure made it possible to create two classes, ComRef and ComWeakRef. ComRef will remove the component when it is destructed, whereas ComWeakRef will not. ComWeakRef is used commonly to refer to other components and is what is returned when retrieving a component from an Entity.
The code excerpts below are some examples of classes in the component system module, you can view additional examples here: https://gist.github.com/Daikalos/62fcd447a113aab40bde9ec544f852f5
Entity Hierarchy
Hierarchy for entities was implemented by adding parent and child data to an entity (pointers to other entities). This will, for example, cause an object to follow its parent entity's world transform. It can also be used for, e.g., searching for an entity with a tag or component in their children.
To improve performance, whenever an entity's position, rotation, or scale is updated, it is marked as dirty, along with its children. When the entity's transform is retrieved, and if the entity is dirty, the transform matrix is recalculated and returned. Otherwise, it just returns the matrix unchanged.
The GIF to the right shows a cube at the bottom that rotates the chest, which rotates the character.

Component Import
Because we were using Unreal as an editor to import and load stuff into our engine, we had the problem of adding functionality to specific entities in the game. One solution was to use actor tags in Unreal and add components to entities in our engine based on those tags. However, I decided that solution felt too inflexible, prone to errors, and takes away being able to use tags for what they are meant for. Therefore, I added registration for components in our engine, where you can find the corresponding ComponentPool via its name.
In the export script, the name of an actor's components are exported, and then when importing, they can be used to find which component to add to the entity.
The excerpt below is an example of a macro I created to make it easy to register a component in the .cpp file. You can furthermore specify priority which determines the order of execution for the component, for example, to allow a specific component to call its Update before another one does.

An additional useful feature that was added, was the ability to import the blueprint variables on actor components in Unreal into our engine. I felt that this was extremely important to speed up testing and enable better control of modifying functionality for different entities. What I did was implementing the conversion of variables in the exported JSON file, which is then put into a format that is easily interpreted in the component to serialize its corresponding members. To make it convenient for others, I added a macro shown below that serializes specified member variables in the component.


Asset Registry
The AssetRegistry holds all the assets (naturally) which can be a mesh, texture, material, shader, animation, etc. All assets that are located under the Content directory local to our engine are automatically registered when the application starts. This allows for the name of the asset to be used to find it, with the drawback of requiring all assets to have unique names (which has honestly been an issue…).
When an asset is requested for the first time in the engine, it attempts to load the file at the path that was registered. This ensures that only the assets that are used in the game are the ones being loaded. An added feature is that after a scene is done loading, it will attempt to unload assets that are not being used by checking use count on the std::shared_ptr. The reason for this is simply to release assets being unnecessarily loaded in memory.
Asset Serialization
Serialization for all [.fbx] assets was added to improve the loading speed when an asset is first requested. When the asset successfully loads, it will also serialize its results to a new file with the extension [.rose]. This is done mostly using basic memcpy for trivial types, whereas non-trivial gets special handling such as string or vector. If the original asset that is being loaded is older than its corresponding serialized file, then the latter will be used to load the asset. Thanks to Zoe Thysell for inspiration on how to build a flexible binary serialization handler, which you can find below.
During serialization, the type of asset, the path to the original file, and the serialization version also get serialized. This is so that when the file with the serialized contents gets loaded, it first checks if the asset at the original filepath is up-to-date with the serialized file. If the original asset is newer, then the serialized file gets deleted and the asset must be loaded anew again. Serialization version is mostly helpful to remove old files and serialize the assets anew.
The code excerpts below are examples of how serialization looks like, if you want a more holistic view on how exactly serialization is handled, you can check it out here:
Render & Update Threads
I added double buffered rendering to the engine, which means that all game logic runs on its own thread separated from the main thread where rendering occurs. To implement this, we have two separate GraphicsCommandList, where one is filled with commands from the update thread, while the other is being executed on the main thread. This is a quick and efficient way to generally improve performance, with the drawback of the game being one frame behind, which isn't noticeable anyway.
Graphics Assembler
To provide a flexible way to add new types of rendering techniques when needed, I created a class called GraphicsAssembler. Through this class, we externally enqueue an item to be drawn by passing a DrawID, where the class then takes care of the rest to make sure it is drawn correctly. DrawID contains flags such as which rendering layer and what transparency the item has to eventually sort the enqueued items, for example, rendering opaque objects sorted by depth first and then all transparent sorted in reverse order. This furthermore improves performance by reducing the number of times the graphics engine has to change its internal pipeline states (pixel shader, vertex shader, etc.) by sorting material IDs.
The GraphicsAssembler has been immensely helpful to quickly test or add new rendering techniques. For example, Axel Franzén in our group had no trouble at all modifying DrawID and adding a new pass to render out decals in the world.
Scene Graph & Frustum Culling

I added a SceneGraph which uses an Octree to efficiently cull objects that are not seen by the player. All drawable things must inherit from a SceneNode which contains logic to handle, e.g., referencing which node it occupies in the SceneGraph to quickly remove itself if need be.
The first step when rendering in the GraphicsAssembler is to take the frustum generated by the projection view matrix from the camera and query the SceneGraph for nodes that intersect the frustum. This way, objects that are not seen can be culled as early as possible before even being sent to the graphics command list.
Frustum culling was also added for shadow casting lights to quickly find objects in their view. Directional light and spotlight cull similarly using a frustum projected from their point of view, while pointlight uses a basic sphere to query.
Threaded Scene Loading
Threaded scene loading required me to rethink the design of several systems in the engine. To reduce the risk of data race, the loading thread is designed to use as little external code as possible.
The code that had to be made thread-safe was at least the AssetRegistry and the component system. The AssetRegistry because assets are being loaded in, and the component system because components are being added to new entities being created.

The AssetRegistry was solved simply by adding a mutex into its functions to prevent multiple threads from writing at the same time. The component manager was trickier because I desired for it to be possible to load another scene while the game is running at the same time. To solve this, thread-safe pending queues were added for many actions that are then flushed when loading is done.
The code excerpts below show the SceneHandle which is an object that is returned when loading a scene that you can use to query, for example, the current status of the scene being loaded.
Robust Exception Handling
As the engine is being utilized by all members of the group, for example, playtesting and examining models in the ModelViewer, it would be annoying if the application just closed without knowing what happened. When something crashed, if we could get data on where it happened in the code and for that to be shared to us programmers, it would make it a lot easier to fix. Furthermore, it would also be convenient for others, if it were to crash, that the application could recover from it.
The solution for this was simply to put some try catch blocks in sensitive code so that exceptions could be caught, for example, when updating components. An addition to it was to add StackWalker that prints out the current stack to the console, which made it easy to find where the crash occurred.
A considerable problem we had was importing rotations from Unreal into our engine. Specifically, at some times objects would just flip, which I discovered happened occasionally when you convert directly from a rotationmatrix to Euler angles. It seems to be caused from the Euler angles reaching a singularity at the north/south poles. Then there was also animation blending, which requires spherical linear interpolation for rotations to look correct.
To solve many of these problems, and also solving the Gimbal lock, I added Quaternion to the math library which replaced most applications of Euler angles in the project. After that, a rotationmatrix could be accurately converted to a quaternion, and vice versa. It could also be used for interpolation when blending two rotations.