From ce46866403fdcc479cf9d67e4d430409b15dadc3 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 21 Aug 2002 16:07:07 +0000 Subject: Initial revision svn-id: r4785 --- backends/mac/Carbon.r | 111 +++ backends/mac/CarbonPort-ReadMe.txt | 34 + backends/mac/mac.cpp | 1790 ++++++++++++++++++++++++++++++++++++ backends/mac/macos.h | 24 + backends/mac/scummvm.icns | Bin 0 -> 38332 bytes backends/mac/scummvm.mcp | Bin 0 -> 158716 bytes 6 files changed, 1959 insertions(+) create mode 100644 backends/mac/Carbon.r create mode 100644 backends/mac/CarbonPort-ReadMe.txt create mode 100644 backends/mac/mac.cpp create mode 100644 backends/mac/macos.h create mode 100644 backends/mac/scummvm.icns create mode 100644 backends/mac/scummvm.mcp (limited to 'backends/mac') diff --git a/backends/mac/Carbon.r b/backends/mac/Carbon.r new file mode 100644 index 0000000000..a296c97b26 --- /dev/null +++ b/backends/mac/Carbon.r @@ -0,0 +1,111 @@ +/* + * Permit this Carbon application to launch on OS X + * + * © 1997-2000 Metrowerks Corp. + * + * Questions and comments to: + * + * + */ + +#include "MacTypes.r" +#include "Dialogs.r" +#include "Balloons.r" +#include "Menus.r" +#include "Finder.r" +#include "Quickdraw.r" +#include "Icons.r" +#include "Processes.r" +#include "Controls.r" + +/*----------------------------carb ¥ Carbon on OS X launch information --------------------------*/ +type 'carb' { +}; + + +resource 'carb'(0) { +}; + +resource 'ALRT' (129) { + {55, 39, 153, 407}, + 128, + { /* array: 4 elements */ + /* [1] */ + OK, visible, sound1, + /* [2] */ + OK, visible, sound1, + /* [3] */ + OK, visible, sound1, + /* [4] */ + OK, visible, sound1 + }, + alertPositionParentWindowScreen +}; + +resource 'DITL'(128) { + { + {8, 74, 61, 356}, + StaticText { + disabled, + "^0" + }, + + {70, 299, 90, 357}, + Button { + enabled, + "OK" + } + } +}; + +resource 'MENU'(999) { + 999, 63, allEnabled, enabled, "Please Select a GameÉ", + { + "Maniac Mansion (C64)", noIcon, noKey, noMark, plain, + "Zak McKracken and the Alien Mindbenders (C64)", noIcon, noKey, noMark, plain, + "Maniac Mansion", noIcon, noKey, noMark, plain, + "Zak McKracken and the Alien Mindbenders", noIcon, noKey, noMark, plain, + "Indiana Jones and the Last Crusade", noIcon, noKey, noMark, plain, + "Indiana Jones and the Last Crusade (256)", noIcon, noKey, noMark, plain, + "Zak McKracken and the Alien Mindbenders (256)", noIcon, noKey, noMark, plain, + "Loom", noIcon, noKey, noMark, plain, + "Monkey Island 1 (EGA)", noIcon, noKey, noMark, plain, + "Monkey Island 1 (256 color Floppy version)", noIcon, noKey, noMark, plain, + "Loom (256 color CD version)", noIcon, noKey, noMark, plain, + "Monkey Island 1", noIcon, noKey, noMark, plain, + "Monkey Island 1 (alt)", noIcon, noKey, noMark, plain, + "Monkey Island 2: LeChuck's revenge", noIcon, noKey, noMark, plain, + "Indiana Jones 4 and the Fate of Atlantis", noIcon, noKey, noMark, plain, + "Indiana Jones 4 and the Fate of Atlantis (Demo)", noIcon, noKey, noMark, plain, + "Day Of The Tentacle", noIcon, noKey, noMark, plain, + "Day Of The Tentacle (Demo)", noIcon, noKey, noMark, plain, + "Sam & Max", noIcon, noKey, noMark, plain, + "Sam & Max (Demo)", noIcon, noKey, noMark, plain, + "Full Throttle", noIcon, noKey, noMark, plain, + "The Dig", noIcon, noKey, noMark, plain, + "The Curse of Monkey Island", noIcon, noKey, noMark, plain, + "-", noIcon, noKey, noMark, plain, + "Simon the Sorcerer 1 (DOS)", noIcon, noKey, noMark, plain, + "Simon the Sorcerer 1 (Windows)", noIcon, noKey, noMark, plain, + "Simon the Sorcerer 2 (Windows)", noIcon, noKey, noMark, plain + } +}; + +resource 'MENU'(1000) { + 1000, 63, allEnabled, enabled, apple, + { + "About ScummVMÉ", noIcon, noKey, noMark, plain, + "-", noIcon, noKey, noMark, plain + } +}; + +resource 'MENU'(1001) { + 1001, 63, allEnabled, enabled, "File", + { + "New Game", noIcon, "N", noMark, plain, + "Open Game", noIcon, "O", noMark, plain, + "Save Game", noIcon, "S", noMark, plain, + "-", noIcon, noKey, noMark, plain, + "Q", noIcon, "Q", noMark, plain + } +}; \ No newline at end of file diff --git a/backends/mac/CarbonPort-ReadMe.txt b/backends/mac/CarbonPort-ReadMe.txt new file mode 100644 index 0000000000..262b9a50f8 --- /dev/null +++ b/backends/mac/CarbonPort-ReadMe.txt @@ -0,0 +1,34 @@ +README FOR THE MAC CARBON PORT + +Runs on Mac OS X 10.1 (could also run on 10.0.x, but not tested), and Mac OS 8.6 or later (with CarbonLib +installed). + +HOW TO COMPILE? +Launch the scummvm.mcp file in CodeWarrior and choose one of the Targets to compile. For just playing, +you should choose "ScummVM Final", the Debug one is just for Developing. +Binaries will come up to the Website with the release 0.2.0, which will be hopefully soon. + +NOTES: +Put the games in a folder in the same directory as ScummVM, which have the name of the Data Files, like this: + +-- - ScummVM + \- monkey2- + \- monkey2.000 + - monkey2.001 + + +Hope this will help you :) + +CHANGES: +- Thanks to Florent Boudet, QuickTime MIDI has been added, although it currently only works with DOTT +- Added SFX Sound Support +- Now draws the Games Cursors + +BUGS: +- On OS X it got some Problems with KeyDown-Events (seems to work now, most of the time) +- Bad behaviour of the Application towards other, will be fixed soon. +- Some minor bugs + +If you find any bugs, just make a Bug Report on our SourceForge Page. + +-- Mutle \ No newline at end of file diff --git a/backends/mac/mac.cpp b/backends/mac/mac.cpp new file mode 100644 index 0000000000..f22d72666b --- /dev/null +++ b/backends/mac/mac.cpp @@ -0,0 +1,1790 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001/2002 Mutwin Kraus (Mac Port) and The ScummVM Project + * + * 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; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#include +#include + +#include "stdafx.h" +#include "scumm.h" +#include "mididrv.h" +#include "gameDetector.h" +//#include "mp3_cd.h" +#include "gui.h" +//#include "gameDetector.h" +#include "scaler.h" + +#define MAX(a,b) (((a)<(b)) ? (b) : (a)) +#define MIN(a,b) (((a)>(b)) ? (b) : (a)) + +class OSystem_MAC : public OSystem { +public: + // Set colors of the palette + void set_palette(const byte *colors, uint start, uint num); + + // Set the size of the video bitmap. + // Typically, 320x200 + void init_size(uint w, uint h); + + // Draw a bitmap to screen. + // The screen will not be updated to reflect the new bitmap + void copy_rect(const byte *buf, int pitch, int x, int y, int w, int h); + + // Update the dirty areas of the screen + void update_screen(); + + // Either show or hide the mouse cursor + bool show_mouse(bool visible); + + // Set the position of the mouse cursor + void set_mouse_pos(int x, int y); + + // Set the bitmap that's used when drawing the cursor. + void set_mouse_cursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y); + + // Shaking is used in SCUMM. Set current shake position. + void set_shake_pos(int shake_pos); + + // Get the number of milliseconds since the program was started. + uint32 get_msecs(); + + // Delay for a specified amount of milliseconds + void delay_msecs(uint msecs); + + // Create a thread + void *create_thread(ThreadProc *proc, void *param); + + // Get the next event. + // Returns true if an event was retrieved. + bool poll_event(Event *event); + + // Set function that generates samples + bool set_sound_proc(void *param, SoundProc *proc, byte sound); + + // Poll cdrom status + // Returns true if cd audio is playing + bool poll_cdrom(); + + // Play cdrom audio track + void play_cdrom(int track, int num_loops, int start_frame, int end_frame); + + // Stop cdrom audio track + void stop_cdrom(); + + // Update cdrom audio status + void update_cdrom(); + + // Add a new callback timer + void set_timer(int timer, int (*callback)(int)) { /* FIXME - TODO */ } + + // Mutex handling + void *create_mutex(void) { return NULL; /* FIXME - TODO */ } + void lock_mutex(void *mutex) { /* FIXME - TODO */ } + void unlock_mutex(void *mutex) { /* FIXME - TODO */ } + void delete_mutex(void *mutex) { /* FIXME - TODO */ } + + // Quit + void quit(); + + // Set a parameter + uint32 property(int param, Property *value); + + static OSystem *create(int gfx_mode, bool full_screen); + + void sound_callback(SndChannel *chan, SndCommand *cmd_passed); +private: + typedef void TwoXSaiProc(uint8 *srcPtr, uint32 srcPitch, uint8 *deltaPtr, + uint8 *dstPtr, uint32 dstPitch, int width, int height); + + GWorldPtr screenBuf; + WindowRef wref; + CTabHandle pal; + Rect blit_rect; + + enum { + DF_WANT_RECT_OPTIM = 1 << 0, + DF_REAL_8BIT = 1 << 1, + DF_SEPARATE_TEMPSCREEN = 1 << 2, + DF_UPDATE_EXPAND_1_PIXEL = 1 << 3 + }; + + int _mode; + bool _full_screen; + bool _mouse_visible; + bool _mouse_drawn; + uint32 _mode_flags; + byte _internal_scaling; + + bool force_full; //Force full redraw on next update_screen + bool cksum_valid; + + enum { + NUM_DIRTY_RECT = 100, + + MAX_MOUSE_W = 40, + MAX_MOUSE_H = 40, + MAX_SCALING = 3 + }; + + int SCREEN_WIDTH, SCREEN_HEIGHT, CKSUM_NUM; + Rect *dirty_rect_list; + int num_dirty_rects; + uint32 *dirty_checksums; + + int scaling; + + /* CD Audio */ + int cd_track, cd_num_loops, cd_start_frame, cd_end_frame; + uint32 cd_end_time, cd_stop_time, cd_next_second; + + struct MousePos { + int16 x,y,w,h; + }; + + byte *_ms_buf; + byte *_ms_backup; + MousePos _ms_cur; + MousePos _ms_old; + int16 _ms_hotspot_x; + int16 _ms_hotspot_y; + int _current_shake_pos; + + byte* _gfx_buf; /* Graphics memory */ + int16 *_sai_buf, *_tmp_buf; + uint _palette_changed_first, _palette_changed_last; + + TwoXSaiProc *_sai_func; + + void add_dirty_rgn_auto(const byte *buf); + void mk_checksums(const byte *buf); + + static void fill_sound(void *userdata, uint8 * stream, int len); + + void add_dirty_rect(int x, int y, int w, int h); + + void draw_mouse(); + void undraw_mouse(); + + void load_gfx_mode(); + void unload_gfx_mode(); + + void hotswap_gfx_mode(); + + void get_320x200_image(byte *buf); + + void init_mac_stuff(); + void set_scaling(); + void blit_to_screen(); + void update_rects(); + + static void autosave(Scumm * scumm); + + UInt8 *buffer[2]; + CmpSoundHeader header; + SndChannelPtr channel; + int size; + SoundProc *sndProc; + void * parameter; +}; + +KeyMap fKeyMap; + +Boolean CommandKeyDown() +{ + GetKeys(fKeyMap); // get info + if (fKeyMap[1] & 0x8000) + return true; + else + return false; +} + +static unsigned char *CToPascal(char *str) { + register char *p,*q; + register long len; + + len = strlen(str); + if (len > 255) len = 255; + p = str + len; + q = p-1; + while (p != str) + *p-- = *q--; + *str = len; + return((unsigned char *)str); +} + +static char *PascalToC(unsigned char *str) { + register unsigned char *p,*q,*end; + + end = str + *str; + q = (p=str) + 1; + + while (p < end) + *p++ = *q++; + *p = '\0'; + + return((char *)str); +} + +const EventTypeSpec kCmdEvents[] = +{ + { kEventClassMouse, kEventMouseDown }, + { kEventClassMouse, kEventMouseUp }, + { kEventClassMouse, kEventMouseMoved }, + { kEventClassKeyboard, kEventRawKeyDown }, + { kEventClassCommand, kEventProcessCommand } +}; + +const EventTypeSpec kWindowEvents[] = +{ + { kEventClassWindow, kEventWindowDrawContent }, + { kEventClassWindow, kEventWindowHandleContentClick }, + { kEventClassWindow, kEventWindowClose } +}; + +pascal OSErr QuitEventHandler(const AppleEvent *theEvent, AppleEvent *theReply, SInt32 refCon) +{ + //OSystem_MAC::quit(); + return(noErr); +} + +enum +{ + kNewGameCmd = 'newG', + kQuitCmd = kHICommandQuit, + kOpenGameCmd = 'opnG', + kSaveGameCmd = 'savG', + kPrefsCmd = kHICommandPreferences, + kAboutCmd = 'abtG' +}; + +ControlRef radioGroupRef, musicVolumeSlider, masterVolumeSlider; +char *gameTitle; +ControlRef popUpControlRef, checkBoxControlRef; + +OSStatus prefsEventHandler(EventHandlerCallRef eventHandlerCallRef,EventRef eventRef, + void *userData) +{ + OSStatus result = eventNotHandledErr; + UInt32 eventClass; + UInt32 eventKind; + ControlRef controlRef; + ControlID controlID; + + eventClass = GetEventClass(eventRef); + eventKind = GetEventKind(eventRef); + + if(eventClass == kEventClassControl) + { + if(eventKind == kEventControlHit) + { + GetEventParameter(eventRef,kEventParamDirectObject,typeControlRef,NULL, + sizeof(ControlRef),NULL,&controlRef); + + GetControlID(controlRef,&controlID); + if(controlID.id == 'okay') + { + /*scumm->_noSubtitles = (Boolean)!GetControlValue(checkBoxControlRef); + short scale = GetControlValue(radioGroupRef); + if(scale != scumm->_scale) + wm->ChangeScaling(scale); + short music_vol = GetControlValue(musicVolumeSlider); + if(music_vol != sound.get_music_volume()) + sound.set_music_volume(music_vol); + short master_vol = GetControlValue(masterVolumeSlider); + if(master_vol != sound.get_master_volume()) + sound.set_master_volume(master_vol);*/ + QuitAppModalLoopForWindow((WindowRef)userData); + DisposeWindow((WindowRef)userData); + result = noErr; + } + } + } +} + +void Preferences() +{ + WindowRef prefsWin; + OSStatus osError = noErr; + Rect rect = { 0,0,210,300 }; + Rect okButtonRect; + ControlID controlID; + ControlRef controlRef; + EventTypeSpec dialogEvents[] = { kEventClassControl, kEventControlHit }; + + osError = CreateNewWindow(kMovableModalWindowClass,kWindowStandardHandlerAttribute,&rect, &prefsWin); + SetWTitle(prefsWin, "\pPreferences"); + RepositionWindow(prefsWin,FrontWindow(),kWindowAlertPositionOnMainScreen); + SetThemeWindowBackground(prefsWin,kThemeBrushDialogBackgroundActive,false); + CreateRootControl(prefsWin,&controlRef); + + SetRect(&rect, 5, 5, 150, 21); + + CreateStaticTextControl(prefsWin, &rect, CFSTR("ScummVM Preferences"), NULL, &controlRef); + AutoEmbedControl(controlRef, prefsWin); + + SetRect(&okButtonRect, 225, 180, 295, 200); + + CreatePushButtonControl(prefsWin,&okButtonRect,CFSTR("OK"),&controlRef); + SetWindowDefaultButton(prefsWin,controlRef); + controlID.id = 'okay'; + SetControlID(controlRef,&controlID); + AutoEmbedControl(controlRef,prefsWin); + + SetRect(&rect, 150, 35, 260, 51); + + CreateCheckBoxControl(prefsWin,&rect, CFSTR("Subtitles"), 1, true, &checkBoxControlRef); + AutoEmbedControl(checkBoxControlRef, prefsWin); + + //if(scumm->_noSubtitles) + SetControlValue(checkBoxControlRef, false); + + OffsetRect(&rect, 0, 20); + + CreateCheckBoxControl(prefsWin,&rect, CFSTR("Fullscreen"), 0, true, &controlRef); + AutoEmbedControl(controlRef, prefsWin); + DeactivateControl(controlRef); + + Rect RadioGroupRect; + SetRect(&RadioGroupRect, 5, 35, 120, 100); + CreateRadioGroupControl(prefsWin, &RadioGroupRect, &radioGroupRef); + AutoEmbedControl(radioGroupRef, prefsWin); + + ControlRef radioButton; + + Rect RadioButtonRect; + SetRect(&RadioButtonRect, 5, 35, 120, 51); + CreateRadioButtonControl(prefsWin, &RadioButtonRect, CFSTR("Scaling 1x"), 0, true, &radioButton); + AutoEmbedControl(radioButton, prefsWin); + + OffsetRect(&RadioButtonRect, 0, 20); + CreateRadioButtonControl(prefsWin, &RadioButtonRect, CFSTR("Scaling 2x"), 0, true, &radioButton); + AutoEmbedControl(radioButton, prefsWin); + + OffsetRect(&RadioButtonRect, 0, 20); + CreateRadioButtonControl(prefsWin, &RadioButtonRect, CFSTR("Scaling 3x"), 0, true, &radioButton); + AutoEmbedControl(radioButton, prefsWin); + + //SetControlValue(radioGroupRef, scumm->_scale); + + SetRect(&rect, 5, 110, 175, 146); + + CreateSliderControl(prefsWin, &rect, 100, 1, 100, + kControlSliderPointsDownOrRight, 10, false, NULL, &musicVolumeSlider); + AutoEmbedControl(musicVolumeSlider, prefsWin); + + OffsetRect(&rect, 0, 36); + + CreateSliderControl(prefsWin, &rect, 100, 1, 100, + kControlSliderPointsDownOrRight, 10, false, NULL, &masterVolumeSlider); + AutoEmbedControl(masterVolumeSlider, prefsWin); + + OffsetRect(&rect, 180, -36); + + CreateStaticTextControl(prefsWin, &rect, CFSTR("Music Volume"), NULL, &controlRef); + AutoEmbedControl(controlRef, prefsWin); + + OffsetRect(&rect, 0, 36); + + CreateStaticTextControl(prefsWin, &rect, CFSTR("Master Volume"), NULL, &controlRef); + AutoEmbedControl(controlRef, prefsWin); + + InstallWindowEventHandler(prefsWin, NewEventHandlerUPP((EventHandlerProcPtr) prefsEventHandler), + GetEventTypeCount(dialogEvents),dialogEvents,prefsWin,NULL); + ShowWindow(prefsWin); + osError = RunAppModalLoopForWindow(prefsWin); +} + +void LaunchGame(int id) +{ + switch(id) + { + case 6: + gameTitle = "indy3"; + break; + + case 7: + gameTitle = "zak256"; + break; + + case 8: + gameTitle = "loom"; + break; + + case 9: + gameTitle = "monkeyEGA"; + break; + + case 10: + gameTitle = "monkeyVGA"; + break; + + case 11: + gameTitle = "loomcd"; + break; + + case 12: + gameTitle = "monkey"; + break; + + case 13: + gameTitle = "monkey1"; + break; + + case 14: + gameTitle = "monkey2"; + break; + + case 15: + gameTitle = "atlantis"; + break; + + case 16: + gameTitle = "playfate"; + break; + + case 17: + gameTitle = "tentacle"; + break; + + case 18: + gameTitle = "dottdemo"; + break; + + case 19: + gameTitle = "samnmax"; + break; + + case 20: + gameTitle = "snmdemo"; + break; + + case 21: + gameTitle = "ft"; + break; + + case 22: + gameTitle = "dig"; + break; + + case 25: + gameTitle = "simon1dos"; + break; + + case 26: + gameTitle = "simon1win"; + break; + + case 27: + gameTitle = "simon2win"; + break; + } +} + +OSStatus dialogEventHandler(EventHandlerCallRef eventHandlerCallRef,EventRef eventRef, + void *userData) +{ + OSStatus result = eventNotHandledErr; + UInt32 eventClass; + UInt32 eventKind; + ControlRef controlRef; + ControlID controlID; + + eventClass = GetEventClass(eventRef); + eventKind = GetEventKind(eventRef); + + if(eventClass == kEventClassControl) + { + if(eventKind == kEventControlHit) + { + + GetEventParameter(eventRef,kEventParamDirectObject,typeControlRef,NULL, + sizeof(ControlRef),NULL,&controlRef); + + GetControlID(controlRef,&controlID); + if(controlID.id == 'okay') + { + QuitAppModalLoopForWindow((WindowRef)userData); + LaunchGame(GetControlValue(popUpControlRef)); + + DisposeWindow((WindowRef)userData); + result = noErr; + } + else if(controlID.id == 'cncl') + { + QuitAppModalLoopForWindow((WindowRef)userData); + DisposeWindow((WindowRef)userData); + ExitToShell(); + } + } + } + return result; +} + +char* SelectGame() +{ + WindowRef aboutWin; + OSStatus osError = noErr; + Rect rect = { 0,0,120,350 }; + Rect pushButtonRect = { 75,250,96,330 }; + Rect popupRect = { 10, 10, 26, 330 }; + ControlID controlID; + ControlRef controlRef; + Rect checkboxRect = { 36, 10, 50, 80 }; + EventTypeSpec dialogEvents[] = { kEventClassControl, kEventControlHit }; + + InitCursor(); + + SIOUXSettings.autocloseonquit = true; + SIOUXSettings.asktosaveonclose = false; + SIOUXSettings.showstatusline = false; + SIOUXSettings.fontsize = 9; + GetFNum("\pMonaco",&SIOUXSettings.fontid); + SIOUXSettings.standalone = false; + SIOUXSettings.setupmenus = false; + SIOUXSettings.toppixel = 40; + SIOUXSettings.leftpixel = 5; + + osError = CreateNewWindow(kMovableModalWindowClass,kWindowStandardHandlerAttribute,&rect, &aboutWin); + SetWTitle(aboutWin, "\pPlease Select a GameÉ"); + RepositionWindow(aboutWin,FrontWindow(),kWindowAlertPositionOnMainScreen); + SetThemeWindowBackground(aboutWin,kThemeBrushDialogBackgroundActive,false); + CreateRootControl(aboutWin,&controlRef); + + CreatePushButtonControl(aboutWin,&pushButtonRect,CFSTR("OK"),&controlRef); + SetWindowDefaultButton(aboutWin,controlRef); + controlID.id = 'okay'; + SetControlID(controlRef,&controlID); + AutoEmbedControl(controlRef,aboutWin); + + OffsetRect(&pushButtonRect, -100, 0); + CreatePushButtonControl(aboutWin,&pushButtonRect,CFSTR("Cancel"),&controlRef); + SetWindowCancelButton(aboutWin,controlRef); + controlID.id = 'cncl'; + SetControlID(controlRef,&controlID); + AutoEmbedControl(controlRef,aboutWin); + + CreatePopupButtonControl(aboutWin, &popupRect, CFSTR("Game: "), 999, false, -1, 0, NULL, &popUpControlRef); + SetWindowDefaultButton(aboutWin,popUpControlRef); + controlID.id = 'game'; + + SetControlID(popUpControlRef,&controlID); + + AutoEmbedControl(controlRef,aboutWin); + + InstallWindowEventHandler(aboutWin, NewEventHandlerUPP((EventHandlerProcPtr) dialogEventHandler), + GetEventTypeCount(dialogEvents),dialogEvents,aboutWin,NULL); + ShowWindow(aboutWin); + osError = RunAppModalLoopForWindow(aboutWin); + return gameTitle; +} + +OSystem *OSystem_MAC::create(int gfx_mode, bool full_screen) { + Rect rectWin; + OSystem_MAC *syst = new OSystem_MAC(); + syst->_mode = gfx_mode; + syst->_full_screen = full_screen; + + /* Macintosh init */ + syst->init_mac_stuff(); + + return syst; +} + +void OSystem_MAC::autosave(Scumm * scumm) +{ + scumm->_doAutosave = true; + + return interval; +} + +OSystem *OSystem_MAC_create(int gfx_mode, bool full_screen) { + return OSystem_MAC::create(gfx_mode, full_screen); +} + +void OSystem_MAC::set_palette(const byte *colors, uint start, uint num) { + const byte *b = colors; + + (*pal)->ctSeed = TickCount(); + for(int i = start; i < num; i++, b += 4) { + (*pal)->ctTable[i].value = i; + (*pal)->ctTable[i].rgb.red = b[0]<<8; + (*pal)->ctTable[i].rgb.green = b[1]<<8; + (*pal)->ctTable[i].rgb.blue = b[2]<<8; + } + + CTabChanged(pal); + + if(_sai_func) + UpdateGWorld(&screenBuf, 16, &blit_rect, NULL, NULL, 0); + else + UpdateGWorld(&screenBuf, 8, &blit_rect, pal, NULL, 0); + + if(start < _palette_changed_first) + _palette_changed_first = start; + + if(start + num > _palette_changed_last) + _palette_changed_last = start + num; +} + +void OSystem_MAC::load_gfx_mode() { + force_full = true; + scaling = 1; + _internal_scaling = 1; + _mode_flags = 0; + _sai_func = NULL; + + switch(_mode) { + case GFX_2XSAI: + _sai_func = _2xSaI; + break; + + case GFX_SUPER2XSAI: + _sai_func = Super2xSaI; + break; + + case GFX_SUPEREAGLE: + _sai_func = SuperEagle; + break; + + case GFX_ADVMAME2X: + _sai_func = AdvMame2x; + break; + + case GFX_DOUBLESIZE: + scaling = 2; + _internal_scaling = 2; + _mode_flags = DF_WANT_RECT_OPTIM; + break; + + case GFX_TRIPLESIZE: + if (_full_screen) { + warning("full screen in useless in triplesize mode, reverting to normal mode"); + goto normal_mode; + } + scaling = 3; + _internal_scaling = 3; + _mode_flags = DF_WANT_RECT_OPTIM; + break; + + case GFX_NORMAL: + normal_mode:; + _mode_flags = DF_WANT_RECT_OPTIM; + break; + + } + + if(_sai_func) + { + _mode_flags = DF_WANT_RECT_OPTIM | DF_SEPARATE_TEMPSCREEN | DF_UPDATE_EXPAND_1_PIXEL; + + Init_2xSaI(565); + _tmp_buf = (int16*)calloc((SCREEN_WIDTH+3)*(SCREEN_HEIGHT+3), sizeof(int16)); + + scaling = 2; + } + else + { + switch(scaling) { + case 3: + _sai_func = Normal3x; + break; + case 2: + _sai_func = Normal2x; + break; + case 1: + _sai_func = Normal1x; + break; + } + + _mode_flags = DF_WANT_RECT_OPTIM | DF_REAL_8BIT; + } + + set_scaling(); +} + +void OSystem_MAC::unload_gfx_mode() { + //warning("STUB: unload_gfx_mode()"); /* FIXME: Must free data here */ + +} + +void OSystem_MAC::init_size(uint w, uint h) { + //if (w != SCREEN_WIDTH && h != SCREEN_HEIGHT) + // error("320x200 is the only game resolution supported"); + + SCREEN_WIDTH = w; + SCREEN_HEIGHT = h; + CKSUM_NUM = (SCREEN_WIDTH * SCREEN_HEIGHT / (8*8)); + dirty_rect_list = (Rect*)calloc(NUM_DIRTY_RECT, sizeof(Rect)); + _ms_backup = (byte*)malloc(MAX_MOUSE_W * MAX_MOUSE_H * MAX_SCALING); + dirty_checksums = (uint32*)calloc(CKSUM_NUM*2, sizeof(uint32)); + + load_gfx_mode(); +} + +void OSystem_MAC::copy_rect(const byte *buf, int pitch, int x, int y, int w, int h) { + if (pitch == SCREEN_WIDTH && x==0 && y==0 && w==SCREEN_WIDTH && h==SCREEN_HEIGHT && _mode_flags&DF_WANT_RECT_OPTIM) { + /* Special, optimized case for full screen updates. + * It tries to determine what areas were actually changed, + * and just updates those, on the actual display. */ + add_dirty_rgn_auto(buf); + } else { + /* Clip the coordinates */ + if (x < 0) { w+=x; buf-=x; x = 0; } + + if (y < 0) { h+=y; buf-=y*pitch; y = 0; } + if (w >= SCREEN_WIDTH-x) { w = SCREEN_WIDTH - x; } + if (h >= SCREEN_HEIGHT-y) { h = SCREEN_HEIGHT - y; } + + if (w<=0 || h<=0) + return; + + cksum_valid = false; + add_dirty_rect(x, y, w, h); + } + + /* FIXME: undraw mouse only if the draw rect intersects with the mouse rect */ + if (_mouse_drawn) + undraw_mouse(); + + byte *dst = (byte*)buf + y * SCREEN_WIDTH + x; + do { + memcpy(dst, buf, w); + dst += SCREEN_WIDTH; + buf += pitch; + } while(--h); +} + +void OSystem_MAC::add_dirty_rect(int x, int y, int w, int h) { + if (force_full) + return; + + if (num_dirty_rects == NUM_DIRTY_RECT) + force_full = true; + else { + Rect *r = &dirty_rect_list[num_dirty_rects++]; + + /* Update the dirty region by 1 pixel for graphics drivers + * that "smear" the screen */ + if (_mode_flags & DF_UPDATE_EXPAND_1_PIXEL) { + x--; + y--; + w+=2; + h+=2; + } + + /* clip */ + if (x<0) { w+=x; x=0; } + if (y<0) { h+=y; y=0; } + if (w>=SCREEN_WIDTH-x) { w=SCREEN_WIDTH-x; } + if (h>=SCREEN_HEIGHT-y) { h=SCREEN_HEIGHT-y; } + + if (_internal_scaling != 1) { + x *= _internal_scaling; + y *= _internal_scaling; + w *= _internal_scaling; + h *= _internal_scaling; + } + + r->left = x; + r->top = y; + r->right = x + w; + r->bottom = y + h; + } +} + +#define ROL(a,n) a = (a<<(n)) | (a>>(32-(n))) +#define DOLINE(x) a ^= ((uint32*)buf)[0+(x)*(SCREEN_WIDTH/4)]; b ^= ((uint32*)buf)[1+(x)*(SCREEN_WIDTH/4)] +void OSystem_MAC::mk_checksums(const byte *buf) { + uint32 *sums = dirty_checksums; + uint x,y; + + /* the 8x8 blocks in buf are enumerated starting in the top left corner and + * reading each line at a time from left to right */ + for(y=0; y!=SCREEN_HEIGHT/8; y++,buf+=SCREEN_WIDTH*(8-1)) + for(x=0; x!=SCREEN_WIDTH/8; x++,buf+=8) { + uint32 a = x; + uint32 b = y; + + DOLINE(0); ROL(a,13); ROL(b,11); + DOLINE(2); ROL(a,13); ROL(b,11); + DOLINE(4); ROL(a,13); ROL(b,11); + DOLINE(6); ROL(a,13); ROL(b,11); + + a*=0xDEADBEEF; + b*=0xBAADF00D; + + DOLINE(1); ROL(a,13); ROL(b,11); + DOLINE(3); ROL(a,13); ROL(b,11); + DOLINE(5); ROL(a,13); ROL(b,11); + DOLINE(7); ROL(a,13); ROL(b,11); + + /* output the checksum for this block */ + *sums++=a+b; + } +} +#undef DOLINE +#undef ROL + + +void OSystem_MAC::add_dirty_rgn_auto(const byte *buf) { + assert( ((uint32)buf & 3) == 0); + + /* generate a table of the checksums */ + mk_checksums(buf); + +if (!cksum_valid) { + force_full = true; + cksum_valid = true; + } + + /* go through the checksum list, compare it with the previous checksums, + and add all dirty rectangles to a list. try to combine small rectangles + into bigger ones in a simple way */ + if (!force_full) { + uint x,y,w; + uint32 *ck = dirty_checksums; + + for(y=0; y!=SCREEN_HEIGHT/8; y++) { + for(x=0; x!=SCREEN_WIDTH/8; x++,ck++) { + if (ck[0] != ck[CKSUM_NUM]) { + /* found a dirty 8x8 block, now go as far to the right as possible, + and at the same time, unmark the dirty status by setting old to new. */ + w=0; + do { + ck[w+CKSUM_NUM] = ck[w]; + w++; + } while (x+w != SCREEN_WIDTH/8 && ck[w] != ck[w+CKSUM_NUM]); + + add_dirty_rect(x*8, y*8, w*8, 8); + + if (force_full) + goto get_out; + } + } + } + } else { + get_out:; + /* Copy old checksums to new */ + memcpy(dirty_checksums + CKSUM_NUM, dirty_checksums, CKSUM_NUM * sizeof(uint32)); + } +} + +void OSystem_MAC::update_screen() { +#if 0 + /* First make sure the mouse is drawn, if it should be drawn. */ + draw_mouse(); + + if (_palette_changed_last != 0) { + //warning("MAC: Palette should be uploaded!");/* FIXME: Add Palette changing code */ + + /*GDevice **odisplay; + odisplay = GetGDevice(); + SetGDevice(GetMainDevice()); + SetEntries(0, (**pal).ctSize, (ColorSpec *)&(**pal).ctTable); + SetGDevice(odisplay);*/ + + /*_palette_changed_last = 0; + if (_mode_flags & DF_FORCE_FULL_ON_PALETTE) + */force_full = true; + } + + /* force a full redraw, accomplish that by adding one big rect to the dirty + * rect list */ + if (force_full) { + num_dirty_rects = 1; + + dirty_rect_list[0].left = 0; + dirty_rect_list[0].top = 0; + dirty_rect_list[0].right = SCREEN_WIDTH; + dirty_rect_list[0].bottom = SCREEN_HEIGHT; + } + + if (num_dirty_rects > 0) + { + Rect *r; + uint32 srcPitch, dstPitch; + Rect *last_rect = dirty_rect_list + num_dirty_rects; + + /* Convert appropriate parts of the image into 16bpp */ + if ((_mode_flags & DF_REAL_8BIT) == 0) { + Rect dst; + for(r=dirty_rect_list; r!=last_rect; ++r) { + dst = *r; + dst.left++; + dst.top++; + dst.right++; + dst.bottom++; + } + } + + /*srcPitch = sdl_tmpscreen->pitch; + dstPitch = sdl_hwscreen->pitch;*/ + + if ((_mode_flags & DF_REAL_8BIT) == 0) { + for(r=dirty_rect_list; r!=last_rect; ++r) { + register int dst_y = r->y + _current_shake_pos; + register int dst_h = 0; + if (dst_y < SCREEN_HEIGHT) { + dst_h = r->h; + if (dst_h > SCREEN_HEIGHT - dst_y) + dst_h = SCREEN_HEIGHT - dst_y; + + r->x <<= 1; + dst_y <<= 1; + + _sai_func((byte*)sdl_tmpscreen->pixels + (r->x+2) + (r->y+1)*srcPitch, srcPitch, NULL, + (byte*)sdl_hwscreen->pixels + r->x*scaling + dst_y*dstPitch, dstPitch, r->w, dst_h); + } + + r->y = dst_y; + r->w <<= 1; + r->h = dst_h << 1; + } + } else { + for(r=dirty_rect_list; r!=last_rect; ++r) { + register int dst_y = r->y + _current_shake_pos; + register int dst_h = 0; + if (dst_y < SCREEN_HEIGHT) { + dst_h = r->h; + if (dst_h > SCREEN_HEIGHT - dst_y) + dst_h = SCREEN_HEIGHT - dst_y; + + dst_y *= scaling; + + _sai_func((byte*)sdl_tmpscreen->pixels + r->x + r->y*srcPitch, srcPitch, NULL, + (byte*)sdl_hwscreen->pixels + r->x*scaling + dst_y*dstPitch, dstPitch, r->w, dst_h); + } + + r->x *= scaling; + r->y = dst_y; + r->w *= scaling; + r->h = dst_h * scaling; + } + } + + if (force_full) { + dirty_rect_list[0].y = 0; + dirty_rect_list[0].h = SCREEN_HEIGHT * scaling; + } + } + + /*if(_mode_flags & DF_2xSAI) + { + Rect *r; + uint32 area = 0; + + Rect *dr = dirty_rect_list + num_dirty_rects; + + for(r = dirty_rect_list; r != dr; r++) + { + GWorldPtr gw; + Rect rec; + SetRect(&rec, 0, 0, 320, 200); + NewGWorldFromPtr(&gw, 16, &rec, NULL, NULL, 0, (char*)_tmp_buf, rec.right); + CopyBits(GetPortBitMapForCopyBits(gw), GetPortBitMapForCopyBits(screenBuf), + r, r, srcCopy, 0L); + } + + for(r = dirty_rect_list; r != dr; r++) + { + _sai_func((byte*)_tmp_buf + r->left * 2 + r->top * 640, 640, NULL, + (byte*)_sai_buf + r->left * 4 + r->top * 640 * 4, 640 * 2, + r->right - r->left, r->bottom - r->top); + + area += (r->right - r->left) * (r->bottom - r->top); + + r->left <<= 1; + r->right <<= 1; + r->top <<= 1; + r->bottom <<= 1; + } + }*/ + + update_rects(); + //blit_to_screen(); + + num_dirty_rects = 0; + +#endif +} + +bool OSystem_MAC::show_mouse(bool visible) { + if (_mouse_visible == visible) + return visible; + + bool last = _mouse_visible; + _mouse_visible = visible; + + if (visible) + draw_mouse(); + else + undraw_mouse(); + + return last; +} + +void OSystem_MAC::set_mouse_pos(int x, int y) { + if (x != _ms_cur.x || y != _ms_cur.y) { + _ms_cur.x = x; + _ms_cur.y = y; + undraw_mouse(); + } +} + +void OSystem_MAC::set_mouse_cursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y) { + _ms_cur.w = w; + _ms_cur.h = h; + + _ms_hotspot_x = hotspot_x; + _ms_hotspot_y = hotspot_y; + + _ms_buf = (byte*)buf; + + undraw_mouse(); +} + +void OSystem_MAC::set_shake_pos(int shake_pos) { + /*int old_shake_pos = _current_shake_pos; + int dirty_height, dirty_blackheight; + int dirty_top, dirty_blacktop; + + if (shake_pos != old_shake_pos) { + _current_shake_pos = shake_pos; + force_full = true; + + /* Old shake pos was current_shake_pos, new is shake_pos. + * Move the screen up or down to account for the change. + */ + //SDL_Rect dstr = { 0, shake_pos*scaling, 320*scaling, 200*scaling }; + //SDL_Rect srcr = { 0, old_shake_pos*scaling, 320*scaling, 200*scaling }; + //SDL_BlitSurface(sdl_screen, &srcr, sdl_screen, &dstr); + /* Rect srcr, dstr; + + SetRect(&srcr, 0, old_shake_pos * scaling, 320 * scaling, 200 * scaling); + SetRect(&dstr, 0, shake_pos * scaling, 320 * scaling, 200 * scaling); + + CopyBits(GetPortBitMapForCopyBits(screenBuf), GetPortBitMapForCopyBits(GetWindowPort(wref)), + &srcr, &dstr, srcCopy, 0L); + + /* Refresh either the upper part of the screen, + * or the lower part */ + /* if (shake_pos > old_shake_pos) { + dirty_height = MIN(shake_pos, 0) - MIN(old_shake_pos, 0); + dirty_top = -MIN(shake_pos, 0); + dirty_blackheight = MAX(shake_pos, 0) - MAX(old_shake_pos, 0); + dirty_blacktop = MAX(old_shake_pos, 0); + } else { + dirty_height = MAX(old_shake_pos, 0) - MAX(shake_pos, 0); + dirty_top = 200 - MAX(old_shake_pos, 0); + dirty_blackheight = MIN(old_shake_pos, 0) - MIN(shake_pos, 0); + dirty_blacktop = 200 + MIN(shake_pos, 0); + } + + /* Fill the dirty area with blackness or the scumm image */ + //SDL_Rect blackrect = {0, dirty_blacktop*scaling, 320*scaling, dirty_blackheight*scaling}; + //SDL_FillRect(sdl_screen, &blackrect, 0); + + /* FIXME: Um, screen seems to glitch since this + 'not needed' function was removed */ + //g_scumm->redrawLines(dirty_top, dirty_top + dirty_height); +/* }*/ +} + +uint32 OSystem_MAC::get_msecs() { + UnsignedWide ms; + + Microseconds(&ms); + return(ms.lo / 1000); +} + +void OSystem_MAC::delay_msecs(uint msecs) { + uint32 start = get_msecs(); + Event dummy; + + do { + poll_event(&dummy); /* Do something to avoid CPU lock */ + if(get_msecs() >= start + msecs) + break; + } while (1); +} + +void *OSystem_MAC::create_thread(ThreadProc *proc, void *param) { + warning("MAC: Stub create_thread()"); + //NewThread(kCooperativeThread, (void*)proc, param, 0L, kCreateIfNeeded, NULL, NULL); +} + +int mapKey(int key, byte code, byte mod) +{ + switch(code) { + case 0x35: + key = 27; + break; + case 0x31: + key = 32; + break; + case 0x60: + key = 601; + break; + } + + return key; +} + +bool OSystem_MAC::poll_event(Event *event) +{ + EventRef theEvent; + EventTargetRef theTarget; + OSStatus theErr; + + OSStatus result = eventNotHandledErr; + HICommand command; + Point mouse; + + theTarget = GetEventDispatcherTarget(); + theErr = ReceiveNextEvent(GetEventTypeCount(kCmdEvents), kCmdEvents, kEventDurationNoWait,true, &theEvent); + + GetEventParameter( theEvent, kEventParamDirectObject, typeHICommand, NULL, + sizeof( HICommand ), NULL, &command ); + + switch(GetEventClass(theEvent)) + { + case kEventClassWindow: + switch(GetEventKind(theEvent)) + { + case kEventWindowDrawContent: + break; + + case kEventWindowHandleContentClick: + EventMouseButton btn; + + GetEventParameter(theEvent, kEventParamMouseButton, typeMouseButton, NULL, + sizeof(EventMouseButton), NULL, &btn); + + if(btn == kEventMouseButtonPrimary) + event->event_code = EVENT_RBUTTONDOWN; + else if(btn == kEventMouseButtonSecondary) + event->event_code = EVENT_LBUTTONDOWN; + + debug(1, "Mouse down!"); + + if(wref != FrontWindow()) + { +// FIXME - seems some versions of the CarbonLib stub are missing ActivateWindow +// ActivateWindow(wref, true); + BringToFront(wref); + } + return true; + break; + + case kEventWindowClose: + quit(); + break; + } + break; + + case kEventClassCommand: + switch(command.commandID) + { + case kNewGameCmd: + + break; + + case kOpenGameCmd: + //scumm->_saveLoadSlot = 0; + //scumm->_saveLoadFlag = 2; + break; + + case kSaveGameCmd: + //scumm->_saveLoadSlot = 0; + //sprintf(scumm->_saveLoadName, "Quicksave %d", scumm->_saveLoadSlot); + //scumm->_saveLoadFlag = 1; + break; + + case kQuitCmd: + quit(); + break; + + case kPrefsCmd: + //Preferences(); + break; + + case kAboutCmd: + //About(); + break; + } + break; + + case kEventClassKeyboard: + if(GetEventKind(theEvent) == kEventRawKeyDown) + { + char key; + UInt32 mod, code; + + GetEventParameter(theEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &code); + GetEventParameter(theEvent, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &key); + GetEventParameter(theEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &mod); + + event->event_code = EVENT_KEYDOWN; + event->kbd.keycode = code; + event->kbd.ascii = mapKey(key, code, mod); + debug(1, "Key down: %c", event->kbd.ascii); + return true; + } + break; + + case kEventClassMouse: + EventMouseButton btn; + Rect winRect; + + switch(GetEventKind(theEvent)) + { + case kEventMouseDown: + WindowRef theWin; + + GetEventParameter(theEvent, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), + NULL, &theWin); + if(theWin != FrontWindow()) + { +// FIXME - seems some versions of the CarbonLib stub are missing ActivateWindow +// ActivateWindow(theWin, true); + BringToFront(theWin); + } + + GetEventParameter(theEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &mouse); + + GetWindowBounds(wref, kWindowContentRgn, &winRect); + if(PtInRect(mouse, &winRect)) + { + GetEventParameter(theEvent, kEventParamMouseButton, typeMouseButton, NULL, + sizeof(EventMouseButton), NULL, &btn); + + if(btn == kEventMouseButtonPrimary) + event->event_code = EVENT_RBUTTONDOWN; + else if(btn == kEventMouseButtonSecondary) + event->event_code = EVENT_LBUTTONDOWN; + + debug(1, "Mouse down!"); + } + break; + + case kEventMouseUp: + + GetEventParameter(theEvent, kEventParamMouseButton, typeMouseButton, NULL, + sizeof(EventMouseButton), NULL, &btn); + + if(btn == kEventMouseButtonPrimary) + event->event_code = EVENT_RBUTTONUP; + else if(btn == kEventMouseButtonSecondary) + event->event_code = EVENT_LBUTTONUP; + + debug(1, "Mouse up!"); + + return true; + break; + + case kEventMouseMoved: + GetEventParameter(theEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &mouse); + + GetWindowBounds(wref, kWindowContentRgn, &winRect); + if(PtInRect(mouse, &winRect)) + { + CGrafPtr oldPort; + + GetPort(&oldPort); + SetPortWindowPort(wref); + GlobalToLocal(&mouse); + + event->event_code = EVENT_MOUSEMOVE; + event->mouse.x = mouse.h / scaling; + event->mouse.y = mouse.v / scaling; + + //scumm->mouse.x = mouse.h/wm->scale; + //scumm->mouse.y = mouse.v/wm->scale; + } + Point offset = {0, 0}; + ShieldCursor(&winRect, offset); + return true; + break; + } + break; + } + + if(theErr == noErr && theEvent != NULL) { + SendEventToEventTarget (theEvent, theTarget); + ReleaseEvent(theEvent); + } +} + +pascal void sound_callback(SndChannel *chan, SndCommand *cmd_passed) +{ + OSystem_MAC* syst = (OSystem_MAC*)chan->userInfo; + syst->sound_callback(chan, cmd_passed); +} + +void OSystem_MAC::sound_callback(SndChannel *chan, SndCommand *cmd_passed) +{ + UInt32 fill_me, play_me; + SndCommand cmd; + + fill_me = cmd_passed->param2; + play_me = ! fill_me; + + header.samplePtr = (Ptr)buffer[play_me]; + + cmd.cmd = bufferCmd; + cmd.param1 = 0; + cmd.param2 = (long)&header; + + SndDoCommand(chan, &cmd, 0); + + memset(buffer[fill_me], 0, size); + //sndProc(parameter, buffer[fill_me], size); + //SoundMixer::on_generate_samples(parameter, buffer[fill_me], size); + + cmd.cmd = callBackCmd; + cmd.param1 = 0; + cmd.param2 = play_me; + + SndDoCommand(chan, &cmd, 0); +} + +bool OSystem_MAC::set_sound_proc(void *param, SoundProc *proc, byte format) +{ + SndCallBackUPP callback; + int sample_size; + + memset(&header, 0, sizeof(header)); + callback = NewSndCallBackUPP(::sound_callback); + size = ((0x9010 & 0xFF) / 8) * 2048; + sample_size = size / 2048 * 8; + header.numChannels = 1; + header.sampleSize = sample_size; + header.sampleRate = SAMPLES_PER_SEC << 16; + header.numFrames = 2048; + header.encode = cmpSH; + + for(int i = 0; i < 2; i++) + { + buffer[i] = (UInt8*)malloc(sizeof(UInt8) * size); + memset(buffer[i], 0, size); + } + + channel = (SndChannelPtr)malloc(sizeof(*channel)); + channel->qLength = 128; + channel->userInfo = (long)this; + SndNewChannel(&channel, sampledSynth, initMono, callback); + + SndCommand cmd; + cmd.cmd = callBackCmd; + cmd.param2 = 0; + SndDoCommand(channel, &cmd, 0); + + sndProc = proc; + parameter = param; + + return true; +} + + +/* retrieve the 320x200 bitmap currently being displayed */ +void OSystem_MAC::get_320x200_image(byte *buf) +{ + /* make sure the mouse is gone */ + undraw_mouse(); + + byte *src; + int x,y; + + switch(_internal_scaling) { + case 1: + memcpy(buf, _gfx_buf, 320*200); + break; + + case 2: + src = (byte*)_gfx_buf; + for(y=0; y!=200; y++) { + for(x=0; x!=320; x++) + buf[x] = src[x*2]; + buf += 320; + src += 320 * 2 * 2; + } + break; + + case 3: + src = (byte*)_gfx_buf; + for(y=0; y!=200; y++) { + for(x=0; x!=320; x++) + buf[x] = src[x*3]; + buf += 320; + src += 320 * 3 * 3; + } + break; + } +} + +void OSystem_MAC::hotswap_gfx_mode() +{ + /* hmm, need to allocate a 320x200 bitmap + * which will contain the "backup" of the screen during the change. + * then draw that to the new screen right after it's setup. + */ + + byte *bak_mem = (byte*)malloc(320*200); + + get_320x200_image(bak_mem); + + unload_gfx_mode(); + load_gfx_mode(); + + force_full = true; + + /* reset palette ? */ + pal = (CTabHandle)NewHandleClear(sizeof(ColorTable) + 255 * sizeof(ColorSpec)); + (*pal)->ctFlags = 0; + (*pal)->ctSize = 255; + + /* blit image */ + copy_rect(bak_mem, 320, 0, 0, 320, 200); + free(bak_mem); + + update_screen(); +} + +uint32 OSystem_MAC::property(int param, Property *value) { + switch(param) { + case PROP_TOGGLE_FULLSCREEN: + _full_screen ^= true; + return 1; + + case PROP_SET_WINDOW_CAPTION: + StringPtr gameText = CToPascal((char*)value->caption); + SetWTitle(wref, gameText); + return 1; + + case PROP_OPEN_CD: + break; + + case PROP_SET_GFX_MODE: + if(value->gfx_mode >= 7) + return 0; + _mode = value->gfx_mode; + hotswap_gfx_mode(); + return 1; + + + case PROP_SHOW_DEFAULT_CURSOR: + break; + + case PROP_GET_SAMPLE_RATE: + return SAMPLES_PER_SEC; + break; + } + + return 0; +} + +void OSystem_MAC::quit() { + unload_gfx_mode(); + + QuitApplicationEventLoop(); + ExitToShell(); +} + +void OSystem_MAC::draw_mouse() { + if (_mouse_drawn || !_mouse_visible) + return; + _mouse_drawn = true; + + const int ydraw = _ms_cur.y + _current_shake_pos - _ms_hotspot_y; + const int xdraw = _ms_cur.x - _ms_hotspot_x; + const int w = _ms_cur.w; + const int h = _ms_cur.h; + int x,y; + byte color; + byte *dst, *bak = _ms_backup; + byte *buf = _ms_buf; + + _ms_old.w = w; + _ms_old.h = h; + _ms_old.x = xdraw; + _ms_old.y = ydraw; + + byte *src; + if(_sai_func) + src = (byte*)_tmp_buf; + else + src = _gfx_buf; + + switch(_internal_scaling) { + case 1: + dst = (byte *)src + ydraw * 320 + xdraw; + + for (y = 0; y < h; y++, dst += 320, bak += MAX_MOUSE_W, buf += w) { + if ((uint) (ydraw + y) < 200) { + for (x = 0; x < w; x++) { + if ((uint) (xdraw + x) < 320) { + bak[x] = dst[x]; + if ((color = buf[x]) != 0xFF) { + dst[x] = color; + } + } + } + } + } + break; + + case 2: + dst = (byte *)src + ydraw * 640 * 2 + xdraw * 2; + + for (y = 0; y < h; y++, dst += 640 * 2, bak += MAX_MOUSE_W * 2, buf += w) { + if ((uint) (ydraw + y) < 200) { + for (x = 0; x < w; x++) { + if ((uint) (xdraw + x) < 320) { + bak[x * 2] = dst[x * 2]; + bak[x * 2 + 1] = dst[x * 2 + 1]; + if ((color = buf[x]) != 0xFF) { + dst[x * 2] = color; + dst[x * 2 + 1] = color; + dst[x * 2 + 640] = color; + dst[x * 2 + 1 + 640] = color; + } + } + } + } + } + break; + + case 3: + dst = (byte *)src + ydraw * 960 * 3 + xdraw * 3; + + for (y = 0; y < h; y++, dst += 960 * 3, bak += MAX_MOUSE_W * 3, buf += w) { + if ((uint) (ydraw + y) < 200) { + for (x = 0; x < w; x++) { + if ((uint) (xdraw + x) < 320) { + bak[x * 3] = dst[x * 3]; + bak[x * 3 + 1] = dst[x * 3 + 1]; + bak[x * 3 + 2] = dst[x * 3 + 2]; + if ((color = buf[x]) != 0xFF) { + dst[x * 3] = color; + dst[x * 3 + 1] = color; + dst[x * 3 + 2] = color; + dst[x * 3 + 960] = color; + dst[x * 3 + 1 + 960] = color; + dst[x * 3 + 2 + 960] = color; + dst[x * 3 + 960 + 960] = color; + dst[x * 3 + 1 + 960 + 960] = color; + dst[x * 3 + 2 + 960 + 960] = color; + } + } + } + } + } + break; + } + + add_dirty_rect(xdraw,ydraw,w,h); +} + +void OSystem_MAC::undraw_mouse() { + if (!_mouse_drawn) + return; + _mouse_drawn = false; + + byte *dst, *bak = _ms_backup; + byte *src; + const int old_mouse_x = _ms_old.x; + const int old_mouse_y = _ms_old.y; + const int old_mouse_w = _ms_old.w; + const int old_mouse_h = _ms_old.h; + int x,y; + + if(_sai_func) + src = (byte*)_tmp_buf; + else + src = _gfx_buf; + + switch(_internal_scaling) { + case 1: + dst = (byte *)src + old_mouse_y * 320 + old_mouse_x; + + for (y = 0; y < old_mouse_h; y++, bak += MAX_MOUSE_W, dst += 320) { + if ((uint) (old_mouse_y + y) < 200) { + for (x = 0; x < old_mouse_w; x++) { + if ((uint) (old_mouse_x + x) < 320) { + dst[x] = bak[x]; + } + } + } + } + break; + + case 2: + dst = (byte *)src + old_mouse_y * 640 * 2 + old_mouse_x * 2; + + for (y = 0; y < old_mouse_h; y++, bak += MAX_MOUSE_W * 2, dst += 640 * 2) { + if ((uint) (old_mouse_y + y) < 200) { + for (x = 0; x < old_mouse_w; x++) { + if ((uint) (old_mouse_x + x) < 320) { + dst[x * 2 + 640] = dst[x * 2] = bak[x * 2]; + dst[x * 2 + 640 + 1] = dst[x * 2 + 1] = bak[x * 2 + 1]; + } + } + } + } + break; + + case 3: + dst = (byte *)src + old_mouse_y * 960 * 3 + old_mouse_x * 3; + + for (y = 0; y < old_mouse_h; y++, bak += MAX_MOUSE_W * 3, dst += 960 * 3) { + if ((uint) (old_mouse_y + y) < 200) { + for (x = 0; x < old_mouse_w; x++) { + if ((uint) (old_mouse_x + x) < 320) { + dst[x * 3 + 960] = dst[x * 3 + 960 + 960] = dst[x * 3] = + bak[x * 3]; + dst[x * 3 + 960 + 1] = dst[x * 3 + 960 + 960 + 1] = + dst[x * 3 + 1] = bak[x * 3 + 1]; + dst[x * 3 + 960 + 2] = dst[x * 3 + 960 + 960 + 2] = + dst[x * 3 + 2] = bak[x * 3 + 2]; + } + } + } + } + break; + } + + add_dirty_rect(old_mouse_x, old_mouse_y, old_mouse_w, old_mouse_h); +} + +void OSystem_MAC::stop_cdrom() { +} + +void OSystem_MAC::play_cdrom(int track, int num_loops, int start_frame, int end_frame) { + /* Reset sync count */ + g_scumm->_vars[g_scumm->VAR_MI1_TIMER] = 0; +} + +bool OSystem_MAC::poll_cdrom() { +} + +void OSystem_MAC::update_cdrom() { +} + + + +/*************************************************************/ +/** Mac specific code ****************************************/ +void OSystem_MAC::set_scaling() { + Rect rectWin; + SetRect(&rectWin, 0, 0, 320 * scaling, 200 * scaling); + HideWindow(wref); + SetWindowBounds(wref, kWindowContentRgn, &rectWin); + RepositionWindow(wref, NULL, kWindowCenterOnMainScreen); + ShowWindow(wref); + blit_rect = rectWin; + + if(_sai_func) + { + Rect r; + + //SetRect(&r, 0, 0, 320, 240); + _sai_buf = (int16*)malloc((320 * 200) * 2 * sizeof(int16)); + + NewGWorldFromPtr(&screenBuf, 16, &blit_rect, NULL, nil, 0, (char *)_sai_buf, blit_rect.right); + } + else + { + _gfx_buf = (byte*)malloc((320 * 200) * scaling * sizeof(byte)); + NewGWorldFromPtr(&screenBuf, 8, &blit_rect, pal, nil, 0, (char *)_gfx_buf, blit_rect.right); + } + + //NewGWorldFromPtr(&screenBuf, 8, &blit_rect, pal, nil, 0, (char *)_gfx_buf, blit_rect.right); + + //if(screenBuf != NULL) + // UpdateGWorld(&screenBuf, 8, &blit_rect, pal, NULL, NULL); +} + +void OSystem_MAC::blit_to_screen() +{ + CopyBits(GetPortBitMapForCopyBits(screenBuf), + GetPortBitMapForCopyBits(GetWindowPort(wref)), &blit_rect, &blit_rect, srcCopy, 0L); +} + +void OSystem_MAC::init_mac_stuff() +{ + Rect rectWin; + + + MenuRef AppleMenu = GetMenu(1000); + InsertMenu(AppleMenu, 0); + SetMenuItemCommandID(AppleMenu, 1, kAboutCmd); + MenuRef FileMenu = GetMenu(1001); + SetMenuItemCommandID(FileMenu, 1, kNewGameCmd); + SetMenuItemCommandID(FileMenu, 2, kOpenGameCmd); + SetMenuItemCommandID(FileMenu, 3, kSaveGameCmd); + SetMenuItemCommandID(FileMenu, 5, kQuitCmd); + DeleteMenuItems(FileMenu, CountMenuItems(FileMenu)-1, 2); + InsertMenu(FileMenu, 0); + MenuRef windMenu; + CreateStandardWindowMenu(0, &windMenu); + InsertMenu(windMenu, 0); + EnableMenuCommand(NULL, kPrefsCmd); + DrawMenuBar(); + + SetRect(&rectWin, 0, 0, 320, 200); + UInt32 WinAttrib = (kWindowCloseBoxAttribute | kWindowCollapseBoxAttribute | + kWindowInWindowMenuAttribute | kWindowStandardHandlerAttribute); + + if(noErr != CreateNewWindow(kDocumentWindowClass, WinAttrib, &rectWin, &wref)) + { + //Error("Couldn't create Window!"); + } + + RepositionWindow(wref, NULL, kWindowCenterOnMainScreen); + + Str255 WindowTitle = "\pScummVM"; + SetWTitle(wref, WindowTitle); + + SetPortWindowPort(wref); + //ShowWindow(wref); + + InstallStandardEventHandler(GetWindowEventTarget(wref)); + + //OSStatus err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP(QuitEventHandler), 0L, false); + + blit_rect = rectWin; + pal = (CTabHandle)NewHandleClear(sizeof(ColorTable) + 255 * sizeof(ColorSpec)); + (*pal)->ctFlags = 0; + (*pal)->ctSize = 255; + //NewGWorld(&screenBuf, 8, &blit_rect, 0, 0, 0); +} + +void OSystem_MAC::update_rects() +{ + for(int i = 0; i < num_dirty_rects; i++) + { + Rect rec = dirty_rect_list[i]; + + CopyBits(GetPortBitMapForCopyBits(screenBuf), + GetPortBitMapForCopyBits(GetWindowPort(wref)), + &rec, &rec, srcCopy, 0L); + } +} diff --git a/backends/mac/macos.h b/backends/mac/macos.h new file mode 100644 index 0000000000..09c40456e9 --- /dev/null +++ b/backends/mac/macos.h @@ -0,0 +1,24 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * + * 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; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * + */ + + //#define MACOS_SDL + #define MACOS_CARBON + \ No newline at end of file diff --git a/backends/mac/scummvm.icns b/backends/mac/scummvm.icns new file mode 100644 index 0000000000..5f5e10d732 Binary files /dev/null and b/backends/mac/scummvm.icns differ diff --git a/backends/mac/scummvm.mcp b/backends/mac/scummvm.mcp new file mode 100644 index 0000000000..41a29050f4 Binary files /dev/null and b/backends/mac/scummvm.mcp differ -- cgit v1.2.3