diff options
author | Peter Moraliyski | 2002-11-30 15:34:37 +0000 |
---|---|---|
committer | Peter Moraliyski | 2002-11-30 15:34:37 +0000 |
commit | f9a833abf01109021bc5f73521685263882dd017 (patch) | |
tree | 9818aa7a0d2b461a60107899b104619ef7ddf073 /backends | |
parent | ae7310ff28d2e7db6496a1869ed5a3119f5d4567 (diff) | |
download | scummvm-rg350-f9a833abf01109021bc5f73521685263882dd017.tar.gz scummvm-rg350-f9a833abf01109021bc5f73521685263882dd017.tar.bz2 scummvm-rg350-f9a833abf01109021bc5f73521685263882dd017.zip |
fg
svn-id: r5759
Diffstat (limited to 'backends')
-rw-r--r-- | backends/gp32/build.rules | 35 | ||||
-rw-r--r-- | backends/gp32/dirent.h | 52 | ||||
-rw-r--r-- | backends/gp32/emudebug.cpp | 328 | ||||
-rw-r--r-- | backends/gp32/emudebug.txt | 35 | ||||
-rw-r--r-- | backends/gp32/gp32.cpp | 1555 | ||||
-rw-r--r-- | backends/gp32/gp32.h | 203 | ||||
-rw-r--r-- | backends/gp32/gpdebug.c | 125 | ||||
-rw-r--r-- | backends/gp32/gpdebug.h | 49 | ||||
-rw-r--r-- | backends/gp32/gpregs.h | 69 | ||||
-rw-r--r-- | backends/gp32/gpsdl.h | 82 | ||||
-rw-r--r-- | backends/gp32/portdefs.h | 78 | ||||
-rw-r--r-- | backends/gp32/readme.txt | 29 | ||||
-rw-r--r-- | backends/gp32/stat.h | 23 |
13 files changed, 2663 insertions, 0 deletions
diff --git a/backends/gp32/build.rules b/backends/gp32/build.rules new file mode 100644 index 0000000000..10a83ea6f2 --- /dev/null +++ b/backends/gp32/build.rules @@ -0,0 +1,35 @@ +# Makefile for GP32 development using devkitadv under Win32 +# Written 2002 by Christian Nowak <chnowak@web.de> +# Modified by ph0x (ph0x@freemail.hu) + +# devkitadv base dir +CCBASE=c:/devkitadv + +CXX = $(CCBASE)/bin/g++ +CFLAGS = -mcpu=arm9tdmi \ + -mtune=arm9tdmi \ + -mapcs \ + -O2 \ + -fomit-frame-pointer \ + -finline-functions \ + -fno-exceptions \ + -fno-common \ + -fno-builtin \ + -fshort-enums \ + -ffast-math \ + -fshort-double \ + -fallow-single-precision \ + -ffreestanding \ + -fexpensive-optimizations \ + -mstructure-size-boundary=32 \ + -mno-thumb-interwork \ + -I$(CCBASE)/arm-agb-elf/include/gp32 \ + -Wno-multichar + +DEFINES = -D__GP32__ -DNONSTANDARD_PORT +LNKSCRIPT =$(CCBASE)/arm-agb-elf/lib/lnkscript +LDFLAGS = -Wl,-T $(LNKSCRIPT) +LIBS += -lgpgraphic -lgpmem -lgpos -lgpstdlib -lgpstdio -lgpsound -lgpfont +INCLUDES += -Ibackends/gp32 +MODULES += backends/gp32 +OBJS += $(CCBASE)/arm-agb-elf/lib/gpstart/gpstart.o backends/gp32/gp32.o backends/gp32/gpdebug.o
\ No newline at end of file diff --git a/backends/gp32/dirent.h b/backends/gp32/dirent.h new file mode 100644 index 0000000000..82dd0b2ee7 --- /dev/null +++ b/backends/gp32/dirent.h @@ -0,0 +1,52 @@ +/* Header is not present in Windows CE SDK */ +/* It would not be a bad idea to take this thing from gcc distro and port + it properly. For now only required part is ported. */ + +struct dirent +{ + long d_ino; /* Always zero. */ + unsigned short d_reclen; /* Always zero. */ + unsigned short d_namlen; /* Length of name in d_name. */ + char* d_name; /* File name. */ + /* NOTE: The name in the dirent structure points to the name in the + * finddata_t structure in the DIR. */ +}; + +/* + * This is an internal data structure. Good programmers will not use it + * except as an argument to one of the functions below. + */ +typedef struct +{ + /* disk transfer area for this dir */ +/* struct _finddata_t dd_dta; */ + + /* dirent struct to return from dir (NOTE: this makes this thread + * safe as long as only one thread uses a particular DIR struct at + * a time) */ + struct dirent dd_dir; + + /* _findnext handle */ + long dd_handle; + + /* + * Status of search: + * 0 = not started yet (next entry to read is first entry) + * -1 = off the end + * positive = 0 based index of next entry + */ + short dd_stat; + + /* given path for dir with search pattern (struct is extended) */ + char dd_name[1]; +} DIR; + + +DIR* opendir (const char*); +struct dirent* readdir (DIR*); +int closedir (DIR*); +/* +void rewinddir (DIR*); +long telldir (DIR*); +void seekdir (DIR*, long); +*/ diff --git a/backends/gp32/emudebug.cpp b/backends/gp32/emudebug.cpp new file mode 100644 index 0000000000..2d561af6c9 --- /dev/null +++ b/backends/gp32/emudebug.cpp @@ -0,0 +1,328 @@ +////////////////////////////////////////////////////////////////////////////// +// emudebug.cpp // +////////////////////////////////////////////////////////////////////////////// +/* + EmuDebug by Rafael Vuijk (aka Dark Fader) + + see emudebug.txt for more info +*/ + +////////////////////////////////////////////////////////////////////////////// +// Includes // +////////////////////////////////////////////////////////////////////////////// +#include <windows.h> +#include <stdio.h> +#include <conio.h> + +////////////////////////////////////////////////////////////////////////////// +// Pragmas // +////////////////////////////////////////////////////////////////////////////// +#pragma comment(lib, "user32") + +////////////////////////////////////////////////////////////////////////////// +// Defines // +////////////////////////////////////////////////////////////////////////////// +#define VER "1.02" + +////////////////////////////////////////////////////////////////////////////// +// Variables // +////////////////////////////////////////////////////////////////////////////// +// set in InitDebug +HWND hDebugWnd = 0; +HWND hEmuWnd = 0; +HANDLE hProcess = 0; + +// set in ScanBuffer +void *debugBufferBeginAddr = 0; +void *debugBufferEndAddr = 0; +void *debugBufferDataAddr = 0; +int debugBufferDataSize = 0; +char *debugBufferData = 0; // temp. data + +// default options +int minDebugBufferSize = 31; +int maxDebugBufferSize = 16*1024; +int pollInterval = 10; +int priorityClass = NORMAL_PRIORITY_CLASS; +char windowClass[256] = "BOYCOTTADVANCE"; // :) +char windowTitle[256] = "BoycottAdvance - "; +bool waitForKey = false; + +////////////////////////////////////////////////////////////////////////////// +// InitDebug // +////////////////////////////////////////////////////////////////////////////// +int InitDebug() +{ + // minimize debug window + //ShowWindow(hDebugWnd, SW_MINIMIZE); //ph0x + +restart: + printf("Searching debugging target..."); + + char *pWindowClass = windowClass[0] ? windowClass : 0; + char *pWindowTitle = windowTitle[0] ? windowTitle : 0; + + // loop + while (1) + { + hEmuWnd = FindWindow(pWindowClass, pWindowTitle); + //if (!hEmuWnd) { printf("Can't find window!\n"); return -1; } + if (hEmuWnd) break; + + if (kbhit() && (getch() == 27)) return -1; // abort? + Sleep(20); + } + + DWORD processId = 0; + GetWindowThreadProcessId(hEmuWnd, &processId); + if (!processId) { printf("Can't get process ID!\n"); return -1; } + + hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, processId); + if (!hProcess) { printf("Can't open process!\n"); return -1; } + + SetPriorityClass(hProcess, priorityClass); // set process priority class + + printf(" done.\n"); + + int bufferSize = 1*1024*1024; // start with 1MB or so + char *buffer = new char[bufferSize]; // temp ReadProcessMemory buffer + + if (!waitForKey) printf("Searching debug buffer..."); + + // loop + while (1) + { + if (waitForKey) + { + printf("Press any key to begin searching for debug buffer..."); + getch(); + printf("\n"); + printf("Searching debug buffer..."); + } + + DWORD exitCode; + if (!GetExitCodeProcess(hProcess, &exitCode)) { printf("\n"); goto restart; } + if (exitCode != STILL_ACTIVE) { printf("\n"); goto restart; } + + bool something = false; // some data found? + MEMORY_BASIC_INFORMATION mbi; + + unsigned int addr; + for (addr=0; VirtualQueryEx(hProcess, (void*)addr, &mbi, sizeof(mbi)); addr = (unsigned int)mbi.BaseAddress + mbi.RegionSize) + { + //printf("base=%08X, size=%d, protect=%08X, type=%08X\n", mbi.BaseAddress, mbi.RegionSize, mbi.Protect, mbi.Type); + if (mbi.Type == MEM_PRIVATE) // type=00020000 + if (mbi.Protect == PAGE_READWRITE) // protect=00000004 + { + if (mbi.RegionSize > bufferSize) + { + delete buffer; + bufferSize = mbi.RegionSize * 3/2; + buffer = new char[bufferSize]; + } + + if (ReadProcessMemory(hProcess, mbi.BaseAddress, buffer, mbi.RegionSize, NULL)) + { + something = true; + for (unsigned int i=0; i<mbi.RegionSize; i += minDebugBufferSize-2) + { + if (buffer[i] == ' ') // might be somewhere in the buffer + { + //printf("scan left\n"); + // scan to left + int left = i; + while (buffer[left] == ' ') if (--left <= 0) { continue; } // nothing left + if (buffer[left] != '{') { continue; } // nope, wrong start + + //printf("scan right\n"); + // scan to right + int right = i; + while (buffer[right] == ' ') if (++right >= mbi.RegionSize) { i = right; continue; } // nothing left + if (buffer[right] != '}') { i = right; continue; } // nope, wrong end + + // alloc new temp. debug buffer with max debug buffer length + debugBufferDataSize = right - left + 1; + //printf("debugBufferDataSize = %d\n", debugBufferDataSize); + if ( + (debugBufferDataSize >= minDebugBufferSize) && // minimum size + (debugBufferDataSize <= maxDebugBufferSize) && // maximum size + (*(unsigned int *)(buffer + left - 8) == 0xEDEBEDEB) && // start + (*(unsigned int *)(buffer + left - 4) == 0xEDEBEDEB) // end + ) + { + // remember addresses + debugBufferBeginAddr = (void *)((int)mbi.BaseAddress + left - 8); + debugBufferEndAddr = (void *)((int)mbi.BaseAddress + left - 4); + debugBufferDataAddr = (void *)((int)mbi.BaseAddress + left - 0); + + // allocate temporary buffer + if (debugBufferData) delete debugBufferData; + debugBufferData = new char[debugBufferDataSize]; + + // start debugging + int n = 0; + WriteProcessMemory(hProcess, debugBufferBeginAddr, &n, sizeof(n), NULL); + WriteProcessMemory(hProcess, debugBufferEndAddr, &n, sizeof(n), NULL); + + // show done + printf(" done.\n"); + delete buffer; + + //printf("base=%08X, size=%d, protect=%08X, type=%08X\n", mbi.BaseAddress, mbi.RegionSize, mbi.Protect, mbi.Type); + + // do things to activate/show debugger + ShowWindow(hEmuWnd, SW_RESTORE); //ph0x + SetActiveWindow(hEmuWnd); //ph0x + SetForegroundWindow(hEmuWnd); //ph0x + FlashWindow(hDebugWnd, TRUE); + SetWindowPos(hDebugWnd, HWND_TOP, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE); + + return 0; // ok + } + } // ' ' + } // for + } // ReadProcessMemory + else + { + // can't read memory anymore + //printf("\n"); goto restart; + } + //printf("\n"); + } // type + } // for VirtualQueryEx + + if (waitForKey) printf("\n"); + + //if (!addr) { printf("\n"); goto restart; } // no VirtualQueryEx data + + //if (!something) { printf("\n"); goto restart; } // invalid process or something + + if (kbhit() && (getch() == 27)) break; // abort + Sleep(20); + } // while + + delete buffer; + + return -1; +} + +////////////////////////////////////////////////////////////////////////////// +// ShowHelp // +////////////////////////////////////////////////////////////////////////////// +void ShowHelp() +{ + printf("EmuDebug "VER" by Rafael Vuijk (aka Dark Fader)\n\n"); + printf("Flags:\n"); + printf(" -h -? Show this help.\n"); + printf(" -b Set emulator process to below priority class.\n"); + printf(" -i Set emulator process to idle priority class.\n"); + printf(" -p<n> Set polling interval in milliseconds.\n"); + printf(" -c[<n>] Window class name to find. Default: \"BOYCOTTADVANCE\".\n"); + printf(" You can use MS Spy++ or something to find this.\n"); + printf(" -t[<n>] Window title name to find. Default: \"BoycottAdvance - \".\n"); + printf(" -s<n> Set mininum debug buffer size to look for.\n"); + printf(" -k Wait for a key to commence searching.\n"); + printf("\n"); + printf("Some 'good' working examples:\n"); + printf(" emudebug -i -p100 -s127\n"); + printf(" emudebug -p20 -k -b -c\"\" -t\"VGBA-Windows 1.1r\" -s63\n"); +} + +////////////////////////////////////////////////////////////////////////////// +// main // +////////////////////////////////////////////////////////////////////////////// +int main(int argc, char *argv[]) +{ + // check parameters + for (int a=1; a<argc; a++) + { + if (argv[a][0] == '-') + switch (argv[a][1]) + { + case 'h': case '?': ShowHelp(); return 0; + case 'i': priorityClass = IDLE_PRIORITY_CLASS; break; + //case 'b': priorityClass = BELOW_NORMAL_PRIORITY_CLASS; break; //ph0x + case 'p': pollInterval = strtoul(argv[a]+2, NULL, 0); break; + case 'c': strcpy(windowClass, argv[a]+2); break; + case 't': strcpy(windowTitle, argv[a]+2); break; + case 's': minDebugBufferSize = strtoul(argv[a]+2, NULL, 0); break; + case 'k': waitForKey = true; break; + default: printf("Unknown uption: %c\n", argv[a][1]); break; + } + } + + // find debug window + SetConsoleTitle("EmuDebug Console"); + hDebugWnd = FindWindow(NULL, "EmuDebug Console"); + + // search for debug buffer + if (InitDebug()) return -1; + + // do debug console + int boostPollInterval = pollInterval; + while (1) + { + // check keyboard input + if (kbhit()) + { + char c = getch(); + if (c == 27) // escape + { + // try to close emulator & minimize debug window + SendMessage(hEmuWnd, WM_CLOSE, 0, 0); + SendMessage(hDebugWnd, WM_CLOSE, 0, 0); //ph0x + //SetWindowPos(hDebugWnd, HWND_TOP, 0,0,0,0, SWP_HIDEWINDOW|SWP_NOMOVE|SWP_NOSIZE); + //ShowWindow(hDebugWnd, SW_MINIMIZE); //ph0x + } + } + + // get begin/end from debug buffer + int end = 0; + if (!ReadProcessMemory(hProcess, (void *)debugBufferEndAddr, &end, sizeof(end), NULL)) + { + // re-init debug after failure + if (InitDebug()) break; + continue; + } + + int begin = 0; + ReadProcessMemory(hProcess, (void *)debugBufferBeginAddr, &begin, sizeof(begin), NULL); + + // some data? + if (begin != end) + { + unsigned int nextBegin; + while (1) //begin != end) + { + int begin = end; + ReadProcessMemory(hProcess, (void *)debugBufferBeginAddr, &begin, sizeof(begin), NULL); + if (begin == end) break; // no more data + nextBegin = begin + 1; + if (nextBegin >= debugBufferDataSize) nextBegin = 0; + char c; + ReadProcessMemory(hProcess, (void *)((int)debugBufferDataAddr + begin), &c, 1, NULL); + putchar(c); + begin = nextBegin; + WriteProcessMemory(hProcess, debugBufferBeginAddr, &begin, sizeof(begin), NULL); + } + + // boost poll interval + boostPollInterval /= 2; + } + else + { + // slow down again + if (boostPollInterval == 0) boostPollInterval = 1; else boostPollInterval *= 2; + if (boostPollInterval > pollInterval) boostPollInterval = pollInterval; + } + + // poll interval + Sleep(boostPollInterval); + } + + // clean up + if (debugBufferData) delete debugBufferData; + CloseHandle(hProcess); + + return 0; +} diff --git a/backends/gp32/emudebug.txt b/backends/gp32/emudebug.txt new file mode 100644 index 0000000000..5bef9008fa --- /dev/null +++ b/backends/gp32/emudebug.txt @@ -0,0 +1,35 @@ +EmuDebug by Rafael Vuijk (aka Dark Fader) +Console debug output for emulators. +GBA apps must use the new debug library found in MyLib + +Usage +----- +Please run program with '-h' parameter to get possible options. + +How it works +------------ +1) PC searches the debug buffer in emulators memory. + begin & end init value is 0xEDEBEDEB, must reset to 0 to start debugging + data all spaces except first and last character, which are '{' & '}' +2) GBA waits for begin/end to become something else than init value +3) GBA reads any characters until begin & end index are equal again + +History +------- +v1.02 + minimizes window & pop-ups when debugging + escape closes emulator window + rotating buffer, so incompatable with older versions but who cares :) + +v1.01 + waits for emulator at startup + reconnects to new emulator instance + window class/title options + poll interval boosting + option for minimum buffersize + wait for key before searching option + +v1.00 + 'protocol' defined + searches buffer in Boycott Advance + console output diff --git a/backends/gp32/gp32.cpp b/backends/gp32/gp32.cpp new file mode 100644 index 0000000000..a2cb85ad38 --- /dev/null +++ b/backends/gp32/gp32.cpp @@ -0,0 +1,1555 @@ +/* + * ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001/2002 The ScummVM project + * Copyright (C) 2002 ph0x (GP32 port) + */ + +/* + TODO: + - replce constants (ie 320, 200) + - implement time() ? + - fix rgb macro in util.h + - implement save/load + - add music + - relative path + - kbd cursor + - error/warning + - shake + */ + +//#define GPDEBUG //uncomment for debug messages (use DarkFader's emudebug.exe) +#include "gp32.h" + +#define MARK printf("%s, %s, %d", __FUNCTION__, __FILE__, __LINE__) //ph0x +#define GP_RGB16(r,g,b) (((((r>>3))&0x1f)<<11)|((((g>>3))&0x1f)<<6)|((((b>>3))&0x1f)<<1)) +void GpSetPaletteEntry(u8 i, u8 r, u8 g, u8 b); + +#define GAME_SURFACE 0 +#define NAMEME_SURFACE 1 +#define DEBUG_SURFACE 2 + +GPDRAWSURFACE gpDraw[2]; // surfaces +int mx=1, my=1; // wrong if 0? +char currsurface; + +// Set colors of the palette +void OSystem_GP32::set_palette(const byte *colors, uint start, uint num) { + const byte *b = colors; + uint i; + SDL_Color *base = _currentPalette + start; + for(i = 0; i < num; i++) { + base[i].r = b[0]; + base[i].g = b[1]; + base[i].b = b[2]; + b += 4; + } + + if (start < _paletteDirtyStart) + _paletteDirtyStart = start; + + if (start + num > _paletteDirtyEnd) + _paletteDirtyEnd = start + num; +} + +// Set the size of the video bitmap. +// Typically, 320x200 +void OSystem_GP32::init_size(uint w, uint h) { + // Avoid redundant res changes + if ((int)w == _screenWidth && (int)h == _screenHeight) + return; + + _screenWidth = w; + _screenHeight = h; + CKSUM_NUM = (_screenWidth*_screenHeight/(8*8)); + if (_dirty_checksums) + free(_dirty_checksums); + _dirty_checksums = (uint32*)calloc(CKSUM_NUM*2, sizeof(uint32)); + + unload_gfx_mode(); + load_gfx_mode(); + +} + +void OSystem_GP32::add_dirty_rect(int x, int y, int w, int h) { + if (_forceFull) + return; + + if (_num_dirty_rects == NUM_DIRTY_RECT) + _forceFull = true; + else { + SDL_Rect *r = &_dirty_rect_list[_num_dirty_rects++]; + + // Extend the dirty region by 1 pixel for scalers + // that "smear" the screen, e.g. 2xSAI + if (_mode_flags & DF_UPDATE_EXPAND_1_PIXEL) { + x--; + y--; + w+=2; + h+=2; + } + + // clip + if (x < 0) { w+=x; x=0; } + if (y < 0) { h+=y; y=0; } + if (w > _screenWidth-x) { w = _screenWidth - x; } + if (h > _screenHeight-y) { h = _screenHeight - y; } + + r->x = x; + r->y = y; + r->w = w; + r->h = h; + } +} + +#define ROL(a,n) a = (a<<(n)) | (a>>(32-(n))) +#define DOLINE(x) a ^= ((uint32*)buf)[0+(x)*(_screenWidth/4)]; b ^= ((uint32*)buf)[1+(x)*(_screenWidth/4)] +void OSystem_GP32::mk_checksums(const byte *buf) { + uint32 *sums = _dirty_checksums; + uint x,y; + const uint last_x = (uint)_screenWidth/8; + const uint last_y = (uint)_screenHeight/8; + + /* the 8x8 blocks in buf are enumerated starting in the top left corner and + * reading each line at a time from left to right */ + for(y=0; y != last_y; y++, buf+=_screenWidth*(8-1)) + for(x=0; x != last_x; x++, buf+=8) { + uint32 a = x; + uint32 b = y; + + DOLINE(0); ROL(a,13); ROL(b,11); + DOLINE(2); ROL(a,13); ROL(b,11); + DOLINE(4); ROL(a,13); ROL(b,11); + DOLINE(6); ROL(a,13); ROL(b,11); + + a*=0xDEADBEEF; + b*=0xBAADF00D; + + DOLINE(1); ROL(a,13); ROL(b,11); + DOLINE(3); ROL(a,13); ROL(b,11); + DOLINE(5); ROL(a,13); ROL(b,11); + DOLINE(7); ROL(a,13); ROL(b,11); + + /* output the checksum for this block */ + *sums++=a+b; + } +} +#undef DOLINE +#undef ROL + + +void OSystem_GP32::add_dirty_rgn_auto(const byte *buf) { + assert( ((uint32)buf & 3) == 0); + + /* generate a table of the checksums */ + mk_checksums(buf); + + if (!cksum_valid) { + _forceFull = true; + cksum_valid = true; + } + + /* go through the checksum list, compare it with the previous checksums, + and add all dirty rectangles to a list. try to combine small rectangles + into bigger ones in a simple way */ + if (!_forceFull) { + int x,y,w; + uint32 *ck = _dirty_checksums; + + for(y=0; y!=_screenHeight/8; y++) { + for(x=0; x!=_screenWidth/8; x++,ck++) { + if (ck[0] != ck[CKSUM_NUM]) { + /* found a dirty 8x8 block, now go as far to the right as possible, + and at the same time, unmark the dirty status by setting old to new. */ + w=0; + do { + ck[w+CKSUM_NUM] = ck[w]; + w++; + } while (x+w != _screenWidth/8 && ck[w] != ck[w+CKSUM_NUM]); + + add_dirty_rect(x*8, y*8, w*8, 8); + + if (_forceFull) + goto get_out; + } + } + } + } else { + get_out:; + /* Copy old checksums to new */ + memcpy(_dirty_checksums + CKSUM_NUM, _dirty_checksums, CKSUM_NUM * sizeof(uint32)); + } +} + +// Draw a bitmap to screen. +// The screen will not be updated to reflect the new bitmap +void OSystem_GP32::copy_rect(const byte *buf, int pitch, int x, int y, int w, int h) { + if (_screen == NULL) + return; + + if (pitch == _screenWidth && x==0 && y==0 && w==_screenWidth && h==_screenHeight && _mode_flags&DF_WANT_RECT_OPTIM) { + /* Special, optimized case for full screen updates. + * It tries to determine what areas were actually changed, + * and just updates those, on the actual display. */ + add_dirty_rgn_auto(buf); + } else { + /* Clip the coordinates */ + if (x < 0) { w+=x; buf-=x; x = 0; } + if (y < 0) { h+=y; buf-=y*pitch; y = 0; } + if (w > _screenWidth-x) { w = _screenWidth - x; } + if (h > _screenHeight-y) { h = _screenHeight - y; } + + if (w <= 0 || h <= 0) + return; + + cksum_valid = false; + add_dirty_rect(x, y, w, h); + } + + /* FIXME: undraw mouse only if the draw rect intersects with the mouse rect */ + if (_mouseDrawn) + undraw_mouse(); + + ///if (SDL_LockSurface(_screen) == -1) + /// error("SDL_LockSurface failed: %s.\n", SDL_GetError()); + + byte *dst = (byte *)_screen->pixels + y * _screenWidth + x; + do { + memcpy(dst, buf, w); + dst += _screenWidth; + buf += pitch; + } while (--h); + + ///SDL_UnlockSurface(_screen); +} + + +SDL_Surface *SDL_CreateRGBSurface + (Uint32 flags, int width, int height, int depth, + Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask) { + + SDL_Surface *surf = (SDL_Surface*)malloc(sizeof(SDL_Surface)); + surf->format = (SDL_PixelFormat*)malloc(sizeof(SDL_PixelFormat)); + + if ((flags & SDL_HWSURFACE) == SDL_HWSURFACE) { + error(">HW surface (w=%d, h=%d)", width, height); + } else + if ((flags & SDL_SWSURFACE) == SDL_SWSURFACE) { + int size=width*height*(depth/8); + printf(">SW surface (w=%d, h=%d, size=%d, depth=%d)", width, height, size, depth); + surf->pixels = malloc(size); + } else { + error(">unknown surface", width, height); + return NULL; + } + surf->w=width; + surf->h=height; + surf->pitch=width*(depth/8); + surf->format->BitsPerPixel=depth; + surf->format->BytesPerPixel=depth/8; + return surf; +} + +SDL_Surface *SDL_SetVideoMode + (int width, int height, int bpp, Uint32 flags) { + + return SDL_CreateRGBSurface(flags, width, height, bpp, 0, 0, 0, 0); +} + +void SDL_FreeSurface(SDL_Surface *surface) { + // implement +} + +SDL_Surface *SDL_CreateRGBSurfaceFrom(void *pixels, + int width, int height, int depth, int pitch, + Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask) { + +// FIXME dont reuse code + + SDL_Surface *surf = (SDL_Surface*)malloc(sizeof(SDL_Surface)); + surf->format = (SDL_PixelFormat*)malloc(sizeof(SDL_PixelFormat)); + + surf->w=width; + surf->h=height; + surf->pitch=pitch; + surf->pixels=pixels; + surf->format->BitsPerPixel=depth; + surf->format->BytesPerPixel=depth/8; + return surf; +} + +int SDL_FillRect + (SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color) { + + // implement + return 0; +} + + +void SDL_UpdateRects(SDL_Surface *screen, int numrects, SDL_Rect *rects) { + + // FIXME dont duplicate code :) + + if (screen->format->BitsPerPixel==8) + while (numrects--) { + u8 *s=(u8*)((u8*)screen->pixels+rects->y*320+rects->x); + u8 *d=(u8*)((u8*)gpDraw[GAME_SURFACE].ptbuffer+rects->x*240+239-rects->y); + u8 *s2=s, *d2=d; + + for (int x=rects->w; x; x--) { + for (int y=rects->h; y; y--) { + *d--=*s; + s+=320; // FIXME? screen->pitch; + } + d2+=240; + d=d2; + s2++; + s=s2; + } + rects++; + } + else + if (screen->format->BitsPerPixel==16) + while (numrects--) { + u16 *s=(u16*)((u16*)screen->pixels+rects->y*320+rects->x); + u16 *d=(u16*)((u16*)gpDraw[GAME_SURFACE].ptbuffer+rects->x*240+239-rects->y); + u16 *s2=s, *d2=d; + + for (int x=rects->w; x; x--) { + for (int y=rects->h; y; y--) { + *d--=*s; + s+=320; // FIXME? screen->pitch; + } + d2+=240; + d=d2; + s2++; + s=s2; + } + rects++; + } + else error("blitting surface with wrong depth (%d)", screen->format->BitsPerPixel); + // eh? works also when rects++ is here?? +} + +//#define SDL_BlitSurface SDL_UpperBlit +int SDL_BlitSurface(SDL_Surface *screen, SDL_Rect *rects, + SDL_Surface *dst, SDL_Rect *dstrect) { + + // FIXME? role?? + //SDL_UpdateRects(screen, 1, rects); //ph0x! sdl_hwscreen + return 0; +} + +int SDL_SetColors(SDL_Surface *surface, SDL_Color *colors, int firstcolor, int ncolors) { + if (currsurface == DEBUG_SURFACE) return 1; + + GpPaletteEntryChangeEx(firstcolor, ncolors, (GP_LOGPALENTRY*)colors, 0); + return 1; +} + +// Moves the screen content around by the given amount of pixels +// but only the top height pixel rows, the rest stays untouched +void OSystem_GP32::move_screen(int dx, int dy, int height) { + if ((dx == 0) && (dy == 0)) + return; + + if (dx == 0) { + // vertical movement + if (dy > 0) { + // move down + // copy from bottom to top + for (int y = height - 1; y >= dy; y--) + copy_rect((byte *)_screen->pixels + _screenWidth * (y - dy), _screenWidth, 0, y, _screenWidth, 1); + } else { + // move up + // copy from top to bottom + for (int y = 0; y < height + dx; y++) + copy_rect((byte *)_screen->pixels + _screenWidth * (y - dy), _screenWidth, 0, y, _screenWidth, 1); + } + } else if (dy == 0) { + // horizontal movement + if (dx > 0) { + // move right + // copy from right to left + for (int x = _screenWidth - 1; x >= dx; x--) + copy_rect((byte *)_screen->pixels + x - dx, _screenWidth, x, 0, 1, height); + } else { + // move left + // copy from left to right + for (int x = 0; x < _screenWidth; x++) + copy_rect((byte *)_screen->pixels + x - dx, _screenWidth, x, 0, 1, height); + } + } else { + // free movement + // not neccessary for now + } +} + +void OSystem_GP32::load_gfx_mode() { + + GpRectFill(NULL,&gpDraw[GAME_SURFACE], 0, 0, 320, 240, 0); //black border + + _forceFull = true; + _mode_flags = DF_WANT_RECT_OPTIM | DF_UPDATE_EXPAND_1_PIXEL; + + sdl_tmpscreen = NULL; + TMP_SCREEN_WIDTH = (_screenWidth + 3); + + switch(_mode) { + + case GFX_NORMAL: +normal_mode:; + _scaleFactor = 1; + _scaler_proc = Normal1x; + break; + default: + error("unknown gfx mode"); + _scaleFactor = 1; + _scaler_proc = NULL; + } + + // + // Create the surface that contains the 8 bit game data + // + _screen = SDL_CreateRGBSurface(SDL_SWSURFACE, _screenWidth, _screenHeight, 8, 0, 0, 0, 0); + if (_screen == NULL) + error("_screen failed"); + + + // + // Create the surface that contains the scaled graphics in 16 bit mode + // + sdl_hwscreen = SDL_SetVideoMode(_screenWidth * _scaleFactor, _screenHeight * _scaleFactor, 16, + _full_screen ? (SDL_FULLSCREEN|SDL_SWSURFACE) : SDL_SWSURFACE + ); + if (sdl_hwscreen == NULL) + error("sdl_hwscreen failed"); + + // + // Create the surface used for the graphics in 16 bit before scaling, and also the overlay + // + +/* + // Distinguish 555 and 565 mode + if (sdl_hwscreen->format->Rmask == 0x7C00) + Init_2xSaI(555); + else + Init_2xSaI(565); +*/ + //Init_2xSaI(555); // ph0x fixme? + + //ph0x fixme - tmpscreen needed? + // Need some extra bytes around when using 2xSaI + uint16 *tmp_screen = (uint16*)calloc(TMP_SCREEN_WIDTH*(_screenHeight+3),sizeof(uint16)); + sdl_tmpscreen = SDL_CreateRGBSurfaceFrom(tmp_screen, + TMP_SCREEN_WIDTH, _screenHeight + 3, 16, TMP_SCREEN_WIDTH*2, + sdl_hwscreen->format->Rmask, + sdl_hwscreen->format->Gmask, + sdl_hwscreen->format->Bmask, + sdl_hwscreen->format->Amask); + + if (sdl_tmpscreen == NULL) + error("sdl_tmpscreen failed"); + + + // keyboard cursor control, some other better place for it? + km.x_max = _screenWidth * _scaleFactor - 1; + km.y_max = _screenHeight * _scaleFactor - 1; + km.delay_time = 25; + km.last_time = 0; + +} + +void OSystem_GP32::unload_gfx_mode() { + if (_screen) { + SDL_FreeSurface(_screen); + _screen = NULL; + } + + if (sdl_hwscreen) { + SDL_FreeSurface(sdl_hwscreen); + sdl_hwscreen = NULL; + } + + if (sdl_tmpscreen) { + free((uint16*)sdl_tmpscreen->pixels); + SDL_FreeSurface(sdl_tmpscreen); + sdl_tmpscreen = NULL; + } +} + + +#include "common/util.h" +void OSystem_GP32::draw_mouse() { + if (!_overlay_visible) { + + if (_mouseDrawn || !_mouseVisible) + return; + + int x = _mouse_cur_state.x - _mouseHotspotX; + int y = _mouse_cur_state.y - _mouseHotspotY; + int w = _mouse_cur_state.w; + int h = _mouse_cur_state.h; + byte color; + byte *src = _mouseData; // Image representing the mouse + byte *bak = _mouseBackup; // Surface used to backup the area obscured by the mouse + byte *dst; // Surface we are drawing into + + // clip the mouse rect, and addjust the src pointer accordingly + if (x < 0) { + w += x; + src -= x; + x = 0; + } + if (y < 0) { + h += y; + src -= y * _mouse_cur_state.w; + y = 0; + } + if (w > _screenWidth - x) + w = _screenWidth - x; + if (h > _screenHeight - y) + h = _screenHeight - y; + + // Quick check to see if anything has to be drawn at all + if (w <= 0 || h <= 0) + return; + + // Store the bounding box so that undraw mouse can restore the area the + // mouse currently covers to its original content. + _mouse_old_state.x = x; + _mouse_old_state.y = y; + _mouse_old_state.w = w; + _mouse_old_state.h = h; + + // Draw the mouse cursor; backup the covered area in "bak" + + ///if (SDL_LockSurface(_screen) == -1) + /// error("SDL_LockSurface failed: %s.\n", SDL_GetError()); + + // Mark as dirty + add_dirty_rect(x, y, w, h); + + dst = (byte *)_screen->pixels + y * _screenWidth + x; + while (h > 0) { + int width = w; + while (width > 0) { + *bak++ = *dst; + color = *src++; + if (color != 0xFF) // 0xFF = transparent, don't draw + *dst = color; + dst++; + width--; + } + src += _mouse_cur_state.w - w; + bak += MAX_MOUSE_W - w; + dst += _screenWidth - w; + h--; + } + + ///SDL_UnlockSurface(_screen); + + // Finally, set the flag to indicate the mouse has been drawn + _mouseDrawn = true; + } + + if (_mouseDrawn || !_mouseVisible) + return; + + int x = _mouse_cur_state.x - _mouseHotspotX; + int y = _mouse_cur_state.y - _mouseHotspotY; + int w = _mouse_cur_state.w; + int h = _mouse_cur_state.h; + byte color; + byte *src = _mouseData; // Image representing the mouse + uint16 *bak = (uint16*)_mouseBackup; // Surface used to backup the area obscured by the mouse + uint16 *dst; // Surface we are drawing into + + // clip the mouse rect, and addjust the src pointer accordingly + if (x < 0) { + w += x; + src -= x; + x = 0; + } + if (y < 0) { + h += y; + src -= y * _mouse_cur_state.w; + y = 0; + } + + // Quick check to see if anything has to be drawn at all + if (w <= 0 || h <= 0) + return; + + if (w > _screenWidth - x) + w = _screenWidth - x; + if (h > _screenHeight - y) + h = _screenHeight - y; + + // Store the bounding box so that undraw mouse can restore the area the + // mouse currently covers to its original content. + _mouse_old_state.x = x; + _mouse_old_state.y = y; + _mouse_old_state.w = w; + _mouse_old_state.h = h; + + // Draw the mouse cursor; backup the covered area in "bak" + + ///if (SDL_LockSurface(sdl_tmpscreen) == -1) + /// error("SDL_LockSurface failed: %s.\n", SDL_GetError()); + + // Mark as dirty + add_dirty_rect(x, y, w, h); + + dst = (uint16 *)sdl_tmpscreen->pixels + (y+1) * TMP_SCREEN_WIDTH + (x+1); + while (h > 0) { + int width = w; + while (width > 0) { + *bak++ = *dst; + color = *src++; + if (color != 0xFF) // 0xFF = transparent, don't draw + *dst = RGB_TO_16(_currentPalette[color].r, _currentPalette[color].g, _currentPalette[color].b); + dst++; + width--; + } + src += _mouse_cur_state.w - w; + bak += MAX_MOUSE_W - w; + dst += TMP_SCREEN_WIDTH - w; + h--; + } + + ///SDL_UnlockSurface(sdl_tmpscreen); + + // Finally, set the flag to indicate the mouse has been drawn + _mouseDrawn = true; +} + +void OSystem_GP32::undraw_mouse() { //return; //fixme! + if (!_overlay_visible) { + + if (!_mouseDrawn) + return; + _mouseDrawn = false; + + ///if (SDL_LockSurface(_screen) == -1) + /// error("SDL_LockSurface failed: %s.\n", SDL_GetError()); + + byte *dst, *bak = _mouseBackup; + const int old_mouse_x = _mouse_old_state.x; + const int old_mouse_y = _mouse_old_state.y; + const int old_mouse_w = _mouse_old_state.w; + const int old_mouse_h = _mouse_old_state.h; + int x, y; + + // No need to do clipping here, since draw_mouse() did that already + + dst = (byte *)_screen->pixels + old_mouse_y * _screenWidth + old_mouse_x; + for (y = 0; y < old_mouse_h; ++y, bak += MAX_MOUSE_W, dst += _screenWidth) { + for (x = 0; x < old_mouse_w; ++x) { + dst[x] = bak[x]; + } + } + + add_dirty_rect(old_mouse_x, old_mouse_y, old_mouse_w, old_mouse_h); + + ///SDL_UnlockSurface(_screen); + } + + if (!_mouseDrawn) + return; + _mouseDrawn = false; + + ///if (SDL_LockSurface(sdl_tmpscreen) == -1) + /// error("SDL_LockSurface failed: %s.\n", SDL_GetError()); + + uint16 *dst, *bak = (uint16 *)_mouseBackup; + const int old_mouse_x = _mouse_old_state.x; + const int old_mouse_y = _mouse_old_state.y; + const int old_mouse_w = _mouse_old_state.w; + const int old_mouse_h = _mouse_old_state.h; + int x, y; + + // No need to do clipping here, since draw_mouse() did that already + + dst = (uint16 *)sdl_tmpscreen->pixels + (old_mouse_y+1) * TMP_SCREEN_WIDTH + (old_mouse_x+1); + for (y = 0; y < old_mouse_h; ++y, bak += MAX_MOUSE_W, dst += TMP_SCREEN_WIDTH) { + for (x = 0; x < old_mouse_w; ++x) { + dst[x] = bak[x]; + } + } + + add_dirty_rect(old_mouse_x, old_mouse_y, old_mouse_w, old_mouse_h); + + ///SDL_UnlockSurface(sdl_tmpscreen); +} + +char * SDL_GetError(void) { + + // implement + return NULL; +} + +// Update the dirty areas of the screen +void OSystem_GP32::update_screen() { + assert(sdl_hwscreen != NULL); + + // If the shake position changed, fill the dirty area with blackness + if (_currentShakePos != _newShakePos) { + SDL_Rect blackrect = {0, 0, _screenWidth*_scaleFactor, _newShakePos*_scaleFactor}; + SDL_FillRect(sdl_hwscreen, &blackrect, 0); + + _currentShakePos = _newShakePos; + + _forceFull = true; + } + + // Make sure the mouse is drawn, if it should be drawn. + draw_mouse(); //ph0x + + // Check whether the palette was changed in the meantime and update the + // screen surface accordingly. + if (_paletteDirtyEnd != 0) { + SDL_SetColors(_screen, _currentPalette + _paletteDirtyStart, + _paletteDirtyStart, + _paletteDirtyEnd - _paletteDirtyStart); + + _paletteDirtyEnd = 0; + + _forceFull = true; + } + + // Force a full redraw if requested + if (_forceFull) { + _num_dirty_rects = 1; + + _dirty_rect_list[0].x = 0; + _dirty_rect_list[0].y = 0; + _dirty_rect_list[0].w = _screenWidth; + _dirty_rect_list[0].h = _screenHeight; + } + + // Only draw anything if necessary + if (_num_dirty_rects > 0) { + + SDL_Rect *r; + uint32 srcPitch, dstPitch; + SDL_Rect *last_rect = _dirty_rect_list + _num_dirty_rects; + + // Convert appropriate parts of the 8bpp image into 16bpp + if (!_overlay_visible) { + SDL_Rect dst; + for(r = _dirty_rect_list; r != last_rect; ++r) { + dst = *r; + dst.x++; // FIXME? Shift rect by one since 2xSai needs to acces the data around + dst.y++; // FIXME? any pixel to scale it, and we want to avoid mem access crashes. + if (SDL_BlitSurface(_screen, r, sdl_hwscreen, &dst) != 0) //ph0x! sdl_tmpscreen + error("SDL_BlitSurface failed: %s", SDL_GetError()); + } + } + + ///SDL_LockSurface(sdl_tmpscreen); + ///SDL_LockSurface(sdl_hwscreen); + +// ph0x! (no scaling) cannot skip intro if commented? + + srcPitch = sdl_tmpscreen->pitch; + dstPitch = sdl_hwscreen->pitch; + for(r = _dirty_rect_list; r != last_rect; ++r) { + register int dst_y = r->y + _currentShakePos; + register int dst_h = 0; + if (dst_y < _screenHeight) { + dst_h = r->h; + if (dst_h > _screenHeight - dst_y) + dst_h = _screenHeight - dst_y; + + dst_y *= _scaleFactor; + + _scaler_proc((byte*)sdl_tmpscreen->pixels + (r->x*2+2) + (r->y+1)*srcPitch, srcPitch, NULL, + (byte*)sdl_hwscreen->pixels + r->x*2*_scaleFactor + dst_y*dstPitch, dstPitch, r->w, dst_h); + } + r->x *= _scaleFactor; + r->y = dst_y; + r->w *= _scaleFactor; + r->h = dst_h * _scaleFactor; + } + + ///SDL_UnlockSurface(sdl_tmpscreen); + ///SDL_UnlockSurface(sdl_hwscreen); + + // Readjust the dirty rect list in case we are doing a full update. + // This is necessary if shaking is active. + if (_forceFull) { + _dirty_rect_list[0].y = 0; + _dirty_rect_list[0].h = _screenHeight * _scaleFactor; + } + + // Finally, blit all our changes to the screen + + // FIXME (dont use condition) + if (_overlay_visible) + SDL_UpdateRects(sdl_hwscreen, _num_dirty_rects, _dirty_rect_list); //ph0x! sdl_hwscreen + else + SDL_UpdateRects(_screen, _num_dirty_rects, _dirty_rect_list); + } + + _num_dirty_rects = 0; + _forceFull = false; +} + +// Either show or hide the mouse cursor +bool OSystem_GP32::show_mouse(bool visible) { + if (_mouseVisible == visible) + return visible; + + bool last = _mouseVisible; + _mouseVisible = visible; + + if (visible) + draw_mouse(); + else + undraw_mouse(); + + return last; +} + +// Set the position of the mouse cursor +void OSystem_GP32::set_mouse_pos(int x, int y) { + if (x != _mouse_cur_state.x || y != _mouse_cur_state.y) { + _mouse_cur_state.x = x; + _mouse_cur_state.y = y; + + mx=x; //ph0x fixme + my=y; //ph0x fixme + undraw_mouse(); + } +} + +// Set the bitmap that's used when drawing the cursor. +void OSystem_GP32::set_mouse_cursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y) { + _mouse_cur_state.w = w; + _mouse_cur_state.h = h; + + _mouseHotspotX = hotspot_x; + _mouseHotspotY = hotspot_y; + + _mouseData = (byte*)buf; + + undraw_mouse(); +} + +// Shaking is used in SCUMM. Set current shake position. +void OSystem_GP32::set_shake_pos(int shake_pos) { + _newShakePos = shake_pos; +} + +// Get the number of milliseconds since the program was started. +uint32 OSystem_GP32::get_msecs() { + return GpTickCountGet(); +} + +// Delay for a specified amount of milliseconds +void OSystem_GP32::delay_msecs(uint msecs) { + int n = GpTickCountGet(); + while ( ( GpTickCountGet() - n ) < msecs) ; +} + +// Create a thread +void* OSystem_GP32::create_thread(ThreadProc *proc, void *param) { return NULL;} + +// Get the next event. +// Returns true if an event was retrieved. + +bool OSystem_GP32::poll_event(Event *event) { // fixme: make more user-friendly :) + + #define EVENT_COUNT 2 // >=1 + #define MOUSE_MIPS 1 // bg updates wrong if >1 ?? + + static int oldkey, eventcount=EVENT_COUNT, lastevent=0; + int key; + + key=GpKeyGet(); + if (key == GPC_VK_NONE) { + if (lastevent==EVENT_LBUTTONDOWN) { + lastevent=0; + event->event_code = EVENT_LBUTTONUP; + return true; + } + return false; + } + + if (key == oldkey) { + eventcount--; + if (eventcount) return false; + } + oldkey=key; + eventcount=EVENT_COUNT; + + event->event_code = EVENT_KEYDOWN; + + if (key & GPC_VK_FL && key & GPC_VK_FR) { // L+R = save state + printf("Saving game, please wait..."); + + extern void autosave(void * engine); + autosave(NULL); //FIXME? + do key=GpKeyGet(); while (key != GPC_VK_NONE) ; + return false; + } else + + if(key & GPC_VK_FL) { // L = debug console + //GpGraphicModeSet(8, NULL); //FIXME: if 16bit? + currsurface=DEBUG_SURFACE; + GpSurfaceFlip(&gpDraw[currsurface]); + GpSetPaletteEntry ( 0, 0,0,0 ); + GpSetPaletteEntry ( 1, 255,0,0 ); + GpSetPaletteEntry ( 2, 255,255,255 ); + return false; + } else + + if (key & GPC_VK_FR) { // R = game screen + //if (_overlay_visible) GpGraphicModeSet(16, NULL); + // else GpGraphicModeSet(8, NULL); + currsurface=GAME_SURFACE; + GpSurfaceFlip(&gpDraw[currsurface]); + + _paletteDirtyStart=0; + _paletteDirtyEnd=255; //fixme? + return false; + } + + if(key & GPC_VK_START) { // START = menu + event->kbd.keycode = 319; + event->kbd.ascii = 319; + return true; + } + + if(key & GPC_VK_SELECT) { // SELECT == escape/skip + if (_overlay_visible) + do key=GpKeyGet(); while (key != GPC_VK_NONE) ; // prevent 2xESC + event->kbd.keycode = 27; + event->kbd.ascii = 27; + return true; + } + + if (key & GPC_VK_FA) { + lastevent=EVENT_LBUTTONDOWN; + event->event_code = EVENT_LBUTTONDOWN; + return true; + } + if (key & GPC_VK_FB) { + lastevent=EVENT_RBUTTONDOWN; + event->event_code = EVENT_RBUTTONDOWN; + return true; + } + + event->event_code = EVENT_MOUSEMOVE; + + if(key & GPC_VK_LEFT) { + mx-=MOUSE_MIPS; + if (mx<1) mx=1; // wrong if 0? + } + + if(key & GPC_VK_RIGHT) { + mx+=MOUSE_MIPS; + if (mx>319) mx=319; + } + + if(key & GPC_VK_UP) { + my-=MOUSE_MIPS; + if (my<1) my=1; // wrong if 0? + } + + if(key & GPC_VK_DOWN) { + my+=MOUSE_MIPS; + if (my>199) my=199; + } + + event->event_code = EVENT_MOUSEMOVE; + km.x = event->mouse.x = mx; + km.y = event->mouse.y = my; + + event->mouse.x /= _scaleFactor; + event->mouse.y /= _scaleFactor; +} + +// Set the function to be invoked whenever samples need to be generated +// Format is the sample type format. +// Only 16-bit signed mode is needed for simon & scumm +bool OSystem_GP32::set_sound_proc(void *param, SoundProc *proc, byte format) { + return false; +} + +void OSystem_GP32::get_screen_image(byte *buf) { + /* make sure the mouse is gone */ + undraw_mouse(); + + ///if (SDL_LockSurface(_screen) == -1) + /// error("SDL_LockSurface failed: %s.\n", SDL_GetError()); + + memcpy(buf, _screen->pixels, _screenWidth*_screenHeight); + + ///SDL_UnlockSurface(_screen); +} + +void OSystem_GP32::hotswap_gfx_mode() { + /* We allocate a screen sized bitmap which contains a "backup" + * of the screen data during the change. Then we draw that to + * the new screen right after it's setup. + */ + + byte *bak_mem = (byte*)malloc(_screenWidth*_screenHeight); + + get_screen_image(bak_mem); + + unload_gfx_mode(); + load_gfx_mode(); + + // reset palette + SDL_SetColors(_screen, _currentPalette, 0, 256); + + // blit image + copy_rect(bak_mem, _screenWidth, 0, 0, _screenWidth, _screenHeight); + free(bak_mem); + + update_screen(); +} + +// Get or set a property +uint32 OSystem_GP32::property(int param, Property *value) { + switch(param) { + + case PROP_GET_FULLSCREEN: + return _full_screen; + + case PROP_OPEN_CD: //fixme? + /*if (SDL_InitSubSystem(SDL_INIT_CDROM) == -1) + _cdrom = NULL; + else { + _cdrom = SDL_CDOpen(value->cd_num); + // Did if open? Check if _cdrom is NULL + if (!_cdrom) { + warning("Couldn't open drive: %s\n", SDL_GetError()); + } + }*/ + break; + + case PROP_SET_GFX_MODE: + if (value->gfx_mode >= 7) + return 0; + _mode = value->gfx_mode; + hotswap_gfx_mode(); + + return 1; + + case PROP_SHOW_DEFAULT_CURSOR: + ///SDL_ShowCursor(value->show_cursor ? SDL_ENABLE : SDL_DISABLE); //fixme? + break; + + case PROP_GET_SAMPLE_RATE: + ///return SAMPLES_PER_SEC; //ph0x fixme + return 22050; + } + + return 0; +} + +// Poll cdrom status +// Returns true if cd audio is playing +bool OSystem_GP32::poll_cdrom() { return false; } + +// Play cdrom audio track +void OSystem_GP32::play_cdrom(int track, int num_loops, int start_frame, int end_frame) { } + +// Stop cdrom audio track +void OSystem_GP32::stop_cdrom() { } + +// Update cdrom audio status +void OSystem_GP32::update_cdrom() { } + +// Add a new callback timer +void OSystem_GP32::set_timer(int timer, int (*callback)(int)) { } + +// Mutex handling +void* OSystem_GP32::create_mutex(void) { } +void OSystem_GP32::lock_mutex(void *mutex) { } +void OSystem_GP32::unlock_mutex(void *mutex) { } +void OSystem_GP32::delete_mutex(void *mutex) { } + +// Quit +void gphalt(int); +void OSystem_GP32::quit() { + gphalt(); +} + +// Overlay +void OSystem_GP32::show_overlay() { + // hide the mouse + + undraw_mouse(); + +u8* s=(u8*)_screen->pixels; +u16* d=(u16*)sdl_tmpscreen->pixels; +u8 c; +// convert to 16 bit +for (int y=0; y<200; y++) { + for (int x=0; x<320; x++) { + c=*s; + *d++ = (u16)GP_RGB16(_currentPalette[c].r, _currentPalette[c].g, _currentPalette[c].b); + s++; + } + d+=3; // tmpscreen width is screen+3 +} +GpGraphicModeSet(16, NULL); //ph0x +//GpRectFill(NULL,&gpDraw[GAME_SURFACE], 0, 0, 320, 240*2, 0); //black border + + _overlay_visible = true; + clear_overlay(); +} + +void OSystem_GP32::hide_overlay() { + // hide the mouse + undraw_mouse(); + +GpGraphicModeSet(8, NULL); //ph0x +GpRectFill(NULL,&gpDraw[GAME_SURFACE], 0, 200, 320, 40, 0); //black border + + _overlay_visible = false; + _forceFull = true; +} + +void OSystem_GP32::clear_overlay() { + if (!_overlay_visible) + return; + + // hide the mouse + undraw_mouse(); + + // Clear the overlay by making the game screen "look through" everywhere. + SDL_Rect src, dst; + src.x = src.y = 0; + dst.x = dst.y = 1; + src.w = dst.w = _screenWidth; + src.h = dst.h = _screenHeight; + if (SDL_BlitSurface(_screen, &src, sdl_tmpscreen, &dst) != 0) //FIXME + error("SDL_BlitSurface failed: %s", SDL_GetError()); + + _forceFull = true; +} + +void OSystem_GP32::grab_overlay(int16 *buf, int pitch) { + if (!_overlay_visible) + return; + + if (sdl_tmpscreen == NULL) + return; + + // hide the mouse + undraw_mouse(); + + ///if (SDL_LockSurface(sdl_tmpscreen) == -1) + /// error("SDL_LockSurface failed: %s.\n", SDL_GetError()); + + int16 *src = (int16 *)sdl_tmpscreen->pixels + TMP_SCREEN_WIDTH + 1; + int h = _screenHeight; + do { + memcpy(buf, src, _screenWidth*2); + src += TMP_SCREEN_WIDTH; + buf += pitch; + } while (--h); + + ///SDL_UnlockSurface(sdl_tmpscreen); +} + +void OSystem_GP32::copy_rect_overlay(const int16 *buf, int pitch, int x, int y, int w, int h) { + if (!_overlay_visible) + return; + + if (sdl_tmpscreen == NULL) + return; + + // Clip the coordinates + if (x < 0) { w+=x; buf-=x; x = 0; } + if (y < 0) { h+=y; buf-=y*pitch; y = 0; } + if (w > _screenWidth-x) { w = _screenWidth - x; } + if (h > _screenHeight-y) { h = _screenHeight - y; } + if (w <= 0 || h <= 0) + return; + + // Mark the modified region as dirty + cksum_valid = false; + add_dirty_rect(x, y, w, h); + + /* FIXME: undraw mouse only if the draw rect intersects with the mouse rect */ + undraw_mouse(); + + ///if (SDL_LockSurface(sdl_tmpscreen) == -1) + /// error("SDL_LockSurface failed: %s.\n", SDL_GetError()); + + int16 *dst = (int16 *)sdl_tmpscreen->pixels + (y+1) * TMP_SCREEN_WIDTH + (x+1); + do { + memcpy(dst, buf, w*2); + dst += TMP_SCREEN_WIDTH; + buf += pitch; + } while (--h); + + ///SDL_UnlockSurface(sdl_tmpscreen); +} + +OSystem *OSystem_GP32::create(int gfx_mode, bool full_screen) { + OSystem_GP32 *syst = new OSystem_GP32(); + + syst->_mode = gfx_mode; + syst->_full_screen = full_screen; + + // allocate palette storage + syst->_currentPalette = (SDL_Color*)calloc(sizeof(SDL_Color), 256); + + // allocate the dirty rect storage + syst->_mouseBackup = (byte*)malloc(MAX_MOUSE_W * MAX_MOUSE_H * MAX_SCALING * 2); + return syst; +} + +OSystem *OSystem_GP32_create(int gfx_mode, bool full_screen) { + return OSystem_GP32::create(gfx_mode, full_screen); // fullscreen +} + +////////////////////////////////////////////////// +// GP32 stuff +////////////////////////////////////////////////// + +extern "C" int write(int fd, void *p, size_t n); +int write(int fd, void *p, size_t n) { return 0; } //ph0x hack! + +// fixme - unnecessary? +int SerializerStream::fwrite(void *buf, int size, int cnt) { + // implement me + return ::fwrite(buf, size, cnt, (FILE*)context); +} + +bool SerializerStream::fopen(const char *filename, const char *mode) { + // implement me + (FILE*)context = ::fopen(filename, mode); + //if (tolower(mode[0])=='w') error("Autosaving.."); + return context != NULL; +} + +void SerializerStream::fclose() { + // implement me + ::fclose((FILE*)context); +} +int SerializerStream::fread(void *buf, int size, int cnt) { + // implement me + return ::fread(buf, size, cnt, (FILE*)context); + +} + +// Converts 8bit rgb values to a GP32 palette value +void GpSetPaletteEntry(u8 i, u8 r, u8 g, u8 b) { + GP_PALETTEENTRY entry = GP_RGB16(r,g,b); + GpPaletteEntryChange ( i, 1, &entry, 0 ); +} + +int gpprintf(const char *fmt, ...) { //return 0; //fixme + static int y; + char s[1024]; // ? + int r; + va_list marker; + + // combine + va_start(marker, fmt); + r = vsprintf(s, fmt, marker); + va_end(marker); + // print to console + +#ifdef GPDEBUG +//dprintf("mem: %d ", gm_availablesize()); + dprintf(s); + if (s[strlen(s)-1] != '\n') dprintf("\n"); + //if (s[0]!='>') return r; +#endif + + // print to lcd + GpTextOut(NULL, &gpDraw[DEBUG_SURFACE], 0, y, s, 1); + y+= (ENGFONT_H-FONT_LINEGAP); + if (y>(240/(ENGFONT_H-FONT_LINEGAP)) * (ENGFONT_H-FONT_LINEGAP)) { + y=0; + GpRectFill(NULL,&gpDraw[DEBUG_SURFACE], 0, 0, 320, 240, 2); + } + return r; +} + +int gpfprintf(FILE *stream, const char *fmt, ...) { + //printf(fmt, "fixme"); +} + +FILE *gpfopen(const char *filename, const char *mode) { + //FIXME: + // - allocation ? + // - mode + // - malloc -> new + ulong m; + FILE *f = (FILE*)malloc(sizeof(FILE) + sizeof(ulong)); + + //printf(">open %s as %s", filename, mode); + + // FIXME add binary/text support + if (tolower(mode[0])=='r') { + m=OPEN_R; + GpFileGetSize(filename, (ulong*)(f+1)); // hack (size in handle :) + } else + if (tolower(mode[0])=='w') { + //printf("open if as W"); + + *(ulong*)(f+1)=0; // FIXME? new file has no size? + m=OPEN_W; + GpFileCreate(filename, ALWAYS_CREATE, f); + } + else error("wrong file mode"); + + if (!f) error("%s: cannot crate F_HANDLE", __FUNCTION__); + ERR_CODE err = GpFileOpen(filename, m, f); + if (err) { + //if (strcmp(filename, "tentacle.000")==0 || strcmp(filename, "TENTACLE.000")==0) error(">bingo!"); + //if (blah>1) error("(%s) %s", filename, __FUNCTION__); else + return NULL; + } else return f; +} + + + +int gpfclose(FILE *stream) { + if (*(u32*)((char*)stream-sizeof(u32)) == 0x4321) { + debug(0, "double closing", __FUNCTION__); + return 1; + } // return 1 ?? + ERR_CODE err = GpFileClose(*stream); + free(stream); + return err; +} + +int gpfseek(FILE *stream, long offset, int whence) { + ulong dummy; + + switch (whence) { + case SEEK_SET : whence = FROM_BEGIN; break; + case SEEK_CUR : whence = FROM_CURRENT; break; + case SEEK_END : whence = FROM_END; break; + } + return GpFileSeek(*stream, whence, offset, (long*)&dummy); +} + +long gpftell(FILE *stream) { // fixme? use standard func + ulong pos=0; + ERR_CODE err = GpFileSeek(*stream, FROM_CURRENT, 0, (long*)&pos); + return pos; +} + + +size_t gpfread(void *ptr, size_t size, size_t n, FILE *stream) { + ulong readcount=0; + ERR_CODE err = GpFileRead(*stream, ptr, size*n, &readcount); //fixme? size*n + return readcount/size; //FIXME? +} + +size_t gpfwrite(const void *ptr, size_t size, size_t n, FILE *stream) { + ERR_CODE err=GpFileWrite(*stream, ptr, size*n); //fixme size*n? + //printf("writing to file"); + return err; +} + +void gpclearerr(FILE *stream) { + //error("fixme: %s", __FUNCTION__); +} + +int gpfeof(FILE *stream) { //fixme! + return ftell(stream) >= *(ulong*)(stream+1); +} + +char *gpfgets(char *s, int n, FILE *f) { + int err, i=0; + + while (!feof(f) && i<n) { + fread(&s[i], 1, 1, f); + if (s[i]=='\n') { + s[i+1]=0; + return s; + } + i++; + } + if (feof(f)) + return NULL; + else return s; +} + +int gpfflush(FILE *stream) { return 0;} + +void *gpmalloc(size_t size) { + void *p = gm_malloc(size+sizeof(u32)); // gm_zi_malloc(size+sizeof(u32)); + + //memset((char*)((char*)p+sizeof(u32)), 0, size); + //printf("callocing"); + if (p) { + *(u32*)p = 0x1234; + return ((char*)p+sizeof(u32)); + } else return NULL; +} + +void *gpcalloc(size_t nitems, size_t size) { + void *p = gpmalloc(nitems*size); //gpcalloc doesnt clear? + + memset(p, 0, nitems*size); + if (*(u8*)p) warning("%s: calloc doesn't clear!", __FUNCTION__); //fixme: was error + //printf("callocing"); + return p; +} + +void gpfree(void *block) { + if (!block) {debug(0, "freeing null pointer"); return;} + if (*(u32*)((char*)block-sizeof(u32)) == 0x4321) error("%s: double deallocation!", __FUNCTION__); + if (*(u32*)((char*)block-sizeof(u32)) != 0x1234) error("%s: corrupt block!", __FUNCTION__); + *(u32*)((char*)block-sizeof(u32)) = 0x4321; + gm_free((char*)block-sizeof(u32)); +} + +void gphalt(int code=0) { + GpGraphicModeSet(8, NULL); + currsurface=DEBUG_SURFACE; + GpSurfaceFlip(&gpDraw[currsurface]); + GpSetPaletteEntry ( 0, 0,0,0 ); + GpSetPaletteEntry ( 1, 255,0,0 ); + GpSetPaletteEntry ( 2, 255,255,255 ); + printf("HALT!"); + while (1); +} + +//#include <string.h> +#include "common/gamedetector.h" +VersionSettings* menu() { + const VersionSettings *v = version_settings; + VersionSettings* games[30]; + int n=0; + + /*GpSetPaletteEntry ( 0, 0,0,0 ); + GpSetPaletteEntry ( 1, 255,0,0 ); + GpSetPaletteEntry ( 2, 255,255,255 );*/ + + currsurface=GAME_SURFACE; + GpSurfaceFlip(&gpDraw[currsurface]); + printf("menu"); + + char s[256]; + while (v->filename && v->gamename) { + sprintf(s, "%s.000", v->filename); //fixme? (extension ok?) + FILE* f = fopen(s, "r"); + if (f) { + (const VersionSettings*)games[n++]=v; + fclose(f); + } + v++; + } + + int i, key, fg, bg, choice=0, y=0; + + //GpRectFill(NULL,&gpDraw[currsurface], 0, 0, 320, 200, 2); + GpTextOut(NULL, &gpDraw[currsurface], 0, y, "ScummVM (GP32 port by ph0x)", 255); y+=ENGFONT_H; + + if (!n) { + GpTextOut(NULL, &gpDraw[currsurface], 0, y, "No games found! put game data in gp:\\", 255); y+=ENGFONT_H; + while (1); + } + + + if (n==1) return games[choice]; //fixme? + GpTextOut(NULL, &gpDraw[currsurface], 0, y, "select game:", 255); y+=ENGFONT_H; + do { + for (i=0; i<n; i++) { + if (i==choice) {fg=100; bg=255;} else {fg=123; bg=0;} + GpRectFill(NULL,&gpDraw[currsurface], 0, y+i*ENGFONT_H, 320, ENGFONT_H, bg); + GpTextOut(NULL, &gpDraw[currsurface], 0, y+i*ENGFONT_H, (char*)games[i]->gamename, fg); + } + + do key=GpKeyGet(); while (key == GPC_VK_NONE) ; + if (key & GPC_VK_DOWN) + {if (choice<n-1) choice++;} else + if (key & GPC_VK_UP) + {if (choice>0) choice--;} else + if (key & GPC_VK_START || key & GPC_VK_FA) return games[choice]; //fixme? + do key=GpKeyGet(); while (key != GPC_VK_NONE) ; + + } while (1); +} + +int gpinit() { + // Initialize graphics + GpGraphicModeSet(8, NULL); + GpLcdSurfaceGet(&gpDraw[DEBUG_SURFACE], DEBUG_SURFACE); + GpLcdSurfaceGet(&gpDraw[NAMEME_SURFACE], NAMEME_SURFACE); + GpLcdSurfaceGet(&gpDraw[GAME_SURFACE], GAME_SURFACE); + +// gpDraw[GAME_SURFACE].oy=19; //center screen? +// GpRectFill(NULL,&gpDraw[GAME_SURFACE], 0, 0, 320, 240, 0); //black border + GpLcdEnable(); + // fixme - use get function + currsurface=DEBUG_SURFACE; + GpSurfaceSet(&gpDraw[currsurface]); + +// _gp_sdk_init(); +// GpKeyInit(); + GpFatInit(); + GpRelativePathSet("gp:"); // fixme (get path) + +/* + char s[256]; + GpRelativePathGet(s); + printf("path=%s", s); +*/ +#ifdef GPDEBUG + printf(">waiting debugger..."); + InitDebug(); +#endif + printf(">Running ScummVM"); + +} + +void createfakeini() { +/* +char s[] = "\ +[dott]\n\ +gameid=tentacle\n\ +[samnmax]\n\ +gameid=samnmax\n\ +[atlantis]\n\ +gameid=playfate\n\ +"; +FILE *f=fopen("scummvm.ini", "w"); +fwrite(s, 1, sizeof(s)+1, f); +fclose(f); +*/ + printf("Creating scummvm.ini, please wait..."); + FILE *f=fopen("scummvm.ini", "w"); + const VersionSettings *v = version_settings; + char s[256]; + while (v->filename && v->gamename) { + sprintf(s, "[%s]\ngameid=%s\n", v->filename, v->filename); + fwrite(s, 1, strlen(s), f); + v++; + } + fclose(f); +} + +extern "C" void GpMain (void * arg); // hack +void GpMain (void * arg) { + gpinit(); + createfakeini(); //FIXME: use methods :) + + // fixme - use get function + currsurface=GAME_SURFACE; + GpSurfaceFlip(&gpDraw[currsurface]); + + char *argv[] = { "scummvm", /*(char*)menu()->filename*/ NULL }; + int argc = 1; + + extern int main(int argc, char *argv[]); + main(argc, argv); + + error("returned from main ?!"); +} diff --git a/backends/gp32/gp32.h b/backends/gp32/gp32.h new file mode 100644 index 0000000000..d58f894157 --- /dev/null +++ b/backends/gp32/gp32.h @@ -0,0 +1,203 @@ +#include "common/stdafx.h" +#include "common/scummsys.h" +#include "common/system.h" +#include "common/scummsys.h" +#include "common/stdafx.h" +#include "common/engine.h" +#include "scumm/saveload.h" +#include "common/scaler.h" + +extern "C" { + #include "gpdebug.h" +} + +#include "gpsdl.h" // hehe :) + +class OSystem_GP32 : public OSystem { +public: + // Set colors of the palette + void set_palette(const byte *colors, uint start, uint num); + + // Set the size of the video bitmap. + // Typically, 320x200 + void init_size(uint w, uint h); + + // Draw a bitmap to screen. + // The screen will not be updated to reflect the new bitmap + void copy_rect(const byte *buf, int pitch, int x, int y, int w, int h); + + // Moves the screen content around by the given amount of pixels + // but only the top height pixel rows, the rest stays untouched + void move_screen(int dx, int dy, int height); + + // Update the dirty areas of the screen + void update_screen(); + + // Either show or hide the mouse cursor + bool show_mouse(bool visible); + + // Set the position of the mouse cursor + void set_mouse_pos(int x, int y); + + // Set the bitmap that's used when drawing the cursor. + void set_mouse_cursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y); + + // Shaking is used in SCUMM. Set current shake position. + void set_shake_pos(int shake_pos); + + // Get the number of milliseconds since the program was started. + uint32 get_msecs(); + + // Delay for a specified amount of milliseconds + void delay_msecs(uint msecs); + + // Create a thread + void *create_thread(ThreadProc *proc, void *param); + + // Get the next event. + // Returns true if an event was retrieved. + bool poll_event(Event *event); + + // Set the function to be invoked whenever samples need to be generated + // Format is the sample type format. + // Only 16-bit signed mode is needed for simon & scumm + bool set_sound_proc(void *param, SoundProc *proc, byte format); + + // Get or set a property + uint32 property(int param, Property *value); + + // Poll cdrom status + // Returns true if cd audio is playing + bool poll_cdrom(); + + // Play cdrom audio track + void play_cdrom(int track, int num_loops, int start_frame, int end_frame); + + // Stop cdrom audio track + void stop_cdrom(); + + // Update cdrom audio status + void update_cdrom(); + + // Add a new callback timer + void set_timer(int timer, int (*callback)(int)); + + // Mutex handling + void *create_mutex(void); + void lock_mutex(void *mutex); + void unlock_mutex(void *mutex); + void delete_mutex(void *mutex); + + // Quit + void quit(); + + // Overlay + void show_overlay(); + void hide_overlay(); + void clear_overlay(); + void grab_overlay(int16 *buf, int pitch); + void copy_rect_overlay(const int16 *buf, int pitch, int x, int y, int w, int h); + + static OSystem *create(int gfx_mode, bool full_screen); +private: + typedef void ScalerProc(uint8 *srcPtr, uint32 srcPitch, uint8 *deltaPtr, + uint8 *dstPtr, uint32 dstPitch, int width, int height); + + SDL_Surface *sdl_tmpscreen; // temporary screen (for scalers/overlay) + SDL_Surface *sdl_hwscreen; // hardware screen + bool _overlay_visible; + + ScalerProc *_scaler_proc; + + int TMP_SCREEN_WIDTH; + + //uint msec_start; + //uint32 get_ticks(); + + ///OSystem_GP32(); // eh? + /// ~OSystem_GP32(); + + // unseen game screen + SDL_Surface *_screen; + int _screenWidth, _screenHeight; + + // CD Audio + ///SDL_CD *_cdrom; + int cd_track, cd_num_loops, cd_start_frame, cd_end_frame; + uint32 cd_end_time, cd_stop_time, cd_next_second; + + enum { + DF_WANT_RECT_OPTIM = 1 << 0, + DF_UPDATE_EXPAND_1_PIXEL = 1 << 3 + }; + + bool _forceFull; // Force full redraw on next update_screen + int _scaleFactor; + int _mode; + bool _full_screen; + uint32 _mode_flags; + + enum { + NUM_DIRTY_RECT = 100, + + MAX_MOUSE_W = 40, + MAX_MOUSE_H = 40, + MAX_SCALING = 3 + }; + + // Dirty rect managment + SDL_Rect _dirty_rect_list[100]; + int _num_dirty_rects; + uint32 *_dirty_checksums; + bool cksum_valid; + int CKSUM_NUM; + + // Keyboard mouse emulation + struct KbdMouse { + int16 x, y, x_vel, y_vel, x_max, y_max, x_down_count, y_down_count; + uint32 last_time, delay_time, x_down_time, y_down_time; + } km; + + struct MousePos { + int16 x, y, w, h; + }; + + bool _mouseVisible; + bool _mouseDrawn; + byte *_mouseData; + byte *_mouseBackup; + MousePos _mouse_cur_state; + MousePos _mouse_old_state; + int16 _mouseHotspotX; + int16 _mouseHotspotY; + + // Shake mode + int _currentShakePos; + int _newShakePos; + + // Palette data + SDL_Color *_currentPalette; + uint _paletteDirtyStart, _paletteDirtyEnd; + + + void add_dirty_rgn_auto(const byte *buf); + void mk_checksums(const byte *buf); + + static void fill_sound(void *userdata, Uint8 * stream, int len); + + void add_dirty_rect(int x, int y, int w, int h); + + void draw_mouse(); + void undraw_mouse(); + + void load_gfx_mode(); + void unload_gfx_mode(); + void hotswap_gfx_mode(); + + void get_screen_image(byte *buf); + + void setup_icon(); + void kbd_mouse(); + + static OSystem_GP32 *create(); +}; diff --git a/backends/gp32/gpdebug.c b/backends/gp32/gpdebug.c new file mode 100644 index 0000000000..4626c44bc5 --- /dev/null +++ b/backends/gp32/gpdebug.c @@ -0,0 +1,125 @@ +////////////////////////////////////////////////////////////////////////////// +// debug_emu.cpp // +////////////////////////////////////////////////////////////////////////////// +/* + debug support for EmuDebug console v1.2+ +*/ + +////////////////////////////////////////////////////////////////////////////// +// Includes // +////////////////////////////////////////////////////////////////////////////// +#include "gpdebug.h" + +////////////////////////////////////////////////////////////////////////////// +// Defines // +////////////////////////////////////////////////////////////////////////////// +#define debugBufferData ((volatile char *)debugBufferAddr + 8) +#define debugBufferBegin REG4((int)debugBufferAddr + 0) // read +#define debugBufferEnd REG4((int)debugBufferAddr + 4) // write +#define debugBufferDataSize 256 +#define debugBufferSize (8 + debugBufferDataSize) + +////////////////////////////////////////////////////////////////////////////// +// Variables // +////////////////////////////////////////////////////////////////////////////// + +static int debugging = 0; +static void * volatile debugBufferAddr; +char debugBuffer[debugBufferDataSize]; // instead of malloc + +////////////////////////////////////////////////////////////////////////////// +// __putchar // +////////////////////////////////////////////////////////////////////////////// +void __putchar(int c) +{ + unsigned int nextEnd; + if (!debugging) return; + do + { + nextEnd = debugBufferEnd + 1; + if (nextEnd >= debugBufferDataSize) nextEnd = 0; + } while (nextEnd == debugBufferBegin); // full? + debugBufferData[debugBufferEnd] = c; + debugBufferEnd = nextEnd; +} + +////////////////////////////////////////////////////////////////////////////// +// __getchar // +////////////////////////////////////////////////////////////////////////////// +int __getchar() +{ + //if (!debugging) return -1; + return -1; +} + +////////////////////////////////////////////////////////////////////////////// +// __kbhit // +////////////////////////////////////////////////////////////////////////////// +int __kbhit() +{ + //if (!debugging) return false; + return 0; +} + +////////////////////////////////////////////////////////////////////////////// +// __gets // +////////////////////////////////////////////////////////////////////////////// +char * __gets(char *s) +{ + char *p = s; + if (!debugging) return 0; + while (1) + { + int c = getchar(); + if (c >= 0) *p++ = c; + if (c == 0) return s; + } + return s; +} + +////////////////////////////////////////////////////////////////////////////// +// __puts // +////////////////////////////////////////////////////////////////////////////// +int __puts(const char *s) +{ + if (!debugging) return 0; + while (*s) putchar(*s++); + return 0; +/* + while (debugBufferAddr[0]) {} // wait until buffer is clear + int r = sprintf(debugBufferAddr+1, "%s", s); + debugBufferAddr[0] = r; + return r; +*/ +} + +////////////////////////////////////////////////////////////////////////////// +// __printf // +////////////////////////////////////////////////////////////////////////////// +int __printf(char *fmt, ...) +{ + char s[256]; + int r; + va_list marker; + + if (!debugging) return 0; + va_start(marker, fmt); + r = vsprintf(s, fmt, marker); + va_end(marker); + puts(s); + return r; +} + +////////////////////////////////////////////////////////////////////////////// +// InitDebug // +////////////////////////////////////////////////////////////////////////////// +void InitDebug() +{ + debugBufferAddr = debugBuffer; + //debugBufferAddr = malloc(debugBufferSize); + debugBufferBegin = debugBufferEnd = 0xEDEBEDEB; + memset((void *)debugBufferData, ' ', debugBufferDataSize); + debugBufferData[0] = '{'; debugBufferData[debugBufferDataSize - 1] = '}'; + while (debugBufferBegin && debugBufferEnd) { } // wait for debugger + debugging = 1; +} diff --git a/backends/gp32/gpdebug.h b/backends/gp32/gpdebug.h new file mode 100644 index 0000000000..a7894baa7d --- /dev/null +++ b/backends/gp32/gpdebug.h @@ -0,0 +1,49 @@ +////////////////////////////////////////////////////////////////////////////// +// debug.h // +////////////////////////////////////////////////////////////////////////////// +#ifndef _GP_DEBUG_H +#define _GP_DEBUG_H + +/* + Debug library + Note: include debug.h after stdio.h and conio.h!!! +*/ + +////////////////////////////////////////////////////////////////////////////// +// Includes // +////////////////////////////////////////////////////////////////////////////// +#include "gpregs.h" +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> + +////////////////////////////////////////////////////////////////////////////// +// Defines // +////////////////////////////////////////////////////////////////////////////// +// public +#define dprintf __printf //ph0x ..redefine rest? +#undef getchar +#define getchar __getchar +#undef putchar +#define putchar(c) __putchar(c) +#define gets(s) __gets(s) +#define puts(s) __puts(s) // fixme? +#define kbhit() __kbhit() // uncomment? + +// function -> constructor & class instance +//#define INIT(fn) class fn##_Init { public: fn##_Init() { fn(); } } fn##_init +//#define INIT1(fn,param1) class fn##_Init { public: fn##_Init() { fn(param1); } } fn##_init + +////////////////////////////////////////////////////////////////////////////// +// Prototypes // +////////////////////////////////////////////////////////////////////////////// +extern void InitDebug(void); // auto-initialized +extern int __kbhit(void); +extern void __putchar(int c); +extern int __getchar(void); // non-blocking +extern int __printf(char *fmt, ...); +extern int __puts(const char *s); +extern char * __gets(char *s); + +#endif // _DEBUG_H diff --git a/backends/gp32/gpregs.h b/backends/gp32/gpregs.h new file mode 100644 index 0000000000..165b800476 --- /dev/null +++ b/backends/gp32/gpregs.h @@ -0,0 +1,69 @@ +////////////////////////////////////////////////////////////////////////////// +// GP32.h // +////////////////////////////////////////////////////////////////////////////// +#ifndef _GP32_H +#define _GP32_H + +/* + GP32 stuff + just a bunch of includes +*/ + +////////////////////////////////////////////////////////////////////////////// +// Includes // +////////////////////////////////////////////////////////////////////////////// +/* +#include "24x.h" +#include "gpdef.h" +#include "gpos_def.h" +#include "gpmem.h" +#include "gpstdio.h" +#include "gpstdlib.h" +#include "gpmm.h" +#include "gpgraphic.h" +#include "gpfont.h" +#include "gpsockdef.h" +#include "gpcomm.h" +#include "gpnetlib.h" +*/ +////////////////////////////////////////////////////////////////////////////// +// Defines // +////////////////////////////////////////////////////////////////////////////// +// C++ bools +//typedef int bool; +#define false 0 +#define true 1 + +typedef unsigned char u8; +typedef volatile u8 vu8; +typedef signed char s8; +typedef volatile s8 vs8; +typedef unsigned short u16; +typedef volatile u16 vu16; +typedef signed short s16; +typedef volatile s16 vs16; +typedef unsigned int u32; +typedef volatile u32 vu32; +typedef signed int s32; +typedef volatile s32 vs32; + +// memory/register typecasting +#define MEM1(addr) ( (u8 *)(addr)) +#define MEM2(addr) ( (u16*)(addr)) +#define MEM4(addr) ( (u32*)(addr)) +#define REG1(addr) (*(vu8 *)(addr)) +#define REG2(addr) (*(vu16*)(addr)) +#define REG4(addr) (*(vu32*)(addr)) +#define RPTR(addr) (*(void **)(addr)) + +// array length +#define lengthof(id) (sizeof(id) / sizeof((id)[0])) + +////////////////////////////////////////////////////////////////////////////// +// Typedefs // +////////////////////////////////////////////////////////////////////////////// + + + + +#endif // _GP32_H diff --git a/backends/gp32/gpsdl.h b/backends/gp32/gpsdl.h new file mode 100644 index 0000000000..5d8d749096 --- /dev/null +++ b/backends/gp32/gpsdl.h @@ -0,0 +1,82 @@ +/* Useful data types */ + +#define Sint16 s16 +#define Uint16 u16 +#define Uint32 u32 +#define Uint8 u8 + +typedef struct { + Sint16 x, y; + Uint16 w, h; +} SDL_Rect; + +typedef struct { + Uint8 r; + Uint8 g; + Uint8 b; + Uint8 unused; +} SDL_Color; + +typedef struct { + int ncolors; + SDL_Color *colors; +} SDL_Palette; + + +/* Everything in the pixel format structure is read-only */ +typedef struct SDL_PixelFormat { + SDL_Palette *palette; + Uint8 BitsPerPixel; + Uint8 BytesPerPixel; + Uint8 Rloss; + Uint8 Gloss; + Uint8 Bloss; + Uint8 Aloss; + Uint8 Rshift; + Uint8 Gshift; + Uint8 Bshift; + Uint8 Ashift; + Uint32 Rmask; + Uint32 Gmask; + Uint32 Bmask; + Uint32 Amask; + + /* RGB color key information */ + Uint32 colorkey; + /* Alpha value information (per-surface alpha) */ + Uint8 alpha; +} SDL_PixelFormat; + +typedef struct SDL_Surface { + Uint32 flags; /* Read-only */ + SDL_PixelFormat *format; /* Read-only */ + int w, h; /* Read-only */ + Uint16 pitch; /* Read-only */ + void *pixels; /* Read-write */ + int offset; /* Private */ + + /* Hardware-specific surface info */ + struct private_hwdata *hwdata; + + /* clipping information */ + SDL_Rect clip_rect; /* Read-only */ + Uint32 unused1; /* for binary compatibility */ + + /* Allow recursive locks */ + Uint32 locked; /* Private */ + + /* info for fast blit mapping to other surfaces */ +/// struct SDL_BlitMap *map; /* Private */ + + /* format version, bumped at every change to invalidate blit maps */ + unsigned int format_version; /* Private */ + + /* Reference count -- used when freeing surface */ + int refcount; /* Read-mostly */ +} SDL_Surface; + +#define SDL_SWSURFACE 0x00000000 +#define SDL_HWSURFACE 0x00000001 +#define SDL_FULLSCREEN 0x80000000 + +// EOF diff --git a/backends/gp32/portdefs.h b/backends/gp32/portdefs.h new file mode 100644 index 0000000000..d8d91512db --- /dev/null +++ b/backends/gp32/portdefs.h @@ -0,0 +1,78 @@ + #include <stdio.h> + #include <stdlib.h> + #include <string.h> + #include <stdarg.h> + #include <ctype.h> + +extern "C" { + #include "h/gpfont.h" + #include "h/gpfont_port.h" + #include "h/gpgraphic.h" + #include "h/gpmm.h" + #include "h/gpmem.h" + #include "h/gpos_def.h" + #include "h/gpstdio.h" + #include "h/gpstdlib.h" + #include "h/gpdef.h" + #include "h/defines.h" +} + + extern int gpprintf(const char *fmt, ...); + #define printf gpprintf + + extern void *gpmalloc(size_t size); + extern void *gpcalloc(size_t nitems, size_t size); + extern void gpfree(void *block); + #define malloc gpmalloc + #define calloc gpcalloc //gm_calloc + #define free gpfree + /*#define memset gm_memset + #define memcopy gm_memcopy + + #define strcpy gm_strcpy // uncomment? + #define strncpy gm_strncpy + #define strcat gm_strcat + #define sprintf gm_sprintf*/ + + #define assert(e) ((e) ? 0 : (printf("!AS: " #e " (%s, %d)\n", __FILE__, __LINE__))) + #define ASSERT assert + + #define ENDLESSLOOP while (1) + + #define FILE F_HANDLE + #define stderr NULL // hack... + #define stdout stderr + #define stdin stderr + + extern FILE *gpfopen(const char *filename, const char *mode); + extern int gpfclose(FILE *stream); + extern int gpfseek(FILE *stream, long offset, int whence); + extern size_t gpfread(void *ptr, size_t size, size_t n, FILE *stream); + extern size_t gpfwrite(const void *ptr, size_t size, size_t n, FILE*stream); + extern long gpftell(FILE *stream); + extern void gpclearerr(FILE *stream); + extern int gpfeof(FILE *stream); + extern char *gpfgets(char *s, int n, FILE *stream); + extern int gpfflush(FILE *stream); + + #define fopen gpfopen + #define fclose gpfclose + #define fseek gpfseek + #define fread gpfread + #define fwrite gpfwrite + #define ftell gpftell + #define clearerr gpclearerr + #define feof gpfeof + #define fgets gpfgets + + extern int gpfprintf(FILE *stream, const char *fmt, ...); + #define fprintf gpfprintf + #define fflush gpfflush + + extern void gphalt(int code=0); + #define exit gphalt + //#define error printf + + #define time(x) (0) // fixme! (SIMON) + + // EOF diff --git a/backends/gp32/readme.txt b/backends/gp32/readme.txt new file mode 100644 index 0000000000..97f43b68be --- /dev/null +++ b/backends/gp32/readme.txt @@ -0,0 +1,29 @@ +ScummVM port for GamePark 32 +============================ + +Compiling instructions: + 1. download and install Fenix's devkit advance (see Windows.txt) + 2. get chn's gp32 devkit and install it (see readme-gp32.txt) + 3. In Makefile change the line: build.rules: to + $(CP) backends/gp32/build.rules build.rules + 4. run make + + * In case you have installed devkitadv to a different directory + than it's default, you'll have to modify build.rules in backend/gp32/ + +To-do: + - add sound support + - make more friendly build.rules ? :) + +For the latest source release visit the official ScummVM page: + http://www.scummvm.org/ + +You can get the precompiled gp32 executable (fxe) from my site: + http://people.inf.elte.hu/ph0x + + +Thanks to the following people for their help: + Endy, khalek and the rest ScummVM team members, + Jeff, DarkFader, Inopia, groepaz, chn, FireFly, #gp32dev + + ph0x (ph0x@freemail.hu)
\ No newline at end of file diff --git a/backends/gp32/stat.h b/backends/gp32/stat.h new file mode 100644 index 0000000000..d9eef1318d --- /dev/null +++ b/backends/gp32/stat.h @@ -0,0 +1,23 @@ +/* Header is not present in Windows CE SDK */ + +#include <sys/types.h> + +struct stat { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + _off_t st_size; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; +}; + + +#define _S_IFDIR 0040000 /* directory */ +#define S_IFDIR _S_IFDIR + +int stat(const char *, struct stat *); |