diff options
Diffstat (limited to 'pugl/.svn/pristine/08/0824cfa41e889fddfea6ab4870872f0057e37373.svn-base')
| -rw-r--r-- | pugl/.svn/pristine/08/0824cfa41e889fddfea6ab4870872f0057e37373.svn-base | 376 | 
1 files changed, 376 insertions, 0 deletions
| diff --git a/pugl/.svn/pristine/08/0824cfa41e889fddfea6ab4870872f0057e37373.svn-base b/pugl/.svn/pristine/08/0824cfa41e889fddfea6ab4870872f0057e37373.svn-base new file mode 100644 index 0000000..5f85d12 --- /dev/null +++ b/pugl/.svn/pristine/08/0824cfa41e889fddfea6ab4870872f0057e37373.svn-base @@ -0,0 +1,376 @@ +/* +  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 <stdio.h> +#include <stdlib.h> + +#include "pugl_internal.h" + +#ifndef WM_MOUSEWHEEL +#    define WM_MOUSEWHEEL 0x020A +#endif +#ifndef WM_MOUSEHWHEEL +#    define WM_MOUSEHWHEEL 0x020E +#endif +#ifndef WHEEL_DELTA +#    define WHEEL_DELTA 120 +#endif + +const int LOCAL_CLOSE_MSG = WM_USER + 50; + +struct PuglInternalsImpl { +	HWND     hwnd; +	HDC      hdc; +	HGLRC    hglrc; +	WNDCLASS wc; +}; + +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             visible) +{ +	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; + +	// FIXME: This is nasty, and pugl should not have static anything. +	// Should class be a parameter?  Does this make sense on other platforms? +	static int wc_count = 0; +	char classNameBuf[256]; +	_snprintf(classNameBuf, sizeof(classNameBuf), "%s_%d\n", title, wc_count++); + +	impl->wc.style         = CS_OWNDC; +	impl->wc.lpfnWndProc   = wndProc; +	impl->wc.cbClsExtra    = 0; +	impl->wc.cbWndExtra    = 0; +	impl->wc.hInstance     = 0; +	impl->wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION); +	impl->wc.hCursor       = LoadCursor(NULL, IDC_ARROW); +	impl->wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); +	impl->wc.lpszMenuName  = NULL; +	impl->wc.lpszClassName = classNameBuf; +	RegisterClass(&impl->wc); + +	int winFlags = WS_POPUPWINDOW | WS_CAPTION; +	if (resizable) { +		winFlags |= WS_SIZEBOX; +	} + +	// Adjust the overall window size to accomodate our requested client size +	RECT wr = { 0, 0, width, height }; +	AdjustWindowRectEx(&wr, winFlags, FALSE, WS_EX_TOPMOST); + +	impl->hwnd = CreateWindowEx( +		WS_EX_TOPMOST, + 		classNameBuf, title, +		(visible ? WS_VISIBLE : 0) | (parent ? WS_CHILD : winFlags), +		0, 0, wr.right-wr.left, wr.bottom-wr.top, +		(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; +} + +void +puglDestroy(PuglView* view) +{ +	wglMakeCurrent(NULL, NULL); +	wglDeleteContext(view->impl->hglrc); +	ReleaseDC(view->impl->hwnd, view->impl->hdc); +	DestroyWindow(view->impl->hwnd); +	UnregisterClass(view->impl->wc.lpszClassName, NULL); +	free(view->impl); +	free(view); +} + +static 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) +{ +	view->event_timestamp_ms = GetMessageTime(); +	if (press) { +		SetCapture(view->impl->hwnd); +	} else { +		ReleaseCapture(); +	} + +	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: +		RECT rect; +		GetClientRect(view->impl->hwnd, &rect); +		puglReshape(view, rect.right, rect.bottom); +		view->width = rect.right; +		view->height = rect.bottom; +		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, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), +				(int16_t)HIWORD(wParam) / (float)WHEEL_DELTA); +		} +		break; +	case WM_MOUSEHWHEEL: +		if (view->scrollFunc) { +			view->scrollFunc( +				view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), +				(int16_t)HIWORD(wParam) / float(WHEEL_DELTA), 0); +		} +		break; +	case WM_KEYDOWN: +		view->event_timestamp_ms = (GetMessageTime()); +		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: +	case LOCAL_CLOSE_MSG: +		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) { +		InvalidateRect(view->impl->hwnd, NULL, FALSE); +	} + +	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: +		PostMessage(hwnd, LOCAL_CLOSE_MSG, wParam, lParam); +		return 0; +	case WM_DESTROY: +		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; +} | 
