feat: add stroke thickness
This commit is contained in:
@@ -1,41 +1,60 @@
|
|||||||
#include "./applicationstate.h"
|
#include "./applicationstate.h"
|
||||||
|
#include "glib.h"
|
||||||
#include "src/core/primitives.h"
|
#include "src/core/primitives.h"
|
||||||
#include "src/core/raster.h"
|
#include "src/core/raster.h"
|
||||||
#include "src/ui/vektorcanvas.h"
|
#include "src/ui/vektorcanvas.h"
|
||||||
|
|
||||||
typedef struct button_tool_set_data {
|
typedef struct button_tool_set_data {
|
||||||
VektorAppState* state;
|
VektorAppState *state;
|
||||||
VektorAppTool tool;
|
VektorAppTool tool;
|
||||||
} button_tool_set_data;
|
} button_tool_set_data;
|
||||||
|
|
||||||
static void appstate_set_tool(GtkButton* button, gpointer user_data) {
|
static void appstate_set_tool(GtkButton *button, gpointer user_data) {
|
||||||
button_tool_set_data* data = (button_tool_set_data*)user_data;
|
button_tool_set_data *data = (button_tool_set_data *)user_data;
|
||||||
data->state->selectedTool = data->tool;
|
data->state->selectedTool = data->tool;
|
||||||
|
|
||||||
// setting tool also resets selected primitive
|
// setting tool also resets selected primitive
|
||||||
data->state->selectedPrimitive = NULL;
|
data->state->selectedPrimitive = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void canvas_onclick(GtkGestureClick* gesture, int n_press, double x, double y, gpointer user_data) {
|
static void canvas_onclick(GtkGestureClick *gesture, int n_press, double x,
|
||||||
vektor_appstate_canvas_click(user_data, x, y);
|
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) {
|
void vektor_appstate_canvas_click(VektorAppState *state, double x, double y) {
|
||||||
V2 pos = (V2){x,y};
|
V2 pos = (V2){x, y};
|
||||||
|
|
||||||
begin_click_dispatch:
|
begin_click_dispatch:
|
||||||
if(state->selectedTool == VektorLineTool) {
|
if (state->selectedTool == VektorLineTool) {
|
||||||
// create new polyline primitive if none is selected
|
// create new polyline primitive if none is selected
|
||||||
if(state->selectedPrimitive == NULL) {
|
if (state->selectedPrimitive == NULL) {
|
||||||
|
|
||||||
VektorPolyline* line = vektor_polyline_new();
|
VektorPolyline *line = vektor_polyline_new();
|
||||||
VektorPrimitive linePrimitive = (VektorPrimitive){
|
VektorPrimitive linePrimitive =
|
||||||
.kind = VEKTOR_POLYLINE, .polyline = line
|
(VektorPrimitive){.kind = VEKTOR_POLYLINE, .polyline = line};
|
||||||
};
|
vektor_primitivebuffer_add_primitive(state->primitiveBuffer,
|
||||||
vektor_primitivebuffer_add_primitive(state->primitiveBuffer, linePrimitive);
|
linePrimitive);
|
||||||
|
|
||||||
state->selectedPrimitive =
|
state->selectedPrimitive =
|
||||||
&(state->primitiveBuffer->primitives[state->primitiveBuffer->count - 1]);
|
&(state->primitiveBuffer
|
||||||
|
->primitives[state->primitiveBuffer->count - 1]);
|
||||||
|
|
||||||
} else if (state->selectedPrimitive->kind != VEKTOR_POLYLINE) {
|
} else if (state->selectedPrimitive->kind != VEKTOR_POLYLINE) {
|
||||||
// selecting a tool resets the selection, so this condition
|
// selecting a tool resets the selection, so this condition
|
||||||
@@ -45,7 +64,6 @@ void vektor_appstate_canvas_click(VektorAppState* state, double x, double y) {
|
|||||||
goto begin_click_dispatch; // retry
|
goto begin_click_dispatch; // retry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
vektor_polyline_add_point(state->selectedPrimitive->polyline, pos);
|
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);
|
vektor_canvas_update(state->canvas);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut) {
|
void vektor_appstate_new(VektorWidgetState *wstate, VektorAppState *stateOut) {
|
||||||
button_tool_set_data* data_linetool = malloc(sizeof(button_tool_set_data));
|
button_tool_set_data *data_linetool = malloc(sizeof(button_tool_set_data));
|
||||||
data_linetool->state = stateOut;
|
data_linetool->state = stateOut;
|
||||||
data_linetool->tool = VektorLineTool;
|
data_linetool->tool = VektorLineTool;
|
||||||
|
|
||||||
@@ -68,18 +86,13 @@ void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut) {
|
|||||||
vektor_canvas_init(wstate, stateOut->canvas);
|
vektor_canvas_init(wstate, stateOut->canvas);
|
||||||
|
|
||||||
// link all the buttons
|
// link all the buttons
|
||||||
g_signal_connect(
|
g_signal_connect(G_OBJECT(wstate->workspaceButtonLinetool), "clicked",
|
||||||
G_OBJECT(wstate->workspaceButtonLinetool),
|
G_CALLBACK(appstate_set_tool), data_linetool);
|
||||||
"clicked", G_CALLBACK(appstate_set_tool), data_linetool);
|
|
||||||
|
|
||||||
// Add click gesture to canvas
|
// Add click gesture to canvas
|
||||||
GtkGesture* canvasClickGesture = gtk_gesture_click_new();
|
GtkGesture *canvasClickGesture = gtk_gesture_click_new();
|
||||||
g_signal_connect(
|
g_signal_connect(G_OBJECT(canvasClickGesture), "pressed",
|
||||||
G_OBJECT(canvasClickGesture),
|
G_CALLBACK(canvas_onclick), stateOut);
|
||||||
"pressed", G_CALLBACK(canvas_onclick), stateOut
|
gtk_widget_add_controller(GTK_WIDGET(wstate->workspaceCanvas),
|
||||||
);
|
GTK_EVENT_CONTROLLER(canvasClickGesture));
|
||||||
gtk_widget_add_controller(
|
|
||||||
GTK_WIDGET(wstate->workspaceCanvas),
|
|
||||||
GTK_EVENT_CONTROLLER(canvasClickGesture)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
@@ -1,29 +1,27 @@
|
|||||||
#ifndef VKTR_APPSTATE_H
|
#ifndef VKTR_APPSTATE_H
|
||||||
#define VKTR_APPSTATE_H
|
#define VKTR_APPSTATE_H
|
||||||
|
|
||||||
#include "../ui/uicontroller.h"
|
|
||||||
#include "../core/primitives.h"
|
#include "../core/primitives.h"
|
||||||
#include "src/core/raster.h"
|
#include "../ui/uicontroller.h"
|
||||||
#include "../ui/vektorcanvas.h"
|
#include "../ui/vektorcanvas.h"
|
||||||
|
#include "src/core/raster.h"
|
||||||
|
|
||||||
typedef enum VektorAppTool {
|
typedef enum VektorAppTool { VektorLineTool } VektorAppTool;
|
||||||
VektorLineTool
|
|
||||||
} VektorAppTool;
|
|
||||||
|
|
||||||
typedef struct VektorAppState {
|
typedef struct VektorAppState {
|
||||||
VektorAppTool selectedTool;
|
VektorAppTool selectedTool;
|
||||||
VektorPrimitive* selectedPrimitive;
|
VektorPrimitive *selectedPrimitive;
|
||||||
|
|
||||||
// Logic space
|
// Logic space
|
||||||
VektorPrimitiveBuffer* primitiveBuffer;
|
VektorPrimitiveBuffer *primitiveBuffer;
|
||||||
// Pixel space
|
// Pixel space
|
||||||
VektorFramebuffer* frameBuffer;
|
VektorFramebuffer *frameBuffer;
|
||||||
// View space
|
// View space
|
||||||
VektorCanvas* canvas;
|
VektorCanvas *canvas;
|
||||||
|
|
||||||
} VektorAppState;
|
} VektorAppState;
|
||||||
|
|
||||||
void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut);
|
void vektor_appstate_new(VektorWidgetState *wstate, VektorAppState *stateOut);
|
||||||
void vektor_appstate_canvas_click(VektorAppState* state, double x, double y);
|
void vektor_appstate_canvas_click(VektorAppState *state, double x, double y);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -4,86 +4,86 @@
|
|||||||
inline M33 m33_zero(void) { return (M33){{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}}; }
|
inline M33 m33_zero(void) { return (M33){{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}}; }
|
||||||
|
|
||||||
inline M33 m33_identity(void) {
|
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) {
|
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) {
|
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) {
|
inline M33 m33_rotate(double theta) {
|
||||||
return (M33){
|
return (M33){
|
||||||
{{cos(theta), -sin(theta), 0}, {sin(theta), cos(theta), 0}, {0, 0, 1}}};
|
{{cos(theta), -sin(theta), 0}, {sin(theta), cos(theta), 0}, {0, 0, 1}}};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline M33 m33_shear(double theta_x, double theta_y) {
|
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 m33_add(const M33 m1, const M33 m2) {
|
||||||
M33 res;
|
M33 res;
|
||||||
for (int i = 0; i < 3; ++i)
|
for (int i = 0; i < 3; ++i)
|
||||||
for (int j = 0; j < 3; ++j)
|
for (int j = 0; j < 3; ++j)
|
||||||
res.m[i][j] = m1.m[i][j] + m2.m[i][j];
|
res.m[i][j] = m1.m[i][j] + m2.m[i][j];
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
M33 m33_sub(const M33 m1, const M33 m2) {
|
M33 m33_sub(const M33 m1, const M33 m2) {
|
||||||
M33 res;
|
M33 res;
|
||||||
for (int i = 0; i < 3; ++i)
|
for (int i = 0; i < 3; ++i)
|
||||||
for (int j = 0; j < 3; ++j)
|
for (int j = 0; j < 3; ++j)
|
||||||
res.m[i][j] = m1.m[i][j] - m2.m[i][j];
|
res.m[i][j] = m1.m[i][j] - m2.m[i][j];
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
M33 m33_mul(const M33 m1, const M33 m2) {
|
M33 m33_mul(const M33 m1, const M33 m2) {
|
||||||
M33 res = {{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}};
|
M33 res = {{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}};
|
||||||
for (int i = 0; i < 3; ++i)
|
for (int i = 0; i < 3; ++i)
|
||||||
for (int j = 0; j < 3; ++j)
|
for (int j = 0; j < 3; ++j)
|
||||||
for (int k = 0; k < 3; ++k)
|
for (int k = 0; k < 3; ++k)
|
||||||
res.m[i][j] += m1.m[i][k] * m2.m[k][j];
|
res.m[i][j] += m1.m[i][k] * m2.m[k][j];
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
M33 m33_transpose(const M33 m) {
|
M33 m33_transpose(const M33 m) {
|
||||||
M33 res;
|
M33 res;
|
||||||
for (int i = 0; i < 3; ++i)
|
for (int i = 0; i < 3; ++i)
|
||||||
for (int j = 0; j < 3; ++j)
|
for (int j = 0; j < 3; ++j)
|
||||||
res.m[i][j] = m.m[j][i];
|
res.m[i][j] = m.m[j][i];
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2D affine transform inversion (not general 3x3 inversion)
|
// 2D affine transform inversion (not general 3x3 inversion)
|
||||||
M33 m33_inverse(const M33 m) {
|
M33 m33_inverse(const M33 m) {
|
||||||
M33 inv;
|
M33 inv;
|
||||||
double det;
|
double det;
|
||||||
|
|
||||||
det = m.m[0][0] * m.m[1][1] - m.m[0][1] * m.m[1][0];
|
det = m.m[0][0] * m.m[1][1] - m.m[0][1] * m.m[1][0];
|
||||||
if (det == 0.0) {
|
if (det == 0.0) {
|
||||||
return m33_identity();
|
return m33_identity();
|
||||||
}
|
}
|
||||||
double invDet = 1.0 / det;
|
double invDet = 1.0 / det;
|
||||||
|
|
||||||
inv.m[0][0] = m.m[1][1] * invDet;
|
inv.m[0][0] = m.m[1][1] * invDet;
|
||||||
inv.m[0][1] = -m.m[0][1] * invDet;
|
inv.m[0][1] = -m.m[0][1] * invDet;
|
||||||
inv.m[1][0] = -m.m[1][0] * invDet;
|
inv.m[1][0] = -m.m[1][0] * invDet;
|
||||||
inv.m[1][1] = m.m[0][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[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[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][0] = 0;
|
||||||
inv.m[2][1] = 0;
|
inv.m[2][1] = 0;
|
||||||
inv.m[2][2] = 1;
|
inv.m[2][2] = 1;
|
||||||
|
|
||||||
return inv;
|
return inv;
|
||||||
}
|
}
|
||||||
|
|
||||||
V2 m33_transform(const M33 mat, const V2 v) {
|
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],
|
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]};
|
mat.m[1][0] * v.x + mat.m[1][1] * v.y + mat.m[1][2]};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
// Row major 3x3 matricies
|
// Row major 3x3 matricies
|
||||||
typedef struct {
|
typedef struct {
|
||||||
double m[3][3];
|
double m[3][3];
|
||||||
} M33;
|
} M33;
|
||||||
|
|
||||||
M33 m33_identity(void);
|
M33 m33_identity(void);
|
||||||
|
|||||||
@@ -1,57 +1,57 @@
|
|||||||
#include "primitives.h"
|
#include "primitives.h"
|
||||||
|
|
||||||
VektorPolyline *vektor_polyline_new(void) {
|
VektorPolyline *vektor_polyline_new(void) {
|
||||||
VektorPolyline *pl = malloc(sizeof(VektorPolyline));
|
VektorPolyline *pl = malloc(sizeof(VektorPolyline));
|
||||||
pl->count = 0;
|
pl->count = 0;
|
||||||
pl->capacity = 4;
|
pl->capacity = 4;
|
||||||
pl->points = malloc(sizeof(V2) * pl->capacity);
|
pl->points = malloc(sizeof(V2) * pl->capacity);
|
||||||
return pl;
|
return pl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vektor_polyline_add_point(VektorPolyline *pl, V2 point) {
|
void vektor_polyline_add_point(VektorPolyline *pl, V2 point) {
|
||||||
if (pl->count >= pl->capacity) {
|
if (pl->count >= pl->capacity) {
|
||||||
pl->capacity *= 2;
|
pl->capacity *= 2;
|
||||||
pl->points = realloc(pl->points, sizeof(V2) * pl->capacity);
|
pl->points = realloc(pl->points, sizeof(V2) * pl->capacity);
|
||||||
}
|
}
|
||||||
pl->points[pl->count++] = point;
|
pl->points[pl->count++] = point;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vektor_polyline_free(VektorPolyline *pl) {
|
void vektor_polyline_free(VektorPolyline *pl) {
|
||||||
if (!pl)
|
if (!pl)
|
||||||
return;
|
return;
|
||||||
free(pl->points);
|
free(pl->points);
|
||||||
free(pl);
|
free(pl);
|
||||||
}
|
}
|
||||||
|
|
||||||
VektorPolygon *vektor_polygon_new(void) {
|
VektorPolygon *vektor_polygon_new(void) {
|
||||||
VektorPolygon *pg = malloc(sizeof(VektorPolygon));
|
VektorPolygon *pg = malloc(sizeof(VektorPolygon));
|
||||||
pg->count = 0;
|
pg->count = 0;
|
||||||
pg->capacity = 4;
|
pg->capacity = 4;
|
||||||
pg->points = malloc(sizeof(V2) * pg->capacity);
|
pg->points = malloc(sizeof(V2) * pg->capacity);
|
||||||
return pg;
|
return pg;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vektor_polygon_add_point(VektorPolygon *pg, V2 point) {
|
void vektor_polygon_add_point(VektorPolygon *pg, V2 point) {
|
||||||
if (pg->count >= pg->capacity) {
|
if (pg->count >= pg->capacity) {
|
||||||
pg->capacity *= 2;
|
pg->capacity *= 2;
|
||||||
pg->points = realloc(pg->points, sizeof(V2) * pg->capacity);
|
pg->points = realloc(pg->points, sizeof(V2) * pg->capacity);
|
||||||
}
|
}
|
||||||
pg->points[pg->count++] = point;
|
pg->points[pg->count++] = point;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vektor_polygon_free(VektorPolygon *pg) {
|
void vektor_polygon_free(VektorPolygon *pg) {
|
||||||
if (!pg)
|
if (!pg)
|
||||||
return;
|
return;
|
||||||
free(pg->points);
|
free(pg->points);
|
||||||
free(pg);
|
free(pg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vektor_primitivebuffer_add_primitive(VektorPrimitiveBuffer *buffer,
|
void vektor_primitivebuffer_add_primitive(VektorPrimitiveBuffer *buffer,
|
||||||
VektorPrimitive prim) {
|
VektorPrimitive prim) {
|
||||||
if (buffer->count >= buffer->capacity) {
|
if (buffer->count >= buffer->capacity) {
|
||||||
buffer->capacity = buffer->capacity ? buffer->capacity * 2 : 4;
|
buffer->capacity = buffer->capacity ? buffer->capacity * 2 : 4;
|
||||||
buffer->primitives =
|
buffer->primitives = realloc(
|
||||||
realloc(buffer->primitives, sizeof(VektorPrimitive) * buffer->capacity);
|
buffer->primitives, sizeof(VektorPrimitive) * buffer->capacity);
|
||||||
}
|
}
|
||||||
buffer->primitives[buffer->count++] = prim;
|
buffer->primitives[buffer->count++] = prim;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,42 +6,42 @@
|
|||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
V2 p1;
|
V2 p1;
|
||||||
V2 p2;
|
V2 p2;
|
||||||
} VektorLine;
|
} VektorLine;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
V2 *points;
|
V2 *points;
|
||||||
size_t count;
|
size_t count;
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
} VektorPolyline;
|
} VektorPolyline;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
V2 *points;
|
V2 *points;
|
||||||
size_t count;
|
size_t count;
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
} VektorPolygon;
|
} VektorPolygon;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
V2 center;
|
V2 center;
|
||||||
double radius;
|
double radius;
|
||||||
} VektorCircle;
|
} VektorCircle;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
VEKTOR_LINE,
|
VEKTOR_LINE,
|
||||||
VEKTOR_POLYLINE,
|
VEKTOR_POLYLINE,
|
||||||
VEKTOR_POLYGON,
|
VEKTOR_POLYGON,
|
||||||
VEKTOR_CIRCLE
|
VEKTOR_CIRCLE
|
||||||
} VektorPrimitiveKind;
|
} VektorPrimitiveKind;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
VektorPrimitiveKind kind;
|
VektorPrimitiveKind kind;
|
||||||
union {
|
union {
|
||||||
VektorLine line;
|
VektorLine line;
|
||||||
VektorPolyline *polyline;
|
VektorPolyline *polyline;
|
||||||
VektorPolygon *polygon;
|
VektorPolygon *polygon;
|
||||||
VektorCircle circle;
|
VektorCircle circle;
|
||||||
};
|
};
|
||||||
} VektorPrimitive;
|
} VektorPrimitive;
|
||||||
|
|
||||||
VektorPolyline *vektor_polyline_new(void);
|
VektorPolyline *vektor_polyline_new(void);
|
||||||
@@ -53,9 +53,9 @@ void vektor_polygon_add_point(VektorPolygon *pl, V2 point);
|
|||||||
void vektor_polygon_free(VektorPolygon *pl);
|
void vektor_polygon_free(VektorPolygon *pl);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
VektorPrimitive *primitives;
|
VektorPrimitive *primitives;
|
||||||
size_t count;
|
size_t count;
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
} VektorPrimitiveBuffer;
|
} VektorPrimitiveBuffer;
|
||||||
|
|
||||||
void vektor_primitivebuffer_add_primitive(VektorPrimitiveBuffer *edges,
|
void vektor_primitivebuffer_add_primitive(VektorPrimitiveBuffer *edges,
|
||||||
|
|||||||
@@ -4,112 +4,123 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
void vektor_edgebuffer_add_edge(EdgeBuffer *buffer, Edge edge) {
|
void vektor_edgebuffer_add_edge(EdgeBuffer *buffer, Edge edge) {
|
||||||
if (buffer->count >= buffer->capacity) {
|
if (buffer->count >= buffer->capacity) {
|
||||||
buffer->capacity = buffer->capacity ? buffer->capacity * 2 : 4;
|
buffer->capacity = buffer->capacity ? buffer->capacity * 2 : 4;
|
||||||
buffer->edges = realloc(buffer->edges, sizeof(Edge) * buffer->capacity);
|
buffer->edges = realloc(buffer->edges, sizeof(Edge) * buffer->capacity);
|
||||||
}
|
}
|
||||||
buffer->edges[buffer->count++] = edge;
|
buffer->edges[buffer->count++] = edge;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vektor_line_flatten(EdgeBuffer *buffer, VektorLine line) {
|
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) {
|
void vektor_polyline_flatten(EdgeBuffer *buffer, VektorPolyline *line) {
|
||||||
for (size_t i = 0; i + 1 < line->count; i++) {
|
for (size_t i = 0; i + 1 < line->count; i++) {
|
||||||
vektor_edgebuffer_add_edge(buffer,
|
vektor_edgebuffer_add_edge(
|
||||||
(Edge){line->points[i], line->points[i + 1], 0});
|
buffer, (Edge){line->points[i], line->points[i + 1], 0});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vektor_polygon_flatten(EdgeBuffer *buffer, VektorPolygon *pg) {
|
void vektor_polygon_flatten(EdgeBuffer *buffer, VektorPolygon *pg) {
|
||||||
size_t n = pg->count;
|
size_t n = pg->count;
|
||||||
if (n < 3)
|
if (n < 3)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (size_t i = 0; i < n; i++) {
|
for (size_t i = 0; i < n; i++) {
|
||||||
V2 p1 = pg->points[i];
|
V2 p1 = pg->points[i];
|
||||||
V2 p2 = pg->points[(i + 1) % n];
|
V2 p2 = pg->points[(i + 1) % n];
|
||||||
int winding = (p1.y < p2.y) ? +1 : -1;
|
int winding = (p1.y < p2.y) ? +1 : -1;
|
||||||
vektor_edgebuffer_add_edge(buffer, (Edge){p1, p2, winding});
|
vektor_edgebuffer_add_edge(buffer, (Edge){p1, p2, winding});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline VektorFramebuffer vektor_framebuffer_new(unsigned int W,
|
inline VektorFramebuffer vektor_framebuffer_new(unsigned int W,
|
||||||
unsigned int H) {
|
unsigned int H) {
|
||||||
VektorFramebuffer fb = {
|
VektorFramebuffer fb = {
|
||||||
.width = W, .height = H, .pixels = calloc(W * H * 4, 1)};
|
.width = W, .height = H, .pixels = calloc(W * H * 4, 1)};
|
||||||
return fb;
|
return fb;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void vektor_framebuffer_putpixel(VektorFramebuffer *fb, int x, int y,
|
inline void vektor_framebuffer_putpixel(VektorFramebuffer *fb, int x, int y,
|
||||||
VektorColor color) {
|
VektorColor color) {
|
||||||
if ((unsigned)x >= fb->width || (unsigned)y >= fb->height)
|
if ((unsigned)x >= fb->width || (unsigned)y >= fb->height)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int i = (y * fb->width + x) * 4;
|
int i = (y * fb->width + x) * 4;
|
||||||
fb->pixels[i + 0] = color.r;
|
fb->pixels[i + 0] = color.r;
|
||||||
fb->pixels[i + 1] = color.g;
|
fb->pixels[i + 1] = color.g;
|
||||||
fb->pixels[i + 2] = color.b;
|
fb->pixels[i + 2] = color.b;
|
||||||
fb->pixels[i + 3] = color.a;
|
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,
|
void vektor_framebuffer_drawline(VektorFramebuffer *fb, V2 a, V2 b,
|
||||||
VektorColor color) {
|
VektorColor color, double thickness) {
|
||||||
int x0 = (int)a.x;
|
int x0 = (int)a.x;
|
||||||
int y0 = (int)a.y;
|
int y0 = (int)a.y;
|
||||||
int x1 = (int)b.x;
|
int x1 = (int)b.x;
|
||||||
int y1 = (int)b.y;
|
int y1 = (int)b.y;
|
||||||
|
|
||||||
int dx = abs(x1 - x0);
|
int dx = abs(x1 - x0);
|
||||||
int sx = x0 < x1 ? 1 : -1;
|
int sx = x0 < x1 ? 1 : -1;
|
||||||
int dy = -abs(y1 - y0);
|
int dy = -abs(y1 - y0);
|
||||||
int sy = y0 < y1 ? 1 : -1;
|
int sy = y0 < y1 ? 1 : -1;
|
||||||
int err = dx + dy;
|
int err = dx + dy;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
vektor_framebuffer_putpixel(fb, x0, y0, color);
|
draw_filled_circle(fb, x0, y0, thickness / 2, color);
|
||||||
if (x0 == x1 && y0 == y1)
|
if (x0 == x1 && y0 == y1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
int e2 = 2 * err;
|
int e2 = 2 * err;
|
||||||
if (e2 >= dy) {
|
if (e2 >= dy) {
|
||||||
err += dy;
|
err += dy;
|
||||||
x0 += sx;
|
x0 += sx;
|
||||||
|
}
|
||||||
|
if (e2 <= dx) {
|
||||||
|
err += dx;
|
||||||
|
y0 += sy;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (e2 <= dx) {
|
|
||||||
err += dx;
|
|
||||||
y0 += sy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vektor_framebuffer_rasterize(VektorFramebuffer *fb, VektorPrimitiveBuffer *prims) {
|
void vektor_framebuffer_rasterize(VektorFramebuffer *fb,
|
||||||
EdgeBuffer edges = {0};
|
VektorPrimitiveBuffer *prims) {
|
||||||
for (size_t i = 0; i < prims->count; i++) {
|
EdgeBuffer edges = {0};
|
||||||
VektorPrimitive *p = &prims->primitives[i];
|
for (size_t i = 0; i < prims->count; i++) {
|
||||||
|
VektorPrimitive *p = &prims->primitives[i];
|
||||||
|
|
||||||
switch (p->kind) {
|
switch (p->kind) {
|
||||||
case VEKTOR_LINE:
|
case VEKTOR_LINE:
|
||||||
vektor_line_flatten(&edges, p->line);
|
vektor_line_flatten(&edges, p->line);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VEKTOR_POLYLINE:
|
case VEKTOR_POLYLINE:
|
||||||
vektor_polyline_flatten(&edges, p->polyline);
|
vektor_polyline_flatten(&edges, p->polyline);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VEKTOR_POLYGON:
|
case VEKTOR_POLYGON:
|
||||||
vektor_polygon_flatten(&edges, p->polygon);
|
vektor_polygon_flatten(&edges, p->polygon);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// TODO fill in all primitives
|
// TODO fill in all primitives
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < edges.count; i++) {
|
for (size_t i = 0; i < edges.count; i++) {
|
||||||
vektor_framebuffer_drawline(fb, edges.edges[i].p1, edges.edges[i].p2,
|
vektor_framebuffer_drawline(fb, edges.edges[i].p1, edges.edges[i].p2,
|
||||||
vektor_color_solid(255, 0, 255));
|
vektor_color_solid(255, 0, 255), 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,15 +8,15 @@
|
|||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
V2 p1;
|
V2 p1;
|
||||||
V2 p2;
|
V2 p2;
|
||||||
int winding;
|
int winding;
|
||||||
} Edge;
|
} Edge;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Edge *edges;
|
Edge *edges;
|
||||||
size_t count;
|
size_t count;
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
} EdgeBuffer;
|
} EdgeBuffer;
|
||||||
|
|
||||||
void vektor_edgebuffer_add_edge(EdgeBuffer *edges, Edge edge);
|
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);
|
void vektor_polygon_flatten(EdgeBuffer *buffer, VektorPolygon *line);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned int width;
|
unsigned int width;
|
||||||
unsigned int height;
|
unsigned int height;
|
||||||
unsigned char *pixels; // Flat RGBA8 array
|
unsigned char *pixels; // Flat RGBA8 array
|
||||||
} VektorFramebuffer;
|
} VektorFramebuffer;
|
||||||
|
|
||||||
VektorFramebuffer vektor_framebuffer_new(unsigned int width,
|
VektorFramebuffer vektor_framebuffer_new(unsigned int width,
|
||||||
@@ -38,8 +38,9 @@ void vektor_framebuffer_putpixel(VektorFramebuffer *fb, int x, int y,
|
|||||||
VektorColor color);
|
VektorColor color);
|
||||||
|
|
||||||
void vektor_framebuffer_drawline(VektorFramebuffer *fb, V2 a, V2 b,
|
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_
|
#endif // RASTER_H_
|
||||||
|
|||||||
@@ -4,14 +4,14 @@
|
|||||||
#include "math.h"
|
#include "math.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
double x;
|
double x;
|
||||||
double y;
|
double y;
|
||||||
} V2;
|
} V2;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
double x;
|
double x;
|
||||||
double y;
|
double y;
|
||||||
double z;
|
double z;
|
||||||
} V3;
|
} V3;
|
||||||
|
|
||||||
static inline V3 vec2_vector(const V2 v) { return (V3){v.x, v.y, 0}; }
|
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 V3 vec2_point(const V2 v) { return (V3){v.x, v.y, 1}; }
|
||||||
|
|
||||||
static inline V2 vec2_add(const V2 v1, const V2 v2) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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_
|
#endif // VECTOR_H_
|
||||||
|
|||||||
37
src/main.c
37
src/main.c
@@ -4,41 +4,40 @@
|
|||||||
#include "stdio.h"
|
#include "stdio.h"
|
||||||
#include "stdlib.h"
|
#include "stdlib.h"
|
||||||
|
|
||||||
|
#include "./application/applicationstate.h"
|
||||||
#include "./core/raster.h"
|
#include "./core/raster.h"
|
||||||
#include "./ui/uicontroller.h"
|
#include "./ui/uicontroller.h"
|
||||||
#include "./ui/vektorcanvas.h"
|
#include "./ui/vektorcanvas.h"
|
||||||
#include "./util/color.h"
|
#include "./util/color.h"
|
||||||
#include "./application/applicationstate.h"
|
|
||||||
|
|
||||||
static void on_map(GtkWidget *window, gpointer user_data) {
|
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) {
|
static void activate(GtkApplication *app, gpointer user_data) {
|
||||||
|
|
||||||
VektorWidgetState *widget_state =
|
VektorWidgetState *widget_state =
|
||||||
(VektorWidgetState *)malloc(sizeof(VektorWidgetState));
|
(VektorWidgetState *)malloc(sizeof(VektorWidgetState));
|
||||||
vektor_uictrl_init(app, widget_state);
|
vektor_uictrl_init(app, widget_state);
|
||||||
VektorAppState* app_state =
|
VektorAppState *app_state =
|
||||||
(VektorAppState *)malloc(sizeof(VektorAppState));
|
(VektorAppState *)malloc(sizeof(VektorAppState));
|
||||||
vektor_appstate_new(widget_state, app_state);
|
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),
|
gtk_window_present(widget_state->window);
|
||||||
widget_state);
|
|
||||||
|
|
||||||
gtk_window_present(widget_state->window);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
GtkApplication *app;
|
GtkApplication *app;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
app = gtk_application_new("dev.frox.vektor", G_APPLICATION_DEFAULT_FLAGS);
|
app = gtk_application_new("dev.frox.vektor", G_APPLICATION_DEFAULT_FLAGS);
|
||||||
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
|
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
|
||||||
status = g_application_run(G_APPLICATION(app), argc, argv);
|
status = g_application_run(G_APPLICATION(app), argc, argv);
|
||||||
g_object_unref(app);
|
g_object_unref(app);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,43 +5,43 @@
|
|||||||
#include "gtk/gtkcssprovider.h"
|
#include "gtk/gtkcssprovider.h"
|
||||||
|
|
||||||
void vektor_uictrl_init(GtkApplication *app, VektorWidgetState *stateOut) {
|
void vektor_uictrl_init(GtkApplication *app, VektorWidgetState *stateOut) {
|
||||||
GtkBuilder *builder = gtk_builder_new();
|
GtkBuilder *builder = gtk_builder_new();
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
// TODO: .ui files as resources instead of sketchy relative paths
|
// TODO: .ui files as resources instead of sketchy relative paths
|
||||||
if (!gtk_builder_add_from_file(builder, "./ui/main.ui", &error)) {
|
if (!gtk_builder_add_from_file(builder, "./ui/main.ui", &error)) {
|
||||||
g_error("Fatal: %s", error->message);
|
g_error("Fatal: %s", error->message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load css
|
// Load css
|
||||||
GtkCssProvider* provider = gtk_css_provider_new();
|
GtkCssProvider *provider = gtk_css_provider_new();
|
||||||
gtk_css_provider_load_from_path(provider, "./ui/main.css");
|
gtk_css_provider_load_from_path(provider, "./ui/main.css");
|
||||||
gtk_style_context_add_provider_for_display(gdk_display_get_default(),
|
gtk_style_context_add_provider_for_display(
|
||||||
GTK_STYLE_PROVIDER(provider),
|
gdk_display_get_default(), GTK_STYLE_PROVIDER(provider),
|
||||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION
|
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||||
);
|
|
||||||
|
|
||||||
// populate state
|
// populate state
|
||||||
stateOut->window = GTK_WINDOW(gtk_builder_get_object(builder, "main_window"));
|
stateOut->window =
|
||||||
stateOut->workspacePaned =
|
GTK_WINDOW(gtk_builder_get_object(builder, "main_window"));
|
||||||
GTK_PANED(gtk_builder_get_object(builder, "workspace_paned"));
|
stateOut->workspacePaned =
|
||||||
stateOut->workspaceCanvas =
|
GTK_PANED(gtk_builder_get_object(builder, "workspace_paned"));
|
||||||
GTK_PICTURE(gtk_builder_get_object(builder, "workspace"));
|
stateOut->workspaceCanvas =
|
||||||
stateOut->workspaceButtonLinetool =
|
GTK_PICTURE(gtk_builder_get_object(builder, "workspace"));
|
||||||
GTK_BUTTON(gtk_builder_get_object(builder, "button_linetool"));
|
stateOut->workspaceButtonLinetool =
|
||||||
|
GTK_BUTTON(gtk_builder_get_object(builder, "button_linetool"));
|
||||||
|
|
||||||
// Set window properties
|
// Set window properties
|
||||||
gtk_window_set_application(stateOut->window, app);
|
gtk_window_set_application(stateOut->window, app);
|
||||||
gtk_window_set_title(stateOut->window, "Vektor");
|
gtk_window_set_title(stateOut->window, "Vektor");
|
||||||
gtk_window_set_default_size(stateOut->window, 800, 600);
|
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
|
// set the workspace divider to 7:3 ratio
|
||||||
int window_width = gtk_widget_get_width(GTK_WIDGET(state->window));
|
int window_width = gtk_widget_get_width(GTK_WIDGET(state->window));
|
||||||
g_print("%i", window_width);
|
g_print("%i", window_width);
|
||||||
gtk_paned_set_position(state->workspacePaned, 800 * .7);
|
gtk_paned_set_position(state->workspacePaned, 800 * .7);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ Global application widget state, holding references to
|
|||||||
all the widgets used in internal logic of the program
|
all the widgets used in internal logic of the program
|
||||||
*/
|
*/
|
||||||
typedef struct VektorWidgetState {
|
typedef struct VektorWidgetState {
|
||||||
GtkWindow *window;
|
GtkWindow *window;
|
||||||
GtkPaned *workspacePaned;
|
GtkPaned *workspacePaned;
|
||||||
GtkPicture *workspaceCanvas;
|
GtkPicture *workspaceCanvas;
|
||||||
|
|
||||||
GtkButton* workspaceButtonLinetool;
|
GtkButton *workspaceButtonLinetool;
|
||||||
|
|
||||||
// GtkWidget* Workspace
|
// GtkWidget* Workspace
|
||||||
} VektorWidgetState;
|
} VektorWidgetState;
|
||||||
|
|
||||||
void vektor_uictrl_init(GtkApplication *app, VektorWidgetState *stateOut);
|
void vektor_uictrl_init(GtkApplication *app, VektorWidgetState *stateOut);
|
||||||
|
|||||||
@@ -9,59 +9,60 @@
|
|||||||
#define VKTR_CANVAS_SIZE (VKTR_CANVAS_WIDTH * VKTR_CANVAS_HEIGHT * 4)
|
#define VKTR_CANVAS_SIZE (VKTR_CANVAS_WIDTH * VKTR_CANVAS_HEIGHT * 4)
|
||||||
|
|
||||||
void vektor_canvas_init(VektorWidgetState *state, VektorCanvas *canvasOut) {
|
void vektor_canvas_init(VektorWidgetState *state, VektorCanvas *canvasOut) {
|
||||||
canvasOut->canvasWidget = state->workspaceCanvas;
|
canvasOut->canvasWidget = state->workspaceCanvas;
|
||||||
canvasOut->width = VKTR_CANVAS_WIDTH;
|
canvasOut->width = VKTR_CANVAS_WIDTH;
|
||||||
canvasOut->height = VKTR_CANVAS_HEIGHT;
|
canvasOut->height = VKTR_CANVAS_HEIGHT;
|
||||||
canvasOut->canvasPixels = g_malloc0(VKTR_CANVAS_SIZE);
|
canvasOut->canvasPixels = g_malloc0(VKTR_CANVAS_SIZE);
|
||||||
|
|
||||||
canvasOut->canvasPixelBytes =
|
canvasOut->canvasPixelBytes =
|
||||||
g_bytes_new(canvasOut->canvasPixels, VKTR_CANVAS_SIZE);
|
g_bytes_new(canvasOut->canvasPixels, VKTR_CANVAS_SIZE);
|
||||||
canvasOut->canvasTexture = gdk_memory_texture_new(
|
canvasOut->canvasTexture = gdk_memory_texture_new(
|
||||||
VKTR_CANVAS_WIDTH, VKTR_CANVAS_HEIGHT, GDK_MEMORY_R8G8B8A8,
|
VKTR_CANVAS_WIDTH, VKTR_CANVAS_HEIGHT, GDK_MEMORY_R8G8B8A8,
|
||||||
canvasOut->canvasPixelBytes, VKTR_CANVAS_WIDTH * 4);
|
canvasOut->canvasPixelBytes, VKTR_CANVAS_WIDTH * 4);
|
||||||
|
|
||||||
gtk_picture_set_paintable(canvasOut->canvasWidget,
|
gtk_picture_set_paintable(canvasOut->canvasWidget,
|
||||||
GDK_PAINTABLE(canvasOut->canvasTexture));
|
GDK_PAINTABLE(canvasOut->canvasTexture));
|
||||||
|
gtk_picture_set_content_fit(GTK_PICTURE(canvasOut->canvasWidget),
|
||||||
// g_object_unref(bytes);
|
GTK_CONTENT_FIT_CONTAIN);
|
||||||
|
// g_object_unref(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate new texture based on canvasPixels*/
|
/* Generate new texture based on canvasPixels*/
|
||||||
void vektor_canvas_update(VektorCanvas *canvas) {
|
void vektor_canvas_update(VektorCanvas *canvas) {
|
||||||
g_bytes_unref(canvas->canvasPixelBytes);
|
g_bytes_unref(canvas->canvasPixelBytes);
|
||||||
canvas->canvasPixelBytes =
|
canvas->canvasPixelBytes =
|
||||||
g_bytes_new(canvas->canvasPixels, VKTR_CANVAS_SIZE);
|
g_bytes_new(canvas->canvasPixels, VKTR_CANVAS_SIZE);
|
||||||
|
|
||||||
g_object_unref(canvas->canvasTexture);
|
g_object_unref(canvas->canvasTexture);
|
||||||
canvas->canvasTexture =
|
canvas->canvasTexture = gdk_memory_texture_new(
|
||||||
gdk_memory_texture_new(canvas->width, canvas->height, GDK_MEMORY_R8G8B8A8,
|
canvas->width, canvas->height, GDK_MEMORY_R8G8B8A8,
|
||||||
canvas->canvasPixelBytes, canvas->width * 4);
|
canvas->canvasPixelBytes, canvas->width * 4);
|
||||||
|
|
||||||
gtk_picture_set_paintable(canvas->canvasWidget,
|
gtk_picture_set_paintable(canvas->canvasWidget,
|
||||||
GDK_PAINTABLE(canvas->canvasTexture));
|
GDK_PAINTABLE(canvas->canvasTexture));
|
||||||
}
|
}
|
||||||
|
|
||||||
void vektor_canvas_fill(VektorCanvas *canvas, VektorColor color) {
|
void vektor_canvas_fill(VektorCanvas *canvas, VektorColor color) {
|
||||||
for (int x = 0; x < VKTR_CANVAS_WIDTH; x++) {
|
for (int x = 0; x < VKTR_CANVAS_WIDTH; x++) {
|
||||||
for (int y = 0; y < VKTR_CANVAS_HEIGHT; y++) {
|
for (int y = 0; y < VKTR_CANVAS_HEIGHT; y++) {
|
||||||
int i = (y * VKTR_CANVAS_WIDTH + x) * 4;
|
int i = (y * VKTR_CANVAS_WIDTH + x) * 4;
|
||||||
canvas->canvasPixels[i + 0] = color.r;
|
canvas->canvasPixels[i + 0] = color.r;
|
||||||
canvas->canvasPixels[i + 1] = color.g;
|
canvas->canvasPixels[i + 1] = color.g;
|
||||||
canvas->canvasPixels[i + 2] = color.b;
|
canvas->canvasPixels[i + 2] = color.b;
|
||||||
canvas->canvasPixels[i + 3] = color.a;
|
canvas->canvasPixels[i + 3] = color.a;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vektor_canvas_drawfrom(VektorFramebuffer *fb, VektorCanvas *target) {
|
void vektor_canvas_drawfrom(VektorFramebuffer *fb, VektorCanvas *target) {
|
||||||
for (int x = 0; x < fb->width; x++) {
|
for (int x = 0; x < fb->width; x++) {
|
||||||
for (int y = 0; y < fb->height; y++) {
|
for (int y = 0; y < fb->height; y++) {
|
||||||
|
|
||||||
int i = (y * fb->width + x) * 4;
|
int i = (y * fb->width + x) * 4;
|
||||||
target->canvasPixels[i + 0] = (guchar)fb->pixels[i + 0];
|
target->canvasPixels[i + 0] = (guchar)fb->pixels[i + 0];
|
||||||
target->canvasPixels[i + 1] = (guchar)fb->pixels[i + 1];
|
target->canvasPixels[i + 1] = (guchar)fb->pixels[i + 1];
|
||||||
target->canvasPixels[i + 2] = (guchar)fb->pixels[i + 2];
|
target->canvasPixels[i + 2] = (guchar)fb->pixels[i + 2];
|
||||||
target->canvasPixels[i + 3] = (guchar)fb->pixels[i + 3];
|
target->canvasPixels[i + 3] = (guchar)fb->pixels[i + 3];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -6,15 +6,15 @@
|
|||||||
#include "uicontroller.h"
|
#include "uicontroller.h"
|
||||||
|
|
||||||
typedef struct VektorCanvas {
|
typedef struct VektorCanvas {
|
||||||
GtkPicture *canvasWidget;
|
GtkPicture *canvasWidget;
|
||||||
|
|
||||||
// texture related stuff
|
// texture related stuff
|
||||||
guchar *canvasPixels;
|
guchar *canvasPixels;
|
||||||
GdkTexture *canvasTexture;
|
GdkTexture *canvasTexture;
|
||||||
GBytes *canvasPixelBytes;
|
GBytes *canvasPixelBytes;
|
||||||
|
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
} VektorCanvas;
|
} VektorCanvas;
|
||||||
|
|
||||||
void vektor_canvas_init(VektorWidgetState *state, VektorCanvas *canvasOut);
|
void vektor_canvas_init(VektorWidgetState *state, VektorCanvas *canvasOut);
|
||||||
|
|||||||
@@ -2,22 +2,22 @@
|
|||||||
#define COLOR_H_
|
#define COLOR_H_
|
||||||
|
|
||||||
typedef struct VektorColor {
|
typedef struct VektorColor {
|
||||||
unsigned char r;
|
unsigned char r;
|
||||||
unsigned char g;
|
unsigned char g;
|
||||||
unsigned char b;
|
unsigned char b;
|
||||||
unsigned char a;
|
unsigned char a;
|
||||||
} VektorColor;
|
} VektorColor;
|
||||||
|
|
||||||
static VektorColor vektor_color_blank = (VektorColor){0, 0, 0, 0};
|
static VektorColor vektor_color_blank = (VektorColor){0, 0, 0, 0};
|
||||||
|
|
||||||
static inline VektorColor vektor_color_new(unsigned char r, unsigned char g,
|
static inline VektorColor vektor_color_new(unsigned char r, unsigned char g,
|
||||||
unsigned char b, unsigned char a) {
|
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,
|
static inline VektorColor vektor_color_solid(unsigned char r, unsigned char g,
|
||||||
unsigned char b) {
|
unsigned char b) {
|
||||||
return (VektorColor){r, g, b, 255};
|
return (VektorColor){r, g, b, 255};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // COLOR_H_
|
#endif // COLOR_H_
|
||||||
|
|||||||
Reference in New Issue
Block a user