diff --git a/build/linux/platform_specific_code/juce_linux_Windowing.cpp b/build/linux/platform_specific_code/juce_linux_Windowing.cpp index 2966674a51..64aa176112 100644 --- a/build/linux/platform_specific_code/juce_linux_Windowing.cpp +++ b/build/linux/platform_specific_code/juce_linux_Windowing.cpp @@ -2795,59 +2795,70 @@ Image* juce_createIconForFile (const File& file) //============================================================================== #if JUCE_OPENGL -struct OpenGLContextInfo + +//============================================================================== +class WindowedGLContext : public OpenGLContext { - Window embeddedWindow; - GLXContext renderContext; -}; - -void* juce_createOpenGLContext (OpenGLComponent* component, void* sharedContext) -{ - XSync (display, False); - jassert (component != 0); - - if (component == 0) - return 0; - - LinuxComponentPeer* const peer - = dynamic_cast (component->getTopLevelComponent()->getPeer()); - - if (peer == 0) - return 0; - - GLint attribList[] = +public: + WindowedGLContext (Component* const component, + const OpenGLPixelFormat& pixelFormat_, + GLXContext sharedContext) + : renderContext (0), + embeddedWindow (0), + pixelFormat (pixelFormat_) { - GLX_RGBA, - GLX_DOUBLEBUFFER, - GLX_RED_SIZE, 8, - GLX_GREEN_SIZE, 8, - GLX_BLUE_SIZE, 8, - GLX_ALPHA_SIZE, 8, - GLX_DEPTH_SIZE, 8, - None - }; + jassert (component != 0); + LinuxComponentPeer* const peer = dynamic_cast (component->getTopLevelComponent()->getPeer()); + if (peer == 0) + return; - XVisualInfo* const bestVisual = glXChooseVisual (display, DefaultScreen (display), attribList); + XSync (display, False); - if (bestVisual == 0) - return 0; + GLint attribs [64]; + int n = 0; + attribs[n++] = GLX_RGBA; + attribs[n++] = GLX_DOUBLEBUFFER; + attribs[n++] = GLX_RED_SIZE; + attribs[n++] = pixelFormat.redBits; + attribs[n++] = GLX_GREEN_SIZE; + attribs[n++] = pixelFormat.greenBits; + attribs[n++] = GLX_BLUE_SIZE; + attribs[n++] = pixelFormat.blueBits; + attribs[n++] = GLX_ALPHA_SIZE; + attribs[n++] = pixelFormat.alphaBits; + attribs[n++] = GLX_DEPTH_SIZE; + attribs[n++] = pixelFormat.depthBufferBits; + attribs[n++] = GLX_STENCIL_SIZE; + attribs[n++] = pixelFormat.stencilBufferBits; + attribs[n++] = GLX_ACCUM_RED_SIZE; + attribs[n++] = pixelFormat.accumulationBufferRedBits; + attribs[n++] = GLX_ACCUM_GREEN_SIZE; + attribs[n++] = pixelFormat.accumulationBufferGreenBits; + attribs[n++] = GLX_ACCUM_BLUE_SIZE; + attribs[n++] = pixelFormat.accumulationBufferBlueBits; + attribs[n++] = GLX_ACCUM_ALPHA_SIZE; + attribs[n++] = pixelFormat.accumulationBufferAlphaBits; - OpenGLContextInfo* const oc = new OpenGLContextInfo(); + // xxx not sure how to do fullSceneAntiAliasingNumSamples on linux.. - oc->renderContext = glXCreateContext (display, bestVisual, - (sharedContext != 0) ? ((OpenGLContextInfo*) sharedContext)->renderContext - : 0, - GL_TRUE); + attribs[n++] = None; - Window windowH = (Window) peer->getNativeHandle(); + XVisualInfo* const bestVisual = glXChooseVisual (display, DefaultScreen (display), attribs); - Colormap colourMap = XCreateColormap (display, windowH, bestVisual->visual, AllocNone); - XSetWindowAttributes swa; - swa.colormap = colourMap; - swa.border_pixel = 0; - swa.event_mask = ExposureMask | StructureNotifyMask; + if (bestVisual == 0) + return; - oc->embeddedWindow = XCreateWindow (display, windowH, + renderContext = glXCreateContext (display, bestVisual, sharedContext, GL_TRUE); + + 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; + + embeddedWindow = XCreateWindow (display, windowH, 0, 0, 1, 1, 0, bestVisual->depth, InputOutput, @@ -2855,73 +2866,104 @@ void* juce_createOpenGLContext (OpenGLComponent* component, void* sharedContext) CWBorderPixel | CWColormap | CWEventMask, &swa); - XSaveContext (display, (XID) oc->embeddedWindow, improbableNumber, (XPointer) peer); + XSaveContext (display, (XID) embeddedWindow, improbableNumber, (XPointer) peer); - XMapWindow (display, oc->embeddedWindow); - XFreeColormap (display, colourMap); + XMapWindow (display, embeddedWindow); + XFreeColormap (display, colourMap); - XFree (bestVisual); - XSync (display, False); - - return oc; -} - -void juce_updateOpenGLWindowPos (void* context, Component* owner, Component* topComp) -{ - jassert (context != 0); - OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; - - XMoveResizeWindow (display, oc->embeddedWindow, - owner->getScreenX() - topComp->getScreenX(), - owner->getScreenY() - topComp->getScreenY(), - jmax (1, owner->getWidth()), - jmax (1, owner->getHeight())); -} - -void juce_deleteOpenGLContext (void* context) -{ - OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; - - if (oc != 0) - { - glXDestroyContext (display, oc->renderContext); - - XUnmapWindow (display, oc->embeddedWindow); - XDestroyWindow (display, oc->embeddedWindow); - - delete oc; + XFree (bestVisual); + XSync (display, False); } -} -bool juce_makeOpenGLContextCurrent (void* context) -{ - OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; + ~WindowedGLContext() + { + makeInactive(); - if (oc != 0) - return glXMakeCurrent (display, oc->embeddedWindow, oc->renderContext) + glXDestroyContext (display, renderContext); + + XUnmapWindow (display, embeddedWindow); + XDestroyWindow (display, embeddedWindow); + } + + bool makeActive() throw() + { + jassert (renderContext != 0); + + return glXMakeCurrent (display, embeddedWindow, renderContext) && XSync (display, False); - else - return glXMakeCurrent (display, None, 0); + } + + bool makeInactive() throw() + { + return (! isActive()) || glXMakeCurrent (display, None, 0); + } + + bool isActive() const throw() + { + return glXGetCurrentContext() == renderContext; + } + + const OpenGLPixelFormat getPixelFormat() const + { + return pixelFormat; + } + + void* getRawContext() const throw() + { + return renderContext; + } + + void updateWindowPosition (int x, int y, int w, int h, int) + { + XMoveResizeWindow (display, embeddedWindow, + x, y, jmax (1, w), jmax (1, h)); + } + + void swapBuffers() + { + glXSwapBuffers (display, embeddedWindow); + } + + void repaint() + { + } + + //============================================================================== + juce_UseDebuggingNewOperator + + GLXContext renderContext; + +private: + Window embeddedWindow; + OpenGLPixelFormat pixelFormat; + + //============================================================================== + WindowedGLContext (const WindowedGLContext&); + const WindowedGLContext& operator= (const WindowedGLContext&); +}; + +//============================================================================== +OpenGLContext* OpenGLContext::createContextForWindow (Component* const component, + const OpenGLPixelFormat& pixelFormat, + const OpenGLContext* const contextToShareWith) +{ + WindowedGLContext* c = new WindowedGLContext (component, pixelFormat, + contextToShareWith != 0 ? (GLXContext) contextToShareWith->getRawContext() : 0); + + if (c->renderContext == 0) + deleteAndZero (c); + + return c; } -bool juce_isActiveOpenGLContext (void* context) throw() +void juce_glViewport (const int w, const int h) { - OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; - - jassert (oc != 0); - return glXGetCurrentContext() == oc->renderContext; + glViewport (0, 0, w, h); } -void juce_swapOpenGLBuffers (void* context) -{ - OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; - - if (oc != 0) - glXSwapBuffers (display, oc->embeddedWindow); -} - -void juce_repaintOpenGLWindow (void* context) +void OpenGLPixelFormat::getAvailablePixelFormats (OwnedArray & results) { + results.add (new OpenGLPixelFormat()); // xxx } #endif diff --git a/build/macosx/platform_specific_code/juce_mac_Windowing.cpp b/build/macosx/platform_specific_code/juce_mac_Windowing.cpp index 10c6733062..44922d795e 100644 --- a/build/macosx/platform_specific_code/juce_mac_Windowing.cpp +++ b/build/macosx/platform_specific_code/juce_mac_Windowing.cpp @@ -3292,92 +3292,190 @@ void AppleRemoteDevice::handleCallbackInternal() //============================================================================== #if JUCE_OPENGL -struct OpenGLContextInfo +//============================================================================== +class WindowedGLContext : public OpenGLContext { +public: + WindowedGLContext (Component* const component, + const OpenGLPixelFormat& pixelFormat_, + AGLContext sharedContext) + : renderContext (0), + pixelFormat (pixelFormat_) + { + jassert (component != 0); + + HIViewComponentPeer* const peer = dynamic_cast (component->getTopLevelComponent()->getPeer()); + if (peer == 0) + return; + + GLint attribs [64]; + int n = 0; + attribs[n++] = AGL_RGBA; + attribs[n++] = AGL_DOUBLEBUFFER; + attribs[n++] = AGL_ACCELERATED; + attribs[n++] = AGL_RED_SIZE; + attribs[n++] = pixelFormat.redBits; + attribs[n++] = AGL_GREEN_SIZE; + attribs[n++] = pixelFormat.greenBits; + attribs[n++] = AGL_BLUE_SIZE; + attribs[n++] = pixelFormat.blueBits; + attribs[n++] = AGL_ALPHA_SIZE; + attribs[n++] = pixelFormat.alphaBits; + attribs[n++] = AGL_DEPTH_SIZE; + attribs[n++] = pixelFormat.depthBufferBits; + attribs[n++] = AGL_STENCIL_SIZE; + attribs[n++] = pixelFormat.stencilBufferBits; + attribs[n++] = AGL_ACCUM_RED_SIZE; + attribs[n++] = pixelFormat.accumulationBufferRedBits; + attribs[n++] = AGL_ACCUM_GREEN_SIZE; + attribs[n++] = pixelFormat.accumulationBufferGreenBits; + attribs[n++] = AGL_ACCUM_BLUE_SIZE; + attribs[n++] = pixelFormat.accumulationBufferBlueBits; + attribs[n++] = AGL_ACCUM_ALPHA_SIZE; + attribs[n++] = pixelFormat.accumulationBufferAlphaBits; + + // xxx not sure how to do fullSceneAntiAliasingNumSamples.. + + attribs[n++] = AGL_SAMPLE_BUFFERS_ARB; + attribs[n++] = 1; + attribs[n++] = AGL_SAMPLES_ARB; + attribs[n++] = 4; + attribs[n++] = AGL_CLOSEST_POLICY; + attribs[n++] = AGL_NO_RECOVERY; + attribs[n++] = AGL_NONE; + + renderContext = aglCreateContext (aglChoosePixelFormat (0, 0, attribs), + sharedContext); + + aglSetDrawable (renderContext, GetWindowPort (peer->windowRef)); + } + + ~WindowedGLContext() + { + makeInactive(); + aglSetDrawable (renderContext, 0); + aglDestroyContext (renderContext); + } + + bool makeActive() throw() + { + jassert (renderContext != 0); + + return aglSetCurrentContext (renderContext); + } + + bool makeInactive() throw() + { + return (! isActive()) || aglSetCurrentContext (0); + } + + bool isActive() const throw() + { + return aglGetCurrentContext() == renderContext; + } + + const OpenGLPixelFormat getPixelFormat() const + { + return pixelFormat; + } + + void* getRawContext() const throw() + { + return renderContext; + } + + void updateWindowPosition (int x, int y, int w, int h, int outerWindowHeight) + { + GLint bufferRect[4]; + bufferRect[0] = x; + bufferRect[1] = outerWindowHeight - (y + h); + bufferRect[2] = w; + bufferRect[3] = h; + + aglSetInteger (renderContext, AGL_BUFFER_RECT, bufferRect); + aglEnable (renderContext, AGL_BUFFER_RECT); + } + + void swapBuffers() + { + aglSwapBuffers (renderContext); + } + + void repaint() + { + } + + //============================================================================== + juce_UseDebuggingNewOperator + AGLContext renderContext; + +private: + OpenGLPixelFormat pixelFormat; + + //============================================================================== + WindowedGLContext (const WindowedGLContext&); + const WindowedGLContext& operator= (const WindowedGLContext&); }; -void* juce_createOpenGLContext (OpenGLComponent* component, void* sharedContext) +//============================================================================== +OpenGLContext* OpenGLContext::createContextForWindow (Component* const component, + const OpenGLPixelFormat& pixelFormat, + const OpenGLContext* const contextToShareWith) { - jassert (component != 0); + WindowedGLContext* c = new WindowedGLContext (component, pixelFormat, + contextToShareWith != 0 ? (AGLContext) contextToShareWith->getRawContext() : 0); - HIViewComponentPeer* const peer = dynamic_cast (component->getTopLevelComponent()->getPeer()); + if (c->renderContext == 0) + deleteAndZero (c); - if (peer == 0) - return 0; - - OpenGLContextInfo* const oc = new OpenGLContextInfo(); - - GLint attrib[] = { AGL_RGBA, AGL_DOUBLEBUFFER, - AGL_RED_SIZE, 8, - AGL_ALPHA_SIZE, 8, - AGL_DEPTH_SIZE, 24, - AGL_CLOSEST_POLICY, AGL_NO_RECOVERY, - AGL_SAMPLE_BUFFERS_ARB, 1, - AGL_SAMPLES_ARB, 4, - AGL_NONE }; - - oc->renderContext = aglCreateContext (aglChoosePixelFormat (0, 0, attrib), - (sharedContext != 0) ? ((OpenGLContextInfo*) sharedContext)->renderContext - : 0); - - aglSetDrawable (oc->renderContext, - GetWindowPort (peer->windowRef)); - - return oc; + return c; } -void juce_updateOpenGLWindowPos (void* context, Component* owner, Component* topComp) +void juce_glViewport (const int w, const int h) { - jassert (context != 0); - OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; - - GLint bufferRect[4]; - - bufferRect[0] = owner->getScreenX() - topComp->getScreenX(); - bufferRect[1] = topComp->getHeight() - (owner->getHeight() + owner->getScreenY() - topComp->getScreenY()); - bufferRect[2] = owner->getWidth(); - bufferRect[3] = owner->getHeight(); - - aglSetInteger (oc->renderContext, AGL_BUFFER_RECT, bufferRect); - aglEnable (oc->renderContext, AGL_BUFFER_RECT); + glViewport (0, 0, w, h); } -void juce_deleteOpenGLContext (void* context) +static int getAGLAttribute (AGLPixelFormat p, const GLint attrib) { - OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; - - aglDestroyContext (oc->renderContext); - - delete oc; + GLint result = 0; + aglDescribePixelFormat (p, attrib, &result); + return result; } -bool juce_makeOpenGLContextCurrent (void* context) +void OpenGLPixelFormat::getAvailablePixelFormats (OwnedArray & results) { - OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; + GLint attribs [64]; + int n = 0; + attribs[n++] = AGL_RGBA; + attribs[n++] = AGL_DOUBLEBUFFER; + attribs[n++] = AGL_ACCELERATED; + attribs[n++] = AGL_NO_RECOVERY; + attribs[n++] = AGL_NONE; - return aglSetCurrentContext ((oc != 0) ? oc->renderContext : 0); + AGLPixelFormat p = aglChoosePixelFormat (0, 0, attribs); + + while (p != 0) + { + OpenGLPixelFormat* const pf = new OpenGLPixelFormat(); + pf->redBits = getAGLAttribute (p, AGL_RED_SIZE); + pf->greenBits = getAGLAttribute (p, AGL_GREEN_SIZE); + pf->blueBits = getAGLAttribute (p, AGL_BLUE_SIZE); + pf->alphaBits = getAGLAttribute (p, AGL_ALPHA_SIZE); + pf->depthBufferBits = getAGLAttribute (p, AGL_DEPTH_SIZE); + pf->stencilBufferBits = getAGLAttribute (p, AGL_STENCIL_SIZE); + pf->accumulationBufferRedBits = getAGLAttribute (p, AGL_ACCUM_RED_SIZE); + pf->accumulationBufferGreenBits = getAGLAttribute (p, AGL_ACCUM_GREEN_SIZE); + pf->accumulationBufferBlueBits = getAGLAttribute (p, AGL_ACCUM_BLUE_SIZE); + pf->accumulationBufferAlphaBits = getAGLAttribute (p, AGL_ACCUM_ALPHA_SIZE); + + results.add (pf); + + p = aglNextPixelFormat (p); + } } -bool juce_isActiveOpenGLContext (void* context) throw() -{ - OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; - - jassert (oc != 0); - return aglGetCurrentContext() == oc->renderContext; -} - -void juce_swapOpenGLBuffers (void* context) -{ - OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; - - if (oc != 0) - aglSwapBuffers (oc->renderContext); -} - -void juce_repaintOpenGLWindow (void* context) -{ -} #endif diff --git a/build/win32/platform_specific_code/juce_win32_Windowing.cpp b/build/win32/platform_specific_code/juce_win32_Windowing.cpp index 0f60f5c704..92cbc7fef9 100644 --- a/build/win32/platform_specific_code/juce_win32_Windowing.cpp +++ b/build/win32/platform_specific_code/juce_win32_Windowing.cpp @@ -2640,6 +2640,7 @@ void MouseCursor::showInAllWindows() const throw() showInWindow (0); } +//============================================================================== //============================================================================== class JuceDropSource : public IDropSource { @@ -2970,13 +2971,13 @@ static HDROP createHDrop (const StringArray& fileNames) throw() return hDrop; } -static bool performDragDrop (FORMATETC* format, STGMEDIUM* medium, const DWORD whatToDo) throw() +static bool performDragDrop (FORMATETC* const format, STGMEDIUM* const medium, const DWORD whatToDo) throw() { JuceDropSource* const source = new JuceDropSource(); JuceDataObject* const data = new JuceDataObject (source, format, medium, 1); DWORD effect; - HRESULT res = DoDragDrop (data, source, whatToDo, &effect); + const HRESULT res = DoDragDrop (data, source, whatToDo, &effect); data->Release(); source->Release(); @@ -3026,152 +3027,456 @@ bool DragAndDropContainer::performExternalDragDropOfText (const String& text) } +//============================================================================== //============================================================================== #if JUCE_OPENGL -struct OpenGLContextInfo +#define WGL_EXT_FUNCTION_INIT(extType, extFunc) \ + ((extFunc = (extType) wglGetProcAddress (#extFunc)) != 0) + +typedef const char* (WINAPI* PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc); +typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); +typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int* piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); + +#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_SWAP_METHOD_ARB 0x2007 +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_PIXEL_TYPE_ARB 0x2013 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_COLOR_BITS_ARB 0x2014 +#define WGL_RED_BITS_ARB 0x2015 +#define WGL_GREEN_BITS_ARB 0x2017 +#define WGL_BLUE_BITS_ARB 0x2019 +#define WGL_ALPHA_BITS_ARB 0x201B +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_FULL_ACCELERATION_ARB 0x2027 +#define WGL_ACCUM_RED_BITS_ARB 0x201E +#define WGL_ACCUM_GREEN_BITS_ARB 0x201F +#define WGL_ACCUM_BLUE_BITS_ARB 0x2020 +#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 +#define WGL_STEREO_ARB 0x2012 +#define WGL_SAMPLE_BUFFERS_ARB 0x2041 +#define WGL_SAMPLES_ARB 0x2042 +#define WGL_TYPE_RGBA_ARB 0x202B + +static void getWglExtensions (HDC dc, StringArray& result) throw() { - Win32ComponentPeer* nativeWindow; + PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = 0; - HDC dc; - HGLRC renderContext; -}; + if (WGL_EXT_FUNCTION_INIT (PFNWGLGETEXTENSIONSSTRINGARBPROC, wglGetExtensionsStringARB)) + result.addTokens (String (wglGetExtensionsStringARB (dc)), false); + else + jassertfalse // If this fails, it may be because you didn't activate the openGL context +} -void* juce_createOpenGLContext (OpenGLComponent* component, void* sharedContext) + +//============================================================================== +class WindowedGLContext : public OpenGLContext { - jassert (component != 0); - - Win32ComponentPeer* const peer = dynamic_cast (component->getTopLevelComponent()->getPeer()); - - if (peer == 0) - return 0; - - OpenGLContextInfo* const oc = new OpenGLContextInfo(); - - oc->nativeWindow = new Win32ComponentPeer (component, 0); - oc->nativeWindow->dontRepaint = true; - oc->nativeWindow->setVisible (true); - HWND hwnd = (HWND) oc->nativeWindow->getNativeHandle(); - - SetParent (hwnd, (HWND) peer->getNativeHandle()); - juce_setWindowStyleBit (hwnd, GWL_STYLE, WS_CHILD, true); - juce_setWindowStyleBit (hwnd, GWL_STYLE, WS_POPUP, false); - - oc->dc = GetDC (hwnd); - - PIXELFORMATDESCRIPTOR pfd; - zerostruct (pfd); - pfd.nSize = sizeof (pfd); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cColorBits = 32; - pfd.cDepthBits = 32; - pfd.iLayerType = PFD_MAIN_PLANE; - - int format = ChoosePixelFormat (oc->dc, &pfd); - - if (format == 0 || ! SetPixelFormat (oc->dc, format, &pfd)) +public: + WindowedGLContext (Component* const component, HGLRC contextToShareWith) + : renderContext (0), + nativeWindow (0) { - // try some less ambitious formats if it fails.. - pfd.cColorBits = 24; - format = ChoosePixelFormat (oc->dc, &pfd); + jassert (component != 0); + Win32ComponentPeer* const peer = dynamic_cast (component->getTopLevelComponent()->getPeer()); - if (format == 0 || ! SetPixelFormat (oc->dc, format, &pfd)) + nativeWindow = new Win32ComponentPeer (component, 0); + nativeWindow->dontRepaint = true; + nativeWindow->setVisible (true); + + HWND hwnd = (HWND) nativeWindow->getNativeHandle(); + + if (peer != 0) { - pfd.cDepthBits = 16; - format = ChoosePixelFormat (oc->dc, &pfd); + SetParent (hwnd, (HWND) peer->getNativeHandle()); + juce_setWindowStyleBit (hwnd, GWL_STYLE, WS_CHILD, true); + juce_setWindowStyleBit (hwnd, GWL_STYLE, WS_POPUP, false); + } - if (format == 0 || ! SetPixelFormat (oc->dc, format, &pfd)) + dc = GetDC (hwnd); + + // Use a default pixel format that should be supported everywhere + PIXELFORMATDESCRIPTOR pfd; + zerostruct (pfd); + pfd.nSize = sizeof (pfd); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 16; + pfd.cDepthBits = 16; + + const int format = ChoosePixelFormat (dc, &pfd); + + if (format != 0) + SetPixelFormat (dc, format, &pfd); + + renderContext = wglCreateContext (dc); + + if (contextToShareWith != 0 && renderContext != 0) + wglShareLists (renderContext, contextToShareWith); + } + + ~WindowedGLContext() + { + makeInactive(); + + wglDeleteContext (renderContext); + ReleaseDC ((HWND) nativeWindow->getNativeHandle(), dc); + + delete nativeWindow; + } + + bool makeActive() throw() + { + jassert (renderContext != 0); + return wglMakeCurrent (dc, renderContext) != 0; + } + + bool makeInactive() throw() + { + return (! isActive()) || (wglMakeCurrent (0, 0) != 0); + } + + bool isActive() const throw() + { + return wglGetCurrentContext() == renderContext; + } + + const OpenGLPixelFormat getPixelFormat() const + { + OpenGLPixelFormat pf; + + StringArray availableExtensions; + getWglExtensions (dc, availableExtensions); + + fillInPixelFormatDetails (GetPixelFormat (dc), pf, availableExtensions); + return pf; + } + + void* getRawContext() const throw() + { + return renderContext; + } + + bool setPixelFormat (const OpenGLPixelFormat& pixelFormat) + { + jassert (renderContext != 0); + + makeActive(); + + StringArray availableExtensions; + getWglExtensions (dc, availableExtensions); + + PIXELFORMATDESCRIPTOR pfd; + 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 = pixelFormat.redBits + pixelFormat.greenBits + pixelFormat.blueBits; + pfd.cRedBits = pixelFormat.redBits; + pfd.cGreenBits = pixelFormat.greenBits; + pfd.cBlueBits = pixelFormat.blueBits; + pfd.cAlphaBits = pixelFormat.alphaBits; + pfd.cDepthBits = pixelFormat.depthBufferBits; + pfd.cStencilBits = pixelFormat.stencilBufferBits; + pfd.cAccumBits = pixelFormat.accumulationBufferRedBits + pixelFormat.accumulationBufferGreenBits + + pixelFormat.accumulationBufferBlueBits + pixelFormat.accumulationBufferAlphaBits; + pfd.cAccumRedBits = pixelFormat.accumulationBufferRedBits; + pfd.cAccumGreenBits = pixelFormat.accumulationBufferGreenBits; + pfd.cAccumBlueBits = pixelFormat.accumulationBufferBlueBits; + pfd.cAccumAlphaBits = pixelFormat.accumulationBufferAlphaBits; + + int format = 0; + + PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = 0; + + if (availableExtensions.contains ("WGL_ARB_pixel_format") + && WGL_EXT_FUNCTION_INIT (PFNWGLCHOOSEPIXELFORMATARBPROC, wglChoosePixelFormatARB)) + { + int attributes[64]; + int n = 0; + + attributes[n++] = WGL_DRAW_TO_WINDOW_ARB; + attributes[n++] = GL_TRUE; + attributes[n++] = WGL_SUPPORT_OPENGL_ARB; + attributes[n++] = GL_TRUE; + attributes[n++] = WGL_ACCELERATION_ARB; + attributes[n++] = WGL_FULL_ACCELERATION_ARB; + attributes[n++] = WGL_DOUBLE_BUFFER_ARB; + attributes[n++] = GL_TRUE; + attributes[n++] = WGL_PIXEL_TYPE_ARB; + attributes[n++] = WGL_TYPE_RGBA_ARB; + + attributes[n++] = WGL_COLOR_BITS_ARB; + attributes[n++] = pfd.cColorBits; + attributes[n++] = WGL_RED_BITS_ARB; + attributes[n++] = pixelFormat.redBits; + attributes[n++] = WGL_GREEN_BITS_ARB; + attributes[n++] = pixelFormat.greenBits; + attributes[n++] = WGL_BLUE_BITS_ARB; + attributes[n++] = pixelFormat.blueBits; + attributes[n++] = WGL_ALPHA_BITS_ARB; + attributes[n++] = pixelFormat.alphaBits; + attributes[n++] = WGL_DEPTH_BITS_ARB; + attributes[n++] = pixelFormat.depthBufferBits; + + if (pixelFormat.stencilBufferBits > 0) { - pfd.cColorBits = 32; - format = ChoosePixelFormat (oc->dc, &pfd); + attributes[n++] = WGL_STENCIL_BITS_ARB; + attributes[n++] = pixelFormat.stencilBufferBits; + } - if (format == 0 || ! SetPixelFormat (oc->dc, format, &pfd)) - { - jassertfalse // can't find a suitable pixel format that works for opengl - } + attributes[n++] = WGL_ACCUM_RED_BITS_ARB; + attributes[n++] = pixelFormat.accumulationBufferRedBits; + attributes[n++] = WGL_ACCUM_GREEN_BITS_ARB; + attributes[n++] = pixelFormat.accumulationBufferGreenBits; + attributes[n++] = WGL_ACCUM_BLUE_BITS_ARB; + attributes[n++] = pixelFormat.accumulationBufferBlueBits; + attributes[n++] = WGL_ACCUM_ALPHA_BITS_ARB; + attributes[n++] = pixelFormat.accumulationBufferAlphaBits; + + if (availableExtensions.contains ("WGL_ARB_multisample") + && pixelFormat.fullSceneAntiAliasingNumSamples > 0) + { + attributes[n++] = WGL_SAMPLE_BUFFERS_ARB; + attributes[n++] = 1; + attributes[n++] = WGL_SAMPLES_ARB; + attributes[n++] = pixelFormat.fullSceneAntiAliasingNumSamples; + } + + attributes[n++] = 0; + + UINT formatsCount; + const BOOL ok = wglChoosePixelFormatARB (dc, attributes, 0, 1, &format, &formatsCount); + (void) ok; + jassert (ok); + } + else + { + format = ChoosePixelFormat (dc, &pfd); + } + + if (format != 0) + { + makeInactive(); + + // Create the real context.. + if (SetPixelFormat (dc, format, &pfd)) + { + wglDeleteContext (renderContext); + renderContext = wglCreateContext (dc); + + jassert (renderContext != 0); + return renderContext != 0; + } + } + + return false; + } + + void updateWindowPosition (int x, int y, int w, int h, int) + { + SetWindowPos ((HWND) nativeWindow->getNativeHandle(), 0, + x, y, w, h, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING); + } + + void repaint() + { + int x, y, w, h; + nativeWindow->getBounds (x, y, w, h); + nativeWindow->repaint (0, 0, w, h); + } + + void swapBuffers() + { + SwapBuffers (dc); + } + + void findAlternativeOpenGLPixelFormats (OwnedArray & results) + { + jassert (isActive()); + + StringArray availableExtensions; + getWglExtensions (dc, availableExtensions); + + PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB = 0; + int numTypes = 0; + + if (availableExtensions.contains("WGL_ARB_pixel_format") + && WGL_EXT_FUNCTION_INIT (PFNWGLGETPIXELFORMATATTRIBIVARBPROC, wglGetPixelFormatAttribivARB)) + { + int attributes = WGL_NUMBER_PIXEL_FORMATS_ARB; + + if (! wglGetPixelFormatAttribivARB (dc, 1, 0, 1, &attributes, &numTypes)) + jassertfalse + } + else + { + numTypes = DescribePixelFormat (dc, 0, 0, 0); + } + + OpenGLPixelFormat pf; + + for (int i = 0; i < numTypes; ++i) + { + if (fillInPixelFormatDetails (i + 1, pf, availableExtensions)) + { + bool alreadyListed = false; + for (int j = results.size(); --j >= 0;) + if (pf == *results.getUnchecked(j)) + alreadyListed = true; + + if (! alreadyListed) + results.add (new OpenGLPixelFormat (pf)); } } } - oc->renderContext = wglCreateContext (oc->dc); + //============================================================================== + juce_UseDebuggingNewOperator - if (sharedContext != 0) - wglShareLists (((OpenGLContextInfo*) sharedContext)->renderContext, oc->renderContext); + HGLRC renderContext; - return oc; -} +private: + Win32ComponentPeer* nativeWindow; + HDC dc; -void juce_updateOpenGLWindowPos (void* context, Component* owner, Component* topComp) -{ - jassert (context != 0); - OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; - - SetWindowPos ((HWND) oc->nativeWindow->getNativeHandle(), 0, - owner->getScreenX() - topComp->getScreenX(), - owner->getScreenY() - topComp->getScreenY(), - owner->getWidth(), - owner->getHeight(), - SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING); -} - -void juce_deleteOpenGLContext (void* context) -{ - OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; - - if (oc != 0) + //============================================================================== + bool fillInPixelFormatDetails (const int pixelFormatIndex, + OpenGLPixelFormat& result, + const StringArray& availableExtensions) const throw() { - wglDeleteContext (oc->renderContext); - ReleaseDC ((HWND) oc->nativeWindow->getNativeHandle(), oc->dc); + PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB = 0; - deleteAndZero (oc->nativeWindow); + if (availableExtensions.contains ("WGL_ARB_pixel_format") + && WGL_EXT_FUNCTION_INIT (PFNWGLGETPIXELFORMATATTRIBIVARBPROC, wglGetPixelFormatAttribivARB)) + { + int attributes[32]; + int numAttributes = 0; - delete oc; + attributes[numAttributes++] = WGL_DRAW_TO_WINDOW_ARB; + attributes[numAttributes++] = WGL_SUPPORT_OPENGL_ARB; + attributes[numAttributes++] = WGL_ACCELERATION_ARB; + attributes[numAttributes++] = WGL_DOUBLE_BUFFER_ARB; + attributes[numAttributes++] = WGL_PIXEL_TYPE_ARB; + attributes[numAttributes++] = WGL_RED_BITS_ARB; + attributes[numAttributes++] = WGL_GREEN_BITS_ARB; + attributes[numAttributes++] = WGL_BLUE_BITS_ARB; + attributes[numAttributes++] = WGL_ALPHA_BITS_ARB; + attributes[numAttributes++] = WGL_DEPTH_BITS_ARB; + attributes[numAttributes++] = WGL_STENCIL_BITS_ARB; + attributes[numAttributes++] = WGL_ACCUM_RED_BITS_ARB; + attributes[numAttributes++] = WGL_ACCUM_GREEN_BITS_ARB; + attributes[numAttributes++] = WGL_ACCUM_BLUE_BITS_ARB; + attributes[numAttributes++] = WGL_ACCUM_ALPHA_BITS_ARB; + + if (availableExtensions.contains ("WGL_ARB_multisample")) + attributes[numAttributes++] = WGL_SAMPLES_ARB; + + int values[32]; + zeromem (values, sizeof (values)); + + if (wglGetPixelFormatAttribivARB (dc, pixelFormatIndex, 0, numAttributes, attributes, values)) + { + int n = 0; + bool isValidFormat = (values[n++] == GL_TRUE); // WGL_DRAW_TO_WINDOW_ARB + isValidFormat = (values[n++] == GL_TRUE) && isValidFormat; // WGL_SUPPORT_OPENGL_ARB + isValidFormat = (values[n++] == WGL_FULL_ACCELERATION_ARB) && isValidFormat; // WGL_ACCELERATION_ARB + isValidFormat = (values[n++] == GL_TRUE) && isValidFormat; // WGL_DOUBLE_BUFFER_ARB: + isValidFormat = (values[n++] == WGL_TYPE_RGBA_ARB) && isValidFormat; // WGL_PIXEL_TYPE_ARB + result.redBits = values[n++]; // WGL_RED_BITS_ARB + result.greenBits = values[n++]; // WGL_GREEN_BITS_ARB + result.blueBits = values[n++]; // WGL_BLUE_BITS_ARB + result.alphaBits = values[n++]; // WGL_ALPHA_BITS_ARB + result.depthBufferBits = values[n++]; // WGL_DEPTH_BITS_ARB + result.stencilBufferBits = values[n++]; // WGL_STENCIL_BITS_ARB + result.accumulationBufferRedBits = values[n++]; // WGL_ACCUM_RED_BITS_ARB + result.accumulationBufferGreenBits = values[n++]; // WGL_ACCUM_GREEN_BITS_ARB + result.accumulationBufferBlueBits = values[n++]; // WGL_ACCUM_BLUE_BITS_ARB + result.accumulationBufferAlphaBits = values[n++]; // WGL_ACCUM_ALPHA_BITS_ARB + result.fullSceneAntiAliasingNumSamples = values[n++]; // WGL_SAMPLES_ARB + + return isValidFormat; + } + else + { + jassertfalse + } + } + else + { + PIXELFORMATDESCRIPTOR pfd; + + if (DescribePixelFormat (dc, pixelFormatIndex, sizeof (pfd), &pfd)) + { + result.redBits = pfd.cRedBits; + result.greenBits = pfd.cGreenBits; + result.blueBits = pfd.cBlueBits; + result.alphaBits = pfd.cAlphaBits; + result.depthBufferBits = pfd.cDepthBits; + result.stencilBufferBits = pfd.cStencilBits; + result.accumulationBufferRedBits = pfd.cAccumRedBits; + result.accumulationBufferGreenBits = pfd.cAccumGreenBits; + result.accumulationBufferBlueBits = pfd.cAccumBlueBits; + result.accumulationBufferAlphaBits = pfd.cAccumAlphaBits; + result.fullSceneAntiAliasingNumSamples = 0; + + return true; + } + else + { + jassertfalse + } + } + + return false; } + + WindowedGLContext (const WindowedGLContext&); + const WindowedGLContext& operator= (const WindowedGLContext&); +}; + +//============================================================================== +OpenGLContext* OpenGLContext::createContextForWindow (Component* const component, + const OpenGLPixelFormat& pixelFormat, + const OpenGLContext* const contextToShareWith) +{ + WindowedGLContext* c = new WindowedGLContext (component, + contextToShareWith != 0 ? (HGLRC) contextToShareWith->getRawContext() : 0); + + if (c->renderContext == 0 || ! c->setPixelFormat (pixelFormat)) + deleteAndZero (c); + + return c; } -bool juce_makeOpenGLContextCurrent (void* context) +void juce_glViewport (const int w, const int h) { - OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; - - if (oc != 0) - return wglMakeCurrent (oc->dc, oc->renderContext) != 0; - else - return wglMakeCurrent (0, 0) != 0; + glViewport (0, 0, w, h); } -bool juce_isActiveOpenGLContext (void* context) throw() +void OpenGLPixelFormat::getAvailablePixelFormats (OwnedArray & results) { - OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; + Component tempComp; - jassert (oc != 0); - return wglGetCurrentContext() == oc->renderContext; -} - -void juce_swapOpenGLBuffers (void* context) -{ - OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; - - if (oc != 0) - SwapBuffers (oc->dc); -} - -void juce_repaintOpenGLWindow (void* context) -{ - OpenGLContextInfo* const oc = (OpenGLContextInfo*) context; - - if (oc != 0) { - int x, y, w, h; - oc->nativeWindow->getBounds (x, y, w, h); - oc->nativeWindow->repaint (0, 0, w, h); + WindowedGLContext wc (&tempComp, 0); + wc.makeActive(); + wc.findAlternativeOpenGLPixelFormats (results); } } #endif +//============================================================================== //============================================================================== class JuceIStorage : public IStorage { diff --git a/docs/JUCE changelist.txt b/docs/JUCE changelist.txt index 95bea243e0..763ab8eb45 100644 --- a/docs/JUCE changelist.txt +++ b/docs/JUCE changelist.txt @@ -14,6 +14,7 @@ Changelist for version 1.45 - new class: FileSearchPathListComponent, for letting the user edit a FileSearchPath. - added a critical section option to ReferenceCountedArray - refactored and added features to the Socket class, replacing it with StreamableSocket (basically the same as the original class), and DatagramSocket. +- refactored the OpenGLComponent, adding new classes OpenGLPixelFormat and OpenGLContext ============================================================================== Changelist for version 1.44 diff --git a/extras/juce demo/build/linux/JuceDemo.make b/extras/juce demo/build/linux/JuceDemo.make index 66f84dccb0..a6476543ab 100644 --- a/extras/juce demo/build/linux/JuceDemo.make +++ b/extras/juce demo/build/linux/JuceDemo.make @@ -13,7 +13,7 @@ ifeq ($(CONFIG),Debug) CPPFLAGS := -MMD -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -I "/usr/include" CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -g -D_DEBUG -ggdb CXXFLAGS := $(CFLAGS) - LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -mwindows -L"/usr/X11R6/lib/" -L"../../../../bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound -ljuce_debug + LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -mwindows -L"/usr/X11R6/lib/" -L"../../../../bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound -lXss -ljuce_debug LDDEPS := RESFLAGS := -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -I "/usr/include" TARGET := jucedemo @@ -28,7 +28,7 @@ ifeq ($(CONFIG),Release) CPPFLAGS := -MMD -D "LINUX=1" -D "NDEBUG=1" -I "/usr/include" CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -O2 CXXFLAGS := $(CFLAGS) - LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -mwindows -s -L"/usr/X11R6/lib/" -L"../../../../bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound -ljuce + LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -mwindows -s -L"/usr/X11R6/lib/" -L"../../../../bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound -lXss -ljuce LDDEPS := RESFLAGS := -D "LINUX=1" -D "NDEBUG=1" -I "/usr/include" TARGET := jucedemo diff --git a/extras/juce demo/build/linux/jucedemo_premake.lua b/extras/juce demo/build/linux/jucedemo_premake.lua index abab2a2e84..5fc9968fc5 100644 --- a/extras/juce demo/build/linux/jucedemo_premake.lua +++ b/extras/juce demo/build/linux/jucedemo_premake.lua @@ -31,11 +31,11 @@ package.libpaths = { } package.config["Debug"].links = { - "freetype", "pthread", "rt", "X11", "GL", "GLU", "Xinerama", "asound", "juce_debug" + "freetype", "pthread", "rt", "X11", "GL", "GLU", "Xinerama", "asound", "Xss", "juce_debug" } package.config["Release"].links = { - "freetype", "pthread", "rt", "X11", "GL", "GLU", "Xinerama", "asound", "juce" + "freetype", "pthread", "rt", "X11", "GL", "GLU", "Xinerama", "asound", "Xss", "juce" } package.linkflags = { "static-runtime" } diff --git a/extras/juce demo/src/demos/OpenGLDemo.cpp b/extras/juce demo/src/demos/OpenGLDemo.cpp index a20a09c96e..3579af7f82 100644 --- a/extras/juce demo/src/demos/OpenGLDemo.cpp +++ b/extras/juce demo/src/demos/OpenGLDemo.cpp @@ -81,6 +81,32 @@ public: delete im; startTimer (20); + + // Just for demo purposes, let's dump a list of all the available pixel formats.. + OwnedArray availablePixelFormats; + OpenGLPixelFormat::getAvailablePixelFormats (availablePixelFormats); + + for (int i = 0; i < availablePixelFormats.size(); ++i) + { + const OpenGLPixelFormat* const pixFormat = availablePixelFormats[i]; + + String formatDescription; + formatDescription + << i << ": RGBA=(" << pixFormat->redBits + << ", " << pixFormat->greenBits + << ", " << pixFormat->blueBits + << ", " << pixFormat->alphaBits + << "), depth=" << pixFormat->depthBufferBits + << ", stencil=" << pixFormat->stencilBufferBits + << ", accum RGBA=(" << pixFormat->accumulationBufferRedBits + << ", " << pixFormat->accumulationBufferGreenBits + << ", " << pixFormat->accumulationBufferBlueBits + << ", " << pixFormat->accumulationBufferAlphaBits + << "), full-scene AA=" + << pixFormat->fullSceneAntiAliasingNumSamples; + + Logger::outputDebugString (formatDescription); + } } ~DemoOpenGLCanvas() diff --git a/src/juce_appframework/gui/components/special/juce_OpenGLComponent.cpp b/src/juce_appframework/gui/components/special/juce_OpenGLComponent.cpp index e4cdded509..d2ecbf4ca1 100644 --- a/src/juce_appframework/gui/components/special/juce_OpenGLComponent.cpp +++ b/src/juce_appframework/gui/components/special/juce_OpenGLComponent.cpp @@ -29,229 +29,216 @@ ============================================================================== */ -#ifdef _MSC_VER - #pragma warning (disable: 4514) - #pragma warning (push) -#endif - -#include "../../../../../juce_Config.h" +#include "../../../../juce_core/basics/juce_StandardHeader.h" #if JUCE_OPENGL -#ifdef _WIN32 -#include -#include -#else - #ifdef LINUX - #include - #else - #include - #endif -#endif - -#include "../../../../juce_core/basics/juce_StandardHeader.h" - BEGIN_JUCE_NAMESPACE -#undef KeyPress #include "juce_OpenGLComponent.h" -#include "../../graphics/geometry/juce_RectangleList.h" -#include "../../../events/juce_Timer.h" #include "../layout/juce_ComponentMovementWatcher.h" - -#ifdef _MSC_VER - #pragma warning (pop) -#endif - -//============================================================================== -extern void* juce_createOpenGLContext (OpenGLComponent* component, void* sharedContext); -extern void juce_deleteOpenGLContext (void* context); -extern bool juce_makeOpenGLContextCurrent (void* context); -extern void juce_swapOpenGLBuffers (void* context); -extern void juce_updateOpenGLWindowPos (void* context, Component* owner, Component* topComp); -extern void juce_repaintOpenGLWindow (void* context); -extern bool juce_isActiveOpenGLContext (void* context) throw(); - -static VoidArray activeGLWindows (2); +#include "../../../../juce_core/threads/juce_ScopedLock.h" //============================================================================== -class InternalGLContextHolder : public ComponentMovementWatcher +extern void juce_glViewport (const int w, const int h); + + +//============================================================================== +OpenGLPixelFormat::OpenGLPixelFormat (const int bitsPerRGBComponent, + const int alphaBits_, + const int depthBufferBits_, + const int stencilBufferBits_) throw() + : redBits (bitsPerRGBComponent), + greenBits (bitsPerRGBComponent), + blueBits (bitsPerRGBComponent), + alphaBits (alphaBits_), + depthBufferBits (depthBufferBits_), + stencilBufferBits (stencilBufferBits_), + accumulationBufferRedBits (0), + accumulationBufferGreenBits (0), + accumulationBufferBlueBits (0), + accumulationBufferAlphaBits (0), + fullSceneAntiAliasingNumSamples (0) { -private: - OpenGLComponent* owner; - void* context; - InternalGLContextHolder* sharedContext; - bool wasShowing; +} +bool OpenGLPixelFormat::operator== (const OpenGLPixelFormat& other) const throw() +{ + return memcmp (this, &other, sizeof (other)) == 0; +} + + +//============================================================================== +class OpenGLComponentWatcher : public ComponentMovementWatcher +{ public: - bool needToUpdateViewport; - //============================================================================== - InternalGLContextHolder (OpenGLComponent* const owner_, - InternalGLContextHolder* const sharedContext_) + OpenGLComponentWatcher (OpenGLComponent* const owner_) : ComponentMovementWatcher (owner_), owner (owner_), - context (0), - sharedContext (sharedContext_), - wasShowing (false), - needToUpdateViewport (true) + wasShowing (false) { } - ~InternalGLContextHolder() - { - release(); - } - - //============================================================================== - void release() - { - if (context != 0) - { - juce_deleteOpenGLContext (context); - context = 0; - } - } - - void initialise() - { - jassert (context == 0); - - if (context == 0) - { - context = juce_createOpenGLContext (owner, - sharedContext != 0 ? sharedContext->context - : 0); - - if (context != 0) - { - componentMovedOrResized (true, true); - - if (makeCurrent()) - owner->newOpenGLContextCreated(); - } - } - } - - //============================================================================== - bool makeCurrent() const - { - return context != 0 && juce_makeOpenGLContextCurrent (context); - } - - bool isActive() const throw() - { - return context != 0 && juce_isActiveOpenGLContext (context); - } - - void swapBuffers() const - { - if (context != 0) - juce_swapOpenGLBuffers (context); - } - - void repaint() const - { - if (context != 0) - juce_repaintOpenGLWindow (context); - } + ~OpenGLComponentWatcher() {} //============================================================================== void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) { - if (owner->getWidth() > 0 && owner->getHeight() > 0) - { - Component* const topComp = owner->getTopLevelComponent(); - - if (topComp->getPeer() != 0) - { - needToUpdateViewport = true; - - if (context == 0) - { - if (owner->isShowing()) - initialise(); - else - return; - } - - if (context != 0) - juce_updateOpenGLWindowPos (context, owner, topComp); - } - } + owner->updateContextPosition(); } void componentPeerChanged() { - release(); - - if (owner->isShowing() && owner->getTopLevelComponent()->getPeer() != 0) - initialise(); + const ScopedLock sl (owner->getContextLock()); + owner->deleteContext(); + owner->createContext(); } void componentVisibilityChanged (Component&) { - if (wasShowing != owner->isShowing()) + const bool isShowingNow = owner->isShowing(); + + if (wasShowing != isShowingNow) { - wasShowing = owner->isShowing(); - componentMovedOrResized (true, true); + wasShowing = isShowingNow; + owner->updateContextPosition(); } } + + //============================================================================== + juce_UseDebuggingNewOperator + +private: + OpenGLComponent* const owner; + bool wasShowing; }; //============================================================================== -OpenGLComponent::OpenGLComponent (OpenGLComponent* share) +OpenGLComponent::OpenGLComponent() + : context (0), + componentToShareListsWith (0), + needToUpdateViewport (true) { setOpaque (true); - internalData = new InternalGLContextHolder (this, (InternalGLContextHolder*) (share != 0 ? share->internalData : 0)); - - activeGLWindows.add (this); + componentWatcher = new OpenGLComponentWatcher (this); } OpenGLComponent::~OpenGLComponent() { - activeGLWindows.removeValue ((void*) this); + deleteContext(); + delete componentWatcher; +} - InternalGLContextHolder* const context = (InternalGLContextHolder*) internalData; - delete context; +void OpenGLComponent::createContext() +{ + const ScopedLock sl (contextLock); + + jassert (context == 0); + + if (context == 0 && isShowing() && getTopLevelComponent()->getPeer() != 0) + { + context = OpenGLContext::createContextForWindow (this, + preferredPixelFormat, + componentToShareListsWith != 0 + ? componentToShareListsWith->context + : 0); + + if (context != 0) + { + updateContextPosition(); + + if (makeCurrentContextActive()) + newOpenGLContextCreated(); + } + } +} + +void OpenGLComponent::deleteContext() +{ + const ScopedLock sl (contextLock); + deleteAndZero (context); +} + +void OpenGLComponent::updateContextPosition() +{ + needToUpdateViewport = true; + + if (getWidth() > 0 && getHeight() > 0) + { + Component* const topComp = getTopLevelComponent(); + + if (topComp->getPeer() != 0) + { + const ScopedLock sl (contextLock); + + if (context == 0) + createContext(); + + if (context != 0) + context->updateWindowPosition (getScreenX() - topComp->getScreenX(), + getScreenY() - topComp->getScreenY(), + getWidth(), + getHeight(), + topComp->getHeight()); + } + } +} + +const OpenGLPixelFormat OpenGLComponent::getPixelFormat() const +{ + OpenGLPixelFormat pf; + + const ScopedLock sl (contextLock); + if (context != 0) + pf = context->getPixelFormat(); + + return pf; +} + +bool OpenGLComponent::setPixelFormat (const OpenGLPixelFormat& formatToUse) +{ + if (preferredPixelFormat == formatToUse) + return true; + + const ScopedLock sl (contextLock); + deleteContext(); + preferredPixelFormat = formatToUse; + createContext(); + + return context != 0; +} + +void OpenGLComponent::shareWith (OpenGLComponent* const comp) +{ + if (componentToShareListsWith != comp) + { + const ScopedLock sl (contextLock); + deleteContext(); + componentToShareListsWith = comp; + createContext(); + } } bool OpenGLComponent::makeCurrentContextActive() { - InternalGLContextHolder* const context = (InternalGLContextHolder*) internalData; - return context->makeCurrent(); + return context != 0 && context->makeActive(); } void OpenGLComponent::makeCurrentContextInactive() { - juce_makeOpenGLContextCurrent (0); + if (context != 0) + context->makeInactive(); } bool OpenGLComponent::isActiveContext() const throw() { - const InternalGLContextHolder* const context = (InternalGLContextHolder*) internalData; - return context != 0 && context->isActive(); } -OpenGLComponent* OpenGLComponent::getCurrentlyActiveContextComponent() throw() -{ - for (int i = activeGLWindows.size(); --i >= 0;) - { - OpenGLComponent* const component = (OpenGLComponent*) activeGLWindows.getUnchecked(i); - - if (component->isActiveContext()) - return component; - } - - return 0; -} - void OpenGLComponent::swapBuffers() { - InternalGLContextHolder* const context = (InternalGLContextHolder*) internalData; - if (context != 0) context->swapBuffers(); } @@ -273,20 +260,19 @@ void OpenGLComponent::paint (Graphics&) bool OpenGLComponent::renderAndSwapBuffers() { + const ScopedLock sl (contextLock); + if (! makeCurrentContextActive()) return false; - InternalGLContextHolder* const context = (InternalGLContextHolder*) internalData; - - if (context->needToUpdateViewport) + if (needToUpdateViewport) { - context->needToUpdateViewport = false; - glViewport (0, 0, getWidth(), getHeight()); + needToUpdateViewport = false; + juce_glViewport (getWidth(), getHeight()); } renderOpenGL(); - - context->swapBuffers(); + swapBuffers(); return true; } @@ -295,8 +281,8 @@ void OpenGLComponent::internalRepaint (int x, int y, int w, int h) { Component::internalRepaint (x, y, w, h); - InternalGLContextHolder* const context = (InternalGLContextHolder*) internalData; - context->repaint(); + if (context != 0) + context->repaint(); } diff --git a/src/juce_appframework/gui/components/special/juce_OpenGLComponent.h b/src/juce_appframework/gui/components/special/juce_OpenGLComponent.h index 8c6f13ab59..3b9e557be2 100644 --- a/src/juce_appframework/gui/components/special/juce_OpenGLComponent.h +++ b/src/juce_appframework/gui/components/special/juce_OpenGLComponent.h @@ -37,6 +37,119 @@ // this is used to disable OpenGL, and is defined in juce_Config.h #if JUCE_OPENGL || DOXYGEN +class OpenGLComponentWatcher; + + +//============================================================================== +/** + Represents the various properties of an OpenGL bitmap format. + + @see OpenGLComponent::setPixelFormat +*/ +struct OpenGLPixelFormat +{ + //============================================================================== + /** Creates an OpenGLPixelFormat. + + The default constructor just initialises the object as a simple 8-bit + RGBA format. + */ + OpenGLPixelFormat (const int bitsPerRGBComponent = 8, + const int alphaBits = 8, + const int depthBufferBits = 16, + const int stencilBufferBits = 0) throw(); + + //============================================================================== + int redBits; /**< The number of bits per pixel to use for the red channel. */ + int greenBits; /**< The number of bits per pixel to use for the green channel. */ + int blueBits; /**< The number of bits per pixel to use for the blue channel. */ + int alphaBits; /**< The number of bits per pixel to use for the alpha channel. */ + + int depthBufferBits; /**< The number of bits per pixel to use for a depth buffer. */ + int stencilBufferBits; /**< The number of bits per pixel to use for a stencil buffer. */ + + int accumulationBufferRedBits; /**< The number of bits per pixel to use for an accumulation buffer's red channel. */ + int accumulationBufferGreenBits; /**< The number of bits per pixel to use for an accumulation buffer's green channel. */ + int accumulationBufferBlueBits; /**< The number of bits per pixel to use for an accumulation buffer's blue channel. */ + int accumulationBufferAlphaBits; /**< The number of bits per pixel to use for an accumulation buffer's alpha channel. */ + + uint8 fullSceneAntiAliasingNumSamples; /**< The number of samples to use in full-scene anti-aliasing (if available). */ + + //============================================================================== + /** Returns a list of all the pixel formats that can be used in this system. + */ + static void getAvailablePixelFormats (OwnedArray & results); + + //============================================================================== + bool operator== (const OpenGLPixelFormat&) const throw(); + + juce_UseDebuggingNewOperator +}; + +//============================================================================== +/** + A base class for types of OpenGL context. + + An OpenGLComponent will supply its own context for drawing in its window. +*/ +class OpenGLContext +{ +public: + //============================================================================== + /** Destructor. */ + virtual ~OpenGLContext() {} + + //============================================================================== + /** Makes this context the currently active one. */ + virtual bool makeActive() throw() = 0; + /** If this context is currently active, it is disactivated. */ + virtual bool makeInactive() throw() = 0; + /** Returns true if this context is currently active. */ + virtual bool isActive() const throw() = 0; + + /** Swaps the buffers (if the context can do this). */ + virtual void swapBuffers() = 0; + + //============================================================================== + /** Returns the pixel format being used by this context. */ + virtual const OpenGLPixelFormat getPixelFormat() const = 0; + + /** For windowed contexts, this moves the context within the bounds of + its parent window. + */ + virtual void updateWindowPosition (int x, int y, int w, int h, int outerWindowHeight) = 0; + + /** For windowed contexts, this triggers a repaint of the window. + + (Not relevent on all platforms). + */ + virtual void repaint() = 0; + + /** Returns an OS-dependent handle to the raw GL context. + + On win32, this will be a HGLRC; on the Mac, an AGLContext; on Linux, + a GLXContext. + */ + virtual void* getRawContext() const throw() = 0; + + //============================================================================== + /** This tries to create a context that can be used for drawing into the + area occupied by the specified component. + + Note that you probably shouldn't use this method directly unless you know what + you're doing - the OpenGLComponent calls this and manages the context for you. + */ + static OpenGLContext* createContextForWindow (Component* componentToDrawTo, + const OpenGLPixelFormat& pixelFormat, + const OpenGLContext* const contextToShareWith); + + //============================================================================== + juce_UseDebuggingNewOperator + +protected: + OpenGLContext() throw() {}; +}; + //============================================================================== /** @@ -51,42 +164,28 @@ class JUCE_API OpenGLComponent : public Component public: //============================================================================== /** Creates an OpenGLComponent. - - @param componentToShareContextWith if this is another OpenGLComponent, then - the two contexts will have their OpenGL contexts - shared */ - OpenGLComponent (OpenGLComponent* componentToShareContextWith = 0); + OpenGLComponent(); /** Destructor. */ ~OpenGLComponent(); //============================================================================== - /** Makes this component the current openGL context. + /** Changes the pixel format used by this component. - You might want to use this in things like your resize() method, before calling - GL commands. - - If this returns false, then the context isn't active, so you should avoid - making any calls. + @see OpenGLPixelFormat::getAvailablePixelFormats() */ - bool makeCurrentContextActive(); + bool setPixelFormat (const OpenGLPixelFormat& formatToUse); - /** Stops the current component being the active OpenGL context. + /** Returns the pixel format that this component is currently using. */ + const OpenGLPixelFormat getPixelFormat() const; - This is the opposite of makeCurrentContextActive() + /** Specifies another component whose OpenGL context should be shared with + this one. + + This is an OpenGL feature that lets two contexts share their texture data. */ - void makeCurrentContextInactive(); - - /** Returns true if this component is the active openGL context for the - current thread. - */ - bool isActiveContext() const throw(); - - /** Returns the OpenGLComponent that is currently the active context for - the current thread. - */ - static OpenGLComponent* getCurrentlyActiveContextComponent() throw(); + void shareWith (OpenGLComponent* const componentToShareListsWith); //============================================================================== /** Flips the openGL buffers over. */ @@ -115,16 +214,63 @@ public: virtual void newOpenGLContextCreated() = 0; + //============================================================================== + /** Returns the context that will draw into this component. + + This may return 0 if it failed to initialise properly, or if the component + is currently invisible. The context object may be deleted and a new one created + during the life of this component - see newOpenGLContextCreated(). + */ + OpenGLContext* getCurrentContext() const throw(); + + /** Makes this component the current openGL context. + + You might want to use this in things like your resize() method, before calling + GL commands. + + If this returns false, then the context isn't active, so you should avoid + making any calls. + + @see OpenGLContext::makeActive + */ + bool makeCurrentContextActive(); + + /** Stops the current component being the active OpenGL context. + + This is the opposite of makeCurrentContextActive() + + @see OpenGLContext::makeInactive + */ + void makeCurrentContextInactive(); + + /** Returns true if this component is the active openGL context for the + current thread. + + @see OpenGLContext::isActive + */ + bool isActiveContext() const throw(); + + //============================================================================== /** Calls the rendering callback, and swaps the buffers afterwards. - Called by paint(), this can be overridden if you need to decouple the rendering - from the paint callback and render with a different thread. + This is called automatically by paint() when the component needs to be rendered. + + It can be overridden if you need to decouple the rendering from the paint callback + and render with a custom thread. Returns true if the operation succeeded. */ virtual bool renderAndSwapBuffers(); + /** This returns a critical section that can be used to lock the current context. + + Because the context that is used by this component can change, e.g. when the + component is shown or hidden, then if you're rendering to it on a background + thread, this allows you to lock the context for the duration of your rendering + routine. + */ + CriticalSection& getContextLock() throw() { return contextLock; } //============================================================================== /** @internal */ @@ -133,13 +279,23 @@ public: juce_UseDebuggingNewOperator private: - friend class InternalGLContextHolder; - void* internalData; + friend class OpenGLComponentWatcher; + OpenGLComponentWatcher* componentWatcher; + + OpenGLContext* context; + OpenGLComponent* componentToShareListsWith; + + CriticalSection contextLock; + OpenGLPixelFormat preferredPixelFormat; + bool needToUpdateViewport; + + void createContext(); + void deleteContext(); + void updateContextPosition(); + void internalRepaint (int x, int y, int w, int h); OpenGLComponent (const OpenGLComponent&); const OpenGLComponent& operator= (const OpenGLComponent&); - - void internalRepaint (int x, int y, int w, int h); };