1 /*
2 * Copyright (c) 2016 Hanspeter Portner (dev@open-music-kontrollers.ch)
3 *
4 * This is free software: you can redistribute it and/or modify
5 * it under the terms of the Artistic License 2.0 as published by
6 * The Perl Foundation.
7 *
8 * This source is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * Artistic License 2.0 for more details.
12 *
13 * You should have received a copy of the Artistic License 2.0
14 * along the source as a COPYING file. If not, obtain it from
15 * http://www.perlfoundation.org/artistic_license_2_0.
16 */
17
18 #ifndef _LV2_CANVAS_RENDER_NANOVG_H
19 #define _LV2_CANVAS_RENDER_NANOVG_H
20
21 #include <assert.h>
22
23 #include <nanovg.h>
24
25 #if defined(__APPLE__)
26 # include <OpenGL/gl.h>
27 # include <OpenGL/glext.h>
28 #else
29 # include <GL/glew.h>
30 #endif
31
32 #define NANOVG_GL2_IMPLEMENTATION
33 #include <nanovg_gl.h>
34
35 #if defined(NANOVG_GL2_IMPLEMENTATION)
36 # define nvgCreate nvgCreateGL2
37 # define nvgDelete nvgDeleteGL2
38 #elif defined(NANOVG_GL3_IMPLEMENTATION)
39 # define nvgCreate nvgCreateGL3
40 # define nvgDelete nvgDeleteGL3
41 #elif defined(NANOVG_GLES2_IMPLEMENTATION)
42 # define nvgCreate nvgCreateGLES2
43 # define nvgDelete nvgDeleteGLES2
44 #elif defined(NANOVG_GLES3_IMPLEMENTATION)
45 # define nvgCreate nvgCreateGLES3
46 # define nvgDelete nvgDeleteGLES3
47 #endif
48
49 #ifdef __cplusplus
50 extern "C" {
51 #endif
52
53 static inline void
_lv2_canvas_render_beginPath(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)54 _lv2_canvas_render_beginPath(void *data,
55 LV2_Canvas_URID *urid, const LV2_Atom *body)
56 {
57 NVGcontext *ctx = data;
58 nvgBeginPath(ctx);
59 }
60
61 static inline void
_lv2_canvas_render_closePath(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)62 _lv2_canvas_render_closePath(void *data,
63 LV2_Canvas_URID *urid, const LV2_Atom *body)
64 {
65 NVGcontext *ctx = data;
66 nvgClosePath(ctx);
67 }
68
69 static inline void
_lv2_canvas_render_arc(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)70 _lv2_canvas_render_arc(void *data,
71 LV2_Canvas_URID *urid, const LV2_Atom *body)
72 {
73 NVGcontext *ctx = data;
74 const float *v = _lv2_canvas_render_get_float_vec(urid, body, 5);
75
76 if(v)
77 {
78 nvgArc(ctx, v[0], v[1], v[2], v[3], v[4], NVG_CCW);
79 }
80 }
81
82 static inline void
_lv2_canvas_render_curveTo(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)83 _lv2_canvas_render_curveTo(void *data,
84 LV2_Canvas_URID *urid, const LV2_Atom *body)
85 {
86 NVGcontext *ctx = data;
87 const float *v = _lv2_canvas_render_get_float_vec(urid, body, 6);
88
89 if(v)
90 {
91 nvgBezierTo(ctx, v[0], v[1], v[2], v[3], v[4], v[5]);
92 }
93 }
94
95 static inline void
_lv2_canvas_render_lineTo(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)96 _lv2_canvas_render_lineTo(void *data,
97 LV2_Canvas_URID *urid, const LV2_Atom *body)
98 {
99 NVGcontext *ctx = data;
100 const float *v = _lv2_canvas_render_get_float_vec(urid, body, 2);
101
102 if(v)
103 {
104 nvgLineTo(ctx, v[0], v[1]);
105 }
106 }
107
108 static inline void
_lv2_canvas_render_moveTo(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)109 _lv2_canvas_render_moveTo(void *data,
110 LV2_Canvas_URID *urid, const LV2_Atom *body)
111 {
112 NVGcontext *ctx = data;
113 const float *v = _lv2_canvas_render_get_float_vec(urid, body, 2);
114
115 if(v)
116 {
117 nvgMoveTo(ctx, v[0], v[1]);
118 }
119 }
120
121 static inline void
_lv2_canvas_render_rectangle(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)122 _lv2_canvas_render_rectangle(void *data,
123 LV2_Canvas_URID *urid, const LV2_Atom *body)
124 {
125 NVGcontext *ctx = data;
126 const float *v = _lv2_canvas_render_get_float_vec(urid, body, 4);
127
128 if(v)
129 {
130 nvgRect(ctx, v[0], v[1], v[2], v[3]);
131 }
132 }
133
134 static inline void
_lv2_canvas_render_polyline(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)135 _lv2_canvas_render_polyline(void *data,
136 LV2_Canvas_URID *urid, const LV2_Atom *body)
137 {
138 NVGcontext *ctx = data;
139 uint32_t N;
140 const float *v = _lv2_canvas_render_get_float_vecs(urid, body, &N);
141
142 if(v)
143 {
144 for(uint32_t i = 0; i < 2; i += 2)
145 {
146 nvgMoveTo(ctx, v[i], v[i+1]);
147 }
148
149 for(uint32_t i = 2; i < N; i += 2)
150 {
151 nvgLineTo(ctx, v[i], v[i+1]);
152 }
153 }
154 }
155
156 static inline void
_lv2_canvas_render_style(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)157 _lv2_canvas_render_style(void *data,
158 LV2_Canvas_URID *urid, const LV2_Atom *body)
159 {
160 NVGcontext *ctx = data;
161 const int64_t *v = _lv2_canvas_render_get_type(body, urid->forge.Long);
162
163 if(v)
164 {
165 const uint8_t r = (*v >> 24) & 0xff;
166 const uint8_t g = (*v >> 16) & 0xff;
167 const uint8_t b = (*v >> 8) & 0xff;
168 const uint8_t a = (*v >> 0) & 0xff;
169
170 nvgStrokeColor(ctx, nvgRGBA(r, g, b, a));
171 nvgFillColor(ctx, nvgRGBA(r, g, b, a));
172 }
173 }
174
175 static inline void
_lv2_canvas_render_lineWidth(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)176 _lv2_canvas_render_lineWidth(void *data,
177 LV2_Canvas_URID *urid, const LV2_Atom *body)
178 {
179 NVGcontext *ctx = data;
180 const float *v = _lv2_canvas_render_get_type(body, urid->forge.Float);
181
182 if(v)
183 {
184 nvgStrokeWidth(ctx, *v);
185 }
186 }
187
188 static inline void
_lv2_canvas_render_lineDash(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)189 _lv2_canvas_render_lineDash(void *data,
190 LV2_Canvas_URID *urid, const LV2_Atom *body)
191 {
192 NVGcontext *ctx = data;
193 (void)ctx; //FIXME
194 const float *v = _lv2_canvas_render_get_float_vec(urid, body, 2);
195
196 if(v)
197 {
198 //const double d[2] = {v[0], v[1]};
199 //FIXME cairo_set_dash(ctx, d, 2, 0);
200 }
201 }
202
203 static inline void
_lv2_canvas_render_lineCap(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)204 _lv2_canvas_render_lineCap(void *data,
205 LV2_Canvas_URID *urid, const LV2_Atom *body)
206 {
207 NVGcontext *ctx = data;
208 const LV2_URID *v = _lv2_canvas_render_get_type(body, urid->forge.URID);
209
210 if(v)
211 {
212 int cap = NVG_BUTT;
213
214 if(*v == urid->Canvas_lineCapButt)
215 cap = NVG_BUTT;
216 else if(*v == urid->Canvas_lineCapRound)
217 cap = NVG_ROUND;
218 else if(*v == urid->Canvas_lineCapSquare)
219 cap = NVG_SQUARE;
220
221 nvgLineCap(ctx, cap);
222 }
223 }
224
225 static inline void
_lv2_canvas_render_lineJoin(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)226 _lv2_canvas_render_lineJoin(void *data,
227 LV2_Canvas_URID *urid, const LV2_Atom *body)
228 {
229 NVGcontext *ctx = data;
230 const LV2_URID *v = _lv2_canvas_render_get_type(body, urid->forge.URID);
231
232 if(v)
233 {
234 int join = NVG_MITER;
235
236 if(*v == urid->Canvas_lineJoinMiter)
237 join = NVG_MITER;
238 else if(*v == urid->Canvas_lineJoinRound)
239 join = NVG_ROUND;
240 else if(*v == urid->Canvas_lineJoinBevel)
241 join = NVG_BEVEL;
242
243 nvgLineJoin(ctx, join);
244 }
245 }
246
247 static inline void
_lv2_canvas_render_miterLimit(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)248 _lv2_canvas_render_miterLimit(void *data,
249 LV2_Canvas_URID *urid, const LV2_Atom *body)
250 {
251 NVGcontext *ctx = data;
252 const float *v = _lv2_canvas_render_get_type(body, urid->forge.Float);
253
254 if(v)
255 {
256 nvgMiterLimit(ctx, *v);
257 }
258 }
259
260 static inline void
_lv2_canvas_render_stroke(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)261 _lv2_canvas_render_stroke(void *data,
262 LV2_Canvas_URID *urid, const LV2_Atom *body)
263 {
264 NVGcontext *ctx = data;
265 nvgStroke(ctx);
266 }
267
268 static inline void
_lv2_canvas_render_fill(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)269 _lv2_canvas_render_fill(void *data,
270 LV2_Canvas_URID *urid, const LV2_Atom *body)
271 {
272 NVGcontext *ctx = data;
273 nvgFill(ctx);
274 }
275
276 static inline void
_lv2_canvas_render_clip(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)277 _lv2_canvas_render_clip(void *data,
278 LV2_Canvas_URID *urid, const LV2_Atom *body)
279 {
280 NVGcontext *ctx = data;
281 (void)ctx; //FIXME
282 //FIXME cairo_clip(ctx);
283 }
284
285 static inline void
_lv2_canvas_render_save(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)286 _lv2_canvas_render_save(void *data,
287 LV2_Canvas_URID *urid, const LV2_Atom *body)
288 {
289 NVGcontext *ctx = data;
290 nvgSave(ctx);
291 }
292
293 static inline void
_lv2_canvas_render_restore(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)294 _lv2_canvas_render_restore(void *data,
295 LV2_Canvas_URID *urid, const LV2_Atom *body)
296 {
297 NVGcontext *ctx = data;
298 nvgRestore(ctx);
299 }
300
301 static inline void
_lv2_canvas_render_translate(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)302 _lv2_canvas_render_translate(void *data,
303 LV2_Canvas_URID *urid, const LV2_Atom *body)
304 {
305 NVGcontext *ctx = data;
306 const float *v = _lv2_canvas_render_get_float_vec(urid, body, 2);
307
308 if(v)
309 {
310 nvgTranslate(ctx, v[0], v[1]);
311 }
312 }
313
314 static inline void
_lv2_canvas_render_scale(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)315 _lv2_canvas_render_scale(void *data,
316 LV2_Canvas_URID *urid, const LV2_Atom *body)
317 {
318 NVGcontext *ctx = data;
319 const float *v = _lv2_canvas_render_get_float_vec(urid, body, 2);
320
321 if(v)
322 {
323 nvgScale(ctx, v[0], v[1]);
324 }
325 }
326
327 static inline void
_lv2_canvas_render_rotate(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)328 _lv2_canvas_render_rotate(void *data,
329 LV2_Canvas_URID *urid, const LV2_Atom *body)
330 {
331 NVGcontext *ctx = data;
332 const float *v = _lv2_canvas_render_get_type(body, urid->forge.Float);
333
334 if(v)
335 {
336 nvgRotate(ctx, *v);
337 }
338 }
339
340 static inline void
_lv2_canvas_render_transform(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)341 _lv2_canvas_render_transform(void *data,
342 LV2_Canvas_URID *urid, const LV2_Atom *body)
343 {
344 NVGcontext *ctx = data;
345 const float *v = _lv2_canvas_render_get_float_vec(urid, body, 6);
346
347 if(v)
348 {
349 nvgTransform(ctx, v[0], v[1], v[2], v[3], v[4], v[5]);
350 }
351 }
352
353 static inline void
_lv2_canvas_render_reset(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)354 _lv2_canvas_render_reset(void *data,
355 LV2_Canvas_URID *urid, const LV2_Atom *body)
356 {
357 NVGcontext *ctx = data;
358 nvgReset(ctx);
359 }
360
361 static inline void
_lv2_canvas_render_fontSize(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)362 _lv2_canvas_render_fontSize(void *data,
363 LV2_Canvas_URID *urid, const LV2_Atom *body)
364 {
365 NVGcontext *ctx = data;
366 const float *v = _lv2_canvas_render_get_type(body, urid->forge.Float);
367
368 if(v)
369 {
370 nvgFontSize(ctx, *v);
371 }
372 }
373
374 static inline void
_lv2_canvas_render_fillText(void * data,LV2_Canvas_URID * urid,const LV2_Atom * body)375 _lv2_canvas_render_fillText(void *data,
376 LV2_Canvas_URID *urid, const LV2_Atom *body)
377 {
378 NVGcontext *ctx = data;
379 (void)ctx; //FIXME
380 const char *v = _lv2_canvas_render_get_type(body, urid->forge.String);
381
382 if(v)
383 {
384 /* FIXME
385 NVGcontextext_extents_t extents;
386 NVGcontextext_extents(ctx, v, &extents);
387 const float dx = extents.width/2 + extents.x_bearing;
388 const float dy = extents.height/2 + extents.y_bearing;
389 cairo_rel_move_to(ctx, -dx, -dy);
390 cairo_show_text(ctx, v);
391 */
392 /*
393 float bounds [4];
394 const float adv_x = nvgTextBounds(ctx, 0.f, 0.f, v, NULL, bounds);
395 nvgText(ctx, float x, float y, const char* string, const char* end);
396 */
397 }
398 }
399
400 static inline void
_lv2_canvas_qsort(LV2_Canvas_Meth * A,int n)401 _lv2_canvas_qsort(LV2_Canvas_Meth *A, int n)
402 {
403 if(n < 2)
404 return;
405
406 LV2_Canvas_Meth *p = A;
407
408 int i = -1;
409 int j = n;
410
411 while(true)
412 {
413 do {
414 i += 1;
415 } while(A[i].command < p->command);
416
417 do {
418 j -= 1;
419 } while(A[j].command > p->command);
420
421 if(i >= j)
422 break;
423
424 const LV2_Canvas_Meth tmp = A[i];
425 A[i] = A[j];
426 A[j] = tmp;
427 }
428
429 _lv2_canvas_qsort(A, j + 1);
430 _lv2_canvas_qsort(A + j + 1, n - j - 1);
431 }
432
433 static inline LV2_Canvas_Meth *
_lv2_canvas_bsearch(LV2_URID p,LV2_Canvas_Meth * a,int n)434 _lv2_canvas_bsearch(LV2_URID p, LV2_Canvas_Meth *a, int n)
435 {
436 LV2_Canvas_Meth *base = a;
437
438 for(int N = n, half; N > 1; N -= half)
439 {
440 half = N/2;
441 LV2_Canvas_Meth *dst = &base[half];
442 base = (dst->command > p) ? base : dst;
443 }
444
445 return (base->command == p) ? base : NULL;
446 }
447
448 static inline void
lv2_canvas_init(LV2_Canvas * canvas,LV2_URID_Map * map)449 lv2_canvas_init(LV2_Canvas *canvas, LV2_URID_Map *map)
450 {
451 lv2_canvas_urid_init(&canvas->urid, map);
452
453 unsigned ptr = 0;
454
455 canvas->methods[ptr].command = canvas->urid.Canvas_BeginPath;
456 canvas->methods[ptr++].func = _lv2_canvas_render_beginPath;
457
458 canvas->methods[ptr].command = canvas->urid.Canvas_ClosePath;
459 canvas->methods[ptr++].func = _lv2_canvas_render_closePath;
460
461 canvas->methods[ptr].command = canvas->urid.Canvas_Arc;
462 canvas->methods[ptr++].func = _lv2_canvas_render_arc;
463
464 canvas->methods[ptr].command = canvas->urid.Canvas_CurveTo;
465 canvas->methods[ptr++].func = _lv2_canvas_render_curveTo;
466
467 canvas->methods[ptr].command = canvas->urid.Canvas_LineTo;
468 canvas->methods[ptr++].func = _lv2_canvas_render_lineTo;
469
470 canvas->methods[ptr].command = canvas->urid.Canvas_MoveTo;
471 canvas->methods[ptr++].func = _lv2_canvas_render_moveTo;
472
473 canvas->methods[ptr].command = canvas->urid.Canvas_Rectangle;
474 canvas->methods[ptr++].func = _lv2_canvas_render_rectangle;
475
476 canvas->methods[ptr].command = canvas->urid.Canvas_PolyLine;
477 canvas->methods[ptr++].func = _lv2_canvas_render_polyline;
478
479 canvas->methods[ptr].command = canvas->urid.Canvas_Style;
480 canvas->methods[ptr++].func = _lv2_canvas_render_style;
481
482 canvas->methods[ptr].command = canvas->urid.Canvas_LineWidth;
483 canvas->methods[ptr++].func = _lv2_canvas_render_lineWidth;
484
485 canvas->methods[ptr].command = canvas->urid.Canvas_LineDash;
486 canvas->methods[ptr++].func = _lv2_canvas_render_lineDash;
487
488 canvas->methods[ptr].command = canvas->urid.Canvas_LineCap;
489 canvas->methods[ptr++].func = _lv2_canvas_render_lineCap;
490
491 canvas->methods[ptr].command = canvas->urid.Canvas_LineJoin;
492 canvas->methods[ptr++].func = _lv2_canvas_render_lineJoin;
493
494 canvas->methods[ptr].command = canvas->urid.Canvas_MiterLimit;
495 canvas->methods[ptr++].func = _lv2_canvas_render_miterLimit;
496
497 canvas->methods[ptr].command = canvas->urid.Canvas_Stroke;
498 canvas->methods[ptr++].func = _lv2_canvas_render_stroke;
499
500 canvas->methods[ptr].command = canvas->urid.Canvas_Fill;
501 canvas->methods[ptr++].func = _lv2_canvas_render_fill;
502
503 canvas->methods[ptr].command = canvas->urid.Canvas_Clip;
504 canvas->methods[ptr++].func = _lv2_canvas_render_clip;
505
506 canvas->methods[ptr].command = canvas->urid.Canvas_Save;
507 canvas->methods[ptr++].func = _lv2_canvas_render_save;
508
509 canvas->methods[ptr].command = canvas->urid.Canvas_Restore;
510 canvas->methods[ptr++].func = _lv2_canvas_render_restore;
511
512 canvas->methods[ptr].command = canvas->urid.Canvas_Translate;
513 canvas->methods[ptr++].func = _lv2_canvas_render_translate;
514
515 canvas->methods[ptr].command = canvas->urid.Canvas_Scale;
516 canvas->methods[ptr++].func = _lv2_canvas_render_scale;
517
518 canvas->methods[ptr].command = canvas->urid.Canvas_Rotate;
519 canvas->methods[ptr++].func = _lv2_canvas_render_rotate;
520
521 canvas->methods[ptr].command = canvas->urid.Canvas_Transform;
522 canvas->methods[ptr++].func = _lv2_canvas_render_transform;
523
524 canvas->methods[ptr].command = canvas->urid.Canvas_Reset;
525 canvas->methods[ptr++].func = _lv2_canvas_render_reset;
526
527 canvas->methods[ptr].command = canvas->urid.Canvas_FontSize;
528 canvas->methods[ptr++].func = _lv2_canvas_render_fontSize;
529
530 canvas->methods[ptr].command = canvas->urid.Canvas_FillText;
531 canvas->methods[ptr++].func = _lv2_canvas_render_fillText;
532
533 assert(ptr == LV2_CANVAS_NUM_METHODS);
534
535 _lv2_canvas_qsort(canvas->methods, LV2_CANVAS_NUM_METHODS);
536 }
537
538 static inline bool
lv2_canvas_render_body(LV2_Canvas * canvas,NVGcontext * ctx,uint32_t type,uint32_t size,const LV2_Atom * body)539 lv2_canvas_render_body(LV2_Canvas *canvas, NVGcontext *ctx, uint32_t type,
540 uint32_t size, const LV2_Atom *body)
541 {
542 LV2_Canvas_URID *urid = &canvas->urid;
543
544 if(!body || (type != urid->forge.Tuple) )
545 return false;
546
547 // save state
548 nvgSave(ctx);
549
550 // clear surface
551 nvgBeginPath(ctx);
552 nvgRect(ctx, 0, 0, 1.f, 1.f);
553 nvgFillColor(ctx, nvgRGBA(0x1e, 0x1e, 0x1e, 0xff));
554 nvgFill(ctx);
555
556 nvgFontSize(ctx, 0.1);
557 nvgStrokeWidth(ctx, 0.01);
558 nvgStrokeColor(ctx, nvgRGBA(0xff, 0xff, 0xff, 0xff));
559 nvgFillColor(ctx, nvgRGBA(0xff, 0xff, 0xff, 0xff));
560
561 LV2_ATOM_TUPLE_BODY_FOREACH(body, size, itm)
562 {
563 if(lv2_atom_forge_is_object_type(&urid->forge, itm->type))
564 {
565 const LV2_Atom_Object *obj = (const LV2_Atom_Object *)itm;
566 const LV2_Atom *body = NULL;
567
568 lv2_atom_object_get(obj, urid->Canvas_body, &body, 0);
569
570 LV2_Canvas_Meth *meth = _lv2_canvas_bsearch(obj->body.otype,
571 canvas->methods, LV2_CANVAS_NUM_METHODS);
572
573 if(meth)
574 {
575 meth->func(ctx, urid, body);
576 }
577 }
578 }
579
580 // save state
581 nvgRestore(ctx);
582
583 return true;
584 }
585
586 static inline bool
lv2_canvas_render(LV2_Canvas * canvas,NVGcontext * ctx,const LV2_Atom_Tuple * tup)587 lv2_canvas_render(LV2_Canvas *canvas, NVGcontext *ctx, const LV2_Atom_Tuple *tup)
588 {
589 return lv2_canvas_render_body(canvas, ctx, tup->atom.type, tup->atom.size,
590 LV2_ATOM_BODY_CONST(&tup->atom));
591 }
592
593 #ifdef __cplusplus
594 }
595 #endif
596
597 #endif // LV2_CANVAS_RENDER_NANOVG_H
598