Win32 OpenGL Transparent Background [duplicate] - c++
Rendering contexts usually have a solid color on the background (black or whatever, see the image below):
I'm wondering if it's possible to setup a window, with no decorations AND with the transparent background, while allowing me to render OpenGL stuff on it.
This would give the illusion that the triangle is floating on the screen. The transparent background should allow you to see the desktop or other applications that might be behind it.
Could you please exemplify with source code?
Platform: Windows (win32 only)
After spending some reputation on a unsuccessful bounty to get some help on this issue, I finally realized how complex was the problem I was interested in.
The few individuals that have accomplished this task don't share much. During my research I found different ways to achieve what I was looking for. One of the most interesting ones is AeroGL, and it shows snippets of code using a technique that was not mentioned so far, which is rendering the graphics to a device-independent bitmap (DIB).
To close this thread permanently, the source code below implements that technique. The code itself is a slight modification of an application presented here (big thanks to Andrei Sapronov Y.).
The end result can be seen in the image below:
The code has been tested on Windows XP (32-bits) and Windows 8.1 (32-bits).
Enjoy!
#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")
#include <assert.h>
#include <tchar.h>
#ifdef assert
#define verify(expr) if(!expr) assert(0)
#else verify(expr) expr
#endif
const TCHAR szAppName[]=_T("TransparentGL");
const TCHAR wcWndName[]=_T("WS_EX_LAYERED OpenGL");
HDC hDC;
HGLRC m_hrc;
int w(240);
int h(240);
HDC pdcDIB;
HBITMAP hbmpDIB;
void *bmp_cnt(NULL);
int cxDIB(0);
int cyDIB(0);
BITMAPINFOHEADER BIH;
BOOL initSC()
{
glEnable(GL_ALPHA_TEST);
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glClearColor(0, 0, 0, 0);
return 0;
}
void resizeSC(int width,int height)
{
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW );
glLoadIdentity();
}
BOOL renderSC()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
glColor3f(0, 1, 1);
glBegin(GL_TRIANGLES); // Drawing Using Triangles
glColor3f(1.0f,0.0f,0.0f); // Set The Color To Red
glVertex3f( 0.0f, 1.0f, 0.0f); // Top
glColor3f(0.0f,1.0f,0.0f); // Set The Color To Green
glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
glColor3f(0.0f,0.0f,1.0f); // Set The Color To Blue
glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
glEnd();
glPopMatrix();
glFlush();
return 0;
}
// DIB -> hDC
void draw(HDC pdcDest)
{
assert(pdcDIB);
verify(BitBlt(pdcDest, 0, 0, w, h, pdcDIB, 0, 0, SRCCOPY));
}
void CreateDIB(int cx, int cy)
{
assert(cx > 0);
assert(cy > 0);
cxDIB = cx ;
cyDIB = cy ;
int iSize = sizeof(BITMAPINFOHEADER);
memset(&BIH, 0, iSize);
BIH.biSize = iSize;
BIH.biWidth = cx;
BIH.biHeight = cy;
BIH.biPlanes = 1;
BIH.biBitCount = 24;
BIH.biCompression = BI_RGB;
if(pdcDIB)
verify(DeleteDC(pdcDIB));
pdcDIB = CreateCompatibleDC(NULL);
assert(pdcDIB);
if(hbmpDIB)
verify(DeleteObject(hbmpDIB));
hbmpDIB = CreateDIBSection(
pdcDIB,
(BITMAPINFO*)&BIH,
DIB_RGB_COLORS,
&bmp_cnt,
NULL,
0);
assert(hbmpDIB);
assert(bmp_cnt);
if(hbmpDIB)
SelectObject(pdcDIB, hbmpDIB);
}
BOOL CreateHGLRC()
{
DWORD dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_BITMAP;
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(pdcDIB, &pfd);
if (PixelFormat == 0){
assert(0);
return FALSE ;
}
BOOL bResult = SetPixelFormat(pdcDIB, PixelFormat, &pfd);
if (bResult==FALSE){
assert(0);
return FALSE ;
}
m_hrc = wglCreateContext(pdcDIB);
if (!m_hrc){
assert(0);
return FALSE;
}
return TRUE;
}
LRESULT CALLBACK WindowFunc(HWND hWnd,UINT msg, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
switch(msg)
{
case WM_ERASEBKGND:
return 0;
break;
case WM_CREATE:
break;
case WM_DESTROY:
if(m_hrc)
{
wglMakeCurrent(NULL, NULL);
wglDeleteContext(m_hrc) ;
}
PostQuitMessage(0) ;
break;
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
renderSC(); // OpenGL -> DIB
draw(hDC); // DIB -> hDC
EndPaint(hWnd, &ps);
break;
case WM_SIZE:
w = LOWORD(lParam); h = HIWORD(lParam);
wglMakeCurrent(NULL, NULL);
wglDeleteContext(m_hrc);
CreateDIB(w, h);
CreateHGLRC();
verify(wglMakeCurrent(pdcDIB, m_hrc));
initSC();
resizeSC(w, h);
renderSC();
break;
default:
return DefWindowProc(hWnd,msg,wParam,lParam);
}
return 0;
}
int WINAPI _tWinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR str,int nWinMode)
{
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)WindowFunc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hThisInst;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW);
wc.lpszClassName = szAppName;
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, _T("RegisterClassEx - failed"), _T("Error"), MB_OK | MB_ICONERROR);
return FALSE;
}
HWND hWnd = CreateWindowEx(WS_EX_LAYERED, szAppName, wcWndName,
WS_VISIBLE | WS_POPUP, 200, 150, w, h,
NULL, NULL, hThisInst, NULL);
if(!hWnd){
MessageBox(NULL, _T("CreateWindowEx - failed"), _T("Error"), MB_OK | MB_ICONERROR);
return FALSE;
}
verify(SetLayeredWindowAttributes(hWnd, 0x0, 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);
}
Since all the answers given so far target Windows only, but there's surely also a demand doing this on X11 with a composited window manager, for reference I post my example code here (also to be found at https://github.com/datenwolf/codesamples/blob/master/samples/OpenGL/x11argb_opengl/x11argb_opengl.c
/*------------------------------------------------------------------------
* A demonstration of OpenGL in a ARGB window
* => support for composited window transparency
*
* (c) 2011 by Wolfgang 'datenwolf' Draxinger
* See me at comp.graphics.api.opengl and StackOverflow.com
* License agreement: This source code is provided "as is". You
* can use this source code however you want for your own personal
* use. If you give this source code to anybody else then you must
* leave this message in it.
*
* This program is based on the simplest possible
* Linux OpenGL program by FTB (see info below)
The simplest possible Linux OpenGL program? Maybe...
(c) 2002 by FTB. See me in comp.graphics.api.opengl
--
<\___/>
/ O O \
\_____/ FTB.
------------------------------------------------------------------------*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <GL/glxext.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xrender.h>
#include <X11/Xutil.h>
#define USE_CHOOSE_FBCONFIG
static void fatalError(const char *why)
{
fprintf(stderr, "%s", why);
exit(0x666);
}
static int Xscreen;
static Atom del_atom;
static Colormap cmap;
static Display *Xdisplay;
static XVisualInfo *visual;
static XRenderPictFormat *pict_format;
static GLXFBConfig *fbconfigs, fbconfig;
static int numfbconfigs;
static GLXContext render_context;
static Window Xroot, window_handle;
static GLXWindow glX_window_handle;
static int width, height;
static int VisData[] = {
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_DOUBLEBUFFER, True,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_DEPTH_SIZE, 16,
None
};
static int isExtensionSupported(const char *extList, const char *extension)
{
const char *start;
const char *where, *terminator;
/* Extension names should not have spaces. */
where = strchr(extension, ' ');
if ( where || *extension == '\0' )
return 0;
/* It takes a bit of care to be fool-proof about parsing the
OpenGL extensions string. Don't be fooled by sub-strings,
etc. */
for ( start = extList; ; ) {
where = strstr( start, extension );
if ( !where )
break;
terminator = where + strlen( extension );
if ( where == start || *(where - 1) == ' ' )
if ( *terminator == ' ' || *terminator == '\0' )
return 1;
start = terminator;
}
return 0;
}
static Bool WaitForMapNotify(Display *d, XEvent *e, char *arg)
{
return d && e && arg && (e->type == MapNotify) && (e->xmap.window == *(Window*)arg);
}
static void describe_fbconfig(GLXFBConfig fbconfig)
{
int doublebuffer;
int red_bits, green_bits, blue_bits, alpha_bits, depth_bits;
glXGetFBConfigAttrib(Xdisplay, fbconfig, GLX_DOUBLEBUFFER, &doublebuffer);
glXGetFBConfigAttrib(Xdisplay, fbconfig, GLX_RED_SIZE, &red_bits);
glXGetFBConfigAttrib(Xdisplay, fbconfig, GLX_GREEN_SIZE, &green_bits);
glXGetFBConfigAttrib(Xdisplay, fbconfig, GLX_BLUE_SIZE, &blue_bits);
glXGetFBConfigAttrib(Xdisplay, fbconfig, GLX_ALPHA_SIZE, &alpha_bits);
glXGetFBConfigAttrib(Xdisplay, fbconfig, GLX_DEPTH_SIZE, &depth_bits);
fprintf(stderr, "FBConfig selected:\n"
"Doublebuffer: %s\n"
"Red Bits: %d, Green Bits: %d, Blue Bits: %d, Alpha Bits: %d, Depth Bits: %d\n",
doublebuffer == True ? "Yes" : "No",
red_bits, green_bits, blue_bits, alpha_bits, depth_bits);
}
static void createTheWindow()
{
XEvent event;
int x,y, attr_mask;
XSizeHints hints;
XWMHints *startup_state;
XTextProperty textprop;
XSetWindowAttributes attr = {0,};
static char *title = "FTB's little OpenGL example - ARGB extension by WXD";
Xdisplay = XOpenDisplay(NULL);
if (!Xdisplay) {
fatalError("Couldn't connect to X server\n");
}
Xscreen = DefaultScreen(Xdisplay);
Xroot = RootWindow(Xdisplay, Xscreen);
fbconfigs = glXChooseFBConfig(Xdisplay, Xscreen, VisData, &numfbconfigs);
fbconfig = 0;
for(int i = 0; i<numfbconfigs; i++) {
visual = (XVisualInfo*) glXGetVisualFromFBConfig(Xdisplay, fbconfigs[i]);
if(!visual)
continue;
pict_format = XRenderFindVisualFormat(Xdisplay, visual->visual);
XFree(visual);
if(!pict_format)
continue;
fbconfig = fbconfigs[i];
if(pict_format->direct.alphaMask > 0) {
break;
}
}
if(!fbconfig) {
fatalError("No matching FB config found");
}
describe_fbconfig(fbconfig);
/* Create a colormap - only needed on some X clients, eg. IRIX */
cmap = XCreateColormap(Xdisplay, Xroot, visual->visual, AllocNone);
attr.colormap = cmap;
attr.background_pixmap = None;
attr.border_pixmap = None;
attr.border_pixel = 0;
attr.event_mask =
StructureNotifyMask |
EnterWindowMask |
LeaveWindowMask |
ExposureMask |
ButtonPressMask |
ButtonReleaseMask |
OwnerGrabButtonMask |
KeyPressMask |
KeyReleaseMask;
attr_mask =
CWBackPixmap|
CWColormap|
CWBorderPixel|
CWEventMask;
width = DisplayWidth(Xdisplay, DefaultScreen(Xdisplay))/2;
height = DisplayHeight(Xdisplay, DefaultScreen(Xdisplay))/2;
x=width/2, y=height/2;
window_handle = XCreateWindow( Xdisplay,
Xroot,
x, y, width, height,
0,
visual->depth,
InputOutput,
visual->visual,
attr_mask, &attr);
if( !window_handle ) {
fatalError("Couldn't create the window\n");
}
#if USE_GLX_CREATE_WINDOW
int glXattr[] = { None };
glX_window_handle = glXCreateWindow(Xdisplay, fbconfig, window_handle, glXattr);
if( !glX_window_handle ) {
fatalError("Couldn't create the GLX window\n");
}
#else
glX_window_handle = window_handle;
#endif
textprop.value = (unsigned char*)title;
textprop.encoding = XA_STRING;
textprop.format = 8;
textprop.nitems = strlen(title);
hints.x = x;
hints.y = y;
hints.width = width;
hints.height = height;
hints.flags = USPosition|USSize;
startup_state = XAllocWMHints();
startup_state->initial_state = NormalState;
startup_state->flags = StateHint;
XSetWMProperties(Xdisplay, window_handle,&textprop, &textprop,
NULL, 0,
&hints,
startup_state,
NULL);
XFree(startup_state);
XMapWindow(Xdisplay, window_handle);
XIfEvent(Xdisplay, &event, WaitForMapNotify, (char*)&window_handle);
if ((del_atom = XInternAtom(Xdisplay, "WM_DELETE_WINDOW", 0)) != None) {
XSetWMProtocols(Xdisplay, window_handle, &del_atom, 1);
}
}
static int ctxErrorHandler( Display *dpy, XErrorEvent *ev )
{
fputs("Error at context creation", stderr);
return 0;
}
static void createTheRenderContext()
{
int dummy;
if (!glXQueryExtension(Xdisplay, &dummy, &dummy)) {
fatalError("OpenGL not supported by X server\n");
}
#if USE_GLX_CREATE_CONTEXT_ATTRIB
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
render_context = NULL;
if( isExtensionSupported( glXQueryExtensionsString(Xdisplay, DefaultScreen(Xdisplay)), "GLX_ARB_create_context" ) ) {
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
glXCreateContextAttribsARBProc glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" );
if( glXCreateContextAttribsARB ) {
int context_attribs[] =
{
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 0,
//GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
None
};
int (*oldHandler)(Display*, XErrorEvent*) = XSetErrorHandler(&ctxErrorHandler);
render_context = glXCreateContextAttribsARB( Xdisplay, fbconfig, 0, True, context_attribs );
XSync( Xdisplay, False );
XSetErrorHandler( oldHandler );
fputs("glXCreateContextAttribsARB failed", stderr);
} else {
fputs("glXCreateContextAttribsARB could not be retrieved", stderr);
}
} else {
fputs("glXCreateContextAttribsARB not supported", stderr);
}
if(!render_context)
{
#else
{
#endif
render_context = glXCreateNewContext(Xdisplay, fbconfig, GLX_RGBA_TYPE, 0, True);
if (!render_context) {
fatalError("Failed to create a GL context\n");
}
}
if (!glXMakeContextCurrent(Xdisplay, glX_window_handle, glX_window_handle, render_context)) {
fatalError("glXMakeCurrent failed for window\n");
}
}
static int updateTheMessageQueue()
{
XEvent event;
XConfigureEvent *xc;
while (XPending(Xdisplay))
{
XNextEvent(Xdisplay, &event);
switch (event.type)
{
case ClientMessage:
if (event.xclient.data.l[0] == del_atom)
{
return 0;
}
break;
case ConfigureNotify:
xc = &(event.xconfigure);
width = xc->width;
height = xc->height;
break;
}
}
return 1;
}
/* 6----7
/| /|
3----2 |
| 5--|-4
|/ |/
0----1
*/
GLfloat cube_vertices[][8] = {
/* X Y Z Nx Ny Nz S T */
{-1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0}, // 0
{ 1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0}, // 1
{ 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0}, // 2
{-1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0}, // 3
{ 1.0, -1.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0}, // 4
{-1.0, -1.0, -1.0, 0.0, 0.0, -1.0, 1.0, 0.0}, // 5
{-1.0, 1.0, -1.0, 0.0, 0.0, -1.0, 1.0, 1.0}, // 6
{ 1.0, 1.0, -1.0, 0.0, 0.0, -1.0, 0.0, 1.0}, // 7
{-1.0, -1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 0.0}, // 5
{-1.0, -1.0, 1.0, -1.0, 0.0, 0.0, 1.0, 0.0}, // 0
{-1.0, 1.0, 1.0, -1.0, 0.0, 0.0, 1.0, 1.0}, // 3
{-1.0, 1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 1.0}, // 6
{ 1.0, -1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0}, // 1
{ 1.0, -1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 0.0}, // 4
{ 1.0, 1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 1.0}, // 7
{ 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0}, // 2
{-1.0, -1.0, -1.0, 0.0, -1.0, 0.0, 0.0, 0.0}, // 5
{ 1.0, -1.0, -1.0, 0.0, -1.0, 0.0, 1.0, 0.0}, // 4
{ 1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 1.0, 1.0}, // 1
{-1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 0.0, 1.0}, // 0
{-1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0}, // 3
{ 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0}, // 2
{ 1.0, 1.0, -1.0, 0.0, 1.0, 0.0, 1.0, 1.0}, // 7
{-1.0, 1.0, -1.0, 0.0, 1.0, 0.0, 0.0, 1.0}, // 6
};
static void draw_cube(void)
{
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(GLfloat) * 8, &cube_vertices[0][0]);
glNormalPointer(GL_FLOAT, sizeof(GLfloat) * 8, &cube_vertices[0][3]);
glTexCoordPointer(2, GL_FLOAT, sizeof(GLfloat) * 8, &cube_vertices[0][6]);
glDrawArrays(GL_QUADS, 0, 24);
}
float const light0_dir[]={0,1,0,0};
float const light0_color[]={78./255., 80./255., 184./255.,1};
float const light1_dir[]={-1,1,1,0};
float const light1_color[]={255./255., 220./255., 97./255.,1};
float const light2_dir[]={0,-1,0,0};
float const light2_color[]={31./255., 75./255., 16./255.,1};
static void redrawTheWindow()
{
float const aspect = (float)width / (float)height;
static float a=0;
static float b=0;
static float c=0;
glDrawBuffer(GL_BACK);
glViewport(0, 0, width, height);
// Clear with alpha = 0.0, i.e. full transparency
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-aspect, aspect, -1, 1, 2.5, 10);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLightfv(GL_LIGHT0, GL_POSITION, light0_dir);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_color);
glLightfv(GL_LIGHT1, GL_POSITION, light1_dir);
glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_color);
glLightfv(GL_LIGHT2, GL_POSITION, light2_dir);
glLightfv(GL_LIGHT2, GL_DIFFUSE, light2_color);
glTranslatef(0., 0., -5.);
glRotatef(a, 1, 0, 0);
glRotatef(b, 0, 1, 0);
glRotatef(c, 0, 0, 1);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHT1);
glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
glColor4f(1., 1., 1., 0.5);
glCullFace(GL_FRONT);
draw_cube();
glCullFace(GL_BACK);
draw_cube();
a = fmod(a+0.1, 360.);
b = fmod(b+0.5, 360.);
c = fmod(c+0.25, 360.);
glXSwapBuffers(Xdisplay, glX_window_handle);
}
int main(int argc, char *argv[])
{
createTheWindow();
createTheRenderContext();
while (updateTheMessageQueue()) {
redrawTheWindow();
}
return 0;
}
The main trick is getting the right FBConfig. You need to ask for a alpha channel and test the associated XRenderPictFormat for the presence of an alpha mask.
I know this is possible with Windows 7, not sure about earlier versions.
To get rid of the window border you need to remove the WS_OVERLAPPEDWINDOW style from the window and add the WS_POPUP style:
DWORD style = ::GetWindowLong(hWnd, GWL_STYLE);
style &= ~WS_OVERLAPPEDWINDOW;
style |= WS_POPUP;
::SetWindowLong(hWnd, GWL_STYLE, style);
To make the background of the OpenGL window transparent, you will need to use the DwmEnableBlurBehindWindow function:
DWM_BLURBEHIND bb = {0};
bb.dwFlags = DWM_BB_ENABLE;
bb.fEnable = true;
bb.hRgnBlur = NULL;
DwmEnableBlurBehindWindow(hWnd, &bb);
You will also need to specify 0 for the alpha value when calling glClearColor.
glClearColor(0.0f,0.0f,0.0f,0.0f);
Also, when creating your OpenGL context, make sure you allocate an alpha channel.
Now your background should be fully transparent. If you keep the window decorations, then the background will use the Aero blur look and you can adjust the level of transparency using the alpha value in glClearColor.
This is an old question, but since newer versions of Windows have compositing and support, as datenwolf hints, for opengl, we can use some of that special sauce for accomplishing this. Although it is also trivial with DirectX (go figure...) Microsoft did add compositing hints to opengl contexts. Yay anti-trust fears!
So instead of an inefficient copy-to-physical-memory action, we can have the compositing engine just understand how to make use of the opengl context.
So, you have to create an opengl context with a pixelformat that specifies an alpha channel and that it should use composition (line 82). Then, you use the DwmApi.h routines to enable a blurred window (line 179) with a completely invalid region specified, which will blur nothing and leave the window transparent. (You need to specify a black+transparent brush on the window class! Oddly!) Then, you actually just use opengl as you are used to using it. In the event loop, every chance you get, you can just draw and swap buffers (line 201) and remember to enable GL_BLEND! :)
Please review/fork https://gist.github.com/3644466 or just view the following code snippet based off of the OP's own answer with this technique instead (you can just plop this in an empty project):
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <windowsx.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <dwmapi.h>
#pragma comment (lib, "opengl32.lib")
#pragma comment (lib, "glu32.lib")
#pragma comment (lib, "dwmapi.lib")
#include <assert.h>
#include <tchar.h>
#ifdef assert
#define verify(expr) if(!expr) assert(0)
#else verify(expr) expr
#endif
const TCHAR szAppName[]=_T("TransparentGL");
const TCHAR wcWndName[]=_T("TransparentGL");
HDC hDC;
HGLRC m_hrc;
int w = 240;
int h = 240;
BOOL initSC() {
glEnable(GL_ALPHA_TEST);
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glClearColor(0, 0, 0, 0);
return 0;
}
void resizeSC(int width,int height) {
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW );
glLoadIdentity();
}
BOOL renderSC() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
glColor3f(0, 1, 1);
glBegin(GL_TRIANGLES); // Drawing Using Triangles
glColor3f(1.0f,0.0f,0.0f); // Set The Color To Red
glVertex3f( 0.0f, 1.0f, 0.0f); // Top
glColor3f(0.0f,1.0f,0.0f); // Set The Color To Green
glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
glColor3f(0.0f,0.0f,1.0f); // Set The Color To Blue
glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
glEnd();
glPopMatrix();
glFlush();
return 0;
}
BOOL CreateHGLRC(HWND hWnd) {
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR),
1, // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_SUPPORT_COMPOSITION | // Format Must Support Composition
PFD_DOUBLEBUFFER, // Must Support Double Buffering
PFD_TYPE_RGBA, // Request An RGBA Format
32, // Select Our Color Depth
0, 0, 0, 0, 0, 0, // Color Bits Ignored
8, // An Alpha Buffer
0, // Shift Bit Ignored
0, // No Accumulation Buffer
0, 0, 0, 0, // Accumulation Bits Ignored
24, // 16Bit Z-Buffer (Depth Buffer)
8, // Some Stencil Buffer
0, // No Auxiliary Buffer
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 // Layer Masks Ignored
};
HDC hdc = GetDC(hWnd);
int PixelFormat = ChoosePixelFormat(hdc, &pfd);
if (PixelFormat == 0) {
assert(0);
return FALSE ;
}
BOOL bResult = SetPixelFormat(hdc, PixelFormat, &pfd);
if (bResult==FALSE) {
assert(0);
return FALSE ;
}
m_hrc = wglCreateContext(hdc);
if (!m_hrc){
assert(0);
return FALSE;
}
ReleaseDC(hWnd, hdc);
return TRUE;
}
LRESULT CALLBACK WindowFunc(HWND hWnd,UINT msg, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT ps;
switch(msg) {
case WM_CREATE:
break;
case WM_DESTROY:
if(m_hrc) {
wglMakeCurrent(NULL, NULL);
wglDeleteContext(m_hrc) ;
}
PostQuitMessage(0) ;
break;
default:
return DefWindowProc(hWnd,msg,wParam,lParam);
}
return 0;
}
int WINAPI _tWinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR str,int nWinMode) {
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)WindowFunc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hThisInst;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)CreateSolidBrush(0x00000000);
wc.lpszClassName = szAppName;
if(!RegisterClassEx(&wc)) {
MessageBox(NULL, _T("RegisterClassEx - failed"), _T("Error"), MB_OK | MB_ICONERROR);
return FALSE;
}
HWND hWnd = CreateWindowEx(WS_EX_APPWINDOW, szAppName, wcWndName,
WS_VISIBLE | WS_POPUP, 200, 150, w, h,
NULL, NULL, hThisInst, NULL);
if(!hWnd) {
MessageBox(NULL, _T("CreateWindowEx - failed"), _T("Error"), MB_OK | MB_ICONERROR);
return FALSE;
}
DWM_BLURBEHIND bb = {0};
HRGN hRgn = CreateRectRgn(0, 0, -1, -1);
bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
bb.hRgnBlur = hRgn;
bb.fEnable = TRUE;
DwmEnableBlurBehindWindow(hWnd, &bb);
CreateHGLRC(hWnd);
HDC hdc = GetDC(hWnd);
wglMakeCurrent(hdc, m_hrc);
initSC();
resizeSC(w, h);
ReleaseDC(hWnd, hdc);
MSG msg;
while(1) {
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
HDC hdc = GetDC(hWnd);
wglMakeCurrent(hdc, m_hrc);
renderSC();
SwapBuffers(hdc);
ReleaseDC(hWnd, hdc);
}
}
return (FALSE);
}
This would be very easy if OpenGL windows were allowed to be layered. But they are not, so you'll have to go for something else.
What you could do is to create a layered window (WS_EX_LAYERED + SetLayeredWindowAttributes() - Google 'em if you don't know them) to handle the transparency, and a hidden OpenGL window for the rendering. Render the OpenGL scene to an off-screen buffer, read it back and share it with the layered window, then bitblt (GDI function) it to the layered window.
This might be too slow for very complex stuff, but will give you the effect you are asking for, and work on Windows 2000 and above.
EDIT: When it comes to creating the actual off-screen buffer, framebuffer objects (FBOs) are probably your best bet. You could just draw on the hidden OpenGL window, though I think I recall someone posting about running into troubles with that, because of pixel ownership - FBOs are recommended. You could also use pixel buffers (pbuffers), but these are kind of outdated (stamped "legacy"), and FBOs are considered the modern way to do this. FBOs should give you hardware acceleration (if supported), and won't itself limit you to a specific OpenGL version. You'll need an OpenGL context to use it, so you'll have to create that hidden OpenGL window and set up the FBO from there.
Here are some resources on FBOs:
Wikipedia
FBO
Gamedev article
Guide (for mac, but might be helpful)
I know this is old, but I was trying to port the Xlib solution to Gtk+. After a lot of study I finally made it so I really want to share it here for anyone in need.
#include <gtk/gtk.h>
#include <gdk/gdkscreen.h>
#include <gdk/gdkkeysyms.h>
#include <gtk/gtkgl.h>
#include <GL/gl.h>
#include <GL/glu.h>
static gboolean supports_alpha = FALSE;
/***
*** Configure the OpenGL framebuffer.
***/
static GdkGLConfig* configure_gl(void)
{
GdkGLConfig* glconfig;
/* Try double-buffered visual */
glconfig = gdk_gl_config_new_by_mode(GDK_GL_MODE_RGBA |
GDK_GL_MODE_ALPHA |
GDK_GL_MODE_DEPTH |
GDK_GL_MODE_DOUBLE);
if (glconfig == NULL)
{
printf("Cannot find the double-buffered visual.\n");
printf("No appropriate OpenGL-capable visual found.\n");
exit(1);
}
printf("Find GLConfig with alpha channel.\n");
return glconfig;
}
static void screen_changed(GtkWidget* widget, GdkScreen* old_screen, gpointer userdata)
{
/* To check if the display supports alpha channels, get the colormap */
GdkScreen* screen = gtk_widget_get_screen(widget);
GdkColormap* colormap = gdk_screen_get_rgba_colormap(screen);
if (!colormap)
{
printf("Your screen does not support alpha channels!\n");
colormap = gdk_screen_get_rgb_colormap(screen);
supports_alpha = FALSE;
}
else
{
printf("Your screen supports alpha channels!\n");
supports_alpha = TRUE;
}
gtk_widget_set_colormap(widget, colormap);
}
static gboolean expose(GtkWidget* widget, GdkEventExpose* event, gpointer userdata)
{
GdkGLContext* glcontext = gtk_widget_get_gl_context(widget);
GdkGLDrawable* gldrawable = gtk_widget_get_gl_drawable(widget);
if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext))
{
return FALSE;
}
glDrawBuffer(GL_BACK);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_QUADS);
glColor4f(1.0f, 0.0f, 0.0f, 0.3f);
glVertex3f(-0.5f, -0.5f, 0);
glVertex3f(+0.5f, -0.5f, 0);
glVertex3f(+0.5f, +0.5f, 0);
glVertex3f(-0.5f, +0.5f, 0);
glEnd();
gdk_gl_drawable_swap_buffers(gldrawable);
gdk_gl_drawable_gl_end(gldrawable);
return TRUE;
}
int main(int argc, char** argv)
{
gtk_init(&argc, &argv);
GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
/* Added to config GLConfig */
GdkGLConfig* glconfig = configure_gl();
gtk_widget_set_gl_capability(window,
glconfig,
NULL,
TRUE,
GDK_GL_RGBA_TYPE);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 400, 400);
gtk_window_set_title(GTK_WINDOW(window), "Alpha Demo");
g_signal_connect(G_OBJECT(window), "delete-event", gtk_main_quit, NULL);
gtk_widget_set_app_paintable(window, TRUE);
g_signal_connect(G_OBJECT(window), "expose-event", G_CALLBACK(expose), NULL);
g_signal_connect(G_OBJECT(window), "screen-changed", G_CALLBACK(screen_changed), NULL);
screen_changed(window, NULL, NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
Compiled with gcc main.c -o main `pkg-config --libs --cflags gtk+-2.0 gtkglext-1.0`. Tested on Ubuntu 18.04 (in addition to gtk, you'll need to install libgtkglext1-dev).
EDIT
I changed the rendering code from simply a glClear to a rectangle.
The code is a modified version from this question and also this question.
You can render the 3d scene to a pbuffer and blit it to screen using a color key.
The ClanLib game SDK does this.
If you only require a static transparent border use the following technique:
Creates 5 windows
AAAAA
B###C
B###C
DDDDD
A,B,C,D are layered windows
"#" is the main window.
See the images at the bottom of - http://clanlib.org/wiki/ClanLib_2.2.9_Release_Notes
Related
Unable to glTranslate() light source
I am having a problem translating the light source. I have coded a program that accepts up, down, left, and right keys to increase/decrease the x, y, and z values to reposition the light source. But the problem right now is the x, y, and z value does change but the light source remains in the same place. I believe the problem shall be somewhere inside the void lighting() function. below is my code: #include <Windows.h> #include <gl/GL.h> #include <math.h> #include <gl/GLU.h> #pragma comment (lib, "OpenGL32.lib") //link library #pragma comment(lib, "Winmm.lib") #define WINDOW_TITLE "Lighting" bool isOrtho = true; float ONear = -10.0, OFar = 10.0; //Ortho Near & Far float PNear = 1.0, PFar = 21.0; //Perspective Near & Far float exeDif[3] = { 1.0,0.0,0.0 }; //Red diffuse light float x =6 , y=0, z=0; float exePosD[3] = { 6,0,0 }; float exeDifM[3] = { 1.0,0.0,0.0 }; bool isLightOn = false; //is light on? LRESULT WINAPI WindowProcedure(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_DESTROY: PostQuitMessage(0);//quit application break; case WM_KEYDOWN: if (wParam == VK_ESCAPE) PostQuitMessage(0); else if (wParam == VK_SPACE) { isLightOn = !isLightOn; } else if (wParam == VK_UP) { y = y + 1.0; } else if (wParam == VK_DOWN) { y = y - 1.0; } else if (wParam == VK_LEFT) { x = x - 1.0; } else if (wParam == VK_RIGHT) { x = x + 1.0; } else if (wParam == 'Q') { z = z - 1.0; } else if (wParam == 'E') { z = z + 1.0; } break; default: break; } return DefWindowProc(hWnd, msg, wParam, lParam); } bool initPixelFormat(HDC hdc) { PIXELFORMATDESCRIPTOR pfd; ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR)); pfd.cAlphaBits = 8; pfd.cColorBits = 32; pfd.cDepthBits = 24; pfd.cStencilBits = 0; pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW; pfd.iLayerType = PFD_MAIN_PLANE; pfd.iPixelType = PFD_TYPE_RGBA; pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); pfd.nVersion = 1; // choose pixel format returns the number most similar pixel format available int n = ChoosePixelFormat(hdc, &pfd); // set pixel format returns whether it sucessfully set the pixel format if (SetPixelFormat(hdc, n, &pfd)) { return true; } else { return false; } } void lighting() { if (isLightOn) { glEnable(GL_LIGHTING); //Turon on lighting for the whole scene } else { //Turn off lighting for the whole screen glDisable(GL_LIGHTING); } glPushMatrix(); glTranslatef(x, y, z); glLightfv(GL_LIGHT0, GL_POSITION, exePosD); glPopMatrix(); glLightfv(GL_LIGHT0, GL_DIFFUSE, exeDif); glEnable(GL_LIGHT0); } void projection() { glMatrixMode(GL_PROJECTION); //refer to projection matrix glLoadIdentity(); //reset projection matrix if (isOrtho) { //Ortho View glOrtho(-10.0, 10.0, -10.0, 10.0, ONear, OFar); //Ortho view } else { //Perspective view gluPerspective(20, 1.0, -1.0, 1.0); glFrustum(-10.0, 10.0, -10.0, 10.0, PNear, PFar); } } void drawSphere(double r) { GLUquadricObj* sphere = NULL; sphere = gluNewQuadric(); gluQuadricDrawStyle(sphere, GLU_FILL); gluSphere(sphere, r, 30, 30); gluDeleteQuadric(sphere); } void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); projection(); //projection lighting(); glMatrixMode(GL_MODELVIEW); //refer to modelview matrix glLoadIdentity(); //reset drawSphere(3.0); //red color diffuse glMaterialfv(GL_FRONT, GL_DIFFUSE, exeDifM); glColor3f(0.0, 0.0, 1.0); //blue drawSphere(3.0); } int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int nCmdShow) { WNDCLASSEX wc; ZeroMemory(&wc, sizeof(WNDCLASSEX)); wc.cbSize = sizeof(WNDCLASSEX); wc.hInstance = GetModuleHandle(NULL); wc.lpfnWndProc = WindowProcedure; wc.lpszClassName = WINDOW_TITLE; wc.style = CS_HREDRAW | CS_VREDRAW; if (!RegisterClassEx(&wc)) return false; HWND hWnd = CreateWindow(WINDOW_TITLE, WINDOW_TITLE, WS_OVERLAPPEDWINDOW, 720, 10, 300, 300, NULL, NULL, wc.hInstance, NULL); //-------------------------------- // Initialize window for OpenGL //-------------------------------- HDC hdc = GetDC(hWnd); // initialize pixel format for the window initPixelFormat(hdc); // get an openGL context HGLRC hglrc = wglCreateContext(hdc); // make context current if (!wglMakeCurrent(hdc, hglrc)) return false; //-------------------------------- // End initialization //-------------------------------- ShowWindow(hWnd, nCmdShow); MSG msg; ZeroMemory(&msg, sizeof(msg)); while (true) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); } display(); SwapBuffers(hdc); } UnregisterClass(WINDOW_TITLE, wc.hInstance); return true; } This is the output screen:
The light position is transformed with the modelview matrix, but not with the projection matrix. Therefore you need to switch to the modelview matrix after projection() and before lighting(): projection(); //projection glMatrixMode(GL_MODELVIEW); //refer to modelview matrix glLoadIdentity(); lighting();
OpenGL primitives in Win32 window distorted according to window size
I've made a simple OpenGL program in C that draws a triangle rotating inside a box. The triangle is supposed to be equilateral but even when the window width and height are the same the triangles vertices contract and extrude when they go along the width and length of the window. I can tell because I made a static equiangular box and the vertices of the triangle go outside of it. Here's a short clip of what it's doing: https://edwardseverinsen1717-gmail.tinytake.com/sf/NDg5NjQ0XzI2MDQzMDM Excuse the lag at some moments. And here's my code: #include <windows.h> #include <gl/gl.h> #include <gl/glu.h> LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM); void EnableOpenGL(HWND hwnd, HDC*, HGLRC*); void DisableOpenGL(HWND, HDC, HGLRC); void DrawTriangle(float theta); void DrawBox(void); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wcex; HWND hwnd; HDC hDC; HGLRC hRC; MSG msg; BOOL bQuit = FALSE; float theta = 0.0f; int i; /* register window class */ wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_OWNDC; wcex.lpfnWndProc = WindowProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); wcex.lpszMenuName = NULL; wcex.lpszClassName = "GLSample"; wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);; if (!RegisterClassEx(&wcex)) return 0; /* create main window */ hwnd = CreateWindowEx(0, "GLSample", "OpenGL Sample", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 500, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, nCmdShow); /* enable OpenGL for the window */ EnableOpenGL(hwnd, &hDC, &hRC); /* program main loop */ while (!bQuit) { /* check for messages */ if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { /* handle or dispatch messages */ if (msg.message == WM_QUIT) { bQuit = TRUE; } else { TranslateMessage(&msg); DispatchMessage(&msg); } } else { /* OpenGL animation code goes here */ glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); DrawTriangle(theta); DrawBox(); SwapBuffers(hDC); theta += 1.0f; Sleep (1); } } /* shutdown OpenGL */ DisableOpenGL(hwnd, hDC, hRC); /* destroy the window explicitly */ DestroyWindow(hwnd); return msg.wParam; } LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CLOSE: PostQuitMessage(0); break; case WM_DESTROY: return 0; case WM_KEYDOWN: { switch (wParam) { case VK_ESCAPE: PostQuitMessage(0); break; } } break; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0; } void EnableOpenGL(HWND hwnd, HDC* hDC, HGLRC* hRC) { PIXELFORMATDESCRIPTOR pfd; int iFormat; /* get the device context (DC) */ *hDC = GetDC(hwnd); /* set the pixel format for the DC */ ZeroMemory(&pfd, sizeof(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 = 24; pfd.cDepthBits = 16; pfd.iLayerType = PFD_MAIN_PLANE; iFormat = ChoosePixelFormat(*hDC, &pfd); SetPixelFormat(*hDC, iFormat, &pfd); /* create and enable the render context (RC) */ *hRC = wglCreateContext(*hDC); wglMakeCurrent(*hDC, *hRC); } void DisableOpenGL (HWND hwnd, HDC hDC, HGLRC hRC) { wglMakeCurrent(NULL, NULL); wglDeleteContext(hRC); ReleaseDC(hwnd, hDC); } void DrawTriangle(float theta) { glPushMatrix(); if(theta != 0) { glRotatef(theta, 0.0f, 0.0f, 1.0f); } if(theta == 1) { glRotatef(89, 0.0f, 0.0f, 1.0f); } glBegin(GL_TRIANGLES); glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(0.0f, 0.50f); glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(0.45f, -0.50f); glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(-0.45f, -0.50f); glEnd(); glPopMatrix(); } void DrawBox(void) { glPushMatrix(); glBegin(GL_LINE_LOOP); glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(0.45f, 0.5f); /*I decremented each x value by 0.05 to compensate for the bullshit with the window throwing off scale*/ glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(0.45f, -0.5f); glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(-0.45f, -0.5f); glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(-0.45f, 0.5f); glEnd(); glPopMatrix(); }
The coordinates you use do not span a equilateral triangle. Equilateral triangles always have three sides with the same length. In your example, the bottom side has a length of 0.9, but the other two have a length of sqrt(0.45^2 + 1.0^2) = 1.097. Even when assuming that you took 0.45 instead of 0.5, this is still not equilateral. (Bottom = 1.0, Other sides = sqrt(0.5^2 + 1.0^2) = 1.12) As you have already noted, you have to compensate for the aspect ratio of the renderable area (which is not quadratic when passing 500x500 to CreateWindowEx since titlebar and borders are included here). This is normally done by defining a projection matrix with the correct aspect ratio of the client area. Have a look at GetClientRect to query the client area size and glOrtho to specify the projection matrix.
OpenGL - restricting Arcball rotation
I have a simple red rectangle rendered in a window, and I created an arcball in order to rotate it in any direction. I was following the code from NeHe's Arcball Rotation tutorial. The problem is that once the rectangle is rendered and the left mouse button is clicked, it spins like a top in the window. The mouse click-drag-stop update happens every time the mouse is moved, which is the reason why it spins that way. I am not able to figure out a way to restrict the rotation only for the duration of the click-drag-stop. How do I restrict the rotation? I have been trying to debug this for about 4-5 days now with no luck. I added the original Arcball.h and Arcball.cpp files to my project, with one change to to the header file; I simply created a default constructor for the Arcball_t class with this line - ArcBall_t() {}; The only other changes from the original project are that I threw the Update() function call into my code: // ========================================================================================== // function declarations #define GET_PROC_ADDRESS( str ) wglGetProcAddress( str ) LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); void DrawOpenGLScene(HDC hDC); void Update(); HGLRC SetUpOpenGLContext(HWND hWnd); // ========================================================================================== // Trackball declarations const float PI2 = 2.0*3.1415926535f; // PI Squared GLUquadricObj *quadratic; Point2fT MousePt; // NEW: Current Mouse Point bool isClicked = false; // NEW: Clicking The Mouse? bool isRClicked = false; // NEW: Clicking The Right Mouse Button? bool isDragging = false; // NEW: Dragging The Mouse? Matrix4fT Transform = { 1.0f, 0.0f, 0.0f, 0.0f, // NEW: Final Transform 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; Matrix3fT LastRot = { 1.0f, 0.0f, 0.0f, // NEW: Last Rotation 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f }; Matrix3fT ThisRot = { 1.0f, 0.0f, 0.0f, // NEW: This Rotation 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f }; // ========================================================================================== int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { static char szClassName[] = "Myclass"; static char szTitle[]="A Simple Win32 API OpenGL Program"; WNDCLASS wc; MSG msg; HWND hWnd; wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC)WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject (BLACK_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = szClassName; if (!RegisterClass (&wc)) return 0; hWnd = CreateWindow(szClassName, szTitle, WS_OVERLAPPEDWINDOW | // NEED THESE for OpenGL calls to work! WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, 1024, 256, NULL, NULL, hInstance, NULL); ArcBall_t ArcBall(1024.0f, 256.0f); // NEW: ArcBall Instance ShowWindow(hWnd, nCmdShow); UpdateWindow( hWnd ); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage( &msg ); DispatchMessage( &msg ); } return(msg.wParam); } // ========================================================================================== //******************************************************* // This is the brain of the loop // Checks for a new key press or mouse movement // renders when something is detected //******************************************************* LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { HDC hDC; static HGLRC hRC; // Note this is STATIC! PAINTSTRUCT ps; switch (msg) { case WM_CREATE: // Select a pixel format and create a rendering context hRC = SetUpOpenGLContext(hWnd); break; case WM_PAINT: // Draw the scene // Get a DC, make RC current & associate it with this DC hDC = BeginPaint(hWnd, &ps); wglMakeCurrent(hDC, hRC); DrawOpenGLScene(hDC); // Draw // We're done with the RC, so deselect it wglMakeCurrent(NULL, NULL); EndPaint(hWnd, &ps); break; //*NEW* Mouse based messages for arcball case WM_LBUTTONUP: isClicked = false; break; case WM_RBUTTONUP: isRClicked = false; break; case WM_LBUTTONDOWN: isClicked = true; break; case WM_RBUTTONDOWN: isRClicked = true; break; case WM_MOUSEMOVE: MousePt.s.X = (GLfloat)LOWORD(lParam); MousePt.s.Y = (GLfloat)HIWORD(lParam); isClicked = (LOWORD(wParam) & MK_LBUTTON) ? true : false; isRClicked = (LOWORD(wParam) & MK_RBUTTON) ? true : false; Update(); RedrawWindow(hWnd, NULL, NULL, RDW_INTERNALPAINT); break; case WM_DESTROY: // Clean up and terminate wglDeleteContext(hRC); PostQuitMessage(0); break; default: return DefWindowProc(hWnd, msg, wParam, lParam); } return (0); } // ========================================================================================== //******************************************************* // SetUpOpenGL sets the pixel format and a rendering // context then returns the RC //******************************************************* HGLRC SetUpOpenGLContext(HWND hWnd) { static PIXELFORMATDESCRIPTOR pfd = { sizeof (PIXELFORMATDESCRIPTOR), // strcut size 1, // Version number PFD_DRAW_TO_WINDOW | // Flags, draw to a window, PFD_SUPPORT_OPENGL | // use OpenGL PFD_DOUBLEBUFFER, // Use a double buffer PFD_TYPE_RGBA, // RGBA pixel values 32, // 24-bit color 0, 0, 0, // RGB bits & shift sizes. 0, 0, 0, // Don't care about them 0, 0, // No alpha buffer info 0, 0, 0, 0, 0, // No accumulation buffer 32, // 32-bit depth buffer 8, // No stencil buffer 0, // No auxiliary buffers PFD_MAIN_PLANE, // Layer type 0, // Reserved (must be 0) 0, // No layer mask 0, // No visible mask 0 // No damage mask }; int nMyPixelFormatID; HDC hDC; HGLRC hRC; hDC = GetDC(hWnd); nMyPixelFormatID = ChoosePixelFormat(hDC, &pfd); SetPixelFormat(hDC, nMyPixelFormatID, &pfd); hRC = wglCreateContext(hDC); ReleaseDC(hWnd, hDC); quadratic=gluNewQuadric(); // Create A Pointer To The Quadric Object gluQuadricNormals(quadratic, GLU_SMOOTH); // Create Smooth Normals gluQuadricTexture(quadratic, GL_TRUE); // Create Texture Coords return hRC; } // ========================================================================================== // simple test code - rectangle/triangle void DrawOpenGLScene(HDC hDC) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode( GL_MODELVIEW ); glTranslatef(0.0f, 0.0f, 0.0f); glColor3f(1.0, 0.0, 0.0); // drawing color glBegin(GL_POLYGON); // define the rectangle glVertex2f(-0.5,-0.5); glVertex2f(-0.5,0.5); glVertex2f(0.5,0.5); glVertex2f(0.5,-0.5); glEnd(); glMultMatrixf(Transform.M); glFlush(); // force execution SwapBuffers(hDC); } // ========================================================================================== void Update () // Perform Motion Updates Here { ArcBall_t ArcBall; if (isRClicked) // If Right Mouse Clicked, Reset All Rotations { Matrix3fSetIdentity(&LastRot); // Reset Rotation Matrix3fSetIdentity(&ThisRot); // Reset Rotation Matrix4fSetRotationFromMatrix3f(&Transform, &ThisRot); // Reset Rotation } if (!isDragging) // Not Dragging { if (isClicked) // First Click { isDragging = true; // Prepare For Dragging LastRot = ThisRot; // Set Last Static Rotation To Last Dynamic One ArcBall.click(&MousePt); // Update Start Vector And Prepare For Dragging } } else { if (isClicked) // Still Clicked, So Still Dragging { Quat4fT ThisQuat; ArcBall.drag(&MousePt, &ThisQuat); // Update End Vector And Get Rotation As Quaternion Matrix3fSetRotationFromQuat4f(&ThisRot, &ThisQuat); // Convert Quaternion Into Matrix3fT Matrix3fMulMatrix3f(&ThisRot, &LastRot); // Accumulate Last Rotation Into This One Matrix4fSetRotationFromMatrix3f(&Transform, &ThisRot); // Set Our Final Transform's Rotation From This One } else // No Longer Dragging isDragging = false; } } EDIT: I fixed the issue with the uncontrollable scene rotation by inserting a check within the case WM_MOUSEMOVE: handler of the WndProc() routine. The check was: if(isClicked == true) { //code }, and that seemed to do the trick. It no longer spins like a top. However, I still do not have fine control over the rotation; it still spins like a top within the click-drag-release duration.
Assuming your arcball.drag and arcball.click functions are correct, the only problem with your code is that you are applying the rotation after you draw and your need to do it before. Your Code: glTranslatef(0.0f, 0.0f, 0.0f); glColor3f(1.0, 0.0, 0.0); // drawing color glBegin(GL_POLYGON); // define the rectangle glVertex2f(-0.5,-0.5); glVertex2f(-0.5,0.5); glVertex2f(0.5,0.5); glVertex2f(0.5,-0.5); glEnd(); glMultMatrixf(Transform.M); Try changing it to: glTranslatef(0.0f, 0.0f, 0.0f); glMultMatrixf(Transform.M); glColor3f(1.0, 0.0, 0.0); // drawing color glBegin(GL_POLYGON); // define the rectangle glVertex2f(-0.5,-0.5); glVertex2f(-0.5,0.5); glVertex2f(0.5,0.5); glVertex2f(0.5,-0.5); glEnd(); Although, based on the code you have provided, I dont think your image should rotate at all BECAUSE you are applying the rotation after. I think more code might be needed to find your issue.
OpenGL window always busy
I have a small framework which displays a texture in borderless screen window, but when I start it, the application is showing a busy mouse icon when I activate the OpenGL window, and I cannot seem to understand where it is coming from. The following code is the complete solution (Visual Studio 2010) and should compile as is. Unfortunately I don't even know where to start looking, thus I copied the complete code here. BasicProject creates a random texture, and pipes that into the OpenGL window. Can anyone see why the code is stuck into a busy window? The OpenGL Callbacks are never reached, but I do not see why not. BasicProject.cpp (entry point): /** Sample Project for OpenGL-Display functionality * * Anton Roth, 2013 */ #include "stdafx.h" #include <conio.h> #include <process.h> #include <vector> #include <Windows.h> #include <cstdlib> #include <ctime> #include "OpenGL-Display.h" void RunOpenGL(void* pParams); bool applicationRunning = true; HANDLE threadOGL; int _tmain(int argc, _TCHAR* argv[]) { OGD::OpenGLDisplay_Init(640, 480, 200, 200, 0, "First Display"); threadOGL = (HANDLE)_beginthread(RunOpenGL, 0, NULL); while(!_kbhit()) { Sleep(500); } applicationRunning = false; WaitForSingleObject( threadOGL, 500 ); return 0; } void RunOpenGL(void* pParams) { std::vector<char> texture; texture.resize(640 * 480 * 3); std::srand(time(0)); while(applicationRunning) { for(int i = 0; i < 640 * 480 * 3; ++i) { texture.at(i) = std::rand() % 255; } OGD::OpenGLDisplay_Wrapper(&texture.at(0), 640, 480, false, 24, 0); int x, y; OGD::OpenGLDisplay_MousePos(x, y, 0); Sleep(300); } } OpenGL-Display.h: #ifndef __OPENGLDISPLAY #define __OPENGLDISPLAY #include <windows.h> // Header File For Windows #include <stdio.h> // Header File For Standard Input/Output #include <gl\gl.h> // Header File For The OpenGL32 Library #include <gl\glu.h> // Header File For The GLu32 Library #include <vector> namespace OGD { class OpenGL_Display { public: OpenGL_Display(int newId); ~OpenGL_Display(); void Init_Display(int width, int height, int posX, int posY, LPCSTR className); void DrawNewImage(int width, int height, char* imageData, bool flip, int bpp); void GetMouseCords(int& x, int& y); int ID; protected: bool CreateGLWindow(char* title, int bits, int posX, int posY, LPCSTR className); GLvoid ReSizeGLScene(GLsizei width, GLsizei height); int LoadGLTextures(); int InitGL(GLvoid); void UpdateGLBuffers(int width, int height, char* imageData, int bpp); int DrawGLScene(bool flip); GLvoid KillGLWindow(GLvoid); HDC hDC; // Private GDI Device Context static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc HGLRC hRC; // Permanent Rendering Context HWND hWnd; // Holds Our Window Handle HINSTANCE hInstance; // Holds The Instance Of The Application bool keys[256]; // Array Used For The Keyboard Routine bool active; // Window Active Flag Set To TRUE By Default bool fullscreen; // Fullscreen Flag Set To Fullscreen Mode By Default bool g_bExitThread; // end thread GLuint texture; // Bitmap image buffer int g_iCounter; // Current buffer being grabbed to bool g_GLdone; // Counter to make sure no unnecessary updates are made which cause CPU load int xPos; int yPos; int xPos_right; int yPos_right; int width; int height; }; static std::vector<OGD::OpenGL_Display*> oglDisp; void OpenGLDisplay_Wrapper(char* image, int width, int height, bool flip, int bpp, int ID); void OpenGLDisplay_Init(int width, int height, int posX, int posY, int ID, LPCSTR className); void OpenGLDisplay_MousePos(int&x, int&y, int ID); }; #endif OpenGL-Display.cpp: /** Based on code by NeHe tutorials Adapted to display live camera display with OpenGL */ #include "OpenGL-Display.h" using namespace OGD; OpenGL_Display::OpenGL_Display(int newId) { xPos = -1; yPos = -1; ID = newId; width = 1; height = 1; } OpenGL_Display::~OpenGL_Display() { KillGLWindow(); } void OpenGL_Display::Init_Display(int newWidth, int newHeight, int posX, int posY, LPCSTR inputName) { width = newWidth; height = newHeight; className = inputName; if (!CreateGLWindow((char*)className, 24, posX, posY, className)) { throw; } } LRESULT CALLBACK OpenGL_Display::WndProc( HWND hWnd, // Handle For This Window UINT uMsg, // Message For This Window WPARAM wParam, // Additional Message Information LPARAM lParam) // Additional Message Information { switch (uMsg) // Check For Windows Messages { case WM_SYSCOMMAND: // Intercept System Commands { switch (wParam) // Check System Calls { case SC_SCREENSAVE: // Screensaver Trying To Start? case SC_MONITORPOWER: // Monitor Trying To Enter Powersave? return 0; // Prevent From Happening } break; // Exit } case WM_CLOSE: // Did We Receive A Close Message? { PostQuitMessage(0); // Send A Quit Message return 0; // Jump Back } case WM_SIZE: // Resize The OpenGL Window { oglDisp.at(0)->ReSizeGLScene(LOWORD(lParam),HIWORD(lParam)); // LoWord=Width, HiWord=Height return 0; // Jump Back } } // Pass All Unhandled Messages To DefWindowProc return DefWindowProc(hWnd,uMsg,wParam,lParam); } bool OpenGL_Display::CreateGLWindow(char* title, int bits, int posX, int posY, LPCSTR className) { GLuint PixelFormat; // Holds The Results After Searching For A Match WNDCLASS wc; // Windows Class Structure DWORD dwExStyle; // Window Extended Style DWORD dwStyle; // Window Style RECT WindowRect; // Grabs Rectangle Upper Left / Lower Right Values WindowRect.left=(long)0; // Set Left Value To 0 WindowRect.right=(long)width; // Set Right Value To Requested Width WindowRect.top=(long)0; // Set Top Value To 0 WindowRect.bottom=(long)height; // Set Bottom Value To Requested Height hInstance = GetModuleHandle(NULL); // Grab An Instance For Our Window wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraw On Size, And Own DC For Window. wc.lpfnWndProc = WndProc; // WndProc Handles Messages wc.cbClsExtra = 0; // No Extra Window Data wc.cbWndExtra = 0; // No Extra Window Data wc.hInstance = hInstance; // Set The Instance wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // Load The Default Icon wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Load The Arrow Pointer wc.hbrBackground = NULL; // No Background Required For GL wc.lpszMenuName = NULL; // We Don't Want A Menu wc.lpszClassName = className; // Set The Class Name RegisterClass(&wc); // Return FALSE dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Window Extended Style dwStyle=WS_VISIBLE | WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;; // Windows Style AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); // Adjust Window To True Requested Size //HWND hwndC = GetConsoleWindow(); // Create The Window hWnd=CreateWindowEx( dwExStyle, // Extended Style For The Window className, // Class Name title, // Window Title //WS_OVERLAPPEDWINDOW, dwStyle | // Defined Window Style WS_CLIPSIBLINGS | // Required Window Style WS_CLIPCHILDREN, // Required Window Style posX, posY, // Window Position WindowRect.right-WindowRect.left, // Calculate Window Width WindowRect.bottom-WindowRect.top, // Calculate Window Height NULL, // No Parent Window NULL, // No Menu hInstance, // Instance NULL); static PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be { sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor 1, // Version Number PFD_DRAW_TO_WINDOW | // Format Must Support Window PFD_SUPPORT_OPENGL | // Format Must Support OpenGL PFD_DOUBLEBUFFER, // Must Support Double Buffering PFD_TYPE_RGBA, // Request An RGBA Format bits, // Select Our Color Depth 0, 0, 0, 0, 0, 0, // Color Bits Ignored 0, // No Alpha Buffer 0, // Shift Bit Ignored 0, // No Accumulation Buffer 0, 0, 0, 0, // Accumulation Bits Ignored 16, // 16Bit Z-Buffer (Depth Buffer) 0, // No Stencil Buffer 0, // No Auxiliary Buffer PFD_MAIN_PLANE, // Main Drawing Layer 0, // Reserved 0, 0, 0 // Layer Masks Ignored }; hDC=GetDC(hWnd); PixelFormat=ChoosePixelFormat(hDC,&pfd); SetPixelFormat(hDC,PixelFormat,&pfd); hRC=wglCreateContext(hDC); wglMakeCurrent(hDC,hRC); ShowWindow(hWnd,SW_SHOW); // Show The Window SetForegroundWindow(hWnd); // Slightly Higher Priority SetFocus(hWnd); // Sets Keyboard Focus To The Window ReSizeGLScene(width, height); // Set Up Our Perspective GL Screen InitGL(); return TRUE; // Success } int OpenGL_Display::LoadGLTextures() // Load Bitmaps And Convert To Textures { // Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit glGenTextures(1, &texture); // Create The Texture // Typical Texture Generation Using Data From The Bitmap glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); // Minimizing filter, in case display is smaller image size glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); // Magnifying filter, in case display is smaller image size return 1; // Return The Status } GLvoid OpenGL_Display::ReSizeGLScene(GLsizei newWidth, GLsizei newHeight) // Resize And Initialize The GL Window { width = newWidth; height = newHeight; } int OpenGL_Display::InitGL(GLvoid) // All Setup For OpenGL Goes Here { if (!LoadGLTextures()) // Jump To Texture Loading Routine { return FALSE; // If Texture Didn't Load Return FALSE } return TRUE; // Initialization Went OK } void OpenGL_Display::GetMouseCords(int& x, int& y) // All Setup For OpenGL Goes Here { x = xPos; y = yPos; } void OpenGL_Display::UpdateGLBuffers(int width, int height, char* imageData, int bpp) { glBindTexture(GL_TEXTURE_2D, texture); switch(bpp) { case 8: glTexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, imageData); break; case 16: glTexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY, width, height, 0, GL_RED, GL_UNSIGNED_SHORT, imageData); break; case 24: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, imageData); break; default: return; } GLenum mError = glGetError(); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); } int OpenGL_Display::DrawGLScene(bool flip) // Here's Where We Do All The Drawing { if (height==0) // Prevent A Divide By Zero { height=1; // Making Height Equal One } glViewport(0,0,width,height); // Reset The Current Viewport glMatrixMode(GL_PROJECTION); // Select The Projection Matrix glLoadIdentity(); // Reset The Projection Matrix // Calculate The Aspect Ratio Of The Window gluPerspective(25.0f,1.0f,0.1f,100.0f); glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix glLoadIdentity(); // Reset The Modelview Matrix glEnable(GL_TEXTURE_2D); // Enable Texture Mapping glShadeModel(GL_SMOOTH); // Enable Smooth Shading glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background glClearDepth(1.0f); // Depth Buffer Setup glDisable(GL_DEPTH_TEST); // Enables Depth Testing glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations GLenum mError = glGetError(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer glLoadIdentity(); // Reset The View glTranslatef(0.0f,0.0f,-5.0f); mError = glGetError(); glBindTexture(GL_TEXTURE_2D, texture); mError = glGetError(); glColor4f(1.0, 1.0, 1.0, 1.0); mError = glGetError(); if(flip) { glBegin(GL_QUADS); // Front Face glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 0.5f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 0.5f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 0.5f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 0.5f); glEnd(); mError = glGetError(); } else { glBegin(GL_QUADS); // Front Face glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, -1.0f, 0.5f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, -1.0f, 0.5f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 0.5f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 0.5f); glEnd(); mError = glGetError(); } mError = glGetError(); return TRUE; // Keep Going } GLvoid OpenGL_Display::KillGLWindow(GLvoid) // Properly Kill The Window { if (fullscreen) // Are We In Fullscreen Mode? { ChangeDisplaySettings(NULL,0); // If So Switch Back To The Desktop ShowCursor(TRUE); // Show Mouse Pointer } if (hRC) // Do We Have A Rendering Context? { wglMakeCurrent(NULL,NULL); wglDeleteContext(hRC); hRC=NULL; // Set RC To NULL } ReleaseDC(hWnd,hDC); DestroyWindow(hWnd); UnregisterClass("OpenGL_Display",hInstance); } void OpenGL_Display::DrawNewImage(int width, int height, char* imageData, bool flip, int bpp) { BOOL returnVal = wglMakeCurrent(hDC, hRC); UpdateGLBuffers(width, height, imageData, bpp); DrawGLScene(flip); SwapBuffers(hDC); wglMakeCurrent(NULL, NULL); } void OGD::OpenGLDisplay_Init(int width, int height, int posX, int posY, int ID, LPCSTR className) { for(unsigned int i = 0; i < oglDisp.size(); ++i) { if(oglDisp.at(i)->ID == ID) { return; } } oglDisp.push_back(new OGD::OpenGL_Display(ID)); oglDisp.at(oglDisp.size()-1)->Init_Display(width, height, posX, posY, className); //by default this ID is latest wglMakeCurrent(NULL, NULL); GLenum mError = glGetError(); } void OGD::OpenGLDisplay_Wrapper(char* image, int width, int height, bool flip, int bpp, int ID) { for(unsigned int i = 0; i < oglDisp.size(); ++i) { if(oglDisp.at(i)->ID == ID) { oglDisp.at(i)->DrawNewImage(width, height, image, flip, bpp); return; } } }
Even though your window is OpenGL-based, you should create a message loop and repeatedly call GetMessage, TranslateMessage and DispatchMessage. Handle WM_PAINT even though it doesn't need to draw anything. If you don't do this, Windows will think your application doesn't respond, and shows the busy cursor (or worse, shows the 'Application not responding' dialogue.)
OpenGL won't draw my quad
I've learnt a bit of OpenGL using java. Now I'm trying to transition to C++. I'm trying to setup a window and render a quad, but its not showing up. I just get a black screen. I'm using an example from the OpenGL Superbible as a start. Here is my code: #include <stdio.h> #define GLEW_STATIC #include "include\GL\glew.h" #include "include\GL\wglew.h" #pragma comment(lib, "lib\\glew32s.lib") #pragma comment(lib, "opengl32.lib") #pragma comment(lib, "glu32.lib") HWND g_hWnd; HGLRC g_hRC; HDC g_hDC; HINSTANCE g_hInstance; WNDCLASS g_windClass; RECT g_windowRect; bool g_ContinueRendering; void RenderScene(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glBegin(GL_QUADS); glVertex3f(-10.0f, -10.0f, 5.0f); glVertex3f(-10.0f, 10.0f, 5.0f); glVertex3f(10.0f, 10.0f, 5.0f); glVertex3f(10.0f, -10.0f, 5.0f); glEnd(); printf("%s", gluErrorString(glGetError())); SwapBuffers(g_hDC); } /////////////////////////////////////////////////////////////////////////////// // Window has changed size, or has just been created. In either case, we need // to use the window dimensions to set the viewport and the projection matrix. void ChangeSize(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(90.0f, float(w) / float(h), 1.0f, 500.0f); } /////////////////////////////////////////////////////////////////////////////// // Callback functions to handle all window functions this app cares about. // Once complete, pass message on to next app in the hook chain. LRESULT CALLBACK WndProc( HWND hWnd, // Handle For This Window UINT uMsg, // Message For This Window WPARAM wParam, // Additional Message Information LPARAM lParam) // Additional Message Information { unsigned int key = 0; // Handle relevant messages individually switch(uMsg) { case WM_ACTIVATE: case WM_SETFOCUS: RenderScene(); return 0; case WM_SIZE: ChangeSize(LOWORD(lParam),HIWORD(lParam)); RenderScene(); break; case WM_CLOSE: g_ContinueRendering = false; PostQuitMessage(0); return 0; default: // Nothing to do now break; } // Pass All Unhandled Messages To DefWindowProc return DefWindowProc(hWnd,uMsg,wParam,lParam); } bool setupWindow(int nWidth, int nHeight) { bool bRetVal = true; int nWindowX = 0; int nWindowY = 0; int nPixelFormat = -1; PIXELFORMATDESCRIPTOR pfd; DWORD dwExtStyle; DWORD dwWindStyle; HINSTANCE g_hInstance = GetModuleHandle(NULL); TCHAR szWindowName[50] = TEXT("Block Redux"); TCHAR szClassName[50] = TEXT("OGL_CLASS"); // setup window class g_windClass.lpszClassName = szClassName; // Set the name of the Class g_windClass.lpfnWndProc = (WNDPROC)WndProc; g_windClass.hInstance = g_hInstance; // Use this module for the module handle g_windClass.hCursor = LoadCursor(NULL, IDC_ARROW);// Pick the default mouse cursor g_windClass.hIcon = LoadIcon(NULL, IDI_WINLOGO);// Pick the default windows icons g_windClass.hbrBackground = NULL; // No Background g_windClass.lpszMenuName = NULL; // No menu for this window g_windClass.style = CS_HREDRAW | CS_OWNDC | // set styles for this class, specifically to catch CS_VREDRAW; // window redraws, unique DC, and resize g_windClass.cbClsExtra = 0; // Extra class memory g_windClass.cbWndExtra = 0; // Extra window memory // Register the newly defined class if(!RegisterClass( &g_windClass )) bRetVal = false; dwExtStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; dwWindStyle = WS_OVERLAPPEDWINDOW; ShowCursor(TRUE); g_windowRect.left = nWindowX; g_windowRect.right = nWindowX + nWidth; g_windowRect.top = nWindowY; g_windowRect.bottom = nWindowY + nHeight; // Setup window width and height AdjustWindowRectEx(&g_windowRect, dwWindStyle, FALSE, dwExtStyle); //Adjust for adornments int nWindowWidth = g_windowRect.right - g_windowRect.left; int nWindowHeight = g_windowRect.bottom - g_windowRect.top; // Create window g_hWnd = CreateWindowEx(dwExtStyle, // Extended style szClassName, // class name szWindowName, // window name dwWindStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,// window stlye nWindowX, // window position, x nWindowY, // window position, y nWindowWidth, // height nWindowHeight, // width NULL, // Parent window NULL, // menu g_hInstance, // instance NULL); // pass this to WM_CREATE // now that we have a window, setup the pixel format descriptor g_hDC = GetDC(g_hWnd); // Set a dummy pixel format so that we can get access to wgl functions SetPixelFormat( g_hDC, 1,&pfd); // Create OGL context and make it current g_hRC = wglCreateContext( g_hDC ); wglMakeCurrent( g_hDC, g_hRC ); if (g_hDC == 0 || g_hDC == 0) { bRetVal = false; printf("!!! An error occured creating an OpenGL window.\n"); } // Setup GLEW which loads OGL function pointers GLenum err = glewInit(); if (GLEW_OK != err) { /* Problem: glewInit failed, something is seriously wrong. */ bRetVal = false; printf("Error: %s\n", glewGetErrorString(err)); } const GLubyte *oglVersion = glGetString(GL_VERSION); printf("This system supports OpenGL Version %s.\n", oglVersion); // Now that extensions are setup, delete window and start over picking a real format. wglMakeCurrent(NULL, NULL); wglDeleteContext(g_hRC); ReleaseDC(g_hWnd, g_hDC); DestroyWindow(g_hWnd); // Create the window again g_hWnd = CreateWindowEx(dwExtStyle, // Extended style szClassName, // class name szWindowName, // window name dwWindStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,// window stlye nWindowX, // window position, x nWindowY, // window position, y nWindowWidth, // height nWindowHeight, // width NULL, // Parent window NULL, // menu g_hInstance, // instance NULL); // pass this to WM_CREATE g_hDC = GetDC(g_hWnd); int nPixCount = 0; // Specify the important attributes we care about int pixAttribs[] = { WGL_SUPPORT_OPENGL_ARB, 1, // Must support OGL rendering WGL_DRAW_TO_WINDOW_ARB, 1, // pf that can run a window WGL_COLOR_BITS_ARB, 24, // 8 bits of each R, G and B WGL_DEPTH_BITS_ARB, 16, // 16 bits of depth precision for window WGL_DOUBLE_BUFFER_ARB, GL_TRUE, // Double buffered context WGL_SAMPLE_BUFFERS_ARB, GL_TRUE, // MSAA on WGL_SAMPLES_ARB, 8, // 8x MSAA WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, // pf should be RGBA type 0 // NULL termination }; // Ask OpenGL to find the most relevant format matching our attribs // Only get one format back. wglChoosePixelFormatARB(g_hDC, &pixAttribs[0], NULL, 1, &nPixelFormat, (UINT*)&nPixCount); if(nPixelFormat == -1) { // Couldn't find a format, perhaps no 3D HW or drivers are installed g_hDC = 0; g_hDC = 0; bRetVal = false; printf("!!! An error occurred trying to find a pixel format with the requested attribs.\n"); } else { // Got a format, now set it as the current one SetPixelFormat( g_hDC, nPixelFormat, &pfd ); GLint attribs[] = {WGL_CONTEXT_MAJOR_VERSION_ARB, 3, WGL_CONTEXT_MINOR_VERSION_ARB, 3, 0 }; g_hRC = wglCreateContextAttribsARB(g_hDC, 0, attribs); if (g_hRC == NULL) { printf("!!! Could not create an OpenGL 3.3 context.\n"); attribs[3] = 2; g_hRC = wglCreateContextAttribsARB(g_hDC, 0, attribs); if (g_hRC == NULL) { printf("!!! Could not create an OpenGL 3.2 context.\n"); attribs[3] = 1; g_hRC = wglCreateContextAttribsARB(g_hDC, 0, attribs); if (g_hRC == NULL) { printf("!!! Could not create an OpenGL 3.1 context.\n"); attribs[3] = 0; g_hRC = wglCreateContextAttribsARB(g_hDC, 0, attribs); if (g_hRC == NULL) { printf("!!! Could not create an OpenGL 3.0 context.\n"); printf("!!! OpenGL 3.0 and higher are not supported on this system.\n"); } } } } wglMakeCurrent( g_hDC, g_hRC ); } if (g_hDC == 0 || g_hDC == 0) { bRetVal = false; printf("!!! An error occured creating an OpenGL window.\n"); } // If everything went as planned, display the window if( bRetVal ) { ShowWindow( g_hWnd, SW_SHOW ); SetForegroundWindow( g_hWnd ); SetFocus( g_hWnd ); g_ContinueRendering = true; } return bRetVal; } /////////////////////////////////////////////////////////////////////////////// // Cleanup window, OGL context and related state // Called on exit and on error bool KillWindow( ) { bool bRetVal = true; //Cleanup OGL RC if(g_hRC) { wglMakeCurrent(NULL, NULL); wglDeleteContext(g_hRC); g_hRC = NULL; } // release the DC if(g_hDC) { ReleaseDC(g_hWnd, g_hDC); g_hDC = NULL; } // Destroy the window if(g_hWnd) { DestroyWindow(g_hWnd); g_hWnd = NULL;; } // Delete the window class TCHAR szClassName[50] = TEXT("OGL_CLASS"); UnregisterClass(szClassName, g_hInstance); g_hInstance = NULL; ShowCursor(TRUE); return bRetVal; } /////////////////////////////////////////////////////////////////////////////// // Main rendering loop // Check for window messages and handle events, also draw scene void mainLoop() { MSG msg; // Check for waiting mssgs if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if (msg.message==WM_QUIT) { g_ContinueRendering = false; } else { // Deal with mssgs TranslateMessage(&msg); DispatchMessage(&msg); } } else { RenderScene(); } } int main(int argc, char **argv) { if(setupWindow(800, 600)) { ChangeSize(800, 600); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); while (g_ContinueRendering) { mainLoop(); } } KillWindow(); return 0; } I'm pretty sure all the window setup stuff is working. If i change the glClearColor, the windows color changes. I hope someone can see what's wrong with it.
Looking at your code, you're using OpenGL 3.x. Try triangles, as GL_QUADS is deprecated. Also, you should pass CreateContextAttrib the minimum version you require, you will automatically get a newer version if available.
You're drawing them behind you. The z-value of your quad is +5, but in OpenGL, forward is negative in the z direction. Change the z-value to -5 and I think you'll see something. Or add: glPushMatrix(); glTranslatef(0,0,-20.0f); //Your code for drawing. glBegin(GL_QUADS); ... glEnd(); //Added glPopMatrix();
I'm just shooting from the hip here, but have you tried changing the order of the vertices? This could be the culprit of backface culling.