@@ -238,26 +238,36 @@ all: | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# Common | |||
$(BUILD_DIR)/%.S.o: %.S | |||
$(BUILD_DIR)/%.S.o: %.S $(EXTRA_LIBS) | |||
-@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||
@echo "Compiling $<" | |||
@$(CC) $< $(BUILD_C_FLAGS) -c -o $@ | |||
$(BUILD_DIR)/%.c.o: %.c | |||
$(BUILD_DIR)/%.c.o: %.c $(EXTRA_LIBS) | |||
-@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||
@echo "Compiling $<" | |||
$(SILENT)$(CC) $< $(BUILD_C_FLAGS) -c -o $@ | |||
$(BUILD_DIR)/%.cc.o: %.cc | |||
$(BUILD_DIR)/%.cc.o: %.cc $(EXTRA_LIBS) | |||
-@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||
@echo "Compiling $<" | |||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
$(BUILD_DIR)/%.cpp.o: %.cpp | |||
$(BUILD_DIR)/%.cpp.o: %.cpp $(EXTRA_LIBS) | |||
-@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||
@echo "Compiling $<" | |||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
$(BUILD_DIR)/%.m.o: %.m $(EXTRA_LIBS) | |||
-@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||
@echo "Compiling $<" | |||
$(SILENT)$(CC) $< $(BUILD_C_FLAGS) -ObjC -c -o $@ | |||
$(BUILD_DIR)/%.mm.o: %.mm $(EXTRA_LIBS) | |||
-@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||
@echo "Compiling $<" | |||
$(SILENT)$(CC) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@ | |||
clean: | |||
rm -rf $(BUILD_DIR) | |||
rm -rf $(TARGET_DIR)/$(NAME) $(TARGET_DIR)/$(NAME)-* $(TARGET_DIR)/$(NAME).lv2 | |||
@@ -312,7 +322,7 @@ $(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp | |||
jack: $(jack) | |||
ifeq ($(HAVE_DGL),true) | |||
$(jack): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o $(BUILD_DIR)/DistrhoUIMain_JACK.cpp.o $(DGL_LIB) | |||
$(jack): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o $(BUILD_DIR)/DistrhoUIMain_JACK.cpp.o $(DGL_LIB) $(EXTRA_LIBS) | |||
else | |||
$(jack): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o | |||
endif | |||
@@ -355,7 +365,7 @@ lv2_dsp: $(lv2_dsp) | |||
lv2_sep: $(lv2_dsp) $(lv2_ui) | |||
ifeq ($(HAVE_DGL),true) | |||
$(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) | |||
$(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) $(EXTRA_LIBS) | |||
else | |||
$(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o | |||
endif | |||
@@ -379,7 +389,7 @@ $(lv2_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) | |||
vst2 vst: $(vst2) | |||
ifeq ($(HAVE_DGL),true) | |||
$(vst2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST2.cpp.o $(DGL_LIB) | |||
$(vst2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST2.cpp.o $(DGL_LIB) $(EXTRA_LIBS) | |||
else | |||
$(vst2): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.o | |||
endif | |||
@@ -393,7 +403,7 @@ endif | |||
vst3: $(vst3) | |||
ifeq ($(HAVE_DGL),true) | |||
$(vst3): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST3.cpp.o $(DGL_LIB) | |||
$(vst3): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST3.cpp.o $(DGL_LIB) $(EXTRA_LIBS) | |||
else | |||
$(vst3): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o | |||
endif | |||
@@ -16,6 +16,12 @@ LINK_FLAGS += $(DGL_LIBS) | |||
ifeq ($(USE_OPENGL3),true) | |||
BUILD_CXX_FLAGS += -DDGL_USE_OPENGL3 | |||
endif | |||
ifeq ($(USE_NANOVG_FBO),true) | |||
BUILD_CXX_FLAGS += -DDGL_USE_NANOVG_FBO | |||
endif | |||
ifeq ($(USE_RGBA),true) | |||
BUILD_CXX_FLAGS += -DDGL_USE_RGBA | |||
endif | |||
# TODO fix these after pugl-upstream is done | |||
BUILD_CXX_FLAGS += -Wno-attributes -Wno-extra -Wno-missing-field-initializers | |||
@@ -943,6 +943,7 @@ private: | |||
inline void onDisplay() override | |||
{ | |||
// NOTE maybe should use BaseWidget::getWindow().getScaleFactor() as 3rd arg ? | |||
NanoVG::reset(); | |||
NanoVG::beginFrame(BaseWidget::getWidth(), BaseWidget::getHeight()); | |||
onNanoDisplay(); | |||
NanoVG::endFrame(); | |||
@@ -397,10 +397,10 @@ public: | |||
void runAsModal(bool blockWait = false); | |||
/** | |||
Get the size constraint set for the Window. | |||
Get the geometry constraints set for the Window. | |||
@see setGeometryConstraints | |||
*/ | |||
Size<uint> getMinimumSizeConstraint(bool& keepAspectRatio); | |||
Size<uint> getGeometryConstraints(bool& keepAspectRatio); | |||
/** | |||
Set geometry constraints for the Window when resized by the user, and optionally scale contents automatically. | |||
@@ -54,6 +54,18 @@ DGL_EXT(PFNGLUNIFORM4FVPROC, glUniform4fv) | |||
DGL_EXT(PFNGLUSEPROGRAMPROC, glUseProgram) | |||
DGL_EXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer) | |||
DGL_EXT(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate) | |||
# ifdef DGL_USE_NANOVG_FBO | |||
DGL_EXT(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer) | |||
DGL_EXT(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer) | |||
DGL_EXT(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus) | |||
DGL_EXT(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers) | |||
DGL_EXT(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers) | |||
DGL_EXT(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D) | |||
DGL_EXT(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer) | |||
DGL_EXT(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers) | |||
DGL_EXT(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers) | |||
DGL_EXT(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage) | |||
# endif | |||
# ifdef DGL_USE_OPENGL3 | |||
DGL_EXT(PFNGLBINDBUFFERRANGEPROC, glBindBufferRange) | |||
DGL_EXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray) | |||
@@ -84,6 +96,11 @@ DGL_EXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding) | |||
#include "nanovg/nanovg_gl.h" | |||
#ifdef DGL_USE_NANOVG_FBO | |||
# define NANOVG_FBO_VALID 1 | |||
# include "nanovg/nanovg_gl_utils.h" | |||
#endif | |||
#if defined(NANOVG_GL2) | |||
# define nvgCreateGL nvgCreateGL2 | |||
# define nvgDeleteGL nvgDeleteGL2 | |||
@@ -145,6 +162,18 @@ DGL_EXT(PFNGLUNIFORM4FVPROC, glUniform4fv) | |||
DGL_EXT(PFNGLUSEPROGRAMPROC, glUseProgram) | |||
DGL_EXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer) | |||
DGL_EXT(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate) | |||
# ifdef DGL_USE_NANOVG_FBO | |||
DGL_EXT(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer) | |||
DGL_EXT(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer) | |||
DGL_EXT(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus) | |||
DGL_EXT(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers) | |||
DGL_EXT(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers) | |||
DGL_EXT(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D) | |||
DGL_EXT(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer) | |||
DGL_EXT(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers) | |||
DGL_EXT(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers) | |||
DGL_EXT(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage) | |||
# endif | |||
# ifdef DGL_USE_OPENGL3 | |||
DGL_EXT(PFNGLBINDBUFFERRANGEPROC, glBindBufferRange) | |||
DGL_EXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray) | |||
@@ -346,7 +346,7 @@ void Window::runAsModal(bool blockWait) | |||
pData->runAsModal(blockWait); | |||
} | |||
Size<uint> Window::getMinimumSizeConstraint(bool& keepAspectRatio) | |||
Size<uint> Window::getGeometryConstraints(bool& keepAspectRatio) | |||
{ | |||
keepAspectRatio = pData->keepAspectRatio; | |||
return Size<uint>(pData->minWidth, pData->minHeight); | |||
@@ -249,7 +249,11 @@ void Window::PrivateData::initPre(const uint width, const uint height, const boo | |||
puglSetHandle(view, this); | |||
puglSetViewHint(view, PUGL_RESIZABLE, resizable ? PUGL_TRUE : PUGL_FALSE); | |||
puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, PUGL_FALSE); | |||
#if DGL_USE_RGBA | |||
puglSetViewHint(view, PUGL_DEPTH_BITS, 24); | |||
#else | |||
puglSetViewHint(view, PUGL_DEPTH_BITS, 16); | |||
#endif | |||
puglSetViewHint(view, PUGL_STENCIL_BITS, 8); | |||
#ifdef DGL_USE_OPENGL3 | |||
puglSetViewHint(view, PUGL_USE_COMPAT_PROFILE, PUGL_FALSE); | |||
@@ -24,8 +24,11 @@ | |||
#include "nanovg.h" | |||
#define FONTSTASH_IMPLEMENTATION | |||
#include "fontstash.h" | |||
#ifndef NVG_NO_STB | |||
#define STB_IMAGE_IMPLEMENTATION | |||
#include "stb_image.h" | |||
#endif | |||
#ifdef _MSC_VER | |||
#pragma warning(disable: 4100) // unreferenced formal parameter | |||
@@ -74,7 +77,7 @@ struct NVGstate { | |||
float miterLimit; | |||
int lineJoin; | |||
int lineCap; | |||
float alpha; | |||
NVGcolor tint; | |||
float xform[6]; | |||
NVGscissor scissor; | |||
float fontSize; | |||
@@ -109,6 +112,14 @@ struct NVGpathCache { | |||
}; | |||
typedef struct NVGpathCache NVGpathCache; | |||
struct NVGfontContext { // Fontstash context plus font images; shared between shared NanoVG contexts. | |||
int refCount; | |||
struct FONScontext* fs; | |||
int fontImages[NVG_MAX_FONTIMAGES]; | |||
int fontImageIdx; | |||
}; | |||
typedef struct NVGfontContext NVGfontContext; | |||
struct NVGcontext { | |||
NVGparams params; | |||
float* commands; | |||
@@ -122,9 +133,7 @@ struct NVGcontext { | |||
float distTol; | |||
float fringeWidth; | |||
float devicePxRatio; | |||
struct FONScontext* fs; | |||
int fontImages[NVG_MAX_FONTIMAGES]; | |||
int fontImageIdx; | |||
NVGfontContext* fontContext; | |||
int drawCallCount; | |||
int fillTriCount; | |||
int strokeTriCount; | |||
@@ -283,7 +292,7 @@ static NVGstate* nvg__getState(NVGcontext* ctx) | |||
return &ctx->states[ctx->nstates-1]; | |||
} | |||
NVGcontext* nvgCreateInternal(NVGparams* params) | |||
NVGcontext* nvgCreateInternal(NVGparams* params, NVGcontext* other) // Share the fonts and images of 'other' if it's non-NULL. | |||
{ | |||
FONSparams fontParams; | |||
NVGcontext* ctx = (NVGcontext*)malloc(sizeof(NVGcontext)); | |||
@@ -292,8 +301,16 @@ NVGcontext* nvgCreateInternal(NVGparams* params) | |||
memset(ctx, 0, sizeof(NVGcontext)); | |||
ctx->params = *params; | |||
for (i = 0; i < NVG_MAX_FONTIMAGES; i++) | |||
ctx->fontImages[i] = 0; | |||
if (other) { | |||
ctx->fontContext = other->fontContext; | |||
ctx->fontContext->refCount++; | |||
} else { | |||
ctx->fontContext = (NVGfontContext*)malloc(sizeof(NVGfontContext)); | |||
if (ctx->fontContext == NULL) goto error; | |||
for (i = 0; i < NVG_MAX_FONTIMAGES; i++) | |||
ctx->fontContext->fontImages[i] = 0; | |||
ctx->fontContext->refCount = 1; | |||
} | |||
ctx->commands = (float*)malloc(sizeof(float)*NVG_INIT_COMMANDS_SIZE); | |||
if (!ctx->commands) goto error; | |||
@@ -308,25 +325,27 @@ NVGcontext* nvgCreateInternal(NVGparams* params) | |||
nvg__setDevicePixelRatio(ctx, 1.0f); | |||
if (ctx->params.renderCreate(ctx->params.userPtr) == 0) goto error; | |||
if (ctx->params.renderCreate(ctx->params.userPtr, other ? other->params.userPtr : NULL) == 0) goto error; | |||
// Init font rendering | |||
memset(&fontParams, 0, sizeof(fontParams)); | |||
fontParams.width = NVG_INIT_FONTIMAGE_SIZE; | |||
fontParams.height = NVG_INIT_FONTIMAGE_SIZE; | |||
fontParams.flags = FONS_ZERO_TOPLEFT; | |||
fontParams.renderCreate = NULL; | |||
fontParams.renderUpdate = NULL; | |||
fontParams.renderDraw = NULL; | |||
fontParams.renderDelete = NULL; | |||
fontParams.userPtr = NULL; | |||
ctx->fs = fonsCreateInternal(&fontParams); | |||
if (ctx->fs == NULL) goto error; | |||
// Create font texture | |||
ctx->fontImages[0] = ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_ALPHA, fontParams.width, fontParams.height, 0, NULL); | |||
if (ctx->fontImages[0] == 0) goto error; | |||
ctx->fontImageIdx = 0; | |||
if (!other) { | |||
memset(&fontParams, 0, sizeof(fontParams)); | |||
fontParams.width = NVG_INIT_FONTIMAGE_SIZE; | |||
fontParams.height = NVG_INIT_FONTIMAGE_SIZE; | |||
fontParams.flags = FONS_ZERO_TOPLEFT; | |||
fontParams.renderCreate = NULL; | |||
fontParams.renderUpdate = NULL; | |||
fontParams.renderDraw = NULL; | |||
fontParams.renderDelete = NULL; | |||
fontParams.userPtr = NULL; | |||
ctx->fontContext->fs = fonsCreateInternal(&fontParams); | |||
if (ctx->fontContext->fs == NULL) goto error; | |||
// Create font texture | |||
ctx->fontContext->fontImages[0] = ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_ALPHA, fontParams.width, fontParams.height, 0, NULL); | |||
if (ctx->fontContext->fontImages[0] == 0) goto error; | |||
ctx->fontContext->fontImageIdx = 0; | |||
} | |||
return ctx; | |||
@@ -347,14 +366,18 @@ void nvgDeleteInternal(NVGcontext* ctx) | |||
if (ctx->commands != NULL) free(ctx->commands); | |||
if (ctx->cache != NULL) nvg__deletePathCache(ctx->cache); | |||
if (ctx->fs) | |||
fonsDeleteInternal(ctx->fs); | |||
if (ctx->fontContext != NULL && --ctx->fontContext->refCount == 0) { | |||
if (ctx->fontContext->fs) | |||
fonsDeleteInternal(ctx->fontContext->fs); | |||
for (i = 0; i < NVG_MAX_FONTIMAGES; i++) { | |||
if (ctx->fontImages[i] != 0) { | |||
nvgDeleteImage(ctx, ctx->fontImages[i]); | |||
ctx->fontImages[i] = 0; | |||
for (i = 0; i < NVG_MAX_FONTIMAGES; i++) { | |||
if (ctx->fontContext->fontImages[i] != 0) { | |||
nvgDeleteImage(ctx, ctx->fontContext->fontImages[i]); | |||
ctx->fontContext->fontImages[i] = 0; | |||
} | |||
} | |||
free(ctx->fontContext); | |||
} | |||
if (ctx->params.renderDelete != NULL) | |||
@@ -391,30 +414,30 @@ void nvgCancelFrame(NVGcontext* ctx) | |||
void nvgEndFrame(NVGcontext* ctx) | |||
{ | |||
ctx->params.renderFlush(ctx->params.userPtr); | |||
if (ctx->fontImageIdx != 0) { | |||
int fontImage = ctx->fontImages[ctx->fontImageIdx]; | |||
if (ctx->fontContext->fontImageIdx != 0) { | |||
int fontImage = ctx->fontContext->fontImages[ctx->fontContext->fontImageIdx]; | |||
int i, j, iw, ih; | |||
// delete images that smaller than current one | |||
if (fontImage == 0) | |||
return; | |||
nvgImageSize(ctx, fontImage, &iw, &ih); | |||
for (i = j = 0; i < ctx->fontImageIdx; i++) { | |||
if (ctx->fontImages[i] != 0) { | |||
for (i = j = 0; i < ctx->fontContext->fontImageIdx; i++) { | |||
if (ctx->fontContext->fontImages[i] != 0) { | |||
int nw, nh; | |||
nvgImageSize(ctx, ctx->fontImages[i], &nw, &nh); | |||
nvgImageSize(ctx, ctx->fontContext->fontImages[i], &nw, &nh); | |||
if (nw < iw || nh < ih) | |||
nvgDeleteImage(ctx, ctx->fontImages[i]); | |||
nvgDeleteImage(ctx, ctx->fontContext->fontImages[i]); | |||
else | |||
ctx->fontImages[j++] = ctx->fontImages[i]; | |||
ctx->fontContext->fontImages[j++] = ctx->fontContext->fontImages[i]; | |||
} | |||
} | |||
// make current font image to first | |||
ctx->fontImages[j++] = ctx->fontImages[0]; | |||
ctx->fontImages[0] = fontImage; | |||
ctx->fontImageIdx = 0; | |||
ctx->fontContext->fontImages[j++] = ctx->fontContext->fontImages[0]; | |||
ctx->fontContext->fontImages[0] = fontImage; | |||
ctx->fontContext->fontImageIdx = 0; | |||
// clear all images after j | |||
for (i = j; i < NVG_MAX_FONTIMAGES; i++) | |||
ctx->fontImages[i] = 0; | |||
ctx->fontContext->fontImages[i] = 0; | |||
} | |||
} | |||
@@ -651,7 +674,7 @@ void nvgReset(NVGcontext* ctx) | |||
state->miterLimit = 10.0f; | |||
state->lineCap = NVG_BUTT; | |||
state->lineJoin = NVG_MITER; | |||
state->alpha = 1.0f; | |||
state->tint = nvgRGBAf(1, 1, 1, 1); | |||
nvgTransformIdentity(state->xform); | |||
state->scissor.extent[0] = -1.0f; | |||
@@ -699,7 +722,33 @@ void nvgLineJoin(NVGcontext* ctx, int join) | |||
void nvgGlobalAlpha(NVGcontext* ctx, float alpha) | |||
{ | |||
NVGstate* state = nvg__getState(ctx); | |||
state->alpha = alpha; | |||
state->tint.a = alpha; | |||
} | |||
void nvgGlobalTint(NVGcontext* ctx, NVGcolor tint) | |||
{ | |||
NVGstate* state = nvg__getState(ctx); | |||
state->tint = tint; | |||
} | |||
NVGcolor nvgGetGlobalTint(NVGcontext* ctx) | |||
{ | |||
NVGstate* state = nvg__getState(ctx); | |||
return state->tint; | |||
} | |||
void nvgAlpha(NVGcontext* ctx, float alpha) | |||
{ | |||
NVGstate* state = nvg__getState(ctx); | |||
state->tint.a *= alpha; | |||
} | |||
void nvgTint(NVGcontext* ctx, NVGcolor tint) | |||
{ | |||
NVGstate* state = nvg__getState(ctx); | |||
int i; | |||
for (i = 0; i < 4; i++) | |||
state->tint.rgba[i] *= tint.rgba[i]; | |||
} | |||
void nvgTransform(NVGcontext* ctx, float a, float b, float c, float d, float e, float f) | |||
@@ -788,6 +837,7 @@ void nvgFillPaint(NVGcontext* ctx, NVGpaint paint) | |||
nvgTransformMultiply(state->fill.xform, state->xform); | |||
} | |||
#ifndef NVG_NO_STB | |||
int nvgCreateImage(NVGcontext* ctx, const char* filename, int imageFlags) | |||
{ | |||
int w, h, n, image; | |||
@@ -816,6 +866,7 @@ int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, unsigned char* data, int | |||
stbi_image_free(img); | |||
return image; | |||
} | |||
#endif | |||
int nvgCreateImageRaw(NVGcontext* ctx, int w, int h, int imageFlags, NVGtexture format, const unsigned char* data) | |||
{ | |||
@@ -2234,9 +2285,11 @@ void nvgFill(NVGcontext* ctx) | |||
else | |||
nvg__expandFill(ctx, 0.0f, NVG_MITER, 2.4f); | |||
// Apply global alpha | |||
fillPaint.innerColor.a *= state->alpha; | |||
fillPaint.outerColor.a *= state->alpha; | |||
// Apply global tint | |||
for (i = 0; i < 4; i++) { | |||
fillPaint.innerColor.rgba[i] *= state->tint.rgba[i]; | |||
fillPaint.outerColor.rgba[i] *= state->tint.rgba[i]; | |||
} | |||
ctx->params.renderFill(ctx->params.userPtr, &fillPaint, state->compositeOperation, &state->scissor, ctx->fringeWidth, | |||
ctx->cache->bounds, ctx->cache->paths, ctx->cache->npaths); | |||
@@ -2269,9 +2322,11 @@ void nvgStroke(NVGcontext* ctx) | |||
strokeWidth = ctx->fringeWidth; | |||
} | |||
// Apply global alpha | |||
strokePaint.innerColor.a *= state->alpha; | |||
strokePaint.outerColor.a *= state->alpha; | |||
// Apply global tint | |||
for (i = 0; i < 4; i++) { | |||
strokePaint.innerColor.rgba[i] *= state->tint.rgba[i]; | |||
strokePaint.outerColor.rgba[i] *= state->tint.rgba[i]; | |||
} | |||
nvg__flattenPaths(ctx); | |||
@@ -2294,35 +2349,35 @@ void nvgStroke(NVGcontext* ctx) | |||
// Add fonts | |||
int nvgCreateFont(NVGcontext* ctx, const char* name, const char* filename) | |||
{ | |||
return fonsAddFont(ctx->fs, name, filename, 0); | |||
return fonsAddFont(ctx->fontContext->fs, name, filename, 0); | |||
} | |||
int nvgCreateFontAtIndex(NVGcontext* ctx, const char* name, const char* filename, const int fontIndex) | |||
{ | |||
return fonsAddFont(ctx->fs, name, filename, fontIndex); | |||
return fonsAddFont(ctx->fontContext->fs, name, filename, fontIndex); | |||
} | |||
int nvgCreateFontMem(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData) | |||
{ | |||
return fonsAddFontMem(ctx->fs, name, data, ndata, freeData, 0); | |||
return fonsAddFontMem(ctx->fontContext->fs, name, data, ndata, freeData, 0); | |||
} | |||
int nvgCreateFontMemAtIndex(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData, const int fontIndex) | |||
{ | |||
return fonsAddFontMem(ctx->fs, name, data, ndata, freeData, fontIndex); | |||
return fonsAddFontMem(ctx->fontContext->fs, name, data, ndata, freeData, fontIndex); | |||
} | |||
int nvgFindFont(NVGcontext* ctx, const char* name) | |||
{ | |||
if (name == NULL) return -1; | |||
return fonsGetFontByName(ctx->fs, name); | |||
return fonsGetFontByName(ctx->fontContext->fs, name); | |||
} | |||
int nvgAddFallbackFontId(NVGcontext* ctx, int baseFont, int fallbackFont) | |||
{ | |||
if(baseFont == -1 || fallbackFont == -1) return 0; | |||
return fonsAddFallbackFont(ctx->fs, baseFont, fallbackFont); | |||
return fonsAddFallbackFont(ctx->fontContext->fs, baseFont, fallbackFont); | |||
} | |||
int nvgAddFallbackFont(NVGcontext* ctx, const char* baseFont, const char* fallbackFont) | |||
@@ -2332,7 +2387,7 @@ int nvgAddFallbackFont(NVGcontext* ctx, const char* baseFont, const char* fallba | |||
void nvgResetFallbackFontsId(NVGcontext* ctx, int baseFont) | |||
{ | |||
fonsResetFallbackFont(ctx->fs, baseFont); | |||
fonsResetFallbackFont(ctx->fontContext->fs, baseFont); | |||
} | |||
void nvgResetFallbackFonts(NVGcontext* ctx, const char* baseFont) | |||
@@ -2380,7 +2435,7 @@ void nvgFontFaceId(NVGcontext* ctx, int font) | |||
void nvgFontFace(NVGcontext* ctx, const char* font) | |||
{ | |||
NVGstate* state = nvg__getState(ctx); | |||
state->fontId = fonsGetFontByName(ctx->fs, font); | |||
state->fontId = fonsGetFontByName(ctx->fontContext->fs, font); | |||
} | |||
static float nvg__quantize(float a, float d) | |||
@@ -2397,12 +2452,12 @@ static void nvg__flushTextTexture(NVGcontext* ctx) | |||
{ | |||
int dirty[4]; | |||
if (fonsValidateTexture(ctx->fs, dirty)) { | |||
int fontImage = ctx->fontImages[ctx->fontImageIdx]; | |||
if (fonsValidateTexture(ctx->fontContext->fs, dirty)) { | |||
int fontImage = ctx->fontContext->fontImages[ctx->fontContext->fontImageIdx]; | |||
// Update texture | |||
if (fontImage != 0) { | |||
int iw, ih; | |||
const unsigned char* data = fonsGetTextureData(ctx->fs, &iw, &ih); | |||
const unsigned char* data = fonsGetTextureData(ctx->fontContext->fs, &iw, &ih); | |||
int x = dirty[0]; | |||
int y = dirty[1]; | |||
int w = dirty[2] - dirty[0]; | |||
@@ -2416,37 +2471,40 @@ static int nvg__allocTextAtlas(NVGcontext* ctx) | |||
{ | |||
int iw, ih; | |||
nvg__flushTextTexture(ctx); | |||
if (ctx->fontImageIdx >= NVG_MAX_FONTIMAGES-1) | |||
if (ctx->fontContext->fontImageIdx >= NVG_MAX_FONTIMAGES-1) | |||
return 0; | |||
// if next fontImage already have a texture | |||
if (ctx->fontImages[ctx->fontImageIdx+1] != 0) | |||
nvgImageSize(ctx, ctx->fontImages[ctx->fontImageIdx+1], &iw, &ih); | |||
if (ctx->fontContext->fontImages[ctx->fontContext->fontImageIdx+1] != 0) | |||
nvgImageSize(ctx, ctx->fontContext->fontImages[ctx->fontContext->fontImageIdx+1], &iw, &ih); | |||
else { // calculate the new font image size and create it. | |||
nvgImageSize(ctx, ctx->fontImages[ctx->fontImageIdx], &iw, &ih); | |||
nvgImageSize(ctx, ctx->fontContext->fontImages[ctx->fontContext->fontImageIdx], &iw, &ih); | |||
if (iw > ih) | |||
ih *= 2; | |||
else | |||
iw *= 2; | |||
if (iw > NVG_MAX_FONTIMAGE_SIZE || ih > NVG_MAX_FONTIMAGE_SIZE) | |||
iw = ih = NVG_MAX_FONTIMAGE_SIZE; | |||
ctx->fontImages[ctx->fontImageIdx+1] = ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_ALPHA, iw, ih, 0, NULL); | |||
ctx->fontContext->fontImages[ctx->fontContext->fontImageIdx+1] = ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_ALPHA, iw, ih, 0, NULL); | |||
} | |||
++ctx->fontImageIdx; | |||
fonsResetAtlas(ctx->fs, iw, ih); | |||
++ctx->fontContext->fontImageIdx; | |||
fonsResetAtlas(ctx->fontContext->fs, iw, ih); | |||
return 1; | |||
} | |||
static void nvg__renderText(NVGcontext* ctx, NVGvertex* verts, int nverts) | |||
{ | |||
int i; | |||
NVGstate* state = nvg__getState(ctx); | |||
NVGpaint paint = state->fill; | |||
// Render triangles. | |||
paint.image = ctx->fontImages[ctx->fontImageIdx]; | |||
paint.image = ctx->fontContext->fontImages[ctx->fontContext->fontImageIdx]; | |||
// Apply global alpha | |||
paint.innerColor.a *= state->alpha; | |||
paint.outerColor.a *= state->alpha; | |||
// Apply global tint | |||
for (i = 0; i < 4; i++) { | |||
paint.innerColor.rgba[i] *= state->tint.rgba[i]; | |||
paint.outerColor.rgba[i] *= state->tint.rgba[i]; | |||
} | |||
ctx->params.renderTriangles(ctx->params.userPtr, &paint, state->compositeOperation, &state->scissor, verts, nverts, ctx->fringeWidth); | |||
@@ -2454,6 +2512,12 @@ static void nvg__renderText(NVGcontext* ctx, NVGvertex* verts, int nverts) | |||
ctx->textTriCount += nverts/3; | |||
} | |||
static int nvg__isTransformFlipped(const float *xform) | |||
{ | |||
float det = xform[0] * xform[3] - xform[2] * xform[1]; | |||
return( det < 0); | |||
} | |||
float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char* end) | |||
{ | |||
NVGstate* state = nvg__getState(ctx); | |||
@@ -2464,25 +2528,26 @@ float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char* | |||
float invscale = 1.0f / scale; | |||
int cverts = 0; | |||
int nverts = 0; | |||
int isFlipped = nvg__isTransformFlipped(state->xform); | |||
if (end == NULL) | |||
end = string + strlen(string); | |||
if (state->fontId == FONS_INVALID) return x; | |||
fonsSetSize(ctx->fs, state->fontSize*scale); | |||
fonsSetSpacing(ctx->fs, state->letterSpacing*scale); | |||
fonsSetBlur(ctx->fs, state->fontBlur*scale); | |||
fonsSetAlign(ctx->fs, state->textAlign); | |||
fonsSetFont(ctx->fs, state->fontId); | |||
fonsSetSize(ctx->fontContext->fs, state->fontSize*scale); | |||
fonsSetSpacing(ctx->fontContext->fs, state->letterSpacing*scale); | |||
fonsSetBlur(ctx->fontContext->fs, state->fontBlur*scale); | |||
fonsSetAlign(ctx->fontContext->fs, state->textAlign); | |||
fonsSetFont(ctx->fontContext->fs, state->fontId); | |||
cverts = nvg__maxi(2, (int)(end - string)) * 6; // conservative estimate. | |||
verts = nvg__allocTempVerts(ctx, cverts); | |||
if (verts == NULL) return x; | |||
fonsTextIterInit(ctx->fs, &iter, x*scale, y*scale, string, end, FONS_GLYPH_BITMAP_REQUIRED); | |||
fonsTextIterInit(ctx->fontContext->fs, &iter, x*scale, y*scale, string, end, FONS_GLYPH_BITMAP_REQUIRED); | |||
prevIter = iter; | |||
while (fonsTextIterNext(ctx->fs, &iter, &q)) { | |||
while (fonsTextIterNext(ctx->fontContext->fs, &iter, &q)) { | |||
float c[4*2]; | |||
if (iter.prevGlyphIndex == -1) { // can not retrieve glyph? | |||
if (nverts != 0) { | |||
@@ -2492,11 +2557,17 @@ float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char* | |||
if (!nvg__allocTextAtlas(ctx)) | |||
break; // no memory :( | |||
iter = prevIter; | |||
fonsTextIterNext(ctx->fs, &iter, &q); // try again | |||
fonsTextIterNext(ctx->fontContext->fs, &iter, &q); // try again | |||
if (iter.prevGlyphIndex == -1) // still can not find glyph? | |||
break; | |||
} | |||
prevIter = iter; | |||
if(isFlipped) { | |||
float tmp; | |||
tmp = q.y0; q.y0 = q.y1; q.y1 = tmp; | |||
tmp = q.t0; q.t0 = q.t1; q.t1 = tmp; | |||
} | |||
// Transform corners. | |||
nvgTransformPoint(&c[0],&c[1], state->xform, q.x0*invscale, q.y0*invscale); | |||
nvgTransformPoint(&c[2],&c[3], state->xform, q.x1*invscale, q.y0*invscale); | |||
@@ -2571,18 +2642,18 @@ int nvgTextGlyphPositions(NVGcontext* ctx, float x, float y, const char* string, | |||
if (string == end) | |||
return 0; | |||
fonsSetSize(ctx->fs, state->fontSize*scale); | |||
fonsSetSpacing(ctx->fs, state->letterSpacing*scale); | |||
fonsSetBlur(ctx->fs, state->fontBlur*scale); | |||
fonsSetAlign(ctx->fs, state->textAlign); | |||
fonsSetFont(ctx->fs, state->fontId); | |||
fonsSetSize(ctx->fontContext->fs, state->fontSize*scale); | |||
fonsSetSpacing(ctx->fontContext->fs, state->letterSpacing*scale); | |||
fonsSetBlur(ctx->fontContext->fs, state->fontBlur*scale); | |||
fonsSetAlign(ctx->fontContext->fs, state->textAlign); | |||
fonsSetFont(ctx->fontContext->fs, state->fontId); | |||
fonsTextIterInit(ctx->fs, &iter, x*scale, y*scale, string, end, FONS_GLYPH_BITMAP_OPTIONAL); | |||
fonsTextIterInit(ctx->fontContext->fs, &iter, x*scale, y*scale, string, end, FONS_GLYPH_BITMAP_OPTIONAL); | |||
prevIter = iter; | |||
while (fonsTextIterNext(ctx->fs, &iter, &q)) { | |||
while (fonsTextIterNext(ctx->fontContext->fs, &iter, &q)) { | |||
if (iter.prevGlyphIndex < 0 && nvg__allocTextAtlas(ctx)) { // can not retrieve glyph? | |||
iter = prevIter; | |||
fonsTextIterNext(ctx->fs, &iter, &q); // try again | |||
fonsTextIterNext(ctx->fontContext->fs, &iter, &q); // try again | |||
} | |||
prevIter = iter; | |||
positions[npos].str = iter.str; | |||
@@ -2635,20 +2706,20 @@ int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, floa | |||
if (string == end) return 0; | |||
fonsSetSize(ctx->fs, state->fontSize*scale); | |||
fonsSetSpacing(ctx->fs, state->letterSpacing*scale); | |||
fonsSetBlur(ctx->fs, state->fontBlur*scale); | |||
fonsSetAlign(ctx->fs, state->textAlign); | |||
fonsSetFont(ctx->fs, state->fontId); | |||
fonsSetSize(ctx->fontContext->fs, state->fontSize*scale); | |||
fonsSetSpacing(ctx->fontContext->fs, state->letterSpacing*scale); | |||
fonsSetBlur(ctx->fontContext->fs, state->fontBlur*scale); | |||
fonsSetAlign(ctx->fontContext->fs, state->textAlign); | |||
fonsSetFont(ctx->fontContext->fs, state->fontId); | |||
breakRowWidth *= scale; | |||
fonsTextIterInit(ctx->fs, &iter, 0, 0, string, end, FONS_GLYPH_BITMAP_OPTIONAL); | |||
fonsTextIterInit(ctx->fontContext->fs, &iter, 0, 0, string, end, FONS_GLYPH_BITMAP_OPTIONAL); | |||
prevIter = iter; | |||
while (fonsTextIterNext(ctx->fs, &iter, &q)) { | |||
while (fonsTextIterNext(ctx->fontContext->fs, &iter, &q)) { | |||
if (iter.prevGlyphIndex < 0 && nvg__allocTextAtlas(ctx)) { // can not retrieve glyph? | |||
iter = prevIter; | |||
fonsTextIterNext(ctx->fs, &iter, &q); // try again | |||
fonsTextIterNext(ctx->fontContext->fs, &iter, &q); // try again | |||
} | |||
prevIter = iter; | |||
switch (iter.codepoint) { | |||
@@ -2819,16 +2890,16 @@ float nvgTextBounds(NVGcontext* ctx, float x, float y, const char* string, const | |||
if (state->fontId == FONS_INVALID) return 0; | |||
fonsSetSize(ctx->fs, state->fontSize*scale); | |||
fonsSetSpacing(ctx->fs, state->letterSpacing*scale); | |||
fonsSetBlur(ctx->fs, state->fontBlur*scale); | |||
fonsSetAlign(ctx->fs, state->textAlign); | |||
fonsSetFont(ctx->fs, state->fontId); | |||
fonsSetSize(ctx->fontContext->fs, state->fontSize*scale); | |||
fonsSetSpacing(ctx->fontContext->fs, state->letterSpacing*scale); | |||
fonsSetBlur(ctx->fontContext->fs, state->fontBlur*scale); | |||
fonsSetAlign(ctx->fontContext->fs, state->textAlign); | |||
fonsSetFont(ctx->fontContext->fs, state->fontId); | |||
width = fonsTextBounds(ctx->fs, x*scale, y*scale, string, end, bounds); | |||
width = fonsTextBounds(ctx->fontContext->fs, x*scale, y*scale, string, end, bounds); | |||
if (bounds != NULL) { | |||
// Use line bounds for height. | |||
fonsLineBounds(ctx->fs, y*scale, &bounds[1], &bounds[3]); | |||
fonsLineBounds(ctx->fontContext->fs, y*scale, &bounds[1], &bounds[3]); | |||
bounds[0] *= invscale; | |||
bounds[1] *= invscale; | |||
bounds[2] *= invscale; | |||
@@ -2863,12 +2934,12 @@ void nvgTextBoxBounds(NVGcontext* ctx, float x, float y, float breakRowWidth, co | |||
minx = maxx = x; | |||
miny = maxy = y; | |||
fonsSetSize(ctx->fs, state->fontSize*scale); | |||
fonsSetSpacing(ctx->fs, state->letterSpacing*scale); | |||
fonsSetBlur(ctx->fs, state->fontBlur*scale); | |||
fonsSetAlign(ctx->fs, state->textAlign); | |||
fonsSetFont(ctx->fs, state->fontId); | |||
fonsLineBounds(ctx->fs, 0, &rminy, &rmaxy); | |||
fonsSetSize(ctx->fontContext->fs, state->fontSize*scale); | |||
fonsSetSpacing(ctx->fontContext->fs, state->letterSpacing*scale); | |||
fonsSetBlur(ctx->fontContext->fs, state->fontBlur*scale); | |||
fonsSetAlign(ctx->fontContext->fs, state->textAlign); | |||
fonsSetFont(ctx->fontContext->fs, state->fontId); | |||
fonsLineBounds(ctx->fontContext->fs, 0, &rminy, &rmaxy); | |||
rminy *= invscale; | |||
rmaxy *= invscale; | |||
@@ -2914,13 +2985,13 @@ void nvgTextMetrics(NVGcontext* ctx, float* ascender, float* descender, float* l | |||
if (state->fontId == FONS_INVALID) return; | |||
fonsSetSize(ctx->fs, state->fontSize*scale); | |||
fonsSetSpacing(ctx->fs, state->letterSpacing*scale); | |||
fonsSetBlur(ctx->fs, state->fontBlur*scale); | |||
fonsSetAlign(ctx->fs, state->textAlign); | |||
fonsSetFont(ctx->fs, state->fontId); | |||
fonsSetSize(ctx->fontContext->fs, state->fontSize*scale); | |||
fonsSetSpacing(ctx->fontContext->fs, state->letterSpacing*scale); | |||
fonsSetBlur(ctx->fontContext->fs, state->fontBlur*scale); | |||
fonsSetAlign(ctx->fontContext->fs, state->textAlign); | |||
fonsSetFont(ctx->fontContext->fs, state->fontId); | |||
fonsVertMetrics(ctx->fs, ascender, descender, lineh); | |||
fonsVertMetrics(ctx->fontContext->fs, ascender, descender, lineh); | |||
if (ascender != NULL) | |||
*ascender *= invscale; | |||
if (descender != NULL) | |||
@@ -279,6 +279,10 @@ void nvgLineJoin(NVGcontext* ctx, int join); | |||
// Sets the transparency applied to all rendered shapes. | |||
// Already transparent paths will get proportionally more transparent as well. | |||
void nvgGlobalAlpha(NVGcontext* ctx, float alpha); | |||
void nvgGlobalTint(NVGcontext* ctx, NVGcolor tint); | |||
NVGcolor nvgGetGlobalTint(NVGcontext* ctx); | |||
void nvgAlpha(NVGcontext* ctx, float alpha); | |||
void nvgTint(NVGcontext* ctx, NVGcolor tint); | |||
// | |||
// Transforms | |||
@@ -385,7 +389,7 @@ int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, unsigned char* data, int | |||
// 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); | |||
int nvgCreateImageRaw(NVGcontext* ctx, int w, int h, int imageFlags, enum NVGtexture format, const unsigned char* data); | |||
// Creates image from specified image data. | |||
// Returns handle to the image. | |||
@@ -426,7 +430,7 @@ NVGpaint nvgBoxGradient(NVGcontext* ctx, float x, float y, float w, float h, | |||
NVGpaint nvgRadialGradient(NVGcontext* ctx, float cx, float cy, float inr, float outr, | |||
NVGcolor icol, NVGcolor ocol); | |||
// Creates and returns an image patter. Parameters (ox,oy) specify the left-top location of the image pattern, | |||
// Creates and returns an image pattern. Parameters (ox,oy) specify the left-top location of the image pattern, | |||
// (ex,ey) the size of one image, angle rotation around the top-left corner, image is handle to the image to render. | |||
// The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint(). | |||
NVGpaint nvgImagePattern(NVGcontext* ctx, float ox, float oy, float ex, float ey, | |||
@@ -667,7 +671,7 @@ typedef struct NVGpath NVGpath; | |||
struct NVGparams { | |||
void* userPtr; | |||
int edgeAntiAlias; | |||
int (*renderCreate)(void* uptr); | |||
int (*renderCreate)(void* uptr, void* otherUptr); | |||
int (*renderCreateTexture)(void* uptr, int type, int w, int h, int imageFlags, const unsigned char* data); | |||
int (*renderDeleteTexture)(void* uptr, int image); | |||
int (*renderUpdateTexture)(void* uptr, int image, int x, int y, int w, int h, const unsigned char* data); | |||
@@ -683,7 +687,7 @@ struct NVGparams { | |||
typedef struct NVGparams NVGparams; | |||
// Constructor and destructor, called by the render back-end. | |||
NVGcontext* nvgCreateInternal(NVGparams* params); | |||
NVGcontext* nvgCreateInternal(NVGparams* params, NVGcontext* other); | |||
void nvgDeleteInternal(NVGcontext* ctx); | |||
NVGparams* nvgInternalParams(NVGcontext* ctx); | |||
@@ -40,9 +40,7 @@ enum NVGcreateFlags { | |||
#elif defined NANOVG_GL3_IMPLEMENTATION | |||
# define NANOVG_GL3 1 | |||
# define NANOVG_GL_IMPLEMENTATION 1 | |||
# ifndef __APPLE__ | |||
# define NANOVG_GL_USE_UNIFORMBUFFER 1 | |||
# endif | |||
# define NANOVG_GL_USE_UNIFORMBUFFER 1 | |||
#elif defined NANOVG_GLES2_IMPLEMENTATION | |||
# define NANOVG_GLES2 1 | |||
# define NANOVG_GL_IMPLEMENTATION 1 | |||
@@ -59,6 +57,7 @@ enum NVGcreateFlags { | |||
#if defined NANOVG_GL2 | |||
NVGcontext* nvgCreateGL2(int flags); | |||
NVGcontext* nvgCreateSharedGL2(NVGcontext* other, int flags); | |||
void nvgDeleteGL2(NVGcontext* ctx); | |||
int nvglCreateImageFromHandleGL2(NVGcontext* ctx, GLuint textureId, int w, int h, int flags); | |||
@@ -69,6 +68,7 @@ GLuint nvglImageHandleGL2(NVGcontext* ctx, int image); | |||
#if defined NANOVG_GL3 | |||
NVGcontext* nvgCreateGL3(int flags); | |||
NVGcontext* nvgCreateSharedGL3(NVGcontext* other, int flags); | |||
void nvgDeleteGL3(NVGcontext* ctx); | |||
int nvglCreateImageFromHandleGL3(NVGcontext* ctx, GLuint textureId, int w, int h, int flags); | |||
@@ -79,6 +79,7 @@ GLuint nvglImageHandleGL3(NVGcontext* ctx, int image); | |||
#if defined NANOVG_GLES2 | |||
NVGcontext* nvgCreateGLES2(int flags); | |||
NVGcontext* nvgCreateSharedGLES2(NVGcontext* other, int flags); | |||
void nvgDeleteGLES2(NVGcontext* ctx); | |||
int nvglCreateImageFromHandleGLES2(NVGcontext* ctx, GLuint textureId, int w, int h, int flags); | |||
@@ -89,6 +90,7 @@ GLuint nvglImageHandleGLES2(NVGcontext* ctx, int image); | |||
#if defined NANOVG_GLES3 | |||
NVGcontext* nvgCreateGLES3(int flags); | |||
NVGcontext* nvgCreateSharedGLES3(NVGcontext* other, int flags); | |||
void nvgDeleteGLES3(NVGcontext* ctx); | |||
int nvglCreateImageFromHandleGLES3(NVGcontext* ctx, GLuint textureId, int w, int h, int flags); | |||
@@ -230,9 +232,18 @@ struct GLNVGfragUniforms { | |||
}; | |||
typedef struct GLNVGfragUniforms GLNVGfragUniforms; | |||
struct GLNVGtextureContext { // Textures; shared between shared NanoVG contexts. | |||
int refCount; | |||
GLNVGtexture* textures; | |||
int ntextures; | |||
int ctextures; | |||
int textureId; | |||
}; | |||
typedef struct GLNVGtextureContext GLNVGtextureContext; | |||
struct GLNVGcontext { | |||
GLNVGshader shader; | |||
GLNVGtexture* textures; | |||
GLNVGtextureContext* textureContext; | |||
float view[2]; | |||
int ntextures; | |||
int ctextures; | |||
@@ -352,26 +363,26 @@ static GLNVGtexture* glnvg__allocTexture(GLNVGcontext* gl) | |||
GLNVGtexture* tex = NULL; | |||
int i; | |||
for (i = 0; i < gl->ntextures; i++) { | |||
if (gl->textures[i].id == 0) { | |||
tex = &gl->textures[i]; | |||
for (i = 0; i < gl->textureContext->ntextures; i++) { | |||
if (gl->textureContext->textures[i].id == 0) { | |||
tex = &gl->textureContext->textures[i]; | |||
break; | |||
} | |||
} | |||
if (tex == NULL) { | |||
if (gl->ntextures+1 > gl->ctextures) { | |||
if (gl->textureContext->ntextures+1 > gl->textureContext->ctextures) { | |||
GLNVGtexture* textures; | |||
int ctextures = glnvg__maxi(gl->ntextures+1, 4) + gl->ctextures/2; // 1.5x Overallocate | |||
textures = (GLNVGtexture*)realloc(gl->textures, sizeof(GLNVGtexture)*ctextures); | |||
int ctextures = glnvg__maxi(gl->textureContext->ntextures+1, 4) + gl->textureContext->ctextures/2; // 1.5x Overallocate | |||
textures = (GLNVGtexture*)realloc(gl->textureContext->textures, sizeof(GLNVGtexture)*ctextures); | |||
if (textures == NULL) return NULL; | |||
gl->textures = textures; | |||
gl->ctextures = ctextures; | |||
gl->textureContext->textures = textures; | |||
gl->textureContext->ctextures = ctextures; | |||
} | |||
tex = &gl->textures[gl->ntextures++]; | |||
tex = &gl->textureContext->textures[gl->textureContext->ntextures++]; | |||
} | |||
memset(tex, 0, sizeof(*tex)); | |||
tex->id = ++gl->textureId; | |||
tex->id = ++gl->textureContext->textureId; | |||
return tex; | |||
} | |||
@@ -379,20 +390,20 @@ static GLNVGtexture* glnvg__allocTexture(GLNVGcontext* gl) | |||
static GLNVGtexture* glnvg__findTexture(GLNVGcontext* gl, int id) | |||
{ | |||
int i; | |||
for (i = 0; i < gl->ntextures; i++) | |||
if (gl->textures[i].id == id) | |||
return &gl->textures[i]; | |||
for (i = 0; i < gl->textureContext->ntextures; i++) | |||
if (gl->textureContext->textures[i].id == id) | |||
return &gl->textureContext->textures[i]; | |||
return NULL; | |||
} | |||
static int glnvg__deleteTexture(GLNVGcontext* gl, int id) | |||
{ | |||
int i; | |||
for (i = 0; i < gl->ntextures; i++) { | |||
if (gl->textures[i].id == id) { | |||
if (gl->textures[i].tex != 0 && (gl->textures[i].flags & NVG_IMAGE_NODELETE) == 0) | |||
glDeleteTextures(1, &gl->textures[i].tex); | |||
memset(&gl->textures[i], 0, sizeof(gl->textures[i])); | |||
for (i = 0; i < gl->textureContext->ntextures; i++) { | |||
if (gl->textureContext->textures[i].id == id) { | |||
if (gl->textureContext->textures[i].tex != 0 && (gl->textureContext->textures[i].flags & NVG_IMAGE_NODELETE) == 0) | |||
glDeleteTextures(1, &gl->textureContext->textures[i].tex); | |||
memset(&gl->textureContext->textures[i], 0, sizeof(gl->textureContext->textures[i])); | |||
return 1; | |||
} | |||
} | |||
@@ -506,9 +517,20 @@ static void glnvg__getUniforms(GLNVGshader* shader) | |||
static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int imageFlags, const unsigned char* data); | |||
static int glnvg__renderCreate(void* uptr) | |||
static int glnvg__renderCreate(void* uptr, void* otherUptr) // Share the textures of GLNVGcontext 'otherUptr' if it's non-NULL. | |||
{ | |||
GLNVGcontext* gl = (GLNVGcontext*)uptr; | |||
if (otherUptr) { | |||
GLNVGcontext* other = (GLNVGcontext*)otherUptr; | |||
gl->textureContext = other->textureContext; | |||
gl->textureContext->refCount++; | |||
} else { | |||
gl->textureContext = (GLNVGtextureContext*)malloc(sizeof(GLNVGtextureContext)); | |||
memset(gl->textureContext, 0, sizeof(GLNVGtextureContext)); | |||
gl->textureContext->refCount = 1; | |||
} | |||
int align = 4; | |||
// TODO: mediump float may not be enough for GLES2 in iOS. | |||
@@ -1605,11 +1627,14 @@ static void glnvg__renderDelete(void* uptr) | |||
if (gl->vertBuf != 0) | |||
glDeleteBuffers(1, &gl->vertBuf); | |||
for (i = 0; i < gl->ntextures; i++) { | |||
if (gl->textures[i].tex != 0 && (gl->textures[i].flags & NVG_IMAGE_NODELETE) == 0) | |||
glDeleteTextures(1, &gl->textures[i].tex); | |||
if (gl->textureContext != NULL && --gl->textureContext->refCount == 0) { | |||
for (i = 0; i < gl->textureContext->ntextures; i++) { | |||
if (gl->textureContext->textures[i].tex != 0 && (gl->textureContext->textures[i].flags & NVG_IMAGE_NODELETE) == 0) | |||
glDeleteTextures(1, &gl->textureContext->textures[i].tex); | |||
} | |||
free(gl->textureContext->textures); | |||
free(gl->textureContext); | |||
} | |||
free(gl->textures); | |||
free(gl->paths); | |||
free(gl->verts); | |||
@@ -1629,6 +1654,28 @@ NVGcontext* nvgCreateGLES2(int flags) | |||
#elif defined NANOVG_GLES3 | |||
NVGcontext* nvgCreateGLES3(int flags) | |||
#endif | |||
{ | |||
#if defined NANOVG_GL2 | |||
return nvgCreateSharedGL2(NULL, flags); | |||
#elif defined NANOVG_GL3 | |||
return nvgCreateSharedGL3(NULL, flags); | |||
#elif defined NANOVG_GLES2 | |||
return nvgCreateSharedGLES2(NULL, flags); | |||
#elif defined NANOVG_GLES3 | |||
return nvgCreateSharedGLES3(NULL, flags); | |||
#endif | |||
} | |||
// Share the fonts and textures of 'other' if it's non-NULL. | |||
#if defined NANOVG_GL2 | |||
NVGcontext* nvgCreateSharedGL2(NVGcontext* other, int flags) | |||
#elif defined NANOVG_GL3 | |||
NVGcontext* nvgCreateSharedGL3(NVGcontext* other, int flags) | |||
#elif defined NANOVG_GLES2 | |||
NVGcontext* nvgCreateSharedGLES2(NVGcontext* other, int flags) | |||
#elif defined NANOVG_GLES3 | |||
NVGcontext* nvgCreateSharedGLES3(NVGcontext* other, int flags) | |||
#endif | |||
{ | |||
NVGparams params; | |||
NVGcontext* ctx = NULL; | |||
@@ -1654,7 +1701,7 @@ NVGcontext* nvgCreateGLES3(int flags) | |||
gl->flags = flags; | |||
ctx = nvgCreateInternal(¶ms); | |||
ctx = nvgCreateInternal(¶ms, other); | |||
if (ctx == NULL) goto error; | |||
return ctx; | |||
@@ -1,6 +1,7 @@ | |||
Checks: > | |||
*, | |||
-*-uppercase-literal-suffix, | |||
-altera-struct-pack-align, | |||
-clang-diagnostic-unused-macros, | |||
-cppcoreguidelines-pro-bounds-pointer-arithmetic, | |||
-cppcoreguidelines-pro-type-reinterpret-cast, | |||
@@ -4,6 +4,7 @@ Checks: > | |||
-*avoid-c-arrays, | |||
-*magic-numbers, | |||
-*uppercase-literal-suffix, | |||
-altera-struct-pack-align, | |||
-android-cloexec-fopen, | |||
-bugprone-macro-parentheses, | |||
-bugprone-reserved-identifier, | |||
@@ -13,6 +14,7 @@ Checks: > | |||
-cert-flp30-c, | |||
-clang-analyzer-alpha.*, | |||
-clang-analyzer-security.FloatLoopCounter, | |||
-concurrency-mt-unsafe, | |||
-cppcoreguidelines-avoid-non-const-global-variables, | |||
-cppcoreguidelines-macro-usage, | |||
-cppcoreguidelines-pro-bounds-array-to-pointer-decay, | |||
@@ -33,6 +35,8 @@ Checks: > | |||
-llvmlibc-*, | |||
-misc-misplaced-const, | |||
-modernize-use-trailing-return-type, | |||
-performance-no-int-to-ptr, | |||
-readability-function-cognitive-complexity, | |||
-readability-implicit-bool-conversion, | |||
-readability-named-parameter, | |||
FormatStyle: file | |||
@@ -2,6 +2,7 @@ Checks: > | |||
*, | |||
-*-magic-numbers, | |||
-*-uppercase-literal-suffix, | |||
-altera-struct-pack-align, | |||
-clang-diagnostic-unused-function, | |||
-clang-diagnostic-unused-macros, | |||
-llvmlibc-*, | |||
@@ -2,6 +2,7 @@ Checks: > | |||
*, | |||
-*-uppercase-literal-suffix, | |||
-*magic-numbers, | |||
-altera-struct-pack-align, | |||
-bugprone-reserved-identifier, | |||
-cert-dcl37-c, | |||
-cert-dcl51-cpp, | |||
@@ -10,5 +11,6 @@ Checks: > | |||
-hicpp-signed-bitwise, | |||
-llvm-header-guard, | |||
-llvmlibc-*, | |||
-readability-function-cognitive-complexity, | |||
FormatStyle: file | |||
HeaderFilterRegex: 'pugl/.*' |
@@ -29,12 +29,9 @@ | |||
#include <stdlib.h> | |||
#ifndef __MAC_10_9 | |||
typedef NSUInteger NSEventSubtype; | |||
#endif | |||
#ifndef __MAC_10_10 | |||
typedef NSUInteger NSEventModifierFlags; | |||
typedef NSUInteger NSEventSubtype; | |||
#endif | |||
#ifndef __MAC_10_12 | |||
@@ -366,9 +366,8 @@ puglRealize(PuglView* const view) | |||
} | |||
#ifdef HAVE_XRANDR | |||
int ignored; | |||
if (XRRQueryExtension(display, &ignored, &ignored)) | |||
{ | |||
int ignored = 0; | |||
if (XRRQueryExtension(display, &ignored, &ignored)) { | |||
// Set refresh rate hint to the real refresh rate | |||
XRRScreenConfiguration* conf = XRRGetScreenInfo(display, parent); | |||
short current_rate = XRRConfigCurrentRate(conf); | |||
@@ -63,6 +63,9 @@ puglX11GlConfigure(PuglView* view) | |||
// clang-format off | |||
const int attrs[] = { | |||
#ifdef DGL_USE_RGBA | |||
GLX_RGBA, | |||
#endif | |||
GLX_X_RENDERABLE, True, | |||
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, | |||
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, | |||
@@ -149,7 +152,7 @@ puglX11GlCreate(PuglView* view) | |||
GLX_CONTEXT_PROFILE_MASK_ARB, | |||
(view->hints[PUGL_USE_COMPAT_PROFILE] | |||
? GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | |||
? GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB | |||
: GLX_CONTEXT_CORE_PROFILE_BIT_ARB), | |||
0}; | |||
@@ -2,7 +2,9 @@ Checks: > | |||
*, | |||
-*-magic-numbers, | |||
-*-uppercase-literal-suffix, | |||
-altera-struct-pack-align, | |||
-bugprone-reserved-identifier, | |||
-bugprone-suspicious-include, | |||
-cert-dcl37-c, | |||
-cert-dcl51-cpp, | |||
-google-runtime-references, | |||
@@ -11,5 +13,6 @@ Checks: > | |||
-llvm-header-guard, | |||
-llvmlibc-*, | |||
-modernize-use-trailing-return-type, | |||
-readability-function-cognitive-complexity, | |||
FormatStyle: file | |||
HeaderFilterRegex: 'pugl/.*|test/.*' |
@@ -295,7 +295,8 @@ public: | |||
*/ | |||
void setSize(uint width, uint height) | |||
{ | |||
DISTRHO_SAFE_ASSERT_UINT2_RETURN(width > 1 && height > 1, width, height,); | |||
DISTRHO_SAFE_ASSERT_UINT_RETURN(width > 1, width,); | |||
DISTRHO_SAFE_ASSERT_UINT_RETURN(height > 1, height,); | |||
if (pData.width == width && pData.height == height) | |||
return; | |||
@@ -314,10 +315,24 @@ public: | |||
{ | |||
if (pData.title == title) | |||
return; | |||
pData.title = title; | |||
titleChanged(title); | |||
} | |||
/** | |||
Set geometry constraints for the Window when resized by the user. | |||
*/ | |||
void setGeometryConstraints(uint minimumWidth, uint minimumHeight, bool keepAspectRatio = false) | |||
{ | |||
DISTRHO_SAFE_ASSERT_UINT_RETURN(minimumWidth > 0, minimumWidth,); | |||
DISTRHO_SAFE_ASSERT_UINT_RETURN(minimumHeight > 0, minimumHeight,); | |||
pData.minWidth = minimumWidth; | |||
pData.minHeight = minimumHeight; | |||
pData.keepAspectRatio = keepAspectRatio; | |||
} | |||
/* -------------------------------------------------------------------------------------------------------- | |||
* TopLevelWidget-like calls - actions called by the host */ | |||
@@ -339,6 +354,7 @@ public: | |||
{ | |||
if (pData.visible == visible) | |||
return; | |||
pData.visible = visible; | |||
visibilityChanged(visible); | |||
} | |||
@@ -351,6 +367,7 @@ public: | |||
{ | |||
if (pData.transientWinId == winId) | |||
return; | |||
pData.transientWinId = winId; | |||
transientParentWindowChanged(winId); | |||
} | |||
@@ -388,39 +405,35 @@ protected: | |||
A callback for when the window size changes. | |||
@note WIP this might need to get fed back into the host somehow. | |||
*/ | |||
virtual void sizeChanged(uint width, uint height) | |||
virtual void sizeChanged(uint /* width */, uint /* height */) | |||
{ | |||
// unused, meant for custom implementations | |||
return; (void)width; (void)height; | |||
} | |||
/** | |||
A callback for when the window title changes. | |||
@note WIP this might need to get fed back into the host somehow. | |||
*/ | |||
virtual void titleChanged(const char* title) | |||
virtual void titleChanged(const char* /* title */) | |||
{ | |||
// unused, meant for custom implementations | |||
return; (void)title; | |||
} | |||
/** | |||
A callback for when the window visibility changes. | |||
@note WIP this might need to get fed back into the host somehow. | |||
*/ | |||
virtual void visibilityChanged(bool visible) | |||
virtual void visibilityChanged(bool /* visible */) | |||
{ | |||
// unused, meant for custom implementations | |||
return; (void)visible; | |||
} | |||
/** | |||
A callback for when the transient parent window changes. | |||
*/ | |||
virtual void transientParentWindowChanged(uintptr_t winId) | |||
virtual void transientParentWindowChanged(uintptr_t /* winId */) | |||
{ | |||
// unused, meant for custom implementations | |||
return; (void)winId; | |||
} | |||
private: | |||
@@ -533,6 +546,9 @@ private: | |||
uint height; | |||
double scaleFactor; | |||
String title; | |||
uint minWidth; | |||
uint minHeight; | |||
bool keepAspectRatio; | |||
bool isQuitting; | |||
bool isStandalone; | |||
bool visible; | |||
@@ -544,6 +560,9 @@ private: | |||
height(1), | |||
scaleFactor(1.0), | |||
title(), | |||
minWidth(0), | |||
minHeight(0), | |||
keepAspectRatio(false), | |||
isQuitting(false), | |||
isStandalone(false), | |||
visible(false) {} | |||
@@ -757,6 +757,10 @@ public: | |||
{ | |||
res = v3_cpp_obj(stream)->read(stream, buffer, sizeof(buffer)-1, &read); | |||
DISTRHO_SAFE_ASSERT_INT_RETURN(res == V3_OK, res, res); | |||
if (read == 0) | |||
return V3_OK; | |||
DISTRHO_SAFE_ASSERT_INT_RETURN(read > 0, read, V3_INTERNAL_ERR); | |||
for (int32_t i = 0; i < read; ++i) | |||
@@ -2501,6 +2505,9 @@ struct dpf_edit_controller : v3_edit_controller_cpp { | |||
hostContextFromComponent(hc), | |||
hostContextFromInitialize(nullptr) | |||
{ | |||
d_stdout("dpf_edit_controller() has contexts %p %p", | |||
hostContextFromFactory, hostContextFromComponent); | |||
// make sure context is valid through this controller lifetime | |||
if (hostContextFromComponent != nullptr) | |||
v3_cpp_obj_ref(hostContextFromComponent); | |||
@@ -2537,6 +2544,10 @@ struct dpf_edit_controller : v3_edit_controller_cpp { | |||
v3_cpp_obj_unref(hostContextFromComponent); | |||
hostContextFromComponent = nullptr; | |||
} | |||
d_stdout("dpf_edit_controller::cleanup() has contexts %p %p", | |||
hostContextFromFactory, hostContextFromComponent); | |||
} | |||
// ---------------------------------------------------------------------------------------------------------------- | |||
@@ -2594,6 +2605,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { | |||
static uint32_t V3_API ref_edit_controller(void* self) | |||
{ | |||
d_stdout("dpf_edit_controller::ref => %p", self); | |||
return ++(*(dpf_edit_controller**)self)->refcounter; | |||
} | |||
@@ -2608,6 +2620,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { | |||
return refcount; | |||
} | |||
d_stdout("dpf_edit_controller::unref => %p is zero, doing cleanup", self); | |||
controller->cleanup(); | |||
return 0; | |||
} | |||
@@ -2628,6 +2641,8 @@ struct dpf_edit_controller : v3_edit_controller_cpp { | |||
v3_host_application** host = nullptr; | |||
v3_cpp_obj_query_interface(context, v3_host_application_iid, &host); | |||
d_stdout("dpf_edit_controller::initialize => %p %p | host %p", self, context, host); | |||
// save it for later so we can unref it | |||
controller->hostContextFromInitialize = host; | |||
@@ -2831,11 +2846,20 @@ struct dpf_edit_controller : v3_edit_controller_cpp { | |||
dpf_edit_controller* const controller = *(dpf_edit_controller**)self; | |||
DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, nullptr); | |||
d_stdout("create_view has contexts %p %p", | |||
controller->hostContextFromFactory, controller->hostContextFromComponent); | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
// plugin must be initialized | |||
PluginVst3* const vst3 = controller->vst3; | |||
DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, nullptr); | |||
d_stdout("dpf_edit_controller::create_view => %p %s | edit-ctrl %p, host %p, factory %p", | |||
self, name, | |||
controller->hostContextFromInitialize, | |||
controller->hostContextFromComponent, | |||
controller->hostContextFromFactory); | |||
// we require a host context for message creation | |||
v3_host_application** host = controller->hostContextFromInitialize != nullptr | |||
? controller->hostContextFromInitialize | |||
@@ -3238,6 +3262,9 @@ struct dpf_component : v3_component_cpp { | |||
if (v3_tuid_match(iid, v3_edit_controller_iid)) | |||
{ | |||
d_stdout("query_interface_component called with contexts %p %p", | |||
component->hostContextFromFactory, component->hostContextFromInitialize); | |||
if (component->controller == nullptr) | |||
component->controller = new dpf_edit_controller(component->vst3, | |||
component->hostContextFromFactory, | |||
@@ -3352,6 +3379,8 @@ struct dpf_component : v3_component_cpp { | |||
if (context != nullptr) | |||
v3_cpp_obj_query_interface(context, v3_host_application_iid, &host); | |||
d_stdout("dpf_component::initialize => %p %p | host %p", self, context, host); | |||
// save it for later so we can unref it | |||
component->hostContextFromInitialize = host; | |||
@@ -132,9 +132,16 @@ public: | |||
return uiData->window->getScaleFactor(); | |||
} | |||
Size<uint> getMinimumSizeConstraint(bool& keepAspectRatio) | |||
bool getGeometryConstraints(uint& minimumWidth, uint& minimumHeight, bool& keepAspectRatio) const noexcept | |||
{ | |||
return uiData->window->getMinimumSizeConstraint(keepAspectRatio); | |||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
uiData->window->getGeometryConstraints(minimumWidth, minimumHeight, keepAspectRatio); | |||
#else | |||
const DGL_NAMESPACE::Size<uint> size(uiData->window->getGeometryConstraints(keepAspectRatio)); | |||
minimumWidth = size.getWidth(); | |||
minimumHeight = size.getHeight(); | |||
#endif | |||
return true; | |||
} | |||
bool isResizable() const noexcept | |||
@@ -269,12 +276,16 @@ public: | |||
// ------------------------------------------------------------------- | |||
#ifdef DISTRHO_PLUGIN_TARGET_VST3 | |||
void setWindowSizeForVST3(const uint width, const uint height) | |||
{ | |||
ui->setSize(width, height); | |||
# if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
uiData->window->setSize(width, height); | |||
// uiData->app.idle(); | |||
# endif | |||
} | |||
#endif | |||
void setWindowTitle(const char* const uiTitle) | |||
{ | |||
@@ -320,6 +331,29 @@ public: | |||
ui->onCharacterInput(cev); | |||
return ret; | |||
} | |||
bool handlePluginKeyboardVST3(const bool press, const uint keychar, const uint keycode, const uint16_t mods) | |||
{ | |||
DGL_NAMESPACE::Widget::KeyboardEvent ev; | |||
ev.mod = mods; | |||
ev.press = press; | |||
ev.key = keychar; | |||
ev.keycode = keycode; | |||
const bool ret = ui->onKeyboard(ev); | |||
DGL_NAMESPACE::Widget::CharacterInputEvent cev; | |||
cev.mod = mods; | |||
cev.keycode = keycode; | |||
cev.character = keychar; | |||
// if shift modifier is on, convert a-z -> A-Z for character input | |||
if (keychar >= 'a' && keychar <= 'z' && (mods & DGL_NAMESPACE::kModifierShift) != 0) | |||
cev.character -= 'a' - 'A'; | |||
ui->onCharacterInput(cev); | |||
return ret; | |||
} | |||
#endif | |||
// ------------------------------------------------------------------- | |||
@@ -152,6 +152,12 @@ public: | |||
void setTitle(const char* const title) { ui->setTitle(title); } | |||
void setVisible(const bool visible) { ui->setVisible(visible); } | |||
uintptr_t getNativeWindowHandle() const noexcept { return ui->getNativeWindowHandle(); } | |||
void getGeometryConstraints(uint& minimumWidth, uint& minimumHeight, bool& keepAspectRatio) const noexcept | |||
{ | |||
minimumWidth = ui->pData.minWidth; | |||
minimumHeight = ui->pData.minHeight; | |||
keepAspectRatio = ui->pData.keepAspectRatio; | |||
} | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow) | |||
}; | |||
@@ -75,10 +75,11 @@ struct ScopedUTF16String { | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
static bool checkSizeConstraint(const Size<uint>& size, const bool keepAspectRatio, v3_view_rect* const rect) | |||
static bool applyGeometryConstraints(const uint minimumWidth, const uint minimumHeight, const bool keepAspectRatio, | |||
v3_view_rect* const rect) | |||
{ | |||
const int32_t minWidth = static_cast<int32_t>(size.getWidth()); | |||
const int32_t minHeight = static_cast<int32_t>(size.getHeight()); | |||
const int32_t minWidth = static_cast<int32_t>(minimumWidth); | |||
const int32_t minHeight = static_cast<int32_t>(minimumHeight); | |||
bool changed = false; | |||
if (keepAspectRatio) | |||
@@ -92,10 +93,10 @@ static bool checkSizeConstraint(const Size<uint>& size, const bool keepAspectRat | |||
// fix width | |||
if (reqRatio > ratio) | |||
rect->right = static_cast<uint>(rect->bottom * ratio + 0.5); | |||
rect->right = static_cast<int32_t>(rect->bottom * ratio + 0.5); | |||
// fix height | |||
else | |||
rect->bottom = static_cast<uint>(static_cast<double>(rect->right) / ratio + 0.5); | |||
rect->bottom = static_cast<int32_t>(static_cast<double>(rect->right) / ratio + 0.5); | |||
} | |||
} | |||
@@ -168,10 +169,10 @@ public: | |||
disconnect(); | |||
} | |||
void postInit(const Size<uint>& requestedSize) | |||
void postInit(const int32_t nextWidth, const int32_t nextHeight) | |||
{ | |||
if (fIsResizingFromHost && requestedSize.isValid()) | |||
fUI.setWindowSizeForVST3(requestedSize.getWidth(), requestedSize.getHeight()); | |||
if (fIsResizingFromHost && nextWidth > 0 && nextHeight > 0) | |||
fUI.setWindowSizeForVST3(nextWidth, nextHeight); | |||
if (fConnection != nullptr) | |||
connect(fConnection); | |||
@@ -190,16 +191,66 @@ public: | |||
return V3_NOT_IMPLEMENTED; | |||
} | |||
v3_result onKeyDown(int16_t /*key_char*/, int16_t /*key_code*/, int16_t /*modifiers*/) | |||
v3_result onKeyDown(const int16_t keychar, const int16_t keycode, const int16_t modifiers) | |||
{ | |||
d_stdout("onKeyDown %i %i %x\n", keychar, keycode, modifiers); | |||
DISTRHO_SAFE_ASSERT_INT_RETURN(keychar >= 0 && keychar < 0x7f, keychar, V3_FALSE); | |||
using namespace DGL_NAMESPACE; | |||
// TODO | |||
return V3_NOT_IMPLEMENTED; | |||
uint dglcode = 0; | |||
// TODO verify these | |||
uint dglmods = 0; | |||
if (modifiers & (1 << 0)) | |||
dglmods |= kModifierShift; | |||
if (modifiers & (1 << 1)) | |||
dglmods |= kModifierAlt; | |||
#ifdef DISTRHO_OS_MAC | |||
if (modifiers & (1 << 2)) | |||
dglmods |= kModifierSuper; | |||
if (modifiers & (1 << 3)) | |||
dglmods |= kModifierControl; | |||
#else | |||
if (modifiers & (1 << 2)) | |||
dglmods |= kModifierControl; | |||
if (modifiers & (1 << 3)) | |||
dglmods |= kModifierSuper; | |||
#endif | |||
return fUI.handlePluginKeyboardVST3(true, static_cast<uint>(keychar), dglcode, dglmods) ? V3_TRUE : V3_FALSE; | |||
} | |||
v3_result onKeyUp(int16_t /*key_char*/, int16_t /*key_code*/, int16_t /*modifiers*/) | |||
v3_result onKeyUp(const int16_t keychar, const int16_t keycode, const int16_t modifiers) | |||
{ | |||
d_stdout("onKeyDown %i %i %x\n", keychar, keycode, modifiers); | |||
DISTRHO_SAFE_ASSERT_INT_RETURN(keychar >= 0 && keychar < 0x7f, keychar, V3_FALSE); | |||
using namespace DGL_NAMESPACE; | |||
// TODO | |||
return V3_NOT_IMPLEMENTED; | |||
uint dglcode = 0; | |||
// TODO verify these | |||
uint dglmods = 0; | |||
if (modifiers & (1 << 0)) | |||
dglmods |= kModifierShift; | |||
if (modifiers & (1 << 1)) | |||
dglmods |= kModifierAlt; | |||
#ifdef DISTRHO_OS_MAC | |||
if (modifiers & (1 << 2)) | |||
dglmods |= kModifierSuper; | |||
if (modifiers & (1 << 3)) | |||
dglmods |= kModifierControl; | |||
#else | |||
if (modifiers & (1 << 2)) | |||
dglmods |= kModifierControl; | |||
if (modifiers & (1 << 3)) | |||
dglmods |= kModifierSuper; | |||
#endif | |||
return fUI.handlePluginKeyboardVST3(false, static_cast<uint>(keychar), dglcode, dglmods) ? V3_TRUE : V3_FALSE; | |||
} | |||
v3_result getSize(v3_view_rect* const rect) const noexcept | |||
@@ -255,9 +306,10 @@ public: | |||
v3_result checkSizeConstraint(v3_view_rect* const rect) | |||
{ | |||
uint minimumWidth, minimumHeight; | |||
bool keepAspectRatio; | |||
const Size<uint> size(fUI.getMinimumSizeConstraint(keepAspectRatio)); | |||
return ::checkSizeConstraint(size, keepAspectRatio, rect) ? V3_FALSE : V3_TRUE; | |||
fUI.getGeometryConstraints(minimumWidth, minimumHeight, keepAspectRatio); | |||
return applyGeometryConstraints(minimumWidth, minimumHeight, keepAspectRatio, rect) ? V3_FALSE : V3_TRUE; | |||
} | |||
// ---------------------------------------------------------------------------------------------------------------- | |||
@@ -919,14 +971,16 @@ struct dpf_plugin_view : v3_plugin_view_cpp { | |||
void* const instancePointer; | |||
double sampleRate; | |||
v3_plugin_frame** frame; | |||
Size<uint> nextSize; | |||
int32_t nextWidth, nextHeight; | |||
dpf_plugin_view(v3_host_application** const h, void* const instance, const double sr) | |||
: refcounter(1), | |||
host(h), | |||
instancePointer(instance), | |||
sampleRate(sr), | |||
frame(nullptr) | |||
frame(nullptr), | |||
nextWidth(0), | |||
nextHeight(0) | |||
{ | |||
// v3_funknown, everything custom | |||
query_interface = query_interface_view; | |||
@@ -1083,10 +1137,11 @@ struct dpf_plugin_view : v3_plugin_view_cpp { | |||
scaleFactor, | |||
view->sampleRate, | |||
view->instancePointer, | |||
view->nextSize.isValid()); | |||
view->nextWidth > 0 && view->nextHeight > 0); | |||
view->uivst3->postInit(view->nextSize); | |||
view->nextSize = Size<uint>(); | |||
view->uivst3->postInit(view->nextWidth, view->nextHeight); | |||
view->nextWidth = 0; | |||
view->nextHeight = 0; | |||
#ifdef DPF_VST3_USING_HOST_RUN_LOOP | |||
// register a timer host run loop stuff | |||
@@ -1206,7 +1261,8 @@ struct dpf_plugin_view : v3_plugin_view_cpp { | |||
if (UIVst3* const uivst3 = view->uivst3) | |||
return uivst3->onSize(rect); | |||
view->nextSize = Size<uint>(rect->right - rect->left, rect->bottom - rect->top); | |||
view->nextWidth = rect->right - rect->left; | |||
view->nextHeight = rect->bottom - rect->top; | |||
return V3_OK; | |||
} | |||
@@ -1261,9 +1317,10 @@ struct dpf_plugin_view : v3_plugin_view_cpp { | |||
UIExporter tmpUI(nullptr, 0, view->sampleRate, | |||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | |||
view->instancePointer, scaleFactor); | |||
uint minimumWidth, minimumHeight; | |||
bool keepAspectRatio; | |||
const Size<uint> size(tmpUI.getMinimumSizeConstraint(keepAspectRatio)); | |||
return ::checkSizeConstraint(size, keepAspectRatio, rect) ? V3_FALSE : V3_TRUE; | |||
tmpUI.getGeometryConstraints(minimumWidth, minimumHeight, keepAspectRatio); | |||
return applyGeometryConstraints(minimumWidth, minimumHeight, keepAspectRatio, rect) ? V3_FALSE : V3_TRUE; | |||
} | |||
}; | |||