Flora
An open source C++ game engine framework
by Jason Heflinger
Flora is a game engine framework built in C++. It's meant to be easy to use, open source, and cross platform. Using the best of object oriented design and the considerable performance C++ offers, it offers a library of all the basic tools a game developer needs to create their first game. It currently focuses on 2D game design, but there are basic fundamentals in place to support 3D design in the future!
Motivation
Flora is one of my biggest passion projects; sitting at nearly 400 commits and a project duration of about 1.5 years, I can truly say that I sank my blood, sweat, and tears into it.

It all first started off as a learning project to delve into what goes on behind the scenes in modern game engines; at first I simply didn't want to have to sit through hours of boring engine tutorials to get proficient with a typical engine, but after a while I began to wonder how game engine technologies have optimized games to the state they are today. After all, looking back, many of the biggest advancements and optimizations in software have been through the motivation of creating video games. Video games today can have ultra-realistic graphics not just because our processors are several magnitudes faster, but also because of the advanced toolkits developers have created. Since then, this project has become about discovering the architecture and techniques behind modern game engine tooling and implementing them myself.

After all, its not like any particular person is going to be using this engine, nor is it doing anything particularly revolutionary. This project has been and probably always will be a learning outlet for myself.
Features
As stated before, Flora offers the basic fundamentals that a 2D game developer needs to make their first game. This includes features such as (but not limited to!):
  • Custom 2D/3D rendering via OpenGL
  • An entity component system
  • Texture support
  • Animation support
  • Precompiled entity components
  • Scene serialization
  • Entity serialization
  • 2D physics
  • Developer tools
  • Stat analysis
  • C# scripting engine
  • Build capabilities
  • Asset management
  • C# script reflection
  • Text rendering
  • Audio capabilities
  • Network capabilities
This main feature set was decided and created via a basic analysis on what exactly the typical developer wants in a game, as well as what basic features can be used to create customized more advanced features. Read more about how these features are implemented and used in the Development Process section below!
Development Process
I figured early on that this project would be my biggest one yet, so I quickly realized that I had to put in a lot more effort this time in the quality of the project architecture and long-term performance. However, the fact that I didn't have much experience in C++ or large project management was pretty damning to say the least. To get past this, I took a lot of help from game engine development tutorials on youtube, specifically TheCherno's tutorials. At the beginning, I treated a lot of it as a follow-along type of walkthrough, which helped me break through really well! Watching a veteran programmer at work helped me develop habits and forward thinking for the architecture far better than if I were to just go about it alone. Of course at some point, I branched onto my own to develop my own ideas and implementations and walked back through the past implementations to properly understand everything.
Early setup
Early on, I have to admit that it was difficult to stay motivated. With most of the beginning being just figuring out how to properly compile C++ projects and setting up architecture and tools for the future, there wasn't a lot of "satisfying results" that rewarded a long stream of work. It was a lot of setting up basic rendering components, the logging system, and platform compatibility.

System compatibility was a huge thing to consider in the beginning, as I wanted to leave room in the future to not just be cross compatible, but to support different rendering backends such as using Vulkan, Metal, or DirectX rather than just OpenGL. This was especially important for rendering, since I didn't want to have to rewrite the entire rendering backend when I was done with OpenGL.

On a side note, this was also when I really learned about C/C++ macros! Macros have quickly become one of my favorite features of C/C++ due to how versatile and powerful they are to use! When I first started using and understanding them, it felt like I could basically create my own minor programming language within C/C++ to customize my programming experience while at the same time optimizing performance! Every time I start a new C/C++ project I thank Alan Snyder (who I believe introduced the C preprocessor?) for making macros a reality. 🙏
Windows, Events, GLFW!
Way back long ago, when baby Jason was like 12, I tried to create a windowed program in C++. After being met with youtube videos telling me to use C++ Windows Forms, I was immediately repelled and never tried to touch it again. Starting this project up again and needing to create a window frightened me, as I could only imagine how horrible it could be. However, using GLFW was quite the delight! I have no why I saw Windows Forms before this, but GLFW was the perfect amount of control and customizability I needed to create a game window. Thankfully, it also had a nice event system for grabbing inputs!
Rendering
The rendering system was the first large-scale implementation that I had to do. I've never known how graphics work prior to this, so implementing an entire customized graphics pipeline was definitely quite a challenge. To be fair, it was an OpenGL graphics pipeline, but it was still a new area to work in nonetheless. Even after following youtube tutorial after youtube tutorial, I struggled to understand what I was even doing that made the funny triangle appear on my screen. In fact, I can say that I truly understood the graphics pipeline only after I finished implementing it, in which I attempted to create a similar renderer using Vulkan. Vulkan is, to say the least, to OpenGL as C is to Python. Considerably harder to understand and use, but far more powerful in terms of potential. Ironically, it was only after I finished creating the Vulkan pipeline was I able to look back on my OpenGL pipeline and understand it.
3D Math
As one might expect, it's not just enough to draw a colorful triangle on a window to create an entire game engine. To make objects appear in 3D or orthographic space, there is a slight degree of 3D math involved. However, back when I was first starting work on this, I did not have much knowledge in the subject matter, since I didn't take a linear algebra class yet. However, I was enrolled in a computer vision course, which taught the basics of 3D math for the application of image processing and analyzation. Because of this, learning and applying these concepts to create view-projection cameras with both projection and orthographic modes were pretty fun to do!
Debugging
Debugging this project had its ups and downs; when it came to debugging the graphics pipeline, I was fairly clueless on how to detect errors due to my inexperience. I didn't know how to properly log the information I needed, nor did I know what information I was exactly looking for. For the rest of the project, however, things were suprisingly pleasant.

Debugging Flora is really where the architecture I set up in the beginning truly shined. This is also where I truly think object-oriented programming shines the most. When a bug appears, it was so easy to immediately identity what systems/classes are linked to it, which ones could cause it, and which one the irregular behavior likely stemmed from. In fact, 9 times out of 10, I could immediately pinpoint which function from memory (my brain's memory, not the computer lol) the bug was located in. Compared to debugging previous projects, this was like a wave of relaxation and relief. In fact, I rarely worried or stressed over bugs and issues, and I can only thank my past self for putting the time and effort into creating a clear and purposeful architecture.

An honorable mention here is actually for Visual Studio! I know that people have their gripes with Visual Studio as a bloated and overengineered piece of proprietary software from Microsoft, but as a first C++ IDE, I found it delightful! Even though I've switched away from it since, I still hold a spot for it in my heart, and this is primarily due to its debugging capabilities. Adding in breakpoints, navigating the codebase, and monitoring memory locations were so intuitive and easy, I never really had to "learn" how to use the debugger officially. It came naturally, and made debugging issues just that much easier!
Serialization
Serialization for Flora was one of the more interesting things to think about, despite it not exactly being the most visually exciting function. Saving information between scenes and even entities was indeed a pain to implement (no thanks to C++ lacking reflection support...), but boy did it pay off! Being able to completely save a scene and even an entity, and load it easily was such a nice feature, especially for collaborative game development projects!

This was because of the fact that the serialization system uses YAML! Although this is definitely not the most efficient system, especially for larger scenes, the tradeoff here is that it becomes very human readable. Looking at scene content and modifying it becomes incredibly easy without having to touch or compile code at all! And because of this, it becomes easy for collaborating developers to share resources, such as entities across scenes and projects. Have a cool game object? Just serialize it and send it over! As long as any assets such as textures or scripts are also sent over, another developer can immediately load it and use it without any issues!
Entities & Scenes
To make a game, a developer is going to need game objects. A game engine's job is to provide extremely abstracted game objects that can be customized to such a degree that the developer will have total freedom over the implementation of their creative vision. To do this, I decided on a scene and entity system. Entities are essentially empty pointers which a scene handles, and then the developer is then able to customize their entity to their hearts desire through entity components. Components package basic values such as a transform or a texture to render. Some prebuilt components are precompiled with Flora, such as a transformcomponent, spritecomponent, audiocomponent, etc. However, the true customizability lies in the scriptcomponent. While the Flora backend can handle the precompiled components in a specialized manner, what happens if the user wants to handle their custom component? This is done with the scriptcomponent. Each entity that has a scriptcomponent holds packaged and customized code that can handle any properties the entity has. Pretty cool!
Scripting
As to avoid cutting down several years of my life trying to make my own embedded runtime that wouldn't explode, I chose to integrate mono as a C# scripting engine! This was also my first introduction really to how .dll files worked and what exactly C# was in terms of a language. Communicating between the C++ backend and a C# frontend was incredibly cool to do. This was really the first time I saw 2 different languages actually intertwine and communicate between each other outside of just communicating via sockets or modifying a file. That being said, mono did not come without its difficulties. Sharing entities and structures between the two languages resulted in some...memory issues, specifically because of the C# garbage collector. Unless I designated an object that was created in C++ to be garbage collected, it would just stay there forever, eventually bloating and crashing the C# runtime. Unfortunately, I did not realize this for about... 3 weeks of debugging. As embarassing as that is, I definitely am more versed in debugging via memory monitoring and addresses now.
Physics
For physics, I opted to use box2D. Before you start shouting "aw weak! If you were a REAL programmer you would make your own physics engine!", know that I've made physics engines before, and I've had QUITE ENOUGH. I'm not great at making them super efficient, and box2D works out of the box (haha pun) like a dream. That being said, box2D has pretty much every feature I could ask for, so it was super easy to integrate. However, one large challenge was integrating box2D bodies with subentities.

The way Flora handles subentities is that subentities can inherit properties from their parents, namely their transformation. When this happens, a subentity's transform is handled in reference to the parent's transform as the origin. When this is mixed with binding a rigid body to the transform, it has...unintented consequences. When subentities who try to bind their transform to their parents also try to bind themselves to the world of physics, the two constraints collide. This results in what I have deduced to be them fighting and then exponentially increasing their control to win over the subentity. This results in a lot of shaking, then expanding, and then dissapearance. Because of this, I "locked" binding physics bodies to subentities that inherit transforms under a VERY heavy warning.
Stats & Analysis
Stats for flora included mainly resource usage and rendering system statistics. However, the pain that doing resource usage put me through merits the existence of this section in the first place. This was because I used the "pdh.h" header to monitor system resources (exclusively on windows). Memory, disk, and CPU were not very hard at all with this. However, trying to monitor GPU usage has been and still is something that is simply just beyond me. Although there is an implemented attempt at it, Flora still lacks a working reliable GPU usage monitor. I'm not sure if its because of some bullcrap between AMD and NVIDIA cards having different support names or drivers, but I could just never really find out how to detect the usage behind them. Not only this, the documentation and support for this library header is either non-existant or just plain wrong. In terms of the official Microsoft documentation, the actual usage outlined is just plain wrong in terms of syntax and functionality I've found. If this is due to incompetence or if it just hasn't been updated in years, I will never know. When turning to forums such as slack overflow however, it seems that everyone is collectively scratching their head on how to use this library.
Audio
For audio, I chose to use OpenAL! Although it was a little harder than expected to link and use at first, I eventually got it to work! OpenAL was my first choice because, well, it was open source, cross platform, and had lots of support! Another thing that I loved about OpenAL was that it came prepackaged with the capability of 3D sound! This was perfect for a game engine, and perfect for audio "source" and "listener" components. Overall, OpenAL was a delight to work with! The only caviat was the audio file support.

Loading audio files came with 2 main obstacles. The first one, was learning the structure of a .wav file. APPARENTLY, some .wav files are just structured...differently? Depending on the .wav file, it can just not load correctly if you're not meticulous enough with the preprocessing. It took a while for me to realize this, which was... frustrating to say the least. The second obstacle, however, was even worse.

To my surprise, common software developers just... can't use .mp3 audio files! After hours of searching and disbelief, it appears that .mp3 files are just... impossible to decode?? You apparently need to pay for a software license to decode them?? This seemed to be just utterly ridiculous to me that such a widely used format...is pay to win. I'm hoping that I'm just wrong, and there is indeed an mp3 decoding library out there somewhere.
Text
Implementing text was a treat. This was because I chose to implement MSDF text rendering. For those who don't know what MSDF rendering is, read this paper! For those of you who don't want to read another 64 pages after sifting though all my rambling, here's the basics:

In typical font rendering, a .ttf file is used to generate an atlas with 2 color channels. The TLDR of what this means is that when you zoooooooooom in a lot, the font will get blurry. This can be seen in a lot of applications if you want to dick around with that kind of stuff. The reason behihnd this is because the 2 channels can only create an "outline" with a specific resolution, as it is not stored as a vector format when being rendered. However, MSDF uses multiple color channels! This allows fonts to "blob" parts of a glyph so the renderer can identify points where these blobs cross, indicating a clean point. Because of this, you can zoom in infinitely, and there will be zero loss of quality!

Really the only downside of using MSDF rendering is that you need to generate a MSDF font atlas from the .ttf file, which can take several seconds on startup. However, this problem is easily made insignificant by making a user "import" the font and caching the atlas for quick loading.
Technologies
This project is done almost entirely in C++, with just enough C# to create a C# scripting engine with mono! To develop this project, I started off with Visual Studio (yes, get your groans out now) using a tool called premake5 to create my build configurations. A lot of the beginning of this project is inspired by TheCherno's game engine series on youtube, so the details of how that works and is set up can be found there! However, as I grew beyond just following youtube academy's tutorials, I switched to a new build system: bazel.

This descision was motivated mainly by the desire to develop the engine on my linux device, as well as to develop a deeper understanding on how building in C/C++ works. Although the linux SDK of Flora is slightly more limited in capability due to some parts of the engine needing to be rewritten to not depend on Windows, the bazel build of Flora is far more stable and properly linked together than when I was cobbling together the sources and headers via premake5 and Visual Studio. For those of you who don't know, bazel is a project build system developed by Google, which can be used for a multitude of different languages such as C/C++! But why this over something more widely used such as CMake?

The short answer to this question is, well, that I simply do not like CMake. I have used CMake before for smaller projects, but the steep learning curve and lack of basic understanding lead to just nightmares when working with it. Bazel, on the other hand, while has less support, has a much more fluent and basic syntax, and overall make the concepts of C/C++ building click that much faster. On top of this, bazel is just so easy to set up! Downloading and adding a simple binary to path on windows or just sudo pacman -S bazel on arch linux is all it takes!

Lastly, some doxygen is used to auto-generate documentation, as well as some plantuml to create an architecture diagram :)
Resources
Besides youtube academy, there are plenty of dependencies used in Flora! As much as I'd love to reinvent the wheel and truly write every single software component from scratch, at this level of complexity and at my experience level I decided it wasn't worth the extra 5 years I'd have to dedicate to fine tuning and creating intensely powerful libraries that already exist. In fact, just recreating one of these dependencies, e.g. imgui, could take 5 years alone! Some of these dependencies are simply that powerful! That being said, here's a list of the dependencies I've used to create Flora's systems!
  • GLFW (for window creation)
  • glad (OpenGL stuff!)
  • imgui (for UI made easy!)
  • ImGuizmo (for imgui editor gizmos)
  • implot (imgui graphs!)
  • box2D (for 2D physics)
  • entt (for super efficient entity registries)
  • TheCherno's filewatch.h (for monitoring file changes)
  • glm (super efficient 3D math!)
  • mono (for a packaged C# scripted runtime)
  • msdf-atlas-gen (super accurate fonts!)
  • openAL (open source audio)
  • spdlog (powerful and efficient logging)
  • stb_image (fine-tuned texture support)
  • yaml-cpp (for serialization)
Takeaways
Flora has definitely been one of the most rewarding projects I've ever done. Even though this project is the least likely to ever be used by anyone else, it has been incredibly useful as an experience.

Learning the innerworkings of this project has provided me with so much experience in lower-level and performance-dependent programming, as well as managing a large project over time. Not only that, it has greatly increased my confidence as a programmer! Dealing with and experiencing different solutions, design patterns, techniques, and more has made me feel more competent as a programmer. Looking back on previous projects and older code I can see so many more errors and things that I would do differently. This project has forced me to grow to levels where I can concretely see progress in myself as of even just months ago!

Not only was the experience valuable, it was most importantly fun. I think this was absolutely the project I've had the most fun with in my life. There is just something about the gratification of building something so cool from the ground up that makes each small milestone and achievement so satisfying. Prior to this project, a lot of modern software was still just magic and sparks behind the hood to me. However, during this project I began to understand so many aspects of how to create software that it felt like I could create anything. If nothing else, this project was worth every minute of work simply because of how fun it was.