paint: meshes tab previews
This commit is contained in:
@@ -561,6 +561,7 @@ void ui_box_show_message(char *title, char *text, bool c
|
||||
void ui_box_show_custom(void (*commands)(void), i32 mw, i32 mh, void (*on_hide)(void), bool draggable, char *title);
|
||||
void ui_box_hide();
|
||||
void tab_meshes_draw(ui_handle_t *htab);
|
||||
void tab_meshes_reset_preview_map();
|
||||
void tab_scene_select_object(mesh_object_t *mo);
|
||||
void tab_scene_sort();
|
||||
void tab_scene_import_mesh_done();
|
||||
|
||||
@@ -102,6 +102,7 @@ void import_mesh_finish_import() {
|
||||
ui_view2d_hwnd->redraws = 2;
|
||||
render_path_raytrace_ready = false;
|
||||
g_context->paint_body = NULL;
|
||||
tab_meshes_reset_preview_map();
|
||||
}
|
||||
|
||||
void _import_mesh_make_mesh_finish_import(void *_) {
|
||||
|
||||
@@ -341,6 +341,7 @@ void project_new(bool reset_layers) {
|
||||
if (in_use)
|
||||
draw_begin(current, false, 0);
|
||||
|
||||
tab_meshes_reset_preview_map();
|
||||
base_update_workflow();
|
||||
project_set_default_envmap();
|
||||
context_select_tool(TOOL_TYPE_BRUSH);
|
||||
|
||||
+268
-30
@@ -1,7 +1,10 @@
|
||||
|
||||
#include "global.h"
|
||||
|
||||
i32 _tab_meshes_draw_i;
|
||||
extern buffer_t *slot_material_default_canvas;
|
||||
|
||||
i32 _tab_meshes_draw_i;
|
||||
any_map_t *tab_meshes_preview_map = NULL;
|
||||
|
||||
void tab_meshes_draw_properties(mesh_object_t *o) {
|
||||
g_context->selected_object = o->base;
|
||||
@@ -358,6 +361,153 @@ void tab_meshes_draw_import() {
|
||||
}
|
||||
}
|
||||
|
||||
static vec4_t aabb_center(mesh_data_t *raw) {
|
||||
vec4_t aabb_min = (vec4_t){-0.01, -0.01, -0.01, 0.0};
|
||||
vec4_t aabb_max = (vec4_t){0.01, 0.01, 0.01, 0.0};
|
||||
i32 i = 0;
|
||||
vertex_array_t *positions = mesh_data_get_vertex_array(raw, "pos");
|
||||
while (i < positions->values->length) {
|
||||
if (positions->values->buffer[i] > aabb_max.x) {
|
||||
aabb_max.x = positions->values->buffer[i];
|
||||
}
|
||||
if (positions->values->buffer[i + 1] > aabb_max.y) {
|
||||
aabb_max.y = positions->values->buffer[i + 1];
|
||||
}
|
||||
if (positions->values->buffer[i + 2] > aabb_max.z) {
|
||||
aabb_max.z = positions->values->buffer[i + 2];
|
||||
}
|
||||
if (positions->values->buffer[i] < aabb_min.x) {
|
||||
aabb_min.x = positions->values->buffer[i];
|
||||
}
|
||||
if (positions->values->buffer[i + 1] < aabb_min.y) {
|
||||
aabb_min.y = positions->values->buffer[i + 1];
|
||||
}
|
||||
if (positions->values->buffer[i + 2] < aabb_min.z) {
|
||||
aabb_min.z = positions->values->buffer[i + 2];
|
||||
}
|
||||
i += 4;
|
||||
}
|
||||
f32 f = raw->scale_pos / 32767.0f;
|
||||
return (vec4_t){(aabb_min.x + aabb_max.x) / 2.0f * f, (aabb_min.y + aabb_max.y) / 2.0f * f, (aabb_min.z + aabb_max.z) / 2.0f * f, 0.0f};
|
||||
}
|
||||
|
||||
void tab_meshes_make_preview(mesh_object_t *o) {
|
||||
if (tab_meshes_preview_map == NULL) {
|
||||
tab_meshes_preview_map = any_map_create();
|
||||
gc_root(tab_meshes_preview_map);
|
||||
}
|
||||
|
||||
char *uid_key = i32_to_string(o->base->uid);
|
||||
gpu_texture_t *image = any_map_get(tab_meshes_preview_map, uid_key);
|
||||
if (image == NULL) {
|
||||
image = gpu_create_render_target(util_render_material_preview_size, util_render_material_preview_size, GPU_TEXTURE_FORMAT_RGBA64);
|
||||
any_map_set(tab_meshes_preview_map, uid_key, image);
|
||||
}
|
||||
|
||||
g_context->material_preview = true;
|
||||
|
||||
slot_material_t *mat = GC_ALLOC_INIT(slot_material_t, {0});
|
||||
mat->image = image;
|
||||
mat->image_icon = gpu_create_render_target(50, 50, GPU_TEXTURE_FORMAT_RGBA64);
|
||||
mat->preview_ready = true;
|
||||
mat->canvas = armpack_decode(slot_material_default_canvas);
|
||||
mat->canvas = util_clone_canvas(mat->canvas); // Clone to create GC references
|
||||
|
||||
slot_material_t *_material = g_context->material;
|
||||
g_context->material = mat;
|
||||
|
||||
mesh_object_t_array_t *_scene_meshes = scene_meshes;
|
||||
gc_unroot(scene_meshes);
|
||||
scene_meshes = any_array_create_from_raw((void *[]){o}, 1);
|
||||
gc_root(scene_meshes);
|
||||
|
||||
mesh_object_t *painto = g_context->paint_object;
|
||||
g_context->paint_object = o;
|
||||
|
||||
g_context->saved_camera = scene_camera->base->transform->local;
|
||||
mat4_t m =
|
||||
(mat4_t){0.9146286343879498, 0.404295023959927, 0.000007410128652369705, 0, -0.0032648027153306235, 0.007367569133732468, 0.9999675337275382, 0,
|
||||
0.404281837254303, -0.9145989516155143, 0.008058532943908717, 0, 0.4659988049397712, -1.0687517188018691, 0.015935682577325486, 1};
|
||||
transform_set_matrix(scene_camera->base->transform, m);
|
||||
f32 saved_fov = scene_camera->data->fov;
|
||||
scene_camera->data->fov = 0.4;
|
||||
viewport_update_camera_type(CAMERA_TYPE_PERSPECTIVE);
|
||||
|
||||
world_data_t *probe = scene_world;
|
||||
f32 _probe_strength = probe->strength;
|
||||
probe->strength = 2;
|
||||
f32 _envmap_angle = g_context->envmap_angle;
|
||||
g_context->envmap_angle = 0.0;
|
||||
|
||||
gpu_texture_t *_envmap = scene_world->_->envmap;
|
||||
scene_world->_->envmap = g_context->preview_envmap;
|
||||
|
||||
// Fit into camera
|
||||
vec4_t saved_scale = o->base->transform->scale;
|
||||
vec4_t saved_loc = o->base->transform->loc;
|
||||
quat_t saved_rot = o->base->transform->rot;
|
||||
{
|
||||
vec4_t aabb = mesh_data_calculate_aabb(o->data);
|
||||
f32 r = math_sqrt(aabb.x * aabb.x + aabb.y * aabb.y + aabb.z * aabb.z);
|
||||
f32 s = 1.0 / r;
|
||||
if (o->base->parent == NULL) {
|
||||
s *= o->base->transform->scale.x;
|
||||
}
|
||||
s *= o->data->scale_pos;
|
||||
vec4_t center = aabb_center(o->data);
|
||||
o->base->transform->scale = (vec4_t){s, s, s, 1.0};
|
||||
o->base->transform->loc = (vec4_t){-s * center.x, -s * center.y, -s * center.z, 1.0};
|
||||
o->base->transform->rot = (quat_t){0, 0, 0, 1};
|
||||
transform_build_matrix(o->base->transform);
|
||||
}
|
||||
|
||||
_render_path_last_w = util_render_material_preview_size;
|
||||
_render_path_last_h = util_render_material_preview_size;
|
||||
camera_object_build_proj(scene_camera, -1.0);
|
||||
camera_object_build_mat(scene_camera);
|
||||
|
||||
make_material_parse_mesh_preview_material();
|
||||
void (*_commands)(void) = render_path_commands;
|
||||
gc_unroot(render_path_commands);
|
||||
render_path_commands = render_path_preview_commands_preview;
|
||||
gc_root(render_path_commands);
|
||||
render_path_render_frame();
|
||||
gc_unroot(render_path_commands);
|
||||
render_path_commands = _commands;
|
||||
gc_root(render_path_commands);
|
||||
|
||||
g_context->material_preview = false;
|
||||
_render_path_last_w = sys_w();
|
||||
_render_path_last_h = sys_h();
|
||||
|
||||
// Restore
|
||||
o->base->transform->scale = saved_scale;
|
||||
o->base->transform->loc = saved_loc;
|
||||
o->base->transform->rot = saved_rot;
|
||||
transform_build_matrix(o->base->transform);
|
||||
|
||||
gc_unroot(scene_meshes);
|
||||
scene_meshes = _scene_meshes;
|
||||
gc_root(scene_meshes);
|
||||
g_context->paint_object = painto;
|
||||
|
||||
transform_set_matrix(scene_camera->base->transform, g_context->saved_camera);
|
||||
viewport_update_camera_type(g_context->camera_type);
|
||||
scene_camera->data->fov = saved_fov;
|
||||
camera_object_build_proj(scene_camera, -1.0);
|
||||
camera_object_build_mat(scene_camera);
|
||||
|
||||
probe->strength = _probe_strength;
|
||||
g_context->envmap_angle = _envmap_angle;
|
||||
scene_world->_->envmap = _envmap;
|
||||
|
||||
g_context->material = _material;
|
||||
gpu_delete_texture(mat->image_icon);
|
||||
|
||||
make_material_parse_mesh_material();
|
||||
g_context->ddirty = 0;
|
||||
}
|
||||
|
||||
void tab_meshes_draw(ui_handle_t *htab) {
|
||||
if (ui_tab(htab, tr("Meshes"), false, -1, false) && ui->_window_h > ui_statusbar_default_h * UI_SCALE()) {
|
||||
|
||||
@@ -382,40 +532,128 @@ void tab_meshes_draw(ui_handle_t *htab) {
|
||||
|
||||
ui_end_sticky();
|
||||
|
||||
for (i32 i = 0; i < project_paint_objects->length; ++i) {
|
||||
i32 slotw = math_floor(78 * UI_SCALE());
|
||||
i32 num = math_floor(ui->_window_w / (float)slotw);
|
||||
if (num == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
f32_array_t *row = f32_array_create_from_raw(
|
||||
(f32[]){
|
||||
-30,
|
||||
1.0,
|
||||
},
|
||||
2);
|
||||
ui_row(row);
|
||||
gpu_texture_t *icons = resource_get("icons05x.k");
|
||||
rect_t *rect = resource_tile50(icons, ICON_CUBE);
|
||||
i32 icon_h = 25 * UI_SCALE();
|
||||
ui_sub_image(icons, base_darker(ui->ops->theme->LABEL_COL, 0x00333333), icon_h, rect->x / 2.0, rect->y / 2.0, rect->w / 2.0, rect->h / 2.0);
|
||||
f32 uix = 0.0;
|
||||
f32 uiy = 0.0;
|
||||
|
||||
mesh_object_t *o = project_paint_objects->buffer[i];
|
||||
ui_handle_t *h = ui_handle(__ID__);
|
||||
h->b = o->base->visible;
|
||||
o->base->visible = ui_check(h, o->base->name, "");
|
||||
|
||||
if (ui->is_hovered && ui->input_released_r) {
|
||||
_tab_meshes_draw_i = i;
|
||||
ui_menu_draw(&tab_meshes_draw_context_menu, -1, -1);
|
||||
for (i32 row = 0; row < math_floor(math_ceil(project_paint_objects->length / (float)num)); ++row) {
|
||||
f32_array_t *ar = f32_array_create_from_raw((f32[]){}, 0);
|
||||
for (i32 i = 0; i < num * 2; ++i) {
|
||||
f32_array_push(ar, 1 / (float)num);
|
||||
}
|
||||
if (h->changed) {
|
||||
mesh_object_t_array_t *visibles = any_array_create_from_raw((void *[]){}, 0);
|
||||
for (i32 i = 0; i < project_paint_objects->length; ++i) {
|
||||
mesh_object_t *p = project_paint_objects->buffer[i];
|
||||
if (p->base->visible) {
|
||||
any_array_push(visibles, p);
|
||||
}
|
||||
ui_row(ar);
|
||||
|
||||
ui->_x += 2;
|
||||
if (row > 0) {
|
||||
ui->_y += UI_ELEMENT_OFFSET() * 10.0;
|
||||
}
|
||||
|
||||
for (i32 j = 0; j < num; ++j) {
|
||||
i32 imgw = math_floor(75 * UI_SCALE());
|
||||
i32 i = j + row * num;
|
||||
if (i >= project_paint_objects->length) {
|
||||
ui_end_element_of_size(imgw);
|
||||
ui_end_element_of_size(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
mesh_object_t *o = project_paint_objects->buffer[i];
|
||||
uix = ui->_x;
|
||||
uiy = ui->_y;
|
||||
|
||||
// Draw mesh preview
|
||||
char *uid_key = i32_to_string(o->base->uid);
|
||||
gpu_texture_t *preview = tab_meshes_preview_map != NULL ? any_map_get(tab_meshes_preview_map, uid_key) : NULL;
|
||||
ui_state_t state;
|
||||
if (preview != NULL) {
|
||||
state = ui_image(preview, 0xffffffff, (f32)slotw);
|
||||
}
|
||||
else {
|
||||
gpu_texture_t *icons = resource_get("icons.k");
|
||||
rect_t *rect = resource_tile50(icons, ICON_CUBE);
|
||||
state = ui_sub_image(icons, ui->ops->theme->BUTTON_COL, slotw, rect->x, rect->y, rect->w, rect->h);
|
||||
sys_notify_on_next_frame(tab_meshes_make_preview, o);
|
||||
}
|
||||
|
||||
// Selection highlight
|
||||
if (g_context->paint_object == o) {
|
||||
f32 _uix = ui->_x;
|
||||
f32 _uiy = ui->_y;
|
||||
ui->_x = uix;
|
||||
ui->_y = uiy + 4;
|
||||
i32 hoff = i % 2 == 1 ? 1 : 0;
|
||||
i32 w = 75;
|
||||
ui_fill(0, 0, w + 3, 2, ui->ops->theme->HIGHLIGHT_COL);
|
||||
ui_fill(0, w - hoff + 2, w + 3, 2 + hoff, ui->ops->theme->HIGHLIGHT_COL);
|
||||
ui_fill(0, 0, 2, w + 3, ui->ops->theme->HIGHLIGHT_COL);
|
||||
ui_fill(w + 2, 0, 2, w + 4, ui->ops->theme->HIGHLIGHT_COL);
|
||||
ui->_x = _uix;
|
||||
ui->_y = _uiy;
|
||||
}
|
||||
|
||||
// Click to select
|
||||
if (state == UI_STATE_STARTED && ui->input_y > ui->_window_y) {
|
||||
g_context->paint_object = o;
|
||||
}
|
||||
|
||||
// Context menu
|
||||
if (ui->is_hovered && ui->input_released_r) {
|
||||
g_context->paint_object = o;
|
||||
_tab_meshes_draw_i = i;
|
||||
ui_menu_draw(&tab_meshes_draw_context_menu, -1, -1);
|
||||
}
|
||||
|
||||
if (ui->is_hovered) {
|
||||
ui_tooltip(o->base->name);
|
||||
}
|
||||
|
||||
// Label
|
||||
i32 check_w = UI_ELEMENT_H();
|
||||
i32 text_w = draw_string_width(ui->ops->font, ui->font_size, o->base->name);
|
||||
i32 center_x = (slotw - check_w - text_w) / 2;
|
||||
ui->_x = uix + (center_x > 0 ? center_x : 0);
|
||||
ui->_y += slotw * 0.9 + 8;
|
||||
|
||||
ui_handle_t *h = ui_handle(__ID__);
|
||||
h->b = o->base->visible;
|
||||
o->base->visible = ui_check(h, o->base->name, "");
|
||||
|
||||
if (h->changed) {
|
||||
mesh_object_t_array_t *visibles = any_array_create_from_raw((void *[]){}, 0);
|
||||
for (i32 k = 0; k < project_paint_objects->length; ++k) {
|
||||
mesh_object_t *p = project_paint_objects->buffer[k];
|
||||
if (p->base->visible) {
|
||||
any_array_push(visibles, p);
|
||||
}
|
||||
}
|
||||
util_mesh_merge(visibles);
|
||||
g_context->ddirty = 2;
|
||||
}
|
||||
|
||||
ui->_y -= slotw * 0.9 + 8;
|
||||
if (i == project_paint_objects->length - 1) {
|
||||
ui->_y += j == num - 1 ? imgw : imgw + UI_ELEMENT_H() + UI_ELEMENT_OFFSET();
|
||||
}
|
||||
util_mesh_merge(visibles);
|
||||
g_context->ddirty = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tab_meshes_reset_preview_map() {
|
||||
if (tab_meshes_preview_map == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
any_array_t *keys = map_keys(tab_meshes_preview_map);
|
||||
for (i32 i = 0; i < keys->length; ++i) {
|
||||
gpu_texture_t *image = any_map_get(tab_meshes_preview_map, keys->buffer[i]);
|
||||
gpu_delete_texture(image);
|
||||
}
|
||||
gc_unroot(tab_meshes_preview_map);
|
||||
tab_meshes_preview_map = NULL;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user