For a while now, I’ve been working on CHIFEngine, a low-level graphics engine designed for large-scale open-world games. The goal? To create something different from others. I am focusing on making a Engine, that´s completely customizable and easy to extend but tailored for my own needs—performance-focused and capable of handling massive, procedurally generated worlds.
The Architecture – A Custom Approach
CHIFEngine is built around an ECS (Entity Component System) to keep things modular and efficient. Instead of handling entities in an OOP-heavy way, components are stored in contiguous memory to improve cache efficiency and performance.
For rendering, I’m using OpenGL (later on Vulkan), but the architecture allows for future extensions like DirectX or even ray tracing implementations. The engine is also built to support both PC and Switch Homebrew, meaning portability is key.
- Some key features:
- ✅ Custom ECS – High-performance, flexible, and minimal overhead.
- ✅ Procedural Generation – Handling large, infinite terrains dynamically.
- ✅ Low-Level Rendering – Optimized Graphics API pipelines.
The Job System – Keeping Everything Fast
One of the core features of CHIFEngine is its custom job system, which ensures that expensive tasks like physics, AI, and procedural generation run asynchronously without blocking the main thread.
The job system follows a task graph model:
Tasks are broken down into independent units.
The system distributes them across available CPU threads.
Dependencies are handled automatically to prevent race conditions.
This allows for parallel execution of heavy workloads, such as terrain generation, background asset loading, or even GPU-based calculations. Without this system, handling open-world mechanics at scale would be far too slow.
An example of a simple and modified Job System:
struct JobDispatchArgs
{
uint32_t jobIndex;
uint32_t groupIndex;
};
namespace chif::Core::JobSystem
{
// Create the internal resources such as worker threads, etc. Call it once when initializing the application.
void Initialize();
// Add a job to execute asynchronously. Any idle thread will execute this job.
void Execute(const std::function<void()>& job);
// Divide a job onto multiple jobs and execute in parallel.
// jobCount : how many jobs to generate for this task.
// groupSize : how many jobs to execute per thread. Jobs inside a group execute serially. It might be worth to increase for small jobs
// func : receives a JobDispatchArgs as parameter
void Dispatch(uint32_t jobCount, uint32_t groupSize, const std::function<void(JobDispatchArgs)>& job);
// Check if any threads are working currently or not
bool IsBusy();
// Wait until all threads become idle
void Wait();
}
The Struggles – Every Engine Has Them
🛠 Memory Management – Keeping everything fast without unnecessary allocations is a challenge. ECS helps, but proper memory tracking is crucial.
🌍 Procedural Generation – Balancing performance with quality when generating large environments on the fly.
📦 Asset Handling – Implementing an efficient way to load, unload, and manage assets dynamically.
Conclusion
There’s still a long way to go, but seeing CHIFEngine evolve is incredibly rewarding. If you're into game engine development, rendering, or large-scale world design, I’d love to discuss ideas! 🚀
What are your thoughts on building custom engines? Ever tried working with ECS or procedural rendering? Let’s talk!
CHIFEngine´s Github Repo: Github Link
Top comments (0)