From 562cbc12da4694af91bf7e4f854adae30c37cffa Mon Sep 17 00:00:00 2001 From: Beriff Date: Wed, 11 Mar 2026 21:04:11 +0700 Subject: [PATCH] feat: handle drawing --- src/application/applicationstate.c | 23 +++++++++++++++++++++++ src/core/primitives.c | 28 +++++++++++++++++++++++++++- src/core/primitives.h | 2 ++ src/ui/vektorcanvas.c | 28 +++++++++++++++++++++++----- 4 files changed, 75 insertions(+), 6 deletions(-) diff --git a/src/application/applicationstate.c b/src/application/applicationstate.c index d11b216..52e2f50 100644 --- a/src/application/applicationstate.c +++ b/src/application/applicationstate.c @@ -131,6 +131,10 @@ begin_click_dispatch: vektor_polyline_add_point(state->selectedShape->primitive.polyline, pos); vektor_shapes_update_bbox(state->shapeBuffer); + + // polyline's handle count is not fixed, so we have to add them manually + vektor_shape_add_handle(state->selectedShape, pos); + } else if (state->selectedTool == VektorPolygonTool) { // create new polygon shape if none is selected if (state->selectedShape == NULL) { @@ -155,6 +159,10 @@ begin_click_dispatch: vektor_polygon_add_point(state->selectedShape->primitive.polygon, pos); vektor_shapes_update_bbox(state->shapeBuffer); + + // polygon's handle count is not fixed, so we have to add them manually + vektor_shape_add_handle(state->selectedShape, pos); + } else if (state->selectedTool == VektorCircleTool) { VektorCircle* circle = vektor_circle_new(); @@ -174,6 +182,12 @@ begin_click_dispatch: vektor_circle_set_radius(&state->selectedShape->primitive.circle, 0.1f); vektor_shapes_update_bbox(state->shapeBuffer); + + vektor_circle_create_handles( + &state->selectedShape->primitive.circle, + &state->selectedShape->handles, + &state->selectedShape->handleCount + ); } else if (state->selectedTool == VektorRectangleTool) { VektorRectangle* rect = vektor_rectangle_new(); @@ -193,6 +207,12 @@ begin_click_dispatch: pos); vektor_rectangle_set_end(&state->selectedShape->primitive.rectangle, vec2_add(pos, (V2){0.1f, 0.1f})); + vektor_rectangle_create_handles( + &state->selectedShape->primitive.rectangle, + &state->selectedShape->handles, + &state->selectedShape->handleCount + ); + // state->selectedShape = NULL; vektor_shapes_update_bbox(state->shapeBuffer); } else if (state->selectedTool == VektorSelectionTool) { @@ -207,6 +227,9 @@ begin_click_dispatch: // was clicked outside any shapes - reset selection state->selectedShape = NULL; } + + if(state->selectedShape != NULL) + g_print("%zu\n", state->selectedShape->handleCount); } void vektor_appstate_canvas_drag_begin(GtkGestureDrag* gesture, gdouble x, diff --git a/src/core/primitives.c b/src/core/primitives.c index 0ea2309..f2fa931 100644 --- a/src/core/primitives.c +++ b/src/core/primitives.c @@ -205,6 +205,8 @@ void vektor_rectangle_create_handles(VektorRectangle* rectangle, V2** handleArr, V2 halfdist = vec2_scale(vec2_sub(rectangle->end, rectangle->start), 0.5f); V2 center = vec2_add(rectangle->start, halfdist); + g_print("boobs: %f %f\n", rectangle->start.x, rectangle->start.y); + g_print("pussy: %f %f\n", rectangle->end.x, rectangle->end.y); (*handleArr)[0] = center; (*handleArr)[1] = vec2_add( center, vec2_mul(halfdist, (V2){-1.0f, 1.0f}) ); @@ -320,6 +322,15 @@ void vektor_shape_handles_updated(VektorShape* shape) { } } +void vektor_shape_add_handle(VektorShape* shape, V2 handle) { + // could be optimised with capacity property + // but this function is only called when adding new + // points to polyline and polygon, so it should + // not be that much of an overhead + shape->handles = realloc(shape->handles, sizeof(V2) * shape->handleCount + 1); + shape->handles[shape->handleCount++] = handle; +} + // ------ BBOX METHODS ------ bool vektor_bbox_isinside(VektorBBox bbox, V2 point) { @@ -334,14 +345,29 @@ VektorBBox vektor_bbox_fromcenter(V2 center, float dist) { return (VektorBBox){min,max}; } +VektorBBox vektor_bbox_expand(VektorBBox bbox, float val) { + return (VektorBBox){ + vec2_sub(bbox.min, vec2_fromfloat(val)), + vec2_add(bbox.max, vec2_fromfloat(val)) + }; +} + // ------ SHAPE METHODS ------ VektorShape vektor_shape_new(VektorPrimitive prim, VektorStyle style, int z_index) { - return (VektorShape){.primitive = prim, + VektorShape shape = (VektorShape){.primitive = prim, .style = style, .z_index = z_index, .bbox = vektor_primitive_get_bbox(prim)}; + + /* + create_handles() allocates new buffer for handles, + and even if the local shape variable goes out of scope and deallocates, + the passed value's pointer to an array of handles remains valid in the passed copy. + */ + vektor_shape_create_handles(&shape); + return shape; } void vektor_shapes_update_bbox(VektorShapeBuffer* buffer) { diff --git a/src/core/primitives.h b/src/core/primitives.h index 8fd694b..ef75e79 100644 --- a/src/core/primitives.h +++ b/src/core/primitives.h @@ -93,6 +93,7 @@ VektorBBox vektor_rectangle_get_bbox(VektorPrimitive prim); VektorBBox vektor_primitive_get_bbox(VektorPrimitive prim); bool vektor_bbox_isinside(VektorBBox bbox, V2 point); VektorBBox vektor_bbox_fromcenter(V2 center, float dist); +VektorBBox vektor_bbox_expand(VektorBBox bbox, float val); // shape handles void vektor_polyline_create_handles(VektorPolyline* polyline, V2** handleArr, size_t* count); @@ -100,6 +101,7 @@ void vektor_polygon_create_handles(VektorPolygon* polygon, V2** handleArr, size_ void vektor_circle_create_handles(VektorCircle* circle, V2** handleArr, size_t* count); void vektor_rectangle_create_handles(VektorRectangle* rectangle, V2** handleArr, size_t* count); void vektor_shape_create_handles(VektorShape* shape); +void vektor_shape_add_handle(VektorShape* shape, V2 handle); /* reconstructs the shape based on handles alone */ void vektor_polyline_handles_updated(VektorPolyline* polyline, V2** handles, size_t* count); diff --git a/src/ui/vektorcanvas.c b/src/ui/vektorcanvas.c index 9dff91d..d962a52 100644 --- a/src/ui/vektorcanvas.c +++ b/src/ui/vektorcanvas.c @@ -140,19 +140,36 @@ static gboolean render(GtkGLArea* a, GdkGLContext* ctx, vb.count = 0; vektor_rasterize(&vb, renderInfo->shapes, renderInfo->zoom); - size_t shape_vertex_count = - vb.count; // remember how many vertices belong to shapes + size_t shape_vertex_count = vb.count; // remember how many vertices belong to shapes - // create selection quad if a shape is selected + if (renderInfo->selectedShape != NULL && *(renderInfo->selectedShape) != NULL) { - VektorBBox bbox = vektor_primitive_get_bbox( - (*(renderInfo->selectedShape))->primitive); + + VektorShape* selectedShape = *renderInfo->selectedShape; + + // create handle quads if a shape is selected + for(size_t i = 0; i < selectedShape->handleCount; i++) { + V2 handle = selectedShape->handles[i]; + VektorBBox handleBbox = vektor_bbox_fromcenter(handle, 0.01f); + vektor_vb_add_quad(&vb, handleBbox.min, handleBbox.max, vektor_color_new(255, 255, 255, 255)); + } + + shape_vertex_count = vb.count; + + // create selection quad if a shape is selected + VektorBBox bbox = vektor_primitive_get_bbox(selectedShape->primitive); + // expand it a little so it is not inset + bbox = vektor_bbox_expand(bbox, 0.03f); vektor_vb_add_quad(&vb, bbox.min, bbox.max, vektor_color_new(255, 255, 255, 255)); + } + + + glBufferData(GL_ARRAY_BUFFER, vb.count * sizeof(Vertex), vb.vertices, GL_STATIC_DRAW); @@ -180,6 +197,7 @@ static gboolean render(GtkGLArea* a, GdkGLContext* ctx, // re-fetch bbox (we know a shape is selected) VektorBBox bbox = vektor_primitive_get_bbox( (*(renderInfo->selectedShape))->primitive); + bbox = vektor_bbox_expand(bbox, 0.03f); glUseProgram(selection_shader_program);