paint: add player export
This commit is contained in:
@@ -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"));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
Reference in New Issue
Block a user