Signed-off-by: falkTX <falktx@falktx.com>tags/v1.5
@@ -29,22 +29,17 @@ ifneq ($(WINDOWS),true) | |||
ifneq (,$(findstring bsd,$(TARGET_MACHINE))) | |||
BSD=true | |||
endif | |||
ifneq (,$(findstring haiku,$(TARGET_MACHINE))) | |||
else ifneq (,$(findstring haiku,$(TARGET_MACHINE))) | |||
HAIKU=true | |||
endif | |||
ifneq (,$(findstring linux,$(TARGET_MACHINE))) | |||
else ifneq (,$(findstring linux,$(TARGET_MACHINE))) | |||
LINUX=true | |||
else ifneq (,$(findstring gnu,$(TARGET_MACHINE))) | |||
HURD=true | |||
endif | |||
ifneq (,$(findstring apple,$(TARGET_MACHINE))) | |||
else ifneq (,$(findstring apple,$(TARGET_MACHINE))) | |||
MACOS=true | |||
endif | |||
ifneq (,$(findstring mingw,$(TARGET_MACHINE))) | |||
else ifneq (,$(findstring mingw,$(TARGET_MACHINE))) | |||
WINDOWS=true | |||
endif | |||
ifneq (,$(findstring windows,$(TARGET_MACHINE))) | |||
else ifneq (,$(findstring windows,$(TARGET_MACHINE))) | |||
WINDOWS=true | |||
endif | |||
@@ -112,12 +112,29 @@ endif | |||
# Set plugin symbols to export | |||
ifeq ($(MACOS),true) | |||
SYMBOLS_LADSPA = -Wl,-exported_symbol,_ladspa_descriptor | |||
SYMBOLS_DSSI = -Wl,-exported_symbol,_ladspa_descriptor -Wl,-exported_symbol,_dssi_descriptor | |||
SYMBOLS_LV2 = -Wl,-exported_symbol,_lv2_descriptor -Wl,-exported_symbol,_lv2_generate_ttl | |||
SYMBOLS_LV2UI = -Wl,-exported_symbol,_lv2ui_descriptor | |||
SYMBOLS_VST2 = -Wl,-exported_symbol,_VSTPluginMain | |||
SYMBOLS_VST3 = -Wl,-exported_symbol,_GetPluginFactory -Wl,-exported_symbol,_bundleEntry -Wl,-exported_symbol,_bundleExit | |||
SYMBOLS_LADSPA = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/ladspa.exp | |||
SYMBOLS_DSSI = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/dssi.exp | |||
SYMBOLS_LV2DSP = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/lv2-dsp.exp | |||
SYMBOLS_LV2UI = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/lv2-ui.exp | |||
SYMBOLS_LV2 = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/lv2.exp | |||
SYMBOLS_VST2 = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/vst2.exp | |||
SYMBOLS_VST3 = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/vst3.exp | |||
else ifeq ($(WINDOWS),true) | |||
SYMBOLS_LADSPA = $(DPF_PATH)/utils/symbols/ladspa.def | |||
SYMBOLS_DSSI = $(DPF_PATH)/utils/symbols/dssi.def | |||
SYMBOLS_LV2DSP = $(DPF_PATH)/utils/symbols/lv2-dsp.def | |||
SYMBOLS_LV2UI = $(DPF_PATH)/utils/symbols/lv2-ui.def | |||
SYMBOLS_LV2 = $(DPF_PATH)/utils/symbols/lv2.def | |||
SYMBOLS_VST2 = $(DPF_PATH)/utils/symbols/vst2.def | |||
SYMBOLS_VST3 = $(DPF_PATH)/utils/symbols/vst3.def | |||
else | |||
SYMBOLS_LADSPA = -Wl,--version-script=$(DPF_PATH)/utils/symbols/ladspa.version | |||
SYMBOLS_DSSI = -Wl,--version-script=$(DPF_PATH)/utils/symbols/dssi.version | |||
SYMBOLS_LV2DSP = -Wl,--version-script=$(DPF_PATH)/utils/symbols/lv2-dsp.version | |||
SYMBOLS_LV2UI = -Wl,--version-script=$(DPF_PATH)/utils/symbols/lv2-ui.version | |||
SYMBOLS_LV2 = -Wl,--version-script=$(DPF_PATH)/utils/symbols/lv2.version | |||
SYMBOLS_VST2 = -Wl,--version-script=$(DPF_PATH)/utils/symbols/vst2.version | |||
SYMBOLS_VST3 = -Wl,--version-script=$(DPF_PATH)/utils/symbols/vst3.version | |||
endif | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
@@ -337,12 +354,12 @@ $(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o | |||
endif | |||
-@mkdir -p $(shell dirname $@) | |||
@echo "Creating LV2 plugin for $(NAME)" | |||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_LV2) $(SYMBOLS_LV2UI) -o $@ | |||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_LV2) -o $@ | |||
$(lv2_dsp): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o | |||
-@mkdir -p $(shell dirname $@) | |||
@echo "Creating LV2 plugin library for $(NAME)" | |||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(SHARED) $(SYMBOLS_LV2) -o $@ | |||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(SHARED) $(SYMBOLS_LV2DSP) -o $@ | |||
$(lv2_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) | |||
-@mkdir -p $(shell dirname $@) | |||
@@ -206,6 +206,7 @@ function(dpf__build_ladspa NAME) | |||
dpf__add_module("${NAME}-ladspa" ${_no_srcs}) | |||
dpf__add_plugin_main("${NAME}-ladspa" "ladspa") | |||
dpf__set_module_export_list("${NAME}-ladspa" "ladspa") | |||
target_link_libraries("${NAME}-ladspa" PRIVATE "${NAME}-dsp") | |||
set_target_properties("${NAME}-ladspa" PROPERTIES | |||
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>" | |||
@@ -234,6 +235,7 @@ function(dpf__build_dssi NAME DGL_LIBRARY) | |||
dpf__add_module("${NAME}-dssi" ${_no_srcs}) | |||
dpf__add_plugin_main("${NAME}-dssi" "dssi") | |||
dpf__set_module_export_list("${NAME}-dssi" "dssi") | |||
target_link_libraries("${NAME}-dssi" PRIVATE "${NAME}-dsp") | |||
set_target_properties("${NAME}-dssi" PROPERTIES | |||
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>" | |||
@@ -264,6 +266,11 @@ function(dpf__build_lv2 NAME DGL_LIBRARY MONOLITHIC) | |||
dpf__add_module("${NAME}-lv2" ${_no_srcs}) | |||
dpf__add_plugin_main("${NAME}-lv2" "lv2") | |||
if(DGL_LIBRARY AND MONOLITHIC) | |||
dpf__set_module_export_list("${NAME}-lv2" "lv2") | |||
else() | |||
dpf__set_module_export_list("${NAME}-lv2" "lv2-dsp") | |||
endif() | |||
target_link_libraries("${NAME}-lv2" PRIVATE "${NAME}-dsp") | |||
set_target_properties("${NAME}-lv2" PROPERTIES | |||
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.lv2/$<0:>" | |||
@@ -280,6 +287,7 @@ function(dpf__build_lv2 NAME DGL_LIBRARY MONOLITHIC) | |||
else() | |||
dpf__add_module("${NAME}-lv2-ui" ${_no_srcs}) | |||
dpf__add_ui_main("${NAME}-lv2-ui" "lv2" "${DGL_LIBRARY}") | |||
dpf__set_module_export_list("${NAME}-lv2-ui" "lv2-ui") | |||
target_link_libraries("${NAME}-lv2-ui" PRIVATE "${NAME}-ui") | |||
set_target_properties("${NAME}-lv2-ui" PROPERTIES | |||
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.lv2/$<0:>" | |||
@@ -311,6 +319,7 @@ function(dpf__build_vst2 NAME DGL_LIBRARY) | |||
dpf__add_module("${NAME}-vst2" ${_no_srcs}) | |||
dpf__add_plugin_main("${NAME}-vst2" "vst2") | |||
dpf__add_ui_main("${NAME}-vst2" "vst2" "${DGL_LIBRARY}") | |||
dpf__set_module_export_list("${NAME}-vst2" "vst2") | |||
target_link_libraries("${NAME}-vst2" PRIVATE "${NAME}-dsp" "${NAME}-ui") | |||
set_target_properties("${NAME}-vst2" PROPERTIES | |||
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>" | |||
@@ -566,6 +575,24 @@ function(dpf__add_static_library NAME) | |||
dpf__set_target_defaults("${NAME}") | |||
endfunction() | |||
# dpf__set_module_export_list | |||
# ------------------------------------------------------------------------------ | |||
# | |||
# Applies a list of exported symbols to the module target. | |||
# | |||
function(dpf__set_module_export_list NAME EXPORTS) | |||
if(WIN32) | |||
target_sources("${NAME}" PRIVATE "${DPF_ROOT_DIR}/utils/symbols/${EXPORTS}.def") | |||
elseif(APPLE) | |||
set_property(TARGET "${NAME}" APPEND PROPERTY LINK_OPTIONS | |||
"-Xlinker" "-exported_symbols_list" | |||
"-Xlinker" "${DPF_ROOT_DIR}/utils/symbols/${EXPORTS}.exp") | |||
else() | |||
set_property(TARGET "${NAME}" APPEND PROPERTY LINK_OPTIONS | |||
"-Xlinker" "--version-script=${DPF_ROOT_DIR}/utils/symbols/${EXPORTS}.version") | |||
endif() | |||
endfunction() | |||
# dpf__set_target_defaults | |||
# ------------------------------------------------------------------------------ | |||
# | |||
@@ -582,12 +582,26 @@ public: | |||
NanoImage::Handle createImageFromMemory(uchar* data, uint dataSize, int imageFlags); | |||
/** | |||
Creates image from specified image data. | |||
Creates image from specified raw format image data. | |||
*/ | |||
NanoImage::Handle createImageFromRawMemory(uint w, uint h, const uchar* data, | |||
ImageFlags imageFlags, ImageFormat format); | |||
/** | |||
Creates image from specified raw format image data. | |||
Overloaded function for convenience. | |||
@see ImageFlags | |||
*/ | |||
NanoImage::Handle createImageFromRawMemory(uint w, uint h, const uchar* data, | |||
int imageFlags, ImageFormat format); | |||
/** | |||
Creates image from specified RGBA image data. | |||
*/ | |||
NanoImage::Handle createImageFromRGBA(uint w, uint h, const uchar* data, ImageFlags imageFlags); | |||
/** | |||
Creates image from specified image data. | |||
Creates image from specified RGBA image data. | |||
Overloaded function for convenience. | |||
@see ImageFlags | |||
*/ | |||
@@ -382,6 +382,13 @@ public: | |||
*/ | |||
void repaint(const Rectangle<uint>& rect) noexcept; | |||
/** | |||
Render this window's content into a picture file, specified by @a filename. | |||
Window must be visible and on screen. | |||
Written picture format is PPM. | |||
*/ | |||
void renderToPicture(const char* filename); | |||
/** | |||
Run this window as a modal, blocking input events from the parent. | |||
Only valid for windows that have been created with another window as parent (as passed in the constructor). | |||
@@ -808,6 +808,13 @@ void TopLevelWidget::PrivateData::display() | |||
// ----------------------------------------------------------------------- | |||
void Window::PrivateData::renderToPicture(const char*, const GraphicsContext&, uint, uint) | |||
{ | |||
notImplemented("Window::PrivateData::renderToPicture"); | |||
} | |||
// ----------------------------------------------------------------------- | |||
const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | |||
{ | |||
GraphicsContext& context((GraphicsContext&)graphicsContext); | |||
@@ -215,6 +215,7 @@ NanoImage& NanoImage::operator=(const Handle& handle) | |||
fHandle.context = handle.context; | |||
fHandle.imageId = handle.imageId; | |||
_updateSize(); | |||
return *this; | |||
} | |||
@@ -631,6 +632,45 @@ NanoImage::Handle NanoVG::createImageFromMemory(uchar* data, uint dataSize, int | |||
return NanoImage::Handle(fContext, nvgCreateImageMem(fContext, imageFlags, data,static_cast<int>(dataSize))); | |||
} | |||
NanoImage::Handle NanoVG::createImageFromRawMemory(uint w, uint h, const uchar* data, | |||
ImageFlags imageFlags, ImageFormat format) | |||
{ | |||
return createImageFromRawMemory(w, h, data, static_cast<int>(imageFlags), format); | |||
} | |||
NanoImage::Handle NanoVG::createImageFromRawMemory(uint w, uint h, const uchar* data, | |||
int imageFlags, ImageFormat format) | |||
{ | |||
if (fContext == nullptr) return NanoImage::Handle(); | |||
DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, NanoImage::Handle()); | |||
NVGtexture nvgformat; | |||
switch (format) | |||
{ | |||
case kImageFormatGrayscale: | |||
nvgformat = NVG_TEXTURE_ALPHA; | |||
break; | |||
case kImageFormatBGR: | |||
nvgformat = NVG_TEXTURE_BGR; | |||
break; | |||
case kImageFormatBGRA: | |||
nvgformat = NVG_TEXTURE_BGRA; | |||
break; | |||
case kImageFormatRGB: | |||
nvgformat = NVG_TEXTURE_RGB; | |||
break; | |||
case kImageFormatRGBA: | |||
nvgformat = NVG_TEXTURE_RGBA; | |||
break; | |||
default: | |||
return NanoImage::Handle(); | |||
} | |||
return NanoImage::Handle(fContext, nvgCreateImageRaw(fContext, | |||
static_cast<int>(w), | |||
static_cast<int>(h), imageFlags, nvgformat, data)); | |||
} | |||
NanoImage::Handle NanoVG::createImageFromRGBA(uint w, uint h, const uchar* data, ImageFlags imageFlags) | |||
{ | |||
return createImageFromRGBA(w, h, data, static_cast<int>(imageFlags)); | |||
@@ -646,12 +686,14 @@ NanoImage::Handle NanoVG::createImageFromRGBA(uint w, uint h, const uchar* data, | |||
static_cast<int>(h), imageFlags, data)); | |||
} | |||
NanoImage::Handle NanoVG::createImageFromTextureHandle(GLuint textureId, uint w, uint h, ImageFlags imageFlags, bool deleteTexture) | |||
NanoImage::Handle NanoVG::createImageFromTextureHandle(GLuint textureId, uint w, uint h, | |||
ImageFlags imageFlags, bool deleteTexture) | |||
{ | |||
return createImageFromTextureHandle(textureId, w, h, static_cast<int>(imageFlags), deleteTexture); | |||
} | |||
NanoImage::Handle NanoVG::createImageFromTextureHandle(GLuint textureId, uint w, uint h, int imageFlags, bool deleteTexture) | |||
NanoImage::Handle NanoVG::createImageFromTextureHandle(GLuint textureId, uint w, uint h, | |||
int imageFlags, bool deleteTexture) | |||
{ | |||
if (fContext == nullptr) return NanoImage::Handle(); | |||
DISTRHO_SAFE_ASSERT_RETURN(textureId != 0, NanoImage::Handle()); | |||
@@ -667,6 +667,36 @@ void TopLevelWidget::PrivateData::display() | |||
// ----------------------------------------------------------------------- | |||
void Window::PrivateData::renderToPicture(const char* const filename, | |||
const GraphicsContext&, | |||
const uint width, | |||
const uint height) | |||
{ | |||
FILE* const f = fopen(filename, "w"); | |||
DISTRHO_SAFE_ASSERT_RETURN(f != nullptr,); | |||
GLubyte* const pixels = new GLubyte[width * height * 3 * sizeof(GLubyte)]; | |||
glFlush(); | |||
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels); | |||
fprintf(f, "P3\n%d %d\n255\n", width, height); | |||
for (uint y = 0; y < height; y++) | |||
{ | |||
for (uint i, x = 0; x < width; x++) | |||
{ | |||
i = 3 * ((height - y - 1) * width + x); | |||
fprintf(f, "%3d %3d %3d ", pixels[i], pixels[i+1], pixels[i+2]); | |||
} | |||
fprintf(f, "\n"); | |||
} | |||
delete[] pixels; | |||
fclose(f); | |||
} | |||
// ----------------------------------------------------------------------- | |||
const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | |||
{ | |||
return (const GraphicsContext&)graphicsContext; | |||
@@ -231,6 +231,13 @@ void TopLevelWidget::PrivateData::display() | |||
// ----------------------------------------------------------------------- | |||
void Window::PrivateData::renderToPicture(const char*, const GraphicsContext&, uint, uint) | |||
{ | |||
notImplemented("Window::PrivateData::renderToPicture"); | |||
} | |||
// ----------------------------------------------------------------------- | |||
const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | |||
{ | |||
return (const GraphicsContext&)graphicsContext; | |||
@@ -336,6 +336,11 @@ void Window::repaint(const Rectangle<uint>& rect) noexcept | |||
puglPostRedisplayRect(pData->view, prect); | |||
} | |||
void Window::renderToPicture(const char* const filename) | |||
{ | |||
pData->filenameToRenderInto = strdup(filename); | |||
} | |||
void Window::runAsModal(bool blockWait) | |||
{ | |||
pData->runAsModal(blockWait); | |||
@@ -95,6 +95,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s) | |||
minHeight(0), | |||
keepAspectRatio(false), | |||
ignoreIdleCallbacks(false), | |||
filenameToRenderInto(nullptr), | |||
#ifdef DISTRHO_OS_WINDOWS | |||
win32SelectedFile(nullptr), | |||
#endif | |||
@@ -120,6 +121,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c | |||
minHeight(0), | |||
keepAspectRatio(false), | |||
ignoreIdleCallbacks(false), | |||
filenameToRenderInto(nullptr), | |||
#ifdef DISTRHO_OS_WINDOWS | |||
win32SelectedFile(nullptr), | |||
#endif | |||
@@ -149,6 +151,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||
minHeight(0), | |||
keepAspectRatio(false), | |||
ignoreIdleCallbacks(false), | |||
filenameToRenderInto(nullptr), | |||
#ifdef DISTRHO_OS_WINDOWS | |||
win32SelectedFile(nullptr), | |||
#endif | |||
@@ -180,6 +183,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||
minHeight(0), | |||
keepAspectRatio(false), | |||
ignoreIdleCallbacks(false), | |||
filenameToRenderInto(nullptr), | |||
#ifdef DISTRHO_OS_WINDOWS | |||
win32SelectedFile(nullptr), | |||
#endif | |||
@@ -195,6 +199,7 @@ Window::PrivateData::~PrivateData() | |||
{ | |||
appData->idleCallbacks.remove(this); | |||
appData->windows.remove(self); | |||
std::free(filenameToRenderInto); | |||
if (view == nullptr) | |||
return; | |||
@@ -743,6 +748,14 @@ void Window::PrivateData::onPuglExpose() | |||
if (widget->isVisible()) | |||
widget->pData->display(); | |||
} | |||
if (char* const filename = filenameToRenderInto) | |||
{ | |||
const PuglRect rect = puglGetFrame(view); | |||
filenameToRenderInto = nullptr; | |||
renderToPicture(filename, getGraphicsContext(), static_cast<uint>(rect.width), static_cast<uint>(rect.height)); | |||
std::free(filename); | |||
} | |||
#endif | |||
} | |||
@@ -77,6 +77,9 @@ struct Window::PrivateData : IdleCallback { | |||
/** Whether to ignore idle callback requests, useful for temporary windows. */ | |||
bool ignoreIdleCallbacks; | |||
/** Render to a picture file when non-null, automatically free+unset after saving. */ | |||
char* filenameToRenderInto; | |||
#ifdef DISTRHO_OS_WINDOWS | |||
/** Selected file for openFileBrowser on windows, stored for fake async operation. */ | |||
const char* win32SelectedFile; | |||
@@ -162,6 +165,8 @@ struct Window::PrivateData : IdleCallback { | |||
# endif | |||
#endif | |||
static void renderToPicture(const char* filename, const GraphicsContext& context, uint width, uint height); | |||
// modal handling | |||
void startModal(); | |||
void stopModal(); | |||
@@ -817,9 +817,14 @@ int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, unsigned char* data, int | |||
return image; | |||
} | |||
int nvgCreateImageRaw(NVGcontext* ctx, int w, int h, int imageFlags, NVGtexture format, const unsigned char* data) | |||
{ | |||
return ctx->params.renderCreateTexture(ctx->params.userPtr, format, w, h, imageFlags, data); | |||
} | |||
int nvgCreateImageRGBA(NVGcontext* ctx, int w, int h, int imageFlags, const unsigned char* data) | |||
{ | |||
return ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_RGBA, w, h, imageFlags, data); | |||
return nvgCreateImageRaw(ctx, w, h, imageFlags, NVG_TEXTURE_RGBA, data); | |||
} | |||
void nvgUpdateImage(NVGcontext* ctx, int image, const unsigned char* data) | |||
@@ -144,6 +144,14 @@ enum NVGimageFlags { | |||
NVG_IMAGE_NEAREST = 1<<5, // Image interpolation is Nearest instead Linear | |||
}; | |||
enum NVGtexture { | |||
NVG_TEXTURE_ALPHA, | |||
NVG_TEXTURE_BGR, | |||
NVG_TEXTURE_BGRA, | |||
NVG_TEXTURE_RGB, | |||
NVG_TEXTURE_RGBA, | |||
}; | |||
// Begin drawing a new frame | |||
// Calls to nanovg drawing API should be wrapped in nvgBeginFrame() & nvgEndFrame() | |||
// nvgBeginFrame() defines the size of the window to render to in relation currently | |||
@@ -375,6 +383,10 @@ int nvgCreateImage(NVGcontext* ctx, const char* filename, int imageFlags); | |||
// Returns handle to the image. | |||
int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, unsigned char* data, int ndata); | |||
// Creates image from specified image data and texture format. | |||
// Returns handle to the image. | |||
int nvgCreateImageRaw(NVGcontext* ctx, int w, int h, int imageFlags, NVGtexture format, const unsigned char* data); | |||
// Creates image from specified image data. | |||
// Returns handle to the image. | |||
int nvgCreateImageRGBA(NVGcontext* ctx, int w, int h, int imageFlags, const unsigned char* data); | |||
@@ -627,11 +639,6 @@ int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, floa | |||
// | |||
// Internal Render API | |||
// | |||
enum NVGtexture { | |||
NVG_TEXTURE_ALPHA = 0x01, | |||
NVG_TEXTURE_RGBA = 0x02, | |||
}; | |||
struct NVGscissor { | |||
float xform[6]; | |||
float extent[2]; | |||
@@ -761,9 +761,21 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im | |||
} | |||
#endif | |||
if (type == NVG_TEXTURE_RGBA) | |||
switch (type) | |||
{ | |||
case NVG_TEXTURE_BGR: | |||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGR, GL_UNSIGNED_BYTE, data); | |||
break; | |||
case NVG_TEXTURE_BGRA: | |||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, data); | |||
break; | |||
case NVG_TEXTURE_RGB: | |||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data); | |||
break; | |||
case NVG_TEXTURE_RGBA: | |||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); | |||
else | |||
break; | |||
default: | |||
#if defined(NANOVG_GLES2) || defined (NANOVG_GL2) | |||
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, w, h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); | |||
#elif defined(NANOVG_GLES3) | |||
@@ -771,6 +783,8 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im | |||
#else | |||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, data); | |||
#endif | |||
break; | |||
} | |||
if (imageFlags & NVG_IMAGE_GENERATE_MIPMAPS) { | |||
if (imageFlags & NVG_IMAGE_NEAREST) { | |||
@@ -845,22 +859,50 @@ static int glnvg__renderUpdateTexture(void* uptr, int image, int x, int y, int w | |||
glPixelStorei(GL_UNPACK_SKIP_ROWS, y); | |||
#else | |||
// No support for all of skip, need to update a whole row at a time. | |||
if (tex->type == NVG_TEXTURE_RGBA) | |||
switch (tex->type) | |||
{ | |||
case NVG_TEXTURE_BGR: | |||
data += y*tex->width*3; | |||
break; | |||
case NVG_TEXTURE_BGRA: | |||
data += y*tex->width*4; | |||
else | |||
break; | |||
case NVG_TEXTURE_RGB: | |||
data += y*tex->width*3; | |||
break; | |||
case NVG_TEXTURE_RGBA: | |||
data += y*tex->width*4; | |||
break; | |||
default: | |||
data += y*tex->width; | |||
break; | |||
} | |||
x = 0; | |||
w = tex->width; | |||
#endif | |||
if (tex->type == NVG_TEXTURE_RGBA) | |||
switch (tex->type) | |||
{ | |||
case NVG_TEXTURE_BGR: | |||
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_BGR, GL_UNSIGNED_BYTE, data); | |||
break; | |||
case NVG_TEXTURE_BGRA: | |||
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_BGRA, GL_UNSIGNED_BYTE, data); | |||
break; | |||
case NVG_TEXTURE_RGB: | |||
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RGB, GL_UNSIGNED_BYTE, data); | |||
break; | |||
case NVG_TEXTURE_RGBA: | |||
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RGBA, GL_UNSIGNED_BYTE, data); | |||
else | |||
break; | |||
default: | |||
#if defined(NANOVG_GLES2) || defined(NANOVG_GL2) | |||
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); | |||
#else | |||
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RED, GL_UNSIGNED_BYTE, data); | |||
#endif | |||
break; | |||
} | |||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); | |||
#ifndef NANOVG_GLES2 | |||
@@ -956,15 +998,31 @@ static int glnvg__convertPaint(GLNVGcontext* gl, GLNVGfragUniforms* frag, NVGpai | |||
frag->type = NSVG_SHADER_FILLIMG; | |||
#if NANOVG_GL_USE_UNIFORMBUFFER | |||
if (tex->type == NVG_TEXTURE_RGBA) | |||
switch (tex->type) | |||
{ | |||
case NVG_TEXTURE_BGR: | |||
case NVG_TEXTURE_BGRA: | |||
case NVG_TEXTURE_RGB: | |||
case NVG_TEXTURE_RGBA: | |||
frag->texType = (tex->flags & NVG_IMAGE_PREMULTIPLIED) ? 0 : 1; | |||
else | |||
break; | |||
default: | |||
frag->texType = 2; | |||
break; | |||
} | |||
#else | |||
if (tex->type == NVG_TEXTURE_RGBA) | |||
switch (tex->type) | |||
{ | |||
case NVG_TEXTURE_BGR: | |||
case NVG_TEXTURE_BGRA: | |||
case NVG_TEXTURE_RGB: | |||
case NVG_TEXTURE_RGBA: | |||
frag->texType = (tex->flags & NVG_IMAGE_PREMULTIPLIED) ? 0.0f : 1.0f; | |||
else | |||
break; | |||
default: | |||
frag->texType = 2.0f; | |||
break; | |||
} | |||
#endif | |||
// printf("frag->texType = %d\n", frag->texType); | |||
} else { | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* 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 | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* 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 | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* 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 | |||
@@ -44,11 +44,11 @@ START_NAMESPACE_DISTRHO | |||
Some important notes when using this class: | |||
1. MidiEvent::frame retains its original value, but it is useless, do not use it. | |||
2. The class variables names are be the same as the default ones in the run function. | |||
2. The class variable names are the same as the default ones in the run function. | |||
Keep that in mind and try to avoid typos. :) | |||
*/ | |||
class AudioMidiSyncHelper { | |||
public: | |||
struct AudioMidiSyncHelper | |||
{ | |||
/** Parameters from the run function, adjusted for event sync */ | |||
float* outputs[DISTRHO_PLUGIN_NUM_OUTPUTS]; | |||
uint32_t frames; | |||
@@ -618,6 +618,36 @@ public: | |||
return *this; | |||
} | |||
/* | |||
* Create a new string where all non-basic characters are converted to '_'. | |||
* @see toBasic() | |||
*/ | |||
String asBasic() const noexcept | |||
{ | |||
String s(*this); | |||
return s.toBasic(); | |||
} | |||
/* | |||
* Create a new string where all ascii characters are converted lowercase. | |||
* @see toLower() | |||
*/ | |||
String asLower() const noexcept | |||
{ | |||
String s(*this); | |||
return s.toLower(); | |||
} | |||
/* | |||
* Create a new string where all ascii characters are converted to uppercase. | |||
* @see toUpper() | |||
*/ | |||
String asUpper() const noexcept | |||
{ | |||
String s(*this); | |||
return s.toUpper(); | |||
} | |||
/* | |||
* Direct access to the string buffer (read-only). | |||
*/ | |||
@@ -146,12 +146,11 @@ | |||
// ----------------------------------------------------------------------- | |||
// Enable full state if plugin exports presets | |||
// FIXME | |||
// #if DISTRHO_PLUGIN_WANT_PROGRAMS && DISTRHO_PLUGIN_WANT_STATE && ! DISTRHO_PLUGIN_WANT_FULL_STATE | |||
// # warning Plugins with programs and state need to implement full state API | |||
// # undef DISTRHO_PLUGIN_WANT_FULL_STATE | |||
// # define DISTRHO_PLUGIN_WANT_FULL_STATE 1 | |||
// #endif | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS && DISTRHO_PLUGIN_WANT_STATE && ! DISTRHO_PLUGIN_WANT_FULL_STATE | |||
# warning Plugins with programs and state need to implement full state API too | |||
# undef DISTRHO_PLUGIN_WANT_FULL_STATE | |||
# define DISTRHO_PLUGIN_WANT_FULL_STATE 1 | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
// Disable UI if DGL or External UI is not available | |||
@@ -332,6 +332,7 @@ void lv2_generate_ttl(const char* const basename) | |||
pluginString += "@prefix doap: <http://usefulinc.com/ns/doap#> .\n"; | |||
pluginString += "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n"; | |||
pluginString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; | |||
pluginString += "@prefix midi: <" LV2_MIDI_PREFIX "> .\n"; | |||
pluginString += "@prefix mod: <http://moddevices.com/ns/mod#> .\n"; | |||
pluginString += "@prefix opts: <" LV2_OPTIONS_PREFIX "> .\n"; | |||
pluginString += "@prefix pg: <" LV2_PORT_GROUPS_PREFIX "> .\n"; | |||
@@ -341,6 +342,7 @@ void lv2_generate_ttl(const char* const basename) | |||
#if DISTRHO_LV2_USE_EVENTS_IN || DISTRHO_LV2_USE_EVENTS_OUT | |||
pluginString += "@prefix rsz: <" LV2_RESIZE_PORT_PREFIX "> .\n"; | |||
#endif | |||
pluginString += "@prefix spdx: <http://spdx.org/rdf/terms#> .\n"; | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
pluginString += "@prefix ui: <" LV2_UI_PREFIX "> .\n"; | |||
#endif | |||
@@ -368,11 +370,11 @@ void lv2_generate_ttl(const char* const basename) | |||
// plugin | |||
pluginString += "<" DISTRHO_PLUGIN_URI ">\n"; | |||
#ifdef DISTRHO_PLUGIN_LV2_CATEGORY | |||
pluginString += " a " DISTRHO_PLUGIN_LV2_CATEGORY ", lv2:Plugin ;\n"; | |||
pluginString += " a " DISTRHO_PLUGIN_LV2_CATEGORY ", lv2:Plugin, doap:Project ;\n"; | |||
#elif DISTRHO_PLUGIN_IS_SYNTH | |||
pluginString += " a lv2:InstrumentPlugin, lv2:Plugin ;\n"; | |||
pluginString += " a lv2:InstrumentPlugin, lv2:Plugin, doap:Project ;\n"; | |||
#else | |||
pluginString += " a lv2:Plugin ;\n"; | |||
pluginString += " a lv2:Plugin, doap:Project ;\n"; | |||
#endif | |||
pluginString += "\n"; | |||
@@ -594,10 +596,13 @@ void lv2_generate_ttl(const char* const basename) | |||
pluginString += " rsz:minimumSize " + String(DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE) + " ;\n"; | |||
pluginString += " atom:bufferType atom:Sequence ;\n"; | |||
# if (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI) | |||
pluginString += " atom:supports <" LV2_ATOM__String "> ;\n"; | |||
pluginString += " atom:supports atom:String ;\n"; | |||
# endif | |||
# if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
pluginString += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n"; | |||
pluginString += " atom:supports midi:MidiEvent ;\n"; | |||
# endif | |||
# if DISTRHO_PLUGIN_WANT_STATEFILES | |||
pluginString += " atom:supports <" LV2_PATCH__Message "> ;\n"; | |||
# endif | |||
# if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
pluginString += " atom:supports <" LV2_TIME__Position "> ;\n"; | |||
@@ -615,10 +620,13 @@ void lv2_generate_ttl(const char* const basename) | |||
pluginString += " rsz:minimumSize " + String(DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE) + " ;\n"; | |||
pluginString += " atom:bufferType atom:Sequence ;\n"; | |||
# if (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI) | |||
pluginString += " atom:supports <" LV2_ATOM__String "> ;\n"; | |||
pluginString += " atom:supports atom:String ;\n"; | |||
# endif | |||
# if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
pluginString += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n"; | |||
pluginString += " atom:supports midi:MidiEvent ;\n"; | |||
# endif | |||
# if DISTRHO_PLUGIN_WANT_STATEFILES | |||
pluginString += " atom:supports <" LV2_PATCH__Message "> ;\n"; | |||
# endif | |||
pluginString += " ] ;\n\n"; | |||
++portIndex; | |||
@@ -746,12 +754,22 @@ void lv2_generate_ttl(const char* const basename) | |||
} | |||
if (j+1 == enumValues.count) | |||
pluginString += " ] ;\n\n"; | |||
pluginString += " ] ;\n"; | |||
else | |||
pluginString += " ] ,\n"; | |||
} | |||
} | |||
// MIDI CC binding | |||
if (const uint8_t midiCC = plugin.getParameterMidiCC(i)) | |||
{ | |||
char midiCCBuf[7]; | |||
snprintf(midiCCBuf, sizeof(midiCCBuf), "B0%02x00", midiCC); | |||
pluginString += " midi:binding \""; | |||
pluginString += midiCCBuf; | |||
pluginString += "\"^^midi:MidiEvent ;\n"; | |||
} | |||
// unit | |||
const String& unit(plugin.getParameterUnit(i)); | |||
@@ -814,7 +832,7 @@ void lv2_generate_ttl(const char* const basename) | |||
} | |||
// hints | |||
const uint32_t hints(plugin.getParameterHints(i)); | |||
const uint32_t hints = plugin.getParameterHints(i); | |||
if (hints & kParameterIsBoolean) | |||
{ | |||
@@ -832,8 +850,6 @@ void lv2_generate_ttl(const char* const basename) | |||
pluginString += " <" LV2_KXSTUDIO_PROPERTIES__NonAutomable "> ;\n"; | |||
} | |||
// TODO midiCC | |||
// group | |||
const uint32_t groupId = plugin.getParameterGroupId(i); | |||
@@ -895,13 +911,154 @@ void lv2_generate_ttl(const char* const basename) | |||
{ | |||
const String license(plugin.getLicense()); | |||
// TODO always convert to URL, do best-guess based on known licenses | |||
// Using URL as license | |||
if (license.contains("://")) | |||
{ | |||
pluginString += " doap:license <" + license + "> ;\n\n"; | |||
} | |||
// String contaning quotes, use as-is | |||
else if (license.contains('"')) | |||
{ | |||
pluginString += " doap:license \"\"\"" + license + "\"\"\" ;\n\n"; | |||
} | |||
// Regular license string, convert to URL as much as we can | |||
else | |||
pluginString += " doap:license \"" + license + "\" ;\n\n"; | |||
{ | |||
const String uplicense(license.asUpper()); | |||
// for reference, see https://spdx.org/licenses/ | |||
// common licenses | |||
/**/ if (uplicense == "AGPL-1.0-ONLY" || | |||
uplicense == "AGPL1" || | |||
uplicense == "AGPLV1") | |||
{ | |||
pluginString += " doap:license <http://spdx.org/licenses/AGPL-1.0-only.html> ;\n\n"; | |||
} | |||
else if (uplicense == "AGPL-1.0-OR-LATER" || | |||
uplicense == "AGPL1+" || | |||
uplicense == "AGPLV1+") | |||
{ | |||
pluginString += " doap:license <http://spdx.org/licenses/AGPL-1.0-or-later.html> ;\n\n"; | |||
} | |||
else if (uplicense == "AGPL-3.0-ONLY" || | |||
uplicense == "AGPL3" || | |||
uplicense == "AGPLV3") | |||
{ | |||
pluginString += " doap:license <http://spdx.org/licenses/AGPL-3.0-only.html> ;\n\n"; | |||
} | |||
else if (uplicense == "AGPL-3.0-OR-LATER" || | |||
uplicense == "AGPL3+" || | |||
uplicense == "AGPLV3+") | |||
{ | |||
pluginString += " doap:license <http://spdx.org/licenses/AGPL-3.0-or-later.html> ;\n\n"; | |||
} | |||
else if (uplicense == "APACHE-2.0" || | |||
uplicense == "APACHE2" || | |||
uplicense == "APACHE-2") | |||
{ | |||
pluginString += " doap:license <http://spdx.org/licenses/Apache-2.0.html> ;\n\n"; | |||
} | |||
else if (uplicense == "BSD-2-CLAUSE" || | |||
uplicense == "BSD2" || | |||
uplicense == "BSD-2") | |||
{ | |||
pluginString += " doap:license <http://spdx.org/licenses/BSD-2-Clause.html> ;\n\n"; | |||
} | |||
else if (uplicense == "BSD-3-CLAUSE" || | |||
uplicense == "BSD3" || | |||
uplicense == "BSD-3") | |||
{ | |||
pluginString += " doap:license <http://spdx.org/licenses/BSD-3-Clause.html> ;\n\n"; | |||
} | |||
else if (uplicense == "GPL-2.0-ONLY" || | |||
uplicense == "GPL2" || | |||
uplicense == "GPLV2") | |||
{ | |||
pluginString += " doap:license <http://spdx.org/licenses/GPL-2.0-only.html> ;\n\n"; | |||
} | |||
else if (uplicense == "GPL-2.0-OR-LATER" || | |||
uplicense == "GPL2+" || | |||
uplicense == "GPLV2+" || | |||
uplicense == "GPL V2+") | |||
{ | |||
pluginString += " doap:license <http://spdx.org/licenses/GPL-2.0-or-later.html> ;\n\n"; | |||
} | |||
else if (uplicense == "GPL-3.0-ONLY" || | |||
uplicense == "GPL3" || | |||
uplicense == "GPLV3") | |||
{ | |||
pluginString += " doap:license <http://spdx.org/licenses/GPL-3.0-only.html> ;\n\n"; | |||
} | |||
else if (uplicense == "GPL-3.0-OR-LATER" || | |||
uplicense == "GPL3+" || | |||
uplicense == "GPLV3+" || | |||
uplicense == "GPL V3+") | |||
{ | |||
pluginString += " doap:license <http://spdx.org/licenses/GPL-3.0-or-later.html> ;\n\n"; | |||
} | |||
else if (uplicense == "ISC") | |||
{ | |||
pluginString += " doap:license <http://spdx.org/licenses/ISC.html> ;\n\n"; | |||
} | |||
else if (uplicense == "LGPL-2.0-ONLY" || | |||
uplicense == "LGPL2" || | |||
uplicense == "LGPLV2") | |||
{ | |||
pluginString += " doap:license <http://spdx.org/licenses/LGPL-2.0-only.html> ;\n\n"; | |||
} | |||
else if (uplicense == "LGPL-2.0-OR-LATER" || | |||
uplicense == "LGPL2+" || | |||
uplicense == "LGPLV2+") | |||
{ | |||
pluginString += " doap:license <http://spdx.org/licenses/LGPL-2.0-or-later.html> ;\n\n"; | |||
} | |||
else if (uplicense == "LGPL-2.1-ONLY" || | |||
uplicense == "LGPL2.1" || | |||
uplicense == "LGPLV2.1") | |||
{ | |||
pluginString += " doap:license <http://spdx.org/licenses/LGPL-2.1-only.html> ;\n\n"; | |||
} | |||
else if (uplicense == "LGPL-2.1-OR-LATER" || | |||
uplicense == "LGPL2.1+" || | |||
uplicense == "LGPLV2.1+") | |||
{ | |||
pluginString += " doap:license <http://spdx.org/licenses/LGPL-2.1-or-later.html> ;\n\n"; | |||
} | |||
else if (uplicense == "LGPL-3.0-ONLY" || | |||
uplicense == "LGPL3" || | |||
uplicense == "LGPLV3") | |||
{ | |||
pluginString += " doap:license <http://spdx.org/licenses/LGPL-2.0-only.html> ;\n\n"; | |||
} | |||
else if (uplicense == "LGPL-3.0-OR-LATER" || | |||
uplicense == "LGPL3+" || | |||
uplicense == "LGPLV3+") | |||
{ | |||
pluginString += " doap:license <http://spdx.org/licenses/LGPL-3.0-or-later.html> ;\n\n"; | |||
} | |||
else if (uplicense == "MIT") | |||
{ | |||
pluginString += " doap:license <http://spdx.org/licenses/MIT.html> ;\n\n"; | |||
} | |||
// generic fallbacks | |||
else if (uplicense.startsWith("GPL")) | |||
{ | |||
pluginString += " doap:license <https://opensource.org/licenses/gpl-license> ;\n\n"; | |||
} | |||
else if (uplicense.startsWith("LGPL")) | |||
{ | |||
pluginString += " doap:license <https://opensource.org/licenses/lgpl-license> ;\n\n"; | |||
} | |||
// unknown or not handled yet, log a warning | |||
else | |||
{ | |||
d_stderr("Unknown license string '%s'", license.buffer()); | |||
pluginString += " doap:license \"" + license + "\" ;\n\n"; | |||
} | |||
} | |||
} | |||
// developer | |||
@@ -1037,7 +1194,10 @@ void lv2_generate_ttl(const char* const basename) | |||
presetsString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; | |||
presetsString += "@prefix pset: <" LV2_PRESETS_PREFIX "> .\n"; | |||
# if DISTRHO_PLUGIN_WANT_STATE | |||
presetsString += "@prefix owl: <http://www.w3.org/2002/07/owl#> .\n"; | |||
presetsString += "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"; | |||
presetsString += "@prefix state: <" LV2_STATE_PREFIX "> .\n"; | |||
presetsString += "@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n"; | |||
# endif | |||
presetsString += "\n"; | |||
@@ -1045,8 +1205,13 @@ void lv2_generate_ttl(const char* const basename) | |||
const uint32_t numPrograms = plugin.getProgramCount(); | |||
# if DISTRHO_PLUGIN_WANT_FULL_STATE | |||
const uint32_t numStates = plugin.getStateCount(); | |||
const bool valid = numParameters != 0 || numStates != 0; | |||
# else | |||
const bool valid = numParameters != 0; | |||
# endif | |||
DISTRHO_CUSTOM_SAFE_ASSERT_RETURN("Programs require parameters or full state", valid, presetsFile.close()); | |||
const String presetSeparator(std::strstr(DISTRHO_PLUGIN_URI, "#") != nullptr ? ":" : "#"); | |||
char strBuf[0xff+1]; | |||
@@ -1054,6 +1219,22 @@ void lv2_generate_ttl(const char* const basename) | |||
String presetString; | |||
# if DISTRHO_PLUGIN_WANT_FULL_STATE | |||
for (uint32_t i=0; i<numStates; ++i) | |||
{ | |||
# if DISTRHO_PLUGIN_WANT_STATEFILES | |||
if (plugin.isStateFile(i)) | |||
continue; | |||
# endif | |||
presetString = "<" DISTRHO_PLUGIN_LV2_STATE_PREFIX + plugin.getStateKey(i) + ">\n"; | |||
presetString += " a owl:DatatypeProperty ;\n"; | |||
presetString += " rdfs:label \"Plugin state key-value string pair\" ;\n"; | |||
presetString += " rdfs:domain state:State ;\n"; | |||
presetString += " rdfs:range xsd:string .\n\n"; | |||
presetsString += presetString; | |||
} | |||
# endif | |||
for (uint32_t i=0; i<numPrograms; ++i) | |||
{ | |||
std::snprintf(strBuf, 0xff, "%03i", i+1); | |||
@@ -1062,17 +1243,6 @@ void lv2_generate_ttl(const char* const basename) | |||
presetString = "<" DISTRHO_PLUGIN_URI + presetSeparator + "preset" + strBuf + ">\n"; | |||
# if DISTRHO_PLUGIN_WANT_FULL_STATE | |||
if (numParameters == 0 && numStates == 0) | |||
#else | |||
if (numParameters == 0) | |||
#endif | |||
{ | |||
presetString += " ."; | |||
presetsString += presetString; | |||
continue; | |||
} | |||
# if DISTRHO_PLUGIN_WANT_FULL_STATE | |||
presetString += " state:state [\n"; | |||
for (uint32_t j=0; j<numStates; ++j) | |||
@@ -44,6 +44,7 @@ | |||
#include <clocale> | |||
#include <map> | |||
#include <string> | |||
#include <vector> | |||
#if VESTIGE_HEADER | |||
# include "vestige/vestige.h" | |||
@@ -1635,6 +1636,20 @@ static void vst_processReplacingCallback(AEffect* effect, float** inputs, float* | |||
#undef validPlugin | |||
#undef vstObjectPtr | |||
static struct Cleanup { | |||
std::vector<AEffect*> effects; | |||
~Cleanup() | |||
{ | |||
for (std::vector<AEffect*>::iterator it = effects.begin(), end = effects.end(); it != end; ++it) | |||
{ | |||
AEffect* const effect = *it; | |||
delete (VstObject*)effect->object; | |||
delete effect; | |||
} | |||
} | |||
} sCleanup; | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DISTRHO | |||
@@ -1714,12 +1729,13 @@ const AEffect* VSTPluginMain(audioMasterCallback audioMaster) | |||
effect->processReplacing = vst_processReplacingCallback; | |||
// pointers | |||
VstObject* const obj(new VstObject()); | |||
VstObject* const obj = new VstObject(); | |||
obj->audioMaster = audioMaster; | |||
obj->plugin = nullptr; | |||
// done | |||
effect->object = obj; | |||
sCleanup.effects.push_back(effect); | |||
return effect; | |||
} | |||
@@ -31,6 +31,7 @@ endif | |||
ifeq ($(HAVE_OPENGL),true) | |||
MANUAL_TESTS += Demo.opengl | |||
MANUAL_TESTS += FileBrowserDialog | |||
MANUAL_TESTS += NanoImage | |||
MANUAL_TESTS += NanoSubWidgets | |||
UNIT_TESTS += Window.opengl | |||
endif | |||
@@ -140,11 +141,15 @@ clean: | |||
$(SILENT)$(CXX) $^ $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(VULKAN_LIBS) -o $@ | |||
../build/tests/FileBrowserDialog$(APP_EXT): ../build/tests/FileBrowserDialog.cpp.o ../build/libdgl-opengl.a | |||
@echo "Linking Demo (OpenGL)" | |||
@echo "Linking FileBrowserDialog (OpenGL)" | |||
$(SILENT)$(CXX) $^ $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(OPENGL_LIBS) -o $@ | |||
../build/tests/NanoImage$(APP_EXT): ../build/tests/NanoImage.cpp.o ../build/libdgl-opengl.a | |||
@echo "Linking NanoImage (OpenGL)" | |||
$(SILENT)$(CXX) $^ $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(OPENGL_LIBS) -o $@ | |||
../build/tests/NanoSubWidgets$(APP_EXT): ../build/tests/NanoSubWidgets.cpp.o ../build/libdgl-opengl.a | |||
@echo "Linking Demo (OpenGL)" | |||
@echo "Linking NanoSubWidgets (OpenGL)" | |||
$(SILENT)$(CXX) $^ $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(OPENGL_LIBS) -o $@ | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
@@ -0,0 +1,229 @@ | |||
/* | |||
* DISTRHO Plugin Framework (DPF) | |||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* 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. | |||
* | |||
* THE 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. | |||
*/ | |||
#include "tests.hpp" | |||
#include "dgl/NanoVG.hpp" | |||
START_NAMESPACE_DGL | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
// Images | |||
#include "images_res/CatPics.cpp" | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
class NanoImageExample : public NanoStandaloneWindow, | |||
public IdleCallback | |||
{ | |||
static const int kImg1y = 0; | |||
static const int kImg2y = 500/2-CatPics::cat2Height/2; | |||
static const int kImg3x = 400/3-CatPics::cat3Width/3; | |||
static const int kImg1max = 500-CatPics::cat1Width; | |||
static const int kImg2max = 500-CatPics::cat2Width; | |||
static const int kImg3max = 400-CatPics::cat3Height; | |||
static const int kImgFlags = IMAGE_GENERATE_MIPMAPS | IMAGE_REPEAT_X; | |||
int imgTop1st, imgTop2nd, imgTop3rd; | |||
int img1x, img2x, img3y; | |||
bool img1rev, img2rev, img3rev; | |||
NanoImage img1, img2, img3; | |||
public: | |||
NanoImageExample(Application& app) | |||
: NanoStandaloneWindow(app), | |||
imgTop1st(1), | |||
imgTop2nd(2), | |||
imgTop3rd(3), | |||
img1x(0), | |||
img2x(kImg2max), | |||
img3y(kImg3max), | |||
img1rev(false), | |||
img2rev(true), | |||
img3rev(true), | |||
img1(createImageFromRawMemory(CatPics::cat1Width, CatPics::cat1Height, (uchar*)CatPics::cat1Data, kImgFlags, kImageFormatBGR)), | |||
img2(createImageFromRawMemory(CatPics::cat2Width, CatPics::cat2Height, (uchar*)CatPics::cat2Data, kImgFlags, kImageFormatBGR)), | |||
img3(createImageFromRawMemory(CatPics::cat3Width, CatPics::cat3Height, (uchar*)CatPics::cat3Data, kImgFlags, kImageFormatBGR)) | |||
{ | |||
DISTRHO_SAFE_ASSERT(img1.isValid()); | |||
DISTRHO_SAFE_ASSERT(img2.isValid()); | |||
DISTRHO_SAFE_ASSERT(img3.isValid()); | |||
DISTRHO_SAFE_ASSERT_UINT2(img1.getSize().getWidth() == CatPics::cat1Width, | |||
img1.getSize().getWidth(), CatPics::cat1Width); | |||
DISTRHO_SAFE_ASSERT_UINT2(img1.getSize().getHeight() == CatPics::cat1Height, | |||
img1.getSize().getHeight(), CatPics::cat1Height); | |||
DISTRHO_SAFE_ASSERT_UINT2(img2.getSize().getWidth() == CatPics::cat2Width, | |||
img2.getSize().getWidth(), CatPics::cat2Width); | |||
DISTRHO_SAFE_ASSERT_UINT2(img2.getSize().getHeight() == CatPics::cat2Height, | |||
img2.getSize().getHeight(), CatPics::cat2Height); | |||
DISTRHO_SAFE_ASSERT_UINT2(img3.getSize().getWidth() == CatPics::cat3Width, | |||
img3.getSize().getWidth(), CatPics::cat3Width); | |||
DISTRHO_SAFE_ASSERT_UINT2(img3.getSize().getHeight() == CatPics::cat3Height, | |||
img3.getSize().getHeight(), CatPics::cat3Height); | |||
setResizable(true); | |||
setSize(500, 500); | |||
// setGeometryConstraints(500, 500, false); | |||
setTitle("NanoImage"); | |||
done(); | |||
addIdleCallback(this); | |||
} | |||
protected: | |||
void onNanoDisplay() override | |||
{ | |||
// bottom image | |||
beginPath(); | |||
fillPaint(setupImagePaint(imgTop3rd)); | |||
fill(); | |||
// middle image | |||
beginPath(); | |||
fillPaint(setupImagePaint(imgTop2nd)); | |||
fill(); | |||
// top image | |||
beginPath(); | |||
fillPaint(setupImagePaint(imgTop1st)); | |||
fill(); | |||
} | |||
void idleCallback() noexcept override | |||
{ | |||
if (img1rev) | |||
{ | |||
img1x -= 2; | |||
if (img1x <= -50) | |||
{ | |||
img1rev = false; | |||
setNewTopImg(1); | |||
} | |||
} | |||
else | |||
{ | |||
img1x += 2; | |||
if (img1x >= kImg1max+50) | |||
{ | |||
img1rev = true; | |||
setNewTopImg(1); | |||
} | |||
} | |||
if (img2rev) | |||
{ | |||
img2x -= 1; | |||
if (img2x <= -50) | |||
{ | |||
img2rev = false; | |||
setNewTopImg(2); | |||
} | |||
} | |||
else | |||
{ | |||
img2x += 4; | |||
if (img2x >= kImg2max+50) | |||
{ | |||
img2rev = true; | |||
setNewTopImg(2); | |||
} | |||
} | |||
if (img3rev) | |||
{ | |||
img3y -= 3; | |||
if (img3y <= -50) | |||
{ | |||
img3rev = false; | |||
setNewTopImg(3); | |||
} | |||
} | |||
else | |||
{ | |||
img3y += 3; | |||
if (img3y >= kImg3max+50) | |||
{ | |||
img3rev = true; | |||
setNewTopImg(3); | |||
} | |||
} | |||
repaint(); | |||
} | |||
private: | |||
Paint setupImagePaint(const int imgId) noexcept | |||
{ | |||
switch (imgId) | |||
{ | |||
case 1: | |||
rect(img1x, kImg1y, CatPics::cat1Width, CatPics::cat1Height); | |||
return imagePattern(img1x, kImg1y, CatPics::cat1Width, CatPics::cat1Height, 0, img1, 1.0f); | |||
case 2: | |||
rect(img2x, kImg2y, CatPics::cat2Width, CatPics::cat2Height); | |||
return imagePattern(img2x, kImg2y, CatPics::cat2Width, CatPics::cat2Height, 0, img2, 1.0f); | |||
case 3: | |||
rect(kImg3x, img3y, CatPics::cat3Width, CatPics::cat3Height); | |||
return imagePattern(kImg3x, img3y, CatPics::cat3Width, CatPics::cat3Height, 0, img3, 1.0f); | |||
}; | |||
return Paint(); | |||
} | |||
void setNewTopImg(const int imgId) noexcept | |||
{ | |||
if (imgTop1st == imgId) | |||
return; | |||
if (imgTop2nd == imgId) | |||
{ | |||
imgTop2nd = imgTop1st; | |||
imgTop1st = imgId; | |||
return; | |||
} | |||
imgTop3rd = imgTop2nd; | |||
imgTop2nd = imgTop1st; | |||
imgTop1st = imgId; | |||
} | |||
}; | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
END_NAMESPACE_DGL | |||
int main() | |||
{ | |||
USE_NAMESPACE_DGL; | |||
Application app(true); | |||
NanoImageExample win(app); | |||
win.show(); | |||
app.exec(); | |||
return 0; | |||
} | |||
// -------------------------------------------------------------------------------------------------------------------- |
@@ -9,19 +9,19 @@ ifeq ($(WINDOWS),true) | |||
build: ../lv2_ttl_generator.exe | |||
../lv2_ttl_generator.exe: lv2_ttl_generator.c | |||
$(CC) $< $(CFLAGS) -o $@ $(LDFLAGS) -static | |||
$(CC) $< $(BUILD_C_FLAGS) -o $@ $(LINK_FLAGS) -static | |||
touch ../lv2_ttl_generator | |||
else # WINDOWS | |||
ifneq ($(HAIKU),true) | |||
LDFLAGS += -ldl | |||
ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) | |||
LINK_FLAGS += -ldl | |||
endif | |||
build: ../lv2_ttl_generator | |||
../lv2_ttl_generator: lv2_ttl_generator.c | |||
$(CC) $< $(CFLAGS) -o $@ $(LDFLAGS) | |||
$(CC) $< $(BUILD_C_FLAGS) -o $@ $(LINK_FLAGS) | |||
endif # WINDOWS | |||
@@ -0,0 +1,3 @@ | |||
EXPORTS | |||
ladspa_descriptor | |||
dssi_descriptor |
@@ -0,0 +1,2 @@ | |||
_ladspa_descriptor | |||
_dssi_descriptor |
@@ -0,0 +1,4 @@ | |||
{ | |||
global: ladspa_descriptor; dssi_descriptor; | |||
local: *; | |||
}; |
@@ -0,0 +1,2 @@ | |||
EXPORTS | |||
ladspa_descriptor |
@@ -0,0 +1 @@ | |||
_ladspa_descriptor |
@@ -0,0 +1,4 @@ | |||
{ | |||
global: ladspa_descriptor; | |||
local: *; | |||
}; |
@@ -0,0 +1,3 @@ | |||
EXPORTS | |||
lv2_descriptor | |||
lv2_generate_ttl |
@@ -0,0 +1,2 @@ | |||
_lv2_descriptor | |||
_lv2_generate_ttl |
@@ -0,0 +1,4 @@ | |||
{ | |||
global: lv2_descriptor; lv2_generate_ttl; | |||
local: *; | |||
}; |
@@ -0,0 +1,2 @@ | |||
EXPORTS | |||
lv2ui_descriptor |
@@ -0,0 +1 @@ | |||
_lv2ui_descriptor |
@@ -0,0 +1,4 @@ | |||
{ | |||
global: lv2ui_descriptor; | |||
local: *; | |||
}; |
@@ -0,0 +1,4 @@ | |||
EXPORTS | |||
lv2_descriptor | |||
lv2ui_descriptor | |||
lv2_generate_ttl |
@@ -0,0 +1,3 @@ | |||
_lv2_descriptor | |||
_lv2ui_descriptor | |||
_lv2_generate_ttl |
@@ -0,0 +1,4 @@ | |||
{ | |||
global: lv2_descriptor; lv2ui_descriptor; lv2_generate_ttl; | |||
local: *; | |||
}; |
@@ -0,0 +1,3 @@ | |||
EXPORTS | |||
VSTPluginMain | |||
main=VSTPluginMain |
@@ -0,0 +1 @@ | |||
_VSTPluginMain |
@@ -0,0 +1,4 @@ | |||
{ | |||
global: VSTPluginMain; main; | |||
local: *; | |||
}; |
@@ -0,0 +1,4 @@ | |||
EXPORTS | |||
GetPluginFactory | |||
InitDll | |||
ExitDll |
@@ -0,0 +1,3 @@ | |||
_GetPluginFactory | |||
_bundleEntry | |||
_bundleExit |
@@ -0,0 +1,4 @@ | |||
{ | |||
global: GetPluginFactory; ModuleEntry; ModuleExit; | |||
local: *; | |||
}; |
@@ -0,0 +1,41 @@ | |||
{ | |||
libdl is full of leaks | |||
Memcheck:Leak | |||
... | |||
fun:_dl_open | |||
... | |||
} | |||
{ | |||
libdl is full of leaks | |||
Memcheck:Leak | |||
... | |||
fun:_dl_close | |||
... | |||
} | |||
{ | |||
libdl is full of leaks | |||
Memcheck:Leak | |||
... | |||
fun:_dl_init | |||
} | |||
{ | |||
libdl is full of leaks | |||
Memcheck:Leak | |||
fun:calloc | |||
fun:allocate_dtv | |||
fun:_dl_allocate_tls | |||
... | |||
} | |||
{ | |||
libdl is full of leaks | |||
Memcheck:Leak | |||
... | |||
fun:call_init.part.0 | |||
} | |||
{ | |||
ignore XInitThreads | |||
Memcheck:Leak | |||
... | |||
fun:XInitThreads | |||
... | |||
} |
@@ -135,7 +135,6 @@ DistrhoPluginNekobi::DistrhoPluginNekobi() | |||
fParams.decay = 75.0f; | |||
fParams.accent = 25.0f; | |||
fParams.volume = 75.0f; | |||
fParams.bypass = false; | |||
// Internal stuff | |||
fSynth.waveform = 0.0f; | |||
@@ -251,9 +250,6 @@ void DistrhoPluginNekobi::initParameter(uint32_t index, Parameter& parameter) | |||
parameter.ranges.max = 100.0f; | |||
parameter.midiCC = 7; //Volume | |||
break; | |||
case paramBypass: | |||
parameter.initDesignation(kParameterDesignationBypass); | |||
break; | |||
} | |||
} | |||
@@ -280,8 +276,6 @@ float DistrhoPluginNekobi::getParameterValue(uint32_t index) const | |||
return fParams.accent; | |||
case paramVolume: | |||
return fParams.volume; | |||
case paramBypass: | |||
return fParams.bypass ? 1.0f : 0.0f; | |||
} | |||
return 0.0f; | |||
@@ -331,14 +325,6 @@ void DistrhoPluginNekobi::setParameterValue(uint32_t index, float value) | |||
fSynth.volume = value/100.0f; | |||
DISTRHO_SAFE_ASSERT(fSynth.volume >= 0.0f && fSynth.volume <= 1.0f); | |||
break; | |||
case paramBypass: { | |||
const bool bypass = (value > 0.5f); | |||
if (fParams.bypass != bypass) | |||
{ | |||
fParams.bypass = bypass; | |||
nekobee_synth_all_voices_off(&fSynth); | |||
} | |||
} break; | |||
} | |||
} | |||
@@ -374,10 +360,6 @@ void DistrhoPluginNekobi::run(const float**, float** outputs, uint32_t frames, c | |||
return; | |||
} | |||
// ignore midi input if bypassed | |||
if (fParams.bypass) | |||
midiEventCount = 0; | |||
while (framesDone < frames) | |||
{ | |||
if (fSynth.nugget_remains == 0) | |||
@@ -42,7 +42,6 @@ public: | |||
paramDecay, | |||
paramAccent, | |||
paramVolume, | |||
paramBypass, | |||
paramCount | |||
}; | |||
@@ -118,7 +117,6 @@ private: | |||
float decay; | |||
float accent; | |||
float volume; | |||
bool bypass; | |||
} fParams; | |||
nekobee_synth_t fSynth; | |||
@@ -96,6 +96,9 @@ DistrhoUIProM::DistrhoUIProM() | |||
DistrhoUIProM::~DistrhoUIProM() | |||
{ | |||
if (fPM == nullptr) | |||
return; | |||
if (DistrhoPluginProM* const dspPtr = (DistrhoPluginProM*)getPluginInstancePointer()) | |||
{ | |||
const MutexLocker csm(dspPtr->fMutex); | |||
@@ -74,8 +74,8 @@ void DistrhoPluginGLBars::initParameter(uint32_t index, Parameter& parameter) | |||
parameter.name = "X"; | |||
parameter.symbol = "x"; | |||
parameter.unit = ""; | |||
parameter.ranges.def = -4.0f; | |||
parameter.ranges.min = 0.0f; | |||
parameter.ranges.def = 0.0f; | |||
parameter.ranges.min = -4.0f; | |||
parameter.ranges.max = 4.0f; | |||
break; | |||
@@ -26,13 +26,17 @@ START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
DistrhoUIGLBars::DistrhoUIGLBars() | |||
: UI(512, 512) | |||
: UI(512, 512), | |||
fInitialized(false) | |||
{ | |||
setGeometryConstraints(256, 256, true); | |||
} | |||
DistrhoUIGLBars::~DistrhoUIGLBars() | |||
{ | |||
if (! fInitialized) | |||
return; | |||
if (DistrhoPluginGLBars* const dspPtr = (DistrhoPluginGLBars*)getPluginInstancePointer()) | |||
{ | |||
const MutexLocker csm(dspPtr->fMutex); | |||
@@ -81,6 +85,8 @@ void DistrhoUIGLBars::uiIdle() | |||
if (dspPtr->fState != nullptr) | |||
return; | |||
fInitialized = true; | |||
const MutexLocker csm(dspPtr->fMutex); | |||
dspPtr->fState = &fState; | |||
} | |||
@@ -53,6 +53,7 @@ protected: | |||
bool onKeyboard(const KeyboardEvent&) override; | |||
private: | |||
bool fInitialized; | |||
glBarsState fState; | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DistrhoUIGLBars) | |||