diff --git a/paint/sources/base.c b/paint/sources/base.c index 122f8ab7..312ac8af 100644 --- a/paint/sources/base.c +++ b/paint/sources/base.c @@ -2247,7 +2247,7 @@ void ui_base_set_viewport_col(i32 col) { void base_update_workspace() { config_init_layout(); - if (g_config->workspace == WORKSPACE_PAINT_3D || g_config->workspace == WORKSPACE_SCULPT) { + if (g_config->workspace == WORKSPACE_PAINT_3D) { base_view3d_show = true; ui_menubar_tab->i = 0; ui_view2d_show = false; @@ -2297,7 +2297,8 @@ void base_update_workflow() { ui_node_array_t *nodes = 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_BASE ? 2 : 9; + 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"); } } } diff --git a/paint/sources/enums.h b/paint/sources/enums.h index f4cf4355..5dba56fd 100644 --- a/paint/sources/enums.h +++ b/paint/sources/enums.h @@ -74,13 +74,13 @@ typedef enum { WORKSPACE_PAINT_2D = 1, WORKSPACE_NODES = 2, WORKSPACE_SCRIPT = 3, - WORKSPACE_SCULPT = 4, - WORKSPACE_PLAYER = 5, + WORKSPACE_PLAYER = 4, } workspace_t; typedef enum { - WORKFLOW_PBR = 0, - WORKFLOW_BASE = 1, + WORKFLOW_PBR = 0, + WORKFLOW_BASE = 1, + WORKFLOW_SCULPT = 2, } workflow_t; typedef enum { diff --git a/paint/sources/make_sculpt.c b/paint/sources/make_sculpt.c index 87fc1cf0..7512e8fd 100644 --- a/paint/sources/make_sculpt.c +++ b/paint/sources/make_sculpt.c @@ -78,6 +78,8 @@ node_shader_context_t *sculpt_make_sculpt_run(material_t *data, material_context node_shader_write_vert(kong, "output.tex_coord.y = 1.0 - output.tex_coord.y;"); node_shader_write_vert(kong, "output.pos = float4(input.pos.xy, 0.0, 1.0);"); node_shader_write_attrib_frag(kong, "var tex_coord: float2 = input.tex_coord;"); + node_shader_write_attrib_frag(kong, "var sculpt_uv: float2 = tex_coord;"); + node_shader_add_constant(kong, "inp: float4", "_input_brush"); node_shader_add_constant(kong, "inplast: float4", "_input_brush_last"); node_shader_add_texture(kong, "gbufferD", NULL); @@ -86,8 +88,8 @@ node_shader_context_t *sculpt_make_sculpt_run(material_t *data, material_context node_shader_add_constant(kong, "brush_opacity: float", "_brush_opacity"); node_shader_add_constant(kong, "brush_hardness: float", "_brush_hardness"); - if (g_context->tool == TOOL_TYPE_BRUSH || g_context->tool == TOOL_TYPE_ERASER || g_context->tool == TOOL_TYPE_CLONE || - g_context->tool == TOOL_TYPE_BLUR || g_context->tool == TOOL_TYPE_SMUDGE || g_context->tool == TOOL_TYPE_PARTICLE || decal) { + if (g_context->tool == TOOL_TYPE_BRUSH || g_context->tool == TOOL_TYPE_ERASER || g_context->tool == TOOL_TYPE_CLONE || g_context->tool == TOOL_TYPE_BLUR || + g_context->tool == TOOL_TYPE_SMUDGE || g_context->tool == TOOL_TYPE_PARTICLE || decal) { node_shader_write_frag(kong, "var dist: float = 0.0;"); node_shader_write_frag(kong, "var depth: float = sample_lod(gbufferD, sampler_linear, constants.inp.xy, 0.0).r;"); node_shader_add_constant(kong, "invVP: float4x4", "_inv_view_proj_matrix"); @@ -105,8 +107,11 @@ node_shader_context_t *sculpt_make_sculpt_run(material_t *data, material_context node_shader_write_frag(kong, "var winplast: float4 = float4(float2(constants.inplast.x, 1.0 - constants.inplast.y) * 2.0 - 1.0, depthlast, 1.0);"); node_shader_write_frag(kong, "winplast = constants.invVP * winplast;"); node_shader_write_frag(kong, "winplast.xyz = winplast.xyz / winplast.w;"); - node_shader_write_frag(kong, "dist = distance(wposition.xyz, winp.xyz);"); - node_shader_write_frag(kong, "if (dist > constants.brush_radius) { discard; }"); + + if (!decal) { + node_shader_write_frag(kong, "dist = distance(wposition.xyz, winp.xyz);"); + node_shader_write_frag(kong, "if (dist > constants.brush_radius) { discard; }"); + } } else if (g_context->tool == TOOL_TYPE_FILL) { node_shader_write_frag(kong, "var dist: float = 0.0;"); @@ -116,11 +121,41 @@ node_shader_context_t *sculpt_make_sculpt_run(material_t *data, material_context kong, "var wposition: float3 = (constants.W * texpaint_sculpt_undo[uint2(uint(tex_coord.x * 2048.0), uint(tex_coord.y * 2048.0))]).xyz;"); } - parser_material_parse_height = true; - parser_material_parse_height_as_channel = true; - shader_out_t *sout = parser_material_parse(g_context->material->canvas, con_paint, kong, matcon); - char *height = sout->out_height; - node_shader_write_frag(kong, string("var height: float = %s;", height)); + if (decal) { + // Project wposition to screen-space and compute decal tex_coord + node_shader_add_constant(kong, "VP: float4x4", "_view_proj_matrix"); + node_shader_write_attrib_frag(kong, "var decal_ndc: float4 = constants.VP * float4(wposition.xyz, 1.0);"); + node_shader_write_attrib_frag(kong, "var sp: float3 = decal_ndc.xyz / decal_ndc.w;"); + node_shader_write_attrib_frag(kong, "sp.x = sp.x * 0.5 + 0.5;"); + node_shader_write_attrib_frag(kong, "sp.y = sp.y * 0.5 + 0.5;"); + node_shader_write_attrib_frag(kong, "sp.y = 1.0 - sp.y;"); + node_shader_add_constant(kong, "aspect_ratio: float", "_aspect_ratio_window"); + node_shader_add_constant(kong, "decal_mask: float4", "_decal_mask"); + node_shader_write_attrib_frag(kong, "var uvsp: float2 = sp.xy;"); + node_shader_write_attrib_frag(kong, "uvsp = uvsp - constants.decal_mask.xy;"); + node_shader_write_attrib_frag(kong, "uvsp.x *= constants.aspect_ratio;"); + node_shader_write_attrib_frag(kong, "uvsp = uvsp * (0.21 / (constants.decal_mask.w * 0.9));"); + f32 angle = g_context->brush_angle + g_context->brush_nodes_angle; + if (angle != 0.0) { + node_shader_add_constant(kong, "brush_angle: float2", "_brush_angle"); + node_shader_write_attrib_frag(kong, "uvsp = float2(uvsp.x * constants.brush_angle.x - uvsp.y * constants.brush_angle.y, uvsp.x * " + "constants.brush_angle.y + uvsp.y * constants.brush_angle.x);"); + } + node_shader_add_constant(kong, "brush_scale_x: float", "_brush_scale_x"); + node_shader_write_attrib_frag(kong, "uvsp.x *= constants.brush_scale_x;"); + node_shader_write_attrib_frag(kong, "uvsp += float2(0.5, 0.5);"); + node_shader_write_attrib_frag(kong, "if (uvsp.x < 0.0 || uvsp.y < 0.0 || uvsp.x > 1.0 || uvsp.y > 1.0) { discard; }"); + node_shader_add_constant(kong, "brush_scale: float", "_brush_scale"); + node_shader_write_attrib_frag(kong, "tex_coord = uvsp * constants.brush_scale;"); + } + + // parser_material_parse may add vertex elements + i32 velen = con_paint->data->vertex_elements->length; + parser_material_parse_height = true; + parser_material_parse_height_as_channel = true; + shader_out_t *sout = parser_material_parse(g_context->material->canvas, con_paint, kong, matcon); + con_paint->data->vertex_elements->length = velen; + node_shader_write_frag(kong, string("var height: float = %s.r;", sout->out_basecol)); if (kong->frag_bposition) { kong->frag_bposition = false; @@ -128,11 +163,12 @@ node_shader_context_t *sculpt_make_sculpt_run(material_t *data, material_context } node_shader_write_frag(kong, "var basecol: float3 = float3(1.0, 1.0, 1.0);"); - node_shader_write_frag(kong, "var opacity: float = 1.0;"); + node_shader_write_frag(kong, string("var opacity: float = %s;", sout->out_opacity)); node_shader_write_frag(kong, "if (opacity == 0.0) { discard; }"); node_shader_write_frag(kong, "var str: float = clamp((constants.brush_radius - dist) * constants.brush_hardness * 1.0, 0.0, 1.0) * opacity;"); node_shader_add_texture(kong, "texpaint_sculpt_undo", "_texpaint_sculpt_undo"); - node_shader_write_frag(kong, "var sample_undo: float4 = sample_lod(texpaint_sculpt_undo, sampler_linear, tex_coord, 0.0);"); + node_shader_write_frag(kong, "var sample_undo: float4 = sample_lod(texpaint_sculpt_undo, sampler_linear, sculpt_uv, 0.0);"); + node_shader_write_frag(kong, "if (sample_undo.r == 0.0 && sample_undo.g == 0.0 && sample_undo.b == 0.0) { discard; }"); node_shader_add_function(kong, str_octahedron_wrap); node_shader_add_texture(kong, "gbuffer0_undo", NULL); diff --git a/paint/sources/project.c b/paint/sources/project.c index 6a95d80b..40434e89 100644 --- a/paint/sources/project.c +++ b/paint/sources/project.c @@ -341,6 +341,7 @@ void project_new(bool reset_layers) { if (in_use) draw_begin(current, false, 0); + base_update_workflow(); project_set_default_envmap(); context_init_tool(); viewport_reset(); diff --git a/paint/sources/tab_layers.c b/paint/sources/tab_layers.c index 7ab2a584..8653f105 100644 --- a/paint/sources/tab_layers.c +++ b/paint/sources/tab_layers.c @@ -982,7 +982,7 @@ void tab_layers_button_new_sculpt_layer(void *_) { void tab_layers_button_new_menu() { slot_layer_t *l = g_context->layer; - if (g_config->workspace == WORKSPACE_SCULPT) { + if (g_config->workflow == WORKFLOW_SCULPT) { if (ui_menu_button(tr("Sculpt Layer"), "", ICON_PAINT)) { sys_notify_on_next_frame(&tab_layers_button_new_sculpt_layer, NULL); } diff --git a/paint/sources/tab_materials.c b/paint/sources/tab_materials.c index 99ed5cf9..9754b8d8 100644 --- a/paint/sources/tab_materials.c +++ b/paint/sources/tab_materials.c @@ -28,6 +28,7 @@ void tab_materials_update_material() { if (decal) { util_render_make_decal_preview(); } + base_update_workflow(); } void tab_materials_draw_slots_duplicate(void *_) { @@ -103,6 +104,11 @@ void tab_materials_draw_slots_menu() { tab_materials_delete_material(m); } + if (g_config->experimental && ui_menu_button(tr("Inspect as Script"), "", ICON_SEARCH)) { + node_shader_dump_to_script = true; + context_select_material(i); + } + ui_handle_t *base_handle = ui_nest(ui_handle(__ID__), m->id); if (base_handle->init) { base_handle->b = m->paint_base; diff --git a/paint/sources/ui_menubar.c b/paint/sources/ui_menubar.c index 120ae687..35470ea5 100644 --- a/paint/sources/ui_menubar.c +++ b/paint/sources/ui_menubar.c @@ -784,7 +784,6 @@ void ui_menubar_draw_category_items() { 4); if (g_config->experimental) { - any_array_push(modes, tr("Sculpt")); any_array_push(modes, tr("Player")); } @@ -810,6 +809,11 @@ void ui_menubar_draw_category_items() { tr("Base"), }, 2); + + if (g_config->experimental) { + any_array_push(workflow_items, tr("Sculpt")); + } + g_config->workflow = ui_inline_radio(workflow_handle, workflow_items, UI_ALIGN_LEFT); if (workflow_handle->changed) { g_config->workflow = workflow_handle->i;