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.

243 lines
7.9KB

  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 JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
  19. METHOD (layout, "layout", "(IIII)V") \
  20. METHOD (requestRender, "requestRender", "()V") \
  21. DECLARE_JNI_CLASS (OpenGLView, JUCE_ANDROID_ACTIVITY_CLASSPATH "$OpenGLView");
  22. #undef JNI_CLASS_MEMBERS
  23. jobject createOpenGLView (ComponentPeer*);
  24. //==============================================================================
  25. class AndroidGLContext : public OpenGLContext
  26. {
  27. public:
  28. AndroidGLContext (OpenGLComponent* const component_,
  29. ComponentPeer* peer,
  30. const OpenGLPixelFormat& pixelFormat,
  31. const AndroidGLContext* const sharedContext,
  32. const bool isGLES2_)
  33. : component (component_),
  34. lastWidth (0), lastHeight (0),
  35. isGLES2 (isGLES2_),
  36. isInsideGLCallback (false)
  37. {
  38. jassert (peer != nullptr);
  39. glView = GlobalRef (createOpenGLView (peer));
  40. const ScopedLock sl (getContextListLock());
  41. getContextList().add (this);
  42. }
  43. ~AndroidGLContext()
  44. {
  45. properties.clear(); // to release any stored programs, etc that may be held in properties.
  46. android.activity.callVoidMethod (JuceAppActivity.deleteView, glView.get());
  47. glView.clear();
  48. const ScopedLock sl (getContextListLock());
  49. getContextList().removeValue (this);
  50. }
  51. //==============================================================================
  52. bool makeActive() const noexcept { return isInsideGLCallback; }
  53. bool makeInactive() const noexcept { return true; }
  54. bool isActive() const noexcept { return isInsideGLCallback; }
  55. void swapBuffers() {}
  56. void* getRawContext() const noexcept { return glView.get(); }
  57. unsigned int getFrameBufferID() const { return 0; }
  58. int getWidth() const { return lastWidth; }
  59. int getHeight() const { return lastHeight; }
  60. bool areShadersAvailable() const { return isGLES2; }
  61. void updateWindowPosition (const Rectangle<int>& bounds)
  62. {
  63. if (lastWidth != bounds.getWidth() || lastHeight != bounds.getHeight())
  64. {
  65. lastWidth = bounds.getWidth();
  66. lastHeight = bounds.getHeight();
  67. glView.callVoidMethod (OpenGLView.layout,
  68. bounds.getX(), bounds.getY(),
  69. bounds.getRight(), bounds.getBottom());
  70. }
  71. }
  72. bool setSwapInterval (const int /*numFramesPerSwap*/) { return false; }
  73. int getSwapInterval() const { return 0; }
  74. //==============================================================================
  75. void contextCreatedCallback()
  76. {
  77. properties.clear();
  78. isInsideGLCallback = true;
  79. if (component != nullptr)
  80. dynamic_cast <OpenGLComponent*> (component.get())->newOpenGLContextCreated();
  81. isInsideGLCallback = false;
  82. }
  83. void renderCallback()
  84. {
  85. isInsideGLCallback = true;
  86. if (component != nullptr)
  87. dynamic_cast <OpenGLComponent*> (component.get())->performRender();
  88. isInsideGLCallback = false;
  89. }
  90. //==============================================================================
  91. static CriticalSection& getContextListLock()
  92. {
  93. static CriticalSection lock;
  94. return lock;
  95. }
  96. static Array<AndroidGLContext*>& getContextList()
  97. {
  98. static Array <AndroidGLContext*> contexts;
  99. return contexts;
  100. }
  101. static AndroidGLContext* findContextFor (JNIEnv* env, jobject glView)
  102. {
  103. const ScopedLock sl (getContextListLock());
  104. const Array<AndroidGLContext*>& contexts = getContextList();
  105. for (int i = contexts.size(); --i >= 0;)
  106. {
  107. AndroidGLContext* const c = contexts.getUnchecked(i);
  108. if (env->IsSameObject (c->glView.get(), glView))
  109. return c;
  110. }
  111. return nullptr;
  112. }
  113. static bool isAnyContextActive()
  114. {
  115. const ScopedLock sl (getContextListLock());
  116. const Array<AndroidGLContext*>& contexts = getContextList();
  117. for (int i = contexts.size(); --i >= 0;)
  118. {
  119. const AndroidGLContext* const c = contexts.getUnchecked(i);
  120. if (c->isInsideGLCallback)
  121. return true;
  122. }
  123. return false;
  124. }
  125. //==============================================================================
  126. GlobalRef glView;
  127. private:
  128. WeakReference<Component> component;
  129. int lastWidth, lastHeight;
  130. bool isGLES2;
  131. bool isInsideGLCallback;
  132. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidGLContext);
  133. };
  134. //==============================================================================
  135. OpenGLContext* OpenGLComponent::createContext()
  136. {
  137. ComponentPeer* peer = getTopLevelComponent()->getPeer();
  138. if (peer != nullptr)
  139. return new AndroidGLContext (this, peer, preferredPixelFormat,
  140. dynamic_cast <const AndroidGLContext*> (contextToShareListsWith),
  141. (flags & openGLES1) == 0);
  142. return nullptr;
  143. }
  144. void OpenGLComponent::updateEmbeddedPosition (const Rectangle<int>& bounds)
  145. {
  146. const ScopedLock sl (contextLock);
  147. if (context != nullptr)
  148. static_cast <AndroidGLContext*> (context.get())->updateWindowPosition (bounds);
  149. }
  150. bool OpenGLHelpers::isContextActive()
  151. {
  152. return AndroidGLContext::isAnyContextActive();
  153. }
  154. void triggerAndroidOpenGLRepaint (OpenGLContext* context)
  155. {
  156. AndroidGLContext* c = dynamic_cast <AndroidGLContext*> (context);
  157. if (c != nullptr)
  158. c->glView.callVoidMethod (OpenGLView.requestRender);
  159. }
  160. //==============================================================================
  161. JUCE_JNI_CALLBACK (JUCE_JOIN_MACRO (JUCE_ANDROID_ACTIVITY_CLASSNAME, _00024OpenGLView), contextCreated, void, (JNIEnv* env, jobject view))
  162. {
  163. JUCE_CHECK_OPENGL_ERROR
  164. for (int i = 100; --i >= 0;)
  165. {
  166. AndroidGLContext* const context = AndroidGLContext::findContextFor (env, view);
  167. if (context != nullptr)
  168. {
  169. context->contextCreatedCallback();
  170. JUCE_CHECK_OPENGL_ERROR
  171. return;
  172. }
  173. Thread::sleep (20);
  174. }
  175. jassertfalse;
  176. }
  177. JUCE_JNI_CALLBACK (JUCE_JOIN_MACRO (JUCE_ANDROID_ACTIVITY_CLASSNAME, _00024OpenGLView), render, void, (JNIEnv* env, jobject view))
  178. {
  179. AndroidGLContext* const context = AndroidGLContext::findContextFor (env, view);
  180. if (context != nullptr)
  181. context->renderCallback();
  182. }