diff --git a/dpf/Makefile.plugins.mk b/dpf/Makefile.plugins.mk index 0ba0ce4..67f8f2d 100644 --- a/dpf/Makefile.plugins.mk +++ b/dpf/Makefile.plugins.mk @@ -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 diff --git a/dpf/dgl/Makefile b/dpf/dgl/Makefile index bac32fc..e570a94 100644 --- a/dpf/dgl/Makefile +++ b/dpf/dgl/Makefile @@ -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 diff --git a/dpf/dgl/NanoVG.hpp b/dpf/dgl/NanoVG.hpp index af33ab8..e7f96f1 100644 --- a/dpf/dgl/NanoVG.hpp +++ b/dpf/dgl/NanoVG.hpp @@ -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(); diff --git a/dpf/dgl/Window.hpp b/dpf/dgl/Window.hpp index c204615..181f012 100644 --- a/dpf/dgl/Window.hpp +++ b/dpf/dgl/Window.hpp @@ -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 getMinimumSizeConstraint(bool& keepAspectRatio); + Size getGeometryConstraints(bool& keepAspectRatio); /** Set geometry constraints for the Window when resized by the user, and optionally scale contents automatically. diff --git a/dpf/dgl/src/NanoVG.cpp b/dpf/dgl/src/NanoVG.cpp index 3ad9032..1faa60f 100644 --- a/dpf/dgl/src/NanoVG.cpp +++ b/dpf/dgl/src/NanoVG.cpp @@ -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) diff --git a/dpf/dgl/src/Window.cpp b/dpf/dgl/src/Window.cpp index 776db8d..c09106f 100644 --- a/dpf/dgl/src/Window.cpp +++ b/dpf/dgl/src/Window.cpp @@ -346,7 +346,7 @@ void Window::runAsModal(bool blockWait) pData->runAsModal(blockWait); } -Size Window::getMinimumSizeConstraint(bool& keepAspectRatio) +Size Window::getGeometryConstraints(bool& keepAspectRatio) { keepAspectRatio = pData->keepAspectRatio; return Size(pData->minWidth, pData->minHeight); diff --git a/dpf/dgl/src/WindowPrivateData.cpp b/dpf/dgl/src/WindowPrivateData.cpp index 15a1d28..27bee50 100644 --- a/dpf/dgl/src/WindowPrivateData.cpp +++ b/dpf/dgl/src/WindowPrivateData.cpp @@ -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); diff --git a/dpf/dgl/src/nanovg/nanovg.c b/dpf/dgl/src/nanovg/nanovg.c index 209c34f..3f9c0b4 100644 --- a/dpf/dgl/src/nanovg/nanovg.c +++ b/dpf/dgl/src/nanovg/nanovg.c @@ -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) diff --git a/dpf/dgl/src/nanovg/nanovg.h b/dpf/dgl/src/nanovg/nanovg.h index a2abfe9..89b4dd8 100644 --- a/dpf/dgl/src/nanovg/nanovg.h +++ b/dpf/dgl/src/nanovg/nanovg.h @@ -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); diff --git a/dpf/dgl/src/nanovg/nanovg_gl.h b/dpf/dgl/src/nanovg/nanovg_gl.h index fd4b416..cdf0901 100644 --- a/dpf/dgl/src/nanovg/nanovg_gl.h +++ b/dpf/dgl/src/nanovg/nanovg_gl.h @@ -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; diff --git a/dpf/dgl/src/nanovg/stb_image.h b/dpf/dgl/src/nanovg/stb_image.h index 2857f05..e06f7a1 100644 --- a/dpf/dgl/src/nanovg/stb_image.h +++ b/dpf/dgl/src/nanovg/stb_image.h @@ -1,5 +1,5 @@ -/* stb_image - v2.25 - public domain image loader - http://nothings.org/stb - no warranty implied; use at your own risk +/* stb_image - v2.10 - public domain image loader - http://nothings.org/stb_image.h + no warranty implied; use at your own risk Do this: #define STB_IMAGE_IMPLEMENTATION @@ -21,7 +21,7 @@ avoid problematic images and only need the trivial interface JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) - PNG 1/2/4/8/16-bit-per-channel + PNG 1/2/4/8-bit-per-channel (16 bpc not supported) TGA (not sure what subset, if a subset) BMP non-1bpp, non-RLE @@ -42,32 +42,135 @@ Full documentation under "DOCUMENTATION" below. -LICENSE - - See end of file for license information. - -RECENT REVISION HISTORY: - - 2.25 (2020-02-02) fix warnings - 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically - 2.23 (2019-08-11) fix clang static analysis warning - 2.22 (2019-03-04) gif fixes, fix warnings - 2.21 (2019-02-25) fix typo in comment - 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs - 2.19 (2018-02-11) fix warning - 2.18 (2018-01-30) fix warnings - 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings - 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes - 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC - 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs - 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes - 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes - 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 - RGB-format JPEG; remove white matting in PSD; - allocate large structures on the stack; - correct channel count for PNG & BMP + Revision 2.00 release notes: + + - Progressive JPEG is now supported. + + - PPM and PGM binary formats are now supported, thanks to Ken Miller. + + - x86 platforms now make use of SSE2 SIMD instructions for + JPEG decoding, and ARM platforms can use NEON SIMD if requested. + This work was done by Fabian "ryg" Giesen. SSE2 is used by + default, but NEON must be enabled explicitly; see docs. + + With other JPEG optimizations included in this version, we see + 2x speedup on a JPEG on an x86 machine, and a 1.5x speedup + on a JPEG on an ARM machine, relative to previous versions of this + library. The same results will not obtain for all JPGs and for all + x86/ARM machines. (Note that progressive JPEGs are significantly + slower to decode than regular JPEGs.) This doesn't mean that this + is the fastest JPEG decoder in the land; rather, it brings it + closer to parity with standard libraries. If you want the fastest + decode, look elsewhere. (See "Philosophy" section of docs below.) + + See final bullet items below for more info on SIMD. + + - Added STBI_MALLOC, STBI_REALLOC, and STBI_FREE macros for replacing + the memory allocator. Unlike other STBI libraries, these macros don't + support a context parameter, so if you need to pass a context in to + the allocator, you'll have to store it in a global or a thread-local + variable. + + - Split existing STBI_NO_HDR flag into two flags, STBI_NO_HDR and + STBI_NO_LINEAR. + STBI_NO_HDR: suppress implementation of .hdr reader format + STBI_NO_LINEAR: suppress high-dynamic-range light-linear float API + + - You can suppress implementation of any of the decoders to reduce + your code footprint by #defining one or more of the following + symbols before creating the implementation. + + STBI_NO_JPEG + STBI_NO_PNG + STBI_NO_BMP + STBI_NO_PSD + STBI_NO_TGA + STBI_NO_GIF + STBI_NO_HDR + STBI_NO_PIC + STBI_NO_PNM (.ppm and .pgm) + + - You can request *only* certain decoders and suppress all other ones + (this will be more forward-compatible, as addition of new decoders + doesn't require you to disable them explicitly): + + STBI_ONLY_JPEG + STBI_ONLY_PNG + STBI_ONLY_BMP + STBI_ONLY_PSD + STBI_ONLY_TGA + STBI_ONLY_GIF + STBI_ONLY_HDR + STBI_ONLY_PIC + STBI_ONLY_PNM (.ppm and .pgm) + + Note that you can define multiples of these, and you will get all + of them ("only x" and "only y" is interpreted to mean "only x&y"). + + - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still + want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB + + - Compilation of all SIMD code can be suppressed with + #define STBI_NO_SIMD + It should not be necessary to disable SIMD unless you have issues + compiling (e.g. using an x86 compiler which doesn't support SSE + intrinsics or that doesn't support the method used to detect + SSE2 support at run-time), and even those can be reported as + bugs so I can refine the built-in compile-time checking to be + smarter. + + - The old STBI_SIMD system which allowed installing a user-defined + IDCT etc. has been removed. If you need this, don't upgrade. My + assumption is that almost nobody was doing this, and those who + were will find the built-in SIMD more satisfactory anyway. + + - RGB values computed for JPEG images are slightly different from + previous versions of stb_image. (This is due to using less + integer precision in SIMD.) The C code has been adjusted so + that the same RGB values will be computed regardless of whether + SIMD support is available, so your app should always produce + consistent results. But these results are slightly different from + previous versions. (Specifically, about 3% of available YCbCr values + will compute different RGB results from pre-1.49 versions by +-1; + most of the deviating values are one smaller in the G channel.) + + - If you must produce consistent results with previous versions of + stb_image, #define STBI_JPEG_OLD and you will get the same results + you used to; however, you will not get the SIMD speedups for + the YCbCr-to-RGB conversion step (although you should still see + significant JPEG speedup from the other changes). + + Please note that STBI_JPEG_OLD is a temporary feature; it will be + removed in future versions of the library. It is only intended for + near-term back-compatibility use. + + + Latest revision history: 2.10 (2016-01-22) avoid warning introduced in 2.09 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) partial animated GIF support + limited 16-bit PSD support + minor bugs, code cleanup, and compiler warnings + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) additional corruption checking + stbi_set_flip_vertically_on_load + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPEG, including x86 SSE2 & ARM NEON SIMD + progressive JPEG + PGM/PPM support + STBI_MALLOC,STBI_REALLOC,STBI_FREE + STBI_NO_*, STBI_ONLY_* + GIF bugfix + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support (both grayscale and paletted) + optimize PNG + fix bug in interlaced PNG with user-specified channel count See end of file for full revision history. @@ -82,33 +185,34 @@ RECENT REVISION HISTORY: Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) - github:urraka (animated gif) Junggon Kim (PNM comments) - Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) - socks-the-fox (16-bit PNG) - Jeremy Sawicki (handle all ImageNet JPGs) - Optimizations & bugfixes Mikhail Morozov (1-bit BMP) - Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) + urraka@github (animated gif) Junggon Kim (PNM comments) + Daniel Gibson (16-bit TGA) + + Optimizations & bugfixes + Fabian "ryg" Giesen Arseny Kapoulkine - John-Mark Allen - Carmelo J Fdez-Aguera Bug & warning fixes Marc LeBlanc David Woo Guillaume George Martins Mozeiko - Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan - Dave Moore Roy Eltham Hayaki Saito Nathan Reed - Won Chun Luke Graham Johan Duparc Nick Verigakis - the Horde3D community Thomas Ruf Ronny Chevalier github:rlyeh - Janez Zemva John Bartholomew Michal Cichon github:romigrou - Jonathan Blow Ken Hamada Tero Hanninen github:svdijk - Laurent Gomila Cort Stratton Sergio Gonzalez github:snagar - Aruelien Pocheville Thibault Reuille Cass Everitt github:Zelex - Ryamond Barbiero Paul Du Bois Engin Manap github:grim210 - Aldo Culquicondor Philipp Wiesemann Dale Weiler github:sammyhw - Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus - Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo - Christian Floisand Kevin Schmidt JR Smith github:darealshinji - Brad Weinberger Matvey Cherevko github:Michaelangel007 - Blazej Dariusz Roszkowski Alexander Veselov + Christpher Lloyd Martin Golini Jerry Jansson Joseph Thomson + Dave Moore Roy Eltham Hayaki Saito Phil Jordan + Won Chun Luke Graham Johan Duparc Nathan Reed + the Horde3D community Thomas Ruf Ronny Chevalier Nick Verigakis + Janez Zemva John Bartholomew Michal Cichon svdijk@github + Jonathan Blow Ken Hamada Tero Hanninen Baldur Karlsson + Laurent Gomila Cort Stratton Sergio Gonzalez romigrou@github + Aruelien Pocheville Thibault Reuille Cass Everitt + Ryamond Barbiero Paul Du Bois Engin Manap + Blazej Dariusz Roszkowski + Michaelangel007@github + + +LICENSE + +This software is in the public domain. Where that dedication is not +recognized, you are granted a perpetual, irrevocable license to copy, +distribute, and modify this file as you see fit. + */ #ifndef STBI_INCLUDE_STB_IMAGE_H @@ -117,8 +221,10 @@ RECENT REVISION HISTORY: // DOCUMENTATION // // Limitations: +// - no 16-bit-per-channel PNG // - no 12-bit-per-channel JPEG // - no JPEGs with arithmetic coding +// - no 1-bit BMP // - GIF always returns *comp=4 // // Basic usage (see HDR discussion below for HDR usage): @@ -131,10 +237,10 @@ RECENT REVISION HISTORY: // stbi_image_free(data) // // Standard parameters: -// int *x -- outputs image width in pixels -// int *y -- outputs image height in pixels -// int *channels_in_file -- outputs # of image components in image file -// int desired_channels -- if non-zero, # of image components requested in result +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *comp -- outputs # of image components in image file +// int req_comp -- if non-zero, # of image components requested in result // // The return value from an image loader is an 'unsigned char *' which points // to the pixel data, or NULL on an allocation failure or if the image is @@ -142,12 +248,11 @@ RECENT REVISION HISTORY: // with each pixel consisting of N interleaved 8-bit components; the first // pixel pointed to is top-left-most in the image. There is no padding between // image scanlines or between pixels, regardless of format. The number of -// components N is 'desired_channels' if desired_channels is non-zero, or -// *channels_in_file otherwise. If desired_channels is non-zero, -// *channels_in_file has the number of components that _would_ have been -// output otherwise. E.g. if you set desired_channels to 4, you will always -// get RGBA output, but you can check *channels_in_file to see if it's trivially -// opaque because e.g. there were only 3 channels in the source image. +// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise. +// If req_comp is non-zero, *comp has the number of components that _would_ +// have been output otherwise. E.g. if you set req_comp to 4, you will always +// get RGBA output, but you can check *comp to see if it's trivially opaque +// because e.g. there were only 3 channels in the source image. // // An output image with N components has the following components interleaved // in this order in each pixel: @@ -159,26 +264,16 @@ RECENT REVISION HISTORY: // 4 red, green, blue, alpha // // If image loading fails for any reason, the return value will be NULL, -// and *x, *y, *channels_in_file will be unchanged. The function -// stbi_failure_reason() can be queried for an extremely brief, end-user -// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS -// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// and *x, *y, *comp will be unchanged. The function stbi_failure_reason() +// can be queried for an extremely brief, end-user unfriendly explanation +// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid +// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly // more user-friendly ones. // // Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. // // =========================================================================== // -// UNICODE: -// -// If compiling for Windows and you wish to use Unicode filenames, compile -// with -// #define STBI_WINDOWS_UTF8 -// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert -// Windows wchar_t filenames to utf8. -// -// =========================================================================== -// // Philosophy // // stb libraries are designed with the following priorities: @@ -189,15 +284,15 @@ RECENT REVISION HISTORY: // // Sometimes I let "good performance" creep up in priority over "easy to maintain", // and for best performance I may provide less-easy-to-use APIs that give higher -// performance, in addition to the easy-to-use ones. Nevertheless, it's important +// performance, in addition to the easy to use ones. Nevertheless, it's important // to keep in mind that from the standpoint of you, a client of this library, -// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. +// all you care about is #1 and #3, and stb libraries do not emphasize #3 above all. // // Some secondary priorities arise directly from the first two, some of which -// provide more explicit reasons why performance can't be emphasized. +// make more explicit reasons why performance can't be emphasized. // // - Portable ("ease of use") -// - Small source code footprint ("easy to maintain") +// - Small footprint ("easy to maintain") // - No dependencies ("ease of use") // // =========================================================================== @@ -229,6 +324,13 @@ RECENT REVISION HISTORY: // (at least this is true for iOS and Android). Therefore, the NEON support is // toggled by a build flag: define STBI_NEON to get NEON loops. // +// The output of the JPEG decoder is slightly different from versions where +// SIMD support was introduced (that is, for versions before 1.49). The +// difference is only +-1 in the 8-bit RGB channels, and only on a small +// fraction of pixels. You can force the pre-1.49 behavior by defining +// STBI_JPEG_OLD, but this will disable some of the SIMD decoding path +// and hence cost some performance. +// // If for some reason you do not want to use any of SIMD code, or if // you have issues compiling it, you can disable it entirely by // defining STBI_NO_SIMD. @@ -237,10 +339,11 @@ RECENT REVISION HISTORY: // // HDR image support (disable by defining STBI_NO_HDR) // -// stb_image supports loading HDR images in general, and currently the Radiance -// .HDR file format specifically. You can still load any file through the existing -// interface; if you attempt to load an HDR file, it will be automatically remapped -// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// stb_image now supports loading HDR images in general, and currently +// the Radiance .HDR file format, although the support is provided +// generically. You can still load any file through the existing interface; +// if you attempt to load an HDR file, it will be automatically remapped to +// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; // both of these constants can be reconfigured through this interface: // // stbi_hdr_to_ldr_gamma(2.2f); @@ -274,7 +377,7 @@ RECENT REVISION HISTORY: // // By default we convert iphone-formatted PNGs back to RGB, even though // they are internally encoded differently. You can disable this conversion -// by calling stbi_convert_iphone_png_to_rgb(0), in which case +// by by calling stbi_convert_iphone_png_to_rgb(0), in which case // you will always just get the native iphone "format" through (which // is BGR stored in RGB). // @@ -283,41 +386,6 @@ RECENT REVISION HISTORY: // says there's premultiplied data (currently only happens in iPhone images, // and only if iPhone convert-to-rgb processing is on). // -// =========================================================================== -// -// ADDITIONAL CONFIGURATION -// -// - You can suppress implementation of any of the decoders to reduce -// your code footprint by #defining one or more of the following -// symbols before creating the implementation. -// -// STBI_NO_JPEG -// STBI_NO_PNG -// STBI_NO_BMP -// STBI_NO_PSD -// STBI_NO_TGA -// STBI_NO_GIF -// STBI_NO_HDR -// STBI_NO_PIC -// STBI_NO_PNM (.ppm and .pgm) -// -// - You can request *only* certain decoders and suppress all other ones -// (this will be more forward-compatible, as addition of new decoders -// doesn't require you to disable them explicitly): -// -// STBI_ONLY_JPEG -// STBI_ONLY_PNG -// STBI_ONLY_BMP -// STBI_ONLY_PSD -// STBI_ONLY_TGA -// STBI_ONLY_GIF -// STBI_ONLY_HDR -// STBI_ONLY_PIC -// STBI_ONLY_PNM (.ppm and .pgm) -// -// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still -// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB -// #ifndef STBI_NO_STDIO @@ -328,7 +396,7 @@ RECENT REVISION HISTORY: enum { - STBI_default = 0, // only used for desired_channels + STBI_default = 0, // only used for req_comp STBI_grey = 1, STBI_grey_alpha = 2, @@ -336,21 +404,17 @@ enum STBI_rgb_alpha = 4 }; -#include typedef unsigned char stbi_uc; -typedef unsigned short stbi_us; #ifdef __cplusplus extern "C" { #endif -#ifndef STBIDEF #ifdef STB_IMAGE_STATIC #define STBIDEF static #else #define STBIDEF extern #endif -#endif ////////////////////////////////////////////////////////////////////////////// // @@ -368,52 +432,22 @@ typedef struct int (*eof) (void *user); // returns nonzero if we are at end of file/data } stbi_io_callbacks; -//////////////////////////////////// -// -// 8-bits-per-channel interface -// - -STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp); +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *comp, int req_comp); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *comp, int req_comp); #ifndef STBI_NO_STDIO -STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); // for stbi_load_from_file, file pointer is left pointing immediately after image #endif -#ifndef STBI_NO_GIF -STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); -#endif - -#ifdef STBI_WINDOWS_UTF8 -STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); -#endif - -//////////////////////////////////// -// -// 16-bits-per-channel interface -// - -STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); - -#ifndef STBI_NO_STDIO -STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); -#endif - -//////////////////////////////////// -// -// float-per-channel interface -// #ifndef STBI_NO_LINEAR - STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); - STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp); + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); #ifndef STBI_NO_STDIO - STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); - STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); #endif #endif @@ -437,7 +471,7 @@ STBIDEF int stbi_is_hdr_from_file(FILE *f); // get a VERY brief reason for failure -// on most compilers (and ALL modern mainstream compilers) this is threadsafe +// NOT THREADSAFE STBIDEF const char *stbi_failure_reason (void); // free the loaded image -- this is just free() @@ -446,14 +480,11 @@ STBIDEF void stbi_image_free (void *retval_from_stbi_load); // get image dimensions & components without fully decoding STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); -STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); -STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); #ifndef STBI_NO_STDIO -STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); -STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); -STBIDEF int stbi_is_16_bit (char const *filename); -STBIDEF int stbi_is_16_bit_from_file(FILE *f); +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); + #endif @@ -470,11 +501,6 @@ STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); // flip the image vertically, so the first pixel in the output array is the bottom left STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); -// as above, but only applies to images loaded on the thread that calls the function -// this function is only available if your compiler supports thread-local variables; -// calling it will fail to link if your compiler doesn't -STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); - // ZLIB client - used by PNG, available for other purposes STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); @@ -539,10 +565,9 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #include // ptrdiff_t on osx #include #include -#include #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) -#include // ldexp, pow +#include // ldexp #endif #ifndef STBI_NO_STDIO @@ -554,12 +579,6 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #define STBI_ASSERT(x) assert(x) #endif -#ifdef __cplusplus -#define STBI_EXTERN extern "C" -#else -#define STBI_EXTERN extern -#endif - #ifndef _MSC_VER #ifdef __cplusplus @@ -571,17 +590,6 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #define stbi_inline __forceinline #endif -#ifndef STBI_NO_THREAD_LOCALS - #if defined(__cplusplus) && __cplusplus >= 201103L - #define STBI_THREAD_LOCAL thread_local - #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L - #define STBI_THREAD_LOCAL _Thread_local - #elif defined(__GNUC__) - #define STBI_THREAD_LOCAL __thread - #elif defined(_MSC_VER) - #define STBI_THREAD_LOCAL __declspec(thread) -#endif -#endif #ifdef _MSC_VER typedef unsigned short stbi__uint16; @@ -640,14 +648,12 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #define STBI__X86_TARGET #endif -#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +#if defined(__GNUC__) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +// NOTE: not clear do we actually need this for the 64-bit path? // gcc doesn't support sse2 intrinsics unless you compile with -msse2, -// which in turn means it gets to use SSE2 everywhere. This is unfortunate, -// but previous attempts to provide the SSE2 functions with runtime -// detection caused numerous issues. The way architecture extensions are -// exposed in GCC/Clang is, sadly, not really suited for one-file libs. -// New behavior: if compiled with -msse2, we use SSE2 without any -// detection; if not, we don't use it at all. +// (but compiling with -msse2 allows the compiler to use SSE2 everywhere; +// this is just broken and gcc are jerks for not fixing it properly +// http://www.virtualdub.org/blog/pivot/entry.php?id=363 ) #define STBI_NO_SIMD #endif @@ -666,7 +672,7 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #define STBI_NO_SIMD #endif -#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) +#if !defined(STBI_NO_SIMD) && defined(STBI__X86_TARGET) #define STBI_SSE2 #include @@ -695,27 +701,25 @@ static int stbi__cpuid3(void) #define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name -#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) -static int stbi__sse2_available(void) +static int stbi__sse2_available() { int info3 = stbi__cpuid3(); return ((info3 >> 26) & 1) != 0; } -#endif - #else // assume GCC-style if not VC++ #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) -#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) -static int stbi__sse2_available(void) +static int stbi__sse2_available() { - // If we're even attempting to compile this on GCC/Clang, that means - // -msse2 is on, which means the compiler is allowed to use SSE2 - // instructions at will, and so are we. - return 1; -} +#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 // GCC 4.8 or later + // GCC 4.8+ has a nice way to do this + return __builtin_cpu_supports("sse2"); +#else + // portable way to do this, preferably without using GCC inline ASM? + // just bail for now. + return 0; #endif - +} #endif #endif @@ -822,179 +826,79 @@ static void stbi__rewind(stbi__context *s) s->img_buffer_end = s->img_buffer_original_end; } -enum -{ - STBI_ORDER_RGB, - STBI_ORDER_BGR -}; - -typedef struct -{ - int bits_per_channel; - int num_channels; - int channel_order; -} stbi__result_info; - #ifndef STBI_NO_JPEG static int stbi__jpeg_test(stbi__context *s); -static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static stbi_uc *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PNG static int stbi__png_test(stbi__context *s); -static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static stbi_uc *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); -static int stbi__png_is16(stbi__context *s); #endif #ifndef STBI_NO_BMP static int stbi__bmp_test(stbi__context *s); -static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_TGA static int stbi__tga_test(stbi__context *s); -static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PSD static int stbi__psd_test(stbi__context *s); -static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); +static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); -static int stbi__psd_is16(stbi__context *s); #endif #ifndef STBI_NO_HDR static int stbi__hdr_test(stbi__context *s); -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PIC static int stbi__pic_test(stbi__context *s); -static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static stbi_uc *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_GIF static int stbi__gif_test(stbi__context *s); -static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PNM static int stbi__pnm_test(stbi__context *s); -static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); #endif -static -#ifdef STBI_THREAD_LOCAL -STBI_THREAD_LOCAL -#endif -const char *stbi__g_failure_reason; +// this is not threadsafe +static const char *stbi__g_failure_reason; STBIDEF const char *stbi_failure_reason(void) { return stbi__g_failure_reason; } -#ifndef STBI_NO_FAILURE_STRINGS static int stbi__err(const char *str) { stbi__g_failure_reason = str; return 0; } -#endif static void *stbi__malloc(size_t size) { return STBI_MALLOC(size); } -// stb_image uses ints pervasively, including for offset calculations. -// therefore the largest decoded image size we can support with the -// current code, even on 64-bit targets, is INT_MAX. this is not a -// significant limitation for the intended use case. -// -// we do, however, need to make sure our size calculations don't -// overflow. hence a few helper functions for size calculations that -// multiply integers together, making sure that they're non-negative -// and no overflow occurs. - -// return 1 if the sum is valid, 0 on overflow. -// negative terms are considered invalid. -static int stbi__addsizes_valid(int a, int b) -{ - if (b < 0) return 0; - // now 0 <= b <= INT_MAX, hence also - // 0 <= INT_MAX - b <= INTMAX. - // And "a + b <= INT_MAX" (which might overflow) is the - // same as a <= INT_MAX - b (no overflow) - return a <= INT_MAX - b; -} - -// returns 1 if the product is valid, 0 on overflow. -// negative factors are considered invalid. -static int stbi__mul2sizes_valid(int a, int b) -{ - if (a < 0 || b < 0) return 0; - if (b == 0) return 1; // mul-by-0 is always safe - // portable way to check for no overflows in a*b - return a <= INT_MAX/b; -} - -#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) -// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow -static int stbi__mad2sizes_valid(int a, int b, int add) -{ - return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); -} -#endif - -// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow -static int stbi__mad3sizes_valid(int a, int b, int c, int add) -{ - return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && - stbi__addsizes_valid(a*b*c, add); -} - -// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow -#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) -static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) -{ - return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && - stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); -} -#endif - -#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) -// mallocs with size overflow checking -static void *stbi__malloc_mad2(int a, int b, int add) -{ - if (!stbi__mad2sizes_valid(a, b, add)) return NULL; - return stbi__malloc(a*b + add); -} -#endif - -static void *stbi__malloc_mad3(int a, int b, int c, int add) -{ - if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; - return stbi__malloc(a*b*c + add); -} - -#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) -static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) -{ - if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; - return stbi__malloc(a*b*c*d + add); -} -#endif - // stbi__err - error // stbi__errpf - error returning pointer to float // stbi__errpuc - error returning pointer to unsigned char @@ -1023,63 +927,40 @@ static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); #endif -static int stbi__vertically_flip_on_load_global = 0; +static int stbi__vertically_flip_on_load = 0; STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) { - stbi__vertically_flip_on_load_global = flag_true_if_should_flip; + stbi__vertically_flip_on_load = flag_true_if_should_flip; } -#ifndef STBI_THREAD_LOCAL -#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global -#else -static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set; - -STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) +static unsigned char *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) { - stbi__vertically_flip_on_load_local = flag_true_if_should_flip; - stbi__vertically_flip_on_load_set = 1; -} - -#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ - ? stbi__vertically_flip_on_load_local \ - : stbi__vertically_flip_on_load_global) -#endif // STBI_THREAD_LOCAL - -static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) -{ - memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields - ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed - ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order - ri->num_channels = 0; - #ifndef STBI_NO_JPEG - if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp); #endif #ifndef STBI_NO_PNG - if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp); #endif #ifndef STBI_NO_BMP - if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp); #endif #ifndef STBI_NO_GIF - if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp); #endif #ifndef STBI_NO_PSD - if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); - #else - STBI_NOTUSED(bpc); + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp); #endif #ifndef STBI_NO_PIC - if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp); #endif #ifndef STBI_NO_PNM - if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp); #endif #ifndef STBI_NO_HDR if (stbi__hdr_test(s)) { - float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp); return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); } #endif @@ -1087,175 +968,66 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re #ifndef STBI_NO_TGA // test tga last because it's a crappy test! if (stbi__tga_test(s)) - return stbi__tga_load(s,x,y,comp,req_comp, ri); + return stbi__tga_load(s,x,y,comp,req_comp); #endif return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); } -static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) +static unsigned char *stbi__load_flip(stbi__context *s, int *x, int *y, int *comp, int req_comp) { - int i; - int img_len = w * h * channels; - stbi_uc *reduced; - - reduced = (stbi_uc *) stbi__malloc(img_len); - if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); - - for (i = 0; i < img_len; ++i) - reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling - - STBI_FREE(orig); - return reduced; -} + unsigned char *result = stbi__load_main(s, x, y, comp, req_comp); -static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) -{ - int i; - int img_len = w * h * channels; - stbi__uint16 *enlarged; - - enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); - if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); - - for (i = 0; i < img_len; ++i) - enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff - - STBI_FREE(orig); - return enlarged; -} - -static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) -{ - int row; - size_t bytes_per_row = (size_t)w * bytes_per_pixel; - stbi_uc temp[2048]; - stbi_uc *bytes = (stbi_uc *)image; - - for (row = 0; row < (h>>1); row++) { - stbi_uc *row0 = bytes + row*bytes_per_row; - stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; - // swap row0 with row1 - size_t bytes_left = bytes_per_row; - while (bytes_left) { - size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); - memcpy(temp, row0, bytes_copy); - memcpy(row0, row1, bytes_copy); - memcpy(row1, temp, bytes_copy); - row0 += bytes_copy; - row1 += bytes_copy; - bytes_left -= bytes_copy; + if (stbi__vertically_flip_on_load && result != NULL) { + int w = *x, h = *y; + int depth = req_comp ? req_comp : *comp; + int row,col,z; + stbi_uc temp; + + // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once + for (row = 0; row < (h>>1); row++) { + for (col = 0; col < w; col++) { + for (z = 0; z < depth; z++) { + temp = result[(row * w + col) * depth + z]; + result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z]; + result[((h - row - 1) * w + col) * depth + z] = temp; + } + } } } -} - -#ifndef STBI_NO_GIF -static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) -{ - int slice; - int slice_size = w * h * bytes_per_pixel; - - stbi_uc *bytes = (stbi_uc *)image; - for (slice = 0; slice < z; ++slice) { - stbi__vertical_flip(bytes, w, h, bytes_per_pixel); - bytes += slice_size; - } -} -#endif - -static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi__result_info ri; - void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); - - if (result == NULL) - return NULL; - if (ri.bits_per_channel != 8) { - STBI_ASSERT(ri.bits_per_channel == 16); - result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); - ri.bits_per_channel = 8; - } - - // @TODO: move stbi__convert_format to here - - if (stbi__vertically_flip_on_load) { - int channels = req_comp ? req_comp : *comp; - stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); - } - - return (unsigned char *) result; -} - -static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi__result_info ri; - void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); - - if (result == NULL) - return NULL; - - if (ri.bits_per_channel != 16) { - STBI_ASSERT(ri.bits_per_channel == 8); - result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); - ri.bits_per_channel = 16; - } - - // @TODO: move stbi__convert_format16 to here - // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision - - if (stbi__vertically_flip_on_load) { - int channels = req_comp ? req_comp : *comp; - stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); - } - - return (stbi__uint16 *) result; + return result; } -#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR) +#ifndef STBI_NO_HDR static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) { if (stbi__vertically_flip_on_load && result != NULL) { - int channels = req_comp ? req_comp : *comp; - stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); + int w = *x, h = *y; + int depth = req_comp ? req_comp : *comp; + int row,col,z; + float temp; + + // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once + for (row = 0; row < (h>>1); row++) { + for (col = 0; col < w; col++) { + for (z = 0; z < depth; z++) { + temp = result[(row * w + col) * depth + z]; + result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z]; + result[((h - row - 1) * w + col) * depth + z] = temp; + } + } + } } } #endif #ifndef STBI_NO_STDIO -#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) -STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); -STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); -#endif - -#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) -STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) -{ - return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); -} -#endif - static FILE *stbi__fopen(char const *filename, char const *mode) { FILE *f; -#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) - wchar_t wMode[64]; - wchar_t wFilename[1024]; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) - return 0; - - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) - return 0; - -#if _MSC_VER >= 1400 - if (0 != _wfopen_s(&f, wFilename, wMode)) - f = 0; -#else - f = _wfopen(wFilename, wMode); -#endif - -#elif defined(_MSC_VER) && _MSC_VER >= 1400 +#if defined(_MSC_VER) && _MSC_VER >= 1400 if (0 != fopen_s(&f, filename, mode)) f=0; #else @@ -1280,83 +1052,28 @@ STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req unsigned char *result; stbi__context s; stbi__start_file(&s,f); - result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); + result = stbi__load_flip(&s,x,y,comp,req_comp); if (result) { // need to 'unget' all the characters in the IO buffer fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); } return result; } - -STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - stbi__uint16 *result; - stbi__context s; - stbi__start_file(&s,f); - result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); - if (result) { - // need to 'unget' all the characters in the IO buffer - fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); - } - return result; -} - -STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - stbi__uint16 *result; - if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); - result = stbi_load_from_file_16(f,x,y,comp,req_comp); - fclose(f); - return result; -} - - #endif //!STBI_NO_STDIO -STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); -} - -STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); - return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); -} - STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_mem(&s,buffer,len); - return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); + return stbi__load_flip(&s,x,y,comp,req_comp); } STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); -} - -#ifndef STBI_NO_GIF -STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) -{ - unsigned char *result; - stbi__context s; - stbi__start_mem(&s,buffer,len); - - result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); - if (stbi__vertically_flip_on_load) { - stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); - } - - return result; + return stbi__load_flip(&s,x,y,comp,req_comp); } -#endif #ifndef STBI_NO_LINEAR static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) @@ -1364,14 +1081,13 @@ static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int unsigned char *data; #ifndef STBI_NO_HDR if (stbi__hdr_test(s)) { - stbi__result_info ri; - float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp); if (hdr_data) stbi__float_postprocess(hdr_data,x,y,comp,req_comp); return hdr_data; } #endif - data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); + data = stbi__load_flip(s, x, y, comp, req_comp); if (data) return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); @@ -1441,16 +1157,12 @@ STBIDEF int stbi_is_hdr (char const *filename) return result; } -STBIDEF int stbi_is_hdr_from_file(FILE *f) +STBIDEF int stbi_is_hdr_from_file(FILE *f) { #ifndef STBI_NO_HDR - long pos = ftell(f); - int res; stbi__context s; stbi__start_file(&s,f); - res = stbi__hdr_test(&s); - fseek(f, pos, SEEK_SET); - return res; + return stbi__hdr_test(&s); #else STBI_NOTUSED(f); return 0; @@ -1523,9 +1235,6 @@ stbi_inline static stbi_uc stbi__get8(stbi__context *s) return 0; } -#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) -// nothing -#else stbi_inline static int stbi__at_eof(stbi__context *s) { if (s->io.read) { @@ -1537,11 +1246,7 @@ stbi_inline static int stbi__at_eof(stbi__context *s) return s->img_buffer >= s->img_buffer_end; } -#endif -#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) -// nothing -#else static void stbi__skip(stbi__context *s, int n) { if (n < 0) { @@ -1558,11 +1263,7 @@ static void stbi__skip(stbi__context *s, int n) } s->img_buffer += n; } -#endif -#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM) -// nothing -#else static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) { if (s->io.read) { @@ -1586,27 +1287,18 @@ static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) } else return 0; } -#endif -#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) -// nothing -#else static int stbi__get16be(stbi__context *s) { int z = stbi__get8(s); return (z << 8) + stbi__get8(s); } -#endif -#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) -// nothing -#else static stbi__uint32 stbi__get32be(stbi__context *s) { stbi__uint32 z = stbi__get16be(s); return (z << 16) + stbi__get16be(s); } -#endif #if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) // nothing @@ -1628,9 +1320,7 @@ static stbi__uint32 stbi__get32le(stbi__context *s) #define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings -#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) -// nothing -#else + ////////////////////////////////////////////////////////////////////////////// // // generic converter from built-in img_n to req_comp @@ -1646,11 +1336,7 @@ static stbi_uc stbi__compute_y(int r, int g, int b) { return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); } -#endif -#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) -// nothing -#else static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) { int i,j; @@ -1659,7 +1345,7 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r if (req_comp == img_n) return data; STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); + good = (unsigned char *) stbi__malloc(req_comp * x * y); if (good == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); @@ -1669,97 +1355,37 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r unsigned char *src = data + j * x * img_n ; unsigned char *dest = good + j * x * req_comp; - #define STBI__COMBO(a,b) ((a)*8+(b)) - #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + #define COMBO(a,b) ((a)*8+(b)) + #define CASE(a,b) case COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) // convert source image with img_n components to one with req_comp components; // avoid switch per pixel, so use switch per scanline and massive macros - switch (STBI__COMBO(img_n, req_comp)) { - STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break; - STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break; - STBI__CASE(2,1) { dest[0]=src[0]; } break; - STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; - STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break; - STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break; - STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; - STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + switch (COMBO(img_n, req_comp)) { + CASE(1,2) dest[0]=src[0], dest[1]=255; break; + CASE(1,3) dest[0]=dest[1]=dest[2]=src[0]; break; + CASE(1,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; break; + CASE(2,1) dest[0]=src[0]; break; + CASE(2,3) dest[0]=dest[1]=dest[2]=src[0]; break; + CASE(2,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; break; + CASE(3,4) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; break; + CASE(3,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break; + CASE(3,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; break; + CASE(4,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break; + CASE(4,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; break; + CASE(4,3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break; default: STBI_ASSERT(0); } - #undef STBI__CASE + #undef CASE } STBI_FREE(data); return good; } -#endif - -#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) -// nothing -#else -static stbi__uint16 stbi__compute_y_16(int r, int g, int b) -{ - return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); -} -#endif - -#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) -// nothing -#else -static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) -{ - int i,j; - stbi__uint16 *good; - - if (req_comp == img_n) return data; - STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - - good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); - if (good == NULL) { - STBI_FREE(data); - return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); - } - - for (j=0; j < (int) y; ++j) { - stbi__uint16 *src = data + j * x * img_n ; - stbi__uint16 *dest = good + j * x * req_comp; - - #define STBI__COMBO(a,b) ((a)*8+(b)) - #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) - // convert source image with img_n components to one with req_comp components; - // avoid switch per pixel, so use switch per scanline and massive macros - switch (STBI__COMBO(img_n, req_comp)) { - STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break; - STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break; - STBI__CASE(2,1) { dest[0]=src[0]; } break; - STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; - STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break; - STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break; - STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; - STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; - default: STBI_ASSERT(0); - } - #undef STBI__CASE - } - - STBI_FREE(data); - return good; -} -#endif #ifndef STBI_NO_LINEAR static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) { int i,k,n; - float *output; - if (!data) return NULL; - output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); + float *output = (float *) stbi__malloc(x * y * comp * sizeof(float)); if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } // compute number of non-alpha components if (comp & 1) n = comp; else n = comp-1; @@ -1767,11 +1393,7 @@ static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) for (k=0; k < n; ++k) { output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); } - } - if (n < comp) { - for (i=0; i < x*y; ++i) { - output[i*comp + n] = data[i*comp + n]/255.0f; - } + if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; } STBI_FREE(data); return output; @@ -1783,9 +1405,7 @@ static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) { int i,k,n; - stbi_uc *output; - if (!data) return NULL; - output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); + stbi_uc *output = (stbi_uc *) stbi__malloc(x * y * comp); if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } // compute number of non-alpha components if (comp & 1) n = comp; else n = comp-1; @@ -1850,7 +1470,7 @@ typedef struct stbi__context *s; stbi__huffman huff_dc[4]; stbi__huffman huff_ac[4]; - stbi__uint16 dequant[4][64]; + stbi_uc dequant[4][64]; stbi__int16 fast_ac[4][1 << FAST_BITS]; // sizes for components, interleaved MCUs @@ -1886,9 +1506,6 @@ typedef struct int succ_high; int succ_low; int eob_run; - int jfif; - int app14_color_transform; // Adobe APP14 tag - int rgb; int scan_n, order[4]; int restart_interval, todo; @@ -1901,8 +1518,7 @@ typedef struct static int stbi__build_huffman(stbi__huffman *h, int *count) { - int i,j,k=0; - unsigned int code; + int i,j,k=0,code; // build size list for each symbol (from JPEG spec) for (i=0; i < 16; ++i) for (j=0; j < count[i]; ++j) @@ -1918,7 +1534,7 @@ static int stbi__build_huffman(stbi__huffman *h, int *count) if (h->size[k] == j) { while (h->size[k] == j) h->code[k++] = (stbi__uint16) (code++); - if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG"); + if (code-1 >= (1 << j)) return stbi__err("bad code lengths","Corrupt JPEG"); } // compute largest code + 1 for this size, preshifted as needed later h->maxcode[j] = code << (16-j); @@ -1959,10 +1575,10 @@ static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) // magnitude code followed by receive_extend code int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); int m = 1 << (magbits - 1); - if (k < m) k += (~0U << magbits) + 1; + if (k < m) k += (-1 << magbits) + 1; // if the result is small enough, we can fit it in fast_ac table if (k >= -128 && k <= 127) - fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); + fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits)); } } } @@ -1971,10 +1587,9 @@ static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) static void stbi__grow_buffer_unsafe(stbi__jpeg *j) { do { - unsigned int b = j->nomore ? 0 : stbi__get8(j->s); + int b = j->nomore ? 0 : stbi__get8(j->s); if (b == 0xff) { int c = stbi__get8(j->s); - while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes if (c != 0) { j->marker = (unsigned char) c; j->nomore = 1; @@ -1987,7 +1602,7 @@ static void stbi__grow_buffer_unsafe(stbi__jpeg *j) } // (1 << n) - 1 -static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; +static stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; // decode a jpeg huffman value from the bitstream stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) @@ -2040,7 +1655,7 @@ stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) } // bias[n] = (-1<s); if (x != 0xff) return STBI__MARKER_none; while (x == 0xff) - x = stbi__get8(j->s); // consume repeated 0xff fill bytes + x = stbi__get8(j->s); return x; } @@ -2823,7 +2438,7 @@ static void stbi__jpeg_reset(stbi__jpeg *j) j->code_bits = 0; j->code_buffer = 0; j->nomore = 0; - j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0; j->marker = STBI__MARKER_none; j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; j->eob_run = 0; @@ -2955,7 +2570,7 @@ static int stbi__parse_entropy_coded_data(stbi__jpeg *z) } } -static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) +static void stbi__jpeg_dequantize(short *data, stbi_uc *dequant) { int i; for (i=0; i < 64; ++i) @@ -2997,14 +2612,13 @@ static int stbi__process_marker(stbi__jpeg *z, int m) L = stbi__get16be(z->s)-2; while (L > 0) { int q = stbi__get8(z->s); - int p = q >> 4, sixteen = (p != 0); + int p = q >> 4; int t = q & 15,i; - if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); + if (p != 0) return stbi__err("bad DQT type","Corrupt JPEG"); if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); - for (i=0; i < 64; ++i) - z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); - L -= (sixteen ? 129 : 65); + z->dequant[t][stbi__jpeg_dezigzag[i]] = stbi__get8(z->s); + L -= 65; } return L==0; @@ -3037,50 +2651,12 @@ static int stbi__process_marker(stbi__jpeg *z, int m) } return L==0; } - // check for comment block or APP blocks if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { - L = stbi__get16be(z->s); - if (L < 2) { - if (m == 0xFE) - return stbi__err("bad COM len","Corrupt JPEG"); - else - return stbi__err("bad APP len","Corrupt JPEG"); - } - L -= 2; - - if (m == 0xE0 && L >= 5) { // JFIF APP0 segment - static const unsigned char tag[5] = {'J','F','I','F','\0'}; - int ok = 1; - int i; - for (i=0; i < 5; ++i) - if (stbi__get8(z->s) != tag[i]) - ok = 0; - L -= 5; - if (ok) - z->jfif = 1; - } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment - static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; - int ok = 1; - int i; - for (i=0; i < 6; ++i) - if (stbi__get8(z->s) != tag[i]) - ok = 0; - L -= 6; - if (ok) { - stbi__get8(z->s); // version - stbi__get16be(z->s); // flags0 - stbi__get16be(z->s); // flags1 - z->app14_color_transform = stbi__get8(z->s); // color transform - L -= 6; - } - } - - stbi__skip(z->s, L); + stbi__skip(z->s, stbi__get16be(z->s)-2); return 1; } - - return stbi__err("unknown marker","Corrupt JPEG"); + return 0; } // after we see SOS @@ -3123,28 +2699,6 @@ static int stbi__process_scan_header(stbi__jpeg *z) return 1; } -static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) -{ - int i; - for (i=0; i < ncomp; ++i) { - if (z->img_comp[i].raw_data) { - STBI_FREE(z->img_comp[i].raw_data); - z->img_comp[i].raw_data = NULL; - z->img_comp[i].data = NULL; - } - if (z->img_comp[i].raw_coeff) { - STBI_FREE(z->img_comp[i].raw_coeff); - z->img_comp[i].raw_coeff = 0; - z->img_comp[i].coeff = 0; - } - if (z->img_comp[i].linebuf) { - STBI_FREE(z->img_comp[i].linebuf); - z->img_comp[i].linebuf = NULL; - } - } - return why; -} - static int stbi__process_frame_header(stbi__jpeg *z, int scan) { stbi__context *s = z->s; @@ -3154,7 +2708,7 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires c = stbi__get8(s); - if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); + if (c != 3 && c != 1) return stbi__err("bad component count","Corrupt JPEG"); // JFIF requires s->img_n = c; for (i=0; i < c; ++i) { z->img_comp[i].data = NULL; @@ -3163,12 +2717,11 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); - z->rgb = 0; for (i=0; i < s->img_n; ++i) { - static const unsigned char rgb[3] = { 'R', 'G', 'B' }; z->img_comp[i].id = stbi__get8(s); - if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) - ++z->rgb; + if (z->img_comp[i].id != i+1) // JFIF requires + if (z->img_comp[i].id != i) // some version of jpegtran outputs non-JFIF-compliant files! + return stbi__err("bad component ID","Corrupt JPEG"); q = stbi__get8(s); z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); @@ -3177,7 +2730,7 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) if (scan != STBI__SCAN_load) return 1; - if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); for (i=0; i < s->img_n; ++i) { if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; @@ -3189,7 +2742,6 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) z->img_v_max = v_max; z->img_mcu_w = h_max * 8; z->img_mcu_h = v_max * 8; - // these sizes can't be more than 17 bits z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; @@ -3201,27 +2753,28 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) // the bogus oversized data from using interleaved MCUs and their // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't // discard the extra data until colorspace conversion - // - // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) - // so these muls can't overflow with 32-bit ints (which we require) z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; - z->img_comp[i].coeff = 0; - z->img_comp[i].raw_coeff = 0; - z->img_comp[i].linebuf = NULL; - z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); - if (z->img_comp[i].raw_data == NULL) - return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].raw_data = stbi__malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15); + + if (z->img_comp[i].raw_data == NULL) { + for(--i; i >= 0; --i) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + } + return stbi__err("outofmem", "Out of memory"); + } // align blocks for idct using mmx/sse z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + z->img_comp[i].linebuf = NULL; if (z->progressive) { - // w2, h2 are multiples of 8 (see above) - z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; - z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; - z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); - if (z->img_comp[i].raw_coeff == NULL) - return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].coeff_w = (z->img_comp[i].w2 + 7) >> 3; + z->img_comp[i].coeff_h = (z->img_comp[i].h2 + 7) >> 3; + z->img_comp[i].raw_coeff = STBI_MALLOC(z->img_comp[i].coeff_w * z->img_comp[i].coeff_h * 64 * sizeof(short) + 15); z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } else { + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; } } @@ -3240,8 +2793,6 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) { int m; - z->jfif = 0; - z->app14_color_transform = -1; // valid values are 0,1,2 z->marker = STBI__MARKER_none; // initialize cached marker to empty m = stbi__get_marker(z); if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); @@ -3283,15 +2834,12 @@ static int stbi__decode_jpeg_image(stbi__jpeg *j) if (x == 255) { j->marker = stbi__get8(j->s); break; + } else if (x != 0) { + return stbi__err("junk before marker", "Corrupt JPEG"); } } // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 } - } else if (stbi__DNL(m)) { - int Ld = stbi__get16be(j->s); - stbi__uint32 NL = stbi__get16be(j->s); - if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); - if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); } else { if (!stbi__process_marker(j, m)) return 0; } @@ -3510,9 +3058,38 @@ static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_ return out; } +#ifdef STBI_JPEG_OLD +// this is the same YCbCr-to-RGB calculation that stb_image has used +// historically before the algorithm changes in 1.49 +#define float2fixed(x) ((int) ((x) * 65536 + 0.5)) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 16) + 32768; // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr*float2fixed(1.40200f); + g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f); + b = y_fixed + cb*float2fixed(1.77200f); + r >>= 16; + g >>= 16; + b >>= 16; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#else // this is a reduced-precision calculation of YCbCr-to-RGB introduced // to make sure the code produces the same results in both SIMD and scalar -#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +#define float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) { int i; @@ -3521,9 +3098,9 @@ static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc int r,g,b; int cr = pcr[i] - 128; int cb = pcb[i] - 128; - r = y_fixed + cr* stbi__float2fixed(1.40200f); - g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); - b = y_fixed + cb* stbi__float2fixed(1.77200f); + r = y_fixed + cr* float2fixed(1.40200f); + g = y_fixed + (cr*-float2fixed(0.71414f)) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* float2fixed(1.77200f); r >>= 20; g >>= 20; b >>= 20; @@ -3537,6 +3114,7 @@ static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc out += step; } } +#endif #if defined(STBI_SSE2) || defined(STBI_NEON) static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) @@ -3655,9 +3233,9 @@ static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc cons int r,g,b; int cr = pcr[i] - 128; int cb = pcb[i] - 128; - r = y_fixed + cr* stbi__float2fixed(1.40200f); - g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); - b = y_fixed + cb* stbi__float2fixed(1.77200f); + r = y_fixed + cr* float2fixed(1.40200f); + g = y_fixed + cr*-float2fixed(0.71414f) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* float2fixed(1.77200f); r >>= 20; g >>= 20; b >>= 20; @@ -3683,14 +3261,18 @@ static void stbi__setup_jpeg(stbi__jpeg *j) #ifdef STBI_SSE2 if (stbi__sse2_available()) { j->idct_block_kernel = stbi__idct_simd; + #ifndef STBI_JPEG_OLD j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + #endif j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; } #endif #ifdef STBI_NEON j->idct_block_kernel = stbi__idct_simd; + #ifndef STBI_JPEG_OLD j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + #endif j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; #endif } @@ -3698,7 +3280,23 @@ static void stbi__setup_jpeg(stbi__jpeg *j) // clean up the temporary component buffers static void stbi__cleanup_jpeg(stbi__jpeg *j) { - stbi__free_jpeg_components(j, j->s->img_n, 0); + int i; + for (i=0; i < j->s->img_n; ++i) { + if (j->img_comp[i].raw_data) { + STBI_FREE(j->img_comp[i].raw_data); + j->img_comp[i].raw_data = NULL; + j->img_comp[i].data = NULL; + } + if (j->img_comp[i].raw_coeff) { + STBI_FREE(j->img_comp[i].raw_coeff); + j->img_comp[i].raw_coeff = 0; + j->img_comp[i].coeff = 0; + } + if (j->img_comp[i].linebuf) { + STBI_FREE(j->img_comp[i].linebuf); + j->img_comp[i].linebuf = NULL; + } + } } typedef struct @@ -3711,16 +3309,9 @@ typedef struct int ypos; // which pre-expansion row we're on } stbi__resample; -// fast 0..255 * 0..255 => 0..255 rounded multiplication -static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) -{ - unsigned int t = x*y + 128; - return (stbi_uc) ((t + (t >>8)) >> 8); -} - static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) { - int n, decode_n, is_rgb; + int n, decode_n; z->s->img_n = 0; // make stbi__cleanup_jpeg safe // validate req_comp @@ -3730,11 +3321,9 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } // determine actual number of components to generate - n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; - - is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + n = req_comp ? req_comp : z->s->img_n; - if (z->s->img_n == 3 && n < 3 && !is_rgb) + if (z->s->img_n == 3 && n < 3) decode_n = 1; else decode_n = z->s->img_n; @@ -3744,7 +3333,7 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp int k; unsigned int i,j; stbi_uc *output; - stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL }; + stbi_uc *coutput[4]; stbi__resample res_comp[4]; @@ -3771,7 +3360,7 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp } // can't error after this so, this is safe - output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); + output = (stbi_uc *) stbi__malloc(n * z->s->img_x * z->s->img_y + 1); if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } // now go ahead and resample @@ -3794,39 +3383,7 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp if (n >= 3) { stbi_uc *y = coutput[0]; if (z->s->img_n == 3) { - if (is_rgb) { - for (i=0; i < z->s->img_x; ++i) { - out[0] = y[i]; - out[1] = coutput[1][i]; - out[2] = coutput[2][i]; - out[3] = 255; - out += n; - } - } else { - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - } - } else if (z->s->img_n == 4) { - if (z->app14_color_transform == 0) { // CMYK - for (i=0; i < z->s->img_x; ++i) { - stbi_uc m = coutput[3][i]; - out[0] = stbi__blinn_8x8(coutput[0][i], m); - out[1] = stbi__blinn_8x8(coutput[1][i], m); - out[2] = stbi__blinn_8x8(coutput[2][i], m); - out[3] = 255; - out += n; - } - } else if (z->app14_color_transform == 2) { // YCCK - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - for (i=0; i < z->s->img_x; ++i) { - stbi_uc m = coutput[3][i]; - out[0] = stbi__blinn_8x8(255 - out[0], m); - out[1] = stbi__blinn_8x8(255 - out[1], m); - out[2] = stbi__blinn_8x8(255 - out[2], m); - out += n; - } - } else { // YCbCr + alpha? Ignore the fourth channel for now - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - } + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); } else for (i=0; i < z->s->img_x; ++i) { out[0] = out[1] = out[2] = y[i]; @@ -3834,70 +3391,37 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp out += n; } } else { - if (is_rgb) { - if (n == 1) - for (i=0; i < z->s->img_x; ++i) - *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); - else { - for (i=0; i < z->s->img_x; ++i, out += 2) { - out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); - out[1] = 255; - } - } - } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { - for (i=0; i < z->s->img_x; ++i) { - stbi_uc m = coutput[3][i]; - stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); - stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); - stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); - out[0] = stbi__compute_y(r, g, b); - out[1] = 255; - out += n; - } - } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { - for (i=0; i < z->s->img_x; ++i) { - out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); - out[1] = 255; - out += n; - } - } else { - stbi_uc *y = coutput[0]; - if (n == 1) - for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; - else - for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; } - } + stbi_uc *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; } } stbi__cleanup_jpeg(z); *out_x = z->s->img_x; *out_y = z->s->img_y; - if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output + if (comp) *comp = z->s->img_n; // report original components, not output return output; } } -static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +static unsigned char *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) { - unsigned char* result; - stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); - STBI_NOTUSED(ri); - j->s = s; - stbi__setup_jpeg(j); - result = load_jpeg_image(j, x,y,comp,req_comp); - STBI_FREE(j); - return result; + stbi__jpeg j; + j.s = s; + stbi__setup_jpeg(&j); + return load_jpeg_image(&j, x,y,comp,req_comp); } static int stbi__jpeg_test(stbi__context *s) { int r; - stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); - j->s = s; - stbi__setup_jpeg(j); - r = stbi__decode_jpeg_header(j, STBI__SCAN_type); + stbi__jpeg j; + j.s = s; + stbi__setup_jpeg(&j); + r = stbi__decode_jpeg_header(&j, STBI__SCAN_type); stbi__rewind(s); - STBI_FREE(j); return r; } @@ -3909,18 +3433,15 @@ static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) } if (x) *x = j->s->img_x; if (y) *y = j->s->img_y; - if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; + if (comp) *comp = j->s->img_n; return 1; } static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) { - int result; - stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); - j->s = s; - result = stbi__jpeg_info_raw(j, x, y, comp); - STBI_FREE(j); - return result; + stbi__jpeg j; + j.s = s; + return stbi__jpeg_info_raw(&j, x, y, comp); } #endif @@ -3966,7 +3487,7 @@ stbi_inline static int stbi__bit_reverse(int v, int bits) return stbi__bitreverse16(v) >> (16-bits); } -static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) +static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) { int i,k=0; int code, next_code[16], sizes[17]; @@ -4109,18 +3630,18 @@ static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room return 1; } -static const int stbi__zlength_base[31] = { +static int stbi__zlength_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; -static const int stbi__zlength_extra[31]= +static int stbi__zlength_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; -static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; -static const int stbi__zdist_extra[32] = +static int stbi__zdist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; static int stbi__parse_huffman_block(stbi__zbuf *a) @@ -4167,7 +3688,7 @@ static int stbi__parse_huffman_block(stbi__zbuf *a) static int stbi__compute_huffman_codes(stbi__zbuf *a) { - static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; stbi__zhuffman z_codelength; stbi_uc lencodes[286+32+137];//padding for maximum single op stbi_uc codelength_sizes[19]; @@ -4176,7 +3697,6 @@ static int stbi__compute_huffman_codes(stbi__zbuf *a) int hlit = stbi__zreceive(a,5) + 257; int hdist = stbi__zreceive(a,5) + 1; int hclen = stbi__zreceive(a,4) + 4; - int ntot = hlit + hdist; memset(codelength_sizes, 0, sizeof(codelength_sizes)); for (i=0; i < hclen; ++i) { @@ -4186,35 +3706,33 @@ static int stbi__compute_huffman_codes(stbi__zbuf *a) if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; n = 0; - while (n < ntot) { + while (n < hlit + hdist) { int c = stbi__zhuffman_decode(a, &z_codelength); if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); if (c < 16) lencodes[n++] = (stbi_uc) c; - else { - stbi_uc fill = 0; - if (c == 16) { - c = stbi__zreceive(a,2)+3; - if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); - fill = lencodes[n-1]; - } else if (c == 17) - c = stbi__zreceive(a,3)+3; - else { - STBI_ASSERT(c == 18); - c = stbi__zreceive(a,7)+11; - } - if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); - memset(lencodes+n, fill, c); + else if (c == 16) { + c = stbi__zreceive(a,2)+3; + memset(lencodes+n, lencodes[n-1], c); + n += c; + } else if (c == 17) { + c = stbi__zreceive(a,3)+3; + memset(lencodes+n, 0, c); + n += c; + } else { + STBI_ASSERT(c == 18); + c = stbi__zreceive(a,7)+11; + memset(lencodes+n, 0, c); n += c; } } - if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); + if (n != hlit+hdist) return stbi__err("bad codelengths","Corrupt PNG"); if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; return 1; } -static int stbi__parse_uncompressed_block(stbi__zbuf *a) +static int stbi__parse_uncomperssed_block(stbi__zbuf *a) { stbi_uc header[4]; int len,nlen,k; @@ -4252,28 +3770,13 @@ static int stbi__parse_zlib_header(stbi__zbuf *a) if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png - // window = 1 << (8 + cinfo)... but who cares, we fully buffer output - return 1; -} - -static const stbi_uc stbi__zdefault_length[288] = -{ - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 -}; -static const stbi_uc stbi__zdefault_distance[32] = -{ - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 -}; -/* -Init algorithm: + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +// @TODO: should statically initialize these for optimal thread safety +static stbi_uc stbi__zdefault_length[288], stbi__zdefault_distance[32]; +static void stbi__init_zdefaults(void) { int i; // use <= to match clearly with spec for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; @@ -4283,7 +3786,6 @@ Init algorithm: for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; } -*/ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) { @@ -4296,12 +3798,13 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) final = stbi__zreceive(a,1); type = stbi__zreceive(a,2); if (type == 0) { - if (!stbi__parse_uncompressed_block(a)) return 0; + if (!stbi__parse_uncomperssed_block(a)) return 0; } else if (type == 3) { return 0; } else { if (type == 1) { // use fixed code lengths + if (!stbi__zdefault_distance[31]) stbi__init_zdefaults(); if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; } else { @@ -4426,7 +3929,7 @@ static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) static int stbi__check_png_header(stbi__context *s) { - static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; int i; for (i=0; i < 8; ++i) if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); @@ -4437,7 +3940,6 @@ typedef struct { stbi__context *s; stbi_uc *idata, *expanded, *out; - int depth; } stbi__png; @@ -4472,40 +3974,35 @@ static int stbi__paeth(int a, int b, int c) return c; } -static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; +static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; // create the png data from post-deflated data static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) { - int bytes = (depth == 16? 2 : 1); stbi__context *s = a->s; - stbi__uint32 i,j,stride = x*out_n*bytes; + stbi__uint32 i,j,stride = x*out_n; stbi__uint32 img_len, img_width_bytes; int k; int img_n = s->img_n; // copy it into a local for later - int output_bytes = out_n*bytes; - int filter_bytes = img_n*bytes; - int width = x; - STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); - a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into + a->out = (stbi_uc *) stbi__malloc(x * y * out_n); // extra bytes to write off the end into if (!a->out) return stbi__err("outofmem", "Out of memory"); - if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); img_width_bytes = (((img_n * x * depth) + 7) >> 3); img_len = (img_width_bytes + 1) * y; - - // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, - // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), - // so just check for raw_len < img_len always. - if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + if (s->img_x == x && s->img_y == y) { + if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG"); + } else { // interlaced: + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + } for (j=0; j < y; ++j) { stbi_uc *cur = a->out + stride*j; - stbi_uc *prior; + stbi_uc *prior = cur - stride; int filter = *raw++; - + int filter_bytes = img_n; + int width = x; if (filter > 4) return stbi__err("invalid filter","Corrupt PNG"); @@ -4515,7 +4012,6 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r filter_bytes = 1; width = img_width_bytes; } - prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above // if first row, use special filter that doesn't sample previous row if (j == 0) filter = first_row_filter[filter]; @@ -4539,14 +4035,6 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r raw += img_n; cur += out_n; prior += out_n; - } else if (depth == 16) { - if (img_n != out_n) { - cur[filter_bytes] = 255; // first pixel top byte - cur[filter_bytes+1] = 255; // first pixel bottom byte - } - raw += filter_bytes; - cur += output_bytes; - prior += output_bytes; } else { raw += 1; cur += 1; @@ -4555,47 +4043,38 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r // this is a little gross, so that we don't switch per-pixel or per-component if (depth < 8 || img_n == out_n) { - int nk = (width - 1)*filter_bytes; - #define STBI__CASE(f) \ + int nk = (width - 1)*img_n; + #define CASE(f) \ case f: \ for (k=0; k < nk; ++k) switch (filter) { // "none" filter turns into a memcpy here; make that explicit. case STBI__F_none: memcpy(cur, raw, nk); break; - STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; - STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; - STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; - STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; + CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); break; + CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); break; + CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); break; + CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); break; + CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); break; } - #undef STBI__CASE + #undef CASE raw += nk; } else { STBI_ASSERT(img_n+1 == out_n); - #define STBI__CASE(f) \ + #define CASE(f) \ case f: \ - for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ - for (k=0; k < filter_bytes; ++k) + for (i=x-1; i >= 1; --i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \ + for (k=0; k < img_n; ++k) switch (filter) { - STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; - STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; - STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; - STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; - STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; - } - #undef STBI__CASE - - // the loop above sets the high byte of the pixels' alpha, but for - // 16 bit png files we also need the low byte set. we'll do that here. - if (depth == 16) { - cur = a->out + stride*j; // start at the beginning of the row again - for (i=0; i < x; ++i,cur+=output_bytes) { - cur[filter_bytes+1] = 255; - } + CASE(STBI__F_none) cur[k] = raw[k]; break; + CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-out_n]); break; + CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-out_n])>>1)); break; + CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],prior[k],prior[k-out_n])); break; + CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-out_n] >> 1)); break; + CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],0,0)); break; } + #undef CASE } } @@ -4671,17 +4150,6 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r } } } - } else if (depth == 16) { - // force the image data from big-endian to platform-native. - // this is done in a separate pass due to the decoding relying - // on the data being untouched, but could probably be done - // per-line during decode if care is taken. - stbi_uc *cur = a->out; - stbi__uint16 *cur16 = (stbi__uint16*)cur; - - for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { - *cur16 = (cur[0] << 8) | cur[1]; - } } return 1; @@ -4689,15 +4157,13 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) { - int bytes = (depth == 16 ? 2 : 1); - int out_bytes = out_n * bytes; stbi_uc *final; int p; if (!interlaced) return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); // de-interlacing - final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + final = (stbi_uc *) stbi__malloc(a->s->img_x * a->s->img_y * out_n); for (p=0; p < 7; ++p) { int xorig[] = { 0,4,0,2,0,1,0 }; int yorig[] = { 0,0,4,0,2,0,1 }; @@ -4717,8 +4183,8 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint3 for (i=0; i < x; ++i) { int out_y = j*yspc[p]+yorig[p]; int out_x = i*xspc[p]+xorig[p]; - memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, - a->out + (j*x+i)*out_bytes, out_bytes); + memcpy(final + out_y*a->s->img_x*out_n + out_x*out_n, + a->out + (j*x+i)*out_n, out_n); } } STBI_FREE(a->out); @@ -4756,37 +4222,12 @@ static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) return 1; } -static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi__uint16 *p = (stbi__uint16*) z->out; - - // compute color-based transparency, assuming we've - // already got 65535 as the alpha value in the output - STBI_ASSERT(out_n == 2 || out_n == 4); - - if (out_n == 2) { - for (i = 0; i < pixel_count; ++i) { - p[1] = (p[0] == tc[0] ? 0 : 65535); - p += 2; - } - } else { - for (i = 0; i < pixel_count; ++i) { - if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) - p[3] = 0; - p += 4; - } - } - return 1; -} - static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) { stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; stbi_uc *p, *temp_out, *orig = a->out; - p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); + p = (stbi_uc *) stbi__malloc(pixel_count * pal_img_n); if (p == NULL) return stbi__err("outofmem", "Out of memory"); // between here and free(out) below, exitting would leak @@ -4852,10 +4293,9 @@ static void stbi__de_iphone(stbi__png *z) stbi_uc a = p[3]; stbi_uc t = p[0]; if (a) { - stbi_uc half = a / 2; - p[0] = (p[2] * 255 + half) / a; - p[1] = (p[1] * 255 + half) / a; - p[2] = ( t * 255 + half) / a; + p[0] = p[2] * 255 / a; + p[1] = p[1] * 255 / a; + p[2] = t * 255 / a; } else { p[0] = p[2]; p[2] = t; @@ -4874,15 +4314,14 @@ static void stbi__de_iphone(stbi__png *z) } } -#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) +#define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) { stbi_uc palette[1024], pal_img_n=0; - stbi_uc has_trans=0, tc[3]={0}; - stbi__uint16 tc16[3]; + stbi_uc has_trans=0, tc[3]; stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; - int first=1,k,interlace=0, color=0, is_iphone=0; + int first=1,k,interlace=0, color=0, depth=0, is_iphone=0; stbi__context *s = z->s; z->expanded = NULL; @@ -4907,9 +4346,8 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); + depth = stbi__get8(s); if (depth != 1 && depth != 2 && depth != 4 && depth != 8) return stbi__err("1/2/4/8-bit only","PNG not supported: 1/2/4/8-bit only"); color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); @@ -4957,11 +4395,8 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); has_trans = 1; - if (z->depth == 16) { - for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is - } else { - for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger - } + for (k=0; k < s->img_n; ++k) + tc[k] = (stbi_uc) (stbi__get16be(s) & 255) * stbi__depth_scale_table[depth]; // non 8-bit images will be larger } break; } @@ -4992,7 +4427,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (scan != STBI__SCAN_load) return 1; if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); // initial guess for decoded data size to avoid unnecessary reallocs - bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + bpl = (s->img_x * depth + 7) / 8; // bytes per line, per component raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); if (z->expanded == NULL) return 0; // zlib should set error @@ -5001,14 +4436,9 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) s->img_out_n = s->img_n+1; else s->img_out_n = s->img_n; - if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; - if (has_trans) { - if (z->depth == 16) { - if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; - } else { - if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; - } - } + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, depth, color, interlace)) return 0; + if (has_trans) + if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) stbi__de_iphone(z); if (pal_img_n) { @@ -5018,13 +4448,8 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (req_comp >= 3) s->img_out_n = req_comp; if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) return 0; - } else if (has_trans) { - // non-paletted image with tRNS -> source image has (constant) alpha - ++s->img_n; } STBI_FREE(z->expanded); z->expanded = NULL; - // end of PNG chunk, read and skip CRC - stbi__get32be(s); return 1; } @@ -5050,28 +4475,21 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) } } -static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) +static unsigned char *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp) { - void *result=NULL; + unsigned char *result=NULL; if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { - if (p->depth < 8) - ri->bits_per_channel = 8; - else - ri->bits_per_channel = p->depth; result = p->out; p->out = NULL; if (req_comp && req_comp != p->s->img_out_n) { - if (ri->bits_per_channel == 8) - result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); - else - result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + result = stbi__convert_format(result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); p->s->img_out_n = req_comp; if (result == NULL) return result; } *x = p->s->img_x; *y = p->s->img_y; - if (n) *n = p->s->img_n; + if (n) *n = p->s->img_out_n; } STBI_FREE(p->out); p->out = NULL; STBI_FREE(p->expanded); p->expanded = NULL; @@ -5080,11 +4498,11 @@ static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, st return result; } -static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +static unsigned char *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) { stbi__png p; p.s = s; - return stbi__do_png(&p, x,y,comp,req_comp, ri); + return stbi__do_png(&p, x,y,comp,req_comp); } static int stbi__png_test(stbi__context *s) @@ -5113,19 +4531,6 @@ static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) p.s = s; return stbi__png_info_raw(&p, x, y, comp); } - -static int stbi__png_is16(stbi__context *s) -{ - stbi__png p; - p.s = s; - if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) - return 0; - if (p.depth != 16) { - stbi__rewind(p.s); - return 0; - } - return 1; -} #endif // Microsoft/Windows BMP image @@ -5159,11 +4564,11 @@ static int stbi__high_bit(unsigned int z) { int n=0; if (z == 0) return -1; - if (z >= 0x10000) { n += 16; z >>= 16; } - if (z >= 0x00100) { n += 8; z >>= 8; } - if (z >= 0x00010) { n += 4; z >>= 4; } - if (z >= 0x00004) { n += 2; z >>= 2; } - if (z >= 0x00002) { n += 1;/* >>= 1;*/ } + if (z >= 0x10000) n += 16, z >>= 16; + if (z >= 0x00100) n += 8, z >>= 8; + if (z >= 0x00010) n += 4, z >>= 4; + if (z >= 0x00004) n += 2, z >>= 2; + if (z >= 0x00002) n += 1, z >>= 1; return n; } @@ -5177,34 +4582,27 @@ static int stbi__bitcount(unsigned int a) return a & 0xff; } -// extract an arbitrarily-aligned N-bit value (N=bits) -// from v, and then make it 8-bits long and fractionally -// extend it to full full range. -static int stbi__shiftsigned(unsigned int v, int shift, int bits) -{ - static unsigned int mul_table[9] = { - 0, - 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, - 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, - }; - static unsigned int shift_table[9] = { - 0, 0,0,1,0,2,4,6,0, - }; - if (shift < 0) - v <<= -shift; - else - v >>= shift; - STBI_ASSERT(v < 256); - v >>= (8-bits); - STBI_ASSERT(bits >= 0 && bits <= 8); - return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; +static int stbi__shiftsigned(int v, int shift, int bits) +{ + int result; + int z=0; + + if (shift < 0) v <<= -shift; + else v >>= shift; + result = v; + + z = bits; + while (z < 8) { + result += v >> z; + z += bits; + } + return result; } typedef struct { int bpp, offset, hsz; unsigned int mr,mg,mb,ma, all_a; - int extra_read; } stbi__bmp_data; static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) @@ -5216,9 +4614,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) stbi__get16le(s); // discard reserved info->offset = stbi__get32le(s); info->hsz = hsz = stbi__get32le(s); - info->mr = info->mg = info->mb = info->ma = 0; - info->extra_read = 14; - + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); if (hsz == 12) { s->img_x = stbi__get16le(s); @@ -5229,6 +4625,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) } if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); info->bpp = stbi__get16le(s); + if (info->bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit"); if (hsz != 12) { int compress = stbi__get32le(s); if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); @@ -5245,6 +4642,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) stbi__get32le(s); } if (info->bpp == 16 || info->bpp == 32) { + info->mr = info->mg = info->mb = 0; if (compress == 0) { if (info->bpp == 32) { info->mr = 0xffu << 16; @@ -5261,7 +4659,6 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) info->mr = stbi__get32le(s); info->mg = stbi__get32le(s); info->mb = stbi__get32le(s); - info->extra_read += 12; // not documented, but generated by photoshop and handled by mspaint if (info->mr == info->mg && info->mg == info->mb) { // ?!?!? @@ -5293,7 +4690,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) } -static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) { stbi_uc *out; unsigned int mr=0,mg=0,mb=0,ma=0, all_a; @@ -5301,9 +4698,8 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req int psize=0,i,j,width; int flip_vertically, pad, target; stbi__bmp_data info; - STBI_NOTUSED(ri); - info.all_a = 255; + info.all_a = 255; if (stbi__bmp_parse_header(s, &info) == NULL) return NULL; // error code already set @@ -5318,29 +4714,19 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req if (info.hsz == 12) { if (info.bpp < 24) - psize = (info.offset - info.extra_read - 24) / 3; + psize = (info.offset - 14 - 24) / 3; } else { if (info.bpp < 16) - psize = (info.offset - info.extra_read - info.hsz) >> 2; - } - if (psize == 0) { - STBI_ASSERT(info.offset == (s->img_buffer - s->buffer_start)); + psize = (info.offset - 14 - info.hsz) >> 2; } - if (info.bpp == 24 && ma == 0xff000000) - s->img_n = 3; - else - s->img_n = ma ? 4 : 3; + s->img_n = ma ? 4 : 3; if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 target = req_comp; else target = s->img_n; // if they want monochrome, we'll post-convert - // sanity-check size - if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) - return stbi__errpuc("too large", "Corrupt BMP"); - - out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); + out = (stbi_uc *) stbi__malloc(target * s->img_x * s->img_y); if (!out) return stbi__errpuc("outofmem", "Out of memory"); if (info.bpp < 16) { int z=0; @@ -5352,56 +4738,36 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req if (info.hsz != 12) stbi__get8(s); pal[i][3] = 255; } - stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); - if (info.bpp == 1) width = (s->img_x + 7) >> 3; - else if (info.bpp == 4) width = (s->img_x + 1) >> 1; + stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + if (info.bpp == 4) width = (s->img_x + 1) >> 1; else if (info.bpp == 8) width = s->img_x; else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } pad = (-width)&3; - if (info.bpp == 1) { - for (j=0; j < (int) s->img_y; ++j) { - int bit_offset = 7, v = stbi__get8(s); - for (i=0; i < (int) s->img_x; ++i) { - int color = (v>>bit_offset)&0x1; - out[z++] = pal[color][0]; - out[z++] = pal[color][1]; - out[z++] = pal[color][2]; - if (target == 4) out[z++] = 255; - if (i+1 == (int) s->img_x) break; - if((--bit_offset) < 0) { - bit_offset = 7; - v = stbi__get8(s); - } - } - stbi__skip(s, pad); - } - } else { - for (j=0; j < (int) s->img_y; ++j) { - for (i=0; i < (int) s->img_x; i += 2) { - int v=stbi__get8(s),v2=0; - if (info.bpp == 4) { - v2 = v & 15; - v >>= 4; - } - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - if (i+1 == (int) s->img_x) break; - v = (info.bpp == 8) ? stbi__get8(s) : v2; - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (info.bpp == 4) { + v2 = v & 15; + v >>= 4; } - stbi__skip(s, pad); + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; } + stbi__skip(s, pad); } } else { int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; int z = 0; int easy=0; - stbi__skip(s, info.offset - info.extra_read - info.hsz); + stbi__skip(s, info.offset - 14 - info.hsz); if (info.bpp == 24) width = 3 * s->img_x; else if (info.bpp == 16) width = 2*s->img_x; else /* bpp = 32 and pad = 0 */ width=0; @@ -5436,7 +4802,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req int bpp = info.bpp; for (i=0; i < (int) s->img_x; ++i) { stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); - unsigned int a; + int a; out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); @@ -5448,7 +4814,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req stbi__skip(s, pad); } } - + // if alpha channel is all 0s, replace with all 255s if (target == 4 && all_a == 0) for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) @@ -5460,7 +4826,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req stbi_uc *p1 = out + j *s->img_x*target; stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; for (i=0; i < (int) s->img_x*target; ++i) { - t = p1[i]; p1[i] = p2[i]; p2[i] = t; + t = p1[i], p1[i] = p2[i], p2[i] = t; } } } @@ -5484,14 +4850,14 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) { // only RGB or RGBA (incl. 16bit) or grey allowed - if (is_rgb16) *is_rgb16 = 0; + if(is_rgb16) *is_rgb16 = 0; switch(bits_per_pixel) { case 8: return STBI_grey; case 16: if(is_grey) return STBI_grey_alpha; - // fallthrough + // else: fall-through case 15: if(is_rgb16) *is_rgb16 = 1; - return STBI_rgb; - case 24: // fallthrough + return STBI_rgb; + case 24: // fall-through case 32: return bits_per_pixel/8; default: return 0; } @@ -5594,18 +4960,18 @@ errorEnd: } // read 16bit value and convert to 24bit RGB -static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) +void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) { - stbi__uint16 px = (stbi__uint16)stbi__get16le(s); + stbi__uint16 px = stbi__get16le(s); stbi__uint16 fiveBitMask = 31; // we have 3 channels with 5bits each int r = (px >> 10) & fiveBitMask; int g = (px >> 5) & fiveBitMask; int b = px & fiveBitMask; // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later - out[0] = (stbi_uc)((r * 255)/31); - out[1] = (stbi_uc)((g * 255)/31); - out[2] = (stbi_uc)((b * 255)/31); + out[0] = (r * 255)/31; + out[1] = (g * 255)/31; + out[2] = (b * 255)/31; // some people claim that the most significant bit might be used for alpha // (possibly if an alpha-bit is set in the "image descriptor byte") @@ -5613,7 +4979,7 @@ static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) // so let's treat all 15 and 16bit TGAs as RGB with no alpha. } -static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) { // read in the TGA header stuff int tga_offset = stbi__get8(s); @@ -5635,13 +5001,10 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req unsigned char *tga_data; unsigned char *tga_palette = NULL; int i, j; - unsigned char raw_data[4] = {0}; + unsigned char raw_data[4]; int RLE_count = 0; int RLE_repeating = 0; int read_next_pixel = 1; - STBI_NOTUSED(ri); - STBI_NOTUSED(tga_x_origin); // @TODO - STBI_NOTUSED(tga_y_origin); // @TODO // do a tiny bit of precessing if ( tga_image_type >= 8 ) @@ -5663,10 +5026,7 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req *y = tga_height; if (comp) *comp = tga_comp; - if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) - return stbi__errpuc("too large", "Corrupt TGA"); - - tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); + tga_data = (unsigned char*)stbi__malloc( (size_t)tga_width * tga_height * tga_comp ); if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); // skip to the data's starting position (offset usually = 0) @@ -5685,7 +5045,7 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req // any data to skip? (offset usually = 0) stbi__skip(s, tga_palette_start ); // load the palette - tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); + tga_palette = (unsigned char*)stbi__malloc( tga_palette_len * tga_comp ); if (!tga_palette) { STBI_FREE(tga_data); return stbi__errpuc("outofmem", "Out of memory"); @@ -5805,7 +5165,6 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req // Microsoft's C compilers happy... [8^( tga_palette_start = tga_palette_len = tga_palette_bits = tga_x_origin = tga_y_origin = 0; - STBI_NOTUSED(tga_palette_start); // OK, done return tga_data; } @@ -5822,53 +5181,14 @@ static int stbi__psd_test(stbi__context *s) return r; } -static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) -{ - int count, nleft, len; - - count = 0; - while ((nleft = pixelCount - count) > 0) { - len = stbi__get8(s); - if (len == 128) { - // No-op. - } else if (len < 128) { - // Copy next len+1 bytes literally. - len++; - if (len > nleft) return 0; // corrupt data - count += len; - while (len) { - *p = stbi__get8(s); - p += 4; - len--; - } - } else if (len > 128) { - stbi_uc val; - // Next -len+1 bytes in the dest are replicated from next source byte. - // (Interpret len as a negative 8-bit int.) - len = 257 - len; - if (len > nleft) return 0; // corrupt data - val = stbi__get8(s); - count += len; - while (len) { - *p = val; - p += 4; - len--; - } - } - } - - return 1; -} - -static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) { - int pixelCount; + int pixelCount; int channelCount, compression; - int channel, i; + int channel, i, count, len; int bitdepth; int w,h; stbi_uc *out; - STBI_NOTUSED(ri); // Check identifier if (stbi__get32be(s) != 0x38425053) // "8BPS" @@ -5925,18 +5245,8 @@ static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req if (compression > 1) return stbi__errpuc("bad compression", "PSD has an unknown compression format"); - // Check size - if (!stbi__mad3sizes_valid(4, w, h, 0)) - return stbi__errpuc("too large", "Corrupt PSD"); - // Create the destination image. - - if (!compression && bitdepth == 16 && bpc == 16) { - out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); - ri->bits_per_channel = 16; - } else - out = (stbi_uc *) stbi__malloc(4 * w*h); - + out = (stbi_uc *) stbi__malloc(4 * w*h); if (!out) return stbi__errpuc("outofmem", "Out of memory"); pixelCount = w*h; @@ -5953,7 +5263,7 @@ static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req // Else if n is 128, noop. // Endloop - // The RLE-compressed data is preceded by a 2-byte data count for each row in the data, + // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, // which we're going to just skip. stbi__skip(s, h * channelCount * 2 ); @@ -5968,86 +5278,67 @@ static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req *p = (channel == 3 ? 255 : 0); } else { // Read the RLE data. - if (!stbi__psd_decode_rle(s, p, pixelCount)) { - STBI_FREE(out); - return stbi__errpuc("corrupt", "bad RLE data"); + count = 0; + while (count < pixelCount) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len ^= 0x0FF; + len += 2; + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } } } } } else { // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) - // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. + // where each channel consists of an 8-bit value for each pixel in the image. // Read the data by channel. for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out + channel; if (channel >= channelCount) { // Fill this channel with default data. - if (bitdepth == 16 && bpc == 16) { - stbi__uint16 *q = ((stbi__uint16 *) out) + channel; - stbi__uint16 val = channel == 3 ? 65535 : 0; - for (i = 0; i < pixelCount; i++, q += 4) - *q = val; - } else { - stbi_uc *p = out+channel; - stbi_uc val = channel == 3 ? 255 : 0; - for (i = 0; i < pixelCount; i++, p += 4) - *p = val; - } + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; } else { - if (ri->bits_per_channel == 16) { // output bpc - stbi__uint16 *q = ((stbi__uint16 *) out) + channel; - for (i = 0; i < pixelCount; i++, q += 4) - *q = (stbi__uint16) stbi__get16be(s); + // Read the data. + if (bitdepth == 16) { + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc) (stbi__get16be(s) >> 8); } else { - stbi_uc *p = out+channel; - if (bitdepth == 16) { // input bpc - for (i = 0; i < pixelCount; i++, p += 4) - *p = (stbi_uc) (stbi__get16be(s) >> 8); - } else { - for (i = 0; i < pixelCount; i++, p += 4) - *p = stbi__get8(s); - } - } - } - } - } - - // remove weird white matte from PSD - if (channelCount >= 4) { - if (ri->bits_per_channel == 16) { - for (i=0; i < w*h; ++i) { - stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; - if (pixel[3] != 0 && pixel[3] != 65535) { - float a = pixel[3] / 65535.0f; - float ra = 1.0f / a; - float inv_a = 65535.0f * (1 - ra); - pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); - pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); - pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); - } - } - } else { - for (i=0; i < w*h; ++i) { - unsigned char *pixel = out + 4*i; - if (pixel[3] != 0 && pixel[3] != 255) { - float a = pixel[3] / 255.0f; - float ra = 1.0f / a; - float inv_a = 255.0f * (1 - ra); - pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); - pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); - pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); } } } } - // convert to desired output format if (req_comp && req_comp != 4) { - if (ri->bits_per_channel == 16) - out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); - else - out = stbi__convert_format(out, 4, req_comp, w, h); + out = stbi__convert_format(out, 4, req_comp, w, h); if (out == NULL) return out; // stbi__convert_format frees input on failure } @@ -6231,13 +5522,10 @@ static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *c return result; } -static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) +static stbi_uc *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp) { stbi_uc *result; - int i, x,y, internal_comp; - STBI_NOTUSED(ri); - - if (!comp) comp = &internal_comp; + int i, x,y; for (i=0; i<92; ++i) stbi__get8(s); @@ -6245,14 +5533,14 @@ static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_c x = stbi__get16be(s); y = stbi__get16be(s); if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); - if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); + if ((1 << 28) / x < y) return stbi__errpuc("too large", "Image too large to decode"); stbi__get32be(s); //skip `ratio' stbi__get16be(s); //skip `fields' stbi__get16be(s); //skip `pad' // intermediate buffer is RGBA - result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + result = (stbi_uc *) stbi__malloc(x*y*4); memset(result, 0xff, x*y*4); if (!stbi__pic_load_core(s,x,y,comp, result)) { @@ -6289,13 +5577,11 @@ typedef struct typedef struct { int w,h; - stbi_uc *out; // output buffer (always 4 components) - stbi_uc *background; // The current "background" as far as a gif is concerned - stbi_uc *history; - int flags, bgindex, ratio, transparent, eflags; + stbi_uc *out, *old_out; // output buffer (always 4 components) + int flags, bgindex, ratio, transparent, eflags, delay; stbi_uc pal[256][4]; stbi_uc lpal[256][4]; - stbi__gif_lzw codes[8192]; + stbi__gif_lzw codes[4096]; stbi_uc *color_table; int parse, step; int lflags; @@ -6303,7 +5589,6 @@ typedef struct int max_x, max_y; int cur_x, cur_y; int line_size; - int delay; } stbi__gif; static int stbi__gif_test_raw(stbi__context *s) @@ -6364,22 +5649,19 @@ static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_in static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) { - stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); - if (!stbi__gif_header(s, g, comp, 1)) { - STBI_FREE(g); + stbi__gif g; + if (!stbi__gif_header(s, &g, comp, 1)) { stbi__rewind( s ); return 0; } - if (x) *x = g->w; - if (y) *y = g->h; - STBI_FREE(g); + if (x) *x = g.w; + if (y) *y = g.h; return 1; } static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) { stbi_uc *p, *c; - int idx; // recurse to decode the prefixes, since the linked-list is backwards, // and working backwards through an interleaved image would be nasty @@ -6388,12 +5670,10 @@ static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) if (g->cur_y >= g->max_y) return; - idx = g->cur_x + g->cur_y; - p = &g->out[idx]; - g->history[idx / 4] = 1; - + p = &g->out[g->cur_x + g->cur_y]; c = &g->color_table[g->codes[code].suffix * 4]; - if (c[3] > 128) { // don't render transparent pixels; + + if (c[3] >= 128) { p[0] = c[2]; p[1] = c[1]; p[2] = c[0]; @@ -6467,16 +5747,11 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) stbi__skip(s,len); return g->out; } else if (code <= avail) { - if (first) { - return stbi__errpuc("no clear code", "Corrupt GIF"); - } + if (first) return stbi__errpuc("no clear code", "Corrupt GIF"); if (oldcode >= 0) { p = &g->codes[avail++]; - if (avail > 8192) { - return stbi__errpuc("too many codes", "Corrupt GIF"); - } - + if (avail > 4096) return stbi__errpuc("too many codes", "Corrupt GIF"); p->prefix = (stbi__int16) oldcode; p->first = g->codes[oldcode].first; p->suffix = (code == avail) ? p->first : g->codes[code].first; @@ -6498,77 +5773,59 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) } } +static void stbi__fill_gif_background(stbi__gif *g, int x0, int y0, int x1, int y1) +{ + int x, y; + stbi_uc *c = g->pal[g->bgindex]; + for (y = y0; y < y1; y += 4 * g->w) { + for (x = x0; x < x1; x += 4) { + stbi_uc *p = &g->out[y + x]; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = 0; + } + } +} + // this function is designed to support animated gifs, although stb_image doesn't support it -// two back is the image from two frames ago, used for a very specific disposal format -static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp) { - int dispose; - int first_frame; - int pi; - int pcount; - STBI_NOTUSED(req_comp); + int i; + stbi_uc *prev_out = 0; - // on first frame, any non-written pixels get the background colour (non-transparent) - first_frame = 0; - if (g->out == 0) { - if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header - if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) - return stbi__errpuc("too large", "GIF image is too large"); - pcount = g->w * g->h; - g->out = (stbi_uc *) stbi__malloc(4 * pcount); - g->background = (stbi_uc *) stbi__malloc(4 * pcount); - g->history = (stbi_uc *) stbi__malloc(pcount); - if (!g->out || !g->background || !g->history) - return stbi__errpuc("outofmem", "Out of memory"); - - // image is treated as "transparent" at the start - ie, nothing overwrites the current background; - // background colour is only used for pixels that are not rendered first frame, after that "background" - // color refers to the color that was there the previous frame. - memset(g->out, 0x00, 4 * pcount); - memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) - memset(g->history, 0x00, pcount); // pixels that were affected previous frame - first_frame = 1; - } else { - // second frame - how do we dispoase of the previous one? - dispose = (g->eflags & 0x1C) >> 2; - pcount = g->w * g->h; + if (g->out == 0 && !stbi__gif_header(s, g, comp,0)) + return 0; // stbi__g_failure_reason set by stbi__gif_header - if ((dispose == 3) && (two_back == 0)) { - dispose = 2; // if I don't have an image to revert back to, default to the old background - } + prev_out = g->out; + g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); + if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); - if (dispose == 3) { // use previous graphic - for (pi = 0; pi < pcount; ++pi) { - if (g->history[pi]) { - memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); - } - } - } else if (dispose == 2) { - // restore what was changed last frame to background before that frame; - for (pi = 0; pi < pcount; ++pi) { - if (g->history[pi]) { - memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); - } + switch ((g->eflags & 0x1C) >> 2) { + case 0: // unspecified (also always used on 1st frame) + stbi__fill_gif_background(g, 0, 0, 4 * g->w, 4 * g->w * g->h); + break; + case 1: // do not dispose + if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h); + g->old_out = prev_out; + break; + case 2: // dispose to background + if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h); + stbi__fill_gif_background(g, g->start_x, g->start_y, g->max_x, g->max_y); + break; + case 3: // dispose to previous + if (g->old_out) { + for (i = g->start_y; i < g->max_y; i += 4 * g->w) + memcpy(&g->out[i + g->start_x], &g->old_out[i + g->start_x], g->max_x - g->start_x); } - } else { - // This is a non-disposal case eithe way, so just - // leave the pixels as is, and they will become the new background - // 1: do not dispose - // 0: not specified. - } - - // background is what out is after the undoing of the previou frame; - memcpy( g->background, g->out, 4 * g->w * g->h ); + break; } - // clear my history; - memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame - for (;;) { - int tag = stbi__get8(s); - switch (tag) { + switch (stbi__get8(s)) { case 0x2C: /* Image Descriptor */ { + int prev_trans = -1; stbi__int32 x, y, w, h; stbi_uc *o; @@ -6587,13 +5844,6 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i g->cur_x = g->start_x; g->cur_y = g->start_y; - // if the width of the specified rectangle is 0, that means - // we may not see *any* pixels or the image is malformed; - // to make sure this is caught, move the current y down to - // max_y (which is what out_gif_code checks). - if (w == 0) - g->cur_y = g->max_y; - g->lflags = stbi__get8(s); if (g->lflags & 0x40) { @@ -6608,24 +5858,19 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); g->color_table = (stbi_uc *) g->lpal; } else if (g->flags & 0x80) { + if (g->transparent >= 0 && (g->eflags & 0x01)) { + prev_trans = g->pal[g->transparent][3]; + g->pal[g->transparent][3] = 0; + } g->color_table = (stbi_uc *) g->pal; } else return stbi__errpuc("missing color table", "Corrupt GIF"); o = stbi__process_gif_raster(s, g); - if (!o) return NULL; - - // if this was the first frame, - pcount = g->w * g->h; - if (first_frame && (g->bgindex > 0)) { - // if first frame, any pixel not drawn to gets the background color - for (pi = 0; pi < pcount; ++pi) { - if (g->history[pi] == 0) { - g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; - memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); - } - } - } + if (o == NULL) return NULL; + + if (prev_trans != -1) + g->pal[g->transparent][3] = (stbi_uc) prev_trans; return o; } @@ -6633,35 +5878,19 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i case 0x21: // Comment Extension. { int len; - int ext = stbi__get8(s); - if (ext == 0xF9) { // Graphic Control Extension. + if (stbi__get8(s) == 0xF9) { // Graphic Control Extension. len = stbi__get8(s); if (len == 4) { g->eflags = stbi__get8(s); - g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. - - // unset old transparent - if (g->transparent >= 0) { - g->pal[g->transparent][3] = 255; - } - if (g->eflags & 0x01) { - g->transparent = stbi__get8(s); - if (g->transparent >= 0) { - g->pal[g->transparent][3] = 0; - } - } else { - // don't need transparent - stbi__skip(s, 1); - g->transparent = -1; - } + g->delay = stbi__get16le(s); + g->transparent = stbi__get8(s); } else { stbi__skip(s, len); break; } } - while ((len = stbi__get8(s)) != 0) { + while ((len = stbi__get8(s)) != 0) stbi__skip(s, len); - } break; } @@ -6672,103 +5901,26 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i return stbi__errpuc("unknown code", "Corrupt GIF"); } } -} - -static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) -{ - if (stbi__gif_test(s)) { - int layers = 0; - stbi_uc *u = 0; - stbi_uc *out = 0; - stbi_uc *two_back = 0; - stbi__gif g; - int stride; - memset(&g, 0, sizeof(g)); - if (delays) { - *delays = 0; - } - - do { - u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); - if (u == (stbi_uc *) s) u = 0; // end of animated gif marker - - if (u) { - *x = g.w; - *y = g.h; - ++layers; - stride = g.w * g.h * 4; - - if (out) { - void *tmp = (stbi_uc*) STBI_REALLOC( out, layers * stride ); - if (NULL == tmp) { - STBI_FREE(g.out); - STBI_FREE(g.history); - STBI_FREE(g.background); - return stbi__errpuc("outofmem", "Out of memory"); - } - else - out = (stbi_uc*) tmp; - if (delays) { - *delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers ); - } - } else { - out = (stbi_uc*)stbi__malloc( layers * stride ); - if (delays) { - *delays = (int*) stbi__malloc( layers * sizeof(int) ); - } - } - memcpy( out + ((layers - 1) * stride), u, stride ); - if (layers >= 2) { - two_back = out - 2 * stride; - } - - if (delays) { - (*delays)[layers - 1U] = g.delay; - } - } - } while (u != 0); - - // free temp buffer; - STBI_FREE(g.out); - STBI_FREE(g.history); - STBI_FREE(g.background); - - // do the final conversion after loading everything; - if (req_comp && req_comp != 4) - out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); - *z = layers; - return out; - } else { - return stbi__errpuc("not GIF", "Image was not as a gif type."); - } + STBI_NOTUSED(req_comp); } -static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) { stbi_uc *u = 0; stbi__gif g; memset(&g, 0, sizeof(g)); - STBI_NOTUSED(ri); - u = stbi__gif_load_next(s, &g, comp, req_comp, 0); + u = stbi__gif_load_next(s, &g, comp, req_comp); if (u == (stbi_uc *) s) u = 0; // end of animated gif marker if (u) { *x = g.w; *y = g.h; - - // moved conversion to after successful load so that the same - // can be done for multiple frames. if (req_comp && req_comp != 4) u = stbi__convert_format(u, 4, req_comp, g.w, g.h); - } else if (g.out) { - // if there was an error and we allocated an image buffer, free it! - STBI_FREE(g.out); } - - // free buffers needed for multiple frame loading; - STBI_FREE(g.history); - STBI_FREE(g.background); + else if (g.out) + STBI_FREE(g.out); return u; } @@ -6783,24 +5935,20 @@ static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) // Radiance RGBE HDR loader // originally by Nicolas Schulz #ifndef STBI_NO_HDR -static int stbi__hdr_test_core(stbi__context *s, const char *signature) +static int stbi__hdr_test_core(stbi__context *s) { + const char *signature = "#?RADIANCE\n"; int i; for (i=0; signature[i]; ++i) if (stbi__get8(s) != signature[i]) - return 0; - stbi__rewind(s); + return 0; return 1; } static int stbi__hdr_test(stbi__context* s) { - int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); + int r = stbi__hdr_test_core(s); stbi__rewind(s); - if(!r) { - r = stbi__hdr_test_core(s, "#?RGBE\n"); - stbi__rewind(s); - } return r; } @@ -6854,7 +6002,7 @@ static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) } } -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) { char buffer[STBI__HDR_BUFLEN]; char *token; @@ -6865,12 +6013,10 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re int len; unsigned char count, value; int i, j, k, c1,c2, z; - const char *headerToken; - STBI_NOTUSED(ri); + // Check identifier - headerToken = stbi__hdr_gettoken(s,buffer); - if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) + if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) return stbi__errpf("not HDR", "Corrupt HDR image"); // Parse header @@ -6899,13 +6045,8 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re if (comp) *comp = 3; if (req_comp == 0) req_comp = 3; - if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) - return stbi__errpf("too large", "HDR image is too large"); - // Read data - hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); - if (!hdr_data) - return stbi__errpf("outofmem", "Out of memory"); + hdr_data = (float *) stbi__malloc(height * width * req_comp * sizeof(float)); // Load image data // image data is stored as some number of sca @@ -6944,29 +6085,20 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re len <<= 8; len |= stbi__get8(s); if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } - if (scanline == NULL) { - scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); - if (!scanline) { - STBI_FREE(hdr_data); - return stbi__errpf("outofmem", "Out of memory"); - } - } + if (scanline == NULL) scanline = (stbi_uc *) stbi__malloc(width * 4); for (k = 0; k < 4; ++k) { - int nleft; i = 0; - while ((nleft = width - i) > 0) { + while (i < width) { count = stbi__get8(s); if (count > 128) { // Run value = stbi__get8(s); count -= 128; - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = value; } else { // Dump - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = stbi__get8(s); } @@ -6975,8 +6107,7 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re for (i=0; i < width; ++i) stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); } - if (scanline) - STBI_FREE(scanline); + STBI_FREE(scanline); } return hdr_data; @@ -6987,11 +6118,6 @@ static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) char buffer[STBI__HDR_BUFLEN]; char *token; int valid = 0; - int dummy; - - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; if (stbi__hdr_test(s) == 0) { stbi__rewind( s ); @@ -7033,19 +6159,14 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) void *p; stbi__bmp_data info; - info.all_a = 255; + info.all_a = 255; p = stbi__bmp_parse_header(s, &info); stbi__rewind( s ); if (p == NULL) return 0; - if (x) *x = s->img_x; - if (y) *y = s->img_y; - if (comp) { - if (info.bpp == 24 && info.ma == 0xff000000) - *comp = 3; - else - *comp = info.ma ? 4 : 3; - } + *x = s->img_x; + *y = s->img_y; + *comp = info.ma ? 4 : 3; return 1; } #endif @@ -7053,10 +6174,7 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) #ifndef STBI_NO_PSD static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) { - int channelCount, dummy, depth; - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; + int channelCount; if (stbi__get32be(s) != 0x38425053) { stbi__rewind( s ); return 0; @@ -7073,8 +6191,7 @@ static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) } *y = stbi__get32be(s); *x = stbi__get32be(s); - depth = stbi__get16be(s); - if (depth != 8 && depth != 16) { + if (stbi__get16be(s) != 8) { stbi__rewind( s ); return 0; } @@ -7085,45 +6202,14 @@ static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) *comp = 4; return 1; } - -static int stbi__psd_is16(stbi__context *s) -{ - int channelCount, depth; - if (stbi__get32be(s) != 0x38425053) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 1) { - stbi__rewind( s ); - return 0; - } - stbi__skip(s, 6); - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) { - stbi__rewind( s ); - return 0; - } - (void) stbi__get32be(s); - (void) stbi__get32be(s); - depth = stbi__get16be(s); - if (depth != 16) { - stbi__rewind( s ); - return 0; - } - return 1; -} #endif #ifndef STBI_NO_PIC static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) { - int act_comp=0,num_packets=0,chained,dummy; + int act_comp=0,num_packets=0,chained; stbi__pic_packet packets[10]; - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; - if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { stbi__rewind(s); return 0; @@ -7199,22 +6285,16 @@ static int stbi__pnm_test(stbi__context *s) return 1; } -static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) { stbi_uc *out; - STBI_NOTUSED(ri); - if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) return 0; - *x = s->img_x; *y = s->img_y; - if (comp) *comp = s->img_n; + *comp = s->img_n; - if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) - return stbi__errpuc("too large", "PNM too large"); - - out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); + out = (stbi_uc *) stbi__malloc(s->img_n * s->img_x * s->img_y); if (!out) return stbi__errpuc("outofmem", "Out of memory"); stbi__getn(s, out, s->img_n * s->img_x * s->img_y); @@ -7263,20 +6343,16 @@ static int stbi__pnm_getinteger(stbi__context *s, char *c) static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) { - int maxv, dummy; + int maxv; char c, p, t; - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; - - stbi__rewind(s); + stbi__rewind( s ); // Get identifier p = (char) stbi__get8(s); t = (char) stbi__get8(s); if (p != 'P' || (t != '5' && t != '6')) { - stbi__rewind(s); + stbi__rewind( s ); return 0; } @@ -7342,19 +6418,6 @@ static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) return stbi__err("unknown image type", "Image not of any known type, or corrupt"); } -static int stbi__is_16_main(stbi__context *s) -{ - #ifndef STBI_NO_PNG - if (stbi__png_is16(s)) return 1; - #endif - - #ifndef STBI_NO_PSD - if (stbi__psd_is16(s)) return 1; - #endif - - return 0; -} - #ifndef STBI_NO_STDIO STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) { @@ -7376,27 +6439,6 @@ STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) fseek(f,pos,SEEK_SET); return r; } - -STBIDEF int stbi_is_16_bit(char const *filename) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result; - if (!f) return stbi__err("can't fopen", "Unable to open file"); - result = stbi_is_16_bit_from_file(f); - fclose(f); - return result; -} - -STBIDEF int stbi_is_16_bit_from_file(FILE *f) -{ - int r; - stbi__context s; - long pos = ftell(f); - stbi__start_file(&s, f); - r = stbi__is_16_main(&s); - fseek(f,pos,SEEK_SET); - return r; -} #endif // !STBI_NO_STDIO STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) @@ -7413,51 +6455,10 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int return stbi__info_main(&s,x,y,comp); } -STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__is_16_main(&s); -} - -STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); - return stbi__is_16_main(&s); -} - #endif // STB_IMAGE_IMPLEMENTATION /* revision history: - 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs - 2.19 (2018-02-11) fix warning - 2.18 (2018-01-30) fix warnings - 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug - 1-bit BMP - *_is_16_bit api - avoid warnings - 2.16 (2017-07-23) all functions have 16-bit variants; - STBI_NO_STDIO works again; - compilation fixes; - fix rounding in unpremultiply; - optimize vertical flip; - disable raw_len validation; - documentation fixes - 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; - warning fixes; disable run-time SSE detection on gcc; - uniform handling of optional "return" values; - thread-safe initialization of zlib tables - 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs - 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now - 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes - 2.11 (2016-04-02) allocate large structures on the stack - remove white matting for transparent PSD - fix reported channel count for PNG & BMP - re-enable SSE2 in non-gcc 64-bit - support RGB-formatted JPEG - read 16-bit PNGs (only as 8-bit) 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED 2.09 (2016-01-16) allow comments in PNM files 16-bit-per-pixel TGA (not bit-per-component) @@ -7611,46 +6612,3 @@ STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user 0.50 (2006-11-19) first released version */ - - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, -commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to -this software under copyright law. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------- -*/ diff --git a/dpf/dgl/src/pugl-upstream/bindings/cpp/include/.clang-tidy b/dpf/dgl/src/pugl-upstream/bindings/cpp/include/.clang-tidy index 15651d3..20c477e 100644 --- a/dpf/dgl/src/pugl-upstream/bindings/cpp/include/.clang-tidy +++ b/dpf/dgl/src/pugl-upstream/bindings/cpp/include/.clang-tidy @@ -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, diff --git a/dpf/dgl/src/pugl-upstream/examples/.clang-tidy b/dpf/dgl/src/pugl-upstream/examples/.clang-tidy index e7e83a6..a03027e 100644 --- a/dpf/dgl/src/pugl-upstream/examples/.clang-tidy +++ b/dpf/dgl/src/pugl-upstream/examples/.clang-tidy @@ -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 diff --git a/dpf/dgl/src/pugl-upstream/include/.clang-tidy b/dpf/dgl/src/pugl-upstream/include/.clang-tidy index dd2fd47..b6d941c 100644 --- a/dpf/dgl/src/pugl-upstream/include/.clang-tidy +++ b/dpf/dgl/src/pugl-upstream/include/.clang-tidy @@ -2,6 +2,7 @@ Checks: > *, -*-magic-numbers, -*-uppercase-literal-suffix, + -altera-struct-pack-align, -clang-diagnostic-unused-function, -clang-diagnostic-unused-macros, -llvmlibc-*, diff --git a/dpf/dgl/src/pugl-upstream/src/.clang-tidy b/dpf/dgl/src/pugl-upstream/src/.clang-tidy index 2ee3372..f4378ba 100644 --- a/dpf/dgl/src/pugl-upstream/src/.clang-tidy +++ b/dpf/dgl/src/pugl-upstream/src/.clang-tidy @@ -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/.*' diff --git a/dpf/dgl/src/pugl-upstream/src/mac.m b/dpf/dgl/src/pugl-upstream/src/mac.m index 249b11b..a6d09a7 100644 --- a/dpf/dgl/src/pugl-upstream/src/mac.m +++ b/dpf/dgl/src/pugl-upstream/src/mac.m @@ -29,12 +29,9 @@ #include -#ifndef __MAC_10_9 -typedef NSUInteger NSEventSubtype; -#endif - #ifndef __MAC_10_10 typedef NSUInteger NSEventModifierFlags; +typedef NSUInteger NSEventSubtype; #endif #ifndef __MAC_10_12 diff --git a/dpf/dgl/src/pugl-upstream/src/x11.c b/dpf/dgl/src/pugl-upstream/src/x11.c index e1e2857..455ee20 100644 --- a/dpf/dgl/src/pugl-upstream/src/x11.c +++ b/dpf/dgl/src/pugl-upstream/src/x11.c @@ -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); diff --git a/dpf/dgl/src/pugl-upstream/src/x11_gl.c b/dpf/dgl/src/pugl-upstream/src/x11_gl.c index 8c061cd..ac2659b 100644 --- a/dpf/dgl/src/pugl-upstream/src/x11_gl.c +++ b/dpf/dgl/src/pugl-upstream/src/x11_gl.c @@ -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}; diff --git a/dpf/dgl/src/pugl-upstream/test/.clang-tidy b/dpf/dgl/src/pugl-upstream/test/.clang-tidy index 30893c7..f3a1adc 100644 --- a/dpf/dgl/src/pugl-upstream/test/.clang-tidy +++ b/dpf/dgl/src/pugl-upstream/test/.clang-tidy @@ -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/.*' diff --git a/dpf/distrho/extra/ExternalWindow.hpp b/dpf/distrho/extra/ExternalWindow.hpp index 53b0f54..1f1c360 100644 --- a/dpf/distrho/extra/ExternalWindow.hpp +++ b/dpf/distrho/extra/ExternalWindow.hpp @@ -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) {} diff --git a/dpf/distrho/src/DistrhoPluginVST3.cpp b/dpf/distrho/src/DistrhoPluginVST3.cpp index b4fabf9..d7695f0 100644 --- a/dpf/distrho/src/DistrhoPluginVST3.cpp +++ b/dpf/distrho/src/DistrhoPluginVST3.cpp @@ -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; diff --git a/dpf/distrho/src/DistrhoUIInternal.hpp b/dpf/distrho/src/DistrhoUIInternal.hpp index e22a578..fd79f64 100644 --- a/dpf/distrho/src/DistrhoUIInternal.hpp +++ b/dpf/distrho/src/DistrhoUIInternal.hpp @@ -132,9 +132,16 @@ public: return uiData->window->getScaleFactor(); } - Size 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 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 // ------------------------------------------------------------------- diff --git a/dpf/distrho/src/DistrhoUIPrivateData.hpp b/dpf/distrho/src/DistrhoUIPrivateData.hpp index 1b63a33..1371b9d 100644 --- a/dpf/distrho/src/DistrhoUIPrivateData.hpp +++ b/dpf/distrho/src/DistrhoUIPrivateData.hpp @@ -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) }; diff --git a/dpf/distrho/src/DistrhoUIVST3.cpp b/dpf/distrho/src/DistrhoUIVST3.cpp index b156616..660d052 100644 --- a/dpf/distrho/src/DistrhoUIVST3.cpp +++ b/dpf/distrho/src/DistrhoUIVST3.cpp @@ -75,10 +75,11 @@ struct ScopedUTF16String { // -------------------------------------------------------------------------------------------------------------------- -static bool checkSizeConstraint(const Size& 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(size.getWidth()); - const int32_t minHeight = static_cast(size.getHeight()); + const int32_t minWidth = static_cast(minimumWidth); + const int32_t minHeight = static_cast(minimumHeight); bool changed = false; if (keepAspectRatio) @@ -92,10 +93,10 @@ static bool checkSizeConstraint(const Size& size, const bool keepAspectRat // fix width if (reqRatio > ratio) - rect->right = static_cast(rect->bottom * ratio + 0.5); + rect->right = static_cast(rect->bottom * ratio + 0.5); // fix height else - rect->bottom = static_cast(static_cast(rect->right) / ratio + 0.5); + rect->bottom = static_cast(static_cast(rect->right) / ratio + 0.5); } } @@ -168,10 +169,10 @@ public: disconnect(); } - void postInit(const Size& 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(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(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 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 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(); + 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(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 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; } };