mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-13 00:04:19 +00:00
Added Animated App template and examples
This commit is contained in:
parent
fefcf7aca6
commit
ff6520a89a
1141 changed files with 438491 additions and 94 deletions
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/** These are important openGL values that aren't defined by default
|
||||
by the GL headers on various platforms.
|
||||
*/
|
||||
enum MissingOpenGLDefinitions
|
||||
{
|
||||
#ifndef GL_CLAMP_TO_EDGE
|
||||
GL_CLAMP_TO_EDGE = 0x812f,
|
||||
#endif
|
||||
|
||||
#ifndef GL_NUM_EXTENSIONS
|
||||
GL_NUM_EXTENSIONS = 0x821d,
|
||||
#endif
|
||||
|
||||
#ifndef GL_BGRA_EXT
|
||||
GL_BGRA_EXT = 0x80e1,
|
||||
#endif
|
||||
|
||||
#ifndef GL_DEPTH24_STENCIL8
|
||||
GL_DEPTH24_STENCIL8 = 0x88F0,
|
||||
#endif
|
||||
|
||||
#ifndef GL_RGBA8
|
||||
GL_RGBA8 = GL_RGBA,
|
||||
#endif
|
||||
|
||||
#ifndef GL_COLOR_ATTACHMENT0
|
||||
GL_COLOR_ATTACHMENT0 = 0x8CE0,
|
||||
#endif
|
||||
|
||||
#ifndef GL_DEPTH_ATTACHMENT
|
||||
GL_DEPTH_ATTACHMENT = 0x8D00,
|
||||
#endif
|
||||
|
||||
#ifndef GL_FRAMEBUFFER
|
||||
GL_FRAMEBUFFER = 0x8D40,
|
||||
#endif
|
||||
|
||||
#ifndef GL_FRAMEBUFFER_BINDING
|
||||
GL_FRAMEBUFFER_BINDING = 0x8CA6,
|
||||
#endif
|
||||
|
||||
#ifndef GL_FRAMEBUFFER_COMPLETE
|
||||
GL_FRAMEBUFFER_COMPLETE = 0x8CD5,
|
||||
#endif
|
||||
|
||||
#ifndef GL_RENDERBUFFER
|
||||
GL_RENDERBUFFER = 0x8D41,
|
||||
#endif
|
||||
|
||||
#ifndef GL_RENDERBUFFER_DEPTH_SIZE
|
||||
GL_RENDERBUFFER_DEPTH_SIZE = 0x8D54,
|
||||
#endif
|
||||
|
||||
#ifndef GL_STENCIL_ATTACHMENT
|
||||
GL_STENCIL_ATTACHMENT = 0x8D20,
|
||||
#endif
|
||||
|
||||
#if JUCE_WINDOWS && ! defined (GL_TEXTURE0)
|
||||
GL_OPERAND0_RGB = 0x8590,
|
||||
GL_OPERAND1_RGB = 0x8591,
|
||||
GL_OPERAND0_ALPHA = 0x8598,
|
||||
GL_OPERAND1_ALPHA = 0x8599,
|
||||
GL_SRC0_RGB = 0x8580,
|
||||
GL_SRC1_RGB = 0x8581,
|
||||
GL_SRC0_ALPHA = 0x8588,
|
||||
GL_SRC1_ALPHA = 0x8589,
|
||||
GL_TEXTURE0 = 0x84C0,
|
||||
GL_TEXTURE1 = 0x84C1,
|
||||
GL_TEXTURE2 = 0x84C2,
|
||||
GL_COMBINE = 0x8570,
|
||||
GL_COMBINE_RGB = 0x8571,
|
||||
GL_COMBINE_ALPHA = 0x8572,
|
||||
GL_PREVIOUS = 0x8578,
|
||||
GL_COMPILE_STATUS = 0x8B81,
|
||||
GL_LINK_STATUS = 0x8B82,
|
||||
GL_SHADING_LANGUAGE_VERSION = 0x8B8C,
|
||||
GL_FRAGMENT_SHADER = 0x8B30,
|
||||
GL_VERTEX_SHADER = 0x8B31,
|
||||
GL_ARRAY_BUFFER = 0x8892,
|
||||
GL_ELEMENT_ARRAY_BUFFER = 0x8893,
|
||||
GL_STATIC_DRAW = 0x88E4,
|
||||
GL_DYNAMIC_DRAW = 0x88E8,
|
||||
GL_STREAM_DRAW = 0x88E0,
|
||||
|
||||
WGL_NUMBER_PIXEL_FORMATS_ARB = 0x2000,
|
||||
WGL_DRAW_TO_WINDOW_ARB = 0x2001,
|
||||
WGL_ACCELERATION_ARB = 0x2003,
|
||||
WGL_SWAP_METHOD_ARB = 0x2007,
|
||||
WGL_SUPPORT_OPENGL_ARB = 0x2010,
|
||||
WGL_PIXEL_TYPE_ARB = 0x2013,
|
||||
WGL_DOUBLE_BUFFER_ARB = 0x2011,
|
||||
WGL_COLOR_BITS_ARB = 0x2014,
|
||||
WGL_RED_BITS_ARB = 0x2015,
|
||||
WGL_GREEN_BITS_ARB = 0x2017,
|
||||
WGL_BLUE_BITS_ARB = 0x2019,
|
||||
WGL_ALPHA_BITS_ARB = 0x201B,
|
||||
WGL_DEPTH_BITS_ARB = 0x2022,
|
||||
WGL_STENCIL_BITS_ARB = 0x2023,
|
||||
WGL_FULL_ACCELERATION_ARB = 0x2027,
|
||||
WGL_ACCUM_RED_BITS_ARB = 0x201E,
|
||||
WGL_ACCUM_GREEN_BITS_ARB = 0x201F,
|
||||
WGL_ACCUM_BLUE_BITS_ARB = 0x2020,
|
||||
WGL_ACCUM_ALPHA_BITS_ARB = 0x2021,
|
||||
WGL_STEREO_ARB = 0x2012,
|
||||
WGL_SAMPLE_BUFFERS_ARB = 0x2041,
|
||||
WGL_SAMPLES_ARB = 0x2042,
|
||||
WGL_TYPE_RGBA_ARB = 0x202B,
|
||||
WGL_CONTEXT_MAJOR_VERSION_ARB = 0x2091,
|
||||
WGL_CONTEXT_MINOR_VERSION_ARB = 0x2092,
|
||||
WGL_CONTEXT_PROFILE_MASK_ARB = 0x9126,
|
||||
#endif
|
||||
|
||||
#if JUCE_ANDROID
|
||||
JUCE_RGBA_FORMAT = GL_RGBA
|
||||
#else
|
||||
JUCE_RGBA_FORMAT = GL_BGRA_EXT
|
||||
#endif
|
||||
};
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
typedef char GLchar;
|
||||
typedef pointer_sized_int GLsizeiptr;
|
||||
typedef pointer_sized_int GLintptr;
|
||||
#endif
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef JUCE_OPENGLEXTENSIONS_H_INCLUDED
|
||||
#define JUCE_OPENGLEXTENSIONS_H_INCLUDED
|
||||
|
||||
#if JUCE_MAC && (JUCE_PPC || ((! defined (MAC_OS_X_VERSION_10_6)) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6))
|
||||
#define JUCE_EXT(func) func ## EXT
|
||||
#else
|
||||
#define JUCE_EXT(func) func
|
||||
#endif
|
||||
|
||||
/** @internal This macro contains a list of GL extension functions that need to be dynamically loaded on Windows/Linux.
|
||||
@see OpenGLExtensionFunctions
|
||||
*/
|
||||
#define JUCE_GL_EXTENSION_FUNCTIONS(USE_FUNCTION, EXT_FUNCTION) \
|
||||
USE_FUNCTION (glActiveTexture, void, (GLenum p1), (p1))\
|
||||
USE_FUNCTION (glBindBuffer, void, (GLenum p1, GLuint p2), (p1, p2))\
|
||||
USE_FUNCTION (glDeleteBuffers, void, (GLsizei p1, const GLuint* p2), (p1, p2))\
|
||||
USE_FUNCTION (glGenBuffers, void, (GLsizei p1, GLuint* p2), (p1, p2))\
|
||||
USE_FUNCTION (glBufferData, void, (GLenum p1, GLsizeiptr p2, const GLvoid* p3, GLenum p4), (p1, p2, p3, p4))\
|
||||
USE_FUNCTION (glBufferSubData, void, (GLenum p1, GLintptr p2, GLsizeiptr p3, const GLvoid* p4), (p1, p2, p3, p4))\
|
||||
EXT_FUNCTION (glIsRenderbuffer, GLboolean, (GLuint p1), (p1))\
|
||||
EXT_FUNCTION (glBindRenderbuffer, void, (GLenum p1, GLuint p2), (p1, p2))\
|
||||
EXT_FUNCTION (glDeleteRenderbuffers, void, (GLsizei p1, const GLuint* p2), (p1, p2))\
|
||||
EXT_FUNCTION (glGenRenderbuffers, void, (GLsizei p1, GLuint* p2), (p1, p2))\
|
||||
EXT_FUNCTION (glRenderbufferStorage, void, (GLenum p1, GLenum p2, GLsizei p3, GLsizei p4), (p1, p2, p3, p4))\
|
||||
EXT_FUNCTION (glGetRenderbufferParameteriv, void, (GLenum p1, GLenum p2, GLint* p3), (p1, p2, p3))\
|
||||
EXT_FUNCTION (glIsFramebuffer, GLboolean, (GLuint p1), (p1))\
|
||||
EXT_FUNCTION (glBindFramebuffer, void, (GLenum p1, GLuint p2), (p1, p2))\
|
||||
EXT_FUNCTION (glDeleteFramebuffers, void, (GLsizei p1, const GLuint* p2), (p1, p2))\
|
||||
EXT_FUNCTION (glGenFramebuffers, void, (GLsizei p1, GLuint* p2), (p1, p2))\
|
||||
EXT_FUNCTION (glCheckFramebufferStatus, GLenum, (GLenum p1), (p1))\
|
||||
EXT_FUNCTION (glFramebufferTexture2D, void, (GLenum p1, GLenum p2, GLenum p3, GLuint p4, GLint p5), (p1, p2, p3, p4, p5))\
|
||||
EXT_FUNCTION (glFramebufferRenderbuffer, void, (GLenum p1, GLenum p2, GLenum p3, GLuint p4), (p1, p2, p3, p4))\
|
||||
EXT_FUNCTION (glGetFramebufferAttachmentParameteriv, void, (GLenum p1, GLenum p2, GLenum p3, GLint* p4), (p1, p2, p3, p4))\
|
||||
USE_FUNCTION (glCreateProgram, GLuint, (), ())\
|
||||
USE_FUNCTION (glDeleteProgram, void, (GLuint p1), (p1))\
|
||||
USE_FUNCTION (glCreateShader, GLuint, (GLenum p1), (p1))\
|
||||
USE_FUNCTION (glDeleteShader, void, (GLuint p1), (p1))\
|
||||
USE_FUNCTION (glShaderSource, void, (GLuint p1, GLsizei p2, const GLchar** p3, const GLint* p4), (p1, p2, p3, p4))\
|
||||
USE_FUNCTION (glCompileShader, void, (GLuint p1), (p1))\
|
||||
USE_FUNCTION (glAttachShader, void, (GLuint p1, GLuint p2), (p1, p2))\
|
||||
USE_FUNCTION (glLinkProgram, void, (GLuint p1), (p1))\
|
||||
USE_FUNCTION (glUseProgram, void, (GLuint p1), (p1))\
|
||||
USE_FUNCTION (glGetShaderiv, void, (GLuint p1, GLenum p2, GLint* p3), (p1, p2, p3))\
|
||||
USE_FUNCTION (glGetShaderInfoLog, void, (GLuint p1, GLsizei p2, GLsizei* p3, GLchar* p4), (p1, p2, p3, p4))\
|
||||
USE_FUNCTION (glGetProgramInfoLog, void, (GLuint p1, GLsizei p2, GLsizei* p3, GLchar* p4), (p1, p2, p3, p4))\
|
||||
USE_FUNCTION (glGetProgramiv, void, (GLuint p1, GLenum p2, GLint* p3), (p1, p2, p3))\
|
||||
USE_FUNCTION (glGetUniformLocation, GLint, (GLuint p1, const GLchar* p2), (p1, p2))\
|
||||
USE_FUNCTION (glGetAttribLocation, GLint, (GLuint p1, const GLchar* p2), (p1, p2))\
|
||||
USE_FUNCTION (glVertexAttribPointer, void, (GLuint p1, GLint p2, GLenum p3, GLboolean p4, GLsizei p5, const GLvoid* p6), (p1, p2, p3, p4, p5, p6))\
|
||||
USE_FUNCTION (glEnableVertexAttribArray, void, (GLuint p1), (p1))\
|
||||
USE_FUNCTION (glDisableVertexAttribArray, void, (GLuint p1), (p1))\
|
||||
USE_FUNCTION (glUniform1f, void, (GLint p1, GLfloat p2), (p1, p2))\
|
||||
USE_FUNCTION (glUniform1i, void, (GLint p1, GLint p2), (p1, p2))\
|
||||
USE_FUNCTION (glUniform2f, void, (GLint p1, GLfloat p2, GLfloat p3), (p1, p2, p3))\
|
||||
USE_FUNCTION (glUniform3f, void, (GLint p1, GLfloat p2, GLfloat p3, GLfloat p4), (p1, p2, p3, p4))\
|
||||
USE_FUNCTION (glUniform4f, void, (GLint p1, GLfloat p2, GLfloat p3, GLfloat p4, GLfloat p5), (p1, p2, p3, p4, p5))\
|
||||
USE_FUNCTION (glUniform4i, void, (GLint p1, GLint p2, GLint p3, GLint p4, GLint p5), (p1, p2, p3, p4, p5))\
|
||||
USE_FUNCTION (glUniform1fv, void, (GLint p1, GLsizei p2, const GLfloat* p3), (p1, p2, p3))\
|
||||
USE_FUNCTION (glUniformMatrix2fv, void, (GLint p1, GLsizei p2, GLboolean p3, const GLfloat* p4), (p1, p2, p3, p4))\
|
||||
USE_FUNCTION (glUniformMatrix3fv, void, (GLint p1, GLsizei p2, GLboolean p3, const GLfloat* p4), (p1, p2, p3, p4))\
|
||||
USE_FUNCTION (glUniformMatrix4fv, void, (GLint p1, GLsizei p2, GLboolean p3, const GLfloat* p4), (p1, p2, p3, p4))
|
||||
|
||||
|
||||
/** This class contains a generated list of OpenGL extension functions, which are either dynamically loaded
|
||||
for a specific GL context, or simply call-through to the appropriate OS function where available.
|
||||
*/
|
||||
struct OpenGLExtensionFunctions
|
||||
{
|
||||
void initialise();
|
||||
|
||||
#if JUCE_WINDOWS && ! DOXYGEN
|
||||
typedef char GLchar;
|
||||
typedef pointer_sized_int GLsizeiptr;
|
||||
typedef pointer_sized_int GLintptr;
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_WINDOWS
|
||||
#define JUCE_DECLARE_GL_FUNCTION(name, returnType, params, callparams) typedef returnType (__stdcall *type_ ## name) params; type_ ## name name;
|
||||
JUCE_GL_EXTENSION_FUNCTIONS (JUCE_DECLARE_GL_FUNCTION, JUCE_DECLARE_GL_FUNCTION)
|
||||
//==============================================================================
|
||||
#elif JUCE_LINUX
|
||||
#define JUCE_DECLARE_GL_FUNCTION(name, returnType, params, callparams) typedef returnType (*type_ ## name) params; type_ ## name name;
|
||||
JUCE_GL_EXTENSION_FUNCTIONS (JUCE_DECLARE_GL_FUNCTION, JUCE_DECLARE_GL_FUNCTION)
|
||||
//==============================================================================
|
||||
#elif JUCE_OPENGL_ES
|
||||
#define JUCE_DECLARE_GL_FUNCTION(name, returnType, params, callparams) static returnType name params;
|
||||
JUCE_GL_EXTENSION_FUNCTIONS (JUCE_DECLARE_GL_FUNCTION, JUCE_DECLARE_GL_FUNCTION)
|
||||
//==============================================================================
|
||||
#else
|
||||
#define JUCE_DECLARE_GL_FUNCTION(name, returnType, params, callparams) inline static returnType name params { return ::name callparams; }
|
||||
#if JUCE_OPENGL3
|
||||
JUCE_GL_EXTENSION_FUNCTIONS (JUCE_DECLARE_GL_FUNCTION, JUCE_DECLARE_GL_FUNCTION)
|
||||
#else
|
||||
#define JUCE_DECLARE_GL_FUNCTION_EXT(name, returnType, params, callparams) inline static returnType name params { return ::name ## EXT callparams; }
|
||||
JUCE_GL_EXTENSION_FUNCTIONS (JUCE_DECLARE_GL_FUNCTION, JUCE_DECLARE_GL_FUNCTION_EXT)
|
||||
#undef JUCE_DECLARE_GL_FUNCTION_EXT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#undef JUCE_DECLARE_GL_FUNCTION
|
||||
};
|
||||
|
||||
#endif // JUCE_OPENGLEXTENSIONS_H_INCLUDED
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||
METHOD (layout, "layout", "(IIII)V") \
|
||||
METHOD (requestRender, "requestRender", "()V") \
|
||||
|
||||
DECLARE_JNI_CLASS (OpenGLView, JUCE_ANDROID_ACTIVITY_CLASSPATH "$OpenGLView");
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
extern jobject createOpenGLView (ComponentPeer*);
|
||||
|
||||
//==============================================================================
|
||||
class OpenGLContext::NativeContext
|
||||
{
|
||||
public:
|
||||
NativeContext (Component& comp,
|
||||
const OpenGLPixelFormat& pixelFormat,
|
||||
void* /*contextToShareWith*/,
|
||||
bool /*useMultisampling*/,
|
||||
OpenGLVersion)
|
||||
: component (comp),
|
||||
isInsideGLCallback (false)
|
||||
{
|
||||
{
|
||||
const ScopedLock sl (contextListLock);
|
||||
glView = GlobalRef (createOpenGLView (component.getPeer()));
|
||||
contextList.add (this);
|
||||
}
|
||||
|
||||
updateWindowPosition (component.getTopLevelComponent()
|
||||
->getLocalArea (&component, component.getLocalBounds()));
|
||||
}
|
||||
|
||||
~NativeContext()
|
||||
{
|
||||
{
|
||||
const ScopedLock sl (contextListLock);
|
||||
contextList.removeFirstMatchingValue (this);
|
||||
}
|
||||
|
||||
android.activity.callVoidMethod (JuceAppActivity.deleteView, glView.get());
|
||||
glView.clear();
|
||||
}
|
||||
|
||||
void initialiseOnRenderThread (OpenGLContext&) {}
|
||||
void shutdownOnRenderThread() {}
|
||||
|
||||
bool makeActive() const noexcept { return isInsideGLCallback; }
|
||||
bool isActive() const noexcept { return isInsideGLCallback; }
|
||||
static void deactivateCurrentContext() {}
|
||||
|
||||
void swapBuffers() const noexcept {}
|
||||
bool setSwapInterval (const int) { return false; }
|
||||
int getSwapInterval() const { return 0; }
|
||||
|
||||
bool createdOk() const noexcept { return getRawContext() != nullptr; }
|
||||
void* getRawContext() const noexcept { return glView.get(); }
|
||||
GLuint getFrameBufferID() const noexcept { return 0; }
|
||||
|
||||
void updateWindowPosition (const Rectangle<int>& bounds)
|
||||
{
|
||||
if (lastBounds != bounds)
|
||||
{
|
||||
lastBounds = bounds;
|
||||
glView.callVoidMethod (OpenGLView.layout,
|
||||
bounds.getX(), bounds.getY(),
|
||||
bounds.getRight(), bounds.getBottom());
|
||||
}
|
||||
}
|
||||
|
||||
void triggerRepaint()
|
||||
{
|
||||
glView.callVoidMethod (OpenGLView.requestRender);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void contextCreatedCallback();
|
||||
void contextChangedSize() {}
|
||||
void renderCallback();
|
||||
|
||||
//==============================================================================
|
||||
static NativeContext* findContextFor (JNIEnv* env, jobject glView)
|
||||
{
|
||||
const ScopedLock sl (contextListLock);
|
||||
|
||||
for (int i = contextList.size(); --i >= 0;)
|
||||
{
|
||||
NativeContext* const c = contextList.getUnchecked(i);
|
||||
|
||||
if (env->IsSameObject (c->glView.get(), glView))
|
||||
return c;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static NativeContext* getActiveContext() noexcept
|
||||
{
|
||||
const ScopedLock sl (contextListLock);
|
||||
|
||||
for (int i = contextList.size(); --i >= 0;)
|
||||
{
|
||||
NativeContext* const c = contextList.getUnchecked(i);
|
||||
|
||||
if (c->isInsideGLCallback)
|
||||
return c;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
struct Locker { Locker (NativeContext&) {} };
|
||||
|
||||
Component& component;
|
||||
|
||||
private:
|
||||
GlobalRef glView;
|
||||
Rectangle<int> lastBounds;
|
||||
bool isInsideGLCallback;
|
||||
|
||||
typedef Array<NativeContext*> ContextArray;
|
||||
static CriticalSection contextListLock;
|
||||
static ContextArray contextList;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
|
||||
};
|
||||
|
||||
CriticalSection OpenGLContext::NativeContext::contextListLock;
|
||||
OpenGLContext::NativeContext::ContextArray OpenGLContext::NativeContext::contextList;
|
||||
|
||||
//==============================================================================
|
||||
bool OpenGLHelpers::isContextActive()
|
||||
{
|
||||
return OpenGLContext::NativeContext::getActiveContext() != nullptr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#define GL_VIEW_CLASS_NAME JUCE_JOIN_MACRO (JUCE_ANDROID_ACTIVITY_CLASSNAME, _00024OpenGLView)
|
||||
|
||||
JUCE_JNI_CALLBACK (GL_VIEW_CLASS_NAME, contextCreated, void, (JNIEnv* env, jobject view))
|
||||
{
|
||||
threadLocalJNIEnvHolder.getOrAttach();
|
||||
|
||||
if (OpenGLContext::NativeContext* const context = OpenGLContext::NativeContext::findContextFor (env, view))
|
||||
context->contextCreatedCallback();
|
||||
else
|
||||
jassertfalse;
|
||||
}
|
||||
|
||||
JUCE_JNI_CALLBACK (GL_VIEW_CLASS_NAME, contextChangedSize, void, (JNIEnv* env, jobject view))
|
||||
{
|
||||
if (OpenGLContext::NativeContext* const context = OpenGLContext::NativeContext::findContextFor (env, view))
|
||||
context->contextChangedSize();
|
||||
}
|
||||
|
||||
JUCE_JNI_CALLBACK (GL_VIEW_CLASS_NAME, render, void, (JNIEnv* env, jobject view))
|
||||
{
|
||||
if (OpenGLContext::NativeContext* const context = OpenGLContext::NativeContext::findContextFor (env, view))
|
||||
context->renderCallback();
|
||||
}
|
||||
|
|
@ -0,0 +1,294 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
} // (juce namespace)
|
||||
|
||||
@interface JuceGLView : UIView
|
||||
{
|
||||
}
|
||||
+ (Class) layerClass;
|
||||
@end
|
||||
|
||||
@implementation JuceGLView
|
||||
+ (Class) layerClass
|
||||
{
|
||||
return [CAEAGLLayer class];
|
||||
}
|
||||
@end
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
class OpenGLContext::NativeContext
|
||||
{
|
||||
public:
|
||||
NativeContext (Component& component,
|
||||
const OpenGLPixelFormat& pixFormat,
|
||||
void* contextToShare,
|
||||
bool multisampling,
|
||||
OpenGLVersion version)
|
||||
: context (nil), frameBufferHandle (0), colorBufferHandle (0),
|
||||
depthBufferHandle (0), msaaColorHandle (0), msaaBufferHandle (0),
|
||||
lastWidth (0), lastHeight (0), needToRebuildBuffers (false),
|
||||
swapFrames (0), useDepthBuffer (pixFormat.depthBufferBits > 0),
|
||||
useMSAA (multisampling)
|
||||
{
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
ComponentPeer* const peer = component.getPeer();
|
||||
jassert (peer != nullptr);
|
||||
|
||||
const Rectangle<int> bounds (peer->getComponent().getLocalArea (&component, component.getLocalBounds()));
|
||||
lastWidth = bounds.getWidth();
|
||||
lastHeight = bounds.getHeight();
|
||||
|
||||
view = [[JuceGLView alloc] initWithFrame: convertToCGRect (bounds)];
|
||||
view.opaque = YES;
|
||||
view.hidden = NO;
|
||||
view.backgroundColor = [UIColor blackColor];
|
||||
view.userInteractionEnabled = NO;
|
||||
|
||||
glLayer = (CAEAGLLayer*) [view layer];
|
||||
glLayer.contentsScale = Desktop::getInstance().getDisplays().getMainDisplay().scale;
|
||||
glLayer.opaque = true;
|
||||
|
||||
[((UIView*) peer->getNativeHandle()) addSubview: view];
|
||||
|
||||
#if defined (__IPHONE_7_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_7_0
|
||||
if (version == OpenGLContext::openGL3_2 && [[UIDevice currentDevice].systemVersion floatValue] >= 7.0)
|
||||
{
|
||||
if (! createContext (kEAGLRenderingAPIOpenGLES3, contextToShare))
|
||||
{
|
||||
releaseContext();
|
||||
createContext (kEAGLRenderingAPIOpenGLES2, contextToShare);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
createContext (kEAGLRenderingAPIOpenGLES2, contextToShare);
|
||||
}
|
||||
|
||||
jassert (context != nil);
|
||||
|
||||
// I'd prefer to put this stuff in the initialiseOnRenderThread() call, but doing
|
||||
// so causes myserious timing-related failures.
|
||||
[EAGLContext setCurrentContext: context];
|
||||
createGLBuffers();
|
||||
deactivateCurrentContext();
|
||||
}
|
||||
}
|
||||
|
||||
~NativeContext()
|
||||
{
|
||||
releaseContext();
|
||||
[view removeFromSuperview];
|
||||
[view release];
|
||||
}
|
||||
|
||||
void initialiseOnRenderThread (OpenGLContext&) {}
|
||||
|
||||
void shutdownOnRenderThread()
|
||||
{
|
||||
JUCE_CHECK_OPENGL_ERROR
|
||||
freeGLBuffers();
|
||||
deactivateCurrentContext();
|
||||
}
|
||||
|
||||
bool createdOk() const noexcept { return getRawContext() != nullptr; }
|
||||
void* getRawContext() const noexcept { return context; }
|
||||
GLuint getFrameBufferID() const noexcept { return useMSAA ? msaaBufferHandle : frameBufferHandle; }
|
||||
|
||||
bool makeActive() const noexcept
|
||||
{
|
||||
if (! [EAGLContext setCurrentContext: context])
|
||||
return false;
|
||||
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, useMSAA ? msaaBufferHandle
|
||||
: frameBufferHandle);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isActive() const noexcept
|
||||
{
|
||||
return [EAGLContext currentContext] == context;
|
||||
}
|
||||
|
||||
static void deactivateCurrentContext()
|
||||
{
|
||||
[EAGLContext setCurrentContext: nil];
|
||||
}
|
||||
|
||||
void swapBuffers()
|
||||
{
|
||||
if (useMSAA)
|
||||
{
|
||||
glBindFramebuffer (GL_DRAW_FRAMEBUFFER, frameBufferHandle);
|
||||
glBindFramebuffer (GL_READ_FRAMEBUFFER, msaaBufferHandle);
|
||||
|
||||
#if defined (__IPHONE_7_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_7_0
|
||||
glBlitFramebuffer (0, 0, lastWidth, lastHeight, 0, 0, lastWidth, lastHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
#else
|
||||
glResolveMultisampleFramebufferAPPLE();
|
||||
#endif
|
||||
}
|
||||
|
||||
glBindRenderbuffer (GL_RENDERBUFFER, colorBufferHandle);
|
||||
[context presentRenderbuffer: GL_RENDERBUFFER];
|
||||
|
||||
if (needToRebuildBuffers)
|
||||
{
|
||||
needToRebuildBuffers = false;
|
||||
|
||||
freeGLBuffers();
|
||||
createGLBuffers();
|
||||
makeActive();
|
||||
}
|
||||
}
|
||||
|
||||
void updateWindowPosition (const Rectangle<int>& bounds)
|
||||
{
|
||||
view.frame = convertToCGRect (bounds);
|
||||
|
||||
if (lastWidth != bounds.getWidth() || lastHeight != bounds.getHeight())
|
||||
{
|
||||
lastWidth = bounds.getWidth();
|
||||
lastHeight = bounds.getHeight();
|
||||
needToRebuildBuffers = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool setSwapInterval (const int numFramesPerSwap) noexcept
|
||||
{
|
||||
swapFrames = numFramesPerSwap;
|
||||
return false;
|
||||
}
|
||||
|
||||
int getSwapInterval() const noexcept { return swapFrames; }
|
||||
|
||||
struct Locker { Locker (NativeContext&) {} };
|
||||
|
||||
private:
|
||||
JuceGLView* view;
|
||||
CAEAGLLayer* glLayer;
|
||||
EAGLContext* context;
|
||||
GLuint frameBufferHandle, colorBufferHandle, depthBufferHandle,
|
||||
msaaColorHandle, msaaBufferHandle;
|
||||
|
||||
int volatile lastWidth, lastHeight;
|
||||
bool volatile needToRebuildBuffers;
|
||||
int swapFrames;
|
||||
bool useDepthBuffer, useMSAA;
|
||||
|
||||
bool createContext (EAGLRenderingAPI type, void* contextToShare)
|
||||
{
|
||||
jassert (context == nil);
|
||||
context = [EAGLContext alloc];
|
||||
|
||||
context = contextToShare != nullptr
|
||||
? [context initWithAPI: type sharegroup: [(EAGLContext*) contextToShare sharegroup]]
|
||||
: [context initWithAPI: type];
|
||||
|
||||
return context != nil;
|
||||
}
|
||||
|
||||
void releaseContext()
|
||||
{
|
||||
[context release];
|
||||
context = nil;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void createGLBuffers()
|
||||
{
|
||||
glGenFramebuffers (1, &frameBufferHandle);
|
||||
glGenRenderbuffers (1, &colorBufferHandle);
|
||||
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, frameBufferHandle);
|
||||
glBindRenderbuffer (GL_RENDERBUFFER, colorBufferHandle);
|
||||
|
||||
glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBufferHandle);
|
||||
|
||||
bool ok = [context renderbufferStorage: GL_RENDERBUFFER fromDrawable: glLayer];
|
||||
jassert (ok); (void) ok;
|
||||
|
||||
GLint width, height;
|
||||
glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
|
||||
glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
|
||||
|
||||
if (useMSAA)
|
||||
{
|
||||
glGenFramebuffers (1, &msaaBufferHandle);
|
||||
glGenRenderbuffers (1, &msaaColorHandle);
|
||||
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, msaaBufferHandle);
|
||||
glBindRenderbuffer (GL_RENDERBUFFER, msaaColorHandle);
|
||||
|
||||
glRenderbufferStorageMultisample (GL_RENDERBUFFER, 4, GL_RGBA8, width, height);
|
||||
|
||||
glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, msaaColorHandle);
|
||||
}
|
||||
|
||||
if (useDepthBuffer)
|
||||
{
|
||||
glGenRenderbuffers (1, &depthBufferHandle);
|
||||
glBindRenderbuffer (GL_RENDERBUFFER, depthBufferHandle);
|
||||
|
||||
if (useMSAA)
|
||||
glRenderbufferStorageMultisample (GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, width, height);
|
||||
else
|
||||
glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
|
||||
|
||||
glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBufferHandle);
|
||||
}
|
||||
|
||||
jassert (glCheckFramebufferStatus (GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
|
||||
JUCE_CHECK_OPENGL_ERROR
|
||||
}
|
||||
|
||||
void freeGLBuffers()
|
||||
{
|
||||
JUCE_CHECK_OPENGL_ERROR
|
||||
[context renderbufferStorage: GL_RENDERBUFFER fromDrawable: nil];
|
||||
|
||||
deleteFrameBuffer (frameBufferHandle);
|
||||
deleteFrameBuffer (msaaBufferHandle);
|
||||
deleteRenderBuffer (colorBufferHandle);
|
||||
deleteRenderBuffer (depthBufferHandle);
|
||||
deleteRenderBuffer (msaaColorHandle);
|
||||
|
||||
JUCE_CHECK_OPENGL_ERROR
|
||||
}
|
||||
|
||||
static void deleteFrameBuffer (GLuint& i) { if (i != 0) glDeleteFramebuffers (1, &i); i = 0; }
|
||||
static void deleteRenderBuffer (GLuint& i) { if (i != 0) glDeleteRenderbuffers (1, &i); i = 0; }
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
bool OpenGLHelpers::isContextActive()
|
||||
{
|
||||
return [EAGLContext currentContext] != nil;
|
||||
}
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
extern Display* display;
|
||||
extern XContext windowHandleXContext;
|
||||
|
||||
//==============================================================================
|
||||
class OpenGLContext::NativeContext
|
||||
{
|
||||
public:
|
||||
NativeContext (Component& component,
|
||||
const OpenGLPixelFormat& pixelFormat,
|
||||
void* shareContext,
|
||||
bool /*useMultisampling*/,
|
||||
OpenGLVersion)
|
||||
: renderContext (0), embeddedWindow (0), swapFrames (0), bestVisual (0),
|
||||
contextToShareWith (shareContext)
|
||||
{
|
||||
ScopedXLock xlock;
|
||||
XSync (display, False);
|
||||
|
||||
GLint attribs[] =
|
||||
{
|
||||
GLX_RGBA,
|
||||
GLX_DOUBLEBUFFER,
|
||||
GLX_RED_SIZE, pixelFormat.redBits,
|
||||
GLX_GREEN_SIZE, pixelFormat.greenBits,
|
||||
GLX_BLUE_SIZE, pixelFormat.blueBits,
|
||||
GLX_ALPHA_SIZE, pixelFormat.alphaBits,
|
||||
GLX_DEPTH_SIZE, pixelFormat.depthBufferBits,
|
||||
GLX_STENCIL_SIZE, pixelFormat.stencilBufferBits,
|
||||
GLX_ACCUM_RED_SIZE, pixelFormat.accumulationBufferRedBits,
|
||||
GLX_ACCUM_GREEN_SIZE, pixelFormat.accumulationBufferGreenBits,
|
||||
GLX_ACCUM_BLUE_SIZE, pixelFormat.accumulationBufferBlueBits,
|
||||
GLX_ACCUM_ALPHA_SIZE, pixelFormat.accumulationBufferAlphaBits,
|
||||
None
|
||||
};
|
||||
|
||||
bestVisual = glXChooseVisual (display, DefaultScreen (display), attribs);
|
||||
if (bestVisual == nullptr)
|
||||
return;
|
||||
|
||||
ComponentPeer* const peer = component.getPeer();
|
||||
Window windowH = (Window) peer->getNativeHandle();
|
||||
|
||||
Colormap colourMap = XCreateColormap (display, windowH, bestVisual->visual, AllocNone);
|
||||
XSetWindowAttributes swa;
|
||||
swa.colormap = colourMap;
|
||||
swa.border_pixel = 0;
|
||||
swa.event_mask = ExposureMask | StructureNotifyMask;
|
||||
|
||||
const Rectangle<int> bounds (component.getTopLevelComponent()
|
||||
->getLocalArea (&component, component.getLocalBounds()));
|
||||
|
||||
embeddedWindow = XCreateWindow (display, windowH,
|
||||
bounds.getX(), bounds.getY(),
|
||||
jmax (1, bounds.getWidth()),
|
||||
jmax (1, bounds.getHeight()),
|
||||
0, bestVisual->depth,
|
||||
InputOutput,
|
||||
bestVisual->visual,
|
||||
CWBorderPixel | CWColormap | CWEventMask,
|
||||
&swa);
|
||||
|
||||
XSaveContext (display, (XID) embeddedWindow, windowHandleXContext, (XPointer) peer);
|
||||
|
||||
XMapWindow (display, embeddedWindow);
|
||||
XFreeColormap (display, colourMap);
|
||||
|
||||
XSync (display, False);
|
||||
}
|
||||
|
||||
~NativeContext()
|
||||
{
|
||||
if (embeddedWindow != 0)
|
||||
{
|
||||
ScopedXLock xlock;
|
||||
XUnmapWindow (display, embeddedWindow);
|
||||
XDestroyWindow (display, embeddedWindow);
|
||||
}
|
||||
|
||||
if (bestVisual != nullptr)
|
||||
XFree (bestVisual);
|
||||
}
|
||||
|
||||
void initialiseOnRenderThread (OpenGLContext& context)
|
||||
{
|
||||
ScopedXLock xlock;
|
||||
renderContext = glXCreateContext (display, bestVisual, (GLXContext) contextToShareWith, GL_TRUE);
|
||||
context.makeActive();
|
||||
}
|
||||
|
||||
void shutdownOnRenderThread()
|
||||
{
|
||||
deactivateCurrentContext();
|
||||
glXDestroyContext (display, renderContext);
|
||||
renderContext = nullptr;
|
||||
}
|
||||
|
||||
bool makeActive() const noexcept
|
||||
{
|
||||
return renderContext != 0
|
||||
&& glXMakeCurrent (display, embeddedWindow, renderContext);
|
||||
}
|
||||
|
||||
bool isActive() const noexcept
|
||||
{
|
||||
return glXGetCurrentContext() == renderContext && renderContext != 0;
|
||||
}
|
||||
|
||||
static void deactivateCurrentContext()
|
||||
{
|
||||
glXMakeCurrent (display, None, 0);
|
||||
}
|
||||
|
||||
void swapBuffers()
|
||||
{
|
||||
glXSwapBuffers (display, embeddedWindow);
|
||||
}
|
||||
|
||||
void updateWindowPosition (const Rectangle<int>& newBounds)
|
||||
{
|
||||
bounds = newBounds;
|
||||
|
||||
ScopedXLock xlock;
|
||||
XMoveResizeWindow (display, embeddedWindow,
|
||||
bounds.getX(), bounds.getY(),
|
||||
jmax (1, bounds.getWidth()),
|
||||
jmax (1, bounds.getHeight()));
|
||||
}
|
||||
|
||||
bool setSwapInterval (int numFramesPerSwap)
|
||||
{
|
||||
if (numFramesPerSwap == swapFrames)
|
||||
return true;
|
||||
|
||||
PFNGLXSWAPINTERVALSGIPROC GLXSwapIntervalSGI
|
||||
= (PFNGLXSWAPINTERVALSGIPROC) OpenGLHelpers::getExtensionFunction ("glXSwapIntervalSGI");
|
||||
|
||||
if (GLXSwapIntervalSGI != nullptr)
|
||||
{
|
||||
swapFrames = numFramesPerSwap;
|
||||
GLXSwapIntervalSGI (numFramesPerSwap);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int getSwapInterval() const { return swapFrames; }
|
||||
bool createdOk() const noexcept { return true; }
|
||||
void* getRawContext() const noexcept { return renderContext; }
|
||||
GLuint getFrameBufferID() const noexcept { return 0; }
|
||||
|
||||
struct Locker { Locker (NativeContext&) {} };
|
||||
|
||||
private:
|
||||
GLXContext renderContext;
|
||||
Window embeddedWindow;
|
||||
|
||||
int swapFrames;
|
||||
Rectangle<int> bounds;
|
||||
XVisualInfo* bestVisual;
|
||||
void* contextToShareWith;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
bool OpenGLHelpers::isContextActive()
|
||||
{
|
||||
ScopedXLock xlock;
|
||||
return glXGetCurrentContext() != 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
class OpenGLContext::NativeContext
|
||||
{
|
||||
public:
|
||||
NativeContext (Component& component,
|
||||
const OpenGLPixelFormat& pixFormat,
|
||||
void* contextToShare,
|
||||
bool /*useMultisampling*/,
|
||||
OpenGLVersion version)
|
||||
: lastSwapTime (0), minSwapTimeMs (0), underrunCounter (0)
|
||||
{
|
||||
(void) version;
|
||||
|
||||
NSOpenGLPixelFormatAttribute attribs[] =
|
||||
{
|
||||
#if JUCE_OPENGL3
|
||||
NSOpenGLPFAOpenGLProfile, version >= openGL3_2 ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy,
|
||||
#endif
|
||||
NSOpenGLPFADoubleBuffer,
|
||||
NSOpenGLPFAClosestPolicy,
|
||||
NSOpenGLPFANoRecovery,
|
||||
NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute) (pixFormat.redBits + pixFormat.greenBits + pixFormat.blueBits),
|
||||
NSOpenGLPFAAlphaSize, (NSOpenGLPixelFormatAttribute) pixFormat.alphaBits,
|
||||
NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute) pixFormat.depthBufferBits,
|
||||
NSOpenGLPFAStencilSize, (NSOpenGLPixelFormatAttribute) pixFormat.stencilBufferBits,
|
||||
NSOpenGLPFAAccumSize, (NSOpenGLPixelFormatAttribute) (pixFormat.accumulationBufferRedBits + pixFormat.accumulationBufferGreenBits
|
||||
+ pixFormat.accumulationBufferBlueBits + pixFormat.accumulationBufferAlphaBits),
|
||||
pixFormat.multisamplingLevel > 0 ? NSOpenGLPFASamples : (NSOpenGLPixelFormatAttribute) 0,
|
||||
(NSOpenGLPixelFormatAttribute) pixFormat.multisamplingLevel,
|
||||
0
|
||||
};
|
||||
|
||||
NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes: attribs];
|
||||
|
||||
static MouseForwardingNSOpenGLViewClass cls;
|
||||
view = [cls.createInstance() initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)
|
||||
pixelFormat: format];
|
||||
|
||||
#if defined (MAC_OS_X_VERSION_10_7) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7)
|
||||
if ([view respondsToSelector: @selector (setWantsBestResolutionOpenGLSurface:)])
|
||||
[view setWantsBestResolutionOpenGLSurface: YES];
|
||||
#endif
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver: view
|
||||
selector: @selector (_surfaceNeedsUpdate:)
|
||||
name: NSViewGlobalFrameDidChangeNotification
|
||||
object: view];
|
||||
|
||||
renderContext = [[[NSOpenGLContext alloc] initWithFormat: format
|
||||
shareContext: (NSOpenGLContext*) contextToShare] autorelease];
|
||||
|
||||
[view setOpenGLContext: renderContext];
|
||||
[format release];
|
||||
|
||||
viewAttachment = NSViewComponent::attachViewToComponent (component, view);
|
||||
}
|
||||
|
||||
~NativeContext()
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver: view];
|
||||
[renderContext clearDrawable];
|
||||
[renderContext setView: nil];
|
||||
[view setOpenGLContext: nil];
|
||||
renderContext = nil;
|
||||
}
|
||||
|
||||
void initialiseOnRenderThread (OpenGLContext&) {}
|
||||
void shutdownOnRenderThread() { deactivateCurrentContext(); }
|
||||
|
||||
bool createdOk() const noexcept { return getRawContext() != nullptr; }
|
||||
void* getRawContext() const noexcept { return static_cast <void*> (renderContext); }
|
||||
GLuint getFrameBufferID() const noexcept { return 0; }
|
||||
|
||||
bool makeActive() const noexcept
|
||||
{
|
||||
jassert (renderContext != nil);
|
||||
|
||||
if ([renderContext view] != view)
|
||||
[renderContext setView: view];
|
||||
|
||||
if (NSOpenGLContext* context = [view openGLContext])
|
||||
{
|
||||
[context makeCurrentContext];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isActive() const noexcept
|
||||
{
|
||||
return [NSOpenGLContext currentContext] == renderContext;
|
||||
}
|
||||
|
||||
static void deactivateCurrentContext()
|
||||
{
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
}
|
||||
|
||||
struct Locker
|
||||
{
|
||||
Locker (NativeContext& nc) : cglContext ((CGLContextObj) [nc.renderContext CGLContextObj])
|
||||
{
|
||||
CGLLockContext (cglContext);
|
||||
}
|
||||
|
||||
~Locker()
|
||||
{
|
||||
CGLUnlockContext (cglContext);
|
||||
}
|
||||
|
||||
private:
|
||||
CGLContextObj cglContext;
|
||||
};
|
||||
|
||||
void swapBuffers()
|
||||
{
|
||||
[renderContext flushBuffer];
|
||||
|
||||
sleepIfRenderingTooFast();
|
||||
}
|
||||
|
||||
void updateWindowPosition (const Rectangle<int>&) {}
|
||||
|
||||
bool setSwapInterval (int numFramesPerSwap)
|
||||
{
|
||||
minSwapTimeMs = (numFramesPerSwap * 1000) / 60;
|
||||
|
||||
[renderContext setValues: (const GLint*) &numFramesPerSwap
|
||||
forParameter: NSOpenGLCPSwapInterval];
|
||||
return true;
|
||||
}
|
||||
|
||||
int getSwapInterval() const
|
||||
{
|
||||
GLint numFrames = 0;
|
||||
[renderContext getValues: &numFrames
|
||||
forParameter: NSOpenGLCPSwapInterval];
|
||||
|
||||
return numFrames;
|
||||
}
|
||||
|
||||
void sleepIfRenderingTooFast()
|
||||
{
|
||||
// When our window is entirely occluded by other windows, the system
|
||||
// fails to correctly implement the swap interval time, so the render
|
||||
// loop spins at full speed, burning CPU. This hack detects when things
|
||||
// are going too fast and slows things down if necessary.
|
||||
|
||||
if (minSwapTimeMs > 0)
|
||||
{
|
||||
const double now = Time::getMillisecondCounterHiRes();
|
||||
const int elapsed = (int) (now - lastSwapTime);
|
||||
lastSwapTime = now;
|
||||
|
||||
if (isPositiveAndBelow (elapsed, minSwapTimeMs - 3))
|
||||
{
|
||||
if (underrunCounter > 3)
|
||||
Thread::sleep (minSwapTimeMs - elapsed);
|
||||
else
|
||||
++underrunCounter;
|
||||
}
|
||||
else
|
||||
{
|
||||
underrunCounter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSOpenGLContext* renderContext;
|
||||
NSOpenGLView* view;
|
||||
ReferenceCountedObjectPtr<ReferenceCountedObject> viewAttachment;
|
||||
double lastSwapTime;
|
||||
int minSwapTimeMs, underrunCounter;
|
||||
|
||||
//==============================================================================
|
||||
struct MouseForwardingNSOpenGLViewClass : public ObjCClass <NSOpenGLView>
|
||||
{
|
||||
MouseForwardingNSOpenGLViewClass() : ObjCClass <NSOpenGLView> ("JUCEGLView_")
|
||||
{
|
||||
addMethod (@selector (rightMouseDown:), rightMouseDown, "v@:@");
|
||||
addMethod (@selector (rightMouseUp:), rightMouseUp, "v@:@");
|
||||
addMethod (@selector (acceptsFirstMouse:), acceptsFirstMouse, "v@:@");
|
||||
|
||||
registerClass();
|
||||
}
|
||||
|
||||
private:
|
||||
static void rightMouseDown (id self, SEL, NSEvent* ev) { [[(NSOpenGLView*) self superview] rightMouseDown: ev]; }
|
||||
static void rightMouseUp (id self, SEL, NSEvent* ev) { [[(NSOpenGLView*) self superview] rightMouseUp: ev]; }
|
||||
static BOOL acceptsFirstMouse (id, SEL, NSEvent*) { return YES; }
|
||||
};
|
||||
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
bool OpenGLHelpers::isContextActive()
|
||||
{
|
||||
return CGLGetCurrentContext() != 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
extern ComponentPeer* createNonRepaintingEmbeddedWindowsPeer (Component&, void* parent);
|
||||
|
||||
//==============================================================================
|
||||
class OpenGLContext::NativeContext
|
||||
{
|
||||
public:
|
||||
NativeContext (Component& component,
|
||||
const OpenGLPixelFormat& pixelFormat,
|
||||
void* contextToShareWith,
|
||||
bool /*useMultisampling*/,
|
||||
OpenGLVersion)
|
||||
: context (nullptr)
|
||||
{
|
||||
dummyComponent = new DummyComponent (*this);
|
||||
createNativeWindow (component);
|
||||
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
initialisePixelFormatDescriptor (pfd, pixelFormat);
|
||||
|
||||
const int pixFormat = ChoosePixelFormat (dc, &pfd);
|
||||
if (pixFormat != 0)
|
||||
SetPixelFormat (dc, pixFormat, &pfd);
|
||||
|
||||
renderContext = wglCreateContext (dc);
|
||||
|
||||
if (renderContext != 0)
|
||||
{
|
||||
makeActive();
|
||||
initialiseGLExtensions();
|
||||
|
||||
const int wglFormat = wglChoosePixelFormatExtension (pixelFormat);
|
||||
deactivateCurrentContext();
|
||||
|
||||
if (wglFormat != pixFormat && wglFormat != 0)
|
||||
{
|
||||
// can't change the pixel format of a window, so need to delete the
|
||||
// old one and create a new one..
|
||||
releaseDC();
|
||||
nativeWindow = nullptr;
|
||||
createNativeWindow (component);
|
||||
|
||||
if (SetPixelFormat (dc, wglFormat, &pfd))
|
||||
{
|
||||
deleteRenderContext();
|
||||
renderContext = wglCreateContext (dc);
|
||||
}
|
||||
}
|
||||
|
||||
if (contextToShareWith != nullptr)
|
||||
wglShareLists ((HGLRC) contextToShareWith, renderContext);
|
||||
|
||||
component.getTopLevelComponent()->repaint();
|
||||
component.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
~NativeContext()
|
||||
{
|
||||
deleteRenderContext();
|
||||
releaseDC();
|
||||
}
|
||||
|
||||
void initialiseOnRenderThread (OpenGLContext& c) { context = &c; }
|
||||
void shutdownOnRenderThread() { deactivateCurrentContext(); context = nullptr; }
|
||||
|
||||
static void deactivateCurrentContext() { wglMakeCurrent (0, 0); }
|
||||
bool makeActive() const noexcept { return isActive() || wglMakeCurrent (dc, renderContext) != FALSE; }
|
||||
bool isActive() const noexcept { return wglGetCurrentContext() == renderContext; }
|
||||
void swapBuffers() const noexcept { SwapBuffers (dc); }
|
||||
|
||||
bool setSwapInterval (int numFramesPerSwap)
|
||||
{
|
||||
jassert (isActive()); // this can only be called when the context is active..
|
||||
return wglSwapIntervalEXT != nullptr && wglSwapIntervalEXT (numFramesPerSwap) != FALSE;
|
||||
}
|
||||
|
||||
int getSwapInterval() const
|
||||
{
|
||||
jassert (isActive()); // this can only be called when the context is active..
|
||||
return wglGetSwapIntervalEXT != nullptr ? wglGetSwapIntervalEXT() : 0;
|
||||
}
|
||||
|
||||
void updateWindowPosition (const Rectangle<int>& bounds)
|
||||
{
|
||||
if (nativeWindow != nullptr)
|
||||
SetWindowPos ((HWND) nativeWindow->getNativeHandle(), 0,
|
||||
bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(),
|
||||
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER);
|
||||
}
|
||||
|
||||
bool createdOk() const noexcept { return getRawContext() != nullptr; }
|
||||
void* getRawContext() const noexcept { return renderContext; }
|
||||
unsigned int getFrameBufferID() const noexcept { return 0; }
|
||||
|
||||
void triggerRepaint()
|
||||
{
|
||||
if (context != nullptr)
|
||||
context->triggerRepaint();
|
||||
}
|
||||
|
||||
struct Locker { Locker (NativeContext&) {} };
|
||||
|
||||
private:
|
||||
struct DummyComponent : public Component
|
||||
{
|
||||
DummyComponent (NativeContext& c) : context (c) {}
|
||||
|
||||
// The windowing code will call this when a paint callback happens
|
||||
void handleCommandMessage (int) override { context.triggerRepaint(); }
|
||||
|
||||
NativeContext& context;
|
||||
};
|
||||
|
||||
ScopedPointer<DummyComponent> dummyComponent;
|
||||
ScopedPointer<ComponentPeer> nativeWindow;
|
||||
HGLRC renderContext;
|
||||
HDC dc;
|
||||
OpenGLContext* context;
|
||||
|
||||
#define JUCE_DECLARE_WGL_EXTENSION_FUNCTION(name, returnType, params) \
|
||||
typedef returnType (__stdcall *type_ ## name) params; type_ ## name name;
|
||||
|
||||
JUCE_DECLARE_WGL_EXTENSION_FUNCTION (wglChoosePixelFormatARB, BOOL, (HDC, const int*, const FLOAT*, UINT, int*, UINT*))
|
||||
JUCE_DECLARE_WGL_EXTENSION_FUNCTION (wglSwapIntervalEXT, BOOL, (int))
|
||||
JUCE_DECLARE_WGL_EXTENSION_FUNCTION (wglGetSwapIntervalEXT, int, ())
|
||||
#undef JUCE_DECLARE_WGL_EXTENSION_FUNCTION
|
||||
|
||||
void initialiseGLExtensions()
|
||||
{
|
||||
#define JUCE_INIT_WGL_FUNCTION(name) name = (type_ ## name) OpenGLHelpers::getExtensionFunction (#name);
|
||||
JUCE_INIT_WGL_FUNCTION (wglChoosePixelFormatARB);
|
||||
JUCE_INIT_WGL_FUNCTION (wglSwapIntervalEXT);
|
||||
JUCE_INIT_WGL_FUNCTION (wglGetSwapIntervalEXT);
|
||||
#undef JUCE_INIT_WGL_FUNCTION
|
||||
}
|
||||
|
||||
void createNativeWindow (Component& component)
|
||||
{
|
||||
Component* topComp = component.getTopLevelComponent();
|
||||
nativeWindow = createNonRepaintingEmbeddedWindowsPeer (*dummyComponent, topComp->getWindowHandle());
|
||||
|
||||
if (ComponentPeer* peer = topComp->getPeer())
|
||||
updateWindowPosition (peer->getAreaCoveredBy (component));
|
||||
|
||||
nativeWindow->setVisible (true);
|
||||
dc = GetDC ((HWND) nativeWindow->getNativeHandle());
|
||||
}
|
||||
|
||||
void deleteRenderContext()
|
||||
{
|
||||
if (renderContext != 0)
|
||||
{
|
||||
wglDeleteContext (renderContext);
|
||||
renderContext = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void releaseDC()
|
||||
{
|
||||
ReleaseDC ((HWND) nativeWindow->getNativeHandle(), dc);
|
||||
}
|
||||
|
||||
static void initialisePixelFormatDescriptor (PIXELFORMATDESCRIPTOR& pfd, const OpenGLPixelFormat& pixelFormat)
|
||||
{
|
||||
zerostruct (pfd);
|
||||
pfd.nSize = sizeof (pfd);
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;
|
||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||
pfd.iLayerType = PFD_MAIN_PLANE;
|
||||
pfd.cColorBits = (BYTE) (pixelFormat.redBits + pixelFormat.greenBits + pixelFormat.blueBits);
|
||||
pfd.cRedBits = (BYTE) pixelFormat.redBits;
|
||||
pfd.cGreenBits = (BYTE) pixelFormat.greenBits;
|
||||
pfd.cBlueBits = (BYTE) pixelFormat.blueBits;
|
||||
pfd.cAlphaBits = (BYTE) pixelFormat.alphaBits;
|
||||
pfd.cDepthBits = (BYTE) pixelFormat.depthBufferBits;
|
||||
pfd.cStencilBits = (BYTE) pixelFormat.stencilBufferBits;
|
||||
pfd.cAccumBits = (BYTE) (pixelFormat.accumulationBufferRedBits + pixelFormat.accumulationBufferGreenBits
|
||||
+ pixelFormat.accumulationBufferBlueBits + pixelFormat.accumulationBufferAlphaBits);
|
||||
pfd.cAccumRedBits = (BYTE) pixelFormat.accumulationBufferRedBits;
|
||||
pfd.cAccumGreenBits = (BYTE) pixelFormat.accumulationBufferGreenBits;
|
||||
pfd.cAccumBlueBits = (BYTE) pixelFormat.accumulationBufferBlueBits;
|
||||
pfd.cAccumAlphaBits = (BYTE) pixelFormat.accumulationBufferAlphaBits;
|
||||
}
|
||||
|
||||
int wglChoosePixelFormatExtension (const OpenGLPixelFormat& pixelFormat) const
|
||||
{
|
||||
int format = 0;
|
||||
|
||||
if (wglChoosePixelFormatARB != nullptr)
|
||||
{
|
||||
int atts[64];
|
||||
int n = 0;
|
||||
|
||||
atts[n++] = WGL_DRAW_TO_WINDOW_ARB; atts[n++] = GL_TRUE;
|
||||
atts[n++] = WGL_SUPPORT_OPENGL_ARB; atts[n++] = GL_TRUE;
|
||||
atts[n++] = WGL_DOUBLE_BUFFER_ARB; atts[n++] = GL_TRUE;
|
||||
atts[n++] = WGL_PIXEL_TYPE_ARB; atts[n++] = WGL_TYPE_RGBA_ARB;
|
||||
atts[n++] = WGL_ACCELERATION_ARB;
|
||||
atts[n++] = WGL_FULL_ACCELERATION_ARB;
|
||||
|
||||
atts[n++] = WGL_COLOR_BITS_ARB; atts[n++] = pixelFormat.redBits + pixelFormat.greenBits + pixelFormat.blueBits;
|
||||
atts[n++] = WGL_RED_BITS_ARB; atts[n++] = pixelFormat.redBits;
|
||||
atts[n++] = WGL_GREEN_BITS_ARB; atts[n++] = pixelFormat.greenBits;
|
||||
atts[n++] = WGL_BLUE_BITS_ARB; atts[n++] = pixelFormat.blueBits;
|
||||
atts[n++] = WGL_ALPHA_BITS_ARB; atts[n++] = pixelFormat.alphaBits;
|
||||
atts[n++] = WGL_DEPTH_BITS_ARB; atts[n++] = pixelFormat.depthBufferBits;
|
||||
|
||||
atts[n++] = WGL_STENCIL_BITS_ARB; atts[n++] = pixelFormat.stencilBufferBits;
|
||||
atts[n++] = WGL_ACCUM_RED_BITS_ARB; atts[n++] = pixelFormat.accumulationBufferRedBits;
|
||||
atts[n++] = WGL_ACCUM_GREEN_BITS_ARB; atts[n++] = pixelFormat.accumulationBufferGreenBits;
|
||||
atts[n++] = WGL_ACCUM_BLUE_BITS_ARB; atts[n++] = pixelFormat.accumulationBufferBlueBits;
|
||||
atts[n++] = WGL_ACCUM_ALPHA_BITS_ARB; atts[n++] = pixelFormat.accumulationBufferAlphaBits;
|
||||
|
||||
if (pixelFormat.multisamplingLevel > 0
|
||||
&& OpenGLHelpers::isExtensionSupported ("GL_ARB_multisample"))
|
||||
{
|
||||
atts[n++] = WGL_SAMPLE_BUFFERS_ARB;
|
||||
atts[n++] = 1;
|
||||
atts[n++] = WGL_SAMPLES_ARB;
|
||||
atts[n++] = pixelFormat.multisamplingLevel;
|
||||
}
|
||||
|
||||
atts[n++] = 0;
|
||||
jassert (n <= numElementsInArray (atts));
|
||||
|
||||
UINT formatsCount = 0;
|
||||
wglChoosePixelFormatARB (dc, atts, nullptr, 1, &format, &formatsCount);
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
bool OpenGLHelpers::isContextActive()
|
||||
{
|
||||
return wglGetCurrentContext() != 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue