plugins: add make_tilesheet

This commit is contained in:
luboslenco
2026-06-03 15:19:04 +02:00
parent d06de67830
commit 748d6a0832
8 changed files with 228 additions and 40 deletions
+40 -12
View File
@@ -680,6 +680,10 @@ void node_shader_write_frag(void *raw, char *s);
mesh_object_t *context_main_object();
void export_texture_run(char *path, bool bake_material);
void context_select_tool(i32 i);
gpu_texture_t *gpu_create_render_target(i32 width, i32 height, i32 format);
void viewport_capture_screenshot_to(gpu_texture_t *target, float x, float y, float w, float h);
void viewport_save_texture(gpu_texture_t *screenshot);
void project_reimport_mesh_skinned(i32 frame);
extern any_map_t *import_texture_importers;
extern string_array_t *_path_texture_formats;
@@ -880,6 +884,12 @@ void minic_register_builtins() {
static const int ui_node_flag_values[] = {0, 1, 2};
minic_register_enum("ui_node_flag_t", ui_node_flag_names, ui_node_flag_values, 3);
static const char *gpu_texture_format_names[] = {"GPU_TEXTURE_FORMAT_RGBA32", "GPU_TEXTURE_FORMAT_RGBA64", "GPU_TEXTURE_FORMAT_RGBA128",
"GPU_TEXTURE_FORMAT_R8", "GPU_TEXTURE_FORMAT_R16", "GPU_TEXTURE_FORMAT_R32",
"GPU_TEXTURE_FORMAT_D32", "GPU_TEXTURE_FORMAT_RGBA32_BC7"};
static const int gpu_texture_format_values[] = {0, 1, 2, 3, 4, 5, 6, 7};
minic_register_enum("gpu_texture_format_t", gpu_texture_format_names, gpu_texture_format_values, 8);
static const char *ui_handle_fields[] = {"i", "f", "b", "layout", "scroll_offset",
"color", "redraws", "text", "scroll_enabled", "drag_enabled",
"changed", "init", "children"};
@@ -1275,23 +1285,36 @@ void minic_register_builtins() {
minic_struct_field_set_type("config_t", "plugins", "string_array_t");
// context_t
static const char *ctx_fields[] = {"paint_object", "ddirty", "pdirty", "rdirty", "material", "layer",
"brush", "tool", "brush_radius", "brush_opacity", "brush_hardness", "brush_scale",
"brush_angle", "brush_blending", "viewport_mode", "xray"};
static const char *ctx_fields[] = {
"paint_object", "ddirty", "pdirty", "rdirty", "material", "layer", "brush", "tool",
"brush_radius", "brush_opacity", "brush_hardness", "brush_scale", "brush_angle", "brush_blending", "viewport_mode", "xray",
"capturing_screenshot"};
static const int ctx_offsets[] = {
(int)offsetof(context_t, paint_object), (int)offsetof(context_t, ddirty), (int)offsetof(context_t, pdirty),
(int)offsetof(context_t, rdirty), (int)offsetof(context_t, material), (int)offsetof(context_t, layer),
(int)offsetof(context_t, brush), (int)offsetof(context_t, tool), (int)offsetof(context_t, brush_radius),
(int)offsetof(context_t, brush_opacity), (int)offsetof(context_t, brush_hardness), (int)offsetof(context_t, brush_scale),
(int)offsetof(context_t, brush_angle), (int)offsetof(context_t, brush_blending), (int)offsetof(context_t, viewport_mode),
(int)offsetof(context_t, paint_object),
(int)offsetof(context_t, ddirty),
(int)offsetof(context_t, pdirty),
(int)offsetof(context_t, rdirty),
(int)offsetof(context_t, material),
(int)offsetof(context_t, layer),
(int)offsetof(context_t, brush),
(int)offsetof(context_t, tool),
(int)offsetof(context_t, brush_radius),
(int)offsetof(context_t, brush_opacity),
(int)offsetof(context_t, brush_hardness),
(int)offsetof(context_t, brush_scale),
(int)offsetof(context_t, brush_angle),
(int)offsetof(context_t, brush_blending),
(int)offsetof(context_t, viewport_mode),
(int)offsetof(context_t, xray),
(int)offsetof(context_t, capturing_screenshot),
};
static const minic_type_t ctx_types[] = {MINIC_T_PTR, MINIC_T_INT, MINIC_T_INT, MINIC_T_INT, MINIC_T_PTR, MINIC_T_PTR, MINIC_T_PTR, MINIC_T_INT,
MINIC_T_FLOAT, MINIC_T_FLOAT, MINIC_T_FLOAT, MINIC_T_FLOAT, MINIC_T_FLOAT, MINIC_T_INT, MINIC_T_INT, MINIC_T_INT};
static const minic_type_t ctx_types[] = {MINIC_T_PTR, MINIC_T_INT, MINIC_T_INT, MINIC_T_INT, MINIC_T_PTR, MINIC_T_PTR,
MINIC_T_PTR, MINIC_T_INT, MINIC_T_FLOAT, MINIC_T_FLOAT, MINIC_T_FLOAT, MINIC_T_FLOAT,
MINIC_T_FLOAT, MINIC_T_INT, MINIC_T_INT, MINIC_T_INT, MINIC_T_BOOL};
static const minic_type_t ctx_deref_types[] = {MINIC_T_PTR, MINIC_T_INT, MINIC_T_INT, MINIC_T_INT, MINIC_T_PTR, MINIC_T_PTR,
MINIC_T_PTR, MINIC_T_INT, MINIC_T_FLOAT, MINIC_T_FLOAT, MINIC_T_FLOAT, MINIC_T_FLOAT,
MINIC_T_FLOAT, MINIC_T_INT, MINIC_T_INT, MINIC_T_INT};
minic_register_struct_native("context_t", ctx_fields, ctx_offsets, ctx_types, ctx_deref_types, 16);
MINIC_T_FLOAT, MINIC_T_INT, MINIC_T_INT, MINIC_T_INT, MINIC_T_BOOL};
minic_register_struct_native("context_t", ctx_fields, ctx_offsets, ctx_types, ctx_deref_types, 17);
minic_struct_set_size("context_t", (int)sizeof(context_t));
minic_struct_field_set_type("context_t", "paint_object", "mesh_object_t");
@@ -2030,6 +2053,11 @@ void minic_register_builtins() {
R(context_main_object, "p()");
R(export_texture_run, "v(p,i)");
R(context_select_tool, "v(i)");
R(gpu_create_render_target, "p(i,i,i)");
R(viewport_capture_screenshot_to, "v(p,f,f,f,f)");
R(viewport_save_texture, "v(p)");
R(project_reimport_mesh_skinned, "v(i)");
R(iron_delay_idle_sleep, "v()");
// json
R(json_parse, "p(p)");
+119
View File
@@ -0,0 +1,119 @@
#include "global.h"
void *plugin;
ui_handle_t *h0;
ui_handle_t *h1;
ui_handle_t *h2;
ui_handle_t *h3;
ui_handle_t *h4;
void *tilesheet;
int baking;
int tile_size;
int columns;
int frames;
int frame;
int col;
int row;
int wait;
int skinning;
int reimported;
void on_update() {
if (!baking) {
return;
}
iron_delay_idle_sleep();
if (frame < frames) {
if (skinning && !reimported) {
project_reimport_mesh_skinned(frame);
reimported = 1;
wait = 2; // Wait for re-import and re-render
return;
}
if (wait > 0) {
wait = wait - 1;
return;
}
float x = col * tile_size;
float y = row * tile_size;
viewport_capture_screenshot_to(tilesheet, x, y, tile_size, tile_size);
frame = frame + 1;
col = col + 1;
if (col >= columns) {
col = 0;
row = row + 1;
}
reimported = 0;
}
else {
viewport_save_texture(tilesheet);
context_t *c = script_get_context();
c->capturing_screenshot = false;
c->ddirty = 2;
gc_unroot(tilesheet);
tilesheet = NULL;
baking = 0;
}
}
void on_ui() {
if (ui_panel(h0, "Make Tilesheet", false, false, false)) {
ui_slider(h1, "Tile Size", 0, 512, true, 1, true, UI_ALIGN_LEFT, true);
ui_slider(h2, "Columns", 0, 64, true, 1, true, UI_ALIGN_LEFT, true);
ui_slider(h3, "Frames", 0, 1024, true, 1, true, UI_ALIGN_LEFT, true);
ui_check(h4, "Skinning", "");
if (ui_button("Bake", UI_ALIGN_CENTER, "") && !baking) {
tile_size = h1->f;
columns = h2->f;
frames = h3->f;
skinning = h4->b;
// Square atlas
int size = tile_size * columns;
tilesheet = gpu_create_render_target(size, size, GPU_TEXTURE_FORMAT_RGBA32);
gc_root(tilesheet);
frame = 0;
col = 0;
row = 0;
wait = 2;
reimported = 0;
baking = 1;
context_t *c = script_get_context();
c->capturing_screenshot = true;
c->ddirty = 2;
}
}
}
void main() {
plugin = plugin_create();
h0 = ui_handle_create();
h1 = ui_handle_create();
h1->f = 256;
h2 = ui_handle_create();
h2->f = 8;
h3 = ui_handle_create();
h3->f = 64;
h4 = ui_handle_create();
h4->b = 0;
tilesheet = NULL;
baking = 0;
gc_root(plugin);
gc_root(h0);
gc_root(h1);
gc_root(h2);
gc_root(h3);
gc_root(h4);
plugin_notify_on_ui(plugin, on_ui);
plugin_notify_on_update(plugin, on_update);
}
+5 -2
View File
@@ -302,7 +302,7 @@ void render_path_preview_commands_decal();
node_shader_context_t *make_paint_run(material_t *data, material_context_t *matcon);
node_shader_context_t *make_mesh_preview_run(material_t *data, material_context_t *matcon);
void import_audio_run(char *path);
void import_mesh_run(char *path, bool _clear_layers, bool replace_existing);
void import_mesh_run(char *path, bool _clear_layers, bool replace_existing, bool keep_camera);
void import_mesh_finish_import(void *_);
void import_mesh_make_mesh(raw_mesh_t *mesh);
void import_mesh_add_mesh(raw_mesh_t *mesh);
@@ -336,6 +336,8 @@ void viewport_orbit_opposite();
void viewport_zoom(f32 f);
void viewport_update_camera_type(i32 camera_type);
void viewport_capture_screenshot();
void viewport_capture_screenshot_to(gpu_texture_t *target, float x, float y, float w, float h);
void viewport_save_texture(gpu_texture_t *screenshot);
void viewport_capture_video_begin();
void viewport_capture_video_end();
void tab_fonts_draw(ui_handle_t *htab);
@@ -385,8 +387,9 @@ void project_import_material();
void project_import_brush();
void project_import_mesh(bool replace_existing, void (*done)(void));
void project_append_mesh();
void project_import_mesh_box(char *path, bool replace_existing, bool clear_layers, void (*done)(void));
void project_import_mesh_box(char *path, bool replace_existing, bool clear_layers, bool keep_camera, void (*done)(void));
void project_reimport_mesh();
void project_reimport_mesh_skinned(int frame);
void project_unwrap_mesh_box();
void project_import_asset(char *filters, bool hdr_as_envmap);
void project_import_swatches(bool replace_existing);
+1 -1
View File
@@ -35,7 +35,7 @@ void import_asset_run(char *path, f32 drop_x, f32 drop_y, bool show_box, bool hd
}
if (path_is_mesh(path)) {
show_box ? project_import_mesh_box(path, true, true, NULL) : import_mesh_run(path, true, true);
show_box ? project_import_mesh_box(path, true, true, false, NULL) : import_mesh_run(path, true, true, false);
if (drop_x > 0) {
ui_box_click_to_hide = false; // Prevent closing when going back to window after drag and drop
}
+9 -1
View File
@@ -3,8 +3,10 @@
bool import_mesh_clear_layers = true;
bool import_mesh_needs_unwrap = false;
bool import_mesh_no_reset = false;
bool import_mesh_no_scale = false;
void import_mesh_run(char *path, bool _clear_layers, bool replace_existing) {
void import_mesh_run(char *path, bool _clear_layers, bool replace_existing, bool keep_camera) {
if (!path_is_mesh(path)) {
if (!context_enable_import_plugin(path)) {
console_error(strings_unknown_asset_format());
@@ -13,6 +15,7 @@ void import_mesh_run(char *path, bool _clear_layers, bool replace_existing) {
}
import_mesh_clear_layers = _clear_layers;
import_mesh_no_reset = keep_camera;
g_context->layer_filter = 0;
char *p = to_lower_case(path);
@@ -98,7 +101,10 @@ void import_mesh_finish_import(void *_) {
g_context->merged_object->base->visible = true;
}
if (!import_mesh_no_scale) {
viewport_scale_to_bounds(2.0);
}
import_mesh_no_scale = false;
if (string_equals(g_context->paint_object->base->name, "")) {
g_context->paint_object->base->name = "Object";
@@ -160,7 +166,9 @@ void import_mesh_make_mesh(raw_mesh_t *mesh) {
g_context->paint_object = context_main_object();
context_select_paint_object(context_main_object());
if (!import_mesh_no_reset) {
viewport_reset();
}
for (i32 i = 0; i < project_paint_objects->length; ++i) {
mesh_object_t *p = project_paint_objects->buffer[i];
@@ -22,7 +22,7 @@ void image_to_3d_mesh_node_check_result(ui_node_t *node) {
// map_set(neural_node_results, node.id, result);
ui_nodes_hwnd->redraws = 2;
ui_view2d_hwnd->redraws = 2;
project_import_mesh_box(file, true, true, NULL);
project_import_mesh_box(file, true, true, false, NULL);
}
sys_remove_update(image_to_3d_mesh_node_check_result);
}
+17 -4
View File
@@ -7,6 +7,7 @@ void (*_project_import_mesh_done)(void);
char *_project_import_mesh_box_path;
bool _project_import_mesh_box_replace_existing;
bool _project_import_mesh_box_clear_layers;
bool _project_import_mesh_box_keep_camera;
void (*_project_import_mesh_box_done)(void);
bool _project_import_asset_hdr_as_envmap;
bool _project_import_swatches_replace_existing;
@@ -413,7 +414,7 @@ void project_import_brush() {
}
void project_import_mesh_on_file_picked(char *path) {
project_import_mesh_box(path, _project_import_mesh_replace_existing, true, _project_import_mesh_done);
project_import_mesh_box(path, _project_import_mesh_replace_existing, true, false, _project_import_mesh_done);
}
void project_import_mesh(bool replace_existing, void (*done)(void)) {
@@ -436,6 +437,7 @@ void project_import_mesh_box_draw() {
char *path = _project_import_mesh_box_path;
bool replace_existing = _project_import_mesh_box_replace_existing;
bool clear_layers = _project_import_mesh_box_clear_layers;
bool keep_camera = _project_import_mesh_box_keep_camera;
void (*done)(void) = _project_import_mesh_box_done;
if (ends_with(to_lower_case(path), ".obj") || ends_with(to_lower_case(path), ".fbx")) {
@@ -488,7 +490,7 @@ void project_import_mesh_box_draw() {
console_toast(tr("Importing mesh"));
#endif
import_mesh_run(path, clear_layers, replace_existing);
import_mesh_run(path, clear_layers, replace_existing, keep_camera);
if (done != NULL) {
done();
}
@@ -498,12 +500,13 @@ void project_import_mesh_box_draw() {
}
}
void project_import_mesh_box(char *path, bool replace_existing, bool clear_layers, void (*done)(void)) {
void project_import_mesh_box(char *path, bool replace_existing, bool clear_layers, bool keep_camera, void (*done)(void)) {
gc_unroot(_project_import_mesh_box_path);
_project_import_mesh_box_path = string_copy(path);
gc_root(_project_import_mesh_box_path);
_project_import_mesh_box_replace_existing = replace_existing;
_project_import_mesh_box_clear_layers = clear_layers;
_project_import_mesh_box_keep_camera = keep_camera;
gc_unroot(_project_import_mesh_box_done);
_project_import_mesh_box_done = done;
gc_root(_project_import_mesh_box_done);
@@ -513,13 +516,23 @@ void project_import_mesh_box(char *path, bool replace_existing, bool clear_layer
void project_reimport_mesh() {
if (project_mesh_assets != NULL && project_mesh_assets->length > 0 && iron_file_exists(project_mesh_assets->buffer[0])) {
project_import_mesh_box(project_mesh_assets->buffer[0], true, false, NULL);
project_import_mesh_box(project_mesh_assets->buffer[0], true, false, true, NULL);
}
else {
project_import_asset(NULL, true);
}
}
void project_reimport_mesh_skinned(int frame) {
extern bool import_mesh_no_scale;
if (project_mesh_assets != NULL && project_mesh_assets->length > 0 && iron_file_exists(project_mesh_assets->buffer[0])) {
plugins_skinning_frame = frame;
import_mesh_no_scale = true;
import_mesh_run(project_mesh_assets->buffer[0], false, true, true);
plugins_skinning_frame = -1;
}
}
void project_unwrap_mesh(raw_mesh_t *mesh, void (*done)(raw_mesh_t *)) {
char *f = "uv_unwrap";
void (*cb)(void *mesh) = any_map_get(util_mesh_unwrappers, f);
+31 -14
View File
@@ -93,20 +93,8 @@ void viewport_update_camera_type(i32 camera_type) {
g_context->ddirty = 2;
}
void viewport_capture_screenshot() {
render_target_t *rt = any_map_get(render_path_render_targets, "last");
gpu_texture_t *tex = rt->_image;
// let screenshot: gpu_texture_t = gpu_create_render_target(512, 512);
// let r: f32 = sys_w() / sys_h();
// draw_begin(screenshot);
// draw_scaled_image(tex, -(512 * r - 512) / 2, 0, 512 * r, 512);
// draw_end();
gpu_texture_t *screenshot = gpu_create_render_target(tex->width, tex->height, GPU_TEXTURE_FORMAT_RGBA32);
draw_begin(screenshot, false, 0);
draw_image(tex, 0, 0);
draw_end();
void viewport_save_texture(gpu_texture_t *screenshot) {
// Save into the textures tab
if (g_project->packed_assets == NULL) {
g_project->packed_assets = any_array_create_from_raw((void *[]){}, 0);
}
@@ -126,6 +114,35 @@ void viewport_capture_screenshot() {
any_array_push(g_project->packed_assets, pa);
any_map_set(data_cached_images, abs, screenshot);
import_texture_run(abs, true);
}
void viewport_capture_screenshot() {
render_target_t *rt = any_map_get(render_path_render_targets, "last");
gpu_texture_t *tex = rt->_image;
gpu_texture_t *screenshot = gpu_create_render_target(tex->width, tex->height, GPU_TEXTURE_FORMAT_RGBA32);
draw_begin(screenshot, false, 0);
draw_image(tex, 0, 0);
draw_end();
viewport_save_texture(screenshot);
g_context->capturing_screenshot = false;
g_context->ddirty = 2;
}
void viewport_capture_screenshot_to(gpu_texture_t *target, float x, float y, float w, float h) {
render_target_t *rt = any_map_get(render_path_render_targets, "last");
gpu_texture_t *tex = rt->_image;
// Crop the viewport texture to a square
float size = tex->width < tex->height ? tex->width : tex->height;
float sx = (tex->width - size) / 2.0f;
float sy = (tex->height - size) / 2.0f;
draw_begin(target, false, 0);
draw_scaled_sub_image(tex, sx, sy, size, size, x, y, w, h);
draw_end();
g_context->capturing_screenshot = false;
g_context->ddirty = 2;
}