feat: polyline drawing
This commit is contained in:
@@ -18,7 +18,8 @@ src = files(
|
||||
'src/core/primitives.c',
|
||||
'src/core/raster.c',
|
||||
'src/ui/uicontroller.c',
|
||||
'src/ui/vektorcanvas.c'
|
||||
'src/ui/vektorcanvas.c',
|
||||
'src/application/applicationstate.c'
|
||||
)
|
||||
|
||||
executable(
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
#include "./applicationstate.h"
|
||||
#include "src/core/primitives.h"
|
||||
#include "src/core/raster.h"
|
||||
#include "src/ui/vektorcanvas.h"
|
||||
|
||||
typedef struct button_tool_set_data {
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
void vektor_appstate_canvas_click(VektorAppState* state, double x, double y) {
|
||||
V2 pos = (V2){x,y};
|
||||
|
||||
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]);
|
||||
|
||||
} else if (state->selectedPrimitive->kind != VEKTOR_POLYLINE) {
|
||||
// selecting a tool resets the selection, so this condition
|
||||
// should not happen
|
||||
g_warning("Invalid selected primitive; polyline expected");
|
||||
state->selectedPrimitive = NULL;
|
||||
goto begin_click_dispatch; // retry
|
||||
}
|
||||
|
||||
|
||||
vektor_polyline_add_point(state->selectedPrimitive->polyline, pos);
|
||||
}
|
||||
|
||||
vektor_framebuffer_rasterize(state->frameBuffer, state->primitiveBuffer);
|
||||
vektor_canvas_drawfrom(state->frameBuffer, state->canvas);
|
||||
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));
|
||||
data_linetool->state = stateOut;
|
||||
data_linetool->tool = VektorLineTool;
|
||||
|
||||
// populate appstate
|
||||
stateOut->primitiveBuffer = malloc(sizeof(VektorPrimitiveBuffer));
|
||||
*stateOut->primitiveBuffer = (VektorPrimitiveBuffer){0};
|
||||
stateOut->frameBuffer = malloc(sizeof(VektorFramebuffer));
|
||||
*stateOut->frameBuffer = vektor_framebuffer_new(400, 400);
|
||||
stateOut->canvas = malloc(sizeof(VektorCanvas));
|
||||
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);
|
||||
|
||||
// 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)
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,29 @@
|
||||
#ifndef VKTR_APPSTATE_H
|
||||
#define VKTR_APPSTATE_H
|
||||
|
||||
#include "../ui/uicontroller.h"
|
||||
#include "../core/primitives.h"
|
||||
#include "src/core/raster.h"
|
||||
#include "../ui/vektorcanvas.h"
|
||||
|
||||
typedef enum VektorAppTool {
|
||||
CircleTool
|
||||
VektorLineTool
|
||||
} VektorAppTool;
|
||||
|
||||
typedef struct VektorAppState {
|
||||
VektorAppTool selectedTool;
|
||||
} VektorAppState;
|
||||
VektorPrimitive* selectedPrimitive;
|
||||
|
||||
// Logic space
|
||||
VektorPrimitiveBuffer* primitiveBuffer;
|
||||
// Pixel space
|
||||
VektorFramebuffer* frameBuffer;
|
||||
// View space
|
||||
VektorCanvas* canvas;
|
||||
|
||||
} VektorAppState;
|
||||
|
||||
void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut);
|
||||
void vektor_appstate_canvas_click(VektorAppState* state, double x, double y);
|
||||
|
||||
#endif
|
||||
@@ -84,7 +84,7 @@ void vektor_framebuffer_drawline(VektorFramebuffer *fb, V2 a, V2 b,
|
||||
}
|
||||
}
|
||||
|
||||
void rasterize(VektorFramebuffer *fb, VektorPrimitiveBuffer *prims) {
|
||||
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];
|
||||
|
||||
@@ -40,6 +40,6 @@ void vektor_framebuffer_putpixel(VektorFramebuffer *fb, int x, int y,
|
||||
void vektor_framebuffer_drawline(VektorFramebuffer *fb, V2 a, V2 b,
|
||||
VektorColor color);
|
||||
|
||||
void rasterize(VektorFramebuffer *fb, VektorPrimitiveBuffer *primitives);
|
||||
void vektor_framebuffer_rasterize(VektorFramebuffer *fb, VektorPrimitiveBuffer *primitives);
|
||||
|
||||
#endif // RASTER_H_
|
||||
|
||||
46
src/main.c
46
src/main.c
@@ -1,4 +1,5 @@
|
||||
#include "gtk/gtk.h"
|
||||
#include "src/application/applicationstate.h"
|
||||
#include "src/core/primitives.h"
|
||||
#include "stdio.h"
|
||||
#include "stdlib.h"
|
||||
@@ -7,58 +8,21 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
void write_ppm(const char *path, const VektorFramebuffer *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 * 4, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static void activate(GtkApplication *app, gpointer user_data) {
|
||||
VektorFramebuffer fb = vektor_framebuffer_new(400, 400);
|
||||
|
||||
VektorPolygon triangle = *vektor_polygon_new();
|
||||
vektor_polygon_add_point(&triangle, (V2){50, 150});
|
||||
vektor_polygon_add_point(&triangle, (V2){200, 180});
|
||||
vektor_polygon_add_point(&triangle, (V2){120, 300});
|
||||
|
||||
VektorPolygon star = *vektor_polygon_new();
|
||||
vektor_polygon_add_point(&star, (V2){150, 40});
|
||||
vektor_polygon_add_point(&star, (V2){180, 110});
|
||||
vektor_polygon_add_point(&star, (V2){260, 110});
|
||||
vektor_polygon_add_point(&star, (V2){200, 160});
|
||||
vektor_polygon_add_point(&star, (V2){220, 240});
|
||||
vektor_polygon_add_point(&star, (V2){150, 190});
|
||||
vektor_polygon_add_point(&star, (V2){80, 240});
|
||||
vektor_polygon_add_point(&star, (V2){100, 160});
|
||||
vektor_polygon_add_point(&star, (V2){40, 110});
|
||||
vektor_polygon_add_point(&star, (V2){120, 110});
|
||||
|
||||
VektorPrimitiveBuffer prims = {0};
|
||||
vektor_primitivebuffer_add_primitive(
|
||||
&prims, (VektorPrimitive){.kind = VEKTOR_POLYGON, .polygon = &triangle});
|
||||
vektor_primitivebuffer_add_primitive(
|
||||
&prims, (VektorPrimitive){.kind = VEKTOR_POLYGON, .polygon = &star});
|
||||
|
||||
rasterize(&fb, &prims);
|
||||
|
||||
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);
|
||||
|
||||
VektorCanvas *canvas = (VektorCanvas *)malloc(sizeof(VektorCanvas));
|
||||
vektor_canvas_init(widget_state, canvas);
|
||||
vektor_canvas_fill(canvas, vektor_color_new(255, 0, 0, 255));
|
||||
vektor_canvas_drawfrom(&fb, canvas);
|
||||
vektor_canvas_update(canvas);
|
||||
|
||||
g_signal_connect(widget_state->window, "map", G_CALLBACK(on_map),
|
||||
widget_state);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "uicontroller.h"
|
||||
#include "gdk/gdk.h"
|
||||
#include "glib-object.h"
|
||||
#include "gtk/gtk.h"
|
||||
#include "gtk/gtkcssprovider.h"
|
||||
|
||||
@@ -12,6 +13,7 @@ void vektor_uictrl_init(GtkApplication *app, VektorWidgetState *stateOut) {
|
||||
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(),
|
||||
@@ -19,12 +21,16 @@ void vektor_uictrl_init(GtkApplication *app, VektorWidgetState *stateOut) {
|
||||
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"));
|
||||
|
||||
// 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);
|
||||
|
||||
@@ -12,6 +12,8 @@ typedef struct VektorWidgetState {
|
||||
GtkPaned *workspacePaned;
|
||||
GtkPicture *workspaceCanvas;
|
||||
|
||||
GtkButton* workspaceButtonLinetool;
|
||||
|
||||
// GtkWidget* Workspace
|
||||
} VektorWidgetState;
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
|
||||
<!--Tool buttons-->
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<object class="GtkButton" id="button_linetool">
|
||||
<property name="icon-name">insert-object-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
Reference in New Issue
Block a user