While i was working on a video player i wondered wether i could make my window transparent using the video's alpha channel as a mask. Video Codecs like Prores 4444 or DXV (our own codec) can contain an alpha channel.
So I set my OpenGLAppComponent to be not opaque and made sure i would clear to transparentBlack in the render callback. I actually though it would just work out of the box because with a normal Component this is all you have to do.
What i found out is though that on OSX you need to set the NSOpenGLCPSurfaceOpacity of the native NSOpenGLContext, otherwise it will be always opaque and show black. Once i figured out how to set this flag it worked beatifully.
So i though i share the code with you. I added a screenshot that demonstrates what you would see if you use the code below and show it on top of a Chrome browser with the Juce.com homepage ;-)
Code:
Usage:
glComponent = new GLComponent(); glComponent->setVisible(true); glComponent->centreWithSize(800, 600); glComponent->addToDesktop(0);
GLComponent.h
#include "headers.h" class GLComponent : public OpenGLAppComponent { public: GLComponent (); ~GLComponent(); void paint (Graphics& g) override; void resized() override; void setOpenGLContextSurfaceOpacityToZero(); void initialise() override; void shutdown() override; void render() override; private: void drawCube(); void setPerspectiveProjection( float fovy, float aspect, float zNear, float zFar ); };
GLComponent.mm
#include <AppKit/NSOpenGL.h> #include "GLComponent.h" void GLComponent::setOpenGLContextSurfaceOpacityToZero() { NSOpenGLContext* context = (NSOpenGLContext*)openGLContext.getRawContext(); GLint aValue = 0; [context setValues:&aValue forParameter:NSOpenGLCPSurfaceOpacity]; }
GLComponent.cpp
Just some demonstration code, rendering a few cubes using ancient OpenGL code.
#include "GLComponent.h" GLComponent::GLComponent() { setOpaque (false); setSize (800, 600); } GLComponent::~GLComponent() { } void GLComponent::paint (Graphics& g) { } void GLComponent::resized() { } void GLComponent::initialise() { setOpenGLContextSurfaceOpacityToZero(); } void GLComponent::shutdown() { } void GLComponent::render() { OpenGLHelpers::clear(Colours::transparentBlack); glMatrixMode( GL_PROJECTION ); glPushMatrix(); setPerspectiveProjection( 45.0f, (float)getWidth() / getHeight(), 0.1, 100.0 ); glMatrixMode( GL_MODELVIEW ); glPushMatrix(); glLoadIdentity(); glPushMatrix(); //OpenGLHelpers::clear(); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); float value = sin(Time::getMillisecondCounter()/1000.0f); Colour blue = Colours::steelblue; float x = -1.0; float y = -1.0; for (int i=0; i<9;i++) { glPushMatrix(); glTranslatef(x, y, -9.0); glRotatef(-180.0f + value*360.0f, 0.5, 1.0, 0.0); glColor4f(blue.getFloatRed(), blue.getFloatGreen(), blue.getFloatBlue(), 1.0/(float)(i+1)); drawCube(); glPopMatrix(); if (i % 3 == 0) { x = -1.0; y += 1.0; } else { x += 1.0; } } glPopMatrix(); glMatrixMode( GL_PROJECTION ); glPopMatrix(); glMatrixMode( GL_MODELVIEW ); glPopMatrix(); } void GLComponent::drawCube() { static const GLfloat cube_vertices[] = { -1.0f,-1.0f,-1.0f, // triangle 1 : begin -1.0f,-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, // triangle 1 : end 1.0f, 1.0f,-1.0f, // triangle 2 : begin -1.0f,-1.0f,-1.0f, -1.0f, 1.0f,-1.0f, // triangle 2 : end 1.0f,-1.0f, 1.0f, -1.0f,-1.0f,-1.0f, 1.0f,-1.0f,-1.0f, 1.0f, 1.0f,-1.0f, 1.0f,-1.0f,-1.0f, -1.0f,-1.0f,-1.0f, -1.0f,-1.0f,-1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f,-1.0f, 1.0f,-1.0f, 1.0f, -1.0f,-1.0f, 1.0f, -1.0f,-1.0f,-1.0f, -1.0f, 1.0f, 1.0f, -1.0f,-1.0f, 1.0f, 1.0f,-1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,-1.0f,-1.0f, 1.0f, 1.0f,-1.0f, 1.0f,-1.0f,-1.0f, 1.0f, 1.0f, 1.0f, 1.0f,-1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,-1.0f, -1.0f, 1.0f,-1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f,-1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f,-1.0f, 1.0f }; glEnableClientState( GL_VERTEX_ARRAY ); glVertexPointer(3, GL_FLOAT, 0, &cube_vertices[0] ); glDrawArrays(GL_TRIANGLES, 0, 12*3); glDisableClientState( GL_VERTEX_ARRAY ); } void GLComponent::setPerspectiveProjection( float fovy, float aspect, float zNear, float zFar ) { RA_GLCONTEXT; glMatrixMode( GL_PROJECTION ); glLoadIdentity(); // This code is based off the MESA source for gluPerspective // *NOTE* This assumes GL_PROJECTION is the current matrix float xmin, xmax, ymin, ymax; float m[ 16 ] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; #define M(x,y) m[((y)<<2)+(x)] ymax = zNear * tan( fovy * PI / 360.0 ); ymin = -ymax; xmin = ymin * aspect; xmax = ymax * aspect; // Set up the projection matrix M( 0, 0 ) = ( 2.0 * zNear ) / ( xmax - xmin ); //proj00 = M( 1, 1 ) = ( 2.0 * zNear ) / ( ymax - ymin ); //proj11 = M( 2, 2 ) = -( zFar + zNear ) / ( zFar - zNear ); M( 0, 2 ) = ( xmax + xmin ) / ( xmax - xmin ); M( 1, 2 ) = ( ymax + ymin ) / ( ymax - ymin ); M( 3, 2 ) = -1.0; M( 2, 3 ) = -( 2.0 * zFar * zNear ) / ( zFar - zNear ); #undef M // Add to current matrix glMultMatrixf( m ); glMatrixMode( GL_MODELVIEW ); }