diff options
author | Marcus Comstedt | 2006-06-30 20:21:42 +0000 |
---|---|---|
committer | Marcus Comstedt | 2006-06-30 20:21:42 +0000 |
commit | 25f68b08ab8c1fc35aab2d060b0f38ebf7856785 (patch) | |
tree | 7a5847167a031aaa1eaeb6e3cb1a5bd8e8161330 /backends/platform/dc | |
parent | 8c5ead1f70ec3bb49e6633af0192bbcc90f4a1bf (diff) | |
download | scummvm-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')
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(); +} |