Files
armorpaint/base/sources/project.ts
T
luboslenco 298c4b3d3e Build fixes
2024-10-16 23:51:15 +02:00

869 lines
26 KiB
TypeScript

let project_raw: project_format_t = {};
let project_filepath: string = "";
let project_assets: asset_t[] = [];
let project_asset_names: string[] = [];
let project_asset_id: i32 = 0;
let project_mesh_assets: string[] = [];
let project_material_groups: node_group_t[] = [];
let project_paint_objects: mesh_object_t[] = null;
let project_asset_map: map_t<i32, any> = map_create(); // image_t | font_t
let project_mesh_list: string[] = null;
///if (is_paint || is_sculpt)
let project_materials: slot_material_t[] = null;
let project_brushes: slot_brush_t[] = null;
let project_layers: slot_layer_t[] = null;
let project_fonts: slot_font_t[] = null;
let project_atlas_objects: i32[] = null;
let project_atlas_names: string[] = null;
///end
///if is_lab
let project_material_data: material_data_t = null; ////
let project_materials: any[] = null; ////
let project_nodes: ui_nodes_t;
let project_canvas: ui_node_canvas_t;
let project_default_canvas: buffer_t = null;
///end
function project_open() {
ui_files_show("arm", false, false, function (path: string) {
if (!ends_with(path, ".arm")) {
console_error(strings_error0());
return;
}
let current: image_t = _g2_current;
let g2_in_use: bool = _g2_in_use;
if (g2_in_use) g2_end();
import_arm_run_project(path);
if (g2_in_use) g2_begin(current);
});
}
let _project_save_and_quit: bool;
function project_save(save_and_quit: bool = false) {
if (project_filepath == "") {
///if arm_ios
let document_directory: string = iron_save_dialog("", "");
document_directory = substring(document_directory, 0, document_directory.length - 8); // Strip /"untitled"
project_filepath = document_directory + "/" + sys_title() + ".arm";
///elseif arm_android
project_filepath = iron_save_path() + "/" + sys_title() + ".arm";
///else
project_save_as(save_and_quit);
return;
///end
}
///if (arm_windows || arm_linux || arm_macos)
let filename: string = substring(project_filepath, string_last_index_of(project_filepath, path_sep) + 1, project_filepath.length - 4);
sys_title_set(filename + " - " + manifest_title);
///end
_project_save_and_quit = save_and_quit;
app_notify_on_init(function () {
export_arm_run_project();
if (_project_save_and_quit) {
sys_stop();
}
});
}
function project_save_as(save_and_quit: bool = false) {
_project_save_and_quit = save_and_quit;
ui_files_show("arm", true, false, function (path: string) {
let f: string = ui_files_filename;
if (f == "") {
f = tr("untitled");
}
project_filepath = path + path_sep + f;
if (!ends_with(project_filepath, ".arm")) {
project_filepath += ".arm";
}
project_save(_project_save_and_quit);
});
}
function project_new_box() {
///if (is_paint || is_sculpt)
ui_box_show_custom(function (ui: ui_t) {
if (ui_tab(ui_handle(__ID__), tr("New Project"))) {
if (project_mesh_list == null) {
project_mesh_list = file_read_directory(path_data() + path_sep + "meshes");
for (let i: i32 = 0; i < project_mesh_list.length; ++i) {
let s: string = project_mesh_list[i];
project_mesh_list[i] = substring(project_mesh_list[i], 0, s.length - 4); // Trim .arm
}
array_insert(project_mesh_list, 0, "plane");
array_insert(project_mesh_list, 0, "sphere");
array_insert(project_mesh_list, 0, "rounded_cube");
}
let row: f32[] = [0.5, 0.5];
ui_row(row);
let h_project_type: ui_handle_t = ui_handle(__ID__);
if (h_project_type.init) {
h_project_type.position = context_raw.project_type;
}
context_raw.project_type = ui_combo(h_project_type, project_mesh_list, tr("Template"), true);
let h_project_aspect_ratio: ui_handle_t = ui_handle(__ID__);
if (h_project_aspect_ratio.init) {
h_project_aspect_ratio.position = context_raw.project_aspect_ratio;
}
let project_aspect_ratio_combo: string[] = ["1:1", "2:1", "1:2"];
context_raw.project_aspect_ratio = ui_combo(h_project_aspect_ratio, project_aspect_ratio_combo, tr("Aspect Ratio"), true);
_ui_end_element();
ui_row(row);
if (ui_button(tr("Cancel"))) {
ui_box_hide();
}
if (ui_button(tr("OK")) || ui.is_return_down) {
project_new();
viewport_scale_to_bounds();
ui_box_hide();
}
}
});
///end
///if is_lab
project_new();
viewport_scale_to_bounds();
///end
}
function project_new(reset_layers: bool = true) {
///if (arm_windows || arm_linux || arm_macos)
sys_title_set(manifest_title);
///end
project_filepath = "";
///if (is_paint || is_sculpt)
if (context_raw.merged_object != null) {
mesh_object_remove(context_raw.merged_object);
data_delete_mesh(context_raw.merged_object.data._.handle);
context_raw.merged_object = null;
}
context_raw.layer_preview_dirty = true;
context_raw.layer_filter = 0;
project_mesh_assets = [];
///end
viewport_reset();
context_raw.paint_object = context_main_object();
context_select_paint_object(context_main_object());
for (let i: i32 = 1; i < project_paint_objects.length; ++i) {
let p: mesh_object_t = project_paint_objects[i];
if (p == context_raw.paint_object) {
continue;
}
data_delete_mesh(p.data._.handle);
mesh_object_remove(p);
}
let meshes: mesh_object_t[] = scene_meshes;
let len: i32 = meshes.length;
for (let i: i32 = 0; i < len; ++i) {
let m: mesh_object_t = meshes[len - i - 1];
if (array_index_of(context_raw.project_objects, m) == -1 &&
m.base.name != ".ParticleEmitter" &&
m.base.name != ".Particle") {
data_delete_mesh(m.data._.handle);
mesh_object_remove(m);
}
}
let handle: string = context_raw.paint_object.data._.handle;
if (handle != "SceneSphere" && handle != "ScenePlane") {
data_delete_mesh(handle);
}
if (context_raw.project_type != project_model_t.ROUNDED_CUBE) {
let raw: mesh_data_t = null;
if (context_raw.project_type == project_model_t.SPHERE || context_raw.project_type == project_model_t.TESSELLATED_PLANE) {
let mesh: raw_mesh_t = context_raw.project_type == project_model_t.SPHERE ?
geom_make_uv_sphere(1, 512, 256) :
geom_make_plane(1, 1, 512, 512);
mesh.name = "Tessellated";
raw = import_mesh_raw_mesh(mesh);
///if is_sculpt
app_notify_on_next_frame(function (mesh: raw_mesh_t) {
let f32a: f32_array_t = f32_array_create(config_get_texture_res_x() * config_get_texture_res_y() * 4);
for (let i: i32 = 0; i < math_floor(mesh.inda.length); ++i) {
let index: i32 = mesh.inda[i];
f32a[i * 4] = mesh.posa[index * 4] / 32767;
f32a[i * 4 + 1] = mesh.posa[index * 4 + 1] / 32767;
f32a[i * 4 + 2] = mesh.posa[index * 4 + 2] / 32767;
f32a[i * 4 + 3] = 1.0;
}
let imgmesh: image_t = image_from_bytes(f32a, config_get_texture_res_x(), config_get_texture_res_y(), tex_format_t.RGBA128);
let texpaint: image_t = project_layers[0].texpaint;
g2_begin(texpaint);
g2_set_pipeline(base_pipe_copy128);
g2_draw_scaled_image(imgmesh, 0, 0, config_get_texture_res_x(), config_get_texture_res_y());
g2_set_pipeline(null);
g2_end();
}, mesh);
///end
}
else {
let b: buffer_t = data_get_blob("meshes/" + project_mesh_list[context_raw.project_type] + ".arm");
let scene: scene_t = armpack_decode(b);
raw = scene.mesh_datas[0];
}
let md: mesh_data_t = mesh_data_create(raw);
map_set(data_cached_meshes, "SceneTessellated", md);
if (context_raw.project_type == project_model_t.TESSELLATED_PLANE) {
viewport_set_view(0, 0, 0.75, 0, 0, 0); // Top
}
}
let n: string = context_raw.project_type == project_model_t.ROUNDED_CUBE ? ".Cube" : "Tessellated";
let md: mesh_data_t = data_get_mesh("Scene", n);
let current: image_t = _g2_current;
let g2_in_use: bool = _g2_in_use;
if (g2_in_use) g2_end();
///if is_paint
context_raw.picker_mask_handle.position = picker_mask_t.NONE;
///end
mesh_object_set_data(context_raw.paint_object, md);
context_raw.paint_object.base.transform.scale = vec4_create(1, 1, 1);
transform_build_matrix(context_raw.paint_object.base.transform);
context_raw.paint_object.base.name = n;
project_paint_objects = [context_raw.paint_object];
///if (is_paint || is_sculpt)
while (project_materials.length > 0) {
slot_material_unload(array_pop(project_materials));
}
///end
let m: material_data_t = data_get_material("Scene", "Material");
///if (is_paint || is_sculpt)
array_push(project_materials, slot_material_create(m));
///end
///if is_lab
project_material_data = m;
///end
///if (is_paint || is_sculpt)
context_raw.material = project_materials[0];
///end
ui_nodes_hwnd.redraws = 2;
ui_nodes_group_stack = [];
project_material_groups = [];
///if (is_paint || is_sculpt)
project_brushes = [slot_brush_create()];
context_raw.brush = project_brushes[0];
project_fonts = [slot_font_create("default.ttf", base_font)];
context_raw.font = project_fonts[0];
///end
project_set_default_swatches();
context_raw.swatch = project_raw.swatches[0];
context_raw.picked_color = make_swatch();
context_raw.color_picker_callback = null;
history_reset();
make_material_parse_paint_material();
make_material_parse_brush();
///if (is_paint || is_sculpt)
util_render_make_material_preview();
///end
for (let i: i32 = 0; i < project_assets.length; ++i) {
let a: asset_t = project_assets[i];
data_delete_image(a.file);
}
project_assets = [];
project_asset_names = [];
project_asset_map = map_create();
project_asset_id = 0;
project_raw.packed_assets = [];
context_raw.ddirty = 4;
///if (is_paint || is_sculpt)
ui_base_hwnds[tab_area_t.SIDEBAR0].redraws = 2;
ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2;
///end
if (reset_layers) {
///if (is_paint || is_sculpt)
let aspect_ratio_changed: bool = project_layers[0].texpaint.width != config_get_texture_res_x() || project_layers[0].texpaint.height != config_get_texture_res_y();
while (project_layers.length > 0) {
slot_layer_unload(array_pop(project_layers));
}
let layer: slot_layer_t = slot_layer_create();
array_push(project_layers, layer);
context_set_layer(layer);
if (aspect_ratio_changed) {
app_notify_on_init(base_resize_layers);
}
///end
app_notify_on_init(base_init_layers);
}
if (g2_in_use) g2_begin(current);
context_raw.saved_envmap = null;
context_raw.envmap_loaded = false;
scene_world._.envmap = context_raw.empty_envmap;
scene_world.envmap = "World_radiance.k";
context_raw.show_envmap_handle.selected = context_raw.show_envmap = false;
scene_world._.radiance = context_raw.default_radiance;
scene_world._.radiance_mipmaps = context_raw.default_radiance_mipmaps;
scene_world._.irradiance = context_raw.default_irradiance;
scene_world.strength = 4.0;
///if (is_paint || is_sculpt)
context_init_tool();
///end
///if (arm_direct3d12 || arm_vulkan || arm_metal)
render_path_raytrace_ready = false;
///end
}
///if (is_paint || is_sculpt)
function project_import_material() {
ui_files_show("arm,blend", false, true, function (path: string) {
ends_with(path, ".blend") ?
import_blend_material_run(path) :
import_arm_run_material(path);
});
}
function project_create_node_link(links: ui_node_link_t[], from_id: i32, from_socket: i32, to_id: i32, to_socket: i32): ui_node_link_t {
let link: ui_node_link_t = {
id: ui_next_link_id(links),
from_id: from_id,
from_socket: from_socket,
to_id: to_id,
to_socket: to_socket
};
return link;
}
function project_import_brush() {
let formats: string = string_array_join(path_texture_formats, ",");
ui_files_show("arm," + formats, false, true, function (path: string) {
// Create brush from texture
if (path_is_texture(path)) {
// Import texture
import_asset_run(path);
let asset_index: i32 = 0;
for (let i: i32 = 0; i < project_assets.length; ++i) {
if (project_assets[i].file == path) {
asset_index = i;
break;
}
}
// Create a new brush
context_raw.brush = slot_brush_create();
array_push(project_brushes, context_raw.brush);
// Create and link image node
let n: ui_node_t = nodes_brush_create_node("TEX_IMAGE");
n.x = 83;
n.y = 340;
n.buttons[0].default_value = f32_array_create_x(asset_index);
let links: ui_node_link_t[] = context_raw.brush.canvas.links;
let link: ui_node_link_t = project_create_node_link(links, n.id, 0, 0, 4);
array_push(links, link);
// Parse brush
make_material_parse_brush();
ui_nodes_hwnd.redraws = 2;
app_notify_on_init(util_render_make_brush_preview);
}
// Import from project file
else {
import_arm_run_brush(path);
}
});
}
///end
let _project_import_mesh_replace_existing: bool;
let _project_import_mesh_done: ()=>void;
function project_import_mesh(replace_existing: bool = true, done: ()=>void = null) {
_project_import_mesh_replace_existing = replace_existing;
_project_import_mesh_done = done;
ui_files_show(string_array_join(path_mesh_formats, ","), false, false, function (path: string) {
project_import_mesh_box(path, _project_import_mesh_replace_existing, true, _project_import_mesh_done);
});
}
let _project_import_mesh_box_path: string;
let _project_import_mesh_box_replace_existing: bool;
let _project_import_mesh_box_clear_layers: bool;
let _project_import_mesh_box_done: ()=>void;
function project_import_mesh_box(path: string, replace_existing: bool = true, clear_layers: bool = true, done: ()=>void = null) {
_project_import_mesh_box_path = path;
_project_import_mesh_box_replace_existing = replace_existing;
_project_import_mesh_box_clear_layers = clear_layers;
_project_import_mesh_box_done = done;
///if arm_ios
// Import immediately while access to resource is unlocked
// data_get_blob(path);
///end
ui_box_show_custom(function (ui: ui_t) {
let path: string = _project_import_mesh_box_path;
let replace_existing: bool = _project_import_mesh_box_replace_existing;
let clear_layers: bool = _project_import_mesh_box_clear_layers;
let done: ()=>void = _project_import_mesh_box_done;
let tab_vertical: bool = config_raw.touch_ui;
if (ui_tab(ui_handle(__ID__), tr("Import Mesh"), tab_vertical)) {
if (ends_with(to_lower_case(path), ".obj")) {
let split_by_combo: string[] = [tr("Object"), tr("Group"), tr("Material"), tr("UDIM Tile")];
context_raw.split_by = ui_combo(ui_handle(__ID__), split_by_combo, tr("Split By"), true);
if (ui.is_hovered) {
ui_tooltip(tr("Split .obj mesh into objects"));
}
}
///if (is_paint || is_sculpt)
// if (ends_with(to_lower_case(path), ".fbx") || ends_with(to_lower_case(path), ".blend")) {
if (ends_with(to_lower_case(path), ".blend")) {
let h: ui_handle_t = ui_handle(__ID__);
if (h.init) {
h.selected = context_raw.parse_vcols;
}
context_raw.parse_vcols = ui_check(h, tr("Parse Vertex Colors"));
if (ui.is_hovered) {
ui_tooltip(tr("Import vertex color data"));
}
}
///end
let row: f32 [] = [0.45, 0.45, 0.1];
ui_row(row);
if (ui_button(tr("Cancel"))) {
ui_box_hide();
}
if (ui_button(tr("Import")) || ui.is_return_down) {
ui_box_hide();
///if (arm_android || arm_ios)
console_toast(tr("Importing mesh"));
iron_g4_swap_buffers();
///end
///if (is_paint || is_sculpt)
import_mesh_run(path, clear_layers, replace_existing);
///end
///if is_lab
import_mesh_run(path, replace_existing);
///end
if (done != null) {
done();
}
}
if (ui_button(tr("?"))) {
file_load_url("https://github.com/armory3d/armorpaint_docs/blob/master/faq.md");
}
}
});
ui_box_click_to_hide = false; // Prevent closing when going back to window from file browser
}
function project_reimport_mesh() {
if (project_mesh_assets != null && project_mesh_assets.length > 0 && file_exists(project_mesh_assets[0])) {
project_import_mesh_box(project_mesh_assets[0], true, false);
}
else {
project_import_asset();
}
}
let _project_unwrap_mesh_box_mesh: raw_mesh_t;
let _project_unwrap_mesh_box_done: (a: raw_mesh_t)=>void;
let _project_unwrap_mesh_box_skip_ui: bool;
function project_unwrap_mesh_box(mesh: raw_mesh_t, done: (a: raw_mesh_t)=>void, skip_ui: bool = false) {
_project_unwrap_mesh_box_mesh = mesh;
_project_unwrap_mesh_box_done = done;
_project_unwrap_mesh_box_skip_ui = skip_ui;
ui_box_show_custom(function (ui: ui_t) {
let mesh: raw_mesh_t = _project_unwrap_mesh_box_mesh;
let done: (a: raw_mesh_t)=>void = _project_unwrap_mesh_box_done;
let skip_ui: bool = _project_unwrap_mesh_box_skip_ui;
let tab_vertical: bool = config_raw.touch_ui;
if (ui_tab(ui_handle(__ID__), tr("Unwrap Mesh"), tab_vertical)) {
let unwrap_plugins: string[] = [];
if (box_preferences_files_plugin == null) {
box_preferences_fetch_plugins();
}
for (let i: i32 = 0; i < box_preferences_files_plugin.length; ++i) {
let f: string = box_preferences_files_plugin[i];
if (string_index_of(f, "uv_unwrap") >= 0 && ends_with(f, ".js")) {
array_push(unwrap_plugins, f);
}
}
array_push(unwrap_plugins, "equirect");
let unwrap_by: i32 = ui_combo(ui_handle(__ID__), unwrap_plugins, tr("Plugin"), true);
let row: f32[] = [0.5, 0.5];
ui_row(row);
if (ui_button(tr("Cancel"))) {
ui_box_hide();
}
if (ui_button(tr("Unwrap")) || ui.is_return_down || skip_ui) {
ui_box_hide();
///if (arm_android || arm_ios)
console_toast(tr("Unwrapping mesh"));
iron_g4_swap_buffers();
///end
if (unwrap_by == unwrap_plugins.length - 1) {
util_mesh_equirect_unwrap(mesh);
}
else {
let f: string = unwrap_plugins[unwrap_by];
if (array_index_of(config_raw.plugins, f) == -1) {
config_enable_plugin(f);
console_info(f + " " + tr("plugin enabled"));
}
let cb: any = map_get(util_mesh_unwrappers, f); // JSValue * -> (a: raw_mesh_t)=>void
js_call_ptr(cb, mesh);
}
done(mesh);
}
}
});
}
let _project_import_asset_hdr_as_envmap: bool;
function project_import_asset(filters: string = null, hdr_as_envmap: bool = true) {
if (filters == null) {
filters = string_array_join(path_texture_formats, ",") + "," + string_array_join(path_mesh_formats, ",");
}
_project_import_asset_hdr_as_envmap = hdr_as_envmap;
ui_files_show(filters, false, true, function (path: string) {
import_asset_run(path, -1.0, -1.0, true, _project_import_asset_hdr_as_envmap);
});
}
let _project_import_swatches_replace_existing: bool;
function project_import_swatches(replace_existing: bool = false) {
_project_import_swatches_replace_existing = replace_existing;
ui_files_show("arm,gpl", false, false, function (path: string) {
if (path_is_gimp_color_palette(path)) {
import_gpl_run(path, _project_import_swatches_replace_existing);
}
else {
import_arm_run_swatches(path, _project_import_swatches_replace_existing);
}
});
}
function project_reimport_textures() {
for (let i: i32 = 0; i < project_assets.length; ++i) {
let asset: asset_t = project_assets[i];
project_reimport_texture(asset);
}
}
function project_reimport_texture_load(path: string, asset: asset_t) {
asset.file = path;
let i: i32 = array_index_of(project_assets, asset);
data_delete_image(asset.file);
map_delete(project_asset_map, asset.id);
let old_asset: asset_t = project_assets[i];
array_splice(project_assets, i, 1);
array_splice(project_asset_names, i, 1);
import_texture_run(asset.file);
array_insert(project_assets, i, array_pop(project_assets));
array_insert(project_asset_names, i, array_pop(project_asset_names));
///if (is_paint || is_sculpt)
if (context_raw.texture == old_asset) {
context_raw.texture = project_assets[i];
}
///end
app_notify_on_next_frame(function () {
make_material_parse_paint_material();
///if (is_paint || is_sculpt)
util_render_make_material_preview();
ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2;
///end
});
}
let _project_reimport_texture_asset: asset_t;
function project_reimport_texture(asset: asset_t) {
if (!file_exists(asset.file)) {
let filters: string = string_array_join(path_texture_formats, ",");
_project_reimport_texture_asset = asset;
ui_files_show(filters, false, false, function (path: string) {
project_reimport_texture_load(path, _project_reimport_texture_asset);
});
}
else {
project_reimport_texture_load(asset.file, asset);
}
}
function project_get_image(asset: asset_t): image_t {
return asset != null ? map_get(project_asset_map, asset.id) : null;
}
///if (is_paint || is_sculpt)
function project_get_used_atlases(): string[] {
if (project_atlas_objects == null) {
return null;
}
let used: i32[] = [];
for (let i: i32 = 0; i < project_atlas_objects.length; ++i) {
let ao: i32 = project_atlas_objects[i];
if (array_index_of(used, ao) == -1) {
array_push(used, ao);
}
}
if (used.length > 1) {
let res: string[] = [];
for (let i: i32 = 0; i < used.length; ++i) {
let u: i32 = used[i];
array_push(res, project_atlas_names[u]);
}
return res;
}
else return null;
}
function project_is_atlas_object(p: mesh_object_t): bool {
if (context_raw.layer_filter <= project_paint_objects.length) {
return false;
}
let atlas_name: string = project_get_used_atlases()[context_raw.layer_filter - project_paint_objects.length - 1];
let atlas_i: i32 = array_index_of(project_atlas_names, atlas_name);
return atlas_i == project_atlas_objects[array_index_of(project_paint_objects, p)];
}
function project_get_atlas_objects(object_mask: i32): mesh_object_t[] {
let atlas_name: string = project_get_used_atlases()[object_mask - project_paint_objects.length - 1];
let atlas_i: i32 = array_index_of(project_atlas_names, atlas_name);
let visibles: mesh_object_t[] = [];
for (let i: i32 = 0; i < project_paint_objects.length; ++i) {
if (project_atlas_objects[i] == atlas_i) {
array_push(visibles, project_paint_objects[i]);
}
}
return visibles;
}
///end
function project_packed_asset_exists(packed_assets: packed_asset_t[], name: string): bool {
for (let i: i32 = 0; i < packed_assets.length; ++i) {
let pa: packed_asset_t = packed_assets[i];
if (pa.name == name) {
return true;
}
}
return false;
}
function project_export_swatches() {
ui_files_show("arm,gpl", true, false, function (path: string) {
let f: string = ui_files_filename;
if (f == "") {
f = tr("untitled");
}
if (path_is_gimp_color_palette(f)) {
export_gpl_run(path + path_sep + f, substring(f, 0, string_last_index_of(f, ".")), project_raw.swatches);
}
else {
export_arm_run_swatches(path + path_sep + f);
}
});
}
function make_swatch(base: i32 = 0xffffffff): swatch_color_t {
let s: swatch_color_t = { base: base, opacity: 1.0, occlusion: 1.0, roughness: 0.0, metallic: 0.0, normal: 0xff8080ff, emission: 0.0, height: 0.0, subsurface: 0.0 };
return s;
}
function project_clone_swatch(swatch: swatch_color_t): swatch_color_t {
let s: swatch_color_t = { base: swatch.base, opacity: swatch.opacity, occlusion: swatch.occlusion, roughness: swatch.roughness, metallic: swatch.metallic, normal: swatch.normal, emission: swatch.emission, height: swatch.height, subsurface: swatch.subsurface };
return s;
}
function project_set_default_swatches() {
// 32-Color Palette by Andrew Kensler
// http://eastfarthing.com/blog/2016-05-06-palette/
project_raw.swatches = [];
let colors: i32[] = [0xffffffff, 0xff000000, 0xffd6a090, 0xffa12c32, 0xfffa2f7a, 0xfffb9fda, 0xffe61cf7, 0xff992f7c, 0xff47011f, 0xff051155, 0xff4f02ec, 0xff2d69cb, 0xff00a6ee, 0xff6febff, 0xff08a29a, 0xff2a666a, 0xff063619, 0xff4a4957, 0xff8e7ba4, 0xffb7c0ff, 0xffacbe9c, 0xff827c70, 0xff5a3b1c, 0xffae6507, 0xfff7aa30, 0xfff4ea5c, 0xff9b9500, 0xff566204, 0xff11963b, 0xff51e113, 0xff08fdcc];
for (let i: i32 = 0; i < colors.length; ++i) {
let c: i32 = colors[i];
array_push(project_raw.swatches, make_swatch(c));
}
}
function project_get_material_group_by_name(group_name: string): node_group_t {
for (let i: i32 = 0; i < project_material_groups.length; ++i) {
let g: node_group_t = project_material_groups[i];
if (g.canvas.name == group_name) {
return g;
}
}
return null;
}
///if (is_paint || is_sculpt)
function project_is_material_group_in_use(group: node_group_t): bool {
let canvases: ui_node_canvas_t[] = [];
for (let i: i32 = 0; i < project_materials.length; ++i) {
let m: slot_material_t = project_materials[i];
array_push(canvases, m.canvas);
}
for (let i: i32 = 0; i < project_material_groups.length; ++i) {
let m: node_group_t = project_material_groups[i];
array_push(canvases, m.canvas);
}
for (let i: i32 = 0; i < canvases.length; ++i) {
let canvas: ui_node_canvas_t = canvases[i];
for (let i: i32 = 0; i < canvas.nodes.length; ++i) {
let n: ui_node_t = canvas.nodes[i];
let cname: string = group.canvas.name;
if (n.type == "GROUP" && n.name == cname) {
return true;
}
}
}
return false;
}
///end
type node_group_t = {
nodes?: ui_nodes_t;
canvas?: ui_node_canvas_t;
};
type project_format_t = {
version?: string;
assets?: string[]; // texture_assets
is_bgra?: bool; // Swapped red and blue channels for layer textures
packed_assets?: packed_asset_t[];
envmap?: string; // Asset name
envmap_strength?: f32;
camera_world?: f32_array_t;
camera_origin?: f32_array_t;
camera_fov?: f32;
swatches?: swatch_color_t[];
brush_nodes?: ui_node_canvas_t[];
brush_icons?: buffer_t[];
material_nodes?: ui_node_canvas_t[];
material_groups?: ui_node_canvas_t[];
material_icons?: buffer_t[];
font_assets?: string[];
layer_datas?: layer_data_t[];
mesh_datas?: mesh_data_t[];
mesh_assets?: string[];
mesh_icons?: buffer_t[];
atlas_objects?: i32[];
atlas_names?: string[];
///if is_lab
material?: ui_node_canvas_t;
material_groups?: ui_node_canvas_t[];
mesh_data?: mesh_data_t;
mesh_icon?: buffer_t;
///end
};
type asset_t = {
id?: i32;
name?: string;
file?: string;
};
type packed_asset_t = {
name?: string;
bytes?: buffer_t;
};
type swatch_color_t = {
base?: color_t;
opacity?: f32;
occlusion?: f32;
roughness?: f32;
metallic?: f32;
normal?: color_t;
emission?: f32;
height?: f32;
subsurface?: f32;
};
type layer_data_t = {
name?: string;
res?: i32; // Width pixels
bpp?: i32; // Bits per pixel
texpaint?: buffer_t;
uv_scale?: f32;
uv_rot?: f32;
uv_type?: i32;
decal_mat?: f32_array_t;
opacity_mask?: f32;
fill_layer?: i32;
object_mask?: i32;
blending?: i32;
parent?: i32;
visible?: bool;
texpaint_nor?: buffer_t;
texpaint_pack?: buffer_t;
paint_base?: bool;
paint_opac?: bool;
paint_occ?: bool;
paint_rough?: bool;
paint_met?: bool;
paint_nor?: bool;
paint_nor_blend?: bool;
paint_height?: bool;
paint_height_blend?: bool;
paint_emis?: bool;
paint_subs?: bool;
};