top of page

Null Engine: A bit of Refactoring

  • Writer: Anthon Reid
    Anthon Reid
  • Aug 6
  • 4 min read
Simple Breakout
Simple Breakout

Since "completing" the particle system, I have been going around the engine looking to do some refactoring, and it took much longer than I was intending to. Nevertheless, I’ll give a quick walkthrough of some of the refactors I made, and maybe walk through some of my thought process as to why I chose to do so.



The Null Engine


To give some context, I decided to work on this engine because I wanted to try my hand at graphics programming. A few TheCherno videos later, I found myself with an ImGui Layer. I realized a bit later that I needed objects to draw, and that led me to try and implement my own ECS.


In the early stages, I focused on getting features working, writing code as a means to an end. That meant taking shortcuts,  like relying on god objects or building monolithic classes with little thought for how they’d scale later.

Now felt like the right time to go back and rework those systems a bit with a more solid architectural foundation.


The Entity Wrapper Class


One such shortcut was the entity wrapper class. It was supposed to be a simple class that provided some helper functions to get or add components. At some point, however, I made the decision to give it more responsibility.


ree

Part of my refactoring endeavor was to remove these extra fields from the wrapper class, which then led to some other issues: that data had to go somewhere else.


The solution to this turned out to be pretty simple: use components.

For some reason, I had it in my head that components needed to be gameplay related, a sprite, a transform, or a script component. But then I realized that components had nothing to do with the game, and everything to do with entities. They were containers for information about a given entity, names, archetypes, or other states included.


I’m not sure if that’s the best solution still, but I figured: why create an additional system when components are available to hold that information?

The DOD Rabbit Hole


I got to have a very fascinating conversation where the concept of data-oriented programming was brought up. Next thing I knew, I was a few Mike Acton and Data-Oriented Design YouTube videos deep, and I figured, I might as well try my hand at it within this engine. It was what it was here for, after all.


And so I came to realize that my components were not very well designed.


Each came with its own set of issues. For instance, none of them were POD since they were all derived from a common base class. They weren’t trivially copyable since I had strings and other STL structures within them. So I decided to refactor that side of the engine as well.



I basically went through all my components and changed them to follow a format similar to this, where I restructured them into a tightly-packed format, prioritizing cache efficiency and simplicity. It was a very tedious business, but in the end I am way happier with that setup. Following that pattern helps keep my components predictable in size, which even lets me use memcpy where I couldn’t before.


I also started experimenting with CodeGen using Python, writing a very simple script that generates boilerplate code to help me add C++ components into the engine quicker. Another idea I got from watching that Mike Acton video on DOD.


At this point, I’m more inspired by DOD principles than fully subscribed to them. From watching YouTube videos and picking up the book on it by Richard Fabian, it feels more like I’m giving myself options when implementing a new feature in the engine.


I have to say, writing code felt easier before. Now, I see holes everywhere, and I keep wondering if I could’ve written the code better, whether through data-oriented programming or object-oriented programming.


There’s this line I read in Richard Fabian’s book that stuck with me, and now I constantly ask myself:


“Is my class a banana… or is there a gorilla holding it?”


Ultimately, I’m just glad that I still feel like there’s more to learn and that I’m not stagnating or getting too comfortable with my limited knowledge.

Render passes


Post Processing and Render passes
Post Processing and Render passes

I also refactored my graphics system a bit. I didn’t feel like I had a good understanding of framebuffers, so I figured a good way to fix that was to try using more than one of them.

This led to me setting up a multi-pass pipeline to apply effects like chromatic aberration and grayscale.


Example of JSON Definition of Render Passes
Example of JSON Definition of Render Passes

This took me hours to achieve, and at some point at one point, I even had to bring out RenderDoc to debug my shader. But in the end, it turned out I had a name mismatch between my vertex and fragment shader, which caused my texture coordinates to be inaccurate...


Once I sorted that out, I was able to make my sprites emissive and even add a few real-time post-processing effects to the camera, like grayscale and chromatic aberration.



Emissive Objects
Emissive Objects

What next?

Currently, I’m refactoring my scene editor. I’ve decided that I want to add support for multiple "Editors", with the main one being the Scene Editor.

I’ve refactored my monolithic ImGuiLayer into a tabbed layer where I can toggle between different editors each with their own Dockspace and pannels. This allows me to use my window context to its fullest.



Animation Clip Creator
Animation Clip Creator

As I’m working on my animation system, I’m hoping to create an Animation Editor, which will come with its own set of ImGui panels and layout. This will also make it easier to add more editors later, like a behavior tree editor.



So, that’s where the engine’s at right now.


There’s still a lot I want to fix and change, but I’ve come to accept that at some point, you have to be happy when the code works as intended, even if it’s not perfect, as long as you made an honest effort to write it well at the time.


Here’s hoping that in a few months, I won’t feel the urge to refactor this too. But let’s be real...I probably will.



Thanks for reading this far and here’s a gif of my spaceship controller that I threw together for fun in between all the madness of refactoring.


Simple Spaceship Controller
Simple Spaceship Controller

Lua Script For Spaceship Controller
Lua Script For Spaceship Controller
CppCon 2014: Mike Acton "Data-Oriented Design and C++: https://www.youtube.com/watch?v=rX0ItVEVjHc
Richard Fabian, 'Data-Oriented Design': https://dataorienteddesign.com/dodbook
bottom of page