|
- /*
- Copyright 2012 David Robillard <http://drobilla.net>
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
- /**
- @file pugl_win.cpp Windows/WGL Pugl Implementation.
- */
-
- #include <windows.h>
- #include <windowsx.h>
- #include <GL/gl.h>
-
- #include "pugl_internal.h"
-
- #ifndef WM_MOUSEWHEEL
- # define WM_MOUSEWHEEL 0x020A
- #endif
- #ifndef WM_MOUSEHWHEEL
- # define WM_MOUSEHWHEEL 0x020E
- #endif
-
- struct PuglInternalsImpl {
- HWND hwnd;
- HDC hdc;
- HGLRC hglrc;
- };
-
- LRESULT CALLBACK
- wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
-
- PuglView*
- puglCreate(PuglNativeWindow parent,
- const char* title,
- int width,
- int height,
- bool resizable,
- bool addToDesktop,
- const char* x11Display)
- {
- PuglView* view = (PuglView*)calloc(1, sizeof(PuglView));
- PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals));
- if (!view || !impl) {
- return NULL;
- }
-
- view->impl = impl;
- view->width = width;
- view->height = height;
-
- WNDCLASS wc;
- wc.style = CS_OWNDC;
- wc.lpfnWndProc = wndProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.hInstance = 0;
- wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
- wc.lpszMenuName = NULL;
- wc.lpszClassName = "Pugl";
- RegisterClass(&wc);
-
- impl->hwnd = CreateWindow(
- "Pugl", title,
- (addToDesktop ? WS_VISIBLE : 0) | (parent ? WS_CHILD : (WS_POPUPWINDOW | WS_CAPTION)),
- 0, 0, width, height,
- (HWND)parent, NULL, NULL, NULL);
- if (!impl->hwnd) {
- free(impl);
- free(view);
- return NULL;
- }
-
- SetWindowLongPtr(impl->hwnd, GWL_USERDATA, (LONG)view);
-
- impl->hdc = GetDC(impl->hwnd);
-
- PIXELFORMATDESCRIPTOR pfd;
- ZeroMemory(&pfd, sizeof(pfd));
- pfd.nSize = sizeof(pfd);
- pfd.nVersion = 1;
- pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
- pfd.iPixelType = PFD_TYPE_RGBA;
- pfd.cColorBits = 24;
- pfd.cDepthBits = 16;
- pfd.iLayerType = PFD_MAIN_PLANE;
-
- int format = ChoosePixelFormat(impl->hdc, &pfd);
- SetPixelFormat(impl->hdc, format, &pfd);
-
- impl->hglrc = wglCreateContext(impl->hdc);
- wglMakeCurrent(impl->hdc, impl->hglrc);
-
- view->width = width;
- view->height = height;
-
- return view;
-
- // unused
- (void)resizable;
- (void)x11Display;
- }
-
- void
- puglDestroy(PuglView* view)
- {
- wglMakeCurrent(NULL, NULL);
- wglDeleteContext(view->impl->hglrc);
- ReleaseDC(view->impl->hwnd, view->impl->hdc);
- DestroyWindow(view->impl->hwnd);
- free(view->impl);
- free(view);
- }
-
- void
- puglReshape(PuglView* view, int width, int height)
- {
- wglMakeCurrent(view->impl->hdc, view->impl->hglrc);
-
- if (view->reshapeFunc) {
- view->reshapeFunc(view, width, height);
- } else {
- puglDefaultReshape(view, width, height);
- }
-
- view->width = width;
- view->height = height;
- }
-
- void
- puglDisplay(PuglView* view)
- {
- wglMakeCurrent(view->impl->hdc, view->impl->hglrc);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- glLoadIdentity();
-
- if (view->displayFunc) {
- view->displayFunc(view);
- }
-
- glFlush();
- SwapBuffers(view->impl->hdc);
- view->redisplay = false;
- }
-
- static PuglKey
- keySymToSpecial(int sym)
- {
- switch (sym) {
- case VK_F1: return PUGL_KEY_F1;
- case VK_F2: return PUGL_KEY_F2;
- case VK_F3: return PUGL_KEY_F3;
- case VK_F4: return PUGL_KEY_F4;
- case VK_F5: return PUGL_KEY_F5;
- case VK_F6: return PUGL_KEY_F6;
- case VK_F7: return PUGL_KEY_F7;
- case VK_F8: return PUGL_KEY_F8;
- case VK_F9: return PUGL_KEY_F9;
- case VK_F10: return PUGL_KEY_F10;
- case VK_F11: return PUGL_KEY_F11;
- case VK_F12: return PUGL_KEY_F12;
- case VK_LEFT: return PUGL_KEY_LEFT;
- case VK_UP: return PUGL_KEY_UP;
- case VK_RIGHT: return PUGL_KEY_RIGHT;
- case VK_DOWN: return PUGL_KEY_DOWN;
- case VK_PRIOR: return PUGL_KEY_PAGE_UP;
- case VK_NEXT: return PUGL_KEY_PAGE_DOWN;
- case VK_HOME: return PUGL_KEY_HOME;
- case VK_END: return PUGL_KEY_END;
- case VK_INSERT: return PUGL_KEY_INSERT;
- case VK_SHIFT: return PUGL_KEY_SHIFT;
- case VK_CONTROL: return PUGL_KEY_CTRL;
- case VK_MENU: return PUGL_KEY_ALT;
- case VK_LWIN: return PUGL_KEY_SUPER;
- case VK_RWIN: return PUGL_KEY_SUPER;
- }
- return (PuglKey)0;
- }
-
- static void
- processMouseEvent(PuglView* view, int button, bool press, LPARAM lParam)
- {
- if (view->mouseFunc) {
- view->mouseFunc(view, button, press,
- GET_X_LPARAM(lParam),
- GET_Y_LPARAM(lParam));
- }
- }
-
- static void
- setModifiers(PuglView* view)
- {
- view->mods = 0;
- view->mods |= (GetKeyState(VK_SHIFT) < 0) ? PUGL_MOD_SHIFT : 0;
- view->mods |= (GetKeyState(VK_CONTROL) < 0) ? PUGL_MOD_CTRL : 0;
- view->mods |= (GetKeyState(VK_MENU) < 0) ? PUGL_MOD_ALT : 0;
- view->mods |= (GetKeyState(VK_LWIN) < 0) ? PUGL_MOD_SUPER : 0;
- view->mods |= (GetKeyState(VK_RWIN) < 0) ? PUGL_MOD_SUPER : 0;
- }
-
- static LRESULT
- handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam)
- {
- PAINTSTRUCT ps;
- PuglKey key;
-
- setModifiers(view);
- switch (message) {
- case WM_CREATE:
- case WM_SHOWWINDOW:
- case WM_SIZE:
- puglReshape(view, view->width, view->height);
- break;
- case WM_PAINT:
- BeginPaint(view->impl->hwnd, &ps);
- puglDisplay(view);
- EndPaint(view->impl->hwnd, &ps);
- break;
- case WM_MOUSEMOVE:
- if (view->motionFunc) {
- view->motionFunc(
- view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
- }
- break;
- case WM_LBUTTONDOWN:
- processMouseEvent(view, 1, true, lParam);
- break;
- case WM_MBUTTONDOWN:
- processMouseEvent(view, 2, true, lParam);
- break;
- case WM_RBUTTONDOWN:
- processMouseEvent(view, 3, true, lParam);
- break;
- case WM_LBUTTONUP:
- processMouseEvent(view, 1, false, lParam);
- break;
- case WM_MBUTTONUP:
- processMouseEvent(view, 2, false, lParam);
- break;
- case WM_RBUTTONUP:
- processMouseEvent(view, 3, false, lParam);
- break;
- case WM_MOUSEWHEEL:
- if (view->scrollFunc) {
- view->scrollFunc(
- view, 0, (int16_t)HIWORD(wParam) / (float)WHEEL_DELTA);
- }
- break;
- case WM_MOUSEHWHEEL:
- if (view->scrollFunc) {
- view->scrollFunc(
- view, (int16_t)HIWORD(wParam) / float(WHEEL_DELTA), 0);
- }
- break;
- case WM_KEYDOWN:
- if (view->ignoreKeyRepeat && (lParam & (1 << 30))) {
- break;
- } // else nobreak
- case WM_KEYUP:
- if ((key = keySymToSpecial(wParam))) {
- if (view->specialFunc) {
- view->specialFunc(view, message == WM_KEYDOWN, key);
- }
- } else if (view->keyboardFunc) {
- view->keyboardFunc(view, message == WM_KEYDOWN, wParam);
- }
- break;
- case WM_QUIT:
- if (view->closeFunc) {
- view->closeFunc(view);
- }
- break;
- default:
- return DefWindowProc(
- view->impl->hwnd, message, wParam, lParam);
- }
-
- return 0;
- }
-
- PuglStatus
- puglProcessEvents(PuglView* view)
- {
- MSG msg;
- while (PeekMessage(&msg, view->impl->hwnd, 0, 0, PM_REMOVE)) {
- handleMessage(view, msg.message, msg.wParam, msg.lParam);
- }
-
- if (view->redisplay) {
- puglDisplay(view);
- }
-
- return PUGL_SUCCESS;
- }
-
- LRESULT CALLBACK
- wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
- {
- PuglView* view = (PuglView*)GetWindowLongPtr(hwnd, GWL_USERDATA);
- switch (message) {
- case WM_CREATE:
- PostMessage(hwnd, WM_SHOWWINDOW, TRUE, 0);
- return 0;
- case WM_CLOSE:
- PostQuitMessage(0);
- return 0;
- case WM_DESTROY:
- return 0;
- case WM_MOUSEWHEEL:
- case WM_MOUSEHWHEEL:
- PostMessage(hwnd, message, wParam, lParam);
- return 0;
- default:
- if (view) {
- return handleMessage(view, message, wParam, lParam);
- } else {
- return DefWindowProc(hwnd, message, wParam, lParam);
- }
- }
- }
-
- void
- puglPostRedisplay(PuglView* view)
- {
- view->redisplay = true;
- }
-
- PuglNativeWindow
- puglGetNativeWindow(PuglView* view)
- {
- return (PuglNativeWindow)view->impl->hwnd;
- }
|