Retrospective and 2023 Plans24 Dec 2022
2022 was a hectic year for The Force Engine. With the basic cutscenes working at the end of 2021, I had high hopes for quickly getting iMuse out of the way. As it turns out, there was a lot of change at the beginning of the year and development slowed for quite a few months. But during this initial period, the reverse-engineering process on the iMuse library began, which itself was a massive endeavor. The iMuse library not only handles midi, but also digital audio mixing for Dark Forces. The iMuse system supports blending, fading, conditional loops and jumps, even callbacks into game code. It will even sustain specific notes between songs - in order to smooth out transitions. In mid-May, the iMuse system was finally released as version 0.9. Though the year was already half over I still had high hopes of releasing version 1.0 in 2022.
Once iMuse was complete I made two, somewhat risky decisions - 1) that the GPU Renderer would be part of the version 1.0 release and 2) to also add a save and load system to the release. I felt confident that both those tasks could be completed in the remaining 6 months, though it would certainly turn out to be a close call.
I had always planned to add a GPU Renderer and there were several reasons - but mainly to support high resolutions and high framerates. The other main reason was to support perspective-correct pitch, since many found “y shearing” to be uncomfortable with mouselook. I also want TFE to be an attractive target for future mods and Dark Forces development, which means having to be forward looking.
The GPU Renderer itself is somewhat of a strange beast, it doesn’t really act like a modern game renderer. It takes the idea of the 1d-zbuffer in Jedi and extends that to 2d, all the while supporting being able to look straight up and down like a modern renderer. There is no sector triangulation involved, it directly extends the original algorithms into 3d. So what does this do? It allows the renderer to act in a very similar fashion to the software renderer, no sprite or object clipping issues with the floor and ceiling, sprites sort in front of or behind walls like in the original. Portals behave properly, allowing for all sorts of non-euclidean effects. Lighting and shading match the original - even the dithering on 3D objects, which shows up best at low resolution. Color map effects are preserved.
The other aspect that was important is good performance and avoiding OpenGL pitfalls. This meant pushing as much of the work as possible to the GPU and limiting driver overhead and CPU to GPU bandwidth. Final geometry generation, clipping, and shading had to occur on the GPU. As a result, the sector data is uploaded to GPU memory and updated only as needed - and a sort of “display list” of wall, floor and ceiling parts is built that passes along the wall flags, texture ID, and other compacted data. The shaders than read the compacted data, and maps it to the semi-static data stored in memory and then sets up the geometry correctly. Portal planes are read and used to setup GPU clip planes. The textureID is used to look up a texture table that maps to an array of texture atlases (essentially virtual textures).
As a result all sector data is rendered in two draw calls, sprites one or two draw calls, and 3D objects one draw call per object, no matter how many textures or shading modes they use. CPU to GPU bandwidth is minimized and a large amount of the work is pushed to the GPU that would traditionally be done on the CPU. All with the feature set offered by OpenGL 3.3.
At this point in development, there were a number of latent crashes hidden in the code due to global state issues in the original code. In addition, exiting back to the menu from in-game was fraught with bugs and issues. Something needed to be done to get a handle on all of the global, DOS-style state. And so, I spent a large amount of time cleaning up the global state situation, collapsing state into structures and properly handling setting and clearing these structures to known values. And when thinking about this, it occured to me that I could also handle serialization at that same time. And so, I decided to implement the save system in version 1.0.
In order to build a robust system and avoid save compatibility, I planned out my approach:
- Versioning as a first-class consideration.
- Every read and write specifies the desired version and a default value.
- Read and Writing occur in the same functions, often with the exact same code.
- Serialization to binary data and it should be fast.
- Saves store the mods used, so you can load directly from the save without having to select your mod(s) first.
- Saves act somewhat like save states - full level state, AI state, player state, INF state, and game state is stored. This includes a list of all the per-level assets used. When loading from a save, the original level data is not loaded - it is reconstructed from the save itself. Assets, like textures, are loaded as usual, of course.
The Save System has already paid dividends and made the next phase of development much easier.
The Final Push
In the final weeks, builds were coming out almost daily. Every night, after work, I was churning through the bug list as people found yet more bugs (for which I am grateful). But slowly, things started coming together. I made the final version 1.0 list and within a surprinsingly short time managed to finish it. Many important issues were found and fixed in those final weeks. Some bugs that had been in the project for months or years. And then, after about three years of development - it was finally time to release version 1.0.
Of course the process isn’t over. There are still bugs, though only a few that an affect gameplay. But overall, despite the large increase in testing - the release went really smoothly. And that is mostly thanks to the tireless efforts of all of those listed in the credits - the people who played through the game multiple times, who played various custom levels, who did weird things and got TFE to crash.
2023 promises to be an exciting year for The Force Engine. Initially there will be a focus on fixing issues with the version 1.0 release. A lot of that has been done already with version 1.01, but there are still some bugs that need to be resolved and features that would be nice to have, such as being able to select audio and midi devices from the menu. There are a few major areas of development that will be the focus for 2023.
I list items in a specific order but in reality I expect more of a mixing. For example Vulkan support might not be done immediately, or Metal support added very late in development. The editors will also be an ongoing project extending well past the point where Outlaws development begins. There will be some parallel development, shifting of priorities and other changes as we go.
And like all plans, things may change in response to other events, findings, or just changes in perspective. None of this is set in stone.
Others have already spent a lot of time to help add support for Linux. My goal is to take that work and make any other changes and fixes needed to make TFE work well on Linux - especially the Steam Deck, as well as OS X. These efforts include:
- Support for midi synth and sound fonts.
- High quality audio support in the engine, as a result of the above.
- Fix other sound issues on Linux/Mac.
- Proper CMake build system.
- Support for Keyboard and Contoller control of the System and Game UI.
- DirectX, Vulkan, and potentially Metal backends. The current renderbackend was designed with this in mind, so I expect this to go fairly smoothly. This will also help with low end Intel GPUs without proper OpenGL drivers as well as newer models with poor or emulated drivers.
Level Editor and Tools
During the development of TFE, I had built a level editor to help me visually inspect the data in a friendly way. I integrated the editor directly into TFE for quick iteration and debugging. And I plan on using that for Outlaws. Unfortunately, the editor had to be removed because the engine just changed too much and it was getting in the way of development. So in early 2023 I want to bring it back, refactor the code and get it into a usable state. Various other tools are also in the mix, such as being able to view, import and export textures, WAXes, and so forth.
So why a new editor, why not use WDFuse or even earlier options? Here are the features the editor supports (or will support):
- The ability to directly draw sectors, and place objects.
- CSG support - union, subtraction, clipping, and more.
- Full 3D editing support with the same UI. An entire level can be built using only the 3D editig tools.
- Modern UI and tools.
- Support for both Dark Forces and, later, Outlaws.
- Built-in INF editing with helper tools.
- And more.
True Color Rendering
True color rendering is also planned and needed for Outlaws. This will include new features such as dynamic lighting, antialiasing, and post processing options. This also means that texture filtering wil become available, including anisotropic filtering and mipmapping.
Finally taking the prototype voxel work I did during TFE development and make it “real.” The software renderer was basically done, but this includes the GPU Renderer, definition/replacement metadata, and “map hacks” so that objects can be repositioned in levels.
And finally, the last major project of the year. Reverse-engineering work on Outlaws, using the Dark Forces code as a base. Like Dark Forces support, this will start showing up as bits and pieces that can be tested as development continues. Outlaws Jedi Enhancments and features will also be added to the editors as progress continues - and made available for new Dark Forces mods.