diff options
author | Bent Bisballe Nyeng <deva@aasimon.org> | 2016-08-14 14:49:02 +0200 |
---|---|---|
committer | Bent Bisballe Nyeng <deva@aasimon.org> | 2016-08-14 14:49:02 +0200 |
commit | 7db0ce19674393a4dd9af3beed236038bcfa2e65 (patch) | |
tree | a9d1f410fbbac877919ef3a72ce0abd35eabaa43 | |
parent | a9eadcc1b483d5d30a8443e78fa4d84c8f18d6c3 (diff) |
Experimental inline display added.
-rw-r--r-- | inline-display.h | 101 | ||||
-rw-r--r-- | manifest.ttl | 2 | ||||
-rw-r--r-- | plugin.h | 26 | ||||
-rw-r--r-- | pluginlv2.cc | 39 | ||||
-rw-r--r-- | pluginlv2.h | 36 | ||||
-rw-r--r-- | plugintest.cc | 32 | ||||
-rw-r--r-- | plugintest.h | 8 |
7 files changed, 244 insertions, 0 deletions
diff --git a/inline-display.h b/inline-display.h new file mode 100644 index 0000000..886c3c8 --- /dev/null +++ b/inline-display.h @@ -0,0 +1,101 @@ +/* + Copyright 2012 David Robillard <http://drobilla.net> + Copyright 2016 Robin Gareus <robin@gareus.org> + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +/** + @defgroup inlinedisplay Inline-Display + Support for displaying a miniaturized, non-interactive view + in the host's mixer strip. + @{ +*/ + +#ifndef LV2_INLINE_DISPLAY_H +#define LV2_INLINE_DISPLAY_H + +#include <stdint.h> + +#include "lv2/lv2plug.in/ns/lv2core/lv2.h" + +#define LV2_INLINEDISPLAY_URI "http://harrisonconsoles.com/lv2/inlinedisplay" +#define LV2_INLINEDISPLAY_PREFIX LV2_INLINEDISPLAY_URI "#" +#define LV2_INLINEDISPLAY__interface LV2_INLINEDISPLAY_PREFIX "interface" +#define LV2_INLINEDISPLAY__queue_draw LV2_INLINEDISPLAY_PREFIX "queue_draw" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Opaque handle for LV2_Inline_Display::queue_draw() */ +typedef void* LV2_Inline_Display_Handle; + +/** raw image pixmap format is ARGB32, + * the data pointer is owned by the plugin and must be valid + * from the first call to render until cleanup. + */ +typedef struct { + unsigned char *data; + int width; + int height; + int stride; +} LV2_Inline_Display_Image_Surface; + +/** a LV2 Feature provided by the Host to the plugin + * + * This allows a the plugin during in realtime context to + * invalidate the currently displayed data and request from + * the host to call render() as soon as feasible. + */ +typedef struct { + /** Opaque host data */ + LV2_Inline_Display_Handle handle; + /** Request from run() that the host should call render() at a later + * time to update the inline display + */ + void (*queue_draw)(LV2_Inline_Display_Handle handle); +} LV2_Inline_Display; + +/** + * Plugin Inline-Display Interface. + */ +typedef struct { + /** + * The render method. This is called by the host in the main GUI thread + * (non realtime, the context with access to graphics drawing APIs). + * + * The data pointer is owned by the plugin and must be valid + * from the first call to render until cleanup. + * + * The host specifies a maxium available area for the plugin to draw. + * the returned Image Surface contains the actual area which + * the plugin allocated. + * + * @param instance The LV2 instance + * @param w the max available width + * @param h the max available height + * @return pointer to a LV2_Inline_Display_Image_Surface or NULL + */ + LV2_Inline_Display_Image_Surface* (*render)( + LV2_Handle instance, + uint32_t w, uint32_t h); +} LV2_Inline_Display_Interface; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LV2_INLINE_DISPLAY_H */ + +/** + @} +*/ diff --git a/manifest.ttl b/manifest.ttl index 61304ed..1468215 100644 --- a/manifest.ttl +++ b/manifest.ttl @@ -20,6 +20,7 @@ @prefix ui: <http://lv2plug.in/ns/extensions/ui#> . @prefix state: <http://lv2plug.in/ns/ext/state#> . @prefix pprops: <http://lv2plug.in/ns/ext/port-props#> . +@prefix idpy: <http://harrisonconsoles.com/lv2/inlinedisplay#> . @prefix lv2: <http://lv2plug.in/ns/lv2core#> . @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . @@ -34,6 +35,7 @@ <http://example.org/plugintest> a lv2:Plugin ; + lv2:optionalFeature idpy:queue_draw ; lv2:binary <plugintest_lv2.so> ; a lv2:InstrumentPlugin ; doap:name "LV2Test" ; @@ -139,6 +139,32 @@ public: // + // Inline GUI (optional) + // + + //! Return true if a GUI implementation is to be used. + virtual bool hasInlineGUI() + { + return false; + } + + struct InlineDrawContext + { + std::size_t width{0}; //< Width of the render buffer. + std::size_t height{0}; //< Height of the render buffer. + std::uint8_t* data{nullptr}; //< Allocated (or reused) RGBA buffer, filled by the plugin. + }; + + //! Render call back. + //! \param width The client area width as specified by the host. + //! \param max_height The maximum allowed clieant area height as specified + //! by the host. + //! \param context The render context filled an maintained by the plugin. + virtual void onInlineRedraw(std::size_t width, + std::size_t max_height, + InlineDrawContext& context) {} + + // // GUI (optional) // diff --git a/pluginlv2.cc b/pluginlv2.cc index 39d0e6c..c264223 100644 --- a/pluginlv2.cc +++ b/pluginlv2.cc @@ -114,6 +114,13 @@ LV2_Handle PluginLV2::instantiate(const struct _LV2_Descriptor* descriptor, plugin_lv2->map = (LV2_URID_Map*)data; } +#ifdef DISPLAY_INTERFACE + if(uri == LV2_INLINEDISPLAY__queue_draw) + { + plugin_lv2->queue_draw = (LV2_Inline_Display*)data; + } +#endif + ++features; } @@ -348,6 +355,13 @@ void PluginLV2::run(LV2_Handle instance, uint32_t sample_count) } plugin_lv2->pos += sample_count; + +#ifdef DISPLAY_INTERFACE + if(plugin_lv2->queue_draw) + { + plugin_lv2->queue_draw->queue_draw(plugin_lv2->queue_draw->handle); + } +#endif } void PluginLV2::activate(LV2_Handle instance) @@ -440,6 +454,23 @@ static LV2_State_Interface persist = { PluginLV2::restore }; +LV2_Inline_Display_Image_Surface* PluginLV2::inlineRender(LV2_Handle instance, + uint32_t w, + uint32_t max_h) +{ + PluginLV2* plugin_lv2 = (PluginLV2*)instance; + + plugin_lv2->onInlineRedraw(w, max_h, plugin_lv2->drawContext); + + plugin_lv2->surf.width = plugin_lv2->drawContext.width; + plugin_lv2->surf.height = plugin_lv2->drawContext.height; + plugin_lv2->surf.stride = plugin_lv2->surf.width; // no padding + + plugin_lv2->surf.data = plugin_lv2->drawContext.data; + + return &plugin_lv2->surf; +} + const void* PluginLV2::extensionData(const char *uri) { if(!strcmp(uri, LV2_STATE__interface)) @@ -447,6 +478,14 @@ const void* PluginLV2::extensionData(const char *uri) return &persist; } +#ifdef DISPLAY_INTERFACE + static const LV2_Inline_Display_Interface display = { inlineRender }; + if(!strcmp(uri, LV2_INLINEDISPLAY__interface)) + { + return &display; + } +#endif + return nullptr; } diff --git a/pluginlv2.h b/pluginlv2.h index da10ac3..ee80f7a 100644 --- a/pluginlv2.h +++ b/pluginlv2.h @@ -35,6 +35,12 @@ #include <lv2/lv2plug.in/ns/ext/dynmanifest/dynmanifest.h> #include <lv2/lv2plug.in/ns/extensions/ui/ui.h> +#define DISPLAY_INTERFACE + +#ifdef DISPLAY_INTERFACE +#include "inline-display.h" +#endif + enum class LV2Ports { FreeWheel = 0, @@ -126,6 +132,25 @@ public: std::size_t count) = 0; // + // Inline GUI (optional) + // + + //! Return true if a GUI implementation is to be used. + virtual bool hasInlineGUI() + { + return false; + } + + //! Render call back. + //! \param width The client area width as specified by the host. + //! \param max_height The maximum allowed clieant area height as specified + //! by the host. + //! \param context The render context filled an maintained by the plugin. + virtual void onInlineRedraw(std::size_t width, + std::size_t max_height, + InlineDrawContext& context) {} + + // // GUI (optional) // @@ -220,6 +245,17 @@ private: LV2_URID_Map* map{nullptr}; +#ifdef DISPLAY_INTERFACE + LV2_Inline_Display_Image_Surface surf; + LV2_Inline_Display* queue_draw{nullptr}; + + InlineDrawContext drawContext; + + static LV2_Inline_Display_Image_Surface *inlineRender(LV2_Handle instance, + uint32_t w, + uint32_t max_h); +#endif + bool active{false}; // diff --git a/plugintest.cc b/plugintest.cc index 48dad58..a23c44b 100644 --- a/plugintest.cc +++ b/plugintest.cc @@ -173,6 +173,38 @@ void PluginTest::process(size_t pos, } } +bool PluginTest::hasInlineGUI() +{ + return true; +} + +void PluginTest::onInlineRedraw(std::size_t width, + std::size_t max_height, + InlineDrawContext& context) +{ + std::size_t height = std::min(width / 2, max_height); + if (!context.data || (context.width != width)) + { + delete[] context.data; + context.data = new std::uint8_t[width * height * 4]; + } + + context.width = width; + context.height = height; + + for(std::size_t x = 0; x < context.width; ++x) + { + for(std::size_t y = 0; y < context.height; ++y) + { + unsigned char* p = context.data + ((x + y * context.width) * 4); + p[0] = 0; // B; + p[1] = 0; // G + p[2] = 255; // R + p[3] = 0; // A + } + } +} + bool PluginTest::hasGUI() { return true; diff --git a/plugintest.h b/plugintest.h index 294eecc..f750121 100644 --- a/plugintest.h +++ b/plugintest.h @@ -87,6 +87,14 @@ public: size_t count) override; // + // Inline GUI + // + bool hasInlineGUI() override; + void onInlineRedraw(std::size_t width, + std::size_t max_height, + InlineDrawContext& context) override; + + // // GUI // bool hasGUI() override; |