diff options
Diffstat (limited to 'src/Window_MacClassic.c')
-rw-r--r-- | src/Window_MacClassic.c | 558 |
1 files changed, 558 insertions, 0 deletions
diff --git a/src/Window_MacClassic.c b/src/Window_MacClassic.c new file mode 100644 index 0000000..0b90ae8 --- /dev/null +++ b/src/Window_MacClassic.c @@ -0,0 +1,558 @@ +#include "Core.h" +#if defined CC_BUILD_MACCLASSIC + +#include "_WindowBase.h" +#include "String.h" +#include "Funcs.h" +#include "Bitmap.h" +#include "Options.h" +#include "Errors.h" + +#undef true +#undef false +#include <Quickdraw.h> +#include <Dialogs.h> +#include <Fonts.h> +#include <Events.h> +#include <LowMem.h> +#ifndef M68K_INLINE +#include <DiskInit.h> +#include <Scrap.h> +#endif +#include <Gestalt.h> +static WindowPtr win; +static cc_bool hasColorQD, useGWorld; + + +/*########################################################################################################################* +*--------------------------------------------------Console log window-----------------------------------------------------* +*#########################################################################################################################*/ +static int con_cellSizeX, con_cellSizeY; +static int con_rows, con_cols; +static int cursorX, cursorY; +static WindowPtr con_win; +static Rect con_bounds; + +static void Console_EraseLine(int y) { + Rect r = con_bounds; + r.top += y * con_cellSizeY; + r.bottom = r.top + con_cellSizeY; + + MoveTo(r.left, r.bottom - 2); + EraseRect(&r); +} + +static void Console_Init(void) { + Rect r = qd.screenBits.bounds; + r.top += 40; + InsetRect(&r, 5, 5); + + con_win = NewWindow(NULL, &r, "\pConsole log", true, 0, (WindowPtr)-1, true, 0); + GrafPtr savedPort; + GetPort(&savedPort); + SetPort(con_win); + + con_bounds = con_win->portRect; + EraseRect(&con_bounds); + + TextFont(kFontIDMonaco); + TextSize(9); + + InsetRect(&con_bounds, 2, 2); + con_cellSizeX = CharWidth('M'); + con_cellSizeY = 12; + + con_rows = (con_bounds.bottom - con_bounds.top) / con_cellSizeY; + con_cols = (con_bounds.right - con_bounds.left) / con_cellSizeX; + + Console_EraseLine(0); + cursorX = cursorY = 0; + SetPort(savedPort); +} + +static void Console_NewLine(void) { + Console_EraseLine(cursorY); + cursorY++; + cursorX = 0; + if (cursorY >= con_rows) cursorY = 0; +} + +void Console_Write(const char* msg, int len) { + if (!con_win) Console_Init(); + + GrafPtr savedPort; + GetPort(&savedPort); + SetPort(con_win); + + for (int i = 0; i < len; i++) + { + DrawChar(msg[i]); + cursorX++; + if (cursorX >= con_cols) Console_NewLine(); + } + Console_NewLine(); + + SetPort(savedPort); +} + + +/*########################################################################################################################* +*---------------------------------------------------Imported headers------------------------------------------------------* +*#########################################################################################################################*/ +// On 68k these are implemented using direct 68k opcodes +// On PPC these are implemented using function calls +#if TARGET_CPU_68K + #define MAC_SYSAPI(_type) static _type + #define MAC_ONEWORDINLINE(w1) = w1 + #define MAC_TWOWORDINLINE(w1,w2) = {w1, w2} + #define MAC_THREEWORDINLINE(w1,w2,w3) = {w1, w2, w3} + #define MAC_FOURWORDINLINE(w1,w2,w3,w4) = {w1, w2, w3, w4} +#else + #define MAC_SYSAPI(_type) extern pascal _type + #define MAC_ONEWORDINLINE(w1) + #define MAC_TWOWORDINLINE(w1,w2) + #define MAC_THREEWORDINLINE(w1,w2,w3) + #define MAC_FOURWORDINLINE(w1,w2,w3,w4) +#endif +typedef unsigned long MAC_FourCharCode; +typedef SInt16 MAC_WindowPartCode; +typedef UInt16 MAC_EventMask; + +// Workaround issue in multiversal headers +#if defined M68K_INLINE && TARGET_CPU_68K + +// Availability: in InterfaceLib 7.1 and later +MAC_SYSAPI(void) _SetEventMask(MAC_EventMask value) MAC_TWOWORDINLINE(0x31DF, 0x0144); +#define SetEventMask _SetEventMask +#endif + +/*########################################################################################################################* +*--------------------------------------------------Public implementation--------------------------------------------------* +*#########################################################################################################################*/ +static const cc_uint8 key_map[8 * 16] = { +/* 0x00 */ 'A', 'S', 'D', 'F', 'H', 'G', 'Z', 'X', +/* 0x08 */ 'C', 'V', 0, 'B', 'Q', 'W', 'E', 'R', +/* 0x10 */ 'Y', 'T', '1', '2', '3', '4', '6', '5', +/* 0x18 */ CCKEY_EQUALS, '9', '7', CCKEY_MINUS, '8', '0', CCKEY_RBRACKET, 'O', +/* 0x20 */ 'U', CCKEY_LBRACKET, 'I', 'P', CCKEY_ENTER, 'L', 'J', CCKEY_QUOTE, +/* 0x28 */ 'K', CCKEY_SEMICOLON, CCKEY_BACKSLASH, CCKEY_COMMA, CCKEY_SLASH, 'N', 'M', CCKEY_PERIOD, +/* 0x30 */ CCKEY_TAB, CCKEY_SPACE, CCKEY_TILDE, CCKEY_BACKSPACE, 0, CCKEY_ESCAPE, 0, CCKEY_LWIN, +/* 0x38 */ CCKEY_LSHIFT, CCKEY_CAPSLOCK, CCKEY_LALT, CCKEY_LCTRL, 0, 0, 0, 0, +/* 0x40 */ 0, CCKEY_KP_DECIMAL, 0, CCKEY_KP_MULTIPLY, 0, CCKEY_KP_PLUS, 0, CCKEY_NUMLOCK, +/* 0x48 */ CCKEY_VOLUME_UP, CCKEY_VOLUME_DOWN, CCKEY_VOLUME_MUTE, CCKEY_KP_DIVIDE, CCKEY_KP_ENTER, 0, CCKEY_KP_MINUS, 0, +/* 0x50 */ 0, CCKEY_KP_ENTER, CCKEY_KP0, CCKEY_KP1, CCKEY_KP2, CCKEY_KP3, CCKEY_KP4, CCKEY_KP5, +/* 0x58 */ CCKEY_KP6, CCKEY_KP7, 0, CCKEY_KP8, CCKEY_KP9, 'N', 'M', CCKEY_PERIOD, +/* 0x60 */ CCKEY_F5, CCKEY_F6, CCKEY_F7, CCKEY_F3, CCKEY_F8, CCKEY_F9, 0, CCKEY_F11, +/* 0x68 */ 0, CCKEY_F13, 0, CCKEY_F14, 0, CCKEY_F10, 0, CCKEY_F12, +/* 0x70 */ 'U', CCKEY_F15, CCKEY_INSERT, CCKEY_HOME, CCKEY_PAGEUP, CCKEY_DELETE, CCKEY_F4, CCKEY_END, +/* 0x78 */ CCKEY_F2, CCKEY_PAGEDOWN, CCKEY_F1, CCKEY_LEFT, CCKEY_RIGHT, CCKEY_DOWN, CCKEY_UP, 0, +}; +static int MapNativeKey(UInt32 key) { return key < Array_Elems(key_map) ? key_map[key] : 0; } + +void Window_PreInit(void) { + InitGraf(&qd.thePort); + InitFonts(); + InitWindows(); + InitMenus(); + InitDialogs(NULL); + InitCursor(); + + EventRecord event; + for (int i = 0; i < 5; i++) + EventAvail(everyEvent, &event); + FlushEvents(everyEvent, 0); + SetEventMask(everyEvent); + + long tmpLong = 0; + Gestalt(gestaltQuickdrawVersion, &tmpLong); + hasColorQD = tmpLong >= gestalt32BitQD; +} + +void Window_Init(void) { + Rect r = qd.screenBits.bounds; + DisplayInfo.x = r.left; + DisplayInfo.y = r.top; + DisplayInfo.Width = r.right - r.left; + DisplayInfo.Height = r.bottom - r.top; + + DisplayInfo.ScaleX = 1.0f; + DisplayInfo.ScaleY = 1.0f; +} + +void Window_Free(void) { } + +static void DoCreateWindow(int width, int height) { + if (Window_Main.Exists) return; + + Rect r = qd.screenBits.bounds; + r.top += 40; + InsetRect(&r, 100, 100); + + if (hasColorQD) { + win = NewCWindow(NULL, &r, "\pClassiCube", true, documentProc, (WindowPtr)-1, true, 0); + } else { + win = NewWindow( NULL, &r, "\pClassiCube", true, documentProc, (WindowPtr)-1, true, 0); + } + + if (hasColorQD) { + Platform_LogConst("BLITTING IN FAST MODE"); + } else { + Platform_LogConst("BLITTING IN SLOW MODE"); + } + + useGWorld = hasColorQD; + SetPort(win); + r = win->portRect; + + Window_Main.Width = r.right - r.left; + Window_Main.Height = r.bottom - r.top; + Window_Main.Focused = true; + Window_Main.Exists = true; +} + +void Window_Create2D(int width, int height) { DoCreateWindow(width, height); } +void Window_Create3D(int width, int height) { DoCreateWindow(width, height); } + +void Window_SetTitle(const cc_string* title) { + // TODO +} + +void Clipboard_GetText(cc_string* value) { + Handle tmp = NewHandle(0); + HLock(tmp); + int dataSize = GetScrap(tmp, 'TEXT', 0); + HUnlock(tmp); + + String_AppendAll(value, (char*)tmp, dataSize); + DisposeHandle(tmp); + // TODO +} + +void Clipboard_SetText(const cc_string* value) { + PutScrap(value->length, 'TEXT', value->buffer); + // TODO +} + +int Window_GetWindowState(void) { + return WINDOW_STATE_NORMAL; + // TODO +} + +cc_result Window_EnterFullscreen(void) { + // TODO + return 0; +} + +cc_result Window_ExitFullscreen(void) { + // TODO + return 0; +} + +int Window_IsObscured(void) { return 0; } + +void Window_Show(void) { + // TODO +} + +void Window_SetSize(int width, int height) { + // TODO +} + +void Window_RequestClose(void) { + Event_RaiseVoid(&WindowEvents.Closing); +} + + +static void HandleMouseDown(EventRecord* event) { + MAC_WindowPartCode part; + WindowPtr window; + Point localPoint; + long res; + int x, y; + + part = FindWindow(event->where, &window); + switch (part) + { + case inMenuBar: + HiliteMenu(0); + break; + case inSysWindow: + SystemClick(event, window); + break; + case inContent: + SetPt(&localPoint, event->where.h, event->where.v); + GlobalToLocal(&localPoint); + if (window != win) break; + + x = localPoint.h; + y = localPoint.v; + Pointer_SetPosition(0, x, y); + Input_SetPressed(CCMOUSE_L); + break; + case inDrag: + DragWindow(window, event->where, &qd.screenBits.bounds); + break; + case inGoAway: + if (TrackGoAway(window, event->where)) { + Window_RequestClose(); + Window_Main.Exists = false; + } + break; + case inGrow: + res = GrowWindow(window, event->where, &qd.screenBits.bounds); + x = res & 0xFFFF; + y = res >> 16; + SizeWindow(window, x, y, false); + if (window != win) break; + + Window_Main.Width = x; + Window_Main.Height = y; + Event_RaiseVoid(&WindowEvents.Resized); + break; + } +} + +static void HandleMouseUp(EventRecord* event) { + Input_SetReleased(CCMOUSE_L); +} + +static void HandleKeyDown(EventRecord* event) { + if ((event->modifiers & cmdKey)) + HiliteMenu(0); + + int ch = event->message & 0xFF; + int key = (event->message >> 8) & 0xFF; + + if (ch >= 32 && ch <= 127) + Event_RaiseInt(&InputEvents.Press, (cc_unichar)ch); + + key = MapNativeKey(key); + if (key) Input_SetPressed(key); +} + +static void HandleKeyUp(EventRecord* event) { + int key = (event->message >> 8) & 0xFF; + + key = MapNativeKey(key); + if (key) Input_SetReleased(key); +} + +void Window_ProcessEvents(float delta) { + EventRecord event; + SystemTask(); + + while (GetNextEvent(everyEvent, &event)) { + switch (event.what) + { + case mouseDown: + HandleMouseDown(&event); + break; + case mouseUp: + HandleMouseUp(&event); + break; + case keyDown: + case autoKey: + HandleKeyDown(&event); + break; + case keyUp: + HandleKeyUp(&event); + break; + case updateEvt: + BeginUpdate((WindowPtr)event.message); + EndUpdate( (WindowPtr)event.message); + Event_RaiseVoid(&WindowEvents.RedrawNeeded); + break; + case diskEvt: + if ((event.message & 0xFFFF0000) != noErr) + { + Point pt = { 100, 100 }; + DILoad(); + DIBadMount(pt, event.message); + DIUnload(); + } + break; + case kHighLevelEvent: + AEProcessAppleEvent(&event); + break; + default: + break; + } + } +} + +void Window_ProcessGamepads(float delta) { +} + +static void Cursor_GetRawPos(int* x, int* y) { + Point point; + GetMouse(&point); + + *x = point.h; + *y = point.v; +} + +void Cursor_SetPosition(int x, int y) { + // TODO + Point where; + where.h = x; + where.v = y; + //LMSetRawMouseLocation(where); +} + +static void Cursor_DoSetVisible(cc_bool visible) { + if (visible) { + ShowCursor(); + } else { + HideCursor(); + } +} + +static void ShowDialogCore(const char* title, const char* msg) { + // TODO + for (int i = 0; i < 20; i++) + { + Platform_LogConst(title); + Platform_LogConst(msg); + } +} + +cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) { + // TODO + return ERR_NOT_SUPPORTED; +} + +cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) { + // TODO + return ERR_NOT_SUPPORTED; +} + +static GWorldPtr fb_world; +static PixMapHandle fb_pixmap; + +void Window_AllocFramebuffer(struct Bitmap* bmp, int width, int height) { + if (!useGWorld) { + bmp->scan0 = (BitmapCol*)Mem_Alloc(width * height, 4, "window pixels"); + bmp->width = width; + bmp->height = height; + return; + } + + QDErr err = NewGWorld(&fb_world, 32, &win->portRect, 0, 0, 0); + if (err != noErr) Logger_Abort2(err, "Failed to allocate GWorld"); + + fb_pixmap = GetGWorldPixMap(fb_world); + if (!fb_pixmap) Logger_Abort("Failed to allocate pixmap"); + + LockPixels(fb_pixmap); + int stride = (*fb_pixmap)->rowBytes & 0x3FFF; + + bmp->scan0 = (BitmapCol*)GetPixBaseAddr(fb_pixmap); + bmp->width = stride >> 2; + bmp->height = height; +} + +static void DrawFramebufferBulk(Rect2D r, struct Bitmap* bmp) { + GrafPtr thePort = (GrafPtr)win; + BitMap* memBits = &((GrafPtr)fb_world)->portBits; + BitMap* winBits = &thePort->portBits; + + Rect update; + update.left = r.x; + update.right = r.x + r.width; + update.top = r.y; + update.bottom = r.y + r.height; + + CopyBits(memBits, winBits, &update, &update, srcCopy, nil); +} + +static void DrawFramebufferSlow(Rect2D r, struct Bitmap* bmp) { + for (int y = r.y; y < r.y + r.height; ++y) + { + BitmapCol* row = Bitmap_GetRow(bmp, y); + for (int x = r.x; x < r.x + r.width; ++x) + { + // TODO optimise + BitmapCol col = row[x]; + cc_uint8 R = BitmapCol_R(col); + cc_uint8 G = BitmapCol_G(col); + cc_uint8 B = BitmapCol_B(col); + + RGBColor pixelColor; + pixelColor.red = R << 8; + pixelColor.green = G << 8; + pixelColor.blue = B << 8; + + RGBForeColor(&pixelColor); + MoveTo(x, y); + Line(0, 0); + //SetCPixel(x, y, &pixelColor); + } + } +} + +void Window_DrawFramebuffer(Rect2D r, struct Bitmap* bmp) { + SetPort(win); + + if (useGWorld) { + DrawFramebufferBulk(r, bmp); + } else { + DrawFramebufferSlow(r, bmp); + } +} + +void Window_FreeFramebuffer(struct Bitmap* bmp) { + Mem_Free(bmp->scan0); + if (!useGWorld) return; + + UnlockPixels(fb_pixmap); + DisposeGWorld(fb_world); +} + +void OnscreenKeyboard_Open(struct OpenKeyboardArgs* args) { } +void OnscreenKeyboard_SetText(const cc_string* text) { } +void OnscreenKeyboard_Draw2D(Rect2D* r, struct Bitmap* bmp) { } +void OnscreenKeyboard_Draw3D(void) { } +void OnscreenKeyboard_Close(void) { } + +void Window_EnableRawMouse(void) { + DefaultEnableRawMouse(); +} + +void Window_UpdateRawMouse(void) { + DefaultUpdateRawMouse(); +} + +void Window_DisableRawMouse(void) { + DefaultDisableRawMouse(); +} + + +/*########################################################################################################################* +*-------------------------------------------------------WGL OpenGL--------------------------------------------------------* +*#########################################################################################################################*/ +#if (CC_GFX_BACKEND & CC_GFX_BACKEND_GL_MASK) && !defined CC_BUILD_EGL +void GLContext_Create(void) { + // TODO +} + +void GLContext_Update(void) { } +cc_bool GLContext_TryRestore(void) { return true; } +void GLContext_Free(void) { + // TODO +} + +void* GLContext_GetAddress(const char* function) { + return NULL; +} + +cc_bool GLContext_SwapBuffers(void) { + // TODO + return true; +} + +void GLContext_SetFpsLimit(cc_bool vsync, float minFrameMs) { + // TODO +} +void GLContext_GetApiInfo(cc_string* info) { } +#endif +#endif |