#include "WindowManager.h" void TransWindow(WindowRef w, Boolean vis) { WindowTransitionAction Action; if(vis) Action = kWindowShowTransitionAction; else Action = kWindowHideTransitionAction; TransitionWindow(w, kWindowZoomTransitionEffect, Action, NULL); } #pragma mark - void SetOrtho(VWindow * w) { Rect bounds; bounds = WindowSize(w); glMatrixMode(GL_PROJECTION); glLoadIdentity(); w->Ortho = true; glDisable(GL_DEPTH_TEST); glOrtho(0, 800, 0, 600, 0, 20); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void SetPerspective(VWindow * w) { Rect bounds; GLfloat ratio; bounds = WindowSize(w); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if ((bounds.right - bounds.left) > (bounds.bottom - bounds.top)) { ratio = ((GLfloat) (bounds.right - bounds.left) / (bounds.bottom - bounds.top)); glFrustum(-ratio, ratio, -1.0, 1.0, 1.5, 10000.0); } else { ratio = ((GLfloat) (bounds.bottom - bounds.top) / (bounds.right - bounds.left)); glFrustum(-1.0, 1.0, -ratio, ratio, 1.5, 10000.0); } glScalef(10.0, 10.0, 10.0); w->Ortho = false; glEnable(GL_DEPTH_TEST); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } static void SetOGLSetttings(VWindow * w) { glLineWidth(1.0); glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); glEnable(GL_ALPHA_TEST); glEnable(GL_POLYGON_OFFSET_FILL); glAlphaFunc(GL_GREATER, 0.0f); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthFunc(GL_LEQUAL); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST); glHint(GL_POLYGON_SMOOTH_HINT, GL_FASTEST); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); /* Wireframe mode */ if(w->Ortho) SetOrtho(w); else SetPerspective(w); } Rect WindowSize(VWindow * w) { Rect result; GDHandle Display; if(w->IsFullScreen) { Display = GetMainDevice(); return (**Display).gdRect; } else { GetWindowPortBounds(w->TheWindow, &result); return result; } } void CreateWindowedContext(VWindow * w) { GLint Attribs[] = {AGL_RGBA, AGL_DOUBLEBUFFER, AGL_DEPTH_SIZE, 24, AGL_NO_RECOVERY, AGL_ACCELERATED, AGL_PIXEL_SIZE, 32, AGL_NONE}; AGLPixelFormat Format; Rect windowBounds; GLint sync = 1; Format = aglChoosePixelFormat(NULL, 0, Attribs); w->Windowed = aglCreateContext(Format, w->FullScreen); if(w->FullScreen) { glClear(GL_COLOR_BUFFER_BIT); aglSwapBuffers(w->FullScreen); aglSetCurrentContext(NULL); aglSetDrawable(w->FullScreen, NULL); aglDestroyContext(w->FullScreen); w->FullScreen = NULL; } aglSetDrawable(w->Windowed, GetWindowPort(w->TheWindow)); aglSetCurrentContext(w->Windowed); aglSetInteger(w->Windowed, AGL_SWAP_INTERVAL, &sync); aglDestroyPixelFormat(Format); GetWindowPortBounds(w->TheWindow, &windowBounds); w->IsFullScreen = false; SetOGLSetttings(w); glClear(GL_COLOR_BUFFER_BIT); aglSwapBuffers(w->Windowed); if(aglGetError()) SysBeep(0); } void CreateFullScreenContext(VWindow * w) { GLint Attribs[] = {AGL_RGBA, AGL_DOUBLEBUFFER, AGL_DEPTH_SIZE, 24, AGL_FULLSCREEN, AGL_NO_RECOVERY, AGL_ACCELERATED, AGL_PIXEL_SIZE, 32, AGL_NONE}; AGLPixelFormat Format; GDHandle Display; VSettings * s; int Width, Height, RefreshRate; GLint sync = 1; Display = GetMainDevice(); Format = aglChoosePixelFormat(&Display, 1, Attribs); w->FullScreen = aglCreateContext(Format, w->Windowed); if(w->Windowed) { glClear(GL_COLOR_BUFFER_BIT); aglSwapBuffers(w->Windowed); aglSetCurrentContext(NULL); aglSetDrawable(w->Windowed, NULL); aglDestroyContext(w->Windowed); w->Windowed = NULL; } s = GetSettings(); if (s == NULL) { /* Default to no change */ Width = (**Display).gdRect.right; Height = (**Display).gdRect.bottom; RefreshRate = 0; } else { GetFullscreenSettings(s, &Width, &Height, &RefreshRate); } if (aglSetFullScreen(w->FullScreen, Width, Height, RefreshRate, 0)) { aglSetCurrentContext(w->FullScreen); } else { SysBeep(1); aglDestroyPixelFormat(Format); CreateWindowedContext(w); return; } aglSetInteger(w->FullScreen, AGL_SWAP_INTERVAL, &sync); aglDestroyPixelFormat(Format); w->IsFullScreen = true; SetOGLSetttings(w); glClear(GL_COLOR_BUFFER_BIT); aglSwapBuffers(w->FullScreen); if(aglGetError()) SysBeep(0); } static void InitWindowContext(VWindow * w) { VSettings * s; w->FullScreen = NULL; w->Windowed = NULL; w->Ortho = false; w->Scaled = false; s = GetSettings(); if (s != NULL && s->StartInFullScreen) CreateFullScreenContext(w); else CreateWindowedContext(w); } #pragma mark - static OSStatus windowEventHandler(EventHandlerCallRef nextEvent, EventRef theEvent, void * userData) { VWindow * w; UInt32 attributes; switch (GetEventClass(theEvent)) { case kEventClassWindow: switch (GetEventKind(theEvent)) { case kEventWindowClose: w = (VWindow *) userData; if (w->quitOnClose) QuitApplicationEventLoop(); break; case kEventWindowCollapsing: w = (VWindow *) userData; w->isMinimized = 1; if (!w->IsFullScreen && w->Windowed != NULL) { PixMapHandle myPixMap; Rect windowBounds; void * imageData; GWorldPtr origGWorld; GDHandle origGDev; short currentRow; Rect srcRect, destRect; GetWindowPortBounds(w->TheWindow, &windowBounds); OffsetRect(&windowBounds, -windowBounds.left, -windowBounds.top); myPixMap = NewPixMap(); if (myPixMap == NULL) return eventNotHandledErr; imageData = NewPtr(4 * windowBounds.right * windowBounds.bottom); if (imageData == NULL) { DisposePixMap(myPixMap); return eventNotHandledErr; } glReadPixels(0, 0, windowBounds.right, windowBounds.bottom, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, imageData); (**myPixMap).baseAddr = imageData; (**myPixMap).rowBytes = ((windowBounds.right * 4) | (1 << 15)); (**myPixMap).bounds = windowBounds; (**myPixMap).pmVersion = 0; (**myPixMap).packType = 0; (**myPixMap).packSize = 0; (**myPixMap).hRes = (72 << 16); /* hRes is a Fixed */ (**myPixMap).vRes = (72 << 16); /* vRes is a Fixed */ (**myPixMap).pixelType = RGBDirect; (**myPixMap).pixelSize = 32; (**myPixMap).cmpCount = 3; /* RGB, ignore Alpha */ (**myPixMap).cmpSize = 8; (**myPixMap).pixelFormat = 0; (**myPixMap).pmExt = 0; (**myPixMap).pmTable = GetCTable(72); /* Unnecessary? */ GetGWorld(&origGWorld, &origGDev); SetPortWindowPort(w->TheWindow); srcRect = destRect = windowBounds; /* Since glReadPixels will give us an upside-down image, copy one row at a time. Not the most efficient way to do it, but it works well enough. */ for (currentRow = 0; currentRow < windowBounds.bottom; currentRow++) { srcRect.bottom = (windowBounds.bottom - currentRow); srcRect.top = (srcRect.bottom - 1); destRect.top = currentRow; destRect.bottom = (currentRow + 1); CopyBits((BitMap *) *myPixMap, GetPortBitMapForCopyBits(GetWindowPort(w->TheWindow)), &srcRect, &destRect, srcCopy, NULL); } /* Make sure the image shows up */ QDFlushPortBuffer(GetWindowPort(w->TheWindow), NULL); SetGWorld(origGWorld, origGDev); DisposePixMap(myPixMap); DisposePtr(imageData); } break; case kEventWindowExpanding: w = (VWindow *) userData; w->isMinimized = 0; break; case kEventWindowBoundsChanged: w = (VWindow *) userData; GetEventParameter(theEvent, kEventParamAttributes, typeUInt32, NULL, sizeof(UInt32), NULL, &attributes); if (attributes & kWindowBoundsChangeSizeChanged) { Rect windowBounds; aglUpdateContext(w->Windowed); GetWindowBounds(w->TheWindow, kWindowContentRgn, &windowBounds); windowBounds.right -= windowBounds.left; windowBounds.bottom -= windowBounds.top; windowBounds.left = windowBounds.top = 0; glViewport(windowBounds.left, windowBounds.top, windowBounds.right, windowBounds.bottom); if (w->Ortho) { SetOrtho(w); } else { SetPerspective(w); } return noErr; } break; } } return eventNotHandledErr; } void InitWindow(VWindow * w) { GDHandle mainDevice; Point screenSize; Rect Bounds; EventTypeSpec eventTypes[] = {{kEventClassWindow, kEventWindowClose}, {kEventClassWindow, kEventWindowCollapsing}, {kEventClassWindow, kEventWindowExpanding}, {kEventClassWindow, kEventWindowBoundsChanged}}; mainDevice = GetMainDevice(); screenSize.h = (**mainDevice).gdRect.right; screenSize.v = (**mainDevice).gdRect.bottom; /* This will center the window onscreen. */ SetRect(&Bounds, ((screenSize.h / 2) - 800/2), ((screenSize.v / 2) - 600/2), ((screenSize.h / 2) + 800/2), ((screenSize.v / 2) + 600/2)); CreateNewWindow(kDocumentWindowClass, kWindowCloseBoxAttribute | kWindowCollapseBoxAttribute | kWindowResizableAttribute | kWindowLiveResizeAttribute | kWindowFullZoomAttribute, &Bounds, &w->TheWindow); SetWindowTitleWithCFString(w->TheWindow, CFSTR("Infiltration")); InstallStandardEventHandler(GetWindowEventTarget(w->TheWindow)); InstallWindowEventHandler(w->TheWindow, NewEventHandlerUPP(windowEventHandler), GetEventTypeCount(eventTypes), eventTypes, w, NULL); TransWindow(w->TheWindow, true); InitWindowContext(w); w->quitOnClose = 0; w->isMinimized = 0; } void CleanUpWindow(VWindow * w) { TransWindow(w->TheWindow, false); if(w->FullScreen) { aglSetCurrentContext(NULL); aglSetDrawable(w->FullScreen, NULL); aglDestroyContext(w->FullScreen); w->FullScreen = NULL; } if(w->Windowed) { aglSetCurrentContext(NULL); aglSetDrawable(w->Windowed, NULL); aglDestroyContext(w->Windowed); w->Windowed = NULL; } DisposeWindow(w->TheWindow); w->TheWindow = NULL; }