//---------------------------------------------------------------------------- static pascal OSStatus ProcessKeyModifierChanged (EventHandlerCallRef, EventRef evt, void*) { static UInt32 sLastState = 0; UInt32 currState; GetEventParameter(evt, kEventParamKeyModifiers, typeUInt32, 0, sizeof(currState), 0, &currState); currState &= 0x0000FFFF; if (currState != sLastState) { WindowApplication* theApp = (WindowApplication*)Application::TheApplication; CGrafPtr currPort; GetPort(&currPort); SetPortWindowPort((WindowRef)(theApp->GetWindowID())); Point mouseLoc; GetMouse(&mouseLoc); SetPort(currPort); ProcessModifier(theApp, shiftKey, mouseLoc, currState, sLastState); ProcessModifier(theApp, controlKey, mouseLoc, currState, sLastState); ProcessModifier(theApp, optionKey, mouseLoc, currState, sLastState); ProcessModifier(theApp, cmdKey, mouseLoc, currState, sLastState); sLastState = currState; } // Allow standard handler to run. return eventNotHandledErr; }
void WindowManager::Render() { list<WindowApplication*>::reverse_iterator windowIt = _windows.rbegin(); list<WindowApplication*>::reverse_iterator finalWindow = _windows.rend(); WindowApplication* ontop = 0; while (windowIt != finalWindow) { WindowApplication* window = (WindowApplication*)*windowIt; if (window->Settings->Enabled == 1) { window->Render(); if (window->Settings->Fullscreen) { window->RenderFullscreen(); FullScreenEnabled = 1; break; } if (window->Settings->OnTop == 1) ontop = window; else RenderWindow(window); } windowIt++; } if (ontop) RenderWindow(ontop); ontop = 0; }
//---------------------------------------------------------------------------- static pascal OSStatus ProcessMouseDragged (EventHandlerCallRef, EventRef evt, void*) { Point mouseLoc; GetEventParameter(evt, kEventParamMouseLocation, typeQDPoint, 0, sizeof(mouseLoc), 0, &mouseLoc); EventMouseButton mouseButton; GetEventParameter(evt, kEventParamMouseButton, typeMouseButton, 0, sizeof(mouseButton), 0, &mouseButton); UInt32 modifiers; GetEventParameter(evt, kEventParamKeyModifiers, typeUInt32, 0, sizeof(modifiers), 0, &modifiers); WindowApplication* theApp = (WindowApplication*)Application::TheApplication; CGrafPtr currPort; GetPort(&currPort); SetPortWindowPort((WindowRef)(theApp->GetWindowID())); GlobalToLocal(&mouseLoc); SetPort(currPort); theApp->OnMotion(mouseButton, mouseLoc.h, mouseLoc.v, modifiers); // Allow standard handler to run. return eventNotHandledErr; }
//---------------------------------------------------------------------------- static pascal void ProcessTimer (EventLoopTimerRef, void*) { WindowApplication* theApp = (WindowApplication*)Application::TheApplication; theApp->OnIdle(); }
//---------------------------------------------------------------------------- static pascal OSStatus ProcessWindowBoundsChange (EventHandlerCallRef, EventRef evt, void*) { UInt32 attributes; GetEventParameter(evt, kEventParamAttributes, typeUInt32, 0, sizeof(attributes), 0, &attributes); Rect rect; GetEventParameter(evt, kEventParamCurrentBounds, typeQDRectangle, 0, sizeof(rect), 0, &rect); WindowApplication* theApp = (WindowApplication*)Application::TheApplication; if (attributes & kWindowBoundsChangeUserDrag || attributes & kWindowBoundsChangeOriginChanged) { // Bounds are changing due to window moving. theApp->OnMove(rect.top, rect.left); } else if (attributes & kWindowBoundsChangeUserResize || attributes & kWindowBoundsChangeSizeChanged) { // Bounds are changing due to window resizing. theApp->OnResize(rect.right - rect.left, rect.bottom - rect.top); } // Allow standard handler to run. return eventNotHandledErr; }
//---------------------------------------------------------------------------- static void PassiveMotionCallback (int x, int y) { WindowApplication* theApp = (WindowApplication*)Application::TheApplication; if (theApp) { theApp->OnPassiveMotion(x, y); } }
//---------------------------------------------------------------------------- static void MotionCallback (int x, int y) { WindowApplication* theApp = (WindowApplication*)Application::TheApplication; if (theApp) { theApp->OnMotion(gsButton, x, y, gsGLUTModifiers); } }
//---------------------------------------------------------------------------- static void SpecialKeyUpCallback (int key, int x, int y) { WindowApplication* theApp = (WindowApplication*)Application::TheApplication; if (theApp) { theApp->OnSpecialKeyUp(key, x, y); } }
//---------------------------------------------------------------------------- static void KeyUpCallback (unsigned char key, int x, int y) { WindowApplication* theApp = (WindowApplication*)Application::TheApplication; if (theApp) { theApp->OnKeyUp(key, x, y); } }
//---------------------------------------------------------------------------- static void IdleCallback () { WindowApplication* theApp = (WindowApplication*)Application::TheApplication; if (theApp) { theApp->OnIdle(); } }
//---------------------------------------------------------------------------- static void DisplayCallback () { WindowApplication* theApp = (WindowApplication*)Application::TheApplication; if (theApp) { theApp->OnDisplay(); } }
//---------------------------------------------------------------------------- static void ReshapeCallback (int width, int height) { WindowApplication* theApp = (WindowApplication*)Application::TheApplication; if (theApp) { theApp->OnResize(width, height); theApp->OnDisplay(); } }
//---------------------------------------------------------------------------- static pascal OSStatus ProcessWindowRedraw (EventHandlerCallRef, EventRef, void*) { WindowApplication* theApp = (WindowApplication*)Application::TheApplication; theApp->OnDisplay(); // Allow standard handler to run. return eventNotHandledErr; }
//---------------------------------------------------------------------------- static void Terminate () { WindowApplication* theApp = (WindowApplication*)Application::TheApplication; if (theApp) { theApp->OnTerminate(); glutDestroyWindow(theApp->GetWindowID()); Renderer* renderer = (Renderer*)theApp->GetRenderer(); delete0(renderer); } }
//---------------------------------------------------------------------------- static void KeyDownCallback (unsigned char key, int x, int y) { WindowApplication* theApp = (WindowApplication*)Application::TheApplication; if (theApp) { if (key == theApp->KEY_TERMINATE) { exit(0); } theApp->OnKeyDown(key, x, y); } }
//---------------------------------------------------------------------------- void WindowApplication::GetMousePosition (int& x, int& y) const { WindowApplication* theApp = (WindowApplication*)Application::TheApplication; CGrafPtr currPort; GetPort(&currPort); SetPortWindowPort((WindowRef)(theApp->GetWindowID())); Point mouseLoc; GetMouse(&mouseLoc); SetPort(currPort); x = (int)mouseLoc.h; y = (int)mouseLoc.v; }
//---------------------------------------------------------------------------- static pascal OSStatus ProcessKeyDown (EventHandlerCallRef, EventRef evt, void*) { char charCode; GetEventParameter(evt, kEventParamKeyMacCharCodes, typeChar, 0, sizeof(charCode), 0, &charCode); WindowApplication* theApp = (WindowApplication*)Application::TheApplication; CGrafPtr currPort; GetPort(&currPort); SetPortWindowPort((WindowRef)(theApp->GetWindowID())); Point mouseLoc; GetMouse(&mouseLoc); SetPort(currPort); if (charCode == kEscapeCharCode) { // Quit the application when 'esc' is pressed. QuitApplicationEventLoop(); return eventNotHandledErr; } if (isalnum(charCode) || isprint(charCode)) { theApp->OnKeyDown(charCode, mouseLoc.h, mouseLoc.v); } else { if (charCode == kFunctionKeyCharCode) { // Function key - get key identity. UInt32 keyCode; GetEventParameter(evt, kEventParamKeyCode, typeUInt32, 0, sizeof(keyCode), 0, &keyCode); charCode = keyCode & 0x000000FF; } // Do not filter for specific keys. This allows for keys such as tab, // delete, enter. theApp->OnSpecialKeyDown(charCode, mouseLoc.h, mouseLoc.v); } // Allow standard handler to run. return eventNotHandledErr; }
//---------------------------------------------------------------------------- void WindowApplication::SetMousePosition (int x, int y) { WindowApplication* theApp = (WindowApplication*)Application::TheApplication; CGrafPtr currPort; GetPort(&currPort); SetPortWindowPort((WindowRef)(theApp->GetWindowID())); Point mouseLoc; mouseLoc.h = (short)x; mouseLoc.v = (short)y; LocalToGlobal(&mouseLoc); SetPort(currPort); CGPoint point = CGPointMake((float)mouseLoc.h, (float)mouseLoc.v); CGPostMouseEvent(point, true, 1, false, 0); }
//---------------------------------------------------------------------------- static pascal OSStatus ProcessWindowZoomed (EventHandlerCallRef, EventRef evt, void*) { WindowRef window; GetEventParameter(evt, kEventParamDirectObject, typeWindowRef, 0, sizeof(window), 0, &window); Rect rect; GetWindowBounds(window, kWindowContentRgn, &rect); WindowApplication* theApp = (WindowApplication*)Application::TheApplication; theApp->OnResize(rect.right - rect.left, rect.bottom - rect.top); // Allow standard handler to run. return eventNotHandledErr; }
void WindowManager::HandleController() { if (_windows.size() > 0) { WindowApplication* window = _windows.front(); if ((Interface::IsWithinWindowContent(_controller->CursorX, _controller->CursorY, window) || _isActive) && window->Settings->Enabled == 1) { if (!window->Settings->Fullscreen) window->HandleController(_controller->CursorX - window->ContentX, _controller->CursorY - window->ContentY); else window->HandleController(_controller->CursorX, _controller->CursorY); _controller->Handled = 1; } else _isActive = 0; } }
//---------------------------------------------------------------------------- static void MouseClickCallback (int button, int state, int x, int y) { WindowApplication* theApp = (WindowApplication*)Application::TheApplication; if (theApp) { int modifiers = glutGetModifiers(); gsGLUTModifiers = *(unsigned int*)&modifiers; if (state == WindowApplication::MOUSE_DOWN) { gsButton = button; } else { gsButton = -1; } theApp->OnMouseClick(button, state, x, y, gsGLUTModifiers); } }
//---------------------------------------------------------------------------- static pascal OSStatus ProcessMouseMoved (EventHandlerCallRef, EventRef evt, void*) { Point mouseLoc; GetEventParameter(evt,kEventParamMouseLocation, typeQDPoint, 0, sizeof(mouseLoc), 0, &mouseLoc); WindowApplication* theApp = (WindowApplication*)Application::TheApplication; CGrafPtr currPort; GetPort(&currPort); SetPortWindowPort((WindowRef)(theApp->GetWindowID())); GlobalToLocal(&mouseLoc); SetPort(currPort); theApp->OnPassiveMotion(mouseLoc.h, mouseLoc.v); // Allow standard handler to run. return eventNotHandledErr; }
//---------------------------------------------------------------------------- int WindowApplication::Main (int, char**) { // Initialize the extra data. TODO: Port the extra-data system of WM4 // to WM5. memset(gsExtraData, 0, APP_EXTRA_DATA_QUANTITY*sizeof(char)); InitCursor(); WindowApplication* theApp = (WindowApplication*)Application::TheApplication; theApp->KEY_TERMINATE = WindowApplication::KEY_ESCAPE; // OpenGL uses a projection matrix for depth in [-1,1]. Camera::SetDefaultDepthType(Camera::PM_DEPTH_MINUS_ONE_TO_ONE); // Allocate temporary back buffer to be used for font management. GDHandle device = GetGDevice(); PixMapHandle pixmap = (**device).gdPMap; Rect area; GetPixBounds(pixmap, &area); int depth = GetPixDepth(pixmap); GWorldPtr back; OSErr error = NewGWorld(&back, depth, &area, 0, 0, useTempMem | pixPurge); if (error != noErr || !back) { return -1; } SetExtraData(AGLAPP_BACK, sizeof(GWorldPtr), &back); // Assign desired font settings to back buffer. const int fontSize = 9; unsigned char fontName[256]; fontName[0] = 6; strcpy((char*)&fontName[1], "Monaco"); short fontNum; GetFNum(fontName, &fontNum); SetExtraData(AGLAPP_FONT, sizeof(short), &fontNum); GWorldPtr currentWorld; GDHandle currentDevice; GetGWorld(¤tWorld, ¤tDevice); SetGWorld(back, 0); TextFont(fontNum); TextSize(fontSize); TextFace(normal); SetGWorld(currentWorld, currentDevice); // Add standard window menu. MenuRef menu = 0; CreateStandardWindowMenu(0, &menu); InsertMenu(menu, 0); // Change current directory into application bundle. FSRef processRef; FSCatalogInfo processInfo; ProcessSerialNumber serial = { 0, kCurrentProcess }; GetProcessBundleLocation(&serial, &processRef); FSSpec fileSpec; FSGetCatalogInfo(&processRef, kFSCatInfoNodeFlags, &processInfo, 0, &fileSpec, 0); std::string appFile = GetStringPathname(fileSpec); const int maxPathLen = 1024; char path[maxPathLen]; strcpy(path, appFile.c_str()); char* last = strrchr(path, '/'); *last = 0; int result = chdir(path); assertion(result == 0, "Cannot change directory.\n"); // If the application is packaged, we have to get back up a couple of // levels such that the current working directory is the same as the // application's directory. char buffer[maxPathLen]; char* currentDirectory = getcwd(buffer, maxPathLen); if (strstr(currentDirectory, "/Contents/MacOS")) { result = chdir("../../.."); assertion(result == 0, "Cannot change directory.\n"); currentDirectory = getcwd(buffer, maxPathLen); } #if 0 // TODO. We had this in Wild Magic 4. Add it to Wild Magic 5. // // Launch a file dialog, if requested, when the application needs to // select an input file. The derived-class application should set // mLaunchFileDialog to 'true' in its constructor when the dialog is // needed. if (theApp->LaunchFileDialog()) { char* arguments = GetCommandLine(); if (arguments) { delete0(theApp->TheCommand); theApp->TheCommand = new0 Command(arguments); delete1(arguments); } } #endif if (!theApp->OnPrecreate()) { return -2; } // Require the window to have the specified client area. short windowTop = 60, windowLeft = 40; Rect rect = { windowTop, windowLeft, theApp->GetHeight() + windowTop - 1, theApp->GetWidth() + windowLeft - 1 }; // Create the application window. WindowRef window = 0; OSStatus status = CreateNewWindow(kDocumentWindowClass, kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute, &rect, &window); if (status != noErr) { assertion(false, "Error in creating window.\n"); return -3; } // Grab GD from kRect - based on FindGDHandleFromRect in Carbon SetupGL. GDHandle hGD = 0; GDHandle hgdNthDevice = GetDeviceList(); unsigned int greatestArea = 0; // Check window against all gdRects in gDevice list and remember which // gdRect contains largest area of window. while (hgdNthDevice) { if (TestDeviceAttribute(hgdNthDevice, screenDevice) && TestDeviceAttribute(hgdNthDevice, screenActive)) { // The SectRect routine calculates the intersection of the window // rectangle and this gDevice rectangle and returns TRUE if the // rectangles intersect, FALSE if they don't. Rect rectSect; SectRect(&rect, &(**hgdNthDevice).gdRect, &rectSect); // Determine which screen holds greatest window area first. // Calculate area of rectangle on current device. unsigned int sectArea = (unsigned int)(rectSect.right - rectSect.left) * (rectSect.bottom - rectSect.top); if (sectArea > greatestArea) { greatestArea = sectArea; // set greatest area so far hGD = hgdNthDevice; // set zoom device } hgdNthDevice = GetNextDevice(hgdNthDevice); } } // Set window title. CFStringRef windowTitle = CFStringCreateWithCString(0, theApp->GetWindowTitle(), kCFStringEncodingASCII); SetWindowTitleWithCFString(window, windowTitle); CFRelease(windowTitle); theApp->SetWindowID((int)window); SetPortWindowPort(window); // Create the renderer. RendererInput input; input.mDevice = (AGLDevice)hGD; input.mWindow = window; mRenderer = new0 Renderer(input, theApp->GetWidth(), theApp->GetHeight(), mColorFormat, mDepthStencilFormat, mNumMultisamples); // Install quit apple event handler. error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP((AEEventHandlerProcPtr)QuitAppleEventHandler), 0, false); if (error != noErr) { ExitToShell(); } // Install window close handler. EventTypeSpec eventType; eventType.eventClass = kEventClassWindow; eventType.eventKind = kEventWindowClose; EventHandlerUPP handlerUPP = NewEventHandlerUPP(ProcessWindowClose); InstallWindowEventHandler(window, handlerUPP, 1, &eventType, 0, 0); // Install window bounds change handler. eventType.eventKind = kEventWindowBoundsChanged; handlerUPP = NewEventHandlerUPP(ProcessWindowBoundsChange); InstallWindowEventHandler(window, handlerUPP, 1, &eventType, 0, 0); // Install window zoomed handler. eventType.eventKind = kEventWindowZoomed; handlerUPP = NewEventHandlerUPP(ProcessWindowZoomed); InstallWindowEventHandler(window, handlerUPP, 1, &eventType, 0, 0); // Install window redraw handler. eventType.eventKind = kEventWindowDrawContent; handlerUPP = NewEventHandlerUPP(ProcessWindowRedraw); InstallWindowEventHandler(window, handlerUPP, 1, &eventType, 0, 0); // Install key down handler. EventTypeSpec eventTypes[2]; eventTypes[0].eventClass = kEventClassKeyboard; eventTypes[0].eventKind = kEventRawKeyDown; eventTypes[1].eventClass = kEventClassKeyboard; eventTypes[1].eventKind = kEventRawKeyRepeat; handlerUPP = NewEventHandlerUPP(ProcessKeyDown); InstallWindowEventHandler(window, handlerUPP, 2, eventTypes, 0, 0); // Install key up handler. eventTypes[0].eventClass = kEventClassKeyboard; eventTypes[0].eventKind = kEventRawKeyUp; handlerUPP = NewEventHandlerUPP(ProcessKeyUp); InstallWindowEventHandler(window, handlerUPP, 1, eventTypes, 0, 0); // Install key-modifier-changed handler. eventTypes[0].eventClass = kEventClassKeyboard; eventTypes[0].eventKind = kEventRawKeyModifiersChanged; handlerUPP = NewEventHandlerUPP(ProcessKeyModifierChanged); InstallWindowEventHandler(window, handlerUPP, 1, eventTypes, 0, 0); // Install mouse down handler. eventType.eventClass = kEventClassMouse; eventType.eventKind = kEventMouseDown; handlerUPP = NewEventHandlerUPP(ProcessMouseDown); InstallWindowEventHandler(window, handlerUPP, 1, &eventType, 0, 0); // Install mouse up handler. eventType.eventKind = kEventMouseUp; handlerUPP = NewEventHandlerUPP(ProcessMouseUp); InstallWindowEventHandler(window, handlerUPP, 1, &eventType, 0, 0); // Install mouse drag handler. eventType.eventKind = kEventMouseDragged; handlerUPP = NewEventHandlerUPP(ProcessMouseDragged); InstallWindowEventHandler(window, handlerUPP, 1, &eventType, 0, 0); // Install mouse move handler. eventType.eventKind = kEventMouseMoved; handlerUPP = NewEventHandlerUPP(ProcessMouseMoved); InstallWindowEventHandler(window, handlerUPP, 1, &eventType, 0, 0); // Create timer. EventLoopTimerRef timer; InstallEventLoopTimer(GetMainEventLoop(), 0, kEventDurationMillisecond, NewEventLoopTimerUPP(ProcessTimer), 0, &timer); if (!theApp->OnInitialize()) { return -4; } // Set auto-repeat key timing. short keyRepeatThresh = LMGetKeyRepThresh(); short keyThresh = LMGetKeyThresh(); LMSetKeyRepThresh(1); LMSetKeyThresh(30); // The default OnPreidle() clears the buffers. Allow the application to // fill them before the window is shown and before the event loop starts. theApp->OnPreidle(); // Display the window. ShowWindow(window); // Run event loop. RunApplicationEventLoop(); // Reset auto-repeat key timing to initial value. LMSetKeyRepThresh(keyRepeatThresh); LMSetKeyThresh(keyThresh); theApp->OnTerminate(); delete0(mRenderer); RemoveEventLoopTimer(timer); DisposeMenu(menu); return 0; }
//---------------------------------------------------------------------------- int WindowApplication::Main (int, char**) { WindowApplication* theApp = (WindowApplication*)TheApplication; theApp->KEY_TERMINATE = WindowApplication::KEY_ESCAPE; // OpenGL uses a projection matrix for depth in [-1,1]. Camera::SetDefaultDepthType(Camera::PM_DEPTH_MINUS_ONE_TO_ONE); // Register the termination function so that we can destroy the window // after GLUT abnormally calls 'exit'. if (atexit(Terminate) != 0) { return -1; } // Give GLUT dummy arguments, because we are not allowing control to // GLUT via command-line parameters. int numArguments = 1; char* arguments[1]; arguments[0] = new char[6]; strcpy(arguments[0], "dummy"); glutInit(&numArguments, arguments); delete[] arguments[0]; // We will always use double buffering, 32-bit RGBA front buffer, // depth buffer, and stencil buffer. if (mNumMultisamples == 0) { glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL); } else { glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL | GLUT_MULTISAMPLE); mNumMultisamples = glutGet(GLUT_WINDOW_NUM_SAMPLES); } // Allow work to be done before the window is created. if (!theApp->OnPrecreate()) { return -2; } // Create window and renderer. Multisampling is not supported. glutInitWindowSize(theApp->GetWidth(), theApp->GetHeight()); RendererInput input; input.mWindowID = glutCreateWindow(theApp->GetWindowTitle()); input.mDisableVerticalSync = true; mRenderer = new0 Renderer(input, theApp->GetWidth(), theApp->GetHeight(), mColorFormat, mDepthStencilFormat, mNumMultisamples); // Save the handle as an 'int' for portable handle storage. theApp->SetWindowID(input.mWindowID); // Set the callbacks for event handling. glutReshapeFunc(ReshapeCallback); glutDisplayFunc(DisplayCallback); glutIdleFunc(IdleCallback); glutKeyboardFunc(KeyDownCallback); glutKeyboardUpFunc(KeyUpCallback); glutSpecialFunc(SpecialKeyDownCallback); glutSpecialUpFunc(SpecialKeyUpCallback); glutMouseFunc(MouseClickCallback); glutMotionFunc(MotionCallback); glutPassiveMotionFunc(PassiveMotionCallback); if (theApp->OnInitialize()) { // The default OnPreidle() clears the buffers. Allow the application // to fill them before the window is shown and before the event loop // starts. theApp->OnPreidle(); glutMainLoop(); } // Because glutMainLoop never exits, the clean-up is handled via the // static Terminate in this file (registered with 'atexit'). return 0; }
//---------------------------------------------------------------------------- LRESULT CALLBACK MsWindowEventHandler (HWND handle, UINT message, WPARAM wParam, LPARAM lParam) { WindowApplication* theApp = (WindowApplication*)Application::TheApplication; if (!theApp || !theApp->GetWindowID()) { return DefWindowProc(handle, message, wParam, lParam); } switch (message) { case WM_PAINT: { PAINTSTRUCT ps; BeginPaint(handle, &ps); theApp->OnDisplay(); EndPaint(handle, &ps); return 0; } case WM_ERASEBKGND: { // This tells Windows not to erase the background (and that the // application is doing so). return 1; } case WM_MOVE: { int xPos = (int)(LOWORD(lParam)); int yPos = (int)(HIWORD(lParam)); theApp->OnMove(xPos, yPos); return 0; } case WM_SIZE: { int width = (int)(LOWORD(lParam)); int height = (int)(HIWORD(lParam)); theApp->OnResize(width, height); return 0; } case WM_CHAR: { unsigned char key = (unsigned char)(char)wParam; // Quit the application if the KEY_TERMINATE key is pressed. if (key == theApp->KEY_TERMINATE) { PostQuitMessage(0); return 0; } // Get the cursor position in client coordinates. POINT point; GetCursorPos(&point); ScreenToClient(handle, &point); int xPos = (int)point.x; int yPos = (int)point.y; theApp->OnKeyDown(key, xPos, yPos); return 0; } case WM_KEYDOWN: { int virtKey = (int)wParam; // Get cursor position client coordinates. POINT point; GetCursorPos(&point); ScreenToClient(handle, &point); int xPos = (int)point.x; int yPos = (int)point.y; if ((VK_F1 <= virtKey && virtKey <= VK_F12) || (VK_PRIOR <= virtKey && virtKey <= VK_DOWN) || (virtKey == VK_INSERT) || (virtKey == VK_DELETE) || (virtKey == VK_SHIFT) || (virtKey == VK_CONTROL)) { theApp->OnSpecialKeyDown(virtKey, xPos, yPos); } return 0; } case WM_KEYUP: { int virtKey = (int)wParam; // get the cursor position in client coordinates POINT point; GetCursorPos(&point); ScreenToClient(handle, &point); int xPos = (int)point.x; int yPos = (int)point.y; if ((VK_F1 <= virtKey && virtKey <= VK_F12) || (VK_PRIOR <= virtKey && virtKey <= VK_DOWN) || (virtKey == VK_INSERT) || (virtKey == VK_DELETE) || (virtKey == VK_SHIFT) || (virtKey == VK_CONTROL)) { theApp->OnSpecialKeyUp(virtKey, xPos, yPos); } else { theApp->OnKeyUp((unsigned char)virtKey, xPos, yPos); } return 0; } case WM_LBUTTONDOWN: { int xPos = (int)(LOWORD(lParam)); int yPos = (int)(HIWORD(lParam)); theApp->OnMouseClick(WindowApplication::MOUSE_LEFT_BUTTON, WindowApplication::MOUSE_DOWN, xPos, yPos, PtrToUint(wParam)); return 0; } case WM_LBUTTONUP: { int xPos = (int)(LOWORD(lParam)); int yPos = (int)(HIWORD(lParam)); theApp->OnMouseClick(WindowApplication::MOUSE_LEFT_BUTTON, WindowApplication::MOUSE_UP, xPos, yPos, PtrToUint(wParam)); return 0; } case WM_MBUTTONDOWN: { int xPos = (int)(LOWORD(lParam)); int yPos = (int)(HIWORD(lParam)); theApp->OnMouseClick(WindowApplication::MOUSE_MIDDLE_BUTTON, WindowApplication::MOUSE_DOWN, xPos, yPos, PtrToUint(wParam)); return 0; } case WM_MBUTTONUP: { int xPos = (int)(LOWORD(lParam)); int yPos = (int)(HIWORD(lParam)); theApp->OnMouseClick(WindowApplication::MOUSE_MIDDLE_BUTTON, WindowApplication::MOUSE_UP, xPos, yPos, PtrToUint(wParam)); return 0; } case WM_RBUTTONDOWN: { int xPos = (int)(LOWORD(lParam)); int yPos = (int)(HIWORD(lParam)); theApp->OnMouseClick(WindowApplication::MOUSE_RIGHT_BUTTON, WindowApplication::MOUSE_DOWN, xPos, yPos, PtrToUint(wParam)); return 0; } case WM_RBUTTONUP: { int xPos = (int)(LOWORD(lParam)); int yPos = (int)(HIWORD(lParam)); theApp->OnMouseClick(WindowApplication::MOUSE_RIGHT_BUTTON, WindowApplication::MOUSE_UP, xPos, yPos, PtrToUint(wParam)); return 0; } case WM_MOUSEMOVE: { int xPos = (int)(LOWORD(lParam)); int yPos = (int)(HIWORD(lParam)); int button = -1; if (wParam & MK_LBUTTON) { button = WindowApplication::MOUSE_LEFT_BUTTON; } else if (wParam & MK_MBUTTON) { button = WindowApplication::MOUSE_MIDDLE_BUTTON; } else if (wParam & MK_RBUTTON) { button = WindowApplication::MOUSE_RIGHT_BUTTON; } if (button >= 0) { theApp->OnMotion(button, xPos, yPos, PtrToUint(wParam)); } else { theApp->OnPassiveMotion(xPos, yPos); } return 0; } case WM_MOUSEWHEEL: { short sWParam = (short)(HIWORD(wParam)); int delta = ((int)sWParam)/WHEEL_DELTA; int xPos = (int)(LOWORD(lParam)); int yPos = (int)(HIWORD(lParam)); unsigned int modifiers = (unsigned int)(LOWORD(wParam)); theApp->OnMouseWheel(delta, xPos, yPos, modifiers); return 0; } case WM_DESTROY: { // The DestroyWindow call when recreating the window for // multisampling causes the application to terminate. It is // not clear why the same problem did not occur in WM4. if (!gsIgnoreWindowDestroy) { PostQuitMessage(0); } gsIgnoreWindowDestroy = false; return 0; } } return DefWindowProc(handle, message, wParam, lParam); }
//---------------------------------------------------------------------------- int WindowApplication::Main (int, char**) { WindowApplication* theApp = (WindowApplication*)TheApplication; theApp->KEY_TERMINATE = WindowApplication::KEY_ESCAPE; #ifdef WM5_USE_DX9 // DirectX uses a projection matrix for depth in [0,1]. Camera::SetDefaultDepthType(Camera::PM_DEPTH_ZERO_TO_ONE); #endif #ifdef WM5_USE_OPENGL // OpenGL uses a projection matrix for depth in [-1,1]. Camera::SetDefaultDepthType(Camera::PM_DEPTH_MINUS_ONE_TO_ONE); #endif // Allow work to be done before the window is created. if (!theApp->OnPrecreate()) { return -1; } // === Create the window for rendering. === // Register the window class. static char sWindowClass[] = "Wild Magic 5 Application"; WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wc.lpfnWndProc = MsWindowEventHandler; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = 0; wc.hIcon = LoadIcon(0, IDI_APPLICATION); wc.hCursor = LoadCursor(0, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszClassName = sWindowClass; wc.lpszMenuName = 0; RegisterClass(&wc); DWORD dwStyle; if (mAllowResize) { dwStyle = WS_OVERLAPPEDWINDOW; } else { // This removes WS_THICKFRAME and WS_MAXIMIZEBOX, both of which allow // resizing of windows. dwStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; } // Require the window to have the specified client area. RECT rect = { 0, 0, theApp->GetWidth()-1, theApp->GetHeight()-1 }; AdjustWindowRect(&rect, dwStyle, FALSE); // Create the application window. HWND handle = CreateWindow(sWindowClass, theApp->GetWindowTitle(), dwStyle, theApp->GetXPosition(), theApp->GetYPosition(), rect.right - rect.left + 1, rect.bottom - rect.top + 1, 0, 0, 0, 0); // Save the handle as an 'int' for portable handle storage. theApp->SetWindowID(PtrToInt(handle)); // === #ifdef WM5_USE_DX9 // Create the device for rendering. RendererInput input; input.mWindowHandle = handle; input.mDriver = Direct3DCreate9(D3D_SDK_VERSION); assertion(input.mDriver != 0, "Failed to create Direct3D9\n"); mRenderer = new0 Renderer(input, theApp->GetWidth(), theApp->GetHeight(), mColorFormat, mDepthStencilFormat, mNumMultisamples); #endif #ifdef WM5_USE_OPENGL // The pixelFormat variable is used to support creation of a window that // supports multisampling. This process requires creating a normal window, // and then querying whether the renderer supports multisampling. The // renderer creates a device context for the window which we then need to // create a second window that supports multisampling. The device context // rendererDC is set by the renderer during the process. RendererInput input; input.mWindowHandle = handle; input.mPixelFormat = 0; input.mRendererDC = 0; input.mDisableVerticalSync = true; mRenderer = new0 Renderer(input, theApp->GetWidth(), theApp->GetHeight(), mColorFormat, mDepthStencilFormat, mNumMultisamples); // To determine whether multisampling is supported, it is necessary to // create a window, an OpenGL context, and query the driver for the // multisampling extensions. If it is, a new window must be created // because the renderer creation involves SetPixelFormat(...) that can // be called only once for a window. int numMultisamples = mRenderer->GetNumMultisamples(); if (numMultisamples > 0) { int attributes[256], pos = 0; attributes[pos++] = WGL_SUPPORT_OPENGL_ARB; attributes[pos++] = 1; attributes[pos++] = WGL_DRAW_TO_WINDOW_ARB; attributes[pos++] = 1; attributes[pos++] = WGL_ACCELERATION_ARB; attributes[pos++] = WGL_FULL_ACCELERATION_ARB; attributes[pos++] = WGL_PIXEL_TYPE_ARB; attributes[pos++] = WGL_TYPE_RGBA_ARB; attributes[pos++] = WGL_RED_BITS_ARB; attributes[pos++] = 8; attributes[pos++] = WGL_GREEN_BITS_ARB; attributes[pos++] = 8; attributes[pos++] = WGL_BLUE_BITS_ARB; attributes[pos++] = 8; attributes[pos++] = WGL_ALPHA_BITS_ARB; attributes[pos++] = 8; attributes[pos++] = WGL_DEPTH_BITS_ARB; attributes[pos++] = 24; attributes[pos++] = WGL_STENCIL_BITS_ARB; attributes[pos++] = 8; attributes[pos++] = WGL_DOUBLE_BUFFER_ARB; attributes[pos++] = 1; attributes[pos++] = WGL_SAMPLE_BUFFERS_ARB; attributes[pos++] = 1; attributes[pos++] = WGL_SAMPLES_ARB; attributes[pos++] = numMultisamples; attributes[pos++] = 0; // list is zero-terminated unsigned int numFormats = 0; BOOL successful = wglChoosePixelFormatARB(input.mRendererDC, attributes, 0, 1, &input.mPixelFormat, &numFormats); if (successful && numFormats > 0) { // The card supports multisampling with the requested number of // samples. Recreate the window and renderer. delete0(mRenderer); gsIgnoreWindowDestroy = true; DestroyWindow(handle); handle = CreateWindow(sWindowClass, theApp->GetWindowTitle(), WS_OVERLAPPEDWINDOW, theApp->GetXPosition(), theApp->GetYPosition(), rect.right - rect.left + 1, rect.bottom - rect.top + 1, 0, 0, 0, 0); theApp->SetWindowID(PtrToInt(handle)); input.mWindowHandle = handle; mRenderer = new0 Renderer(input, theApp->GetWidth(), theApp->GetHeight(), mColorFormat, mDepthStencilFormat, mNumMultisamples); } } #endif if (theApp->OnInitialize()) { // The default OnPreidle() clears the buffers. Allow the application // to fill them before the window is shown and before the event loop // starts. theApp->OnPreidle(); // Display the window. ShowWindow(handle, SW_SHOW); UpdateWindow(handle); // Start the message pump. bool applicationRunning = true; while (applicationRunning) { MSG msg; if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) { applicationRunning = false; continue; } HACCEL accel = 0; if (!TranslateAccelerator(handle, accel, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } else { theApp->OnIdle(); } } } theApp->OnTerminate(); delete0(mRenderer); #ifdef WM5_USE_DX9 input.mDriver->Release(); #endif return 0; }
//---------------------------------------------------------------------------- int WindowApplication::Main (int numArguments, char** arguments) { // Initialize the extra data. TODO: Port the extra-data system of WM4 // to WM5. memset(gsExtraData, 0, APP_EXTRA_DATA_QUANTITY*sizeof(char)); WindowApplication* theApp = (WindowApplication*)TheApplication; theApp->KEY_TERMINATE = KEY_ESCAPE; // OpenGL uses a projection matrix for depth in [-1,1]. Camera::SetDefaultDepthType(Camera::PM_DEPTH_MINUS_ONE_TO_ONE); // Allow work to be done before the window is created. if (!theApp->OnPrecreate()) { return -1; } // Connect to the X server. const char* displayName = 0; Display* display = XOpenDisplay(displayName); if (!display) { return -2; } // Make sure the X server has OpenGL GLX extensions. int errorBase, eventBase; Bool success = glXQueryExtension(display, &errorBase, &eventBase); assertion(success == True, "GLX extensions not found.\n"); if (!success) { return -3; } // Partial construction of a GLX renderer. The window for the renderer // is not yet constructed. When it is, the window identifier is supplied // to the renderer to complete its construction. RendererInput input; input.mDisplay = display; input.mVisual = 0; input.mContext = 0; mRenderer = new0 Renderer(input, theApp->GetWidth(), theApp->GetHeight(), mColorFormat, mDepthStencilFormat, mNumMultisamples); if (!input.mVisual || !input.mContext) { return -4; } // Create an X Window with the visual information created by the renderer // constructor. The visual information might not be the default, so // create an X colormap to use. Window rootWindow = RootWindow(display, input.mVisual->screen); Colormap cMap = XCreateColormap(display, rootWindow, input.mVisual->visual, AllocNone); // Set the event mask to include exposure (paint), button presses (mouse), // and key presses (keyboard). XSetWindowAttributes windowAttributes; windowAttributes.colormap = cMap; windowAttributes.border_pixel = 0; windowAttributes.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | Button1MotionMask | Button2MotionMask | Button3MotionMask | KeyPressMask | KeyReleaseMask | ExposureMask | StructureNotifyMask; int xPos = theApp->GetXPosition(); int yPos = theApp->GetYPosition(); unsigned int width = (unsigned int)theApp->GetWidth(); unsigned int height = (unsigned int)theApp->GetHeight(); unsigned int borderWidth = 0; unsigned long valueMask = CWBorderPixel | CWColormap | CWEventMask; Window window = XCreateWindow(display, rootWindow, xPos, yPos, width, height, borderWidth, input.mVisual->depth, InputOutput, input.mVisual->visual, valueMask, &windowAttributes); XSizeHints hints; hints.flags = PPosition | PSize; hints.x = xPos; hints.y = yPos; hints.width = width; hints.height = height; XSetNormalHints(display, window, &hints); const char* iconName = theApp->GetWindowTitle(); Pixmap iconPixmap = None; XSetStandardProperties(display, window, theApp->GetWindowTitle(), iconName, iconPixmap, arguments, numArguments, &hints); // Intercept the close-window event when the user selects the // window close button. The event is a "client message". Atom wmDelete = XInternAtom(display, "WM_DELETE_WINDOW", False); XSetWMProtocols(display, window, &wmDelete, 1); // Finish the construction of the renderer. GlxRendererData* data = (GlxRendererData*)mRenderer->mData; if (!data->FinishConstruction(window, mRenderer)) { return -5; } if (theApp->OnInitialize()) { // The default OnPreidle() clears the buffers. Allow the application // to fill them before the window is shown and before the event loop // starts. theApp->OnPreidle(); // Display the window. XMapWindow(display, window); // Start the message pump. bool applicationRunning = true; while (applicationRunning) { if (!XPending(display)) { theApp->OnIdle(); continue; } XEvent evt; XNextEvent(display, &evt); int index; bool state; if (evt.type == ButtonPress || evt.type == ButtonRelease) { theApp->OnMouseClick(evt.xbutton.button, evt.xbutton.type, evt.xbutton.x, evt.xbutton.y, evt.xbutton.state); if (evt.type == ButtonPress) { index = GLXAPP_BUTTONDOWN + evt.xbutton.button; state = true; SetExtraData(index, sizeof(bool), &state); } else { index = GLXAPP_BUTTONDOWN + evt.xbutton.button; state = false; SetExtraData(index, sizeof(bool), &state); } continue; } if (evt.type == MotionNotify) { int button = 0; index = GLXAPP_BUTTONDOWN + 1; GetExtraData(index, sizeof(bool), &state); if (state) { button = MOUSE_LEFT_BUTTON; } else { index = GLXAPP_BUTTONDOWN + 2; GetExtraData(index, sizeof(bool), &state); if (state) { button = MOUSE_MIDDLE_BUTTON; } else { index = GLXAPP_BUTTONDOWN + 3; GetExtraData(index, sizeof(bool), &state); if (state) { button = MOUSE_RIGHT_BUTTON; } } } if (button > 0) { theApp->OnMotion(button, evt.xmotion.x, evt.xmotion.y, evt.xmotion.state); } else { theApp->OnPassiveMotion(evt.xmotion.x, evt.xmotion.y); } continue; } if (evt.type == KeyPress || evt.type == KeyRelease) { KeySym keySym = XKeycodeToKeysym(display, evt.xkey.keycode, 0); int key = (keySym & 0x00FF); // Quit application if the KEY_TERMINATE key is pressed. if (key == theApp->KEY_TERMINATE) { XDestroyWindow(display, window); applicationRunning = false; continue; } // Adjust for special keys that exist on the key pad and on // the number pad. if ((keySym & 0xFF00) != 0) { if (0x50 <= key && key <= 0x57) { // keypad Home, {L,U,R,D}Arrow, Pg{Up,Dn}, End key += 0x45; } else if (key == 0x63) { // keypad Insert key = 0x9e; } else if (key == 0xFF) { // keypad Delete key = 0x9f; } else if (key == 0xE1 || key == 0xE2) { // L-shift or R-shift key = KEY_SHIFT; state = (evt.type == KeyPress); SetExtraData(GLXAPP_SHIFTDOWN, sizeof(bool), &state); } else if (key == 0xE3 || key == 0xE4) { // L-ctrl or R-ctrl key = KEY_CONTROL; } else if (key == 0xE9 || key == 0xEA) { // L-alt or R-alt key = KEY_ALT; } else if (key == 0xEB || key == 0xEC) { key = KEY_COMMAND; } } if ((KEY_HOME <= key && key <= KEY_END) || (KEY_F1 <= key && key <= KEY_F12) || (KEY_SHIFT <= key && key <= KEY_COMMAND)) { if (evt.type == KeyPress) { theApp->OnSpecialKeyDown(key, evt.xbutton.x, evt.xbutton.y); } else { theApp->OnSpecialKeyUp(key, evt.xbutton.x, evt.xbutton.y); } } else { // Get key-modifier state. Adjust for shift state. unsigned char ucKey = (unsigned char)key; GetExtraData(GLXAPP_SHIFTDOWN, sizeof(bool), &state); if (state && 'a' <= ucKey && ucKey <= 'z') { ucKey = (unsigned char)(key - 32); } if (evt.type == KeyPress) { theApp->OnKeyDown(ucKey, evt.xbutton.x, evt.xbutton.y); } else { theApp->OnKeyUp(ucKey, evt.xbutton.x, evt.xbutton.y); } } continue; } if (evt.type == Expose) { theApp->OnDisplay(); continue; } if (evt.type == ConfigureNotify) { theApp->OnMove(evt.xconfigure.x, evt.xconfigure.y); theApp->OnResize(evt.xconfigure.width, evt.xconfigure.height); continue; } if (evt.type == ClientMessage && evt.xclient.data.l[0] == wmDelete) { XDestroyWindow(display, window); applicationRunning = false; continue; } } } theApp->OnTerminate(); XCloseDisplay(display); return 0; }