| @@ -31,9 +31,9 @@ namespace DistrhoArtworkNekobi | |||
| const unsigned int claw2Height = 32; | |||
| extern const char* knobData; | |||
| const unsigned int knobDataSize = 390000; | |||
| const unsigned int knobDataSize = 10000; | |||
| const unsigned int knobWidth = 50; | |||
| const unsigned int knobHeight = 1950; | |||
| const unsigned int knobHeight = 50; | |||
| extern const char* run1Data; | |||
| const unsigned int run1DataSize = 4096; | |||
| @@ -41,10 +41,11 @@ DistrhoUINekobi::DistrhoUINekobi() | |||
| Image sliderImage(DistrhoArtworkNekobi::sliderData, DistrhoArtworkNekobi::sliderWidth, DistrhoArtworkNekobi::sliderHeight); | |||
| fSliderWaveform = new ImageSlider(this, sliderImage); | |||
| fSliderWaveform->setStartPos(133, 38); | |||
| fSliderWaveform->setEndPos(133, 64); | |||
| fSliderWaveform->setStartPos(133, 40); | |||
| fSliderWaveform->setEndPos(133, 60); | |||
| fSliderWaveform->setRange(0.0f, 1.0f); | |||
| fSliderWaveform->setValue(0.0f); | |||
| fSliderWaveform->setIsSwitch(true); | |||
| fSliderWaveform->setCallback(this); | |||
| // knobs | |||
| @@ -52,51 +53,58 @@ DistrhoUINekobi::DistrhoUINekobi() | |||
| // knob Tuning | |||
| fKnobTuning = new ImageKnob(this, knobImage); | |||
| fKnobTuning->setPos(42, 45); | |||
| fKnobTuning->setPos(41, 43); | |||
| fKnobTuning->setRange(-12.0f, 12.0f); | |||
| fKnobTuning->setValue(0.0f); | |||
| fKnobTuning->setRotationAngle(270); | |||
| fKnobTuning->setCallback(this); | |||
| // knob Cutoff | |||
| fKnobCutoff = new ImageKnob(this, knobImage); | |||
| fKnobCutoff->setPos(185, 45); | |||
| fKnobCutoff->setPos(185, 43); | |||
| fKnobCutoff->setRange(0.0f, 100.0f); | |||
| fKnobCutoff->setValue(25.0f); | |||
| fKnobCutoff->setRotationAngle(270); | |||
| fKnobCutoff->setCallback(this); | |||
| // knob Resonance | |||
| fKnobResonance = new ImageKnob(this, knobImage); | |||
| fKnobResonance->setPos(258, 45); | |||
| fKnobResonance->setPos(257, 43); | |||
| fKnobResonance->setRange(0.0f, 95.0f); | |||
| fKnobResonance->setValue(25.0f); | |||
| fKnobResonance->setRotationAngle(270); | |||
| fKnobResonance->setCallback(this); | |||
| // knob Env Mod | |||
| fKnobEnvMod = new ImageKnob(this, knobImage); | |||
| fKnobEnvMod->setPos(330, 45); | |||
| fKnobEnvMod->setPos(329, 43); | |||
| fKnobEnvMod->setRange(0.0f, 100.0f); | |||
| fKnobEnvMod->setValue(50.0f); | |||
| fKnobEnvMod->setRotationAngle(270); | |||
| fKnobEnvMod->setCallback(this); | |||
| // knob Decay | |||
| fKnobDecay = new ImageKnob(this, knobImage); | |||
| fKnobDecay->setPos(402, 45); | |||
| fKnobDecay->setPos(400, 43); | |||
| fKnobDecay->setRange(0.0f, 100.0f); | |||
| fKnobDecay->setValue(75.0f); | |||
| fKnobDecay->setRotationAngle(270); | |||
| fKnobDecay->setCallback(this); | |||
| // knob Accent | |||
| fKnobAccent = new ImageKnob(this, knobImage); | |||
| fKnobAccent->setPos(474, 45); | |||
| fKnobAccent->setPos(473, 43); | |||
| fKnobAccent->setRange(0.0f, 100.0f); | |||
| fKnobAccent->setValue(25.0f); | |||
| fKnobAccent->setRotationAngle(270); | |||
| fKnobAccent->setCallback(this); | |||
| // knob Volume | |||
| fKnobVolume = new ImageKnob(this, knobImage); | |||
| fKnobVolume->setPos(546, 45); | |||
| fKnobVolume->setPos(545, 43); | |||
| fKnobVolume->setRange(0.0f, 100.0f); | |||
| fKnobVolume->setValue(75.0f); | |||
| fKnobVolume->setRotationAngle(270); | |||
| fKnobVolume->setCallback(this); | |||
| // about button | |||
| @@ -50,6 +50,7 @@ public: | |||
| void setOrientation(Orientation orientation); | |||
| void setRange(float min, float max); | |||
| void setValue(float value, bool sendCallback = false); | |||
| void setRotationAngle(int angle); | |||
| void setCallback(Callback* callback); | |||
| @@ -57,6 +58,8 @@ protected: | |||
| void onDisplay() override; | |||
| bool onMouse(int button, bool press, int x, int y) override; | |||
| bool onMotion(int x, int y) override; | |||
| void onReshape(int width, int height) override; | |||
| void onClose() override; | |||
| private: | |||
| Image fImage; | |||
| @@ -65,6 +68,7 @@ private: | |||
| float fValue; | |||
| Orientation fOrientation; | |||
| int fRotationAngle; | |||
| bool fDragging; | |||
| int fLastX; | |||
| int fLastY; | |||
| @@ -75,6 +79,7 @@ private: | |||
| int fImgLayerSize; | |||
| int fImgLayerCount; | |||
| Rectangle<int> fKnobArea; | |||
| GLuint fTextureId; | |||
| }; | |||
| // ------------------------------------------------- | |||
| @@ -49,6 +49,7 @@ public: | |||
| void setRange(float min, float max); | |||
| void setValue(float value, bool sendCallback = false); | |||
| void setIsSwitch(bool yesNo); | |||
| void setCallback(Callback* callback); | |||
| @@ -63,6 +64,7 @@ private: | |||
| float fMaximum; | |||
| float fValue; | |||
| bool fIsSwitch; | |||
| bool fDragging; | |||
| int fStartedX; | |||
| int fStartedY; | |||
| @@ -16,6 +16,9 @@ | |||
| #include "../ImageKnob.hpp" | |||
| #include <cassert> | |||
| #include <cstdio> | |||
| START_NAMESPACE_DGL | |||
| // ------------------------------------------------- | |||
| @@ -27,6 +30,7 @@ ImageKnob::ImageKnob(Window* parent, const Image& image, Orientation orientation | |||
| fMaximum(1.0f), | |||
| fValue(0.5f), | |||
| fOrientation(orientation), | |||
| fRotationAngle(0), | |||
| fDragging(false), | |||
| fLastX(0), | |||
| fLastY(0), | |||
| @@ -34,7 +38,8 @@ ImageKnob::ImageKnob(Window* parent, const Image& image, Orientation orientation | |||
| fIsImgVertical(image.getHeight() > image.getWidth()), | |||
| fImgLayerSize(fIsImgVertical ? image.getWidth() : image.getHeight()), | |||
| fImgLayerCount(fIsImgVertical ? image.getHeight()/fImgLayerSize : image.getWidth()/fImgLayerSize), | |||
| fKnobArea(0, 0, fImgLayerSize, fImgLayerSize) | |||
| fKnobArea(0, 0, fImgLayerSize, fImgLayerSize), | |||
| fTextureId(0) | |||
| { | |||
| setSize(fImgLayerSize, fImgLayerSize); | |||
| } | |||
| @@ -46,6 +51,7 @@ ImageKnob::ImageKnob(Widget* widget, const Image& image, Orientation orientation | |||
| fMaximum(1.0f), | |||
| fValue(0.5f), | |||
| fOrientation(orientation), | |||
| fRotationAngle(0), | |||
| fDragging(false), | |||
| fLastX(0), | |||
| fLastY(0), | |||
| @@ -53,7 +59,8 @@ ImageKnob::ImageKnob(Widget* widget, const Image& image, Orientation orientation | |||
| fIsImgVertical(image.getHeight() > image.getWidth()), | |||
| fImgLayerSize(fIsImgVertical ? image.getWidth() : image.getHeight()), | |||
| fImgLayerCount(fIsImgVertical ? image.getHeight()/fImgLayerSize : image.getWidth()/fImgLayerSize), | |||
| fKnobArea(0, 0, fImgLayerSize, fImgLayerSize) | |||
| fKnobArea(0, 0, fImgLayerSize, fImgLayerSize), | |||
| fTextureId(0) | |||
| { | |||
| setSize(fImgLayerSize, fImgLayerSize); | |||
| } | |||
| @@ -65,6 +72,7 @@ ImageKnob::ImageKnob(const ImageKnob& imageKnob) | |||
| fMaximum(imageKnob.fMaximum), | |||
| fValue(imageKnob.fValue), | |||
| fOrientation(imageKnob.fOrientation), | |||
| fRotationAngle(imageKnob.fRotationAngle), | |||
| fDragging(false), | |||
| fLastX(0), | |||
| fLastY(0), | |||
| @@ -72,9 +80,17 @@ ImageKnob::ImageKnob(const ImageKnob& imageKnob) | |||
| fIsImgVertical(imageKnob.fIsImgVertical), | |||
| fImgLayerSize(imageKnob.fImgLayerSize), | |||
| fImgLayerCount(imageKnob.fImgLayerCount), | |||
| fKnobArea(imageKnob.fKnobArea) | |||
| fKnobArea(imageKnob.fKnobArea), | |||
| fTextureId(0) | |||
| { | |||
| setSize(fImgLayerSize, fImgLayerSize); | |||
| if (fRotationAngle != 0) | |||
| { | |||
| // force new texture creation | |||
| fRotationAngle = 0; | |||
| setRotationAngle(imageKnob.fRotationAngle); | |||
| } | |||
| } | |||
| float ImageKnob::getValue() const | |||
| @@ -125,6 +141,38 @@ void ImageKnob::setValue(float value, bool sendCallback) | |||
| fCallback->imageKnobValueChanged(this, fValue); | |||
| } | |||
| void ImageKnob::setRotationAngle(int angle) | |||
| { | |||
| if (fRotationAngle == angle) | |||
| return; | |||
| if (fRotationAngle != 0) | |||
| { | |||
| // delete old texture | |||
| glDeleteTextures(1, &fTextureId); | |||
| fTextureId = 0; | |||
| } | |||
| fRotationAngle = angle; | |||
| if (angle != 0) | |||
| { | |||
| glEnable(GL_TEXTURE_2D); | |||
| glGenTextures(1, &fTextureId); | |||
| glBindTexture(GL_TEXTURE_2D, fTextureId); | |||
| glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |||
| glPixelStorei(GL_PACK_ALIGNMENT, 1); | |||
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWidth(), getHeight(), 0, fImage.getFormat(), fImage.getType(), fImage.getRawData()); | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||
| glBindTexture(GL_TEXTURE_2D, 0); | |||
| glDisable(GL_TEXTURE_2D); | |||
| } | |||
| } | |||
| void ImageKnob::setCallback(Callback* callback) | |||
| { | |||
| fCallback = callback; | |||
| @@ -132,17 +180,58 @@ void ImageKnob::setCallback(Callback* callback) | |||
| void ImageKnob::onDisplay() | |||
| { | |||
| float normValue = (fValue - fMinimum) / (fMaximum - fMinimum); | |||
| const float normValue = (fValue - fMinimum) / (fMaximum - fMinimum); | |||
| if (fRotationAngle != 0 || true) | |||
| { | |||
| glEnable(GL_TEXTURE_2D); | |||
| glBindTexture(GL_TEXTURE_2D, fTextureId); | |||
| // FIXME: assuming GL_BGRA data (* 4) | |||
| int layerDataSize = fImgLayerSize * fImgLayerSize * 4; | |||
| int imageDataSize = layerDataSize * fImgLayerCount; | |||
| int imageDataOffset = imageDataSize - layerDataSize - (layerDataSize * int(normValue * float(fImgLayerCount-1))); | |||
| glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |||
| glPixelStorei(GL_PACK_ALIGNMENT, 1); | |||
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWidth(), getHeight(), 0, fImage.getFormat(), fImage.getType(), fImage.getRawData()); | |||
| glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |||
| glPixelStorei(GL_PACK_ALIGNMENT, 1); | |||
| glRasterPos2i(getX(), getY()+getHeight()); | |||
| glDrawPixels(fImgLayerSize, fImgLayerSize, fImage.getFormat(), fImage.getType(), fImage.getRawData() + imageDataOffset); | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||
| glPushMatrix(); | |||
| const GLint w2 = getWidth()/2; | |||
| const GLint h2 = getHeight()/2; | |||
| glTranslatef(getX()+w2, getY()+h2, 0.f); | |||
| glRotatef(normValue*fRotationAngle, 0.0f, 0.0f, 1.0f); | |||
| glBegin(GL_QUADS); | |||
| glTexCoord2f(0.0f, 1.0f); | |||
| glVertex2i(-w2, -h2); | |||
| glTexCoord2f(1.0f, 1.0f); | |||
| glVertex2i(getWidth()-w2, -h2); | |||
| glTexCoord2f(1.0f, 0.0f); | |||
| glVertex2i(getWidth()-w2, getHeight()-h2); | |||
| glTexCoord2f(0.0f, 0.0f); | |||
| glVertex2i(-w2, getHeight()-h2); | |||
| glEnd(); | |||
| glPopMatrix(); | |||
| glBindTexture(GL_TEXTURE_2D, 0); | |||
| glDisable(GL_TEXTURE_2D); | |||
| } | |||
| else | |||
| { | |||
| const int layerDataSize = fImgLayerSize * fImgLayerSize * (fImage.getFormat() == GL_BGRA || fImage.getFormat() == GL_RGBA ? 4 : 3); | |||
| const int imageDataSize = layerDataSize * fImgLayerCount; | |||
| const int imageDataOffset = imageDataSize - layerDataSize - (layerDataSize * int(normValue * float(fImgLayerCount-1))); | |||
| glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |||
| glPixelStorei(GL_PACK_ALIGNMENT, 1); | |||
| glRasterPos2i(getX(), getY()+getHeight()); | |||
| glDrawPixels(fImgLayerSize, fImgLayerSize, fImage.getFormat(), fImage.getType(), fImage.getRawData() + imageDataOffset); | |||
| } | |||
| } | |||
| bool ImageKnob::onMouse(int button, bool press, int x, int y) | |||
| @@ -222,6 +311,20 @@ bool ImageKnob::onMotion(int x, int y) | |||
| return true; | |||
| } | |||
| void ImageKnob::onReshape(int width, int height) | |||
| { | |||
| // if (fRotationAngle != 0) | |||
| // glEnable(GL_TEXTURE_2D); | |||
| Widget::onReshape(width, height); | |||
| } | |||
| void ImageKnob::onClose() | |||
| { | |||
| // delete old texture | |||
| setRotationAngle(0); | |||
| } | |||
| // ------------------------------------------------- | |||
| END_NAMESPACE_DGL | |||
| @@ -26,6 +26,7 @@ ImageSlider::ImageSlider(Window* parent, const Image& image) | |||
| fMinimum(0.0f), | |||
| fMaximum(1.0f), | |||
| fValue(0.5f), | |||
| fIsSwitch(false), | |||
| fDragging(false), | |||
| fStartedX(0), | |||
| fStartedY(0), | |||
| @@ -40,6 +41,7 @@ ImageSlider::ImageSlider(Widget* widget, const Image& image) | |||
| fMinimum(0.0f), | |||
| fMaximum(1.0f), | |||
| fValue(0.5f), | |||
| fIsSwitch(false), | |||
| fDragging(false), | |||
| fStartedX(0), | |||
| fStartedY(0), | |||
| @@ -54,6 +56,7 @@ ImageSlider::ImageSlider(const ImageSlider& imageSlider) | |||
| fMinimum(imageSlider.fMinimum), | |||
| fMaximum(imageSlider.fMaximum), | |||
| fValue(imageSlider.fValue), | |||
| fIsSwitch(imageSlider.fIsSwitch), | |||
| fDragging(false), | |||
| fStartedX(0), | |||
| fStartedY(0), | |||
| @@ -127,6 +130,15 @@ void ImageSlider::setValue(float value, bool sendCallback) | |||
| fCallback->imageSliderValueChanged(this, fValue); | |||
| } | |||
| void ImageSlider::setIsSwitch(bool yesNo) | |||
| { | |||
| if (fIsSwitch == yesNo) | |||
| return; | |||
| fIsSwitch = yesNo; | |||
| repaint(); | |||
| } | |||
| void ImageSlider::setCallback(Callback* callback) | |||
| { | |||
| fCallback = callback; | |||
| @@ -184,12 +196,24 @@ bool ImageSlider::onMouse(int button, bool press, int x, int y) | |||
| else | |||
| return false; | |||
| float value = fMaximum - vper * (fMaximum - fMinimum); | |||
| float value; | |||
| if (fIsSwitch) | |||
| { | |||
| if (vper < 0.5f) | |||
| value = fMaximum; | |||
| else | |||
| value = fMinimum; | |||
| } | |||
| else | |||
| { | |||
| value = fMaximum - vper * (fMaximum - fMinimum); | |||
| if (value < fMinimum) | |||
| value = fMinimum; | |||
| else if (value > fMaximum) | |||
| value = fMaximum; | |||
| if (value < fMinimum) | |||
| value = fMinimum; | |||
| else if (value > fMaximum) | |||
| value = fMaximum; | |||
| } | |||
| fDragging = true; | |||
| fStartedX = x; | |||
| @@ -236,12 +260,24 @@ bool ImageSlider::onMotion(int x, int y) | |||
| vper = float(y - fSliderArea.getY()) / float(fSliderArea.getHeight()); | |||
| } | |||
| float value = fMaximum - vper * (fMaximum - fMinimum); | |||
| float value; | |||
| if (value < fMinimum) | |||
| value = fMinimum; | |||
| else if (value > fMaximum) | |||
| value = fMaximum; | |||
| if (fIsSwitch) | |||
| { | |||
| if (vper < 0.5f) | |||
| value = fMaximum; | |||
| else | |||
| value = fMinimum; | |||
| } | |||
| else | |||
| { | |||
| value = fMaximum - vper * (fMaximum - fMinimum); | |||
| if (value < fMinimum) | |||
| value = fMinimum; | |||
| else if (value > fMaximum) | |||
| value = fMaximum; | |||
| } | |||
| setValue(value, true); | |||
| } | |||