Mixing GDI and OpenGL

Hi everyone. For 3 days I am fighting with this code. What I am trying to do is mixing GDI with OpenGL child window. However even though it seems all right I can not get any projection in GL area. Since I am learning Win32 programming I suspect I have some problem with initialization of OpenGL child window. Please help me out with this.
Thanks.

#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <stdio.h>
#include <wingdi.h>
#define DIVISIONS 5

void display();
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
LRESULT CALLBACK ChildWndProc (HWND, UINT, WPARAM, LPARAM) ;

PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1, // version number
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL ,//| // support OpenGL
// PFD_DOUBLEBUFFER, // double buffered
PFD_TYPE_RGBA, // RGBA type
32, // 24-bit 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, // accum bits ignored
32, // 32-bit z-buffer
0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};

int idFocus = 0 ;
TCHAR szChildClass[] = TEXT (“Checker4_Child”) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT (“Checker4”) ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;

 wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
 wndclass.lpfnWndProc   = WndProc ;
 wndclass.cbClsExtra    = 0 ;
 wndclass.cbWndExtra    = 0 ;
 wndclass.hInstance     = hInstance ;
 wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
 wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
 wndclass.hbrBackground = (HBRUSH) GetStockObject (GRAY_BRUSH) ;
 wndclass.lpszMenuName  = NULL ;
 wndclass.lpszClassName = szAppName ;    

 if (!RegisterClass (&wndclass)){ MessageBox (NULL, TEXT ("Program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; }

 wndclass.style			= CS_OWNDC;
 wndclass.lpfnWndProc   = ChildWndProc;
 wndclass.cbClsExtra    = 0 ;
 wndclass.cbWndExtra    = sizeof (long) ;
 wndclass.hInstance     = GetModuleHandle(NULL);
 wndclass.hIcon         = NULL;
 wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
 wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
 wndclass.lpszMenuName  = NULL ;
 wndclass.lpszClassName = szChildClass;

 if (!RegisterClass (&wndclass)){MessageBox (NULL, TEXT ("Program requires Windows GL"), szAppName, MB_ICONERROR); return 0;}  
 hwnd = CreateWindow (szAppName, TEXT ("Checker4 Mouse Hit-Test Demo"),WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
 ShowWindow (hwnd, iCmdShow); UpdateWindow (hwnd);
 while (GetMessage (&msg, NULL, 0, 0)){ TranslateMessage (&msg); DispatchMessage (&msg); }
 return msg.wParam ;

}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hDC;
int pf;
static HWND hwndChild;

switch (message)
{
case WM_CREATE :
	hwndChild= CreateWindow (szChildClass, NULL,  WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILDWINDOW | WS_VISIBLE, 0, 0, 0, 0, hwnd, (HMENU) 1, (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE), NULL) ;
	hDC = GetDC(hwndChild);
	pf = ChoosePixelFormat(hDC, &pfd);
	if (pf == 0) { MessageBox(NULL, "ChoosePixelFormat() failed:  " "Cannot find a suitable pixel format.", "Error", MB_OK); exit(2);    } 
	if (SetPixelFormat(hDC, pf, &pfd) == FALSE) { MessageBox(NULL, "SetPixelFormat() failed:  " "Cannot set format specified.", "Error", MB_OK);exit(3);} 
	DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
	ReleaseDC(hwndChild, hDC);		 
    return 0 ;

case WM_SIZE :
    MoveWindow (hwndChild, 0, 0, 110, 110, TRUE) ;
	return 0 ;

case WM_DESTROY :
    PostQuitMessage (0) ;
    return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;

}

LRESULT CALLBACK ChildWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HDC hdc ;
static PAINTSTRUCT ps;
static HGLRC hRC;
char tmp[100];
switch (message)
{
case WM_CREATE :
hdc = GetDC(hwnd);
hRC = wglCreateContext(hdc);
wglMakeCurrent(hdc, hRC);
glViewport(0, 0, 200, 200);
glMatrixMode(GL_MODELVIEW);
return 0 ;

 case WM_LBUTTONDOWN :
		MessageBox(NULL, "Left Button", "MOUSE", MB_OK);

// SetWindowLong (hwnd, 0, 1 ^ GetWindowLong (hwnd, 0)) ;
InvalidateRect (hwnd, NULL, FALSE) ;
return 0 ;
case WM_MOUSEMOVE: return 0 ;

 case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);
		sprintf(tmp, "T = %d L = %d  B = %d R = %d", ps.rcPaint.top, ps.rcPaint.left, ps.rcPaint.bottom, ps.rcPaint.right);

//MessageBox(NULL, tmp, “DONE”, MB_OK);
display();
// SwapBuffers(hdc);
EndPaint(hwnd, &ps);
return 0;

 case WM_DESTROY :
		hdc = GetDC(hwnd);
		wglMakeCurrent(NULL, NULL);
		ReleaseDC(hwnd, hdc);
		wglDeleteContext(hRC);
		PostQuitMessage (0) ;
		return 0 ;
 }
 return DefWindowProc (hwnd, message, wParam, lParam) ;

}

void display()
{

glClear(GL_COLOR_BUFFER_BIT);
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);	

glBegin(GL_POLYGON);
	glColor3f(1.0f, 0.0f, 0.0f); glVertex2i(-1,  1);
	glColor3f(0.0f, 1.0f, 0.0f); glVertex2i(1, 1);
	glColor3f(0.0f, 0.0f, 1.0f); glVertex2i(1, -1);
	glColor3f(0.0f, 1.0f, 1.0f); glVertex2i(-1, -1);
glEnd();

glFlush();

// MessageBox(NULL, “PAINT”, “DONE”, MB_OK);

}

Hello Steve,

In the current implementation of Windows, you cannot make GDI calls to a device context that is using a double buffered pixel format, this is probably the most likely cause for the lack of projection your experiencing.

If your willing to sacrifice the double buffer, you can try substituting the PFD_DOUBLEBUFFER flag with PFD_SUPPORT_GDI when you create the pixel format and see if that helps. I don’t think these two flags can be Or’ed which is a shame

I hope this helps :wink:

moNoKnoT, actually if you look closer at his code, you’ll see that it is not double buffered.

Steve_7, it would appear to me your problem is simply a failure to set the proper projection and viewing transforms.

[This message has been edited by DFrey (edited 07-15-2001).]

Thanks, I really appreciate your help. moNoKnoT I did not use double buffering here and I also tried to “OR” PFD_SUPPORT_GDI flag with no success . DFrey I will definitely check OpenGL setup lines. I have one more question. Is there any way to use double buffer in such kind of program, without using MFC?
Thanks.

Hi again. I got it. Here is the solution.

case WM_PAINT:
if((hdc = BeginPaint(hwnd, &ps)) == NULL) { Catch_Error(“ERROR in ChildWndProc <BeginPaint>”); }
if((hRC = wglCreateContext(hdc)) == NULL) { Catch_Error(“ERROR in ChildWndProc <wglCreateContext2>”); }
if(wglMakeCurrent(hdc, hRC) == FALSE) { Catch_Error(“ERROR in ChildWndProc <wglMakeCurrent2”); }
display();
// SwapBuffers(hdc);
EndPaint(hwnd, &ps);
wglMakeCurrent(NULL,NULL);
return 0;

Change body of the WM_PAINT in ChildWndProc
and that is it. I should write Catch_Error before so I would not waste my time. here is Catch_Error if you are interested:

void Catch_Error(char *fun_name)
{

LPVOID lpMsgBuf;
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
	NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL );
MessageBox( NULL, (LPCTSTR)lpMsgBuf, fun_name, MB_OK | MB_ICONINFORMATION );
LocalFree( lpMsgBuf );

}