I Need Help!

I am a novice at OpenGL, and have been tasked to convert existing Win32 API graphics functions embedded in MS Visual C++ code to OpenGL. Because the code (and graphics) is non-event driven, the MFC classes were not used and the application was created as a Win 32 application.

As an overview, the system displays simulated aircraft targets as colored circles, squares, arrowheads, etc and completely repaints the screen every 1/4 second using the Bitblt function to copy the memory device context to the screen to eliminate screen flicker.

It does all of this inside of a 1/4 second loop. The loop receives new data every 1/4 second,
all Win32 API graphics functions write to the memory device context, and then the Bitblt function is called to completely repaint the screen. This 1/4 second loop is made up of only
2 functions. A function named “process_cdti_data” receives new data every 1/4 second and then calls another function named “mypaint” which calls Bitblt. Both functions write to the memory device context.

My BIG problem in converting this system to OpenGL is the apparent necessity to use an event driven callback function in GlutDisplayFunc (as per Example 1-2 on Page 19 of the OpenGL Programming Guide). This callback function apparently must also exist within an
untimed loop between the init() function and the return statement.

To compound problems, we purchased a $25K software package called “Designers Workbench” (DWB) thinking that it would assist in this conversion. Apparently, the only involvement it has with OpenGL is to take free form artwork (drawn using DWB) and convert it to OpenGL code using a code generator.

Do you have any suggestions or ideas relating to how (if possible) I might perform this conversion? Will having DWB be of any help? Can I keep my current non-event driven system design and still convert my Win32 API graphics in V++ over to OpenGL?

Any help or suggestions you have would be very much appreciated. Thank you!

I don’t know glut and can’t speak to any need to use untimed callbacks, but it seems to me you can simply use the same 250ms timer and call a Repaint function as you like.

An example of some code that does the same timer loop driven painting is at http://p-squared.com/Display3DS.zip which may help.

Otherwise, dunno.

Last time I used glut, it didn’t really have good control for timing. Do you need glut? Are you planning to port it over to linux/unix? The only reason to use glut is a)portability, and b) hides normal windows code.
They may have improved glut, and some people have used SDL for portabillity.

If I read your post correctly, just set up windows normally, and then have a timing function that draws every X ticks. This can be called from your main windows message loop…
Something like:

if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)){ if (msg.message==WM_QUIT) // Have We Received A Quit Message?
{ done=TRUE;} else // If Not, Deal With Window Messages

{ TranslateMessage(&msg); // Translate The Message

DispatchMessage(&msg); // Dispatch The Message

}}
else // If There Are No Messages
{ // Draw The Scene. Watch For ESC Key And Quit Messages
if (active && keys[VK_ESCAPE]) // Active? Was There A Quit Received?

{done=TRUE; // ESC Signalled A Quit
} else // Update Screen
{
[insert timing code here]
DrawGLScene();
SwapBuffers(hDC);

… and so on…
Oh, $25k for DWB? Ouch. Ask for a refund.

Note, WOW is that formatting bad. Sorry…

[This message has been edited by Elixer (edited 01-08-2002).]

You bought 25k of software to do Opengl because it mention opengl , wann buy some sand ;p

Thanks for your reponse Elixir.

Instead of putting my 1/4 second timing loop in WinMain as you suggested, I’d ideally like to put it in InitInstance. Will that work?

How about setting up my 1/4 second timer in InitInstance and calling my display function called MyPaint within within that 1/4 second loop?

Also, why won’t the MyPaint function in the below program display anything in the felicia window? Nothing is drawn to the felicia screen window. Why?? Why isn’t the MyPaint function drawing anything?
Here’s the code:

// felicia.cpp : Defines the entry point for the application.
//

#include “stdafx.h”
#include “resource.h”
#include <gl\gl.h>
#include <gl\glu.h>
//#include <gl\glut.h>
#include “windows.h”

#define MAX_LOADSTRING 100

//prototypes
//void MyPaint(HWND hWnd);
GLvoid MyPaint(GLvoid);

// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];

//HDC ghDC;
// The title bar text

// Foward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;

// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_FELICIA, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);

// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow)) 
{
	return FALSE;
}

hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_FELICIA);

// Main message loop:
while (GetMessage(&msg, NULL, 0, 0)) 
{
	if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

}

return msg.wParam;

}

//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage is only necessary if you want this code
// to be compatible with Win32 systems prior to the ‘RegisterClassEx’
// function that was added to Windows 95. It is important to call this function
// so that the application will get ‘well formed’ small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;

wcex.cbSize = sizeof(WNDCLASSEX); 

wcex.style			= CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc	= (WNDPROC)WndProc;
wcex.cbClsExtra		= 0;
wcex.cbWndExtra		= 0;
wcex.hInstance		= hInstance;
wcex.hIcon			= LoadIcon(hInstance, (LPCTSTR)IDI_FELICIA);
wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName	= (LPCSTR)IDC_FELICIA;
wcex.lpszClassName	= szWindowClass;
wcex.hIconSm		= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);

return RegisterClassEx(&wcex);

}

//
// FUNCTION: InitInstance(HANDLE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;

hInst = hInstance; // Store instance handle in our global variable

hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

if (!hWnd)
{
return FALSE;
}

ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

MyPaint();
return TRUE;
}

//
// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
TCHAR szHello[MAX_LOADSTRING];
LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);

switch (message) 
{
	case WM_COMMAND:
		wmId    = LOWORD(wParam); 
		wmEvent = HIWORD(wParam); 
		// Parse the menu selections:
		switch (wmId)
		{
			case IDM_ABOUT:
			   DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
			   break;
			case IDM_EXIT:
			   DestroyWindow(hWnd);
			   break;
			default:
			   return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
	case WM_PAINT:

/* hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here…
RECT rt;
GetClientRect(hWnd, &rt);
DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
EndPaint(hWnd, &ps); */
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

// Mesage handler for about box.
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return TRUE;

	case WM_COMMAND:
		if (LOWORD(wParam) == IDOK | | LOWORD(wParam) == IDCANCEL) 
		{
			EndDialog(hDlg, LOWORD(wParam));
			return TRUE;
		}
		break;
}
return FALSE;

}

GLvoid MyPaint(GLvoid)
{

glClearColor(0.0, 0.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);

glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_POLYGON);
glVertex3f(.25, .25, 0.0);
glVertex3f(.75, .25, 0.0);
glVertex3f(.75, .75, 0.0);
glVertex3f(.25, .75, 0.0);
glEnd();
glFlush();
}

Any comments are most welcome.

Thanks for your reponse Elixir.
Instead of putting my 1/4 second timing loop in WinMain as you suggested, I’d ideally like to put it in InitInstance. Will that work?

How about setting up my 1/4 second timer in InitInstance and calling my display function called MyPaint within within that 1/4 second loop?

Also, why won’t the MyPaint function in the below program display anything in the felicia window? Nothing is drawn to the felicia screen window. Why?? Why isn’t the MyPaint function drawing anything?
Here’s the code:

// felicia.cpp : Defines the entry point for the application.
//

#include “stdafx.h”
#include “resource.h”
#include <gl\gl.h>
#include <gl\glu.h>
//#include <gl\glut.h>
#include “windows.h”

#define MAX_LOADSTRING 100

//prototypes
//void MyPaint(HWND hWnd);
GLvoid MyPaint(GLvoid);

// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];

//HDC ghDC;
// The title bar text

// Foward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;

// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_FELICIA, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);

// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}

hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_FELICIA);

// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

}

return msg.wParam;
}

//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage is only necessary if you want this code
// to be compatible with Win32 systems prior to the ‘RegisterClassEx’
// function that was added to Windows 95. It is important to call this function
// so that the application will get ‘well formed’ small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_FELICIA);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = (LPCSTR)IDC_FELICIA;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);

return RegisterClassEx(&wcex);
}

//
// FUNCTION: InitInstance(HANDLE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;

hInst = hInstance; // Store instance handle in our global variable

hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

if (!hWnd)
{
return FALSE;
}

ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

MyPaint();
return TRUE;
}

//
// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
TCHAR szHello[MAX_LOADSTRING];
LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);

switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
/* hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here…
RECT rt;
GetClientRect(hWnd, &rt);
DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
EndPaint(hWnd, &ps); */
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

// Mesage handler for about box.
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return TRUE;

case WM_COMMAND:
if (LOWORD(wParam) == IDOK | | LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
}

GLvoid MyPaint(GLvoid)
{

glClearColor(0.0, 0.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);

glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_POLYGON);
glVertex3f(.25, .25, 0.0);
glVertex3f(.75, .25, 0.0);
glVertex3f(.75, .75, 0.0);
glVertex3f(.25, .75, 0.0);
glEnd();
glFlush();
}

Any comments are most welcome.

Originally posted by Elixer:
[b]Last time I used glut, it didn’t really have good control for timing. Do you need glut? Are you planning to port it over to linux/unix? The only reason to use glut is a)portability, and b) hides normal windows code.
They may have improved glut, and some people have used SDL for portabillity.

If I read your post correctly, just set up windows normally, and then have a timing function that draws every X ticks. This can be called from your main windows message loop…
Something like:

[quote]

if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)){ if (msg.message==WM_QUIT) // Have We Received A Quit Message?
{ done=TRUE;} else // If Not, Deal With Window Messages

{ TranslateMessage(&msg); // Translate The Message

DispatchMessage(&msg); // Dispatch The Message

}}
else // If There Are No Messages
{ // Draw The Scene. Watch For ESC Key And Quit Messages
if (active && keys[VK_ESCAPE]) // Active? Was There A Quit Received?

{done=TRUE; // ESC Signalled A Quit
} else // Update Screen
{
[insert timing code here]
DrawGLScene();
SwapBuffers(hDC);

… and so on…
Oh, $25k for DWB? Ouch. Ask for a refund.

Note, WOW is that formatting bad. Sorry…

[This message has been edited by Elixer (edited 01-08-2002).][/b][/QUOTE]

A) Don’t see any glut code
B) Don’t see anyplace where you set up openGL window/screen (Pixelformat and so on…)
C) check the FAQ or gamedev.net for some tutorials, since it looks like you need more help on setting things up.
D) No need to post twice, I heard ya the first time!
E)Hire me! woohoo! LOL
F)Ignore E, since I am too busy at this time.