From 7bb8db1eac6085e63cefd1e81d39aa720b1aa69b Mon Sep 17 00:00:00 2001 From: luboslenco Date: Wed, 12 Aug 2026 12:59:40 +0200 Subject: [PATCH] paint: remove path layer point with delete key --- paint/sources/util/util_path.c | 119 +++++++++++++++++++++++++++++++-- 1 file changed, 113 insertions(+), 6 deletions(-) diff --git a/paint/sources/util/util_path.c b/paint/sources/util/util_path.c index 52a89f0c..f1d7448e 100644 --- a/paint/sources/util/util_path.c +++ b/paint/sources/util/util_path.c @@ -280,7 +280,7 @@ static void path_repaint(slot_layer_t *l) { return; } f32_array_t *points_world = l->path_points_world; - if (points_world == NULL || points_world->length == 0) { + if (points_world == NULL) { return; } @@ -319,11 +319,13 @@ static void path_repaint(slot_layer_t *l) { f32 r_world = g_context->brush_radius * g_context->brush_nodes_radius / 15.0f * 2.0f; f32 dot_spacing = sphere_mode ? g_context->brush_lazy_radius * g_context->brush_lazy_step * r_world * 3.0 : 0.0f; - if (l->path_curved && num_world >= 1) { - path_paint_curved(points, points_world, points_camera, points_parent, num_world, num_camera, num_parent, sphere_mode, dot_spacing); - } - else { - path_paint_straight(points, points_world, points_camera, points_parent, num_world, num_camera, sphere_mode, dot_spacing); + if (num_world >= 1) { + if (l->path_curved) { + path_paint_curved(points, points_world, points_camera, points_parent, num_world, num_camera, num_parent, sphere_mode, dot_spacing); + } + else { + path_paint_straight(points, points_world, points_camera, points_parent, num_world, num_camera, sphere_mode, dot_spacing); + } } scene_camera->base->transform->loc = _camera_loc; @@ -356,6 +358,107 @@ void util_layer_clear_path_points(slot_layer_t *l) { path_layer_last_active = -1; } +static void path_array_remove_f32(f32_array_t *ar, i32 stride, i32 start, i32 count) { + i32 n = ar->length / stride; + if (start >= n) { + return; + } + if (start + count > n) { + count = n - start; + } + i32 tail = (n - start - count) * stride; + if (tail > 0) { + memmove(&ar->buffer[start * stride], &ar->buffer[(start + count) * stride], tail * sizeof(f32)); + } + ar->length -= count * stride; +} + +static void path_array_remove_i32(i32_array_t *ar, i32 start, i32 count) { + i32 n = ar->length; + if (start >= n) { + return; + } + if (start + count > n) { + count = n - start; + } + i32 tail = n - start - count; + if (tail > 0) { + memmove(&ar->buffer[start], &ar->buffer[start + count], tail * sizeof(i32)); + } + ar->length -= count; +} + +void util_layer_remove_path_point(slot_layer_t *l) { + if (!slot_layer_is_path(l)) { + return; + } + + i32 num_points = l->path_points->length / 2; + i32 idx = path_layer_last_active; + if (idx < 0 || idx >= num_points) { + return; + } + + // Anchors sit at even indices, their control points at the odd index before them + i32 start = idx; + i32 count = 1; + if (l->path_curved) { + if (idx % 2 == 1) { + // Control point - remove the anchor it belongs to as well + start = idx; + count = idx + 1 < num_points ? 2 : 1; + } + else if (idx > 0) { + start = idx - 1; + count = 2; + } + else { + start = 0; + count = num_points > 1 ? 2 : 1; + } + } + + i32_array_t *points_parent = l->path_points_parent; + i32 last = start + count - 1; + i32 new_parent = last < (i32)points_parent->length ? points_parent->buffer[last] : -1; + if (new_parent >= start && new_parent <= last) { + new_parent = -1; + } + else if (new_parent > last) { + new_parent -= count; + } + + // Reparent orphaned points and shift the indices of the remaining ones + for (i32 i = 0; i < (i32)points_parent->length; i++) { + i32 p = points_parent->buffer[i]; + if (p >= start && p <= last) { + p = new_parent; + } + else if (p > last) { + p -= count; + } + points_parent->buffer[i] = p; + } + + path_array_remove_f32(l->path_points, 2, start, count); + path_array_remove_f32(l->path_points_world, 3, start, count); + path_array_remove_f32(l->path_points_camera, 9, start, count); + path_array_remove_i32(points_parent, start, count); + + i32 left = l->path_points->length / 2; + path_layer_last_active = left > 0 ? (new_parent >= 0 ? new_parent : left - 1) : -1; + path_point_dragging = -1; + + util_layer_repaint_path(l); + + if (left == 0) { + util_layer_clear_path_points(l); + } + + g_context->layer_preview_dirty = true; + g_context->layers_preview_dirty = true; +} + void util_layer_add_path_point(slot_layer_t *l, f32 screen_x, f32 screen_y) { if (l->path_tool == -1) { l->path_tool = g_context->tool; @@ -542,6 +645,10 @@ void util_layer_update_path() { return; } + if (keyboard_started("delete") && !g_ui->is_typing && context_in_3d_view()) { + util_layer_remove_path_point(l); + } + f32_array_t *points = l->path_points; f32_array_t *points_world = l->path_points_world; i32 num_points = points->length / 2;