From eefd95e4d27fdd32f62335eaa4417fb7ef62c92b Mon Sep 17 00:00:00 2001 From: Froxwin <56168224+Froxwin@users.noreply.github.com> Date: Thu, 5 Mar 2026 00:51:20 +0530 Subject: [PATCH] feat: add stroke thickness --- src/application/applicationstate.c | 85 ++++++++------- src/application/applicationstate.h | 20 ++-- src/core/matrix.c | 92 ++++++++--------- src/core/matrix.h | 2 +- src/core/primitives.c | 68 ++++++------ src/core/primitives.h | 48 ++++----- src/core/raster.c | 159 +++++++++++++++-------------- src/core/raster.h | 23 +++-- src/core/vector.h | 28 ++--- src/main.c | 37 ++++--- src/ui/uicontroller.c | 60 +++++------ src/ui/uicontroller.h | 10 +- src/ui/vektorcanvas.c | 77 +++++++------- src/ui/vektorcanvas.h | 14 +-- src/util/color.h | 12 +-- 15 files changed, 379 insertions(+), 356 deletions(-) diff --git a/src/application/applicationstate.c b/src/application/applicationstate.c index 115d915..169fe3a 100644 --- a/src/application/applicationstate.c +++ b/src/application/applicationstate.c @@ -1,42 +1,61 @@ #include "./applicationstate.h" +#include "glib.h" #include "src/core/primitives.h" #include "src/core/raster.h" #include "src/ui/vektorcanvas.h" typedef struct button_tool_set_data { - VektorAppState* state; + VektorAppState *state; VektorAppTool tool; } button_tool_set_data; -static void appstate_set_tool(GtkButton* button, gpointer user_data) { - button_tool_set_data* data = (button_tool_set_data*)user_data; +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; // setting tool also resets selected primitive data->state->selectedPrimitive = NULL; } -static void canvas_onclick(GtkGestureClick* gesture, int n_press, double x, double y, gpointer user_data) { - vektor_appstate_canvas_click(user_data, x, y); +static void canvas_onclick(GtkGestureClick *gesture, int n_press, double x, + double y, gpointer user_data) { + + VektorAppState *state = user_data; + + GtkWidget *widget = + gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + + int widget_w = gtk_widget_get_width(widget); + int widget_h = gtk_widget_get_height(widget); + + int canvas_w = state->canvas->width; + int canvas_h = state->canvas->height; + + double sx = canvas_w / (double)widget_w; + double sy = canvas_h / (double)widget_h; + + g_debug("<%f , %f>", x * sx, y * sy); + vektor_appstate_canvas_click(state, x * sx, y * sy); } -void vektor_appstate_canvas_click(VektorAppState* state, double x, double y) { - V2 pos = (V2){x,y}; +void vektor_appstate_canvas_click(VektorAppState *state, double x, double y) { + V2 pos = (V2){x, y}; - begin_click_dispatch: - if(state->selectedTool == VektorLineTool) { +begin_click_dispatch: + if (state->selectedTool == VektorLineTool) { // create new polyline primitive if none is selected - if(state->selectedPrimitive == NULL) { - - VektorPolyline* line = vektor_polyline_new(); - VektorPrimitive linePrimitive = (VektorPrimitive){ - .kind = VEKTOR_POLYLINE, .polyline = line - }; - vektor_primitivebuffer_add_primitive(state->primitiveBuffer, linePrimitive); - - state->selectedPrimitive = - &(state->primitiveBuffer->primitives[state->primitiveBuffer->count - 1]); - + if (state->selectedPrimitive == NULL) { + + VektorPolyline *line = vektor_polyline_new(); + VektorPrimitive linePrimitive = + (VektorPrimitive){.kind = VEKTOR_POLYLINE, .polyline = line}; + vektor_primitivebuffer_add_primitive(state->primitiveBuffer, + linePrimitive); + + state->selectedPrimitive = + &(state->primitiveBuffer + ->primitives[state->primitiveBuffer->count - 1]); + } else if (state->selectedPrimitive->kind != VEKTOR_POLYLINE) { // selecting a tool resets the selection, so this condition // should not happen @@ -44,8 +63,7 @@ void vektor_appstate_canvas_click(VektorAppState* state, double x, double y) { state->selectedPrimitive = NULL; goto begin_click_dispatch; // retry } - - + vektor_polyline_add_point(state->selectedPrimitive->polyline, pos); } @@ -54,8 +72,8 @@ void vektor_appstate_canvas_click(VektorAppState* state, double x, double y) { vektor_canvas_update(state->canvas); } -void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut) { - button_tool_set_data* data_linetool = malloc(sizeof(button_tool_set_data)); +void vektor_appstate_new(VektorWidgetState *wstate, VektorAppState *stateOut) { + button_tool_set_data *data_linetool = malloc(sizeof(button_tool_set_data)); data_linetool->state = stateOut; data_linetool->tool = VektorLineTool; @@ -68,18 +86,13 @@ void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut) { vektor_canvas_init(wstate, stateOut->canvas); // link all the buttons - g_signal_connect( - G_OBJECT(wstate->workspaceButtonLinetool), - "clicked", G_CALLBACK(appstate_set_tool), data_linetool); + g_signal_connect(G_OBJECT(wstate->workspaceButtonLinetool), "clicked", + G_CALLBACK(appstate_set_tool), data_linetool); // Add click gesture to canvas - GtkGesture* canvasClickGesture = gtk_gesture_click_new(); - g_signal_connect( - G_OBJECT(canvasClickGesture), - "pressed", G_CALLBACK(canvas_onclick), stateOut - ); - gtk_widget_add_controller( - GTK_WIDGET(wstate->workspaceCanvas), - GTK_EVENT_CONTROLLER(canvasClickGesture) - ); + GtkGesture *canvasClickGesture = gtk_gesture_click_new(); + g_signal_connect(G_OBJECT(canvasClickGesture), "pressed", + G_CALLBACK(canvas_onclick), stateOut); + gtk_widget_add_controller(GTK_WIDGET(wstate->workspaceCanvas), + GTK_EVENT_CONTROLLER(canvasClickGesture)); } \ No newline at end of file diff --git a/src/application/applicationstate.h b/src/application/applicationstate.h index 1c143d6..9967f5c 100644 --- a/src/application/applicationstate.h +++ b/src/application/applicationstate.h @@ -1,29 +1,27 @@ #ifndef VKTR_APPSTATE_H #define VKTR_APPSTATE_H -#include "../ui/uicontroller.h" #include "../core/primitives.h" -#include "src/core/raster.h" +#include "../ui/uicontroller.h" #include "../ui/vektorcanvas.h" +#include "src/core/raster.h" -typedef enum VektorAppTool { - VektorLineTool -} VektorAppTool; +typedef enum VektorAppTool { VektorLineTool } VektorAppTool; typedef struct VektorAppState { VektorAppTool selectedTool; - VektorPrimitive* selectedPrimitive; + VektorPrimitive *selectedPrimitive; // Logic space - VektorPrimitiveBuffer* primitiveBuffer; + VektorPrimitiveBuffer *primitiveBuffer; // Pixel space - VektorFramebuffer* frameBuffer; + VektorFramebuffer *frameBuffer; // View space - VektorCanvas* canvas; + VektorCanvas *canvas; } VektorAppState; -void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut); -void vektor_appstate_canvas_click(VektorAppState* state, double x, double y); +void vektor_appstate_new(VektorWidgetState *wstate, VektorAppState *stateOut); +void vektor_appstate_canvas_click(VektorAppState *state, double x, double y); #endif \ No newline at end of file diff --git a/src/core/matrix.c b/src/core/matrix.c index f2013c1..3ab914e 100644 --- a/src/core/matrix.c +++ b/src/core/matrix.c @@ -4,86 +4,86 @@ inline M33 m33_zero(void) { return (M33){{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}}; } inline M33 m33_identity(void) { - return (M33){{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}}; + return (M33){{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}}; } inline M33 m33_translate(double tx, double ty) { - return (M33){{{1, 0, tx}, {0, 1, ty}, {0, 0, 1}}}; + return (M33){{{1, 0, tx}, {0, 1, ty}, {0, 0, 1}}}; } inline M33 m33_scale(double sx, double sy) { - return (M33){{{sx, 0, 0}, {0, sy, 0}, {0, 0, 1}}}; + return (M33){{{sx, 0, 0}, {0, sy, 0}, {0, 0, 1}}}; } inline M33 m33_rotate(double theta) { - return (M33){ - {{cos(theta), -sin(theta), 0}, {sin(theta), cos(theta), 0}, {0, 0, 1}}}; + return (M33){ + {{cos(theta), -sin(theta), 0}, {sin(theta), cos(theta), 0}, {0, 0, 1}}}; } inline M33 m33_shear(double theta_x, double theta_y) { - return (M33){{{1, tan(theta_x), 0}, {tan(theta_y), 1, 0}, {0, 0, 0}}}; + return (M33){{{1, tan(theta_x), 0}, {tan(theta_y), 1, 0}, {0, 0, 0}}}; } M33 m33_add(const M33 m1, const M33 m2) { - M33 res; - for (int i = 0; i < 3; ++i) - for (int j = 0; j < 3; ++j) - res.m[i][j] = m1.m[i][j] + m2.m[i][j]; - return res; + M33 res; + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) + res.m[i][j] = m1.m[i][j] + m2.m[i][j]; + return res; } M33 m33_sub(const M33 m1, const M33 m2) { - M33 res; - for (int i = 0; i < 3; ++i) - for (int j = 0; j < 3; ++j) - res.m[i][j] = m1.m[i][j] - m2.m[i][j]; - return res; + M33 res; + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) + res.m[i][j] = m1.m[i][j] - m2.m[i][j]; + return res; } M33 m33_mul(const M33 m1, const M33 m2) { - M33 res = {{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}}; - for (int i = 0; i < 3; ++i) - for (int j = 0; j < 3; ++j) - for (int k = 0; k < 3; ++k) - res.m[i][j] += m1.m[i][k] * m2.m[k][j]; - return res; + M33 res = {{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}}; + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) + for (int k = 0; k < 3; ++k) + res.m[i][j] += m1.m[i][k] * m2.m[k][j]; + return res; } M33 m33_transpose(const M33 m) { - M33 res; - for (int i = 0; i < 3; ++i) - for (int j = 0; j < 3; ++j) - res.m[i][j] = m.m[j][i]; - return res; + M33 res; + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) + res.m[i][j] = m.m[j][i]; + return res; } // 2D affine transform inversion (not general 3x3 inversion) M33 m33_inverse(const M33 m) { - M33 inv; - double det; + M33 inv; + double det; - det = m.m[0][0] * m.m[1][1] - m.m[0][1] * m.m[1][0]; - if (det == 0.0) { - return m33_identity(); - } - double invDet = 1.0 / det; + det = m.m[0][0] * m.m[1][1] - m.m[0][1] * m.m[1][0]; + if (det == 0.0) { + return m33_identity(); + } + double invDet = 1.0 / det; - inv.m[0][0] = m.m[1][1] * invDet; - inv.m[0][1] = -m.m[0][1] * invDet; - inv.m[1][0] = -m.m[1][0] * invDet; - inv.m[1][1] = m.m[0][0] * invDet; + inv.m[0][0] = m.m[1][1] * invDet; + inv.m[0][1] = -m.m[0][1] * invDet; + inv.m[1][0] = -m.m[1][0] * invDet; + inv.m[1][1] = m.m[0][0] * invDet; - inv.m[0][2] = -(inv.m[0][0] * m.m[0][2] + inv.m[0][1] * m.m[1][2]); - inv.m[1][2] = -(inv.m[1][0] * m.m[0][2] + inv.m[1][1] * m.m[1][2]); + inv.m[0][2] = -(inv.m[0][0] * m.m[0][2] + inv.m[0][1] * m.m[1][2]); + inv.m[1][2] = -(inv.m[1][0] * m.m[0][2] + inv.m[1][1] * m.m[1][2]); - inv.m[2][0] = 0; - inv.m[2][1] = 0; - inv.m[2][2] = 1; + inv.m[2][0] = 0; + inv.m[2][1] = 0; + inv.m[2][2] = 1; - return inv; + return inv; } V2 m33_transform(const M33 mat, const V2 v) { - return (V2){mat.m[0][0] * v.x + mat.m[0][1] * v.y + mat.m[0][2], - mat.m[1][0] * v.x + mat.m[1][1] * v.y + mat.m[1][2]}; + return (V2){mat.m[0][0] * v.x + mat.m[0][1] * v.y + mat.m[0][2], + mat.m[1][0] * v.x + mat.m[1][1] * v.y + mat.m[1][2]}; } diff --git a/src/core/matrix.h b/src/core/matrix.h index 55219f1..10a47f1 100644 --- a/src/core/matrix.h +++ b/src/core/matrix.h @@ -5,7 +5,7 @@ // Row major 3x3 matricies typedef struct { - double m[3][3]; + double m[3][3]; } M33; M33 m33_identity(void); diff --git a/src/core/primitives.c b/src/core/primitives.c index 402b7cc..51b3238 100644 --- a/src/core/primitives.c +++ b/src/core/primitives.c @@ -1,57 +1,57 @@ #include "primitives.h" VektorPolyline *vektor_polyline_new(void) { - VektorPolyline *pl = malloc(sizeof(VektorPolyline)); - pl->count = 0; - pl->capacity = 4; - pl->points = malloc(sizeof(V2) * pl->capacity); - return pl; + VektorPolyline *pl = malloc(sizeof(VektorPolyline)); + pl->count = 0; + pl->capacity = 4; + pl->points = malloc(sizeof(V2) * pl->capacity); + return pl; } void vektor_polyline_add_point(VektorPolyline *pl, V2 point) { - if (pl->count >= pl->capacity) { - pl->capacity *= 2; - pl->points = realloc(pl->points, sizeof(V2) * pl->capacity); - } - pl->points[pl->count++] = point; + if (pl->count >= pl->capacity) { + pl->capacity *= 2; + pl->points = realloc(pl->points, sizeof(V2) * pl->capacity); + } + pl->points[pl->count++] = point; } void vektor_polyline_free(VektorPolyline *pl) { - if (!pl) - return; - free(pl->points); - free(pl); + if (!pl) + return; + free(pl->points); + free(pl); } VektorPolygon *vektor_polygon_new(void) { - VektorPolygon *pg = malloc(sizeof(VektorPolygon)); - pg->count = 0; - pg->capacity = 4; - pg->points = malloc(sizeof(V2) * pg->capacity); - return pg; + VektorPolygon *pg = malloc(sizeof(VektorPolygon)); + pg->count = 0; + pg->capacity = 4; + pg->points = malloc(sizeof(V2) * pg->capacity); + return pg; } void vektor_polygon_add_point(VektorPolygon *pg, V2 point) { - if (pg->count >= pg->capacity) { - pg->capacity *= 2; - pg->points = realloc(pg->points, sizeof(V2) * pg->capacity); - } - pg->points[pg->count++] = point; + if (pg->count >= pg->capacity) { + pg->capacity *= 2; + pg->points = realloc(pg->points, sizeof(V2) * pg->capacity); + } + pg->points[pg->count++] = point; } void vektor_polygon_free(VektorPolygon *pg) { - if (!pg) - return; - free(pg->points); - free(pg); + if (!pg) + return; + free(pg->points); + free(pg); } void vektor_primitivebuffer_add_primitive(VektorPrimitiveBuffer *buffer, VektorPrimitive prim) { - if (buffer->count >= buffer->capacity) { - buffer->capacity = buffer->capacity ? buffer->capacity * 2 : 4; - buffer->primitives = - realloc(buffer->primitives, sizeof(VektorPrimitive) * buffer->capacity); - } - buffer->primitives[buffer->count++] = prim; + if (buffer->count >= buffer->capacity) { + buffer->capacity = buffer->capacity ? buffer->capacity * 2 : 4; + buffer->primitives = realloc( + buffer->primitives, sizeof(VektorPrimitive) * buffer->capacity); + } + buffer->primitives[buffer->count++] = prim; } diff --git a/src/core/primitives.h b/src/core/primitives.h index 8ad91bb..e342cba 100644 --- a/src/core/primitives.h +++ b/src/core/primitives.h @@ -6,42 +6,42 @@ #include "vector.h" typedef struct { - V2 p1; - V2 p2; + V2 p1; + V2 p2; } VektorLine; typedef struct { - V2 *points; - size_t count; - size_t capacity; + V2 *points; + size_t count; + size_t capacity; } VektorPolyline; typedef struct { - V2 *points; - size_t count; - size_t capacity; + V2 *points; + size_t count; + size_t capacity; } VektorPolygon; typedef struct { - V2 center; - double radius; + V2 center; + double radius; } VektorCircle; typedef enum { - VEKTOR_LINE, - VEKTOR_POLYLINE, - VEKTOR_POLYGON, - VEKTOR_CIRCLE + VEKTOR_LINE, + VEKTOR_POLYLINE, + VEKTOR_POLYGON, + VEKTOR_CIRCLE } VektorPrimitiveKind; typedef struct { - VektorPrimitiveKind kind; - union { - VektorLine line; - VektorPolyline *polyline; - VektorPolygon *polygon; - VektorCircle circle; - }; + VektorPrimitiveKind kind; + union { + VektorLine line; + VektorPolyline *polyline; + VektorPolygon *polygon; + VektorCircle circle; + }; } VektorPrimitive; VektorPolyline *vektor_polyline_new(void); @@ -53,9 +53,9 @@ void vektor_polygon_add_point(VektorPolygon *pl, V2 point); void vektor_polygon_free(VektorPolygon *pl); typedef struct { - VektorPrimitive *primitives; - size_t count; - size_t capacity; + VektorPrimitive *primitives; + size_t count; + size_t capacity; } VektorPrimitiveBuffer; void vektor_primitivebuffer_add_primitive(VektorPrimitiveBuffer *edges, diff --git a/src/core/raster.c b/src/core/raster.c index 83f255b..32f276b 100644 --- a/src/core/raster.c +++ b/src/core/raster.c @@ -4,112 +4,123 @@ #include void vektor_edgebuffer_add_edge(EdgeBuffer *buffer, Edge edge) { - if (buffer->count >= buffer->capacity) { - buffer->capacity = buffer->capacity ? buffer->capacity * 2 : 4; - buffer->edges = realloc(buffer->edges, sizeof(Edge) * buffer->capacity); - } - buffer->edges[buffer->count++] = edge; + if (buffer->count >= buffer->capacity) { + buffer->capacity = buffer->capacity ? buffer->capacity * 2 : 4; + buffer->edges = realloc(buffer->edges, sizeof(Edge) * buffer->capacity); + } + buffer->edges[buffer->count++] = edge; } void vektor_line_flatten(EdgeBuffer *buffer, VektorLine line) { - vektor_edgebuffer_add_edge(buffer, (Edge){line.p1, line.p2, 0}); + vektor_edgebuffer_add_edge(buffer, (Edge){line.p1, line.p2, 0}); } void vektor_polyline_flatten(EdgeBuffer *buffer, VektorPolyline *line) { - for (size_t i = 0; i + 1 < line->count; i++) { - vektor_edgebuffer_add_edge(buffer, - (Edge){line->points[i], line->points[i + 1], 0}); - } + for (size_t i = 0; i + 1 < line->count; i++) { + vektor_edgebuffer_add_edge( + buffer, (Edge){line->points[i], line->points[i + 1], 0}); + } } void vektor_polygon_flatten(EdgeBuffer *buffer, VektorPolygon *pg) { - size_t n = pg->count; - if (n < 3) - return; + size_t n = pg->count; + if (n < 3) + return; - for (size_t i = 0; i < n; i++) { - V2 p1 = pg->points[i]; - V2 p2 = pg->points[(i + 1) % n]; - int winding = (p1.y < p2.y) ? +1 : -1; - vektor_edgebuffer_add_edge(buffer, (Edge){p1, p2, winding}); - } + for (size_t i = 0; i < n; i++) { + V2 p1 = pg->points[i]; + V2 p2 = pg->points[(i + 1) % n]; + int winding = (p1.y < p2.y) ? +1 : -1; + vektor_edgebuffer_add_edge(buffer, (Edge){p1, p2, winding}); + } } inline VektorFramebuffer vektor_framebuffer_new(unsigned int W, unsigned int H) { - VektorFramebuffer fb = { - .width = W, .height = H, .pixels = calloc(W * H * 4, 1)}; - return fb; + VektorFramebuffer fb = { + .width = W, .height = H, .pixels = calloc(W * H * 4, 1)}; + return fb; } inline void vektor_framebuffer_putpixel(VektorFramebuffer *fb, int x, int y, VektorColor color) { - if ((unsigned)x >= fb->width || (unsigned)y >= fb->height) - return; + if ((unsigned)x >= fb->width || (unsigned)y >= fb->height) + return; - int i = (y * fb->width + x) * 4; - fb->pixels[i + 0] = color.r; - fb->pixels[i + 1] = color.g; - fb->pixels[i + 2] = color.b; - fb->pixels[i + 3] = color.a; + int i = (y * fb->width + x) * 4; + fb->pixels[i + 0] = color.r; + fb->pixels[i + 1] = color.g; + fb->pixels[i + 2] = color.b; + fb->pixels[i + 3] = color.a; +} + +void draw_filled_circle(VektorFramebuffer *fb, int cx, int cy, int r, + VektorColor color) { + for (int y = -r; y <= r; y++) { + int dx = (int)sqrt(r * r - y * y); + for (int x = -dx; x <= dx; x++) { + vektor_framebuffer_putpixel(fb, cx + x, cy + y, color); + } + } } void vektor_framebuffer_drawline(VektorFramebuffer *fb, V2 a, V2 b, - VektorColor color) { - int x0 = (int)a.x; - int y0 = (int)a.y; - int x1 = (int)b.x; - int y1 = (int)b.y; + VektorColor color, double thickness) { + int x0 = (int)a.x; + int y0 = (int)a.y; + int x1 = (int)b.x; + int y1 = (int)b.y; - int dx = abs(x1 - x0); - int sx = x0 < x1 ? 1 : -1; - int dy = -abs(y1 - y0); - int sy = y0 < y1 ? 1 : -1; - int err = dx + dy; + int dx = abs(x1 - x0); + int sx = x0 < x1 ? 1 : -1; + int dy = -abs(y1 - y0); + int sy = y0 < y1 ? 1 : -1; + int err = dx + dy; - for (;;) { - vektor_framebuffer_putpixel(fb, x0, y0, color); - if (x0 == x1 && y0 == y1) - break; + for (;;) { + draw_filled_circle(fb, x0, y0, thickness / 2, color); + if (x0 == x1 && y0 == y1) + break; - int e2 = 2 * err; - if (e2 >= dy) { - err += dy; - x0 += sx; + int e2 = 2 * err; + if (e2 >= dy) { + err += dy; + x0 += sx; + } + if (e2 <= dx) { + err += dx; + y0 += sy; + } } - if (e2 <= dx) { - err += dx; - y0 += sy; - } - } } -void vektor_framebuffer_rasterize(VektorFramebuffer *fb, VektorPrimitiveBuffer *prims) { - EdgeBuffer edges = {0}; - for (size_t i = 0; i < prims->count; i++) { - VektorPrimitive *p = &prims->primitives[i]; +void vektor_framebuffer_rasterize(VektorFramebuffer *fb, + VektorPrimitiveBuffer *prims) { + EdgeBuffer edges = {0}; + for (size_t i = 0; i < prims->count; i++) { + VektorPrimitive *p = &prims->primitives[i]; - switch (p->kind) { - case VEKTOR_LINE: - vektor_line_flatten(&edges, p->line); - break; + switch (p->kind) { + case VEKTOR_LINE: + vektor_line_flatten(&edges, p->line); + break; - case VEKTOR_POLYLINE: - vektor_polyline_flatten(&edges, p->polyline); - break; + case VEKTOR_POLYLINE: + vektor_polyline_flatten(&edges, p->polyline); + break; - case VEKTOR_POLYGON: - vektor_polygon_flatten(&edges, p->polygon); - break; + case VEKTOR_POLYGON: + vektor_polygon_flatten(&edges, p->polygon); + break; - default: - // TODO fill in all primitives - break; + default: + // TODO fill in all primitives + break; + } } - } - for (size_t i = 0; i < edges.count; i++) { - vektor_framebuffer_drawline(fb, edges.edges[i].p1, edges.edges[i].p2, - vektor_color_solid(255, 0, 255)); - } + for (size_t i = 0; i < edges.count; i++) { + vektor_framebuffer_drawline(fb, edges.edges[i].p1, edges.edges[i].p2, + vektor_color_solid(255, 0, 255), 4); + } } \ No newline at end of file diff --git a/src/core/raster.h b/src/core/raster.h index b35bd6c..e8100be 100644 --- a/src/core/raster.h +++ b/src/core/raster.h @@ -8,15 +8,15 @@ #include "vector.h" typedef struct { - V2 p1; - V2 p2; - int winding; + V2 p1; + V2 p2; + int winding; } Edge; typedef struct { - Edge *edges; - size_t count; - size_t capacity; + Edge *edges; + size_t count; + size_t capacity; } EdgeBuffer; void vektor_edgebuffer_add_edge(EdgeBuffer *edges, Edge edge); @@ -26,9 +26,9 @@ void vektor_polyline_flatten(EdgeBuffer *edges, VektorPolyline *line); void vektor_polygon_flatten(EdgeBuffer *buffer, VektorPolygon *line); typedef struct { - unsigned int width; - unsigned int height; - unsigned char *pixels; // Flat RGBA8 array + unsigned int width; + unsigned int height; + unsigned char *pixels; // Flat RGBA8 array } VektorFramebuffer; VektorFramebuffer vektor_framebuffer_new(unsigned int width, @@ -38,8 +38,9 @@ void vektor_framebuffer_putpixel(VektorFramebuffer *fb, int x, int y, VektorColor color); void vektor_framebuffer_drawline(VektorFramebuffer *fb, V2 a, V2 b, - VektorColor color); + VektorColor color, double thickness); -void vektor_framebuffer_rasterize(VektorFramebuffer *fb, VektorPrimitiveBuffer *primitives); +void vektor_framebuffer_rasterize(VektorFramebuffer *fb, + VektorPrimitiveBuffer *primitives); #endif // RASTER_H_ diff --git a/src/core/vector.h b/src/core/vector.h index 0b1c1b4..0038ead 100644 --- a/src/core/vector.h +++ b/src/core/vector.h @@ -4,14 +4,14 @@ #include "math.h" typedef struct { - double x; - double y; + double x; + double y; } V2; typedef struct { - double x; - double y; - double z; + double x; + double y; + double z; } V3; static inline V3 vec2_vector(const V2 v) { return (V3){v.x, v.y, 0}; } @@ -19,39 +19,39 @@ static inline V3 vec2_vector(const V2 v) { return (V3){v.x, v.y, 0}; } static inline V3 vec2_point(const V2 v) { return (V3){v.x, v.y, 1}; } static inline V2 vec2_add(const V2 v1, const V2 v2) { - return (V2){v1.x + v2.x, v1.y + v2.y}; + return (V2){v1.x + v2.x, v1.y + v2.y}; } static inline V2 vec2_sub(const V2 v1, const V2 v2) { - return (V2){v1.x - v2.x, v1.y - v2.y}; + return (V2){v1.x - v2.x, v1.y - v2.y}; } static inline V2 vec2_mul(const V2 v1, const V2 v2) { - return (V2){v1.x * v2.x, v1.y * v2.y}; + return (V2){v1.x * v2.x, v1.y * v2.y}; } static inline V2 vec2_scale(const V2 v, const double k) { - return (V2){v.x * k, v.y * k}; + return (V2){v.x * k, v.y * k}; } static inline double vec2_dot(const V2 v1, const V2 v2) { - return v1.x * v2.x + v1.y * v2.y; + return v1.x * v2.x + v1.y * v2.y; } static inline double vec2_cross(const V2 a, const V2 b) { - return a.x * b.y - a.y * b.x; + return a.x * b.y - a.y * b.x; } static inline double vec2_norm(const V2 v) { - return sqrt(v.x * v.x + v.y * v.y); + return sqrt(v.x * v.x + v.y * v.y); } static inline double vec2_quadrance(const V2 v) { - return (v.x * v.x + v.y * v.y); + return (v.x * v.x + v.y * v.y); } static inline V2 vec2_normalize(const V2 v) { - return vec2_scale(v, 1 / vec2_norm(v)); + return vec2_scale(v, 1 / vec2_norm(v)); } #endif // VECTOR_H_ diff --git a/src/main.c b/src/main.c index ba4318d..fde87e7 100644 --- a/src/main.c +++ b/src/main.c @@ -4,41 +4,40 @@ #include "stdio.h" #include "stdlib.h" +#include "./application/applicationstate.h" #include "./core/raster.h" #include "./ui/uicontroller.h" #include "./ui/vektorcanvas.h" #include "./util/color.h" -#include "./application/applicationstate.h" static void on_map(GtkWidget *window, gpointer user_data) { - vektor_uictrl_map((VektorWidgetState *)user_data); + vektor_uictrl_map((VektorWidgetState *)user_data); } static void activate(GtkApplication *app, gpointer user_data) { - VektorWidgetState *widget_state = - (VektorWidgetState *)malloc(sizeof(VektorWidgetState)); - vektor_uictrl_init(app, widget_state); - VektorAppState* app_state = - (VektorAppState *)malloc(sizeof(VektorAppState)); - vektor_appstate_new(widget_state, app_state); + VektorWidgetState *widget_state = + (VektorWidgetState *)malloc(sizeof(VektorWidgetState)); + vektor_uictrl_init(app, widget_state); + VektorAppState *app_state = + (VektorAppState *)malloc(sizeof(VektorAppState)); + vektor_appstate_new(widget_state, app_state); + g_signal_connect(widget_state->window, "map", G_CALLBACK(on_map), + widget_state); - g_signal_connect(widget_state->window, "map", G_CALLBACK(on_map), - widget_state); - - gtk_window_present(widget_state->window); + gtk_window_present(widget_state->window); } int main(int argc, char **argv) { - GtkApplication *app; - int status; + GtkApplication *app; + int status; - app = gtk_application_new("dev.frox.vektor", G_APPLICATION_DEFAULT_FLAGS); - g_signal_connect(app, "activate", G_CALLBACK(activate), NULL); - status = g_application_run(G_APPLICATION(app), argc, argv); - g_object_unref(app); + app = gtk_application_new("dev.frox.vektor", G_APPLICATION_DEFAULT_FLAGS); + g_signal_connect(app, "activate", G_CALLBACK(activate), NULL); + status = g_application_run(G_APPLICATION(app), argc, argv); + g_object_unref(app); - return status; + return status; } diff --git a/src/ui/uicontroller.c b/src/ui/uicontroller.c index 0a7ab85..14750b6 100644 --- a/src/ui/uicontroller.c +++ b/src/ui/uicontroller.c @@ -5,43 +5,43 @@ #include "gtk/gtkcssprovider.h" void vektor_uictrl_init(GtkApplication *app, VektorWidgetState *stateOut) { - GtkBuilder *builder = gtk_builder_new(); - GError *error = NULL; + GtkBuilder *builder = gtk_builder_new(); + GError *error = NULL; - // TODO: .ui files as resources instead of sketchy relative paths - if (!gtk_builder_add_from_file(builder, "./ui/main.ui", &error)) { - g_error("Fatal: %s", error->message); - } + // TODO: .ui files as resources instead of sketchy relative paths + if (!gtk_builder_add_from_file(builder, "./ui/main.ui", &error)) { + g_error("Fatal: %s", error->message); + } - // Load css - GtkCssProvider* provider = gtk_css_provider_new(); - gtk_css_provider_load_from_path(provider, "./ui/main.css"); - gtk_style_context_add_provider_for_display(gdk_display_get_default(), - GTK_STYLE_PROVIDER(provider), - GTK_STYLE_PROVIDER_PRIORITY_APPLICATION - ); + // Load css + GtkCssProvider *provider = gtk_css_provider_new(); + gtk_css_provider_load_from_path(provider, "./ui/main.css"); + gtk_style_context_add_provider_for_display( + gdk_display_get_default(), GTK_STYLE_PROVIDER(provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); - // populate state - stateOut->window = GTK_WINDOW(gtk_builder_get_object(builder, "main_window")); - stateOut->workspacePaned = - GTK_PANED(gtk_builder_get_object(builder, "workspace_paned")); - stateOut->workspaceCanvas = - GTK_PICTURE(gtk_builder_get_object(builder, "workspace")); - stateOut->workspaceButtonLinetool = - GTK_BUTTON(gtk_builder_get_object(builder, "button_linetool")); + // populate state + stateOut->window = + GTK_WINDOW(gtk_builder_get_object(builder, "main_window")); + stateOut->workspacePaned = + GTK_PANED(gtk_builder_get_object(builder, "workspace_paned")); + stateOut->workspaceCanvas = + GTK_PICTURE(gtk_builder_get_object(builder, "workspace")); + stateOut->workspaceButtonLinetool = + GTK_BUTTON(gtk_builder_get_object(builder, "button_linetool")); - // Set window properties - gtk_window_set_application(stateOut->window, app); - gtk_window_set_title(stateOut->window, "Vektor"); - gtk_window_set_default_size(stateOut->window, 800, 600); + // Set window properties + gtk_window_set_application(stateOut->window, app); + gtk_window_set_title(stateOut->window, "Vektor"); + gtk_window_set_default_size(stateOut->window, 800, 600); - g_object_unref(builder); + g_object_unref(builder); } void vektor_uictrl_map(VektorWidgetState *state) { - // set the workspace divider to 7:3 ratio - int window_width = gtk_widget_get_width(GTK_WIDGET(state->window)); - g_print("%i", window_width); - gtk_paned_set_position(state->workspacePaned, 800 * .7); + // set the workspace divider to 7:3 ratio + int window_width = gtk_widget_get_width(GTK_WIDGET(state->window)); + g_print("%i", window_width); + gtk_paned_set_position(state->workspacePaned, 800 * .7); } diff --git a/src/ui/uicontroller.h b/src/ui/uicontroller.h index d2ee11d..24c9124 100644 --- a/src/ui/uicontroller.h +++ b/src/ui/uicontroller.h @@ -8,13 +8,13 @@ Global application widget state, holding references to all the widgets used in internal logic of the program */ typedef struct VektorWidgetState { - GtkWindow *window; - GtkPaned *workspacePaned; - GtkPicture *workspaceCanvas; + GtkWindow *window; + GtkPaned *workspacePaned; + GtkPicture *workspaceCanvas; - GtkButton* workspaceButtonLinetool; + GtkButton *workspaceButtonLinetool; - // GtkWidget* Workspace + // GtkWidget* Workspace } VektorWidgetState; void vektor_uictrl_init(GtkApplication *app, VektorWidgetState *stateOut); diff --git a/src/ui/vektorcanvas.c b/src/ui/vektorcanvas.c index e274c99..2fae98c 100644 --- a/src/ui/vektorcanvas.c +++ b/src/ui/vektorcanvas.c @@ -9,59 +9,60 @@ #define VKTR_CANVAS_SIZE (VKTR_CANVAS_WIDTH * VKTR_CANVAS_HEIGHT * 4) void vektor_canvas_init(VektorWidgetState *state, VektorCanvas *canvasOut) { - canvasOut->canvasWidget = state->workspaceCanvas; - canvasOut->width = VKTR_CANVAS_WIDTH; - canvasOut->height = VKTR_CANVAS_HEIGHT; - canvasOut->canvasPixels = g_malloc0(VKTR_CANVAS_SIZE); + canvasOut->canvasWidget = state->workspaceCanvas; + canvasOut->width = VKTR_CANVAS_WIDTH; + canvasOut->height = VKTR_CANVAS_HEIGHT; + canvasOut->canvasPixels = g_malloc0(VKTR_CANVAS_SIZE); - canvasOut->canvasPixelBytes = - g_bytes_new(canvasOut->canvasPixels, VKTR_CANVAS_SIZE); - canvasOut->canvasTexture = gdk_memory_texture_new( - VKTR_CANVAS_WIDTH, VKTR_CANVAS_HEIGHT, GDK_MEMORY_R8G8B8A8, - canvasOut->canvasPixelBytes, VKTR_CANVAS_WIDTH * 4); + canvasOut->canvasPixelBytes = + g_bytes_new(canvasOut->canvasPixels, VKTR_CANVAS_SIZE); + canvasOut->canvasTexture = gdk_memory_texture_new( + VKTR_CANVAS_WIDTH, VKTR_CANVAS_HEIGHT, GDK_MEMORY_R8G8B8A8, + canvasOut->canvasPixelBytes, VKTR_CANVAS_WIDTH * 4); - gtk_picture_set_paintable(canvasOut->canvasWidget, - GDK_PAINTABLE(canvasOut->canvasTexture)); - - // g_object_unref(bytes); + gtk_picture_set_paintable(canvasOut->canvasWidget, + GDK_PAINTABLE(canvasOut->canvasTexture)); + gtk_picture_set_content_fit(GTK_PICTURE(canvasOut->canvasWidget), + GTK_CONTENT_FIT_CONTAIN); + // g_object_unref(bytes); } /* Generate new texture based on canvasPixels*/ void vektor_canvas_update(VektorCanvas *canvas) { - g_bytes_unref(canvas->canvasPixelBytes); - canvas->canvasPixelBytes = - g_bytes_new(canvas->canvasPixels, VKTR_CANVAS_SIZE); + g_bytes_unref(canvas->canvasPixelBytes); + canvas->canvasPixelBytes = + g_bytes_new(canvas->canvasPixels, VKTR_CANVAS_SIZE); - g_object_unref(canvas->canvasTexture); - canvas->canvasTexture = - gdk_memory_texture_new(canvas->width, canvas->height, GDK_MEMORY_R8G8B8A8, - canvas->canvasPixelBytes, canvas->width * 4); + g_object_unref(canvas->canvasTexture); + canvas->canvasTexture = gdk_memory_texture_new( + canvas->width, canvas->height, GDK_MEMORY_R8G8B8A8, + canvas->canvasPixelBytes, canvas->width * 4); - gtk_picture_set_paintable(canvas->canvasWidget, - GDK_PAINTABLE(canvas->canvasTexture)); + gtk_picture_set_paintable(canvas->canvasWidget, + GDK_PAINTABLE(canvas->canvasTexture)); } void vektor_canvas_fill(VektorCanvas *canvas, VektorColor color) { - for (int x = 0; x < VKTR_CANVAS_WIDTH; x++) { - for (int y = 0; y < VKTR_CANVAS_HEIGHT; y++) { - int i = (y * VKTR_CANVAS_WIDTH + x) * 4; - canvas->canvasPixels[i + 0] = color.r; - canvas->canvasPixels[i + 1] = color.g; - canvas->canvasPixels[i + 2] = color.b; - canvas->canvasPixels[i + 3] = color.a; + for (int x = 0; x < VKTR_CANVAS_WIDTH; x++) { + for (int y = 0; y < VKTR_CANVAS_HEIGHT; y++) { + int i = (y * VKTR_CANVAS_WIDTH + x) * 4; + canvas->canvasPixels[i + 0] = color.r; + canvas->canvasPixels[i + 1] = color.g; + canvas->canvasPixels[i + 2] = color.b; + canvas->canvasPixels[i + 3] = color.a; + } } - } } void vektor_canvas_drawfrom(VektorFramebuffer *fb, VektorCanvas *target) { - for (int x = 0; x < fb->width; x++) { - for (int y = 0; y < fb->height; y++) { + for (int x = 0; x < fb->width; x++) { + for (int y = 0; y < fb->height; y++) { - int i = (y * fb->width + x) * 4; - target->canvasPixels[i + 0] = (guchar)fb->pixels[i + 0]; - target->canvasPixels[i + 1] = (guchar)fb->pixels[i + 1]; - target->canvasPixels[i + 2] = (guchar)fb->pixels[i + 2]; - target->canvasPixels[i + 3] = (guchar)fb->pixels[i + 3]; + int i = (y * fb->width + x) * 4; + target->canvasPixels[i + 0] = (guchar)fb->pixels[i + 0]; + target->canvasPixels[i + 1] = (guchar)fb->pixels[i + 1]; + target->canvasPixels[i + 2] = (guchar)fb->pixels[i + 2]; + target->canvasPixels[i + 3] = (guchar)fb->pixels[i + 3]; + } } - } } \ No newline at end of file diff --git a/src/ui/vektorcanvas.h b/src/ui/vektorcanvas.h index bf6bad7..91f6937 100644 --- a/src/ui/vektorcanvas.h +++ b/src/ui/vektorcanvas.h @@ -6,15 +6,15 @@ #include "uicontroller.h" typedef struct VektorCanvas { - GtkPicture *canvasWidget; + GtkPicture *canvasWidget; - // texture related stuff - guchar *canvasPixels; - GdkTexture *canvasTexture; - GBytes *canvasPixelBytes; + // texture related stuff + guchar *canvasPixels; + GdkTexture *canvasTexture; + GBytes *canvasPixelBytes; - int width; - int height; + int width; + int height; } VektorCanvas; void vektor_canvas_init(VektorWidgetState *state, VektorCanvas *canvasOut); diff --git a/src/util/color.h b/src/util/color.h index 176f4b7..27f3b9b 100644 --- a/src/util/color.h +++ b/src/util/color.h @@ -2,22 +2,22 @@ #define COLOR_H_ typedef struct VektorColor { - unsigned char r; - unsigned char g; - unsigned char b; - unsigned char a; + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char a; } VektorColor; static VektorColor vektor_color_blank = (VektorColor){0, 0, 0, 0}; static inline VektorColor vektor_color_new(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { - return (VektorColor){r, g, b, a}; + return (VektorColor){r, g, b, a}; } static inline VektorColor vektor_color_solid(unsigned char r, unsigned char g, unsigned char b) { - return (VektorColor){r, g, b, 255}; + return (VektorColor){r, g, b, 255}; } #endif // COLOR_H_