Jump to content
  • Advertisement
  • 07/25/99 06:05 PM
    Sign in to follow this  

    Example of Processing Mouse Events in OpenGL

    Graphics and GPU Programming

    Myopic Rhino
    /* 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;
    }



      Report Article
    Sign in to follow this  


    User Feedback


    There are no comments to display.



    Create an account or sign in to comment

    You need to be a member in order to leave a comment

    Create an account

    Sign up for a new account in our community. It's easy!

    Register a new account

    Sign in

    Already have an account? Sign in here.

    Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!