aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Hanspeter Portner <dev@open-music-kontrollers.ch>2016-10-27 18:29:41 +0200
committerGravatar Hanspeter Portner <dev@open-music-kontrollers.ch>2016-10-27 18:29:41 +0200
commitb0a89a03a800bb023fa115d7129272e880984dc6 (patch)
tree73245291c17a6d12e6b398e8524ea349635dc04a
parent3de29e8fcccf0736767ce0938dbc28878ba7111f (diff)
downloadcanvas.lv2-b0a89a03a800bb023fa115d7129272e880984dc6.zip
canvas.lv2-b0a89a03a800bb023fa115d7129272e880984dc6.tar.gz
canvas.lv2-b0a89a03a800bb023fa115d7129272e880984dc6.tar.bz2
canvas.lv2-b0a89a03a800bb023fa115d7129272e880984dc6.tar.xz
prototype full canvas API.
-rw-r--r--.gitlab-ci.yml4
-rw-r--r--VERSION2
-rw-r--r--canvas.c141
-rw-r--r--canvas.h988
-rw-r--r--canvas_ui.c216
5 files changed, 1198 insertions, 153 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 7ce9838..dedfdba 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -61,8 +61,8 @@ x86_64-w64-mingw32:
i686-w64-mingw32:
<<: *universal_w64_definition
-#universal-apple-darwin:
-# <<: *universal_apple_definition
+universal-apple-darwin:
+ <<: *universal_apple_definition
pack:
<<: *variables_definition
diff --git a/VERSION b/VERSION
index 6980ac0..c0c8dd5 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.1.293
+0.1.295
diff --git a/canvas.c b/canvas.c
index cc3c311..4d06252 100644
--- a/canvas.c
+++ b/canvas.c
@@ -25,6 +25,8 @@
#include <cairo/cairo.h>
+#define MAX_GRAPH_BUF 0x10000
+
typedef struct _plughandle_t plughandle_t;
struct _plughandle_t {
@@ -37,6 +39,11 @@ struct _plughandle_t {
const LV2_Atom_Sequence *control;
LV2_Atom_Sequence *notify;
+ LV2_URID patch_Get;
+ LV2_URID patch_Set;
+ LV2_URID patch_property;
+ LV2_URID patch_value;
+
atomic_flag lock;
LV2_Inline_Display *queue_draw;
@@ -46,9 +53,11 @@ struct _plughandle_t {
cairo_t *ctx;
} cairo;
+ LV2_Canvas canvas;
+
union {
- LV2_Atom_Tuple tup;
- uint8_t buf [0x10000];
+ LV2_Atom_Tuple graph;
+ uint8_t buf [MAX_GRAPH_BUF];
};
};
@@ -105,16 +114,23 @@ instantiate(const LV2_Descriptor* descriptor, double rate,
return NULL;
}
+ handle->patch_Get = handle->map->map(handle->map->handle, LV2_PATCH__Get);
+ handle->patch_Set = handle->map->map(handle->map->handle, LV2_PATCH__Set);
+ handle->patch_property = handle->map->map(handle->map->handle, LV2_PATCH__property);
+ handle->patch_value = handle->map->map(handle->map->handle, LV2_PATCH__value);
+
if(handle->log)
lv2_log_logger_init(&handle->logger, handle->map, handle->log);
lv2_atom_forge_init(&handle->forge, handle->map);
- handle->tup.atom.size = 0;
- handle->tup.atom.type = handle->forge.Tuple;
+ handle->graph.atom.size = 0;
+ handle->graph.atom.type = handle->forge.Tuple;
_init_lock(&handle->lock);
+ lv2_canvas_init(&handle->canvas, handle->map);
+
return handle;
}
@@ -141,18 +157,83 @@ run(LV2_Handle instance, uint32_t nsamples)
{
plughandle_t *handle = instance;
- const uint32_t sz = lv2_atom_total_size(&handle->control->atom);
- memcpy(handle->notify, handle->control, sz);
+ const uint32_t capacity = handle->notify->atom.size;
+ lv2_atom_forge_set_buffer(&handle->forge, (uint8_t *)handle->notify, capacity);
+ LV2_Atom_Forge_Frame frame;
+ LV2_Atom_Forge_Ref ref = lv2_atom_forge_sequence_head(&handle->forge, &frame, 0);
- if(_try_lock(&handle->lock))
+ LV2_ATOM_SEQUENCE_FOREACH(handle->control, ev)
{
- //FIXME
+ const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body;
- _unlock_lock(&handle->lock);
-
- if(handle->queue_draw)
- handle->queue_draw->queue_draw(handle->queue_draw->handle);
+ if(lv2_atom_forge_is_object_type(&handle->forge, obj->atom.type))
+ {
+ if(obj->body.otype == handle->patch_Get)
+ {
+ const LV2_Atom_URID *property = NULL;
+
+ lv2_atom_object_get(obj, handle->patch_property, &property, 0);
+
+ if( property
+ && (property->atom.type == handle->forge.URID)
+ && (property->body == handle->canvas.urid.Canvas_graph) )
+ {
+ LV2_Atom_Forge_Frame obj_frame;
+ if(ref)
+ ref = lv2_atom_forge_frame_time(&handle->forge, ev->time.frames);
+ if(ref)
+ ref = lv2_atom_forge_object(&handle->forge, &obj_frame, 0, handle->patch_Set);
+ if(ref)
+ ref = lv2_atom_forge_key(&handle->forge, handle->patch_property);
+ if(ref)
+ ref = lv2_atom_forge_urid(&handle->forge, handle->canvas.urid.Canvas_graph);
+ if(ref)
+ ref = lv2_atom_forge_key(&handle->forge, handle->patch_value);
+ if(ref)
+ ref = lv2_atom_forge_write(&handle->forge, &handle->graph, lv2_atom_total_size(&handle->graph.atom));
+ if(ref)
+ lv2_atom_forge_pop(&handle->forge, &obj_frame);
+ }
+ }
+ else if(obj->body.otype == handle->patch_Set)
+ {
+ const LV2_Atom_URID *property = NULL;
+ const LV2_Atom_Tuple *graph = NULL;
+
+ lv2_atom_object_get(obj, handle->patch_property, &property,
+ handle->patch_value, &graph, 0);
+
+ if( property
+ && (property->atom.type == handle->forge.URID)
+ && (property->body == handle->canvas.urid.Canvas_graph)
+ && graph
+ && (graph->atom.type == handle->forge.Tuple) )
+ {
+ const uint32_t sz = lv2_atom_total_size(&graph->atom);
+
+ if( (sz <= MAX_GRAPH_BUF) && _try_lock(&handle->lock))
+ {
+ memcpy(&handle->graph, graph, sz);
+
+ _unlock_lock(&handle->lock);
+
+ if(handle->queue_draw)
+ handle->queue_draw->queue_draw(handle->queue_draw->handle);
+ }
+
+ if(ref)
+ ref = lv2_atom_forge_frame_time(&handle->forge, ev->time.frames);
+ if(ref)
+ ref = lv2_atom_forge_write(&handle->forge, obj, lv2_atom_total_size(&obj->atom));
+ }
+ }
+ }
}
+
+ if(ref)
+ lv2_atom_forge_pop(&handle->forge, &frame);
+ else
+ lv2_atom_sequence_clear(handle->notify);
}
static inline LV2_Inline_Display_Image_Surface *
@@ -225,44 +306,12 @@ _render(LV2_Handle instance, uint32_t w, uint32_t h)
if(!surf)
return NULL;
- // save state
- cairo_save(handle->cairo.ctx);
-
- // clear surface
- cairo_set_operator(handle->cairo.ctx, CAIRO_OPERATOR_CLEAR);
- cairo_paint(handle->cairo.ctx);
-
- // default attributes
- cairo_set_operator(handle->cairo.ctx, CAIRO_OPERATOR_SOURCE);
- cairo_set_font_size(handle->cairo.ctx, 0.1);
- cairo_set_line_width(handle->cairo.ctx, 0.01);
- cairo_set_source_rgba(handle->cairo.ctx, 1.0, 1.0, 1.0, 1.0);
-
_spin_lock(&handle->lock);
- LV2_ATOM_TUPLE_FOREACH(&handle->tup, itm)
- {
- if(lv2_atom_forge_is_object_type(&handle->forge, itm->type))
- ;//_render_cmd(handle, handle->cairo.ctx, (const LV2_Atom_Object *)itm);
- }
+ lv2_canvas_render(&handle->canvas, handle->cairo.ctx, &handle->forge, &handle->graph);
_unlock_lock(&handle->lock);
- //FIXME
- {
- cairo_translate(handle->cairo.ctx, 0.5, 0.5);
- cairo_rotate(handle->cairo.ctx, M_PI/4);
- cairo_rectangle(handle->cairo.ctx, -0.3, -0.3, 0.6, 0.6);
- cairo_set_source_rgba(handle->cairo.ctx, 0.8, 0.8, 0.0, 1.0);
- cairo_fill(handle->cairo.ctx);
- }
-
- // save state
- cairo_restore(handle->cairo.ctx);
-
- // flush
- cairo_surface_flush(handle->cairo.surface);
-
return surf;
}
@@ -294,7 +343,7 @@ extension_data(const char *uri)
}
const LV2_Descriptor canvas_canvas = {
- .URI = CANVAS_CANVAS_URI,
+ .URI = CANVAS_PREFIX"canvas",
.instantiate = instantiate,
.connect_port = connect_port,
.activate = NULL,
diff --git a/canvas.h b/canvas.h
index 85fb65c..4c196ab 100644
--- a/canvas.h
+++ b/canvas.h
@@ -22,15 +22,993 @@
#include "lv2/lv2plug.in/ns/ext/atom/forge.h"
#include "lv2/lv2plug.in/ns/ext/log/log.h"
#include "lv2/lv2plug.in/ns/ext/log/logger.h"
+#include "lv2/lv2plug.in/ns/ext/patch/patch.h"
#include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
-
+
+#include <cairo.h>
+
#define CANVAS_URI "http://open-music-kontrollers.ch/lv2/canvas"
+#define CANVAS_PREFIX CANVAS_URI"#"
+
+#define CANVAS__graph CANVAS_PREFIX"graph"
+#define CANVAS__body CANVAS_PREFIX"body"
+
+#define CANVAS__BeginPath CANVAS_PREFIX"BeginPath"
+#define CANVAS__ClosePath CANVAS_PREFIX"ClosePath"
+#define CANVAS__Arc CANVAS_PREFIX"Arc"
+#define CANVAS__CurveTo CANVAS_PREFIX"CurveTo"
+#define CANVAS__LineTo CANVAS_PREFIX"LineTo"
+#define CANVAS__MoveTo CANVAS_PREFIX"MoveTo"
+#define CANVAS__Rectangle CANVAS_PREFIX"Rectangle"
+#define CANVAS__Style CANVAS_PREFIX"Style"
+#define CANVAS__LineWidth CANVAS_PREFIX"LineWidth"
+#define CANVAS__LineDash CANVAS_PREFIX"LineDash"
+#define CANVAS__LineCap CANVAS_PREFIX"LineCap"
+#define CANVAS__LineJoin CANVAS_PREFIX"LineJoin"
+#define CANVAS__MiterLimit CANVAS_PREFIX"MiterLimig"
+#define CANVAS__Stroke CANVAS_PREFIX"Stroke"
+#define CANVAS__Fill CANVAS_PREFIX"Fill"
+#define CANVAS__Clip CANVAS_PREFIX"Clip"
+#define CANVAS__Save CANVAS_PREFIX"Save"
+#define CANVAS__Restore CANVAS_PREFIX"Restore"
+#define CANVAS__Translate CANVAS_PREFIX"Translate"
+#define CANVAS__Scale CANVAS_PREFIX"Scale"
+#define CANVAS__Rotate CANVAS_PREFIX"Rotate"
+#define CANVAS__Reset CANVAS_PREFIX"Reset"
+#define CANVAS__FontSize CANVAS_PREFIX"FontSize"
+#define CANVAS__FillText CANVAS_PREFIX"FillText"
+
+#define CANVAS__lineCapButt CANVAS_PREFIX"lineCapButt"
+#define CANVAS__lineCapRound CANVAS_PREFIX"lineCapRound"
+#define CANVAS__lineCapSquare CANVAS_PREFIX"lineCapSquare"
+
+#define CANVAS__lineJoinMiter CANVAS_PREFIX"lineJoinMiter"
+#define CANVAS__lineJoinRound CANVAS_PREFIX"lineJoinRound"
+#define CANVAS__lineJoinBevel CANVAS_PREFIX"lineJoinBevel"
+
+#define CANVAS_NUM_METHODS 24
+
+typedef struct _LV2_Canvas_URID LV2_Canvas_URID;
+typedef struct _LV2_Canvas_Meth LV2_Canvas_Meth;
+typedef struct _LV2_Canvas LV2_Canvas;
+typedef void (*LV2_Canvas_Func)(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body);
+
+struct _LV2_Canvas_URID {
+ LV2_URID Canvas_graph;
+ LV2_URID Canvas_body;
+
+ LV2_URID Canvas_BeginPath;
+ LV2_URID Canvas_ClosePath;
+ LV2_URID Canvas_Arc;
+ LV2_URID Canvas_CurveTo;
+ LV2_URID Canvas_LineTo;
+ LV2_URID Canvas_MoveTo;
+ LV2_URID Canvas_Rectangle;
+ LV2_URID Canvas_Style;
+ LV2_URID Canvas_LineWidth;
+ LV2_URID Canvas_LineDash;
+ LV2_URID Canvas_LineCap;
+ LV2_URID Canvas_LineJoin;
+ LV2_URID Canvas_MiterLimit;
+ LV2_URID Canvas_Stroke;
+ LV2_URID Canvas_Fill;
+ LV2_URID Canvas_Clip;
+ LV2_URID Canvas_Save;
+ LV2_URID Canvas_Restore;
+ LV2_URID Canvas_Translate;
+ LV2_URID Canvas_Scale;
+ LV2_URID Canvas_Rotate;
+ LV2_URID Canvas_Reset;
+ LV2_URID Canvas_FontSize;
+ LV2_URID Canvas_FillText;
+
+ LV2_URID Canvas_lineCapButt;
+ LV2_URID Canvas_lineCapRound;
+ LV2_URID Canvas_lineCapSquare;
+
+ LV2_URID Canvas_lineJoinMiter;
+ LV2_URID Canvas_lineJoinRound;
+ LV2_URID Canvas_lineJoinBevel;
+};
+
+struct _LV2_Canvas_Meth {
+ LV2_URID command;
+ LV2_Canvas_Func func;
+};
+
+struct _LV2_Canvas {
+ LV2_Canvas_URID urid;
+ LV2_Canvas_Meth methods [CANVAS_NUM_METHODS];
+};
+
+static inline const float *
+_lv2_canvas_get_float_vec(LV2_Atom_Forge *forge, const LV2_Atom *body, uint32_t N)
+{
+ const LV2_Atom_Vector *vec = (const LV2_Atom_Vector *)body;
+ const float *flt = LV2_ATOM_CONTENTS_CONST(LV2_Atom_Vector, vec);
+ const uint32_t n = (vec->atom.type == forge->Vector)
+ && (vec->body.child_type == forge->Float)
+ ? (vec->atom.size - sizeof(LV2_Atom_Vector_Body)) / vec->body.child_size
+ : 0;
+
+ return n == N ? flt : NULL;
+}
+
+static inline const void *
+_lv2_canvas_get_type(const LV2_Atom *body, LV2_URID type)
+{
+ const float *flt = &((const LV2_Atom_Float *)body)->body;
+
+ return body->type == type ? LV2_ATOM_BODY_CONST(body) : NULL;
+}
+
+static inline void
+lv2_canvas_render_beginPath(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ cairo_new_sub_path(ctx);
+}
+
+static inline void
+lv2_canvas_render_closePath(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ cairo_close_path(ctx);
+}
+
+static inline void
+lv2_canvas_render_arc(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ const float *v = _lv2_canvas_get_float_vec(forge, body, 5);
+
+ if(v)
+ cairo_arc(ctx, v[0], v[1], v[2], v[3], v[4]);
+}
+
+static inline void
+lv2_canvas_render_curveTo(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ const float *v = _lv2_canvas_get_float_vec(forge, body, 6);
+
+ if(v)
+ cairo_curve_to(ctx, v[0], v[1], v[2], v[3], v[4], v[5]);
+}
+
+static inline void
+lv2_canvas_render_lineTo(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ const float *v = _lv2_canvas_get_float_vec(forge, body, 2);
+
+ if(v)
+ cairo_line_to(ctx, v[0], v[1]);
+}
+
+static inline void
+lv2_canvas_render_moveTo(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ const float *v = _lv2_canvas_get_float_vec(forge, body, 2);
+
+ if(v)
+ cairo_move_to(ctx, v[0], v[1]);
+}
+
+static inline void
+lv2_canvas_render_rectangle(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ const float *v = _lv2_canvas_get_float_vec(forge, body, 4);
+
+ if(v)
+ cairo_rectangle(ctx, v[0], v[1], v[2], v[3]);
+}
+
+static inline void
+lv2_canvas_render_style(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ const int64_t *v = _lv2_canvas_get_type(body, forge->Long);
+
+ if(v)
+ cairo_set_source_rgba(ctx,
+ (float)((*v >> 16) & 0xff) / 0xff,
+ (float)((*v >> 8) & 0xff) / 0xff,
+ (float)((*v >> 0) & 0xff) / 0xff,
+ (float)((*v >> 24) & 0xff) / 0xff);
+}
+
+static inline void
+lv2_canvas_render_lineWidth(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ const float *v = _lv2_canvas_get_type(body, forge->Float);
+
+ if(v)
+ cairo_set_line_width(ctx, *v);
+}
+
+static inline void
+lv2_canvas_render_lineDash(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ const float *v = _lv2_canvas_get_float_vec(forge, body, 2);
+
+ if(v)
+ cairo_set_dash(ctx, (const double [2]){v[0], v[1]}, 2, 0);
+}
+
+static inline void
+lv2_canvas_render_lineCap(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ const LV2_URID *v = _lv2_canvas_get_type(body, forge->URID);
+
+ if(v)
+ {
+ cairo_line_cap_t cap = CAIRO_LINE_CAP_BUTT;
+ if(*v == urid->Canvas_lineCapButt)
+ cap = CAIRO_LINE_CAP_BUTT;
+ else if(*v == urid->Canvas_lineCapRound)
+ cap = CAIRO_LINE_CAP_ROUND;
+ else if(*v == urid->Canvas_lineCapRound)
+ cap = CAIRO_LINE_CAP_SQUARE;
+ cairo_set_line_cap(ctx, cap);
+ }
+}
+
+static inline void
+lv2_canvas_render_lineJoin(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ const LV2_URID *v = _lv2_canvas_get_type(body, forge->URID);
+
+ if(v)
+ {
+ cairo_line_join_t join = CAIRO_LINE_JOIN_MITER;
+ if(*v == urid->Canvas_lineJoinMiter)
+ join = CAIRO_LINE_JOIN_MITER;
+ else if(*v == urid->Canvas_lineJoinRound)
+ join = CAIRO_LINE_JOIN_ROUND;
+ else if(*v == urid->Canvas_lineJoinBevel)
+ join = CAIRO_LINE_JOIN_BEVEL;
+ cairo_set_line_join(ctx, join);
+ }
+}
+
+static inline void
+lv2_canvas_render_miterLimit(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ const float *v = _lv2_canvas_get_type(body, forge->Float);
+
+ if(v)
+ cairo_set_miter_limit(ctx, *v);
+}
+
+static inline void
+lv2_canvas_render_stroke(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ cairo_stroke(ctx);
+}
+
+static inline void
+lv2_canvas_render_fill(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ cairo_fill(ctx);
+}
+
+static inline void
+lv2_canvas_render_clip(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ cairo_clip(ctx);
+}
+
+static inline void
+lv2_canvas_render_save(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ cairo_save(ctx);
+}
+
+static inline void
+lv2_canvas_render_restore(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ cairo_restore(ctx);
+}
+
+static inline void
+lv2_canvas_render_translate(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ const float *v = _lv2_canvas_get_float_vec(forge, body, 2);
+
+ if(v)
+ cairo_translate(ctx, v[0], v[1]);
+}
+
+static inline void
+lv2_canvas_render_scale(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ const float *v = _lv2_canvas_get_float_vec(forge, body, 2);
+
+ if(v)
+ cairo_scale(ctx, v[0], v[1]);
+}
+
+static inline void
+lv2_canvas_render_rotate(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ const float *v = _lv2_canvas_get_type(body, forge->Float);
+
+ if(v)
+ cairo_rotate(ctx, *v);
+}
+
+static inline void
+lv2_canvas_render_reset(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ cairo_identity_matrix(ctx);
+}
+
+static inline void
+lv2_canvas_render_fontSize(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ const float *v = _lv2_canvas_get_type(body, forge->Float);
+
+ if(v)
+ cairo_set_font_size(ctx, *v);
+}
+
+static inline void
+lv2_canvas_render_fillText(cairo_t *ctx, LV2_Atom_Forge *forge,
+ LV2_Canvas_URID *urid, const LV2_Atom *body)
+{
+ const char *v = _lv2_canvas_get_type(body, forge->String);
+
+ if(v)
+ {
+ cairo_text_extents_t extents;
+ cairo_text_extents (ctx, v, &extents);
+ const float dx = (extents.width/2 + extents.x_bearing);
+ const float dy = (extents.height/2 + extents.y_bearing);
+ cairo_rel_move_to(ctx, -dx, -dy);
+ cairo_show_text(ctx, v);
+ }
+}
+
+static inline void
+lv2_canvas_urid_init(LV2_Canvas_URID *urid, LV2_URID_Map *map)
+{
+ urid->Canvas_graph = map->map(map->handle, CANVAS__graph);
+ urid->Canvas_body = map->map(map->handle, CANVAS__body);
+
+ urid->Canvas_BeginPath = map->map(map->handle, CANVAS__BeginPath);
+ urid->Canvas_ClosePath = map->map(map->handle, CANVAS__ClosePath);
+ urid->Canvas_Arc = map->map(map->handle, CANVAS__Arc);
+ urid->Canvas_CurveTo = map->map(map->handle, CANVAS__CurveTo);
+ urid->Canvas_LineTo = map->map(map->handle, CANVAS__LineTo);
+ urid->Canvas_MoveTo = map->map(map->handle, CANVAS__MoveTo);
+ urid->Canvas_Rectangle = map->map(map->handle, CANVAS__Rectangle);
+ urid->Canvas_Style = map->map(map->handle, CANVAS__Style);
+ urid->Canvas_LineWidth = map->map(map->handle, CANVAS__LineWidth);
+ urid->Canvas_LineDash = map->map(map->handle, CANVAS__LineDash);
+ urid->Canvas_LineCap = map->map(map->handle, CANVAS__LineCap);
+ urid->Canvas_LineJoin = map->map(map->handle, CANVAS__LineJoin);
+ urid->Canvas_MiterLimit = map->map(map->handle, CANVAS__MiterLimit);
+ urid->Canvas_Stroke = map->map(map->handle, CANVAS__Stroke);
+ urid->Canvas_Fill = map->map(map->handle, CANVAS__Fill);
+ urid->Canvas_Clip = map->map(map->handle, CANVAS__Clip);
+ urid->Canvas_Save = map->map(map->handle, CANVAS__Save);
+ urid->Canvas_Restore = map->map(map->handle, CANVAS__Restore);
+ urid->Canvas_Translate = map->map(map->handle, CANVAS__Translate);
+ urid->Canvas_Scale = map->map(map->handle, CANVAS__Scale);
+ urid->Canvas_Rotate = map->map(map->handle, CANVAS__Rotate);
+ urid->Canvas_Reset = map->map(map->handle, CANVAS__Reset);
+ urid->Canvas_FontSize = map->map(map->handle, CANVAS__FontSize);
+ urid->Canvas_FillText = map->map(map->handle, CANVAS__FillText);
+
+ urid->Canvas_lineCapButt = map->map(map->handle, CANVAS__lineCapButt);
+ urid->Canvas_lineCapRound = map->map(map->handle, CANVAS__lineCapRound);
+ urid->Canvas_lineCapSquare = map->map(map->handle, CANVAS__lineCapSquare);
+
+ urid->Canvas_lineJoinMiter = map->map(map->handle, CANVAS__lineJoinMiter);
+ urid->Canvas_lineJoinRound = map->map(map->handle, CANVAS__lineJoinRound);
+ urid->Canvas_lineJoinBevel = map->map(map->handle, CANVAS__lineJoinBevel);
+}
+
+static inline void
+_lv2_canvas_qsort(LV2_Canvas_Meth *a, unsigned n)
+{
+ if(n < 2)
+ return;
+
+ const LV2_Canvas_Meth *p = &a[n/2];
+
+ unsigned i, j;
+ for(i=0, j=n-1; ; i++, j--)
+ {
+ while(a[i].command < p->command)
+ i++;
+
+ while(p->command < a[j].command)
+ j--;
+
+ if(i >= j)
+ break;
+
+ const LV2_Canvas_Meth t = a[i];
+ a[i] = a[j];
+ a[j] = t;
+ }
+
+ _lv2_canvas_qsort(a, i);
+ _lv2_canvas_qsort(&a[i], n - i);
+}
+
+static inline LV2_Canvas_Meth *
+_lv2_canvas_bsearch(LV2_URID p, LV2_Canvas_Meth *a, unsigned n)
+{
+ LV2_Canvas_Meth *base = a;
+
+ for(unsigned N = n, half; N > 1; N -= half)
+ {
+ half = N/2;
+ LV2_Canvas_Meth *dst = &base[half];
+ base = (dst->command > p) ? base : dst;
+ }
+
+ return (base->command == p) ? base : NULL;
+}
+
+static inline void
+lv2_canvas_init(LV2_Canvas *canvas, LV2_URID_Map *map)
+{
+ lv2_canvas_urid_init(&canvas->urid, map);
+
+ unsigned ptr = 0;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_BeginPath;
+ canvas->methods[ptr++].func = lv2_canvas_render_beginPath;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_ClosePath;
+ canvas->methods[ptr++].func = lv2_canvas_render_closePath;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_Arc;
+ canvas->methods[ptr++].func = lv2_canvas_render_arc;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_CurveTo;
+ canvas->methods[ptr++].func = lv2_canvas_render_curveTo;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_LineTo;
+ canvas->methods[ptr++].func = lv2_canvas_render_lineTo;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_MoveTo;
+ canvas->methods[ptr++].func = lv2_canvas_render_moveTo;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_Rectangle;
+ canvas->methods[ptr++].func = lv2_canvas_render_rectangle;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_Style;
+ canvas->methods[ptr++].func = lv2_canvas_render_style;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_LineWidth;
+ canvas->methods[ptr++].func = lv2_canvas_render_lineWidth;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_LineDash;
+ canvas->methods[ptr++].func = lv2_canvas_render_lineDash;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_LineCap;
+ canvas->methods[ptr++].func = lv2_canvas_render_lineCap;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_LineJoin;
+ canvas->methods[ptr++].func = lv2_canvas_render_lineJoin;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_MiterLimit;
+ canvas->methods[ptr++].func = lv2_canvas_render_miterLimit;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_Stroke;
+ canvas->methods[ptr++].func = lv2_canvas_render_stroke;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_Fill;
+ canvas->methods[ptr++].func = lv2_canvas_render_fill;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_Clip;
+ canvas->methods[ptr++].func = lv2_canvas_render_clip;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_Save;
+ canvas->methods[ptr++].func = lv2_canvas_render_save;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_Restore;
+ canvas->methods[ptr++].func = lv2_canvas_render_restore;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_Translate;
+ canvas->methods[ptr++].func = lv2_canvas_render_translate;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_Scale;
+ canvas->methods[ptr++].func = lv2_canvas_render_scale;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_Rotate;
+ canvas->methods[ptr++].func = lv2_canvas_render_rotate;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_Reset;
+ canvas->methods[ptr++].func = lv2_canvas_render_reset;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_FontSize;
+ canvas->methods[ptr++].func = lv2_canvas_render_fontSize;
+
+ canvas->methods[ptr].command = canvas->urid.Canvas_FillText;
+ canvas->methods[ptr++].func = lv2_canvas_render_fillText;
+
+ assert(ptr == CANVAS_NUM_METHODS);
+
+ _lv2_canvas_qsort(canvas->methods, CANVAS_NUM_METHODS);
+}
+
+static inline bool
+lv2_canvas_render(LV2_Canvas *canvas, cairo_t *ctx, LV2_Atom_Forge *forge,
+ const LV2_Atom_Tuple *tup)
+{
+ if(!tup)
+ return false;
+
+ // save state
+ cairo_save(ctx);
+
+ // clear surface
+ cairo_set_operator(ctx, CAIRO_OPERATOR_CLEAR);
+ cairo_paint(ctx);
+
+ // default attributes
+ cairo_set_operator(ctx, CAIRO_OPERATOR_SOURCE);
+ cairo_set_font_size(ctx, 0.1);
+ cairo_set_line_width(ctx, 0.01);
+ cairo_set_source_rgba(ctx, 1.0, 1.0, 1.0, 1.0);
+
+ LV2_ATOM_TUPLE_FOREACH(tup, itm)
+ {
+ if(!lv2_atom_forge_is_object_type(forge, itm->type))
+ continue;
+
+ const LV2_Atom_Object *obj = (const LV2_Atom_Object *)itm;
+ const LV2_Atom *body = NULL;
+
+ lv2_atom_object_get(obj, canvas->urid.Canvas_body, &body, 0);
+ LV2_Canvas_Meth *meth = _lv2_canvas_bsearch(obj->body.otype,
+ canvas->methods, CANVAS_NUM_METHODS);
+
+ if(meth)
+ meth->func(ctx, forge, &canvas->urid, body);
+ }
+
+ // save state
+ cairo_restore(ctx);
+
+ // flush
+ cairo_surface_t *surface = cairo_get_target(ctx);
+ cairo_surface_flush(surface);
+
+ return true;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_beginPath(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_BeginPath);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_closePath(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_ClosePath);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_arc(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid,
+ float x, float y, float r, float a1, float a2)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ const float vec [5] = {x, y, r, a1, a2};
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_Arc);
+ if(ref)
+ ref = lv2_atom_forge_key(forge, urid->Canvas_body);
+ if(ref)
+ ref = lv2_atom_forge_vector(forge, sizeof(float), forge->Float, 5, vec);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_curveTo(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid,
+ float x1, float y1, float x2, float y2, float x3, float y3)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ const float vec [6] = {x1, y1, x2, y2, x3, y3};
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_CurveTo);
+ if(ref)
+ ref = lv2_atom_forge_key(forge, urid->Canvas_body);
+ if(ref)
+ ref = lv2_atom_forge_vector(forge, sizeof(float), forge->Float, 6, vec);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_lineTo(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid,
+ float x, float y)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ const float vec [2] = {x, y};
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_LineTo);
+ if(ref)
+ ref = lv2_atom_forge_key(forge, urid->Canvas_body);
+ if(ref)
+ ref = lv2_atom_forge_vector(forge, sizeof(float), forge->Float, 2, vec);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_moveTo(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid,
+ float x, float y)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ const float vec [2] = {x, y};
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_MoveTo);
+ if(ref)
+ ref = lv2_atom_forge_key(forge, urid->Canvas_body);
+ if(ref)
+ ref = lv2_atom_forge_vector(forge, sizeof(float), forge->Float, 2, vec);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_rectangle(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid,
+ float x, float y, float w, float h)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ const float vec [4] = {x, y, w, h};
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_Rectangle);
+ if(ref)
+ ref = lv2_atom_forge_key(forge, urid->Canvas_body);
+ if(ref)
+ ref = lv2_atom_forge_vector(forge, sizeof(float), forge->Float, 4, vec);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_style(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid,
+ uint32_t style)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_Style);
+ if(ref)
+ ref = lv2_atom_forge_key(forge, urid->Canvas_body);
+ if(ref)
+ ref = lv2_atom_forge_long(forge, style);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_lineWidth(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid,
+ float line_width)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_LineWidth);
+ if(ref)
+ ref = lv2_atom_forge_key(forge, urid->Canvas_body);
+ if(ref)
+ ref = lv2_atom_forge_long(forge, line_width);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_lineDash(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid,
+ float dash_length, float separator_length)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ const float vec [2] = {dash_length, separator_length};
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_LineDash);
+ if(ref)
+ ref = lv2_atom_forge_key(forge, urid->Canvas_body);
+ if(ref)
+ ref = lv2_atom_forge_vector(forge, sizeof(float), forge->Float, 2, vec);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_lineCap(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid,
+ LV2_URID line_cap)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_LineCap);
+ if(ref)
+ ref = lv2_atom_forge_key(forge, urid->Canvas_body);
+ if(ref)
+ ref = lv2_atom_forge_urid(forge, line_cap);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_lineJoin(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid,
+ LV2_URID line_join)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_LineJoin);
+ if(ref)
+ ref = lv2_atom_forge_key(forge, urid->Canvas_body);
+ if(ref)
+ ref = lv2_atom_forge_urid(forge, line_join);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_miterLimit(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid,
+ float miter_limit)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_MiterLimit);
+ if(ref)
+ ref = lv2_atom_forge_key(forge, urid->Canvas_body);
+ if(ref)
+ ref = lv2_atom_forge_float(forge, miter_limit);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_stroke(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_Stroke);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_fill(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_Fill);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_clip(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_Clip);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_save(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_Save);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_restore(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_Restore);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_translate(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid,
+ float x, float y)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ const float vec [2] = {x, y};
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_Translate);
+ if(ref)
+ ref = lv2_atom_forge_key(forge, urid->Canvas_body);
+ if(ref)
+ ref = lv2_atom_forge_vector(forge, sizeof(float), forge->Float, 2, vec);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_scale(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid,
+ float w, float h)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ const float vec [2] = {w, h};
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_Scale);
+ if(ref)
+ ref = lv2_atom_forge_key(forge, urid->Canvas_body);
+ if(ref)
+ ref = lv2_atom_forge_vector(forge, sizeof(float), forge->Float, 2, vec);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_rotate(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid,
+ float a)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_Scale);
+ if(ref)
+ ref = lv2_atom_forge_key(forge, urid->Canvas_body);
+ if(ref)
+ ref = lv2_atom_forge_float(forge, a);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_reset(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_Reset);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_fontSize(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid,
+ float size)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
+
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_FontSize);
+ if(ref)
+ ref = lv2_atom_forge_key(forge, urid->Canvas_body);
+ if(ref)
+ ref = lv2_atom_forge_float(forge, size);
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
+
+ return ref;
+}
+
+static inline LV2_Atom_Forge_Ref
+lv2_canvas_fillText(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid,
+ const char *text)
+{
+ LV2_Atom_Forge_Ref ref;
+ LV2_Atom_Forge_Frame frame;
-#define CANVAS_CANVAS_URI CANVAS_URI"#canvas"
-#define CANVAS_CANVAS_UI_URI CANVAS_URI"#canvas_ui"
+ ref = lv2_atom_forge_object(forge, &frame, 0, urid->Canvas_FillText);
+ if(ref)
+ ref = lv2_atom_forge_key(forge, urid->Canvas_body);
+ if(ref)
+ ref = lv2_atom_forge_string(forge, text, strlen(text));
+ if(ref)
+ lv2_atom_forge_pop(forge, &frame);
-extern const LV2_Descriptor canvas_canvas;
-extern const LV2UI_Descriptor canvas_canvas_ui;
+ return ref;
+}
#endif // _CANVAS_LV2_H
diff --git a/canvas_ui.c b/canvas_ui.c
index cdbc868..ff953ed 100644
--- a/canvas_ui.c
+++ b/canvas_ui.c
@@ -36,65 +36,80 @@ struct _plughandle_t {
PuglView *view;
int done;
- struct {
- double r;
- double g;
- double b;
- } col;
- struct {
- bool r;
- bool g;
- bool b;
- } dir;
+
+ LV2_Canvas canvas;
+
+ LV2_URID patch_Get;
+ LV2_URID patch_Set;
+ LV2_URID patch_property;
+ LV2_URID patch_value;
+ LV2_URID atom_eventTransfer;
+
+ LV2_Atom_Tuple *graph;
+ bool dirty;
+
+ LV2UI_Write_Function writer;
+ LV2UI_Controller controller;
};
static inline void
+_refresh(plughandle_t *handle)
+{
+ union {
+ LV2_Atom atom;
+ uint8_t buf [128];
+ } dst;
+
+ lv2_atom_forge_set_buffer(&handle->forge, dst.buf, 128);
+ LV2_Atom_Forge_Ref ref;
+
+ LV2_Atom_Forge_Frame obj_frame;
+ ref = lv2_atom_forge_object(&handle->forge, &obj_frame, 0, handle->patch_Get);
+ if(ref)
+ ref = lv2_atom_forge_key(&handle->forge, handle->patch_property);
+ if(ref)
+ ref = lv2_atom_forge_urid(&handle->forge, handle->canvas.urid.Canvas_graph);
+ if(ref)
+ lv2_atom_forge_pop(&handle->forge, &obj_frame);
+
+ const uint32_t sz = lv2_atom_total_size(&dst.atom);
+ handle->writer(handle->controller, 0, sz, handle->atom_eventTransfer, &dst.atom);
+}
+
+static inline void
_expose(plughandle_t *handle)
{
-#ifndef _WIN32 //FIXME
cairo_t *ctx = puglGetContext(handle->view);
- cairo_surface_t *surf = cairo_get_target(ctx);
-
- // Draw background
- int w, h;
- puglGetSize(handle->view, &w, &h);
-
- cairo_surface_set_device_scale(surf, w, h);
-
- cairo_set_source_rgba(ctx, 0.0, 0.0, 0.0, 1.0);
- cairo_rectangle(ctx, 0.0, 0.0, 1.0, 1.0);
- cairo_fill(ctx);
- cairo_set_source_rgba(ctx, handle->col.r, handle->col.g, handle->col.b, 1.0);
- cairo_arc(ctx, 0.5, 0.5, 0.4, 0.0, 2*M_PI);
- cairo_fill(ctx);
+#ifndef _WIN32 //FIXME
+ lv2_canvas_render(&handle->canvas, ctx, &handle->forge, handle->graph);
#endif
}
static inline void
_close(plughandle_t *handle)
{
+printf("_close\n");
handle->done = 1;
}
static inline void
-_enter(plughandle_t *handle)
+_configure(plughandle_t *handle, const PuglEventConfigure *e)
{
- puglPostRedisplay(handle->view);
-}
+ cairo_t *ctx = puglGetContext(handle->view);
-static inline void
-_leave(plughandle_t *handle)
-{
- puglPostRedisplay(handle->view);
+#ifndef _WIN32 //FIXME
+ cairo_surface_t *surf = cairo_get_target(ctx);
+ cairo_surface_set_device_scale(surf, e->width, e->height);
+#endif
}
static void
-_event_func(PuglView *view, const PuglEvent *ev)
+_event_func(PuglView *view, const PuglEvent *e)
{
plughandle_t *handle = puglGetHandle(view);
- switch(ev->type)
+ switch(e->type)
{
case PUGL_NOTHING:
break;
@@ -103,6 +118,7 @@ _event_func(PuglView *view, const PuglEvent *ev)
case PUGL_BUTTON_RELEASE:
break;
case PUGL_CONFIGURE:
+ _configure(handle, (const PuglEventConfigure *)e);
break;
case PUGL_EXPOSE:
_expose(handle);
@@ -114,19 +130,18 @@ _event_func(PuglView *view, const PuglEvent *ev)
break;
case PUGL_KEY_RELEASE:
break;
- case PUGL_ENTER_NOTIFY:
- _enter(handle);
- break;
- case PUGL_LEAVE_NOTIFY:
- _leave(handle);
- break;
case PUGL_MOTION_NOTIFY:
break;
case PUGL_SCROLL:
break;
+ case PUGL_ENTER_NOTIFY:
+ // fall-through
+ case PUGL_LEAVE_NOTIFY:
+ // fall-through
case PUGL_FOCUS_IN:
- break;
+ // fall-through
case PUGL_FOCUS_OUT:
+ puglPostRedisplay(handle->view);
break;
}
}
@@ -175,6 +190,12 @@ instantiate(const LV2UI_Descriptor *descriptor, const char *plugin_uri,
lv2_atom_forge_init(&handle->forge, handle->map);
+ handle->patch_Get = handle->map->map(handle->map->handle, LV2_PATCH__Get);
+ handle->patch_Set = handle->map->map(handle->map->handle, LV2_PATCH__Set);
+ handle->patch_property = handle->map->map(handle->map->handle, LV2_PATCH__property);
+ handle->patch_value = handle->map->map(handle->map->handle, LV2_PATCH__value);
+ handle->atom_eventTransfer= handle->map->map(handle->map->handle, LV2_ATOM__eventTransfer);
+
handle->view = puglInit(NULL, NULL);
if(!handle->view)
{
@@ -214,12 +235,24 @@ instantiate(const LV2UI_Descriptor *descriptor, const char *plugin_uri,
}
puglShowWindow(handle->view);
+ cairo_t *ctx = puglGetContext(handle->view);
+#ifndef _WIN32 //FIXME
+ cairo_surface_t *surf = cairo_get_target(ctx);
+ cairo_surface_set_device_scale(surf, w, h);
+#endif
+
const intptr_t child = puglGetNativeWindow(handle->view);
*(intptr_t *)widget = child;
if(host_resize)
host_resize->ui_resize(host_resize->handle, w, h);
+ lv2_canvas_init(&handle->canvas, handle->map);
+
+ handle->controller = controller;
+ handle->writer = write_function;
+ _refresh(handle);
+
return handle;
}
@@ -228,6 +261,9 @@ cleanup(LV2UI_Handle instance)
{
plughandle_t *handle = instance;
+ if(handle->graph)
+ free(handle->graph);
+
if(handle->view)
{
if(puglGetVisible(handle->view))
@@ -242,72 +278,56 @@ static void
port_event(LV2UI_Handle instance, uint32_t index, uint32_t size,
uint32_t protocol, const void *buf)
{
- //FIXME
-}
-
-static int
-_resize(LV2UI_Handle instance, int w, int h)
-{
plughandle_t *handle = instance;
+ cairo_t *ctx = puglGetContext(handle->view);
- //FIXME
- //puglInitWindowSize(handle->view, w, h);
- //puglInitWindowMinSize(handle->view, w, h);
-
- return 0;
+ if(index == 1) // notify
+ {
+ const LV2_Atom_Object *obj = buf;
+
+ if(lv2_atom_forge_is_object_type(&handle->forge, obj->atom.type))
+ {
+ if(obj->body.otype == handle->patch_Set)
+ {
+ const LV2_Atom_URID *property = NULL;
+ const LV2_Atom_Tuple *body = NULL;
+
+ lv2_atom_object_get(obj,
+ handle->patch_property, &property,
+ handle->patch_value, &body,
+ 0);
+
+ if(property && body)
+ {
+ if( (property->body == handle->canvas.urid.Canvas_graph)
+ && (body->atom.type == handle->forge.Tuple) )
+ {
+ if(handle->graph)
+ free(handle->graph);
+ const size_t sz = lv2_atom_total_size(&body->atom);
+ handle->graph = malloc(sz);
+ if(handle->graph)
+ memcpy(handle->graph, body, sz);
+ handle->dirty = true;
+ }
+ }
+ }
+ }
+ }
}
-static const LV2UI_Resize resize_ext = {
- .ui_resize= _resize
-};
-
static int
_idle(LV2UI_Handle instance)
{
plughandle_t *handle = instance;
- handle->col.r += 0.01 * (handle->dir.r ? 1.0 : -1.0);
- if(handle->dir.r && (handle->col.r > 1.0) )
+ if(handle->dirty)
{
- handle->dir.r = false;
- handle->col.r = 1.0;
- }
- else if(!handle->dir.r && (handle->col.r < 0.0) )
- {
- handle->dir.r = true;
- handle->col.r = 0.0;
- }
-
- handle->col.g += 0.02 * (handle->dir.g ? 1.0 : -1.0);
- if(handle->dir.g && (handle->col.g > 1.0) )
- {
- handle->dir.g = false;
- handle->col.g = 1.0;
- }
- else if(!handle->dir.g && (handle->col.g < 0.0) )
- {
- handle->dir.g = true;
- handle->col.g = 0.0;
- }
-
- handle->col.b += 0.04 * (handle->dir.b ? 1.0 : -1.0);
- if(handle->dir.b && (handle->col.b > 1.0) )
- {
- handle->dir.b = false;
- handle->col.b = 1.0;
- }
- else if(!handle->dir.b && (handle->col.b < 0.0) )
- {
- handle->dir.b = true;
- handle->col.b = 0.0;
+ puglPostRedisplay(handle->view);
+ handle->dirty = false;
}
- puglPostRedisplay(handle->view);
-
- if(puglProcessEvents(handle->view) != PUGL_SUCCESS)
- {
- //TODO
- }
+ puglProcessEvents(handle->view);
return handle->done;
}
@@ -321,14 +341,12 @@ extension_data(const char *uri)
{
if(!strcmp(uri, LV2_UI__idleInterface))
return &idle_ext;
- else if(!strcmp(uri, LV2_UI__resize))
- return &resize_ext;
-
+
return NULL;
}
const LV2UI_Descriptor canvas_canvas_ui = {
- .URI = CANVAS_CANVAS_UI_URI,
+ .URI = CANVAS_PREFIX"canvas_ui",
.instantiate = instantiate,
.cleanup = cleanup,
.port_event = port_event,