# How ArmorPaint Integrates with External Tools: Plugins, Importers, and Native Bridges

> Discover how ArmorPaint integrates with external tools via plugins, native importers, and JNI bridges. Extend its capabilities seamlessly for your workflow.

- Repository: [Armory 3D/armorpaint](https://github.com/armory3d/armorpaint)
- Tags: how-to-guide
- Published: 2026-09-13

---

**ArmorPaint integrates with external tools through a modular plugin system that compiles third-party C code directly into the engine, native import wrappers for industry-standard 3D formats, and platform-specific JNI bridges for mobile deployment.**

The open-source ArmorPaint repository (armory3d/armorpaint) is architected for extensibility, allowing developers to extend functionality without modifying core engine code. Through a combination of compile-time plugin detection, third-party library integration, and callback-based UI hooks, the software seamlessly incorporates external assets, proprietary formats, and platform-specific features.

## External Plugin Architecture

ArmorPaint supports **external plugins** that are compiled directly into the final binary. When a `paint/plugins/external` directory exists, the build system automatically ingests custom C modules, shaders, and assets.

In [`paint/plugins/project.js`](https://github.com/armory3d/armorpaint/blob/main/paint/plugins/project.js), the detection logic looks for this folder and injects the contents into the build pipeline:

```javascript
// paint/plugins/project.js
if (fs_exists(os_cwd() + "/../paint/plugins/external")) {
    project.add_cfiles("external/**");                     // Compile all C files
    project.add_shaders("external/*.kong");               // Compile custom shaders
    project.add_assets("external/assets/*", {destination: "data/{name}"});
    project.add_define("WITH_EXTERNAL");                  // Enable #ifdef blocks
}

```

This mechanism defines the `WITH_EXTERNAL` macro, allowing plugin authors to wrap code in conditional compilation blocks that only activate when external tools are present. The [`paint/plugins/plugins.c`](https://github.com/armory3d/armorpaint/blob/main/paint/plugins/plugins.c) file exposes a C API that these compiled modules use to register functionality with the engine.

## Built-in Import Plugins

ArmorPaint ships with built-in importers for common 3D formats, each wrapping a specialized third-party library. These plugins register callbacks that populate ArmorPaint's internal data structures from external file formats.

### FBX Integration via ufbx

The FBX importer leverages the **ufbx** library to parse Autodesk FBX files. Located in [`paint/plugins/io_fbx/ufbx/ufbx.c`](https://github.com/armory3d/armorpaint/blob/main/paint/plugins/io_fbx/ufbx/ufbx.c), this integration handles complex scene hierarchies and animation data while respecting external file references.

### glTF Integration via cgltf

For Khronos Group glTF files, ArmorPaint uses the **cgltf** single-header library. The implementation in [`paint/plugins/io_gltf/cgltf.c`](https://github.com/armory3d/armorpaint/blob/main/paint/plugins/io_gltf/cgltf.c) supports both embedded and external buffer loading:

```c
// paint/plugins/io_gltf/cgltf.c (excerpt)
cgltf_options opt = {0};
opt.load_external_files = true;          // Enable loading of .bin buffers & images
cgltf_data* data;
cgltf_result result = cgltf_parse_file(&opt, filename, &data);
if (result == cgltf_result_success) {
    cgltf_load_buffers(&opt, data);
    // Convert cgltf data into Armor Paint structures …
}

```

The `load_external_files` flag in the `cgltf_options` struct determines whether the importer fetches external `.bin` buffers and texture images referenced by the glTF manifest. A corresponding `ignore_missing_external_files` flag allows the import to proceed even when auxiliary resources are unavailable.

## Platform-Specific Native Bridges

On Android, ArmorPaint integrates with Java/Kotlin through the **Java Native Interface (JNI)**. The [`base/sources/backends/android_java/org/armory3d/IronActivity.kt`](https://github.com/armory3d/armorpaint/blob/main/base/sources/backends/android_java/org/armory3d/IronActivity.kt) file defines native method signatures that call into the C engine:

```kotlin
// base/sources/backends/android_java/org/armory3d/IronActivity.kt
private external fun nativeIronKeyPress(chars: String)   // Sends key input to C engine

```

This bridge enables the Android app to utilize platform-specific features—such as native file pickers, hardware-accelerated video playback, and system UI conventions—while maintaining a shared C++ core engine across all platforms.

## External Asset Handling and UI Callbacks

Beyond file import, ArmorPaint exposes **external UI callbacks** that allow host applications to inject behavior without recompiling. The UI node system in [`base/sources/iron_ui_nodes.c`](https://github.com/armory3d/armorpaint/blob/main/base/sources/iron_ui_nodes.c) provides hooks like `ui_nodes_on_custom_button` that invoke user-provided functions when specific interface elements are triggered.

For asset workflows, the importers respect external file dependency flags. Whether loading PSD textures, EXR/TIFF high-dynamic-range images, or SVG vector assets, the engine checks library-specific options (such as `ufbx_load_opts` in [`ufbx.h`](https://github.com/armory3d/armorpaint/blob/main/ufbx.h)) to determine whether missing external resources should abort the operation or continue with default values.

## Summary

- **Compile-time plugin system**: Automatically detects and builds C code, shaders, and assets from `paint/plugins/external` via [`project.js`](https://github.com/armory3d/armorpaint/blob/main/project.js)
- **Format-specific importers**: Wraps battle-tested libraries like *ufbx* for FBX and *cgltf* for glTF in `paint/plugins/io_fbx/` and `paint/plugins/io_gltf/`
- **External resource control**: Uses flags like `load_external_files` and `ignore_missing_external_files` to manage dependencies in `cgltf_options` and `ufbx_load_opts`
- **Mobile native bridges**: Implements JNI in [`IronActivity.kt`](https://github.com/armory3d/armorpaint/blob/main/IronActivity.kt) to connect Android Java/Kotlin with the C engine core
- **Runtime extensibility**: Supports external UI callbacks via the node system in [`iron_ui_nodes.c`](https://github.com/armory3d/armorpaint/blob/main/iron_ui_nodes.c)

## Frequently Asked Questions

### How do I create a custom plugin for ArmorPaint?

Create a folder named `external` inside `paint/plugins/` and place your C source files, `.kong` shader files, and asset subdirectories there. The build system in [`paint/plugins/project.js`](https://github.com/armory3d/armorpaint/blob/main/paint/plugins/project.js) automatically compiles these into the binary and defines `WITH_EXTERNAL` for conditional compilation.

### Can ArmorPaint import files that reference external textures?

Yes. Importers for glTF and FBX support external file references through library-specific options. For glTF, set `opt.load_external_files = true` in the `cgltf_options` struct. For FBX, configure `ufbx_load_opts` to handle external geometry caches and texture paths.

### Does ArmorPaint support Android-specific features?

Yes. Through JNI bridges defined in [`base/sources/backends/android_java/org/armory3d/IronActivity.kt`](https://github.com/armory3d/armorpaint/blob/main/base/sources/backends/android_java/org/armory3d/IronActivity.kt), the engine exposes native functions like `nativeIronKeyPress` that allow Java/Kotlin code to send input events and trigger platform-specific features such as file pickers while running the same core engine as the desktop version.

### What file formats can ArmorPaint import natively?

ArmorPaint supports FBX via *ufbx*, glTF via *cgltf*, plus OBJ/MTL, PSD, EXR, TIFF, and SVG through dedicated plugins in `paint/plugins/`. Each importer is modular and can be extended or replaced without modifying the core codebase.