CyEngine (WIP)
CyEngine is currently a work-in-progress 3D game engine built using OpenGL and C++. In the future I'd like to extend this to involve Vulkan as well, and encompass more features. I've always been interested in game engines, so having the opportunity to work on one slowly has been great fun. It's also a nice excuse to learn more about things I otherwise wouldn't encounter in usual game development.
This page will differ slightly from the others, being treated more as an information-dump for the systems that I've worked on in more detail. This might also become more of a blog as I continue to add features.
Links
Current Features
- 3D Mesh Rendering
- Components
- ImGui Interface
- Custom Reflection System
- JSON Parser
- Custom Dynamic Array Class
- Custom String Class
- Custom Smart Pointers
Future Plans
The short term plans for the engine are as follows:
- Improved Reflection System
- In-editor Gizmos
- Serializable scenes, saved as assets
- Asset Manager
- Play In Editor (PIE)
- Packaged Builds
08/12/2023: Enum Reflection, Transforming Transforms and Refactoring
The focus for the last few days was partially on refactoring existing systems and moving functionality over to components. I also looked into making an editor camera and also reflecting enums, as a method of swapping the mesh we use in the MeshComponent.
Enum Reflection
Adding reflection to enums was primarily a means of getting the name of the enum values to display in-editor. This means I can show a drop-down menu to the user and let them select the enum value they want. To get this working I needed to extend the existing build tool, parsing over enums marked up with ENUM() and pulling out both the names and the values. I then store these in a map of enum names to enum value names, alongside the actual value.
A big part of enum parsing was ensuring the values were correct. Since enums can have their values set in multiple ways, either by not doing anything, starting at 0, using an equals operator to set the value directly or using <<. I accounted for each of these in the parsing to ensure the value was always read correctly. This will also help in the future if I decide to setup flags in editor.
Once the build tool could parse enums, the next step was to get them rendering in-engine. This was a bit trickier, as there isn't a shared enum "type", so I had to treat enums as a special case when rendering properties. Once I know a property is an enum (which the build tool tells me) I can render them in a custom PropertyField, as a uint8_t.
Transforms
In the last blog post I made an Outliner to better display scene objects. As part of this, you could parent objects to other objects by dragging one onto another in the list. The issue with this was that whilst they were parented in theory, the transforms of the objects weren't linked at all.
To fix this I needed to refactor the transforms such that they would all be treated as being relative to their parent, in position, rotation and scale. This included setting up TransformPoint and InverseTransformPoint style functions to transform data between world and local space.
After a fair bit of trial and error, I got it to the point where you could parent objects, and use the root object as a pivot, which is exactly what I wanted from this.
Editor Camera
The main reason I needed to make the above changes was because I finally wanted to add some user interaction to the viewport. The movement was fairly easy, just adjusting the camera relative to the direction it is facing. The problems lay with rotating the camera, since if I applied both rotations to the one object we'd get roll, which you couldn't really fix as a user. The fix for this was to use two objects, the first being the root, which we apply the Yaw rotation to, and the second being the actual camera, which we apply Pitch rotation to.
Refactoring
I also took some time over the last few days to look at the way I was rendering properties, since special cases like arrays and enums couldn't be used together. I fixed this by recursing the properties, meaning we are now able to have arrays of enums, and any other special types. I also changed up the PropertyField functions to remove a nasty user-exposed void* as a parameter. Instead now we know the type so we can pass that in directly. Which makes user created property fields easier to setup.
Whilst I was here I also added a property display name override for the inspector as meta data.
05/12/2023: Object Manager, Smart Pointers & Visual Update
This will be the first, of hopefully many, blog style posts to this page. In this one I want to cover the changes that I've made to the engine, including smart pointers (weak and shared), an object manager to control the lifetime of objects and some visual changes I made.
Smart Pointers
Smart pointers were important for the project early, as I wanted to make sure that the objects in the scene could clean themselves up once they are done with. To do this I created three classes, the first two being SharedPtr and WeakPtr, and the final being the ReferenceCount class that holds the number of weak and shared pointers that are accessing the data. The SharedPtr, when removed, decrements the shared count. Once this hits 0 it will delete the data, invalidating the ReferenceCount class but not destroying it if any WeakPtrs remain. The WeakPtr class once removed would decrement the weak count, and if both counts hit 0 the ReferenceCount class is also deleted.
Object Manager
The above classes led into the creation of an ObjectManager, which handles the creation of Object-inherited classes, such as the SceneObjects that will make up the game world. These are registered in a map with a GUID, which stores a shared pointer to the object. This gives us a singular point to create extra shared pointers from, but also to make weak pointers from, in case we need one. This allowed me to fix up the issues that I had with the inspector and the "current selected object", since now I can use a WeakPtr and check for the objects validity, without necessarily keeping the object around in memory.
Visual Update
Alongside the above changes, I also wanted to do a visual update to the engine, including a new ImGui style. I also introduced a new panel called the Outliner, which splits the existing inspector functionality. Instead of storing all of the objects and their properties in a single list, we instead store the list of objects in the Outliner, and the data for the selected object in the Inspector. This also meant I could add Component sections to the inspector, which use CollapsingHeaders. I think these are super neat :)


Contact
In order to get in touch please email me at adamsims.gamedev@gmail.com.