aboutsummaryrefslogtreecommitdiff
path: root/backends/platform/dc
diff options
context:
space:
mode:
authorMarcus Comstedt2006-06-30 20:21:42 +0000
committerMarcus Comstedt2006-06-30 20:21:42 +0000
commit25f68b08ab8c1fc35aab2d060b0f38ebf7856785 (patch)
tree7a5847167a031aaa1eaeb6e3cb1a5bd8e8161330 /backends/platform/dc
parent8c5ead1f70ec3bb49e6633af0192bbcc90f4a1bf (diff)
downloadscummvm-rg350-25f68b08ab8c1fc35aab2d060b0f38ebf7856785.tar.gz
scummvm-rg350-25f68b08ab8c1fc35aab2d060b0f38ebf7856785.tar.bz2
scummvm-rg350-25f68b08ab8c1fc35aab2d060b0f38ebf7856785.zip
Moved backends/dc into new platform directory.
svn-id: r23357
Diffstat (limited to 'backends/platform/dc')
-rw-r--r--backends/platform/dc/DCLauncherDialog.h29
-rw-r--r--backends/platform/dc/Makefile58
-rw-r--r--backends/platform/dc/README26
-rw-r--r--backends/platform/dc/audio.cpp98
-rw-r--r--backends/platform/dc/cache.S38
-rw-r--r--backends/platform/dc/dc.h237
-rw-r--r--backends/platform/dc/dcloader.cpp441
-rw-r--r--backends/platform/dc/dcloader.h65
-rw-r--r--backends/platform/dc/dcmain.cpp230
-rw-r--r--backends/platform/dc/deficon.h50
-rw-r--r--backends/platform/dc/display.cpp656
-rw-r--r--backends/platform/dc/icon.cpp232
-rw-r--r--backends/platform/dc/icon.h48
-rw-r--r--backends/platform/dc/input.cpp250
-rw-r--r--backends/platform/dc/label.cpp138
-rw-r--r--backends/platform/dc/label.h39
-rw-r--r--backends/platform/dc/plugin.syms9
-rw-r--r--backends/platform/dc/plugin.x59
-rw-r--r--backends/platform/dc/portdefs.h39
-rw-r--r--backends/platform/dc/selector.cpp463
-rw-r--r--backends/platform/dc/softkbd.cpp169
-rw-r--r--backends/platform/dc/softkbd.h50
-rw-r--r--backends/platform/dc/time.cpp97
-rw-r--r--backends/platform/dc/vmsave.cpp407
24 files changed, 3928 insertions, 0 deletions
diff --git a/backends/platform/dc/DCLauncherDialog.h b/backends/platform/dc/DCLauncherDialog.h
new file mode 100644
index 0000000000..7dffcaa576
--- /dev/null
+++ b/backends/platform/dc/DCLauncherDialog.h
@@ -0,0 +1,29 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002-2004 Marcus Comstedt
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+class DCLauncherDialog {
+ public:
+ DCLauncherDialog() {}
+ int runModal();
+};
+
diff --git a/backends/platform/dc/Makefile b/backends/platform/dc/Makefile
new file mode 100644
index 0000000000..3ad96a6caf
--- /dev/null
+++ b/backends/platform/dc/Makefile
@@ -0,0 +1,58 @@
+# $URL$
+# $Id$
+
+ronindir = /usr/local/ronin
+
+BUILD_PLUGINS = 1
+
+srcdir = ../../..
+VPATH = $(srcdir)
+
+CC = sh-elf-gcc -ml -m4-single-only
+CXX = sh-elf-g++ -ml -m4-single-only
+CXXFLAGS= -O3 -Wno-multichar -funroll-loops -fschedule-insns2 -fomit-frame-pointer -fdelete-null-pointer-checks -fno-exceptions
+DEFINES = -D__DC__ -DNONSTANDARD_PORT -DUSE_MAD
+LDFLAGS = -Wl,-Ttext,0x8c010000 -nostartfiles $(ronindir)/lib/crt0.o
+INCLUDES= -I./ -I$(srcdir) -I$(srcdir)/common -I$(ronindir)/include/ -I$(srcdir)/engines
+LIBS = -L$(ronindir)/lib -lmad -lronin -lz -lm
+EXECUTABLE = scummvm.elf
+PLUGIN_PREFIX =
+PLUGIN_SUFFIX = .plg
+PLUGIN_EXTRA_DEPS = plugin.x plugin.syms scummvm.elf
+PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,-Tplugin.x,--just-symbols,scummvm.elf,--retain-symbols-file,plugin.syms -L$(ronindir)/lib
+MKDIR = mkdir -p
+RM = rm -f
+RM_REC = rm -rf
+AR = sh-elf-ar cru
+RANLIB = sh-elf-ranlib
+HAVE_GCC3 = true
+DISABLE_SCALERS = true
+
+ifdef BUILD_PLUGINS
+DEFINES += -DDYNAMIC_MODULES
+PRE_OBJS_FLAGS = -Wl,--whole-archive
+POST_OBJS_FLAGS = -Wl,--no-whole-archive
+endif
+
+OBJS := dcmain.o time.o display.o audio.o input.o selector.o icon.o \
+ label.o vmsave.o softkbd.o dcloader.o cache.o
+
+MODULE_DIRS += .
+
+include $(srcdir)/Makefile.common
+
+scummvm.bin : scummvm.elf
+ sh-elf-objcopy -S -R .stack -O binary $< $@
+
+SCUMMVM.BIN : scummvm.bin
+ scramble $< $@
+
+plugin_dist :
+ for p in plugins/*.plg; do \
+ sh-elf-strip -g -o "`basename \"$$p\" | tr '[:lower:]' '[:upper:]'`" "$$p"; \
+ done
+
+dist : SCUMMVM.BIN plugins plugin_dist
+
+spotless : distclean
+ $(RM) SCUMMVM.BIN scummvm.bin *.PLG
diff --git a/backends/platform/dc/README b/backends/platform/dc/README
new file mode 100644
index 0000000000..c83254aa34
--- /dev/null
+++ b/backends/platform/dc/README
@@ -0,0 +1,26 @@
+Compiling ScummVM for SEGA Dreamcast
+====================================
+
+If you want to compile ScummVM for your Dreamcast,
+you'll need the following:
+
+* gcc-3.4.2 configured as a cross-compiler for `sh-elf'
+
+* binutils-2.14 configured likewise (don't use 2.15, it's broken...)
+
+* newlib for sh-elf : <URL:http://mc.pp.se/dc/files/newlib-1.12.0.tar.gz>
+
+* libronin-0.4 : <URL:http://peter.bortas.org/scumm/libronin-0.4.tar.gz>
+
+* libmad : <URL:http://mc.pp.se/dc/files/libmad-0.15.1b.tar.gz>
+
+* GNU make
+
+
+Edit the Makefile to contain the path to libronin if you installed it
+somewhere other than /usr/local/ronin, then run `make dist', and you
+should get a scrambled binary SCUMMVM.BIN and some plugins *.PLG.
+
+For serial/IP upload, remove the "BUILD_PLUGINS" line and just run `make',
+to get a static binary with the name `scummvm.elf'.
+
diff --git a/backends/platform/dc/audio.cpp b/backends/platform/dc/audio.cpp
new file mode 100644
index 0000000000..b69d29172b
--- /dev/null
+++ b/backends/platform/dc/audio.cpp
@@ -0,0 +1,98 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002-2004 Marcus Comstedt
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include <common/stdafx.h>
+#include <common/scummsys.h>
+#include "base/engine.h"
+#include "dc.h"
+
+EXTERN_C void *memcpy4s(void *s1, const void *s2, unsigned int n);
+
+void initSound()
+{
+ stop_sound();
+ do_sound_command(CMD_SET_FREQ_EXP(FREQ_22050_EXP));
+ do_sound_command(CMD_SET_STEREO(1));
+ do_sound_command(CMD_SET_BUFFER(SOUND_BUFFER_SHIFT));
+}
+
+bool OSystem_Dreamcast::setSoundCallback(SoundProc proc, void *param)
+{
+ assert(SAMPLE_MODE == 0);
+
+ _sound_proc_param = param;
+ _sound_proc = proc;
+
+ return true;
+}
+
+void OSystem_Dreamcast::clearSoundCallback()
+{
+ _sound_proc = NULL;
+ _sound_proc_param = NULL;
+}
+
+void OSystem_Dreamcast::checkSound()
+{
+ int n;
+ int curr_ring_buffer_samples;
+
+ if(!_sound_proc)
+ return;
+
+ if(read_sound_int(&SOUNDSTATUS->mode) != MODE_PLAY)
+ start_sound();
+
+ curr_ring_buffer_samples = read_sound_int(&SOUNDSTATUS->ring_length);
+
+ n = read_sound_int(&SOUNDSTATUS->samplepos);
+
+ if((n-=fillpos)<0)
+ n += curr_ring_buffer_samples;
+
+ n = ADJUST_BUFFER_SIZE(n-10);
+
+ if(n<100)
+ return;
+
+ _sound_proc(_sound_proc_param, (byte*)temp_sound_buffer,
+ 2*SAMPLES_TO_BYTES(n));
+
+ if(fillpos+n > curr_ring_buffer_samples) {
+ int r = curr_ring_buffer_samples - fillpos;
+ memcpy4s(RING_BUF+fillpos, temp_sound_buffer, SAMPLES_TO_BYTES(r));
+ fillpos = 0;
+ n -= r;
+ memcpy4s(RING_BUF, temp_sound_buffer+r, SAMPLES_TO_BYTES(n));
+ } else {
+ memcpy4s(RING_BUF+fillpos, temp_sound_buffer, SAMPLES_TO_BYTES(n));
+ }
+ if((fillpos += n) >= curr_ring_buffer_samples)
+ fillpos = 0;
+}
+
+int OSystem_Dreamcast::getOutputSampleRate() const
+{
+ return read_sound_int(&SOUNDSTATUS->freq);
+}
+
diff --git a/backends/platform/dc/cache.S b/backends/platform/dc/cache.S
new file mode 100644
index 0000000000..1af1678ced
--- /dev/null
+++ b/backends/platform/dc/cache.S
@@ -0,0 +1,38 @@
+
+ .globl _flush_instruction_cache
+
+ .align 2
+
+ ! Flush the SH instruction cache
+
+_flush_instruction_cache:
+ mova fcc,r0
+ mov.l p2_mask,r1
+ or r1,r0
+ jmp @r0
+ nop
+ nop
+fcc:
+ mov.l ccr_addr,r0
+ mov.l ccr_data,r1
+ mov.l r1,@r0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ rts
+ nop
+
+ .align 2
+
+p2_mask:
+ .long 0xa0000000
+ccr_addr:
+ .long 0xff00001c
+ccr_data:
+ .word 0x0905
+
diff --git a/backends/platform/dc/dc.h b/backends/platform/dc/dc.h
new file mode 100644
index 0000000000..aaf505bd64
--- /dev/null
+++ b/backends/platform/dc/dc.h
@@ -0,0 +1,237 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002-2004 Marcus Comstedt
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include <common/system.h>
+#include <ronin/soundcommon.h>
+
+#define NUM_BUFFERS 4
+#define SOUND_BUFFER_SHIFT 3
+
+class Interactive
+{
+ public:
+ virtual int key(int k, byte &shiftFlags) = 0;
+ virtual void mouse(int x, int y) = 0;
+};
+
+#include "softkbd.h"
+
+class OSystem_Dreamcast : public OSystem {
+
+ public:
+ OSystem_Dreamcast();
+
+
+ // Determine whether the backend supports the specified feature.
+ bool hasFeature(Feature f);
+
+ // En-/disable the specified feature.
+ void setFeatureState(Feature f, bool enable);
+
+ // Query the state of the specified feature.
+ bool getFeatureState(Feature f);
+
+ // Retrieve a list of all graphics modes supported by this backend.
+ const GraphicsMode *getSupportedGraphicsModes() const;
+
+ // Return the ID of the 'default' graphics mode.
+ int getDefaultGraphicsMode() const;
+
+ // Switch to the specified graphics mode.
+ bool setGraphicsMode(int mode);
+
+ // Determine which graphics mode is currently active.
+ int getGraphicsMode() const;
+
+ // Set colors of the palette
+ void setPalette(const byte *colors, uint start, uint num);
+ void grabPalette(byte *colors, uint start, uint num);
+
+ // Set the size of the video bitmap.
+ // Typically, 320x200
+ void initSize(uint w, uint h);
+ int16 getHeight() { return _screen_h; }
+ int16 getWidth() { return _screen_w; }
+
+ // Draw a bitmap to screen.
+ // The screen will not be updated to reflect the new bitmap
+ void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h);
+
+ // Copies the current screen contents to a new surface.
+ bool grabRawScreen(Graphics::Surface *surf);
+
+ // Clear the screen to black.
+ void clearScreen();
+
+ // Update the dirty areas of the screen
+ void updateScreen();
+
+ // Either show or hide the mouse cursor
+ bool showMouse(bool visible);
+
+ // Move ("warp") the mouse cursor to the specified position.
+ void warpMouse(int x, int y);
+
+ // Set the bitmap that's used when drawing the cursor.
+ void setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor, int cursorTargetScale);
+
+ // Replace the specified range of cursor the palette with new colors.
+ void setCursorPalette(const byte *colors, uint start, uint num);
+
+ // Disable or enable cursor palette.
+ void disableCursorPalette(bool disable);
+
+ // Shaking is used in SCUMM. Set current shake position.
+ void setShakePos(int shake_pos);
+
+ // Get the number of milliseconds since the program was started.
+ uint32 getMillis();
+
+ // Delay for a specified amount of milliseconds
+ void delayMillis(uint msecs);
+
+ // Get the next event.
+ // Returns true if an event was retrieved.
+ bool pollEvent(Event &event);
+
+ // Set function that generates samples
+ bool setSoundCallback(SoundProc proc, void *param);
+ void clearSoundCallback();
+
+ // Determine the output sample rate. Audio data provided by the sound
+ // callback will be played using this rate.
+ int getOutputSampleRate() const;
+
+ // Initialise the specified CD drive for audio playback.
+ bool openCD(int drive);
+
+ // Poll cdrom status
+ // Returns true if cd audio is playing
+ bool pollCD();
+
+ // Play cdrom audio track
+ void playCD(int track, int num_loops, int start_frame, int duration);
+
+ // Stop cdrom audio track
+ void stopCD();
+
+ // Update cdrom audio status
+ void updateCD();
+
+ // Quit
+ void quit();
+
+ // Overlay
+ int16 getOverlayHeight();
+ int16 getOverlayWidth();
+ int screenToOverlayX(int x);
+ int screenToOverlayY(int y);
+ int overlayToScreenX(int x);
+ int overlayToScreenY(int y);
+ void showOverlay();
+ void hideOverlay();
+ void clearOverlay();
+ void grabOverlay(int16 *buf, int pitch);
+ void copyRectToOverlay(const int16 *buf, int pitch, int x, int y, int w, int h);
+ OverlayColor RGBToColor(uint8 r, uint8 g, uint8 b) { return ARGBToColor(255, r, g, b); }
+ void colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b) {
+ uint8 tmp; colorToARGB(color, tmp, r, g, b);
+ }
+ OverlayColor ARGBToColor(uint8 a, uint8 r, uint8 g, uint8 b) {
+ return ((a&0xf0)<<8)|((r&0xf0)<<4)|(g&0xf0)|(b>>4);
+ }
+ void colorToARGB(OverlayColor color, uint8 &a, uint8 &r, uint8 &g, uint8 &b) {
+ a = ((color>>8)&0xf0)|((color>>12)&0x0f);
+ r = ((color>>4)&0xf0)|((color>>8)&0x0f);
+ g = (color&0xf0)|((color>>4)&0x0f);
+ b = ((color<<4)&0xf0)|(color&0x0f);
+ }
+
+ // Add a callback timer
+ void setTimerCallback(TimerProc callback, int timer);
+
+ // Mutex handling
+ MutexRef createMutex();
+ void lockMutex(MutexRef mutex);
+ void unlockMutex(MutexRef mutex);
+ void deleteMutex(MutexRef mutex);
+
+ // Set a window caption or any other comparable status display to the
+ // given value.
+ void setWindowCaption(const char *caption);
+
+ // Savefile handling
+ Common::SaveFileManager *getSavefileManager();
+
+
+ // Extra SoftKbd support
+ void mouseToSoftKbd(int x, int y, int &rx, int &ry) const;
+
+
+ private:
+
+ SoftKeyboard _softkbd;
+
+ int _ms_cur_x, _ms_cur_y, _ms_cur_w, _ms_cur_h, _ms_old_x, _ms_old_y;
+ int _ms_hotspot_x, _ms_hotspot_y, _ms_visible, _devpoll;
+ int _current_shake_pos, _screen_w, _screen_h;
+ int _overlay_x, _overlay_y;
+ unsigned char *_ms_buf;
+ unsigned char _ms_keycolor;
+ SoundProc _sound_proc;
+ void *_sound_proc_param;
+ bool _overlay_visible, _overlay_dirty, _screen_dirty;
+ int _screen_buffer, _overlay_buffer, _mouse_buffer;
+ bool _aspect_stretch, _softkbd_on, _enable_cursor_palette;
+ float _overlay_fade, _xscale, _yscale, _top_offset;
+ int _softkbd_motion;
+
+ uint32 _timer_duration, _timer_next_expiry;
+ bool _timer_active;
+ int (*_timer_callback) (int);
+
+ unsigned char *screen;
+ unsigned short *mouse;
+ unsigned short *overlay;
+ void *screen_tx[NUM_BUFFERS];
+ void *mouse_tx[NUM_BUFFERS];
+ void *ovl_tx[NUM_BUFFERS];
+ unsigned short palette[256], cursor_palette[256];
+
+ int temp_sound_buffer[RING_BUFFER_SAMPLES>>SOUND_BUFFER_SHIFT];
+
+ void checkSound();
+
+ void drawMouse(int xdraw, int ydraw, int w, int h,
+ unsigned char *buf, bool visible);
+
+ void setScaling();
+};
+
+
+extern int handleInput(struct mapledev *pad,
+ int &mouse_x, int &mouse_y,
+ byte &shiftFlags, Interactive *inter = NULL);
+extern void initSound();
+extern bool selectGame(char *&, char *&, class Icon &);
+
diff --git a/backends/platform/dc/dcloader.cpp b/backends/platform/dc/dcloader.cpp
new file mode 100644
index 0000000000..2ce853c061
--- /dev/null
+++ b/backends/platform/dc/dcloader.cpp
@@ -0,0 +1,441 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002-2004 Marcus Comstedt
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include <common/stdafx.h>
+#include <ronin/ronin.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "dcloader.h"
+
+#ifdef DL_DEBUG
+#define DBG(...) reportf(__VA_ARGS__)
+#else
+#define DBG(...) 0
+#endif
+
+
+/* ELF stuff */
+
+typedef unsigned short Elf32_Half, Elf32_Section;
+typedef unsigned long Elf32_Word, Elf32_Addr, Elf32_Off;
+typedef signed long Elf32_Sword;
+typedef Elf32_Half Elf32_Versym;
+
+#define EI_NIDENT (16)
+#define ELFMAG "\177ELF\1\1"
+#define SELFMAG 6
+
+typedef struct
+{
+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ Elf32_Half e_type; /* Object file type */
+ Elf32_Half e_machine; /* Architecture */
+ Elf32_Word e_version; /* Object file version */
+ Elf32_Addr e_entry; /* Entry point virtual address */
+ Elf32_Off e_phoff; /* Program header table file offset */
+ Elf32_Off e_shoff; /* Section header table file offset */
+ Elf32_Word e_flags; /* Processor-specific flags */
+ Elf32_Half e_ehsize; /* ELF header size in bytes */
+ Elf32_Half e_phentsize; /* Program header table entry size */
+ Elf32_Half e_phnum; /* Program header table entry count */
+ Elf32_Half e_shentsize; /* Section header table entry size */
+ Elf32_Half e_shnum; /* Section header table entry count */
+ Elf32_Half e_shstrndx; /* Section header string table index */
+} Elf32_Ehdr;
+
+typedef struct
+{
+ Elf32_Word p_type; /* Segment type */
+ Elf32_Off p_offset; /* Segment file offset */
+ Elf32_Addr p_vaddr; /* Segment virtual address */
+ Elf32_Addr p_paddr; /* Segment physical address */
+ Elf32_Word p_filesz; /* Segment size in file */
+ Elf32_Word p_memsz; /* Segment size in memory */
+ Elf32_Word p_flags; /* Segment flags */
+ Elf32_Word p_align; /* Segment alignment */
+} Elf32_Phdr;
+
+typedef struct
+{
+ Elf32_Word sh_name; /* Section name (string tbl index) */
+ Elf32_Word sh_type; /* Section type */
+ Elf32_Word sh_flags; /* Section flags */
+ Elf32_Addr sh_addr; /* Section virtual addr at execution */
+ Elf32_Off sh_offset; /* Section file offset */
+ Elf32_Word sh_size; /* Section size in bytes */
+ Elf32_Word sh_link; /* Link to another section */
+ Elf32_Word sh_info; /* Additional section information */
+ Elf32_Word sh_addralign; /* Section alignment */
+ Elf32_Word sh_entsize; /* Entry size if section holds table */
+} Elf32_Shdr;
+
+typedef struct
+{
+ Elf32_Word st_name; /* Symbol name (string tbl index) */
+ Elf32_Addr st_value; /* Symbol value */
+ Elf32_Word st_size; /* Symbol size */
+ unsigned char st_info; /* Symbol type and binding */
+ unsigned char st_other; /* Symbol visibility */
+ Elf32_Section st_shndx; /* Section index */
+} Elf32_Sym;
+
+typedef struct
+{
+ Elf32_Addr r_offset; /* Address */
+ Elf32_Word r_info; /* Relocation type and symbol index */
+ Elf32_Sword r_addend; /* Addend */
+} Elf32_Rela;
+
+
+
+extern "C" void flush_instruction_cache();
+
+static void purge_copyback()
+{
+ int i;
+ for(i=0; i!=(1<<14); i+=(1<<5))
+ *(volatile unsigned int *)(0xf4000000+i) &= ~3;
+}
+
+
+void DLObject::seterror(const char *fmt, ...)
+{
+ if(errbuf) {
+ va_list va;
+ va_start(va, fmt);
+ vsnprintf(errbuf, MAXDLERRLEN, fmt, va);
+ va_end(va);
+ }
+}
+
+void DLObject::discard_symtab()
+{
+ free(symtab);
+ free(strtab);
+ symtab = NULL;
+ strtab = NULL;
+ symbol_cnt = 0;
+}
+
+void DLObject::unload()
+{
+ discard_symtab();
+ free(segment);
+ segment = NULL;
+}
+
+bool DLObject::relocate(int fd, unsigned long offset, unsigned long size)
+{
+ Elf32_Rela *rela;
+
+ if(!(rela = (Elf32_Rela *)malloc(size))) {
+ seterror("Out of memory.");
+ return false;
+ }
+
+ if(lseek(fd, offset, SEEK_SET)<0 ||
+ read(fd, rela, size) != size) {
+ seterror("Relocation table load failed.");
+ free(rela);
+ return false;
+ }
+
+ int cnt = size / sizeof(*rela);
+ for(int i=0; i<cnt; i++) {
+
+ Elf32_Sym *sym = (Elf32_Sym *)(((char *)symtab)+(rela[i].r_info>>4));
+
+ void *target = ((char *)segment)+rela[i].r_offset;
+
+ switch(rela[i].r_info & 0xf) {
+ case 1: /* DIR32 */
+ if(sym->st_shndx < 0xff00)
+ *(unsigned long *)target += (unsigned long)segment;
+ break;
+ default:
+ seterror("Unknown relocation type %d.", rela[i].r_info & 0xf);
+ free(rela);
+ return false;
+ }
+
+ }
+
+ free(rela);
+ return true;
+}
+
+
+bool DLObject::load(int fd)
+{
+ Elf32_Ehdr ehdr;
+ Elf32_Phdr phdr;
+ Elf32_Shdr *shdr;
+ int symtab_sect = -1;
+
+ if(read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr) ||
+ memcmp(ehdr.e_ident, ELFMAG, SELFMAG) ||
+ ehdr.e_type != 2 || ehdr.e_machine != 42 ||
+ ehdr.e_phentsize < sizeof(phdr) || ehdr.e_shentsize != sizeof(*shdr) ||
+ ehdr.e_phnum != 1) {
+ seterror("Invalid file type.");
+ return false;
+ }
+
+ DBG("phoff = %d, phentsz = %d, phnum = %d\n",
+ ehdr.e_phoff, ehdr.e_phentsize, ehdr.e_phnum);
+
+ if(lseek(fd, ehdr.e_phoff, SEEK_SET)<0 ||
+ read(fd, &phdr, sizeof(phdr)) != sizeof(phdr)) {
+ seterror("Program header load failed.");
+ return false;
+ }
+
+ if(phdr.p_type != 1 || phdr.p_vaddr != 0 || phdr.p_paddr != 0 ||
+ phdr.p_filesz > phdr.p_memsz) {
+ seterror("Invalid program header.");
+ return false;
+ }
+
+ DBG("offs = %d, filesz = %d, memsz = %d, align = %d\n",
+ phdr.p_offset, phdr.p_filesz, phdr.p_memsz, phdr.p_align);
+
+ if(!(segment = memalign(phdr.p_align, phdr.p_memsz))) {
+ seterror("Out of memory.");
+ return false;
+ }
+
+ DBG("segment @ %p\n", segment);
+
+ if(phdr.p_memsz > phdr.p_filesz)
+ memset(((char *)segment) + phdr.p_filesz, 0, phdr.p_memsz - phdr.p_filesz);
+
+ if(lseek(fd, phdr.p_offset, SEEK_SET)<0 ||
+ read(fd, segment, phdr.p_filesz) != phdr.p_filesz) {
+ seterror("Segment load failed.");
+ return false;
+ }
+
+ DBG("shoff = %d, shentsz = %d, shnum = %d\n",
+ ehdr.e_shoff, ehdr.e_shentsize, ehdr.e_shnum);
+
+ if(!(shdr = (Elf32_Shdr *)malloc(ehdr.e_shnum * sizeof(*shdr)))) {
+ seterror("Out of memory.");
+ return false;
+ }
+
+ if(lseek(fd, ehdr.e_shoff, SEEK_SET)<0 ||
+ read(fd, shdr, ehdr.e_shnum * sizeof(*shdr)) !=
+ ehdr.e_shnum * sizeof(*shdr)) {
+ seterror("Section headers load failed.");
+ free(shdr);
+ return false;
+ }
+
+ for(int i=0; i<ehdr.e_shnum; i++) {
+ DBG("Section %d: type = %d, size = %d, entsize = %d, link = %d\n",
+ i, shdr[i].sh_type, shdr[i].sh_size, shdr[i].sh_entsize, shdr[i].sh_link);
+ if(shdr[i].sh_type == 2 && shdr[i].sh_entsize == sizeof(Elf32_Sym) &&
+ shdr[i].sh_link < ehdr.e_shnum && shdr[shdr[i].sh_link].sh_type == 3 &&
+ symtab_sect < 0)
+ symtab_sect = i;
+ }
+
+ if(symtab_sect < 0) {
+ seterror("No symbol table.");
+ free(shdr);
+ return false;
+ }
+
+ if(!(symtab = malloc(shdr[symtab_sect].sh_size))) {
+ seterror("Out of memory.");
+ free(shdr);
+ return false;
+ }
+
+ if(lseek(fd, shdr[symtab_sect].sh_offset, SEEK_SET)<0 ||
+ read(fd, symtab, shdr[symtab_sect].sh_size) != shdr[symtab_sect].sh_size){
+ seterror("Symbol table load failed.");
+ free(shdr);
+ return false;
+ }
+
+ if(!(strtab = (char *)malloc(shdr[shdr[symtab_sect].sh_link].sh_size))) {
+ seterror("Out of memory.");
+ free(shdr);
+ return false;
+ }
+
+ if(lseek(fd, shdr[shdr[symtab_sect].sh_link].sh_offset, SEEK_SET)<0 ||
+ read(fd, strtab, shdr[shdr[symtab_sect].sh_link].sh_size) !=
+ shdr[shdr[symtab_sect].sh_link].sh_size){
+ seterror("Symbol table strings load failed.");
+ free(shdr);
+ return false;
+ }
+
+ symbol_cnt = shdr[symtab_sect].sh_size / sizeof(Elf32_Sym);
+ DBG("Loaded %d symbols.\n", symbol_cnt);
+
+ Elf32_Sym *s = (Elf32_Sym *)symtab;
+ for(int c = symbol_cnt; c--; s++)
+ if(s->st_shndx < 0xff00)
+ s->st_value += (Elf32_Addr)segment;
+
+ for(int i=0; i<ehdr.e_shnum; i++)
+ if(shdr[i].sh_type == 4 && shdr[i].sh_entsize == sizeof(Elf32_Rela) &&
+ shdr[i].sh_link == symtab_sect && shdr[i].sh_info < ehdr.e_shnum &&
+ (shdr[shdr[i].sh_info].sh_flags & 2))
+ if(!relocate(fd, shdr[i].sh_offset, shdr[i].sh_size)) {
+ free(shdr);
+ return false;
+ }
+
+ free(shdr);
+
+ return true;
+}
+
+bool DLObject::open(const char *path)
+{
+ int fd;
+ void *ctors_start, *ctors_end;
+
+ DBG("open(\"%s\")\n", path);
+
+ if((fd = ::open(path, O_RDONLY))<0) {
+ seterror("%s not found.", path);
+ return false;
+ }
+
+ if(!load(fd)) {
+ ::close(fd);
+ unload();
+ return false;
+ }
+
+ ::close(fd);
+
+ int oldmask = getimask();
+ setimask(15);
+ purge_copyback();
+ flush_instruction_cache();
+ setimask(oldmask);
+
+ ctors_start = symbol("__plugin_ctors");
+ ctors_end = symbol("__plugin_ctors_end");
+ dtors_start = symbol("__plugin_dtors");
+ dtors_end = symbol("__plugin_dtors_end");
+
+ if(ctors_start == NULL || ctors_end == NULL || dtors_start == NULL ||
+ dtors_end == NULL) {
+ seterror("Missing ctors/dtors.");
+ dtors_start = dtors_end = NULL;
+ unload();
+ return false;
+ }
+
+ DBG("Calling constructors.\n");
+ for(void (**f)(void) = (void (**)(void))ctors_start; f != ctors_end; f++)
+ (**f)();
+
+ DBG("%s opened ok.\n", path);
+ return true;
+}
+
+bool DLObject::close()
+{
+ if(dtors_start != NULL && dtors_end != NULL)
+ for(void (**f)(void) = (void (**)(void))dtors_start; f != dtors_end; f++)
+ (**f)();
+ dtors_start = dtors_end = NULL;
+ unload();
+ return true;
+}
+
+void *DLObject::symbol(const char *name)
+{
+ DBG("symbol(\"%s\")\n", name);
+
+ if(symtab == NULL || strtab == NULL || symbol_cnt < 1) {
+ seterror("No symbol table loaded.");
+ return NULL;
+ }
+
+ Elf32_Sym *s = (Elf32_Sym *)symtab;
+ for(int c = symbol_cnt; c--; s++)
+ if((s->st_info>>4 == 1 || s->st_info>>4 == 2) &&
+ strtab[s->st_name] == '_' && !strcmp(name, strtab+s->st_name+1)) {
+ DBG("=> %p\n", (void*)s->st_value);
+ return (void*)s->st_value;
+ }
+
+ seterror("Symbol \"%s\" not found.", name);
+ return NULL;
+}
+
+
+static char dlerr[MAXDLERRLEN];
+
+void *dlopen(const char *filename, int flags)
+{
+ DLObject *obj = new DLObject(dlerr);
+ if(obj->open(filename))
+ return (void *)obj;
+ delete obj;
+ return NULL;
+}
+
+int dlclose(void *handle)
+{
+ DLObject *obj = (DLObject *)handle;
+ if(obj == NULL) {
+ strcpy(dlerr, "Handle is NULL.");
+ return -1;
+ }
+ if(obj->close()) {
+ delete obj;
+ return 0;
+ }
+ return -1;
+}
+
+void *dlsym(void *handle, const char *symbol)
+{
+ if(handle == NULL) {
+ strcpy(dlerr, "Handle is NULL.");
+ return NULL;
+ }
+ return ((DLObject *)handle)->symbol(symbol);
+}
+
+const char *dlerror()
+{
+ return dlerr;
+}
+
+void dlforgetsyms(void *handle)
+{
+ if(handle != NULL)
+ ((DLObject *)handle)->discard_symtab();
+}
diff --git a/backends/platform/dc/dcloader.h b/backends/platform/dc/dcloader.h
new file mode 100644
index 0000000000..2c7010d7dc
--- /dev/null
+++ b/backends/platform/dc/dcloader.h
@@ -0,0 +1,65 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002-2004 Marcus Comstedt
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef DC_DCLOADER_H
+#define DC_DCLOADER_H
+
+#include "dc.h"
+
+#define MAXDLERRLEN 80
+
+class DLObject {
+ private:
+ char *errbuf; /* For error messages, at least MAXDLERRLEN in size */
+
+ void *segment, *symtab;
+ char *strtab;
+ int symbol_cnt;
+ void *dtors_start, *dtors_end;
+
+ void seterror(const char *fmt, ...);
+ void unload();
+ bool relocate(int fd, unsigned long offset, unsigned long size);
+ bool load(int fd);
+
+ public:
+ bool open(const char *path);
+ bool close();
+ void *symbol(const char *name);
+ void discard_symtab();
+
+ DLObject(char *_errbuf = NULL) : errbuf(_errbuf), segment(NULL),symtab(NULL),
+ strtab(NULL), symbol_cnt(0), dtors_start(NULL), dtors_end(NULL) {}
+};
+
+#define RTLD_LAZY 0
+
+extern "C" {
+ void *dlopen(const char *filename, int flags);
+ int dlclose(void *handle);
+ void *dlsym(void *handle, const char *symbol);
+ const char *dlerror();
+ void dlforgetsyms(void *handle);
+};
+
+#endif
diff --git a/backends/platform/dc/dcmain.cpp b/backends/platform/dc/dcmain.cpp
new file mode 100644
index 0000000000..4b03ec1551
--- /dev/null
+++ b/backends/platform/dc/dcmain.cpp
@@ -0,0 +1,230 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002-2004 Marcus Comstedt
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include <common/stdafx.h>
+#include <common/scummsys.h>
+#include <base/engine.h>
+#include <base/main.h>
+#include <base/plugins.h>
+#include "dc.h"
+#include "icon.h"
+#include "DCLauncherDialog.h"
+#include <common/config-manager.h>
+
+
+Icon icon;
+const char *gGameName;
+
+
+OSystem_Dreamcast::OSystem_Dreamcast()
+ : _devpoll(0), screen(NULL), mouse(NULL), overlay(NULL), _softkbd(this),
+ _ms_buf(NULL), _sound_proc(NULL), _timer_active(false),
+ _current_shake_pos(0), _aspect_stretch(false), _softkbd_on(false),
+ _softkbd_motion(0), _enable_cursor_palette(false)
+{
+ memset(screen_tx, 0, sizeof(screen_tx));
+ memset(mouse_tx, 0, sizeof(mouse_tx));
+ memset(ovl_tx, 0, sizeof(ovl_tx));
+}
+
+
+/* CD Audio */
+static bool find_track(int track, int &first_sec, int &last_sec)
+{
+ struct TOC *toc = cdfs_gettoc();
+ if(!toc)
+ return false;
+ int i, first, last;
+ first = TOC_TRACK(toc->first);
+ last = TOC_TRACK(toc->last);
+ if(first < 1 || last > 99 || first > last)
+ return false;
+ for(i=first; i<=last; i++)
+ if(!(TOC_CTRL(toc->entry[i-1])&4))
+ if(track==1) {
+ first_sec = TOC_LBA(toc->entry[i-1]);
+ last_sec = TOC_LBA(toc->entry[i]);
+ return true;
+ } else
+ --track;
+ return false;
+}
+
+void OSystem_Dreamcast::playCD(int track, int num_loops, int start_frame, int duration)
+{
+ int first_sec, last_sec;
+#if 1
+ if(num_loops)
+ --num_loops;
+#endif
+ if(num_loops>14) num_loops=14;
+ else if(num_loops<0) num_loops=15; // infinity
+ if(!find_track(track, first_sec, last_sec))
+ return;
+ if(duration)
+ last_sec = first_sec + start_frame + duration;
+ first_sec += start_frame;
+ play_cdda_sectors(first_sec, last_sec, num_loops);
+}
+
+void OSystem_Dreamcast::stopCD()
+{
+ stop_cdda();
+}
+
+bool OSystem_Dreamcast::pollCD()
+{
+ extern int getCdState();
+ return getCdState() == 3;
+}
+
+void OSystem_Dreamcast::updateCD()
+{
+ // Dummy. The CD drive takes care of itself.
+}
+
+bool OSystem_Dreamcast::openCD(int drive)
+{
+ // Dummy.
+ return true;
+}
+
+void OSystem_Dreamcast::setWindowCaption(const char *caption)
+{
+ gGameName = caption;
+}
+
+void OSystem_Dreamcast::quit() {
+ exit(0);
+}
+
+/* Mutex handling */
+OSystem::MutexRef OSystem_Dreamcast::createMutex()
+{
+ return NULL;
+}
+
+void OSystem_Dreamcast::lockMutex(MutexRef mutex)
+{
+}
+
+void OSystem_Dreamcast::unlockMutex(MutexRef mutex)
+{
+}
+
+void OSystem_Dreamcast::deleteMutex(MutexRef mutex)
+{
+}
+
+
+/* Features */
+bool OSystem_Dreamcast::hasFeature(Feature f)
+{
+ switch(f) {
+ case kFeatureAspectRatioCorrection:
+ case kFeatureVirtualKeyboard:
+ case kFeatureOverlaySupportsAlpha:
+ case kFeatureCursorHasPalette:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void OSystem_Dreamcast::setFeatureState(Feature f, bool enable)
+{
+ switch(f) {
+ case kFeatureAspectRatioCorrection:
+ _aspect_stretch = enable;
+ if(screen)
+ setScaling();
+ break;
+ case kFeatureVirtualKeyboard:
+ _softkbd_on = enable;
+ break;
+ default:
+ break;
+ }
+}
+
+bool OSystem_Dreamcast::getFeatureState(Feature f)
+{
+ switch(f) {
+ case kFeatureAspectRatioCorrection:
+ return _aspect_stretch;
+ case kFeatureVirtualKeyboard:
+ return _softkbd_on;
+ default:
+ return false;
+ }
+}
+
+
+void dc_init_hardware()
+{
+#ifndef NOSERIAL
+ serial_init(57600);
+ usleep(2000000);
+ printf("Serial OK\r\n");
+#endif
+
+ cdfs_init();
+ maple_init();
+ dc_setup_ta();
+ init_arm();
+}
+
+int main()
+{
+ static char *argv[] = { "scummvm", NULL, };
+ static int argc = 1;
+
+ dc_init_hardware();
+ initSound();
+
+ g_system = new OSystem_Dreamcast();
+ assert(g_system);
+
+ int res = scummvm_main(argc, argv);
+
+ exit(0);
+}
+
+int DCLauncherDialog::runModal()
+{
+ char *base = NULL, *dir = NULL;
+
+ if(!selectGame(base, dir, icon))
+ exit(0);
+
+ // Set the game path.
+ ConfMan.addGameDomain(base);
+ if(dir != NULL)
+ ConfMan.set("path", dir, base);
+
+ // Set the target.
+ ConfMan.setActiveDomain(base);
+
+ return 0;
+}
+
diff --git a/backends/platform/dc/deficon.h b/backends/platform/dc/deficon.h
new file mode 100644
index 0000000000..0836d1d2ac
--- /dev/null
+++ b/backends/platform/dc/deficon.h
@@ -0,0 +1,50 @@
+static const unsigned char scummvm_icon[] = {
+0x00,0x00,0x01,0x00,0x01,0x00,0x20,0x20,0x10,0x00,0x01,0x00,0x04,0x00,0xe8,0x02,
+0x00,0x00,0x16,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x40,0x00,
+0x00,0x00,0x01,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x0d,
+0x0b,0x00,0x11,0x1a,0x19,0x00,0x1a,0x27,0x24,0x00,0x0a,0x32,0x27,0x00,0x05,0x45,
+0x2f,0x00,0x27,0x42,0x3a,0x00,0x10,0x61,0x45,0x00,0x03,0x82,0x52,0x00,0x08,0xa0,
+0x72,0x00,0x48,0x92,0x79,0x00,0x12,0xbb,0x7e,0x00,0x1b,0xbe,0x99,0x00,0x3d,0xc0,
+0x8b,0x00,0x5d,0xbf,0x9d,0x00,0x1f,0xdd,0x9d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x01,0x11,0x11,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x12,0x13,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x03,0x46,0x66,0x66,0x44,0x43,0x00,0x00,0x05,0x00,0x00,0x00,0x00,
+0x00,0x00,0x13,0x67,0x77,0x77,0x77,0x77,0x77,0x63,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x03,0x67,0x77,0x77,0x77,0x77,0x77,0x76,0x77,0x41,0x00,0x00,0x00,0x00,0x00,
+0x00,0x47,0x88,0x88,0xa8,0x88,0x78,0x87,0x77,0x77,0x73,0x00,0x00,0x00,0x00,0x00,
+0x00,0x68,0x8a,0xc8,0xac,0x8c,0xac,0x87,0x77,0x77,0x76,0x10,0x00,0x00,0x00,0x00,
+0x00,0x1d,0xcc,0xac,0xcd,0xdd,0xdc,0x8a,0x87,0x77,0x77,0x20,0x10,0x00,0x00,0x00,
+0x00,0x09,0xdd,0xcc,0x96,0x55,0x6d,0xac,0xa7,0x77,0x77,0x31,0x00,0x00,0x00,0x00,
+0x00,0x05,0x9d,0x93,0x21,0x00,0x9c,0xcb,0xc8,0x77,0x77,0x40,0x00,0x00,0x00,0x00,
+0x00,0x01,0x96,0x21,0x10,0x36,0x8a,0xcc,0xa8,0x88,0x77,0x40,0x00,0x00,0x00,0x00,
+0x00,0x00,0x11,0x11,0x36,0x8b,0x8c,0xbb,0xbc,0x87,0x88,0x30,0x00,0x00,0x00,0x00,
+0x00,0x00,0x01,0x36,0x8b,0xbb,0xbb,0xbb,0xcb,0x88,0xa7,0x20,0x00,0x00,0x00,0x00,
+0x00,0x00,0x14,0x88,0x8b,0xbb,0xbb,0xbb,0xbb,0xbb,0xa4,0x00,0x00,0x00,0x00,0x00,
+0x10,0x00,0x68,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0xcb,0x61,0x00,0x00,0x00,0x00,0x00,
+0x00,0x03,0xae,0xbb,0xbb,0xbb,0xbb,0xbb,0xbb,0x86,0x11,0x00,0x00,0x00,0x00,0x00,
+0x00,0x07,0xeb,0xbb,0xbb,0xbb,0xbb,0xbd,0x94,0x20,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x1a,0xee,0xbb,0xbb,0xbb,0xb7,0x43,0x11,0x33,0x11,0x00,0x00,0x00,0x00,0x01,
+0x00,0x1e,0xeb,0xbb,0xbb,0xbb,0x62,0x11,0x14,0x78,0x30,0x00,0x00,0x00,0x00,0x01,
+0x00,0x1c,0xee,0xbb,0xbb,0xbb,0x63,0x33,0x69,0xbe,0x61,0x01,0x00,0x00,0x00,0x00,
+0x00,0x1d,0xee,0xbb,0xbb,0x88,0x87,0x87,0x88,0x8a,0xa4,0x00,0x00,0x00,0x00,0x00,
+0x00,0x05,0xee,0xbb,0xbb,0x88,0x8b,0xdb,0x87,0x88,0xe7,0x10,0x00,0x00,0x00,0x00,
+0x00,0x02,0xdd,0xeb,0xbb,0xbd,0xbb,0xbb,0xb8,0x88,0xaa,0x20,0x00,0x00,0x00,0x00,
+0x00,0x00,0x59,0xce,0xbe,0xbb,0xbb,0xbb,0xbd,0xb8,0x73,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x05,0x9d,0xcc,0xbb,0xbb,0xbc,0xbd,0x74,0x20,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x15,0x99,0x9d,0xdd,0x99,0x65,0x10,0x00,0x01,0x20,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x11,0x11,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xf8,
+0x0f,0xff,0xff,0xc0,0x00,0xff,0xfe,0x00,0x00,0x3f,0xfc,0x00,0x00,0x1f,0xf0,0x00,
+0x00,0x0f,0xe0,0x00,0x00,0x0f,0xe0,0x00,0x00,0x07,0xe0,0x00,0x00,0x07,0xe0,0x00,
+0x00,0x03,0xe0,0x00,0x00,0x03,0xe0,0x00,0x00,0x03,0xf0,0x00,0x00,0x03,0xf0,0x00,
+0x00,0x07,0xf8,0x00,0x00,0x07,0xf8,0x00,0x00,0x07,0xf8,0x00,0x00,0x07,0xf0,0x00,
+0x00,0x0f,0xf0,0x00,0x00,0x0f,0xf0,0x00,0x00,0x0f,0xf0,0x00,0x00,0x1f,0xe0,0x00,
+0x00,0x0f,0xe0,0x00,0x00,0x07,0xf0,0x00,0x00,0x03,0xf0,0x00,0x00,0x03,0xf0,0x00,
+0x00,0x03,0xf8,0x00,0x00,0x03,0xf8,0x00,0x00,0x03,0xfc,0x00,0x00,0x07,0xfe,0x00,
+0x00,0x1f,0xff,0x00,0x00,0x7f,0xff,0xc0,0x01,0xff,0xff,0xfc,0x1f,0xff,
+};
diff --git a/backends/platform/dc/display.cpp b/backends/platform/dc/display.cpp
new file mode 100644
index 0000000000..338138f912
--- /dev/null
+++ b/backends/platform/dc/display.cpp
@@ -0,0 +1,656 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002-2005 Marcus Comstedt
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#define RONIN_TIMER_ACCESS
+
+#include <common/stdafx.h>
+#include <common/scummsys.h>
+#include <graphics/scaler/intern.h>
+#include <graphics/surface.h>
+#include "dc.h"
+
+#define SCREEN_W 640
+#define SCREEN_H 480
+#define MOUSE_W 128
+#define MOUSE_H 128
+
+#define OVL_W 320
+#define OVL_H 200
+#define OVL_TXSTRIDE 512
+
+#define TOP_OFFSET (_top_offset+_yscale*_current_shake_pos)
+
+#define QACR0 (*(volatile unsigned int *)(void *)0xff000038)
+#define QACR1 (*(volatile unsigned int *)(void *)0xff00003c)
+
+
+#define COPYPIXEL(n) do { \
+ unsigned short _tmp = pal[*s++]; \
+ d[n] = _tmp|(pal[*s++]<<16); \
+} while(0)
+
+static void texture_memcpy64_pal(void *dest, void *src, int cnt, unsigned short *pal)
+{
+ unsigned char *s = (unsigned char *)src;
+ unsigned int *d = (unsigned int *)(void *)
+ (0xe0000000 | (((unsigned long)dest) & 0x03ffffc0));
+ QACR0 = ((0xa4000000>>26)<<2)&0x1c;
+ QACR1 = ((0xa4000000>>26)<<2)&0x1c;
+ while(cnt--) {
+ COPYPIXEL(0);
+ COPYPIXEL(1);
+ COPYPIXEL(2);
+ COPYPIXEL(3);
+ asm("pref @%0" : : "r" (s+4*16));
+ COPYPIXEL(4);
+ COPYPIXEL(5);
+ COPYPIXEL(6);
+ COPYPIXEL(7);
+ asm("pref @%0" : : "r" (d));
+ d += 8;
+ COPYPIXEL(0);
+ COPYPIXEL(1);
+ COPYPIXEL(2);
+ COPYPIXEL(3);
+ asm("pref @%0" : : "r" (s+4*16));
+ COPYPIXEL(4);
+ COPYPIXEL(5);
+ COPYPIXEL(6);
+ COPYPIXEL(7);
+ asm("pref @%0" : : "r" (d));
+ d += 8;
+ }
+}
+
+static void texture_memcpy64(void *dest, void *src, int cnt)
+{
+ unsigned int *s = (unsigned int *)src;
+ unsigned int *d = (unsigned int *)(void *)
+ (0xe0000000 | (((unsigned long)dest) & 0x03ffffc0));
+ QACR0 = ((0xa4000000>>26)<<2)&0x1c;
+ QACR1 = ((0xa4000000>>26)<<2)&0x1c;
+ while(cnt--) {
+ d[0] = *s++;
+ d[1] = *s++;
+ d[2] = *s++;
+ d[3] = *s++;
+ asm("pref @%0" : : "r" (s+16));
+ d[4] = *s++;
+ d[5] = *s++;
+ d[6] = *s++;
+ d[7] = *s++;
+ asm("pref @%0" : : "r" (d));
+ d += 8;
+ d[0] = *s++;
+ d[1] = *s++;
+ d[2] = *s++;
+ d[3] = *s++;
+ asm("pref @%0" : : "r" (s+16));
+ d[4] = *s++;
+ d[5] = *s++;
+ d[6] = *s++;
+ d[7] = *s++;
+ asm("pref @%0" : : "r" (d));
+ d += 8;
+ }
+}
+
+void commit_dummy_transpoly()
+{
+ struct polygon_list mypoly;
+
+ mypoly.cmd =
+ TA_CMD_POLYGON|TA_CMD_POLYGON_TYPE_TRANSPARENT|TA_CMD_POLYGON_SUBLIST|
+ TA_CMD_POLYGON_STRIPLENGTH_2|TA_CMD_POLYGON_PACKED_COLOUR;
+ mypoly.mode1 = TA_POLYMODE1_Z_ALWAYS|TA_POLYMODE1_NO_Z_UPDATE;
+ mypoly.mode2 =
+ TA_POLYMODE2_BLEND_SRC_ALPHA|TA_POLYMODE2_BLEND_DST_INVALPHA|
+ TA_POLYMODE2_FOG_DISABLED|TA_POLYMODE2_ENABLE_ALPHA;
+ mypoly.texture = 0;
+ mypoly.red = mypoly.green = mypoly.blue = mypoly.alpha = 0;
+ ta_commit_list(&mypoly);
+}
+
+
+void OSystem_Dreamcast::setPalette(const byte *colors, uint start, uint num)
+{
+ unsigned short *dst = palette + start;
+ if(num>0)
+ while( num-- ) {
+ *dst++ = ((colors[0]<<7)&0x7c00)|
+ ((colors[1]<<2)&0x03e0)|
+ ((colors[2]>>3)&0x001f);
+ colors += 4;
+ }
+ _screen_dirty = true;
+}
+
+void OSystem_Dreamcast::setCursorPalette(const byte *colors, uint start, uint num)
+{
+ unsigned short *dst = cursor_palette + start;
+ if(num>0)
+ while( num-- ) {
+ *dst++ = ((colors[0]<<7)&0x7c00)|
+ ((colors[1]<<2)&0x03e0)|
+ ((colors[2]>>3)&0x001f);
+ colors += 4;
+ }
+ _enable_cursor_palette = true;
+}
+
+void OSystem_Dreamcast::disableCursorPalette(bool disable)
+{
+ _enable_cursor_palette = !disable;
+}
+
+void OSystem_Dreamcast::grabPalette(byte *colors, uint start, uint num)
+{
+ const unsigned short *src = palette + start;
+ if(num>0)
+ while( num-- ) {
+ unsigned short p = *src++;
+ colors[0] = ((p&0x7c00)>>7)|((p&0x7000)>>12);
+ colors[1] = ((p&0x03e0)>>2)|((p&0x0380)>>7);
+ colors[2] = ((p&0x001f)<<3)|((p&0x001c)>>2);
+ colors[3] = 0xff;
+ colors += 4;
+ }
+}
+
+void OSystem_Dreamcast::setScaling()
+{
+ if(_screen_w > 400) {
+ _xscale = _yscale = 1.0;
+ _top_offset = (SCREEN_H-_screen_h)>>1;
+ } else if(_aspect_stretch && _screen_w == 320 && _screen_h == 200) {
+ _xscale = SCREEN_W/320.0;
+ _yscale = SCREEN_H/200.0;
+ _top_offset = 0;
+ } else {
+ _xscale = _yscale = 2.0;
+ _top_offset = (SCREEN_H>>1)-_screen_h;
+ }
+}
+
+void OSystem_Dreamcast::initSize(uint w, uint h)
+{
+ assert(w <= SCREEN_W && h <= SCREEN_H);
+
+ gBitFormat = 4444;
+
+ _overlay_visible = false;
+ _overlay_fade = 0.0;
+ _screen_w = w;
+ _screen_h = h;
+ _overlay_x = (w-OVL_W)/2;
+ _overlay_y = (h-OVL_H)/2;
+ if(_overlay_x<0) _overlay_x = 0;
+ if(_overlay_y<0) _overlay_y = 0;
+ setScaling();
+ ta_sync();
+ if(!screen)
+ screen = new unsigned char[SCREEN_W*SCREEN_H];
+ if(!overlay)
+ overlay = new unsigned short[OVL_W*OVL_H];
+ for(int i=0; i<NUM_BUFFERS; i++)
+ if(!screen_tx[i])
+ screen_tx[i] = ta_txalloc(SCREEN_W*SCREEN_H*2);
+ for(int i=0; i<NUM_BUFFERS; i++)
+ if(!mouse_tx[i])
+ mouse_tx[i] = ta_txalloc(MOUSE_W*MOUSE_H*2);
+ for(int i=0; i<NUM_BUFFERS; i++)
+ if(!ovl_tx[i])
+ ovl_tx[i] = ta_txalloc(OVL_TXSTRIDE*OVL_H*2);
+ _screen_buffer = 0;
+ _mouse_buffer = 0;
+ _overlay_buffer = 0;
+ _screen_dirty = true;
+ _overlay_dirty = true;
+ *(volatile unsigned int *)(0xa05f80e4) = SCREEN_W/32; //stride
+ // dc_reset_screen(0, 0);
+ memset(screen, 0, SCREEN_W*SCREEN_H);
+ memset(overlay, 0, OVL_W*OVL_H*sizeof(unsigned short));
+
+ _devpoll = Timer();
+}
+
+void OSystem_Dreamcast::copyRectToScreen(const byte *buf, int pitch, int x, int y,
+ int w, int h)
+{
+ unsigned char *dst = screen + y*SCREEN_W + x;
+ do {
+ memcpy(dst, buf, w);
+ dst += SCREEN_W;
+ buf += pitch;
+ } while (--h);
+ _screen_dirty = true;
+}
+
+bool OSystem_Dreamcast::showMouse(bool visible)
+{
+ bool last = _ms_visible;
+ _ms_visible = visible;
+
+ return last;
+}
+
+void OSystem_Dreamcast::warpMouse(int x, int y)
+{
+ _ms_cur_x = x;
+ _ms_cur_y = y;
+}
+
+void OSystem_Dreamcast::setMouseCursor(const byte *buf, uint w, uint h,
+ int hotspot_x, int hotspot_y,
+ byte keycolor, int cursorTargetScale)
+{
+ _ms_cur_w = w;
+ _ms_cur_h = h;
+
+ _ms_hotspot_x = hotspot_x;
+ _ms_hotspot_y = hotspot_y;
+
+ _ms_keycolor = keycolor;
+
+ if (_ms_buf)
+ free(_ms_buf);
+
+ _ms_buf = (byte *)malloc(w * h);
+ memcpy(_ms_buf, buf, w * h);
+}
+
+void OSystem_Dreamcast::setShakePos(int shake_pos)
+{
+ _current_shake_pos = shake_pos;
+}
+
+void OSystem_Dreamcast::updateScreen(void)
+{
+ struct polygon_list mypoly;
+ struct packed_colour_vertex_list myvertex;
+
+ if(_screen_dirty) {
+
+ _screen_buffer++;
+ _screen_buffer &= NUM_BUFFERS-1;
+
+ unsigned short *dst = (unsigned short *)screen_tx[_screen_buffer];
+ unsigned char *src = screen;
+
+ // while((*((volatile unsigned int *)(void*)0xa05f810c) & 0x3ff) != 200);
+ // *((volatile unsigned int *)(void*)0xa05f8040) = 0xff0000;
+
+ for( int y = 0; y<_screen_h; y++ )
+ {
+ texture_memcpy64_pal( dst, src, _screen_w>>5, palette );
+ src += SCREEN_W;
+ dst += SCREEN_W;
+ }
+
+ _screen_dirty = false;
+ }
+
+ if( _overlay_visible && _overlay_dirty ) {
+
+ _overlay_buffer++;
+ _overlay_buffer &= NUM_BUFFERS-1;
+
+ unsigned short *dst = (unsigned short *)ovl_tx[_overlay_buffer];
+ unsigned short *src = overlay;
+
+ for( int y = 0; y<OVL_H; y++ )
+ {
+ texture_memcpy64( dst, src, OVL_W>>5 );
+ src += OVL_W;
+ dst += OVL_TXSTRIDE;
+ }
+
+ _overlay_dirty = false;
+ }
+
+ // *((volatile unsigned int *)(void*)0xa05f8040) = 0x00ff00;
+
+ mypoly.cmd =
+ TA_CMD_POLYGON|TA_CMD_POLYGON_TYPE_OPAQUE|TA_CMD_POLYGON_SUBLIST|
+ TA_CMD_POLYGON_STRIPLENGTH_2|TA_CMD_POLYGON_PACKED_COLOUR|TA_CMD_POLYGON_TEXTURED;
+ mypoly.mode1 = TA_POLYMODE1_Z_ALWAYS|TA_POLYMODE1_NO_Z_UPDATE;
+ mypoly.mode2 =
+ TA_POLYMODE2_BLEND_SRC|TA_POLYMODE2_FOG_DISABLED|TA_POLYMODE2_TEXTURE_REPLACE|
+ TA_POLYMODE2_U_SIZE_1024|TA_POLYMODE2_V_SIZE_1024;
+ mypoly.texture = TA_TEXTUREMODE_ARGB1555|TA_TEXTUREMODE_NON_TWIDDLED|
+ TA_TEXTUREMODE_STRIDE|TA_TEXTUREMODE_ADDRESS(screen_tx[_screen_buffer]);
+
+ mypoly.red = mypoly.green = mypoly.blue = mypoly.alpha = 0;
+
+ ta_begin_frame();
+ // *((volatile unsigned int *)(void*)0xa05f8040) = 0x0000ff;
+ ta_commit_list(&mypoly);
+
+ myvertex.cmd = TA_CMD_VERTEX;
+ myvertex.ocolour = 0;
+ myvertex.colour = 0;
+ myvertex.z = 0.5;
+ myvertex.u = 0.0;
+ myvertex.v = 0.0;
+
+ myvertex.x = 0.0;
+ myvertex.y = TOP_OFFSET;
+ ta_commit_list(&myvertex);
+
+ myvertex.x = _screen_w*_xscale;
+ myvertex.u = _screen_w*(1/1024.0);
+ ta_commit_list(&myvertex);
+
+ myvertex.x = 0.0;
+ myvertex.y += _screen_h*_yscale;
+ myvertex.u = 0.0;
+ myvertex.v = _screen_h*(1/1024.0);
+ ta_commit_list(&myvertex);
+
+ myvertex.x = _screen_w*_xscale;
+ myvertex.u = _screen_w*(1/1024.0);
+ myvertex.cmd |= TA_CMD_VERTEX_EOS;
+ ta_commit_list(&myvertex);
+
+ ta_commit_end();
+
+ if(_overlay_visible) {
+ if(_overlay_fade < 1.0)
+ _overlay_fade += 0.125;
+ } else {
+ if(_overlay_fade > 0)
+ _overlay_fade -= 0.125;
+ }
+
+ if(_overlay_fade > 0.0) {
+
+ mypoly.cmd =
+ TA_CMD_POLYGON|TA_CMD_POLYGON_TYPE_TRANSPARENT|TA_CMD_POLYGON_SUBLIST|
+ TA_CMD_POLYGON_STRIPLENGTH_2|TA_CMD_POLYGON_PACKED_COLOUR|TA_CMD_POLYGON_TEXTURED;
+ mypoly.mode1 = TA_POLYMODE1_Z_ALWAYS|TA_POLYMODE1_NO_Z_UPDATE;
+ mypoly.mode2 =
+ TA_POLYMODE2_BLEND_SRC_ALPHA|TA_POLYMODE2_BLEND_DST_INVALPHA|
+ TA_POLYMODE2_ENABLE_ALPHA|
+ TA_POLYMODE2_FOG_DISABLED|TA_POLYMODE2_TEXTURE_MODULATE_ALPHA|
+ TA_POLYMODE2_U_SIZE_512|TA_POLYMODE2_V_SIZE_512;
+ mypoly.texture = TA_TEXTUREMODE_ARGB4444|TA_TEXTUREMODE_NON_TWIDDLED|
+ TA_TEXTUREMODE_ADDRESS(ovl_tx[_overlay_buffer]);
+
+ mypoly.red = mypoly.green = mypoly.blue = mypoly.alpha = 0.0;
+
+ ta_commit_list(&mypoly);
+
+ myvertex.cmd = TA_CMD_VERTEX;
+ myvertex.ocolour = 0;
+ myvertex.colour = 0xffffff|(((int)(255*_overlay_fade))<<24);
+
+ myvertex.z = 0.5;
+ myvertex.u = 0.0;
+ myvertex.v = 0.0;
+
+ myvertex.x = _overlay_x*_xscale;
+ myvertex.y = _overlay_y*_yscale+TOP_OFFSET;
+ ta_commit_list(&myvertex);
+
+ myvertex.x += OVL_W*_xscale;
+ myvertex.u = OVL_W*(1.0/512.0);
+ ta_commit_list(&myvertex);
+
+ myvertex.x = _overlay_x*_xscale;
+ myvertex.y += OVL_H*_yscale;
+ myvertex.u = 0.0;
+ myvertex.v = OVL_H*(1.0/512.0);
+ ta_commit_list(&myvertex);
+
+ myvertex.x += OVL_W*_xscale;
+ myvertex.u = OVL_W*(1.0/512.0);
+ myvertex.cmd |= TA_CMD_VERTEX_EOS;
+ ta_commit_list(&myvertex);
+ }
+
+ if(_softkbd_on)
+ if(_softkbd_motion < 120)
+ _softkbd_motion += 10;
+ else
+ ;
+ else
+ if(_softkbd_motion > 0)
+ _softkbd_motion -= 10;
+
+ if(_softkbd_motion)
+ _softkbd.draw(330.0*sin(0.013*_softkbd_motion) - 320.0, 200.0,
+ 120-_softkbd_motion);
+
+ // *((volatile unsigned int *)(void*)0xa05f8040) = 0xffff00;
+ drawMouse(_ms_cur_x, _ms_cur_y, _ms_cur_w, _ms_cur_h, _ms_buf, _ms_visible);
+ // *((volatile unsigned int *)(void*)0xa05f8040) = 0xff00ff;
+ ta_commit_frame();
+
+ // *((volatile unsigned int *)(void*)0xa05f8040) = 0x0;
+}
+
+void OSystem_Dreamcast::drawMouse(int xdraw, int ydraw, int w, int h,
+ unsigned char *buf, bool visible)
+{
+ struct polygon_list mypoly;
+ struct packed_colour_vertex_list myvertex;
+
+ unsigned short *pal = _enable_cursor_palette? cursor_palette : palette;
+
+ _mouse_buffer++;
+ _mouse_buffer &= NUM_BUFFERS-1;
+
+ unsigned short *dst = (unsigned short *)mouse_tx[_mouse_buffer];
+ int y=0;
+
+ if(visible && w && h && w<=MOUSE_W && h<=MOUSE_H)
+ for(int y=0; y<h; y++) {
+ int x;
+ for(x=0; x<w; x++)
+ if(*buf == _ms_keycolor) {
+ *dst++ = 0;
+ buf++;
+ } else
+ *dst++ = pal[*buf++]|0x8000;
+ dst += MOUSE_W-x;
+ }
+ else {
+ commit_dummy_transpoly();
+ return;
+ }
+
+ mypoly.cmd =
+ TA_CMD_POLYGON|TA_CMD_POLYGON_TYPE_TRANSPARENT|TA_CMD_POLYGON_SUBLIST|
+ TA_CMD_POLYGON_STRIPLENGTH_2|TA_CMD_POLYGON_PACKED_COLOUR|TA_CMD_POLYGON_TEXTURED;
+ mypoly.mode1 = TA_POLYMODE1_Z_ALWAYS|TA_POLYMODE1_NO_Z_UPDATE;
+ mypoly.mode2 =
+ TA_POLYMODE2_BLEND_SRC_ALPHA|TA_POLYMODE2_BLEND_DST_INVALPHA|
+ TA_POLYMODE2_FOG_DISABLED|TA_POLYMODE2_TEXTURE_REPLACE|
+ TA_POLYMODE2_U_SIZE_128|TA_POLYMODE2_V_SIZE_128;
+ mypoly.texture = TA_TEXTUREMODE_ARGB1555|TA_TEXTUREMODE_NON_TWIDDLED|
+ TA_TEXTUREMODE_ADDRESS(mouse_tx[_mouse_buffer]);
+
+ mypoly.red = mypoly.green = mypoly.blue = mypoly.alpha = 0;
+
+ ta_commit_list(&mypoly);
+
+ myvertex.cmd = TA_CMD_VERTEX;
+ myvertex.ocolour = 0;
+ myvertex.colour = 0xffff00;
+ myvertex.z = 0.25;
+ myvertex.u = 0.0;
+ myvertex.v = 0.0;
+
+ myvertex.x = (xdraw-_ms_hotspot_x)*_xscale;
+ myvertex.y = (ydraw-_ms_hotspot_y)*_yscale + TOP_OFFSET;
+ ta_commit_list(&myvertex);
+
+ myvertex.x += w*_xscale;
+ myvertex.u = w*(1.0/MOUSE_W);
+ ta_commit_list(&myvertex);
+
+ myvertex.x -= w*_xscale;
+ myvertex.y += h*_yscale;
+ myvertex.u = 0.0;
+ myvertex.v = h*(1.0/MOUSE_H);
+ ta_commit_list(&myvertex);
+
+ myvertex.x += w*_xscale;
+ myvertex.u = w*(1.0/MOUSE_W);
+ myvertex.cmd |= TA_CMD_VERTEX_EOS;
+ ta_commit_list(&myvertex);
+}
+
+void OSystem_Dreamcast::mouseToSoftKbd(int x, int y, int &rx, int &ry) const
+{
+ if(_softkbd_motion) {
+ rx = (int)(x*_xscale - (330.0*sin(0.013*_softkbd_motion) - 320.0));
+ ry = (int)(y*_yscale + TOP_OFFSET - 200.0);
+ } else {
+ rx = -1;
+ ry = -1;
+ }
+}
+
+
+void OSystem_Dreamcast::showOverlay()
+{
+ _overlay_visible = true;
+ clearOverlay();
+}
+
+void OSystem_Dreamcast::hideOverlay()
+{
+ _overlay_visible = false;
+}
+
+void OSystem_Dreamcast::clearOverlay()
+{
+ if(!_overlay_visible)
+ return;
+
+ memset(overlay, 0, OVL_W*OVL_H*sizeof(unsigned short));
+
+ _overlay_dirty = true;
+}
+
+void OSystem_Dreamcast::grabOverlay(int16 *buf, int pitch)
+{
+ int h = OVL_H;
+ unsigned short *src = overlay;
+ do {
+ memcpy(buf, src, OVL_W*sizeof(int16));
+ src += OVL_W;
+ buf += pitch;
+ } while (--h);
+}
+
+void OSystem_Dreamcast::copyRectToOverlay(const int16 *buf, int pitch,
+ int x, int y, int w, int h)
+{
+ unsigned short *dst = overlay + y*OVL_W + x;
+ do {
+ memcpy(dst, buf, w*sizeof(int16));
+ dst += OVL_W;
+ buf += pitch;
+ } while (--h);
+ _overlay_dirty = true;
+}
+
+
+static const OSystem::GraphicsMode gfxmodes[] = {
+ { "default", "640×480 16bpp", 0 },
+ { NULL, NULL, 0 }
+};
+
+const OSystem::GraphicsMode *OSystem_Dreamcast::getSupportedGraphicsModes() const
+{
+ return gfxmodes;
+}
+
+int OSystem_Dreamcast::getDefaultGraphicsMode() const
+{
+ return 0;
+}
+
+bool OSystem_Dreamcast::setGraphicsMode(int mode)
+{
+ return mode == 0;
+}
+
+int OSystem_Dreamcast::getGraphicsMode() const
+{
+ return 0;
+}
+
+bool OSystem_Dreamcast::grabRawScreen(Graphics::Surface *surf)
+{
+ if(!screen || !surf)
+ return false;
+
+ surf->create(_screen_w, _screen_h, 1);
+ unsigned char *src = screen, *dst = (unsigned char *)surf->pixels;
+ for(int h = _screen_h; h>0; --h) {
+ memcpy(dst, src, _screen_w);
+ src += SCREEN_W;
+ dst += _screen_w;
+ }
+ return true;
+}
+
+void OSystem_Dreamcast::clearScreen()
+{
+ memset(screen, 0, SCREEN_W*SCREEN_H);
+ _screen_dirty = true;
+}
+
+int16 OSystem_Dreamcast::getOverlayHeight()
+{
+ return OVL_H;
+}
+
+int16 OSystem_Dreamcast::getOverlayWidth()
+{
+ return OVL_W;
+}
+
+int OSystem_Dreamcast::screenToOverlayX(int x)
+{
+ return x - _overlay_x;
+}
+
+int OSystem_Dreamcast::screenToOverlayY(int y)
+{
+ return y - _overlay_y;
+}
+
+int OSystem_Dreamcast::overlayToScreenX(int x)
+{
+ return x + _overlay_x;
+}
+
+int OSystem_Dreamcast::overlayToScreenY(int y)
+{
+ return y + _overlay_y;
+}
+
diff --git a/backends/platform/dc/icon.cpp b/backends/platform/dc/icon.cpp
new file mode 100644
index 0000000000..66d3d6f696
--- /dev/null
+++ b/backends/platform/dc/icon.cpp
@@ -0,0 +1,232 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002-2004 Marcus Comstedt
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include <ronin/ronin.h>
+#include <string.h>
+
+#include "icon.h"
+
+void Icon::create_vmicon(void *buffer)
+{
+ unsigned short *pal = (unsigned short *)buffer;
+ unsigned char *pix = ((unsigned char *)buffer)+32;
+
+ for(int n = 0; n<16; n++) {
+ int p = palette[n];
+ pal[n] =
+ ((p>>16)&0xf000)|
+ ((p>>12)&0x0f00)|
+ ((p>> 8)&0x00f0)|
+ ((p>> 4)&0x000f);
+ }
+
+ for(int line = 0; line < 32; line++) {
+ memcpy(pix, &bitmap[32/2*(31-line)], 32/2);
+ pix += 32/2;
+ }
+}
+
+void Icon::create_texture()
+{
+ static char tt[16] = { 0, 1, 4, 5, 16, 17, 20, 21,
+ 64, 65, 68, 69, 80, 81, 84, 85 };
+ unsigned short *tex = (unsigned short *)ta_txalloc(512);
+ unsigned short *linebase;
+ unsigned char *src = bitmap+sizeof(bitmap)-17;
+ for(int y=0; y<16; y++) {
+ linebase = tex + (tt[y]<<1);
+ for(int x=0; x<16; x++, --src)
+ linebase[tt[x]] = src[16]|(src[0]<<8);
+ src -= 16;
+ }
+ texture = tex;
+}
+
+void Icon::setPalette(int pal)
+{
+ unsigned int (*hwpal)[64][16] = (unsigned int (*)[64][16])0xa05f9000;
+ for(int n = 0; n<16; n++)
+ (*hwpal)[pal][n] = palette[n];
+}
+
+void Icon::draw(float x1, float y1, float x2, float y2, int pal,
+ unsigned int argb)
+{
+ struct polygon_list mypoly;
+ struct packed_colour_vertex_list myvertex;
+
+ mypoly.cmd =
+ TA_CMD_POLYGON|TA_CMD_POLYGON_TYPE_TRANSPARENT|TA_CMD_POLYGON_SUBLIST|
+ TA_CMD_POLYGON_STRIPLENGTH_2|TA_CMD_POLYGON_PACKED_COLOUR|TA_CMD_POLYGON_TEXTURED;
+ mypoly.mode1 = TA_POLYMODE1_Z_ALWAYS|TA_POLYMODE1_NO_Z_UPDATE;
+ mypoly.mode2 =
+ TA_POLYMODE2_BLEND_SRC_ALPHA|TA_POLYMODE2_BLEND_DST_INVALPHA|
+ TA_POLYMODE2_FOG_DISABLED|TA_POLYMODE2_ENABLE_ALPHA|
+ TA_POLYMODE2_TEXTURE_MODULATE_ALPHA|TA_POLYMODE2_U_SIZE_32|
+ TA_POLYMODE2_V_SIZE_32;
+ mypoly.texture = TA_TEXTUREMODE_CLUT4|TA_TEXTUREMODE_CLUTBANK4(pal)|
+ TA_TEXTUREMODE_ADDRESS(texture);
+
+ mypoly.red = mypoly.green = mypoly.blue = mypoly.alpha = 0;
+
+ ta_commit_list(&mypoly);
+
+ myvertex.cmd = TA_CMD_VERTEX;
+ myvertex.ocolour = 0;
+ myvertex.colour = argb;
+ myvertex.z = 0.5;
+ myvertex.u = 0.0;
+ myvertex.v = 1.0;
+
+ myvertex.x = x1;
+ myvertex.y = y1;
+ ta_commit_list(&myvertex);
+
+ myvertex.x = x2;
+ myvertex.v = 0.0;
+ ta_commit_list(&myvertex);
+
+ myvertex.x = x1;
+ myvertex.y = y2;
+ myvertex.u = 1.0;
+ myvertex.v = 1.0;
+ ta_commit_list(&myvertex);
+
+ myvertex.x = x2;
+ myvertex.v = 0.0;
+ myvertex.cmd |= TA_CMD_VERTEX_EOS;
+ ta_commit_list(&myvertex);
+}
+
+int Icon::find_unused_pixel()
+{
+ int use[16];
+ memset(use, 0, sizeof(use));
+ for(int n=0; n<32*32/2; n++) {
+ unsigned char pix = bitmap[n];
+ use[pix&0xf]++;
+ use[pix>>4]++;
+ }
+ for(int i=0; i<16; i++)
+ if(!use[i])
+ return i;
+ return -1;
+}
+
+bool Icon::load_image2(const void *data, int len)
+{
+ struct {
+ int size, w, h;
+ short pla, bitcnt;
+ int comp, sizeimg, xres, yres, used, imp;
+ } hdr;
+ if(len < 40)
+ return false;
+ memcpy(&hdr, data, 40);
+ if(hdr.size != 40 || /* hdr.sizeimg<=0 || */ hdr.w<0 || hdr.h<0 ||
+ hdr.bitcnt<0 || hdr.used<0)
+ return false;
+ if(!hdr.used)
+ hdr.used = 1<<hdr.bitcnt;
+ hdr.h >>= 1;
+ /* Fix incorrect sizeimg (The Dig) */
+ if(hdr.sizeimg < ((hdr.w*hdr.h*(1+hdr.bitcnt)+7)>>3))
+ hdr.sizeimg = ((hdr.w*hdr.h*(1+hdr.bitcnt)+7)>>3);
+ if(hdr.size + (hdr.used<<2) + hdr.sizeimg > len /* ||
+ hdr.sizeimg < ((hdr.w*hdr.h*(1+hdr.bitcnt)+7)>>3) */)
+ return false;
+ if(hdr.w != 32 || hdr.h != 32 || hdr.bitcnt != 4 || hdr.used > 16)
+ return false;
+ memcpy(palette, ((const char *)data)+hdr.size, hdr.used<<2);
+ memcpy(bitmap, ((const char *)data)+hdr.size+(hdr.used<<2), 32*32/2);
+ for(int i=0; i<16; i++)
+ palette[i] |= 0xff000000;
+ for(int i=hdr.used; i<16; i++)
+ palette[i] = 0;
+ int unused = find_unused_pixel();
+ if(unused >= 0) {
+ const unsigned char *mask =
+ ((const unsigned char *)data)+hdr.size+(hdr.used<<2)+32*32/2;
+ unsigned char *pix = bitmap;
+ for(int y=0; y<32; y++)
+ for(int x=0; x<32/8; x++) {
+ unsigned char mbits = *mask++;
+ for(int z=0; z<4; z++) {
+ unsigned char pbits = *pix;
+ if(mbits & 64) pbits = (pbits & ~0xf) | unused;
+ if(mbits & 128) pbits = (pbits & 0xf) | (unused << 4);
+ *pix++ = pbits;
+ mbits <<= 2;
+ }
+ }
+ palette[unused] = 0;
+ }
+ return true;
+}
+
+bool Icon::load_image1(const void *data, int len, int offs)
+{
+ struct {
+ char w, h, colors, rsrv;
+ short pla, bitcnt;
+ int bytes, offs;
+ } hdr;
+ if(len < offs+16)
+ return false;
+ memcpy(&hdr, ((const char *)data)+offs, 16);
+ if(hdr.bytes > 0 && hdr.offs >= 0 && hdr.offs+hdr.bytes <= len)
+ return load_image2(((const char *)data)+hdr.offs, hdr.bytes);
+ else
+ return false;
+}
+
+bool Icon::load(const void *data, int len, int offs)
+{
+ struct { short rsrv, type, cnt; } hdr;
+ memset(bitmap, 0, sizeof(bitmap));
+ memset(palette, 0, sizeof(palette));
+ texture = NULL;
+ if(len < offs+6)
+ return false;
+ memcpy(&hdr, ((const char *)data)+offs, 6);
+ if(hdr.type != 1 || hdr.cnt < 1 || offs+6+(hdr.cnt<<4) > len)
+ return false;
+ for(int i=0; i<hdr.cnt; i++)
+ if(load_image1(data, len, offs+6+(i<<4)))
+ return true;
+ return false;
+}
+
+bool Icon::load(const char *filename)
+{
+ char buf[2048];
+ int fd;
+ if((fd = open(filename, O_RDONLY))>=0) {
+ int sz;
+ sz = read(fd, buf, sizeof(buf));
+ close(fd);
+ if(sz>0)
+ return load(buf, sz);
+ }
+ return false;
+}
diff --git a/backends/platform/dc/icon.h b/backends/platform/dc/icon.h
new file mode 100644
index 0000000000..3c38a44d69
--- /dev/null
+++ b/backends/platform/dc/icon.h
@@ -0,0 +1,48 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002-2004 Marcus Comstedt
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef DC_ICON_H
+#define DC_ICON_H
+
+class Icon
+{
+ private:
+ unsigned char bitmap[32*32/2];
+ unsigned int palette[16];
+ void *texture;
+
+ int find_unused_pixel();
+ bool load_image1(const void *data, int len, int offs);
+ bool load_image2(const void *data, int len);
+
+ public:
+ bool load(const void *data, int len, int offs = 0);
+ bool load(const char *filename);
+ void create_texture();
+ void setPalette(int pal);
+ void draw(float x1, float y1, float x2, float y2, int pal,
+ unsigned argb = 0xffffffff);
+ void create_vmicon(void *buffer);
+};
+
+#endif /* DC_ICON_H */
diff --git a/backends/platform/dc/input.cpp b/backends/platform/dc/input.cpp
new file mode 100644
index 0000000000..50587ad59d
--- /dev/null
+++ b/backends/platform/dc/input.cpp
@@ -0,0 +1,250 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002-2004 Marcus Comstedt
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#define RONIN_TIMER_ACCESS
+
+#include <common/stdafx.h>
+#include <common/scummsys.h>
+#include "dc.h"
+
+int handleInput(struct mapledev *pad, int &mouse_x, int &mouse_y,
+ byte &shiftFlags, Interactive *inter)
+{
+ static const char numpadmap[] = "0000039601740285";
+ int lmb=0, rmb=0, newkey=0;
+ static int lastkey = 0;
+ static byte lastlmb = 0, lastrmb = 0;
+ static int8 mouse_wheel = 0, lastwheel = 0;
+ shiftFlags = 0;
+ for(int i=0; i<4; i++, pad++)
+ if(pad->func & MAPLE_FUNC_CONTROLLER) {
+ int buttons = pad->cond.controller.buttons;
+
+ if(!(buttons & 0x060e)) exit(0);
+
+ if(!(buttons & 4)) lmb++;
+ if(!(buttons & 2)) rmb++;
+
+ if(!(buttons & 8)) newkey = 319;
+ else if(!(buttons & 512)) newkey = ' ';
+ else if(!(buttons & 1024)) newkey = numpadmap[(buttons>>4)&15];
+
+ if(!(buttons & 128)) if(inter) newkey = 1001; else mouse_x++;
+ if(!(buttons & 64)) if(inter) newkey = 1002; else mouse_x--;
+ if(!(buttons & 32)) if(inter) newkey = 1003; else mouse_y++;
+ if(!(buttons & 16)) if(inter) newkey = 1004; else mouse_y--;
+
+ mouse_x += ((int)pad->cond.controller.joyx-128)>>4;
+ mouse_y += ((int)pad->cond.controller.joyy-128)>>4;
+
+ if(pad->cond.controller.ltrigger > 200) newkey = 1005;
+ else if(pad->cond.controller.rtrigger > 200) newkey = 1006;
+
+ } else if(pad->func & MAPLE_FUNC_MOUSE) {
+ int buttons = pad->cond.mouse.buttons;
+
+ if(!(buttons & 4)) lmb++;
+ if(!(buttons & 2)) rmb++;
+
+ if(!(buttons & 8)) newkey = 319;
+
+ mouse_x += pad->cond.mouse.axis1;
+ mouse_y += pad->cond.mouse.axis2;
+ mouse_wheel += pad->cond.mouse.axis3;
+
+ if(inter)
+ inter->mouse(mouse_x, mouse_y);
+
+ pad->cond.mouse.axis1 = 0;
+ pad->cond.mouse.axis2 = 0;
+ pad->cond.mouse.axis3 = 0;
+ } else if(pad->func & MAPLE_FUNC_KEYBOARD) {
+ for(int p=0; p<6; p++) {
+ int shift = pad->cond.kbd.shift;
+ int key = pad->cond.kbd.key[p];
+ if(shift & 0x08) lmb++;
+ if(shift & 0x80) rmb++;
+ if(shift & 0x11) shiftFlags |= OSystem::KBD_CTRL;
+ if(shift & 0x44) shiftFlags |= OSystem::KBD_ALT;
+ if(shift & 0x22) shiftFlags |= OSystem::KBD_SHIFT;
+ if(key >= 4 && key <= 0x1d)
+ newkey = key+('a'-4);
+ else if(key >= 0x1e && key <= 0x26)
+ newkey = key+((shift & 0x22)? ('!'-0x1e) : ('1'-0x1e));
+ else if(key >= 0x59 && key <= 0x61)
+ newkey = key+('1'-0x59);
+ else if(key >= 0x2d && key <= 0x38 && key != 0x31)
+ newkey = ((shift & 0x22)?
+ "=¯`{ }+*½<>?" :
+ "-^@[ ];:§,./")[key - 0x2d];
+ else if(key >= 0x3a && key <= 0x43)
+ newkey = key+(315-0x3a);
+ else if(key >= 0x54 && key <= 0x57)
+ newkey = "/*-+"[key-0x54];
+ else switch(key) {
+ case 0x27: case 0x62:
+ newkey = ((shift & 0x22)? '~' : '0'); break;
+ case 0x28: case 0x58:
+ newkey = 13; break;
+ case 0x29:
+ newkey = 27; break;
+ case 0x2a:
+ newkey = 8; break;
+ case 0x2b:
+ newkey = 9; break;
+ case 0x2c:
+ newkey = ' '; break;
+ case 0x4c:
+ if((shift & 0x11) && (shift & 0x44))
+ exit(0);
+ break;
+ case 0x4f:
+ if(inter) newkey = 1001; else mouse_x++; break;
+ case 0x50:
+ if(inter) newkey = 1002; else mouse_x--; break;
+ case 0x51:
+ if(inter) newkey = 1003; else mouse_y++; break;
+ case 0x52:
+ if(inter) newkey = 1004; else mouse_y--; break;
+ case 0x63:
+ newkey = '.'; break;
+ case 0x64: case 0x87:
+ newkey = ((shift & 0x22)? '_' : '\\'); break;
+ case 0x89:
+ newkey = ((shift & 0x22)? '|' : '¥'); break;
+ }
+ }
+ }
+
+ if(lmb && inter && !lastlmb) {
+ newkey = 1000;
+ lmb = 0;
+ }
+
+ if(lmb && !lastlmb) {
+ lastlmb = 1;
+ return -OSystem::EVENT_LBUTTONDOWN;
+ } else if(lastlmb && !lmb) {
+ lastlmb = 0;
+ return -OSystem::EVENT_LBUTTONUP;
+ }
+ if(rmb && !lastrmb) {
+ lastrmb = 1;
+ return -OSystem::EVENT_RBUTTONDOWN;
+ } else if(lastrmb && !rmb) {
+ lastrmb = 0;
+ return -OSystem::EVENT_RBUTTONUP;
+ }
+
+ if(mouse_wheel != lastwheel)
+ if(((int8)(mouse_wheel - lastwheel)) > 0) {
+ lastwheel++;
+ return -OSystem::EVENT_WHEELDOWN;
+ } else {
+ --lastwheel;
+ return -OSystem::EVENT_WHEELUP;
+ }
+
+ if(newkey && inter && newkey != lastkey) {
+ int transkey = inter->key(newkey, shiftFlags);
+ if(transkey) {
+ newkey = transkey;
+ inter = NULL;
+ }
+ }
+
+ if(!newkey || (lastkey && newkey != lastkey)) {
+ int upkey = lastkey;
+ lastkey = 0;
+ if(upkey)
+ return upkey | (1<<30);
+ } else if(!lastkey) {
+ lastkey = newkey;
+ if(newkey >= 1000 || !inter)
+ return newkey;
+ }
+
+ return 0;
+}
+
+bool OSystem_Dreamcast::pollEvent(Event &event)
+{
+ unsigned int t = Timer();
+
+ if(_timer_active && ((int)(t-_timer_next_expiry))>=0) {
+ _timer_duration = _timer_callback(_timer_duration);
+ _timer_next_expiry = t+USEC_TO_TIMER(1000*_timer_duration);
+ }
+
+ if(((int)(t-_devpoll))<0)
+ return false;
+ _devpoll += USEC_TO_TIMER(17000);
+ if(((int)(t-_devpoll))>=0)
+ _devpoll = t + USEC_TO_TIMER(17000);
+
+ int mask = getimask();
+ setimask(15);
+ checkSound();
+ int e = handleInput(locked_get_pads(), _ms_cur_x, _ms_cur_y,
+ event.kbd.flags, (_softkbd_on? &_softkbd : NULL));
+ setimask(mask);
+ if (_ms_cur_x<0) _ms_cur_x=0;
+ if (_ms_cur_x>=_screen_w) _ms_cur_x=_screen_w-1;
+ if (_ms_cur_y<0) _ms_cur_y=0;
+ if (_ms_cur_y>=_screen_h) _ms_cur_y=_screen_h-1;
+ event.mouse.x = _ms_cur_x;
+ event.mouse.y = _ms_cur_y;
+ if (_overlay_visible) {
+ event.mouse.x -= _overlay_x;
+ event.mouse.y -= _overlay_y;
+ }
+ event.kbd.ascii = event.kbd.keycode = 0;
+ if(e<0) {
+ event.type = (EventType)-e;
+ return true;
+ } else if(e>0) {
+ bool processed = false, down = !(e&(1<<30));
+ e &= ~(1<<30);
+ if(e < 1000) {
+ event.type = (down? EVENT_KEYDOWN : EVENT_KEYUP);
+ event.kbd.keycode = e;
+ event.kbd.ascii = (e>='a' && e<='z' && (event.kbd.flags & KBD_SHIFT)?
+ e &~ 0x20 : e);
+ processed = true;
+ } else if(down) {
+ if(e == 1005)
+ setFeatureState(kFeatureVirtualKeyboard,
+ !getFeatureState(kFeatureVirtualKeyboard));
+ }
+ return processed;
+ } else if(_ms_cur_x != _ms_old_x || _ms_cur_y != _ms_old_y) {
+ event.type = EVENT_MOUSEMOVE;
+ _ms_old_x = _ms_cur_x;
+ _ms_old_y = _ms_cur_y;
+ return true;
+ } else {
+ event.type = (EventType)0;
+ return false;
+ }
+}
+
diff --git a/backends/platform/dc/label.cpp b/backends/platform/dc/label.cpp
new file mode 100644
index 0000000000..1603e5c6c9
--- /dev/null
+++ b/backends/platform/dc/label.cpp
@@ -0,0 +1,138 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002-2004 Marcus Comstedt
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include <ronin/ronin.h>
+#include <string.h>
+
+#include "label.h"
+
+
+static void *get_romfont_address() __asm__(".get_romfont_address");
+__asm__("\
+ \n\
+.get_romfont_address: \n\
+ mov.l 1f,r0 \n\
+ mov.l @r0,r0 \n\
+ jmp @r0 \n\
+ mov #0,r1 \n\
+ .align 2 \n\
+1: .long 0x8c0000b4 \n\
+ \n\
+");
+
+
+static void draw_char(unsigned short *dst, int mod, int c, void *font_base)
+{
+ unsigned char *src;
+ int i, j;
+ if(c<=32 || c>255 || (c>=127 && c<160)) c=160;
+ if(c<128) c -= 32; else c -= 64;
+ src = c*36 + (unsigned char *)font_base;
+ for(i=0; i<12; i++) {
+ int n = (src[0]<<16)|(src[1]<<8)|src[2];
+ for(j=0; j<12; j++, n<<=1)
+ if(n & (1<<23)) {
+ dst[j] = 0xffff;
+ dst[j+1] = 0xffff;
+ dst[j+2] = 0xa108;
+ dst[j+mod] = 0xa108;
+ dst[j+mod+1] = 0xa108;
+ }
+ dst += mod;
+ for(j=0; j<12; j++, n<<=1)
+ if(n & (1<<23)) {
+ dst[j] = 0xffff;
+ dst[j+1] = 0xffff;
+ dst[j+2] = 0xa108;
+ dst[j+mod] = 0xa108;
+ dst[j+mod+1] = 0xa108;
+ }
+ dst += mod;
+ src += 3;
+ }
+}
+
+void Label::create_texture(const char *text)
+{
+ void *font = get_romfont_address();
+ int l = strlen(text);
+ if(l>64) l=64;
+ int w = 14*l;
+ for(tex_u=TA_POLYMODE2_U_SIZE_8, u=8; u<w; u<<=1, tex_u += 1<<3);
+ int tsz = u*32;
+ unsigned short *tex = (unsigned short *)ta_txalloc(tsz*2);
+ for(int i=0; i<tsz; i++)
+ tex[i] = 0;
+ int p=l*14;
+ while(l>0)
+ draw_char(tex+(p-=14), u, text[--l], font);
+ texture = tex;
+}
+
+void Label::draw(float x, float y, unsigned int argb, float scale)
+{
+ struct polygon_list mypoly;
+ struct packed_colour_vertex_list myvertex;
+
+ mypoly.cmd =
+ TA_CMD_POLYGON|TA_CMD_POLYGON_TYPE_TRANSPARENT|TA_CMD_POLYGON_SUBLIST|
+ TA_CMD_POLYGON_STRIPLENGTH_2|TA_CMD_POLYGON_PACKED_COLOUR|TA_CMD_POLYGON_TEXTURED;
+ mypoly.mode1 = TA_POLYMODE1_Z_ALWAYS|TA_POLYMODE1_NO_Z_UPDATE;
+ mypoly.mode2 =
+ TA_POLYMODE2_BLEND_SRC_ALPHA|TA_POLYMODE2_BLEND_DST_INVALPHA|
+ TA_POLYMODE2_FOG_DISABLED|TA_POLYMODE2_ENABLE_ALPHA|
+ TA_POLYMODE2_TEXTURE_MODULATE_ALPHA|TA_POLYMODE2_V_SIZE_32|tex_u;
+ mypoly.texture = TA_TEXTUREMODE_ARGB1555|TA_TEXTUREMODE_NON_TWIDDLED|
+ TA_TEXTUREMODE_ADDRESS(texture);
+
+ mypoly.red = mypoly.green = mypoly.blue = mypoly.alpha = 0;
+
+ ta_commit_list(&mypoly);
+
+ myvertex.cmd = TA_CMD_VERTEX;
+ myvertex.ocolour = 0;
+ myvertex.colour = argb;
+ myvertex.z = 0.5;
+ myvertex.u = 0.0;
+ myvertex.v = 0.0;
+
+ myvertex.x = x;
+ myvertex.y = y;
+ ta_commit_list(&myvertex);
+
+ myvertex.x = x+u*scale;
+ myvertex.u = 1.0;
+ ta_commit_list(&myvertex);
+
+ myvertex.x = x;
+ myvertex.y = y+25.0*scale;
+ myvertex.u = 0.0;
+ myvertex.v = 25.0/32.0;
+ ta_commit_list(&myvertex);
+
+ myvertex.x = x+u*scale;
+ myvertex.u = 1.0;
+ myvertex.cmd |= TA_CMD_VERTEX_EOS;
+ ta_commit_list(&myvertex);
+}
+
diff --git a/backends/platform/dc/label.h b/backends/platform/dc/label.h
new file mode 100644
index 0000000000..910d0438af
--- /dev/null
+++ b/backends/platform/dc/label.h
@@ -0,0 +1,39 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002-2004 Marcus Comstedt
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef DC_LABEL_H
+#define DC_LABEL_H
+
+class Label
+{
+ private:
+ void *texture;
+ int tex_u, u;
+
+ public:
+ void create_texture(const char *text);
+ void draw(float x, float y, unsigned int argb = 0xffffffff,
+ float scale = 1.0);
+};
+
+#endif /* DC_LABEL_H */
diff --git a/backends/platform/dc/plugin.syms b/backends/platform/dc/plugin.syms
new file mode 100644
index 0000000000..9d207e4a92
--- /dev/null
+++ b/backends/platform/dc/plugin.syms
@@ -0,0 +1,9 @@
+_PLUGIN_createEngine
+_PLUGIN_detectGames
+_PLUGIN_gameIDList
+_PLUGIN_findGameID
+_PLUGIN_name
+___plugin_ctors
+___plugin_ctors_end
+___plugin_dtors
+___plugin_dtors_end
diff --git a/backends/platform/dc/plugin.x b/backends/platform/dc/plugin.x
new file mode 100644
index 0000000000..2c8469a335
--- /dev/null
+++ b/backends/platform/dc/plugin.x
@@ -0,0 +1,59 @@
+OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl")
+OUTPUT_ARCH(sh)
+PHDRS
+{
+ plugin PT_LOAD ;
+}
+SECTIONS
+{
+ . = 0;
+ .text :
+ {
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ *(.gnu.warning)
+ } :plugin =0
+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+ .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }
+ .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
+ .data :
+ {
+ *(.data .data.* .gnu.linkonce.d.*)
+ SORT(CONSTRUCTORS)
+ }
+ .data1 : { *(.data1) }
+ .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+ .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+ .eh_frame : { KEEP (*(.eh_frame)) }
+ .gcc_except_table : { *(.gcc_except_table) }
+ .ctors :
+ {
+ ___plugin_ctors = .;
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ ___plugin_ctors_end = .;
+ }
+ .dtors :
+ {
+ ___plugin_dtors = .;
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ ___plugin_dtors_end = .;
+ }
+ .sdata :
+ {
+ *(.sdata .sdata.* .gnu.linkonce.s.*)
+ }
+ .sbss :
+ {
+ *(.dynsbss)
+ *(.sbss .sbss.* .gnu.linkonce.sb.*)
+ *(.scommon)
+ }
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ }
+}
diff --git a/backends/platform/dc/portdefs.h b/backends/platform/dc/portdefs.h
new file mode 100644
index 0000000000..cedfd5c0fe
--- /dev/null
+++ b/backends/platform/dc/portdefs.h
@@ -0,0 +1,39 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002-2004 Marcus Comstedt
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <ctype.h>
+#include <math.h>
+#ifndef RONIN_TIMER_ACCESS
+#define Timer ronin_Timer
+#endif
+#include <ronin/ronin.h>
+#ifdef Timer
+#undef Timer
+#endif
diff --git a/backends/platform/dc/selector.cpp b/backends/platform/dc/selector.cpp
new file mode 100644
index 0000000000..5aa5829da8
--- /dev/null
+++ b/backends/platform/dc/selector.cpp
@@ -0,0 +1,463 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002-2004 Marcus Comstedt
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include <common/stdafx.h>
+#include <common/scummsys.h>
+#include <base/engine.h>
+#include <base/plugins.h>
+#include <common/fs.h>
+#include "dc.h"
+#include "icon.h"
+#include "label.h"
+
+#include <ronin/gddrive.h>
+
+
+#define MAX_GAMES 100
+#define MAX_DIR 100
+
+
+void draw_solid_quad(float x1, float y1, float x2, float y2,
+ int c0, int c1, int c2, int c3)
+{
+ struct polygon_list mypoly;
+ struct packed_colour_vertex_list myvertex;
+
+ mypoly.cmd =
+ TA_CMD_POLYGON|TA_CMD_POLYGON_TYPE_OPAQUE|TA_CMD_POLYGON_SUBLIST|
+ TA_CMD_POLYGON_STRIPLENGTH_2|TA_CMD_POLYGON_PACKED_COLOUR|
+ TA_CMD_POLYGON_GOURAUD_SHADING;
+ mypoly.mode1 = TA_POLYMODE1_Z_ALWAYS|TA_POLYMODE1_NO_Z_UPDATE;
+ mypoly.mode2 =
+ TA_POLYMODE2_BLEND_SRC|TA_POLYMODE2_FOG_DISABLED;
+ mypoly.texture = 0;
+
+ mypoly.red = mypoly.green = mypoly.blue = mypoly.alpha = 0;
+
+ ta_commit_list(&mypoly);
+
+ myvertex.cmd = TA_CMD_VERTEX;
+ myvertex.ocolour = 0;
+ myvertex.z = 0.5;
+ myvertex.u = 0.0;
+ myvertex.v = 0.0;
+
+ myvertex.colour = c0;
+ myvertex.x = x1;
+ myvertex.y = y1;
+ ta_commit_list(&myvertex);
+
+ myvertex.colour = c1;
+ myvertex.x = x2;
+ ta_commit_list(&myvertex);
+
+ myvertex.colour = c2;
+ myvertex.x = x1;
+ myvertex.y = y2;
+ ta_commit_list(&myvertex);
+
+ myvertex.colour = c3;
+ myvertex.x = x2;
+ myvertex.cmd |= TA_CMD_VERTEX_EOS;
+ ta_commit_list(&myvertex);
+}
+
+void draw_trans_quad(float x1, float y1, float x2, float y2,
+ int c0, int c1, int c2, int c3)
+{
+ struct polygon_list mypoly;
+ struct packed_colour_vertex_list myvertex;
+
+ mypoly.cmd =
+ TA_CMD_POLYGON|TA_CMD_POLYGON_TYPE_TRANSPARENT|TA_CMD_POLYGON_SUBLIST|
+ TA_CMD_POLYGON_STRIPLENGTH_2|TA_CMD_POLYGON_PACKED_COLOUR|
+ TA_CMD_POLYGON_GOURAUD_SHADING;
+ mypoly.mode1 = TA_POLYMODE1_Z_ALWAYS|TA_POLYMODE1_NO_Z_UPDATE;
+ mypoly.mode2 =
+ TA_POLYMODE2_BLEND_SRC_ALPHA|TA_POLYMODE2_BLEND_DST_INVALPHA|
+ TA_POLYMODE2_FOG_DISABLED|TA_POLYMODE2_ENABLE_ALPHA;
+ mypoly.texture = 0;
+
+ mypoly.red = mypoly.green = mypoly.blue = mypoly.alpha = 0;
+
+ ta_commit_list(&mypoly);
+
+ myvertex.cmd = TA_CMD_VERTEX;
+ myvertex.ocolour = 0;
+ myvertex.z = 0.5;
+ myvertex.u = 0.0;
+ myvertex.v = 0.0;
+
+ myvertex.colour = c0;
+ myvertex.x = x1;
+ myvertex.y = y1;
+ ta_commit_list(&myvertex);
+
+ myvertex.colour = c1;
+ myvertex.x = x2;
+ ta_commit_list(&myvertex);
+
+ myvertex.colour = c2;
+ myvertex.x = x1;
+ myvertex.y = y2;
+ ta_commit_list(&myvertex);
+
+ myvertex.colour = c3;
+ myvertex.x = x2;
+ myvertex.cmd |= TA_CMD_VERTEX_EOS;
+ ta_commit_list(&myvertex);
+}
+
+
+struct Game
+{
+ char dir[256];
+ char filename_base[256];
+ char text[256];
+ Icon icon;
+ Label label;
+};
+
+struct Dir
+{
+ char name[252];
+ char deficon[256];
+ FilesystemNode node;
+};
+
+static Game the_game;
+
+static void detectGames(FSList &files, DetectedGameList &candidates)
+{
+ const PluginList &plugins = PluginManager::instance().getPlugins();
+ PluginList::const_iterator iter = plugins.begin();
+ for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
+ candidates.push_back((*iter)->detectGames(files));
+ }
+}
+
+static bool isIcon(const FilesystemNode &entry)
+{
+ int l = entry.displayName().size();
+ if(l>4 && !strcasecmp(entry.displayName().c_str()+l-4, ".ICO"))
+ return true;
+ else
+ return false;
+}
+
+static bool loadIcon(Game &game, Dir *dirs, int num_dirs)
+{
+ char icofn[520];
+ sprintf(icofn, "%s%s.ICO", game.dir, game.filename_base);
+ if(game.icon.load(icofn))
+ return true;
+ for(int i=0; i<num_dirs; i++)
+ if(!strcmp(dirs[i].name, game.dir) &&
+ dirs[i].deficon[0]) {
+ sprintf(icofn, "%s%s", game.dir, dirs[i].deficon);
+ if(game.icon.load(icofn))
+ return true;
+ break;
+ }
+ return false;
+}
+
+static void makeDefIcon(Icon &icon)
+{
+#include "deficon.h"
+ icon.load(scummvm_icon, sizeof(scummvm_icon));
+}
+
+static bool uniqueGame(const char *base, const char *dir, Game *games, int cnt)
+{
+ while(cnt--)
+ if(!strcmp(dir, games->dir) &&
+ !stricmp(base, games->filename_base))
+ return false;
+ else
+ games++;
+ return true;
+}
+
+static int findGames(Game *games, int max)
+{
+ Dir *dirs = new Dir[MAX_DIR];
+ int curr_game = 0, curr_dir = 0, num_dirs = 1;
+ dirs[0].node = FilesystemNode("");
+ while(curr_game < max && curr_dir < num_dirs) {
+ strncpy(dirs[curr_dir].name, dirs[curr_dir].node.path().c_str(), 252);
+ dirs[curr_dir].name[251] = '\0';
+ dirs[curr_dir].deficon[0] = '\0';
+ FSList files, fslist;
+ dirs[curr_dir++].node.listDir(fslist, FilesystemNode::kListAll);
+ for (FSList::const_iterator entry = fslist.begin(); entry != fslist.end();
+ ++entry) {
+ if (entry->isDirectory()) {
+ if(num_dirs < MAX_DIR && strcasecmp(entry->displayName().c_str(),
+ "install")) {
+ dirs[num_dirs].node = *entry;
+ num_dirs++;
+ }
+ } else
+ if(isIcon(*entry))
+ strcpy(dirs[curr_dir-1].deficon, entry->displayName().c_str());
+ else
+ files.push_back(*entry);
+ }
+
+ DetectedGameList candidates;
+ detectGames(files, candidates);
+
+ for(DetectedGameList::const_iterator ge = candidates.begin();
+ ge != candidates.end(); ++ge)
+ if(curr_game < max) {
+ strcpy(games[curr_game].filename_base, ge->gameid.c_str());
+ strcpy(games[curr_game].dir, dirs[curr_dir-1].name);
+ if(uniqueGame(games[curr_game].filename_base,
+ games[curr_game].dir, games, curr_game)) {
+
+ strcpy(games[curr_game].text, ge->description.c_str());
+#if 0
+ printf("Registered game <%s> in <%s> <%s> because of <%s> <*>\n",
+ games[curr_game].text, games[curr_game].dir,
+ games[curr_game].filename_base,
+ dirs[curr_dir-1].name);
+#endif
+ curr_game++;
+ }
+ }
+ }
+
+ for(int i=0; i<curr_game; i++)
+ if(!loadIcon(games[i], dirs, num_dirs))
+ makeDefIcon(games[i].icon);
+ delete[] dirs;
+ return curr_game;
+}
+
+int getCdState()
+{
+ unsigned int param[4];
+ gdGdcGetDrvStat(param);
+ return param[0];
+}
+
+static void drawBackground()
+{
+ draw_solid_quad(20.0, 20.0, 620.0, 460.0,
+ 0xff0000, 0x00ff00, 0x0000ff, 0xffffff);
+}
+
+void waitForDisk()
+{
+ Label lab;
+ int wasopen = 0;
+ ta_sync();
+ void *mark = ta_txmark();
+ lab.create_texture("Please insert game CD.");
+ //printf("waitForDisk, cdstate = %d\n", getCdState());
+ for(;;) {
+ int s = getCdState();
+ if(s >= 6)
+ wasopen = 1;
+ if(s > 0 && s < 6 && wasopen) {
+ cdfs_reinit();
+ chdir("/");
+ chdir("/");
+ ta_sync();
+ ta_txrelease(mark);
+ return;
+ }
+
+ ta_begin_frame();
+
+ drawBackground();
+
+ ta_commit_end();
+
+ lab.draw(166.0, 200.0, 0xffff2020);
+
+ ta_commit_frame();
+
+ int mousex = 0, mousey = 0;
+ byte shiftFlags;
+
+ int mask = getimask();
+ setimask(15);
+ handleInput(locked_get_pads(), mousex, mousey, shiftFlags);
+ setimask(mask);
+ }
+}
+
+static void drawGameLabel(Game &game, int pal, float x, float y,
+ unsigned int argb, int fade = 0, float scale = 1.0)
+{
+ unsigned int fade_alpha = (255-fade)<<24;
+
+ game.icon.draw(x, y, x+32.0*scale, y+32.0*scale, pal, 0xffffff|fade_alpha);
+ game.label.draw(x+54.0*scale, y+4.0*scale, argb|fade_alpha, scale);
+}
+
+int gameMenu(Game *games, int num_games)
+{
+ int top_game = 0, selector_pos = 0;
+ int mousex = 0, mousey = 0;
+
+ if(!num_games)
+ return -1;
+
+ for(;;) {
+
+ if(getCdState()>=6)
+ return -1;
+
+ ta_begin_frame();
+
+ drawBackground();
+
+ ta_commit_end();
+
+ float y = 40.0;
+ for(int i=top_game, cnt=0; cnt<10 && i<num_games; i++, cnt++) {
+ int pal = 48+(i&15);
+
+ if(cnt == selector_pos)
+ draw_trans_quad(100.0, y, 590.0, y+32.0,
+ 0x7000ff00, 0x7000ff00, 0x7000ff00, 0x7000ff00);
+
+ games[i].icon.setPalette(pal);
+ drawGameLabel(games[i], pal, 50.0, y, (cnt == selector_pos?
+ 0xffff00 : 0xffffff));
+ y += 40.0;
+ }
+
+ ta_commit_frame();
+
+ byte shiftFlags;
+ int event;
+
+ int mask = getimask();
+ setimask(15);
+ event = handleInput(locked_get_pads(), mousex, mousey, shiftFlags);
+ setimask(mask);
+
+ if(event==-OSystem::EVENT_LBUTTONDOWN || event==13 || event==319) {
+ int selected_game = top_game + selector_pos;
+
+ for(int fade=0; fade<=256; fade+=4) {
+
+ unsigned int fade_colour = 0x00ffffff | ((255-fade)<<24);
+
+ ta_begin_frame();
+
+ drawBackground();
+
+ ta_commit_end();
+
+ float y = 40.0;
+
+ if(fade < 256)
+ for(int i=top_game, cnt=0; cnt<10 && i<num_games;
+ i++, cnt++, y += 40.0)
+ if(cnt != selector_pos)
+ drawGameLabel(games[i], 48+(i&15), 50.0, y, 0xffffff, fade);
+
+ y = (40.0/256.0 * (selector_pos + 1))*(256-fade) + 80.0/256.0*fade;
+ float x = 50.0/256.0*(256-fade) + 160.0/256.0*fade;
+ float scale = 1.0+9.0/256.0*fade;
+
+ drawGameLabel(games[selected_game], 48+(selected_game&15), x, y,
+ 0xffff00, 0, scale);
+
+ ta_commit_frame();
+ }
+ return selected_game;
+ }
+
+ if(mousey>=16) {
+ if(selector_pos + top_game + 1 < num_games)
+ if(++selector_pos >= 10) {
+ --selector_pos;
+ ++top_game;
+ }
+ mousey -= 16;
+ } else if(mousey<=-16) {
+ if(selector_pos + top_game > 0)
+ if(--selector_pos < 0) {
+ ++selector_pos;
+ --top_game;
+ }
+ mousey += 16;
+ }
+ }
+}
+
+bool selectGame(char *&ret, char *&dir_ret, Icon &icon)
+{
+ Game *games = new Game[MAX_GAMES];
+ int selected, num_games;
+
+ ta_sync();
+ void *mark = ta_txmark();
+
+ for(;;) {
+ num_games = findGames(games, MAX_GAMES);
+
+ for(int i=0; i<num_games; i++) {
+ games[i].icon.create_texture();
+ games[i].label.create_texture(games[i].text);
+ }
+
+ selected = gameMenu(games, num_games);
+
+ ta_sync();
+ ta_txrelease(mark);
+
+ if(selected == -1)
+ waitForDisk();
+ else
+ break;
+
+ }
+
+ if(selected >= num_games)
+ selected = -1;
+
+ if(selected >= 0)
+ the_game = games[selected];
+
+ delete games;
+
+ if(selected>=0) {
+#if 0
+ chdir(the_game.dir);
+#else
+ chdir("/");
+ dir_ret = the_game.dir;
+#endif
+ ret = the_game.filename_base;
+ icon = the_game.icon;
+ return true;
+ } else
+ return false;
+}
diff --git a/backends/platform/dc/softkbd.cpp b/backends/platform/dc/softkbd.cpp
new file mode 100644
index 0000000000..2e761f4595
--- /dev/null
+++ b/backends/platform/dc/softkbd.cpp
@@ -0,0 +1,169 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002-2004 Marcus Comstedt
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include <common/stdafx.h>
+#include <common/scummsys.h>
+#include "base/engine.h"
+
+#include <ronin/ronin.h>
+#include <string.h>
+#include <assert.h>
+
+#include "dc.h"
+
+
+extern void draw_trans_quad(float x1, float y1, float x2, float y2,
+ int c0, int c1, int c2, int c3);
+
+
+static const char key_names[] =
+ "Esc\0F1\0F2\0F3\0F4\0F5\0F6\0F7\0F8\0F9\0F10\0"
+ "1\0!\0""2\0\"\0""3\0#\0""4\0$\0""5\0%\0"
+ "6\0&\0""7\0'\0""8\0(\0""9\0)\0""0\0~\0-\0=\0"
+ "q\0Q\0w\0W\0e\0E\0r\0R\0t\0T\0y\0Y\0u\0U\0i\0I\0o\0O\0p\0P\0@\0`\0"
+ "a\0A\0s\0S\0d\0D\0f\0F\0g\0G\0h\0H\0j\0J\0k\0K\0l\0L\0;\0+\0:\0*\0"
+ "z\0Z\0x\0X\0c\0C\0v\0V\0b\0B\0n\0N\0m\0M\0,\0<\0.\0>\0/\0?\0\\\0_\0"
+ "Shf\0Ctl\0Alt\0Space\0BS\0Ret";
+
+#define K(a,b) ((a)|((b)<<8))
+
+static const short key_codes[] =
+ {
+ 27, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324,
+ K('1','!'), K('2','"'), K('3','#'), K('4','$'), K('5','%'),
+ K('6','&'), K('7','\''), K('8','('), K('9',')'), K('0','~'), K('-','='),
+ K('q','Q'), K('w','W'), K('e','E'), K('r','R'), K('t','T'),
+ K('y','Y'), K('u','U'), K('i','I'), K('o','O'), K('p','P'), K('@','`'),
+ K('a','A'), K('s','S'), K('d','D'), K('f','F'), K('g','G'),
+ K('h','H'), K('j','J'), K('k','K'), K('l','L'), K(';','+'), K(':','*'),
+ K('z','Z'), K('x','X'), K('c','C'), K('v','V'), K('b','B'),
+ K('n','N'), K('m','M'), K(',','<'), K('.','>'), K('/','?'), K('\\','_'),
+ ~OSystem::KBD_SHIFT, ~OSystem::KBD_CTRL, ~OSystem::KBD_ALT, ' ', 8, 13
+ };
+
+SoftKeyboard::SoftKeyboard(const OSystem_Dreamcast *_os)
+ : os(_os), shiftState(0), keySel(0)
+{
+ assert((sizeof(key_codes)/sizeof(key_codes[0])) == SK_NUM_KEYS);
+
+ const char *np = key_names;
+ for(int i=0; i<SK_NUM_KEYS; i++) {
+ labels[0][i].create_texture(np);
+ np += strlen(np)+1;
+ if(key_codes[i]>8192) {
+ labels[1][i].create_texture(np);
+ np += strlen(np)+1;
+ }
+ }
+}
+
+void SoftKeyboard::draw(float x, float y, int transp)
+{
+ float x0;
+ int c = 0;
+ unsigned int txt_alpha_mask = (255-2*transp)<<24;
+ unsigned int bg_alpha_mask = (128-transp)<<24;
+
+ draw_trans_quad(x, y, x+312.0, y+172.0,
+ bg_alpha_mask|0x8080ff, bg_alpha_mask|0x8080ff,
+ bg_alpha_mask|0x8080ff, bg_alpha_mask|0x8080ff);
+ x0 = x += 4.0;
+ y += 4.0;
+ for(int i=0; i<SK_NUM_KEYS; i++) {
+ float w = (i == 58? 164.0 : 24.0);
+ unsigned int bg = (i == keySel? bg_alpha_mask|0xffff00 :
+ bg_alpha_mask|0xc0c0ff);
+ draw_trans_quad(x, y, x+w, y+24.0, bg, bg, bg, bg);
+ if(key_codes[i]<0 && (shiftState & ~key_codes[i]))
+ labels[0][i].draw(x+2, y+5, txt_alpha_mask|0xffffff, 0.5);
+ else if(key_codes[i]>8192 && (shiftState & OSystem::KBD_SHIFT))
+ labels[1][i].draw(x+2, y+5, txt_alpha_mask|0x000000, 0.5);
+ else
+ labels[0][i].draw(x+2, y+5, txt_alpha_mask|0x000000, 0.5);
+ x += w+4.0;
+ if(++c == 11) {
+ c = 0;
+ x = x0;
+ y += 28.0;
+ }
+ }
+}
+
+int SoftKeyboard::key(int k, byte &shiftFlags)
+{
+ switch(k) {
+ case 1001:
+ if(++keySel == SK_NUM_KEYS)
+ keySel = 0;
+ break;
+ case 1002:
+ if(--keySel < 0)
+ keySel = SK_NUM_KEYS - 1;
+ break;
+ case 1003:
+ if(keySel >= 55) {
+ if(keySel > 58)
+ keySel += 5;
+ keySel -= 55;
+ } else if(keySel > 47) {
+ if((keySel += 6) < 59)
+ keySel = 59;
+ } else
+ keySel += 11;
+ break;
+ case 1004:
+ if(keySel > 58)
+ keySel -= 6;
+ else if((keySel -= 11) < 0)
+ if((keySel += 66) > 58)
+ if((keySel -= 5) < 59)
+ keySel = 59;
+ break;
+ case 1000:
+ case 13:
+ case 32:
+ case 319:
+ if(key_codes[keySel]<0)
+ shiftState ^= ~key_codes[keySel];
+ else {
+ shiftFlags = shiftState;
+ if(key_codes[keySel] > 8192)
+ return ((shiftState & OSystem::KBD_SHIFT)? (key_codes[keySel]>>8):
+ key_codes[keySel]) & 0xff;
+ else
+ return key_codes[keySel];
+ }
+ break;
+ }
+ return 0;
+}
+
+void SoftKeyboard::mouse(int x, int y)
+{
+ os->mouseToSoftKbd(x, y, x, y);
+ if(x >= 0 && x < 11*28 && y >= 0 && y < 6*28 &&
+ x%28 >= 4 && y%28 >= 4)
+ if((keySel = 11*(y/28)+(x/28)) > 58)
+ if((keySel -= 5) < 59)
+ keySel = 58;
+}
diff --git a/backends/platform/dc/softkbd.h b/backends/platform/dc/softkbd.h
new file mode 100644
index 0000000000..b079ab4011
--- /dev/null
+++ b/backends/platform/dc/softkbd.h
@@ -0,0 +1,50 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002-2004 Marcus Comstedt
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef DC_SOFTKBD_H
+#define DC_SOFTKBD_H
+
+#include "label.h"
+
+#define SK_NUM_KEYS 61
+
+class OSystem_Dreamcast;
+
+class SoftKeyboard : public Interactive
+{
+ private:
+
+ const OSystem_Dreamcast *os;
+ Label labels[2][SK_NUM_KEYS];
+ byte shiftState;
+ int8 keySel;
+
+ public:
+ SoftKeyboard(const OSystem_Dreamcast *os);
+
+ void draw(float x, float y, int transp = 0);
+ int key(int k, byte &shiftFlags);
+ void mouse(int x, int y);
+};
+
+#endif /* DC_SOFTKBD_H */
diff --git a/backends/platform/dc/time.cpp b/backends/platform/dc/time.cpp
new file mode 100644
index 0000000000..a4bbfb8be6
--- /dev/null
+++ b/backends/platform/dc/time.cpp
@@ -0,0 +1,97 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002-2004 Marcus Comstedt
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#define RONIN_TIMER_ACCESS
+
+#include <common/stdafx.h>
+#include <common/scummsys.h>
+#include "dc.h"
+
+
+uint32 OSystem_Dreamcast::getMillis()
+{
+ static uint32 msecs=0;
+ static unsigned int t0=0;
+
+ unsigned int t = Timer();
+ unsigned int dm, dt = t - t0;
+
+ t0 = t;
+ dm = (dt << 6)/3125U;
+ dt -= (dm * 3125U)>>6;
+ t0 -= dt;
+
+ return msecs += dm;
+}
+
+void OSystem_Dreamcast::delayMillis(uint msecs)
+{
+ getMillis();
+ unsigned int t, start = Timer();
+ int time = (((unsigned int)msecs)*100000U)>>11;
+ while(((int)((t = Timer())-start))<time)
+ checkSound();
+ getMillis();
+}
+
+void OSystem_Dreamcast::setTimerCallback(TimerProc callback, int timer)
+{
+ if (callback != NULL) {
+ _timer_duration = timer;
+ _timer_next_expiry = Timer() + USEC_TO_TIMER(1000*timer);
+ _timer_callback = callback;
+ _timer_active = true;
+ } else {
+ _timer_active = false;
+ }
+}
+
+
+/*
+void waitForTimer(Scumm *s, int time)
+{
+ if(time<0)
+ return;
+ unsigned int start = Timer();
+ unsigned int devpoll = start+USEC_TO_TIMER(25000);
+ unsigned int t;
+ int oldmousex = s->mouse.x, oldmousey = s->mouse.y;
+ time = (((unsigned int)time)*100000U)>>11;
+ int mask = getimask();
+ while(((int)((t = Timer())-start))<time)
+ if(((int)(t-devpoll))>0) {
+ setimask(15);
+ checkSound();
+ handleInput(locked_get_pads(), s->mouse.x, s->mouse.y,
+ s->_leftBtnPressed, s->_rightBtnPressed, s->_keyPressed);
+ setimask(mask);
+ devpoll += USEC_TO_TIMER(17000);
+ if(s->mouse.x != oldmousex || s->mouse.y != oldmousey) {
+ extern void updateScreen(Scumm *s);
+ updateScreen(s);
+ oldmousex = s->mouse.x;
+ oldmousey = s->mouse.y;
+ }
+ }
+}
+*/
diff --git a/backends/platform/dc/vmsave.cpp b/backends/platform/dc/vmsave.cpp
new file mode 100644
index 0000000000..604d9230a7
--- /dev/null
+++ b/backends/platform/dc/vmsave.cpp
@@ -0,0 +1,407 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002-2004 Marcus Comstedt
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include <common/stdafx.h>
+#include <common/scummsys.h>
+#include "base/engine.h"
+#include "dc.h"
+#include "icon.h"
+#include <common/savefile.h>
+#include <gui/newgui.h>
+#include <gui/message.h>
+
+#include <zlib.h>
+
+
+// Savegame can not be bigger than this, even before compression
+#define MAX_SAVE_SIZE (128*1024)
+
+
+enum vmsaveResult {
+ VMSAVE_OK,
+ VMSAVE_NOVM,
+ VMSAVE_NOSPACE,
+ VMSAVE_WRITEERROR,
+};
+
+
+static int lastvm=-1;
+
+static void displaySaveResult(vmsaveResult res)
+{
+ char buf[1024];
+
+ switch(res) {
+ case VMSAVE_OK:
+ sprintf(buf, "Game saved on unit %c%d", 'A'+(lastvm/6), lastvm%6);
+ break;
+ case VMSAVE_NOVM:
+ strcpy(buf, "No memory card present!");
+ break;
+ case VMSAVE_NOSPACE:
+ strcpy(buf, "Not enough space available!");
+ break;
+ case VMSAVE_WRITEERROR:
+ strcpy(buf, "Write error!!!");
+ break;
+ default:
+ strcpy(buf, "Unknown error!!!");
+ break;
+ }
+
+ GUI::MessageDialog dialog(buf);
+ dialog.runModal();
+}
+
+static vmsaveResult trySave(const char *gamename, const char *data, int size,
+ const char *filename, class Icon &icon, int vm)
+{
+ struct vmsinfo info;
+ struct superblock super;
+ struct vms_file file;
+ struct vms_file_header header;
+ struct timestamp tstamp;
+ struct tm tm;
+ time_t t;
+ unsigned char iconbuffer[512+32];
+
+ if(!vmsfs_check_unit(vm, 0, &info))
+ return VMSAVE_NOVM;
+ if(!vmsfs_get_superblock(&info, &super))
+ return VMSAVE_NOVM;
+ int free_cnt = vmsfs_count_free(&super);
+ if(vmsfs_open_file(&super, filename, &file))
+ free_cnt += file.blks;
+ if(((128+512+size+511)>>9) > free_cnt)
+ return VMSAVE_NOSPACE;
+
+ memset(&header, 0, sizeof(header));
+ strncpy(header.shortdesc, "ScummVM savegame", 16);
+ strncpy(header.longdesc, gamename, 32);
+ strncpy(header.id, "ScummVM", 16);
+ icon.create_vmicon(iconbuffer);
+ header.numicons = 1;
+ memcpy(header.palette, iconbuffer, sizeof(header.palette));
+ time(&t);
+ tm = *localtime(&t);
+ tstamp.year = tm.tm_year+1900;
+ tstamp.month = tm.tm_mon+1;
+ tstamp.day = tm.tm_mday;
+ tstamp.hour = tm.tm_hour;
+ tstamp.minute = tm.tm_min;
+ tstamp.second = tm.tm_sec;
+ tstamp.wkday = (tm.tm_wday+6)%7;
+
+ vmsfs_beep(&info, 1);
+
+ vmsfs_errno = 0;
+ if(!vmsfs_create_file(&super, filename, &header,
+ iconbuffer+sizeof(header.palette), NULL,
+ data, size, &tstamp)) {
+ fprintf(stderr, "%s\n", vmsfs_describe_error());
+ vmsfs_beep(&info, 0);
+ return VMSAVE_WRITEERROR;
+ }
+
+ vmsfs_beep(&info, 0);
+ return VMSAVE_OK;
+}
+
+static bool tryLoad(char *&buffer, int &size, const char *filename, int vm)
+{
+ struct vmsinfo info;
+ struct superblock super;
+ struct vms_file file;
+ struct vms_file_header header;
+ struct timestamp tstamp;
+ struct tm tm;
+ time_t t;
+ unsigned char iconbuffer[512+32];
+
+ if(!vmsfs_check_unit(vm, 0, &info))
+ return false;
+ if(!vmsfs_get_superblock(&info, &super))
+ return false;
+ if(!vmsfs_open_file(&super, filename, &file))
+ return false;
+
+ buffer = new char[size = file.size];
+
+ if(vmsfs_read_file(&file, (unsigned char *)buffer, size))
+ return true;
+
+ delete[] buffer;
+ buffer = NULL;
+ return false;
+}
+
+static void tryList(const char *prefix, bool *marks, int num, int vm)
+{
+ struct vmsinfo info;
+ struct superblock super;
+ struct dir_iterator iter;
+ struct dir_entry de;
+ int pl = strlen(prefix);
+
+ if(!vmsfs_check_unit(vm, 0, &info))
+ return;
+ if(!vmsfs_get_superblock(&info, &super))
+ return;
+ vmsfs_open_dir(&super, &iter);
+ while(vmsfs_next_dir_entry(&iter, &de))
+ if(de.entry[0]) {
+ char buf[16], *endp = NULL;
+ strncpy(buf, (char *)de.entry+4, 12);
+ buf[12] = 0;
+ int l = strlen(buf);
+ long i = 42;
+ if(l > pl && !strncmp(buf, prefix, pl) &&
+ (i = strtol(buf+pl, &endp, 10))>=0 && i<num &&
+ (endp - buf) == l)
+ marks[i] = true;
+ }
+}
+
+vmsaveResult writeSaveGame(const char *gamename, const char *data, int size,
+ const char *filename, class Icon &icon)
+{
+ vmsaveResult r, res = VMSAVE_NOVM;
+
+ if(lastvm >= 0 &&
+ (res = trySave(gamename, data, size, filename, icon, lastvm)) == VMSAVE_OK)
+ return res;
+
+ for(int i=0; i<24; i++)
+ if((r = trySave(gamename, data, size, filename, icon, i)) == VMSAVE_OK) {
+ lastvm = i;
+ return r;
+ } else if(r > res)
+ res = r;
+
+ return res;
+}
+
+bool readSaveGame(char *&buffer, int &size, const char *filename)
+{
+ if(lastvm >= 0 &&
+ tryLoad(buffer, size, filename, lastvm))
+ return true;
+
+ for(int i=0; i<24; i++)
+ if(tryLoad(buffer, size, filename, i)) {
+ lastvm = i;
+ return true;
+ }
+
+ return false;
+}
+
+
+class InVMSave : public Common::InSaveFile {
+private:
+ char *buffer;
+ int _pos, _size;
+
+ uint32 read(void *buf, uint32 cnt);
+ void skip(uint32 offset);
+ void seek(int32 offs, int whence);
+
+public:
+ InVMSave()
+ : _pos(0), buffer(NULL)
+ { }
+
+ ~InVMSave()
+ {
+ if(buffer != NULL)
+ delete[] buffer;
+ }
+
+ bool eos() const { return _pos >= _size; }
+ uint32 pos() const { return _pos; }
+ uint32 size() const { return _size; }
+
+ bool readSaveGame(const char *filename)
+ { return ::readSaveGame(buffer, _size, filename); }
+
+ void tryUncompress()
+ {
+ if(_size > 0 && buffer[0] != 'S') {
+ // Data does not start with "SCVM". Maybe compressed?
+ char *expbuf = new char[MAX_SAVE_SIZE];
+ unsigned long destlen = MAX_SAVE_SIZE;
+ if(!uncompress((Bytef*)expbuf, &destlen, (Bytef*)buffer, _size)) {
+ delete[] buffer;
+ buffer = expbuf;
+ _size = destlen;
+ } else delete[] expbuf;
+ }
+ }
+};
+
+class OutVMSave : public Common::OutSaveFile {
+private:
+ char *buffer;
+ int pos, size, committed;
+ char filename[16];
+ bool iofailed;
+
+public:
+ uint32 write(const void *buf, uint32 cnt);
+
+ OutVMSave(const char *_filename)
+ : pos(0), committed(-1), iofailed(false)
+ {
+ strncpy(filename, _filename, 16);
+ buffer = new char[size = MAX_SAVE_SIZE];
+ }
+
+ ~OutVMSave();
+
+ bool ioFailed() const { return iofailed; }
+ void clearIOFailed() { iofailed = false; }
+ void flush();
+};
+
+class VMSaveManager : public Common::SaveFileManager {
+public:
+
+ virtual Common::OutSaveFile *openForSaving(const char *filename) {
+ return new OutVMSave(filename);
+ }
+
+ virtual Common::InSaveFile *openForLoading(const char *filename) {
+ InVMSave *s = new InVMSave();
+ if(s->readSaveGame(filename)) {
+ s->tryUncompress();
+ return s;
+ } else {
+ delete s;
+ return NULL;
+ }
+ }
+
+ virtual void listSavefiles(const char *prefix, bool *marks, int num);
+};
+
+void OutVMSave::flush()
+{
+ extern const char *gGameName;
+ extern Icon icon;
+
+ if(committed >= pos)
+ return;
+
+ char *data = buffer, *compbuf = NULL;
+ int len = pos;
+
+ if(pos) {
+ // Try compression
+ compbuf = new char[pos];
+ unsigned long destlen = pos;
+ if(!compress((Bytef*)compbuf, &destlen, (Bytef*)buffer, pos)) {
+ data = compbuf;
+ len = destlen;
+ }
+ }
+ vmsaveResult r = writeSaveGame(gGameName, data, len, filename, icon);
+ committed = pos;
+ if(compbuf != NULL)
+ delete[] compbuf;
+ if(r != VMSAVE_OK)
+ iofailed = true;
+ displaySaveResult(r);
+}
+
+OutVMSave::~OutVMSave()
+{
+ flush();
+ delete[] buffer;
+}
+
+uint32 InVMSave::read(void *buf, uint32 cnt)
+{
+ int nbyt = cnt;
+ if (_pos + nbyt > _size) {
+ cnt = (_size - _pos);
+ nbyt = cnt;
+ }
+ if (nbyt)
+ memcpy(buf, buffer + _pos, nbyt);
+ _pos += nbyt;
+ return cnt;
+}
+
+void InVMSave::skip(uint32 offset)
+{
+ int nbyt = offset;
+ if (_pos + nbyt > _size)
+ nbyt = (_size - _pos);
+ _pos += nbyt;
+}
+
+void InVMSave::seek(int32 offs, int whence)
+{
+ switch(whence) {
+ case SEEK_SET:
+ _pos = offs;
+ break;
+ case SEEK_CUR:
+ _pos += offs;
+ break;
+ case SEEK_END:
+ _pos = _size + offs;
+ break;
+ }
+ if(_pos < 0)
+ _pos = 0;
+ else if(_pos > _size)
+ _pos = _size;
+}
+
+uint32 OutVMSave::write(const void *buf, uint32 cnt)
+{
+ int nbyt = cnt;
+ if (pos + nbyt > size) {
+ cnt = (size - pos);
+ nbyt = cnt;
+ }
+ if (nbyt)
+ memcpy(buffer + pos, buf, nbyt);
+ pos += nbyt;
+ return cnt;
+}
+
+
+void VMSaveManager::listSavefiles(const char *prefix, bool *marks, int num)
+{
+ memset(marks, false, num*sizeof(bool));
+
+ for(int i=0; i<24; i++)
+ tryList(prefix, marks, num, i);
+}
+
+Common::SaveFileManager *OSystem_Dreamcast::getSavefileManager()
+{
+ return new VMSaveManager();
+}