Example of Processing Mouse Events in OpenGL

Published July 25, 1999 by Unknown Author, posted by Myopic Rhino
Do you see issues with this article? Let us know.
Advertisement
/* An example of processing mouse events in an OpenGL program using the Win32 API. */


#include /* must include this before GL/gl.h */
#include /* OpenGL header file */
#include /* OpenGL utilities header file */
#include


enum {
PAN = 1, /* pan state bit */
ROTATE, /* rotate state bits */
ZOOM /* zoom state bit */
};


HDC hDC; /* device context */
HPALETTE hPalette = 0; /* custom palette (if needed) */
GLfloat trans[3]; /* current translation */
GLfloat rot[2]; /* current rotation */


static void update(int state, int ox, int nx, int oy, int ny)
{
int dx = ox - nx;
int dy = ny - oy;

switch(state) {
case PAN:
trans[0] -= dx / 100.0f;
trans[1] -= dy / 100.0f;
break;
case ROTATE:
rot[0] += (dy * 180.0f) / 500.0f;
rot[1] -= (dx * 180.0f) / 500.0f;
#define clamp(x) x = x > 360.0f ? x-360.0f : x < -360.0f ? x+=360.0f : x
clamp(rot[0]);
clamp(rot[1]);
break;
case ZOOM:
trans[2] -= (dx+dy) / 100.0f;
break;
}
}


void
init()
{
glEnable(GL_DEPTH_TEST);
}

void
reshape(int width, int height)
{
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, (float)width/height, 0.001, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -3.0f);
}

void
display()
{
/* rotate a triangle around */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(trans[0], trans[1], trans[2]);
glRotatef(rot[0], 1.0f, 0.0f, 0.0f);
glRotatef(rot[1], 0.0f, 1.0f, 0.0f);
glBegin(GL_TRIANGLES);

#define TOP glIndexi(1); glColor3f(1.0f, 0.0f, 0.0f); glVertex3i(0, 1, 0)
#define FR glIndexi(2); glColor3f(0.0f, 1.0f, 0.0f); glVertex3i(1, -1, 1)
#define FL glIndexi(3); glColor3f(0.0f, 0.0f, 1.0f); glVertex3i(-1, -1, 1)
#define BR glIndexi(3); glColor3f(0.0f, 0.0f, 1.0f); glVertex3i(1, -1, -1)
#define BL glIndexi(2); glColor3f(0.0f, 1.0f, 0.0f); glVertex3i(-1, -1, -1)

TOP; FL; FR;
TOP; FR; BR;
TOP; BR; BL;
TOP; BL; FL;
FR; FL; BL;
BL; BR; FR;

glEnd();
glPopMatrix();
glFlush();
SwapBuffers(hDC); /* nop if singlebuffered */
}


LONG WINAPI
WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static PAINTSTRUCT ps;
static GLboolean left = GL_FALSE; /* left button currently down? */
static GLboolean right = GL_FALSE; /* right button currently down? */
static GLuint state = 0; /* mouse state flag */
static int omx, omy, mx, my;

switch(uMsg) {
case WM_PAINT:
display();
BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
return 0;

case WM_SIZE:
reshape(LOWORD(lParam), HIWORD(lParam));
PostMessage(hWnd, WM_PAINT, 0, 0);
return 0;

case WM_CHAR:
switch (wParam) {
case 27: /* ESC key */
PostQuitMessage(0);
break;
}
return 0;

case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
/* if we don't set the capture we won't get mouse move
messages when the mouse moves outside the window. */
SetCapture(hWnd);
mx = LOWORD(lParam);
my = HIWORD(lParam);
if (uMsg == WM_LBUTTONDOWN)
state |= PAN;
if (uMsg == WM_RBUTTONDOWN)
state |= ROTATE;
return 0;

case WM_LBUTTONUP:
case WM_RBUTTONUP:
/* remember to release the capture when we are finished. */
ReleaseCapture();
state = 0;
return 0;

case WM_MOUSEMOVE:
if (state) {
omx = mx;
omy = my;
mx = LOWORD(lParam);
my = HIWORD(lParam);
/* Win32 is pretty braindead about the x, y position that
it returns when the mouse is off the left or top edge
of the window (due to them being unsigned). therefore,
roll the Win32's 0..2^16 pointer co-ord range to the
more amenable (and useful) 0..+/-2^15. */
if(mx & 1 << 15) mx -= (1 << 16);
if(my & 1 << 15) my -= (1 << 16);
update(state, omx, mx, omy, my);
PostMessage(hWnd, WM_PAINT, 0, 0);
}
return 0;

case WM_PALETTECHANGED:
if (hWnd == (HWND)wParam)
break;
/* fall through to WM_QUERYNEWPALETTE */

case WM_QUERYNEWPALETTE:
if (hPalette) {
UnrealizeObject(hPalette);
SelectPalette(hDC, hPalette, FALSE);
RealizePalette(hDC);
return TRUE;
}
return FALSE;

case WM_CLOSE:
PostQuitMessage(0);
return 0;
}

return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

HWND
CreateOpenGLWindow(char* title, int x, int y, int width, int height,
BYTE type, DWORD flags)
{
int n, pf;
HWND hWnd;
WNDCLASS wc;
LOGPALETTE* lpPal;
PIXELFORMATDESCRIPTOR pfd;
static HINSTANCE hInstance = 0;

/* only register the window class once - use hInstance as a flag. */
if (!hInstance) {
hInstance = GetModuleHandle(NULL);
wc.style = CS_OWNDC;
wc.lpfnWndProc = (WNDPROC)WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "OpenGL";

if (!RegisterClass(&wc)) {
MessageBox(NULL, "RegisterClass() failed: "
"Cannot register window class.", "Error", MB_OK);
return NULL;
}
}

hWnd = CreateWindow("OpenGL", title, WS_OVERLAPPEDWINDOW |
WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
x, y, width, height, NULL, NULL, hInstance, NULL);

if (hWnd == NULL) {
MessageBox(NULL, "CreateWindow() failed: Cannot create a window.",
"Error", MB_OK);
return NULL;
}

hDC = GetDC(hWnd);

/* there is no guarantee that the contents of the stack that become
the pfd are zeroed, therefore _make sure_ to clear these bits. */
memset(&pfd, 0, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | flags;
pfd.iPixelType = type;
pfd.cDepthBits = 32;
pfd.cColorBits = 32;

pf = ChoosePixelFormat(hDC, &pfd);
if (pf == 0) {
MessageBox(NULL, "ChoosePixelFormat() failed: "
"Cannot find a suitable pixel format.", "Error", MB_OK);
return 0;
}

if (SetPixelFormat(hDC, pf, &pfd) == FALSE) {
MessageBox(NULL, "SetPixelFormat() failed: "
"Cannot set format specified.", "Error", MB_OK);
return 0;
}

DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

if (pfd.dwFlags & PFD_NEED_PALETTE ||
pfd.iPixelType == PFD_TYPE_COLORINDEX) {

n = 1 << pfd.cColorBits;
if (n > 256) n = 256;

lpPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +
sizeof(PALETTEENTRY) * n);
memset(lpPal, 0, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * n);
lpPal->palVersion = 0x300;
lpPal->palNumEntries = n;

GetSystemPaletteEntries(hDC, 0, n, &lpPal->palPalEntry[0]);

/* if the pixel type is RGBA, then we want to make an RGB ramp,
otherwise (color index) set individual colors. */
if (pfd.iPixelType == PFD_TYPE_RGBA) {
int redMask = (1 << pfd.cRedBits) - 1;
int greenMask = (1 << pfd.cGreenBits) - 1;
int blueMask = (1 << pfd.cBlueBits) - 1;
int i;

/* fill in the entries with an RGB color ramp. */
for (i = 0; i < n; ++i) {
lpPal->palPalEntry.peRed =
(((i >> pfd.cRedShift) & redMask) * 255) / redMask;
lpPal->palPalEntry.peGreen =
(((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask;
lpPal->palPalEntry.peBlue =
(((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask;
lpPal->palPalEntry.peFlags = 0;
}
} else {
lpPal->palPalEntry[0].peRed = 0;
lpPal->palPalEntry[0].peGreen = 0;
lpPal->palPalEntry[0].peBlue = 0;
lpPal->palPalEntry[0].peFlags = PC_NOCOLLAPSE;
lpPal->palPalEntry[1].peRed = 255;
lpPal->palPalEntry[1].peGreen = 0;
lpPal->palPalEntry[1].peBlue = 0;
lpPal->palPalEntry[1].peFlags = PC_NOCOLLAPSE;
lpPal->palPalEntry[2].peRed = 0;
lpPal->palPalEntry[2].peGreen = 255;
lpPal->palPalEntry[2].peBlue = 0;
lpPal->palPalEntry[2].peFlags = PC_NOCOLLAPSE;
lpPal->palPalEntry[3].peRed = 0;
lpPal->palPalEntry[3].peGreen = 0;
lpPal->palPalEntry[3].peBlue = 255;
lpPal->palPalEntry[3].peFlags = PC_NOCOLLAPSE;
}

hPalette = CreatePalette(lpPal);
if (hPalette) {
SelectPalette(hDC, hPalette, FALSE);
RealizePalette(hDC);
}

free(lpPal);
}

ReleaseDC(hWnd, hDC);

return hWnd;
}

int WINAPI WinMain(HINSTANCE hCurrentInst, HINSTANCE hPreviousInst,
LPSTR lpszCmdLine, int nCmdShow)
{
HGLRC hRC; /* opengl context */
HWND hWnd; /* window */
MSG msg; /* message */
DWORD buffer = PFD_DOUBLEBUFFER; /* buffering type */
BYTE color = PFD_TYPE_RGBA; /* color type */

if (strstr(lpszCmdLine, "-sb")) {
buffer = 0;
}
if (strstr(lpszCmdLine, "-ci")) {
color = PFD_TYPE_COLORINDEX;
}
if (strstr(lpszCmdLine, "-h")) {
MessageBox(NULL, "mouse [-ci] [-sb]\n"
" -sb single buffered\n"
" -ci color index\n",
"Usage help", MB_ICONINFORMATION);
exit(0);
}

hWnd = CreateOpenGLWindow("mouse", 0, 0, 256, 256, color, buffer);
if (hWnd == NULL)
exit(1);

hDC = GetDC(hWnd);
hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hRC);

init();

ShowWindow(hWnd, nCmdShow);

while(GetMessage(&msg, hWnd, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

wglMakeCurrent(NULL, NULL);
ReleaseDC(hWnd, hDC);
wglDeleteContext(hRC);
DestroyWindow(hWnd);
if (hPalette)
DeleteObject(hPalette);

return msg.wParam;
}

Cancel Save
0 Likes 0 Comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement