paint: add player export

This commit is contained in:
luboslenco
2026-03-17 20:26:09 +01:00
parent b039927e09
commit 740f7df0fd
6 changed files with 169 additions and 4 deletions
+36
View File
@@ -638,3 +638,39 @@ char *box_export_preset_to_json(export_preset_t *p) {
json_encode_end_array();
return json_encode_end();
}
void box_export_show_player_box_path_picked(char *path) {
char *f = ui_files_filename;
if (string_equals(f, "")) {
f = string_copy(tr("untitled"));
}
export_player_run(string("%s%s%s", path, PATH_SEP, f));
}
void box_export_show_player_box() {
ui_handle_t *htab = ui_handle(__ID__);
bool tab_vertical = config_raw->touch_ui;
if (ui_tab(htab, tr("Export Player"), tab_vertical, -1, false)) {
ui_handle_t *h_export_player_target = ui_handle(__ID__);
string_t_array_t *export_player_target_combo = any_array_create_from_raw(
(void *[]){
"Web",
},
1);
ui_combo(h_export_player_target, export_player_target_combo, tr("Target"), true, UI_ALIGN_LEFT, true);
ui_row2();
if (ui_icon_button(tr("Cancel"), ICON_CLOSE, UI_ALIGN_CENTER)) {
ui_box_hide();
}
if (ui_icon_button(tr("Export"), ICON_CHECK, UI_ALIGN_CENTER)) {
ui_box_hide();
ui_files_show("html", true, false, &box_export_show_player_box_path_picked);
}
}
}
void box_export_show_player() {
ui_box_show_custom(&box_export_show_player_box, 420, 260, NULL, true, tr("Export"));
}
+123
View File
@@ -0,0 +1,123 @@
#include "global.h"
static char *export_player_readme = "\
To start the player locally, use 'python -m http.server'\
and open http://localhost:8000/ in the browser.\n\
";
static char *export_player_index = "\
<!DOCTYPE html>\n\
<html lang=\"en\">\n\
<head>\n\
<meta charset=\"UTF-8\">\n\
<title>Player</title>\n\
<style>\n\
body, html {\n\
margin: 0;\n\
padding: 0;\n\
width: 100%;\n\
height: 100%;\n\
overflow: hidden;\n\
background-color: #222;\n\
font-family: system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n\
}\n\
#iron {\n\
display: block;\n\
width: 100vw;\n\
height: 100vh;\n\
}\n\
.modal {\n\
position: fixed;\n\
top: 0;\n\
left: 0;\n\
width: 100%;\n\
height: 100%;\n\
background: rgba(0, 0, 0, 0.7);\n\
display: none;\n\
align-items: center;\n\
justify-content: center;\n\
z-index: 9999;\n\
}\n\
.modal .modal-content {\n\
background: #2a2a2a;\n\
padding: 32px 40px;\n\
border-radius: 12px;\n\
max-width: 420px;\n\
text-align: center;\n\
color: #fff;\n\
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.6);\n\
border: 1px solid #444;\n\
}\n\
.modal button {\n\
margin-top: 24px;\n\
padding: 10px 24px;\n\
background: #444;\n\
color: #fff;\n\
border: none;\n\
border-radius: 6px;\n\
font-size: 15px;\n\
cursor: pointer;\n\
transition: background 0.2s;\n\
}\n\
.modal button:hover {\n\
background: #555;\n\
}\n\
</style>\n\
</head>\n\
<body>\n\
<canvas id=\"iron\" tabindex=\"0\"></canvas>\n\
<div id=\"webgpu-modal\" class=\"modal\">\n\
<div class=\"modal-content\">\n\
<h2>Player</h2>\n\
<p>This browser does not support WebGPU or it is disabled.</p>\n\
</div>\n\
</div>\n\
<script src=\"start.js\"></script>\n\
<script>\n\
async function check_webgpu() {\n\
const modal = document.getElementById('webgpu-modal');\n\
if (!navigator.gpu) {\n\
modal.style.display = 'flex';\n\
return;\n\
}\n\
const adapter = await navigator.gpu.requestAdapter();\n\
if (!adapter) {\n\
modal.style.display = 'flex';\n\
return;\n\
}\n\
const device = await adapter.requestDevice();\n\
if (!device) {\n\
modal.style.display = 'flex';\n\
}\n\
}\n\
window.addEventListener('DOMContentLoaded', () => {\n\
check_webgpu();\n\
});\n\
</script>\n\
</body>\n\
</html>\n\
";
static void export_player_run_on_download(char *url, buffer_t *ab) {}
void export_player_run(char *path) {
char *path_base = path_base_dir(path);
char *_project_filepath = string_copy(project_filepath);
project_filepath = string("%s/%s", path_base, "start.arm");
export_arm_run_project();
project_filepath = _project_filepath;
char *start_js = string("%s/start.js", path_base);
iron_file_download("https://armorpaint.app/start.js", &export_player_run_on_download, 0, start_js);
char *start_wasm = string("%s/start.wasm", path_base);
iron_file_download("https://armorpaint.app/start.wasm", &export_player_run_on_download, 0, start_wasm);
char *readme_txt = string("%s/readme.txt", path_base);
iron_file_save_bytes(readme_txt, sys_string_to_buffer(export_player_readme), 0);
char *index_html = string("%s/index.html", path_base);
iron_file_save_bytes(index_html, sys_string_to_buffer(export_player_index), 0);
}
+2
View File
@@ -133,6 +133,7 @@ void box_export_parse_preset();
void box_export_new_preset(char *name);
void box_export_save_preset();
char *box_export_preset_to_json(export_preset_t *p);
void box_export_show_player();
void import_blend_mesh_ui();
void import_blend_mesh_run(char *path, bool replace_existing);
void tab_console_draw(ui_handle_t *htab);
@@ -755,6 +756,7 @@ void console_error(char *s);
void console_log(char *s);
void console_trace(char *s);
void export_mesh_run(char *path, mesh_object_t_array_t *paint_objects, bool apply_disp, bool merge_vertices);
void export_player_run(char *path);
void camera_init();
void camera_update(void *_);
f32 camera_distance();
+1
View File
@@ -105,6 +105,7 @@
#include "export_exr.c"
#include "export_mesh.c"
#include "export_obj.c"
#include "export_player.c"
#include "export_texture.c"
#include "geom.c"
#include "gizmo.c"
+3 -3
View File
@@ -28,7 +28,7 @@ void tab_plugins_draw(ui_handle_t *htab) {
}
}
#ifdef is_debug
#ifdef is_debug
string_t_array_t *rt_keys = map_keys(render_path_render_targets);
array_sort(rt_keys, NULL);
for (i32 i = 0; i < rt_keys->length; ++i) {
@@ -36,12 +36,12 @@ void tab_plugins_draw(ui_handle_t *htab) {
ui_text(rt_keys->buffer[i], UI_ALIGN_LEFT, 0x00000000);
ui_image(rt->_image, 0xffffffff, -1.0);
}
#endif
#endif
}
}
void plugin_uv_unwrap_button() {
void * cb = any_map_get(util_mesh_unwrappers, "uv_unwrap.js"); // JSValue * -> (a: raw_mesh_t)=>void
void *cb = any_map_get(util_mesh_unwrappers, "uv_unwrap.js"); // JSValue * -> (a: raw_mesh_t)=>void
for (i32 i = 0; i < project_paint_objects->length; ++i) {
mesh_data_t *md = project_paint_objects->buffer[i]->data;
raw_mesh_t *mesh =
+4 -1
View File
@@ -403,7 +403,7 @@ void ui_menubar_draw_category_items() {
}
ui_menu_separator();
if (ui_menu_sub_button(ui_handle(__ID__), tr("Export"))) {
ui_menu_sub_begin(3);
ui_menu_sub_begin(config_raw->experimental ? 4 : 3);
if (ui_menu_button(tr("Textures..."), any_map_get(config_keymap, "file_export_textures_as"), ICON_IMAGE)) {
context_raw->layers_export = EXPORT_MODE_VISIBLE;
box_export_show_textures();
@@ -415,6 +415,9 @@ void ui_menubar_draw_category_items() {
context_raw->export_mesh_index = 0; // All
box_export_show_mesh();
}
if (config_raw->experimental && ui_menu_button(tr("Player..."), "", ICON_PLAY)) {
box_export_show_player();
}
ui_menu_sub_end();
}
if (ui_menu_button(tr("Bake Material..."), "", ICON_BAKE)) {