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 );
}
