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.

365 lines
9.8KB

  1. /*
  2. * DISTRHO Plugin Toolkit (DPT)
  3. * Copyright (C) 2012-2013 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. 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_UNPACK_ALIGNMENT, 1);
  178. glPixelStorei(GL_PACK_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. 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. glBegin(GL_QUADS);
  192. glTexCoord2f(0.0f, 0.0f);
  193. glVertex2i(-w2, -h2);
  194. glTexCoord2f(1.0f, 0.0f);
  195. glVertex2i(getWidth()-w2, -h2);
  196. glTexCoord2f(1.0f, 1.0f);
  197. glVertex2i(getWidth()-w2, getHeight()-h2);
  198. glTexCoord2f(0.0f, 1.0f);
  199. glVertex2i(-w2, getHeight()-h2);
  200. glEnd();
  201. glPopMatrix();
  202. glBindTexture(GL_TEXTURE_2D, 0);
  203. glDisable(GL_TEXTURE_2D);
  204. }
  205. else
  206. {
  207. const int layerDataSize = fImgLayerSize * fImgLayerSize * ((fImage.getFormat() == GL_BGRA || fImage.getFormat() == GL_RGBA) ? 4 : 3);
  208. const int imageDataSize = layerDataSize * fImgLayerCount;
  209. const int imageDataOffset = imageDataSize - layerDataSize - (layerDataSize * int(normValue * float(fImgLayerCount-1)));
  210. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  211. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  212. glRasterPos2i(getX(), getY()+getHeight());
  213. glDrawPixels(fImgLayerSize, fImgLayerSize, fImage.getFormat(), fImage.getType(), fImage.getRawData() + imageDataOffset);
  214. }
  215. }
  216. bool ImageKnob::onMouse(int button, bool press, int x, int y)
  217. {
  218. if (button != 1)
  219. return false;
  220. if (press)
  221. {
  222. if (! getArea().contains(x, y))
  223. return false;
  224. fDragging = true;
  225. fLastX = x;
  226. fLastY = y;
  227. if (fCallback != nullptr)
  228. fCallback->imageKnobDragStarted(this);
  229. return true;
  230. }
  231. else if (fDragging)
  232. {
  233. if (fCallback != nullptr)
  234. fCallback->imageKnobDragFinished(this);
  235. fDragging = false;
  236. return true;
  237. }
  238. return false;
  239. }
  240. bool ImageKnob::onMotion(int x, int y)
  241. {
  242. if (! fDragging)
  243. return false;
  244. bool doVal = false;
  245. float d, value;
  246. if (fOrientation == ImageKnob::Horizontal)
  247. {
  248. if (int movX = x - fLastX)
  249. {
  250. d = (getModifiers() & MODIFIER_SHIFT) ? 2000.0f : 200.0f;
  251. value = fValueTmp + (float(fMaximum - fMinimum) / d * float(movX));
  252. doVal = true;
  253. }
  254. }
  255. else if (fOrientation == ImageKnob::Vertical)
  256. {
  257. if (int movY = fLastY - y)
  258. {
  259. d = (getModifiers() & MODIFIER_SHIFT) ? 2000.0f : 200.0f;
  260. value = fValueTmp + (float(fMaximum - fMinimum) / d * float(movY));
  261. doVal = true;
  262. }
  263. }
  264. if (! doVal)
  265. return false;
  266. if (value < fMinimum)
  267. {
  268. value = fMinimum;
  269. fValueTmp = value;
  270. }
  271. else if (value > fMaximum)
  272. {
  273. value = fMaximum;
  274. fValueTmp = value;
  275. }
  276. else if (fStep != 0.0f)
  277. {
  278. fValueTmp = value;
  279. const float rest = std::fmod(value, fStep);
  280. value = value - rest + (rest > fStep/2.0f ? fStep : 0.0f);
  281. }
  282. setValue(value, true);
  283. fLastX = x;
  284. fLastY = y;
  285. return true;
  286. }
  287. void ImageKnob::onReshape(int width, int height)
  288. {
  289. // if (fRotationAngle != 0)
  290. // glEnable(GL_TEXTURE_2D);
  291. Widget::onReshape(width, height);
  292. }
  293. void ImageKnob::onClose()
  294. {
  295. // delete old texture
  296. setRotationAngle(0);
  297. }
  298. // -----------------------------------------------------------------------
  299. END_NAMESPACE_DGL