DISTRHO Plugin Framework
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

355 lines
9.5KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. * or without fee is hereby granted, provided that the above copyright notice and this
  7. * permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  10. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  11. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  13. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include "../ImageKnob.hpp"
  17. #include <cmath>
  18. #include <cstdio>
  19. START_NAMESPACE_DGL
  20. // -----------------------------------------------------------------------
  21. ImageKnob::ImageKnob(Window& parent, const Image& image, Orientation orientation)
  22. : Widget(parent),
  23. fImage(image),
  24. fMinimum(0.0f),
  25. fMaximum(1.0f),
  26. fStep(0.0f),
  27. fValue(0.5f),
  28. fValueTmp(fValue),
  29. fOrientation(orientation),
  30. fRotationAngle(0),
  31. fDragging(false),
  32. fLastX(0),
  33. fLastY(0),
  34. fCallback(nullptr),
  35. fIsImgVertical(image.getHeight() > image.getWidth()),
  36. fImgLayerSize(fIsImgVertical ? image.getWidth() : image.getHeight()),
  37. fImgLayerCount(fIsImgVertical ? image.getHeight()/fImgLayerSize : image.getWidth()/fImgLayerSize),
  38. fKnobArea(0, 0, fImgLayerSize, fImgLayerSize),
  39. fTextureId(0)
  40. {
  41. setSize(fImgLayerSize, fImgLayerSize);
  42. }
  43. ImageKnob::ImageKnob(Widget* widget, const Image& image, Orientation orientation)
  44. : Widget(widget->getParentWindow()),
  45. fImage(image),
  46. fMinimum(0.0f),
  47. fMaximum(1.0f),
  48. fStep(0.0f),
  49. fValue(0.5f),
  50. fValueTmp(fValue),
  51. fOrientation(orientation),
  52. fRotationAngle(0),
  53. fDragging(false),
  54. fLastX(0),
  55. fLastY(0),
  56. fCallback(nullptr),
  57. fIsImgVertical(image.getHeight() > image.getWidth()),
  58. fImgLayerSize(fIsImgVertical ? image.getWidth() : image.getHeight()),
  59. fImgLayerCount(fIsImgVertical ? image.getHeight()/fImgLayerSize : image.getWidth()/fImgLayerSize),
  60. fKnobArea(0, 0, fImgLayerSize, fImgLayerSize),
  61. fTextureId(0)
  62. {
  63. setSize(fImgLayerSize, fImgLayerSize);
  64. }
  65. ImageKnob::ImageKnob(const ImageKnob& imageKnob)
  66. : Widget(imageKnob.getParentWindow()),
  67. fImage(imageKnob.fImage),
  68. fMinimum(imageKnob.fMinimum),
  69. fMaximum(imageKnob.fMaximum),
  70. fStep(imageKnob.fStep),
  71. fValue(imageKnob.fValue),
  72. fValueTmp(fValue),
  73. fOrientation(imageKnob.fOrientation),
  74. fRotationAngle(imageKnob.fRotationAngle),
  75. fDragging(false),
  76. fLastX(0),
  77. fLastY(0),
  78. fCallback(imageKnob.fCallback),
  79. fIsImgVertical(imageKnob.fIsImgVertical),
  80. fImgLayerSize(imageKnob.fImgLayerSize),
  81. fImgLayerCount(imageKnob.fImgLayerCount),
  82. fKnobArea(imageKnob.fKnobArea),
  83. fTextureId(0)
  84. {
  85. setSize(fImgLayerSize, fImgLayerSize);
  86. if (fRotationAngle != 0)
  87. {
  88. // force new texture creation
  89. fRotationAngle = 0;
  90. setRotationAngle(imageKnob.fRotationAngle);
  91. }
  92. }
  93. float ImageKnob::getValue() const
  94. {
  95. return fValue;
  96. }
  97. void ImageKnob::setOrientation(Orientation orientation)
  98. {
  99. if (fOrientation == orientation)
  100. return;
  101. fOrientation = orientation;
  102. }
  103. void ImageKnob::setRange(float min, float max)
  104. {
  105. if (fValue < min)
  106. {
  107. fValue = min;
  108. repaint();
  109. if (fCallback != nullptr)
  110. fCallback->imageKnobValueChanged(this, fValue);
  111. }
  112. else if (fValue > max)
  113. {
  114. fValue = max;
  115. repaint();
  116. if (fCallback != nullptr)
  117. fCallback->imageKnobValueChanged(this, fValue);
  118. }
  119. fMinimum = min;
  120. fMaximum = max;
  121. }
  122. void ImageKnob::setStep(float step)
  123. {
  124. fStep = step;
  125. }
  126. void ImageKnob::setValue(float value, bool sendCallback)
  127. {
  128. if (fValue == value)
  129. return;
  130. fValue = value;
  131. if (fStep == 0.0f)
  132. fValueTmp = value;
  133. repaint();
  134. if (sendCallback && fCallback != nullptr)
  135. fCallback->imageKnobValueChanged(this, fValue);
  136. }
  137. void ImageKnob::setRotationAngle(int angle)
  138. {
  139. if (fRotationAngle == angle)
  140. return;
  141. if (fRotationAngle != 0)
  142. {
  143. // delete old texture
  144. glDeleteTextures(1, &fTextureId);
  145. fTextureId = 0;
  146. }
  147. fRotationAngle = angle;
  148. if (angle != 0)
  149. {
  150. glEnable(GL_TEXTURE_2D);
  151. glGenTextures(1, &fTextureId);
  152. glBindTexture(GL_TEXTURE_2D, fTextureId);
  153. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  154. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  155. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWidth(), getHeight(), 0, fImage.getFormat(), fImage.getType(), fImage.getRawData());
  156. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  157. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  158. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
  159. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
  160. static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f };
  161. glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans);
  162. glBindTexture(GL_TEXTURE_2D, 0);
  163. glDisable(GL_TEXTURE_2D);
  164. }
  165. }
  166. void ImageKnob::setCallback(Callback* callback)
  167. {
  168. fCallback = callback;
  169. }
  170. void ImageKnob::onDisplay()
  171. {
  172. const float normValue = (fValue - fMinimum) / (fMaximum - fMinimum);
  173. if (fRotationAngle != 0)
  174. {
  175. glEnable(GL_TEXTURE_2D);
  176. glBindTexture(GL_TEXTURE_2D, fTextureId);
  177. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  178. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  179. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWidth(), getHeight(), 0, fImage.getFormat(), fImage.getType(), fImage.getRawData());
  180. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  181. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  182. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
  183. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
  184. static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f };
  185. glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans);
  186. glPushMatrix();
  187. const GLint w2 = getWidth()/2;
  188. const GLint h2 = getHeight()/2;
  189. glTranslatef(static_cast<float>(getX()+w2), static_cast<float>(getY()+h2), 0.0f);
  190. glRotatef(normValue*static_cast<float>(fRotationAngle), 0.0f, 0.0f, 1.0f);
  191. Rectangle<int>(-w2, -h2, getWidth(), getHeight()).draw();
  192. glPopMatrix();
  193. glBindTexture(GL_TEXTURE_2D, 0);
  194. glDisable(GL_TEXTURE_2D);
  195. }
  196. else
  197. {
  198. // FIXME - DO NOT USE glDrawPixels!
  199. const int layerDataSize = fImgLayerSize * fImgLayerSize * ((fImage.getFormat() == GL_BGRA || fImage.getFormat() == GL_RGBA) ? 4 : 3);
  200. const int imageDataSize = layerDataSize * fImgLayerCount;
  201. const int imageDataOffset = imageDataSize - layerDataSize - (layerDataSize * int(normValue * float(fImgLayerCount-1)));
  202. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  203. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  204. glRasterPos2i(getX(), getY()+getHeight());
  205. glDrawPixels(fImgLayerSize, fImgLayerSize, fImage.getFormat(), fImage.getType(), fImage.getRawData() + imageDataOffset);
  206. }
  207. }
  208. bool ImageKnob::onMouse(int button, bool press, int x, int y)
  209. {
  210. if (button != 1)
  211. return false;
  212. if (press)
  213. {
  214. if (! getArea().contains(x, y))
  215. return false;
  216. fDragging = true;
  217. fLastX = x;
  218. fLastY = y;
  219. if (fCallback != nullptr)
  220. fCallback->imageKnobDragStarted(this);
  221. return true;
  222. }
  223. else if (fDragging)
  224. {
  225. if (fCallback != nullptr)
  226. fCallback->imageKnobDragFinished(this);
  227. fDragging = false;
  228. return true;
  229. }
  230. return false;
  231. }
  232. bool ImageKnob::onMotion(int x, int y)
  233. {
  234. if (! fDragging)
  235. return false;
  236. bool doVal = false;
  237. float d, value;
  238. if (fOrientation == ImageKnob::Horizontal)
  239. {
  240. if (int movX = x - fLastX)
  241. {
  242. d = (getModifiers() & MODIFIER_SHIFT) ? 2000.0f : 200.0f;
  243. value = fValueTmp + (float(fMaximum - fMinimum) / d * float(movX));
  244. doVal = true;
  245. }
  246. }
  247. else if (fOrientation == ImageKnob::Vertical)
  248. {
  249. if (int movY = fLastY - y)
  250. {
  251. d = (getModifiers() & MODIFIER_SHIFT) ? 2000.0f : 200.0f;
  252. value = fValueTmp + (float(fMaximum - fMinimum) / d * float(movY));
  253. doVal = true;
  254. }
  255. }
  256. if (! doVal)
  257. return false;
  258. if (value < fMinimum)
  259. {
  260. value = fMinimum;
  261. fValueTmp = value;
  262. }
  263. else if (value > fMaximum)
  264. {
  265. value = fMaximum;
  266. fValueTmp = value;
  267. }
  268. else if (fStep != 0.0f)
  269. {
  270. fValueTmp = value;
  271. const float rest = std::fmod(value, fStep);
  272. value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f);
  273. }
  274. setValue(value, true);
  275. fLastX = x;
  276. fLastY = y;
  277. return true;
  278. }
  279. void ImageKnob::onReshape(int width, int height)
  280. {
  281. // if (fRotationAngle != 0)
  282. // glEnable(GL_TEXTURE_2D);
  283. Widget::onReshape(width, height);
  284. }
  285. void ImageKnob::onClose()
  286. {
  287. // delete old texture
  288. setRotationAngle(0);
  289. }
  290. // -----------------------------------------------------------------------
  291. END_NAMESPACE_DGL