Reputation: 1329
I want my OpenGL drawing to be inside a transparent windows form.
I got Windows 7 installed on my computer and I am using .NET.
Here is a code that I have managed to write but it is not working - I am still getting back background behind my drawing no matter what I do.
Please tell me what am I doing wrong?
public partial class MainForm : Form
{
private Graphics m_graphics;
private IntPtr m_hDC;
private IntPtr m_RC;
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= (int)User32.WS_EX_LAYERED;
return cp;
}
}
public MainForm()
{
InitializeComponent();
this.m_graphics = null;
this.m_hDC = IntPtr.Zero;
this.m_RC = IntPtr.Zero;
}
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
User32.SetLayeredWindowAttributes(Handle, 0, 0, User32.LWA_COLORKEY);
m_graphics = Graphics.FromHwnd(Handle);
m_hDC = m_graphics.GetHdc();
GosNIIAS.Import.PIXELFORMATDESCRIPTOR pfd = new GosNIIAS.Import.PIXELFORMATDESCRIPTOR();
pfd.nSize = (ushort)Marshal.SizeOf(pfd);
pfd.nVersion = 1;
pfd.dwFlags = OpenGL32.PFD_SUPPORT_OPENGL | OpenGL32.PFD_DRAW_TO_WINDOW | OpenGL32.PFD_DOUBLEBUFFER;
pfd.iPixelType = OpenGL32.PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 16;
pfd.cStencilBits = 8;
int PixelFormat = GDI32.ChoosePixelFormat(m_hDC, ref pfd);
if (PixelFormat != 0)
{
bool bResult = GDI32.SetPixelFormat(m_hDC, PixelFormat, ref pfd);
if (bResult != false)
{
m_RC = OpenGL32.wglCreateContext(m_hDC);
bResult = OpenGL32.wglMakeCurrent(m_hDC, m_RC);
}
}
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
if (m_RC != IntPtr.Zero)
{
OpenGL32.wglMakeCurrent(IntPtr.Zero, IntPtr.Zero);
OpenGL32.wglDeleteContext(m_RC);
m_RC = IntPtr.Zero;
}
if (m_graphics != null)
{
m_graphics.ReleaseHdc();
m_graphics.Dispose();
m_graphics = null;
m_hDC = IntPtr.Zero;
}
}
private void tTimer_Tick(object sender, EventArgs e)
{
OpenGL32.wglMakeCurrent(m_hDC, m_RC);
OpenGL32.glClear(OpenGL32.GL_COLOR_BUFFER_BIT | OpenGL32.GL_DEPTH_BUFFER_BIT);
OpenGL32.glEnable(OpenGL32.GL_BLEND);
OpenGL32.glBlendFunc(OpenGL32.GL_SRC_ALPHA, OpenGL32.GL_ONE_MINUS_SRC_ALPHA);
OpenGL32.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
OpenGL32.glColor3f(0, 1, 1);
OpenGL32.glBegin(OpenGL32.GL_TRIANGLES);
OpenGL32.glColor3f(1.0f, 0.0f, 0.0f);
OpenGL32.glVertex3f(0.0f, 1.0f, 0.0f);
OpenGL32.glColor3f(0.0f, 1.0f, 0.0f);
OpenGL32.glVertex3f(-1.0f, -1.0f, 0.0f);
OpenGL32.glColor3f(0.0f, 0.0f, 1.0f);
OpenGL32.glVertex3f(1.0f, -1.0f, 0.0f);
OpenGL32.glEnd();
GDI32.SwapBuffers(m_hDC);
}
}
Same result when I am using pure c code.
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <windowsx.h>
#include <GL/gl.h>
#include <GL/glu.h>
#pragma comment (lib, "opengl32.lib")
#pragma comment (lib, "glu32.lib")
#define vW 660
#define vH 563
const int cX = vW / 2;
const int cY = vH / 2 - 90;
BOOL CreateHGLRC( HDC hDC, HGLRC* m_hrc )
{
DWORD dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
PIXELFORMATDESCRIPTOR pfd ;
memset(&pfd,0, sizeof(PIXELFORMATDESCRIPTOR)) ;
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = dwFlags ;
pfd.iPixelType = PFD_TYPE_RGBA ;
pfd.cColorBits = 24 ;
pfd.cDepthBits = 32 ;
pfd.iLayerType = PFD_MAIN_PLANE ;
int PixelFormat = ChoosePixelFormat(hDC, &pfd);
BOOL bResult = SetPixelFormat(hDC, PixelFormat, &pfd);
*m_hrc = wglCreateContext(hDC);
return TRUE;
}
LRESULT CALLBACK WndProc( HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
static HDC hDC = NULL; /* Private GDI Device context */
static HGLRC hRC = NULL;
switch (message)
{
/* Window creation, setup for OpenGL */
case WM_CREATE:
{
/* Store the device context */
hDC = GetDC(hWnd);
CreateHGLRC( hDC, &hRC );
wglMakeCurrent(hDC, hRC);
/* Create a timer that fires 100 times a second */
SetTimer(hWnd,10,100,NULL);
}
break;
/* Window is being destroyed, cleanup */
case WM_DESTROY:
{
/* Kill the timer that we created */
KillTimer(hWnd,101);
/* Tell the application to terminate after the window */
/* is gone. */
PostQuitMessage(0);
}
break;
/* Timer, moves and bounces the rectangle, simply calls */
/* our previous OnIdle function, then invalivaluees the */
/* window so it will be redrawn. */
case WM_TIMER:
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(0, 1, 1);
glBegin(GL_TRIANGLES);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 1.0f, 0.0f);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(1.0f, -1.0f, 0.0f);
glEnd();
glPopMatrix();
glFlush();
}
break;
case WM_ERASEBKGND:
return 0;
break;
default: /* Passes it on if unproccessed */
{
return (DefWindowProc(hWnd, message, wParam, lParam));
}
}
return (0L);
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
char *lpszAppName = "TransparentWindow";
WNDCLASSEX wc;
memset(&wc, 0, sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW);
wc.lpszClassName = lpszAppName;
int return_value;
RegisterClassEx(&wc);
HWND hWnd = CreateWindowEx(WS_EX_LAYERED, lpszAppName, lpszAppName,
WS_VISIBLE | WS_POPUP, 200, 150, vW, vH,
NULL, NULL, hInstance, NULL);
SetLayeredWindowAttributes(hWnd, 0x000000, 0, LWA_COLORKEY);
MSG msg;
while(1)
{
while (PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)){
if (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else return 0;
}
}
return (FALSE);
}
Upvotes: 0
Views: 319
Reputation: 162327
To obtain a transparent window a extended framebuffer configuration must be used instead of a plain pixelformat. Like this:
int attribs[] = {
WGL_DRAW_TO_WINDOW_ARB, TRUE,
WGL_DOUBLE_BUFFER_ARB, TRUE,
WGL_SUPPORT_OPENGL_ARB, TRUE,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_TRANSPARENT_ARB, TRUE,
WGL_COLOR_BITS_ARB, 32,
WGL_RED_BITS_ARB, 8,
WGL_GREEN_BITS_ARB, 8,
WGL_BLUE_BITS_ARB, 8,
WGL_ALPHA_BITS_ARB, 8,
WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8,
0, 0
};
INT iPF;
UINT num_formats_choosen;
if( !wglChoosePixelFormatARB(
hDC,
attribs,
NULL,
1,
&iPF,
&num_formats_choosen) ) {
fprintf(stderr, "error choosing proper pixel format\n");
return NULL;
}
if( !num_formats_choosen ) {
return NULL;
}
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(pfd));
/* now this is a kludge; we need to pass something in the PIXELFORMATDESCRIPTOR
* to SetPixelFormat; it will be ignored, mostly. OTOH we want to send something
* sane, we're nice people after all - it doesn't hurt if this fails. */
DescribePixelFormat(hDC, iPF, sizeof(pfd), &pfd);
if( !SetPixelFormat(hDC, iPF, &pfd) ) {
fprintf(stderr, "error setting proper pixel format\n");
ReleaseDC(hWnd, hDC);
DestroyWindow(hWnd);
return NULL;
}
Also you'll have to enable DwmBlurBehindWindow or use WS_POPUP, instead of a toplevel WS_OVERLAPPED with framed window.
WS_EX_LAYERED will not create an "alpha transparency" window! What WS_EX_LAYERED does is, that it allows you a global window opacity (that's applied to the whole window) with only very little control.
For reference you may look at one of my wglarb test programs: https://github.com/datenwolf/wglarb/blob/master/test/layered.c
Upvotes: 1