aboutsummaryrefslogtreecommitdiff
path: root/backends/dc
diff options
context:
space:
mode:
Diffstat (limited to 'backends/dc')
-rw-r--r--backends/dc/.cvsignore5
-rw-r--r--backends/dc/Makefile39
-rw-r--r--backends/dc/README20
-rw-r--r--backends/dc/audio.cpp86
-rw-r--r--backends/dc/dc.h102
-rw-r--r--backends/dc/dcmain.cpp201
-rw-r--r--backends/dc/display.cpp303
-rw-r--r--backends/dc/icon.cpp228
-rw-r--r--backends/dc/icon.h21
-rw-r--r--backends/dc/input.cpp173
-rw-r--r--backends/dc/label.cpp131
-rw-r--r--backends/dc/label.h11
-rw-r--r--backends/dc/portdefs.h9
-rw-r--r--backends/dc/selector.cpp487
-rw-r--r--backends/dc/vmsave.cpp266
15 files changed, 2082 insertions, 0 deletions
diff --git a/backends/dc/.cvsignore b/backends/dc/.cvsignore
new file mode 100644
index 0000000000..ed6bd2b99e
--- /dev/null
+++ b/backends/dc/.cvsignore
@@ -0,0 +1,5 @@
+scummvm
+sound
+v3
+v4
+simon
diff --git a/backends/dc/Makefile b/backends/dc/Makefile
new file mode 100644
index 0000000000..18ba20d6fc
--- /dev/null
+++ b/backends/dc/Makefile
@@ -0,0 +1,39 @@
+# $Header$
+
+ronindir = /usr/local/ronin
+
+VPATH = ..
+
+CC = sh-elf-g++ -ml -m4-single-only
+CFLAGS = -O1 -Wno-multichar
+DEFINES = -D__DC__ -DNONSTANDARD_PORT -DNONSTANDARD_SAVE
+LDFLAGS := -Wl,-Ttext,0x8c010000 -nostartfiles ronin/crt0.o
+INCLUDES:= -I./ -I../ -I../sound
+CPPFLAGS= $(DEFINES) $(INCLUDES)
+LIBS = ronin/libronin.a ronin/libz.a -lm
+EXEEXT =
+
+OBJS = dcmain.o display.o audio.o input.o selector.o icon.o \
+ label.o vmsave.o
+
+include ../Makefile.common
+
+INCS += portdefs.h dc.h
+
+$(OBJS): Makefile sound/.create simon/.create v3/.create v4/.create ronin
+
+sound/.create:
+ mkdir sound && touch $@
+
+simon/.create:
+ mkdir simon && touch $@
+
+v3/.create:
+ mkdir v3 && touch $@
+
+v4/.create:
+ mkdir v4 && touch $@
+
+ronin:
+ ln -s $(ronindir) $@
+
diff --git a/backends/dc/README b/backends/dc/README
new file mode 100644
index 0000000000..d4bf04c5bd
--- /dev/null
+++ b/backends/dc/README
@@ -0,0 +1,20 @@
+Compiling ScummVM for SEGA Dreamcast
+====================================
+
+If you want to compile ScummVM for your Dreamcast,
+you'll need the following:
+
+* gcc-3.0.x configured as a cross-compiler for `sh-elf'
+ (including corresponding binutils)
+
+* newlib for sh-elf : <URL:http://mc.pp.se/dc/files/newlib-1.9.0.tar.gz>
+
+* libronin-0.3 : <URL:http://peter.bortas.org/scumm/libronin-0.3.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', and you should
+get an ELF binary with the name `scummvm'.
+
diff --git a/backends/dc/audio.cpp b/backends/dc/audio.cpp
new file mode 100644
index 0000000000..863c1e97ac
--- /dev/null
+++ b/backends/dc/audio.cpp
@@ -0,0 +1,86 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+#include "scumm.h"
+#include "dc.h"
+
+EXTERN_C void *memcpy4(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_BUFFER(3));
+}
+
+bool OSystem_Dreamcast::set_sound_proc(void *param, SoundProc *proc,
+ byte format)
+{
+#if SAMPLE_MODE == 0
+ assert(format == SOUND_16BIT);
+#elif SAMPLE_MODE == 1
+ assert(format == SOUND_8BIT);
+#else
+#error Invalid SAMPLE_MODE
+#endif
+ _sound_proc_param = param;
+ _sound_proc = proc;
+
+ return true;
+}
+
+void OSystem_Dreamcast::checkSound()
+{
+ int n;
+ int curr_ring_buffer_samples;
+
+ 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,
+ SAMPLES_TO_BYTES(n));
+
+ if(fillpos+n > curr_ring_buffer_samples) {
+ int r = curr_ring_buffer_samples - fillpos;
+ memcpy4(RING_BUF+fillpos, temp_sound_buffer, SAMPLES_TO_BYTES(r));
+ fillpos = 0;
+ n -= r;
+ memcpy4(RING_BUF, temp_sound_buffer+r, SAMPLES_TO_BYTES(n));
+ } else {
+ memcpy4(RING_BUF+fillpos, temp_sound_buffer, SAMPLES_TO_BYTES(n));
+ }
+ if((fillpos += n) >= curr_ring_buffer_samples)
+ fillpos = 0;
+}
diff --git a/backends/dc/dc.h b/backends/dc/dc.h
new file mode 100644
index 0000000000..4a2b78cfb7
--- /dev/null
+++ b/backends/dc/dc.h
@@ -0,0 +1,102 @@
+#include <ronin/soundcommon.h>
+
+#define NUM_BUFFERS 4
+
+class OSystem_Dreamcast : public OSystem {
+
+ public:
+ // Set colors of the palette
+ void set_palette(const byte *colors, uint start, uint num);
+
+ // Set the size of the video bitmap.
+ // Typically, 320x200
+ void init_size(uint w, uint h);
+
+ // Draw a bitmap to screen.
+ // The screen will not be updated to reflect the new bitmap
+ void copy_rect(const byte *buf, int pitch, int x, int y, int w, int h);
+
+ // Update the dirty areas of the screen
+ void update_screen();
+
+ // Either show or hide the mouse cursor
+ bool show_mouse(bool visible);
+
+ // Set the position of the mouse cursor
+ void set_mouse_pos(int x, int y);
+
+ // Set the bitmap that's used when drawing the cursor.
+ void set_mouse_cursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y);
+
+ // Shaking is used in SCUMM. Set current shake position.
+ void set_shake_pos(int shake_pos);
+
+ // Get the number of milliseconds since the program was started.
+ uint32 get_msecs();
+
+ // Delay for a specified amount of milliseconds
+ void delay_msecs(uint msecs);
+
+ // Create a thread
+ void *create_thread(ThreadProc *proc, void *param);
+
+ // Get the next event.
+ // Returns true if an event was retrieved.
+ bool poll_event(Event *event);
+
+ // Set function that generates samples
+ bool set_sound_proc(void *param, SoundProc *proc, byte sound);
+
+ // Poll cdrom status
+ // Returns true if cd audio is playing
+ bool poll_cdrom();
+
+ // Play cdrom audio track
+ void play_cdrom(int track, int num_loops, int start_frame, int end_frame);
+
+ // Stop cdrom audio track
+ void stop_cdrom();
+
+ // Update cdrom audio status
+ void update_cdrom();
+
+ // Quit
+ void quit();
+
+ // Set a parameter
+ uint32 property(int param, Property *value);
+
+ static OSystem *create();
+
+
+ private:
+
+ 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_h;
+ unsigned char *_ms_buf;
+ SoundProc *_sound_proc;
+ void *_sound_proc_param;
+
+ unsigned char *screen;
+ unsigned short *mouse;
+ void *screen_tx[NUM_BUFFERS];
+ void *mouse_tx[NUM_BUFFERS];
+ int current_buffer;
+ unsigned short palette[256];
+
+ short temp_sound_buffer[RING_BUFFER_SAMPLES];
+
+ void checkSound();
+
+ void drawMouse(int xdraw, int ydraw, int w, int h,
+ unsigned char *buf, bool visible);
+
+};
+
+extern int handleInput(struct mapledev *pad,
+ int &mouse_x, int &mouse_y,
+ byte &shiftFlags);
+extern void initSound();
+extern bool selectGame(GameDetector *d, char *&, char *&, class Icon &);
+
diff --git a/backends/dc/dcmain.cpp b/backends/dc/dcmain.cpp
new file mode 100644
index 0000000000..a64643a004
--- /dev/null
+++ b/backends/dc/dcmain.cpp
@@ -0,0 +1,201 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+#include "scumm.h"
+#include "mididrv.h"
+#include "gameDetector.h"
+#include "dc.h"
+#include "icon.h"
+
+
+Icon icon;
+
+
+OSystem *OSystem_Dreamcast_create() {
+ return OSystem_Dreamcast::create();
+}
+
+OSystem *OSystem_Dreamcast::create() {
+ OSystem_Dreamcast *syst = new OSystem_Dreamcast();
+ return syst;
+}
+
+/* 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=last; i>=first; --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::play_cdrom(int track, int num_loops,
+ int start_frame, int end_frame)
+{
+ 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(end_frame)
+ last_sec = first_sec + start_frame + end_frame;
+ first_sec += start_frame;
+ play_cdda_sectors(first_sec, last_sec, num_loops);
+}
+
+void OSystem_Dreamcast::stop_cdrom()
+{
+ stop_cdda();
+}
+
+bool OSystem_Dreamcast::poll_cdrom()
+{
+ extern int getCdState();
+ return getCdState() == 3;
+}
+
+void OSystem_Dreamcast::update_cdrom()
+{
+ // Dummy. The CD drive takes care of itself.
+}
+
+uint32 OSystem_Dreamcast::property(int param, Property *value)
+{
+ switch(param) {
+
+ case PROP_GET_SAMPLE_RATE:
+ return 22050;
+
+ }
+
+ return 0;
+}
+
+void OSystem_Dreamcast::quit() {
+ exit(0);
+}
+
+void *OSystem_Dreamcast::create_thread(ThreadProc *proc, void *param) {
+ warning("Creating a thread! (not supported.)\n");
+}
+
+uint32 OSystem_Dreamcast::get_msecs()
+{
+ 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::delay_msecs(uint msecs)
+{
+ get_msecs();
+ unsigned int t, start = Timer();
+ int time = (((unsigned int)msecs)*100000U)>>11;
+ while(((int)((t = Timer())-start))<time)
+ checkSound();
+ get_msecs();
+}
+
+/*
+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;
+ }
+ }
+}
+*/
+
+void dc_init_hardware(void)
+{
+#ifndef NOSERIAL
+ serial_init(57600);
+ usleep(2000000);
+ printf("Serial OK\r\n");
+#endif
+
+ cdfs_init();
+ maple_init();
+ dc_setup_ta();
+ init_arm();
+}
+
+int dc_setup(GameDetector &detector)
+{
+ static char *argv[] = { "scummvm", NULL, NULL, NULL };
+ static int argc = 3;
+
+ initSound();
+
+ if(!selectGame(&detector, argv[2], argv[1], icon))
+ exit(0);
+
+ detector.parseCommandLine(argc, argv);
+
+ return 0;
+}
diff --git a/backends/dc/display.cpp b/backends/dc/display.cpp
new file mode 100644
index 0000000000..97c7f2aed5
--- /dev/null
+++ b/backends/dc/display.cpp
@@ -0,0 +1,303 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+#include "scumm.h"
+#include "dc.h"
+
+#define SCREEN_W 320
+#define SCREEN_H 240
+#define MOUSE_W 64
+#define MOUSE_H 64
+
+#define TOP_OFFSET (240.0-_screen_h)
+
+#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;
+ }
+}
+
+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::set_palette(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;
+ }
+}
+
+void OSystem_Dreamcast::init_size(uint w, uint h)
+{
+ assert(w == SCREEN_W && h <= SCREEN_H);
+
+ _screen_h = h;
+ ta_sync();
+ if(!screen)
+ screen = new unsigned char[SCREEN_W*SCREEN_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);
+ current_buffer = 0;
+ *(volatile unsigned int *)(0xa05f80e4) = SCREEN_W/32; //stride
+ // dc_reset_screen(0, 0);
+}
+
+void OSystem_Dreamcast::copy_rect(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);
+}
+
+bool OSystem_Dreamcast::show_mouse(bool visible)
+{
+ bool last = _ms_visible;
+ _ms_visible = visible;
+
+ return last;
+}
+
+void OSystem_Dreamcast::set_mouse_pos(int x, int y)
+{
+ _ms_cur_x = x;
+ _ms_cur_y = y;
+}
+
+void OSystem_Dreamcast::set_mouse_cursor(const byte *buf, uint w, uint h,
+ int hotspot_x, int hotspot_y)
+{
+ _ms_cur_w = w;
+ _ms_cur_h = h;
+
+ _ms_hotspot_x = hotspot_x;
+ _ms_hotspot_y = hotspot_y;
+
+ _ms_buf = (byte*)buf;
+}
+
+void OSystem_Dreamcast::set_shake_pos(int shake_pos)
+{
+ _current_shake_pos = shake_pos;
+}
+
+void OSystem_Dreamcast::update_screen(void)
+{
+ struct polygon_list mypoly;
+ struct packed_colour_vertex_list myvertex;
+
+ unsigned short *dst = (unsigned short *)screen_tx[current_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;
+ }
+
+ // *((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_512|TA_POLYMODE2_V_SIZE_512;
+ mypoly.texture = TA_TEXTUREMODE_ARGB1555|TA_TEXTUREMODE_NON_TWIDDLED|
+ TA_TEXTUREMODE_STRIDE|TA_TEXTUREMODE_ADDRESS(screen_tx[current_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 = _current_shake_pos*2.0+TOP_OFFSET;
+ ta_commit_list(&myvertex);
+
+ myvertex.x = SCREEN_W*2.0;
+ myvertex.u = SCREEN_W/512.0;
+ ta_commit_list(&myvertex);
+
+ myvertex.x = 0.0;
+ myvertex.y += _screen_h*2.0;
+ myvertex.u = 0.0;
+ myvertex.v = _screen_h*(1/512.0);
+ ta_commit_list(&myvertex);
+
+ myvertex.x = SCREEN_W*2.0;
+ myvertex.u = SCREEN_W/512.0;
+ myvertex.cmd |= TA_CMD_VERTEX_EOS;
+ ta_commit_list(&myvertex);
+
+ ta_commit_end();
+ // *((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();
+
+ current_buffer++;
+ current_buffer &= NUM_BUFFERS-1;
+ // *((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 *dst = (unsigned short *)mouse_tx[current_buffer];
+ int y=0;
+
+ if(visible && w<=MOUSE_W && h<=MOUSE_H)
+ for(int y=0; y<h; y++) {
+ int x;
+ for(x=0; x<w; x++)
+ if(*buf == 0xff) {
+ *dst++ = 0;
+ buf++;
+ } else
+ *dst++ = palette[*buf++]|0x8000;
+ dst += MOUSE_W-x;
+ }
+ else
+ w = h = 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_FOG_DISABLED|TA_POLYMODE2_TEXTURE_REPLACE|
+ TA_POLYMODE2_U_SIZE_64|TA_POLYMODE2_V_SIZE_64;
+ mypoly.texture = TA_TEXTUREMODE_ARGB1555|TA_TEXTUREMODE_NON_TWIDDLED|
+ TA_TEXTUREMODE_ADDRESS(mouse_tx[current_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_y)*2.0;
+ myvertex.y = (ydraw+_current_shake_pos-_ms_hotspot_x)*2.0 + TOP_OFFSET;
+ ta_commit_list(&myvertex);
+
+ myvertex.x += w*2.0;
+ myvertex.u = w*(1.0/MOUSE_W);
+ ta_commit_list(&myvertex);
+
+ myvertex.x = (xdraw-_ms_hotspot_y)*2.0;
+ myvertex.y += h*2.0;
+ myvertex.u = 0.0;
+ myvertex.v = h*(1.0/MOUSE_H);
+ ta_commit_list(&myvertex);
+
+ myvertex.x += w*2.0;
+ myvertex.u = w*(1.0/MOUSE_W);
+ myvertex.cmd |= TA_CMD_VERTEX_EOS;
+ ta_commit_list(&myvertex);
+}
+
diff --git a/backends/dc/icon.cpp b/backends/dc/icon.cpp
new file mode 100644
index 0000000000..93e70ad2b5
--- /dev/null
+++ b/backends/dc/icon.cpp
@@ -0,0 +1,228 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#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::set_palette(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(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;
+ 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, ((char *)data)+hdr.size, hdr.used<<2);
+ memcpy(bitmap, ((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) {
+ unsigned char *mask =
+ ((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(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, ((char *)data)+offs, 16);
+ if(hdr.bytes > 0 && hdr.offs >= 0 && hdr.offs+hdr.bytes <= len)
+ return load_image2(((char *)data)+hdr.offs, hdr.bytes);
+ else
+ return false;
+}
+
+bool Icon::load(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, ((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/dc/icon.h b/backends/dc/icon.h
new file mode 100644
index 0000000000..b9cf344bab
--- /dev/null
+++ b/backends/dc/icon.h
@@ -0,0 +1,21 @@
+
+class Icon
+{
+ private:
+ unsigned char bitmap[32*32/2];
+ unsigned int palette[16];
+ void *texture;
+
+ int find_unused_pixel();
+ bool load_image1(void *data, int len, int offs);
+ bool load_image2(void *data, int len);
+
+ public:
+ bool load(void *data, int len, int offs = 0);
+ bool load(const char *filename);
+ void create_texture();
+ void set_palette(int pal);
+ void draw(float x1, float y1, float x2, float y2, int pal,
+ unsigned argb = 0xffffffff);
+ void create_vmicon(void *buffer);
+};
diff --git a/backends/dc/input.cpp b/backends/dc/input.cpp
new file mode 100644
index 0000000000..ed7289e463
--- /dev/null
+++ b/backends/dc/input.cpp
@@ -0,0 +1,173 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+#include "scumm.h"
+#include "dc.h"
+
+int handleInput(struct mapledev *pad, int &mouse_x, int &mouse_y,
+ byte &shiftFlags)
+{
+ int lmb=0, rmb=0, newkey=0;
+ static int lastkey = 0;
+ static byte lastlmb = 0, lastrmb = 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 = '0';
+
+ if(!(buttons & 128)) mouse_x++;
+ if(!(buttons & 64)) mouse_x--;
+ if(!(buttons & 32)) mouse_y++;
+ if(!(buttons & 16)) mouse_y--;
+
+ mouse_x += ((int)pad->cond.controller.joyx-128)>>4;
+ mouse_y += ((int)pad->cond.controller.joyy-128)>>4;
+ } 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;
+ pad->cond.mouse.axis1 = 0;
+ pad->cond.mouse.axis2 = 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 >= 0x3a && key <= 0x43)
+ newkey = key+(315-0x3a);
+ 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:
+ mouse_x++; break;
+ case 0x50:
+ mouse_x--; break;
+ case 0x51:
+ mouse_y++; break;
+ case 0x52:
+ mouse_y--; break;
+ }
+ }
+ }
+
+ 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(!newkey)
+ lastkey = 0;
+ else if(newkey != lastkey)
+ return lastkey = newkey;
+
+ return 0;
+}
+
+bool OSystem_Dreamcast::poll_event(Event *event)
+{
+ unsigned int t = Timer();
+ if(((int)(t-_devpoll))<0)
+ return false;
+ _devpoll += 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);
+ setimask(mask);
+ if (_ms_cur_x<0) _ms_cur_x=0;
+ if (_ms_cur_x>319) _ms_cur_x=319;
+ 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;
+ event->kbd.ascii = event->kbd.keycode = 0;
+ if(e<0) {
+ event->event_code = -e;
+ return true;
+ } else if(e>0) {
+ event->event_code = EVENT_KEYDOWN;
+ event->kbd.keycode = e;
+ event->kbd.ascii = (e>='a' && e<='z' && (event->kbd.flags & KBD_SHIFT)?
+ e &~ 0x20 : e);
+ return true;
+ } else if(_ms_cur_x != _ms_old_x || _ms_cur_y != _ms_old_y) {
+ event->event_code = EVENT_MOUSEMOVE;
+ _ms_old_x = _ms_cur_x;
+ _ms_old_y = _ms_cur_y;
+ return true;
+ } else {
+ event->event_code = 0;
+ return false;
+ }
+}
+
diff --git a/backends/dc/label.cpp b/backends/dc/label.cpp
new file mode 100644
index 0000000000..8f263eec0a
--- /dev/null
+++ b/backends/dc/label.cpp
@@ -0,0 +1,131 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include <ronin/ronin.h>
+#include <string.h>
+
+#include "label.h"
+
+static void *get_romfont_address()
+{
+ void *ret;
+ __asm__("jsr @%1; mov #0,r1; mov r0,%0" :
+ "=r" (ret) : "r" (*(void **)0x8c0000b4) :
+ "pr", "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7");
+ return ret;
+}
+
+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/dc/label.h b/backends/dc/label.h
new file mode 100644
index 0000000000..d4a407307d
--- /dev/null
+++ b/backends/dc/label.h
@@ -0,0 +1,11 @@
+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);
+};
diff --git a/backends/dc/portdefs.h b/backends/dc/portdefs.h
new file mode 100644
index 0000000000..fd7929ffe7
--- /dev/null
+++ b/backends/dc/portdefs.h
@@ -0,0 +1,9 @@
+#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 <ronin/ronin.h>
diff --git a/backends/dc/selector.cpp b/backends/dc/selector.cpp
new file mode 100644
index 0000000000..22cba5bbfc
--- /dev/null
+++ b/backends/dc/selector.cpp
@@ -0,0 +1,487 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+#include "scumm.h"
+#include "mididrv.h"
+#include "gameDetector.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[256];
+ char deficon[256];
+};
+
+static Game the_game;
+
+static bool isGame(const char *fn, char *base)
+{
+ int l = strlen(fn);
+ if(l>4 && (!strcasecmp(fn+l-4, ".000") ||
+ !strcasecmp(fn+l-4, ".SM0"))) {
+ strcpy(base, fn);
+ base[l-4]='\0';
+ return true;
+ }
+ if(!strcasecmp(fn, "00.LFL") ||
+ !strcasecmp(fn, "000.LFL")) {
+ *base = '\0';
+ return true;
+ }
+ return false;
+}
+
+static void checkName(GameDetector *d, Game &game)
+{
+ d->_exe_name = game.filename_base;
+ if(d->detectGame()) {
+ char *n = d->getGameName();
+ strcpy(game.text, n);
+ free(n);
+ } else
+ strcpy(game.text, game.filename_base);
+ d->_exe_name = NULL;
+}
+
+static bool checkExe(const char *dir, const char *f)
+{
+ char fn[520];
+ int fd;
+ sprintf(fn, "%s%s.EXE", dir, f);
+ if((fd = open(fn, O_RDONLY))<0)
+ return false;
+ close(fd);
+ return true;
+}
+
+static bool isIcon(const char *fn)
+{
+ int l = strlen(fn);
+ if(l>4 && !strcasecmp(fn+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)
+{
+ icon.load(NULL, 0);
+}
+
+static int findGames(GameDetector *d, Game *games, int max)
+{
+ Dir *dirs = new Dir[MAX_DIR];
+ int curr_game = 0, curr_dir = 0, num_dirs = 1;
+ strcpy(dirs[0].name, "/");
+ while(curr_game < max && curr_dir < num_dirs) {
+ dirs[curr_dir].deficon[0] = '\0';
+ DIR *dirp = opendir(dirs[curr_dir++].name);
+ if(dirp) {
+ struct dirent *entry;
+ while((entry = readdir(dirp)))
+ if(entry->d_size < 0) {
+ if(num_dirs < MAX_DIR) {
+ strcpy(dirs[num_dirs].name, dirs[curr_dir-1].name);
+ if(strlen(dirs[num_dirs].name)+strlen(entry->d_name)<255) {
+ strcat(dirs[num_dirs].name, entry->d_name);
+ strcat(dirs[num_dirs].name, "/");
+ num_dirs++;
+ }
+ }
+ } else
+ if(isIcon(entry->d_name))
+ strcpy(dirs[curr_dir-1].deficon, entry->d_name);
+ else if(curr_game < max &&
+ isGame(entry->d_name, games[curr_game].filename_base)) {
+ strcpy(games[curr_game].dir, dirs[curr_dir-1].name);
+ if(!*games[curr_game].filename_base) {
+ int i;
+ for(i=strlen(games[curr_game].dir)-1; --i>=0; )
+ if(games[curr_game].dir[i]=='/')
+ break;
+ if(i>=0) {
+ strcpy(games[curr_game].filename_base,
+ games[curr_game].dir+i+1);
+ games[curr_game].filename_base[strlen(games[curr_game].
+ filename_base)-1]='\0';
+#if 0
+ games[curr_game].dir[i+1]='\0';
+#endif
+ }
+ if(checkExe(games[curr_game].dir, "loom"))
+ strcpy(games[curr_game].filename_base, "loomcd");
+ }
+ checkName(d, games[curr_game]);
+#if 0
+ printf("Registered game <%s> in <%s> <%s> because of <%s> <%s>\n",
+ games[curr_game].text, games[curr_game].dir,
+ games[curr_game].filename_base,
+ dirs[curr_dir-1].name, entry->d_name);
+#endif
+ curr_game++;
+ }
+ closedir(dirp);
+ }
+ }
+ 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.set_palette(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[selector_pos], 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(GameDetector *d, 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(d, 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("/");
+ static char dirarg[258];
+ sprintf(dirarg, "-p%s", the_game.dir);
+ dir_ret = dirarg;
+#endif
+ ret = the_game.filename_base;
+ icon = the_game.icon;
+ return true;
+ } else
+ return false;
+}
diff --git a/backends/dc/vmsave.cpp b/backends/dc/vmsave.cpp
new file mode 100644
index 0000000000..34bf2e40fa
--- /dev/null
+++ b/backends/dc/vmsave.cpp
@@ -0,0 +1,266 @@
+/* ScummVM - Scumm Interpreter
+ * Dreamcast port
+ * Copyright (C) 2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+#include "scumm.h"
+#include "mididrv.h"
+#include "gameDetector.h"
+#include "dc.h"
+#include "icon.h"
+#include "saveload.h"
+
+#include <ronin/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 vmsaveResult trySave(GameDetector *d, 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);
+ char *game_name = d->getGameName();
+ strncpy(header.longdesc, game_name, 32);
+ free(game_name);
+ 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;
+ return false;
+}
+
+vmsaveResult writeSaveGame(GameDetector *d, const char *data, int size,
+ const char *filename, class Icon &icon)
+{
+ vmsaveResult r, res = VMSAVE_NOVM;
+
+ if(lastvm >= 0 &&
+ (res = trySave(d, data, size, filename, icon, lastvm)) == VMSAVE_OK)
+ return res;
+
+ for(int i=0; i<24; i++)
+ if((r = trySave(d, 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;
+}
+
+
+struct vmStreamContext {
+ bool issave;
+ char *buffer;
+ int pos, size;
+ char filename[16];
+};
+
+bool SerializerStream::fopen(const char *filename, const char *mode)
+{
+ vmStreamContext *c = new vmStreamContext;
+ context = c;
+ if(strchr(mode, 'w')) {
+ c->issave = true;
+ strncpy(c->filename, filename, 16);
+ c->pos = 0;
+ c->buffer = new char[c->size = MAX_SAVE_SIZE];
+ return true;
+ } else if(readSaveGame(c->buffer, c->size, filename)) {
+ if(c->size > 0 && c->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*)c->buffer, c->size)) {
+ delete(c->buffer);
+ c->buffer = expbuf;
+ c->size = destlen;
+ } else delete expbuf;
+ }
+ c->issave = false;
+ c->pos = 0;
+ return true;
+ } else {
+ delete c;
+ context = NULL;
+ return false;
+ }
+}
+
+void SerializerStream::fclose()
+{
+ extern GameDetector detector;
+ extern Icon icon;
+
+ if(context) {
+ vmStreamContext *c = (vmStreamContext *)context;
+ if(c->issave) {
+ if(c->pos) {
+ // Try compression
+ char *compbuf = new char[c->pos];
+ unsigned long destlen = c->pos;
+ if(!compress((Bytef*)compbuf, &destlen, (Bytef*)c->buffer, c->pos)) {
+ delete c->buffer;
+ c->buffer = compbuf;
+ c->pos = destlen;
+ } else delete compbuf;
+ }
+ writeSaveGame(&detector, c->buffer, c->pos,
+ c->filename, icon);
+ }
+ delete c->buffer;
+ delete c;
+ context = NULL;
+ }
+}
+
+int SerializerStream::fread(void *buf, int size, int cnt)
+{
+ vmStreamContext *c = (vmStreamContext *)context;
+
+ if (!c || c->issave)
+ return -1;
+
+ int nbyt = size*cnt;
+ if (c->pos + nbyt > c->size) {
+ cnt = (c->size - c->pos)/size;
+ nbyt = size*cnt;
+ }
+ if (nbyt)
+ memcpy(buf, c->buffer + c->pos, nbyt);
+ c->pos += nbyt;
+ return cnt;
+}
+
+int SerializerStream::fwrite(void *buf, int size, int cnt)
+{
+ vmStreamContext *c = (vmStreamContext *)context;
+
+ if (!c || !c->issave)
+ return -1;
+
+ int nbyt = size*cnt;
+ if (c->pos + nbyt > c->size) {
+ cnt = (c->size - c->pos)/size;
+ nbyt = size*cnt;
+ }
+ if (nbyt)
+ memcpy(c->buffer + c->pos, buf, nbyt);
+ c->pos += nbyt;
+ return cnt;
+}
+