| @@ -37,36 +37,14 @@ public: | |||
| delta (1.0f) | |||
| { | |||
| startTimer (20); | |||
| // Just for demo purposes, let's dump a list of all the available pixel formats.. | |||
| OwnedArray <OpenGLPixelFormat> availablePixelFormats; | |||
| OpenGLPixelFormat::getAvailablePixelFormats (this, availablePixelFormats); | |||
| for (int i = 0; i < availablePixelFormats.size(); ++i) | |||
| { | |||
| const OpenGLPixelFormat* const pixFormat = availablePixelFormats[i]; | |||
| DBG (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=" | |||
| << (int) pixFormat->fullSceneAntiAliasingNumSamples); | |||
| } | |||
| } | |||
| // when the component creates a new internal context, this is called, and | |||
| // we'll use the opportunity to create the textures needed. | |||
| void newOpenGLContextCreated() | |||
| { | |||
| texture1 = createImage1(); | |||
| texture2 = createImage2(); | |||
| texture1.load (createImage1()); | |||
| texture2.load (createImage2()); | |||
| // (no need to call makeCurrentContextActive(), as that will have | |||
| // been done for us before the method call). | |||
| @@ -89,20 +67,17 @@ public: | |||
| void renderOpenGL() | |||
| { | |||
| OpenGLHelpers::clear (Colours::darkgrey.withAlpha (0.0f)); | |||
| OpenGLHelpers::clear (Colours::darkgrey.withAlpha (1.0f)); | |||
| OpenGLHelpers::prepareFor2D (getWidth(), getHeight()); | |||
| glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |||
| glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||
| OpenGLFrameBuffer& frameBuffer1 = dynamic_cast <OpenGLFrameBufferImage*> (texture1.getSharedImage())->frameBuffer; | |||
| OpenGLFrameBuffer& frameBuffer2 = dynamic_cast <OpenGLFrameBufferImage*> (texture2.getSharedImage())->frameBuffer; | |||
| frameBuffer1.draw2D (50.0f, getHeight() - 50.0f, | |||
| getWidth() - 50.0f, getHeight() - 50.0f, | |||
| getWidth() - 50.0f, 50.0f, | |||
| 50.0f, 50.0f, | |||
| Colours::white.withAlpha (fabsf (::sinf (rotation / 100.0f)))); | |||
| texture1.draw2D (50.0f, getHeight() - 50.0f, | |||
| getWidth() - 50.0f, getHeight() - 50.0f, | |||
| getWidth() - 50.0f, 50.0f, | |||
| 50.0f, 50.0f, | |||
| Colours::white.withAlpha (fabsf (::sinf (rotation / 100.0f)))); | |||
| glClear (GL_DEPTH_BUFFER_BIT); | |||
| @@ -112,12 +87,12 @@ public: | |||
| glRotatef (rotation, 0.5f, 1.0f, 0.0f); | |||
| // this draws the sides of our spinning cube.. | |||
| frameBuffer1.draw3D (-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, Colours::white); | |||
| frameBuffer1.draw3D (-1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, Colours::white); | |||
| frameBuffer1.draw3D (-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, Colours::white); | |||
| frameBuffer2.draw3D (-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, Colours::white); | |||
| frameBuffer2.draw3D ( 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, Colours::white); | |||
| frameBuffer2.draw3D (-1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, Colours::white); | |||
| texture1.draw3D (-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, Colours::white); | |||
| texture1.draw3D (-1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, Colours::white); | |||
| texture1.draw3D (-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, Colours::white); | |||
| texture2.draw3D (-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, Colours::white); | |||
| texture2.draw3D ( 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, Colours::white); | |||
| texture2.draw3D (-1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, Colours::white); | |||
| } | |||
| void timerCallback() | |||
| @@ -127,13 +102,13 @@ public: | |||
| } | |||
| private: | |||
| Image texture1, texture2; | |||
| OpenGLTexture texture1, texture2; | |||
| float rotation, delta; | |||
| // Functions to create a couple of images to use as textures.. | |||
| static Image createImage1() | |||
| { | |||
| Image image (new OpenGLFrameBufferImage (256, 256)); | |||
| Image image (Image::ARGB, 256, 256, true); | |||
| Graphics g (image); | |||
| @@ -148,7 +123,7 @@ private: | |||
| static Image createImage2() | |||
| { | |||
| Image image (new OpenGLFrameBufferImage (128, 128)); | |||
| Image image (Image::ARGB, 128, 128, true); | |||
| Graphics g (image); | |||
| g.fillAll (Colours::darkred.withAlpha (0.7f)); | |||
| @@ -158,7 +158,7 @@ public: | |||
| /** Returns a rectangle with the same size as this image. | |||
| The rectangle's origin is always (0, 0). | |||
| */ | |||
| const Rectangle<int> getBounds() const noexcept { return image == nullptr ? Rectangle<int>() : Rectangle<int> (image->width, image->height); } | |||
| Rectangle<int> getBounds() const noexcept { return image == nullptr ? Rectangle<int>() : Rectangle<int> (image->width, image->height); } | |||
| /** Returns the image's pixel format. */ | |||
| PixelFormat getFormat() const noexcept { return image == nullptr ? UnknownFormat : image->format; } | |||
| @@ -34,10 +34,9 @@ void* OpenGLComponent::getNativeWindowHandle() const | |||
| return nullptr; | |||
| } | |||
| void OpenGLPixelFormat::getAvailablePixelFormats (Component* component, | |||
| OwnedArray <OpenGLPixelFormat>& results) | |||
| void OpenGLComponent::internalRepaint (int x, int y, int w, int h) | |||
| { | |||
| Component::internalRepaint (x, y, w, h); | |||
| } | |||
| bool OpenGLHelpers::isContextActive() | |||
| @@ -143,10 +143,6 @@ public: | |||
| return numFrames; | |||
| } | |||
| void repaint() | |||
| { | |||
| } | |||
| //============================================================================== | |||
| void createGLBuffers() | |||
| { | |||
| @@ -231,9 +227,15 @@ OpenGLContext* OpenGLComponent::createContext() | |||
| return nullptr; | |||
| } | |||
| void OpenGLPixelFormat::getAvailablePixelFormats (Component* /*component*/, | |||
| OwnedArray <OpenGLPixelFormat>& /*results*/) | |||
| void OpenGLComponent::internalRepaint (int x, int y, int w, int h) | |||
| { | |||
| Component::internalRepaint (x, y, w, h); | |||
| } | |||
| void OpenGLComponent::updateEmbeddedPosition (const Rectangle<int>& bounds) | |||
| { | |||
| if (context != nullptr) | |||
| static_cast <GLESContext*> (context.get())->updateWindowPosition (bounds); | |||
| } | |||
| //============================================================================== | |||
| @@ -151,13 +151,6 @@ public: | |||
| return 0; | |||
| } | |||
| void updateWindowPosition (const Rectangle<int>& bounds) | |||
| { | |||
| ScopedXLock xlock; | |||
| XMoveResizeWindow (display, embeddedWindow, | |||
| bounds.getX(), bounds.getY(), jmax (1, bounds.getWidth()), jmax (1, bounds.getHeight())); | |||
| } | |||
| void swapBuffers() | |||
| { | |||
| ScopedXLock xlock; | |||
| @@ -179,13 +172,12 @@ public: | |||
| } | |||
| int getSwapInterval() const { return swapInterval; } | |||
| void repaint() {} | |||
| //============================================================================== | |||
| GLXContext renderContext; | |||
| Window embeddedWindow; | |||
| private: | |||
| Window embeddedWindow; | |||
| OpenGLPixelFormat pixelFormat; | |||
| int swapInterval; | |||
| @@ -201,9 +193,21 @@ OpenGLContext* OpenGLComponent::createContext() | |||
| return (c->renderContext != 0) ? c.release() : nullptr; | |||
| } | |||
| void OpenGLPixelFormat::getAvailablePixelFormats (Component* component, OwnedArray <OpenGLPixelFormat>& results) | |||
| void OpenGLComponent::internalRepaint (int x, int y, int w, int h) | |||
| { | |||
| results.add (new OpenGLPixelFormat()); // xxx | |||
| Component::internalRepaint (x, y, w, h); | |||
| } | |||
| void OpenGLComponent::updateEmbeddedPosition (const Rectangle<int>& bounds) | |||
| { | |||
| if (context != nullptr) | |||
| { | |||
| Window embeddedWindow = static_cast<WindowedGLContext*> (context.get())->embeddedWindow; | |||
| ScopedXLock xlock; | |||
| XMoveResizeWindow (display, embeddedWindow, | |||
| bounds.getX(), bounds.getY(), jmax (1, bounds.getWidth()), jmax (1, bounds.getHeight())); | |||
| } | |||
| } | |||
| //============================================================================== | |||
| @@ -209,8 +209,6 @@ public: | |||
| void* getRawContext() const noexcept { return renderContext; } | |||
| unsigned int getFrameBufferID() const { return 0; } | |||
| void updateWindowPosition (const Rectangle<int>&) {} | |||
| void swapBuffers() | |||
| { | |||
| [renderContext flushBuffer]; | |||
| @@ -231,19 +229,6 @@ public: | |||
| return numFrames; | |||
| } | |||
| void repaint() | |||
| { | |||
| // we need to invalidate the juce view that holds this gl view, to make it | |||
| // cause a repaint callback | |||
| NSRect r = [view frame]; | |||
| // bit of a bodge here.. if we only invalidate the area of the gl component, | |||
| // it's completely covered by the NSOpenGLView, so the OS throws away the | |||
| // repaint message, thus never causing our paint() callback, and never repainting | |||
| // the comp. So invalidating just a little bit around the edge helps.. | |||
| [[view superview] setNeedsDisplayInRect: NSInsetRect (r, -2.0f, -2.0f)]; | |||
| } | |||
| void* getNativeWindowHandle() const { return view; } | |||
| //============================================================================== | |||
| @@ -253,7 +238,6 @@ public: | |||
| private: | |||
| OpenGLPixelFormat pixelFormat; | |||
| //============================================================================== | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowedGLContext); | |||
| }; | |||
| @@ -268,52 +252,30 @@ OpenGLContext* OpenGLComponent::createContext() | |||
| void* OpenGLComponent::getNativeWindowHandle() const | |||
| { | |||
| return context != nullptr ? static_cast<WindowedGLContext*> (static_cast<OpenGLContext*> (context))->getNativeWindowHandle() | |||
| return context != nullptr ? static_cast<WindowedGLContext*> (context.get())->getNativeWindowHandle() | |||
| : nullptr; | |||
| } | |||
| static int getPixelFormatAttribute (NSOpenGLPixelFormat* p, NSOpenGLPixelFormatAttribute att) | |||
| void OpenGLComponent::internalRepaint (int x, int y, int w, int h) | |||
| { | |||
| GLint val = 0; | |||
| [p getValues: &val forAttribute: att forVirtualScreen: 0]; | |||
| return (int) val; | |||
| } | |||
| Component::internalRepaint (x, y, w, h); | |||
| void OpenGLPixelFormat::getAvailablePixelFormats (Component* /*component*/, | |||
| OwnedArray <OpenGLPixelFormat>& results) | |||
| { | |||
| NSOpenGLPixelFormatAttribute attributes[] = | |||
| { | |||
| NSOpenGLPFAWindow, | |||
| NSOpenGLPFADoubleBuffer, | |||
| NSOpenGLPFAAccelerated, | |||
| NSOpenGLPFANoRecovery, | |||
| NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute) 16, | |||
| NSOpenGLPFAAlphaSize, (NSOpenGLPixelFormatAttribute) 8, | |||
| NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute) 24, | |||
| NSOpenGLPFAAccumSize, (NSOpenGLPixelFormatAttribute) 32, | |||
| (NSOpenGLPixelFormatAttribute) 0 | |||
| }; | |||
| NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes: attributes]; | |||
| if (format != nil) | |||
| if (context != nullptr) | |||
| { | |||
| OpenGLPixelFormat* const pf = new OpenGLPixelFormat(); | |||
| pf->redBits = pf->greenBits = pf->blueBits = getPixelFormatAttribute (format, NSOpenGLPFAColorSize) / 3; | |||
| pf->alphaBits = getPixelFormatAttribute (format, NSOpenGLPFAAlphaSize); | |||
| pf->depthBufferBits = getPixelFormatAttribute (format, NSOpenGLPFADepthSize); | |||
| pf->stencilBufferBits = getPixelFormatAttribute (format, NSOpenGLPFAStencilSize); | |||
| pf->accumulationBufferRedBits = pf->accumulationBufferGreenBits | |||
| = pf->accumulationBufferBlueBits = pf->accumulationBufferAlphaBits | |||
| = getPixelFormatAttribute (format, NSOpenGLPFAAccumSize) / 4; | |||
| NSView* const v = static_cast<WindowedGLContext*> (context.get())->view; | |||
| [format release]; | |||
| results.add (pf); | |||
| // bit of a bodge here.. if we only invalidate the area of the gl component, | |||
| // it's completely covered by the NSOpenGLView, so the OS throws away the | |||
| // repaint message, thus never causing our paint() callback, and never repainting | |||
| // the comp. So invalidating just a little bit around the edge helps.. | |||
| [[v superview] setNeedsDisplayInRect: NSInsetRect ([v frame], -2.0f, -2.0f)]; | |||
| } | |||
| } | |||
| void OpenGLComponent::updateEmbeddedPosition (const Rectangle<int>&) | |||
| { | |||
| } | |||
| //============================================================================== | |||
| bool OpenGLHelpers::isContextActive() | |||
| { | |||
| @@ -269,18 +269,6 @@ public: | |||
| return false; | |||
| } | |||
| void updateWindowPosition (const Rectangle<int>& bounds) | |||
| { | |||
| SetWindowPos ((HWND) nativeWindow->getNativeHandle(), 0, | |||
| bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(), | |||
| SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER); | |||
| } | |||
| void repaint() | |||
| { | |||
| nativeWindow->repaint (nativeWindow->getBounds().withPosition (Point<int>())); | |||
| } | |||
| void swapBuffers() | |||
| { | |||
| SwapBuffers (dc); | |||
| @@ -354,9 +342,9 @@ public: | |||
| //============================================================================== | |||
| HGLRC renderContext; | |||
| ScopedPointer<ComponentPeer> nativeWindow; | |||
| private: | |||
| ScopedPointer<ComponentPeer> nativeWindow; | |||
| Component* const component; | |||
| HDC dc; | |||
| @@ -471,18 +459,29 @@ OpenGLContext* OpenGLComponent::createContext() | |||
| void* OpenGLComponent::getNativeWindowHandle() const | |||
| { | |||
| return context != nullptr ? static_cast<WindowedGLContext*> (static_cast<OpenGLContext*> (context))->getNativeWindowHandle() : nullptr; | |||
| return context != nullptr ? static_cast<WindowedGLContext*> (context.get())->getNativeWindowHandle() : nullptr; | |||
| } | |||
| void OpenGLPixelFormat::getAvailablePixelFormats (Component* component, | |||
| OwnedArray <OpenGLPixelFormat>& results) | |||
| void OpenGLComponent::internalRepaint (int x, int y, int w, int h) | |||
| { | |||
| Component tempComp; | |||
| Component::internalRepaint (x, y, w, h); | |||
| if (context != nullptr) | |||
| { | |||
| WindowedGLContext wc (component, 0, OpenGLPixelFormat (8, 8, 16, 0)); | |||
| wc.makeActive(); | |||
| wc.findAlternativeOpenGLPixelFormats (results); | |||
| ComponentPeer* peer = static_cast<WindowedGLContext*> (context.get())->nativeWindow; | |||
| peer->repaint (peer->getBounds().withPosition (Point<int>())); | |||
| } | |||
| } | |||
| void OpenGLComponent::updateEmbeddedPosition (const Rectangle<int>& bounds) | |||
| { | |||
| if (context != nullptr) | |||
| { | |||
| ComponentPeer* peer = static_cast<WindowedGLContext*> (context.get())->nativeWindow; | |||
| SetWindowPos ((HWND) peer->getNativeHandle(), 0, | |||
| bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(), | |||
| SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER); | |||
| } | |||
| } | |||
| @@ -127,7 +127,6 @@ public: | |||
| { | |||
| } | |||
| //============================================================================== | |||
| void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) | |||
| { | |||
| owner->updateContextPosition(); | |||
| @@ -349,9 +348,7 @@ void OpenGLComponent::updateContextPosition() | |||
| if (topComp->getPeer() != nullptr) | |||
| { | |||
| const ScopedLock sl (contextLock); | |||
| if (context != nullptr) | |||
| context->updateWindowPosition (topComp->getLocalArea (this, getLocalBounds())); | |||
| updateEmbeddedPosition (topComp->getLocalArea (this, getLocalBounds())); | |||
| } | |||
| } | |||
| } | |||
| @@ -425,14 +422,6 @@ bool OpenGLComponent::renderAndSwapBuffers() | |||
| return true; | |||
| } | |||
| void OpenGLComponent::internalRepaint (int x, int y, int w, int h) | |||
| { | |||
| Component::internalRepaint (x, y, w, h); | |||
| if (context != nullptr) | |||
| context->repaint(); | |||
| } | |||
| unsigned int OpenGLComponent::getFrameBufferID() const | |||
| { | |||
| return context != nullptr ? context->getFrameBufferID() : 0; | |||
| @@ -72,10 +72,7 @@ public: | |||
| ~OpenGLComponent(); | |||
| //============================================================================== | |||
| /** Changes the pixel format used by this component. | |||
| @see OpenGLPixelFormat::getAvailablePixelFormats() | |||
| */ | |||
| /** Changes the pixel format used by this component. */ | |||
| void setPixelFormat (const OpenGLPixelFormat& formatToUse); | |||
| /** Returns the pixel format that this component is currently using. */ | |||
| @@ -261,6 +258,7 @@ private: | |||
| void stopBackgroundThread(); | |||
| void recreateContextAsync(); | |||
| void internalRepaint (int x, int y, int w, int h); | |||
| void updateEmbeddedPosition (const Rectangle<int>&); | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponent); | |||
| }; | |||
| @@ -72,17 +72,6 @@ public: | |||
| /** Returns the pixel format being used by this context. */ | |||
| virtual OpenGLPixelFormat getPixelFormat() const = 0; | |||
| /** For windowed contexts, this moves the context within the bounds of | |||
| its parent window. | |||
| */ | |||
| virtual void updateWindowPosition (const Rectangle<int>& bounds) = 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 NSOpenGLContext; on Linux, | |||
| @@ -244,7 +244,7 @@ namespace | |||
| glVertexPointer (2, GL_FLOAT, 0, vertices); | |||
| glTexCoordPointer (2, GL_FLOAT, 0, textureCoords); | |||
| const Rectangle<int> targetArea (clip.transformed (transform.inverted())); | |||
| const Rectangle<int> targetArea (clip.toFloat().transformed (transform.inverted()).getSmallestIntegerContainer()); | |||
| int x = targetArea.getX() - negativeAwareModulo (targetArea.getX(), textureWidth); | |||
| int y = targetArea.getY() - negativeAwareModulo (targetArea.getY(), textureHeight); | |||
| const int right = targetArea.getRight(); | |||
| @@ -67,17 +67,7 @@ public: | |||
| 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. | |||
| A reference component is needed in case there are multiple screens with different | |||
| capabilities - in which case, the one that the component is on will be used. | |||
| */ | |||
| static void getAvailablePixelFormats (Component* component, | |||
| OwnedArray <OpenGLPixelFormat>& results); | |||
| private: | |||
| //============================================================================== | |||
| JUCE_LEAK_DETECTOR (OpenGLPixelFormat); | |||
| }; | |||