OpenSAGE Dev Diary #3 (2017-12-17)

OpenSAGE is an open-source re-implementation of the SAGE game engine. SAGE was the game engine used in C&C Generals, C&C Generals Zero Hour, Battle for Middle-earth and its sequels, C&C 3 and its sequel, and Red Alert 3 and its sequel. I’ve been working on OpenSAGE for 6 months, and made some good progress, so I’ve started this series of blog posts to talk about what is happening in the project each week. You can also star or watch the OpenSAGE GitHub repo for a more real-time view of things.

Following on from last week’s post, here is what’s been happening this week in OpenSAGE.

Progress this week

GUI - Main Menu

This week in OpenSAGE:

  • I’ve finished porting the data viewer from WPF to Eto.Forms. I haven’t really introduced what the data viewer is, so I’ll do that below. I want OpenSAGE to be a cross-platform project (it’s Windows-only right now), and I’d like the data viewer to at least be on whatever desktop platforms OpenSAGE supports, if not mobile. Xamarin Forms was an option, but on Windows it only supports UWP (a WPF port of Xamarin Forms is in the works, apparently, but not ready yet). UWP is no good for OpenSAGE because of the way it handles file system permissions. So for the data viewer, I wanted a cross-platform UI framework that runs on at least WPF, macOS, and Linux. Eto.Forms ticks those boxes. Having used it for a couple of weeks, I’m really impressed with how easy it is to get up and running. I want to thank Curtis Wensley for making and maintaining such an awesome framework. I built a custom control to render 3D content, and it couldn’t have been easier to integrate with Eto.Forms.

  • I’ve made progress on rendering the various GUI screens from C&C Generals. Thankfully the GUI screens (main menu, options screen, game loading screen, game setup screen, etc.) are defined in parse-able data files, not hardcoded in the game’s binary. This week I have implemented text rendering (using DirectWrite) - quite a critical feature for GUI screens… I’ll talk more about GUI rendering below.

  • I merged a pull request from Stephan Vedder that added support for .const files. .const files were used in Battle for Middle-earth (BFME) and later SAGE games, as part of the Flash-based UI system. This is a whole new area that I haven’t done any work on myself, so it’s exciting to see it starting to appear in OpenSAGE - thanks Stephan!

  • I have started to setup a CI build. Normally I’d setup an AppVeyor build and be done with it, but my requirements for OpenSAGE are a bit different. Most of OpenSAGE’s tests use the actual data files from SAGE game installations. For copyright reasons, I can’t upload those data files anywhere. So I’ve settled on Visual Studio Team Services, which lets me use a private build agent to do the builds. I’ve got a computer running at home, with all the SAGE games installed, that will be a private build agent and run the OpenSAGE test suite whenever it’s instructed to by VSTS. I’m still setting this up, so for now the build badge in the GitHub readme shows a failing build.

Data viewer

When I started working on OpenSAGE, I realised it would be good to have a way to preview the results of the file format parsers that I was working on. At that time I was working on a .map parser. .map files in Generals can contain both multi-player maps and single-player missions; they contain the terrain data as well as scripts needed for multi-player or single-player games. Since I didn’t yet have an in-game UI, I built a simple WPF app with two panels: on the left, a list of files contained in the Generals folder, and on the right, a preview of the selected file. I built previewers for the main file formats as I figured out them out: .w3d, .map, .ini, etc.

Once OpenSAGE is far enough along in development that it’s possible to start a game from the in-game UI, the data viewer will become less important, but still a helpful way to view individual files. For now, there is no “game” executable, so the data viewer is all there is.

This week I finished porting the data viewer from WPF to Eto.Forms, so that it can work on macOS and Linux. I haven’t yet implemented rendering backends for either of those platforms, but at least I’ve removed one of the obstacles.

Here are screenshots with representative examples of all the file types that the OpenSAGE Data Viewer knows how to handle:


.w3d files were used in C&C Generals and subsequent SAGE games to store 3D models. C&C 3 and later games used an evolution of this format, called .w3x, which is kind of the same thing but XML-based.

W3D Viewer


.map files store the single-player and multi-player missions, including terrain data and scripts. The .map viewer lets you change the time of day, which affects lighting.

Map Viewer

.dds and .tga

.dds files were used to store 3D model textures, and .tga files were used for terrain and UI textures.

DDS Viewer


.csf - compiled string files - stored the translated strings.

CSF Viewer


.const files store constant value definitions for use in the .apt UI framework.

Const Viewer


.ini files were used in Generals and subsequent SAGE games to store almost everything about the game, except for what was stored in other file types. My .ini viewer currently only displays object definitions and particle systems.

Const Viewer

GUI rendering

Last week I mentioned the .wnd format used for UI screens in C&C Generals. This week I’ve been working on rendering more parts of it, including text. Here’s the current state of the main menu (defined in MainMenu.wnd):

GUI - Main Menu

Some UI elements are visible that should be hidden - I still need to look at why that’s so. Buttons respond to mouse hover now, but they don’t yet do anything when clicked.

GUI - Options

This is the Options menu. There’s much more to do here. I need to implement textboxes, checkboxes, and comboboxes.

And here’s one we all like to see - the victory screen. Yes, even that was defined in a .wnd file, not hardcoded.

GUI - Victorious

The .wnd viewer has the UI hierarchy in a tree view on the left - you can select a UI element and it will be highlighted on the right.

That’s all for this week - see you next time!