From 61f9f1eed0096844643e076000f016678a033974 Mon Sep 17 00:00:00 2001 From: Beriff Date: Tue, 10 Mar 2026 02:02:22 +0700 Subject: [PATCH] feat(experimental): add rectangle shape support --- src/application/applicationstate.c | 33 +++++++++++++++++++++++- src/application/applicationstate.h | 1 + src/core/primitives.c | 40 ++++++++++++++++++++++++------ src/core/primitives.h | 21 +++++++++++++--- src/core/raster.c | 26 ++++++++++++++++--- src/core/raster.h | 5 ++-- src/core/vector.h | 4 +++ 7 files changed, 112 insertions(+), 18 deletions(-) diff --git a/src/application/applicationstate.c b/src/application/applicationstate.c index 228dd86..ba36c81 100644 --- a/src/application/applicationstate.c +++ b/src/application/applicationstate.c @@ -21,6 +21,8 @@ static void appstate_set_tool(GtkButton* button, gpointer user_data) { button_tool_set_data* data = (button_tool_set_data*)user_data; data->state->selectedTool = data->tool; + g_print("%d", data->tool); + // setting tool makes the sub-tools menu to close gtk_revealer_set_reveal_child(data->revealer, FALSE); @@ -152,6 +154,30 @@ begin_click_dispatch: vektor_polygon_add_point(state->selectedShape->primitive.polygon, pos); vektor_shapes_update_bbox(state->shapeBuffer); } + else if (state->selectedTool == VektorRectangleTool) { + + VektorRectangle* rect = vektor_rectangle_new(); + VektorPrimitive rectPrimitive = + (VektorPrimitive){.kind = VEKTOR_RECTANGLE, .rectangle = *rect}; + VektorStyle style = (VektorStyle){ + .stroke_color = state->currentColor, .stroke_width = 0.01}; + vektor_shapebuffer_add_shape( + state->shapeBuffer, vektor_shape_new(rectPrimitive, style, 0)); + + state->selectedShape = + &(state->shapeBuffer->shapes[state->shapeBuffer->count - 1]); + + vektor_rectangle_free(rect); + + + vektor_rectangle_set_start(&state->selectedShape->primitive.rectangle, pos); + vektor_rectangle_set_end( + &state->selectedShape->primitive.rectangle, + vec2_add(pos, (V2){0.1f,-0.1f}) + ); + //state->selectedShape = NULL; + vektor_shapes_update_bbox(state->shapeBuffer); + } } void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut) { @@ -165,6 +191,11 @@ void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut) { data_polygontool->tool = VektorPolygonTool; data_polygontool->revealer = wstate->workspaceRevealerShapes; + button_tool_set_data* data_rectangletool = malloc(sizeof(button_tool_set_data)); + data_rectangletool->state = stateOut; + data_rectangletool->tool = VektorRectangleTool; + data_rectangletool->revealer = wstate->workspaceRevealerShapes; + // populate appstate stateOut->shapeBuffer = malloc(sizeof(VektorShapeBuffer)); *stateOut->shapeBuffer = (VektorShapeBuffer){0}; @@ -178,7 +209,7 @@ void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut) { g_signal_connect(G_OBJECT(wstate->workspaceButtonLinetool), "clicked", G_CALLBACK(appstate_set_tool), data_linetool); g_signal_connect(G_OBJECT(wstate->workspaceButtonRecttool), "clicked", - G_CALLBACK(appstate_set_tool), data_linetool); + G_CALLBACK(appstate_set_tool), data_rectangletool); g_signal_connect(G_OBJECT(wstate->workspaceButtonCircletool), "clicked", G_CALLBACK(appstate_set_tool), data_linetool); g_signal_connect(G_OBJECT(wstate->workspaceButtonPolygontool), "clicked", diff --git a/src/application/applicationstate.h b/src/application/applicationstate.h index a822662..695a362 100644 --- a/src/application/applicationstate.h +++ b/src/application/applicationstate.h @@ -9,6 +9,7 @@ typedef enum VektorAppTool { VektorLineTool, VektorPolygonTool, + VektorRectangleTool } VektorAppTool; typedef struct VektorAppState { diff --git a/src/core/primitives.c b/src/core/primitives.c index f72453d..497f2b4 100644 --- a/src/core/primitives.c +++ b/src/core/primitives.c @@ -49,6 +49,24 @@ void vektor_polygon_free(VektorPolygon* pg) { free(pg); } +VektorRectangle* vektor_rectangle_new(void) { + VektorRectangle* rct = malloc(sizeof(VektorRectangle)); + rct->start = (V2){.x = 0, .y = 0}; + rct->end = (V2){.x = 0, .y = 0}; + return rct; +} + +void vektor_rectangle_set_end(VektorRectangle* rct, V2 point) { + rct->end = point; +} +void vektor_rectangle_set_start(VektorRectangle* rct, V2 point) { + rct->start = point; +} + +void vektor_rectangle_free(VektorRectangle* rct) { + free(rct); +} + void vektor_shapebuffer_add_shape(VektorShapeBuffer* buffer, VektorShape shape) { if (buffer->count >= buffer->capacity) { @@ -59,7 +77,7 @@ void vektor_shapebuffer_add_shape(VektorShapeBuffer* buffer, buffer->shapes[buffer->count++] = shape; } -VektorBBox polyline_mk_bbox(VektorPrimitive prim) { +VektorBBox vektor_polyline_get_bbox(VektorPrimitive prim) { float min_x, max_x, min_y, max_y; for (size_t i = 0; i < prim.polyline->count; i++) { V2 p = prim.polyline->points[i]; @@ -72,7 +90,7 @@ VektorBBox polyline_mk_bbox(VektorPrimitive prim) { return (VektorBBox){(V2){min_x, min_y}, (V2){max_x, max_y}}; } -VektorBBox polygon_mk_bbox(VektorPrimitive prim) { +VektorBBox vektor_polygon_get_bbox(VektorPrimitive prim) { float min_x, max_x, min_y, max_y; for (size_t i = 0; i < prim.polygon->count; i++) { V2 p = prim.polygon->points[i]; @@ -85,14 +103,22 @@ VektorBBox polygon_mk_bbox(VektorPrimitive prim) { return (VektorBBox){(V2){min_x, min_y}, (V2){max_x, max_y}}; } -VektorBBox vektor_mk_bbox(VektorPrimitive prim) { +VektorBBox vektor_rectangle_get_bbox(VektorPrimitive prim) { + return *(VektorBBox*)&prim.rectangle; +} + +VektorBBox vektor_primitive_get_bbox(VektorPrimitive prim) { switch (prim.kind) { case VEKTOR_POLYLINE: - return polyline_mk_bbox(prim); + return vektor_polyline_get_bbox(prim); break; case VEKTOR_POLYGON: - return polygon_mk_bbox(prim); + return vektor_polygon_get_bbox(prim); + break; + + case VEKTOR_RECTANGLE: + return vektor_rectangle_get_bbox(prim); break; default: @@ -103,11 +129,11 @@ VektorBBox vektor_mk_bbox(VektorPrimitive prim) { VektorShape vektor_shape_new(VektorPrimitive prim, VektorStyle style, int z_index) { - return (VektorShape){.primitive = prim, .style = style, .z_index = z_index, .bbox=vektor_mk_bbox(prim)}; + return (VektorShape){.primitive = prim, .style = style, .z_index = z_index, .bbox=vektor_primitive_get_bbox(prim)}; } void vektor_shapes_update_bbox(VektorShapeBuffer* buffer) { for (size_t i = 0; i < buffer->count; i++) { - buffer->shapes[i].bbox = vektor_mk_bbox(buffer->shapes[i].primitive); + buffer->shapes[i].bbox = vektor_primitive_get_bbox(buffer->shapes[i].primitive); } } \ No newline at end of file diff --git a/src/core/primitives.h b/src/core/primitives.h index cf5734b..ac3d5e5 100644 --- a/src/core/primitives.h +++ b/src/core/primitives.h @@ -23,10 +23,16 @@ typedef struct { double radius; } VektorCircle; +typedef struct { + V2 start; + V2 end; +} VektorRectangle; + typedef enum { VEKTOR_POLYLINE, VEKTOR_POLYGON, - VEKTOR_CIRCLE + VEKTOR_CIRCLE, + VEKTOR_RECTANGLE } VektorPrimitiveKind; typedef struct { @@ -35,6 +41,7 @@ typedef struct { VektorPolyline* polyline; VektorPolygon* polygon; VektorCircle circle; + VektorRectangle rectangle; }; } VektorPrimitive; @@ -46,6 +53,11 @@ VektorPolygon* vektor_polygon_new(void); void vektor_polygon_add_point(VektorPolygon* pl, V2 point); void vektor_polygon_free(VektorPolygon* pl); +VektorRectangle* vektor_rectangle_new(void); +void vektor_rectangle_set_end(VektorRectangle* rct, V2 point); +void vektor_rectangle_set_start(VektorRectangle* rct, V2 point); +void vektor_rectangle_free(VektorRectangle* rct); + typedef struct { VektorColor stroke_color; float stroke_width; @@ -63,10 +75,11 @@ typedef struct { VektorPrimitive primitive; } VektorShape; -VektorBBox polyline_mk_bbox(VektorPrimitive prim); -VektorBBox polygon_mk_bbox(VektorPrimitive prim); +VektorBBox vektor_polyline_get_bbox(VektorPrimitive prim); +VektorBBox vektor_polygon_get_bbox(VektorPrimitive prim); +VektorBBox vektor_rectangle_get_bbox(VektorPrimitive prim); -VektorBBox vektor_mk_bbox(VektorPrimitive prim); +VektorBBox vektor_primitive_get_bbox(VektorPrimitive prim); VektorShape vektor_shape_new(VektorPrimitive prim, VektorStyle style, int z_index); diff --git a/src/core/raster.c b/src/core/raster.c index f7f8a15..7c7066b 100644 --- a/src/core/raster.c +++ b/src/core/raster.c @@ -12,7 +12,7 @@ void vektor_edgebuffer_add_edge(EdgeBuffer* buffer, Edge edge) { buffer->edges[buffer->count++] = edge; } -void vektor_polyline_flatten(EdgeBuffer* buffer, VektorPolyline* line, +void vektor_polyline_tessellate(EdgeBuffer* buffer, VektorPolyline* line, size_t j) { for (size_t i = 0; i + 1 < line->count; i++) { vektor_edgebuffer_add_edge( @@ -20,7 +20,7 @@ void vektor_polyline_flatten(EdgeBuffer* buffer, VektorPolyline* line, } } -void vektor_polygon_flatten(EdgeBuffer* buffer, VektorPolygon* polygon, +void vektor_polygon_tessellate(EdgeBuffer* buffer, VektorPolygon* polygon, size_t j) { for (size_t i = 0; i + 1 < polygon->count; i++) { vektor_edgebuffer_add_edge( @@ -30,6 +30,20 @@ void vektor_polygon_flatten(EdgeBuffer* buffer, VektorPolygon* polygon, buffer, (Edge){polygon->points[polygon->count - 1], polygon->points[0], 0, j}); } +void vektor_rectangle_tessellate(EdgeBuffer* buffer, VektorRectangle* rct, size_t j) { + if (vec2_equals(rct->end, rct->start)) {return;} + + Edge top = (Edge){rct->start, (V2){rct->end.x, rct->start.y}, 0, j }; + Edge right = (Edge){(V2){rct->end.x, rct->start.y}, rct->end, 0, j}; + Edge bottom = (Edge){(V2){rct->start.x, rct->end.y}, rct->end, 0, j}; + Edge left = (Edge){rct->start, (V2){rct->start.x, rct->end.y}, 0, j }; + + vektor_edgebuffer_add_edge(buffer, top); + vektor_edgebuffer_add_edge(buffer, right); + vektor_edgebuffer_add_edge(buffer, bottom); + vektor_edgebuffer_add_edge(buffer, left); +} + void vektor_rasterize(VertexBuffer* vb, VektorShapeBuffer* shapes) { EdgeBuffer edges = {0}; for (size_t i = 0; i < shapes->count; i++) { @@ -37,11 +51,15 @@ void vektor_rasterize(VertexBuffer* vb, VektorShapeBuffer* shapes) { switch (p->kind) { case VEKTOR_POLYLINE: - vektor_polyline_flatten(&edges, p->polyline, i); + vektor_polyline_tessellate(&edges, p->polyline, i); break; case VEKTOR_POLYGON: - vektor_polygon_flatten(&edges, p->polygon, i); + vektor_polygon_tessellate(&edges, p->polygon, i); + break; + + case VEKTOR_RECTANGLE: + vektor_rectangle_tessellate(&edges, &p->rectangle, i); break; default: diff --git a/src/core/raster.h b/src/core/raster.h index 56f70a7..6bbbb3b 100644 --- a/src/core/raster.h +++ b/src/core/raster.h @@ -23,8 +23,9 @@ typedef struct { void vektor_edgebuffer_add_edge(EdgeBuffer* edges, Edge edge); -void vektor_polyline_flatten(EdgeBuffer* edges, VektorPolyline* line, size_t i); -void vektor_polygon_flatten(EdgeBuffer* buffer, VektorPolygon* line, size_t i); +void vektor_polyline_tessellate(EdgeBuffer* edges, VektorPolyline* line, size_t i); +void vektor_polygon_tessellate(EdgeBuffer* buffer, VektorPolygon* polygon, size_t i); +void vektor_rectangle_tessellate(EdgeBuffer* buffer, VektorRectangle* rct, size_t i); typedef struct { V2 coords; diff --git a/src/core/vector.h b/src/core/vector.h index d483711..2cfea10 100644 --- a/src/core/vector.h +++ b/src/core/vector.h @@ -22,6 +22,10 @@ static inline V2 vec2_add(const V2 v1, const V2 v2) { return (V2){v1.x + v2.x, v1.y + v2.y}; } +static inline bool vec2_equals(const V2 v1, const V2 v2) { + return (bool)(v1.x == v2.x && v1.y == v2.x); +} + static inline V2 vec2_sub(const V2 v1, const V2 v2) { return (V2){v1.x - v2.x, v1.y - v2.y}; }