diff options
-rw-r--r-- | .gitlab-ci.yml | 72 | ||||
-rw-r--r-- | COPYING | 201 | ||||
-rw-r--r-- | README.md | 18 | ||||
-rw-r--r-- | canvas.lv2/canvas.h | 195 | ||||
-rw-r--r-- | canvas.lv2/forge.h | 326 | ||||
-rw-r--r-- | canvas.lv2/render.h | 592 |
6 files changed, 1404 insertions, 0 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..a824c765 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,72 @@ +stages: + - build + - deploy + +.variables_template: &variables_definition + variables: + BASE_NAME: "canvas.lv2" + PKG_CONFIG_PATH: "/opt/lv2/lib/pkgconfig:/opt/${CI_BUILD_NAME}/lib/pkgconfig:/usr/lib/${CI_BUILD_NAME}/pkgconfig" + TOOLCHAIN_FILE: "${CI_PROJECT_DIR}/cmake/${CI_BUILD_NAME}.cmake" + +.common_template: &common_definition + <<: *variables_definition + stage: build + artifacts: + name: "${BASE_NAME}-$(cat VERSION)-${CI_BUILD_NAME}" + paths: + - "${BASE_NAME}-$(cat VERSION)/" + +.build_template: &build_definition + <<: *common_definition + script: + - mkdir build + - pushd build + - cmake -DCAIRO_INCLUDE_DIRS="/opt/${CI_BUILD_NAME}/include" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=${CI_PROJECT_DIR} -DPLUGIN_DEST="${BASE_NAME}-$(cat ../VERSION)/${CI_BUILD_NAME}/${BASE_NAME}" -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_FILE} .. + - cmake .. # needed for darwin + - make + - make install + +.universal_linux_template: &universal_linux_definition + image: ventosus/universal-linux-gnu + <<: *build_definition + +.arm_linux_template: &arm_linux_definition + image: ventosus/arm-linux-gnueabihf + <<: *build_definition + +.universal_w64_template: &universal_w64_definition + image: ventosus/universal-w64-mingw32 + <<: *build_definition + +.universal_apple_template: &universal_apple_definition + image: ventosus/universal-apple-darwin + <<: *build_definition + +# building in docker +x86_64-linux-gnu: + <<: *universal_linux_definition + +i686-linux-gnu: + <<: *universal_linux_definition + +arm-linux-gnueabihf: + <<: *arm_linux_definition + +x86_64-w64-mingw32: + <<: *universal_w64_definition + +i686-w64-mingw32: + <<: *universal_w64_definition + +universal-apple-darwin: + <<: *universal_apple_definition + +pack: + <<: *variables_definition + stage: deploy + script: + - echo 'packing up...' + artifacts: + name: "${BASE_NAME}-$(cat VERSION)" + paths: + - "${BASE_NAME}-$(cat VERSION)/" diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..ddb9a463 --- /dev/null +++ b/COPYING @@ -0,0 +1,201 @@ + The Artistic License 2.0 + + Copyright (c) 2000-2006, The Perl Foundation. + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +Preamble + +This license establishes the terms under which a given free software +Package may be copied, modified, distributed, and/or redistributed. +The intent is that the Copyright Holder maintains some artistic +control over the development of that Package while still keeping the +Package available as open source and free software. + +You are always permitted to make arrangements wholly outside of this +license directly with the Copyright Holder of a given Package. If the +terms of this license do not permit the full use that you propose to +make of the Package, you should contact the Copyright Holder and seek +a different licensing arrangement. + +Definitions + + "Copyright Holder" means the individual(s) or organization(s) + named in the copyright notice for the entire Package. + + "Contributor" means any party that has contributed code or other + material to the Package, in accordance with the Copyright Holder's + procedures. + + "You" and "your" means any person who would like to copy, + distribute, or modify the Package. + + "Package" means the collection of files distributed by the + Copyright Holder, and derivatives of that collection and/or of + those files. A given Package may consist of either the Standard + Version, or a Modified Version. + + "Distribute" means providing a copy of the Package or making it + accessible to anyone else, or in the case of a company or + organization, to others outside of your company or organization. + + "Distributor Fee" means any fee that you charge for Distributing + this Package or providing support for this Package to another + party. It does not mean licensing fees. + + "Standard Version" refers to the Package if it has not been + modified, or has been modified only in ways explicitly requested + by the Copyright Holder. + + "Modified Version" means the Package, if it has been changed, and + such changes were not explicitly requested by the Copyright + Holder. + + "Original License" means this Artistic License as Distributed with + the Standard Version of the Package, in its current version or as + it may be modified by The Perl Foundation in the future. + + "Source" form means the source code, documentation source, and + configuration files for the Package. + + "Compiled" form means the compiled bytecode, object code, binary, + or any other form resulting from mechanical transformation or + translation of the Source form. + + +Permission for Use and Modification Without Distribution + +(1) You are permitted to use the Standard Version and create and use +Modified Versions for any purpose without restriction, provided that +you do not Distribute the Modified Version. + + +Permissions for Redistribution of the Standard Version + +(2) You may Distribute verbatim copies of the Source form of the +Standard Version of this Package in any medium without restriction, +either gratis or for a Distributor Fee, provided that you duplicate +all of the original copyright notices and associated disclaimers. At +your discretion, such verbatim copies may or may not include a +Compiled form of the Package. + +(3) You may apply any bug fixes, portability changes, and other +modifications made available from the Copyright Holder. The resulting +Package will still be considered the Standard Version, and as such +will be subject to the Original License. + + +Distribution of Modified Versions of the Package as Source + +(4) You may Distribute your Modified Version as Source (either gratis +or for a Distributor Fee, and with or without a Compiled form of the +Modified Version) provided that you clearly document how it differs +from the Standard Version, including, but not limited to, documenting +any non-standard features, executables, or modules, and provided that +you do at least ONE of the following: + + (a) make the Modified Version available to the Copyright Holder + of the Standard Version, under the Original License, so that the + Copyright Holder may include your modifications in the Standard + Version. + + (b) ensure that installation of your Modified Version does not + prevent the user installing or running the Standard Version. In + addition, the Modified Version must bear a name that is different + from the name of the Standard Version. + + (c) allow anyone who receives a copy of the Modified Version to + make the Source form of the Modified Version available to others + under + + (i) the Original License or + + (ii) a license that permits the licensee to freely copy, + modify and redistribute the Modified Version using the same + licensing terms that apply to the copy that the licensee + received, and requires that the Source form of the Modified + Version, and of any works derived from it, be made freely + available in that license fees are prohibited but Distributor + Fees are allowed. + + +Distribution of Compiled Forms of the Standard Version +or Modified Versions without the Source + +(5) You may Distribute Compiled forms of the Standard Version without +the Source, provided that you include complete instructions on how to +get the Source of the Standard Version. Such instructions must be +valid at the time of your distribution. If these instructions, at any +time while you are carrying out such distribution, become invalid, you +must provide new instructions on demand or cease further distribution. +If you provide valid instructions or cease distribution within thirty +days after you become aware that the instructions are invalid, then +you do not forfeit any of your rights under this license. + +(6) You may Distribute a Modified Version in Compiled form without +the Source, provided that you comply with Section 4 with respect to +the Source of the Modified Version. + + +Aggregating or Linking the Package + +(7) You may aggregate the Package (either the Standard Version or +Modified Version) with other packages and Distribute the resulting +aggregation provided that you do not charge a licensing fee for the +Package. Distributor Fees are permitted, and licensing fees for other +components in the aggregation are permitted. The terms of this license +apply to the use and Distribution of the Standard or Modified Versions +as included in the aggregation. + +(8) You are permitted to link Modified and Standard Versions with +other works, to embed the Package in a larger work of your own, or to +build stand-alone binary or bytecode versions of applications that +include the Package, and Distribute the result without restriction, +provided the result does not expose a direct interface to the Package. + + +Items That are Not Considered Part of a Modified Version + +(9) Works (including, but not limited to, modules and scripts) that +merely extend or make use of the Package, do not, by themselves, cause +the Package to be a Modified Version. In addition, such works are not +considered parts of the Package itself, and are not subject to the +terms of this license. + + +General Provisions + +(10) Any use, modification, and distribution of the Standard or +Modified Versions is governed by this Artistic License. By using, +modifying or distributing the Package, you accept this license. Do not +use, modify, or distribute the Package, if you do not accept this +license. + +(11) If your Modified Version has been derived from a Modified +Version made by someone other than you, you are nevertheless required +to ensure that your Modified Version complies with the requirements of +this license. + +(12) This license does not grant you the right to use any trademark, +service mark, tradename, or logo of the Copyright Holder. + +(13) This license includes the non-exclusive, worldwide, +free-of-charge patent license to make, have made, use, offer to sell, +sell, import and otherwise transfer the Package with respect to any +patent claims licensable by the Copyright Holder that are necessarily +infringed by the Package. If you institute patent litigation +(including a cross-claim or counterclaim) against any party alleging +that the Package constitutes direct or contributory patent +infringement, then this Artistic License to you shall terminate on the +date that such litigation is filed. + +(14) Disclaimer of Warranty: +THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS +IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL +LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 00000000..06b87f29 --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# Canvas LV2 plugin extension + +### License + +Copyright (c) 2016 Hanspeter Portner (dev@open-music-kontrollers.ch) + +This is free software: you can redistribute it and/or modify +it under the terms of the Artistic License 2.0 as published by +The Perl Foundation. + +This source is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +Artistic License 2.0 for more details. + +You should have received a copy of the Artistic License 2.0 +along the source as a COPYING file. If not, obtain it from +<http://www.perlfoundation.org/artistic_license_2_0>. diff --git a/canvas.lv2/canvas.h b/canvas.lv2/canvas.h new file mode 100644 index 00000000..7cca0fae --- /dev/null +++ b/canvas.lv2/canvas.h @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2016 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#ifndef _LV2_CANVAS_H +#define _LV2_CANVAS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <lv2/lv2plug.in/ns/lv2core/lv2.h> +#include <lv2/lv2plug.in/ns/ext/atom/atom.h> +#include <lv2/lv2plug.in/ns/ext/atom/forge.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__aspectRatio CANVAS_PREFIX"aspectRatio" + +// Graph properties and attributes +#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__PolyLine CANVAS_PREFIX"PolyLine" +#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__Transform CANVAS_PREFIX"Transform" +#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" + +// Input properties and attributes + +#define CANVAS__mouseButtonLeft CANVAS_PREFIX"mouseButtonLeft" +#define CANVAS__mouseButtonMiddle CANVAS_PREFIX"mouseButtonMiddle" +#define CANVAS__mouseButtonRight CANVAS_PREFIX"mouseButtonRight" +#define CANVAS__mouseWheelX CANVAS_PREFIX"mouseWheelX" +#define CANVAS__mouseWheelY CANVAS_PREFIX"mouseWheelY" +#define CANVAS__mousePositionX CANVAS_PREFIX"mousePositionX" +#define CANVAS__mousePositionY CANVAS_PREFIX"mousePositionY" +#define CANVAS__mouseFocus CANVAS_PREFIX"mouseFocus" + +typedef struct _LV2_Canvas_URID LV2_Canvas_URID; + +struct _LV2_Canvas_URID { + LV2_URID Canvas_graph; + LV2_URID Canvas_body; + LV2_URID Canvas_aspectRatio; + + 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_PolyLine; + 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_Transform; + 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; + + LV2_URID Canvas_mouseButtonLeft; + LV2_URID Canvas_mouseButtonMiddle; + LV2_URID Canvas_mouseButtonRight; + LV2_URID Canvas_mouseWheelX; + LV2_URID Canvas_mouseWheelY; + LV2_URID Canvas_mousePositionX; + LV2_URID Canvas_mousePositionY; + LV2_URID Canvas_mouseFocus; + + LV2_Atom_Forge forge; +}; + +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_aspectRatio = map->map(map->handle, CANVAS__aspectRatio); + + 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_PolyLine = map->map(map->handle, CANVAS__PolyLine); + 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_Transform = map->map(map->handle, CANVAS__Transform); + 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); + + urid->Canvas_mouseButtonLeft = map->map(map->handle, CANVAS__mouseButtonLeft); + urid->Canvas_mouseButtonMiddle = map->map(map->handle, CANVAS__mouseButtonMiddle); + urid->Canvas_mouseButtonRight = map->map(map->handle, CANVAS__mouseButtonRight); + urid->Canvas_mouseWheelX = map->map(map->handle, CANVAS__mouseWheelX); + urid->Canvas_mouseWheelY = map->map(map->handle, CANVAS__mouseWheelY); + urid->Canvas_mousePositionX = map->map(map->handle, CANVAS__mousePositionX); + urid->Canvas_mousePositionY = map->map(map->handle, CANVAS__mousePositionY); + urid->Canvas_mouseFocus = map->map(map->handle, CANVAS__mouseFocus); + + lv2_atom_forge_init(&urid->forge, map); +} + +#ifdef __cplusplus +} +#endif + +#endif // _LV2_CANVAS_H diff --git a/canvas.lv2/forge.h b/canvas.lv2/forge.h new file mode 100644 index 00000000..c5ce5fe0 --- /dev/null +++ b/canvas.lv2/forge.h @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2016 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#ifndef _LV2_CANVAS_FORGE_H +#define _LV2_CANVAS_FORGE_H + +#include <canvas.lv2/canvas.h> + +#ifdef __cplusplus +extern "C" { +#endif + +static inline LV2_Atom_Forge_Ref +_lv2_canvas_forge_simple(LV2_Atom_Forge *forge, LV2_URID otype) +{ + LV2_Atom_Forge_Ref ref; + LV2_Atom_Forge_Frame frame; + + ref = lv2_atom_forge_object(forge, &frame, 0, otype); + if(ref) + lv2_atom_forge_pop(forge, &frame); + + return ref; +} + +static inline LV2_Atom_Forge_Ref +_lv2_canvas_forge_vec(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + LV2_URID otype, uint32_t n, const float *vec) +{ + LV2_Atom_Forge_Ref ref; + LV2_Atom_Forge_Frame frame; + + ref = lv2_atom_forge_object(forge, &frame, 0, otype); + if(ref) + ref = lv2_atom_forge_key(forge, urid->Canvas_body); + if(ref) + ref = lv2_atom_forge_vector(forge, sizeof(float), forge->Float, n, vec); + if(ref) + lv2_atom_forge_pop(forge, &frame); + + return ref; +} + +static inline LV2_Atom_Forge_Ref +_lv2_canvas_forge_flt(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + LV2_URID otype, float flt) +{ + LV2_Atom_Forge_Ref ref; + LV2_Atom_Forge_Frame frame; + + ref = lv2_atom_forge_object(forge, &frame, 0, otype); + if(ref) + ref = lv2_atom_forge_key(forge, urid->Canvas_body); + if(ref) + ref = lv2_atom_forge_float(forge, flt); + if(ref) + lv2_atom_forge_pop(forge, &frame); + + return ref; +} + +static inline LV2_Atom_Forge_Ref +_lv2_canvas_forge_lng(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + LV2_URID otype, int64_t lng) +{ + LV2_Atom_Forge_Ref ref; + LV2_Atom_Forge_Frame frame; + + ref = lv2_atom_forge_object(forge, &frame, 0, otype); + if(ref) + ref = lv2_atom_forge_key(forge, urid->Canvas_body); + if(ref) + ref = lv2_atom_forge_long(forge, lng); + if(ref) + lv2_atom_forge_pop(forge, &frame); + + return ref; +} + +static inline LV2_Atom_Forge_Ref +_lv2_canvas_forge_prp(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + LV2_URID otype, LV2_URID prop) +{ + LV2_Atom_Forge_Ref ref; + LV2_Atom_Forge_Frame frame; + + ref = lv2_atom_forge_object(forge, &frame, 0, otype); + if(ref) + ref = lv2_atom_forge_key(forge, urid->Canvas_body); + if(ref) + ref = lv2_atom_forge_urid(forge, prop); + if(ref) + lv2_atom_forge_pop(forge, &frame); + + return ref; +} + +static inline LV2_Atom_Forge_Ref +_lv2_canvas_forge_str(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + LV2_URID otype, const char *text) +{ + LV2_Atom_Forge_Ref ref; + LV2_Atom_Forge_Frame frame; + + ref = lv2_atom_forge_object(forge, &frame, 0, otype); + 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); + + return ref; +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_beginPath(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid) +{ + return _lv2_canvas_forge_simple(forge, urid->Canvas_BeginPath); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_closePath(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid) +{ + return _lv2_canvas_forge_simple(forge, urid->Canvas_ClosePath); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_arc(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + float x, float y, float r, float a1, float a2) +{ + const float vec [5] = {x, y, r, a1, a2}; + + return _lv2_canvas_forge_vec(forge, urid, urid->Canvas_Arc, 5, vec); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_curveTo(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + float x1, float y1, float x2, float y2, float x3, float y3) +{ + const float vec [6] = {x1, y1, x2, y2, x3, y3}; + + return _lv2_canvas_forge_vec(forge, urid, urid->Canvas_CurveTo, 6, vec); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_lineTo(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + float x, float y) +{ + const float vec [2] = {x, y}; + + return _lv2_canvas_forge_vec(forge, urid, urid->Canvas_LineTo, 2, vec); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_moveTo(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + float x, float y) +{ + const float vec [2] = {x, y}; + + return _lv2_canvas_forge_vec(forge, urid, urid->Canvas_MoveTo, 2, vec); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_rectangle(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + float x, float y, float w, float h) +{ + const float vec [4] = {x, y, w, h}; + + return _lv2_canvas_forge_vec(forge, urid, urid->Canvas_Rectangle, 4, vec); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_polyLine(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + uint32_t n, const float *vec) +{ + return _lv2_canvas_forge_vec(forge, urid, urid->Canvas_PolyLine, n, vec); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_style(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + uint32_t style) +{ + return _lv2_canvas_forge_lng(forge, urid, urid->Canvas_Style, style); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_lineWidth(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + float line_width) +{ + return _lv2_canvas_forge_flt(forge, urid, urid->Canvas_LineWidth, line_width); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_lineDash(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + float dash_length, float separator_length) +{ + const float vec [2] = {dash_length, separator_length}; + + return _lv2_canvas_forge_vec(forge, urid, urid->Canvas_LineDash, 2, vec); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_lineCap(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + LV2_URID line_cap) +{ + return _lv2_canvas_forge_prp(forge, urid, urid->Canvas_LineCap, line_cap); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_lineJoin(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + LV2_URID line_join) +{ + return _lv2_canvas_forge_prp(forge, urid, urid->Canvas_LineJoin, line_join); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_miterLimit(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + float miter_limit) +{ + return _lv2_canvas_forge_flt(forge, urid, urid->Canvas_MiterLimit, miter_limit); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_stroke(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid) +{ + return _lv2_canvas_forge_simple(forge, urid->Canvas_Stroke); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_fill(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid) +{ + return _lv2_canvas_forge_simple(forge, urid->Canvas_Fill); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_clip(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid) +{ + return _lv2_canvas_forge_simple(forge, urid->Canvas_Clip); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_save(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid) +{ + return _lv2_canvas_forge_simple(forge, urid->Canvas_Save); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_restore(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid) +{ + return _lv2_canvas_forge_simple(forge, urid->Canvas_Restore); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_translate(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + float x, float y) +{ + const float vec [2] = {x, y}; + + return _lv2_canvas_forge_vec(forge, urid, urid->Canvas_Translate, 2, vec); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_scale(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + float w, float h) +{ + const float vec [2] = {w, h}; + + return _lv2_canvas_forge_vec(forge, urid, urid->Canvas_Scale, 2, vec); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_rotate(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + float a) +{ + return _lv2_canvas_forge_flt(forge, urid, urid->Canvas_Rotate, a); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_transform(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + float xx, float xy, float x0, float yy, float yx, float y0) +{ + const float vec [6] = {xx, xy, x0, yy, yx, y0}; + + return _lv2_canvas_forge_vec(forge, urid, urid->Canvas_Transform, 6, vec); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_reset(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid) +{ + return _lv2_canvas_forge_simple(forge, urid->Canvas_Reset); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_fontSize(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + float size) +{ + return _lv2_canvas_forge_flt(forge, urid, urid->Canvas_FontSize, size); +} + +static inline LV2_Atom_Forge_Ref +lv2_canvas_forge_fillText(LV2_Atom_Forge *forge, LV2_Canvas_URID *urid, + const char *text) +{ + return _lv2_canvas_forge_str(forge, urid, urid->Canvas_FillText, text); +} + +#ifdef __cplusplus +} +#endif + +#endif // _LV2_CANVAS_FORGE_H diff --git a/canvas.lv2/render.h b/canvas.lv2/render.h new file mode 100644 index 00000000..2882c877 --- /dev/null +++ b/canvas.lv2/render.h @@ -0,0 +1,592 @@ +/* + * Copyright (c) 2016 Hanspeter Portner (dev@open-music-kontrollers.ch) + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the Artistic License 2.0 as published by + * The Perl Foundation. + * + * This source is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Artistic License 2.0 for more details. + * + * You should have received a copy of the Artistic License 2.0 + * along the source as a COPYING file. If not, obtain it from + * http://www.perlfoundation.org/artistic_license_2_0. + */ + +#ifndef _LV2_CANVAS_RENDER_H +#define _LV2_CANVAS_RENDER_H + +#include <assert.h> + +#include <canvas.lv2/canvas.h> + +#include <cairo/cairo.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define LV2_CANVAS_NUM_METHODS 26 + +typedef struct _LV2_Canvas_Meth LV2_Canvas_Meth; +typedef struct _LV2_Canvas LV2_Canvas; +typedef void (*LV2_Canvas_Func)(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body); + +struct _LV2_Canvas_Meth { + LV2_URID command; + LV2_Canvas_Func func; +}; + +struct _LV2_Canvas { + LV2_Canvas_URID urid; + LV2_Canvas_Meth methods [LV2_CANVAS_NUM_METHODS]; +}; + +static inline const float * +_lv2_canvas_render_get_float_vecs(LV2_Canvas_URID *urid, 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); + *n = (vec->atom.type == urid->forge.Vector) + && (vec->body.child_type == urid->forge.Float) + && (vec->body.child_size == sizeof(float)) + ? (vec->atom.size - sizeof(LV2_Atom_Vector_Body)) / vec->body.child_size + : 0; + + return flt; +} + +static inline const float * +_lv2_canvas_render_get_float_vec(LV2_Canvas_URID *urid, const LV2_Atom *body, + uint32_t n) +{ + uint32_t N; + const float *flt = _lv2_canvas_render_get_float_vecs(urid, body, &N); + + return n == N ? flt : NULL; +} + +static inline const void * +_lv2_canvas_render_get_type(const LV2_Atom *body, LV2_URID type) +{ + return body->type == type + ? LV2_ATOM_BODY_CONST(body) + : NULL; +} + +static inline void +_lv2_canvas_render_beginPath(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + cairo_new_sub_path(ctx); +} + +static inline void +_lv2_canvas_render_closePath(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + cairo_close_path(ctx); +} + +static inline void +_lv2_canvas_render_arc(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + const float *v = _lv2_canvas_render_get_float_vec(urid, 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_Canvas_URID *urid, const LV2_Atom *body) +{ + const float *v = _lv2_canvas_render_get_float_vec(urid, 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_Canvas_URID *urid, const LV2_Atom *body) +{ + const float *v = _lv2_canvas_render_get_float_vec(urid, body, 2); + + if(v) + { + cairo_line_to(ctx, v[0], v[1]); + } +} + +static inline void +_lv2_canvas_render_moveTo(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + const float *v = _lv2_canvas_render_get_float_vec(urid, body, 2); + + if(v) + { + cairo_move_to(ctx, v[0], v[1]); + } +} + +static inline void +_lv2_canvas_render_rectangle(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + const float *v = _lv2_canvas_render_get_float_vec(urid, body, 4); + + if(v) + { + cairo_rectangle(ctx, v[0], v[1], v[2], v[3]); + } +} + +static inline void +_lv2_canvas_render_polyline(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + uint32_t N; + const float *v = _lv2_canvas_render_get_float_vecs(urid, body, &N); + + if(v) + { + for(uint32_t i = 0; i < 2; i += 2) + { + cairo_move_to(ctx, v[i], v[i+1]); + } + + for(uint32_t i = 2; i < N; i += 2) + { + cairo_line_to(ctx, v[i], v[i+1]); + } + } +} + +static inline void +_lv2_canvas_render_style(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + const int64_t *v = _lv2_canvas_render_get_type(body, urid->forge.Long); + + if(v) + { + const float r = (float)((*v >> 24) & 0xff) / 0xff; + const float g = (float)((*v >> 16) & 0xff) / 0xff; + const float b = (float)((*v >> 8) & 0xff) / 0xff; + const float a = (float)((*v >> 0) & 0xff) / 0xff; + + cairo_set_source_rgba(ctx, r, g, b, a); + } +} + +static inline void +_lv2_canvas_render_lineWidth(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + const float *v = _lv2_canvas_render_get_type(body, urid->forge.Float); + + if(v) + { + cairo_set_line_width(ctx, *v); + } +} + +static inline void +_lv2_canvas_render_lineDash(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + const float *v = _lv2_canvas_render_get_float_vec(urid, body, 2); + + if(v) + { + const double d[2] = {v[0], v[1]}; + cairo_set_dash(ctx, d, 2, 0); + } +} + +static inline void +_lv2_canvas_render_lineCap(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + const LV2_URID *v = _lv2_canvas_render_get_type(body, urid->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_lineCapSquare) + cap = CAIRO_LINE_CAP_SQUARE; + + cairo_set_line_cap(ctx, cap); + } +} + +static inline void +_lv2_canvas_render_lineJoin(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + const LV2_URID *v = _lv2_canvas_render_get_type(body, urid->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_Canvas_URID *urid, const LV2_Atom *body) +{ + const float *v = _lv2_canvas_render_get_type(body, urid->forge.Float); + + if(v) + { + cairo_set_miter_limit(ctx, *v); + } +} + +static inline void +_lv2_canvas_render_stroke(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + cairo_stroke(ctx); +} + +static inline void +_lv2_canvas_render_fill(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + cairo_fill(ctx); +} + +static inline void +_lv2_canvas_render_clip(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + cairo_clip(ctx); +} + +static inline void +_lv2_canvas_render_save(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + cairo_save(ctx); +} + +static inline void +_lv2_canvas_render_restore(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + cairo_restore(ctx); +} + +static inline void +_lv2_canvas_render_translate(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + const float *v = _lv2_canvas_render_get_float_vec(urid, body, 2); + + if(v) + { + cairo_translate(ctx, v[0], v[1]); + } +} + +static inline void +_lv2_canvas_render_scale(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + const float *v = _lv2_canvas_render_get_float_vec(urid, body, 2); + + if(v) + { + cairo_scale(ctx, v[0], v[1]); + } +} + +static inline void +_lv2_canvas_render_rotate(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + const float *v = _lv2_canvas_render_get_type(body, urid->forge.Float); + + if(v) + { + cairo_rotate(ctx, *v); + } +} + +static inline void +_lv2_canvas_render_transform(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + const float *v = _lv2_canvas_render_get_float_vec(urid, body, 6); + + if(v) + { + const cairo_matrix_t matrix = { + .xx = v[0], + .xy = v[1], + .x0 = v[2], + .yy = v[3], + .yx = v[4], + .y0 = v[5] + }; + + cairo_transform(ctx, &matrix); + } +} + +static inline void +_lv2_canvas_render_reset(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + cairo_identity_matrix(ctx); +} + +static inline void +_lv2_canvas_render_fontSize(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + const float *v = _lv2_canvas_render_get_type(body, urid->forge.Float); + + if(v) + { + cairo_set_font_size(ctx, *v); + } +} + +static inline void +_lv2_canvas_render_fillText(cairo_t *ctx, + LV2_Canvas_URID *urid, const LV2_Atom *body) +{ + const char *v = _lv2_canvas_render_get_type(body, urid->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_qsort(LV2_Canvas_Meth *A, int n) +{ + if(n < 2) + return; + + LV2_Canvas_Meth *p = A; + + int i = -1; + int j = n; + + while(true) + { + do { + i += 1; + } while(A[i].command < p->command); + + do { + j -= 1; + } while(A[j].command > p->command); + + if(i >= j) + break; + + const LV2_Canvas_Meth tmp = A[i]; + A[i] = A[j]; + A[j] = tmp; + } + + _lv2_canvas_qsort(A, j + 1); + _lv2_canvas_qsort(A + j + 1, n - j - 1); +} + +static inline LV2_Canvas_Meth * +_lv2_canvas_bsearch(LV2_URID p, LV2_Canvas_Meth *a, int n) +{ + LV2_Canvas_Meth *base = a; + + for(int 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_PolyLine; + canvas->methods[ptr++].func = _lv2_canvas_render_polyline; + + 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_Transform; + canvas->methods[ptr++].func = _lv2_canvas_render_transform; + + 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 == LV2_CANVAS_NUM_METHODS); + + _lv2_canvas_qsort(canvas->methods, LV2_CANVAS_NUM_METHODS); +} + +static inline bool +lv2_canvas_render(LV2_Canvas *canvas, cairo_t *ctx, const LV2_Atom_Tuple *tup) +{ + LV2_Canvas_URID *urid = &canvas->urid; + + if(!tup || (tup->atom.type != urid->forge.Tuple) ) + 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(&urid->forge, itm->type)) + { + const LV2_Atom_Object *obj = (const LV2_Atom_Object *)itm; + const LV2_Atom *body = NULL; + + lv2_atom_object_get(obj, urid->Canvas_body, &body, 0); + + LV2_Canvas_Meth *meth = _lv2_canvas_bsearch(obj->body.otype, + canvas->methods, LV2_CANVAS_NUM_METHODS); + + if(meth) + { + meth->func(ctx, urid, body); + } + } + } + + // save state + cairo_restore(ctx); + + // flush + cairo_surface_t *surface = cairo_get_target(ctx); + cairo_surface_flush(surface); + + return true; +} + +#ifdef __cplusplus +} +#endif + +#endif // CANVAS_IMPLEMENTATION |