1. Introduction
CRM64Pro is a modern, lightweight and hardware-accelerated C++17 Game Development Kit built on top of SDL3. It provides a clean, modular architecture for creating 2D games, tools, and interactive applications, combining low-level control with high performance and cross-platform support.
CRM64Pro is distributed under the zlib license.
Modern core
Developed in C++17 and powered by SDL3, featuring multi-threading, advanced logging utilities, proprietary CDC asset compression, and the EditorC64 tool suite.
|
Complete toolset
Includes a versatile Tile Engine (MSTE) with native Tiled map support, a full GUI windowing system, and a robust Sprite engine with planned Spine2D integration.
|
Hardware accelerated
Supports Direct3D 11/12, Vulkan, Metal, and OpenGL, ensuring fast and smooth rendering across all supported platforms.
|
Developed by MegaStorm Systems.
Visit the official website for updates, releases, and complete documentation. | |
2. Supported platforms
The GDK runs on major operating systems. Thanks to SDL3, it supports a wide variety of hardware accelerated rendering and low-latency audio drivers.
| Platform | Requirements | Render drivers | Audio drivers |
|
| Windows 7, 10 and 11
(64-bit only) | Direct3D 9
Direct3D 11
Direct3D 12
Vulkan
GPU
OpenGL
Software | WASAPI
DirectSound |
|
| Kernel 4.18+
(64-bit only) | Vulkan
GPU
OpenGL
X11
Wayland
Software | PulseAudio
ALSA |
|
| Android 5.0+
(API 21+) | OpenGL ES
Vulkan | AAudio
OpenSL ES |
|
| macOS 10.13+
(High Sierra or later for x86_64)
macOS 11+
(Big Sur or later for arm64) | Metal
Vulkan
GPU
OpenGL
Software) | CoreAudio |
3. Installation
This section describes how to install and configure the CRM64Pro GDK for development on the supported platforms.
3.1. Windows (Visual Studio 2022+)
|
|
| Windows Development
Executable Installer (Inno Setup)
|
1. Download and Install CRM64Pro is distributed as a standard Windows installer created with Inno Setup (for example: CRM64Pro-X.Y.Z-win-x64.exe).
The installer will deploy headers, libraries and the EditorC64 into the selected destination (e.g. C:\Program Files\CRM64Pro).
The following libraries are provided:
-
CRM64Pro.lib – Dynamic linking (DLL import library)
-
CRM64Pro.static.lib – Static linking (Release)
-
CRM64Pro.static-debug.lib – Static linking with debug information
2. Configure Visual Studio No global system variables are required. Configure your project locally:
-
Right-click your project in Solution Explorer and select Properties.
-
Select All Configurations and x64 platform.
-
Add the CRM64Pro
include/ directory to C/C++ → General → Additional Include Directories.
-
Add the CRM64Pro
lib/ directory to Linker → General → Additional Library Directories.
-
Add one of the following to Linker → Input → Additional Dependencies:
-
CRM64Pro.lib (Dynamic linking)
-
CRM64Pro.static.lib or CRM64Pro.static-debug.lib (Static linking)
3. Runtime (DLL) When using dynamic linking, ensure that CRM64Pro.dll is located next to your executable or available in the system PATH (the installer allows to update this automatically).
3.2. Linux (GCC 13+)
|
|
| Linux Development
Self-Extracting Bash Installer
|
1. Download and Install CRM64Pro for Linux is distributed as a self-extracting Bash installer (for example: CRM64Pro-X.Y.Z-linux-x64.sh).
Run the installer from a terminal:
chmod +x CRM64Pro-X.Y.Z-linux-x64.sh
sudo ./CRM64Pro-X.Y.Z-linux-x64.sh
The installer places headers and libraries in standard system locations (e.g. /usr/local/include and /usr/local/lib).
2. Compiling Once installed, CRM64Pro can be linked using standard compiler flags:
g++ main.cpp -o mygame -lCRM64Pro
3.3. macOS (Clang 12+)
|
|
| macOS Development
DMG Package (Universal Binary)
|
1. Download and Install CRM64Pro is distributed as a DMG package. The installer provides a universal library supporting both x86_64 and arm64 (Apple Silicon) architectures.
Headers and libraries are installed into standard locations (e.g. /usr/local or /Library).
2. Compiling You can compile from the terminal or configure Xcode normally:
clang++ main.cpp -o mygame -lCRM64Pro
4. Getting started
Ready to write code? Jump straight into development with the practical examples.
|
| First time using the GDK?
Follow the step-by-step guides to create your first window, render sprites, play audio files, etc. | View Tutorials >> |
5. Game architecture
CRM64Pro abstracts the complexity of modern game loops into a flexible "Governor" pattern (Main::update). This allows developers to choose the synchronization strategy that best fits their game genre, from simple variable time-step loops to high-precision interpolated fixed-step systems.
Default Threading Model
While the engine is thread-safe, specific subsystems have architectural constraints or automatic behaviors:
| Subsystem | Execution Context | Description |
| Audio | Dedicated Thread | Managed entirely by SDL3. Audio mixing occurs in parallel to the game loop. |
| Network | Background Threads | Sockets run asynchronously. Packets are queued and processed when the main thread requests them. |
| Graphics | Main Thread | Due to underlying GPU API constraints (Direct3D/OpenGL), rendering commands must be issued from the main thread. |
| Logic | Flexible | Can run coupled on the main thread or decoupled via the Timer system. |
|
| Game loop methods
From basic to professional approaches
|
5.1. Variable Time Step (Synchronous)
This is the classic "render-as-fast-as-possible" loop. Logic and Graphics updates occur sequentially in the same iteration. The "Main loop" will run at the maximum speed provided by the CPU.
-
Mechanism: update() processes events and returns true. You run logic, then render.
-
Pros: Extremely simple to implement and debug.
-
Cons: Physics and game speed are tied to framerate. Requires carefully managed "Delta Time" for movement, or the game will run faster on better hardware.
-
Best for: Simple demos, visual novels, or learning projects.
Performance Note:
You can use CRM64Pro::ConfigMgr::iMTFriendly to specify a minimum wait time (milliseconds) per frame. This yields execution control back to the operating system to prevent eating 100% CPU doing unnecessary work.
Warning: Do not try to use this parameter for "time control" (e.g., setting it to 10ms to get 100fps). OS scheduling is not guaranteed; some iterations could take 10ms and others more, breaking the "smoothness" of the loop.
Code Example: Variable Step
Main &mC64 = Main::Instance();
SDL_Event myEvent;
Uint8 bRunning = 1;
while(bRunning)
{
while(mC64.update(&myEvent))
{
if(myEvent.type == SDL_QUIT) bRunning = 0;
}
}
5.2. Fixed Time Step (Asynchronous)
In this mode, the Logic runs at a guaranteed deterministic rate (e.g., 20 Hz), while Rendering runs at the monitor's refresh rate (e.g., 144 Hz or VSync).
-
Mechanism: You configure ITimer with a target rate. The update() method manages the accumulator and triggers logic updates only when required. Graphics are executed via the EVENT_C64_RENDER event.
-
Pros: Deterministic physics (essential for collision stability). Logic speed is independent of framerate.
-
Cons: Without interpolation, moving objects may appear to "jitter" or "stutter" if the render rate doesn't perfectly match the logic rate.
-
Best for: GUI-heavy applications.
Performance Note:
In this mode, the graphics logic runs without limit (max CPU/GPU speed). On fast systems, CRM64Pro::ConfigMgr::iMTFriendly can still be used to yield execution back to the OS and avoid 100% CPU usage on unnecessary rendering frames.
Code Example: Fixed Step
Main &mC64 = Main::Instance();
mC64.ITimer().init();
mC64.ITimer().setRate(0, 60);
SDL_Event myEvent;
Uint8 bRunning = 1;
while(bRunning)
{
while(mC64.update(&myEvent))
{
switch(myEvent.type)
{
case SDL_QUIT: bRunning = 0; break;
case EVENT_C64:
if(myEvent.user.code == EVENT_C64_RENDER)
{
}
break;
}
}
}
5.3. Fixed Time Step with Interpolation (Professional)
This is the gold standard for action games. Logic runs at a fixed, low frequency (e.g., 20 or 30 Hz) for stability, but the Engine renders at maximum framerate by interpolating positions between the previous and current logic states.
-
Mechanism: You provide a RenderCallback. The engine calls this automatically. CRM64Pro sprites and scrolling handle interpolation automatically.
-
Pros: "Buttery smooth" motion even with low CPU usage. High-performance physics stability. Separation of concerns.
-
Cons: Slightly more complex setup. You must not modify game state inside the render callback.
-
Best for: Retro games, strategy games, tile-based RPGs, platformers, shooters, commercial-grade action games.
Performance Note:
Using the callback function will produce a very smooth graphics output. This callback function can be changed dynamically or disabled using nullptr.
On fast systems, CRM64Pro::ConfigMgr::iMTFriendly can still be used to avoid eating the whole CPU doing plenty of unnecessary graphics rendering.
Code Example: Interpolated
Main &mC64 = Main::Instance();
mC64.ITimer().init();
mC64.ITimer().setRate(0,20);
Screen *mScreen = mC64.IConfigMgr().get();
mScreen->setRenderCallback(myRenderFunc);
SDL_Event myEvent;
Uint8 bRunning = 1;
while(bRunning)
{
while(mC64.update(&myEvent))
{
switch(myEvent.type)
{
case SDL_QUIT:
bRunning = 0;
break;
}
}
}
Sint32 myRenderFunc(Sint32 iMode)
{
return 0;
}
6. Configuration system
|
| Configuration system
Built-in launcher and customization
|
CRM64Pro includes a built-in "Launcher" window (CRM64Pro::ConfigMgr::setup). This allows end-users to configure hardware settings (Resolution, Monitor, Audio Driver) before the engine initializes the full graphical context.
Default Setup Launcher
Key Features:
-
Video Resolution & Window Mode selection.
-
Graphics API & Monitor selection.
-
Audio Driver selection & Output toggling.
-
Automatic configuration saving/loading.
Workflow
-
Call setup(): Launches the GUI. Returns 0 if the user clicked "OK".
-
Call load(): Reads the saved configuration and initializes the system.
Code Example: Implementation
Main &mC64 = Main::Instance();
mC64.ITimer().init();
mC64.ITimer().setRate(0,20);
Sint32 iRet = mC64.IConfigMgr().setup("config.xml", "setup.cdc", "setup.xml");
if(iRet == 0)
{
if(!mC64.IConfigMgr().load("config.xml", "setup.cdc"))
{
mScreen = mC64.IConfigMgr().get();
if(!mScreen->show())
{
}
}
}
Customization via XML
The launcher layout is data-driven. You can provide a custom XML file (e.g., setup.xml) to override the default look. This allows you to:
-
Change the logo (Sprite resource).
-
Hide specific options (e.g., force VSync or specific resolutions).
-
Rename window titles and labels.
Customized Launcher Example
In the example above, the window title was changed to "Validation Setup", the 5th resolution option was hidden, and the logo was replaced.
Code Example: setup.xml
<?xml version="1.0" encoding="UTF-8"?>
<c64_setup title="Validation Setup">
<!--
CRM64Pro GDK Setup Layout. MegaStorm Systems (c) -->
<main>
<logo state="1" name="milogo"/>
</main>
<general>
<wgMTfriendly value="10"/>
</general>
<video>
<wgScreenTitle text="AppCarrier"/>
<wgResolution5 state="5"/> <!-- Hide 5th resolution option -->
<wgSpecialVSync value="1"/>
<wgSpecialBatching value="0"/>
</video>
<audio>
<wgAudio value="0"/>
<wgSample32bits value="1"/>
</audio>
</c64_setup>
CRM64Pro GDK.
Definition AudioTrack.cpp:130
6.1 Master Setup XML Reference
The internal Master XML defines the structure. You can not modify the element names, but you can override their attributes in your custom XML.
Attribute Reference
| Attribute | Description |
| state | 0 (Disabled/Shown), 1 (Enabled/Visible) or 5 (Disabled/Hidden). |
| name | The C64 Sprite resource name (e.g., for logo). |
| x, y | Widget position. Supports CRM64Pro::ePositionHelpers. |
| value | The default value for the widget (Checkbox/Slider). |
| text | The label text displayed to the user. |
| action | Used for specific widgets to open a file or URL. |
View Master Setup XML
<?xml version="1.0" encoding="UTF-8"?>
<c64_setup title="Setup" cursor="default" icon_img="default" font="default">
<main name="default" x="0" y="0">
<logo state="1" name="default" x="59" y="10"/>
<wgTabsGeneral name="default" x="28" y="98" text="General"/>
<wgTabsVideo state="1" name="default" x="94" y="98" text="Video"/>
<wgTabsAudio state="1" name="default" x="160" y="98" text="Audio"/>
<wgSave state="1" name="default" x="44" y="401" text="Save"/>
<wgOK state="1" name="default" x="178" y="401" text="OK"/>
<wgExit state="1" name="default" x="313" y="401" text="Exit"/>
<wgInfoCopyright state="1" x="70" y="439" text="Setup Tool - CRM64Pro GDK - MegaStorm Systems (c)"/>
</main>
<general name="default" x="28" y="115">
<wgInfoCPU state="1" x="43" y="37" text="Processor: "/>
<wgInfoMemory state="1" x="43" y="62" text="Memory: "/>
<wgInfoVideoCard state="1" x="43" y="87" text="Video card: "/>
<wgInfoAudioCard state="1" x="43" y="112" text="Audio card: "/>
<wgMTfriendly state="1" name="default" x="43" y="132" value="1" text=" Multitasking friendly"/>
<wgReadme state="1" name="default" x="73" y="209" text="Readme" action="readme.txt"/>
<wgWeb state="1" name="default" x="223" y="209" text="Website" action="http://www.megastormsystems.com"/>
</general>
<video name="default" x="28" y="115">
<wgScreenTitle text="CRM64Pro GDK Application"/>
<wgRendererSoftware state="1" name="default" x="70" y="15" value="1" text=" Software"/>
<wgRendererOpenGL state="1" name="default" x="142" y="15" value="0" text=" OpenGL"/>
<wgRendererVulkan state="1" name="default" x="214" y="15" value="0" text=" Vulkan"/>
<wgRendererGPU state="1" name="default" x="286" y="15" value="0" text=" GPU"/>
<wgRendererDirect3D9 state="1" name="default" x="70" y="35" value="0" text=" Direct3D9"/>
<wgRendererX11 state="1" name="default" x="70" y="35" value="0" text=" X11"/>
<wgRendererMetal state="1" name="default" x="70" y="35" value="0" text=" Metal"/>
<wgRendererDirect3D11 state="1" name="default" x="142" y="35" value="0" text=" Direct3D11"/>
<wgRendererDirect3D12 state="1" name="default" x="214" y="35" value="0" text=" Direct3D12"/>
<wgResolution1 state="1" name="default" x="30" y="100" value="1" width="800" height="600" text=" 800x600"/>
<wgResolution2 state="1" name="default" x="30" y="120" value="0" width="1280" height="720" text=" 1280x720"/>
<wgResolution3 state="1" name="default" x="30" y="140" value="0" width="1920" height="1080" text=" 1920x1080"/>
<wgResolution4 state="1" name="default" x="30" y="160" value="0" width="2560" height="1440" text=" 2560x1440"/>
<wgResolution5 state="1" name="default" x="30" y="180" value="0" width="3840" height="2160" text=" 3840x2160"/>
<wgResolution6 state="5" name="default" x="30" y="200" value="0" width="c1" height="c1" text=" CustomRes"/>
<wgModeWindow state="1" name="default" x="130" y="100" value="1" text=" Window"/>
<wgModeFullscreen state="1" name="default" x="130" y="120" value="0" text=" Fullscreen"/>
<wgModeFullscreenExclusive state="1" name="default" x="130" y="140" value="0" text=" Fullscreen exclusive"/>
<wgSpecialVSync state="1" name="default" x="255" y="100" value="0" text=" Vertical-Sync"/>
<wgSpecialBatching state="1" name="default" x="255" y="120" value="0" text=" Render-Batching"/>
</video>
<audio name="default" x="28" y="115">
<wgAudio state="1" name="default" x="100" y="11" value="1" text=" Enable audio"/>
<wgSample8bits state="1" name="default" x="30" y="70" value="0" text=" 8bits"/>
<wgSample16bits state="1" name="default" x="30" y="90" value="1" text=" 16bits"/>
<wgSample32bits state="1" name="default" x="30" y="110" value="0" text=" 32bits"/>
<wgFrequency22Hz state="1" name="default" x="125" y="70" value="0" text=" 22050Hz"/>
<wgFrequency44Hz state="1" name="default" x="125" y="90" value="1" text=" 44100Hz"/>
<wgFrequency48Hz state="1" name="default" x="125" y="110" value="0" text=" 48000Hz"/>
<wgModeStereo state="1" name="default" x="242" y="70" value="1" text=" Stereo"/>
<wgModeSurround state="1" name="default" x="242" y="90" value="0" text=" Surround 4ch"/>
<wgModeSurroundPlus state="1" name="default" x="242" y="110" value="0" text=" Surround 6ch"/>
<wgVolumeMaster state="1" name="default" x="100" y="140" value="1.0" text="Master volume:"/>
<wgVolumeMusic state="1" name="default" x="100" y="170" value="1.0" text="Music volume:"/>
<wgVolumeSFX state="1" name="default" x="100" y="200" value="1.0" text="SFX volume:"/>
<wgVolumeVoice state="1" name="default" x="100" y="230" value="1.0" text="Voice volume:"/>
<wgVolumeCustom state="5" name="default" x="100" y="260" value="1.0" text="Custom volume:"/>
</audio>
</c64_setup>
7. High-level Architecture
CRM64Pro Architecture Diagram
8. Changelog
Log of all notable changes made to CRM64Pro GDK including the date, version, and brief description:
## 🚀 2025-12-20 – v0.13.0 – Major update and pre-release v1.0.0
### Added
- GUI: Introduced `Position` struct to handle widget coordinates, combining float precision offsets with `ePositionHelpers` anchors.
- GUI: Added specialized API for `WidgetTextBox` to handle text manipulation: `appendText()`, `appendLine()`, `insertLine()`, `removeLine()`, `setLine()`, and `getLine()`.
- GUI: Added specialized API for `WidgetListBox` to handle item management: `addItem()`, `insertItem()`, `removeItem()`, `selectItem()`, and `clearItems()`.
- Added `AudioTrack` module providing modern, unified audio playback features.
- Added Vulkan and GPU-accelerated renderer backends.
- Integrated `dr_mp3` 0.7.2 (Sept 2025) for MP3 playback.
- Integrated `libxmp` 4.6.3 (Nov 2025) for module/tracker playback.
- Windows deployment support using Inno Setup.
- Added CHANGELOG.md for tracking project changes (replacing History.txt).
- Added README.md for project overview and setup instructions.
### Changed
- Migrated all projects to Visual Studio 2026.
- Updated copyright year to 2025.
- Updated dependencies:
- xxHash 0.8.3 (Nov 2025)
- TinyXML2 11.0.0 (Nov 2025)
- zlib-ng 2.3.2 (Dec 2025)
- libpng 1.6.53 (Dec 2025)
- SDL 3.4.0 (Nov 2025)
- SDL3_mixer 3.1.0 (Nov 2025)
- dr_flac 0.13.2 (Sept 2025)
- Updated documentation to Doxygen 1.15.0.
- Moved Doxygen documentation into CRM64Pro header files for direct IDE integration.
- Unified formatting across all Doxygen documentation.
- `fileRemove()` now supports wildcard patterns.
- GUI: Updated `ePositionHelpers`: Deprecated "Decrement" flags (e.g., `PH_RIGHTD`) in favor of using standard flags with negative float offsets in the `Position` struct.
### Removed
- Removed `AudioSound` and `AudioMusic` modules (fully replaced by `AudioTrack`).
- Removed minimp3 (no longer supported under SDL3).
- Removed libmodplug (deprecated and unsupported under SDL3).
### Fixed
- Fixed multiple issues in `ConfigMgr::setup()` functionality.
- Fixed colorkey and palette handling issues when loading images.
- Fixed a memory leak when loading images from a CDC archive.
- Fixed issues with the Memory Manager on Linux and macOS when no custom memory manager is enabled.
- Fixed `ImageMgr::renderEx()` flip operations when rendering to an Image.
- Fixed `Screen::fadeToColor()` and `Screen::fadeToImage()` behavior.
### Breaking Changes
- Configuration: System updated to comply with SDL3 and SDL3_mixer API changes.
- Audio: Modernized audio system. `AudioMusic` and `AudioSound` classes have been removed; use the new `AudioTrack` module instead.
- API:
- `msg(...)` signature changed: `msg(eLogMessageLevel level, const char *fmt, ...)` (added `const`).
View the Complete Changelog.
9. License
Copyright (C) 2013-2025 Roberto Prieto <contact@megastormsystems.com>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.