diff options
author | Peter Moraliyski | 2002-12-02 16:55:18 +0000 |
---|---|---|
committer | Peter Moraliyski | 2002-12-02 16:55:18 +0000 |
commit | 4042b1f1fcb177dbe85ddbd98ff37fabf80192f1 (patch) | |
tree | 7bbaf93277cf41af7f8e50744815e01e270b39fa | |
parent | 2961f75365e216e413ed73030ce213eba50c80a5 (diff) | |
download | scummvm-rg350-4042b1f1fcb177dbe85ddbd98ff37fabf80192f1.tar.gz scummvm-rg350-4042b1f1fcb177dbe85ddbd98ff37fabf80192f1.tar.bz2 scummvm-rg350-4042b1f1fcb177dbe85ddbd98ff37fabf80192f1.zip |
license issue cleared
svn-id: r5813
-rw-r--r-- | backends/gp32/dirent.h | 59 | ||||
-rw-r--r-- | backends/gp32/gp32.cpp | 1556 | ||||
-rw-r--r-- | backends/gp32/gp32.h | 220 | ||||
-rw-r--r-- | backends/gp32/portdefs.h | 110 | ||||
-rw-r--r-- | backends/gp32/readme.txt | 38 | ||||
-rw-r--r-- | backends/gp32/sdl.h | 84 | ||||
-rw-r--r-- | backends/gp32/stat.h | 29 |
7 files changed, 2096 insertions, 0 deletions
diff --git a/backends/gp32/dirent.h b/backends/gp32/dirent.h new file mode 100644 index 0000000000..8b9698dade --- /dev/null +++ b/backends/gp32/dirent.h @@ -0,0 +1,59 @@ +////////////////////////////////////////////////////////////////////////////// +// NOTE: (ph0x) +// borrowed from wince port as the file was either missing from the gp32sdk +// or was causing conflicts. +////////////////////////////////////////////////////////////////////////////// + + +/* 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/gp32.cpp b/backends/gp32/gp32.cpp new file mode 100644 index 0000000000..773b4e95ec --- /dev/null +++ b/backends/gp32/gp32.cpp @@ -0,0 +1,1556 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001/2002 The ScummVM project + * Copyright (C) 2002 ph0x (GP32 port) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +//#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..7546a25b7b --- /dev/null +++ b/backends/gp32/gp32.h @@ -0,0 +1,220 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001/2002 The ScummVM project + * Copyright (C) 2002 ph0x (GP32 port) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#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" + +#include "sdl.h" + +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/portdefs.h b/backends/gp32/portdefs.h new file mode 100644 index 0000000000..6f6315ebfb --- /dev/null +++ b/backends/gp32/portdefs.h @@ -0,0 +1,110 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001/2002 The ScummVM project + * Copyright (C) 2002 ph0x (GP32 port) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +//#define __size_t // SDK hack? + #include <stdio.h> + #include <stdlib.h> + #include <string.h> + #include <stdarg.h> + #include <ctype.h> + + +extern "C" { + #include "gpfont.h" + #include "gpfont_port.h" + #include "gpgraphic.h" + #include "gpmm.h" + #include "gpmem.h" + #include "gpos_def.h" + #include "gpstdio.h" + #include "gpstdlib.h" + #include "gpdef.h" + //#include "defines.h" +} + +#undef byte // SDK hack? + +typedef unsigned char u8; +typedef signed char s8; +typedef unsigned short u16; +typedef short s16; +typedef unsigned int u32; +typedef int s32; + + 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..c48fa45966 --- /dev/null +++ b/backends/gp32/readme.txt @@ -0,0 +1,38 @@ +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/ + +How to run: + - upload scummvm.fxe in gp:\gpmm + - upload all game data files in gp:\ + +Controls: + A: left click + B: right click + L: debug console + R: game screen + Start: menu + Select:skip + L+R: save + +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/sdl.h b/backends/gp32/sdl.h new file mode 100644 index 0000000000..0ef46966ce --- /dev/null +++ b/backends/gp32/sdl.h @@ -0,0 +1,84 @@ + +////////////////////////////////////////////////////////////////////////////// +// pseudo SDL header (ph0x) +// borrowed from sdl 1.2.3 as port is based mostly on the sdl backend +////////////////////////////////////////////////////////////////////////////// + +#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
\ No newline at end of file diff --git a/backends/gp32/stat.h b/backends/gp32/stat.h new file mode 100644 index 0000000000..5f3c3d8b6e --- /dev/null +++ b/backends/gp32/stat.h @@ -0,0 +1,29 @@ +////////////////////////////////////////////////////////////////////////////// +// NOTE: (ph0x) +// borrowed from wince port as the file was either missing from the gp32sdk +// or was causing conflicts. +////////////////////////////////////////////////////////////////////////////// + +/* 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 *); |