diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..811de74 --- /dev/null +++ b/.clang-format @@ -0,0 +1,5 @@ +BasedOnStyle: LLVM +ColumnLimit: 80 +BreakBeforeBraces: Attach +IndentWidth: 2 +ContinuationIndentWidth: 4 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 241b9ba..b5dcd66 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ .DS_Store +.vscode .idea *.log tmp/ .cache/ build/ .direnv/ +*.ppm \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json deleted file mode 100644 index 7830fd3..0000000 --- a/.vscode/c_cpp_properties.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "configurations": [ - { - "name": "Linux", - "includePath": [ - "${workspaceFolder}/**" - ], - "defines": [], - "compilerPath": "/usr/bin/gcc", - "cStandard": "c17", - "cppStandard": "gnu++17", - "intelliSenseMode": "linux-gcc-x64", - "compileCommands": [ - "${workspaceFolder}/build/compile_commands.json" - ] - } - ], - "version": 4 -} \ No newline at end of file diff --git a/flake.lock b/flake.lock index 7303ed2..113ee2b 100644 --- a/flake.lock +++ b/flake.lock @@ -1,27 +1,23 @@ { - "nodes": { - "nixpkgs": { - "locked": { - "lastModified": 1772433332, - "narHash": "sha256-izhTDFKsg6KeVBxJS9EblGeQ8y+O8eCa6RcW874vxEc=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "cf59864ef8aa2e178cccedbe2c178185b0365705", - "type": "github" + "nodes" : { + "nixpkgs" : { + "locked" : { + "lastModified" : 1772433332, + "narHash" : "sha256-izhTDFKsg6KeVBxJS9EblGeQ8y+O8eCa6RcW874vxEc=", + "owner" : "NixOS", + "repo" : "nixpkgs", + "rev" : "cf59864ef8aa2e178cccedbe2c178185b0365705", + "type" : "github" }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" + "original" : { + "owner" : "NixOS", + "ref" : "nixos-unstable", + "repo" : "nixpkgs", + "type" : "github" } }, - "root": { - "inputs": { - "nixpkgs": "nixpkgs" - } - } + "root" : {"inputs" : {"nixpkgs" : "nixpkgs"}} }, - "root": "root", - "version": 7 + "root" : "root", + "version" : 7 } diff --git a/flake.nix b/flake.nix index c431f09..73ffa36 100644 --- a/flake.nix +++ b/flake.nix @@ -3,32 +3,25 @@ inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - outputs = - { + outputs = { self, nixpkgs, - }: - let - system = "x86_64-linux"; - pkgs = import nixpkgs { inherit system; }; - in - { - devShells.${system}.default = pkgs.mkShell { - nativeBuildInputs = with pkgs; [ - gcc - clang-tools - lldb + } : let system = "x86_64-linux"; + pkgs = import nixpkgs { inherit system; }; + in { + devShells.${system}.default = pkgs.mkShell { + nativeBuildInputs = with pkgs; + [gcc clang - + tools lldb - meson - ninja - pkg-config + meson ninja pkg - + config - gtk4 + gtk4 - gdb - ]; + gdb]; - shellHook = ""; - }; + shellHook = ""; }; + }; } diff --git a/meson.build b/meson.build index 3d5d91e..c2165cd 100644 --- a/meson.build +++ b/meson.build @@ -14,7 +14,9 @@ gtk = dependency('gtk4', required: true) src = files( 'src/main.c', - 'src/matrix.c', + 'src/core/matrix.c', + 'src/core/primitives.c', + 'src/core/raster.c', 'src/ui/uicontroller.c', 'src/ui/vektorcanvas.c' ) diff --git a/src/matrix.c b/src/core/matrix.c similarity index 90% rename from src/matrix.c rename to src/core/matrix.c index 949bd24..f2013c1 100644 --- a/src/matrix.c +++ b/src/core/matrix.c @@ -1,6 +1,8 @@ #include "matrix.h" #include +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}}}; } @@ -18,6 +20,10 @@ inline M33 m33_rotate(double theta) { {{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}}}; +} + M33 m33_add(const M33 m1, const M33 m2) { M33 res; for (int i = 0; i < 3; ++i) diff --git a/src/matrix.h b/src/core/matrix.h similarity index 91% rename from src/matrix.h rename to src/core/matrix.h index de372d6..55219f1 100644 --- a/src/matrix.h +++ b/src/core/matrix.h @@ -12,6 +12,7 @@ M33 m33_identity(void); M33 m33_translate(double tx, double ty); M33 m33_scale(double sx, double sy); M33 m33_rotate(double rad); +M33 m33_shear(double theta_x, double theta_y); M33 m33_add(const M33 m1, const M33 m2); M33 m33_sub(const M33 m1, const M33 m2); diff --git a/src/core/primitives.c b/src/core/primitives.c new file mode 100644 index 0000000..1415abe --- /dev/null +++ b/src/core/primitives.c @@ -0,0 +1,47 @@ +#include "primitives.h" + +Polyline *mk_polyline(void) { + Polyline *pl = malloc(sizeof(Polyline)); + pl->count = 0; + pl->capacity = 4; + pl->points = malloc(sizeof(V2) * pl->capacity); + return pl; +} + +void add_point_polyline(Polyline *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; +} + +void free_polyline(Polyline *pl) { + if (!pl) + return; + free(pl->points); + free(pl); +} + +Polygon *mk_polygon(void) { + Polygon *pg = malloc(sizeof(Polygon)); + pg->count = 0; + pg->capacity = 4; + pg->points = malloc(sizeof(V2) * pg->capacity); + return pg; +} + +void add_point_polygon(Polygon *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; +} + +void free_polygon(Polygon *pg) { + if (!pg) + return; + free(pg->points); + free(pg); +} diff --git a/src/core/primitives.h b/src/core/primitives.h new file mode 100644 index 0000000..253831b --- /dev/null +++ b/src/core/primitives.h @@ -0,0 +1,50 @@ +#ifndef PRIMITIVES_H_ +#define PRIMITIVES_H_ + +#include "stddef.h" +#include "stdlib.h" +#include "vector.h" + +typedef struct { + V2 p1; + V2 p2; +} Line; + +typedef struct { + V2 *points; + size_t count; + size_t capacity; +} Polyline; + +typedef struct { + V2 *points; + size_t count; + size_t capacity; +} Polygon; + +typedef struct { + V2 center; + double radius; +} Circle; + +typedef enum { LINE, POLYLINE, POLYGON, CIRCLE } PrimitiveKind; + +typedef struct { + PrimitiveKind kind; + union { + Line line; + Polyline *polyline; + Polygon *polygon; + Circle circle; + }; +} Primitive; + +Polyline *mk_polyline(void); +void add_point_polyline(Polyline *pl, V2 point); +void free_polyline(Polyline *pl); + +Polygon *mk_polygon(void); +void add_point_polygon(Polygon *pl, V2 point); +void free_polygon(Polygon *pl); + +#endif // PRIMITIVES_H_ diff --git a/src/core/raster.c b/src/core/raster.c new file mode 100644 index 0000000..c8cb72d --- /dev/null +++ b/src/core/raster.c @@ -0,0 +1,80 @@ +#include "raster.h" +#include "primitives.h" +#include "stddef.h" + +void 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; +} + +void flatten_line(EdgeBuffer *buffer, Line line) { + add_edge(buffer, (Edge){line.p1, line.p2, 0}); +} + +void flatten_polyline(EdgeBuffer *buffer, Polyline *line) { + for (size_t i = 0; i + 1 < line->count; i++) { + add_edge(buffer, (Edge){line->points[i], line->points[i + 1], 0}); + } +} + +void flatten_polygon(EdgeBuffer *buffer, Polygon *pg) { + 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; + add_edge(buffer, (Edge){p1, p2, winding}); + } +} + +inline Framebuffer mk_framebuffer(unsigned int W, unsigned int H) { + Framebuffer fb = {.width = W, .height = H, .pixels = calloc(W * H * 3, 1)}; + return fb; +} + +inline void put_pixel(Framebuffer *fb, int x, int y, unsigned char r, + unsigned char g, unsigned char b) { + if ((unsigned)x >= fb->width || (unsigned)y >= fb->height) + return; + + int i = (y * fb->width + x) * 3; + fb->pixels[i + 0] = r; + fb->pixels[i + 1] = g; + fb->pixels[i + 2] = b; +} + +void draw_line(Framebuffer *fb, V2 a, V2 b, unsigned char r, unsigned char g, + unsigned char bl) { + 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; + + for (;;) { + put_pixel(fb, x0, y0, r, g, bl); + if (x0 == x1 && y0 == y1) + break; + + int e2 = 2 * err; + if (e2 >= dy) { + err += dy; + x0 += sx; + } + if (e2 <= dx) { + err += dx; + y0 += sy; + } + } +} \ No newline at end of file diff --git a/src/core/raster.h b/src/core/raster.h new file mode 100644 index 0000000..9f9b4f3 --- /dev/null +++ b/src/core/raster.h @@ -0,0 +1,40 @@ +#ifndef RASTER_H_ +#define RASTER_H_ + +#include "primitives.h" +#include "stddef.h" +#include "vector.h" + +typedef struct { + V2 p1; + V2 p2; + int winding; +} Edge; + +typedef struct { + Edge *edges; + size_t count; + size_t capacity; +} EdgeBuffer; + +void add_edge(EdgeBuffer *edges, Edge edge); + +void flatten_line(EdgeBuffer *edges, Line line); +void flatten_polyline(EdgeBuffer *edges, Polyline *line); +void flatten_polygon(EdgeBuffer *buffer, Polygon *line); + +typedef struct { + unsigned int width; + unsigned int height; + unsigned char *pixels; // Flat RGB8 array +} Framebuffer; + +Framebuffer mk_framebuffer(unsigned int width, unsigned int height); + +void put_pixel(Framebuffer *fb, int x, int y, unsigned char r, unsigned char g, + unsigned char b); + +void draw_line(Framebuffer *fb, V2 a, V2 b, unsigned char r, unsigned char g, + unsigned char bl); + +#endif // RASTER_H_ diff --git a/src/vector.h b/src/core/vector.h similarity index 82% rename from src/vector.h rename to src/core/vector.h index 7ab7b6b..0b1c1b4 100644 --- a/src/vector.h +++ b/src/core/vector.h @@ -8,6 +8,16 @@ typedef struct { double y; } V2; +typedef struct { + double x; + double y; + double z; +} V3; + +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}; } diff --git a/src/main.c b/src/main.c index 183b766..65a6073 100644 --- a/src/main.c +++ b/src/main.c @@ -2,31 +2,58 @@ #include "stdio.h" #include "stdlib.h" +#include "./core/raster.h" #include "./ui/uicontroller.h" #include "./ui/vektorcanvas.h" - -static void on_map(GtkWidget* window, gpointer user_data) { - vektor_uictrl_map((VektorWidgetState*)user_data); +static void on_map(GtkWidget *window, gpointer user_data) { + vektor_uictrl_map((VektorWidgetState *)user_data); } static void activate(GtkApplication *app, gpointer user_data) { - VektorWidgetState* widget_state = (VektorWidgetState*)malloc(sizeof(VektorWidgetState)); + VektorWidgetState *widget_state = + (VektorWidgetState *)malloc(sizeof(VektorWidgetState)); vektor_uictrl_init(app, widget_state); - VektorCanvas* canvas = (VektorCanvas*)malloc(sizeof(VektorCanvas)); + VektorCanvas *canvas = (VektorCanvas *)malloc(sizeof(VektorCanvas)); vektor_canvas_init(widget_state, canvas); VektorCanvasColor red = vektor_color_new(255, 0, 0, 255); vektor_canvas_fill(canvas, &red); vektor_canvas_update(canvas); - 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); } +void write_ppm(const char *path, const Framebuffer *fb) { + FILE *f = fopen(path, "wb"); + if (!f) + abort(); + + fprintf(f, "P6\n%d %d\n255\n", fb->width, fb->height); + fwrite(fb->pixels, 1, fb->width * fb->height * 3, f); + fclose(f); +} + int main(int argc, char **argv) { + Framebuffer fb = mk_framebuffer(256, 256); + EdgeBuffer edges = {0}; + + Polygon pg = *mk_polygon(); + add_point_polygon(&pg, (V2){50, 50}); + add_point_polygon(&pg, (V2){200, 80}); + add_point_polygon(&pg, (V2){120, 200}); + + flatten_polygon(&edges, &pg); + + for (size_t i = 0; i < edges.count; i++) { + draw_line(&fb, edges.edges[i].p1, edges.edges[i].p2, 255, 255, 255); + } + + write_ppm("out.ppm", &fb); GtkApplication *app; int status; diff --git a/src/ui/uicontroller.c b/src/ui/uicontroller.c index 6755d78..6dcbd96 100644 --- a/src/ui/uicontroller.c +++ b/src/ui/uicontroller.c @@ -1,32 +1,34 @@ #include "uicontroller.h" #include "gtk/gtk.h" -void vektor_uictrl_init(GtkApplication* app, VektorWidgetState* stateOut) { - GtkBuilder* builder = gtk_builder_new(); - GError* error = NULL; +void vektor_uictrl_init(GtkApplication *app, VektorWidgetState *stateOut) { + GtkBuilder *builder = gtk_builder_new(); + GError *error = NULL; - g_print("%s\n", g_get_current_dir()); + g_print("%s\n", g_get_current_dir()); - // 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); + } - 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->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")); - gtk_window_set_application(stateOut->window, app); - gtk_window_set_title(stateOut->window, "Vektor"); - gtk_window_set_default_size(stateOut->window, 800, 600); + 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) { +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 addc9ed..e6e5d9b 100644 --- a/src/ui/uicontroller.h +++ b/src/ui/uicontroller.h @@ -8,14 +8,14 @@ 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; - - //GtkWidget* Workspace + GtkWindow *window; + GtkPaned *workspacePaned; + GtkPicture *workspaceCanvas; + + // GtkWidget* Workspace } VektorWidgetState; -void vektor_uictrl_init(GtkApplication* app, VektorWidgetState* stateOut); -void vektor_uictrl_map(VektorWidgetState* state); +void vektor_uictrl_init(GtkApplication *app, VektorWidgetState *stateOut); +void vektor_uictrl_map(VektorWidgetState *state); #endif \ No newline at end of file diff --git a/src/ui/vektorcanvas.c b/src/ui/vektorcanvas.c index cdbfcbc..8de05a8 100644 --- a/src/ui/vektorcanvas.c +++ b/src/ui/vektorcanvas.c @@ -1,65 +1,57 @@ #include "gtk/gtk.h" -#include "vektorcanvas.h" #include "uicontroller.h" +#include "vektorcanvas.h" #define VKTR_CANVAS_WIDTH 400 #define VKTR_CANVAS_HEIGHT 400 #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); +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->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)); + gtk_picture_set_paintable(canvasOut->canvasWidget, + GDK_PAINTABLE(canvasOut->canvasTexture)); - //g_object_unref(bytes); + // g_object_unref(bytes); } -void vektor_canvas_update(VektorCanvas* canvas) { - g_bytes_unref(canvas->canvasPixelBytes); - canvas->canvasPixelBytes = g_bytes_new(canvas->canvasPixels, VKTR_CANVAS_SIZE); +void vektor_canvas_update(VektorCanvas *canvas) { + 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, VektorCanvasColor* 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; - } +void vektor_canvas_fill(VektorCanvas *canvas, VektorCanvasColor *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; } + } } VektorCanvasColor vektor_color_new(guchar cr, guchar cg, guchar cb, guchar ca) { - VektorCanvasColor c = { - .r = cr, - .g = cg, - .b = cb, - .a = ca - }; - return c; + VektorCanvasColor c = {.r = cr, .g = cg, .b = cb, .a = ca}; + return c; } \ No newline at end of file diff --git a/src/ui/vektorcanvas.h b/src/ui/vektorcanvas.h index f9d9aab..bc9300d 100644 --- a/src/ui/vektorcanvas.h +++ b/src/ui/vektorcanvas.h @@ -4,27 +4,27 @@ #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; typedef struct VektorCanvasColor { - guchar r; - guchar g; - guchar b; - guchar a; + guchar r; + guchar g; + guchar b; + guchar a; } VektorCanvasColor; -void vektor_canvas_init(VektorWidgetState* state, VektorCanvas* canvasOut); -void vektor_canvas_update(VektorCanvas* canvas); -void vektor_canvas_fill(VektorCanvas* canvas, VektorCanvasColor* color); +void vektor_canvas_init(VektorWidgetState *state, VektorCanvas *canvasOut); +void vektor_canvas_update(VektorCanvas *canvas); +void vektor_canvas_fill(VektorCanvas *canvas, VektorCanvasColor *color); VektorCanvasColor vektor_color_new(guchar r, guchar g, guchar b, guchar a);