feat(untested): add handles base
This commit is contained in:
@@ -90,9 +90,6 @@ static void canvas_onclick(GtkGestureClick* gesture, int n_press, double x,
|
||||
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;
|
||||
|
||||
V2 normalized_coords =
|
||||
(V2){(2 * (x / widget_w)) - 1, 1 - (2 * (y / widget_h))};
|
||||
|
||||
@@ -163,11 +160,10 @@ begin_click_dispatch:
|
||||
VektorCircle* circle = vektor_circle_new();
|
||||
VektorPrimitive circlePrimitive =
|
||||
(VektorPrimitive){.kind = VEKTOR_CIRCLE, .circle = *circle};
|
||||
VektorStyle style = (VektorStyle){
|
||||
.stroke_color = state->currentColor, .stroke_width = 0.01};
|
||||
VektorStyle style = (VektorStyle){.stroke_color = state->currentColor,
|
||||
.stroke_width = 0.01};
|
||||
vektor_shapebuffer_add_shape(
|
||||
state->shapeBuffer,
|
||||
vektor_shape_new(circlePrimitive, style, 0));
|
||||
state->shapeBuffer, vektor_shape_new(circlePrimitive, style, 0));
|
||||
|
||||
state->selectedShape =
|
||||
&(state->shapeBuffer->shapes[state->shapeBuffer->count - 1]);
|
||||
@@ -213,6 +209,36 @@ begin_click_dispatch:
|
||||
}
|
||||
}
|
||||
|
||||
void vektor_appstate_canvas_drag_begin(GtkGestureDrag* gesture, gdouble x,
|
||||
gdouble y, gpointer 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);
|
||||
|
||||
V2 normalized_coords =
|
||||
(V2){(2 * (x / widget_w)) - 1, 1 - (2 * (y / widget_h))};
|
||||
|
||||
}
|
||||
|
||||
void vektor_appstate_canvas_drag_update(GtkGestureDrag* gesture,
|
||||
gdouble x, gdouble y,
|
||||
gpointer user_data) {
|
||||
gdouble start_x, start_y;
|
||||
gtk_gesture_drag_get_start_point(gesture, &start_x, &start_y);
|
||||
|
||||
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);
|
||||
|
||||
V2 norm =
|
||||
(V2){(2 * ( (x+start_x) / widget_w)) - 1, 1 - (2 * ( (y+start_y) / widget_h))};
|
||||
|
||||
}
|
||||
|
||||
void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut) {
|
||||
button_tool_set_data* data_linetool = malloc(sizeof(button_tool_set_data));
|
||||
data_linetool->state = stateOut;
|
||||
@@ -302,4 +328,14 @@ void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut) {
|
||||
G_CALLBACK(canvas_onclick), stateOut);
|
||||
gtk_widget_add_controller(GTK_WIDGET(wstate->workspaceCanvas),
|
||||
GTK_EVENT_CONTROLLER(canvasClickGesture));
|
||||
|
||||
// Add drag gesture to canvas
|
||||
GtkGesture* canvasDragGesture = gtk_gesture_drag_new();
|
||||
g_signal_connect(G_OBJECT(canvasDragGesture), "drag-update",
|
||||
G_CALLBACK(vektor_appstate_canvas_drag_update), stateOut);
|
||||
g_signal_connect(G_OBJECT(canvasDragGesture), "drag-begin",
|
||||
G_CALLBACK(vektor_appstate_canvas_drag_begin), stateOut);
|
||||
|
||||
gtk_widget_add_controller(GTK_WIDGET(wstate->workspaceCanvas),
|
||||
GTK_EVENT_CONTROLLER(canvasDragGesture));
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
#include "primitives.h"
|
||||
#include "glib.h"
|
||||
#include "src/core/vector.h"
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// ------ PER-PRIMITIVE METHODS ------
|
||||
|
||||
VektorPolyline* vektor_polyline_new(void) {
|
||||
VektorPolyline* pl = malloc(sizeof(VektorPolyline));
|
||||
pl->count = 0;
|
||||
@@ -95,22 +98,6 @@ void vektor_rectangle_set_start(VektorRectangle* rct, V2 point) {
|
||||
|
||||
void vektor_rectangle_free(VektorRectangle* rct) { free(rct); }
|
||||
|
||||
void vektor_shapebuffer_add_shape(VektorShapeBuffer* buffer,
|
||||
VektorShape shape) {
|
||||
if (buffer->count >= buffer->capacity) {
|
||||
buffer->capacity = buffer->capacity ? buffer->capacity * 2 : 4;
|
||||
buffer->shapes =
|
||||
realloc(buffer->shapes, sizeof(VektorShape) * buffer->capacity);
|
||||
}
|
||||
buffer->shapes[buffer->count++] = shape;
|
||||
|
||||
if (buffer->count <= buffer->capacity / 4) {
|
||||
buffer->capacity /= 2;
|
||||
buffer->shapes =
|
||||
realloc(buffer->shapes, sizeof(VektorShape) * buffer->capacity);
|
||||
}
|
||||
}
|
||||
|
||||
VektorBBox vektor_polyline_get_bbox(VektorPrimitive prim) {
|
||||
V2 first = prim.polyline->points[0];
|
||||
|
||||
@@ -188,11 +175,167 @@ VektorBBox vektor_primitive_get_bbox(VektorPrimitive prim) {
|
||||
}
|
||||
}
|
||||
|
||||
// ------ PRIMITIVE HANDLES GENERATION ------
|
||||
|
||||
/* [n]: polyline vertices */
|
||||
void vektor_polyline_create_handles(VektorPolyline* polyline, V2** handleArr, size_t* count) {
|
||||
*count = 0;
|
||||
*handleArr = NULL;
|
||||
}
|
||||
|
||||
/* [n]: polygon vertices */
|
||||
void vektor_polygon_create_handles(VektorPolygon* polygon, V2** handleArr, size_t* count) {
|
||||
*count = 0;
|
||||
*handleArr = NULL;
|
||||
}
|
||||
|
||||
/* [0]: center; [1]: radius */
|
||||
void vektor_circle_create_handles(VektorCircle* circle, V2** handleArr, size_t* count) {
|
||||
*count = 2;
|
||||
*handleArr = (V2*)malloc(sizeof(V2)*(*count));
|
||||
(*handleArr)[0] = circle->center;
|
||||
(*handleArr)[1] = (V2){circle->radius + circle->center.x, circle->center.y};
|
||||
}
|
||||
|
||||
/* [0]: center; [1-4]: corners (l2r, t2b); */
|
||||
void vektor_rectangle_create_handles(VektorRectangle* rectangle, V2** handleArr, size_t* count) {
|
||||
*count = 5;
|
||||
free(*handleArr);
|
||||
*handleArr = (V2*)malloc(sizeof(V2)*(*count));
|
||||
|
||||
V2 halfdist = vec2_scale(vec2_sub(rectangle->end, rectangle->start), 0.5f);
|
||||
V2 center = vec2_add(rectangle->start, halfdist);
|
||||
|
||||
(*handleArr)[0] = center;
|
||||
(*handleArr)[1] = vec2_add( center, vec2_mul(halfdist, (V2){-1.0f, 1.0f}) );
|
||||
(*handleArr)[2] = vec2_add( center, halfdist);
|
||||
(*handleArr)[3] = vec2_add( center, vec2_mul(halfdist, (V2){-1.0f, -1.0f}) );
|
||||
(*handleArr)[4] = vec2_add( center, vec2_mul(halfdist, (V2){1.0f, -1.0f}) );
|
||||
}
|
||||
|
||||
void vektor_shape_create_handles(VektorShape* shape) {
|
||||
switch(shape->primitive.kind) {
|
||||
case VEKTOR_POLYLINE:
|
||||
vektor_polyline_create_handles(shape->primitive.polyline, &shape->handles, &shape->handleCount);
|
||||
break;
|
||||
case VEKTOR_POLYGON:
|
||||
vektor_polygon_create_handles(shape->primitive.polygon, &shape->handles, &shape->handleCount);
|
||||
break;
|
||||
case VEKTOR_CIRCLE:
|
||||
vektor_circle_create_handles(&shape->primitive.circle, &shape->handles, &shape->handleCount);
|
||||
break;
|
||||
case VEKTOR_RECTANGLE:
|
||||
vektor_rectangle_create_handles(&shape->primitive.rectangle, &shape->handles, &shape->handleCount);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ------ PRIMITIVE HANDLES UPDATING ------
|
||||
|
||||
void vektor_polyline_handles_updated(VektorPolyline* polyline, V2** handles, size_t* count) {
|
||||
if(*count != polyline->count) {
|
||||
g_warning("handle count & point count mismatch in polyline");
|
||||
return;
|
||||
}
|
||||
for(size_t i = 0; i < *count; i++) {
|
||||
polyline->points[i] = (*handles)[i];
|
||||
}
|
||||
}
|
||||
|
||||
void vektor_polygon_handles_updated(VektorPolygon* polygon, V2** handles, size_t* count) {
|
||||
if(*count != polygon->count) {
|
||||
g_warning("handle count & point count mismatch in polygon");
|
||||
return;
|
||||
}
|
||||
for(size_t i = 0; i < *count; i++) {
|
||||
polygon->points[i] = (*handles)[i];
|
||||
}
|
||||
}
|
||||
|
||||
void vektor_circle_handles_updated(VektorCircle* circle, V2** handles, size_t* count) {
|
||||
if(*count != 2) {
|
||||
g_warning("unexpected circle handle count (%zu)", *count);
|
||||
return;
|
||||
}
|
||||
circle->center = (*handles)[0];
|
||||
circle->radius = vec2_length(vec2_sub((*handles)[0], (*handles)[1]));
|
||||
}
|
||||
|
||||
void vektor_rectangle_handles_updated(VektorRectangle* rectangle, V2** handles, size_t* count) {
|
||||
if(*count != 5) {
|
||||
g_warning("unexpected rectangle handle count (%zu)", *count);
|
||||
return;
|
||||
}
|
||||
|
||||
// get rectangle center
|
||||
V2 halfdist = vec2_scale(vec2_sub(rectangle->end, rectangle->start), 0.5f);
|
||||
V2 rectcenter = vec2_add(rectangle->start, halfdist);
|
||||
|
||||
// center according to handles
|
||||
V2 center = (*handles)[0];
|
||||
|
||||
if(vec2_equals(center, rectcenter)) { // corner handles were changed
|
||||
V2 p1 = (*handles)[1];
|
||||
V2 p2 = (*handles)[2];
|
||||
V2 p3 = (*handles)[3];
|
||||
V2 p4 = (*handles)[4];
|
||||
|
||||
float min_x = fminf(p1.x, fminf(p2.x, fminf(p3.x, p4.x)));
|
||||
float min_y = fminf(p1.y, fminf(p2.y, fminf(p3.y, p4.y)));
|
||||
float max_x = fmaxf(p1.x, fmaxf(p2.x, fmaxf(p3.x, p4.x)));
|
||||
float max_y = fmaxf(p1.y, fmaxf(p2.y, fmaxf(p3.y, p4.y)));
|
||||
|
||||
V2 min = (V2){min_x, min_y};
|
||||
V2 max = (V2){max_x, max_y};
|
||||
|
||||
VektorRectangle propertRect = (VektorRectangle){min,max};
|
||||
// overwrite handles array (create_handles() frees the passed one)
|
||||
vektor_rectangle_create_handles(&propertRect, handles, count);
|
||||
|
||||
} else { // corner was dragged
|
||||
V2 translation = vec2_sub(center, rectcenter);
|
||||
V2 newmax = vec2_add((*handles)[2], translation);
|
||||
V2 newmin = vec2_add((*handles)[3], translation);
|
||||
|
||||
VektorRectangle propertRect = (VektorRectangle){newmin,newmax};
|
||||
vektor_rectangle_create_handles(&propertRect, handles, count);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void vektor_shape_handles_updated(VektorShape* shape) {
|
||||
switch(shape->primitive.kind) {
|
||||
case VEKTOR_POLYLINE:
|
||||
vektor_polyline_handles_updated(shape->primitive.polyline, &shape->handles, &shape->handleCount);
|
||||
break;
|
||||
case VEKTOR_POLYGON:
|
||||
vektor_polygon_handles_updated(shape->primitive.polygon, &shape->handles, &shape->handleCount);
|
||||
break;
|
||||
case VEKTOR_CIRCLE:
|
||||
vektor_circle_handles_updated(&shape->primitive.circle, &shape->handles, &shape->handleCount);
|
||||
break;
|
||||
case VEKTOR_RECTANGLE:
|
||||
vektor_rectangle_handles_updated(&shape->primitive.rectangle, &shape->handles, &shape->handleCount);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ------ BBOX METHODS ------
|
||||
|
||||
bool vektor_bbox_isinside(VektorBBox bbox, V2 point) {
|
||||
return point.x >= bbox.min.x && point.y >= bbox.min.y &&
|
||||
point.x <= bbox.max.x && point.y <= bbox.max.y;
|
||||
}
|
||||
|
||||
VektorBBox vektor_bbox_fromcenter(V2 center, float dist) {
|
||||
V2 v2dist = vec2_fromfloat(dist);
|
||||
V2 min = vec2_sub(center, v2dist);
|
||||
V2 max = vec2_add(center, v2dist);
|
||||
return (VektorBBox){min,max};
|
||||
}
|
||||
|
||||
// ------ SHAPE METHODS ------
|
||||
|
||||
VektorShape vektor_shape_new(VektorPrimitive prim, VektorStyle style,
|
||||
int z_index) {
|
||||
return (VektorShape){.primitive = prim,
|
||||
@@ -207,3 +350,19 @@ void vektor_shapes_update_bbox(VektorShapeBuffer* buffer) {
|
||||
vektor_primitive_get_bbox(buffer->shapes[i].primitive);
|
||||
}
|
||||
}
|
||||
|
||||
void vektor_shapebuffer_add_shape(VektorShapeBuffer* buffer,
|
||||
VektorShape shape) {
|
||||
if (buffer->count >= buffer->capacity) {
|
||||
buffer->capacity = buffer->capacity ? buffer->capacity * 2 : 4;
|
||||
buffer->shapes =
|
||||
realloc(buffer->shapes, sizeof(VektorShape) * buffer->capacity);
|
||||
}
|
||||
buffer->shapes[buffer->count++] = shape;
|
||||
|
||||
if (buffer->count <= buffer->capacity / 4) {
|
||||
buffer->capacity /= 2;
|
||||
buffer->shapes =
|
||||
realloc(buffer->shapes, sizeof(VektorShape) * buffer->capacity);
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,26 @@ typedef struct {
|
||||
};
|
||||
} VektorPrimitive;
|
||||
|
||||
typedef struct {
|
||||
VektorColor stroke_color;
|
||||
float stroke_width;
|
||||
} VektorStyle;
|
||||
|
||||
typedef struct {
|
||||
V2 min;
|
||||
V2 max;
|
||||
} VektorBBox;
|
||||
|
||||
typedef struct {
|
||||
VektorStyle style;
|
||||
int z_index;
|
||||
VektorBBox bbox;
|
||||
VektorPrimitive primitive;
|
||||
|
||||
V2* handles;
|
||||
size_t handleCount;
|
||||
} VektorShape;
|
||||
|
||||
VektorPolyline* vektor_polyline_new(void);
|
||||
void vektor_polyline_add_point(VektorPolyline* pl, V2 point);
|
||||
void vektor_polyline_free(VektorPolyline* pl);
|
||||
@@ -63,22 +83,7 @@ void vektor_rectangle_set_end(VektorRectangle* rct, V2 point);
|
||||
void vektor_rectangle_set_start(VektorRectangle* rct, V2 point);
|
||||
void vektor_rectangle_free(VektorRectangle* rct);
|
||||
|
||||
typedef struct {
|
||||
VektorColor stroke_color;
|
||||
float stroke_width;
|
||||
} VektorStyle;
|
||||
|
||||
typedef struct {
|
||||
V2 min;
|
||||
V2 max;
|
||||
} VektorBBox;
|
||||
|
||||
typedef struct {
|
||||
VektorStyle style;
|
||||
int z_index;
|
||||
VektorBBox bbox;
|
||||
VektorPrimitive primitive;
|
||||
} VektorShape;
|
||||
VektorShape vektor_shape_new(VektorPrimitive prim, VektorStyle style, int z_index);
|
||||
|
||||
VektorBBox vektor_polyline_get_bbox(VektorPrimitive prim);
|
||||
VektorBBox vektor_polygon_get_bbox(VektorPrimitive prim);
|
||||
@@ -87,9 +92,21 @@ VektorBBox vektor_rectangle_get_bbox(VektorPrimitive prim);
|
||||
|
||||
VektorBBox vektor_primitive_get_bbox(VektorPrimitive prim);
|
||||
bool vektor_bbox_isinside(VektorBBox bbox, V2 point);
|
||||
VektorBBox vektor_bbox_fromcenter(V2 center, float dist);
|
||||
|
||||
VektorShape vektor_shape_new(VektorPrimitive prim, VektorStyle style,
|
||||
int z_index);
|
||||
// shape handles
|
||||
void vektor_polyline_create_handles(VektorPolyline* polyline, V2** handleArr, size_t* count);
|
||||
void vektor_polygon_create_handles(VektorPolygon* polygon, V2** handleArr, size_t* count);
|
||||
void vektor_circle_create_handles(VektorCircle* circle, V2** handleArr, size_t* count);
|
||||
void vektor_rectangle_create_handles(VektorRectangle* rectangle, V2** handleArr, size_t* count);
|
||||
void vektor_shape_create_handles(VektorShape* shape);
|
||||
|
||||
/* reconstructs the shape based on handles alone */
|
||||
void vektor_polyline_handles_updated(VektorPolyline* polyline, V2** handles, size_t* count);
|
||||
void vektor_polygon_handles_updated(VektorPolygon* polygon, V2** handles, size_t* count);
|
||||
void vektor_circle_handles_updated(VektorCircle* circle, V2** handles, size_t* count);
|
||||
void vektor_rectangle_handles_updated(VektorRectangle* rectangle, V2** handles, size_t* count);
|
||||
void vektor_shape_handles_updated(VektorShape* shape);
|
||||
|
||||
typedef struct {
|
||||
VektorShape* shapes;
|
||||
|
||||
@@ -48,16 +48,16 @@ static inline double vec2_cross(const V2 a, const V2 b) {
|
||||
return a.x * b.y - a.y * b.x;
|
||||
}
|
||||
|
||||
static inline double vec2_norm(const V2 v) {
|
||||
static inline double vec2_length(const V2 v) {
|
||||
return sqrt(v.x * v.x + v.y * v.y);
|
||||
}
|
||||
|
||||
static inline double vec2_quadrance(const V2 v) {
|
||||
static inline double vec2_lengthsq(const V2 v) {
|
||||
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_length(v));
|
||||
}
|
||||
|
||||
#endif // VECTOR_H_
|
||||
|
||||
@@ -188,7 +188,7 @@ static gboolean render(GtkGLArea* a, GdkGLContext* ctx,
|
||||
glUniform1f(shader_selection_uTimeLoc, time);
|
||||
glUniform2f(shader_selection_uMinLoc, bbox.min.x, bbox.min.y);
|
||||
glUniform2f(shader_selection_uMaxLoc, bbox.max.x, bbox.max.y);
|
||||
glUniform4f(shader_selection_uC1Loc, 0, 0, 0, 1);
|
||||
glUniform4f(shader_selection_uC1Loc, 0, 0, 0, 0);
|
||||
glUniform4f(shader_selection_uC2Loc, 0.46, 0.46, 1, 1);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, shape_vertex_count,
|
||||
|
||||
Reference in New Issue
Block a user