Merge branch 'main' of https://bundleofsticks.store/git/Frox/Vektor
This commit is contained in:
@@ -5,6 +5,7 @@ in vec2 vPos;
|
||||
out vec4 FragColor;
|
||||
|
||||
uniform float uTime;
|
||||
uniform float uScale;
|
||||
uniform vec4 uColor1;
|
||||
uniform vec4 uColor2;
|
||||
uniform vec2 uMin;
|
||||
@@ -12,7 +13,7 @@ uniform vec2 uMax;
|
||||
|
||||
void main()
|
||||
{
|
||||
float borderWidth = 0.008;
|
||||
float borderWidth = 0.008 / uScale;
|
||||
|
||||
|
||||
float distX = min(vPos.x - uMin.x, uMax.x - vPos.x);
|
||||
|
||||
@@ -96,9 +96,9 @@ static void canvas_onclick(GtkGestureClick* gesture, int n_press, double x,
|
||||
vektor_appstate_canvas_click(state, normalized_coords.x,
|
||||
normalized_coords.y);
|
||||
|
||||
// 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
|
||||
// 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);
|
||||
}
|
||||
@@ -243,10 +243,9 @@ void vektor_appstate_canvas_drag_begin(GtkGestureDrag* gesture, gdouble x,
|
||||
int widget_w = gtk_widget_get_width(widget);
|
||||
int widget_h = gtk_widget_get_height(widget);
|
||||
|
||||
V2 position =
|
||||
(V2){(2 * (x / widget_w)) - 1, 1 - (2 * (y / widget_h))};
|
||||
position =
|
||||
m33_transform(m33_inverse(state->renderInfo->canvasMat), (V2){position.x, position.y});
|
||||
V2 position = (V2){(2 * (x / widget_w)) - 1, 1 - (2 * (y / widget_h))};
|
||||
position = m33_transform(m33_inverse(state->renderInfo->canvasMat),
|
||||
(V2){position.x, position.y});
|
||||
|
||||
if(state->selectedShape != NULL) {
|
||||
VektorShapeNode* selectedShape = state->selectedShape;
|
||||
@@ -262,7 +261,6 @@ void vektor_appstate_canvas_drag_begin(GtkGestureDrag* gesture, gdouble x,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,8 +281,8 @@ void vektor_appstate_canvas_drag_update(GtkGestureDrag* gesture, gdouble x,
|
||||
|
||||
V2 position = (V2){(2 * ((x + start_x) / widget_w)) - 1,
|
||||
1 - (2 * ((y + start_y) / widget_h))};
|
||||
position =
|
||||
m33_transform(m33_inverse(state->renderInfo->canvasMat), (V2){position.x, position.y});
|
||||
position = m33_transform(m33_inverse(state->renderInfo->canvasMat),
|
||||
(V2){position.x, position.y});
|
||||
|
||||
// drag handle if selected
|
||||
if(state->selectedShape != NULL && state->heldHandleIndex != -1) {
|
||||
@@ -300,7 +298,7 @@ void vektor_appstate_canvas_drag_end(GtkGestureDrag* gesture, gdouble x,
|
||||
VektorAppState* state = (VektorAppState*)user_data;
|
||||
|
||||
// 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
|
||||
vektor_canvas_geometry_changed(state->renderInfo);
|
||||
}
|
||||
|
||||
@@ -238,7 +238,6 @@ void vektor_shape_create_handles(VektorShape* shape) {
|
||||
|
||||
// ------ AUXILIARY HANDLE METHODS ------
|
||||
|
||||
|
||||
void vektor_shape_add_handle(VektorShape* shape, V2 handle) {
|
||||
// could be optimised with capacity property
|
||||
// but this function is only called when adding new
|
||||
@@ -284,22 +283,21 @@ void vektor_circle_handles_updated(VektorCircle* circle, V2** handles,
|
||||
return;
|
||||
}
|
||||
|
||||
if(*heldHandleIndex == 0) { // dragging center
|
||||
if (*heldHandleIndex == 0) { // dragging center
|
||||
V2 translation = vec2_sub((*handles)[0], circle->center);
|
||||
circle->center = (*handles)[0];
|
||||
(*handles)[1] = vec2_add(translation, (*handles)[1]);
|
||||
} else {
|
||||
circle->radius = vec2_length(vec2_sub((*handles)[0], (*handles)[1]));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// this shi is big because it dynamically handles handle remapping when
|
||||
// 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) {
|
||||
void vektor_rectangle_handles_updated(VektorRectangle* rectangle, V2** handles,
|
||||
size_t* count, int* heldHandleIndex) {
|
||||
if (*count != 5) {
|
||||
g_warning("unexpected rectangle handle count (%zu)", *count);
|
||||
return;
|
||||
@@ -308,8 +306,7 @@ void vektor_rectangle_handles_updated(VektorRectangle* rectangle, V2** handles,
|
||||
V2 start = rectangle->start;
|
||||
V2 end = rectangle->end;
|
||||
|
||||
switch (*heldHandleIndex)
|
||||
{
|
||||
switch (*heldHandleIndex) {
|
||||
case 0: // center drag
|
||||
{
|
||||
V2 oldCenter = vec2_scale(vec2_add(start, end), 0.5f);
|
||||
@@ -362,31 +359,44 @@ void vektor_rectangle_handles_updated(VektorRectangle* rectangle, V2** handles,
|
||||
bool flipY = raw_min_y > raw_max_y;
|
||||
|
||||
// Remap handle if we crossed axes
|
||||
if (*heldHandleIndex != 0)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
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}
|
||||
};
|
||||
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);
|
||||
@@ -399,11 +409,13 @@ void vektor_shape_handles_updated(VektorShape* shape, int* heldHandleIndex) {
|
||||
switch (shape->primitive.kind) {
|
||||
case VEKTOR_POLYLINE:
|
||||
vektor_polyline_handles_updated(shape->primitive.polyline,
|
||||
&shape->handles, &shape->handleCount, heldHandleIndex);
|
||||
&shape->handles, &shape->handleCount,
|
||||
heldHandleIndex);
|
||||
break;
|
||||
case VEKTOR_POLYGON:
|
||||
vektor_polygon_handles_updated(shape->primitive.polygon,
|
||||
&shape->handles, &shape->handleCount, heldHandleIndex);
|
||||
&shape->handles, &shape->handleCount,
|
||||
heldHandleIndex);
|
||||
break;
|
||||
case VEKTOR_CIRCLE:
|
||||
vektor_circle_handles_updated(&shape->primitive.circle, &shape->handles,
|
||||
@@ -411,7 +423,8 @@ void vektor_shape_handles_updated(VektorShape* shape, int* heldHandleIndex) {
|
||||
break;
|
||||
case VEKTOR_RECTANGLE:
|
||||
vektor_rectangle_handles_updated(&shape->primitive.rectangle,
|
||||
&shape->handles, &shape->handleCount, heldHandleIndex);
|
||||
&shape->handles, &shape->handleCount,
|
||||
heldHandleIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +109,6 @@ void vektor_rectangle_create_handles(VektorRectangle* rectangle, V2** handleArr,
|
||||
size_t* count);
|
||||
void vektor_shape_create_handles(VektorShape* shape);
|
||||
|
||||
|
||||
void vektor_shape_add_handle(VektorShape* shape, V2 handle);
|
||||
VektorBBox vektor_shape_get_handle_bbox(V2 handle);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "raster.h"
|
||||
#include "epoxy/gl.h"
|
||||
#include "glib.h"
|
||||
#include "primitives.h"
|
||||
#include "src/core/matrix.h"
|
||||
#include "src/core/modifier.h"
|
||||
@@ -39,8 +40,8 @@ void vektor_polygon_tessellate(EdgeBuffer* buffer, VektorPolygon* polygon,
|
||||
|
||||
void vektor_circle_tessellate(EdgeBuffer* buffer, VektorCircle* circle,
|
||||
size_t j, double scale) {
|
||||
double err = 0.000025;
|
||||
size_t res = PI * sqrt((scale * circle->radius) / (2 * err));
|
||||
double err = 0.0025;
|
||||
size_t res = MIN(PI * sqrt((scale * circle->radius) / (2 * err)), 20);
|
||||
for (size_t i = 0; i < res; i++) {
|
||||
double theta1 = (2 * PI * i) / res;
|
||||
double theta2 = (2 * PI * (i + 1)) / res;
|
||||
@@ -69,27 +70,33 @@ void vektor_rectangle_tessellate(EdgeBuffer* buffer, VektorRectangle* rct,
|
||||
vektor_edgebuffer_add_edge(buffer, left);
|
||||
}
|
||||
|
||||
void vektor_vb_rasterize(VertexBuffer* vb, VektorShapeNodeBuffer* nodes,
|
||||
void vektor_vb_rasterize(VertexBuffer* vb, VektorShapeNodeBuffer* nodebuf,
|
||||
double scale) {
|
||||
for (size_t i = 0; i < nodebuf->count; i++) {
|
||||
EdgeBuffer edges = {0};
|
||||
for (size_t i = 0; i < nodes->count; i++) {
|
||||
VektorPrimitive* p = &nodes->nodes[i].base.primitive;
|
||||
VektorPrimitive* p = &nodebuf->nodes[i].base.primitive;
|
||||
VektorStyle style = nodebuf->nodes[i].base.style;
|
||||
M33 transform = nodebuf->nodes[i].base.transform;
|
||||
|
||||
switch (p->kind) {
|
||||
case VEKTOR_POLYLINE:
|
||||
vektor_polyline_tessellate(&edges, p->polyline, i, scale);
|
||||
vektor_edges_to_triangles(vb, &edges, &transform, style, FALSE);
|
||||
break;
|
||||
|
||||
case VEKTOR_POLYGON:
|
||||
vektor_polygon_tessellate(&edges, p->polygon, i, scale);
|
||||
vektor_edges_to_triangles(vb, &edges, &transform, style, TRUE);
|
||||
break;
|
||||
|
||||
case VEKTOR_CIRCLE:
|
||||
vektor_circle_tessellate(&edges, &p->circle, i, scale);
|
||||
vektor_edges_to_triangles(vb, &edges, &transform, style, TRUE);
|
||||
break;
|
||||
|
||||
case VEKTOR_RECTANGLE:
|
||||
vektor_rectangle_tessellate(&edges, &p->rectangle, i, scale);
|
||||
vektor_edges_to_triangles(vb, &edges, &transform, style, TRUE);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -133,37 +140,91 @@ void vektor_vb_add_quad(VertexBuffer* vb, V2 a, V2 b, VektorColor color) {
|
||||
vektor_vb_add_triangle(vb, tl, br, tr, color);
|
||||
}
|
||||
|
||||
void vektor_edge_to_triangles(VertexBuffer* vb, Edge e,
|
||||
VektorShapeNodeBuffer* node_buffer) {
|
||||
float dx = e.p2.x - e.p1.x;
|
||||
float dy = e.p2.y - e.p1.y;
|
||||
float len = sqrtf(dx * dx + dy * dy);
|
||||
if (len == 0)
|
||||
return;
|
||||
Edge edge_transform(const Edge* e, const M33* t) {
|
||||
Edge out = *e;
|
||||
out.p1 = m33_transform(*t, e->p1);
|
||||
out.p2 = m33_transform(*t, e->p2);
|
||||
return out;
|
||||
}
|
||||
|
||||
float px =
|
||||
-dy / len * (node_buffer->nodes[e.shape_id].base.style.stroke_width / 2);
|
||||
float py =
|
||||
dx / len * (node_buffer->nodes[e.shape_id].base.style.stroke_width / 2);
|
||||
|
||||
V2 v0 = m33_transform(node_buffer->nodes[e.shape_id].base.transform,
|
||||
(V2){e.p1.x + px, e.p1.y + py});
|
||||
V2 v1 = m33_transform(node_buffer->nodes[e.shape_id].base.transform,
|
||||
(V2){e.p1.x - px, e.p1.y - py});
|
||||
V2 v2 = m33_transform(node_buffer->nodes[e.shape_id].base.transform,
|
||||
(V2){e.p2.x + px, e.p2.y + py});
|
||||
V2 v3 = m33_transform(node_buffer->nodes[e.shape_id].base.transform,
|
||||
(V2){e.p2.x - px, e.p2.y - py});
|
||||
|
||||
vektor_vb_add_triangle(vb, v0, v1, v2,
|
||||
node_buffer->nodes[e.shape_id].base.style.stroke_color);
|
||||
vektor_vb_add_triangle(vb, v2, v1, v3,
|
||||
node_buffer->nodes[e.shape_id].base.style.stroke_color);
|
||||
V2 line_intersection(V2 p, V2 r, V2 q, V2 s) {
|
||||
float t = vec2_cross(vec2_sub(q, p), s) / vec2_cross(r, s);
|
||||
return vec2_add(p, vec2_scale(r, t));
|
||||
}
|
||||
|
||||
void vektor_edges_to_triangles(VertexBuffer* vb, EdgeBuffer* edges,
|
||||
VektorShapeNodeBuffer* node_buffer) {
|
||||
M33* transform, VektorStyle style, bool closed) {
|
||||
if (!edges || edges->count < 1)
|
||||
return;
|
||||
|
||||
float hw = style.stroke_width * 0.5f;
|
||||
|
||||
for (size_t i = 0; i < edges->count; i++) {
|
||||
vektor_edge_to_triangles(vb, edges->edges[i], node_buffer);
|
||||
Edge e = edge_transform(&edges->edges[i], transform);
|
||||
|
||||
V2 d = vec2_normalize(vec2_sub(e.p2, e.p1));
|
||||
V2 n = vec2_perp(d);
|
||||
V2 off = vec2_scale(n, hw);
|
||||
|
||||
V2 v0 = vec2_add(e.p1, off);
|
||||
V2 v1 = vec2_sub(e.p1, off);
|
||||
V2 v2 = vec2_add(e.p2, off);
|
||||
V2 v3 = vec2_sub(e.p2, off);
|
||||
|
||||
vektor_vb_add_triangle(vb, v0, v1, v2, style.stroke_color);
|
||||
vektor_vb_add_triangle(vb, v2, v1, v3, style.stroke_color);
|
||||
}
|
||||
|
||||
size_t limit = closed ? edges->count : edges->count - 1;
|
||||
|
||||
for (size_t i = 0; i < limit; i++) {
|
||||
Edge e1 = edge_transform(&edges->edges[i], transform);
|
||||
Edge e2 =
|
||||
edge_transform(&edges->edges[(i + 1) % edges->count], transform);
|
||||
|
||||
V2 corner = e1.p2;
|
||||
|
||||
V2 d1 = vec2_normalize(vec2_sub(e1.p2, e1.p1));
|
||||
V2 d2 = vec2_normalize(vec2_sub(e2.p2, e2.p1));
|
||||
|
||||
V2 n1 = vec2_perp(d1);
|
||||
V2 n2 = vec2_perp(d2);
|
||||
|
||||
V2 off1 = vec2_scale(n1, hw);
|
||||
V2 off2 = vec2_scale(n2, hw);
|
||||
|
||||
V2 v10 = vec2_add(e1.p1, off1);
|
||||
V2 v11 = vec2_sub(e1.p1, off1);
|
||||
V2 v12 = vec2_add(e1.p2, off1);
|
||||
V2 v13 = vec2_sub(e1.p2, off1);
|
||||
|
||||
V2 v20 = vec2_add(e2.p1, off2);
|
||||
V2 v21 = vec2_sub(e2.p1, off2);
|
||||
V2 v22 = vec2_add(e2.p2, off2);
|
||||
V2 v23 = vec2_sub(e2.p2, off2);
|
||||
|
||||
V2 outer_miter = line_intersection(vec2_add(corner, off1), d1,
|
||||
vec2_add(corner, off2), d2);
|
||||
|
||||
V2 inner_miter = line_intersection(vec2_sub(corner, off1), d1,
|
||||
vec2_sub(corner, off2), d2);
|
||||
|
||||
V2 mo = vec2_sub(outer_miter, corner);
|
||||
V2 mi = vec2_sub(inner_miter, corner);
|
||||
|
||||
V2 vo1 = line_intersection(corner, vec2_normalize(vec2_perp(mo)),
|
||||
vec2_add(corner, off1), d1);
|
||||
V2 vo2 = line_intersection(corner,
|
||||
vec2_negate(vec2_normalize(vec2_perp(mo))),
|
||||
vec2_add(corner, off2), d2);
|
||||
|
||||
V2 vi1 = line_intersection(corner, vec2_normalize(vec2_perp(mi)),
|
||||
vec2_sub(corner, off1), d1);
|
||||
V2 vi2 = line_intersection(corner,
|
||||
vec2_negate(vec2_normalize(vec2_perp(mi))),
|
||||
vec2_sub(corner, off2), d2);
|
||||
|
||||
vektor_vb_add_triangle(vb, vo1, outer_miter, vo2, style.stroke_color);
|
||||
vektor_vb_add_triangle(vb, vi1, inner_miter, vi2, style.stroke_color);
|
||||
}
|
||||
}
|
||||
@@ -51,8 +51,8 @@ void vektor_vb_add_quad(VertexBuffer* vb, V2 v0, V2 v1, VektorColor color);
|
||||
void vektor_edge_to_triangles(VertexBuffer* vb, Edge e,
|
||||
VektorShapeNodeBuffer* node_buffer);
|
||||
void vektor_edges_to_triangles(VertexBuffer* vb, EdgeBuffer* edges,
|
||||
VektorShapeNodeBuffer* node_buffer) ;
|
||||
void vektor_vb_rasterize(VertexBuffer* vb, VektorShapeNodeBuffer* shapes,
|
||||
M33* transform, VektorStyle style, bool closed);
|
||||
void vektor_rasterize(VertexBuffer* vb, VektorShapeBuffer* shapes,
|
||||
double scale);
|
||||
|
||||
#endif // RASTER_H_
|
||||
|
||||
@@ -20,6 +20,10 @@ 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_perp(const V2 v) { return (V2){-v.y, v.x}; }
|
||||
|
||||
static inline V2 vec2_negate(const V2 v) { return (V2){-v.x, -v.y}; }
|
||||
|
||||
static inline V2 vec2_add(const V2 v1, const V2 v2) {
|
||||
return (V2){v1.x + v2.x, v1.y + v2.y};
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ static GLuint shader_standard_uProjMatrixLoc;
|
||||
|
||||
static GLuint shader_selection_uProjMatrixLoc;
|
||||
static GLuint shader_selection_uTimeLoc;
|
||||
static GLuint shader_selection_uScaleLoc;
|
||||
static GLuint shader_selection_uC1Loc;
|
||||
static GLuint shader_selection_uC2Loc;
|
||||
static GLuint shader_selection_uMinLoc;
|
||||
@@ -103,6 +104,8 @@ static void init_shader(void) {
|
||||
glGetUniformLocation(selection_shader_program, "uProjection");
|
||||
shader_selection_uTimeLoc =
|
||||
glGetUniformLocation(selection_shader_program, "uTime");
|
||||
shader_selection_uScaleLoc =
|
||||
glGetUniformLocation(selection_shader_program, "uScale");
|
||||
shader_selection_uC1Loc =
|
||||
glGetUniformLocation(selection_shader_program, "uColor1");
|
||||
shader_selection_uC2Loc =
|
||||
@@ -169,9 +172,7 @@ void vektor_canvas_geometry_changed(VektorCanvasRenderInfo* renderInfo) {
|
||||
|
||||
static gboolean render(GtkGLArea* a, GdkGLContext* ctx,
|
||||
VektorCanvasRenderInfo* renderInfo) {
|
||||
//vektor_canvas_geometry_changed(renderInfo);
|
||||
|
||||
|
||||
// vektor_canvas_geometry_changed(renderInfo);
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, vb.count * sizeof(Vertex), vb.vertices,
|
||||
GL_STATIC_DRAW);
|
||||
@@ -186,7 +187,7 @@ static gboolean render(GtkGLArea* a, GdkGLContext* ctx,
|
||||
|
||||
glBindVertexArray(vao);
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
@@ -207,6 +208,7 @@ static gboolean render(GtkGLArea* a, GdkGLContext* ctx,
|
||||
glUniformMatrix4fv(shader_selection_uProjMatrixLoc, 1, GL_FALSE,
|
||||
renderInfo->canvasTransform);
|
||||
glUniform1f(shader_selection_uTimeLoc, time);
|
||||
glUniform1f(shader_selection_uScaleLoc, renderInfo->zoom);
|
||||
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, 0);
|
||||
|
||||
Reference in New Issue
Block a user