The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

494 lines
19KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #define WGL_EXT_FUNCTION_INIT(extType, extFunc) \
  19. ((extFunc = (extType) wglGetProcAddress (#extFunc)) != 0)
  20. typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues);
  21. typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int* piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
  22. typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval);
  23. typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void);
  24. enum
  25. {
  26. WGL_NUMBER_PIXEL_FORMATS_ARB = 0x2000,
  27. WGL_DRAW_TO_WINDOW_ARB = 0x2001,
  28. WGL_ACCELERATION_ARB = 0x2003,
  29. WGL_SWAP_METHOD_ARB = 0x2007,
  30. WGL_SUPPORT_OPENGL_ARB = 0x2010,
  31. WGL_PIXEL_TYPE_ARB = 0x2013,
  32. WGL_DOUBLE_BUFFER_ARB = 0x2011,
  33. WGL_COLOR_BITS_ARB = 0x2014,
  34. WGL_RED_BITS_ARB = 0x2015,
  35. WGL_GREEN_BITS_ARB = 0x2017,
  36. WGL_BLUE_BITS_ARB = 0x2019,
  37. WGL_ALPHA_BITS_ARB = 0x201B,
  38. WGL_DEPTH_BITS_ARB = 0x2022,
  39. WGL_STENCIL_BITS_ARB = 0x2023,
  40. WGL_FULL_ACCELERATION_ARB = 0x2027,
  41. WGL_ACCUM_RED_BITS_ARB = 0x201E,
  42. WGL_ACCUM_GREEN_BITS_ARB = 0x201F,
  43. WGL_ACCUM_BLUE_BITS_ARB = 0x2020,
  44. WGL_ACCUM_ALPHA_BITS_ARB = 0x2021,
  45. WGL_STEREO_ARB = 0x2012,
  46. WGL_SAMPLE_BUFFERS_ARB = 0x2041,
  47. WGL_SAMPLES_ARB = 0x2042,
  48. WGL_TYPE_RGBA_ARB = 0x202B
  49. };
  50. extern ComponentPeer* createNonRepaintingEmbeddedWindowsPeer (Component* component, void* parent);
  51. //==============================================================================
  52. class WindowedGLContext : public OpenGLContext
  53. {
  54. public:
  55. WindowedGLContext (Component* const component_,
  56. HGLRC contextToShareWith,
  57. const OpenGLPixelFormat& pixelFormat)
  58. : renderContext (0),
  59. component (component_),
  60. dc (0)
  61. {
  62. jassert (component != nullptr);
  63. createNativeWindow();
  64. // Use a default pixel format that should be supported everywhere
  65. PIXELFORMATDESCRIPTOR pfd = { 0 };
  66. pfd.nSize = sizeof (pfd);
  67. pfd.nVersion = 1;
  68. pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
  69. pfd.iPixelType = PFD_TYPE_RGBA;
  70. pfd.cColorBits = 24;
  71. pfd.cDepthBits = 16;
  72. const int format = ChoosePixelFormat (dc, &pfd);
  73. if (format != 0)
  74. SetPixelFormat (dc, format, &pfd);
  75. renderContext = wglCreateContext (dc);
  76. makeActive();
  77. setPixelFormat (pixelFormat);
  78. if (contextToShareWith != 0 && renderContext != 0)
  79. wglShareLists (contextToShareWith, renderContext);
  80. }
  81. ~WindowedGLContext()
  82. {
  83. deleteContext();
  84. ReleaseDC ((HWND) nativeWindow->getNativeHandle(), dc);
  85. nativeWindow = nullptr;
  86. }
  87. void deleteContext()
  88. {
  89. makeInactive();
  90. if (renderContext != 0)
  91. {
  92. wglDeleteContext (renderContext);
  93. renderContext = 0;
  94. }
  95. }
  96. bool makeActive() const noexcept
  97. {
  98. jassert (renderContext != 0);
  99. return wglMakeCurrent (dc, renderContext) != 0;
  100. }
  101. bool makeInactive() const noexcept
  102. {
  103. return (! isActive()) || (wglMakeCurrent (0, 0) != 0);
  104. }
  105. bool isActive() const noexcept
  106. {
  107. return wglGetCurrentContext() == renderContext;
  108. }
  109. OpenGLPixelFormat getPixelFormat() const
  110. {
  111. OpenGLPixelFormat pf;
  112. makeActive();
  113. fillInPixelFormatDetails (GetPixelFormat (dc), pf);
  114. return pf;
  115. }
  116. void* getRawContext() const noexcept
  117. {
  118. return renderContext;
  119. }
  120. unsigned int getFrameBufferID() const
  121. {
  122. return 0;
  123. }
  124. bool setPixelFormat (const OpenGLPixelFormat& pixelFormat)
  125. {
  126. makeActive();
  127. PIXELFORMATDESCRIPTOR pfd = { 0 };
  128. pfd.nSize = sizeof (pfd);
  129. pfd.nVersion = 1;
  130. pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;
  131. pfd.iPixelType = PFD_TYPE_RGBA;
  132. pfd.iLayerType = PFD_MAIN_PLANE;
  133. pfd.cColorBits = (BYTE) (pixelFormat.redBits + pixelFormat.greenBits + pixelFormat.blueBits);
  134. pfd.cRedBits = (BYTE) pixelFormat.redBits;
  135. pfd.cGreenBits = (BYTE) pixelFormat.greenBits;
  136. pfd.cBlueBits = (BYTE) pixelFormat.blueBits;
  137. pfd.cAlphaBits = (BYTE) pixelFormat.alphaBits;
  138. pfd.cDepthBits = (BYTE) pixelFormat.depthBufferBits;
  139. pfd.cStencilBits = (BYTE) pixelFormat.stencilBufferBits;
  140. pfd.cAccumBits = (BYTE) (pixelFormat.accumulationBufferRedBits + pixelFormat.accumulationBufferGreenBits
  141. + pixelFormat.accumulationBufferBlueBits + pixelFormat.accumulationBufferAlphaBits);
  142. pfd.cAccumRedBits = (BYTE) pixelFormat.accumulationBufferRedBits;
  143. pfd.cAccumGreenBits = (BYTE) pixelFormat.accumulationBufferGreenBits;
  144. pfd.cAccumBlueBits = (BYTE) pixelFormat.accumulationBufferBlueBits;
  145. pfd.cAccumAlphaBits = (BYTE) pixelFormat.accumulationBufferAlphaBits;
  146. int format = 0;
  147. PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = 0;
  148. if (OpenGLHelpers::isExtensionSupported ("WGL_ARB_pixel_format")
  149. && WGL_EXT_FUNCTION_INIT (PFNWGLCHOOSEPIXELFORMATARBPROC, wglChoosePixelFormatARB))
  150. {
  151. int attributes[64];
  152. int n = 0;
  153. attributes[n++] = WGL_DRAW_TO_WINDOW_ARB;
  154. attributes[n++] = GL_TRUE;
  155. attributes[n++] = WGL_SUPPORT_OPENGL_ARB;
  156. attributes[n++] = GL_TRUE;
  157. attributes[n++] = WGL_ACCELERATION_ARB;
  158. attributes[n++] = WGL_FULL_ACCELERATION_ARB;
  159. attributes[n++] = WGL_DOUBLE_BUFFER_ARB;
  160. attributes[n++] = GL_TRUE;
  161. attributes[n++] = WGL_PIXEL_TYPE_ARB;
  162. attributes[n++] = WGL_TYPE_RGBA_ARB;
  163. attributes[n++] = WGL_COLOR_BITS_ARB;
  164. attributes[n++] = pfd.cColorBits;
  165. attributes[n++] = WGL_RED_BITS_ARB;
  166. attributes[n++] = pixelFormat.redBits;
  167. attributes[n++] = WGL_GREEN_BITS_ARB;
  168. attributes[n++] = pixelFormat.greenBits;
  169. attributes[n++] = WGL_BLUE_BITS_ARB;
  170. attributes[n++] = pixelFormat.blueBits;
  171. attributes[n++] = WGL_ALPHA_BITS_ARB;
  172. attributes[n++] = pixelFormat.alphaBits;
  173. attributes[n++] = WGL_DEPTH_BITS_ARB;
  174. attributes[n++] = pixelFormat.depthBufferBits;
  175. if (pixelFormat.stencilBufferBits > 0)
  176. {
  177. attributes[n++] = WGL_STENCIL_BITS_ARB;
  178. attributes[n++] = pixelFormat.stencilBufferBits;
  179. }
  180. attributes[n++] = WGL_ACCUM_RED_BITS_ARB;
  181. attributes[n++] = pixelFormat.accumulationBufferRedBits;
  182. attributes[n++] = WGL_ACCUM_GREEN_BITS_ARB;
  183. attributes[n++] = pixelFormat.accumulationBufferGreenBits;
  184. attributes[n++] = WGL_ACCUM_BLUE_BITS_ARB;
  185. attributes[n++] = pixelFormat.accumulationBufferBlueBits;
  186. attributes[n++] = WGL_ACCUM_ALPHA_BITS_ARB;
  187. attributes[n++] = pixelFormat.accumulationBufferAlphaBits;
  188. if (OpenGLHelpers::isExtensionSupported ("WGL_ARB_multisample")
  189. && pixelFormat.fullSceneAntiAliasingNumSamples > 0)
  190. {
  191. attributes[n++] = WGL_SAMPLE_BUFFERS_ARB;
  192. attributes[n++] = 1;
  193. attributes[n++] = WGL_SAMPLES_ARB;
  194. attributes[n++] = pixelFormat.fullSceneAntiAliasingNumSamples;
  195. }
  196. attributes[n++] = 0;
  197. UINT formatsCount;
  198. const BOOL ok = wglChoosePixelFormatARB (dc, attributes, 0, 1, &format, &formatsCount);
  199. (void) ok;
  200. jassert (ok);
  201. }
  202. else
  203. {
  204. format = ChoosePixelFormat (dc, &pfd);
  205. }
  206. if (format != 0)
  207. {
  208. makeInactive();
  209. // win32 can't change the pixel format of a window, so need to delete the
  210. // old one and create a new one..
  211. jassert (nativeWindow != 0);
  212. ReleaseDC ((HWND) nativeWindow->getNativeHandle(), dc);
  213. nativeWindow = nullptr;
  214. createNativeWindow();
  215. if (SetPixelFormat (dc, format, &pfd))
  216. {
  217. wglDeleteContext (renderContext);
  218. renderContext = wglCreateContext (dc);
  219. jassert (renderContext != 0);
  220. return renderContext != 0;
  221. }
  222. }
  223. return false;
  224. }
  225. void updateWindowPosition (const Rectangle<int>& bounds)
  226. {
  227. SetWindowPos ((HWND) nativeWindow->getNativeHandle(), 0,
  228. bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(),
  229. SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER);
  230. }
  231. void repaint()
  232. {
  233. nativeWindow->repaint (nativeWindow->getBounds().withPosition (Point<int>()));
  234. }
  235. void swapBuffers()
  236. {
  237. SwapBuffers (dc);
  238. }
  239. bool setSwapInterval (int numFramesPerSwap)
  240. {
  241. makeActive();
  242. PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = 0;
  243. return OpenGLHelpers::isExtensionSupported ("WGL_EXT_swap_control")
  244. && WGL_EXT_FUNCTION_INIT (PFNWGLSWAPINTERVALEXTPROC, wglSwapIntervalEXT)
  245. && wglSwapIntervalEXT (numFramesPerSwap) != FALSE;
  246. }
  247. int getSwapInterval() const
  248. {
  249. makeActive();
  250. PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT = 0;
  251. if (OpenGLHelpers::isExtensionSupported ("WGL_EXT_swap_control")
  252. && WGL_EXT_FUNCTION_INIT (PFNWGLGETSWAPINTERVALEXTPROC, wglGetSwapIntervalEXT))
  253. return wglGetSwapIntervalEXT();
  254. return 0;
  255. }
  256. void findAlternativeOpenGLPixelFormats (OwnedArray <OpenGLPixelFormat>& results)
  257. {
  258. jassert (isActive());
  259. PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB = 0;
  260. int numTypes = 0;
  261. if (OpenGLHelpers::isExtensionSupported ("WGL_ARB_pixel_format")
  262. && WGL_EXT_FUNCTION_INIT (PFNWGLGETPIXELFORMATATTRIBIVARBPROC, wglGetPixelFormatAttribivARB))
  263. {
  264. int attributes = WGL_NUMBER_PIXEL_FORMATS_ARB;
  265. if (! wglGetPixelFormatAttribivARB (dc, 1, 0, 1, &attributes, &numTypes))
  266. jassertfalse;
  267. }
  268. else
  269. {
  270. numTypes = DescribePixelFormat (dc, 0, 0, 0);
  271. }
  272. OpenGLPixelFormat pf;
  273. for (int i = 0; i < numTypes; ++i)
  274. {
  275. if (fillInPixelFormatDetails (i + 1, pf))
  276. {
  277. bool alreadyListed = false;
  278. for (int j = results.size(); --j >= 0;)
  279. if (pf == *results.getUnchecked(j))
  280. alreadyListed = true;
  281. if (! alreadyListed)
  282. results.add (new OpenGLPixelFormat (pf));
  283. }
  284. }
  285. }
  286. void* getNativeWindowHandle() const
  287. {
  288. return nativeWindow != nullptr ? nativeWindow->getNativeHandle() : nullptr;
  289. }
  290. //==============================================================================
  291. HGLRC renderContext;
  292. private:
  293. ScopedPointer<ComponentPeer> nativeWindow;
  294. Component* const component;
  295. HDC dc;
  296. //==============================================================================
  297. void createNativeWindow()
  298. {
  299. nativeWindow = createNonRepaintingEmbeddedWindowsPeer (component, component->getTopLevelComponent()->getWindowHandle());
  300. nativeWindow->setVisible (true);
  301. dc = GetDC ((HWND) nativeWindow->getNativeHandle());
  302. }
  303. bool fillInPixelFormatDetails (const int pixelFormatIndex, OpenGLPixelFormat& result) const noexcept
  304. {
  305. PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB = 0;
  306. if (OpenGLHelpers::isExtensionSupported ("WGL_ARB_pixel_format")
  307. && WGL_EXT_FUNCTION_INIT (PFNWGLGETPIXELFORMATATTRIBIVARBPROC, wglGetPixelFormatAttribivARB))
  308. {
  309. int attributes[32];
  310. UINT numAttributes = 0;
  311. attributes[numAttributes++] = WGL_DRAW_TO_WINDOW_ARB;
  312. attributes[numAttributes++] = WGL_SUPPORT_OPENGL_ARB;
  313. attributes[numAttributes++] = WGL_ACCELERATION_ARB;
  314. attributes[numAttributes++] = WGL_DOUBLE_BUFFER_ARB;
  315. attributes[numAttributes++] = WGL_PIXEL_TYPE_ARB;
  316. attributes[numAttributes++] = WGL_RED_BITS_ARB;
  317. attributes[numAttributes++] = WGL_GREEN_BITS_ARB;
  318. attributes[numAttributes++] = WGL_BLUE_BITS_ARB;
  319. attributes[numAttributes++] = WGL_ALPHA_BITS_ARB;
  320. attributes[numAttributes++] = WGL_DEPTH_BITS_ARB;
  321. attributes[numAttributes++] = WGL_STENCIL_BITS_ARB;
  322. attributes[numAttributes++] = WGL_ACCUM_RED_BITS_ARB;
  323. attributes[numAttributes++] = WGL_ACCUM_GREEN_BITS_ARB;
  324. attributes[numAttributes++] = WGL_ACCUM_BLUE_BITS_ARB;
  325. attributes[numAttributes++] = WGL_ACCUM_ALPHA_BITS_ARB;
  326. if (OpenGLHelpers::isExtensionSupported ("WGL_ARB_multisample"))
  327. attributes[numAttributes++] = WGL_SAMPLES_ARB;
  328. int values[32] = { 0 };
  329. if (wglGetPixelFormatAttribivARB (dc, pixelFormatIndex, 0, numAttributes, attributes, values))
  330. {
  331. int n = 0;
  332. bool isValidFormat = (values[n++] == GL_TRUE); // WGL_DRAW_TO_WINDOW_ARB
  333. isValidFormat = (values[n++] == GL_TRUE) && isValidFormat; // WGL_SUPPORT_OPENGL_ARB
  334. isValidFormat = (values[n++] == WGL_FULL_ACCELERATION_ARB) && isValidFormat; // WGL_ACCELERATION_ARB
  335. isValidFormat = (values[n++] == GL_TRUE) && isValidFormat; // WGL_DOUBLE_BUFFER_ARB:
  336. isValidFormat = (values[n++] == WGL_TYPE_RGBA_ARB) && isValidFormat; // WGL_PIXEL_TYPE_ARB
  337. result.redBits = values[n++]; // WGL_RED_BITS_ARB
  338. result.greenBits = values[n++]; // WGL_GREEN_BITS_ARB
  339. result.blueBits = values[n++]; // WGL_BLUE_BITS_ARB
  340. result.alphaBits = values[n++]; // WGL_ALPHA_BITS_ARB
  341. result.depthBufferBits = values[n++]; // WGL_DEPTH_BITS_ARB
  342. result.stencilBufferBits = values[n++]; // WGL_STENCIL_BITS_ARB
  343. result.accumulationBufferRedBits = values[n++]; // WGL_ACCUM_RED_BITS_ARB
  344. result.accumulationBufferGreenBits = values[n++]; // WGL_ACCUM_GREEN_BITS_ARB
  345. result.accumulationBufferBlueBits = values[n++]; // WGL_ACCUM_BLUE_BITS_ARB
  346. result.accumulationBufferAlphaBits = values[n++]; // WGL_ACCUM_ALPHA_BITS_ARB
  347. result.fullSceneAntiAliasingNumSamples = (uint8) values[n++]; // WGL_SAMPLES_ARB
  348. return isValidFormat;
  349. }
  350. else
  351. {
  352. jassertfalse;
  353. }
  354. }
  355. else
  356. {
  357. PIXELFORMATDESCRIPTOR pfd;
  358. if (DescribePixelFormat (dc, pixelFormatIndex, sizeof (pfd), &pfd))
  359. {
  360. result.redBits = pfd.cRedBits;
  361. result.greenBits = pfd.cGreenBits;
  362. result.blueBits = pfd.cBlueBits;
  363. result.alphaBits = pfd.cAlphaBits;
  364. result.depthBufferBits = pfd.cDepthBits;
  365. result.stencilBufferBits = pfd.cStencilBits;
  366. result.accumulationBufferRedBits = pfd.cAccumRedBits;
  367. result.accumulationBufferGreenBits = pfd.cAccumGreenBits;
  368. result.accumulationBufferBlueBits = pfd.cAccumBlueBits;
  369. result.accumulationBufferAlphaBits = pfd.cAccumAlphaBits;
  370. result.fullSceneAntiAliasingNumSamples = 0;
  371. return true;
  372. }
  373. else
  374. {
  375. jassertfalse;
  376. }
  377. }
  378. return false;
  379. }
  380. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowedGLContext);
  381. };
  382. //==============================================================================
  383. OpenGLContext* OpenGLComponent::createContext()
  384. {
  385. ScopedPointer<WindowedGLContext> c (new WindowedGLContext (this,
  386. contextToShareListsWith != nullptr ? (HGLRC) contextToShareListsWith->getRawContext() : 0,
  387. preferredPixelFormat));
  388. return (c->renderContext != 0) ? c.release() : nullptr;
  389. }
  390. void* OpenGLComponent::getNativeWindowHandle() const
  391. {
  392. return context != nullptr ? static_cast<WindowedGLContext*> (static_cast<OpenGLContext*> (context))->getNativeWindowHandle() : nullptr;
  393. }
  394. void OpenGLPixelFormat::getAvailablePixelFormats (Component* component,
  395. OwnedArray <OpenGLPixelFormat>& results)
  396. {
  397. Component tempComp;
  398. {
  399. WindowedGLContext wc (component, 0, OpenGLPixelFormat (8, 8, 16, 0));
  400. wc.makeActive();
  401. wc.findAlternativeOpenGLPixelFormats (results);
  402. }
  403. }
  404. //==============================================================================
  405. bool OpenGLHelpers::isContextActive()
  406. {
  407. return wglGetCurrentContext() != 0;
  408. }