@@ -238,26 +238,36 @@ all: | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
# Common | # Common | ||||
$(BUILD_DIR)/%.S.o: %.S | |||||
$(BUILD_DIR)/%.S.o: %.S $(EXTRA_LIBS) | |||||
-@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
@echo "Compiling $<" | @echo "Compiling $<" | ||||
@$(CC) $< $(BUILD_C_FLAGS) -c -o $@ | @$(CC) $< $(BUILD_C_FLAGS) -c -o $@ | ||||
$(BUILD_DIR)/%.c.o: %.c | |||||
$(BUILD_DIR)/%.c.o: %.c $(EXTRA_LIBS) | |||||
-@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
@echo "Compiling $<" | @echo "Compiling $<" | ||||
$(SILENT)$(CC) $< $(BUILD_C_FLAGS) -c -o $@ | $(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)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
@echo "Compiling $<" | @echo "Compiling $<" | ||||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | $(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)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
@echo "Compiling $<" | @echo "Compiling $<" | ||||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | $(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: | clean: | ||||
rm -rf $(BUILD_DIR) | rm -rf $(BUILD_DIR) | ||||
rm -rf $(TARGET_DIR)/$(NAME) $(TARGET_DIR)/$(NAME)-* $(TARGET_DIR)/$(NAME).lv2 | 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) | jack: $(jack) | ||||
ifeq ($(HAVE_DGL),true) | 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 | else | ||||
$(jack): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o | $(jack): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o | ||||
endif | endif | ||||
@@ -355,7 +365,7 @@ lv2_dsp: $(lv2_dsp) | |||||
lv2_sep: $(lv2_dsp) $(lv2_ui) | lv2_sep: $(lv2_dsp) $(lv2_ui) | ||||
ifeq ($(HAVE_DGL),true) | 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 | else | ||||
$(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o | $(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o | ||||
endif | endif | ||||
@@ -379,7 +389,7 @@ $(lv2_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) | |||||
vst2 vst: $(vst2) | vst2 vst: $(vst2) | ||||
ifeq ($(HAVE_DGL),true) | 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 | else | ||||
$(vst2): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.o | $(vst2): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.o | ||||
endif | endif | ||||
@@ -393,7 +403,7 @@ endif | |||||
vst3: $(vst3) | vst3: $(vst3) | ||||
ifeq ($(HAVE_DGL),true) | 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 | else | ||||
$(vst3): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o | $(vst3): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o | ||||
endif | endif | ||||
@@ -16,6 +16,12 @@ LINK_FLAGS += $(DGL_LIBS) | |||||
ifeq ($(USE_OPENGL3),true) | ifeq ($(USE_OPENGL3),true) | ||||
BUILD_CXX_FLAGS += -DDGL_USE_OPENGL3 | BUILD_CXX_FLAGS += -DDGL_USE_OPENGL3 | ||||
endif | 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 | # TODO fix these after pugl-upstream is done | ||||
BUILD_CXX_FLAGS += -Wno-attributes -Wno-extra -Wno-missing-field-initializers | BUILD_CXX_FLAGS += -Wno-attributes -Wno-extra -Wno-missing-field-initializers | ||||
@@ -943,6 +943,7 @@ private: | |||||
inline void onDisplay() override | inline void onDisplay() override | ||||
{ | { | ||||
// NOTE maybe should use BaseWidget::getWindow().getScaleFactor() as 3rd arg ? | // NOTE maybe should use BaseWidget::getWindow().getScaleFactor() as 3rd arg ? | ||||
NanoVG::reset(); | |||||
NanoVG::beginFrame(BaseWidget::getWidth(), BaseWidget::getHeight()); | NanoVG::beginFrame(BaseWidget::getWidth(), BaseWidget::getHeight()); | ||||
onNanoDisplay(); | onNanoDisplay(); | ||||
NanoVG::endFrame(); | NanoVG::endFrame(); | ||||
@@ -397,10 +397,10 @@ public: | |||||
void runAsModal(bool blockWait = false); | void runAsModal(bool blockWait = false); | ||||
/** | /** | ||||
Get the size constraint set for the Window. | |||||
Get the geometry constraints set for the Window. | |||||
@see setGeometryConstraints | @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. | 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(PFNGLUSEPROGRAMPROC, glUseProgram) | ||||
DGL_EXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer) | DGL_EXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer) | ||||
DGL_EXT(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate) | 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 | # ifdef DGL_USE_OPENGL3 | ||||
DGL_EXT(PFNGLBINDBUFFERRANGEPROC, glBindBufferRange) | DGL_EXT(PFNGLBINDBUFFERRANGEPROC, glBindBufferRange) | ||||
DGL_EXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray) | DGL_EXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray) | ||||
@@ -84,6 +96,11 @@ DGL_EXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding) | |||||
#include "nanovg/nanovg_gl.h" | #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) | #if defined(NANOVG_GL2) | ||||
# define nvgCreateGL nvgCreateGL2 | # define nvgCreateGL nvgCreateGL2 | ||||
# define nvgDeleteGL nvgDeleteGL2 | # define nvgDeleteGL nvgDeleteGL2 | ||||
@@ -145,6 +162,18 @@ DGL_EXT(PFNGLUNIFORM4FVPROC, glUniform4fv) | |||||
DGL_EXT(PFNGLUSEPROGRAMPROC, glUseProgram) | DGL_EXT(PFNGLUSEPROGRAMPROC, glUseProgram) | ||||
DGL_EXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer) | DGL_EXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer) | ||||
DGL_EXT(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate) | 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 | # ifdef DGL_USE_OPENGL3 | ||||
DGL_EXT(PFNGLBINDBUFFERRANGEPROC, glBindBufferRange) | DGL_EXT(PFNGLBINDBUFFERRANGEPROC, glBindBufferRange) | ||||
DGL_EXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray) | DGL_EXT(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray) | ||||
@@ -346,7 +346,7 @@ void Window::runAsModal(bool blockWait) | |||||
pData->runAsModal(blockWait); | pData->runAsModal(blockWait); | ||||
} | } | ||||
Size<uint> Window::getMinimumSizeConstraint(bool& keepAspectRatio) | |||||
Size<uint> Window::getGeometryConstraints(bool& keepAspectRatio) | |||||
{ | { | ||||
keepAspectRatio = pData->keepAspectRatio; | keepAspectRatio = pData->keepAspectRatio; | ||||
return Size<uint>(pData->minWidth, pData->minHeight); | 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); | puglSetHandle(view, this); | ||||
puglSetViewHint(view, PUGL_RESIZABLE, resizable ? PUGL_TRUE : PUGL_FALSE); | puglSetViewHint(view, PUGL_RESIZABLE, resizable ? PUGL_TRUE : PUGL_FALSE); | ||||
puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, 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); | puglSetViewHint(view, PUGL_DEPTH_BITS, 16); | ||||
#endif | |||||
puglSetViewHint(view, PUGL_STENCIL_BITS, 8); | puglSetViewHint(view, PUGL_STENCIL_BITS, 8); | ||||
#ifdef DGL_USE_OPENGL3 | #ifdef DGL_USE_OPENGL3 | ||||
puglSetViewHint(view, PUGL_USE_COMPAT_PROFILE, PUGL_FALSE); | puglSetViewHint(view, PUGL_USE_COMPAT_PROFILE, PUGL_FALSE); | ||||
@@ -24,8 +24,11 @@ | |||||
#include "nanovg.h" | #include "nanovg.h" | ||||
#define FONTSTASH_IMPLEMENTATION | #define FONTSTASH_IMPLEMENTATION | ||||
#include "fontstash.h" | #include "fontstash.h" | ||||
#ifndef NVG_NO_STB | |||||
#define STB_IMAGE_IMPLEMENTATION | #define STB_IMAGE_IMPLEMENTATION | ||||
#include "stb_image.h" | #include "stb_image.h" | ||||
#endif | |||||
#ifdef _MSC_VER | #ifdef _MSC_VER | ||||
#pragma warning(disable: 4100) // unreferenced formal parameter | #pragma warning(disable: 4100) // unreferenced formal parameter | ||||
@@ -74,7 +77,7 @@ struct NVGstate { | |||||
float miterLimit; | float miterLimit; | ||||
int lineJoin; | int lineJoin; | ||||
int lineCap; | int lineCap; | ||||
float alpha; | |||||
NVGcolor tint; | |||||
float xform[6]; | float xform[6]; | ||||
NVGscissor scissor; | NVGscissor scissor; | ||||
float fontSize; | float fontSize; | ||||
@@ -109,6 +112,14 @@ struct NVGpathCache { | |||||
}; | }; | ||||
typedef struct NVGpathCache 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 { | struct NVGcontext { | ||||
NVGparams params; | NVGparams params; | ||||
float* commands; | float* commands; | ||||
@@ -122,9 +133,7 @@ struct NVGcontext { | |||||
float distTol; | float distTol; | ||||
float fringeWidth; | float fringeWidth; | ||||
float devicePxRatio; | float devicePxRatio; | ||||
struct FONScontext* fs; | |||||
int fontImages[NVG_MAX_FONTIMAGES]; | |||||
int fontImageIdx; | |||||
NVGfontContext* fontContext; | |||||
int drawCallCount; | int drawCallCount; | ||||
int fillTriCount; | int fillTriCount; | ||||
int strokeTriCount; | int strokeTriCount; | ||||
@@ -283,7 +292,7 @@ static NVGstate* nvg__getState(NVGcontext* ctx) | |||||
return &ctx->states[ctx->nstates-1]; | 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; | FONSparams fontParams; | ||||
NVGcontext* ctx = (NVGcontext*)malloc(sizeof(NVGcontext)); | NVGcontext* ctx = (NVGcontext*)malloc(sizeof(NVGcontext)); | ||||
@@ -292,8 +301,16 @@ NVGcontext* nvgCreateInternal(NVGparams* params) | |||||
memset(ctx, 0, sizeof(NVGcontext)); | memset(ctx, 0, sizeof(NVGcontext)); | ||||
ctx->params = *params; | 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); | ctx->commands = (float*)malloc(sizeof(float)*NVG_INIT_COMMANDS_SIZE); | ||||
if (!ctx->commands) goto error; | if (!ctx->commands) goto error; | ||||
@@ -308,25 +325,27 @@ NVGcontext* nvgCreateInternal(NVGparams* params) | |||||
nvg__setDevicePixelRatio(ctx, 1.0f); | 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 | // 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; | return ctx; | ||||
@@ -347,14 +366,18 @@ void nvgDeleteInternal(NVGcontext* ctx) | |||||
if (ctx->commands != NULL) free(ctx->commands); | if (ctx->commands != NULL) free(ctx->commands); | ||||
if (ctx->cache != NULL) nvg__deletePathCache(ctx->cache); | 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) | if (ctx->params.renderDelete != NULL) | ||||
@@ -391,30 +414,30 @@ void nvgCancelFrame(NVGcontext* ctx) | |||||
void nvgEndFrame(NVGcontext* ctx) | void nvgEndFrame(NVGcontext* ctx) | ||||
{ | { | ||||
ctx->params.renderFlush(ctx->params.userPtr); | 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; | int i, j, iw, ih; | ||||
// delete images that smaller than current one | // delete images that smaller than current one | ||||
if (fontImage == 0) | if (fontImage == 0) | ||||
return; | return; | ||||
nvgImageSize(ctx, fontImage, &iw, &ih); | 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; | int nw, nh; | ||||
nvgImageSize(ctx, ctx->fontImages[i], &nw, &nh); | |||||
nvgImageSize(ctx, ctx->fontContext->fontImages[i], &nw, &nh); | |||||
if (nw < iw || nh < ih) | if (nw < iw || nh < ih) | ||||
nvgDeleteImage(ctx, ctx->fontImages[i]); | |||||
nvgDeleteImage(ctx, ctx->fontContext->fontImages[i]); | |||||
else | else | ||||
ctx->fontImages[j++] = ctx->fontImages[i]; | |||||
ctx->fontContext->fontImages[j++] = ctx->fontContext->fontImages[i]; | |||||
} | } | ||||
} | } | ||||
// make current font image to first | // 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 | // clear all images after j | ||||
for (i = j; i < NVG_MAX_FONTIMAGES; i++) | 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->miterLimit = 10.0f; | ||||
state->lineCap = NVG_BUTT; | state->lineCap = NVG_BUTT; | ||||
state->lineJoin = NVG_MITER; | state->lineJoin = NVG_MITER; | ||||
state->alpha = 1.0f; | |||||
state->tint = nvgRGBAf(1, 1, 1, 1); | |||||
nvgTransformIdentity(state->xform); | nvgTransformIdentity(state->xform); | ||||
state->scissor.extent[0] = -1.0f; | state->scissor.extent[0] = -1.0f; | ||||
@@ -699,7 +722,33 @@ void nvgLineJoin(NVGcontext* ctx, int join) | |||||
void nvgGlobalAlpha(NVGcontext* ctx, float alpha) | void nvgGlobalAlpha(NVGcontext* ctx, float alpha) | ||||
{ | { | ||||
NVGstate* state = nvg__getState(ctx); | 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) | 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); | nvgTransformMultiply(state->fill.xform, state->xform); | ||||
} | } | ||||
#ifndef NVG_NO_STB | |||||
int nvgCreateImage(NVGcontext* ctx, const char* filename, int imageFlags) | int nvgCreateImage(NVGcontext* ctx, const char* filename, int imageFlags) | ||||
{ | { | ||||
int w, h, n, image; | int w, h, n, image; | ||||
@@ -816,6 +866,7 @@ int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, unsigned char* data, int | |||||
stbi_image_free(img); | stbi_image_free(img); | ||||
return image; | return image; | ||||
} | } | ||||
#endif | |||||
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, NVGtexture format, const unsigned char* data) | ||||
{ | { | ||||
@@ -2234,9 +2285,11 @@ void nvgFill(NVGcontext* ctx) | |||||
else | else | ||||
nvg__expandFill(ctx, 0.0f, NVG_MITER, 2.4f); | 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->params.renderFill(ctx->params.userPtr, &fillPaint, state->compositeOperation, &state->scissor, ctx->fringeWidth, | ||||
ctx->cache->bounds, ctx->cache->paths, ctx->cache->npaths); | ctx->cache->bounds, ctx->cache->paths, ctx->cache->npaths); | ||||
@@ -2269,9 +2322,11 @@ void nvgStroke(NVGcontext* ctx) | |||||
strokeWidth = ctx->fringeWidth; | 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); | nvg__flattenPaths(ctx); | ||||
@@ -2294,35 +2349,35 @@ void nvgStroke(NVGcontext* ctx) | |||||
// Add fonts | // Add fonts | ||||
int nvgCreateFont(NVGcontext* ctx, const char* name, const char* filename) | 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) | 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) | 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) | 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) | int nvgFindFont(NVGcontext* ctx, const char* name) | ||||
{ | { | ||||
if (name == NULL) return -1; | if (name == NULL) return -1; | ||||
return fonsGetFontByName(ctx->fs, name); | |||||
return fonsGetFontByName(ctx->fontContext->fs, name); | |||||
} | } | ||||
int nvgAddFallbackFontId(NVGcontext* ctx, int baseFont, int fallbackFont) | int nvgAddFallbackFontId(NVGcontext* ctx, int baseFont, int fallbackFont) | ||||
{ | { | ||||
if(baseFont == -1 || fallbackFont == -1) return 0; | 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) | 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) | void nvgResetFallbackFontsId(NVGcontext* ctx, int baseFont) | ||||
{ | { | ||||
fonsResetFallbackFont(ctx->fs, baseFont); | |||||
fonsResetFallbackFont(ctx->fontContext->fs, baseFont); | |||||
} | } | ||||
void nvgResetFallbackFonts(NVGcontext* ctx, const char* 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) | void nvgFontFace(NVGcontext* ctx, const char* font) | ||||
{ | { | ||||
NVGstate* state = nvg__getState(ctx); | 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) | static float nvg__quantize(float a, float d) | ||||
@@ -2397,12 +2452,12 @@ static void nvg__flushTextTexture(NVGcontext* ctx) | |||||
{ | { | ||||
int dirty[4]; | 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 | // Update texture | ||||
if (fontImage != 0) { | if (fontImage != 0) { | ||||
int iw, ih; | 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 x = dirty[0]; | ||||
int y = dirty[1]; | int y = dirty[1]; | ||||
int w = dirty[2] - dirty[0]; | int w = dirty[2] - dirty[0]; | ||||
@@ -2416,37 +2471,40 @@ static int nvg__allocTextAtlas(NVGcontext* ctx) | |||||
{ | { | ||||
int iw, ih; | int iw, ih; | ||||
nvg__flushTextTexture(ctx); | nvg__flushTextTexture(ctx); | ||||
if (ctx->fontImageIdx >= NVG_MAX_FONTIMAGES-1) | |||||
if (ctx->fontContext->fontImageIdx >= NVG_MAX_FONTIMAGES-1) | |||||
return 0; | return 0; | ||||
// if next fontImage already have a texture | // 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. | 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) | if (iw > ih) | ||||
ih *= 2; | ih *= 2; | ||||
else | else | ||||
iw *= 2; | iw *= 2; | ||||
if (iw > NVG_MAX_FONTIMAGE_SIZE || ih > NVG_MAX_FONTIMAGE_SIZE) | if (iw > NVG_MAX_FONTIMAGE_SIZE || ih > NVG_MAX_FONTIMAGE_SIZE) | ||||
iw = 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; | return 1; | ||||
} | } | ||||
static void nvg__renderText(NVGcontext* ctx, NVGvertex* verts, int nverts) | static void nvg__renderText(NVGcontext* ctx, NVGvertex* verts, int nverts) | ||||
{ | { | ||||
int i; | |||||
NVGstate* state = nvg__getState(ctx); | NVGstate* state = nvg__getState(ctx); | ||||
NVGpaint paint = state->fill; | NVGpaint paint = state->fill; | ||||
// Render triangles. | // 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); | 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; | 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) | float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char* end) | ||||
{ | { | ||||
NVGstate* state = nvg__getState(ctx); | 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; | float invscale = 1.0f / scale; | ||||
int cverts = 0; | int cverts = 0; | ||||
int nverts = 0; | int nverts = 0; | ||||
int isFlipped = nvg__isTransformFlipped(state->xform); | |||||
if (end == NULL) | if (end == NULL) | ||||
end = string + strlen(string); | end = string + strlen(string); | ||||
if (state->fontId == FONS_INVALID) return x; | 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. | cverts = nvg__maxi(2, (int)(end - string)) * 6; // conservative estimate. | ||||
verts = nvg__allocTempVerts(ctx, cverts); | verts = nvg__allocTempVerts(ctx, cverts); | ||||
if (verts == NULL) return x; | 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; | prevIter = iter; | ||||
while (fonsTextIterNext(ctx->fs, &iter, &q)) { | |||||
while (fonsTextIterNext(ctx->fontContext->fs, &iter, &q)) { | |||||
float c[4*2]; | float c[4*2]; | ||||
if (iter.prevGlyphIndex == -1) { // can not retrieve glyph? | if (iter.prevGlyphIndex == -1) { // can not retrieve glyph? | ||||
if (nverts != 0) { | if (nverts != 0) { | ||||
@@ -2492,11 +2557,17 @@ float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char* | |||||
if (!nvg__allocTextAtlas(ctx)) | if (!nvg__allocTextAtlas(ctx)) | ||||
break; // no memory :( | break; // no memory :( | ||||
iter = prevIter; | 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? | if (iter.prevGlyphIndex == -1) // still can not find glyph? | ||||
break; | break; | ||||
} | } | ||||
prevIter = iter; | 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. | // Transform corners. | ||||
nvgTransformPoint(&c[0],&c[1], state->xform, q.x0*invscale, q.y0*invscale); | 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); | 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) | if (string == end) | ||||
return 0; | 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; | 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? | if (iter.prevGlyphIndex < 0 && nvg__allocTextAtlas(ctx)) { // can not retrieve glyph? | ||||
iter = prevIter; | iter = prevIter; | ||||
fonsTextIterNext(ctx->fs, &iter, &q); // try again | |||||
fonsTextIterNext(ctx->fontContext->fs, &iter, &q); // try again | |||||
} | } | ||||
prevIter = iter; | prevIter = iter; | ||||
positions[npos].str = iter.str; | 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; | 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; | 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; | 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? | if (iter.prevGlyphIndex < 0 && nvg__allocTextAtlas(ctx)) { // can not retrieve glyph? | ||||
iter = prevIter; | iter = prevIter; | ||||
fonsTextIterNext(ctx->fs, &iter, &q); // try again | |||||
fonsTextIterNext(ctx->fontContext->fs, &iter, &q); // try again | |||||
} | } | ||||
prevIter = iter; | prevIter = iter; | ||||
switch (iter.codepoint) { | 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; | 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) { | if (bounds != NULL) { | ||||
// Use line bounds for height. | // 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[0] *= invscale; | ||||
bounds[1] *= invscale; | bounds[1] *= invscale; | ||||
bounds[2] *= invscale; | bounds[2] *= invscale; | ||||
@@ -2863,12 +2934,12 @@ void nvgTextBoxBounds(NVGcontext* ctx, float x, float y, float breakRowWidth, co | |||||
minx = maxx = x; | minx = maxx = x; | ||||
miny = maxy = y; | 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; | rminy *= invscale; | ||||
rmaxy *= invscale; | rmaxy *= invscale; | ||||
@@ -2914,13 +2985,13 @@ void nvgTextMetrics(NVGcontext* ctx, float* ascender, float* descender, float* l | |||||
if (state->fontId == FONS_INVALID) return; | 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) | if (ascender != NULL) | ||||
*ascender *= invscale; | *ascender *= invscale; | ||||
if (descender != NULL) | if (descender != NULL) | ||||
@@ -279,6 +279,10 @@ void nvgLineJoin(NVGcontext* ctx, int join); | |||||
// Sets the transparency applied to all rendered shapes. | // Sets the transparency applied to all rendered shapes. | ||||
// Already transparent paths will get proportionally more transparent as well. | // Already transparent paths will get proportionally more transparent as well. | ||||
void nvgGlobalAlpha(NVGcontext* ctx, float alpha); | 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 | // Transforms | ||||
@@ -385,7 +389,7 @@ int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, unsigned char* data, int | |||||
// Creates image from specified image data and texture format. | // Creates image from specified image data and texture format. | ||||
// Returns handle to the image. | // 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. | // Creates image from specified image data. | ||||
// Returns handle to the image. | // 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, | NVGpaint nvgRadialGradient(NVGcontext* ctx, float cx, float cy, float inr, float outr, | ||||
NVGcolor icol, NVGcolor ocol); | 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. | // (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(). | // 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, | NVGpaint nvgImagePattern(NVGcontext* ctx, float ox, float oy, float ex, float ey, | ||||
@@ -667,7 +671,7 @@ typedef struct NVGpath NVGpath; | |||||
struct NVGparams { | struct NVGparams { | ||||
void* userPtr; | void* userPtr; | ||||
int edgeAntiAlias; | 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 (*renderCreateTexture)(void* uptr, int type, int w, int h, int imageFlags, const unsigned char* data); | ||||
int (*renderDeleteTexture)(void* uptr, int image); | int (*renderDeleteTexture)(void* uptr, int image); | ||||
int (*renderUpdateTexture)(void* uptr, int image, int x, int y, int w, int h, const unsigned char* data); | 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; | typedef struct NVGparams NVGparams; | ||||
// Constructor and destructor, called by the render back-end. | // Constructor and destructor, called by the render back-end. | ||||
NVGcontext* nvgCreateInternal(NVGparams* params); | |||||
NVGcontext* nvgCreateInternal(NVGparams* params, NVGcontext* other); | |||||
void nvgDeleteInternal(NVGcontext* ctx); | void nvgDeleteInternal(NVGcontext* ctx); | ||||
NVGparams* nvgInternalParams(NVGcontext* ctx); | NVGparams* nvgInternalParams(NVGcontext* ctx); | ||||
@@ -40,9 +40,7 @@ enum NVGcreateFlags { | |||||
#elif defined NANOVG_GL3_IMPLEMENTATION | #elif defined NANOVG_GL3_IMPLEMENTATION | ||||
# define NANOVG_GL3 1 | # define NANOVG_GL3 1 | ||||
# define NANOVG_GL_IMPLEMENTATION 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 | #elif defined NANOVG_GLES2_IMPLEMENTATION | ||||
# define NANOVG_GLES2 1 | # define NANOVG_GLES2 1 | ||||
# define NANOVG_GL_IMPLEMENTATION 1 | # define NANOVG_GL_IMPLEMENTATION 1 | ||||
@@ -59,6 +57,7 @@ enum NVGcreateFlags { | |||||
#if defined NANOVG_GL2 | #if defined NANOVG_GL2 | ||||
NVGcontext* nvgCreateGL2(int flags); | NVGcontext* nvgCreateGL2(int flags); | ||||
NVGcontext* nvgCreateSharedGL2(NVGcontext* other, int flags); | |||||
void nvgDeleteGL2(NVGcontext* ctx); | void nvgDeleteGL2(NVGcontext* ctx); | ||||
int nvglCreateImageFromHandleGL2(NVGcontext* ctx, GLuint textureId, int w, int h, int flags); | 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 | #if defined NANOVG_GL3 | ||||
NVGcontext* nvgCreateGL3(int flags); | NVGcontext* nvgCreateGL3(int flags); | ||||
NVGcontext* nvgCreateSharedGL3(NVGcontext* other, int flags); | |||||
void nvgDeleteGL3(NVGcontext* ctx); | void nvgDeleteGL3(NVGcontext* ctx); | ||||
int nvglCreateImageFromHandleGL3(NVGcontext* ctx, GLuint textureId, int w, int h, int flags); | 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 | #if defined NANOVG_GLES2 | ||||
NVGcontext* nvgCreateGLES2(int flags); | NVGcontext* nvgCreateGLES2(int flags); | ||||
NVGcontext* nvgCreateSharedGLES2(NVGcontext* other, int flags); | |||||
void nvgDeleteGLES2(NVGcontext* ctx); | void nvgDeleteGLES2(NVGcontext* ctx); | ||||
int nvglCreateImageFromHandleGLES2(NVGcontext* ctx, GLuint textureId, int w, int h, int flags); | 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 | #if defined NANOVG_GLES3 | ||||
NVGcontext* nvgCreateGLES3(int flags); | NVGcontext* nvgCreateGLES3(int flags); | ||||
NVGcontext* nvgCreateSharedGLES3(NVGcontext* other, int flags); | |||||
void nvgDeleteGLES3(NVGcontext* ctx); | void nvgDeleteGLES3(NVGcontext* ctx); | ||||
int nvglCreateImageFromHandleGLES3(NVGcontext* ctx, GLuint textureId, int w, int h, int flags); | int nvglCreateImageFromHandleGLES3(NVGcontext* ctx, GLuint textureId, int w, int h, int flags); | ||||
@@ -230,9 +232,18 @@ struct GLNVGfragUniforms { | |||||
}; | }; | ||||
typedef struct GLNVGfragUniforms 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 { | struct GLNVGcontext { | ||||
GLNVGshader shader; | GLNVGshader shader; | ||||
GLNVGtexture* textures; | |||||
GLNVGtextureContext* textureContext; | |||||
float view[2]; | float view[2]; | ||||
int ntextures; | int ntextures; | ||||
int ctextures; | int ctextures; | ||||
@@ -352,26 +363,26 @@ static GLNVGtexture* glnvg__allocTexture(GLNVGcontext* gl) | |||||
GLNVGtexture* tex = NULL; | GLNVGtexture* tex = NULL; | ||||
int i; | 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; | break; | ||||
} | } | ||||
} | } | ||||
if (tex == NULL) { | if (tex == NULL) { | ||||
if (gl->ntextures+1 > gl->ctextures) { | |||||
if (gl->textureContext->ntextures+1 > gl->textureContext->ctextures) { | |||||
GLNVGtexture* textures; | 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; | 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)); | memset(tex, 0, sizeof(*tex)); | ||||
tex->id = ++gl->textureId; | |||||
tex->id = ++gl->textureContext->textureId; | |||||
return tex; | return tex; | ||||
} | } | ||||
@@ -379,20 +390,20 @@ static GLNVGtexture* glnvg__allocTexture(GLNVGcontext* gl) | |||||
static GLNVGtexture* glnvg__findTexture(GLNVGcontext* gl, int id) | static GLNVGtexture* glnvg__findTexture(GLNVGcontext* gl, int id) | ||||
{ | { | ||||
int i; | 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; | return NULL; | ||||
} | } | ||||
static int glnvg__deleteTexture(GLNVGcontext* gl, int id) | static int glnvg__deleteTexture(GLNVGcontext* gl, int id) | ||||
{ | { | ||||
int i; | 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; | 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__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; | 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; | int align = 4; | ||||
// TODO: mediump float may not be enough for GLES2 in iOS. | // 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) | if (gl->vertBuf != 0) | ||||
glDeleteBuffers(1, &gl->vertBuf); | 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->paths); | ||||
free(gl->verts); | free(gl->verts); | ||||
@@ -1629,6 +1654,28 @@ NVGcontext* nvgCreateGLES2(int flags) | |||||
#elif defined NANOVG_GLES3 | #elif defined NANOVG_GLES3 | ||||
NVGcontext* nvgCreateGLES3(int flags) | NVGcontext* nvgCreateGLES3(int flags) | ||||
#endif | #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; | NVGparams params; | ||||
NVGcontext* ctx = NULL; | NVGcontext* ctx = NULL; | ||||
@@ -1654,7 +1701,7 @@ NVGcontext* nvgCreateGLES3(int flags) | |||||
gl->flags = flags; | gl->flags = flags; | ||||
ctx = nvgCreateInternal(¶ms); | |||||
ctx = nvgCreateInternal(¶ms, other); | |||||
if (ctx == NULL) goto error; | if (ctx == NULL) goto error; | ||||
return ctx; | return ctx; | ||||
@@ -1,6 +1,7 @@ | |||||
Checks: > | Checks: > | ||||
*, | *, | ||||
-*-uppercase-literal-suffix, | -*-uppercase-literal-suffix, | ||||
-altera-struct-pack-align, | |||||
-clang-diagnostic-unused-macros, | -clang-diagnostic-unused-macros, | ||||
-cppcoreguidelines-pro-bounds-pointer-arithmetic, | -cppcoreguidelines-pro-bounds-pointer-arithmetic, | ||||
-cppcoreguidelines-pro-type-reinterpret-cast, | -cppcoreguidelines-pro-type-reinterpret-cast, | ||||
@@ -4,6 +4,7 @@ Checks: > | |||||
-*avoid-c-arrays, | -*avoid-c-arrays, | ||||
-*magic-numbers, | -*magic-numbers, | ||||
-*uppercase-literal-suffix, | -*uppercase-literal-suffix, | ||||
-altera-struct-pack-align, | |||||
-android-cloexec-fopen, | -android-cloexec-fopen, | ||||
-bugprone-macro-parentheses, | -bugprone-macro-parentheses, | ||||
-bugprone-reserved-identifier, | -bugprone-reserved-identifier, | ||||
@@ -13,6 +14,7 @@ Checks: > | |||||
-cert-flp30-c, | -cert-flp30-c, | ||||
-clang-analyzer-alpha.*, | -clang-analyzer-alpha.*, | ||||
-clang-analyzer-security.FloatLoopCounter, | -clang-analyzer-security.FloatLoopCounter, | ||||
-concurrency-mt-unsafe, | |||||
-cppcoreguidelines-avoid-non-const-global-variables, | -cppcoreguidelines-avoid-non-const-global-variables, | ||||
-cppcoreguidelines-macro-usage, | -cppcoreguidelines-macro-usage, | ||||
-cppcoreguidelines-pro-bounds-array-to-pointer-decay, | -cppcoreguidelines-pro-bounds-array-to-pointer-decay, | ||||
@@ -33,6 +35,8 @@ Checks: > | |||||
-llvmlibc-*, | -llvmlibc-*, | ||||
-misc-misplaced-const, | -misc-misplaced-const, | ||||
-modernize-use-trailing-return-type, | -modernize-use-trailing-return-type, | ||||
-performance-no-int-to-ptr, | |||||
-readability-function-cognitive-complexity, | |||||
-readability-implicit-bool-conversion, | -readability-implicit-bool-conversion, | ||||
-readability-named-parameter, | -readability-named-parameter, | ||||
FormatStyle: file | FormatStyle: file | ||||
@@ -2,6 +2,7 @@ Checks: > | |||||
*, | *, | ||||
-*-magic-numbers, | -*-magic-numbers, | ||||
-*-uppercase-literal-suffix, | -*-uppercase-literal-suffix, | ||||
-altera-struct-pack-align, | |||||
-clang-diagnostic-unused-function, | -clang-diagnostic-unused-function, | ||||
-clang-diagnostic-unused-macros, | -clang-diagnostic-unused-macros, | ||||
-llvmlibc-*, | -llvmlibc-*, | ||||
@@ -2,6 +2,7 @@ Checks: > | |||||
*, | *, | ||||
-*-uppercase-literal-suffix, | -*-uppercase-literal-suffix, | ||||
-*magic-numbers, | -*magic-numbers, | ||||
-altera-struct-pack-align, | |||||
-bugprone-reserved-identifier, | -bugprone-reserved-identifier, | ||||
-cert-dcl37-c, | -cert-dcl37-c, | ||||
-cert-dcl51-cpp, | -cert-dcl51-cpp, | ||||
@@ -10,5 +11,6 @@ Checks: > | |||||
-hicpp-signed-bitwise, | -hicpp-signed-bitwise, | ||||
-llvm-header-guard, | -llvm-header-guard, | ||||
-llvmlibc-*, | -llvmlibc-*, | ||||
-readability-function-cognitive-complexity, | |||||
FormatStyle: file | FormatStyle: file | ||||
HeaderFilterRegex: 'pugl/.*' | HeaderFilterRegex: 'pugl/.*' |
@@ -29,12 +29,9 @@ | |||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#ifndef __MAC_10_9 | |||||
typedef NSUInteger NSEventSubtype; | |||||
#endif | |||||
#ifndef __MAC_10_10 | #ifndef __MAC_10_10 | ||||
typedef NSUInteger NSEventModifierFlags; | typedef NSUInteger NSEventModifierFlags; | ||||
typedef NSUInteger NSEventSubtype; | |||||
#endif | #endif | ||||
#ifndef __MAC_10_12 | #ifndef __MAC_10_12 | ||||
@@ -366,9 +366,8 @@ puglRealize(PuglView* const view) | |||||
} | } | ||||
#ifdef HAVE_XRANDR | #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 | // Set refresh rate hint to the real refresh rate | ||||
XRRScreenConfiguration* conf = XRRGetScreenInfo(display, parent); | XRRScreenConfiguration* conf = XRRGetScreenInfo(display, parent); | ||||
short current_rate = XRRConfigCurrentRate(conf); | short current_rate = XRRConfigCurrentRate(conf); | ||||
@@ -63,6 +63,9 @@ puglX11GlConfigure(PuglView* view) | |||||
// clang-format off | // clang-format off | ||||
const int attrs[] = { | const int attrs[] = { | ||||
#ifdef DGL_USE_RGBA | |||||
GLX_RGBA, | |||||
#endif | |||||
GLX_X_RENDERABLE, True, | GLX_X_RENDERABLE, True, | ||||
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, | GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, | ||||
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, | GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, | ||||
@@ -149,7 +152,7 @@ puglX11GlCreate(PuglView* view) | |||||
GLX_CONTEXT_PROFILE_MASK_ARB, | GLX_CONTEXT_PROFILE_MASK_ARB, | ||||
(view->hints[PUGL_USE_COMPAT_PROFILE] | (view->hints[PUGL_USE_COMPAT_PROFILE] | ||||
? GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | |||||
? GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB | |||||
: GLX_CONTEXT_CORE_PROFILE_BIT_ARB), | : GLX_CONTEXT_CORE_PROFILE_BIT_ARB), | ||||
0}; | 0}; | ||||
@@ -2,7 +2,9 @@ Checks: > | |||||
*, | *, | ||||
-*-magic-numbers, | -*-magic-numbers, | ||||
-*-uppercase-literal-suffix, | -*-uppercase-literal-suffix, | ||||
-altera-struct-pack-align, | |||||
-bugprone-reserved-identifier, | -bugprone-reserved-identifier, | ||||
-bugprone-suspicious-include, | |||||
-cert-dcl37-c, | -cert-dcl37-c, | ||||
-cert-dcl51-cpp, | -cert-dcl51-cpp, | ||||
-google-runtime-references, | -google-runtime-references, | ||||
@@ -11,5 +13,6 @@ Checks: > | |||||
-llvm-header-guard, | -llvm-header-guard, | ||||
-llvmlibc-*, | -llvmlibc-*, | ||||
-modernize-use-trailing-return-type, | -modernize-use-trailing-return-type, | ||||
-readability-function-cognitive-complexity, | |||||
FormatStyle: file | FormatStyle: file | ||||
HeaderFilterRegex: 'pugl/.*|test/.*' | HeaderFilterRegex: 'pugl/.*|test/.*' |
@@ -295,7 +295,8 @@ public: | |||||
*/ | */ | ||||
void setSize(uint width, uint height) | 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) | if (pData.width == width && pData.height == height) | ||||
return; | return; | ||||
@@ -314,10 +315,24 @@ public: | |||||
{ | { | ||||
if (pData.title == title) | if (pData.title == title) | ||||
return; | return; | ||||
pData.title = title; | pData.title = title; | ||||
titleChanged(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 */ | * TopLevelWidget-like calls - actions called by the host */ | ||||
@@ -339,6 +354,7 @@ public: | |||||
{ | { | ||||
if (pData.visible == visible) | if (pData.visible == visible) | ||||
return; | return; | ||||
pData.visible = visible; | pData.visible = visible; | ||||
visibilityChanged(visible); | visibilityChanged(visible); | ||||
} | } | ||||
@@ -351,6 +367,7 @@ public: | |||||
{ | { | ||||
if (pData.transientWinId == winId) | if (pData.transientWinId == winId) | ||||
return; | return; | ||||
pData.transientWinId = winId; | pData.transientWinId = winId; | ||||
transientParentWindowChanged(winId); | transientParentWindowChanged(winId); | ||||
} | } | ||||
@@ -388,39 +405,35 @@ protected: | |||||
A callback for when the window size changes. | A callback for when the window size changes. | ||||
@note WIP this might need to get fed back into the host somehow. | @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 | // unused, meant for custom implementations | ||||
return; (void)width; (void)height; | |||||
} | } | ||||
/** | /** | ||||
A callback for when the window title changes. | A callback for when the window title changes. | ||||
@note WIP this might need to get fed back into the host somehow. | @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 | // unused, meant for custom implementations | ||||
return; (void)title; | |||||
} | } | ||||
/** | /** | ||||
A callback for when the window visibility changes. | A callback for when the window visibility changes. | ||||
@note WIP this might need to get fed back into the host somehow. | @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 | // unused, meant for custom implementations | ||||
return; (void)visible; | |||||
} | } | ||||
/** | /** | ||||
A callback for when the transient parent window changes. | 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 | // unused, meant for custom implementations | ||||
return; (void)winId; | |||||
} | } | ||||
private: | private: | ||||
@@ -533,6 +546,9 @@ private: | |||||
uint height; | uint height; | ||||
double scaleFactor; | double scaleFactor; | ||||
String title; | String title; | ||||
uint minWidth; | |||||
uint minHeight; | |||||
bool keepAspectRatio; | |||||
bool isQuitting; | bool isQuitting; | ||||
bool isStandalone; | bool isStandalone; | ||||
bool visible; | bool visible; | ||||
@@ -544,6 +560,9 @@ private: | |||||
height(1), | height(1), | ||||
scaleFactor(1.0), | scaleFactor(1.0), | ||||
title(), | title(), | ||||
minWidth(0), | |||||
minHeight(0), | |||||
keepAspectRatio(false), | |||||
isQuitting(false), | isQuitting(false), | ||||
isStandalone(false), | isStandalone(false), | ||||
visible(false) {} | visible(false) {} | ||||
@@ -757,6 +757,10 @@ public: | |||||
{ | { | ||||
res = v3_cpp_obj(stream)->read(stream, buffer, sizeof(buffer)-1, &read); | res = v3_cpp_obj(stream)->read(stream, buffer, sizeof(buffer)-1, &read); | ||||
DISTRHO_SAFE_ASSERT_INT_RETURN(res == V3_OK, res, res); | 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); | DISTRHO_SAFE_ASSERT_INT_RETURN(read > 0, read, V3_INTERNAL_ERR); | ||||
for (int32_t i = 0; i < read; ++i) | for (int32_t i = 0; i < read; ++i) | ||||
@@ -2501,6 +2505,9 @@ struct dpf_edit_controller : v3_edit_controller_cpp { | |||||
hostContextFromComponent(hc), | hostContextFromComponent(hc), | ||||
hostContextFromInitialize(nullptr) | hostContextFromInitialize(nullptr) | ||||
{ | { | ||||
d_stdout("dpf_edit_controller() has contexts %p %p", | |||||
hostContextFromFactory, hostContextFromComponent); | |||||
// make sure context is valid through this controller lifetime | // make sure context is valid through this controller lifetime | ||||
if (hostContextFromComponent != nullptr) | if (hostContextFromComponent != nullptr) | ||||
v3_cpp_obj_ref(hostContextFromComponent); | v3_cpp_obj_ref(hostContextFromComponent); | ||||
@@ -2537,6 +2544,10 @@ struct dpf_edit_controller : v3_edit_controller_cpp { | |||||
v3_cpp_obj_unref(hostContextFromComponent); | v3_cpp_obj_unref(hostContextFromComponent); | ||||
hostContextFromComponent = nullptr; | 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) | static uint32_t V3_API ref_edit_controller(void* self) | ||||
{ | { | ||||
d_stdout("dpf_edit_controller::ref => %p", self); | |||||
return ++(*(dpf_edit_controller**)self)->refcounter; | return ++(*(dpf_edit_controller**)self)->refcounter; | ||||
} | } | ||||
@@ -2608,6 +2620,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { | |||||
return refcount; | return refcount; | ||||
} | } | ||||
d_stdout("dpf_edit_controller::unref => %p is zero, doing cleanup", self); | |||||
controller->cleanup(); | controller->cleanup(); | ||||
return 0; | return 0; | ||||
} | } | ||||
@@ -2628,6 +2641,8 @@ struct dpf_edit_controller : v3_edit_controller_cpp { | |||||
v3_host_application** host = nullptr; | v3_host_application** host = nullptr; | ||||
v3_cpp_obj_query_interface(context, v3_host_application_iid, &host); | 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 | // save it for later so we can unref it | ||||
controller->hostContextFromInitialize = host; | controller->hostContextFromInitialize = host; | ||||
@@ -2831,11 +2846,20 @@ struct dpf_edit_controller : v3_edit_controller_cpp { | |||||
dpf_edit_controller* const controller = *(dpf_edit_controller**)self; | dpf_edit_controller* const controller = *(dpf_edit_controller**)self; | ||||
DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, nullptr); | DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, nullptr); | ||||
d_stdout("create_view has contexts %p %p", | |||||
controller->hostContextFromFactory, controller->hostContextFromComponent); | |||||
#if DISTRHO_PLUGIN_HAS_UI | #if DISTRHO_PLUGIN_HAS_UI | ||||
// plugin must be initialized | // plugin must be initialized | ||||
PluginVst3* const vst3 = controller->vst3; | PluginVst3* const vst3 = controller->vst3; | ||||
DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, nullptr); | 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 | // we require a host context for message creation | ||||
v3_host_application** host = controller->hostContextFromInitialize != nullptr | v3_host_application** host = controller->hostContextFromInitialize != nullptr | ||||
? controller->hostContextFromInitialize | ? controller->hostContextFromInitialize | ||||
@@ -3238,6 +3262,9 @@ struct dpf_component : v3_component_cpp { | |||||
if (v3_tuid_match(iid, v3_edit_controller_iid)) | 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) | if (component->controller == nullptr) | ||||
component->controller = new dpf_edit_controller(component->vst3, | component->controller = new dpf_edit_controller(component->vst3, | ||||
component->hostContextFromFactory, | component->hostContextFromFactory, | ||||
@@ -3352,6 +3379,8 @@ struct dpf_component : v3_component_cpp { | |||||
if (context != nullptr) | if (context != nullptr) | ||||
v3_cpp_obj_query_interface(context, v3_host_application_iid, &host); | 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 | // save it for later so we can unref it | ||||
component->hostContextFromInitialize = host; | component->hostContextFromInitialize = host; | ||||
@@ -132,9 +132,16 @@ public: | |||||
return uiData->window->getScaleFactor(); | 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 | bool isResizable() const noexcept | ||||
@@ -269,12 +276,16 @@ public: | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
#ifdef DISTRHO_PLUGIN_TARGET_VST3 | |||||
void setWindowSizeForVST3(const uint width, const uint height) | void setWindowSizeForVST3(const uint width, const uint height) | ||||
{ | { | ||||
ui->setSize(width, height); | ui->setSize(width, height); | ||||
# if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
uiData->window->setSize(width, height); | uiData->window->setSize(width, height); | ||||
// uiData->app.idle(); | // uiData->app.idle(); | ||||
# endif | |||||
} | } | ||||
#endif | |||||
void setWindowTitle(const char* const uiTitle) | void setWindowTitle(const char* const uiTitle) | ||||
{ | { | ||||
@@ -320,6 +331,29 @@ public: | |||||
ui->onCharacterInput(cev); | ui->onCharacterInput(cev); | ||||
return ret; | 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 | #endif | ||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
@@ -152,6 +152,12 @@ public: | |||||
void setTitle(const char* const title) { ui->setTitle(title); } | void setTitle(const char* const title) { ui->setTitle(title); } | ||||
void setVisible(const bool visible) { ui->setVisible(visible); } | void setVisible(const bool visible) { ui->setVisible(visible); } | ||||
uintptr_t getNativeWindowHandle() const noexcept { return ui->getNativeWindowHandle(); } | 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) | 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; | bool changed = false; | ||||
if (keepAspectRatio) | if (keepAspectRatio) | ||||
@@ -92,10 +93,10 @@ static bool checkSizeConstraint(const Size<uint>& size, const bool keepAspectRat | |||||
// fix width | // fix width | ||||
if (reqRatio > ratio) | 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 | // fix height | ||||
else | 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(); | 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) | if (fConnection != nullptr) | ||||
connect(fConnection); | connect(fConnection); | ||||
@@ -190,16 +191,66 @@ public: | |||||
return V3_NOT_IMPLEMENTED; | 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 | // 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 | // 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 | v3_result getSize(v3_view_rect* const rect) const noexcept | ||||
@@ -255,9 +306,10 @@ public: | |||||
v3_result checkSizeConstraint(v3_view_rect* const rect) | v3_result checkSizeConstraint(v3_view_rect* const rect) | ||||
{ | { | ||||
uint minimumWidth, minimumHeight; | |||||
bool keepAspectRatio; | 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; | void* const instancePointer; | ||||
double sampleRate; | double sampleRate; | ||||
v3_plugin_frame** frame; | 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) | dpf_plugin_view(v3_host_application** const h, void* const instance, const double sr) | ||||
: refcounter(1), | : refcounter(1), | ||||
host(h), | host(h), | ||||
instancePointer(instance), | instancePointer(instance), | ||||
sampleRate(sr), | sampleRate(sr), | ||||
frame(nullptr) | |||||
frame(nullptr), | |||||
nextWidth(0), | |||||
nextHeight(0) | |||||
{ | { | ||||
// v3_funknown, everything custom | // v3_funknown, everything custom | ||||
query_interface = query_interface_view; | query_interface = query_interface_view; | ||||
@@ -1083,10 +1137,11 @@ struct dpf_plugin_view : v3_plugin_view_cpp { | |||||
scaleFactor, | scaleFactor, | ||||
view->sampleRate, | view->sampleRate, | ||||
view->instancePointer, | 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 | #ifdef DPF_VST3_USING_HOST_RUN_LOOP | ||||
// register a timer host run loop stuff | // 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) | if (UIVst3* const uivst3 = view->uivst3) | ||||
return uivst3->onSize(rect); | 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; | return V3_OK; | ||||
} | } | ||||
@@ -1261,9 +1317,10 @@ struct dpf_plugin_view : v3_plugin_view_cpp { | |||||
UIExporter tmpUI(nullptr, 0, view->sampleRate, | UIExporter tmpUI(nullptr, 0, view->sampleRate, | ||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | ||||
view->instancePointer, scaleFactor); | view->instancePointer, scaleFactor); | ||||
uint minimumWidth, minimumHeight; | |||||
bool keepAspectRatio; | 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; | |||||
} | } | ||||
}; | }; | ||||