The GDK runs on major operating systems. Thanks to SDL3, it supports a wide variety of hardware accelerated rendering and low-latency audio drivers.
The installer places headers and libraries in standard system locations (e.g. /usr/local/include and /usr/local/lib).
Headers and libraries are installed into standard locations (e.g. /usr/local or /Library).
Ready to write code? Jump straight into development with the practical examples.
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.
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).
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.
The internal Master XML defines the structure. You can not modify the element names, but you can override their attributes in your custom XML.
## 🚀 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, ...).
....