ArmorPaint Project Architecture and Code Organization: Inside the Iron Engine Structure
ArmorPaint splits its codebase into two distinct layers: the reusable Iron engine in /base and the application-specific painting logic in /paint, unified by a custom amake build system that compiles C sources and KONG shaders into a cross-platform 3D painting tool.
ArmorPaint is a cross-platform 3D painting application written in C and built on top of the lightweight Iron engine. Understanding the ArmorPaint project architecture and code organization reveals a deliberate separation between the general-purpose engine layer and the specialized painting functionality. This modular structure enables the software to target Windows, macOS, Linux, iOS, and Android while maintaining a minimal, embeddable core.
Two-Layer Repository Structure
The repository is organized into two primary subtrees that separate concerns between engine infrastructure and application logic. This division allows the Iron engine to function as a standalone library while ArmorPaint adds its specific UI, shaders, and viewport handling.
The Iron Engine Layer (/base)
The /base directory contains the reusable Iron engine and build tooling. This layer provides the foundational systems that handle memory management, graphics abstraction, and platform-specific hardware interfaces.
Key components include:
base/sources/engine.c– Contains the core initialization and main loop, includingiron_init()which orchestrates startup by callingiron_init_memory(),iron_init_gpu(), andiron_init_input().base/sources/iron_*.c/h– Modular utility libraries such asiron_lz4.cfor compression,iron_json.cfor parsing, andiron_armpack.cfor serialization.base/sources/backends/*– Platform-specific graphics and audio implementations that isolate OS dependencies into separate files likebackends/linux_video.candbackends/ios_*.m.base/tools/amake– The custom build tool that processes JavaScript-based project files to generate compilation commands.
The ArmorPaint Application Layer (/paint)
The /paint directory contains the specialized code that transforms the Iron engine into a 3D painting application. This layer adds viewport management, brush logic, and rendering passes specific to texture painting.
Key components include:
paint/sources/viewport.c– Handles viewport rendering and forwards mouse/pen input to the painting engine.paint/shaders/*.kong– A collection of shader passes written in the KONG format, including effects like SSAO (ssao_pass.kong), bloom, and temporal anti-aliasing (TAA).paint/project.js– The build configuration that appends Paint-specific sources and shaders to the final executable.
Build System Architecture
The project uses a unique single-pass build system centered on JavaScript-based project files and the amake tool. Unlike traditional build systems like CMake or Make, ArmorPaint uses project.js files as manifests that the amake tool (located in base/tools) interprets at compile time.
The build process works as follows:
base/project.js– Defines core engine sources, backend selections, and compiler flags based on the target platform.paint/project.js– Conditionally adds application-specific sources. For example, on Linux it appends viewport and resource files:
// Paint-specific source files are appended to the build.
if (platform === 'linux') {
project.add_source('paint/sources/viewport.c');
project.add_source('paint/sources/resource.c');
}
- Merge and Compile –
amakemerges the source lists from bothproject.jsfiles, selects the appropriate backend files (such as Direct3D12 for Windows or Metal for macOS), and invokes the TCC compiler or an external toolchain with the necessary flags.
This approach allows the separation of engine and application code while producing a unified executable that contains both layers.
Core Engine Subsystems
The Iron engine follows a classic modular C design where functionality is partitioned into distinct subsystems initialized during startup.
In base/sources/engine.c, the initialization sequence establishes the runtime environment:
// Initialize the Iron engine.
int iron_init() {
iron_init_memory(); // Set up custom allocator.
iron_init_gpu(); // Initialise GPU driver (abstracted per backend).
iron_init_input(); // Register input callbacks.
return 0;
}
The engine architecture separates concerns into:
- Memory Management – Custom allocators defined in
iron_memory.cprovide controlled heap usage across platforms. - Resource Management – Systems for loading textures, meshes, and materials.
- Main Loop – The engine tick that processes input, updates simulation state, and queues render commands.
Graphics Abstraction and Cross-Platform Backends
Iron achieves cross-platform compatibility through a thin graphics abstraction layer implemented in the backends directory. Rather than using conditional compilation throughout the codebase, platform-specific code is isolated into dedicated source files.
The backend structure includes:
backends/linux_*.c– Vulkan implementations for Linux systems.backends/ios_*.m– Objective-C++ implementations using Metal for iOS devices.backends/win_*.c– Direct3D12 implementations for Windows.
This isolation ensures that graphics API-specific code does not leak into the engine core. The iron_init_gpu() function detects the target platform and initializes the appropriate backend, exposing a unified renderer interface to the application layer.
Shader-Centric Rendering Pipeline
ArmorPaint employs a shader-centric rendering architecture where all visual passes are defined in KONG shader files. These files support hot-reloading and define passes for post-processing effects and material rendering.
For example, the SSAO (Screen Space Ambient Occlusion) pass in paint/shaders/ssao_pass.kong demonstrates the format:
// SSAO pass – computes ambient occlusion from depth.
@vertex
fn vs_main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
return vec4<f32>(pos, 1.0);
}
@fragment
fn fs_main() -> @location(0) vec4<f32> {
// Sample depth, compute occlusion, output color.
}
Additional passes include bloom, depth-to-normal conversion, and TAA, all residing in paint/shaders/. The build system compiles these KONG files into the appropriate shader code for the target graphics API during the amake process.
Summary
- Two-layer architecture – The
/basedirectory contains the reusable Iron engine while/paintcontains application-specific code, enabling clean separation of concerns. - Custom build system – The
amaketool processesproject.jsfiles from both directories to merge source lists and compile for the target platform. - Modular C design – Core functionality resides in single-file libraries like
iron_json.candiron_lz4.c, making the engine embeddable. - Platform isolation – Graphics backends in
base/sources/backends/*keep OS-specific code separated from the engine core. - Shader-driven rendering – KONG shader files in
paint/shaders/define all rendering passes, supporting hot-reloading and rapid iteration.
Frequently Asked Questions
What language is ArmorPaint written in?
ArmorPaint is written primarily in C with platform-specific backends utilizing Objective-C for iOS/macOS Metal support. The build system uses JavaScript configuration files (project.js) processed by the custom amake tool. This C-based architecture ensures minimal dependencies and high performance across Windows, macOS, Linux, iOS, and Android platforms.
How does the build system combine the engine and application layers?
The amake build tool processes both base/project.js and paint/project.js to generate the final compilation command. It merges the engine's core sources with application-specific files like paint/sources/viewport.c and selects appropriate graphics backends based on the target OS. This allows the Iron engine to remain a standalone library while ArmorPaint adds its specific UI and painting logic.
What graphics APIs does ArmorPaint support?
ArmorPaint supports Vulkan on Linux and Android, Metal on iOS and macOS, and Direct3D12 on Windows. These backends are implemented as isolated source files in base/sources/backends/ (such as linux_video.c and win_video.c), with the engine abstracting the underlying API through a unified interface initialized via iron_init_gpu().
What is the purpose of the KONG shader format in ArmorPaint?
KONG is a shader format used by ArmorPaint to define rendering passes for effects like SSAO, bloom, and TAA. Stored in paint/shaders/*.kong, these files enable hot-reloading and cross-platform shader compilation. The format uses modern syntax similar to WebGPU/WGSL, allowing developers to write shaders once and target multiple graphics APIs through the build system.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →