Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions paint/sources/context.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ void context_init() {
g_context->sym_x = false;
g_context->sym_y = false;
g_context->sym_z = false;
g_context->fill_sym_x_valid = false;
g_context->fill_sym_y_valid = false;
g_context->fill_sym_z_valid = false;
g_context->fill_xray_valid = false;
g_context->fill_type = FILL_TYPE_OBJECT;
g_context->blur_type = BLUR_TYPE_BLUR;
g_context->paint2d = false;
Expand Down
4 changes: 4 additions & 0 deletions paint/sources/functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,10 @@ void util_render_make_font_preview();
void util_render_make_brush_preview();
void util_render_make_node_preview(ui_node_canvas_t *canvas, ui_node_t *node, gpu_texture_t *image, ui_node_canvas_t *group, ui_node_t_array_t *parents);
void util_render_pick_pos_nor_tex();
vec4_t util_render_closest_point_on_triangle(vec4_t p, vec4_t a, vec4_t b, vec4_t c);
bool util_render_closest_point_on_mesh(vec4_t target, f32 *out_uvx, f32 *out_uvy, f32 *out_norx, f32 *out_nory, f32 *out_norz);
void util_render_pick_fill_symmetry();
void util_render_pick_fill_xray();
mat4_t util_render_get_decal_mat();
void util_brush_update();
vec4_t raycast_aabb_mouse(object_t *object);
Expand Down
36 changes: 34 additions & 2 deletions paint/sources/render/make_discard.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,40 @@ void make_discard_face(node_shader_t *kong) {
node_shader_write_frag(kong, "var face_c1: float4 = textrianglemap[uint2(uint(tex_coord_inp.x * constants.textrianglemap_size.x), uint(tex_coord_inp.y * "
"constants.textrianglemap_size.y))];");
node_shader_write_frag(kong, "var face_c2: float4 = sample_lod(textrianglemap, sampler_linear, input.tex_coord_pick, 0.0);");
// node_shader_write_frag(kong, "if (any(face_c1 != face_c2)) { discard; }");
node_shader_write_frag(kong, "if (face_c1.x != face_c2.x || face_c1.y != face_c2.y || face_c1.z != face_c2.z || face_c1.w != face_c2.w) { discard; }");
node_shader_write_frag(kong,
"var face_match: bool = face_c1.x == face_c2.x && face_c1.y == face_c2.y && face_c1.z == face_c2.z && face_c1.w == face_c2.w;");

bool sym_x = g_context->sym_x && g_context->fill_sym_x_valid;
bool sym_y = g_context->sym_y && g_context->fill_sym_y_valid;
bool sym_z = g_context->sym_z && g_context->fill_sym_z_valid;

if (sym_x) {
node_shader_add_constant(kong, "fill_sym_x_uv: float2", "_fill_sym_x_uv");
node_shader_write_frag(kong, "var face_symx: float4 = sample_lod(textrianglemap, sampler_linear, constants.fill_sym_x_uv, 0.0);");
node_shader_write_frag(
kong, "if (face_symx.x == face_c2.x && face_symx.y == face_c2.y && face_symx.z == face_c2.z && face_symx.w == face_c2.w) { face_match = true; }");
}
if (sym_y) {
node_shader_add_constant(kong, "fill_sym_y_uv: float2", "_fill_sym_y_uv");
node_shader_write_frag(kong, "var face_symy: float4 = sample_lod(textrianglemap, sampler_linear, constants.fill_sym_y_uv, 0.0);");
node_shader_write_frag(
kong, "if (face_symy.x == face_c2.x && face_symy.y == face_c2.y && face_symy.z == face_c2.z && face_symy.w == face_c2.w) { face_match = true; }");
}
if (sym_z) {
node_shader_add_constant(kong, "fill_sym_z_uv: float2", "_fill_sym_z_uv");
node_shader_write_frag(kong, "var face_symz: float4 = sample_lod(textrianglemap, sampler_linear, constants.fill_sym_z_uv, 0.0);");
node_shader_write_frag(
kong, "if (face_symz.x == face_c2.x && face_symz.y == face_c2.y && face_symz.z == face_c2.z && face_symz.w == face_c2.w) { face_match = true; }");
}

if (g_context->xray && g_context->fill_xray_valid) {
node_shader_add_constant(kong, "fill_xray_uv: float2", "_fill_xray_uv");
node_shader_write_frag(kong, "var face_xray: float4 = sample_lod(textrianglemap, sampler_linear, constants.fill_xray_uv, 0.0);");
node_shader_write_frag(
kong, "if (face_xray.x == face_c2.x && face_xray.y == face_c2.y && face_xray.z == face_c2.z && face_xray.w == face_c2.w) { face_match = true; }");
}

node_shader_write_frag(kong, "if (!face_match) { discard; }");
}

void make_discard_uv_island(node_shader_t *kong) {
Expand Down
28 changes: 26 additions & 2 deletions paint/sources/render/make_paint.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,10 +294,34 @@ node_shader_context_t *make_paint_run_context(material_t *data, char *context_id
node_shader_write_frag(kong, "wn = normalize(wn);");
kong->frag_n = true;
f32 angle = g_context->brush_angle_reject_dot;
node_shader_write_frag(kong, string_tmp("if (dot(wn, n) < %s) { discard; }", f32_to_string(angle)));
node_shader_write_frag(kong, string_tmp("var angle_match: bool = dot(wn, n) >= %s;", f32_to_string(angle)));

bool sym_x = g_context->sym_x && g_context->fill_sym_x_valid;
bool sym_y = g_context->sym_y && g_context->fill_sym_y_valid;
bool sym_z = g_context->sym_z && g_context->fill_sym_z_valid;

if (sym_x) {
node_shader_add_constant(kong, "fill_sym_x_nor: float3", "_fill_sym_x_nor");
node_shader_write_frag(kong, string_tmp("if (dot(constants.fill_sym_x_nor, n) >= %s) { angle_match = true; }", f32_to_string(angle)));
}
if (sym_y) {
node_shader_add_constant(kong, "fill_sym_y_nor: float3", "_fill_sym_y_nor");
node_shader_write_frag(kong, string_tmp("if (dot(constants.fill_sym_y_nor, n) >= %s) { angle_match = true; }", f32_to_string(angle)));
}
if (sym_z) {
node_shader_add_constant(kong, "fill_sym_z_nor: float3", "_fill_sym_z_nor");
node_shader_write_frag(kong, string_tmp("if (dot(constants.fill_sym_z_nor, n) >= %s) { angle_match = true; }", f32_to_string(angle)));
}

if (g_context->xray && g_context->fill_xray_valid) {
node_shader_add_constant(kong, "fill_xray_nor: float3", "_fill_xray_nor");
node_shader_write_frag(kong, string_tmp("if (dot(constants.fill_xray_nor, n) >= %s) { angle_match = true; }", f32_to_string(angle)));
}

node_shader_write_frag(kong, "if (!angle_match) { discard; }");
}
bool stencil_fill = g_context->tool == TOOL_TYPE_FILL && g_context->brush_stencil_image != NULL;
if (stencil_fill) {
if (stencil_fill && !g_context->xray) {
node_shader_write_frag(kong, "if (sp.z > sample_lod(gbufferD, sampler_linear, sp.xy, 0.0).r - 0.00005) { discard; }");
}
}
Expand Down
24 changes: 24 additions & 0 deletions paint/sources/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,30 @@ typedef struct context {
bool sym_x;
bool sym_y;
bool sym_z;
bool fill_sym_x_valid;
bool fill_sym_y_valid;
bool fill_sym_z_valid;
f32 fill_sym_x_uvx;
f32 fill_sym_x_uvy;
f32 fill_sym_x_norx;
f32 fill_sym_x_nory;
f32 fill_sym_x_norz;
f32 fill_sym_y_uvx;
f32 fill_sym_y_uvy;
f32 fill_sym_y_norx;
f32 fill_sym_y_nory;
f32 fill_sym_y_norz;
f32 fill_sym_z_uvx;
f32 fill_sym_z_uvy;
f32 fill_sym_z_norx;
f32 fill_sym_z_nory;
f32 fill_sym_z_norz;
bool fill_xray_valid;
f32 fill_xray_uvx;
f32 fill_xray_uvy;
f32 fill_xray_norx;
f32 fill_xray_nory;
f32 fill_xray_norz;
i32 fill_type;
i32 blur_type;
bool paint2d;
Expand Down
3 changes: 2 additions & 1 deletion paint/sources/ui/ui_header.c
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,8 @@ void ui_header_draw_tool_properties() {
make_material_parse_mesh_material();
}
}
else {

{
i32 _w = g_ui->_w;
f32 sc = UI_SCALE();
bool touch_header = (g_config->touch_ui && g_config->layout->buffer[LAYOUT_SIZE_HEADER] == 1);
Expand Down
24 changes: 24 additions & 0 deletions paint/sources/uniforms.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,18 @@ vec2_t uniforms_ext_vec2_link(object_t *object, shader_data_t *mat, char *link)
else if (string_equals(link, "_texpaint_size")) {
return (vec2_t){config_get_texture_res_x(), config_get_texture_res_y()};
}
else if (string_equals(link, "_fill_sym_x_uv")) {
return (vec2_t){g_context->fill_sym_x_uvx, g_context->fill_sym_x_uvy};
}
else if (string_equals(link, "_fill_sym_y_uv")) {
return (vec2_t){g_context->fill_sym_y_uvx, g_context->fill_sym_y_uvy};
}
else if (string_equals(link, "_fill_sym_z_uv")) {
return (vec2_t){g_context->fill_sym_z_uvx, g_context->fill_sym_z_uvy};
}
else if (string_equals(link, "_fill_xray_uv")) {
return (vec2_t){g_context->fill_xray_uvx, g_context->fill_xray_uvy};
}
else if (string_equals(link, "_brush_angle")) {
f32 brush_angle = g_context->brush_angle + g_context->brush_nodes_angle;
f32 angle = g_context->layer->fill_material != NULL ? g_context->layer->angle : brush_angle;
Expand Down Expand Up @@ -255,6 +267,18 @@ vec4_t uniforms_ext_vec3_link(object_t *object, shader_data_t *mat, char *link)
color_get_bb(g_context->picked_color->normal) / 255.0, 1.0};
return v;
}
else if (string_equals(link, "_fill_sym_x_nor")) {
return (vec4_t){g_context->fill_sym_x_norx, g_context->fill_sym_x_nory, g_context->fill_sym_x_norz, 1.0};
}
else if (string_equals(link, "_fill_sym_y_nor")) {
return (vec4_t){g_context->fill_sym_y_norx, g_context->fill_sym_y_nory, g_context->fill_sym_y_norz, 1.0};
}
else if (string_equals(link, "_fill_sym_z_nor")) {
return (vec4_t){g_context->fill_sym_z_norx, g_context->fill_sym_z_nory, g_context->fill_sym_z_norz, 1.0};
}
else if (string_equals(link, "_fill_xray_nor")) {
return (vec4_t){g_context->fill_xray_norx, g_context->fill_xray_nory, g_context->fill_xray_norz, 1.0};
}
else if (string_equals(link, "_particle_hit")) {
v = (vec4_t){g_context->particle_hit_x, g_context->particle_hit_y, g_context->particle_hit_z, 1.0};
return v;
Expand Down
21 changes: 21 additions & 0 deletions paint/sources/util/util_brush.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,27 @@ void util_brush_update() {
}
}

// Keep Fill's symmetry/X-ray candidates following the cursor every frame while painting
// (not just at stroke start), so dragging across multiple faces mirrors/x-rays correctly too.
// The shader only needs recompiling when a candidate's validity actually flips, not on every
// position update, since the picked UV/normal values themselves flow through as constants.
if (g_context->tool == TOOL_TYPE_FILL && (g_context->fill_type == FILL_TYPE_FACE || g_context->fill_type == FILL_TYPE_ANGLE) &&
(g_context->sym_x || g_context->sym_y || g_context->sym_z || g_context->xray)) {
bool was_sym_x_valid = g_context->fill_sym_x_valid;
bool was_sym_y_valid = g_context->fill_sym_y_valid;
bool was_sym_z_valid = g_context->fill_sym_z_valid;
bool was_xray_valid = g_context->fill_xray_valid;

util_render_pick_pos_nor_tex();
util_render_pick_fill_symmetry();
util_render_pick_fill_xray();

if (g_context->fill_sym_x_valid != was_sym_x_valid || g_context->fill_sym_y_valid != was_sym_y_valid ||
g_context->fill_sym_z_valid != was_sym_z_valid || g_context->fill_xray_valid != was_xray_valid) {
make_material_parse_paint_material(true);
}
}

g_context->brush_time += sys_delta();
brush_output_node_run();
}
Expand Down
Loading