Files
armorpaint/paint/sources/base.c
T
2026-06-09 18:04:19 +02:00

1047 lines
30 KiB
C

#include "global.h"
i32 base_drag_tint = 0xffffffff;
i32 base_drag_size = -1;
rect_t *base_drag_rect = NULL;
f32 base_drag_start = 0.0;
f32 base_drop_x = 0.0;
f32 base_drop_y = 0.0;
gpu_texture_t *base_color_wheel;
gpu_texture_t *base_color_wheel_gradient;
i32 base_appx = 0;
i32 base_appy = 0;
i32 base_last_window_width = 0;
i32 base_last_window_height = 0;
bool base_start_arm_found = false;
i32 _base_material_count;
void base_on_shutdown() {
#if defined(IRON_ANDROID) || defined(IRON_IOS)
project_save(false);
#endif
config_save();
}
void base_on_background() {
// Release keys after alt-tab / win-tab
_key_up(KEY_CODE_ALT, NULL);
_key_up(KEY_CODE_WIN, NULL);
_key_up(KEY_CODE_CONTROL, NULL);
_key_up(KEY_CODE_SHIFT, NULL);
}
void base_on_foreground() {
g_context->foreground_event = true;
g_context->last_paint_x = -1;
g_context->last_paint_y = -1;
}
void base_on_drop_files(char *drop_path) {
drop_path = string_copy(trim_end(drop_path));
any_array_push(base_drop_paths, drop_path);
}
void base_init_on_start_arm(void *_) {
if (base_start_arm_found) {
import_arm_run_project(g_project->_->filepath);
}
g_context->tool = TOOL_TYPE_CURSOR;
// Auto-run main script
if (g_project->script_datas != NULL && g_project->script_datas->length > 0) {
minic_ctx_t *ctx = minic_eval(g_project->script_datas->buffer[0]);
}
tab_timeline_play();
}
void base_save_window_rect() {
g_config->window_w = iron_window_width();
g_config->window_h = iron_window_height();
g_config->window_x = iron_window_x();
g_config->window_y = iron_window_y();
config_save();
}
void base_save_and_quit_callback(bool save) {
base_save_window_rect();
if (save) {
project_save(true);
}
else {
iron_stop();
}
}
void base_material_dropped() {
// Material drag and dropped onto viewport or layers tab
if (context_in_3d_view()) {
uv_type_t uv_type = keyboard_down("control") ? UV_TYPE_PROJECT : UV_TYPE_UVMAP;
mat4_t decal_mat = uv_type == UV_TYPE_PROJECT ? util_render_get_decal_mat() : mat4_nan();
layers_create_fill_layer(uv_type, decal_mat, -1);
}
if (context_in_layers() && tab_layers_can_drop_new_layer(g_context->drag_dest)) {
uv_type_t uv_type = keyboard_down("control") ? UV_TYPE_PROJECT : UV_TYPE_UVMAP;
mat4_t decal_mat = uv_type == UV_TYPE_PROJECT ? util_render_get_decal_mat() : mat4_nan();
layers_create_fill_layer(uv_type, decal_mat, g_context->drag_dest);
}
else if (context_in_nodes()) {
ui_nodes_accept_material_drop(array_index_of(g_project->_->materials, base_drag_material));
}
else if (context_in_materials()) {
tab_materials_accept_material_drop(base_drag_material);
}
gc_unroot(base_drag_material);
base_drag_material = NULL;
}
void base_update_import_asset_done() {
// Asset was material
if (g_project->_->materials->length > _base_material_count) {
gc_unroot(base_drag_material);
base_drag_material = g_context->material;
gc_root(base_drag_material);
base_material_dropped();
}
}
void base_handle_drop_paths() {
if (base_drop_paths->length > 0) {
bool wait = false;
#if defined(IRON_LINUX) || defined(IRON_MACOS)
wait = !mouse_moved; // Mouse coords not updated during drag
#endif
if (!wait) {
base_drop_x = mouse_x;
base_drop_y = mouse_y;
char *drop_path = array_shift(base_drop_paths);
import_asset_run(drop_path, base_drop_x, base_drop_y, true, true, NULL);
}
}
}
gpu_texture_t *base_get_drag_image() {
base_drag_tint = 0xffffffff;
base_drag_size = -1;
gc_unroot(base_drag_rect);
base_drag_rect = NULL;
if (base_drag_asset != NULL) {
return project_get_image(base_drag_asset);
}
if (base_drag_swatch != NULL) {
base_drag_tint = base_drag_swatch->base;
base_drag_size = 26;
return tab_swatches_empty_get();
}
if (base_drag_file != NULL) {
if (base_drag_file_icon != NULL) {
return base_drag_file_icon;
}
gpu_texture_t *icons = resource_get("icons.k");
gc_unroot(base_drag_rect);
base_drag_rect = string_index_of(base_drag_file, ".") > 0 ? resource_tile50(icons, ICON_FILE) : resource_tile50(icons, ICON_FOLDER_FULL);
gc_root(base_drag_rect);
base_drag_tint = g_theme->HIGHLIGHT_COL;
return icons;
}
if (base_drag_material != NULL) {
return base_drag_material->image_icon;
}
if (base_drag_brush != NULL) {
return base_drag_brush->image_icon;
}
if (base_drag_font != NULL) {
return base_drag_font->image;
}
if (base_drag_layer != NULL && slot_layer_is_group(base_drag_layer)) {
gpu_texture_t *icons = resource_get("icons.k");
rect_t *folder_closed = resource_tile50(icons, ICON_FOLDER_FULL);
rect_t *folder_open = resource_tile50(icons, ICON_FOLDER_OPEN);
gc_unroot(base_drag_rect);
base_drag_rect = base_drag_layer->show_panel ? folder_open : folder_closed;
gc_root(base_drag_rect);
base_drag_tint = base_darker(g_theme->LABEL_COL, 0x00202020);
return icons;
}
if (base_drag_layer != NULL && slot_layer_is_mask(base_drag_layer) && base_drag_layer->fill_material == NULL) {
tab_layers_make_mask_preview_rgba32(base_drag_layer);
return g_context->mask_preview_rgba32;
}
if (base_drag_layer != NULL) {
return base_drag_layer->fill_material != NULL ? base_drag_layer->fill_material->image_icon : base_drag_layer->texpaint_preview;
}
return NULL;
}
rect_t *base_get_drag_background() {
gpu_texture_t *icons = resource_get("icons.k");
if (base_drag_layer != NULL && !slot_layer_is_group(base_drag_layer) && base_drag_layer->fill_material == NULL) {
return resource_tile50(icons, ICON_CHECKER);
}
return NULL;
}
void base_init_undo_layers() {
if (history_undo_layers == NULL) {
gc_unroot(history_undo_layers);
history_undo_layers = any_array_create_from_raw((void *[]){}, 0);
gc_root(history_undo_layers);
for (i32 i = 0; i < g_config->undo_steps; ++i) {
i32 len = history_undo_layers->length;
char *ext = string("_undo%s", i32_to_string(len));
slot_layer_t *l = slot_layer_create(ext, LAYER_SLOT_TYPE_LAYER, NULL);
any_array_push(history_undo_layers, l);
}
}
}
void base_update(void *_) {
if (mouse_movement_x != 0 || mouse_movement_y != 0) {
iron_mouse_set_cursor(IRON_CURSOR_ARROW);
}
bool has_drag = base_drag_asset != NULL || base_drag_material != NULL || base_drag_layer != NULL || base_drag_file != NULL || base_drag_swatch != NULL ||
base_drag_brush != NULL || base_drag_font != NULL;
if (g_config->touch_ui) {
// Touch and hold to activate dragging
if (base_drag_start < 0.2) {
if (has_drag && mouse_down("left")) {
base_drag_start += sys_real_delta();
}
else {
base_drag_start = 0;
}
has_drag = false;
}
if (mouse_released("left")) {
base_drag_start = 0;
}
bool moved = math_abs(mouse_movement_x) > 1 && math_abs(mouse_movement_y) > 1;
if ((mouse_released("left") || moved) && !has_drag) {
gc_unroot(base_drag_asset);
base_drag_asset = NULL;
gc_unroot(base_drag_swatch);
base_drag_swatch = NULL;
gc_unroot(base_drag_file);
base_drag_file = NULL;
gc_unroot(base_drag_file_icon);
base_drag_file_icon = NULL;
base_is_dragging = false;
gc_unroot(base_drag_material);
base_drag_material = NULL;
gc_unroot(base_drag_layer);
base_drag_layer = NULL;
gc_unroot(base_drag_brush);
base_drag_brush = NULL;
gc_unroot(base_drag_font);
base_drag_font = NULL;
}
// Disable touch scrolling while dragging is active
ui_touch_control = !base_is_dragging;
}
if (has_drag && (mouse_movement_x != 0 || mouse_movement_y != 0)) {
base_is_dragging = true;
}
if (mouse_released("left") && has_drag) {
if (base_drag_asset != NULL) {
// Create image texture
if (context_in_nodes()) {
ui_nodes_accept_asset_drop(array_index_of(g_project->_->assets, base_drag_asset));
}
else if (context_in_3d_view()) {
if (ends_with(to_lower_case(base_drag_asset->file), ".hdr")) {
gpu_texture_t *image = project_get_image(base_drag_asset);
import_envmap_run(base_drag_asset->file, image);
}
}
// Create mask
else if (context_in_layers() || context_in_2d_view(VIEW_2D_TYPE_LAYER)) {
layers_create_image_mask(base_drag_asset);
}
else if (context_in_textures()) {
tab_textures_accept_asset_drop(base_drag_asset);
}
gc_unroot(base_drag_asset);
base_drag_asset = NULL;
}
else if (base_drag_swatch != NULL) {
// Create RGB node
if (context_in_nodes()) {
ui_nodes_accept_swatch_drop(base_drag_swatch);
}
else if (context_in_swatches()) {
tab_swatches_accept_swatch_drop(base_drag_swatch);
}
else if (context_in_materials()) {
tab_materials_accept_swatch_drop(base_drag_swatch);
}
else if (context_in_3d_view()) {
i32 color = base_drag_swatch->base;
color = color_set_ab(color, base_drag_swatch->opacity * 255);
layers_create_color_layer(color, base_drag_swatch->occlusion, base_drag_swatch->roughness, base_drag_swatch->metallic, -1);
}
else if (context_in_layers() && tab_layers_can_drop_new_layer(g_context->drag_dest)) {
i32 color = base_drag_swatch->base;
color = color_set_ab(color, base_drag_swatch->opacity * 255);
layers_create_color_layer(color, base_drag_swatch->occlusion, base_drag_swatch->roughness, base_drag_swatch->metallic, g_context->drag_dest);
}
gc_unroot(base_drag_swatch);
base_drag_swatch = NULL;
}
else if (base_drag_file != NULL) {
if (!context_in_browser()) {
base_drop_x = mouse_x;
base_drop_y = mouse_y;
_base_material_count = g_project->_->materials->length;
import_asset_run(base_drag_file, base_drop_x, base_drop_y, true, true, &base_update_import_asset_done);
}
gc_unroot(base_drag_file);
base_drag_file = NULL;
gc_unroot(base_drag_file_icon);
base_drag_file_icon = NULL;
}
else if (base_drag_material != NULL) {
base_material_dropped();
}
else if (base_drag_layer != NULL) {
if (context_in_nodes()) {
ui_nodes_accept_layer_drop(array_index_of(g_project->_->layers, base_drag_layer));
}
else if (context_in_layers() && base_is_dragging) {
slot_layer_move(base_drag_layer, g_context->drag_dest);
make_material_parse_mesh_material();
}
gc_unroot(base_drag_layer);
base_drag_layer = NULL;
}
else if (base_drag_brush != NULL) {
if (context_in_brushes()) {
tab_brushes_accept_brush_drop(base_drag_brush);
}
gc_unroot(base_drag_brush);
base_drag_brush = NULL;
}
else if (base_drag_font != NULL) {
if (context_in_fonts()) {
tab_fonts_accept_font_drop(base_drag_font);
}
gc_unroot(base_drag_font);
base_drag_font = NULL;
}
iron_mouse_set_cursor(IRON_CURSOR_ARROW);
base_is_dragging = false;
}
if (g_context->color_picker_callback != NULL && (mouse_released("left") || mouse_released("right"))) {
g_context->color_picker_callback = NULL;
context_select_tool(g_context->color_picker_previous_tool);
}
base_handle_drop_paths();
if (g_context->ddirty < 0) {
g_context->ddirty = 0;
}
if (g_context->tool == TOOL_TYPE_CURSOR) {
if (keyboard_down("control") && keyboard_started("d")) {
sim_duplicate();
}
if (keyboard_started("delete")) {
sim_delete();
}
}
// Live material when using sys_time() script node
if (g_context->tool == TOOL_TYPE_MATERIAL) {
bool has_script_node = false;
ui_node_canvas_t *canvas = g_context->material->canvas;
for (i32 i = 0; i < canvas->nodes->length; ++i) {
ui_node_t *n = canvas->nodes->buffer[i];
if (string_equals(n->type, "SCRIPT_CPU")) {
has_script_node = true;
break;
}
}
if (has_script_node) {
layers_update_fill_layers();
iron_delay_idle_sleep();
}
}
render_compass_update();
// if (g_config->workspace == WORKSPACE_PLAYER) {
if (args_player) {
player_update();
}
ui_view2d_update(NULL);
ui_nodes_update(NULL);
ui_base_update(NULL);
camera_update(NULL);
// Render
if (g_context->tool == TOOL_TYPE_CURSOR) {
sim_init();
sim_update();
}
if (g_context->frame == 2) {
util_render_make_material_preview();
ui_base_hwnds->buffer[TAB_AREA_SIDEBAR1]->redraws = 2;
base_init_undo_layers();
make_material_parse_mesh_material();
make_material_parse_paint_material(true);
g_context->ddirty = 0;
}
else if (g_context->frame == 3) {
g_context->ddirty = 3;
}
g_context->frame++;
if (base_is_dragging) {
iron_mouse_set_cursor(IRON_CURSOR_HAND);
gpu_texture_t *img = base_get_drag_image();
f32 scale_factor = UI_SCALE();
f32 size = (base_drag_size == -1 ? 50 : base_drag_size) * scale_factor;
f32 ratio = size / (float)img->width;
f32 h = img->height * ratio;
i32 inv = 0;
draw_begin(NULL, false, 0);
draw_set_color(base_drag_tint);
rect_t *bg_rect = base_get_drag_background();
if (bg_rect != NULL) {
draw_scaled_sub_image(resource_get("icons.k"), bg_rect->x, bg_rect->y, bg_rect->w, bg_rect->h, mouse_x + base_drag_off_x,
mouse_y + base_drag_off_y + inv, size, h - inv * 2);
}
base_drag_rect == NULL ? draw_scaled_image(img, mouse_x + base_drag_off_x, mouse_y + base_drag_off_y + inv, size, h - inv * 2)
: draw_scaled_sub_image(img, base_drag_rect->x, base_drag_rect->y, base_drag_rect->w, base_drag_rect->h,
mouse_x + base_drag_off_x, mouse_y + base_drag_off_y + inv, size, h - inv * 2);
draw_set_color(0xffffffff);
draw_end();
}
// Select tool rectangle mask
if (g_context->select_active || g_context->select_dragging) {
f32 x1 = g_context->select_x1 * sys_w() + sys_x();
f32 y1 = g_context->select_y1 * sys_h() + sys_y();
f32 x2 = g_context->select_x2 * sys_w() + sys_x();
f32 y2 = g_context->select_y2 * sys_h() + sys_y();
draw_begin(NULL, false, 0);
draw_set_color(g_context->select_dragging ? 0xffffffff : 0xaaffffff);
draw_rect(x1, y1, x2 - x1, y2 - y1, 1.0);
draw_set_color(0xffffffff);
draw_end();
}
bool using_menu = ui_menu_show && mouse_y > ui_header_h;
base_ui_enabled = !ui_box_show && !using_menu && g_ui->combo_selected_handle == NULL;
if (ui_box_show) {
ui_box_render();
}
if (ui_menu_show) {
ui_menu_render();
}
#if defined(IRON_ANDROID) || defined(IRON_IOS)
// No mouse move events for touch, re-init last paint position on touch start
if (!mouse_down("left")) {
g_context->last_paint_x = -1;
g_context->last_paint_y = -1;
}
#endif
}
void base_init() {
base_last_window_width = iron_window_width();
base_last_window_height = iron_window_height();
sys_notify_on_drop_files(&base_on_drop_files);
sys_notify_on_app_state(&base_on_foreground, &base_on_background, &base_on_shutdown);
iron_set_save_and_quit_callback(base_save_and_quit_callback);
g_font = data_get_font("font.ttf");
gc_root(g_font);
base_color_wheel = data_get_image("color_wheel.k");
gc_root(base_color_wheel);
base_color_wheel_gradient = data_get_image("color_wheel_gradient.k");
gc_root(base_color_wheel_gradient);
config_load_theme(g_config->theme, false);
base_default_element_w = g_theme->ELEMENT_W;
base_default_element_h = g_theme->ELEMENT_H;
base_default_font_size = g_theme->FONT_SIZE;
translator_load_translations(g_config->locale);
ui_files_filename = string_copy(tr("untitled"));
gc_root(ui_files_filename);
#if defined(IRON_ANDROID) || defined(IRON_IOS)
sys_title_set(tr("untitled"));
#endif
// Baked font for fast startup
if (string_equals(g_config->locale, "en")) {
draw_font_13(g_font);
}
else {
draw_font_init(g_font);
}
ui_nodes_enum_texts = base_combo_enum_texts;
ui_nodes_enum_images = base_combo_enum_images;
gc_root(ui_nodes_enum_texts);
// Init plugins
if (g_config->plugins != NULL) {
for (i32 i = 0; i < g_config->plugins->length; ++i) {
char *plugin = g_config->plugins->buffer[i];
plugin_start(plugin);
}
}
if (!g_config->texture_filter) {
gpu_use_linear_sampling(false);
}
args_parse();
camera_init();
ui_base_init();
ui_viewnodes_init();
ui_view2d_init();
sys_notify_on_update(base_update, NULL);
base_appx = ui_toolbar_w(true);
base_appy = 0;
if (g_config->layout->buffer[LAYOUT_SIZE_HEADER] == 1) {
base_appy = ui_header_h * 2;
}
scene_camera->data->fov = math_floor(scene_camera->data->fov * 100) / 100.0;
camera_object_build_proj(scene_camera, -1.0);
args_run();
if (g_config->workspace != WORKSPACE_PAINT_3D) {
base_update_workspace();
}
if (g_config->workflow != WORKFLOW_PBR) {
base_update_workflow();
}
g_context->camera_pivot = g_config->camera_pivot;
g_context->camera_controls = g_config->camera_controls;
bool has_projects = g_config->recent_projects->length > 0;
if (g_config->splash_screen && has_projects) {
box_projects_show();
}
// Startup project
char *start_arm = string("%s/start.arm", iron_internal_files_location());
if (iron_file_exists(start_arm)) {
g_project->_->filepath = start_arm;
base_start_arm_found = true;
args_player = true;
}
if (args_player) {
// base_player_lock = true;
g_config->workspace = WORKSPACE_PLAYER;
base_update_workspace();
make_material_parse_paint_material(true);
sys_notify_on_next_frame(&base_init_on_start_arm, NULL);
}
}
i32 base_w() {
// Drawing material preview
if (g_context->material_preview) {
return util_render_material_preview_size;
}
// Drawing decal preview
if (g_context->decal_preview) {
return util_render_decal_preview_size;
}
if (g_context->paint2d_view) {
return ui_view2d_ww;
}
// 3D view is hidden
if (!base_view3d_show) {
return 1;
}
i32 res = base_view3d_w();
return res > 0 ? res : 1; // App was minimized, force render path resize
}
i32 base_view3d_w() {
i32 res = 0;
if (g_config->layout == NULL) {
i32 sidebarw = ui_sidebar_default_w;
res = iron_window_width() - sidebarw - ui_toolbar_default_w;
}
else if (ui_nodes_show || ui_view2d_show) {
res = iron_window_width() - g_config->layout->buffer[LAYOUT_SIZE_SIDEBAR_W] - g_config->layout->buffer[LAYOUT_SIZE_NODES_W] - ui_toolbar_w(true);
}
else if (ui_base_show) {
res = iron_window_width() - g_config->layout->buffer[LAYOUT_SIZE_SIDEBAR_W] - ui_toolbar_w(true);
}
else { // Distract free
res = iron_window_width();
}
if (g_context->view_index > -1) {
res = math_ceil(res / 2.0);
}
if (g_context->paint2d_view) {
res = ui_view2d_ww;
}
return res;
}
i32 base_h() {
// Drawing material preview
if (g_context->material_preview) {
return util_render_material_preview_size;
}
// Drawing decal preview
if (g_context->decal_preview) {
return util_render_decal_preview_size;
}
i32 res = iron_window_height();
if (g_config->layout == NULL) {
res -= ui_header_default_h * 2 + ui_statusbar_default_h;
#if defined(IRON_ANDROID) || defined(IRON_IOS)
res += ui_header_h;
#endif
}
else if (ui_base_show && res > 0) {
i32 statush = g_config->layout->buffer[LAYOUT_SIZE_STATUS_H];
res -= math_floor(ui_header_default_h * 2 * g_config->window_scale) + statush;
if (g_config->layout->buffer[LAYOUT_SIZE_HEADER] == 0) {
res += ui_header_h * 2;
}
if (!base_view3d_show) {
res += ui_header_h * 4;
}
}
return res > 0 ? res : 1; // App was minimized, force render path resize
}
i32 base_x() {
return g_context->view_index == 1 ? base_appx + base_w() : base_appx;
}
i32 base_y() {
return base_appy;
}
void base_on_resize() {
if (iron_window_width() == 0 || iron_window_height() == 0) {
return;
}
f32 ratio_w = iron_window_width() / (float)base_last_window_width;
base_last_window_width = iron_window_width();
f32 ratio_h = iron_window_height() / (float)base_last_window_height;
base_last_window_height = iron_window_height();
g_config->layout->buffer[LAYOUT_SIZE_NODES_W] = math_floor(g_config->layout->buffer[LAYOUT_SIZE_NODES_W] * ratio_w);
g_config->layout->buffer[LAYOUT_SIZE_SIDEBAR_H0] = math_floor(g_config->layout->buffer[LAYOUT_SIZE_SIDEBAR_H0] * ratio_h);
g_config->layout->buffer[LAYOUT_SIZE_SIDEBAR_H1] = iron_window_height() - g_config->layout->buffer[LAYOUT_SIZE_SIDEBAR_H0];
base_resize();
base_save_window_rect();
}
void base_resize() {
if (iron_window_width() == 0 || iron_window_height() == 0) {
return;
}
camera_object_t *cam = scene_camera;
if (cam->data->ortho != NULL) {
cam->data->ortho->buffer[2] = -2 * (sys_h() / (float)sys_w());
cam->data->ortho->buffer[3] = 2 * (sys_h() / (float)sys_w());
}
camera_object_build_proj(cam, -1.0);
scene_camera->frame = 0;
if (g_context->camera_type == CAMERA_TYPE_ORTHOGRAPHIC) {
viewport_update_camera_type(g_context->camera_type);
}
g_context->ddirty = 2;
if (ui_base_show && base_view3d_show) {
base_appx = ui_toolbar_w(true);
base_appy = 0;
if (g_config->layout->buffer[LAYOUT_SIZE_HEADER] == 1) {
base_appy = ui_header_h * 2;
}
}
else {
base_appx = -1;
base_appy = 0;
}
ui_nodes_grid_redraw = true;
ui_view2d_grid_redraw = true;
base_redraw_ui();
}
string_array_t *base_combo_enum_texts(char *node_type) {
if (string_equals(node_type, "TEX_IMAGE")) {
if (g_project->_->assets->length > 0) {
string_array_t *asset_names = any_array_create_from_raw((void *[]){}, 0);
for (i32 i = 0; i < g_project->_->assets->length; ++i) {
any_array_push(asset_names, g_project->_->assets->buffer[i]->name);
}
return asset_names;
}
else {
string_array_t *empty = any_array_create_from_raw(
(void *[]){
"",
},
1);
return empty;
}
}
if (string_equals(node_type, "LAYER") || string_equals(node_type, "LAYER_MASK")) {
string_array_t *layer_names = any_array_create_from_raw((void *[]){}, 0);
for (i32 i = 0; i < g_project->_->layers->length; ++i) {
slot_layer_t *l = g_project->_->layers->buffer[i];
any_array_push(layer_names, l->name);
}
return layer_names;
}
if (string_equals(node_type, "MATERIAL")) {
string_array_t *material_names = any_array_create_from_raw((void *[]){}, 0);
for (i32 i = 0; i < g_project->_->materials->length; ++i) {
slot_material_t *m = g_project->_->materials->buffer[i];
any_array_push(material_names, m->canvas->name);
}
return material_names;
}
if (string_equals(node_type, "image_texture_node")) {
if (g_project->_->assets->length > 0) {
string_array_t *asset_names = any_array_create_from_raw((void *[]){}, 0);
for (i32 i = 0; i < g_project->_->assets->length; ++i) {
any_array_push(asset_names, g_project->_->assets->buffer[i]->name);
}
return asset_names;
}
else {
string_array_t *empty = any_array_create_from_raw(
(void *[]){
"",
},
1);
return empty;
}
}
return NULL;
}
any_array_t *base_combo_enum_images(char *node_type) {
if (string_equals(node_type, "TEX_IMAGE")) {
any_array_t *ar = any_array_create(0);
for (i32 i = 0; i < g_project->_->assets->length; ++i) {
asset_t *asset = g_project->_->assets->buffer[i];
gpu_texture_t *img = project_get_image(asset);
any_array_push(ar, img);
}
return ar;
}
if (string_equals(node_type, "LAYER") || string_equals(node_type, "LAYER_MASK")) {
any_array_t *ar = any_array_create(0);
for (i32 i = 0; i < g_project->_->layers->length; ++i) {
slot_layer_t *l = g_project->_->layers->buffer[i];
any_array_push(ar, l->texpaint_preview);
}
return ar;
}
if (string_equals(node_type, "MATERIAL")) {
any_array_t *ar = any_array_create(0);
for (i32 i = 0; i < g_project->_->materials->length; ++i) {
slot_material_t *m = g_project->_->materials->buffer[i];
any_array_push(ar, m->image_icon);
}
return ar;
}
if (string_equals(node_type, "image_texture_node")) {
any_array_t *ar = any_array_create(0);
for (i32 i = 0; i < g_project->_->assets->length; ++i) {
asset_t *asset = g_project->_->assets->buffer[i];
gpu_texture_t *img = project_get_image(asset);
any_array_push(ar, img);
}
return ar;
}
return NULL;
}
i32 base_get_asset_index(char *file_name) {
for (i32 i = 0; i < g_project->_->assets->length; ++i) {
if (string_equals(g_project->_->assets->buffer[i]->name, file_name)) {
return i;
}
}
return 0;
}
void base_toggle_fullscreen() {
if (iron_window_get_mode() == IRON_WINDOW_MODE_WINDOW) {
g_config->window_w = iron_window_width();
g_config->window_h = iron_window_height();
g_config->window_x = iron_window_x();
g_config->window_y = iron_window_y();
iron_window_change_mode(IRON_WINDOW_MODE_FULLSCREEN);
}
else {
iron_window_change_mode(IRON_WINDOW_MODE_WINDOW);
iron_window_resize(g_config->window_w, g_config->window_h);
iron_window_move(g_config->window_x, g_config->window_y);
}
g_context->ddirty = 3;
}
bool base_is_decal_layer() {
bool is_painting = g_context->tool != TOOL_TYPE_MATERIAL;
return is_painting && g_context->layer->fill_material != NULL && g_context->layer->uv_type == UV_TYPE_PROJECT;
}
void base_redraw_status() {
ui_base_hwnds->buffer[TAB_AREA_STATUS]->redraws = 2;
}
void base_redraw_console() {
ui_base_hwnds->buffer[TAB_AREA_STATUS]->redraws = 2;
}
void base_redraw_ui() {
ui_header_handle->redraws = 2;
ui_base_hwnds->buffer[TAB_AREA_STATUS]->redraws = 2;
ui_menubar_menu_handle->redraws = 2;
ui_menubar_hwnd->redraws = 2;
ui_nodes_hwnd->redraws = 2;
ui_box_hwnd->redraws = 2;
ui_view2d_hwnd->redraws = 2;
// Redraw viewport
if (g_context->ddirty < 0) {
g_context->ddirty = 0;
}
ui_base_hwnds->buffer[TAB_AREA_SIDEBAR0]->redraws = 2;
ui_base_hwnds->buffer[TAB_AREA_SIDEBAR1]->redraws = 2;
ui_toolbar_handle->redraws = 2;
if (g_context->split_view) {
g_context->ddirty = 1;
}
}
void base_update_workspace() {
config_init_layout();
if (g_config->workspace == WORKSPACE_PAINT_3D) {
base_view3d_show = true;
ui_menubar_tab->i = 0;
ui_view2d_show = false;
ui_nodes_show = false;
}
else if (g_config->workspace == WORKSPACE_PAINT_2D) {
base_view3d_show = false;
ui_menubar_tab->i = -1;
ui_view2d_show = true;
ui_nodes_show = false;
}
else if (g_config->workspace == WORKSPACE_NODES) {
base_view3d_show = false;
ui_menubar_tab->i = -1;
ui_view2d_show = false;
ui_nodes_show = true;
ui_sidebar_show(false);
}
else if (g_config->workspace == WORKSPACE_SCRIPT) {
base_view3d_show = true;
ui_menubar_tab->i = 0;
ui_view2d_show = false;
ui_nodes_show = false;
ui_base_htabs->buffer[TAB_AREA_STATUS]->i = 5; // Console
g_config->layout_tabs->buffer[TAB_AREA_STATUS] = 5;
ui_base_htabs->buffer[TAB_AREA_SIDEBAR0]->i = 2; // Script
g_config->layout_tabs->buffer[TAB_AREA_SIDEBAR0] = 2;
g_config->layout->buffer[LAYOUT_SIZE_STATUS_H] = iron_window_height() * 0.3;
g_config->layout->buffer[LAYOUT_SIZE_SIDEBAR_W] = iron_window_width() * 0.52;
float h = UI_ELEMENT_H() + UI_ELEMENT_OFFSET() + 2;
g_config->layout->buffer[LAYOUT_SIZE_SIDEBAR_H0] = iron_window_height() - h;
g_config->layout->buffer[LAYOUT_SIZE_SIDEBAR_H1] = h;
render_path_resize();
}
else if (g_config->workspace == WORKSPACE_PLAYER) {
ui_base_show = false;
render_path_resize();
}
base_resize();
}
void base_update_workflow_create_sculpt_layer(void *_) {
if (history_undo_layers != NULL) {
sculpt_layers_create_sculpt_layer();
sys_remove_update(base_update_workflow_create_sculpt_layer);
}
}
void base_update_workflow() {
// Update Material Output nodes
for (i32 i = 0; i < g_project->_->materials->length; ++i) {
ui_node_array_t *nodes = g_project->_->materials->buffer[i]->canvas->nodes;
for (i32 j = 0; j < nodes->length; ++j) {
if (string_equals(nodes->buffer[j]->type, "OUTPUT_MATERIAL_PBR")) {
nodes->buffer[j]->inputs->length = g_config->workflow == WORKFLOW_PBR ? 9 : 2;
nodes->buffer[j]->inputs->buffer[0]->name = g_config->workflow == WORKFLOW_SCULPT ? tr("Displacement") : tr("Base Color");
}
}
}
if (g_config->workflow == WORKFLOW_SCULPT) {
slot_layer_t *first_sculpt = NULL;
for (i32 i = g_project->_->layers->length - 1; i >= 0; --i) {
if (g_project->_->layers->buffer[i]->texpaint_sculpt != NULL) {
first_sculpt = g_project->_->layers->buffer[i];
break;
}
}
if (first_sculpt == NULL) {
sys_remove_update(base_update_workflow_create_sculpt_layer);
sys_notify_on_update(base_update_workflow_create_sculpt_layer, NULL);
}
else {
context_set_layer(first_sculpt);
}
}
else {
for (i32 i = g_project->_->layers->length - 1; i >= 0; --i) {
slot_layer_t *l = g_project->_->layers->buffer[i];
if (l->texpaint_sculpt == NULL && slot_layer_is_layer(l)) {
context_set_layer(l);
break;
}
}
}
}
void base_run_in_player() {
if (string_equals(g_project->_->filepath, "")) {
console_error(tr("Save project first"));
return;
}
export_arm_run_project();
char *bin = iron_get_arg(0);
iron_sys_command(string("%s %s --player", bin, g_project->_->filepath));
// iron_exec_async()
}
uint32_t base_darker(uint32_t x, uint32_t y) {
uint32_t r = ((x >> 16) & 0xff);
uint32_t g = ((x >> 8) & 0xff);
uint32_t b = ((x) & 0xff);
uint32_t ry = ((y >> 16) & 0xff);
uint32_t gy = ((y >> 8) & 0xff);
uint32_t by = ((y) & 0xff);
r = r > ry ? r - ry : 0;
g = g > gy ? g - gy : 0;
b = b > by ? b - by : 0;
return (x & 0xff000000) | (r << 16) | (g << 8) | b;
}
string_array_t *base_get_viewport_modes() {
string_array_t *modes = any_array_create_from_raw(
(void *[]){
tr("Lit"),
tr("Base Color"),
tr("Normal"),
tr("Occlusion"),
tr("Roughness"),
tr("Metallic"),
tr("Opacity"),
tr("Height"),
tr("Emission"),
tr("Subsurface"),
tr("TexCoord"),
tr("Object Normal"),
tr("Material ID"),
tr("Object ID"),
tr("Mask"),
},
15);
if (gpu_raytrace_supported()) {
any_array_push(modes, tr("Path Traced"));
}
return modes;
}
string_array_t *base_get_viewport_mode_shortcuts() {
string_array_t *shortcuts = any_array_create_from_raw(
(void *[]){
"l",
"b",
"n",
"o",
"r",
"m",
"a",
"h",
"e",
"s",
"t",
"1",
"2",
"3",
"4",
},
15);
if (gpu_raytrace_supported()) {
any_array_push(shortcuts, "p");
}
return shortcuts;
}