| CRM64Pro GDK v0.17.0 A free cross-platform game development kit built on top of SDL 3.0

Loading...
Searching...
No Matches
Reference Guide

# 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 an advanced Scene and world management system 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.

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:

1. Right-click your project in Solution Explorer and select Properties.
2. Select All Configurations and x64 platform.
3. Add the CRM64Pro `include/` directory to C/C++ → General → Additional Include Directories.
4. Add the CRM64Pro `lib/` directory to Linker → General → Additional Library Directories.
5. 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 | Runs on a high-precision fixed-timestep for deterministic behavior. The Scene system uses this for ultra-smooth sub-pixel movement.

| ### 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)
{
// 1. Logic (Dependent on Frame Time)
// float dt = mC64.ITimer().getDelta();
// MyGame_Update(dt);
// 2. Render
// MyGame_Draw();
// 3. Engine Governor (Process Input/Events)
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();
// Configure Logic to run exactly 60 times per second
mC64.ITimer().init();
mC64.ITimer().setRate(0, 60);
SDL_Event myEvent;
Uint8 bRunning = 1;
while(bRunning)
{
// 1. Logic (Runs exactly 60Hz)
// MyGame_UpdateFixed();
// 2. Engine Governor
while(mC64.update(&myEvent))
{
switch(myEvent.type)
{
case SDL_QUIT: bRunning = 0; break;
// 3. Render (Triggered freely, e.g., at 144Hz)
case EVENT_C64:
if(myEvent.user.code == EVENT_C64_RENDER)
{
// MyGame_Draw();
}
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: High-performance 2D worlds, complex ARPGs, platformers, and any game requiring pixel-perfect physics and cinematic camera logic.

> 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
// Initialization stuff
Main &mC64 = Main::Instance();
mC64.ITimer().init();
mC64.ITimer().setRate(0,20); // Set the Logic Frame Rate to 20
// ...
// Set a render callback for our main screen
Screen *mScreen = mC64.IConfigMgr().get();
mScreen->setRenderCallback(myRenderFunc);
// Main loop
SDL_Event myEvent;
Uint8 bRunning = 1;
while(bRunning)
{
// My logic stuff
// ...
// C64 main governor
while(mC64.update(&myEvent))
{
switch(myEvent.type)
{
case SDL_QUIT:
bRunning = 0;
break;
}
}
}
Sint32 myRenderFunc(Sint32 iMode)
{
// My graphics stuff
// ...
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

1. Call setup(): Launches the GUI. Returns 0 if the user clicked "OK".
2. Call load(): Reads the saved configuration and initializes the system.

Code Example: Implementation
// Initialization stuff
Main &mC64 = Main::Instance();
mC64.ITimer().init();
mC64.ITimer().setRate(0,20); // Set the Logic Frame Rate to 20
// Call to setup method
// Arguments: Config file to save to, Resource pack, Layout XML (optional)
Sint32 iRet = mC64.IConfigMgr().setup("config.xml", "setup.cdc", "setup.xml");
// If configuration selected by user is saved and clicked on OK, then launch the application
if(iRet == 0)
{
if(!mC64.IConfigMgr().load("config.xml", "setup.cdc"))
{
mScreen = mC64.IConfigMgr().get();
if(!mScreen->show())
{
// main code
// ...
}
}
}

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
CRM64Pro GDK.
Definition AudioTrack.cpp:137

## 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">
<!-- CRM64Pro GDK Setup Layout. MegaStorm Systems (c) -->
<!-- Attributes and values:
state: 0(disabled but shown) , 1(enabled) or 5 (disabled and not shown).
name: the sprite resource name.
x and y: positions. Supports CRM64Pro::ePositionHelpers.
value: for widgets, it is the value.
text: for widgets, it is the text.
action: for widgets: open a file or an url.
-->
<!-- The size of the setup screen is set by the size of the main name resource -->
<main name="default" x="0" y="0">
<logo state="1" name="default" x="59" y="10"/>
<!-- CheckBox widgets group for Tabs -->
<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"/>
<!-- Button widgets -->
<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"/>
<!-- Label widget -->
<wgInfoCopyright state="1" x="70" y="439" text="Setup Tool - CRM64Pro GDK - MegaStorm Systems (c)"/>
</main>
<general name="default" x="28" y="115">
<!-- Label widgets -->
<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: "/>
<!-- CheckBox widget -->
<wgMTfriendly state="1" name="default" x="43" y="132" value="1" text=" Multitasking friendly"/>
<!-- Button widgets -->
<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 configuration is only for "default" C64 screen -->
<video name="default" x="28" y="115">
<!-- Title for screen -->
<wgScreenTitle text="CRM64Pro GDK Application"/>
<!-- CheckBox widgets group for Renderers -->
<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"/>
<!-- CheckBox widgets group for Resolution -->
<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"/>
<!-- CheckBox widgets group for Mode -->
<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"/>
<!-- CheckBox widgets -->
<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">
<!-- CheckBox widget -->
<wgAudio state="1" name="default" x="100" y="11" value="1" text=" Enable audio"/>
<!-- CheckBox widgets group for Sampling -->
<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"/>
<!-- CheckBox widgets group for Frequency -->
<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"/>
<!-- CheckBox widgets group for Mode -->
<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"/>
<!-- Horizontal slider widgets -->
<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:

## 🚀 2026-05-08 – v0.17.0 – GUI refactored and improved
### Added
- GUI:
- Added `Widget::getID()`, `Widget::getName()`, `Widget::getType()` and `Panel::getWidgetIDs()` for widget inspection and panel widget enumeration.
- Added `Panel::createWidgetByType()` and `Panel::getWidgetByID()` for editors, importers, and runtime-driven widget workflows.
- Added `Panel::getWidgetInfoList()` for lightweight widget inspection without generic widget lookup.
- Added typed widget creation/getter pairs such as `createProgress()`, `getProgress()`, `createSlider()`, `getSlider()`,
`createTextEdit()`, `getTextEdit()`, `createList()` and `getList()`.
- Added direct widget callbacks `setOnAction()`, `setOnHoverEnter()`, `setOnHoverExit()`, `setOnPressed()` and `setOnFocusLost()` as
a modern event-style alternative to polling SDL widget events.
- Added semantic widget callbacks `setOnValueCommitted()`, `setOnSelectionChanged()`, `setOnValueChanged()` and `setOnToggled()`,
matching the richer `EC_WIDGET_*` event model.
- Added runtime GUI theming with built-in Default, Dark, and Flat themes plus custom theme creation through GUIMgr.
- Added `GUITheme` and `GUIThemeSkin` APIs for per-widget-type, per-state procedural styling.
- Added `GUIMgr` theme management methods: `createTheme()`, `getTheme()`, `setGlobalTheme()`, `getGlobalTheme()`, `closeTheme()`,
`getThemeDefault()`, `getThemeDark()`, and `getThemeFlat()`.
- Added panel-level theme override through `Panel::setTheme()` and `Panel::getTheme()`.
- `WidgetList` supports interactive multi-selection with Ctrl+Click toggle, Shift+Click range selection, multi-row rendering,
and selection APIs (`setMultiSelect()`, `clearSelection()`, `getSelectedCount()`, `getSelectedItems()`).
- Added panel flow layouts with `PL_HFLOW` and `PL_VFLOW`, plus `Panel::setLayout()`, spacing, padding, justify, align,
and invalidation APIs, allowing modeless/modal/ephemeral panels to auto-arrange child widgets horizontally or
vertically while preserving existing panel behavior.
- Added `Widget::clearBackground()` to clear per-state background image/sprite assignments and reset linked inherited background overrides.
- New `WidgetFrame` (`WT_FRAME`), a lightweight themed primitive for horizontal/vertical lines and outline/filled rectangles.
- New `WidgetNumberEdit` (`WT_NUMBEREDIT`), a numeric text-edit control with integer float input support and configurable min/max/step.
- New `WidgetComboBox`, a themed single-selection drop-down control with popup item list, hover/selection highlighting and autosort.
- `WidgetTextEdit` and `WidgetNumberEdit` support persistent keyboard focus, mouse selection, Ctrl+A/C/X/V/Z/Y, selection-aware editing, and undo/redo.
- Standardized numeric widget APIs around `setValue()`, `getValue()`, `setRange(min,max)` and `getRange(&min,&max)`.
- Standardized selection widget APIs around `setSelectedIndex()`, `getSelectedIndex()`, `setSelectedText()` and `getSelectedText()`.
- Tool:
- New `strToFloat()` and `floatToStr()` methods.
- Font:
- FontMgr now exposes built-in GUI fonts by name through `getBuiltin()`, supporting the embedded Arial/Courier New
black/white 10/12 font set with simple names such as Arial12Black and CourierNew10White.
### Changed
- GUI:
- Widget was reduced to a true common base API. Widget-specific methods were removed from Widget and must now be called on
the corresponding concrete widget classes (`WidgetButton`, `WidgetCheckBox`, `WidgetProgress`, `WidgetSlider`,
`WidgetTextEdit`, `WidgetNumberEdit`, `WidgetList`, `WidgetComboBox`, etc.).
- Internal refactor of the GUI subsystem: normalized widget feature flags, improved widget/panel inspection APIs, extracted update/render helpers,
reduced panel/widget coupling, and reorganized widget implementation units.
- Widget appearance now resolves through a theme cascade: widget explicit override -> panel theme -> global theme -> built-in Default.
- Disabled widgets now remain fully mutable from code, so setters and content-management APIs (`setText()`, `setValue()`,
`addItem()`, `setSelectedIndex()`, text/list editing, etc.) still work while disabled, while user interaction remains blocked.
- Expanded legacy `eEventCode` widget events from action/hover/lost-focus only to a richer model with `EC_WIDGET_SELECTIONCHANGED`,
`EC_WIDGET_VALUECHANGED`, `EC_WIDGET_TOGGLED` and `EC_WIDGET_VALUECOMMITTED` for cleaner widget-state handling.
- Programmatic widget setters now follow a silent-update policy. User interaction and explicit edit commits emit events/callbacks,
while setter callers should run any required application logic directly.
- CheckBox group handling now follows radio-button behavior with silent programmatic selection and event/callback notification only
for user-driven changes.
### Fixed
- GUI:
- TextEdit and NumberEdit now clamp their height so the current font and vertical margins always leave room for at least one visible text line.
- List selection now auto-scrolls the selected item into view using centered reveal when possible.
- TextEdit and NumberEdit value-commit callbacks now fire on Enter and focus-loss commits without treating Enter as focus loss.
- Tooltip and skin color editor fields now apply committed text values on Enter as well as focus loss.
- Grouped CheckBox changes now emit consistent `EC_WIDGET_TOGGLED` events for user-driven group selection changes.
- GFX:
- Fixed filled circle rendering to avoid repeated side overdraw while improving performance with midpoint scanline filling.
### Breaking Changes
- Font:
- Reworked bitmap glyph metrics to derive bounds from image separators, added configurable space width via `setSpaceWidth()` and `getSpaceWidth()`,
Font CDC binary compatibility is broken so existing Fonts must be re-imporated and re-saved or opened with the EditorC64 that will auto-update them.
- GUI:
- Replaced legacy `WIDGET_FEATURE_*` macros with `eWidgetFeature` enum. `Widget::setFeatures()` and `Widget::getFeatures()` now use `eWidgetFeature` with bitwise operator support.
- Removed `Widget::setState()`. Use `Widget::enable()`, `Widget::disable()` for interactivity and `Widget::show()`, `Widget::hide()` for visibility.
- `Widget::disable()` no longer removes the widget from rendering. Disabled widgets now remain visible with their deactivated skin; use hide() to make a widget invisible.
- Removed `Widget::activate()` and `Widget::deactivate()` after consolidating the public widget lifecycle API around `enable()`, `disable()`, `show()`, and `hide()`.
- Generic `Panel::createWidget()` and `Panel::getWidget()` were removed. Use typed creation/getters for normal code, or
`createWidgetByType()` and `getWidgetByID()` for dynamic editor/importer scenarios.
- Legacy widget class naming was modernized. `WidgetProgressBar`, `WidgetHSlider`, `WidgetVSlider`, `WidgetTextBox`, and
`WidgetListBox` were renamed to `WidgetProgress`, `WidgetSlider`, `WidgetTextEdit`, and `WidgetList`.
- Legacy widget type enum names were removed from active API usage. Use `WT_PROGRESS`, `WT_SLIDER`, `WT_TEXTEDIT`, and `WT_LIST`.
- `Widget::setState()` was removed. Widget lifecycle now uses `enable()`, `disable()`, `show()`, and `hide()`.
- `Widget::activate()` and `deactivate()` were removed from the public API after consolidating widget lifecycle semantics.
- `Widget::disable()` semantics changed. Disabled widgets remain visible with their deactivated skin; use hide() to remove a
widget from rendering.
- `Widget::status()` for widgets now reports only `GS_DISABLED`, `GS_HIDDEN`, or `GS_SHOWN`.
- Removed legacy `Widget::setFunction()` and its state-bound void* callback model in favor of typed std::function-based widget callbacks.
- Removed `GUIMgr::getFontWhiteAA()` and `GUIMgr::getFontBlack()`, callers must now use `IFontMgr().getBuiltin()`.
- Widget-specific GUI behaviors were removed from eWidgetFeature. TextEdit now uses direct `setMultiline()` and `setReadOnly()` APIs,
List now uses `setAutoSort()` and `setMultiSelect()`, and Console now uses explicit read-only methods instead of widget feature flags.
- Renamed background styling methods for clarity:
- `setBgColor()` and `getBgColor()` to `setBackgroundColor()` and `getBackgroundColor()`
- `setBgImage()` and `getBgImage()` to `setBackgroundImage()` and `getBackgroundImage()`
- `setBgSprite()` and `getBgSprite()` to `setBackgroundSprite()` and `getBackgroundSprite()`
- Replaced `Panel::type(...)` with explicit panel-type APIs: `setPanelType()` and `getPanelType()`.
- Removed `Widget::setText()` and `Widget::getText()` from the base `Widget` API. Text methods now live only on text-capable
widgets such as `WidgetLabel`, `WidgetButton`, `WidgetCheckBox`, `WidgetTextEdit`, and `WidgetNumberEdit`.
- Added explicit panel title APIs `Panel::setTitle()` and `Panel::getTitle()`. Panel title text should no longer be assigned through `baseWidget().setText()`.
- Renamed ambiguous widget-specific value/range APIs:
- `WidgetCheckBox`: `setValue()` and `getValue()` to `setChecked()` and `isChecked()`
- `WidgetList`: `setValue()`, `getValue()` and `getRange()` to `setSelectedIndex()`, `getSelectedIndex()` and `getItemCount()`
- `WidgetTextEdit`: ambiguous `getValue()` and `getRange()` to `getCursorLine()` and `getLineCount()`
- `WidgetNumberEdit`: `setNumber()`, `getNumber()`, `setMinMax()` and `getMinMax()` to `setValue()`, `getValue()`, `setRange(min,max)` and `getRange(&min,&max)`
- `WidgetProgress`: `setRange(max)` and `getRange()` to `setRange(min,max)` and `getRange(&min,&max)`
- `WidgetSlider`: `setRange(count)` and `getRange()` to `setRange(min,max)` and `getRange(&min,&max)`, with value clamping now based on the explicit inclusive range
- `WidgetList`: `getSelectedItem()` to `getSelectedText()`, and added `setSelectedText()` for symmetry with `WidgetComboBox`
- `WidgetComboBox`: `getSelectedItem()` to `getSelectedText()`, and added `setSelectedText()`
## 🚀 2026-03-25 – v0.16.0 – Network refactored and improved
### Added
- NetTCP:
- Added asynchronous outbound queueing for client and server traffic.
- Added configurable TX soft-brake / backpressure limits via `setTXSoftBrake()` / `getTXSoftBrake()`.
- Added richer `info()` diagnostics for RX/TX queues, buffered data, pending writes, throughput and errors.
- Added server pending-login handling to process new connections without blocking active clients.
- Added public `eNetResult` and `eNetTCPFeature` enums.
- Added challenge-response login with server nonce exchange.
- Added optional AES-CTR session payload encryption negotiated through `setFeatures()`.
- Added bounded string password support for NetTCP login/server creation.
- Added stricter per-message payload validation for login and control messages.
- Tool:
- New xxHash3() methods for XXH3 64-bit hashing.
### Changed
- NetTCP:
- Refactored socket ownership so actual I/O is performed only by the dedicated network thread.
- Converted outbound queues to ring buffers and updated the inbound receive queue to ring-buffer behavior.
- Improved server loop responsiveness under TX backlog by using shorter wait intervals when outbound data is pending.
- Improved `info()` output with cleaner RX/TX naming, feature reporting and clearer queue/buffer diagnostics.
- Upgraded packet integrity from folded 32-bit hashes to full 64-bit xxHash3 while keeping the DataNet wire header size unchanged.
- Tool:
- randSeedPCG() and randPCG() now support optional caller-managed state.
- Updated validation tests (BasicSystem, Config, ConfigSetup) with platform-aware native hardware renderers.
- Updated dependencies:
- SDL3_net 3.0.0 (Jan 2026)
### Fixed
- NetTCP:
- Fixed server login flow so slow connectors no longer stall active clients.
- Fixed login/session edge cases including leaked login payloads, failed `LOGIN_ACCEPTED` rollback, and mismatched negotiated feature reporting.
- Fixed multiple thread-safety issues by moving shared lifecycle/state flags to atomic usage where required.
- Fixed several queue, shutdown and diagnostic inconsistencies in client/server runtime paths.
- Fixed stale documentation/comments and protocol validation issues across the refactored network layer.
- Alpha transparency loss in software renderer during clipped scaling (SDL3 issue #15147).
- Fixed `ConfigMgr::setup()` video configuration saving so existing config.xml files now correctly update renderer and resolution values.
### Breaking Changes
- NetTCP:
- Public NetTCP receive messages were renamed from `NETMSG_*` to `NM_*`.
- Public NetTCP result/error codes now use the new `eNetResult` enum with `NR_*` values.
- Replaced `features()` with:
- `setFeatures()`
- `getFeatures()`
- `sendData()`, `queryKillServer()`, `queryKillClient()`, `queryClientsInfo()` and related NetTCP methods now return `eNetResult`.
- `createServer()` and `connectTo()` now use `const string& sPassword` instead of the old integer password.
- Packet integrity now uses a 64-bit hash field internally while preserving the existing 24-byte DataNet serialized header.
- IP fields were upgraded from IPv4-only Uint32 values to `NetTCP::NetIPAddress`, `ClientInfo::iIP` became `ClientInfo::ipAddress` and `NetTCP::getIP()` now returns `NetIPAddress`.
## 🚀 2026-02-28 – v0.15.0 – Scene with Object support
`TileEngine` has been completely renamed to `Scene` across the entire codebase to better reflect its role as a robust advanced 2D game world management system.
### Added
- Scene:
- Object Layer support:
- Introduced native TMX object layers with support for rectangles, points, polygons and polylines.
- Added runtime access to object data (position, size, properties, type, name).
- Object factory system for creating custom game objects from TMX data.
- Added TMX template (.tx) load/save support.
- Object rotation: shape, tile rotation + rotated AABB supported.
- High-precision timing integration:
- Scene logic now fully supports the new Main fixed-timestep system.
- Deterministic update behavior regardless of frame rate.
- Sub-pixel camera movement:
- Floating-point world coordinates for camera and layer scrolling.
- Smooth pixel-perfect rendering without jitter during slow movement.
- Support for user-defined layers via class inheritance, the new `addLayer()` injection method, and custom type IDs (`TELT_USER_START`).
- Added camera methods, multiple modes, and configurable parameters for per-layer behavior (follow, bounds/clamp, smoothing, and axis controls).
- Implemented a suite of tutorials covering various game genres (RTS, RPG, Scrolling) to fully validate the TileEngine system.
- Added native TE_Object trigger zones with cross-layer + type-hash filtering + delayed one-shot STAY/EXIT cooldown flow.
- Physics:
- Implemented new Physics interface with frame-accurate pixel-perfect collision detection.
- Sprite:
- Added support for new animation types: `ST_ONESHOT_REVERSE` and `ST_RANDOM`.
- CMem:
- Added `MSL_DEBUG` level for detailed leak detection with unique Allocation IDs, memory dump previews, and
debugger breakpoint support via `setBreakOnAlloc()`.
- Tool:
- New PCG32 PRNG methods: `randSeedPCG()`, `randPCG()` and `randRealPCG()`.
- Image:
- Added getWidth() and getHeight() methods to Image objects for easy access to dimensions.
- Added loadFromSurface() method to create an Image directly from an existing SDL_Surface.
- Expanded custom STL memory allocator support to include queue, stack, priority_queue, multimap, list, and shared_ptr/stringbuf aliases.
- Implemented engine-wide memory allocation protection for critical PIMPL/Manager failures and graceful returns for resource allocations.
### Changed
- Scene:
- Internal architecture refactor:
- Major refactor of Scene core to separate logic, rendering and timing concerns.
- Simplified layer update/render flow aligned with Main canonical game loop.
- Logic / render synchronization:
- Scene `update()` now runs strictly on the fixed timestep.
- Interpolation moved to render phase using engine-provided delta helpers.
- Scrolling and parallax math:
- All scrolling, parallax and auto-scroll calculations now use floating-point precision.
- Code cleanup & optimization:
- Reduced redundant state, improved cache locality and simplified internal containers.
- Timer:
- `benchInfoEx()` method in throughput mode now perform unit conversion to thousands and millions for better readability.
- Refactored microbenchmark system to centralize statistical logic and implement consistent, unit-aware formatting (K/M scales) across console logs and HTML reports.
- Main:
- Canonical game loop: Refactored `update()` to use a high-precision accumulator system with nanosecond resolution, ensuring zero-drift timing and
deterministic simulation steps.
- Introduced `getDeltaTime()` and `getLogicTime()` to provide unified, high-precision timing across all engine modules.
- Spiral of death prevention: Implemented safety clamping on delta time to ensure engine stability during significant lag spikes or window interruptions.
- Implemented engine-wide restricted prefix policy (# and @): enforced on create/setName and loadFromFile, while allowed on loadFromBuffer and CDC load.
### Fixed
- Implemented over 70 stability fixes including memory safety, robust I/O validation, and null-pointer guards across all core modules.
- Scene:
- TMX loading issues:
- Fixed incorrect handling of transparent / colorkey tilesets.
- Layer update/render edge cases:
- Fixed inconsistencies when enabling/disabling layers at runtime.
- Sprite:
- Fixed visual glitches caused by desynchronized timing.
- Interpolation now relies on Main timing helpers.
- Fixed an issue with `Sprite::status()` when using one-shot animations.
- Image:
- Fixed a memory leak in `ImageMgr::load()` (CDC path).
### Breaking Changes
- Macros to enum migration:
- Scene:
- Replaced `TE_LAYERFLAG_*` macros with `eSceneLayerFeature` and `SLF__*`.
- Replaced `TE_TILESETTYPE_*` macros with `eSceneTileSetType` and `STST_*`.
- Log: Replaced `LM_*` macros with `eLogMode`. Added bitwise operator support via a reusable template.
- Memory Manager: Replaced `CMEM_MOD_*` macros with `eMemoryModule` and `CMM_*`.
- Updated `alloc()`, `calloc()`, `realloc()`, and `alloc_aligned()` methods.
- Tool: Replaced `TMBB_*` macros with `eMsgBoxButton`.
- C64 System Status: Replaced `C64_STATUS_*` macros with `eGeneralStatus` and `GS_*`.
- Sprite Types: Replaced `SPR_TYPE_*` macros with `eSpriteType` `ST_*`.
- Custom events: Replaced the legacy `#define C64_EVENT` macro with `eEventType` with values `ET_C64` replacing old `C64_EVENT`.
- Audio:
- `eAudioFreq` renamed to `eConfigAudioFreq`. Internal values renamed from `AF_*` to `CAF_*`.
- `eAudioSample` renamed to `eConfigAudioSample`. Internal values renamed from `AS_*` to `CAS_*`.
- `eAudioMode` renamed to `eConfigAudioMode`. Internal values renamed from `AM_*` to `CAM_*`.
- XML:
- Removed parameter-based `getAttribute()` and `setAttribute()` overloads.
- Replaced with explicit typed methods: `getAttribute[String|Int|Uint|Float|Bool]` and `setAttribute[String|Int|Uint|Float|Bool]`.
- API method updates:
- `Tool::messageBox()`: Now returns `eMsgBoxButton` instead of `Sint32`.
Internal failures now log a warning and return TMBB_NONE instead of negative error codes.
- `status()` methods: Updated return type from `Sint32` to `eGeneralStatus` across all classes (Log, Screen, Sprite, Widget, CursorMgr).
- Refactored `renderEx()` methods:
- Standardized the extended rendering API across all high-level graphics objects (Sprite, Tile, Font)
to support asymmetric scaling (X/Y) and improve parameter consistency.
- `Sprite::renderEx()`changed from (float fScale, ...) to (float fScaleX, float fScaleY, ...).
- `Font::renderEx()` changed from (..., float fScale, ...) to (..., float fScaleX, float fScaleY, ...).
- `Tile::renderEx()` changed from (Sint32 iTile, double dAngle, ...) to (Sint32 iTile, float fScaleX, float fScaleY, double dAngle, ...).
....

View the Complete Changelog.

# 9. License

CRM64Pro GDK
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.