paint: merge multi raytrace

This commit is contained in:
luboslenco
2026-08-13 15:31:09 +02:00
parent b61743e2f1
commit f19f1d580e
16 changed files with 272 additions and 143 deletions
+13 -7
View File
@@ -126,7 +126,6 @@ void config_save() {
json_encode_f32("brush_alpha_discard", g_config->brush_alpha_discard);
json_encode_i32("dilate_radius", g_config->dilate_radius);
json_encode_string("blender", g_config->blender);
json_encode_i32("scene_atlas_res", g_config->scene_atlas_res);
json_encode_bool("grid_snap", g_config->grid_snap);
json_encode_bool("experimental", g_config->experimental);
json_encode_i32("neural_res", g_config->neural_res);
@@ -255,7 +254,6 @@ void config_init() {
g_config->show_asset_names = false;
g_config->dilate_radius = 2;
g_config->blender = "";
g_config->scene_atlas_res = TEXTURE_RES_RES8192;
g_config->pathtrace_mode = PATHTRACE_MODE_FAST;
g_config->grid_snap = false;
g_config->view2d_grid_show = false;
@@ -436,11 +434,6 @@ i32 config_get_layer_res() {
return config_texture_res_size(res);
}
i32 config_get_scene_atlas_res() {
i32 res = g_config->scene_atlas_res;
return config_texture_res_size(res);
}
void config_set_texture_res(i32 pos) {
if (pos != TEXTURE_RES_CUSTOM) {
f32 res = (f32)config_texture_res_size(pos);
@@ -517,3 +510,16 @@ bool config_is_iphone() {
return sys_display_ppi() > 330;
}
#endif
bool config_is_raytrace_fast() {
return g_config->pathtrace_mode == PATHTRACE_MODE_FAST || g_config->pathtrace_mode == PATHTRACE_MODE_MULTI_FAST;
}
bool config_is_raytrace_multi() {
bool multi = g_config->pathtrace_mode == PATHTRACE_MODE_MULTI_FAST || g_config->pathtrace_mode == PATHTRACE_MODE_MULTI_QUALITY;
return multi && g_context->viewport_mode == VIEWPORT_MODE_PATH_TRACE;
}
void config_apply_raytrace_multi() {
gpu_raytrace_multi = config_is_raytrace_multi();
}
+4 -4
View File
@@ -325,10 +325,6 @@ void context_select_paint_object(mesh_object_t *o) {
p->skip_context = "paint";
}
// #ifdef is_forge
// g_context->paint_object->skip_context = "";
// #endif
g_context->paint_object = o;
i32 mask = slot_layer_get_object_mask(g_context->layer);
@@ -467,6 +463,10 @@ void context_set_viewport_mode(viewport_mode_t mode) {
}
make_material_parse_mesh_material();
if (g_context->viewport_mode == VIEWPORT_MODE_PATH_TRACE) {
util_mesh_merge(NULL);
}
// Rotate mode is not supported for path tracing yet
if (g_context->viewport_mode == VIEWPORT_MODE_PATH_TRACE && g_context->camera_controls == CAMERA_CONTROLS_ROTATE) {
g_context->camera_controls = CAMERA_CONTROLS_ORBIT;
+4 -2
View File
@@ -108,8 +108,10 @@ typedef enum {
} export_destination_t;
typedef enum {
PATHTRACE_MODE_FAST = 0,
PATHTRACE_MODE_QUALITY = 1,
PATHTRACE_MODE_FAST = 0,
PATHTRACE_MODE_QUALITY = 1,
PATHTRACE_MODE_MULTI_FAST = 2,
PATHTRACE_MODE_MULTI_QUALITY = 3,
} pathtrace_mode_t;
typedef enum {
+8 -3
View File
@@ -81,6 +81,7 @@ void layers_merge_down();
slot_layer_t *layers_merge_group(slot_layer_t *l);
void layers_merge_layer(slot_layer_t *l0, slot_layer_t *l1, bool use_mask);
slot_layer_t *layers_flatten(bool height_to_normal, slot_layer_t_array_t *layers);
void layers_draw_mesh_materials();
void layers_on_resized();
void layers_create_filter();
void layers_create_image_layer(asset_t *asset);
@@ -110,7 +111,6 @@ void config_apply();
i32 config_get_super_sample_quality(f32 f);
f32 config_get_super_sample_size(i32 i);
i32 config_get_layer_res();
i32 config_get_scene_atlas_res();
void config_set_texture_res(i32 pos);
i32 config_get_texture_res_x();
i32 config_get_texture_res_y();
@@ -119,6 +119,9 @@ void config_load_theme(char *theme, bool tag_redraw);
void config_enable_plugin(char *f);
void config_disable_plugin(char *f);
bool config_is_iphone();
bool config_is_raytrace_fast();
bool config_is_raytrace_multi();
void config_apply_raytrace_multi();
void box_export_show_textures();
void box_export_show_bake_material();
void box_export_show_mesh();
@@ -228,7 +231,7 @@ void util_layer_repaint_path(slot_layer_t *l);
void util_layer_remove_path_point(slot_layer_t *l);
void util_layer_clear_path_points(slot_layer_t *l);
f32 util_layer_brush_screen_radius();
void make_texcoord_run(node_shader_t *kong);
void make_texcoord_run(node_shader_t *kong, bool is_atlas);
void context_init();
void context_select_material(i32 i);
void context_set_material(slot_material_t *m);
@@ -343,6 +346,7 @@ void render_path_preview_init();
void render_path_preview_commands_preview();
void render_path_preview_commands_decal();
node_shader_context_t *make_paint_run(material_t *data, material_context_t *matcon);
node_shader_context_t *make_paint_run_context(material_t *data, material_context_t *matcon, char *context_id);
node_shader_context_t *make_mesh_preview_run(material_t *data, material_context_t *matcon, bool viewport);
material_data_t *make_mesh_preview_viewport(slot_material_t *slot);
void import_sound_run(char *path);
@@ -607,7 +611,8 @@ void util_mesh_decimate(f32 strength);
void util_mesh_smooth();
void util_mesh_bevel(f32 amount);
void util_mesh_subdivide();
void util_mesh_pack_uvs(i16_array_t *texa);
i32 util_mesh_atlas_stride();
i32 util_mesh_atlas_slot(object_t *object);
void ui_header_init();
void ui_header_render_ui();
void ui_header_draw_tool_properties();
+1 -1
View File
@@ -235,7 +235,7 @@ void import_mesh_add_mesh(raw_mesh_t *mesh) {
}
mesh_data_t *raw = import_mesh_raw_mesh(mesh);
// util_mesh_pack_uvs(mesh->texa);
mesh_data_t *md = mesh_data_create(raw);
md->_->skin_blob = mesh->blob;
gc_unroot(mesh->blob);
+37 -2
View File
@@ -149,13 +149,48 @@ material_data_t *make_mesh_preview_viewport(slot_material_t *slot) {
shader_context_load(con->data);
material_context_load(mcon);
tool_type_t _tool = g_context->tool;
i32 _fill_type = g_context->fill_type;
slot_layer_t *_layer = g_context->layer;
bool _select_active = g_context->select_active;
bool _colorid_picked = g_context->colorid_picked;
bool _picker_paint_mask = g_context->picker_paint_mask;
gpu_texture_t *_brush_stencil_image = g_context->brush_stencil_image;
gpu_texture_t *_brush_mask_image = g_context->brush_mask_image;
blend_type_t _brush_blending = g_context->brush_blending;
g_context->tool = TOOL_TYPE_FILL;
g_context->fill_type = FILL_TYPE_OBJECT;
g_context->layer = GC_ALLOC_INIT(slot_layer_t, {.fill_material = slot, .uv_type = UV_TYPE_UVMAP, .scale = 1.0, .visible = true});
g_context->select_active = false;
g_context->colorid_picked = false;
g_context->picker_paint_mask = false;
g_context->brush_stencil_image = NULL;
g_context->brush_mask_image = NULL;
g_context->brush_blending = BLEND_TYPE_MIX;
material_context_t *amcon = GC_ALLOC_INIT(material_context_t, {.name = "atlas", .bind_textures = any_array_create_from_raw((void *[]){}, 0)});
material_t *amm = GC_ALLOC_INIT(material_t, {.name = "Material", .canvas = slot->canvas});
node_shader_context_t *acon = make_paint_run_context(amm, amcon, "atlas");
shader_context_load(acon->data);
material_context_load(amcon);
g_context->tool = _tool;
g_context->fill_type = _fill_type;
g_context->layer = _layer;
g_context->select_active = _select_active;
g_context->colorid_picked = _colorid_picked;
g_context->picker_paint_mask = _picker_paint_mask;
g_context->brush_stencil_image = _brush_stencil_image;
g_context->brush_mask_image = _brush_mask_image;
g_context->brush_blending = _brush_blending;
shader_data_t *sd = GC_ALLOC_INIT(shader_data_t, {0});
sd->name = string("_material_%s", i32_to_string(slot->id));
sd->contexts = any_array_create_from_raw((void *[]){con->data}, 1);
sd->contexts = any_array_create_from_raw((void *[]){con->data, acon->data}, 2);
material_data_t *md = GC_ALLOC_INIT(material_data_t, {0});
md->name = sd->name;
md->contexts = any_array_create_from_raw((void *[]){mcon}, 1);
md->contexts = any_array_create_from_raw((void *[]){mcon, amcon}, 2);
md->_ = GC_ALLOC_INIT(material_data_runtime_t, {0});
md->_->shader = sd;
md->_->uid = 0;
+28 -21
View File
@@ -98,33 +98,39 @@ string_array_t *make_paint_color_attachments() {
}
node_shader_context_t *make_paint_run(material_t *data, material_context_t *matcon) {
return make_paint_run_context(data, matcon, "paint");
}
node_shader_context_t *make_paint_run_context(material_t *data, material_context_t *matcon, char *context_id) {
bool picking_tool = g_context->tool == TOOL_TYPE_COLORID || g_context->tool == TOOL_TYPE_PICKER || g_context->tool == TOOL_TYPE_MATERIAL ||
g_context->tool == TOOL_TYPE_CURSOR;
bool is_atlas = string_equals(context_id, "atlas");
if (g_context->layer->texpaint_sculpt != NULL && !picking_tool) {
return sculpt_make_sculpt_run(data, matcon);
}
char *context_id = "paint";
shader_context_t *props = GC_ALLOC_INIT(shader_context_t, {.name = context_id,
.depth_write = false,
.compare_mode = "always",
.cull_mode = "none",
.vertex_elements = any_array_create_from_raw(
shader_context_t *props = GC_ALLOC_INIT(shader_context_t, {.name = context_id,
.depth_write = false,
.compare_mode = "always",
.cull_mode = "none",
.vertex_elements = any_array_create_from_raw(
(void *[]){
GC_ALLOC_INIT(vertex_element_t, {.name = "pos", .data = "short4norm"}),
GC_ALLOC_INIT(vertex_element_t, {.name = "nor", .data = "short2norm"}),
GC_ALLOC_INIT(vertex_element_t, {.name = "tex", .data = "short2norm"}),
},
3),
.color_attachments = make_paint_color_attachments()});
node_shader_context_t *con_paint = node_shader_context_create(data, props);
.color_attachments = make_paint_color_attachments()});
node_shader_context_t *con_paint = node_shader_context_create(data, props);
if (mesh_data_get_vertex_array(g_context->paint_object->data, "col") != NULL) {
node_shader_context_add_elem(con_paint, "col", "short4norm");
}
if (!is_atlas) {
if (mesh_data_get_vertex_array(g_context->paint_object->data, "col") != NULL) {
node_shader_context_add_elem(con_paint, "col", "short4norm");
}
if (mesh_data_get_vertex_array(g_context->paint_object->data, "tex1") != NULL) {
node_shader_context_add_elem(con_paint, "tex1", "short2norm");
if (mesh_data_get_vertex_array(g_context->paint_object->data, "tex1") != NULL) {
node_shader_context_add_elem(con_paint, "tex1", "short2norm");
}
}
con_paint->data->color_writes_red = u8_array_create_from_raw(
@@ -159,7 +165,7 @@ node_shader_context_t *make_paint_run(material_t *data, material_context_t *matc
true,
},
4);
con_paint->allow_vcols = mesh_data_get_vertex_array(g_context->paint_object->data, "col") != NULL;
con_paint->allow_vcols = !is_atlas && mesh_data_get_vertex_array(g_context->paint_object->data, "col") != NULL;
node_shader_t *kong = node_shader_context_make_kong(con_paint);
@@ -189,12 +195,13 @@ node_shader_context_t *make_paint_run(material_t *data, material_context_t *matc
bool uv_island_fill = g_context->tool == TOOL_TYPE_FILL && g_context->fill_type == FILL_TYPE_UV_ISLAND;
bool decal = context_is_decal();
if (g_context->layer->uv_map == 1) {
node_shader_write_vert(kong, "var tpos: float2 = float2(input.tex1.x * 2.0 - 1.0, (1.0 - input.tex1.y) * 2.0 - 1.0);");
}
else {
node_shader_write_vert(kong, "var tpos: float2 = float2(input.tex.x * 2.0 - 1.0, (1.0 - input.tex.y) * 2.0 - 1.0);");
char *tuv = g_context->layer->uv_map == 1 ? "input.tex1" : "input.tex";
if (is_atlas) {
node_shader_add_constant(kong, "atlas_transform: float3", "_atlas_transform");
node_shader_write_vert(kong, string("var atlas_uv: float2 = %s * constants.atlas_transform.z + constants.atlas_transform.xy;", tuv));
tuv = "atlas_uv";
}
node_shader_write_vert(kong, string("var tpos: float2 = float2(%s.x * 2.0 - 1.0, (1.0 - %s.y) * 2.0 - 1.0);", tuv, tuv));
node_shader_write_vert(kong, "output.pos = float4(tpos, 0.0, 1.0);");
@@ -304,7 +311,7 @@ node_shader_context_t *make_paint_run(material_t *data, material_context_t *matc
make_discard_material_id(kong, NULL);
}
make_texcoord_run(kong);
make_texcoord_run(kong, is_atlas);
if (g_context->tool == TOOL_TYPE_CLONE || g_context->tool == TOOL_TYPE_BLUR) {
node_shader_add_texture(kong, "gbuffer2", NULL);
@@ -328,7 +335,7 @@ node_shader_context_t *make_paint_run(material_t *data, material_context_t *matc
parser_material_triplanar = uv_type == UV_TYPE_TRIPLANAR && !decal;
parser_material_sample_keep_aspect = decal;
gc_unroot(parser_material_sample_uv_scale);
parser_material_sample_uv_scale = "constants.brush_scale";
parser_material_sample_uv_scale = is_atlas ? "1.0" : "constants.brush_scale";
gc_root(parser_material_sample_uv_scale);
shader_out_t *sout = parser_material_parse(g_context->material->canvas, con_paint, kong, matcon);
parser_material_parse_emission = false;
+13 -10
View File
@@ -1,7 +1,7 @@
#include "../global.h"
void make_texcoord_run(node_shader_t *kong) {
void make_texcoord_run(node_shader_t *kong, bool is_atlas) {
bool fill_layer = g_context->layer->fill_material != NULL;
uv_type_t uv_type = fill_layer ? g_context->layer->uv_type : g_context->brush_paint;
@@ -9,8 +9,13 @@ void make_texcoord_run(node_shader_t *kong) {
f32 angle = g_context->brush_angle + g_context->brush_nodes_angle;
f32 uv_angle = fill_layer ? g_context->layer->angle : angle;
if (uv_type == UV_TYPE_PROJECT || decal) { // TexCoords - project
char *scale = "1.0";
if (!is_atlas) {
node_shader_add_constant(kong, "brush_scale: float", "_brush_scale");
scale = "constants.brush_scale";
}
if (uv_type == UV_TYPE_PROJECT || decal) { // TexCoords - project
node_shader_write_attrib_frag(kong, "var uvsp: float2 = sp.xy;");
if (fill_layer) { // Decal layer
@@ -117,17 +122,16 @@ void make_texcoord_run(node_shader_t *kong) {
}
}
node_shader_write_attrib_frag(kong, "var tex_coord: float2 = uvsp * constants.brush_scale;");
node_shader_write_attrib_frag(kong, string("var tex_coord: float2 = uvsp * %s;", scale));
}
else if (uv_type == UV_TYPE_UVMAP) { // TexCoords - uvmap
node_shader_add_constant(kong, "brush_scale: float", "_brush_scale");
node_shader_add_out(kong, "tex_coord: float2");
if (g_context->layer->uv_map == 1) {
node_shader_write_vert(kong, "output.tex_coord = input.tex1 * constants.brush_scale;");
node_shader_write_vert(kong, string("output.tex_coord = input.tex1 * %s;", scale));
}
else {
node_shader_write_vert(kong, "output.tex_coord = input.tex * constants.brush_scale;");
node_shader_write_vert(kong, string("output.tex_coord = input.tex * %s;", scale));
}
if (uv_angle > 0.0) {
@@ -141,14 +145,13 @@ void make_texcoord_run(node_shader_t *kong) {
else { // UV_TYPE_TRIPLANAR, TexCoords - triplanar
kong->frag_wposition = true;
kong->frag_n = true;
node_shader_add_constant(kong, "brush_scale: float", "_brush_scale");
node_shader_write_attrib_frag(kong, "var tri_weight: float3 = input.wnormal * input.wnormal;");
node_shader_write_attrib_frag(kong, "var tri_max: float = max(tri_weight.x, max(tri_weight.y, tri_weight.z));");
node_shader_write_attrib_frag(kong, "tri_weight = max3(tri_weight - float3(tri_max * 0.75, tri_max * 0.75, tri_max * 0.75), float3(0.0, 0.0, 0.0));");
node_shader_write_attrib_frag(kong, "var tex_coord_blend: float3 = tri_weight * (1.0 / (tri_weight.x + tri_weight.y + tri_weight.z));");
node_shader_write_attrib_frag(kong, "var tex_coord: float2 = input.wposition.yz * constants.brush_scale * 0.5;");
node_shader_write_attrib_frag(kong, "var tex_coord1: float2 = input.wposition.xz * constants.brush_scale * 0.5;");
node_shader_write_attrib_frag(kong, "var tex_coord2: float2 = input.wposition.xy * constants.brush_scale * 0.5;");
node_shader_write_attrib_frag(kong, string("var tex_coord: float2 = input.wposition.yz * %s * 0.5;", scale));
node_shader_write_attrib_frag(kong, string("var tex_coord1: float2 = input.wposition.xz * %s * 0.5;", scale));
node_shader_write_attrib_frag(kong, string("var tex_coord2: float2 = input.wposition.xy * %s * 0.5;", scale));
if (uv_angle != 0.0) {
node_shader_add_constant(kong, "brush_angle: float2", "_brush_angle");
node_shader_write_attrib_frag(kong, "tex_coord = float2(tex_coord.x * constants.brush_angle.x - tex_coord.y * constants.brush_angle.y, tex_coord.x "
+5
View File
@@ -90,6 +90,11 @@ void render_gizmo_update() {
transform_build_matrix(paint_object->transform);
ui_header_handle->redraws = 2;
if (config_is_raytrace_multi()) {
render_path_raytrace_ready = false;
g_context->ddirty = 2;
}
physics_body_t *pb = paint_object->_->body;
if (pb != NULL) {
physics_body_sync_transform(pb);
+26 -24
View File
@@ -16,10 +16,10 @@ void render_path_raytrace_commands(bool use_live_layer) {
render_path_raytrace_init_shader = true;
}
char *ext = "";
// if (g_context->tool == TOOL_TYPE_CURSOR) {
// ext = "forge_";
// }
char *mode = g_config->pathtrace_mode == PATHTRACE_MODE_FAST ? "core" : "full";
if (config_is_raytrace_multi()) {
ext = "multi_";
}
char *mode = config_is_raytrace_fast() ? "core" : "full";
render_path_raytrace_raytrace_init(string("raytrace_brute_%s%s%s", ext, mode, render_path_raytrace_ext), true);
gc_unroot(render_path_raytrace_last_envmap);
render_path_raytrace_last_envmap = NULL;
@@ -137,12 +137,12 @@ void render_path_raytrace_build_data() {
mesh_object_t *mo = !context_layer_filter_used() ? g_context->merged_object : g_context->paint_object;
// if (g_context->tool == TOOL_TYPE_CURSOR) {
// render_path_raytrace_transform = mo->base->transform->world_unpack;
// }
// else {
render_path_raytrace_transform = mat4_identity();
// }
if (config_is_raytrace_multi()) {
render_path_raytrace_transform = mo->base->transform->world_unpack;
}
else {
render_path_raytrace_transform = mat4_identity();
}
f32 sc = mo->base->transform->scale.x * mo->data->scale_pos;
if (mo->base->parent != NULL) {
@@ -174,20 +174,21 @@ void render_path_raytrace_raytrace_init(char *shader_name, bool build) {
}
{
config_apply_raytrace_multi();
_gpu_raytrace_as_init();
// if (g_context->tool == TOOL_TYPE_CURSOR) {
// for (i32 i = 0; i < g_project->_->paint_objects->length; ++i) {
// mesh_object_t *po = g_project->_->paint_objects->buffer[i];
// if (!po->base->visible) {
// continue;
// }
// _gpu_raytrace_as_add(po->data->_->vertex_buffer, po->data->_->index_buffer, po->base->transform->world_unpack);
// }
// }
// else {
_gpu_raytrace_as_add(render_path_raytrace_vb, render_path_raytrace_ib, render_path_raytrace_transform);
// }
if (config_is_raytrace_multi()) {
for (i32 i = 0; i < g_project->_->paint_objects->length; ++i) {
mesh_object_t *po = g_project->_->paint_objects->buffer[i];
if (!po->base->visible) {
continue;
}
_gpu_raytrace_as_add(po->data->_->vertex_buffer, po->data->_->index_buffer, po->base->transform->world_unpack);
}
}
else {
_gpu_raytrace_as_add(render_path_raytrace_vb, render_path_raytrace_ib, render_path_raytrace_transform);
}
gpu_buffer_t *vb_full = g_context->merged_object->data->_->vertex_buffer;
gpu_buffer_t *ib_full = g_context->merged_object->data->_->index_buffer;
@@ -197,8 +198,9 @@ void render_path_raytrace_raytrace_init(char *shader_name, bool build) {
}
void render_path_raytrace_draw(bool use_live_layer) {
bool is_live = g_config->brush_live && render_path_paint_live_layer_drawn > 0;
if (g_context->ddirty > 1 || g_context->pdirty > 0 || is_live) {
bool is_live = g_config->brush_live && render_path_paint_live_layer_drawn > 0;
bool is_player = g_config->workspace == WORKSPACE_PLAYER;
if (g_context->ddirty > 1 || g_context->pdirty > 0 || is_live || is_player) {
render_path_raytrace_frame = 0;
}
-1
View File
@@ -139,7 +139,6 @@ typedef struct config {
f32 brush_alpha_discard;
i32 dilate_radius;
char *blender;
i32 scene_atlas_res;
bool grid_snap;
bool experimental;
i32 neural_res;
+4 -5
View File
@@ -413,10 +413,6 @@ void box_preferences_usage_tab() {
4);
g_config->layer_res = ui_combo(h_layer_res, res_combo, tr("Default Layer Resolution"), true, UI_ALIGN_LEFT, true);
ui_handle_t *h_scene_atlas_res = ui_handle(__ID__);
h_scene_atlas_res->i = g_config->scene_atlas_res;
g_config->scene_atlas_res = ui_combo(h_scene_atlas_res, res_combo, tr("Scene Atlas Resolution"), true, UI_ALIGN_LEFT, true);
ui_handle_t *h_server = ui_handle(__ID__);
h_server->text = string_copy(g_config->server);
g_config->server = string_copy(ui_text_input(h_server, tr("Cloud Server"), UI_ALIGN_LEFT, true, false));
@@ -615,13 +611,16 @@ void box_preferences_viewport_tab() {
(void *[]){
tr("Fast"),
tr("Quality"),
tr("Multi Fast"),
tr("Multi Quality"),
},
2);
4);
g_config->pathtrace_mode = ui_combo(h_pathtrace_mode, pathtrace_mode_combo, tr("Path Tracer"), true, UI_ALIGN_LEFT, true);
if (h_pathtrace_mode->changed) {
render_path_raytrace_ready = false;
render_path_raytrace_init_shader = true;
g_context->ddirty = 2;
util_mesh_merge(NULL);
}
ui_handle_t *h_render_mode = ui_handle(__ID__);
+6 -3
View File
@@ -85,6 +85,7 @@ void tab_meshes_on_material_deleted(i32 deleted_index) {
if (changed) {
g_project->mesh_materials = i32_array_create(0);
g_context->ddirty = 2;
g_context->rtdirty = 2;
}
}
@@ -117,6 +118,7 @@ void tab_meshes_on_material_reordered(i32 old_index, i32 new_index) {
if (changed) {
g_project->mesh_materials = i32_array_create(0);
g_context->ddirty = 2;
g_context->rtdirty = 2;
}
}
@@ -366,6 +368,7 @@ void tab_meshes_draw_context_menu() {
if (hmat->changed) {
tab_meshes_set_override(o, hmat->i - 1);
g_context->ddirty = 2;
g_context->rtdirty = 2;
g_project->mesh_materials = i32_array_create(0);
}
@@ -392,7 +395,7 @@ void tab_meshes_draw_context_menu() {
// Physics
if (g_config->experimental) {
physics_body_t *pb = o->base->_->body;
physics_body_t *pb = o->base->_->body;
string_array_t *phys_combo = string_array_create(0);
string_array_push(phys_combo, ""); // Empty = no physics
string_array_push(phys_combo, tr("Box"));
@@ -410,7 +413,7 @@ void tab_meshes_draw_context_menu() {
}
if (hphys->i > 0) {
physics_shape_t shape = (physics_shape_t)(hphys->i - 1);
bool dynamic = shape == PHYSICS_SHAPE_BOX || shape == PHYSICS_SHAPE_SPHERE;
bool dynamic = shape == PHYSICS_SHAPE_BOX || shape == PHYSICS_SHAPE_SPHERE;
sim_add_body(o->base, shape, dynamic ? 1.0 : 0.0);
pb = o->base->_->body;
}
@@ -548,7 +551,6 @@ mesh_object_t *tab_meshes_append_shape(char *mesh_name) {
raw = scene_raw->mesh_datas->buffer[0];
}
// util_mesh_pack_uvs(raw->vertex_arrays->buffer[2]->values);
mesh_data_t *md = mesh_data_create(raw);
md->_->handle = md->name;
mesh_object_t *mo = scene_add_mesh_object(md, g_project->_->paint_objects->buffer[0]->material, NULL);
@@ -568,6 +570,7 @@ mesh_object_t *tab_meshes_append_shape(char *mesh_name) {
any_array_push(g_project->_->paint_objects, mo);
tab_stages_add_object(mo->base->name);
g_context->paint_object = mo;
util_mesh_merge(NULL);
return mo;
}
+23 -18
View File
@@ -87,12 +87,6 @@ f32 uniforms_ext_f32_link(object_t *object, material_data_t *mat, char *link) {
return val;
}
else if (string_equals(link, "_brush_scale")) {
// if (g_context->tool == TOOL_TYPE_CURSOR) {
// i32 atlas_w = config_get_scene_atlas_res();
// i32 item_w = config_get_layer_res();
// i32 atlas_stride = atlas_w / (float)item_w;
// return atlas_stride;
// }
bool fill = g_context->layer->fill_material != NULL;
f32 val = (fill ? g_context->layer->scale : g_context->brush_scale) * g_context->brush_nodes_scale;
return val;
@@ -223,6 +217,14 @@ vec4_t uniforms_ext_vec3_link(object_t *object, material_data_t *mat, char *link
g_context->prev_paint_vec_y = g_context->last_paint_vec_y;
return v;
}
else if (string_equals(link, "_atlas_transform")) {
if (!config_is_raytrace_multi()) {
return (vec4_t){0.0, 0.0, 1.0, 1.0};
}
i32 stride = util_mesh_atlas_stride();
i32 slot = util_mesh_atlas_slot(object);
return (vec4_t){(slot % stride) / (f32)stride, (slot / stride) / (f32)stride, 1.0 / stride, 1.0};
}
else if (string_equals(link, "_decal_layer_loc")) {
v = (vec4_t){g_context->layer->decal_mat.m30, g_context->layer->decal_mat.m31, g_context->layer->decal_mat.m32, 1.0};
return v;
@@ -364,26 +366,29 @@ void uniforms_ext_cache_uv_map(void *_) {
util_uv_cache_uv_map();
}
static gpu_texture_t *_uniforms_ext_undo_target(char *name) {
render_target_t *rt = any_map_get(render_path_render_targets, name);
if (rt == NULL) {
rt = any_map_get(render_path_render_targets, "empty_black");
}
return rt->_image;
}
gpu_texture_t *uniforms_ext_tex_link(object_t *object, material_data_t *mat, char *link) {
if (string_equals(link, "_texpaint_undo")) {
i32 i = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1;
render_target_t *rt = any_map_get(render_path_render_targets, string("texpaint_undo%d", i));
return rt->_image;
i32 i = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1;
return _uniforms_ext_undo_target(string("texpaint_undo%d", i));
}
else if (string_equals(link, "_texpaint_nor_undo")) {
i32 i = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1;
render_target_t *rt = any_map_get(render_path_render_targets, string("texpaint_nor_undo%d", i));
return rt->_image;
i32 i = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1;
return _uniforms_ext_undo_target(string("texpaint_nor_undo%d", i));
}
else if (string_equals(link, "_texpaint_pack_undo")) {
i32 i = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1;
render_target_t *rt = any_map_get(render_path_render_targets, string("texpaint_pack_undo%d", i));
return rt->_image;
i32 i = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1;
return _uniforms_ext_undo_target(string("texpaint_pack_undo%d", i));
}
else if (string_equals(link, "_texpaint_sculpt_undo")) {
// Per-frame accumulation reference
render_target_t *rt = any_map_get(render_path_render_targets, "texpaint_sculpt_ref");
return rt->_image;
return _uniforms_ext_undo_target("texpaint_sculpt_ref"); // Per-frame accumulation reference
}
else if (string_equals(link, "_texcolorid")) {
if (g_project->_->assets->length == 0) {
+27 -4
View File
@@ -703,10 +703,6 @@ void layers_create_fill_layer_on_next_frame(void *_) {
}
void layers_create_fill_layer(uv_type_t uv_type, mat4_t decal_mat, i32 position) {
// if (g_context->tool == TOOL_TYPE_CURSOR) {
// return;
// }
_layers_uv_type = uv_type;
_layers_decal_mat = decal_mat;
_layers_position = position;
@@ -1049,6 +1045,31 @@ void layers_merge_layer(slot_layer_t *l0, slot_layer_t *l1, bool use_mask) {
}
}
void layers_draw_mesh_materials() {
bool any = false;
for (i32 i = 0; i < g_project->_->paint_objects->length; ++i) {
if (tab_meshes_get_override(g_project->_->paint_objects->buffer[i]) >= 0) {
any = true;
break;
}
}
if (!any) {
return;
}
string_array_t *additional = any_array_create_from_raw(
(void *[]){
"expb",
"expc",
"texpaint_blend0",
},
3);
render_path_set_target("expa", additional, NULL, GPU_CLEAR_NONE, 0, 0.0);
render_path_bind_target("main", "gbufferD");
render_path_bind_target("texpaint_blend1", "paintmask");
render_path_draw_meshes("atlas");
}
slot_layer_t *layers_flatten(bool height_to_normal, slot_layer_t_array_t *layers) {
if (layers == NULL) {
layers = g_project->_->layers;
@@ -1171,6 +1192,8 @@ slot_layer_t *layers_flatten(bool height_to_normal, slot_layer_t_array_t *layers
}
}
layers_draw_mesh_materials();
slot_layer_t *l0 = GC_ALLOC_INIT(slot_layer_t, {.texpaint = layers_expa, .texpaint_nor = layers_expb, .texpaint_pack = layers_expc});
// Merge height map into normal map
+73 -38
View File
@@ -12,21 +12,24 @@ void util_mesh_remove_merged() {
}
}
static bool _util_mesh_is_representative(i32 i) {
mesh_object_t_array_t *paint_objects = g_project->_->paint_objects;
if (!paint_objects->buffer[i]->base->visible) {
return false;
}
for (i32 j = 0; j < i; ++j) {
if (paint_objects->buffer[j]->base->visible && paint_objects->buffer[j]->data == paint_objects->buffer[i]->data) {
return false;
}
}
return true;
}
mesh_object_t_array_t *util_mesh_get_unique() {
mesh_object_t_array_t *ar = any_array_create_from_raw((void *[]){}, 0);
for (i32 i = 0; i < g_project->_->paint_objects->length; ++i) {
if (!g_project->_->paint_objects->buffer[i]->base->visible) {
continue;
}
bool found = false;
for (i32 j = 0; j < i; ++j) {
if (g_project->_->paint_objects->buffer[i]->data == g_project->_->paint_objects->buffer[j]->data) {
found = true;
break;
}
}
if (!found) {
if (_util_mesh_is_representative(i)) {
any_array_push(ar, g_project->_->paint_objects->buffer[i]);
}
}
@@ -45,6 +48,43 @@ mesh_object_t_array_t *util_mesh_get_visible() {
return ar;
}
#define ATLAS_MAX_STRIDE 8
#define ATLAS_MAX_SLOTS (ATLAS_MAX_STRIDE * ATLAS_MAX_STRIDE)
static i32 _util_mesh_atlas_stride_for(i32 count) {
i32 stride = 1;
while (stride * stride < count && stride < ATLAS_MAX_STRIDE) {
stride++;
}
return stride;
}
static i32 util_mesh_atlas_stride_merged = 1;
static mesh_data_t *util_mesh_atlas_slot_data[ATLAS_MAX_SLOTS];
static i32 util_mesh_atlas_slot_count = 0;
static bool util_mesh_atlas_slots_spent = false;
i32 util_mesh_atlas_stride() {
return util_mesh_atlas_stride_merged;
}
i32 util_mesh_atlas_slot(object_t *object) {
mesh_object_t_array_t *paint_objects = g_project->_->paint_objects;
mesh_data_t *data = NULL;
for (i32 i = 0; i < paint_objects->length; ++i) {
if (paint_objects->buffer[i]->base == object) {
data = paint_objects->buffer[i]->data;
break;
}
}
for (i32 i = 0; i < util_mesh_atlas_slot_count; ++i) {
if (util_mesh_atlas_slot_data[i] == data) {
return i;
}
}
return util_mesh_atlas_slots_spent ? ATLAS_MAX_SLOTS - 1 : 0;
}
mesh_data_t *util_mesh_data_duplicate(mesh_data_t *source) {
mesh_data_t *raw = gc_alloc(sizeof(mesh_data_t));
raw->name = string_copy(source->name);
@@ -86,6 +126,11 @@ static mesh_data_t *util_mesh_build_merged_data(mesh_object_t_array_t *paint_obj
i32 coli = vatex1 != NULL ? 4 : 3;
u32_array_t *ia = u32_array_create(ilen);
i32 atlas_stride = config_is_raytrace_multi() ? _util_mesh_atlas_stride_for(paint_objects->length) : 1;
util_mesh_atlas_stride_merged = atlas_stride;
util_mesh_atlas_slot_count = 0;
util_mesh_atlas_slots_spent = paint_objects->length > ATLAS_MAX_SLOTS;
i32 voff = 0;
i32 ioff = 0;
for (i32 i = 0; i < paint_objects->length; ++i) {
@@ -117,8 +162,17 @@ static mesh_data_t *util_mesh_build_merged_data(mesh_object_t_array_t *paint_obj
va1->buffer[j + voff * 2] = vas->buffer[1]->values->buffer[j];
}
// Tex
for (i32 j = 0; j < vas->buffer[2]->values->length; ++j) {
va2->buffer[j + voff * 2] = vas->buffer[2]->values->buffer[j];
i32 slot = i < ATLAS_MAX_SLOTS ? i : ATLAS_MAX_SLOTS - 1;
if (i < ATLAS_MAX_SLOTS) {
util_mesh_atlas_slot_data[slot] = paint_objects->buffer[i]->data;
util_mesh_atlas_slot_count = slot + 1;
}
f32 tile_step = 32767.0f / atlas_stride;
f32 tile_x = atlas_stride > 1 ? (slot % atlas_stride) * tile_step : 0.0f;
f32 tile_y = atlas_stride > 1 ? (slot / atlas_stride) * tile_step : 0.0f;
for (i32 j = 0; j < vas->buffer[2]->values->length / 2; ++j) {
va2->buffer[j * 2 + voff * 2] = vas->buffer[2]->values->buffer[j * 2] / (float)atlas_stride + tile_x;
va2->buffer[j * 2 + 1 + voff * 2] = vas->buffer[2]->values->buffer[j * 2 + 1] / (float)atlas_stride + tile_y;
}
// Tex1
if (vatex1 != NULL) {
@@ -164,12 +218,12 @@ static mesh_data_t *util_mesh_build_merged_data(mesh_object_t_array_t *paint_obj
void util_mesh_merge(mesh_object_t_array_t *paint_objects) {
if (paint_objects == NULL) {
// if (g_context->tool == TOOL_TYPE_CURSOR) {
// paint_objects = util_mesh_get_unique();
// }
// else {
paint_objects = g_project->_->paint_objects;
// }
if (config_is_raytrace_multi()) {
paint_objects = util_mesh_get_unique();
}
else {
paint_objects = g_project->_->paint_objects;
}
}
if (paint_objects->length == 0) {
return;
@@ -699,25 +753,6 @@ void util_mesh_decimate(f32 strength) {
#endif
}
i32 _util_mesh_unique_data_count() {
return util_mesh_get_unique()->length;
}
void util_mesh_pack_uvs(i16_array_t *texa) {
// Scale tex coords into global atlas
i32 atlas_w = config_get_scene_atlas_res();
i32 item_i = _util_mesh_unique_data_count() - 1; // Add the one being imported
i32 item_w = config_get_layer_res();
i32 atlas_stride = atlas_w / (float)item_w;
i32 atlas_step = 32767 / (float)atlas_stride;
i32 item_x = (item_i % atlas_stride) * atlas_step;
i32 item_y = math_floor(item_i / (float)atlas_stride) * atlas_step;
for (i32 i = 0; i < texa->length / 2.0; ++i) {
texa->buffer[i * 2] = texa->buffer[i * 2] / (float)atlas_stride + item_x;
texa->buffer[i * 2 + 1] = texa->buffer[i * 2 + 1] / (float)atlas_stride + item_y;
}
}
static i32 *_cc_he_vlo;
static i32 *_cc_he_vhi;