diff --git a/dgl/NanoVG.hpp b/dgl/NanoVG.hpp index 881e6d81..248251bc 100644 --- a/dgl/NanoVG.hpp +++ b/dgl/NanoVG.hpp @@ -36,12 +36,46 @@ START_NAMESPACE_DGL */ class NanoImage { +private: + struct Handle { + NVGcontext* context; + int imageId; + + Handle() noexcept + : context(nullptr), + imageId(0) {} + + Handle(NVGcontext* c, int id) noexcept + : context(c), + imageId(id) {} + }; + public: + /** + Constructor for an invalid/null image. + */ + NanoImage(); + + /** + Constructor. + */ + NanoImage(const Handle& handle); + /** Destructor. */ ~NanoImage(); + /** + Create a new image without recreating the C++ class. + */ + NanoImage& operator=(const Handle& handle); + + /** + Wherever the image is valid. + */ + bool isValid() const noexcept; + /** Get size. */ @@ -57,16 +91,8 @@ public: */ void updateImage(const uchar* const data); -protected: - /** - Constructors are protected. - NanoImages must be created within a NanoVG or NanoWidget class. - */ - NanoImage(NVGcontext* const context, const int imageId) noexcept; - private: - NVGcontext* fContext; - int fImageId; + Handle fHandle; Size fSize; friend class NanoVG; @@ -265,6 +291,7 @@ public: /** Constructor. + @see CreateFlags */ NanoVG(int flags = CREATE_ANTIALIAS); @@ -519,30 +546,50 @@ public: /** Creates image by loading it from the disk from specified file name. */ - NanoImage* createImage(const char* filename, int imageFlags); + NanoImage::Handle createImageFromFile(const char* filename, ImageFlags imageFlags); - // TODO overloaded? + /** + Creates image by loading it from the disk from specified file name. + Overloaded function for convenience. + @see ImageFlags + */ + NanoImage::Handle createImageFromFile(const char* filename, int imageFlags); /** Creates image by loading it from the specified chunk of memory. */ - NanoImage* createImageMem(uchar* data, int ndata, int imageFlags); + NanoImage::Handle createImageFromMemory(uchar* data, uint dataSize, ImageFlags imageFlags); - // TODO overloaded? + /** + Creates image by loading it from the specified chunk of memory. + Overloaded function for convenience. + @see ImageFlags + */ + NanoImage::Handle createImageFromMemory(uchar* data, uint dataSize, int imageFlags); /** Creates image from specified image data. */ - NanoImage* createImageRGBA(uint w, uint h, const uchar* data, int imageFlags); + NanoImage::Handle createImageFromRGBA(uint w, uint h, const uchar* data, ImageFlags imageFlags); - // TODO overloaded? + /** + Creates image from specified image data. + Overloaded function for convenience. + @see ImageFlags + */ + NanoImage::Handle createImageFromRGBA(uint w, uint h, const uchar* data, int imageFlags); /** Creates image from an OpenGL texture handle. */ - NanoImage* createImageFromTextureHandle(GLuint textureId, uint w, uint h, int imageFlags, bool deleteTexture = false); + NanoImage::Handle createImageFromTextureHandle(GLuint textureId, uint w, uint h, ImageFlags imageFlags, bool deleteTexture = false); - // TODO overloaded? + /** + Creates image from an OpenGL texture handle. + Overloaded function for convenience. + @see ImageFlags + */ + NanoImage::Handle createImageFromTextureHandle(GLuint textureId, uint w, uint h, int imageFlags, bool deleteTexture = false); /* -------------------------------------------------------------------- * Paints */ @@ -575,7 +622,7 @@ public: (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 fillPaint() or strokePaint(). */ - Paint imagePattern(float ox, float oy, float ex, float ey, float angle, const NanoImage* image, float alpha); + Paint imagePattern(float ox, float oy, float ex, float ey, float angle, const NanoImage& image, float alpha); /* -------------------------------------------------------------------- * Scissoring */ @@ -688,13 +735,13 @@ public: Creates font by loading it from the disk from specified file name. Returns handle to the font. */ - FontId createFont(const char* name, const char* filename); + FontId createFontFromFile(const char* name, const char* filename); /** Creates font by loading it from the specified memory chunk. Returns handle to the font. */ - FontId createFontMem(const char* name, const uchar* data, int ndata, bool freeData); + FontId createFontFromMemory(const char* name, const uchar* data, uint dataSize, bool freeData); /** Finds a loaded font of specified name, and returns handle to it, or -1 if the font is not found. @@ -767,13 +814,13 @@ public: if the bounding box of the text should be returned. The bounds value are [xmin,ymin, xmax,ymax] Measured values are returned in local coordinate space. */ - void textBoxBounds(float x, float y, float breakRowWidth, const char* string, const char* end, float* bounds); + void textBoxBounds(float x, float y, float breakRowWidth, const char* string, const char* end, float bounds[4]); /** Calculates the glyph x positions of the specified text. If end is specified only the sub-string will be used. Measured values are returned in local coordinate space. */ - int textGlyphPositions(float x, float y, const char* string, const char* end, GlyphPosition* positions, int maxPositions); + int textGlyphPositions(float x, float y, const char* string, const char* end, GlyphPosition& positions, int maxPositions); /** Returns the vertical metrics based on the current text style. @@ -786,7 +833,7 @@ public: White space is stripped at the beginning of the rows, the text is split at word boundaries or when new-line characters are encountered. Words longer than the max width are slit at nearest character (i.e. no hyphenation). */ - int textBreakLines(const char* string, const char* end, float breakRowWidth, TextRow* rows, int maxRows); + int textBreakLines(const char* string, const char* end, float breakRowWidth, TextRow& rows, int maxRows); private: NVGcontext* const fContext; @@ -811,10 +858,11 @@ class NanoWidget : public Widget, public: /** Constructor. + @see CreateFlags */ - NanoWidget(Window& parent) + NanoWidget(Window& parent, int flags = CREATE_ANTIALIAS) : Widget(parent), - NanoVG(), + NanoVG(flags), leakDetector_NanoWidget() { setNeedsScaling(true); @@ -834,12 +882,9 @@ private: */ void onDisplay() override { - //glPushAttrib(GL_PIXEL_MODE_BIT|GL_STENCIL_BUFFER_BIT|GL_ENABLE_BIT); beginFrame(getWidth(), getHeight()); onNanoDisplay(); endFrame(); - //glPopAttrib(); - glDisable(GL_CULL_FACE); } DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NanoWidget) diff --git a/dgl/src/NanoVG.cpp b/dgl/src/NanoVG.cpp index 4ea89976..695bf949 100644 --- a/dgl/src/NanoVG.cpp +++ b/dgl/src/NanoVG.cpp @@ -110,19 +110,43 @@ NanoVG::Paint::operator NVGpaint() const noexcept // ----------------------------------------------------------------------- // NanoImage -NanoImage::NanoImage(NVGcontext* const context, const int imageId) noexcept - : fContext(context), - fImageId(imageId), +NanoImage::NanoImage() + : fHandle(), fSize(), leakDetector_NanoImage() { +} + +NanoImage::NanoImage(const Handle& handle) + : fHandle(handle), + fSize(), + leakDetector_NanoImage() +{ + DISTRHO_SAFE_ASSERT_RETURN(fHandle.context != nullptr && fHandle.imageId != 0,); + _updateSize(); } NanoImage::~NanoImage() { - if (fContext != nullptr && fImageId != 0) - nvgDeleteImage(fContext, fImageId); + if (fHandle.context != nullptr && fHandle.imageId != 0) + nvgDeleteImage(fHandle.context, fHandle.imageId); +} + +NanoImage& NanoImage::operator=(const Handle& handle) +{ + if (fHandle.context != nullptr && fHandle.imageId != 0) + nvgDeleteImage(fHandle.context, fHandle.imageId); + + fHandle.context = handle.context; + fHandle.imageId = handle.imageId; + + return *this; +} + +bool NanoImage::isValid() const noexcept +{ + return (fHandle.context != nullptr && fHandle.imageId != 0); } Size NanoImage::getSize() const noexcept @@ -132,31 +156,28 @@ Size NanoImage::getSize() const noexcept GLuint NanoImage::getTextureHandle() const { - return nvglImageHandle(fContext, fImageId); + DISTRHO_SAFE_ASSERT_RETURN(fHandle.context != nullptr && fHandle.imageId != 0, 0); + + return nvglImageHandle(fHandle.context, fHandle.imageId); } void NanoImage::updateImage(const uchar* const data) { DISTRHO_SAFE_ASSERT_RETURN(data != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(fHandle.context != nullptr && fHandle.imageId != 0,); - if (fContext != nullptr && fImageId != 0) - { - nvgUpdateImage(fContext, fImageId, data); - _updateSize(); - } + nvgUpdateImage(fHandle.context, fHandle.imageId, data); + _updateSize(); } void NanoImage::_updateSize() { int w=0, h=0; - if (fContext != nullptr && fImageId != 0) - { - nvgImageSize(fContext, fImageId, &w, &h); + nvgImageSize(fHandle.context, fHandle.imageId, &w, &h); - if (w < 0) w = 0; - if (h < 0) h = 0; - } + if (w < 0) w = 0; + if (h < 0) h = 0; fSize.setSize(static_cast(w), static_cast(h)); } @@ -488,52 +509,65 @@ float NanoVG::radToDeg(float rad) // ----------------------------------------------------------------------- // Images -NanoImage* NanoVG::createImage(const char* filename, int imageFlags) +NanoImage::Handle NanoVG::createImageFromFile(const char* filename, ImageFlags imageFlags) { - if (fContext == nullptr) return nullptr; - DISTRHO_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', nullptr); + return createImageFromFile(filename, static_cast(imageFlags)); +} - if (const int imageId = nvgCreateImage(fContext, filename, imageFlags)) - return new NanoImage(fContext, imageId); +NanoImage::Handle NanoVG::createImageFromFile(const char* filename, int imageFlags) +{ + if (fContext == nullptr) return NanoImage::Handle(); + DISTRHO_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', NanoImage::Handle()); - return nullptr; + return NanoImage::Handle(fContext, nvgCreateImage(fContext, filename, imageFlags)); } -NanoImage* NanoVG::createImageMem(uchar* data, int ndata, int imageFlags) +NanoImage::Handle NanoVG::createImageFromMemory(uchar* data, uint dataSize, ImageFlags imageFlags) { - if (fContext == nullptr) return nullptr; - DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, nullptr); - DISTRHO_SAFE_ASSERT_RETURN(ndata > 0, nullptr); + return createImageFromMemory(data, dataSize, static_cast(imageFlags)); +} - if (const int imageId = nvgCreateImageMem(fContext, imageFlags, data, ndata)) - return new NanoImage(fContext, imageId); +NanoImage::Handle NanoVG::createImageFromMemory(uchar* data, uint dataSize, int imageFlags) +{ + if (fContext == nullptr) return NanoImage::Handle(); + DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, NanoImage::Handle()); + DISTRHO_SAFE_ASSERT_RETURN(dataSize > 0, NanoImage::Handle()); - return nullptr; + return NanoImage::Handle(fContext, nvgCreateImageMem(fContext, imageFlags, data,static_cast(dataSize))); } -NanoImage* NanoVG::createImageRGBA(uint w, uint h, const uchar* data, int imageFlags) +NanoImage::Handle NanoVG::createImageFromRGBA(uint w, uint h, const uchar* data, ImageFlags imageFlags) { - if (fContext == nullptr) return nullptr; - DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, nullptr); + return createImageFromRGBA(w, h, data, static_cast(imageFlags)); +} - if (const int imageId = nvgCreateImageRGBA(fContext, static_cast(w), static_cast(h), imageFlags, data)) - return new NanoImage(fContext, imageId); +NanoImage::Handle NanoVG::createImageFromRGBA(uint w, uint h, const uchar* data, int imageFlags) +{ + if (fContext == nullptr) return NanoImage::Handle(); + DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, NanoImage::Handle()); - return nullptr; + return NanoImage::Handle(fContext, nvgCreateImageRGBA(fContext, + static_cast(w), + static_cast(h), imageFlags, data)); } -NanoImage* NanoVG::createImageFromTextureHandle(GLuint textureId, uint w, uint h, int imageFlags, bool deleteTexture) +NanoImage::Handle NanoVG::createImageFromTextureHandle(GLuint textureId, uint w, uint h, ImageFlags imageFlags, bool deleteTexture) { - if (fContext == nullptr) return nullptr; - DISTRHO_SAFE_ASSERT_RETURN(textureId != 0, nullptr); + return createImageFromTextureHandle(textureId, w, h, static_cast(imageFlags), deleteTexture); +} + +NanoImage::Handle NanoVG::createImageFromTextureHandle(GLuint textureId, uint w, uint h, int imageFlags, bool deleteTexture) +{ + if (fContext == nullptr) return NanoImage::Handle(); + DISTRHO_SAFE_ASSERT_RETURN(textureId != 0, NanoImage::Handle()); if (! deleteTexture) imageFlags |= NVG_IMAGE_NODELETE; - if (const int imageId = nvglCreateImageFromHandle(fContext, textureId, static_cast(w), static_cast(h), imageFlags)) - return new NanoImage(fContext, imageId); - - return nullptr; + return NanoImage::Handle(fContext, nvglCreateImageFromHandle(fContext, + textureId, + static_cast(w), + static_cast(h), imageFlags)); } // ----------------------------------------------------------------------- @@ -557,12 +591,14 @@ NanoVG::Paint NanoVG::radialGradient(float cx, float cy, float inr, float outr, return nvgRadialGradient(fContext, cx, cy, inr, outr, icol, ocol); } -NanoVG::Paint NanoVG::imagePattern(float ox, float oy, float ex, float ey, float angle, const NanoImage* image, float alpha) +NanoVG::Paint NanoVG::imagePattern(float ox, float oy, float ex, float ey, float angle, const NanoImage& image, float alpha) { if (fContext == nullptr) return Paint(); - DISTRHO_SAFE_ASSERT_RETURN(image != nullptr, Paint()); - return nvgImagePattern(fContext, ox, oy, ex, ey, angle, image->fImageId, alpha); + const int imageId(image.fHandle.imageId); + DISTRHO_SAFE_ASSERT_RETURN(imageId != 0, Paint()); + + return nvgImagePattern(fContext, ox, oy, ex, ey, angle, imageId, alpha); } // ----------------------------------------------------------------------- @@ -682,7 +718,7 @@ void NanoVG::stroke() // ----------------------------------------------------------------------- // Text -NanoVG::FontId NanoVG::createFont(const char* name, const char* filename) +NanoVG::FontId NanoVG::createFontFromFile(const char* name, const char* filename) { if (fContext == nullptr) return -1; DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', -1); @@ -691,13 +727,13 @@ NanoVG::FontId NanoVG::createFont(const char* name, const char* filename) return nvgCreateFont(fContext, name, filename); } -NanoVG::FontId NanoVG::createFontMem(const char* name, const uchar* data, int ndata, bool freeData) +NanoVG::FontId NanoVG::createFontFromMemory(const char* name, const uchar* data, uint dataSize, bool freeData) { if (fContext == nullptr) return -1; DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', -1); DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, -1); - return nvgCreateFontMem(fContext, name, const_cast(data), ndata, freeData); + return nvgCreateFontMem(fContext, name, const_cast(data), static_cast(dataSize), freeData); } NanoVG::FontId NanoVG::findFont(const char* name) @@ -795,7 +831,7 @@ float NanoVG::textBounds(float x, float y, const char* string, const char* end, return ret; } -void NanoVG::textBoxBounds(float x, float y, float breakRowWidth, const char* string, const char* end, float* bounds) +void NanoVG::textBoxBounds(float x, float y, float breakRowWidth, const char* string, const char* end, float bounds[4]) { if (fContext == nullptr) return; DISTRHO_SAFE_ASSERT_RETURN(string != nullptr && string[0] != '\0',); @@ -803,12 +839,12 @@ void NanoVG::textBoxBounds(float x, float y, float breakRowWidth, const char* st nvgTextBoxBounds(fContext, x, y, breakRowWidth, string, end, bounds); } -int NanoVG::textGlyphPositions(float x, float y, const char* string, const char* end, NanoVG::GlyphPosition* positions, int maxPositions) +int NanoVG::textGlyphPositions(float x, float y, const char* string, const char* end, NanoVG::GlyphPosition& positions, int maxPositions) { if (fContext == nullptr) return 0; DISTRHO_SAFE_ASSERT_RETURN(string != nullptr && string[0] != '\0', 0); - return nvgTextGlyphPositions(fContext, x, y, string, end, (NVGglyphPosition*)positions, maxPositions); + return nvgTextGlyphPositions(fContext, x, y, string, end, (NVGglyphPosition*)&positions, maxPositions); } void NanoVG::textMetrics(float* ascender, float* descender, float* lineh) @@ -817,10 +853,10 @@ void NanoVG::textMetrics(float* ascender, float* descender, float* lineh) nvgTextMetrics(fContext, ascender, descender, lineh); } -int NanoVG::textBreakLines(const char* string, const char* end, float breakRowWidth, NanoVG::TextRow* rows, int maxRows) +int NanoVG::textBreakLines(const char* string, const char* end, float breakRowWidth, NanoVG::TextRow& rows, int maxRows) { if (fContext != nullptr) - return nvgTextBreakLines(fContext, string, end, breakRowWidth, (NVGtextRow*)rows, maxRows); + return nvgTextBreakLines(fContext, string, end, breakRowWidth, (NVGtextRow*)&rows, maxRows); return 0; }