• 07/25/99 06:05 PM
    Sign in to follow this  
    Followers 0

    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;
    }

    0


    Sign in to follow this  
    Followers 0


    User Feedback

    Create an account or sign in to leave a review

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

    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

    There are no reviews to display.