How to Implement Custom Plugins in ArmorPaint: A Complete Developer Guide
ArmorPaint implements a lightweight plugin system where custom functionality is added by placing MiniC script files in the plugins/ folder and registering callbacks via plugin_create() and plugin_notify_on_*() functions.
ArmorPaint's plugin architecture is deliberately minimal yet powerful, allowing developers to extend the 3D painting software without recompiling the engine. According to the armory3d/armorpaint source code, the system uses an embedded MiniC interpreter to evaluate plugin scripts stored in the repository's plugins/ directory. This guide explains how to implement custom plugins in ArmorPaint by leveraging the core API found in paint/sources/plugin.c and configuration management in paint/sources/config.c.
How the ArmorPaint Plugin System Works
ArmorPaint's plugin system operates through a straightforward callback-based architecture. When you implement custom plugins in ArmorPaint, you create MiniC scripts that define a plugin_t object and register function pointers for UI updates, game tick updates, and cleanup operations.
The engine maintains a global map g_plugins that stores active plugin handles, with lifecycle management handled by plugin_start() and plugin_stop() in paint/sources/plugin.c.
The Five-Stage Plugin Lifecycle
Understanding the execution flow is essential for stable plugin development:
-
Script Loading:
plugin_start()constructs the pathplugins/<name>, reads the file into a blob, and executes it viaminic_eval_named(blob, name)at lines 13-22 inpaint/sources/plugin.c. -
Object Creation: Inside the script,
plugin_create()allocates aplugin_tstructure, registers the plugin name ing_plugins, and returns a handle (lines 6-10 inpaint/sources/plugin.c). -
Callback Registration: The script registers event handlers using
plugin_notify_on_ui(),plugin_notify_on_update(), andplugin_notify_on_delete(), which store function pointers in theplugin_tstruct (lines 43-53 inpaint/sources/plugin.c). -
Execution: During the main UI loop in
paint/sources/base.c, ArmorPaint iterates throughg_plugins, invokingon_uiduring frame rendering,on_updateeach tick, andon_deleteduring unload. -
Cleanup:
plugin_stop()looks up the plugin, executes theon_deletecallback if present, frees the MiniC context, and removes the entry from the global map (lines 30-41 inpaint/sources/plugin.c).
Creating Your First ArmorPaint Plugin
To implement custom plugins in ArmorPaint, create a MiniC file in the plugins/ directory. Here is a minimal "Hello World" implementation that adds a UI button and logs messages:
/* File: plugins/hello.c */
/* 1. Create the plugin object */
var plug = plugin_create();
/* 2. Register a UI callback */
plugin_notify_on_ui(plug, function() {
// Add a button to the side panel
var btn = ui_button("Say Hello");
if (ui_clicked(btn)) {
console_log("Hello from my custom plugin!");
}
});
/* 3. Register an update callback (runs every tick) */
plugin_notify_on_update(plug, function() {
// Simple per-frame log (remove in production!)
console_log("Tick …");
});
/* 4. Optional cleanup when disabled */
plugin_notify_on_delete(plug, function() {
console_log("Good-bye from hello plugin");
});
Save this code as plugins/hello.c. The plugin_create() function initializes the plugin context, while plugin_notify_on_ui() injects custom interface elements into ArmorPaint's side panel.
Enabling Your Plugin
Enable your implementation through the Settings interface or programmatically:
- Open Settings → Plugins in ArmorPaint
- Click Enable and type
hello(the filename without extension) - The engine calls
config_enable_plugin()inpaint/sources/config.c(lines 78-89), which pushes the name tog_config->pluginsand invokesplugin_start()
The UI button appears immediately in the side panel, and the console displays "Tick …" every frame until disabled.
Advanced Plugin Development Patterns
For production implementations, study the reference UV Unwrap plugin located at paint/plugins/uv_unwrap/uv_unwrap.c. This demonstrates how to implement custom plugins in ArmorPaint that interact with the engine's mesh processing API.
The UV Unwrap plugin calls proc_uv_unwrap() and manipulates material slots, showing how to access core painting functionality beyond simple UI elements. Key techniques include:
- Mesh Processing: Call engine procedures like
proc_uv_unwrap()directly from MiniC callbacks - State Management: Store persistent data in global script variables between update calls
- Conditional UI: Use
ui_clicked()and related functions to handle user input events
When implementing complex tools, register only the callbacks you need. If your plugin performs background processing without UI elements, omit plugin_notify_on_ui() to reduce frame overhead.
Managing Plugin Lifecycle Programmatically
The configuration system in paint/sources/config.c provides functions for dynamic plugin management:
config_enable_plugin(name): Adds the plugin to the user configuration and triggersplugin_start()config_disable_plugin(name): Removes the plugin fromg_config->pluginsand callsplugin_stop()
These functions are useful for creating plugin managers or dependency systems where one plugin enables others based on project requirements.
Summary
- ArmorPaint uses a file-based plugin system where MiniC scripts placed in
plugins/are evaluated by the MiniC interpreter at runtime plugin_create()inpaint/sources/plugin.callocates theplugin_tobject and registers it in the globalg_pluginsmap- Callbacks are registered via
plugin_notify_on_ui(),plugin_notify_on_update(), andplugin_notify_on_delete()to hook into the main application loop plugin_start()andplugin_stop()handle script evaluation and cleanup, including MiniC context management at lines 13-22 and 30-41 respectively- Enable plugins through Settings → Plugins or programmatically via
config_enable_plugin()inpaint/sources/config.c - Reference the UV Unwrap plugin at
paint/plugins/uv_unwrap/uv_unwrap.cfor advanced mesh processing examples
Frequently Asked Questions
What programming language do ArmorPaint plugins use?
ArmorPaint plugins are written in MiniC, a lightweight C-like scripting language interpreted at runtime. The engine evaluates plugin scripts using minic_eval_named() as implemented in paint/sources/plugin.c, allowing immediate execution without compilation or engine recompilation.
Where should I place my custom plugin files?
Place your MiniC script files in the plugins/ folder within the ArmorPaint directory. The plugin_start() function constructs paths using the pattern plugins/<name> and automatically loads the script, as defined in paint/sources/plugin.c lines 13-22.
How do I add buttons or UI elements to ArmorPaint?
Register a UI callback using plugin_notify_on_ui(plugin_handle, function). Inside the callback function, use UI construction functions like ui_button() and ui_clicked() to create interactive elements. The engine invokes this callback during every UI frame in the main loop defined in paint/sources/base.c.
Can plugins access ArmorPaint's mesh and texture data?
Yes. Advanced plugins like the UV Unwrap example demonstrate access to the engine's procedural mesh API through functions like proc_uv_unwrap(). Plugins can interact with material slots, mesh data, and painting operations by calling the engine's exposed C functions from MiniC callbacks.
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 →