Crimild never really had an easy way in. The building process itself is a bit more complex that I would like and once you pass that, creating simulations is no walk in the park either. Regardless of the complexity of the scene or the rendering composition, you usually end up with a lot of boilerplate code just to run the application:
- You need a main function (or in the case of OSX/iOS, a whole new project).
- You need to create not only a Simulation instance, but also add any System implementation you require based on what you want to accomplish (which is usually the same set of systems every time).
- You need to call some helper functions to initialize builders and other factory objects. And those must be called before creating the simulation itself, which is error prone.
- Don’t forget to set the Logger level.
- You also need to create asset managers and settings. The later must parse command line arguments before the simulation is created.
- While we could implement the main loop ourselves, we usually end up calling the helper function Simulation::run() most of the time.
Only after completing all those steps correctly we can start creating the actual scene and rendering compositions. Oh, did I forget to mention that the later one is pretty much the same in most situations?
If you’re wondering how these process looks in practice, here’s an example of how to implement a simple simulation that loads an OBJ file and renders it on screen.
In the past, I tried to justify these complexity by arguing that it provides a lot of flexibility, which is true. But here I am today, rewriting all demo and realizing that there’s a lot of duplicated code in our applications. And that code needs to be updated whenever the related classes change in the engine (which happens quite frequently. Sorry about that).
I spent the last week doing a lot of simplifications here and there, which resulted in a much simpler simulation workflow. You don’t believe me? Then check out how the same code looks now.
A lot of things are happening under the hood now:
- The engine will take care of the main function and all of the internal initialization.
- The System class has been upgraded to provide a lot of hooks that are executed during the different stages of the Simulation lifetime.
- The Simulation class itself provides two virtual functions that can be used to configure our simulation in a very easy way:
- onAwake() is called when the Simulation is about to start, just before any system is initialized. This is a great point to attach your own systems or to remove the default ones and configure the simulation as much as you need.
- As the name implies, onStarted() is called after all systems have been started. Here you can create your initial scene and/or a rendering composition. If no rendering composition is provided, the Simulation will use the default one.
- CRIMILD_CREATE_SIMULATION() is a macro that is used to tell the engine the class that implements our Simulation, plus a name that will be used as the title of the window.
And that’s it.
No more complicated main files with lots of code that we don’t really care about. Now we can focus on building beautiful scenes without having to worry about the target platform. Did you notice that we’re only include the only the core header file now? That means that the same simulation code could be executed on desktop, web or mobile, since the engine is the one setting up the target platform based on the build settings.
Speaking of building settings, I mentioned that that the building process is complicated and requires some manual steps. Well, guess what?…
I didn’t have time to fix that yet, sorry. But I do have it on my list (which for some reason it gets bigger and bigger every day).