/* Sarien - A Sierra AGI resource interpreter engine * Copyright (C) 1999-2001 Stuart George and Claudio Matsuoka * * $Id: macos.c,v 1.10 2001/08/31 22:21:55 cmatsuoka Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; see docs/COPYING for further details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "sarien.h" #include "graphics.h" extern struct gfx_driver *gfx; extern struct sarien_options opt; static int macos_init_vidmode (void); static int macos_deinit_vidmode (void); static void macos_put_block (int, int, int, int); static void macos_put_pixels (int, int, int, UINT8 *); static void macos_timer (void); static int macos_get_key (void); static int macos_keypress (void); static struct gfx_driver gfx_macos = { macos_init_vidmode, macos_deinit_vidmode, macos_put_block, NULL, /* put_pixels */ macos_timer, macos_keypress, macos_get_key }; static QDGlobals qd; static WindowPtr window; static int rgb_palette[32]; static GWorldPtr gworld; static PixMapHandle pix, wpix; static UINT8 *screen_buffer; static int depth = 16; #define KEY_QUEUE_SIZE 16 static int key_queue[KEY_QUEUE_SIZE]; static int key_queue_start = 0; static int key_queue_end = 0; #define key_enqueue(k) do { key_queue[key_queue_end++] = (k); \ key_queue_end %= KEY_QUEUE_SIZE; } while (0) #define key_dequeue(k) do { (k) = key_queue[key_queue_start++]; \ key_queue_start %= KEY_QUEUE_SIZE; } while (0) #define ASPECT_RATIO(x) ((x) * 6 / 5) #ifdef __MPW__ char *strdup (char *s) { char *r = malloc (strlen (s) + 1); strcpy (r, s); return r; } #endif int init_machine (int argc, char **argv) { gfx = &gfx_macos; return err_OK; } int deinit_machine () { return err_OK; } /* ===================================================================== */ /* Optimized wrappers to access the offscreen pixmap directly. * From my raster star wars scroller screensaver. */ /* In the normal 8/15/16/24/32 bpp cases idx indexes the data item directly. * x and y are available for the other depths. */ static INLINE void putpixel_32 (void *img, int idx, int p) { ((int *)img)[idx] = p; } static INLINE void putpixel_16 (void *img, int idx, int p) { ((short *)img)[idx] = p; } static INLINE void putpixel_8 (void *img, int idx, int p) { ((char *)img)[idx] = p; } /* ===================================================================== */ /* Standard put pixels handlers */ #define _putpixels_scale1(d) static void \ _putpixels_##d##bits_scale1 (int x, int y, int w, UINT8 *p) { \ if (w == 0) return; \ x += y * GFX_WIDTH + y * 8; \ while (w--) { putpixel_##d## (screen_buffer, x++, rgb_palette[*p++]); }\ } #define _putpixels_scale2(d) static void \ _putpixels_##d##bits_scale2 (int x, int y, int w, UINT8 *p) { \ register int c; if (w == 0) return; \ x <<= 1; y <<= 1; \ x += y * (GFX_WIDTH << 1); \ y = x + (GFX_WIDTH << 1); \ while (w--) { \ c = rgb_palette[*p++]; \ putpixel_##d## (screen_buffer, x++, c); \ putpixel_##d## (screen_buffer, x++, c); \ putpixel_##d## (screen_buffer, y++, c); \ putpixel_##d## (screen_buffer, y++, c); \ } \ } _putpixels_scale1(8); _putpixels_scale1(16); _putpixels_scale1(32); #if 0 /* Don't need these for MacOS */ _putpixels_scale2(8); _putpixels_scale2(16); _putpixels_scale2(32); #endif /* ===================================================================== */ /* Aspect ratio correcting put pixels handlers */ #define _putpixels_fixratio_scale1(d) static void \ _putpixels_fixratio_##d##bits_scale1 (int x, int y, int w, UINT8 *p) { \ if (y > 0 && ASPECT_RATIO (y) - 1 != ASPECT_RATIO (y - 1)) \ _putpixels_##d##bits_scale1 (x, ASPECT_RATIO(y) - 1, w, p);\ _putpixels_##d##bits_scale1 (x, ASPECT_RATIO(y), w, p); \ } #define _putpixels_fixratio_scale2(d) static void \ _putpixels_fixratio_##d##bits_scale2 (int x, int y, int w, UINT8 *p0) { \ register int c; int extra = 0, z; UINT8 *p; \ if (w == 0) return; \ x <<= 1; y <<= 1; \ if (y < ((GFX_WIDTH - 1) << 2) && ASPECT_RATIO (y) + 2 != ASPECT_RATIO (y + 2)) extra = w; \ y = ASPECT_RATIO(y); \ x += y * (GFX_WIDTH << 1); \ y = x + (GFX_WIDTH << 1); \ z = x + (GFX_WIDTH << 2); \ for (p = p0; w--; ) { \ c = rgb_palette[*p++]; \ putpixel_##d## (screen_buffer, x++, c); \ putpixel_##d## (screen_buffer, x++, c); \ putpixel_##d## (screen_buffer, y++, c); \ putpixel_##d## (screen_buffer, y++, c); \ } \ for (p = p0; extra--; ) { \ c = rgb_palette[*p++]; \ putpixel_##d## (screen_buffer, z++, c); \ putpixel_##d## (screen_buffer, z++, c); \ } \ } _putpixels_fixratio_scale1 (8); _putpixels_fixratio_scale1 (16); _putpixels_fixratio_scale1 (32); #if 0 /* Don't need these for MacOS */ _putpixels_fixratio_scale2 (8); _putpixels_fixratio_scale2 (16); _putpixels_fixratio_scale2 (32); #endif /* ===================================================================== */ static int set_palette (UINT8 *pal, int scol, int numcols) { int i; for (i = scol; i < scol + numcols; i++) { switch (depth) { #if 0 case 8: rgb_palette[i] = color[i].pixel; break; #endif case 15: rgb_palette[i] = ((int)(pal[i * 3] & 0x3e) << 9) | ((int)(pal[i * 3 + 1] & 0x3e) << 4) | ((int)(pal[i * 3 + 2] & 0x3e) >> 1); break; case 16: rgb_palette[i] = ((int)(pal[i * 3] & 0x3e) << 10) | ((int)(pal[i * 3 + 1] & 0x3f) << 5) | ((int)(pal[i * 3 + 2] & 0x3e) >> 1); break; case 24: rgb_palette[i] = ((int) pal[i * 3] << 18) | ((int) pal[i * 3 + 1] << 10) | ((int)pal[i * 3 + 2]) << 2; break; } } return err_OK; } static void process_events () { WindowPtr win; EventRecord event; Rect drag_rect; SystemTask(); if (WaitNextEvent (everyEvent, &event, 5L, NULL)) { switch (event.what) { case mouseDown: switch (FindWindow(event.where, &win)) { case inSysWindow: /* desk accessory window: call Desk Manager * to handle it */ SystemClick (&event, win); break; case inMenuBar: /* Menu bar: learn which command, then * execute it. */ /*DoCommand(MenuSelect(event.where));*/ break; case inDrag: /* title bar: call Window Manager to drag */ DragWindow (win, event.where, &drag_rect); break; case inContent: /* body of application window: * make it active if not */ if (win != FrontWindow()) SelectWindow (win); break; } break; case updateEvt: /* Update window. */ if ((WindowPtr) event.message == window) { BeginUpdate((WindowPtr) event.message); /* repaint */ EndUpdate((WindowPtr) event.message); } break; case keyDown: case autoKey: /* key pressed once or held down to repeat */ if (window == FrontWindow()) { int c = (event.message & charCodeMask); key_enqueue (c); } break; } } } static unsigned long delta () { unsigned long dt; UnsignedWide a; static UnsignedWide b; Microseconds (&a); if (a.hi > b.hi) { dt = (0xffffffff - (b.lo - a.lo)) / 1000; } else { dt = (a.lo - b.lo) / 1000; } b.lo = a.lo; b.hi = a.hi; return dt; } static void macos_timer () { while (delta () < 42) { /* usleep (5000); */ } process_events (); } static int macos_init_vidmode () { OSErr error; Rect window_rect; Rect gworld_rect; GDHandle old_gd; GWorldPtr old_gw; SysEnvRec theWorld; error = SysEnvirons (1, &theWorld); if (theWorld.hasColorQD == false) return -1; /* Initialize all the needed managers. */ InitGraf (&qd.thePort); InitFonts (); InitWindows (); InitMenus (); TEInit (); InitDialogs (nil); InitCursor (); /* Set palette */ set_palette (palette, 0, 32); /* Create offscreen pixmap */ SetRect (&gworld_rect, 0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1); GetGWorld (&old_gw, &old_gd); if (NewGWorld (&gworld, depth, &gworld_rect, NULL, NULL, 0) != noErr) return -1; SetGWorld (gworld, NULL); BackColor (blackColor); EraseRect (&gworld->portRect); SetGWorld (old_gw, old_gd); /* Set optimized put_pixels handler */ gfx_macos.put_pixels = _putpixels_16bits_scale1; /* Create window */ SetRect (&window_rect, 50, 50, 50 + GFX_WIDTH - 1, 50 + GFX_HEIGHT - 1); window = NewCWindow (NULL, &window_rect, "\pSarien", true, noGrowDocProc, (WindowPtr) -1, false, NULL); /* Initialize pixmap pointers */ pix = GetGWorldPixMap (gworld); LockPixels (pix); wpix = ((CGrafPort *)window)->portPixMap; //bpl = (*wpix)->rowBytes & 0x3fff; screen_buffer = (UINT8 *)GetPixBaseAddr(pix); /* set window to current graf port */ SetPort (window); /* CopyBits needs these */ ForeColor (blackColor); BackColor (whiteColor); return err_OK; } static int macos_deinit_vidmode () { UnlockPixels (pix); DisposePtr ((char *) gworld); DisposeWindow (window); return err_OK; } /* blit a block onto the screen */ static void macos_put_block (int x1, int y1, int x2, int y2) { Rect r; if (x1 >= GFX_WIDTH) x1 = GFX_WIDTH - 1; if (y1 >= GFX_HEIGHT) y1 = GFX_HEIGHT - 1; if (x2 >= GFX_WIDTH) x2 = GFX_WIDTH - 1; if (y2 >= GFX_HEIGHT) y2 = GFX_HEIGHT - 1; //SetRect (&r, x1, y1, x2, y2); SetRect (&r, 0, 0, 319, 199); CopyBits ((BitMap *)*pix, (BitMap *)*wpix, &r, &r, srcCopy, 0L); } static int macos_keypress () { process_events (); return key_queue_start != key_queue_end; } static int macos_get_key () { UINT16 k; while (key_queue_start == key_queue_end) /* block */ macos_timer (); key_dequeue(k); return k; }