Every long-lived game engine accumulates legacy projects - games built against older API versions, compiled with outdated toolchains, and aimed at hardware that barely resembles what is in use today. HGE is no exception. Games built with HGE during its peak years still exist, some still have active players, and many now need updates to run correctly on modern Windows.
At Relish Games, this modernisation work has already been through the usual rough edges. The notes below cover the practical steps, the parts that tend to break first, and the point where it stops being worth polishing and starts becoming a rewrite in disguise.
A typical legacy HGE setup
A mid-2000s to early-2010s HGE project usually looks much like this:
Visual Studio 2005 to 2010 is common. DirectX 8 or 9 is usually sitting under the hood, often with the fixed-function pipeline still doing the heavy lifting. The build system is normally just Visual Studio project files, with no CMake in sight. Code style tends to be old-school C with classes, minimal STL, and raw pointers everywhere.
The rest of the stack is just as specific. Win32 APIs are used directly, sometimes with deprecated functions that modern compilers no longer treat kindly. Audio often goes through DirectSound or BASS. Resolutions are usually fixed at 800x600 or 1024x768.
That setup was fine on the hardware of the day. On a modern Windows 11 machine with a discrete GPU and a 4K display, the cracks show quickly.
Where legacy builds usually break
Compilation failures
Modern Visual Studio is stricter about deprecated functions, type conversions, and header dependencies. That is where a lot of the first pain shows up.
Typical problems include sprintf -> sprintf_s or warnings that used to be ignored, Windows SDK headers that were once pulled in implicitly, linker errors caused by changed library names or removed legacy libraries, and C++ standard compliance issues that old MSVC simply let slide.
The practical approach is dull, but it works: fix one compilation error at a time, starting from the top. Most of these are mechanical substitutions, not design problems.
Display and resolution
Legacy HGE games often assume one screen size and behave badly when that assumption is wrong. High-DPI displays make everything look tiny. Widescreen monitors stretch or crop the image. Multi-monitor setups can expose odd placement bugs. Exclusive fullscreen is also much less dependable than it once was.
The cleanest fix is to detect resolution at startup, render to a virtual framebuffer at the game’s native aspect ratio, then scale to the display. The HGE system state settings for screen dimensions cover the basics, but letterboxing logic usually needs to be added on top.
Rendering on modern GPUs
Modern GPUs still handle DirectX 8 and 9 through compatibility layers, but compatibility is not the same as identical behaviour.
Fixed-function blend modes can behave differently. Texture format support has changed. Vertex processing defaults are not always what older code expects. Some drivers are also noticeably less forgiving with legacy DirectX than others.
The sensible test plan is simple: run on NVIDIA, AMD, and Intel integrated graphics before calling it done. The blend mode documentation is the reference point for expected rendering behaviour. If the image is wrong, start with blend modes and texture format handling before you go hunting for stranger causes.
Audio compatibility
DirectSound is deprecated, and some of the audio libraries used in older HGE projects have been abandoned outright.
If the game uses HGE’s built-in audio, which wraps BASS, updating BASS to its current version usually clears up compatibility issues. If the project has custom audio code, SDL_mixer or miniaudio are the more realistic migration targets.
Input on modern configurations
USB controllers, high-polling-rate mice, and different keyboard layouts can all expose old assumptions.
XInput gamepads were not common when some of these games were written. Raw input handling can clash with high-polling-rate gaming mice. International keyboard layouts may not map correctly at all.
The fix is usually to add input configuration options and wrap the HGE input system with a remapping layer. The core API is straightforward enough, which is helpful here.
The modernisation process, in order
Phase 1: Get it building
The first job is boring and non-negotiable: compile and link with modern Visual Studio.
Create a new Visual Studio 2022 solution rather than trying to upgrade the old project files. Add the source files, configure the include and library paths for HGE, then work through compilation errors methodically. Once that is clean, fix the linker errors and update library references to the current HGE builds. After that, run the game. It will probably launch, though visual glitches are not unusual at this stage.
For a typical codebase, this phase usually takes 1 to 3 days, depending on complexity.
Phase 2: Fix rendering
Once the game builds, the next priority is visual correctness on modern displays.
Test multiple resolutions, including high-DPI cases. Add resolution-independent rendering by drawing to a virtual framebuffer and scaling to the display. Then compare the output against known-good screenshots and fix blend mode issues before moving on. Widescreen support comes last, and only if the game actually benefits from it. If it does not, letterbox it and move on.
Phase 3: Update audio
Sound has to work on modern Windows without fuss.
Update the BASS library to the current version, then test every audio path: music, sound effects, and volume control. Also check what happens when the audio device changes mid-game, because modern systems do that more often than old code expects. Bluetooth headphones connecting during play is the sort of thing that exposes weak assumptions fast.
Phase 4: Add the quality-of-life fixes that matter
This is where the game starts feeling current rather than merely functional.
Add resolution selection through a launcher or an in-game menu. Add controller support, because modern players expect gamepad input to work without drama. Move save games out of the game directory and into AppData. Add windowed and borderless fullscreen options. Handle quits properly so the game saves state on Alt+F4 and window close.
Phase 5: Modernise the build system
The final step is making sure someone else can build the project without guesswork.
Create CMakeLists.txt for the project. Document the exact HGE version and any additional libraries. Add a build script that pulls dependencies and configures the build. Set up continuous integration too, even if it is only a build-on-push job. That alone catches regressions early.
What should stay untouched
Modernisation has a hard edge, and this is where it lives.
Do not rewrite the game logic if it already works. Refactoring working code is a good way to introduce new bugs. Do not change the art either - the original art is part of the game’s identity, and the right move is to scale it properly, not replace it. Do not add features just because the codebase is in front of you; the job is to make the existing game work, not to design a sequel. And do not rush in to “clean up” code style across the whole project. Consistency with the existing codebase matters more than forcing modern C++ everywhere.
The decisions that keep paying off
Work backwards from the player
Every modernisation choice should answer one question: does this make the game better for a player in 2026? Resolution support does. Refactoring an internal data structure, on its own, usually does not.
That sounds blunt because it needs to be.
Test early, test often
The expensive bugs are the ones you discover after making 50 other changes. Build and test after every significant step. That incremental habit also stops small problems from piling up into something difficult to unwind later, which is the same lesson that shows up in posts about C++ performance and engine architecture.
Write down what changed
Future maintainers, including yourself in six months, need to know what was modified and why. A CHANGELOG that records each compatibility fix is not busywork. It is the thing that keeps the next round of support from becoming archaeology.
The 80/20 rule still applies
Getting the game running delivers most of the value, and it usually takes a fraction of the total effort. Making it behave perfectly in every edge case is where the time goes. Decide where to stop based on the audience size and what they actually expect from the game.
What the timeline usually looks like
For a typical legacy HGE game with 20,000 to 50,000 lines of C++, the work usually breaks down like this:
Getting it to compile takes 1 to 3 days. Fixing core rendering usually takes 2 to 5 days. Audio and input are often another 1 to 2 days. Quality-of-life improvements take 3 to 7 days. Testing across configurations tends to take 2 to 5 days.
Total time is usually around 2 to 4 weeks for a solid modernisation pass. That is real engineering work, not a weekend project, but it is still far less effort than rewriting the game or porting it to a different engine.
Explore the HGE documentation for API references that help with modernisation, browse the downloads page for current HGE builds, or discuss legacy game modernisation in our community forum.