The most common criticism of HGE is its Windows-only nature. It’s a fair point — the engine was built around DirectX, Win32 windowing, and Windows audio APIs. But “the engine is Windows-only” doesn’t mean “your game has to be Windows-only.”
Porting an HGE game to Linux and macOS is a real engineering project, not a weekend task. But it’s achievable, and the architectural lessons you learn in the process make you a better developer. Here’s the practical roadmap.
Understanding What Needs to Change
HGE’s platform dependencies fall into four categories:
1. Rendering (DirectX → OpenGL/Vulkan)
The biggest piece. HGE uses DirectX 8/9 for all rendering. Linux and macOS don’t have DirectX. You need an alternative rendering backend:
- OpenGL: The most practical choice for broad compatibility. Linux supports OpenGL natively, and macOS supports it through a compatibility layer (though Apple has deprecated it)
- Vulkan: Better long-term investment but significantly more complex to implement. Available on Linux natively and macOS through MoltenVK
- SDL2 + OpenGL: SDL handles window creation and OpenGL context setup, giving you cross-platform windowing alongside the rendering change
2. Windowing (Win32 → SDL2/GLFW)
Win32 window creation, message pumps, and input handling need replacement. SDL2 is the standard choice because it provides:
- Window creation on all platforms
- Input handling (keyboard, mouse, gamepad)
- Audio device management
- OpenGL context creation
3. Audio (DirectSound/BASS → SDL_mixer or OpenAL)
HGE’s audio uses platform-specific APIs. Cross-platform alternatives:
- SDL_mixer: Simple, handles most game audio needs
- OpenAL: More capable, better for positional audio
- miniaudio: Lightweight single-header library that works everywhere
4. File I/O and System
Windows-specific path handling, file operations, and system calls. Most of these are straightforward to port using standard C++ filesystem or thin platform abstractions.
Porting Strategies
Strategy A: Replace the Backend, Keep the API
The cleanest approach: rewrite HGE’s internal implementation to use cross-platform libraries while keeping the same public API. Your game code doesn’t change — only the engine internals.
This means reimplementing:
Gfx_*functions using OpenGL instead of DirectXInput_*functions using SDL2 inputStream_*andEffect_*functions using SDL_mixerSystem_*functions using SDL2 windowing
The advantage: your existing HGE game code compiles and runs unmodified against the new backend.
The challenge: it’s a significant amount of work, and some HGE API behaviours are inherently DirectX-specific (blend mode constants, texture format assumptions).
Strategy B: Abstraction Layer Above HGE
Create a thin abstraction layer that your game code targets, with two implementations: one using HGE (Windows) and one using SDL2/OpenGL (Linux/macOS).
Your Game Code
│
└── Platform Abstraction Layer
├── HGE Backend (Windows)
└── SDL2 + OpenGL Backend (Linux/macOS)
This preserves HGE on Windows where it works perfectly, while giving you freedom to implement the other platforms differently.
Strategy C: Migration to SDL2/OpenGL Everywhere
If you’re willing to rewrite the rendering layer anyway, consider migrating entirely away from HGE to SDL2/OpenGL on all platforms. You lose HGE-specific conveniences but gain a single codebase.
The HGE sprite concepts — texture regions, hot spots, colour modulation — map cleanly to OpenGL textured quads. The mental model transfers even if the API calls change.
Practical Implementation Steps
Step 1: Isolate Platform Code
Before writing any cross-platform code, audit your HGE project and separate:
- Pure game logic: Physics, AI, game state — anything that doesn’t call HGE directly
- Rendering calls: Everything that draws to screen
- Input handling: How you read player input
- Audio calls: Sound effect triggers and music management
- System/lifecycle: Initialisation, shutdown, timing
If your code is well-structured, the pure game logic portion should be large and the platform-dependent portion should be concentrated in a few files.
Step 2: Set Up SDL2
On Linux and macOS, get a basic SDL2 window with an OpenGL context running:
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
SDL_Window *window = SDL_CreateWindow("My Game",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
800, 600, SDL_WINDOW_OPENGL);
SDL_GLContext ctx = SDL_GL_CreateContext(window);
This replaces HGE’s System_Initiate() and gives you a rendering surface.
Step 3: Port Rendering
This is the bulk of the work. For each HGE rendering concept, implement the OpenGL equivalent:
- Texture loading: Use stb_image or SDL_image instead of HGE’s Texture_Load
- Sprite rendering: Textured quads with OpenGL, matching HGE’s coordinate system
- Blend modes: Map HGE’s blend mode constants to OpenGL blend functions
- Render targets: OpenGL framebuffer objects replace HGE’s render targets
Step 4: Port Input
Map SDL2 input events to your game’s input abstraction. SDL2 provides:
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
// Map to your input system
break;
case SDL_MOUSEMOTION:
// Update mouse position
break;
}
}
Step 5: Port Audio
SDL_mixer provides a straightforward replacement for HGE’s audio:
Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048);
Mix_Chunk *sfx = Mix_LoadWAV("laser.wav");
Mix_PlayChannel(-1, sfx, 0);
Mix_Music *music = Mix_LoadMUS("theme.ogg");
Mix_PlayMusic(music, -1);
Step 6: Build System
Set up CMake for cross-platform building:
cmake_minimum_required(VERSION 3.20)
project(MyHGEGame)
if(WIN32)
# HGE backend
find_package(HGE REQUIRED)
target_link_libraries(${PROJECT_NAME} hge hgehelp)
else()
# SDL2/OpenGL backend
find_package(SDL2 REQUIRED)
find_package(OpenGL REQUIRED)
target_link_libraries(${PROJECT_NAME} SDL2::SDL2 OpenGL::GL)
endif()
Testing the Port
Visual Parity
The most common porting bugs are visual:
- Coordinate system differences (OpenGL’s Y-axis is inverted relative to DirectX)
- Texture filtering defaults differ between APIs
- Blend mode behaviour can have subtle differences
- Line rendering width and antialiasing vary
Screenshot comparison tools that diff the Windows and Linux outputs pixel-by-pixel will catch issues that the eye misses.
Performance Profiling
Don’t assume cross-platform means equal performance. Profile on each target:
- Linux OpenGL drivers behave differently from Windows DirectX drivers
- macOS’s deprecated OpenGL implementation has specific performance characteristics
- Frame timing on different compositors and window managers varies
Input Feel
Controller behaviour, mouse acceleration, and keyboard handling differ between operating systems. Test with actual hardware on each platform.
What We’d Recommend
For an existing HGE game that needs Linux/macOS support:
- Strategy B (abstraction layer) is usually the best risk/reward balance
- Start with Linux — it’s closer to Windows in development workflow
- Use SDL2 for everything platform-specific — it’s battle-tested
- Port rendering last — get input, audio, and windowing working first
- Accept some visual differences — pixel-perfect parity isn’t worth infinite engineering time
The HGE API documentation is your best reference for understanding what each function does internally, which directly informs how to reimplement it for other platforms.
The effort is real, but the result — a game that runs everywhere, built on a foundation you truly understand — is worth it.
Discuss porting strategies with other developers in our forum, or explore the HGE demos to understand the rendering features you’ll need to replicate.