diff options
author | Max Horn | 2002-08-21 16:07:07 +0000 |
---|---|---|
committer | Max Horn | 2002-08-21 16:07:07 +0000 |
commit | ce46866403fdcc479cf9d67e4d430409b15dadc3 (patch) | |
tree | 75ebfaa1ed13f549959d76d3ce101c3e66f5451b /backends/morphos | |
parent | 662256f25dbe43abf67077a804e225738765f009 (diff) | |
download | scummvm-rg350-ce46866403fdcc479cf9d67e4d430409b15dadc3.tar.gz scummvm-rg350-ce46866403fdcc479cf9d67e4d430409b15dadc3.tar.bz2 scummvm-rg350-ce46866403fdcc479cf9d67e4d430409b15dadc3.zip |
Initial revision
svn-id: r4785
Diffstat (limited to 'backends/morphos')
-rw-r--r-- | backends/morphos/Makefile | 48 | ||||
-rw-r--r-- | backends/morphos/MorphOS.readme | 13 | ||||
-rw-r--r-- | backends/morphos/morphos.cpp | 1293 | ||||
-rw-r--r-- | backends/morphos/morphos.h | 206 | ||||
-rw-r--r-- | backends/morphos/morphos_scaler.cpp | 823 | ||||
-rw-r--r-- | backends/morphos/morphos_scaler.h | 93 | ||||
-rw-r--r-- | backends/morphos/morphos_sound.cpp | 284 | ||||
-rw-r--r-- | backends/morphos/morphos_start.cpp | 359 | ||||
-rw-r--r-- | backends/morphos/morphos_timer.cpp | 243 | ||||
-rw-r--r-- | backends/morphos/morphos_timer.h | 86 |
10 files changed, 3448 insertions, 0 deletions
diff --git a/backends/morphos/Makefile b/backends/morphos/Makefile new file mode 100644 index 0000000000..00fd3992d1 --- /dev/null +++ b/backends/morphos/Makefile @@ -0,0 +1,48 @@ +vpath %.cpp ../:../sound/:../v3/:../v4/:../simon/:../gui/ +vpath %.h ../ + +CC = g++ +CFLAGS = -Wno-multichar -fstrength-reduce -fno-rtti -O2 +DEFINES = -DNO_PPCINLINE_STDARG -DNO_PPCINLINE_VARARGS +LDFLAGS := -noixemul -s +INCLUDES:= -I../ -I../sound +CPPFLAGS= $(DEFINES) $(INCLUDES) +LIBS = -lamiga -lamigastubs -lcdda +ZIPFILE := scummvm-`date '+%Y-%m-%d'`.zip + +INCS = scumm.h scummsys.h stdafx.h + +GUIOBJS = widget.o dialog.o newgui.o ListWidget.o ScrollBarWidget.o + +SIMONOBJS = midi.o simon.o simondebug.o simonitems.o simonres.o simonsys.o simonverb.o simonvga.o + +OBJS = actor.o akos.o boxes.o config-file.o costume.o gfx.o object.o resource.o \ + saveload.o script.o scummvm.o sound.o string.o sys.o verbs.o \ + morphos.o morphos_scaler.o morphos_sound.o morphos_start.o morphos_timer.o \ + script_v1.o script_v2.o debug.o gui.o imuse.o fmopl.o mixer.o mididrv.o \ + debugrl.o vars.o insane.o gameDetector.o resource_v3.o resource_v4.o \ + util.o main.o bundle.o $(GUIOBJS) $(SIMONOBJS) + +DISTFILES=$(OBJS:.o=.cpp) Makefile scumm.h scummsys.h stdafx.h stdafx.cpp \ + windows.cpp debugrl.h whatsnew.txt readme.txt copying.txt \ + scummvm.dsp scummvm.dsw sound/fmopl.h + +.cpp.o: + $(CC) $(CFLAGS) $(CPPFLAGS) -c $(<) -o $*.o + +all: scummvm + +scummvm: $(OBJS) + $(CC) $(LDFLAGS) -o $(@) $(OBJS) $(LIBS) + +#$(OBJS): Makefile + +clean: + rm -f $(OBJS) scummvm + +dist: + rm -f $(ZIPFILE) + zip -q $(ZIPFILE) $(DISTFILES) + +check: +$(OBJS): $(INCS) diff --git a/backends/morphos/MorphOS.readme b/backends/morphos/MorphOS.readme new file mode 100644 index 0000000000..693ae324c4 --- /dev/null +++ b/backends/morphos/MorphOS.readme @@ -0,0 +1,13 @@ +This directory contains the source for the MorphOS port of ScummVM. To build, you +must have a proper Geek Gadgets installation. Just type "make" in the MorphOS +subdirectory. If you don't have the includes for AMidi 2 and cdda.library, check +my webpage. If they aren't uploaded yet, feel free to e-mail me. + +You don't have to build ScummVM yourself. The latest official and CVS binaries are +available from my website at: + +http://www.muenster.de/~tomjoad/scummvm.html + +Ruediger Hanke +tomjoad@muenster.de + diff --git a/backends/morphos/morphos.cpp b/backends/morphos/morphos.cpp new file mode 100644 index 0000000000..a949cbfd2f --- /dev/null +++ b/backends/morphos/morphos.cpp @@ -0,0 +1,1293 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002 Rüdiger Hanke + * + * 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. + * + * MorphOS interface + * + * $Header$ + * + */ + +#include "stdafx.h" +#include "scumm.h" + +#include <exec/types.h> +#include <exec/memory.h> +#include <exec/libraries.h> +#include <exec/semaphores.h> +#include <devices/ahi.h> +#include <dos/dostags.h> +#include <intuition/screens.h> +#include <cybergraphics/cybergraphics.h> +#include <devices/inputevent.h> +#include <intuition/intuition.h> + +#include <clib/alib_protos.h> +#include <proto/exec.h> +#include <proto/dos.h> +#include <proto/graphics.h> +#include <proto/intuition.h> +#include <proto/keymap.h> +#include <proto/timer.h> +#include <proto/cdda.h> +#include <proto/cybergraphics.h> + +#include <emul/emulinterface.h> + +#include <time.h> + +#include "morphos.h" +#include "morphos_scaler.h" + +static TagItem FindCDTags[] = { { CDFA_VolumeName, 0 }, + { TAG_DONE, 0 } + }; +static TagItem PlayTags[] = { { CDPA_StartTrack, 1 }, + { CDPA_StartFrame, 0 }, + { CDPA_EndTrack, 1 }, + { CDPA_EndFrame, 0 }, + { CDPA_Loops, 1 }, + { TAG_DONE, 0 } + }; + +TagItem musicProcTags[] = { { NP_Entry, 0 }, + { NP_Name, (ULONG)"ScummVM Music Thread" }, + { NP_Priority, 0 }, + { TAG_DONE, 0 } + }; +TagItem soundProcTags[] = { { NP_Entry, 0 }, + { NP_Name, (ULONG)"ScummVM Sound Thread" }, + { NP_Priority, 0 }, + { TAG_DONE, 0 } + }; + +#define BLOCKSIZE_X 32 +#define BLOCKSIZE_Y 8 + +#define BLOCKS_X (ScummBufferWidth/BLOCKSIZE_X) +#define BLOCKS_Y (ScummBufferHeight/BLOCKSIZE_Y) +#define BLOCK_ID(x, y) ((y/BLOCKSIZE_Y)*BLOCKS_X+(x/BLOCKSIZE_X)) + +OSystem_MorphOS *OSystem_MorphOS::create(int game_id, SCALERTYPE gfx_scaler, bool full_screen) +{ + OSystem_MorphOS *syst = new OSystem_MorphOS(game_id, gfx_scaler, full_screen); + + return syst; +} + +OSystem_MorphOS::OSystem_MorphOS(int game_id, SCALERTYPE gfx_mode, bool full_screen) +{ + GameID = game_id; + ScummScreen = NULL; + ScummWindow = NULL; + ScummBuffer = NULL; + ScummScreenBuffer[0] = NULL; + ScummScreenBuffer[1] = NULL; + ScummRenderTo = NULL; + ScummNoCursor = NULL; + ScummMusicThread = NULL; + ScummSoundThread = NULL; + ScummWinX = -1; + ScummWinY = -1; + ScummDefaultMouse = false; + ScummOrigMouse = false; + ScummShakePos = 0; + ScummScaler = gfx_mode; + ScummScale = (gfx_mode == ST_NONE) ? 0 : 1; + ScummDepth = 0; + Scumm16ColFmt16 = false; + ScummScrWidth = 0; + ScummScrHeight = 0; + ScreenChanged = false; + DirtyBlocks = NULL; + BlockColors = NULL; + Scaler = NULL; + FullScreenMode = full_screen; + CDrive = NULL; + CDDATrackOffset = 0; + strcpy(ScummWndTitle, "ScummVM MorphOS"); + TimerMsgPort = NULL; + TimerIORequest = NULL; + + OpenATimer(&TimerMsgPort, (IORequest **) &TimerIORequest, UNIT_MICROHZ); + + TimerBase = TimerIORequest->tr_node.io_Device; + ScummNoCursor = (UWORD *) AllocVec(16, MEMF_CHIP | MEMF_CLEAR); + UpdateRegion = NewRegion(); + NewUpdateRegion = NewRegion(); + if (!UpdateRegion || !NewUpdateRegion) + error("Could not create region for screen update"); +} + +OSystem_MorphOS::~OSystem_MorphOS() +{ + if (DirtyBlocks) + { + FreeVec(DirtyBlocks); + + for (int b = 0; b < BLOCKS_X*BLOCKS_Y; b++) + FreeVec(BlockColors[b]); + FreeVec(BlockColors); + } + + if (Scaler) + delete Scaler; + + if (UpdateRegion) + DisposeRegion(UpdateRegion); + + if (NewUpdateRegion) + DisposeRegion(NewUpdateRegion); + + if (CDrive && CDDABase) + { + CDDA_Stop(CDrive); + CDDA_ReleaseDrive(CDrive); + } + + if (TimerIORequest) + { + CloseDevice((IORequest *) TimerIORequest); + DeleteIORequest((IORequest *) TimerIORequest); + } + + if (TimerMsgPort) + DeleteMsgPort(TimerMsgPort); + + if (ScummMusicThread) + { + Signal((Task *) ScummMusicThread, SIGBREAKF_CTRL_C); + ObtainSemaphore(&ScummMusicThreadRunning); /* Wait for thread to finish */ + ReleaseSemaphore(&ScummMusicThreadRunning); + } + + if (ScummSoundThread) + { + Signal((Task *) ScummSoundThread, SIGBREAKF_CTRL_C); + ObtainSemaphore(&ScummSoundThreadRunning); /* Wait for thread to finish */ + ReleaseSemaphore(&ScummSoundThreadRunning); + } + + if (ScummNoCursor) + FreeVec(ScummNoCursor); + + if (ScummBuffer) + FreeVec(ScummBuffer); + + if (ScummRenderTo && !ScummScreen) + FreeBitMap (ScummRenderTo); + + if (ScummWindow) + CloseWindow(ScummWindow); + + if (ScummScreen) + { + if (ScummScreenBuffer[0]) + FreeScreenBuffer(ScummScreen, ScummScreenBuffer[0]); + if( ScummScreenBuffer[1] ) + FreeScreenBuffer(ScummScreen, ScummScreenBuffer[1]); + CloseScreen(ScummScreen); + } +} + +bool OSystem_MorphOS::OpenATimer(MsgPort **port, IORequest **req, ULONG unit, bool required) +{ + *req = NULL; + const char *err_msg = NULL; + + *port = CreateMsgPort(); + if (*port) + { + *req = (IORequest *) CreateIORequest(*port, sizeof (timerequest)); + if (*req) + { + if (OpenDevice(TIMERNAME, unit, *req, 0)) + { + DeleteIORequest(*req); + *req = NULL; + err_msg = "Failed to open timer device"; + } + } + else + err_msg = "Failed to create IO request"; + } + else + err_msg = "Failed to create message port"; + + if (err_msg) + { + if (required) + error(err_msg); + warning(err_msg); + } + + return *req != NULL; +} + +uint32 OSystem_MorphOS::get_msecs() +{ + int ticks = clock(); + ticks *= (1000/CLOCKS_PER_SEC); + return ticks; +} + +void OSystem_MorphOS::delay_msecs(uint msecs) +{ + TimerIORequest->tr_node.io_Command = TR_ADDREQUEST; + TimerIORequest->tr_time.tv_secs = 0; + TimerIORequest->tr_time.tv_micro = msecs*1000; + DoIO((IORequest *) TimerIORequest); +} + +void OSystem_MorphOS::set_timer(int timer, int (*callback)(int)) +{ + warning("set_timer() unexpectedly called"); +} + +void *OSystem_MorphOS::create_thread(ThreadProc *proc, void *param) +{ + static EmulFunc ThreadEmulFunc; + + ThreadEmulFunc.Trap = TRAP_FUNC; + ThreadEmulFunc.Address = (ULONG)proc; + ThreadEmulFunc.StackSize = 16000; + ThreadEmulFunc.Extension = 0; + ThreadEmulFunc.Arg1 = (ULONG)param; + musicProcTags[0].ti_Data = (ULONG)&ThreadEmulFunc; + ScummMusicThread = CreateNewProc(musicProcTags); + return ScummMusicThread; +} + +void *OSystem_MorphOS::create_mutex(void) +{ + SignalSemaphore *sem = (SignalSemaphore *) AllocVec(sizeof (SignalSemaphore), MEMF_PUBLIC); + + if (sem) + InitSemaphore(sem); + + return sem; +} + +void OSystem_MorphOS::lock_mutex(void *mutex) +{ + ObtainSemaphore((SignalSemaphore *) mutex); +} + +void OSystem_MorphOS::unlock_mutex(void *mutex) +{ + ReleaseSemaphore((SignalSemaphore *)mutex); +} + +void OSystem_MorphOS::delete_mutex(void *mutex) +{ + FreeVec(mutex); +} + +uint32 OSystem_MorphOS::property(int param, Property *value) +{ + switch (param) + { + case PROP_TOGGLE_FULLSCREEN: + CreateScreen(CSDSPTYPE_TOGGLE); + return 1; + + case PROP_SET_WINDOW_CAPTION: + sprintf(ScummWndTitle, "ScummVM MorphOS - %s", value->caption); + if (ScummWindow) + SetWindowTitles(ScummWindow, ScummWndTitle, ScummWndTitle); + return 1; + + case PROP_OPEN_CD: + FindCDTags[0].ti_Data = (ULONG) ((GameID == GID_LOOM256) ? "LoomCD" : "Monkey1CD"); + if (!CDDABase) CDDABase = OpenLibrary("cdda.library", 2); + if (CDDABase) + { + CDrive = CDDA_FindNextDrive(NULL, FindCDTags); + if (!CDrive && GameID == GID_MONKEY) + { + FindCDTags[0].ti_Data = (ULONG) "Madness"; + CDrive = CDDA_FindNextDrive(NULL, FindCDTags); + } + if (CDrive) + { + if (!CDDA_ObtainDrive(CDrive, CDDA_SHARED_ACCESS, NULL)) + { + CDrive = NULL; + warning("Failed to obtain CD drive - music will not play"); + } + else if (GameID == GID_LOOM256) + { + // Offset correction *may* be required + CDS_TrackInfo ti = { sizeof (CDS_TrackInfo) }; + + if (CDDA_GetTrackInfo(CDrive, 1, 0, &ti)) + CDDATrackOffset = ti.ti_TrackStart.tm_Format.tm_Frame-22650; + } + } + else + warning( "Could not find game CD inserted in CD-ROM drive - cd audio will not play" ); + } + else + warning( "Failed to open cdda.library - cd audio will not play" ); + break; + + case PROP_SHOW_DEFAULT_CURSOR: + if (value->show_cursor) + ClearPointer(ScummWindow); + else + SetPointer(ScummWindow, ScummNoCursor, 1, 1, 0, 0); + ScummOrigMouse = ScummDefaultMouse = value->show_cursor; + break; + + case PROP_GET_SAMPLE_RATE: + return SAMPLES_PER_SEC; + } + + return 0; +} + +void OSystem_MorphOS::play_cdrom(int track, int num_loops, int start_frame, int length) +{ + if (CDrive && start_frame >= 0) + { + if (start_frame > 0) + start_frame -= CDDATrackOffset; + + PlayTags[0].ti_Data = track; + PlayTags[1].ti_Data = start_frame; + PlayTags[2].ti_Data = (length == 0) ? track+1 : track; + PlayTags[3].ti_Data = length ? start_frame+length : 0; + PlayTags[4].ti_Data = (num_loops == 0) ? 1 : num_loops; + CDDA_Play(CDrive, PlayTags); + } +} + +void OSystem_MorphOS::stop_cdrom() +{ + CDDA_Stop(CDrive); +} + +bool OSystem_MorphOS::poll_cdrom() +{ + ULONG status; + + if (CDrive == NULL) + return false; + + CDDA_GetAttr(CDDA_Status, CDrive, &status); + return status == CDDA_Status_Busy; +} + +void OSystem_MorphOS::update_cdrom() +{ +} + +void OSystem_MorphOS::quit() +{ + exit(0); +} + +#define CVT8TO32(col) ((col<<24) | (col<<16) | (col<<8) | col) + +void OSystem_MorphOS::set_palette(const byte *colors, uint start, uint num) +{ + const byte *data = colors; + UWORD changed_colors[256]; + UWORD num_changed = 0; + + for (uint i = start; i != start+num; i++) + { + ULONG color32 = (data[0] << 16) | (data[1] << 8) | data[2]; + if (color32 != ScummColors[i]) + { + if (ScummDepth == 8) + SetRGB32(&ScummScreen->ViewPort, i, CVT8TO32(data[0]), CVT8TO32(data[1]), CVT8TO32(data[2])); + ScummColors16[i] = Scumm16ColFmt16 ? (((data[0]*31)/255) << 11) | (((data[1]*63)/255) << 5) | ((data[ 2 ]*31)/255) : (((data[0]*31)/255) << 10) | (((data[1]*31)/255) << 5) | ((data[2]*31)/255); + ScummColors[i] = color32; + changed_colors[num_changed++] = i; + } + data += 4; + } + + if (ScummScale || ScummDepth != 8) + { + if (DirtyBlocks && num_changed < 200) + { + for (int b = 0; b < BLOCKS_X*BLOCKS_Y; b++) + { + UWORD *block_colors = BlockColors[b]; + UWORD *color_ptr = changed_colors; + for (int c = 0; c < num_changed; c++) + { + if (block_colors[*color_ptr++]) + { + UWORD x, y; + x = b % BLOCKS_X; + y = b / BLOCKS_X; + DirtyBlocks[b] = true; + AddUpdateRect(x*BLOCKSIZE_X, y*BLOCKSIZE_Y, BLOCKSIZE_X, BLOCKSIZE_Y); + break; + } + } + } + } + else + AddUpdateRect(0, 0, ScummBufferWidth, ScummBufferHeight); + } +} + +void OSystem_MorphOS::CreateScreen(CS_DSPTYPE dspType) +{ + ULONG mode = INVALID_ID; + int depths[] = { 8, 15, 16, 24, 32, 0 }; + int i; + Screen *wb = NULL; + + if (dspType != CSDSPTYPE_KEEP) + FullScreenMode = (dspType == CSDSPTYPE_FULLSCREEN) || (dspType == CSDSPTYPE_TOGGLE && !FullScreenMode); + + if (ScummRenderTo && !ScummScreen) + FreeBitMap(ScummRenderTo); + ScummRenderTo = NULL; + + if (ScummWindow) + { + if (ScummScreen == NULL) + { + ScummWinX = ScummWindow->LeftEdge; + ScummWinY = ScummWindow->TopEdge; + } + CloseWindow (ScummWindow); + ScummWindow = NULL; + } + + if (ScummScreen) + { + if (ScummScreenBuffer[0]) + FreeScreenBuffer(ScummScreen, ScummScreenBuffer[0]); + if (ScummScreenBuffer[1]) + FreeScreenBuffer(ScummScreen, ScummScreenBuffer[1]); + CloseScreen(ScummScreen); + ScummScreen = NULL; + } + + ScummScrWidth = ScummBufferWidth << ScummScale; + ScummScrHeight = ScummBufferHeight << ScummScale; + + if (FullScreenMode) + { + for (i = ScummScale; mode == INVALID_ID && depths[i]; i++) + mode = BestCModeIDTags(CYBRBIDTG_NominalWidth, ScummScrWidth, + CYBRBIDTG_NominalHeight, ScummScrHeight, + CYBRBIDTG_Depth, depths[i], + TAG_DONE + ); + ScummDepth = depths[i-1]; + + if (mode == INVALID_ID) + error("Could not find suitable screenmode"); + + ScummScreen = OpenScreenTags(NULL, SA_AutoScroll, TRUE, + SA_Depth, ScummDepth, + SA_Width, STDSCREENWIDTH, + SA_Height, STDSCREENHEIGHT, + SA_DisplayID, mode, + SA_ShowTitle, FALSE, + SA_Type, CUSTOMSCREEN, + SA_Title, "ScummVM MorphOS", + TAG_DONE + ); + + if (ScummScreen == NULL) + error("Failed to open screen"); + + ULONG RealDepth = GetBitMapAttr(&ScummScreen->BitMap, BMA_DEPTH); + if (RealDepth != ScummDepth) + { + warning("Screen did not open in expected depth"); + ScummDepth = RealDepth; + } + ScummScreenBuffer[0] = AllocScreenBuffer(ScummScreen, NULL, SB_SCREEN_BITMAP); + ScummScreenBuffer[1] = AllocScreenBuffer(ScummScreen, NULL, 0); + ScummRenderTo = ScummScreenBuffer[1]->sb_BitMap; + ScummPaintBuffer = 1; + + if (ScummScreenBuffer[0] == NULL || ScummScreenBuffer[1] == NULL) + error("Failed to allocate screen buffer"); + + // Make both buffers black to avoid grey strip on bottom of screen + RastPort rp; + InitRastPort(&rp); + SetRGB32(&ScummScreen->ViewPort, 0, 0, 0, 0); + rp.BitMap = ScummScreenBuffer[0]->sb_BitMap; + FillPixelArray(&ScummScreen->RastPort, 0, 0, ScummScreen->Width, ScummScreen->Height, 0); + rp.BitMap = ScummRenderTo; + FillPixelArray(&rp, 0, 0, ScummScreen->Width, ScummScreen->Height, 0); + + if (ScummDepth == 8) + { + for (int color = 0; color < 256; color++) + { + ULONG r, g, b; + + r = (ScummColors[color] >> 16) & 0xff; + g = (ScummColors[color] >> 8) & 0xff; + b = (ScummColors[color] >> 0) & 0xff; + SetRGB32(&ScummScreen->ViewPort, color, CVT8TO32(r), CVT8TO32(g), CVT8TO32(b)); + } + } + } + else + { + wb = LockPubScreen(NULL); + if (wb == NULL) + error("Could not lock default public screen"); + + ScreenToFront(wb); + } + + ScummWindow = OpenWindowTags(NULL, WA_Left, (wb && ScummWinX >= 0) ? ScummWinX : 0, + WA_Top, wb ? ((ScummWinY >= 0) ? ScummWinY : wb->BarHeight+1) : 0, + WA_InnerWidth, FullScreenMode ? ScummScreen->Width : ScummScrWidth, + WA_InnerHeight, FullScreenMode ? ScummScreen->Height : ScummScrHeight, + WA_Activate, TRUE, + WA_Title, wb ? ScummWndTitle : NULL, + WA_ScreenTitle, wb ? ScummWndTitle : NULL, + WA_Borderless, FullScreenMode, + WA_CloseGadget, !FullScreenMode, + WA_DepthGadget, !FullScreenMode, + WA_DragBar, !FullScreenMode, + WA_ReportMouse, TRUE, + WA_RMBTrap, TRUE, + WA_IDCMP, IDCMP_RAWKEY | + IDCMP_MOUSEMOVE | + IDCMP_CLOSEWINDOW | + IDCMP_MOUSEBUTTONS, + WA_CustomScreen, FullScreenMode ? (ULONG)ScummScreen : (ULONG)wb, + TAG_DONE + ); + + if (wb) + UnlockPubScreen(NULL, wb); + + if (ScummWindow == NULL) + error("Failed to open window"); + + if (!ScummDefaultMouse) + { + SetPointer(ScummWindow, ScummNoCursor, 1, 1, 0, 0); + ScummOrigMouse = false; + } + + if (ScummScreen == NULL) + { + ScummDepth = GetCyberMapAttr(ScummWindow->RPort->BitMap, CYBRMATTR_DEPTH); + if (ScummDepth == 8) + error("Workbench screen must be running in 15 bit or higher"); + + ScummRenderTo = AllocBitMap(ScummScrWidth, ScummScrHeight, ScummDepth, BMF_MINPLANES, ScummWindow->RPort->BitMap); + if (ScummRenderTo == NULL) + error("Failed to allocate bitmap"); + } + + if ((ScummDepth == 15 && Scumm16ColFmt16) || (ScummDepth == 16 && !Scumm16ColFmt16)) + { + for (int col = 0; col < 256; col++) + { + int r = (ScummColors[col] >> 16) & 0xff; + int g = (ScummColors[col] >> 8) & 0xff; + int b = ScummColors[col] & 0xff; + ScummColors16[col] = (Scumm16ColFmt16 == false) ? (((r*31)/255) << 11) | (((g*63)/255) << 5) | ((b*31)/255) : (((r*31)/255) << 10) | (((g*31)/255) << 5) | ((b*31)/255); + } + + Scumm16ColFmt16 = (ScummDepth == 16); + } + + if (Scaler) + { + delete Scaler; + Scaler = NULL; + } + + if (ScummScale) + { + Scaler = MorphOSScaler::Create(ScummScaler, ScummBuffer, ScummBufferWidth, ScummBufferHeight, ScummColors, ScummColors16, ScummRenderTo); + if (Scaler == NULL) + { + warning("Failed to create scaler - scaling will be disabled"); + SwitchScalerTo(ST_NONE); + } + } + + AddUpdateRect(0, 0, ScummBufferWidth, ScummBufferHeight); +} + +void OSystem_MorphOS::SwitchScalerTo(SCALERTYPE newScaler) +{ + if (newScaler == ST_NONE && ScummScale != 0) + { + if (Scaler) + { + delete Scaler; + Scaler = NULL; + } + ScummScale = 0; + ScummScaler = ST_NONE; + CreateScreen(ScummScreen ? CSDSPTYPE_FULLSCREEN : CSDSPTYPE_WINDOWED); + } + else + { + if (ScummScale == 0) + { + ScummScale = 1; + ScummScaler = newScaler; + CreateScreen(ScummScreen ? CSDSPTYPE_FULLSCREEN : CSDSPTYPE_WINDOWED); + } + else if (ScummScaler != newScaler) + { + ScummScaler = newScaler; + if (Scaler) + delete Scaler; + Scaler = MorphOSScaler::Create(ScummScaler, ScummBuffer, ScummBufferWidth, ScummBufferHeight, ScummColors, ScummColors16, ScummRenderTo); + if (Scaler == NULL) + { + warning("Failed to create scaler - scaling will be disabled"); + SwitchScalerTo(ST_NONE); + } + else + AddUpdateRect(0, 0, ScummBufferWidth, ScummBufferHeight); + } + } +} + +bool OSystem_MorphOS::poll_event(Event *event) +{ + IntuiMessage *ScummMsg; + + if (ScummMsg = (IntuiMessage *) GetMsg(ScummWindow->UserPort)) + { + switch (ScummMsg->Class) + { + case IDCMP_RAWKEY: + { + InputEvent FakedIEvent; + char charbuf; + int qual = 0; + + memset(&FakedIEvent, 0, sizeof (InputEvent)); + FakedIEvent.ie_Class = IECLASS_RAWKEY; + FakedIEvent.ie_Code = ScummMsg->Code; + + if (ScummMsg->Qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_RALT)) + qual |= KBD_ALT; + if (ScummMsg->Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) + qual |= KBD_SHIFT; + if (ScummMsg->Qualifier & IEQUALIFIER_CONTROL) + qual |= KBD_CTRL; + event->kbd.flags = qual; + + event->event_code = EVENT_KEYDOWN; + + if (ScummMsg->Code >= 0x50 && ScummMsg->Code <= 0x59) + { + /* + * Function key + */ + event->kbd.ascii = (ScummMsg->Code-0x50)+315; + event->kbd.keycode = 0; + } + else if (MapRawKey(&FakedIEvent, &charbuf, 1, NULL) == 1) + { + if (qual == KBD_CTRL) + { + switch (charbuf) + { + case 'z': + ReplyMsg((Message *) ScummMsg); + quit(); + } + } + else if (qual == KBD_ALT) + { + if (charbuf >= '0' && charbuf <= '9') + { + SCALERTYPE new_scaler = MorphOSScaler::FindByIndex(charbuf-'0'); + ReplyMsg((Message *) ScummMsg); + if (new_scaler != ST_INVALID) + SwitchScalerTo(new_scaler); + return false; + } + else if (charbuf == 'x') + { + ReplyMsg((Message *) ScummMsg); + quit(); + } + else if (charbuf == 0x0d) + { + ReplyMsg((Message *) ScummMsg); + CreateScreen(CSDSPTYPE_TOGGLE); + return false; + } + } + + event->kbd.ascii = charbuf; + event->kbd.keycode = event->kbd.ascii; + } + break; + } + + case IDCMP_MOUSEMOVE: + { + LONG newx, newy; + + newx = (ScummMsg->MouseX-ScummWindow->BorderLeft) >> ScummScale; + newy = (ScummMsg->MouseY-ScummWindow->BorderTop) >> ScummScale; + + if (!FullScreenMode && !ScummDefaultMouse) + { + if (newx < 0 || newx > ScummBufferWidth || + newy < 0 || newy > ScummBufferHeight + ) + { + if (!ScummOrigMouse) + { + ScummOrigMouse = true; + ClearPointer(ScummWindow); + } + } + else if (ScummOrigMouse) + { + ScummOrigMouse = false; + SetPointer(ScummWindow, ScummNoCursor, 1, 1, 0, 0); + } + } + else if (FullScreenMode) + newy = newy <? (ScummScrHeight >> ScummScale)-2; + + event->event_code = EVENT_MOUSEMOVE; + event->mouse.x = newx; + event->mouse.y = newy; + break; + } + + case IDCMP_MOUSEBUTTONS: + { + int newx, newy; + + newx = (ScummMsg->MouseX-ScummWindow->BorderLeft) >> ScummScale; + newy = (ScummMsg->MouseY-ScummWindow->BorderTop) >> ScummScale; + + switch (ScummMsg->Code) + { + case SELECTDOWN: + event->event_code = EVENT_LBUTTONDOWN; + break; + + case SELECTUP: + event->event_code = EVENT_LBUTTONUP; + break; + + case MENUDOWN: + event->event_code = EVENT_RBUTTONDOWN; + break; + + case MENUUP: + event->event_code = EVENT_RBUTTONUP; + break; + + default: + ReplyMsg((Message *)ScummMsg); + return false; + } + event->mouse.x = newx; + event->mouse.y = newy; + break; + } + + case IDCMP_CLOSEWINDOW: + ReplyMsg((Message *)ScummMsg); + exit(0); + } + + if (ScummMsg) + ReplyMsg((Message *) ScummMsg); + + return true; + } + + return false; +} + +void OSystem_MorphOS::set_shake_pos(int shake_pos) +{ + ScummShakePos = shake_pos; + AddUpdateRect(0, 0, 320, 200); +} + +#define MOUSE_INTERSECTS(x, y, w, h) \ + (!((MouseOldX+MouseOldWidth <= x ) || (MouseOldX >= x+w) || \ + (MouseOldY+MouseOldHeight <= y) || (MouseOldY >= y+h))) + +/* Copy part of bitmap */ +void OSystem_MorphOS::copy_rect(const byte *src, int pitch, int x, int y, int w, int h) +{ + byte *dst; + + if (x < 0) { w+=x; src-=x; x = 0; } + if (y < 0) { h+=y; src-=y*pitch; y = 0; } + if (w >= ScummBufferWidth-x) { w = ScummBufferWidth - x; } + if (h >= ScummBufferHeight-y) { h = ScummBufferHeight - y; } + + if (w <= 0 || h <= 0) + return; + + if (MouseDrawn) + { + if (MOUSE_INTERSECTS(x, y, w, h)) + UndrawMouse(); + } + + AddUpdateRect(x, y, w, h); + + dst = (byte *)ScummBuffer+y*ScummBufferWidth + x; + if (DirtyBlocks) + { + int cx, cy; + int block = BLOCK_ID(x, y); + int line_block = block; + int start_block = BLOCKSIZE_X-(x % BLOCKSIZE_X); + int start_y_block = BLOCKSIZE_Y-(y % BLOCKSIZE_Y); + int next_block; + int next_y_block; + UWORD *block_cols = BlockColors[block]; + + if (start_block == 0) + start_block = BLOCKSIZE_X; + if (start_y_block == 0) + start_y_block = BLOCKSIZE_Y; + + next_block = start_block; + next_y_block = start_y_block; + for (cy = 0; cy < h; cy++) + { + for (cx = 0; cx < w; cx++) + { + UWORD old_pixel = *dst; + UWORD src_pixel = *src++; + if (old_pixel != src_pixel) + { + *dst++ = src_pixel; + block_cols[old_pixel]--; + block_cols[src_pixel]++; + } + else + dst++; + if (--next_block == 0) + { + block++; + block_cols = BlockColors[block]; + next_block = BLOCKSIZE_X; + } + } + if (--next_y_block == 0) + { + line_block += BLOCKS_X; + next_y_block = BLOCKSIZE_Y; + } + block = line_block; + block_cols = BlockColors[block]; + next_block = start_block; + dst += ScummBufferWidth-w; + src += pitch-w; + } + } + else + { + do + { + memcpy(dst, src, w); + dst += ScummBufferWidth; + src += pitch; + } while (--h); + } +} + +bool OSystem_MorphOS::AddUpdateRect(WORD x, WORD y, WORD w, WORD h) +{ + if (x < 0) { w+=x; x = 0; } + if (y < 0) { h+=y; y = 0; } + if (w >= ScummBufferWidth-x) { w = ScummBufferWidth - x; } + if (h >= ScummBufferHeight-y) { h = ScummBufferHeight - y; } + + if (w <= 0 || h <= 0) + return false; + + Rectangle update_rect = { x, y, x+w, y+h }; + OrRectRegion(NewUpdateRegion, &update_rect); + ScreenChanged = true; + + return true; +} + +void OSystem_MorphOS::update_screen() +{ + DrawMouse(); + + if (!ScreenChanged) + return; + + OrRegionRegion(NewUpdateRegion, UpdateRegion); + + if (ScummShakePos) + { + RastPort rp; + + InitRastPort(&rp); + rp.BitMap = ScummRenderTo; + + uint32 src_y = 0; + uint32 dest_y = 0; + if (ScummShakePos < 0) + src_y = -ScummShakePos; + else + dest_y = ScummShakePos; + + if (!ScummScale) + { + if (ScummDepth == 8) + WritePixelArray(ScummBuffer, 0, src_y, ScummBufferWidth, &rp, 0, dest_y, ScummBufferWidth, ScummBufferHeight-src_y-dest_y, RECTFMT_LUT8); + else + WriteLUTPixelArray(ScummBuffer, 0, src_y, ScummBufferWidth, &rp, ScummColors, 0, dest_y, ScummBufferWidth, ScummBufferHeight-src_y-dest_y, CTABFMT_XRGB8); + } + else if (Scaler->Prepare(ScummRenderTo)) + { + Scaler->Scale(0, src_y, 0, dest_y, ScummBufferWidth, ScummBufferHeight-src_y-dest_y); + Scaler->Finish(); + } + + if (ScummShakePos < 0) + FillPixelArray(&rp, 0, (ScummBufferHeight-1) << ScummScale, ScummScrWidth, -ScummShakePos << ScummScale, 0); + else + FillPixelArray(&rp, 0, 0, ScummScrWidth, ScummShakePos << ScummScale, 0); + } + else if (!ScummScale) + { + RastPort rp; + + InitRastPort(&rp); + rp.BitMap = ScummRenderTo; + + uint32 src_x, src_y; + uint32 src_w, src_h; + uint32 reg_x, reg_y; + RegionRectangle *update_rect = UpdateRegion->RegionRectangle; + + reg_x = UpdateRegion->bounds.MinX; + reg_y = UpdateRegion->bounds.MinY; + while (update_rect) + { + src_x = update_rect->bounds.MinX; + src_y = update_rect->bounds.MinY; + src_w = update_rect->bounds.MaxX-src_x; + src_h = update_rect->bounds.MaxY-src_y; + src_x += reg_x; + src_y += reg_y; + + if (src_x) src_x--; + if (src_y) src_y--; + src_w += 2; + if (src_x+src_w >= ScummBufferWidth) + src_w = ScummBufferWidth-src_x; + src_h += 2; + if (src_y+src_h >= ScummBufferHeight) + src_h = ScummBufferHeight-src_y; + + if (ScummDepth == 8) + WritePixelArray(ScummBuffer, src_x, src_y, ScummBufferWidth, &rp, src_x, src_y, src_w, src_h, RECTFMT_LUT8); + else + WriteLUTPixelArray(ScummBuffer, src_x, src_y, ScummBufferWidth, &rp, ScummColors, src_x, src_y, src_w, src_h, CTABFMT_XRGB8); + + update_rect = update_rect->Next; + } + } + else + { + uint32 src_x, src_y; + uint32 src_w, src_h; + uint32 reg_x, reg_y; + RegionRectangle *update_rect = UpdateRegion->RegionRectangle; + + reg_x = UpdateRegion->bounds.MinX; + reg_y = UpdateRegion->bounds.MinY; + + if (!Scaler->Prepare(ScummRenderTo)) + update_rect = NULL; + + while (update_rect) + { + src_x = update_rect->bounds.MinX; + src_y = update_rect->bounds.MinY; + src_w = update_rect->bounds.MaxX-src_x; + src_h = update_rect->bounds.MaxY-src_y; + src_x += reg_x; + src_y += reg_y; + + if (src_x) src_x--; + if (src_y) src_y--; + src_w += 2; + if (src_x+src_w >= ScummBufferWidth) + src_w = ScummBufferWidth-src_x; + src_h += 2; + if (src_y+src_h >= ScummBufferHeight) + src_h = ScummBufferHeight-src_y; + + Scaler->Scale(src_x, src_y, src_x, src_y, src_w, src_h); + update_rect = update_rect->Next; + } + Scaler->Finish(); + } + + if (ScummScreen) + { + while (!ChangeScreenBuffer(ScummScreen, ScummScreenBuffer[ScummPaintBuffer])); + ScummPaintBuffer = !ScummPaintBuffer; + ScummRenderTo = ScummScreenBuffer[ScummPaintBuffer]->sb_BitMap; + } + else + { + int32 x = (UpdateRegion->bounds.MinX-1) << ScummScale; + int32 y = (UpdateRegion->bounds.MinY-1) << ScummScale; + if (x < 0) x = 0; + if (y < 0) y = 0; + int32 w = (UpdateRegion->bounds.MaxX << ScummScale)-x+(1 << ScummScale); + int32 h = (UpdateRegion->bounds.MaxY << ScummScale)-y+(1 << ScummScale); + if (x+w > ScummScrWidth) w = ScummScrWidth-x; + if (y+h > ScummScrHeight) h = ScummScrHeight-y; + BltBitMapRastPort(ScummRenderTo, x, y, ScummWindow->RPort, ScummWindow->BorderLeft+x, ScummWindow->BorderTop+y, w, h, ABNC | ABC); + WaitBlit(); + } + + Region *new_region_part = NewUpdateRegion; + NewUpdateRegion = UpdateRegion; + ClearRegion(NewUpdateRegion); + UpdateRegion = new_region_part; + + ScreenChanged = false; + memset(DirtyBlocks, 0, BLOCKS_X*BLOCKS_Y*sizeof (bool)); +} + +void OSystem_MorphOS::DrawMouse() +{ + int x,y; + byte *dst,*bak; + byte color; + + if (MouseDrawn || !MouseVisible) + return; + MouseDrawn = true; + + const int ydraw = MouseY - MouseHotspotY; + const int xdraw = MouseX - MouseHotspotX; + const int w = MouseWidth; + const int h = MouseHeight; + bak = MouseBackup; + byte *buf = MouseImage; + + MouseOldX = xdraw; + MouseOldY = ydraw; + MouseOldWidth = w; + MouseOldHeight = h; + + AddUpdateRect(xdraw, ydraw, w, h); + + dst = (byte*)ScummBuffer + ydraw*ScummBufferWidth + xdraw; + bak = MouseBackup; + + for (y = 0; y < h; y++, dst += ScummBufferWidth, bak += MAX_MOUSE_W, buf += w) + { + if ((uint)(ydraw+y) < ScummBufferHeight) + { + for( x = 0; x<w; x++ ) + { + if ((uint)(xdraw+x) < ScummBufferWidth) + { + bak[x] = dst[x]; + if ((color=buf[x])!=0xFF) + dst[ x ] = color; + } + } + } + else + break; + } +} + +void OSystem_MorphOS::UndrawMouse() +{ + int x,y; + byte *dst,*bak; + + if (!MouseDrawn) + return; + MouseDrawn = false; + + dst = (byte*)ScummBuffer + MouseOldY*ScummBufferWidth + MouseOldX; + bak = MouseBackup; + + AddUpdateRect(MouseOldX, MouseOldY, MouseOldWidth, MouseOldHeight); + + for (y = 0; y < MouseOldHeight; y++, bak += MAX_MOUSE_W, dst += ScummBufferWidth) + { + if ((uint)(MouseOldY + y) < ScummBufferHeight) + { + for (x = 0; x < MouseOldWidth; x++) + { + if ((uint)(MouseOldX + x) < ScummBufferWidth) + dst[x] = bak[x]; + } + } + else + break; + } +} + +bool OSystem_MorphOS::show_mouse(bool visible) +{ + if (MouseVisible == visible) + return visible; + + bool last = MouseVisible; + MouseVisible = visible; + + if (!visible) + UndrawMouse(); + + return last; +} + +void OSystem_MorphOS::set_mouse_pos(int x, int y) +{ + if (x != MouseX || y != MouseY) + { + MouseX = x; + MouseY = y; + UndrawMouse(); + } +} + +void OSystem_MorphOS::set_mouse_cursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y) +{ + MouseWidth = w; + MouseHeight = h; + + MouseHotspotX = hotspot_x; + MouseHotspotY = hotspot_y; + + MouseImage = (byte*)buf; + + UndrawMouse(); +} + +bool OSystem_MorphOS::set_sound_proc(void *param, OSystem::SoundProc *proc, byte format) +{ + static EmulFunc MySoundEmulFunc; + + SoundProc = proc; + SoundParam = param; + + /* + * Create Sound Thread + */ + MySoundEmulFunc.Trap = TRAP_FUNC; + MySoundEmulFunc.Address = (ULONG)&morphos_sound_thread; + MySoundEmulFunc.StackSize = 8192; + MySoundEmulFunc.Extension = 0; + MySoundEmulFunc.Arg1 = (ULONG)this; + MySoundEmulFunc.Arg2 = AHIST_S16S; + + soundProcTags[0].ti_Data = (ULONG)&MySoundEmulFunc; + ScummSoundThread = CreateNewProc(soundProcTags); + + if (!ScummSoundThread) + { + puts("Failed to create sound thread"); + exit(1); + } + + return true; +} + +void OSystem_MorphOS::fill_sound(byte *stream, int len) +{ + if (SoundProc) + SoundProc(SoundParam, stream, len); + else + memset(stream, 0x0, len); +} + +void OSystem_MorphOS::init_size(uint w, uint h) +{ + /* + * Allocate image buffer + */ + ScummBuffer = AllocVec(w*h, MEMF_CLEAR); + + if (ScummBuffer == NULL) + { + puts("Couldn't allocate image buffer"); + exit(1); + } + + memset(ScummColors, 0, 256*sizeof (ULONG)); + + ScummBufferWidth = w; + ScummBufferHeight = h; + + DirtyBlocks = (bool *) AllocVec(BLOCKS_X*BLOCKS_Y*sizeof (bool), MEMF_CLEAR); + if (DirtyBlocks) + { + BlockColors = (UWORD **) AllocVec(BLOCKS_X*BLOCKS_Y*sizeof (UWORD *), MEMF_CLEAR); + if (BlockColors) + { + int b; + + for (b = 0; b < BLOCKS_X*BLOCKS_Y; b++) + { + BlockColors[b] = (UWORD *) AllocVec(256*sizeof (UWORD), MEMF_CLEAR); + if (BlockColors[b] == NULL) + break; + BlockColors[b][0] = BLOCKSIZE_X*BLOCKSIZE_Y; + } + + if (b < BLOCKS_X*BLOCKS_Y) + { + for (--b; b >= 0; --b) + FreeVec(BlockColors[b]); + FreeVec(BlockColors); + BlockColors = NULL; + } + } + + if (!BlockColors) + { + FreeVec(DirtyBlocks); + DirtyBlocks = NULL; + } + } + + CreateScreen(CSDSPTYPE_KEEP); +} + diff --git a/backends/morphos/morphos.h b/backends/morphos/morphos.h new file mode 100644 index 0000000000..75d2c79f7b --- /dev/null +++ b/backends/morphos/morphos.h @@ -0,0 +1,206 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002 Rüdiger Hanke (MorphOS port) + * + * 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. + * + * MorphOS-specific header file + * + * $Header$ + * + */ + +#ifndef MORPHOS_MORPHOS_H +#define MORPHOS_MORPHOS_H + +#include <exec/semaphores.h> +#include <devices/amidi.h> +#include <graphics/regions.h> +#include <intuition/intuition.h> +#include <intuition/screens.h> +#include <libraries/cdda.h> + +#include "morphos_scaler.h" + +class OSystem_MorphOS : public OSystem +{ + public: + OSystem_MorphOS(int game_id, SCALERTYPE gfx_mode, bool full_screen); + virtual ~OSystem_MorphOS(); + + // Set colors of the palette + virtual void set_palette(const byte *colors, uint start, uint num); + + // Set the size of the video bitmap. + // Typically, 320x200 + virtual void init_size(uint w, uint h); + + // Draw a bitmap to screen. + // The screen will not be updated to reflect the new bitmap + virtual void copy_rect(const byte *buf, int pitch, int x, int y, int w, int h); + + // Update the dirty areas of the screen + virtual void update_screen(); + + // Either show or hide the mouse cursor + virtual bool show_mouse(bool visible); + + // Set the position of the mouse cursor + virtual void set_mouse_pos(int x, int y); + + // Set the bitmap that's used when drawing the cursor. + virtual 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. + virtual void set_shake_pos(int shake_pos); + + // Get the number of milliseconds since the program was started. + virtual uint32 get_msecs(); + + // Delay for a specified amount of milliseconds + virtual void delay_msecs(uint msecs); + + // Add a new callback timer + virtual void set_timer(int timer, int (*callback)(int)); + + // Mutex handling + virtual void *create_mutex(void); + virtual void lock_mutex(void *mutex); + virtual void unlock_mutex(void *mutex); + virtual void delete_mutex(void *mutex); + + // Create a thread + virtual void *create_thread(ThreadProc *proc, void *param); + + // Get the next event. + // Returns true if an event was retrieved. + virtual bool poll_event(Event *event); + + // Set the function to be invoked whenever samples need to be generated + virtual bool set_sound_proc(void *param, SoundProc *proc, byte format); + void fill_sound (byte * stream, int len); + + virtual uint32 property(int param, Property *value); + + // Poll cdrom status + // Returns true if cd audio is playing + virtual bool poll_cdrom(); + + // Play cdrom audio track + virtual void play_cdrom(int track, int num_loops, int start_frame, int length); + + // Stop cdrom audio track + virtual void stop_cdrom(); + + // Update cdrom audio status + virtual void update_cdrom(); + + // Quit + virtual void quit(); + + static OSystem_MorphOS *create(int game_id, SCALERTYPE gfx_scaler, bool full_screen); + + static bool OpenATimer(MsgPort **port, IORequest **req, ULONG unit, bool required = true); + + private: + typedef enum { CSDSPTYPE_WINDOWED, CSDSPTYPE_FULLSCREEN, CSDSPTYPE_TOGGLE, CSDSPTYPE_KEEP } CS_DSPTYPE; + + static const int MAX_MOUSE_W = 40; + static const int MAX_MOUSE_H = 40; + + void CreateScreen(CS_DSPTYPE dspType); + void SwitchScalerTo(SCALERTYPE newScaler); + bool AddUpdateRect(WORD x, WORD y, WORD w, WORD h); + + void DrawMouse(); + void UndrawMouse(); + + /* Display-related attributes */ + Screen *ScummScreen; + Window *ScummWindow; + char ScummWndTitle[125]; + APTR ScummBuffer; + int ScummBufferWidth; + int ScummBufferHeight; + ScreenBuffer *ScummScreenBuffer[2]; + BitMap *ScummRenderTo; + ULONG ScummPaintBuffer; + int ScummScrWidth; + int ScummScrHeight; + int ScummDepth; + bool Scumm16ColFmt16; + UWORD *ScummNoCursor; + ULONG ScummColors[256]; + USHORT ScummColors16[256]; + WORD ScummWinX; + WORD ScummWinY; + bool ScummDefaultMouse; + bool ScummOrigMouse; + int ScummShakePos; + bool FullScreenMode; + bool ScreenChanged; + UWORD **BlockColors; + bool *DirtyBlocks; + Region *UpdateRegion; + Region *NewUpdateRegion; + + /* Sound-related attributes */ + Process *ScummMusicThread; + Process *ScummSoundThread; + SoundProc *SoundProc; + void *SoundParam; + + /* CD-ROM related attributes */ + CDRIVEPTR CDrive; + ULONG CDDATrackOffset; + + /* Scaling-related attributes */ + SCALERTYPE ScummScaler; + int ScummScale; + MorphOSScaler *Scaler; + + /* Mouse cursor-related attributes */ + bool MouseVisible, MouseDrawn; + int MouseX, MouseY; + int MouseWidth, MouseHeight; + int MouseOldX, MouseOldY; + int MouseOldWidth, MouseOldHeight; + int MouseHotspotX, MouseHotspotY; + byte *MouseImage, MouseBackup[MAX_MOUSE_W*MAX_MOUSE_H]; + + /* Timer-related attributes */ + MsgPort *TimerMsgPort; + timerequest *TimerIORequest; + + /* Game-related attributes */ + int GameID; +}; + +int morphos_sound_thread(OSystem_MorphOS *syst, ULONG SampleType); +bool init_morphos_music(ULONG MidiUnit); +void exit_morphos_music(); + +int morphos_main(int argc, char *argv[]); + +extern OSystem_MorphOS *TheSystem; +extern SignalSemaphore ScummMusicThreadRunning; +extern SignalSemaphore ScummSoundThreadRunning; + +extern STRPTR ScummMusicDriver; +extern LONG ScummMidiUnit; +extern IOMidiRequest *ScummMidiRequest; +extern timerequest *MusicTimerIORequest; + +#endif + diff --git a/backends/morphos/morphos_scaler.cpp b/backends/morphos/morphos_scaler.cpp new file mode 100644 index 0000000000..dca4383016 --- /dev/null +++ b/backends/morphos/morphos_scaler.cpp @@ -0,0 +1,823 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002 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 "stdafx.h" +#include "scumm.h" + +#include <exec/types.h> +#include <cybergraphics/cybergraphics.h> + +#include <proto/cybergraphics.h> + +#include "morphos.h" +#include "morphos_scaler.h" + +#define GET_RESULT(A, B, C, D) ((A != C || A != D) - (B != C || B != D)) +#define INTERPOLATE(A, B) (((A & colorMask) >> 1) + ((B & colorMask) >> 1) + (A & B & lowPixelMask)) +#define Q_INTERPOLATE(A, B, C, D) ((A & qcolorMask) >> 2) + ((B & qcolorMask) >> 2) + ((C & qcolorMask) >> 2) + ((D & qcolorMask) >> 2) + ((((A & qlowpixelMask) + (B & qlowpixelMask) + (C & qlowpixelMask) + (D & qlowpixelMask)) >> 2) & qlowpixelMask) +#define SWAP_WORD(word) word = ((word & 0xff) << 8) | (word >> 8) + +MorphOSScaler::GfxScaler MorphOSScaler::ScummScalers[11] + = { { "none", "normal", ST_NONE }, + { "Point", "2x", ST_POINT }, + { "AdvMame2x", "advmame2x", ST_ADVMAME2X }, + { "SuperEagle", "supereagle", ST_SUPEREAGLE }, + { "Super2xSaI", "super2xsai", ST_SUPER2XSAI }, + { NULL, NULL, ST_INVALID }, + { NULL, NULL, ST_INVALID }, + { NULL, NULL, ST_INVALID }, + { NULL, NULL, ST_INVALID }, + { NULL, NULL, ST_INVALID }, + // This is the end marker ... do not assign a scaler to it! + { NULL, NULL, ST_INVALID } + }; + +MorphOSScaler::MorphOSScaler(APTR buffer, int width, int height, ULONG *col_table, UWORD *col_table16, BitMap *bmap) +{ + dest = NULL; + handle = NULL; + + Buffer = buffer; + BufferWidth = width; + BufferHeight = height; + + ScummColors = col_table; + ScummColors16 = col_table16; + + /* Initialize scaling stuff */ + int minr, ming, minb; + ULONG depth = GetCyberMapAttr(bmap, CYBRMATTR_DEPTH); + + if (depth > 16) + { + minr = 1 << 16; + ming = 1 << 8; + minb = 1; + } + else + { + minr = 1 << ((depth == 15) ? 10 : 11); + ming = 1 << 5; + minb = 1; + } + + int pixfmt = GetCyberMapAttr(bmap, CYBRMATTR_PIXFMT); + + ScummPCMode = false; + if (pixfmt == PIXFMT_RGB15PC || pixfmt == PIXFMT_BGR15PC || + pixfmt == PIXFMT_RGB16PC || pixfmt == PIXFMT_BGR16PC) + ScummPCMode = true; + + colorMask = (MakeColor(pixfmt, 255, 0, 0) - minr) | (MakeColor(pixfmt, 0, 255, 0) - ming) | (MakeColor(pixfmt, 0, 0, 255) - minb); + lowPixelMask = minr | ming | minb; + qcolorMask = (MakeColor(pixfmt, 255, 0, 0) - 3*minr) | (MakeColor(pixfmt, 0, 255, 0) - 3*ming) | (MakeColor(pixfmt, 0, 0, 255) - 3*minb); + qlowpixelMask = (minr * 3) | (ming * 3) | (minb * 3); + redblueMask = MakeColor(pixfmt, 255, 0, 255); + greenMask = MakeColor(pixfmt, 0, 255, 0); + + PixelsPerMask = (depth <= 16) ? 2 : 1; + + if (PixelsPerMask == 2) + { + colorMask |= (colorMask << 16); + qcolorMask |= (qcolorMask << 16); + lowPixelMask |= (lowPixelMask << 16); + qlowpixelMask |= (qlowpixelMask << 16); + } +} + +MorphOSScaler::~MorphOSScaler() +{ + Finish(); +} + +MorphOSScaler *MorphOSScaler::Create(SCALERTYPE scaler_type, APTR buffer, int width, int height, ULONG *col_table, UWORD *col_table16, BitMap *bmap) +{ + MorphOSScaler *new_scaler = NULL; + + switch (scaler_type) + { + case ST_POINT: + new_scaler = new PointScaler(buffer, width, height, col_table, col_table16, bmap); + break; + + case ST_ADVMAME2X: + new_scaler = new AdvMame2xScaler(buffer, width, height, col_table, col_table16, bmap); + break; + + case ST_SUPEREAGLE: + new_scaler = new SuperEagleScaler(buffer, width, height, col_table, col_table16, bmap); + break; + + case ST_SUPER2XSAI: + new_scaler = new Super2xSaIScaler(buffer, width, height, col_table, col_table16, bmap); + break; + + default: + warning("Invalid scaler requested - falling back to Super2xSaI"); + new_scaler = new Super2xSaIScaler(buffer, width, height, col_table, col_table16, bmap); + break; + } + + return new_scaler; +} + +bool MorphOSScaler::Prepare(BitMap *render_bmap) +{ + handle = LockBitMapTags(render_bmap, LBMI_BYTESPERPIX, &dest_bpp, + LBMI_BYTESPERROW, &dest_pitch, + LBMI_BASEADDRESS, &dest, + LBMI_PIXFMT, &dest_pixfmt, + TAG_DONE); + + return handle != NULL; +} + +void MorphOSScaler::Finish() +{ + if (handle) + { + UnLockBitMap(handle); + handle = NULL; + } +} + +uint32 MorphOSScaler::MakeColor(int pixfmt, int r, int g, int b) +{ + uint32 col = 0; + + switch (pixfmt) + { + case PIXFMT_RGB15: + case PIXFMT_RGB15PC: + col = (((r*31)/255) << 10) | (((g*31)/255) << 5) | ((b*31)/255); + break; + + case PIXFMT_BGR15: + case PIXFMT_BGR15PC: + col = (((b*31)/255) << 10) | (((g*31)/255) << 5) | ((r*31)/255); + break; + + case PIXFMT_RGB16: + case PIXFMT_RGB16PC: + col = (((r*31)/255) << 11) | (((g*63)/255) << 5) | ((b*31)/255); + break; + + case PIXFMT_BGR16: + case PIXFMT_BGR16PC: + col = (((b*31)/255) << 11) | (((g*63)/255) << 5) | ((r*31)/255); + break; + + case PIXFMT_RGB24: + case PIXFMT_ARGB32: + col = (r << 16) | (g << 8) | b; + break; + + case PIXFMT_BGR24: + col = (b << 16) | (g << 8) | r; + break; + + case PIXFMT_BGRA32: + col = (b << 24) | (g << 16) | (r << 8); + break; + + case PIXFMT_RGBA32: + col = (r << 24) | (g << 16) | (b << 8); + break; + + default: + error("Unsupported pixel format: %d. Please contact author at tomjoad@muenster.de.", pixfmt); + } + + return col; +} + +void Super2xSaIScaler::Scale(uint32 src_x, uint32 src_y, uint32 dest_x, uint32 dest_y, uint32 width, uint32 height) +{ + unsigned int x, y; + unsigned long color[16]; + byte *src; + + if (!handle) + return; + + src = ((byte *)Buffer)+src_y*BufferWidth+src_x; + + /* Point to the first 3 lines. */ + src_line[0] = src; + src_line[1] = src; + src_line[2] = src + BufferWidth; + src_line[3] = src + BufferWidth * 2; + + dst_line[0] = dest+dest_y*2*dest_pitch+dest_x*2*dest_bpp; + dst_line[1] = dst_line[0]+dest_pitch; + + if (PixelsPerMask == 2) + { + byte *sbp; + sbp = src_line[0]; + color[0] = ScummColors16[*sbp]; color[1] = color[0]; color[2] = color[0]; color[3] = color[0]; + color[4] = color[0]; color[5] = color[0]; color[6] = ScummColors16[*(sbp+1)]; color[7] = ScummColors16[*(sbp+2)]; + sbp = src_line[2]; + color[8] = ScummColors16[*sbp]; color[9] = color[8]; color[10] = ScummColors16[*(sbp+1)]; color[11] = ScummColors16[*(sbp+2)]; + sbp = src_line[3]; + color[12] = ScummColors16[*sbp]; color[13] = color[12]; color[14] = ScummColors16[*(sbp+1)]; color[15] = ScummColors16[*(sbp+2)]; + } + else + { + byte *lbp; + lbp = src_line[0]; + color[0] = ScummColors[*lbp]; color[1] = color[0]; color[2] = color[0]; color[3] = color[0]; + color[4] = color[0]; color[5] = color[0]; color[6] = ScummColors[*(lbp+1)]; color[7] = ScummColors[*(lbp+2)]; + lbp = src_line[2]; + color[8] = ScummColors[*lbp]; color[9] = color[8]; color[10] = ScummColors[*(lbp+1)]; color[11] = ScummColors[*(lbp+2)]; + lbp = src_line[3]; + color[12] = ScummColors[*lbp]; color[13] = color[12]; color[14] = ScummColors[*(lbp+1)]; color[15] = ScummColors[*(lbp+2)]; + } + + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + unsigned long product1a, product1b, product2a, product2b; + +//--------------------------------------- B0 B1 B2 B3 0 1 2 3 +// 4 5* 6 S2 -> 4 5* 6 7 +// 1 2 3 S1 8 9 10 11 +// A0 A1 A2 A3 12 13 14 15 +//-------------------------------------- + if (color[9] == color[6] && color[5] != color[10]) + { + product2b = color[9]; + product1b = product2b; + } + else if (color[5] == color[10] && color[9] != color[6]) + { + product2b = color[5]; + product1b = product2b; + } + else if (color[5] == color[10] && color[9] == color[6]) + { + int r = 0; + + r += GET_RESULT(color[6], color[5], color[8], color[13]); + r += GET_RESULT(color[6], color[5], color[4], color[1]); + r += GET_RESULT(color[6], color[5], color[14], color[11]); + r += GET_RESULT(color[6], color[5], color[2], color[7]); + + if (r > 0) + product1b = color[6]; + else if (r < 0) + product1b = color[5]; + else + product1b = INTERPOLATE(color[5], color[6]); + + product2b = product1b; + + } + else + { + if (color[6] == color[10] && color[10] == color[13] && color[9] != color[14] && color[10] != color[12]) + product2b = Q_INTERPOLATE(color[10], color[10], color[10], color[9]); + else if (color[5] == color[9] && color[9] == color[14] && color[13] != color[10] && color[9] != color[15]) + product2b = Q_INTERPOLATE(color[9], color[9], color[9], color[10]); + else + product2b = INTERPOLATE(color[9], color[10]); + + if (color[6] == color[10] && color[6] == color[1] && color[5] != color[2] && color[6] != color[0]) + product1b = Q_INTERPOLATE(color[6], color[6], color[6], color[5]); + else if (color[5] == color[9] && color[5] == color[2] && color[1] != color[6] && color[5] != color[3]) + product1b = Q_INTERPOLATE(color[6], color[5], color[5], color[5]); + else + product1b = INTERPOLATE(color[5], color[6]); + } + + if (color[5] == color[10] && color[9] != color[6] && color[4] == color[5] && color[5] != color[14]) + product2a = INTERPOLATE(color[9], color[5]); + else if (color[5] == color[8] && color[6] == color[5] && color[4] != color[9] && color[5] != color[12]) + product2a = INTERPOLATE(color[9], color[5]); + else + product2a = color[9]; + + if (color[9] == color[6] && color[5] != color[10] && color[8] == color[9] && color[9] != color[2]) + product1a = INTERPOLATE(color[9], color[5]); + else if (color[4] == color[9] && color[10] == color[9] && color[8] != color[5] && color[9] != color[0]) + product1a = INTERPOLATE(color[9], color[5]); + else + product1a = color[5]; + + if (PixelsPerMask == 2) + { + if (ScummPCMode) + { + SWAP_WORD(product1a); + SWAP_WORD(product1b); + SWAP_WORD(product2a); + SWAP_WORD(product2b); + } + *((unsigned long *) (&dst_line[0][x * 4])) = (product1a << 16) | product1b; + *((unsigned long *) (&dst_line[1][x * 4])) = (product2a << 16) | product2b; + } + else + { + *((unsigned long *) (&dst_line[0][x * 8])) = product1a; + *((unsigned long *) (&dst_line[0][x * 8 + 4])) = product1b; + *((unsigned long *) (&dst_line[1][x * 8])) = product2a; + *((unsigned long *) (&dst_line[1][x * 8 + 4])) = product2b; + } + + /* Move color matrix forward */ + color[0] = color[1]; color[4] = color[5]; color[8] = color[9]; color[12] = color[13]; + color[1] = color[2]; color[5] = color[6]; color[9] = color[10]; color[13] = color[14]; + color[2] = color[3]; color[6] = color[7]; color[10] = color[11]; color[14] = color[15]; + + if (src_x+x < BufferWidth-3) + { + x += 3; + if (PixelsPerMask == 2) + { + color[3] = ScummColors16[*(src_line[0] + x) ]; + color[7] = ScummColors16[*(src_line[1] + x) ]; + color[11] = ScummColors16[*(src_line[2] + x) ]; + color[15] = ScummColors16[*(src_line[3] + x) ]; + } + else + { + color[3] = ScummColors[*(src_line[0] + x)]; + color[7] = ScummColors[*(src_line[1] + x)]; + color[11] = ScummColors[*(src_line[2] + x)]; + color[15] = ScummColors[*(src_line[3] + x)]; + } + x -= 3; + } + } + + /* We're done with one line, so we shift the source lines up */ + src_line[0] = src_line[1]; + src_line[1] = src_line[2]; + src_line[2] = src_line[3]; + + /* Read next line */ + if (src_y + y + 3 >= BufferHeight) + src_line[3] = src_line[2]; + else + src_line[3] = src_line[2] + BufferWidth; + + /* Then shift the color matrix up */ + if (PixelsPerMask == 2) + { + byte *sbp; + sbp = src_line[0]; + color[0] = ScummColors16[*sbp]; color[1] = color[0]; color[2] = ScummColors16[ *(sbp + 1) ]; color[3] = ScummColors16[*(sbp + 2)]; + sbp = src_line[1]; + color[4] = ScummColors16[*sbp]; color[5] = color[4]; color[6] = ScummColors16[ *(sbp + 1) ]; color[7] = ScummColors16[*(sbp + 2)]; + sbp = src_line[2]; + color[8] = ScummColors16[*sbp]; color[9] = color[8]; color[10] = ScummColors16[ *(sbp + 1) ]; color[11] = ScummColors16[*(sbp + 2)]; + sbp = src_line[3]; + color[12] = ScummColors16[*sbp]; color[13] = color[12]; color[14] = ScummColors16[ *(sbp + 1) ]; color[15] = ScummColors16[*(sbp + 2)]; + + if (src_x + x > 0) + { + color[0] = ScummColors16[src_line[0][-1]]; + color[4] = ScummColors16[src_line[1][-1]]; + color[8] = ScummColors16[src_line[2][-1]]; + color[12] = ScummColors16[src_line[3][-1]]; + } + } + else + { + byte *lbp; + lbp = src_line[0]; + color[0] = ScummColors[*lbp]; color[1] = color[0]; color[2] = ScummColors[ *(lbp + 1) ]; color[3] = ScummColors[*(lbp+2)]; + lbp = src_line[1]; + color[4] = ScummColors[*lbp]; color[5] = color[4]; color[6] = ScummColors[ *(lbp + 1) ]; color[7] = ScummColors[*(lbp+2)]; + lbp = src_line[2]; + color[8] = ScummColors[*lbp]; color[9] = color[8]; color[10] = ScummColors[ *(lbp + 1) ]; color[11] = ScummColors[*(lbp+2)]; + lbp = src_line[3]; + color[12] = ScummColors[*lbp]; color[13] = color[12]; color[14] = ScummColors[ *(lbp + 1) ]; color[15] = ScummColors[*(lbp+2)]; + } + + if (src_y + y < BufferHeight - 1) + { + dst_line[0] = dst_line[1]+dest_pitch; + dst_line[1] = dst_line[0]+dest_pitch; + } + } +} + +void SuperEagleScaler::Scale(uint32 src_x, uint32 src_y, uint32 dest_x, uint32 dest_y, uint32 width, uint32 height) +{ + unsigned int x, y; + unsigned long color[12]; + byte *src; + + if (!handle) + return; + + src = (byte *)Buffer+src_y*BufferWidth+src_x; + + /* Point to the first 3 lines. */ + src_line[0] = src; + src_line[1] = src; + src_line[2] = src + BufferWidth; + src_line[3] = src + BufferWidth * 2; + + dst_line[0] = dest+dest_y*2*dest_pitch+dest_x*2*dest_bpp; + dst_line[1] = dst_line[0]+dest_pitch; + + x = 0, y = 0; + + if (PixelsPerMask == 2) + { + byte *sbp; + sbp = src_line[0]; + color[0] = ScummColors16[*sbp]; color[1] = color[0]; color[2] = color[0]; color[3] = color[0]; + color[4] = ScummColors16[*(sbp+1)]; color[5] = ScummColors16[*(sbp+2)]; + sbp = src_line[2]; + color[6] = ScummColors16[*sbp]; color[7] = color[6]; color[8] = ScummColors16[*(sbp+1)]; color[9] = ScummColors16[*(sbp+2)]; + sbp = src_line[3]; + color[10] = ScummColors16[*sbp]; color[11] = ScummColors16[*(sbp+1)]; + } + else + { + byte *lbp; + lbp = src_line[0]; + color[0] = ScummColors[*lbp]; color[1] = color[0]; color[2] = color[0]; color[3] = color[0]; + color[4] = ScummColors[*(lbp+1)]; color[5] = ScummColors[*(lbp+2)]; + lbp = src_line[2]; + color[6] = ScummColors[*lbp]; color[7] = color[6]; color[8] = ScummColors[*(lbp+1)]; color[9] = ScummColors[*(lbp+2)]; + lbp = src_line[3]; + color[10] = ScummColors[*lbp]; color[11] = ScummColors[*(lbp+1)]; + } + + for (y = 0; y < height; y++) + { + /* Todo: x = width - 2, x = width - 1 */ + + for (x = 0; x < width; x++) + { + unsigned long product1a, product1b, product2a, product2b; + +//--------------------------------------- B1 B2 0 1 +// 4 5 6 S2 -> 2 3 4 5 +// 1 2 3 S1 6 7 8 9 +// A1 A2 10 11 + + if (color[7] == color[4] && color[3] != color[8]) + { + product1b = product2a = color[7]; + + if ((color[6] == color[7]) || (color[4] == color[1])) + product1a = INTERPOLATE(color[7], INTERPOLATE(color[7], color[3])); + else + product1a = INTERPOLATE(color[3], color[4]); + + if ((color[4] == color[5]) || (color[7] == color[10])) + product2b = INTERPOLATE(color[7], INTERPOLATE(color[7], color[8])); + else + product2b = INTERPOLATE(color[7], color[8]); + } + else if (color[3] == color[8] && color[7] != color[4]) + { + product2b = product1a = color[3]; + + if ((color[0] == color[3]) || (color[5] == color[9])) + product1b = INTERPOLATE(color[3], INTERPOLATE(color[3], color[4])); + else + product1b = INTERPOLATE(color[3], color[1]); + + if ((color[8] == color[11]) || (color[2] == color[3])) + product2a = INTERPOLATE(color[3], INTERPOLATE(color[3], color[2])); + else + product2a = INTERPOLATE(color[7], color[8]); + + } + else if (color[3] == color[8] && color[7] == color[4]) + { + register int r = 0; + + r += GET_RESULT(color[4], color[3], color[6], color[10]); + r += GET_RESULT(color[4], color[3], color[2], color[0]); + r += GET_RESULT(color[4], color[3], color[11], color[9]); + r += GET_RESULT(color[4], color[3], color[1], color[5]); + + if (r > 0) + { + product1b = product2a = color[7]; + product1a = product2b = INTERPOLATE(color[3], color[4]); + } + else if (r < 0) + { + product2b = product1a = color[3]; + product1b = product2a = INTERPOLATE(color[3], color[4]); + } + else + { + product2b = product1a = color[3]; + product1b = product2a = color[7]; + } + } + else + { + product2b = product1a = INTERPOLATE(color[7], color[4]); + product2b = Q_INTERPOLATE(color[8], color[8], color[8], product2b); + product1a = Q_INTERPOLATE(color[3], color[3], color[3], product1a); + + product2a = product1b = INTERPOLATE(color[3], color[8]); + product2a = Q_INTERPOLATE(color[7], color[7], color[7], product2a); + product1b = Q_INTERPOLATE(color[4], color[4], color[4], product1b); + } + + if (PixelsPerMask == 2) + { + if (ScummPCMode) + { + SWAP_WORD(product1a); + SWAP_WORD(product1b); + SWAP_WORD(product2a); + SWAP_WORD(product2b); + } + *((unsigned long *) (&dst_line[0][x * 4])) = (product1a << 16) | product1b; + *((unsigned long *) (&dst_line[1][x * 4])) = (product2a << 16) | product2b; + } + else + { + *((unsigned long *) (&dst_line[0][x * 8])) = product1a; + *((unsigned long *) (&dst_line[0][x * 8 + 4])) = product1b; + *((unsigned long *) (&dst_line[1][x * 8])) = product2a; + *((unsigned long *) (&dst_line[1][x * 8 + 4])) = product2b; + } + + /* Move color matrix forward */ + color[0] = color[1]; + color[2] = color[3]; color[3] = color[4]; color[4] = color[5]; + color[6] = color[7]; color[7] = color[8]; color[8] = color[9]; + color[10] = color[11]; + + if (src_x+x < BufferWidth - 2) + { + x += 2; + if (PixelsPerMask == 2) + { + color[1] = ScummColors16[ *(src_line[0] + x) ]; + if (src_x+x < BufferWidth-1) + { + color[5] = ScummColors16[*(src_line[1]+x+1)]; + color[9] = ScummColors16[*(src_line[2]+x+1)]; + } + color[11] = ScummColors16[*(src_line[3]+x)]; + } + else + { + color[1] = ScummColors[*(src_line[0]+x)]; + if (src_x+x < BufferWidth-1) + { + color[5] = ScummColors[*(src_line[1]+x+1)]; + color[9] = ScummColors[ *(src_line[2]+x+1)]; + } + color[11] = ScummColors[*(src_line[3]+x)]; + } + x -= 2; + } + } + + /* We're done with one line, so we shift the source lines up */ + src_line[0] = src_line[1]; + src_line[1] = src_line[2]; + src_line[2] = src_line[3]; + + /* Read next line */ + if (src_y+y+3 >= BufferHeight) + src_line[3] = src_line[2]; + else + src_line[3] = src_line[2] + BufferWidth; + + /* Then shift the color matrix up */ + if (PixelsPerMask == 2) + { + byte *sbp; + sbp = src_line[0]; + color[0] = ScummColors16[*sbp]; color[1] = ScummColors16[*(sbp+1)]; + sbp = src_line[1]; + color[2] = ScummColors16[*sbp]; color[3] = color[2]; color[4] = ScummColors16[*(sbp+1)]; color[5] = ScummColors16[*(sbp+2)]; + sbp = src_line[2]; + color[6] = ScummColors16[*sbp]; color[7] = color[6]; color[8] = ScummColors16[*(sbp+1)]; color[9] = ScummColors16[*(sbp+2)]; + sbp = src_line[3]; + color[10] = ScummColors16[*sbp]; color[11] = ScummColors16[*(sbp+1)]; + } + else + { + byte *lbp; + lbp = src_line[0]; + color[0] = ScummColors[*lbp]; color[1] = ScummColors[*(lbp+1)]; + lbp = src_line[1]; + color[2] = ScummColors[*lbp]; color[3] = color[2]; color[4] = ScummColors[*(lbp+1)]; color[5] = ScummColors[*(lbp+2)]; + lbp = src_line[2]; + color[6] = ScummColors[*lbp]; color[7] = color[6]; color[8] = ScummColors[*(lbp+1)]; color[9] = ScummColors[*(lbp+2)]; + lbp = src_line[3]; + color[10] = ScummColors[*lbp]; color[11] = ScummColors[*(lbp+1)]; + } + + + if (src_y + y < BufferHeight - 1) + { + dst_line[0] = dst_line[1]+dest_pitch; + dst_line[1] = dst_line[0]+dest_pitch; + } + } +} + +void AdvMame2xScaler::Scale(uint32 src_x, uint32 src_y, uint32 dest_x, uint32 dest_y, uint32 width, uint32 height) +{ + if (!handle) + return; + + byte *src = (byte *)Buffer+src_y*BufferWidth+src_x; + + src_line[0] = src; + src_line[1] = src; + src_line[2] = src + BufferWidth; + + dst_line[0] = dest+dest_y*2*dest_pitch+dest_x*2*dest_bpp; + dst_line[1] = dst_line[0]+dest_pitch; + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + uint32 B, D, E, F, H; + + if (PixelsPerMask == 2) + { + // short A = *(src + i - nextlineSrc - 1); + B = ScummColors16[src_line[0][x]]; + // short C = *(src + i - nextlineSrc + 1); + D = ScummColors16[src_line[1][x-1]]; + E = ScummColors16[src_line[1][x]]; + F = ScummColors16[src_line[1][x+1]]; + // short G = *(src + i + nextlineSrc - 1); + H = ScummColors16[src_line[2][x]]; + // short I = *(src + i + nextlineSrc + 1); + } + else + { + // short A = *(src + i - nextlineSrc - 1); + B = ScummColors[src_line[0][x]]; + // short C = *(src + i - nextlineSrc + 1); + D = ScummColors[src_line[1][x-1]]; + E = ScummColors[src_line[1][x]]; + F = ScummColors[src_line[1][x+1]]; + // short G = *(src + i + nextlineSrc - 1); + H = ScummColors[src_line[2][x]]; + // short I = *(src + i + nextlineSrc + 1); + } + + + if (PixelsPerMask == 2) + { + if (ScummPCMode) + { + SWAP_WORD(B); + SWAP_WORD(D); + SWAP_WORD(E); + SWAP_WORD(F); + SWAP_WORD(H); + } + *((unsigned long *) (&dst_line[0][x * 4])) = ((D == B && B != F && D != H ? D : E) << 16) | (B == F && B != D && F != H ? F : E); + *((unsigned long *) (&dst_line[1][x * 4])) = ((D == H && D != B && H != F ? D : E) << 16) | (H == F && D != H && B != F ? F : E); + } + else + { + *((unsigned long *) (&dst_line[0][x * 8])) = D == B && B != F && D != H ? D : E; + *((unsigned long *) (&dst_line[0][x * 8 + 4])) = B == F && B != D && F != H ? F : E; + *((unsigned long *) (&dst_line[1][x * 8])) = D == H && D != B && H != F ? D : E; + *((unsigned long *) (&dst_line[1][x * 8 + 4])) = H == F && D != H && B != F ? F : E; + } + } + + src_line[0] = src_line[1]; + src_line[1] = src_line[2]; + if (src_y+y+2 >= BufferHeight) + src_line[2] = src_line[1]; + else + src_line[2] = src_line[1] + BufferWidth; + + if (src_y+y < BufferHeight-1) + { + dst_line[0] = dst_line[1]+dest_pitch; + dst_line[1] = dst_line[0]+dest_pitch; + } + } +} + +void PointScaler::Scale(uint32 src_x, uint32 src_y, uint32 dest_x, uint32 dest_y, uint32 width, uint32 height) +{ + byte *src; + uint32 color; + uint32 r, g, b; + uint32 x, y; + + if (!handle) + return; + + src = (byte *)Buffer+src_y*BufferWidth+src_x; + + dst_line[0] = dest+dest_y*2*dest_pitch+dest_x*2*dest_bpp; + dst_line[1] = dst_line[0]+dest_pitch; + + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + r = (ScummColors[*(src+x)] >> 16) & 0xff; + g = (ScummColors[*(src+x)] >> 8) & 0xff; + b = ScummColors[*(src+x)] & 0xff; + + color = MakeColor(dest_pixfmt, r, g, b); + if (PixelsPerMask == 2) + { + if (ScummPCMode) + SWAP_WORD(color); + + *((unsigned long *) (&dst_line[0][x * 4])) = (color << 16) | color; + *((unsigned long *) (&dst_line[1][x * 4])) = (color << 16) | color; + } + else + { + *((unsigned long *) (&dst_line[0][x * 8])) = color; + *((unsigned long *) (&dst_line[0][x * 8 + 4])) = color; + *((unsigned long *) (&dst_line[1][x * 8])) = color; + *((unsigned long *) (&dst_line[1][x * 8 + 4])) = color; + } + } + + src += BufferWidth; + + if (src_y+y < BufferHeight-1) + { + dst_line[0] = dst_line[1]+dest_pitch; + dst_line[1] = dst_line[0]+dest_pitch; + } + } +} + +SCALERTYPE MorphOSScaler::FindByName(const char *ScalerName) +{ + int scaler = 0; + + while (ScummScalers[scaler].gs_Name) + { + if (!stricmp(ScalerName, ScummScalers[scaler].gs_Name)) + return ScummScalers[scaler].gs_Type; + scaler++; + } + + if (ScummScalers[scaler].gs_Name == NULL) + { + puts("Invalid scaler name. Please use one of the following:"); + for (scaler = 0; ScummScalers[scaler].gs_Name != NULL; scaler++) + printf(" %s\n", ScummScalers[scaler].gs_Name); + } + + return ST_INVALID; +} + +SCALERTYPE MorphOSScaler::FindByIndex(int index) +{ + if (index >= 0 && index < 10 && ScummScalers[index].gs_Name) + return ScummScalers[index].gs_Type; + + return ST_INVALID; +} + +const char *MorphOSScaler::GetParamName(SCALERTYPE type) +{ + int scaler = 0; + + while (ScummScalers[scaler].gs_Name) + { + if (ScummScalers[scaler].gs_Type == type) + return ScummScalers[scaler].gs_ParamName; + scaler++; + } + + return NULL; +} + diff --git a/backends/morphos/morphos_scaler.h b/backends/morphos/morphos_scaler.h new file mode 100644 index 0000000000..c23de6cb8a --- /dev/null +++ b/backends/morphos/morphos_scaler.h @@ -0,0 +1,93 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002 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$ + */ + +#ifndef MORPHOS_MORPHOSSCALER_H +#define MORPHOS_MORPHOSSCALER_H + +#include <graphics/gfx.h> + +typedef enum { ST_INVALID = 0, ST_NONE, ST_POINT, ST_ADVMAME2X, ST_SUPEREAGLE, ST_SUPER2XSAI } SCALERTYPE; + +class MorphOSScaler +{ + public: + MorphOSScaler(APTR buffer, int width, int height, ULONG *col_table, UWORD *col_table16, BitMap *bmap); + virtual ~MorphOSScaler(); + + bool Prepare(BitMap *render_bmap); + void Finish(); + + virtual void Scale(uint32 src_x, uint32 src_y, uint32 dest_x, uint32 dest_y, uint32 width, uint32 height) = 0; + + static MorphOSScaler *Create(SCALERTYPE st, APTR buffer, int width, int height, ULONG *col_table, UWORD *col_table16, BitMap *bmap); + + static SCALERTYPE FindByName(const char *ScalerName); + static SCALERTYPE FindByIndex(int index); + static const char *GetParamName(SCALERTYPE type); + + protected: + struct GfxScaler + { + STRPTR gs_Name; + STRPTR gs_ParamName; + SCALERTYPE gs_Type; + }; + + static GfxScaler ScummScalers[11]; + + static uint32 MakeColor(int pixfmt, int r, int g, int b); + + byte *dest; + uint32 dest_bpp; + uint32 dest_pitch; + uint32 dest_pixfmt; + APTR handle; + + uint32 colorMask; + uint32 lowPixelMask; + uint32 qcolorMask; + uint32 qlowpixelMask; + uint32 redblueMask; + uint32 greenMask; + int PixelsPerMask; + byte *src_line[4]; + byte *dst_line[2]; + bool ScummPCMode; + + APTR Buffer; + int BufferWidth; + int BufferHeight; + ULONG *ScummColors; + USHORT *ScummColors16; +}; + +#define DECLARE_SCALER(scaler_name) class scaler_name ## Scaler : public MorphOSScaler \ + { public: scaler_name ## Scaler(APTR buffer, int width, int height, ULONG *col_table, UWORD *col_table16, BitMap *bmap) : MorphOSScaler(buffer, width, height, col_table, col_table16, bmap) {} \ + void Scale(uint32 src_x, uint32 src_y, uint32 dest_x, uint32 dest_y, uint32 width, uint32 height); \ + }; + + +DECLARE_SCALER(Point) +DECLARE_SCALER(AdvMame2x) +DECLARE_SCALER(SuperEagle) +DECLARE_SCALER(Super2xSaI) + +#endif + diff --git a/backends/morphos/morphos_sound.cpp b/backends/morphos/morphos_sound.cpp new file mode 100644 index 0000000000..0585b8708b --- /dev/null +++ b/backends/morphos/morphos_sound.cpp @@ -0,0 +1,284 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002 Rüdiger Hanke + * + * 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. + * + * MorphOS sound support + * + * $Header$ + * + */ + +#include "stdafx.h" +#include "scumm.h" + +#include <dos/dos.h> +#include <exec/memory.h> +#include <devices/ahi.h> +#include <devices/amidi.h> + +#include <clib/alib_protos.h> +#include <proto/exec.h> +#include <proto/dos.h> +#include <proto/ahi.h> + +#include "morphos.h" + +#define AHI_BUF_SIZE (8*1024) + +SignalSemaphore ScummMusicThreadRunning; +SignalSemaphore ScummSoundThreadRunning; + +static MsgPort *ahiPort = NULL; +static AHIRequest *ahiReq[2] = { NULL, NULL }; +static UWORD ahiCurBuf = 0; +static bool ahiReqSent[2] = { false, false }; +static BYTE ahiDevice = -1; + UBYTE ahiUnit = AHI_DEFAULT_UNIT; +static char *ahiBuf[2] = { NULL, NULL }; + +static MsgPort *ScummMidiPort = NULL; + IOMidiRequest *ScummMidiRequest = NULL; +static MsgPort *MusicTimerMsgPort = NULL; + timerequest *MusicTimerIORequest = NULL; + +bool init_morphos_music(ULONG MidiUnit) +{ + if (ScummMusicDriver && !stricmp(ScummMusicDriver, "-eamidi")) // just as ugly as the line below ... + { + MidiUnit = ScummMidiUnit; // Ugly fix, but ... + ScummMidiPort = CreateMsgPort(); + if (ScummMidiPort) + { + ScummMidiRequest = (IOMidiRequest *) CreateIORequest(ScummMidiPort, sizeof (IOMidiRequest)); + if (ScummMidiRequest) + { + ScummMidiRequest->amr_Version = 2; + if (OpenDevice("amidi.device", MidiUnit, (IORequest *) ScummMidiRequest, AMIDIF_MIDISERVER)) + { + DeleteIORequest((IORequest *) ScummMidiRequest); + DeleteMsgPort(ScummMidiPort); + ScummMidiRequest = NULL; + ScummMidiPort = NULL; + } + } + else + { + DeleteMsgPort(ScummMidiPort); + ScummMidiPort = NULL; + } + } + + if (!ScummMidiRequest) + { + warning("Could not open AMidi - music will not play"); + return false; + } + } + + MusicTimerMsgPort = CreateMsgPort(); + if (MusicTimerMsgPort) + { + MusicTimerIORequest = (timerequest *) CreateIORequest(MusicTimerMsgPort, sizeof (timerequest)); + if (MusicTimerIORequest) + { + if (OpenDevice("timer.device", UNIT_MICROHZ, (IORequest *) MusicTimerIORequest, 0)) + { + DeleteIORequest((IORequest *) MusicTimerIORequest); + DeleteMsgPort(MusicTimerMsgPort); + MusicTimerIORequest = NULL; + MusicTimerMsgPort = NULL; + } + } + else + { + DeleteMsgPort(MusicTimerMsgPort); + MusicTimerMsgPort = NULL; + } + } + + if (!MusicTimerIORequest) + { + warning("Could not open timer device - music will not play"); + return false; + } + + return true; +} + + +void exit_morphos_music() +{ + if (ScummMidiRequest) + { + CloseDevice((IORequest *) ScummMidiRequest); + DeleteIORequest((IORequest *) ScummMidiRequest); + DeleteMsgPort(ScummMidiPort); + } + + if (MusicTimerIORequest) + { + CloseDevice((IORequest *) MusicTimerIORequest); + DeleteIORequest((IORequest *) MusicTimerIORequest); + DeleteMsgPort(MusicTimerMsgPort); + } +} + + +static bool init_morphos_sound() +{ + if (!(ahiPort = CreateMsgPort())) + return false; + + if (!(ahiReq[0] = (AHIRequest *) CreateIORequest(ahiPort, sizeof (AHIRequest)))) + { + DeleteMsgPort(ahiPort); + ahiPort = NULL; + return false; + } + + if (!(ahiReq[1] = (AHIRequest *) AllocVec(sizeof (AHIRequest), MEMF_PUBLIC))) + { + DeleteIORequest(ahiReq[0]); + DeleteMsgPort(ahiPort); + ahiReq[0] = NULL; + ahiPort = NULL; + return false; + } + + if (!(ahiBuf[0] = (char *) AllocVec(2*AHI_BUF_SIZE, MEMF_PUBLIC))) + { + FreeVec(ahiReq[1]); + DeleteIORequest(ahiReq[0]); + DeleteMsgPort(ahiPort); + ahiReq[0] = NULL; + ahiReq[1] = NULL; + ahiPort = NULL; + return false; + } + ahiBuf[1] = &ahiBuf[0][AHI_BUF_SIZE]; + + ahiReq[0]->ahir_Version = 4; + if (ahiDevice = OpenDevice(AHINAME, 0, (IORequest *) ahiReq[0], 0)) + { + FreeVec(ahiBuf[0]); + FreeVec(ahiReq[1]); + DeleteIORequest(ahiReq[0]); + DeleteMsgPort(ahiPort); + ahiBuf[0] = NULL; + ahiReq[0] = NULL; + ahiReq[1] = NULL; + ahiPort = NULL; + return false; + } + + CopyMem(ahiReq[0], ahiReq[1], sizeof (AHIRequest)); + + ahiCurBuf = 0; + ahiReqSent[0] = FALSE; + ahiReqSent[1] = FALSE; + + return true; +} + + +static void exit_morphos_sound() +{ + if (ahiReq[1]) + FreeVec(ahiReq[1]); + + if (ahiReq[0]) + { + CloseDevice((IORequest *) ahiReq[0]); + DeleteIORequest(ahiReq[0]); + } + + if (ahiBuf[0]) + FreeVec((APTR) ahiBuf[0]); + + if (ahiPort) + DeleteMsgPort(ahiPort); +} + +int morphos_sound_thread(OSystem_MorphOS *syst, ULONG SampleType) +{ + ULONG signals; + bool initialized; + + ObtainSemaphore(&ScummSoundThreadRunning); + + initialized = init_morphos_sound(); + if (!initialized) + { + warning("Sound could not be initialized. The game may hang at some point (press Ctrl-z then)."); + Wait(SIGBREAKF_CTRL_C); + } + else + { + for (;;) + { + while (!ahiReqSent[ahiCurBuf] || CheckIO((IORequest *) ahiReq[ahiCurBuf])) + { + AHIRequest *req = ahiReq[ahiCurBuf]; + UWORD ahiOtherBuf = !ahiCurBuf; + + if (ahiReqSent[ahiCurBuf]) + WaitIO((IORequest *) req); + + syst->fill_sound((byte *) ahiBuf[ahiCurBuf], AHI_BUF_SIZE); + + req->ahir_Std.io_Message.mn_Node.ln_Pri = 0; + req->ahir_Std.io_Command = CMD_WRITE; + req->ahir_Std.io_Data = ahiBuf[ahiCurBuf]; + req->ahir_Std.io_Length = AHI_BUF_SIZE; + req->ahir_Type = SampleType; + req->ahir_Frequency = SAMPLES_PER_SEC; + req->ahir_Position = 0x8000; + req->ahir_Volume = 0x10000; + req->ahir_Link = (ahiReqSent[ahiOtherBuf] && !CheckIO((IORequest *) ahiReq[ahiOtherBuf])) ? ahiReq[ahiOtherBuf] : NULL; + SendIO((IORequest *)req); + + ahiReqSent[ahiCurBuf] = true; + ahiCurBuf = ahiOtherBuf; + } + + signals = Wait(SIGBREAKF_CTRL_C | (1 << ahiPort->mp_SigBit)); + + if (signals & SIGBREAKF_CTRL_C) + break; + } + + if (ahiReqSent[ahiCurBuf]) + { + AbortIO((IORequest *) ahiReq[ahiCurBuf]); + WaitIO((IORequest *) ahiReq[ahiCurBuf]); + ahiReqSent[ahiCurBuf] = false; + } + + if (ahiReqSent[!ahiCurBuf]) + { + AbortIO((IORequest *) ahiReq[!ahiCurBuf]); + WaitIO((IORequest *) ahiReq[!ahiCurBuf]); + ahiReqSent[!ahiCurBuf] = false; + } + } + + exit_morphos_sound(); + + ReleaseSemaphore(&ScummSoundThreadRunning); + RemTask(NULL); + return 0; +} + diff --git a/backends/morphos/morphos_start.cpp b/backends/morphos/morphos_start.cpp new file mode 100644 index 0000000000..d3305cbe14 --- /dev/null +++ b/backends/morphos/morphos_start.cpp @@ -0,0 +1,359 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002 Rüdiger Hanke (MorphOS port) + * + * 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. + * + * MorphOS startup handling + * + * $Header$ + * + */ + +#include <exec/types.h> +#include <exec/devices.h> +#include <exec/memory.h> +#include <exec/libraries.h> +#include <workbench/startup.h> +#include <workbench/workbench.h> + +#include <proto/exec.h> +#include <proto/dos.h> +#include <proto/cdda.h> +#include <proto/cybergraphics.h> +#include <proto/icon.h> + +#include "stdafx.h" +#include "scumm.h" +#include "morphos.h" +#include "morphos_scaler.h" + +extern "C" WBStartup *_WBenchMsg; + +// For command line parsing +static STRPTR usageTemplate = "STORY/A,DATAPATH/K,WBWINDOW/S,SCALER/K,AMIGA/S,MIDIUNIT/K/N,MUSIC/K,MUSICVOL/K/N,SFXVOL/K/N,TEMPO/K/N,TALKSPEED/K/N,NOSUBTITLES=NST/S"; +typedef enum { USG_STORY = 0, USG_DATAPATH, USG_WBWINDOW, USG_SCALER, USG_AMIGA, USG_MIDIUNIT, USG_MUSIC, USG_MUSICVOL, USG_SFXVOL, USG_TEMPO, USG_TALKSPEED, USG_NOSUBTITLES } usageFields; +static LONG args[13] = { (ULONG) NULL, (ULONG) NULL, FALSE, (ULONG) NULL, false, (ULONG) NULL, (ULONG) NULL, (ULONG) NULL, (ULONG) NULL, (ULONG) NULL, (ULONG) NULL, false }; +static RDArgs *ScummArgs = NULL; + +static char*ScummStory = NULL; +static char*ScummPath = NULL; + STRPTR ScummMusicDriver = NULL; + LONG ScummMidiUnit = 0; +static LONG ScummMidiVolume = 0; +static LONG ScummMidiTempo = 0; +static LONG ScummSfxVolume = 0; +static LONG ScummTalkSpeed = 0; +static SCALERTYPE ScummGfxScaler = ST_INVALID; + +static BPTR OrigDirLock = 0; + +Library *CDDABase = NULL; +Device *TimerBase = NULL; + +OSystem_MorphOS *TheSystem = NULL; + +OSystem *OSystem_MorphOS_create(int game_id, int gfx_mode, bool full_screen) +{ + if (TheSystem) + delete TheSystem; + + SCALERTYPE gfx_scaler = ST_NONE; + switch (gfx_mode) + { + case GFX_DOUBLESIZE: + gfx_scaler = ST_POINT; + break; + + case GFX_SUPEREAGLE: + gfx_scaler = ST_SUPEREAGLE; + break; + + case GFX_SUPER2XSAI: + gfx_scaler = ST_SUPER2XSAI; + break; + } + + TheSystem = OSystem_MorphOS::create(game_id, gfx_scaler, full_screen); + return TheSystem; +} + +void close_resources() +{ + if (TheSystem) + delete TheSystem; + + if (g_scumm) + delete g_scumm; + + if (ScummPath) + FreeVec(ScummPath); + + if (ScummStory) + FreeVec(ScummStory); + + if (ScummArgs) + FreeArgs(ScummArgs); + + if (OrigDirLock) + CurrentDir(OrigDirLock); + + if (CDDABase) + CloseLibrary(CDDABase); +} + +static STRPTR FindMusicDriver(STRPTR argval) +{ + if (!stricmp(argval, "off")) return "-enull"; + if (!stricmp(argval, "midi")) return "-eamidi"; + if (!stricmp(argval, "midiemu")) return "-emidiemu"; + if (!stricmp(argval, "adlib")) return "-eadlib"; + + error("No such music driver supported. Possible values are off, Midi, MidiEmu and Adlib."); + return NULL; +} + +static void ReadToolTypes(WBArg *OfFile) +{ + DiskObject *dobj; + char *ToolValue; + char IconPath[256]; + + NameFromLock(OfFile->wa_Lock, IconPath, 256); + AddPart(IconPath, OfFile->wa_Name, 256); + + dobj = GetDiskObject(IconPath); + if (dobj == NULL) + return; + + if (ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "STORY")) + { + if (ScummStory) + FreeVec(ScummStory); + ScummStory = (char *) AllocVec(strlen(ToolValue)+1, MEMF_PUBLIC); + strcpy(ScummStory, ToolValue); + } + + if (ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "DATAPATH")) + { + if (ScummPath) + FreeVec(ScummPath); + ScummPath = (char *) AllocVec(strlen(ToolValue)+4, MEMF_PUBLIC); + strcpy(ScummPath, "-p"); + strcat(ScummPath, ToolValue); + } + + if (ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "WBWINDOW")) + { + if (MatchToolValue(ToolValue, "YES")) + args[USG_WBWINDOW] = TRUE; + else if (MatchToolValue(ToolValue, "NO")) + args[USG_WBWINDOW] = FALSE; + } + + if (ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "SCALER")) + { + if ((ScummGfxScaler = MorphOSScaler::FindByName(ToolValue)) == ST_INVALID) + { + FreeDiskObject(dobj); + exit(1); + } + } + + if (ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "MUSIC")) + { + if (!(ScummMusicDriver = FindMusicDriver(ToolValue))) + { + FreeDiskObject(dobj); + exit(1); + } + args[USG_MUSIC] = (ULONG) &ScummMusicDriver; + } + + if( ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "MIDIUNIT")) + ScummMidiUnit = atoi(ToolValue); + + if( ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "MUSICVOL")) + { + int vol = atoi(ToolValue); + if (vol >= 0 && vol <= 100) + { + ScummMidiVolume = vol; + args[USG_MUSICVOL] = (ULONG) &ScummMidiVolume; + } + } + + if (ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "SFXVOL")) + { + int vol = atoi(ToolValue); + if (vol >= 0 && vol <= 255) + { + ScummSfxVolume = vol; + args[USG_SFXVOL] = (ULONG) &ScummSfxVolume; + } + } + + if (ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "TEMPO")) + { + ScummMidiTempo = atoi(ToolValue); + args[USG_TEMPO] = (ULONG) &ScummMidiTempo; + } + + if (ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "TALKSPEED")) + { + ScummTalkSpeed = atoi(ToolValue); + args[USG_TALKSPEED] = (ULONG) &ScummMidiTempo; + } + + if (ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "SUBTITLES")) + { + if (MatchToolValue(ToolValue, "YES")) + args[USG_NOSUBTITLES] = FALSE; + else if (MatchToolValue(ToolValue, "NO")) + args[USG_NOSUBTITLES] = TRUE; + } + + if (ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "AMIGA")) + { + if (MatchToolValue(ToolValue, "YES")) + args[USG_AMIGA] = FALSE; + else if (MatchToolValue(ToolValue, "NO")) + args[USG_AMIGA] = TRUE; + } + + FreeDiskObject(dobj); +} + +#undef main + +int main() +{ + int delta; + int last_time, new_time; + char *argv[20]; + char musicvol[6], sfxvol[6], talkspeed[12], tempo[12], scaler[14]; + int argc = 0; + + InitSemaphore(&ScummSoundThreadRunning); + InitSemaphore(&ScummMusicThreadRunning); + + g_scumm = NULL; + atexit(&close_resources); + + if (_WBenchMsg == NULL) + { + /* Parse the command line here */ + ScummArgs = ReadArgs(usageTemplate, args, NULL); + if (ScummArgs == NULL) + { + puts("Error in command line - type \"ScummVM ?\" for usage."); + exit(1); + } + + if (args[USG_STORY]) + { + ScummStory = (char *) AllocVec(strlen((char *) args[USG_STORY])+1, MEMF_PUBLIC); + strcpy(ScummStory, (char *) args[USG_STORY]); + } + + if (args[USG_DATAPATH]) + { + ScummPath = (char *) AllocVec(strlen((char *) args[USG_DATAPATH])+4, MEMF_PUBLIC); + strcpy(ScummPath, "-p"); + strcat(ScummPath, (char *) args[USG_DATAPATH]); + } + + if (args[USG_SCALER]) + { + if ((ScummGfxScaler = MorphOSScaler::FindByName((char *) args[USG_SCALER])) == ST_INVALID) + exit(1); + } + + if (args[USG_MUSIC]) + { + if (!(ScummMusicDriver = FindMusicDriver((char *) args[USG_MUSIC]))) + exit(1); + } + + if (args[USG_MIDIUNIT]) + ScummMidiUnit = *((LONG *) args[USG_MIDIUNIT]); + + if (args[USG_TEMPO]) + ScummMidiTempo = *((LONG *) args[USG_TEMPO]); + + if (args[USG_MUSICVOL]) + ScummMidiVolume = *((LONG *) args[USG_MUSICVOL]); + + if (args[USG_SFXVOL]) + ScummSfxVolume = *((LONG *) args[USG_SFXVOL]); + + if (args[USG_TALKSPEED]) + ScummTalkSpeed = *((LONG *) args[USG_TALKSPEED]); + } + else + { + /* We've been started from Workbench */ + ReadToolTypes(&_WBenchMsg->sm_ArgList[0]); + if (_WBenchMsg->sm_NumArgs > 1) + { + ReadToolTypes(&_WBenchMsg->sm_ArgList[1]); + OrigDirLock = CurrentDir(_WBenchMsg->sm_ArgList[1].wa_Lock); + } + } + + if (ScummPath) + { + char c = ScummPath[strlen(ScummPath)-1]; + if (c != '/' && c != ':') + strcat(ScummPath, "/"); + } + + argv[argc++] = "ScummVM"; + if (ScummPath) argv[argc++] = ScummPath; + if (!args[ USG_WBWINDOW ]) argv[argc++] = "-f"; + if (args[ USG_NOSUBTITLES ]) argv[argc++] = "-n"; + if (args[ USG_AMIGA ]) argv[argc++] = "-a"; + if (args[ USG_MUSIC ]) argv[argc++] = ScummMusicDriver; + if (ScummGfxScaler != ST_INVALID) + { + sprintf(scaler, "-g%s", MorphOSScaler::GetParamName(ScummGfxScaler)); + argv[argc++] = scaler; + } + else + argv[argc++] = "-gsuper2xsai"; + if (args[USG_MUSICVOL] && ScummMidiVolume >= 0 && ScummMidiVolume <= 100) + { + sprintf(musicvol, "-m%d", ScummMidiVolume); + argv[argc++] = musicvol; + } + if (args[USG_SFXVOL] && ScummSfxVolume >= 0 && ScummSfxVolume <= 255) + { + sprintf(sfxvol, "-s%d", ScummSfxVolume); + argv[argc++] = sfxvol; + } + if (args[USG_TEMPO] && ScummMidiTempo > 0) + { + sprintf(tempo, "-t%lx", ScummMidiTempo); + argv[argc++] = tempo; + } + if (args[USG_TALKSPEED] && ScummTalkSpeed >= 0 && ScummTalkSpeed <= 255) + { + sprintf(talkspeed, "-y%d", ScummTalkSpeed); + argv[argc++] = talkspeed; + } + argv[argc++] = ScummStory; + + return morphos_main(argc, argv); +} + diff --git a/backends/morphos/morphos_timer.cpp b/backends/morphos/morphos_timer.cpp new file mode 100644 index 0000000000..d106b9a1a9 --- /dev/null +++ b/backends/morphos/morphos_timer.cpp @@ -0,0 +1,243 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002 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 "stdafx.h" +#include "scumm.h" + +#include <exec/memory.h> +#include <exec/semaphores.h> +#include <dos/dostags.h> +#include <emul/emulinterface.h> + +#include <proto/exec.h> +#include <proto/dos.h> +#include <proto/timer.h> + +#include "morphos.h" +#include "timer.h" + +static TagItem TimerServiceTags[] = { { NP_Entry, 0 }, + { NP_Name, (ULONG)"ScummVM Timer Service" }, + { NP_Priority, 20 }, + { TAG_DONE, 0 } + }; + +Timer::Timer(Scumm * system) +{ + static EmulFunc ThreadEmulFunc; + + InitSemaphore(&TimerServiceSemaphore); + + ThreadEmulFunc.Trap = TRAP_FUNC; + ThreadEmulFunc.Address = (ULONG) &TimerService; + ThreadEmulFunc.StackSize = 16000; + ThreadEmulFunc.Extension = 0; + ThreadEmulFunc.Arg1 = (ULONG) this; + TimerServiceTags[0].ti_Data = (ULONG) &ThreadEmulFunc; + TimerServiceThread = CreateNewProc(TimerServiceTags); +} + +Timer::~Timer() +{ + if (TimerServiceThread) + { + Signal((Task *) TimerServiceThread, SIGBREAKF_CTRL_C); + ObtainSemaphore(&TimerServiceSemaphore); + ReleaseSemaphore(&TimerServiceSemaphore); + } +} + +bool Timer::init() +{ + return TimerServiceThread != NULL; +} + +void Timer::release() +{ +} + +bool Timer::installProcedure(int ((*procedure)(int)), int32 interval) +{ + return SendMsg(TSM_MSGID_ADDTIMER, procedure, interval); +} + +void Timer::releaseProcedure(int ((*procedure)(int))) +{ + SendMsg(TSM_MSGID_REMTIMER, procedure, 0); +} + +bool Timer::SendMsg(ULONG msg_id, int ((*procedure)(int)), LONG interval) +{ + if (TimerServiceThread == NULL) + return false; + + TimerServiceMessage *tmsg = (TimerServiceMessage *) AllocVec(sizeof (TimerServiceMessage), MEMF_PUBLIC | MEMF_CLEAR); + if (tmsg == NULL) + return false; + + MsgPort *reply_port = CreateMsgPort(); + if (reply_port == NULL) + { + FreeVec(tmsg); + return false; + } + + tmsg->tsm_Message.mn_Node.ln_Type = NT_MESSAGE; + tmsg->tsm_Message.mn_ReplyPort = reply_port; + tmsg->tsm_Message.mn_Length = sizeof (TimerServiceMessage); + tmsg->tsm_MsgID = msg_id; + tmsg->tsm_Callback = procedure; + tmsg->tsm_Interval = interval; + PutMsg(&TimerServiceThread->pr_MsgPort, tmsg); + WaitPort(reply_port); + GetMsg(reply_port); + + FreeVec(tmsg); + DeleteMsgPort(reply_port); + + return true; +} + +void Timer::TimerService(Timer *this_ptr) +{ + MsgPort *port = &((Process *) FindTask(NULL))->pr_MsgPort; + ULONG port_bit = 1 << port->mp_SigBit; + ULONG signal_mask = SIGBREAKF_CTRL_C | port_bit; + ULONG timer_bits = 0, signals; + ULONG interval, t; + timeval start_callback, end_callback; + + ULONG timers = 0; + TimerSlot timer_slots[MAX_TIMERS]; + + ObtainSemaphore(&this_ptr->TimerServiceSemaphore); + + for (;;) + { + signals = Wait(signal_mask); + + GetSysTime(&start_callback); + + if (signals & port_bit) + { + TimerServiceMessage *tmsg; + + while (tmsg = (TimerServiceMessage *) GetMsg(port)) + { + if (tmsg->tsm_Message.mn_Length == sizeof (TimerServiceMessage)) + { + switch (tmsg->tsm_MsgID) + { + case TSM_MSGID_ADDTIMER: + if (timers < MAX_TIMERS) + { + ULONG unit = UNIT_MICROHZ; + + if (tmsg->tsm_Interval > 1000) + unit = UNIT_VBLANK; + if (OSystem_MorphOS::OpenATimer(&timer_slots[timers].ts_Port, (IORequest **) &timer_slots[timers].ts_IORequest, unit)) + { + timer_slots[timers].ts_Callback = tmsg->tsm_Callback; + timer_slots[timers].ts_Interval = tmsg->tsm_Interval; + timer_slots[timers].ts_SignalBit = 1 << timer_slots[timers].ts_Port->mp_SigBit; + + signal_mask |= timer_slots[timers].ts_SignalBit; + timer_bits |= timer_slots[timers].ts_SignalBit; + + timerequest *req = timer_slots[timers].ts_IORequest; + interval = timer_slots[timers].ts_Interval; + req->tr_node.io_Command = TR_ADDREQUEST; + req->tr_time.tv_secs = interval/1000; + req->tr_time.tv_micro = (interval%1000)*1000; + SendIO(req); + + timers++; + } + } + break; + + case TSM_MSGID_REMTIMER: + { + for (t = 0; t < timers; t++) + { + if (timer_slots[t].ts_Callback == tmsg->tsm_Callback) + { + AbortIO((IORequest *) timer_slots[t].ts_IORequest); + WaitIO((IORequest *) timer_slots[t].ts_IORequest); + signal_mask &= ~timer_slots[t].ts_SignalBit; + timer_bits &= ~timer_slots[t].ts_SignalBit; + DeleteIORequest((IORequest *) timer_slots[t].ts_IORequest); + DeleteMsgPort(timer_slots[t].ts_Port); + if (t < timers-1) + memmove(&timer_slots[t], &timer_slots[t+1], sizeof (TimerSlot)*(timers-t-1)); + timers--; + continue; + } + } + break; + } + + default: + warning("MorphOS TimerService received message of unknown type."); + } + } + + ReplyMsg((Message *) tmsg); + } + } + + if (signals & SIGBREAKF_CTRL_C) + break; + + if (signals & timer_bits) + { + for (t = 0; t < timers; t++) + { + if (signals & timer_slots[t].ts_SignalBit) + { + timerequest *req = timer_slots[t].ts_IORequest; + WaitIO((IORequest *) req); + interval = timer_slots[t].ts_Interval; + (*timer_slots[t].ts_Callback)(interval); + GetSysTime(&end_callback); + SubTime(&end_callback, &start_callback); + interval -= end_callback.tv_sec*1000+end_callback.tv_micro/1000+40; + + req->tr_node.io_Command = TR_ADDREQUEST; + req->tr_time.tv_secs = interval/1000; + req->tr_time.tv_micro = (interval%1000)*1000; + SendIO(req); + } + } + } + } + + for (t = 0; t < timers; t++) + { + AbortIO((IORequest *) timer_slots[t].ts_IORequest); + WaitIO((IORequest *) timer_slots[t].ts_IORequest); + DeleteIORequest((IORequest *) timer_slots[t].ts_IORequest); + DeleteMsgPort(timer_slots[t].ts_Port); + } + + ReleaseSemaphore(&this_ptr->TimerServiceSemaphore); + RemTask(NULL); +} + diff --git a/backends/morphos/morphos_timer.h b/backends/morphos/morphos_timer.h new file mode 100644 index 0000000000..1593b29a5c --- /dev/null +++ b/backends/morphos/morphos_timer.h @@ -0,0 +1,86 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002 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$ + */ + +#ifndef MORPHOS_TIMER_H +#define MORPHOS_TIMER_H + +#ifndef TIMER_H +#include "timer.h" // for MAX_TIMER +#endif + +#ifndef EXEC_PORTS_H +#include <exec/ports.h> +#endif + +#ifndef EXEC_IO_H +#include <exec/io.h> +#endif + +#ifndef EXEC_SEMAPHORES_H +#include <exec/semaphores.h> +#endif + +#ifndef DOS_DOSEXTENS_H +#include <dos/dosextens.h> +#endif + +class OSystem; + +#define TSM_MSGID_ADDTIMER 0 +#define TSM_MSGID_REMTIMER 1 + +struct TimerServiceMessage +{ + Message tsm_Message; + ULONG tsm_MsgID; + int ((*tsm_Callback)(int)); + LONG tsm_Interval; +}; + +class Timer +{ + public: + Timer(Scumm * system); + ~Timer(); + + bool init(); + void release(); + bool installProcedure(int ((*procedure)(int)), int32 interval); + void releaseProcedure(int ((*procedure)(int))); + + protected: + bool SendMsg(ULONG MsgID, int ((*procedure)(int)), LONG interval); + static void TimerService(Timer *); + + Process *TimerServiceThread; + SignalSemaphore TimerServiceSemaphore; + + struct TimerSlot + { + MsgPort *ts_Port; + timerequest *ts_IORequest; + ULONG ts_SignalBit; + int ((*ts_Callback)(int)); + LONG ts_Interval; + }; +}; + +#endif + |