DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

commit 5f2e1f37075924176acc65561793c9329373ea93
parent f0c52659b94d2bc1c4e49ca9009e434a19f4cd90
Author: falkTX <falktx@falktx.com>
Date:   Fri, 21 May 2021 20:34:35 +0100

Quick and rough conversion of Image widgets fMember to pData

Diffstat:
Mdgl/ImageBaseWidgets.hpp | 56+-------------------------------------------------------
Mdgl/src/Cairo.cpp | 42+++++++++++++++++++++++++++++++++++++++++-
Mdgl/src/Common.hpp | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdgl/src/ImageBaseWidgets.cpp | 845+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mdgl/src/OpenGL.cpp | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 627 insertions(+), 483 deletions(-)

diff --git a/dgl/ImageBaseWidgets.hpp b/dgl/ImageBaseWidgets.hpp @@ -129,36 +129,6 @@ private: struct PrivateData; PrivateData* const pData; - /* - Image fImage; - float fMinimum; - float fMaximum; - float fStep; - float fValue; - float fValueDef; - float fValueTmp; - bool fUsingDefault; - bool fUsingLog; - Orientation fOrientation; - - int fRotationAngle; - bool fDragging; - int fLastX; - int fLastY; - - Callback* fCallback; - - bool fIsImgVertical; - uint fImgLayerWidth; - uint fImgLayerHeight; - uint fImgLayerCount; - bool fIsReady; - GLuint fTextureId; - - float _logscale(float value) const; - float _invlogscale(float value) const; - */ - DISTRHO_LEAK_DETECTOR(ImageBaseKnob) }; @@ -180,6 +150,7 @@ public: }; explicit ImageBaseSlider(Widget* parentWidget, const ImageType& image) noexcept; + ~ImageBaseSlider() override; float getValue() const noexcept; void setValue(float value, bool sendCallback = false) noexcept; @@ -205,31 +176,6 @@ private: struct PrivateData; PrivateData* const pData; - /* - Image fImage; - float fMinimum; - float fMaximum; - float fStep; - float fValue; - float fValueDef; - float fValueTmp; - bool fUsingDefault; - - bool fDragging; - bool fInverted; - bool fValueIsSet; - int fStartedX; - int fStartedY; - - Callback* fCallback; - - Point<int> fStartPos; - Point<int> fEndPos; - Rectangle<double> fSliderArea; - - void _recheckArea() noexcept; - */ - // these should not be used void setAbsoluteX(int) const noexcept {} void setAbsoluteY(int) const noexcept {} diff --git a/dgl/src/Cairo.cpp b/dgl/src/Cairo.cpp @@ -18,6 +18,7 @@ #include "../Color.hpp" #include "../ImageBaseWidgets.hpp" +#include "Common.hpp" #include "SubWidgetPrivateData.hpp" #include "TopLevelWidgetPrivateData.hpp" #include "WidgetPrivateData.hpp" @@ -216,7 +217,6 @@ template class Triangle<uint>; template class Triangle<short>; template class Triangle<ushort>; - // ----------------------------------------------------------------------- // Rectangle @@ -461,17 +461,57 @@ CairoBaseWidget<StandaloneWindow>::CairoBaseWidget(Application& app, Window& par template class CairoBaseWidget<StandaloneWindow>; // ----------------------------------------------------------------------- +// ImageBaseAboutWindow +#if 0 template <> void ImageBaseAboutWindow<CairoImage>::onDisplay() { img.draw(getGraphicsContext()); } +#endif template class ImageBaseAboutWindow<CairoImage>; + +// ----------------------------------------------------------------------- +// ImageBaseButton + template class ImageBaseButton<CairoImage>; // ----------------------------------------------------------------------- +// ImageBaseKnob + +template <> +void ImageBaseKnob<CairoImage>::PrivateData::init() +{ + notImplemented("ImageBaseKnob::PrivateData::init"); +} + +template <> +void ImageBaseKnob<CairoImage>::PrivateData::cleanup() +{ + notImplemented("ImageBaseKnob::PrivateData::cleanup"); +} + +template <> +void ImageBaseKnob<CairoImage>::onDisplay() +{ + notImplemented("ImageBaseKnob::onDisplay"); +} + +template class ImageBaseKnob<CairoImage>; + +// ----------------------------------------------------------------------- +// ImageBaseSlider + +template class ImageBaseSlider<CairoImage>; + +// ----------------------------------------------------------------------- +// ImageBaseSwitch + +template class ImageBaseSwitch<CairoImage>; + +// ----------------------------------------------------------------------- void SubWidget::PrivateData::display(const uint width, const uint height, const double autoScaleFactor) { diff --git a/dgl/src/Common.hpp b/dgl/src/Common.hpp @@ -120,6 +120,64 @@ struct ButtonImpl { // ----------------------------------------------------------------------- +template <class ImageType> +struct ImageBaseKnob<ImageType>::PrivateData { + ImageType image; + float minimum; + float maximum; + float step; + float value; + float valueDef; + float valueTmp; + bool usingDefault; + bool usingLog; + Orientation orientation; + + int rotationAngle; + bool dragging; + int lastX; + int lastY; + + Callback* callback; + + bool isImgVertical; + uint imgLayerWidth; + uint imgLayerHeight; + uint imgLayerCount; + bool isReady; + /*GL*/uint textureId; + + explicit PrivateData(const ImageType& img, const Orientation o); + explicit PrivateData(PrivateData* const other); + void assignFrom(PrivateData* const other); + + ~PrivateData() + { + cleanup(); + } + + void init(); + void cleanup(); + + inline float logscale(float value) const + { + const float b = std::log(maximum/minimum)/(maximum-minimum); + const float a = maximum/std::exp(maximum*b); + return a * std::exp(b*value); + } + + inline float invlogscale(float value) const + { + const float b = std::log(maximum/minimum)/(maximum-minimum); + const float a = maximum/std::exp(maximum*b); + return std::log(value/a)/b; + } + + DISTRHO_DECLARE_NON_COPY_STRUCT(PrivateData) +}; + +// ----------------------------------------------------------------------- + END_NAMESPACE_DGL #endif // DGL_APP_PRIVATE_DATA_HPP_INCLUDED diff --git a/dgl/src/ImageBaseWidgets.cpp b/dgl/src/ImageBaseWidgets.cpp @@ -15,6 +15,7 @@ */ #include "../ImageBaseWidgets.hpp" +#include "../Color.hpp" #include "Common.hpp" START_NAMESPACE_DGL @@ -56,6 +57,12 @@ void ImageBaseAboutWindow<ImageType>::setImage(const ImageType& image) } template <class ImageType> +void ImageBaseAboutWindow<ImageType>::onDisplay() +{ + img.draw(getGraphicsContext()); +} + +template <class ImageType> bool ImageBaseAboutWindow<ImageType>::onKeyboard(const KeyboardEvent& ev) { if (ev.press && ev.key == kKeyEscape) @@ -180,291 +187,246 @@ bool ImageBaseButton<ImageType>::onMotion(const MotionEvent& ev) // -------------------------------------------------------------------------------------------------------------------- -#if 0 -ImageKnob::ImageKnob(Widget* const parentWidget, const Image& image, Orientation orientation) noexcept - : SubWidget(parentWidget), - fImage(image), - fMinimum(0.0f), - fMaximum(1.0f), - fStep(0.0f), - fValue(0.5f), - fValueDef(fValue), - fValueTmp(fValue), - fUsingDefault(false), - fUsingLog(false), - fOrientation(orientation), - fRotationAngle(0), - fDragging(false), - fLastX(0), - fLastY(0), - fCallback(nullptr), - fIsImgVertical(image.getHeight() > image.getWidth()), - fImgLayerWidth(fIsImgVertical ? image.getWidth() : image.getHeight()), - fImgLayerHeight(fImgLayerWidth), - fImgLayerCount(fIsImgVertical ? image.getHeight()/fImgLayerHeight : image.getWidth()/fImgLayerWidth), - fIsReady(false), - fTextureId(0) +template <class ImageType> +ImageBaseKnob<ImageType>::PrivateData::PrivateData(const ImageType& img, const Orientation o) + : image(img), + minimum(0.0f), + maximum(1.0f), + step(0.0f), + value(0.5f), + valueDef(value), + valueTmp(value), + usingDefault(false), + usingLog(false), + orientation(o), + rotationAngle(0), + dragging(false), + lastX(0), + lastY(0), + callback(nullptr), + isImgVertical(img.getHeight() > img.getWidth()), + imgLayerWidth(isImgVertical ? img.getWidth() : img.getHeight()), + imgLayerHeight(imgLayerWidth), + imgLayerCount(isImgVertical ? img.getHeight()/imgLayerHeight : img.getWidth()/imgLayerWidth), + isReady(false), + textureId(0) { - glGenTextures(1, &fTextureId); - setSize(fImgLayerWidth, fImgLayerHeight); + init(); } -ImageKnob::ImageKnob(const ImageKnob& imageKnob) - : SubWidget(imageKnob.getParentWidget()), - fImage(imageKnob.fImage), - fMinimum(imageKnob.fMinimum), - fMaximum(imageKnob.fMaximum), - fStep(imageKnob.fStep), - fValue(imageKnob.fValue), - fValueDef(imageKnob.fValueDef), - fValueTmp(fValue), - fUsingDefault(imageKnob.fUsingDefault), - fUsingLog(imageKnob.fUsingLog), - fOrientation(imageKnob.fOrientation), - fRotationAngle(imageKnob.fRotationAngle), - fDragging(false), - fLastX(0), - fLastY(0), - fCallback(imageKnob.fCallback), - fIsImgVertical(imageKnob.fIsImgVertical), - fImgLayerWidth(imageKnob.fImgLayerWidth), - fImgLayerHeight(imageKnob.fImgLayerHeight), - fImgLayerCount(imageKnob.fImgLayerCount), - fIsReady(false), - fTextureId(0) +template <class ImageType> +ImageBaseKnob<ImageType>::PrivateData::PrivateData(PrivateData* const other) + : image(other->image), + minimum(other->minimum), + maximum(other->maximum), + step(other->step), + value(other->value), + valueDef(other->valueDef), + valueTmp(value), + usingDefault(other->usingDefault), + usingLog(other->usingLog), + orientation(other->orientation), + rotationAngle(other->rotationAngle), + dragging(false), + lastX(0), + lastY(0), + callback(other->callback), + isImgVertical(other->isImgVertical), + imgLayerWidth(other->imgLayerWidth), + imgLayerHeight(other->imgLayerHeight), + imgLayerCount(other->imgLayerCount), + isReady(false), + textureId(0) { - glGenTextures(1, &fTextureId); - setSize(fImgLayerWidth, fImgLayerHeight); + init(); } -ImageKnob& ImageKnob::operator=(const ImageKnob& imageKnob) +template <class ImageType> +void ImageBaseKnob<ImageType>::PrivateData::assignFrom(PrivateData* const other) { - fImage = imageKnob.fImage; - fMinimum = imageKnob.fMinimum; - fMaximum = imageKnob.fMaximum; - fStep = imageKnob.fStep; - fValue = imageKnob.fValue; - fValueDef = imageKnob.fValueDef; - fValueTmp = fValue; - fUsingDefault = imageKnob.fUsingDefault; - fUsingLog = imageKnob.fUsingLog; - fOrientation = imageKnob.fOrientation; - fRotationAngle = imageKnob.fRotationAngle; - fDragging = false; - fLastX = 0; - fLastY = 0; - fCallback = imageKnob.fCallback; - fIsImgVertical = imageKnob.fIsImgVertical; - fImgLayerWidth = imageKnob.fImgLayerWidth; - fImgLayerHeight = imageKnob.fImgLayerHeight; - fImgLayerCount = imageKnob.fImgLayerCount; - fIsReady = false; - - if (fTextureId != 0) - { - glDeleteTextures(1, &fTextureId); - fTextureId = 0; - } + cleanup(); + image = other->image; + minimum = other->minimum; + maximum = other->maximum; + step = other->step; + value = other->value; + valueDef = other->valueDef; + valueTmp = value; + usingDefault = other->usingDefault; + usingLog = other->usingLog; + orientation = other->orientation; + rotationAngle = other->rotationAngle; + dragging = false; + lastX = 0; + lastY = 0; + callback = other->callback; + isImgVertical = other->isImgVertical; + imgLayerWidth = other->imgLayerWidth; + imgLayerHeight = other->imgLayerHeight; + imgLayerCount = other->imgLayerCount; + isReady = false; + init(); +} + +// -------------------------------------------------------------------------------------------------------------------- - glGenTextures(1, &fTextureId); - setSize(fImgLayerWidth, fImgLayerHeight); +template <class ImageType> +ImageBaseKnob<ImageType>::ImageBaseKnob(Widget* const parentWidget, const ImageType& image, const Orientation orientation) noexcept + : SubWidget(parentWidget), + pData(new PrivateData(image, orientation)) +{ + setSize(pData->imgLayerWidth, pData->imgLayerHeight); +} +template <class ImageType> +ImageBaseKnob<ImageType>::ImageBaseKnob(const ImageBaseKnob<ImageType>& imageKnob) + : SubWidget(imageKnob.getParentWidget()), + pData(new PrivateData(imageKnob.pData)) +{ + setSize(pData->imgLayerWidth, pData->imgLayerHeight); +} + +template <class ImageType> +ImageBaseKnob<ImageType>& ImageBaseKnob<ImageType>::operator=(const ImageBaseKnob<ImageType>& imageKnob) +{ + pData->assignFrom(imageKnob.pData); + setSize(pData->imgLayerWidth, pData->imgLayerHeight); return *this; } -ImageKnob::~ImageKnob() +template <class ImageType> +ImageBaseKnob<ImageType>::~ImageBaseKnob() { - if (fTextureId != 0) - { - glDeleteTextures(1, &fTextureId); - fTextureId = 0; - } + delete pData; } -float ImageKnob::getValue() const noexcept +template <class ImageType> +float ImageBaseKnob<ImageType>::getValue() const noexcept { - return fValue; + return pData->value; } // NOTE: value is assumed to be scaled if using log -void ImageKnob::setDefault(float value) noexcept +template <class ImageType> +void ImageBaseKnob<ImageType>::setDefault(float value) noexcept { - fValueDef = value; - fUsingDefault = true; + pData->valueDef = value; + pData->usingDefault = true; } -void ImageKnob::setRange(float min, float max) noexcept +template <class ImageType> +void ImageBaseKnob<ImageType>::setRange(float min, float max) noexcept { DISTRHO_SAFE_ASSERT_RETURN(max > min,); - if (fValue < min) + if (pData->value < min) { - fValue = min; + pData->value = min; repaint(); - if (fCallback != nullptr) + if (pData->callback != nullptr) { try { - fCallback->imageKnobValueChanged(this, fValue); - } DISTRHO_SAFE_EXCEPTION("ImageKnob::setRange < min"); + pData->callback->imageKnobValueChanged(this, pData->value); + } DISTRHO_SAFE_EXCEPTION("ImageBaseKnob<ImageType>::setRange < min"); } } - else if (fValue > max) + else if (pData->value > max) { - fValue = max; + pData->value = max; repaint(); - if (fCallback != nullptr) + if (pData->callback != nullptr) { try { - fCallback->imageKnobValueChanged(this, fValue); - } DISTRHO_SAFE_EXCEPTION("ImageKnob::setRange > max"); + pData->callback->imageKnobValueChanged(this, pData->value); + } DISTRHO_SAFE_EXCEPTION("ImageBaseKnob<ImageType>::setRange > max"); } } - fMinimum = min; - fMaximum = max; + pData->minimum = min; + pData->maximum = max; } -void ImageKnob::setStep(float step) noexcept +template <class ImageType> +void ImageBaseKnob<ImageType>::setStep(float step) noexcept { - fStep = step; + pData->step = step; } // NOTE: value is assumed to be scaled if using log -void ImageKnob::setValue(float value, bool sendCallback) noexcept +template <class ImageType> +void ImageBaseKnob<ImageType>::setValue(float value, bool sendCallback) noexcept { - if (d_isEqual(fValue, value)) + if (d_isEqual(pData->value, value)) return; - fValue = value; + pData->value = value; - if (d_isZero(fStep)) - fValueTmp = value; + if (d_isZero(pData->step)) + pData->valueTmp = value; - if (fRotationAngle == 0) - fIsReady = false; + if (pData->rotationAngle == 0) + pData->isReady = false; repaint(); - if (sendCallback && fCallback != nullptr) + if (sendCallback && pData->callback != nullptr) { try { - fCallback->imageKnobValueChanged(this, fValue); - } DISTRHO_SAFE_EXCEPTION("ImageKnob::setValue"); + pData->callback->imageKnobValueChanged(this, pData->value); + } DISTRHO_SAFE_EXCEPTION("ImageBaseKnob<ImageType>::setValue"); } } -void ImageKnob::setUsingLogScale(bool yesNo) noexcept +template <class ImageType> +void ImageBaseKnob<ImageType>::setUsingLogScale(bool yesNo) noexcept { - fUsingLog = yesNo; + pData->usingLog = yesNo; } -void ImageKnob::setCallback(Callback* callback) noexcept +template <class ImageType> +void ImageBaseKnob<ImageType>::setCallback(Callback* callback) noexcept { - fCallback = callback; + pData->callback = callback; } -void ImageKnob::setOrientation(Orientation orientation) noexcept +template <class ImageType> +void ImageBaseKnob<ImageType>::setOrientation(Orientation orientation) noexcept { - if (fOrientation == orientation) + if (pData->orientation == orientation) return; - fOrientation = orientation; + pData->orientation = orientation; } -void ImageKnob::setRotationAngle(int angle) +template <class ImageType> +void ImageBaseKnob<ImageType>::setRotationAngle(int angle) { - if (fRotationAngle == angle) + if (pData->rotationAngle == angle) return; - fRotationAngle = angle; - fIsReady = false; + pData->rotationAngle = angle; + pData->isReady = false; } -void ImageKnob::setImageLayerCount(uint count) noexcept +template <class ImageType> +void ImageBaseKnob<ImageType>::setImageLayerCount(uint count) noexcept { DISTRHO_SAFE_ASSERT_RETURN(count > 1,); - fImgLayerCount = count; + pData->imgLayerCount = count; - if (fIsImgVertical) - fImgLayerHeight = fImage.getHeight()/count; + if (pData->isImgVertical) + pData->imgLayerHeight = pData->image.getHeight()/count; else - fImgLayerWidth = fImage.getWidth()/count; - - setSize(fImgLayerWidth, fImgLayerHeight); -} - -void ImageKnob::onDisplay() -{ - const float normValue = ((fUsingLog ? _invlogscale(fValue) : fValue) - fMinimum) / (fMaximum - fMinimum); - - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, fTextureId); - - if (! fIsReady) - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - - static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f }; - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans); - - glPixelStorei(GL_PACK_ALIGNMENT, 1); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - uint imageDataOffset = 0; - - if (fRotationAngle == 0) - { - DISTRHO_SAFE_ASSERT_RETURN(fImgLayerCount > 0,); - DISTRHO_SAFE_ASSERT_RETURN(normValue >= 0.0f,); - - const uint& v1(fIsImgVertical ? fImgLayerWidth : fImgLayerHeight); - const uint& v2(fIsImgVertical ? fImgLayerHeight : fImgLayerWidth); - - const uint layerDataSize = v1 * v2 * ((fImage.getFormat() == kImageFormatBGRA || - fImage.getFormat() == kImageFormatRGBA) ? 4 : 3); - /* */ imageDataOffset = layerDataSize * uint(normValue * float(fImgLayerCount-1)); - } - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, - static_cast<GLsizei>(getWidth()), static_cast<GLsizei>(getHeight()), 0, - asOpenGLImageFormat(fImage.getFormat()), GL_UNSIGNED_BYTE, fImage.getRawData() + imageDataOffset); - - fIsReady = true; - } - - const int w = static_cast<int>(getWidth()); - const int h = static_cast<int>(getHeight()); - - if (fRotationAngle != 0) - { - glPushMatrix(); - - const int w2 = w/2; - const int h2 = h/2; - - glTranslatef(static_cast<float>(w2), static_cast<float>(h2), 0.0f); - glRotatef(normValue*static_cast<float>(fRotationAngle), 0.0f, 0.0f, 1.0f); - - Rectangle<int>(-w2, -h2, w, h).draw(); - - glPopMatrix(); - } - else - { - Rectangle<int>(0, 0, w, h).draw(); - } + pData->imgLayerWidth = pData->image.getWidth()/count; - glBindTexture(GL_TEXTURE_2D, 0); - glDisable(GL_TEXTURE_2D); + setSize(pData->imgLayerWidth, pData->imgLayerHeight); } -bool ImageKnob::onMouse(const MouseEvent& ev) +template <class ImageType> +bool ImageBaseKnob<ImageType>::onMouse(const MouseEvent& ev) { if (ev.button != 1) return false; @@ -474,57 +436,58 @@ bool ImageKnob::onMouse(const MouseEvent& ev) if (! contains(ev.pos)) return false; - if ((ev.mod & kModifierShift) != 0 && fUsingDefault) + if ((ev.mod & kModifierShift) != 0 && pData->usingDefault) { - setValue(fValueDef, true); - fValueTmp = fValue; + setValue(pData->valueDef, true); + pData->valueTmp = pData->value; return true; } - fDragging = true; - fLastX = ev.pos.getX(); - fLastY = ev.pos.getY(); + pData->dragging = true; + pData->lastX = ev.pos.getX(); + pData->lastY = ev.pos.getY(); - if (fCallback != nullptr) - fCallback->imageKnobDragStarted(this); + if (pData->callback != nullptr) + pData->callback->imageKnobDragStarted(this); return true; } - else if (fDragging) + else if (pData->dragging) { - if (fCallback != nullptr) - fCallback->imageKnobDragFinished(this); + if (pData->callback != nullptr) + pData->callback->imageKnobDragFinished(this); - fDragging = false; + pData->dragging = false; return true; } return false; } -bool ImageKnob::onMotion(const MotionEvent& ev) +template <class ImageType> +bool ImageBaseKnob<ImageType>::onMotion(const MotionEvent& ev) { - if (! fDragging) + if (! pData->dragging) return false; bool doVal = false; float d, value = 0.0f; - if (fOrientation == ImageKnob::Horizontal) + if (pData->orientation == ImageBaseKnob<ImageType>::Horizontal) { - if (const int movX = ev.pos.getX() - fLastX) + if (const int movX = ev.pos.getX() - pData->lastX) { d = (ev.mod & kModifierControl) ? 2000.0f : 200.0f; - value = (fUsingLog ? _invlogscale(fValueTmp) : fValueTmp) + (float(fMaximum - fMinimum) / d * float(movX)); + value = (pData->usingLog ? pData->invlogscale(pData->valueTmp) : pData->valueTmp) + (float(pData->maximum - pData->minimum) / d * float(movX)); doVal = true; } } - else if (fOrientation == ImageKnob::Vertical) + else if (pData->orientation == ImageBaseKnob<ImageType>::Vertical) { - if (const int movY = fLastY - ev.pos.getY()) + if (const int movY = pData->lastY - ev.pos.getY()) { d = (ev.mod & kModifierControl) ? 2000.0f : 200.0f; - value = (fUsingLog ? _invlogscale(fValueTmp) : fValueTmp) + (float(fMaximum - fMinimum) / d * float(movY)); + value = (pData->usingLog ? pData->invlogscale(pData->valueTmp) : pData->valueTmp) + (float(pData->maximum - pData->minimum) / d * float(movY)); doVal = true; } } @@ -532,265 +495,320 @@ bool ImageKnob::onMotion(const MotionEvent& ev) if (! doVal) return false; - if (fUsingLog) - value = _logscale(value); + if (pData->usingLog) + value = pData->logscale(value); - if (value < fMinimum) + if (value < pData->minimum) { - fValueTmp = value = fMinimum; + pData->valueTmp = value = pData->minimum; } - else if (value > fMaximum) + else if (value > pData->maximum) { - fValueTmp = value = fMaximum; + pData->valueTmp = value = pData->maximum; } - else if (d_isNotZero(fStep)) + else if (d_isNotZero(pData->step)) { - fValueTmp = value; - const float rest = std::fmod(value, fStep); - value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f); + pData->valueTmp = value; + const float rest = std::fmod(value, pData->step); + value = value - rest + (rest > pData->step/2.0f ? pData->step : 0.0f); } setValue(value, true); - fLastX = ev.pos.getX(); - fLastY = ev.pos.getY(); + pData->lastX = ev.pos.getX(); + pData->lastY = ev.pos.getY(); return true; } -bool ImageKnob::onScroll(const ScrollEvent& ev) +template <class ImageType> +bool ImageBaseKnob<ImageType>::onScroll(const ScrollEvent& ev) { if (! contains(ev.pos)) return false; const float d = (ev.mod & kModifierControl) ? 2000.0f : 200.0f; - float value = (fUsingLog ? _invlogscale(fValueTmp) : fValueTmp) + (float(fMaximum - fMinimum) / d * 10.f * ev.delta.getY()); + float value = (pData->usingLog ? pData->invlogscale(pData->valueTmp) : pData->valueTmp) + (float(pData->maximum - pData->minimum) / d * 10.f * ev.delta.getY()); - if (fUsingLog) - value = _logscale(value); + if (pData->usingLog) + value = pData->logscale(value); - if (value < fMinimum) + if (value < pData->minimum) { - fValueTmp = value = fMinimum; + pData->valueTmp = value = pData->minimum; } - else if (value > fMaximum) + else if (value > pData->maximum) { - fValueTmp = value = fMaximum; + pData->valueTmp = value = pData->maximum; } - else if (d_isNotZero(fStep)) + else if (d_isNotZero(pData->step)) { - fValueTmp = value; - const float rest = std::fmod(value, fStep); - value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f); + pData->valueTmp = value; + const float rest = std::fmod(value, pData->step); + value = value - rest + (rest > pData->step/2.0f ? pData->step : 0.0f); } setValue(value, true); return true; } -// ----------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- -float ImageKnob::_logscale(float value) const -{ - const float b = std::log(fMaximum/fMinimum)/(fMaximum-fMinimum); - const float a = fMaximum/std::exp(fMaximum*b); - return a * std::exp(b*value); -} +template <class ImageType> +struct ImageBaseSlider<ImageType>::PrivateData { + ImageType image; + float minimum; + float maximum; + float step; + float value; + float valueDef; + float valueTmp; + bool usingDefault; + + bool dragging; + bool inverted; + bool valueIsSet; + int startedX; + int startedY; -float ImageKnob::_invlogscale(float value) const -{ - const float b = std::log(fMaximum/fMinimum)/(fMaximum-fMinimum); - const float a = fMaximum/std::exp(fMaximum*b); - return std::log(value/a)/b; -} -#endif + Callback* callback; + + Point<int> startPos; + Point<int> endPos; + Rectangle<double> sliderArea; + + PrivateData(const ImageType& img) + : image(img), + minimum(0.0f), + maximum(1.0f), + step(0.0f), + value(0.5f), + valueDef(value), + valueTmp(value), + usingDefault(false), + dragging(false), + inverted(false), + valueIsSet(false), + startedX(0), + startedY(0), + callback(nullptr), + startPos(), + endPos(), + sliderArea() {} + + void recheckArea() noexcept + { + if (startPos.getY() == endPos.getY()) + { + // horizontal + sliderArea = Rectangle<double>(startPos.getX(), + startPos.getY(), + endPos.getX() + static_cast<int>(image.getWidth()) - startPos.getX(), + static_cast<int>(image.getHeight())); + } + else + { + // vertical + sliderArea = Rectangle<double>(startPos.getX(), + startPos.getY(), + static_cast<int>(image.getWidth()), + endPos.getY() + static_cast<int>(image.getHeight()) - startPos.getY()); + } + } + + DISTRHO_DECLARE_NON_COPY_STRUCT(PrivateData) +}; // -------------------------------------------------------------------------------------------------------------------- -#if 0 -ImageSlider::ImageSlider(Widget* const parentWidget, const Image& image) noexcept +template <class ImageType> +ImageBaseSlider<ImageType>::ImageBaseSlider(Widget* const parentWidget, const ImageType& image) noexcept : SubWidget(parentWidget), - fImage(image), - fMinimum(0.0f), - fMaximum(1.0f), - fStep(0.0f), - fValue(0.5f), - fValueDef(fValue), - fValueTmp(fValue), - fUsingDefault(false), - fDragging(false), - fInverted(false), - fValueIsSet(false), - fStartedX(0), - fStartedY(0), - fCallback(nullptr), - fStartPos(), - fEndPos(), - fSliderArea() + pData(new PrivateData(image)) { setNeedsFullViewportDrawing(); } -float ImageSlider::getValue() const noexcept +template <class ImageType> +ImageBaseSlider<ImageType>::~ImageBaseSlider() +{ + delete pData; +} + +template <class ImageType> +float ImageBaseSlider<ImageType>::getValue() const noexcept { - return fValue; + return pData->value; } -void ImageSlider::setValue(float value, bool sendCallback) noexcept +template <class ImageType> +void ImageBaseSlider<ImageType>::setValue(float value, bool sendCallback) noexcept { - if (! fValueIsSet) - fValueIsSet = true; + if (! pData->valueIsSet) + pData->valueIsSet = true; - if (d_isEqual(fValue, value)) + if (d_isEqual(pData->value, value)) return; - fValue = value; + pData->value = value; - if (d_isZero(fStep)) - fValueTmp = value; + if (d_isZero(pData->step)) + pData->valueTmp = value; repaint(); - if (sendCallback && fCallback != nullptr) + if (sendCallback && pData->callback != nullptr) { try { - fCallback->imageSliderValueChanged(this, fValue); - } DISTRHO_SAFE_EXCEPTION("ImageSlider::setValue"); + pData->callback->imageSliderValueChanged(this, pData->value); + } DISTRHO_SAFE_EXCEPTION("ImageBaseSlider::setValue"); } } -void ImageSlider::setStartPos(const Point<int>& startPos) noexcept +template <class ImageType> +void ImageBaseSlider<ImageType>::setStartPos(const Point<int>& startPos) noexcept { - fStartPos = startPos; - _recheckArea(); + pData->startPos = startPos; + pData->recheckArea(); } -void ImageSlider::setStartPos(int x, int y) noexcept +template <class ImageType> +void ImageBaseSlider<ImageType>::setStartPos(int x, int y) noexcept { setStartPos(Point<int>(x, y)); } -void ImageSlider::setEndPos(const Point<int>& endPos) noexcept +template <class ImageType> +void ImageBaseSlider<ImageType>::setEndPos(const Point<int>& endPos) noexcept { - fEndPos = endPos; - _recheckArea(); + pData->endPos = endPos; + pData->recheckArea(); } -void ImageSlider::setEndPos(int x, int y) noexcept +template <class ImageType> +void ImageBaseSlider<ImageType>::setEndPos(int x, int y) noexcept { setEndPos(Point<int>(x, y)); } -void ImageSlider::setInverted(bool inverted) noexcept +template <class ImageType> +void ImageBaseSlider<ImageType>::setInverted(bool inverted) noexcept { - if (fInverted == inverted) + if (pData->inverted == inverted) return; - fInverted = inverted; + pData->inverted = inverted; repaint(); } -void ImageSlider::setDefault(float value) noexcept +template <class ImageType> +void ImageBaseSlider<ImageType>::setDefault(float value) noexcept { - fValueDef = value; - fUsingDefault = true; + pData->valueDef = value; + pData->usingDefault = true; } -void ImageSlider::setRange(float min, float max) noexcept +template <class ImageType> +void ImageBaseSlider<ImageType>::setRange(float min, float max) noexcept { - fMinimum = min; - fMaximum = max; + pData->minimum = min; + pData->maximum = max; - if (fValue < min) + if (pData->value < min) { - fValue = min; + pData->value = min; repaint(); - if (fCallback != nullptr && fValueIsSet) + if (pData->callback != nullptr && pData->valueIsSet) { try { - fCallback->imageSliderValueChanged(this, fValue); - } DISTRHO_SAFE_EXCEPTION("ImageSlider::setRange < min"); + pData->callback->imageSliderValueChanged(this, pData->value); + } DISTRHO_SAFE_EXCEPTION("ImageBaseSlider::setRange < min"); } } - else if (fValue > max) + else if (pData->value > max) { - fValue = max; + pData->value = max; repaint(); - if (fCallback != nullptr && fValueIsSet) + if (pData->callback != nullptr && pData->valueIsSet) { try { - fCallback->imageSliderValueChanged(this, fValue); - } DISTRHO_SAFE_EXCEPTION("ImageSlider::setRange > max"); + pData->callback->imageSliderValueChanged(this, pData->value); + } DISTRHO_SAFE_EXCEPTION("ImageBaseSlider::setRange > max"); } } } -void ImageSlider::setStep(float step) noexcept +template <class ImageType> +void ImageBaseSlider<ImageType>::setStep(float step) noexcept { - fStep = step; + pData->step = step; } -void ImageSlider::setCallback(Callback* callback) noexcept +template <class ImageType> +void ImageBaseSlider<ImageType>::setCallback(Callback* callback) noexcept { - fCallback = callback; + pData->callback = callback; } -void ImageSlider::onDisplay() +template <class ImageType> +void ImageBaseSlider<ImageType>::onDisplay() { -#if 0 // DEBUG, paints slider area - glColor3f(0.4f, 0.5f, 0.1f); - glRecti(fSliderArea.getX(), fSliderArea.getY(), fSliderArea.getX()+fSliderArea.getWidth(), fSliderArea.getY()+fSliderArea.getHeight()); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + const GraphicsContext& context(getGraphicsContext()); + +#if 1 // DEBUG, paints slider area + Color(0.4f, 0.5f, 0.1f).setFor(context); + Rectangle<int>(pData->sliderArea.getX(), + pData->sliderArea.getY(), + pData->sliderArea.getX()+pData->sliderArea.getWidth(), + pData->sliderArea.getY()+pData->sliderArea.getHeight()).draw(context); + Color(1.0f, 1.0f, 1.0f, 1.0f).setFor(context, true); #endif - const float normValue = (fValue - fMinimum) / (fMaximum - fMinimum); + const float normValue = (pData->value - pData->minimum) / (pData->maximum - pData->minimum); int x, y; - if (fStartPos.getY() == fEndPos.getY()) + if (pData->startPos.getY() == pData->endPos.getY()) { // horizontal - if (fInverted) - x = fEndPos.getX() - static_cast<int>(normValue*static_cast<float>(fEndPos.getX()-fStartPos.getX())); + if (pData->inverted) + x = pData->endPos.getX() - static_cast<int>(normValue*static_cast<float>(pData->endPos.getX()-pData->startPos.getX())); else - x = fStartPos.getX() + static_cast<int>(normValue*static_cast<float>(fEndPos.getX()-fStartPos.getX())); + x = pData->startPos.getX() + static_cast<int>(normValue*static_cast<float>(pData->endPos.getX()-pData->startPos.getX())); - y = fStartPos.getY(); + y = pData->startPos.getY(); } else { // vertical - x = fStartPos.getX(); + x = pData->startPos.getX(); - if (fInverted) - y = fEndPos.getY() - static_cast<int>(normValue*static_cast<float>(fEndPos.getY()-fStartPos.getY())); + if (pData->inverted) + y = pData->endPos.getY() - static_cast<int>(normValue*static_cast<float>(pData->endPos.getY()-pData->startPos.getY())); else - y = fStartPos.getY() + static_cast<int>(normValue*static_cast<float>(fEndPos.getY()-fStartPos.getY())); + y = pData->startPos.getY() + static_cast<int>(normValue*static_cast<float>(pData->endPos.getY()-pData->startPos.getY())); } - fImage.drawAt(x, y); + pData->image.drawAt(context, x, y); } -#endif -// -------------------------------------------------------------------------------------------------------------------- - -#if 0 -bool ImageSlider::onMouse(const MouseEvent& ev) +template <class ImageType> +bool ImageBaseSlider<ImageType>::onMouse(const MouseEvent& ev) { if (ev.button != 1) return false; if (ev.press) { - if (! fSliderArea.contains(ev.pos)) + if (! pData->sliderArea.contains(ev.pos)) return false; - if ((ev.mod & kModifierShift) != 0 && fUsingDefault) + if ((ev.mod & kModifierShift) != 0 && pData->usingDefault) { - setValue(fValueDef, true); - fValueTmp = fValue; + setValue(pData->valueDef, true); + pData->valueTmp = pData->value; return true; } @@ -798,166 +816,140 @@ bool ImageSlider::onMouse(const MouseEvent& ev) const int x = ev.pos.getX(); const int y = ev.pos.getY(); - if (fStartPos.getY() == fEndPos.getY()) + if (pData->startPos.getY() == pData->endPos.getY()) { // horizontal - vper = float(x - fSliderArea.getX()) / float(fSliderArea.getWidth()); + vper = float(x - pData->sliderArea.getX()) / float(pData->sliderArea.getWidth()); } else { // vertical - vper = float(y - fSliderArea.getY()) / float(fSliderArea.getHeight()); + vper = float(y - pData->sliderArea.getY()) / float(pData->sliderArea.getHeight()); } float value; - if (fInverted) - value = fMaximum - vper * (fMaximum - fMinimum); + if (pData->inverted) + value = pData->maximum - vper * (pData->maximum - pData->minimum); else - value = fMinimum + vper * (fMaximum - fMinimum); + value = pData->minimum + vper * (pData->maximum - pData->minimum); - if (value < fMinimum) + if (value < pData->minimum) { - fValueTmp = value = fMinimum; + pData->valueTmp = value = pData->minimum; } - else if (value > fMaximum) + else if (value > pData->maximum) { - fValueTmp = value = fMaximum; + pData->valueTmp = value = pData->maximum; } - else if (d_isNotZero(fStep)) + else if (d_isNotZero(pData->step)) { - fValueTmp = value; - const float rest = std::fmod(value, fStep); - value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f); + pData->valueTmp = value; + const float rest = std::fmod(value, pData->step); + value = value - rest + (rest > pData->step/2.0f ? pData->step : 0.0f); } - fDragging = true; - fStartedX = x; - fStartedY = y; + pData->dragging = true; + pData->startedX = x; + pData->startedY = y; - if (fCallback != nullptr) - fCallback->imageSliderDragStarted(this); + if (pData->callback != nullptr) + pData->callback->imageSliderDragStarted(this); setValue(value, true); return true; } - else if (fDragging) + else if (pData->dragging) { - if (fCallback != nullptr) - fCallback->imageSliderDragFinished(this); + if (pData->callback != nullptr) + pData->callback->imageSliderDragFinished(this); - fDragging = false; + pData->dragging = false; return true; } return false; } -#endif -// -------------------------------------------------------------------------------------------------------------------- - -#if 0 -bool ImageSlider::onMotion(const MotionEvent& ev) +template <class ImageType> +bool ImageBaseSlider<ImageType>::onMotion(const MotionEvent& ev) { - if (! fDragging) + if (! pData->dragging) return false; - const bool horizontal = fStartPos.getY() == fEndPos.getY(); + const bool horizontal = pData->startPos.getY() == pData->endPos.getY(); const int x = ev.pos.getX(); const int y = ev.pos.getY(); - if ((horizontal && fSliderArea.containsX(x)) || (fSliderArea.containsY(y) && ! horizontal)) + if ((horizontal && pData->sliderArea.containsX(x)) || (pData->sliderArea.containsY(y) && ! horizontal)) { float vper; if (horizontal) { // horizontal - vper = float(x - fSliderArea.getX()) / float(fSliderArea.getWidth()); + vper = float(x - pData->sliderArea.getX()) / float(pData->sliderArea.getWidth()); } else { // vertical - vper = float(y - fSliderArea.getY()) / float(fSliderArea.getHeight()); + vper = float(y - pData->sliderArea.getY()) / float(pData->sliderArea.getHeight()); } float value; - if (fInverted) - value = fMaximum - vper * (fMaximum - fMinimum); + if (pData->inverted) + value = pData->maximum - vper * (pData->maximum - pData->minimum); else - value = fMinimum + vper * (fMaximum - fMinimum); + value = pData->minimum + vper * (pData->maximum - pData->minimum); - if (value < fMinimum) + if (value < pData->minimum) { - fValueTmp = value = fMinimum; + pData->valueTmp = value = pData->minimum; } - else if (value > fMaximum) + else if (value > pData->maximum) { - fValueTmp = value = fMaximum; + pData->valueTmp = value = pData->maximum; } - else if (d_isNotZero(fStep)) + else if (d_isNotZero(pData->step)) { - fValueTmp = value; - const float rest = std::fmod(value, fStep); - value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f); + pData->valueTmp = value; + const float rest = std::fmod(value, pData->step); + value = value - rest + (rest > pData->step/2.0f ? pData->step : 0.0f); } setValue(value, true); } else if (horizontal) { - if (x < fSliderArea.getX()) - setValue(fInverted ? fMaximum : fMinimum, true); + if (x < pData->sliderArea.getX()) + setValue(pData->inverted ? pData->maximum : pData->minimum, true); else - setValue(fInverted ? fMinimum : fMaximum, true); + setValue(pData->inverted ? pData->minimum : pData->maximum, true); } else { - if (y < fSliderArea.getY()) - setValue(fInverted ? fMaximum : fMinimum, true); + if (y < pData->sliderArea.getY()) + setValue(pData->inverted ? pData->maximum : pData->minimum, true); else - setValue(fInverted ? fMinimum : fMaximum, true); + setValue(pData->inverted ? pData->minimum : pData->maximum, true); } return true; } -void ImageSlider::_recheckArea() noexcept -{ - if (fStartPos.getY() == fEndPos.getY()) - { - // horizontal - fSliderArea = Rectangle<double>(fStartPos.getX(), - fStartPos.getY(), - fEndPos.getX() + static_cast<int>(fImage.getWidth()) - fStartPos.getX(), - static_cast<int>(fImage.getHeight())); - } - else - { - // vertical - fSliderArea = Rectangle<double>(fStartPos.getX(), - fStartPos.getY(), - static_cast<int>(fImage.getWidth()), - fEndPos.getY() + static_cast<int>(fImage.getHeight()) - fStartPos.getY()); - } -} -#endif - // -------------------------------------------------------------------------------------------------------------------- template <class ImageType> struct ImageBaseSwitch<ImageType>::PrivateData { - ImageBaseSwitch<ImageType>* const self; ImageType imageNormal; ImageType imageDown; bool isDown; Callback* callback; - PrivateData(ImageBaseSwitch<ImageType>* const s, const ImageType& normal, const ImageType& down) - : self(s), - imageNormal(normal), + PrivateData(const ImageType& normal, const ImageType& down) + : imageNormal(normal), imageDown(down), isDown(false), callback(nullptr) @@ -965,9 +957,8 @@ struct ImageBaseSwitch<ImageType>::PrivateData { DISTRHO_SAFE_ASSERT(imageNormal.getSize() == imageDown.getSize()); } - PrivateData(ImageBaseSwitch<ImageType>* const s, PrivateData* const other) - : self(s), - imageNormal(other->imageNormal), + PrivateData(PrivateData* const other) + : imageNormal(other->imageNormal), imageDown(other->imageDown), isDown(other->isDown), callback(other->callback) @@ -992,7 +983,7 @@ struct ImageBaseSwitch<ImageType>::PrivateData { template <class ImageType> ImageBaseSwitch<ImageType>::ImageBaseSwitch(Widget* const parentWidget, const ImageType& imageNormal, const ImageType& imageDown) noexcept : SubWidget(parentWidget), - pData(new PrivateData(this, imageNormal, imageDown)) + pData(new PrivateData(imageNormal, imageDown)) { setSize(imageNormal.getSize()); } @@ -1000,7 +991,7 @@ ImageBaseSwitch<ImageType>::ImageBaseSwitch(Widget* const parentWidget, const Im template <class ImageType> ImageBaseSwitch<ImageType>::ImageBaseSwitch(const ImageBaseSwitch<ImageType>& imageSwitch) noexcept : SubWidget(imageSwitch.getParentWidget()), - pData(new PrivateData(this, imageSwitch.pData)) + pData(new PrivateData(imageSwitch.pData)) { setSize(pData->imageNormal.getSize()); } diff --git a/dgl/src/OpenGL.cpp b/dgl/src/OpenGL.cpp @@ -18,6 +18,7 @@ #include "../Color.hpp" #include "../ImageWidgets.hpp" +#include "Common.hpp" #include "SubWidgetPrivateData.hpp" #include "TopLevelWidgetPrivateData.hpp" #include "WidgetPrivateData.hpp" @@ -435,18 +436,126 @@ void OpenGLImage::drawAt(const Point<int>& pos) } // ----------------------------------------------------------------------- +// ImageBaseAboutWindow +#if 0 template <> void ImageBaseAboutWindow<OpenGLImage>::onDisplay() { const GraphicsContext& context(getGraphicsContext()); img.draw(context); } +#endif template class ImageBaseAboutWindow<OpenGLImage>; + +// ----------------------------------------------------------------------- +// ImageBaseButton + template class ImageBaseButton<OpenGLImage>; // ----------------------------------------------------------------------- +// ImageBaseKnob + +template <> +void ImageBaseKnob<OpenGLImage>::PrivateData::init() +{ + glGenTextures(1, &textureId); +} + +template <> +void ImageBaseKnob<OpenGLImage>::PrivateData::cleanup() +{ + if (textureId != 0) + { + glDeleteTextures(1, &textureId); + textureId = 0; + } +} + +template <> +void ImageBaseKnob<OpenGLImage>::onDisplay() +{ + const GraphicsContext& context(getGraphicsContext()); + const float normValue = ((pData->usingLog ? pData->invlogscale(pData->value) : pData->value) - pData->minimum) / (pData->maximum - pData->minimum); + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, pData->textureId); + + if (! pData->isReady) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + + static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans); + + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + uint imageDataOffset = 0; + + if (pData->rotationAngle == 0) + { + DISTRHO_SAFE_ASSERT_RETURN(pData->imgLayerCount > 0,); + DISTRHO_SAFE_ASSERT_RETURN(normValue >= 0.0f,); + + const uint& v1(pData->isImgVertical ? pData->imgLayerWidth : pData->imgLayerHeight); + const uint& v2(pData->isImgVertical ? pData->imgLayerHeight : pData->imgLayerWidth); + + const uint layerDataSize = v1 * v2 * ((pData->image.getFormat() == kImageFormatBGRA || + pData->image.getFormat() == kImageFormatRGBA) ? 4 : 3); + /* */ imageDataOffset = layerDataSize * uint(normValue * float(pData->imgLayerCount-1)); + } + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, + static_cast<GLsizei>(getWidth()), static_cast<GLsizei>(getHeight()), 0, + asOpenGLImageFormat(pData->image.getFormat()), GL_UNSIGNED_BYTE, pData->image.getRawData() + imageDataOffset); + + pData->isReady = true; + } + + const int w = static_cast<int>(getWidth()); + const int h = static_cast<int>(getHeight()); + + if (pData->rotationAngle != 0) + { + glPushMatrix(); + + const int w2 = w/2; + const int h2 = h/2; + + glTranslatef(static_cast<float>(w2), static_cast<float>(h2), 0.0f); + glRotatef(normValue*static_cast<float>(pData->rotationAngle), 0.0f, 0.0f, 1.0f); + + Rectangle<int>(-w2, -h2, w, h).draw(context); + + glPopMatrix(); + } + else + { + Rectangle<int>(0, 0, w, h).draw(context); + } + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); +} + +template class ImageBaseKnob<OpenGLImage>; + +// ----------------------------------------------------------------------- +// ImageBaseSlider + +template class ImageBaseSlider<OpenGLImage>; + +// ----------------------------------------------------------------------- +// ImageBaseSwitch + +template class ImageBaseSwitch<OpenGLImage>; + +// ----------------------------------------------------------------------- void SubWidget::PrivateData::display(const uint width, const uint height, const double autoScaleFactor) {