diff --git a/meson.build b/meson.build index 54346c5..18a27e4 100644 --- a/meson.build +++ b/meson.build @@ -25,6 +25,7 @@ src = files( 'src/core/matrix.c', 'src/core/primitives.c', 'src/core/raster.c', + 'src/core/modifier.c', 'src/ui/uicontroller.c', 'src/ui/vektorcanvas.c', 'src/ui/widgets/colorwheel.c', diff --git a/src/application/applicationstate.c b/src/application/applicationstate.c index 2177b82..4df7752 100644 --- a/src/application/applicationstate.c +++ b/src/application/applicationstate.c @@ -1,4 +1,5 @@ #include "src/core/matrix.h" +#include "src/core/modifier.h" #include "src/ui/uicontroller.h" #include "stdlib.h" @@ -7,7 +8,7 @@ #include "gtk/gtk.h" #include "gtk/gtkrevealer.h" #include "src/core/primitives.h" -#include "src/core/raster.h" + #include "src/ui/vektorcanvas.h" #include "src/ui/widgets/colorwheel.h" #include "src/util/color.h" @@ -46,7 +47,7 @@ static void appstate_on_color_change(VektorColorWheel* wheel, appstate->currentColor = c; if (appstate->selectedShape != NULL) { - appstate->selectedShape->style.stroke_color = c; + appstate->selectedShape->base.style.stroke_color = c; } // set entry fields under the color selector @@ -117,13 +118,13 @@ begin_click_dispatch: VektorStyle style = (VektorStyle){ .stroke_color = state->currentColor, .stroke_width = 0.01}; - vektor_shapebuffer_add_shape( - state->shapeBuffer, vektor_shape_new(linePrimitive, style, 0)); + vektor_shapenodebuf_add( + state->shapeBuffer, vektor_shapenode_new(vektor_shape_new(linePrimitive, style, 0))); state->selectedShape = - &(state->shapeBuffer->shapes[state->shapeBuffer->count - 1]); + &(state->shapeBuffer->nodes[state->shapeBuffer->count - 1]); - } else if (state->selectedShape->primitive.kind != VEKTOR_POLYLINE) { + } else if (state->selectedShape->base.primitive.kind != VEKTOR_POLYLINE) { // selecting a tool resets the selection, so this condition // should not happen g_warning("Invalid selected primitive; polyline expected"); @@ -131,12 +132,12 @@ begin_click_dispatch: goto begin_click_dispatch; // retry } - vektor_polyline_add_point(state->selectedShape->primitive.polyline, + vektor_polyline_add_point(state->selectedShape->base.primitive.polyline, pos); - vektor_shapes_update_bbox(state->shapeBuffer); + state->selectedShape->base.bbox = vektor_primitive_get_bbox(state->selectedShape->base.primitive); // polyline's handle count is not fixed, so we have to add them manually - vektor_shape_add_handle(state->selectedShape, pos); + vektor_shape_add_handle(&state->selectedShape->base, pos); } else if (state->selectedTool == VektorPolygonTool) { // create new polygon shape if none is selected @@ -147,24 +148,23 @@ begin_click_dispatch: (VektorPrimitive){.kind = VEKTOR_POLYGON, .polygon = polygon}; VektorStyle style = (VektorStyle){ .stroke_color = state->currentColor, .stroke_width = 0.01}; - vektor_shapebuffer_add_shape( - state->shapeBuffer, - vektor_shape_new(polygonPrimitive, style, 0)); + vektor_shapenodebuf_add( + state->shapeBuffer, vektor_shapenode_new(vektor_shape_new(polygonPrimitive, style, 0))); state->selectedShape = - &(state->shapeBuffer->shapes[state->shapeBuffer->count - 1]); + &(state->shapeBuffer->nodes[state->shapeBuffer->count - 1]); - } else if (state->selectedShape->primitive.kind != VEKTOR_POLYGON) { + } else if (state->selectedShape->base.primitive.kind != VEKTOR_POLYGON) { g_warning("Invalid selected primitive; polygon expected"); vektor_appstate_deselect_shape(state); goto begin_click_dispatch; // retry } - vektor_polygon_add_point(state->selectedShape->primitive.polygon, pos); - vektor_shapes_update_bbox(state->shapeBuffer); + vektor_polygon_add_point(state->selectedShape->base.primitive.polygon, pos); + state->selectedShape->base.bbox = vektor_primitive_get_bbox(state->selectedShape->base.primitive); // polygon's handle count is not fixed, so we have to add them manually - vektor_shape_add_handle(state->selectedShape, pos); + vektor_shape_add_handle(&state->selectedShape->base, pos); } else if (state->selectedTool == VektorCircleTool) { @@ -173,22 +173,22 @@ begin_click_dispatch: (VektorPrimitive){.kind = VEKTOR_CIRCLE, .circle = *circle}; VektorStyle style = (VektorStyle){.stroke_color = state->currentColor, .stroke_width = 0.01}; - vektor_shapebuffer_add_shape( - state->shapeBuffer, vektor_shape_new(circlePrimitive, style, 0)); + vektor_shapenodebuf_add( + state->shapeBuffer, vektor_shapenode_new(vektor_shape_new(circlePrimitive, style, 0))); state->selectedShape = - &(state->shapeBuffer->shapes[state->shapeBuffer->count - 1]); + &(state->shapeBuffer->nodes[state->shapeBuffer->count - 1]); vektor_circle_free(circle); - vektor_circle_set_center(&state->selectedShape->primitive.circle, pos); - vektor_circle_set_radius(&state->selectedShape->primitive.circle, 0.1f); + vektor_circle_set_center(&state->selectedShape->base.primitive.circle, pos); + vektor_circle_set_radius(&state->selectedShape->base.primitive.circle, 0.1f); - vektor_shapes_update_bbox(state->shapeBuffer); + state->selectedShape->base.bbox = vektor_primitive_get_bbox(state->selectedShape->base.primitive); - vektor_circle_create_handles(&state->selectedShape->primitive.circle, - &state->selectedShape->handles, - &state->selectedShape->handleCount); + vektor_circle_create_handles(&state->selectedShape->base.primitive.circle, + &state->selectedShape->base.handles, + &state->selectedShape->base.handleCount); } else if (state->selectedTool == VektorRectangleTool) { VektorRectangle* rect = vektor_rectangle_new(); @@ -196,35 +196,35 @@ begin_click_dispatch: (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)); + vektor_shapenodebuf_add( + state->shapeBuffer, vektor_shapenode_new(vektor_shape_new(rectPrimitive, style, 0))); state->selectedShape = - &(state->shapeBuffer->shapes[state->shapeBuffer->count - 1]); + &(state->shapeBuffer->nodes[state->shapeBuffer->count - 1]); vektor_rectangle_free(rect); - vektor_rectangle_set_start(&state->selectedShape->primitive.rectangle, + vektor_rectangle_set_start(&state->selectedShape->base.primitive.rectangle, pos); - vektor_rectangle_set_end(&state->selectedShape->primitive.rectangle, + vektor_rectangle_set_end(&state->selectedShape->base.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->base.primitive.rectangle, + &state->selectedShape->base.handles, &state->selectedShape->base.handleCount); + + state->selectedShape->base.bbox = vektor_primitive_get_bbox(state->selectedShape->base.primitive); - // state->selectedShape = NULL; - vektor_shapes_update_bbox(state->shapeBuffer); } else if (state->selectedTool == VektorSelectionTool) { for (size_t i = 0; i < state->shapeBuffer->count; i++) { VektorBBox bbox = vektor_primitive_get_bbox( - state->shapeBuffer->shapes[i].primitive); + state->shapeBuffer->nodes[i].base.primitive); // expand the bbox a little so its not painful to // try to grab handles located on the border of said bbox bbox = vektor_bbox_expand(bbox, 0.02); if (vektor_bbox_isinside(bbox, pos)) { - state->selectedShape = &(state->shapeBuffer->shapes[i]); + state->selectedShape = &(state->shapeBuffer->nodes[i]); return; } } @@ -249,12 +249,12 @@ void vektor_appstate_canvas_drag_begin(GtkGestureDrag* gesture, gdouble x, m33_transform(m33_inverse(state->renderInfo->canvasMat), (V2){position.x, position.y}); if(state->selectedShape != NULL) { - VektorShape* selectedShape = state->selectedShape; + VektorShapeNode* selectedShape = state->selectedShape; // get selected shape's handles and check // if we click any of them - for(size_t i = 0; i < selectedShape->handleCount; i++) { - VektorBBox bbox = vektor_shape_get_handle_bbox(selectedShape->handles[i]); + for(size_t i = 0; i < selectedShape->base.handleCount; i++) { + VektorBBox bbox = vektor_shape_get_handle_bbox(selectedShape->base.handles[i]); if(vektor_bbox_isinside(bbox, position)) { // clicked inside handle state->heldHandleIndex = i; @@ -288,8 +288,8 @@ void vektor_appstate_canvas_drag_update(GtkGestureDrag* gesture, gdouble x, // drag handle if selected if(state->selectedShape != NULL && state->heldHandleIndex != -1) { - state->selectedShape->handles[state->heldHandleIndex] = position; - vektor_shape_handles_updated(state->selectedShape, &state->heldHandleIndex); + state->selectedShape->base.handles[state->heldHandleIndex] = position; + vektor_shape_handles_updated(&state->selectedShape->base, &state->heldHandleIndex); vektor_canvas_geometry_changed(state->renderInfo); } } @@ -337,8 +337,8 @@ void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut) { // populate appstate stateOut->startupTime = g_get_monotonic_time(); - stateOut->shapeBuffer = malloc(sizeof(VektorShapeBuffer)); - *stateOut->shapeBuffer = (VektorShapeBuffer){0}; + stateOut->shapeBuffer = malloc(sizeof(VektorShapeNodeBuffer)); + *stateOut->shapeBuffer = (VektorShapeNodeBuffer){0}; stateOut->canvas = malloc(sizeof(VektorCanvas)); stateOut->widgetState = wstate; stateOut->currentColor = vektor_color_solid(0, 0, 0); diff --git a/src/application/applicationstate.h b/src/application/applicationstate.h index 259fa81..7737271 100644 --- a/src/application/applicationstate.h +++ b/src/application/applicationstate.h @@ -4,7 +4,7 @@ #include "../core/primitives.h" #include "../ui/uicontroller.h" #include "../ui/vektorcanvas.h" -#include "src/core/raster.h" +#include "src/core/modifier.h" typedef enum VektorAppTool { VektorSelectionTool, @@ -20,13 +20,13 @@ typedef struct VektorAppState { VektorWidgetState* widgetState; VektorAppTool selectedTool; - VektorShape* selectedShape; + VektorShapeNode* selectedShape; int heldHandleIndex; VektorColor currentColor; // Logic space - VektorShapeBuffer* shapeBuffer; + VektorShapeNodeBuffer* shapeBuffer; // View space VektorCanvas* canvas; VektorCanvasRenderInfo* renderInfo; diff --git a/src/core/modifier.c b/src/core/modifier.c new file mode 100644 index 0000000..299c821 --- /dev/null +++ b/src/core/modifier.c @@ -0,0 +1,30 @@ +#include "modifier.h" + +VektorShapeNode vektor_shapenode_new(VektorShape shape) { + VektorShapeNode node = (VektorShapeNode) { + .base = shape, + .modifier_count = 0, + .evaluated = shape + }; + return node; +} + +VektorShape* vektor_shapenode_get_evaluated(VektorShapeNode* shapeNode) { + + return &shapeNode->evaluated; +} + +void vektor_shapenodebuf_add(VektorShapeNodeBuffer* buffer, VektorShapeNode node) { + if (buffer->count >= buffer->capacity) { + buffer->capacity = buffer->capacity ? buffer->capacity * 2 : 4; + buffer->nodes = + realloc(buffer->nodes, sizeof(VektorShapeNode) * buffer->capacity); + } + buffer->nodes[buffer->count++] = node; + + if (buffer->count <= buffer->capacity / 4) { + buffer->capacity /= 2; + buffer->nodes = + realloc(buffer->nodes, sizeof(VektorShapeNode) * buffer->capacity); + } +} \ No newline at end of file diff --git a/src/core/modifier.h b/src/core/modifier.h new file mode 100644 index 0000000..024ed55 --- /dev/null +++ b/src/core/modifier.h @@ -0,0 +1,44 @@ +#ifndef VKTR_MODIFIER_H +#define VKTR_MODIFIER_H + +#include "src/core/primitives.h" + +typedef enum { + VEKTOR_MODIFIER_BEVEL +} VektorModifierType; + +typedef struct VektorModifier { + VektorModifierType type; + bool enabled; + bool dirty; + void* parameters; + + VektorShape (*apply)(struct VektorModifier mod, VektorShape input); + +} VektorModifier; + +typedef struct VektorShapeNode { + VektorShape base; + VektorShape evaluated; + + VektorModifier* modifiers; + size_t modifier_count; + + bool base_dirty; +} VektorShapeNode; + +typedef struct VektorShapeNodeBuffer { + VektorShapeNode* nodes; + size_t count; + size_t capacity; +} VektorShapeNodeBuffer; + +VektorShapeNode vektor_shapenode_new(VektorShape shape); +VektorShape* vektor_shapenode_get_evaluated(VektorShapeNode* shapeNode); +void vektor_shapenode_modifier_add(VektorShapeNode* shapeNode, VektorModifier* mod); +void vektor_shapenode_modifier_remove(VektorShapeNode* shapeNode, VektorModifier* mod); +void vektor_shapenode_free(VektorShapeNode* shapeNode); + +void vektor_shapenodebuf_add(VektorShapeNodeBuffer* buffer, VektorShapeNode node); + +#endif \ No newline at end of file diff --git a/src/core/raster.c b/src/core/raster.c index dca16ba..d91f741 100644 --- a/src/core/raster.c +++ b/src/core/raster.c @@ -2,6 +2,7 @@ #include "epoxy/gl.h" #include "primitives.h" #include "src/core/matrix.h" +#include "src/core/modifier.h" #include "src/core/vector.h" #include "stddef.h" #include @@ -68,11 +69,11 @@ void vektor_rectangle_tessellate(EdgeBuffer* buffer, VektorRectangle* rct, vektor_edgebuffer_add_edge(buffer, left); } -void vektor_rasterize(VertexBuffer* vb, VektorShapeBuffer* shapes, +void vektor_vb_rasterize(VertexBuffer* vb, VektorShapeNodeBuffer* nodes, double scale) { EdgeBuffer edges = {0}; - for (size_t i = 0; i < shapes->count; i++) { - VektorPrimitive* p = &shapes->shapes[i].primitive; + for (size_t i = 0; i < nodes->count; i++) { + VektorPrimitive* p = &nodes->nodes[i].base.primitive; switch (p->kind) { case VEKTOR_POLYLINE: @@ -97,7 +98,7 @@ void vektor_rasterize(VertexBuffer* vb, VektorShapeBuffer* shapes, } } - vektor_edges_to_triangles(vb, &edges, shapes); + vektor_edges_to_triangles(vb, &edges, nodes); } void vektor_vb_add_triangle(VertexBuffer* vb, V2 v0, V2 v1, V2 v2, @@ -133,7 +134,7 @@ void vektor_vb_add_quad(VertexBuffer* vb, V2 a, V2 b, VektorColor color) { } void vektor_edge_to_triangles(VertexBuffer* vb, Edge e, - VektorShapeBuffer* shape_buffer) { + VektorShapeNodeBuffer* node_buffer) { float dx = e.p2.x - e.p1.x; float dy = e.p2.y - e.p1.y; float len = sqrtf(dx * dx + dy * dy); @@ -141,28 +142,28 @@ void vektor_edge_to_triangles(VertexBuffer* vb, Edge e, return; float px = - -dy / len * (shape_buffer->shapes[e.shape_id].style.stroke_width / 2); + -dy / len * (node_buffer->nodes[e.shape_id].base.style.stroke_width / 2); float py = - dx / len * (shape_buffer->shapes[e.shape_id].style.stroke_width / 2); + dx / len * (node_buffer->nodes[e.shape_id].base.style.stroke_width / 2); - V2 v0 = m33_transform(shape_buffer->shapes[e.shape_id].transform, + V2 v0 = m33_transform(node_buffer->nodes[e.shape_id].base.transform, (V2){e.p1.x + px, e.p1.y + py}); - V2 v1 = m33_transform(shape_buffer->shapes[e.shape_id].transform, + V2 v1 = m33_transform(node_buffer->nodes[e.shape_id].base.transform, (V2){e.p1.x - px, e.p1.y - py}); - V2 v2 = m33_transform(shape_buffer->shapes[e.shape_id].transform, + V2 v2 = m33_transform(node_buffer->nodes[e.shape_id].base.transform, (V2){e.p2.x + px, e.p2.y + py}); - V2 v3 = m33_transform(shape_buffer->shapes[e.shape_id].transform, + V2 v3 = m33_transform(node_buffer->nodes[e.shape_id].base.transform, (V2){e.p2.x - px, e.p2.y - py}); vektor_vb_add_triangle(vb, v0, v1, v2, - shape_buffer->shapes[e.shape_id].style.stroke_color); + node_buffer->nodes[e.shape_id].base.style.stroke_color); vektor_vb_add_triangle(vb, v2, v1, v3, - shape_buffer->shapes[e.shape_id].style.stroke_color); + node_buffer->nodes[e.shape_id].base.style.stroke_color); } void vektor_edges_to_triangles(VertexBuffer* vb, EdgeBuffer* edges, - VektorShapeBuffer* shape_buffer) { + VektorShapeNodeBuffer* node_buffer) { for (size_t i = 0; i < edges->count; i++) { - vektor_edge_to_triangles(vb, edges->edges[i], shape_buffer); + vektor_edge_to_triangles(vb, edges->edges[i], node_buffer); } } \ No newline at end of file diff --git a/src/core/raster.h b/src/core/raster.h index 7a675fa..ca0c37c 100644 --- a/src/core/raster.h +++ b/src/core/raster.h @@ -4,6 +4,7 @@ #include "primitives.h" #include "../util/color.h" +#include "src/core/modifier.h" #include "stddef.h" #include "vector.h" #include @@ -48,10 +49,10 @@ void vektor_vb_add_triangle(VertexBuffer* vb, V2 v0, V2 v1, V2 v2, void vektor_vb_add_quad(VertexBuffer* vb, V2 v0, V2 v1, VektorColor color); void vektor_edge_to_triangles(VertexBuffer* vb, Edge e, - VektorShapeBuffer* shape_buffer); + VektorShapeNodeBuffer* node_buffer); void vektor_edges_to_triangles(VertexBuffer* vb, EdgeBuffer* edges, - VektorShapeBuffer* shape_buffer); -void vektor_rasterize(VertexBuffer* vb, VektorShapeBuffer* shapes, + VektorShapeNodeBuffer* node_buffer) ; +void vektor_vb_rasterize(VertexBuffer* vb, VektorShapeNodeBuffer* shapes, double scale); #endif // RASTER_H_ diff --git a/src/ui/vektorcanvas.c b/src/ui/vektorcanvas.c index e149d41..0c207b4 100644 --- a/src/ui/vektorcanvas.c +++ b/src/ui/vektorcanvas.c @@ -139,17 +139,17 @@ static void init_geometry(void) { void vektor_canvas_geometry_changed(VektorCanvasRenderInfo* renderInfo) { vb.count = 0; - vektor_rasterize(&vb, renderInfo->shapes, renderInfo->zoom); + vektor_vb_rasterize(&vb, renderInfo->shapes, renderInfo->zoom); shape_vertex_count = vb.count; if (renderInfo->selectedShape != NULL && *(renderInfo->selectedShape) != NULL) { - VektorShape* selectedShape = *renderInfo->selectedShape; + VektorShapeNode* 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]; + for (size_t i = 0; i < selectedShape->base.handleCount; i++) { + V2 handle = selectedShape->base.handles[i]; VektorBBox handleBbox = vektor_shape_get_handle_bbox(handle); vektor_vb_add_quad(&vb, handleBbox.min, handleBbox.max, vektor_color_new(255, 255, 255, 255)); @@ -158,7 +158,7 @@ void vektor_canvas_geometry_changed(VektorCanvasRenderInfo* renderInfo) { shape_vertex_count = vb.count; // create selection quad if a shape is selected - VektorBBox bbox = vektor_primitive_get_bbox(selectedShape->primitive); + VektorBBox bbox = vektor_primitive_get_bbox(selectedShape->base.primitive); // expand it a little so it is not inset bbox = vektor_bbox_expand(bbox, 0.03f); @@ -199,7 +199,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); + (*(renderInfo->selectedShape))->base.primitive); bbox = vektor_bbox_expand(bbox, 0.03f); glUseProgram(selection_shader_program); diff --git a/src/ui/vektorcanvas.h b/src/ui/vektorcanvas.h index 15e0dfc..475a56c 100644 --- a/src/ui/vektorcanvas.h +++ b/src/ui/vektorcanvas.h @@ -5,6 +5,7 @@ #include "../util/color.h" #include "gtk/gtk.h" #include "src/core/matrix.h" +#include "src/core/modifier.h" #include "src/core/primitives.h" #include "uicontroller.h" @@ -22,10 +23,10 @@ typedef struct VektorCanvas { typedef struct VektorCanvasRenderInfo { gint64 startupTime; - VektorShapeBuffer* shapes; + VektorShapeNodeBuffer* shapes; // a pointer to appstate->selectedShape - VektorShape** selectedShape; + VektorShapeNode** selectedShape; float zoom; float panX; float panY;