Compare commits
3 Commits
7bc94d3a96
...
e7dc799f54
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e7dc799f54 | ||
|
|
5e883e2d27 | ||
|
|
09b84a2aa8 |
@@ -61,8 +61,7 @@ static void appstate_on_color_change(VektorColorWheel* wheel,
|
|||||||
gtk_editable_set_text(GTK_EDITABLE(appstate->widgetState->sidepanelEntryB),
|
gtk_editable_set_text(GTK_EDITABLE(appstate->widgetState->sidepanelEntryB),
|
||||||
str_b);
|
str_b);
|
||||||
|
|
||||||
/*gtk_gl_area_queue_render(
|
vektor_canvas_geometry_changed(appstate->renderInfo);
|
||||||
GTK_GL_AREA(appstate->widgetState->workspaceCanvas));*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void appstate_on_entry_update(GtkEntry* entry, gpointer user_data) {
|
static void appstate_on_entry_update(GtkEntry* entry, gpointer user_data) {
|
||||||
@@ -96,7 +95,11 @@ static void canvas_onclick(GtkGestureClick* gesture, int n_press, double x,
|
|||||||
vektor_appstate_canvas_click(state, normalized_coords.x,
|
vektor_appstate_canvas_click(state, normalized_coords.x,
|
||||||
normalized_coords.y);
|
normalized_coords.y);
|
||||||
|
|
||||||
// gtk_gl_area_queue_render(GTK_GL_AREA(widget));
|
// technically there are cases when a click would not result in change of the geometry
|
||||||
|
// but this is more concise then writing it inside that function
|
||||||
|
// a bunch of times and burder future click dispatches with
|
||||||
|
// handling this signal
|
||||||
|
vektor_canvas_geometry_changed(state->renderInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vektor_appstate_canvas_click(VektorAppState* state, double x, double y) {
|
void vektor_appstate_canvas_click(VektorAppState* state, double x, double y) {
|
||||||
@@ -253,6 +256,7 @@ void vektor_appstate_canvas_drag_begin(GtkGestureDrag* gesture, gdouble x,
|
|||||||
if(vektor_bbox_isinside(bbox, position)) {
|
if(vektor_bbox_isinside(bbox, position)) {
|
||||||
// clicked inside handle
|
// clicked inside handle
|
||||||
state->heldHandleIndex = i;
|
state->heldHandleIndex = i;
|
||||||
|
vektor_canvas_geometry_changed(state->renderInfo);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -281,7 +285,8 @@ void vektor_appstate_canvas_drag_update(GtkGestureDrag* gesture, gdouble x,
|
|||||||
// drag handle if selected
|
// drag handle if selected
|
||||||
if(state->selectedShape != NULL && state->heldHandleIndex != -1) {
|
if(state->selectedShape != NULL && state->heldHandleIndex != -1) {
|
||||||
state->selectedShape->handles[state->heldHandleIndex] = position;
|
state->selectedShape->handles[state->heldHandleIndex] = position;
|
||||||
vektor_shape_handles_updated(state->selectedShape);
|
vektor_shape_handles_updated(state->selectedShape, &state->heldHandleIndex);
|
||||||
|
vektor_canvas_geometry_changed(state->renderInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,6 +298,7 @@ void vektor_appstate_canvas_drag_end(GtkGestureDrag* gesture, gdouble x,
|
|||||||
// if we were dragging a handle
|
// if we were dragging a handle
|
||||||
if(state->selectedShape != NULL && state->heldHandleIndex != -1) {
|
if(state->selectedShape != NULL && state->heldHandleIndex != -1) {
|
||||||
state->heldHandleIndex = -1; // ...then remove handle drag flag
|
state->heldHandleIndex = -1; // ...then remove handle drag flag
|
||||||
|
vektor_canvas_geometry_changed(state->renderInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ VektorBBox vektor_shape_get_handle_bbox(V2 handle) {
|
|||||||
// ------ PRIMITIVE HANDLES UPDATING ------
|
// ------ PRIMITIVE HANDLES UPDATING ------
|
||||||
|
|
||||||
void vektor_polyline_handles_updated(VektorPolyline* polyline, V2** handles,
|
void vektor_polyline_handles_updated(VektorPolyline* polyline, V2** handles,
|
||||||
size_t* count) {
|
size_t* count, int* heldHandleIndex) {
|
||||||
if (*count != polyline->count) {
|
if (*count != polyline->count) {
|
||||||
g_warning("handle count & point count mismatch in polyline");
|
g_warning("handle count & point count mismatch in polyline");
|
||||||
return;
|
return;
|
||||||
@@ -267,7 +267,7 @@ void vektor_polyline_handles_updated(VektorPolyline* polyline, V2** handles,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void vektor_polygon_handles_updated(VektorPolygon* polygon, V2** handles,
|
void vektor_polygon_handles_updated(VektorPolygon* polygon, V2** handles,
|
||||||
size_t* count) {
|
size_t* count, int* heldHandleIndex) {
|
||||||
if (*count != polygon->count) {
|
if (*count != polygon->count) {
|
||||||
g_warning("handle count & point count mismatch in polygon");
|
g_warning("handle count & point count mismatch in polygon");
|
||||||
return;
|
return;
|
||||||
@@ -278,74 +278,140 @@ void vektor_polygon_handles_updated(VektorPolygon* polygon, V2** handles,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void vektor_circle_handles_updated(VektorCircle* circle, V2** handles,
|
void vektor_circle_handles_updated(VektorCircle* circle, V2** handles,
|
||||||
size_t* count) {
|
size_t* count, int* heldHandleIndex) {
|
||||||
if (*count != 2) {
|
if (*count != 2) {
|
||||||
g_warning("unexpected circle handle count (%zu)", *count);
|
g_warning("unexpected circle handle count (%zu)", *count);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(*heldHandleIndex == 0) { // dragging center
|
||||||
|
V2 translation = vec2_sub((*handles)[0], circle->center);
|
||||||
circle->center = (*handles)[0];
|
circle->center = (*handles)[0];
|
||||||
|
(*handles)[1] = vec2_add(translation, (*handles)[1]);
|
||||||
|
} else {
|
||||||
circle->radius = vec2_length(vec2_sub((*handles)[0], (*handles)[1]));
|
circle->radius = vec2_length(vec2_sub((*handles)[0], (*handles)[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vektor_rectangle_handles_updated(VektorRectangle* rectangle, V2** handles,
|
// this shi is big because it dynamically handles handle remapping when
|
||||||
size_t* count) {
|
// rectangle enters an invalid state (end < start)
|
||||||
|
// creating the illusion of an invertable rect, while also keeping it
|
||||||
|
// valid at all times
|
||||||
|
void vektor_rectangle_handles_updated(VektorRectangle* rectangle, V2** handles, size_t* count, int* heldHandleIndex) {
|
||||||
if (*count != 5) {
|
if (*count != 5) {
|
||||||
g_warning("unexpected rectangle handle count (%zu)", *count);
|
g_warning("unexpected rectangle handle count (%zu)", *count);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get rectangle center
|
V2 start = rectangle->start;
|
||||||
V2 halfdist = vec2_scale(vec2_sub(rectangle->end, rectangle->start), 0.5f);
|
V2 end = rectangle->end;
|
||||||
V2 rectcenter = vec2_add(rectangle->start, halfdist);
|
|
||||||
|
|
||||||
// center according to handles
|
switch (*heldHandleIndex)
|
||||||
V2 center = (*handles)[0];
|
{
|
||||||
|
case 0: // center drag
|
||||||
|
{
|
||||||
|
V2 oldCenter = vec2_scale(vec2_add(start, end), 0.5f);
|
||||||
|
V2 newCenter = (*handles)[0];
|
||||||
|
|
||||||
if (vec2_equals(center, rectcenter)) { // corner handles were changed
|
V2 translation = vec2_sub(newCenter, oldCenter);
|
||||||
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)));
|
start = vec2_add(start, translation);
|
||||||
float min_y = fminf(p1.y, fminf(p2.y, fminf(p3.y, p4.y)));
|
end = vec2_add(end, translation);
|
||||||
float max_x = fmaxf(p1.x, fmaxf(p2.x, fmaxf(p3.x, p4.x)));
|
break;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 1: // top-left
|
||||||
|
start.x = (*handles)[1].x;
|
||||||
|
end.y = (*handles)[1].y;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: // top-right
|
||||||
|
end.x = (*handles)[2].x;
|
||||||
|
end.y = (*handles)[2].y;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: // bottom-left
|
||||||
|
start.x = (*handles)[3].x;
|
||||||
|
start.y = (*handles)[3].y;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4: // bottom-right
|
||||||
|
end.x = (*handles)[4].x;
|
||||||
|
start.y = (*handles)[4].y;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store raw values before normalization
|
||||||
|
float raw_min_x = start.x;
|
||||||
|
float raw_max_x = end.x;
|
||||||
|
float raw_min_y = start.y;
|
||||||
|
float raw_max_y = end.y;
|
||||||
|
|
||||||
|
// Normalize rectangle
|
||||||
|
float min_x = fminf(start.x, end.x);
|
||||||
|
float max_x = fmaxf(start.x, end.x);
|
||||||
|
float min_y = fminf(start.y, end.y);
|
||||||
|
float max_y = fmaxf(start.y, end.y);
|
||||||
|
|
||||||
|
bool flipX = raw_min_x > raw_max_x;
|
||||||
|
bool flipY = raw_min_y > raw_max_y;
|
||||||
|
|
||||||
|
// Remap handle if we crossed axes
|
||||||
|
if (*heldHandleIndex != 0)
|
||||||
|
{
|
||||||
|
if (flipX) {
|
||||||
|
switch (*heldHandleIndex) {
|
||||||
|
case 1: *heldHandleIndex = 2; break;
|
||||||
|
case 2: *heldHandleIndex = 1; break;
|
||||||
|
case 3: *heldHandleIndex = 4; break;
|
||||||
|
case 4: *heldHandleIndex = 3; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flipY) {
|
||||||
|
switch (*heldHandleIndex) {
|
||||||
|
case 1: *heldHandleIndex = 3; break;
|
||||||
|
case 3: *heldHandleIndex = 1; break;
|
||||||
|
case 2: *heldHandleIndex = 4; break;
|
||||||
|
case 4: *heldHandleIndex = 2; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VektorRectangle properRect = {
|
||||||
|
.start = {min_x, min_y},
|
||||||
|
.end = {max_x, max_y}
|
||||||
|
};
|
||||||
|
|
||||||
|
vektor_rectangle_set_start(rectangle, properRect.start);
|
||||||
|
vektor_rectangle_set_end(rectangle, properRect.end);
|
||||||
|
|
||||||
|
// regenerate handle positions
|
||||||
|
vektor_rectangle_create_handles(&properRect, handles, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vektor_shape_handles_updated(VektorShape* shape) {
|
void vektor_shape_handles_updated(VektorShape* shape, int* heldHandleIndex) {
|
||||||
switch (shape->primitive.kind) {
|
switch (shape->primitive.kind) {
|
||||||
case VEKTOR_POLYLINE:
|
case VEKTOR_POLYLINE:
|
||||||
vektor_polyline_handles_updated(shape->primitive.polyline,
|
vektor_polyline_handles_updated(shape->primitive.polyline,
|
||||||
&shape->handles, &shape->handleCount);
|
&shape->handles, &shape->handleCount, heldHandleIndex);
|
||||||
break;
|
break;
|
||||||
case VEKTOR_POLYGON:
|
case VEKTOR_POLYGON:
|
||||||
vektor_polygon_handles_updated(shape->primitive.polygon,
|
vektor_polygon_handles_updated(shape->primitive.polygon,
|
||||||
&shape->handles, &shape->handleCount);
|
&shape->handles, &shape->handleCount, heldHandleIndex);
|
||||||
break;
|
break;
|
||||||
case VEKTOR_CIRCLE:
|
case VEKTOR_CIRCLE:
|
||||||
vektor_circle_handles_updated(&shape->primitive.circle, &shape->handles,
|
vektor_circle_handles_updated(&shape->primitive.circle, &shape->handles,
|
||||||
&shape->handleCount);
|
&shape->handleCount, heldHandleIndex);
|
||||||
break;
|
break;
|
||||||
case VEKTOR_RECTANGLE:
|
case VEKTOR_RECTANGLE:
|
||||||
vektor_rectangle_handles_updated(&shape->primitive.rectangle,
|
vektor_rectangle_handles_updated(&shape->primitive.rectangle,
|
||||||
&shape->handles, &shape->handleCount);
|
&shape->handles, &shape->handleCount, heldHandleIndex);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,14 +115,14 @@ VektorBBox vektor_shape_get_handle_bbox(V2 handle);
|
|||||||
|
|
||||||
/* reconstructs the shape based on handles alone */
|
/* reconstructs the shape based on handles alone */
|
||||||
void vektor_polyline_handles_updated(VektorPolyline* polyline, V2** handles,
|
void vektor_polyline_handles_updated(VektorPolyline* polyline, V2** handles,
|
||||||
size_t* count);
|
size_t* count, int* heldHandleIndex);
|
||||||
void vektor_polygon_handles_updated(VektorPolygon* polygon, V2** handles,
|
void vektor_polygon_handles_updated(VektorPolygon* polygon, V2** handles,
|
||||||
size_t* count);
|
size_t* count, int* heldHandleIndex);
|
||||||
void vektor_circle_handles_updated(VektorCircle* circle, V2** handles,
|
void vektor_circle_handles_updated(VektorCircle* circle, V2** handles,
|
||||||
size_t* count);
|
size_t* count, int* heldHandleIndex);
|
||||||
void vektor_rectangle_handles_updated(VektorRectangle* rectangle, V2** handles,
|
void vektor_rectangle_handles_updated(VektorRectangle* rectangle, V2** handles,
|
||||||
size_t* count);
|
size_t* count, int* heldHandleIndex);
|
||||||
void vektor_shape_handles_updated(VektorShape* shape);
|
void vektor_shape_handles_updated(VektorShape* shape, int* heldHandleIndex);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
VektorShape* shapes;
|
VektorShape* shapes;
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ static GLuint shader_selection_uMaxLoc;
|
|||||||
|
|
||||||
static GLuint vao;
|
static GLuint vao;
|
||||||
VertexBuffer vb;
|
VertexBuffer vb;
|
||||||
|
static size_t shape_vertex_count = 0;
|
||||||
|
|
||||||
static GLuint compile_shader(GLenum type, const char* src) {
|
static GLuint compile_shader(GLenum type, const char* src) {
|
||||||
GLuint shader = glCreateShader(type);
|
GLuint shader = glCreateShader(type);
|
||||||
@@ -135,13 +136,11 @@ static void init_geometry(void) {
|
|||||||
|
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
}
|
}
|
||||||
static gboolean render(GtkGLArea* a, GdkGLContext* ctx,
|
|
||||||
VektorCanvasRenderInfo* renderInfo) {
|
|
||||||
vb.count = 0;
|
|
||||||
|
|
||||||
|
void vektor_canvas_geometry_changed(VektorCanvasRenderInfo* renderInfo) {
|
||||||
|
vb.count = 0;
|
||||||
vektor_rasterize(&vb, renderInfo->shapes, renderInfo->zoom);
|
vektor_rasterize(&vb, renderInfo->shapes, renderInfo->zoom);
|
||||||
size_t shape_vertex_count =
|
shape_vertex_count = vb.count;
|
||||||
vb.count; // remember how many vertices belong to shapes
|
|
||||||
|
|
||||||
if (renderInfo->selectedShape != NULL &&
|
if (renderInfo->selectedShape != NULL &&
|
||||||
*(renderInfo->selectedShape) != NULL) {
|
*(renderInfo->selectedShape) != NULL) {
|
||||||
@@ -166,6 +165,13 @@ static gboolean render(GtkGLArea* a, GdkGLContext* ctx,
|
|||||||
vektor_vb_add_quad(&vb, bbox.min, bbox.max,
|
vektor_vb_add_quad(&vb, bbox.min, bbox.max,
|
||||||
vektor_color_new(255, 255, 255, 255));
|
vektor_color_new(255, 255, 255, 255));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean render(GtkGLArea* a, GdkGLContext* ctx,
|
||||||
|
VektorCanvasRenderInfo* renderInfo) {
|
||||||
|
//vektor_canvas_geometry_changed(renderInfo);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, vb.count * sizeof(Vertex), vb.vertices,
|
glBufferData(GL_ARRAY_BUFFER, vb.count * sizeof(Vertex), vb.vertices,
|
||||||
GL_STATIC_DRAW);
|
GL_STATIC_DRAW);
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ typedef struct VektorCanvasRenderInfo {
|
|||||||
|
|
||||||
void vektor_canvas_init(VektorWidgetState* state, VektorCanvas* canvasOut,
|
void vektor_canvas_init(VektorWidgetState* state, VektorCanvas* canvasOut,
|
||||||
VektorCanvasRenderInfo* renderInfo);
|
VektorCanvasRenderInfo* renderInfo);
|
||||||
|
void vektor_canvas_geometry_changed(VektorCanvasRenderInfo* renderInfo);
|
||||||
// void vektor_canvas_update(VektorCanvas* canvas);
|
// void vektor_canvas_update(VektorCanvas* canvas);
|
||||||
// void vektor_canvas_fill(VektorCanvas* canvas, VektorColor color);
|
// void vektor_canvas_fill(VektorCanvas* canvas, VektorColor color);
|
||||||
// void vektor_canvas_drawfrom(VektorFramebuffer* fb, VektorCanvas* canvas);
|
// void vektor_canvas_drawfrom(VektorFramebuffer* fb, VektorCanvas* canvas);
|
||||||
|
|||||||
Reference in New Issue
Block a user