| @@ -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; | |||
| } | |||
| }; | |||