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