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.

249 lines
7.8KB

  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. } // (juce namespace)
  19. @interface JuceGLView : UIView
  20. {
  21. }
  22. + (Class) layerClass;
  23. @end
  24. @implementation JuceGLView
  25. + (Class) layerClass
  26. {
  27. return [CAEAGLLayer class];
  28. }
  29. @end
  30. namespace juce
  31. {
  32. class OpenGLContext::NativeContext
  33. {
  34. public:
  35. NativeContext (Component& component,
  36. const OpenGLPixelFormat& pixelFormat,
  37. const NativeContext* const contextToShareWith)
  38. : frameBufferHandle (0), colorBufferHandle (0), depthBufferHandle (0),
  39. lastWidth (0), lastHeight (0), needToRebuildBuffers (false),
  40. swapFrames (0), useDepthBuffer (pixelFormat.depthBufferBits > 0)
  41. {
  42. JUCE_AUTORELEASEPOOL
  43. ComponentPeer* const peer = component.getPeer();
  44. jassert (peer != nullptr);
  45. const Rectangle<int> bounds (peer->getComponent()->getLocalArea (&component, component.getLocalBounds()));
  46. lastWidth = bounds.getWidth();
  47. lastHeight = bounds.getHeight();
  48. view = [[JuceGLView alloc] initWithFrame: getCGRectFor (bounds)];
  49. view.opaque = YES;
  50. view.hidden = NO;
  51. view.backgroundColor = [UIColor blackColor];
  52. view.userInteractionEnabled = NO;
  53. glLayer = (CAEAGLLayer*) [view layer];
  54. [((UIView*) peer->getNativeHandle()) addSubview: view];
  55. context = [EAGLContext alloc];
  56. const NSUInteger type = kEAGLRenderingAPIOpenGLES2;
  57. if (contextToShareWith != nullptr)
  58. [context initWithAPI: type sharegroup: [contextToShareWith->context sharegroup]];
  59. else
  60. [context initWithAPI: type];
  61. // I'd prefer to put this stuff in the initialiseOnRenderThread() call, but doing
  62. // so causes myserious timing-related failures.
  63. [EAGLContext setCurrentContext: context];
  64. createGLBuffers();
  65. [EAGLContext setCurrentContext: nil];
  66. }
  67. ~NativeContext()
  68. {
  69. [context release];
  70. context = nil;
  71. [view removeFromSuperview];
  72. [view release];
  73. }
  74. void initialiseOnRenderThread()
  75. {
  76. }
  77. void shutdownOnRenderThread()
  78. {
  79. JUCE_CHECK_OPENGL_ERROR
  80. freeGLBuffers();
  81. }
  82. bool createdOk() const noexcept { return getRawContext() != nullptr; }
  83. void* getRawContext() const noexcept { return glLayer; }
  84. GLuint getFrameBufferID() const noexcept { return frameBufferHandle; }
  85. bool makeActive() const noexcept
  86. {
  87. if (! [EAGLContext setCurrentContext: context])
  88. return false;
  89. glBindFramebuffer (GL_FRAMEBUFFER, frameBufferHandle);
  90. return true;
  91. }
  92. bool makeInactive() const noexcept
  93. {
  94. return (! isActive()) || [EAGLContext setCurrentContext: nil];
  95. }
  96. bool isActive() const noexcept
  97. {
  98. return [EAGLContext currentContext] == context;
  99. }
  100. void swapBuffers()
  101. {
  102. glBindRenderbuffer (GL_RENDERBUFFER, colorBufferHandle);
  103. [context presentRenderbuffer: GL_RENDERBUFFER];
  104. if (needToRebuildBuffers)
  105. {
  106. needToRebuildBuffers = false;
  107. freeGLBuffers();
  108. createGLBuffers();
  109. makeActive();
  110. }
  111. }
  112. void updateWindowPosition (const Rectangle<int>& bounds)
  113. {
  114. view.frame = getCGRectFor (bounds);
  115. if (lastWidth != bounds.getWidth() || lastHeight != bounds.getHeight())
  116. {
  117. lastWidth = bounds.getWidth();
  118. lastHeight = bounds.getHeight();
  119. needToRebuildBuffers = true;
  120. }
  121. }
  122. bool setSwapInterval (const int numFramesPerSwap) noexcept
  123. {
  124. swapFrames = numFramesPerSwap;
  125. return false;
  126. }
  127. int getSwapInterval() const noexcept { return swapFrames; }
  128. private:
  129. JuceGLView* view;
  130. CAEAGLLayer* glLayer;
  131. EAGLContext* context;
  132. GLuint frameBufferHandle, colorBufferHandle, depthBufferHandle;
  133. int volatile lastWidth, lastHeight;
  134. bool volatile needToRebuildBuffers;
  135. int swapFrames;
  136. bool useDepthBuffer;
  137. //==============================================================================
  138. static CGRect getCGRectFor (const Rectangle<int>& bounds)
  139. {
  140. return CGRectMake ((CGFloat) bounds.getX(),
  141. (CGFloat) bounds.getY(),
  142. (CGFloat) bounds.getWidth(),
  143. (CGFloat) bounds.getHeight());
  144. }
  145. void createGLBuffers()
  146. {
  147. glGenFramebuffers (1, &frameBufferHandle);
  148. glGenRenderbuffers (1, &colorBufferHandle);
  149. glBindRenderbuffer (GL_RENDERBUFFER, colorBufferHandle);
  150. bool ok = [context renderbufferStorage: GL_RENDERBUFFER fromDrawable: glLayer];
  151. jassert (ok); (void) ok;
  152. if (useDepthBuffer)
  153. {
  154. GLint width, height;
  155. glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
  156. glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
  157. glGenRenderbuffers (1, &depthBufferHandle);
  158. glBindRenderbuffer (GL_RENDERBUFFER, depthBufferHandle);
  159. glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
  160. }
  161. glBindRenderbuffer (GL_RENDERBUFFER, colorBufferHandle);
  162. glBindFramebuffer (GL_FRAMEBUFFER, frameBufferHandle);
  163. glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBufferHandle);
  164. if (useDepthBuffer)
  165. glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBufferHandle);
  166. jassert (glCheckFramebufferStatus (GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
  167. JUCE_CHECK_OPENGL_ERROR
  168. }
  169. void freeGLBuffers()
  170. {
  171. JUCE_CHECK_OPENGL_ERROR
  172. [context renderbufferStorage: GL_RENDERBUFFER fromDrawable: nil];
  173. if (frameBufferHandle != 0)
  174. {
  175. glDeleteFramebuffers (1, &frameBufferHandle);
  176. frameBufferHandle = 0;
  177. }
  178. if (colorBufferHandle != 0)
  179. {
  180. glDeleteRenderbuffers (1, &colorBufferHandle);
  181. colorBufferHandle = 0;
  182. }
  183. if (depthBufferHandle != 0)
  184. {
  185. glDeleteRenderbuffers (1, &depthBufferHandle);
  186. depthBufferHandle = 0;
  187. }
  188. JUCE_CHECK_OPENGL_ERROR
  189. }
  190. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext);
  191. };
  192. //==============================================================================
  193. bool OpenGLHelpers::isContextActive()
  194. {
  195. return [EAGLContext currentContext] != nil;
  196. }