scummvm/backends/gp32/gp32.cpp
2005-10-18 01:30:26 +00:00

3222 lines
80 KiB
C++

/* ScummVM - Scumm Interpreter
* Copyright (C) 2001 Ludvig Strigeus
* Copyright (C) 2001/2004 The ScummVM project
* Copyright (C) 2002 Ph0x - GP32 Backend
* Copyright (C) 2003/2004 DJWillis - GP32 Backend
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Header$
*
*/
/*
*
* Main Source for ScummVM for the GP32
*
*/
// TODO:
// Clean up GP leftovers and strip backend to only bits the GP32 needs.
// Finish restructure.
// Sort all remaining GCC 3.4 warnings.
// setTimerCallback: function call doesnt use * ?
//#define REAL_MAIN
#ifdef GP32_GDB
#include <gdb-stub.h>
#endif /*GP32_GDB */
#include "backends/gp32/setup.h"
#include "backends/gp32/gp32.h"
#include "backends/gp32/gfx_splash.h"
//#include "backends/gp32/resources/gfx_splash_alt.h"
#define gpRGB16(r,g,b) (((((r)>>3)&0x1F) << 11) | ((((g)>>3)&0x1F) << 6) | (((b)>>3)&0x1F)<<1)
#define RGB_TO_16(r,g,b) (((((r)>>3)&0x1F) << 11) | ((((g)>>3)&0x1F) << 6) | (((b)>>3)&0x1F)<<1)
int nflip, keydata; // Flip Index
GP_HPALETTE PAL; //palette
GPDRAWSURFACE LCDbuffer[BUFFERCOUNT + 1]; //buffers
void GpSetPaletteEntry(u8 i, u8 r, u8 g, u8 b);
// FIXME: No global init!
float gammatab[256], gammatab2[256]; // fixme: one table
const float scrGamma[] = { 1.0, 1.001, 1.002, 1.003, 1.004, 1.005 };
char gindex = 3;
int mx = 1, my = 1;
int scrofsy = 239;
char currentsurf;
// FIXME!!
// crashes if here and not buildgammatab() not called as very first line! check
// check if sav file handling overwrites something!
// float gammatab[256];
FILE *fstderr, *fstdout, *fstdin;
/****************************************************************
GP32 Input mappings - Returns Button Pressed.
****************************************************************/
int gpTrapKey(void)
{
int value = 0;
#define rKEY_A 0x4000
#define rKEY_B 0x2000
#define rKEY_L 0x1000
#define rKEY_R 0x8000
#define rKEY_UP 0x0800
#define rKEY_DOWN 0x0200
#define rKEY_LEFT 0x0100
#define rKEY_RIGHT 0x0400
#define rKEY_START 0x0040
#define rKEY_SELECT 0x0080
#define rPBDAT (*(volatile unsigned *)0x1560000c)
#define rPEDAT (*(volatile unsigned *)0x15600030)
unsigned long gpb = rPBDAT; // 0x156
unsigned long gpe = rPEDAT;
if ((gpb & rKEY_LEFT) == 0)
value |= GPC_VK_LEFT;
if ((gpb & rKEY_RIGHT) == 0)
value |= GPC_VK_RIGHT;
if ((gpb & rKEY_UP) == 0)
value |= GPC_VK_UP;
if ((gpb & rKEY_DOWN) == 0)
value |= GPC_VK_DOWN;
if ((gpb & rKEY_A) == 0)
value |= GPC_VK_FA;
if ((gpb & rKEY_B) == 0)
value |= GPC_VK_FB;
if ((gpb & rKEY_L) == 0)
value |= GPC_VK_FL;
if ((gpb & rKEY_R) == 0)
value |= GPC_VK_FR;
if ((gpe & rKEY_SELECT) == 0)
value |= GPC_VK_SELECT;
if ((gpe & rKEY_START) == 0)
value |= GPC_VK_START;
return value;
}
/****************************************************************
GP32 ScummVM OSystem Implementation.
****************************************************************/
//OSystem *OSystem_GP32::create()
//{
// //OSystem_GP32 *syst = new OSystem_GP32();
// //return syst;
// return new OSystem_GP32();
//}
OSystem *OSystem_GP32_create()
{
//
// OSystem_GP32 *syst = new OSystem_GP32();
////
//// //syst->_mode = gfx_mode;
//// //syst->_full_screen = full_screen;
//
// // allocate palette storage
// syst->_currentPalette = (gpColor*)calloc(sizeof(gpColor), 256);
//
// // allocate the dirty rect storage
// syst->_mouseBackup = (byte*)malloc(MAX_MOUSE_W * MAX_MOUSE_H * MAX_SCALING * 2);
// return syst;
// return new OSystem_GP32();
//return OSystem_GP32::create();
return new OSystem_GP32();
}
OSystem_GP32::OSystem_GP32() :
//#ifdef USE_OSD
// _osdSurface(0), _osdAlpha(SDL_ALPHA_TRANSPARENT), _osdFadeStartTime(0),
//#endif
_hwscreen(0), _screen(0), _screenWidth(0), _screenHeight(0),
_tmpscreen(0), _overlayVisible(false),
// _cdrom(0),
// _scaler_proc(0),
_modeChanged(false), _dirty_checksums(0),
_mouseVisible(false), _mouseDrawn(false), _mouseData(0),
_mouseHotspotX(0), _mouseHotspotY(0),
_currentShakePos(0), _newShakePos(0),
_paletteDirtyStart(0), _paletteDirtyEnd(0), _graphicsMutex(0) {
// allocate palette storage
_currentPalette = (gpColor *) calloc(sizeof(gpColor), 256);
// allocate the dirty rect storage
_mouseBackup =
(byte *) malloc(MAX_MOUSE_W * MAX_MOUSE_H * MAX_SCALING * 2);
// reset mouse state
memset(&km, 0, sizeof(km));
_scaleFactor = 1;
_scaler_proc = Normal1x;
_mode = GFX_NORMAL;
_full_screen = true;
_adjustAspectRatio = false;
_mode_flags = 0;
//init_intern();
}
OSystem_GP32::~OSystem_GP32() {
if (_dirty_checksums)
free(_dirty_checksums);
free(_currentPalette);
free(_mouseBackup);
deleteMutex(_graphicsMutex);
quit();
}
// Set colors of the palette
void OSystem_GP32::setPalette(const byte * colors, uint start, uint num) {
const byte *b = colors;
uint i;
gpColor *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 (x240 for FMTowns)
// FIXME: Is there a clean way to get the Game_ID in the backend, I still like the virual keymap feature below.
//#include "base/gameDetector.h"
//#include "scumm/scumm.h"
//extern ScummEngine *g_scumm;
const char shortkey0[] = "";
const char shortkey1[] = "gpuolscty"; // give, pick up, use, open, look at, push, close, talk to, pull
const char shortkey2[] = "qwerasdfzxcv"; //push, open, walk to, use, pull, close, pick up, turn on, give, look, what is, turn off
const char shortkey3[] = "wlptuo"; // samnmax
const char *shortkey;
int skindex = 0;
void OSystem_GP32::initSize(uint w, uint h, int overlayScale) {
/*switch (menu[MENU_SCREENPOS].index) {
* case 0 : scrofsy = 239 - (240 - h)/2; break;
* case 1 : scrofsy = 239; break;
* }
*/
//switch (g_scumm->_gameId) { //fixme: add all
// case GID_TENTACLE : case GID_MONKEY2 : case GID_INDY4 : shortkey=shortkey1; break;
// case GID_INDY3 : case GID_ZAK256 : case GID_MONKEY : shortkey=shortkey2; break;
// case GID_SAMNMAX : shortkey=shortkey3; break;
// default : shortkey=shortkey0; break;
//}
shortkey = shortkey0;
// 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));
_mouseData = NULL;
unload_gfx_mode();
load_gfx_mode();
return;
}
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 {
gpRect *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;
}
}
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;
const uint BASE = 65521; /* largest prime smaller than 65536 */
/* 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) {
// Adler32 checksum algorithm (from RFC1950, used by gzip and zlib).
// This computes the Adler32 checksum of a 8x8 pixel block. Note
// that we can do the modulo operation (which is the slowest part)
// of the algorithm) at the end, instead of doing each iteration,
// since we only have 64 iterations in total - and thus s1 and
// s2 can't overflow anyway.
uint32 s1 = 1;
uint32 s2 = 0;
const byte *ptr = buf;
for (int subY = 0; subY < 8; subY++) {
for (int subX = 0; subX < 8; subX++) {
s1 += ptr[subX];
s2 += s1;
}
ptr += _screenWidth;
}
s1 %= BASE;
s2 %= BASE;
/* output the checksum for this block */
*sums++ = (s2 << 16) + s1;
}
}
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::copyRectToScreen(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();
byte *dst = (byte *) _screen->pixels + y * _screenWidth + x;
do {
memcpy(dst, buf, w);
dst += _screenWidth;
buf += pitch;
} while (--h);
}
gpSurface *gpCreateRGBSurface(Uint32 flags, int width, int height, int depth,
Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask) {
gpSurface *surf = (gpSurface *) malloc(sizeof(gpSurface));
surf->format = (gpPixelFormat *) malloc(sizeof(gpPixelFormat));
if ((flags & gpHWSurface) == gpHWSurface) {
error(">HW surface (w=%d, h=%d)", width, height);
} else if ((flags & gpSWSurface) == gpSWSurface) {
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;
}
gpSurface *gpSetVideoMode(int width, int height, int bpp, Uint32 flags) {
return gpCreateRGBSurface(flags, width, height, bpp, 0, 0, 0, 0);
}
void gpFreeSurface(gpSurface *surface) {
// implement
}
gpSurface *gpCreateRGBSurfaceFrom(void *pixels,
int width, int height, int depth, int pitch,
Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask) {
// FIXME dont reuse code
gpSurface *surf = (gpSurface *) malloc(sizeof(gpSurface));
surf->format = (gpPixelFormat *) malloc(sizeof(gpPixelFormat));
surf->w = width;
surf->h = height;
surf->pitch = pitch;
surf->pixels = pixels;
surf->format->BitsPerPixel = depth;
surf->format->BytesPerPixel = depth / 8;
return surf;
}
int gpFillRect(gpSurface *dst, gpRect *dstrect, Uint32 color) {
// FIXME: implement
return 0;
}
int mcshake = 0;
void gpUpdateRects(gpSurface *screen, int numrects, gpRect *rects) {
// FIXME dont duplicate code :)
// CHECK: shake causes crash? mcshake can get negative?
if (screen->format->BitsPerPixel == 8)
while (numrects--) {
//if (mcshake && rects->h == LCD_HEIGHT) { //fixme?
if (mcshake && rects->h == /*_screenHeight*/ 200) { //fixme?
//printf("shaking %d", mcshake);
rects->h -= mcshake;
GpRectFill(NULL, &LCDbuffer[GAME_SURFACE], 0, rects->h + scrofsy, 320, mcshake, 0); //black border
}
u8 *s =
(u8 *) ((u8 *) screen->pixels + (rects->y +
mcshake) * 320 + rects->x);
u8 *d =
(u8 *) ((u8 *) LCDbuffer[GAME_SURFACE].ptbuffer +
rects->x * 240 + scrofsy - 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 *) LCDbuffer[GAME_SURFACE].ptbuffer +
rects->x * 240 + scrofsy - 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 gpBlitSurface gpUpperBlit
int gpBlitSurface(gpSurface *screen, gpRect *rects, gpSurface *dst, gpRect *dstrect) {
// FIXME? role??
//gpUpdateRects(screen, 1, rects); //ph0x! _hwscreen
return 0;
}
int gpSetColors(gpSurface *surface, gpColor *colors, int firstcolor, int ncolors) {
float rr, gg, bb;
gpColor colors2[256];
if (currentsurf == DEBUG_SURFACE)
return 1;
for (int i = firstcolor; i < firstcolor + ncolors; i++) {
rr = colors[i].r * gammatab[colors[i].r];
gg = colors[i].g * gammatab[colors[i].g];
bb = colors[i].b * gammatab[colors[i].b];
if (rr > 255)
rr = 255;
if (gg > 255)
gg = 255;
if (bb > 255)
bb = 255;
colors2[i].r = (u8) rr;
colors2[i].g = (u8) gg;
colors2[i].b = (u8) bb;
}
GpPaletteEntryChangeEx(firstcolor, ncolors, (GP_LOGPALENTRY *) colors2,
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--)
// copyRectToScreen((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++)
// copyRectToScreen((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--)
// copyRectToScreen((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++)
// copyRectToScreen((byte *)_screen->pixels + x - dx, _screenWidth, x, 0, 1, height);
// }
// } else {
// // free movement
// // not necessary for now
// }
//}
int16 OSystem_GP32::get_height() {
return _screenHeight;
}
int16 OSystem_GP32::get_width() {
return _screenWidth;
}
//void OSystem_GP32::warpMouse(int, int)
//{
//}
void OSystem_GP32::warpMouse(int x, int y) {
// set_mouse_pos(x, y);
}
void OSystem_GP32::load_gfx_mode() {
GpRectFill(NULL, &LCDbuffer[GAME_SURFACE], 0, 0, 320, 240, 0); //black border
_forceFull = true;
_mode_flags = DF_WANT_RECT_OPTIM | DF_UPDATE_EXPAND_1_PIXEL;
_tmpscreen = NULL;
TMP_SCREEN_WIDTH = (_screenWidth + 3);
switch (_mode) {
case GFX_NORMAL:
//???????
//normal_mode:;
_scaleFactor = 1;
_scaler_proc = Normal1x;
break;
default:
error("Unknown graphics mode");
_scaleFactor = 1;
_scaler_proc = NULL;
}
//
// Create the surface that contains the 8 bit game data
//
_screen =
gpCreateRGBSurface(gpSWSurface, _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
//
_hwscreen =
gpSetVideoMode(_screenWidth * _scaleFactor,
_screenHeight * _scaleFactor, 16,
_full_screen ? (gpFullScreen | gpSWSurface) : gpSWSurface);
if (_hwscreen == NULL)
error("_hwscreen failed");
//
// Create the surface used for the graphics in 16 bit before scaling, and also the overlay
//
/*
// Distinguish 555 and 565 mode
if (_hwscreen->format->Rmask == 0x7C00)
InitScalers(555);
else
InitScalers(565);
*/
//InitScalers(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));
_tmpscreen =
gpCreateRGBSurfaceFrom(tmp_screen, TMP_SCREEN_WIDTH,
_screenHeight + 3, 16, TMP_SCREEN_WIDTH * 2,
_hwscreen->format->Rmask, _hwscreen->format->Gmask,
_hwscreen->format->Bmask, _hwscreen->format->Amask);
if (_tmpscreen == NULL)
error("_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.delay_time = 15;
km.last_time = 0;
}
void OSystem_GP32::unload_gfx_mode() {
if (_screen) {
gpFreeSurface(_screen);
_screen = NULL;
}
if (_hwscreen) {
gpFreeSurface(_hwscreen);
_hwscreen = NULL;
}
if (_tmpscreen) {
free((uint16 *) _tmpscreen->pixels);
gpFreeSurface(_tmpscreen);
_tmpscreen = NULL;
}
}
#include "common/util.h"
void OSystem_GP32::draw_mouse() {
if (!_overlayVisible) {
if (_mouseDrawn || !_mouseVisible)
return;
int x = _mouseCurState.x - _mouseHotspotX;
int y = _mouseCurState.y - _mouseHotspotY;
int w = _mouseCurState.w;
int h = _mouseCurState.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 * _mouseCurState.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.
_mouseOldState.x = x;
_mouseOldState.y = y;
_mouseOldState.w = w;
_mouseOldState.h = h;
// Draw the mouse cursor; backup the covered area in "bak"
///if (gpLockSurface(_screen) == -1)
/// error("gpLockSurface failed: %s.\n", gpGetError());
// 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 != _mouseKeycolor) // Transparent, don't draw
*dst = color;
dst++;
width--;
}
src += _mouseCurState.w - w;
bak += MAX_MOUSE_W - w;
dst += _screenWidth - w;
h--;
}
///gpUnlockSurface(_screen);
// Finally, set the flag to indicate the mouse has been drawn
_mouseDrawn = true;
}
if (_mouseDrawn || !_mouseVisible)
return;
int x = _mouseCurState.x - _mouseHotspotX;
int y = _mouseCurState.y - _mouseHotspotY;
int w = _mouseCurState.w;
int h = _mouseCurState.h;
byte color;
//byte *src = _mouseData; // Image representing the mouse
//uint16 *src = _mouseData; // Image representing the mouse
const 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
//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 * _mouseCurState.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.
_mouseOldState.x = x;
_mouseOldState.y = y;
_mouseOldState.w = w;
_mouseOldState.h = h;
// Draw the mouse cursor; backup the covered area in "bak"
///if (gpLockSurface(_tmpscreen) == -1)
/// error("gpLockSurface failed: %s.\n", gpGetError());
// as dirty
add_dirty_rect(x, y, w, h);
uint16 *bak = (uint16 *) _mouseBackup; // Surface used to backup the area obscured by the mouse
uint16 *dst; // Surface we are drawing into
dst =
(uint16 *) _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 += _mouseCurState.w - w;
bak += MAX_MOUSE_W - w;
dst += TMP_SCREEN_WIDTH - w;
h--;
}
///gpUnlockSurface(_tmpscreen);
// Finally, set the flag to indicate the mouse has been drawn
_mouseDrawn = true;
}
void OSystem_GP32::undraw_mouse() {
//return; //fixme!
if (!_overlayVisible) {
if (!_mouseDrawn)
return;
_mouseDrawn = false;
byte *dst, *bak = _mouseBackup;
const int old_mouse_x = _mouseOldState.x;
const int old_mouse_y = _mouseOldState.y;
const int old_mouse_w = _mouseOldState.w;
const int old_mouse_h = _mouseOldState.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);
}
if (!_mouseDrawn)
return;
_mouseDrawn = false;
uint16 *dst, *bak = (uint16 *) _mouseBackup;
const int old_mouse_x = _mouseOldState.x;
const int old_mouse_y = _mouseOldState.y;
const int old_mouse_w = _mouseOldState.w;
const int old_mouse_h = _mouseOldState.h;
int x, y;
// No need to do clipping here, since draw_mouse() did that already
dst =
(uint16 *) _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);
}
char *gpGetError(void) {
// FIXME: implement
return NULL;
}
/////////////////////////////////////////////////////////////////////////////
//
// GP32 Screen Update Stuff - Mostly 'borrowed' from GP but using gpSDK
//
/////////////////////////////////////////////////////////////////////////////
//// Update the dirty areas of the screen
void OSystem_GP32::updateScreen() {
//Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
internUpdateScreen();
}
// assert(_hwscreen != NULL);
//
// // If the shake position changed, fill the dirty area with blackness
// if (_currentShakePos != _newShakePos) {
// gpRect blackrect = {0, 0, _screenWidth*_scaleFactor, _newShakePos*_scaleFactor};
//
// if (_adjustAspectRatio)
// blackrect.h = real2Aspect(blackrect.h - 1) + 1;
//
// gpFillRect(_hwscreen, &blackrect, 0);
//
// _currentShakePos = _newShakePos;
//
// _forceFull = true;
// }
//
// // Make sure the mouse is drawn, if it should be drawn.
// draw_mouse();
//
// // Check whether the palette was changed in the meantime and update the
// // screen surface accordingly.
// if (_paletteDirtyEnd != 0) {
// gpSetColors(_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) {
//
// gpRect *r;
// uint32 srcPitch, dstPitch;
// gpRect *last_rect = _dirty_rect_list + _num_dirty_rects;
//
// // Convert appropriate parts of the 8bpp image into 16bpp
// if (!_overlayVisible) {
// gpRect 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 (gpBlitSurface(_screen, r, _hwscreen, &dst) != 0) //ph0x! _tmpscreen
// error("gpBlitSurface failed: %s", gpGetError());
// }
// }
//
//// ph0x! (no scaling) cannot skip intro if commented?
//
// srcPitch = _tmpscreen->pitch;
// dstPitch = _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;
//
// if (_overlayVisible) //ph0x fixme?
// _scaler_proc((byte*)_tmpscreen->pixels + (r->x*2+2) + (r->y+1)*srcPitch, srcPitch,
// (byte*)_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;
// }
//
// // 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 (_overlayVisible)
// gpUpdateRects(_hwscreen, _num_dirty_rects, _dirty_rect_list); //ph0x! _hwscreen
// else
// gpUpdateRects(_screen, _num_dirty_rects, _dirty_rect_list);
// }
//
// _num_dirty_rects = 0;
// _forceFull = false;
//}
// Either show or hide the mouse cursor
bool OSystem_GP32::showMouse(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 != _mouseCurState.x || y != _mouseCurState.y) {
_mouseCurState.x = x;
_mouseCurState.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::setMouseCursor(const byte *buf, uint w, uint h,
int hotspot_x, int hotspot_y, byte keycolor, int cursorTargetScale) {
// assert(w <= MAX_MOUSE_W);
// assert(h <= MAX_MOUSE_H);
_mouseCurState.w = w;
_mouseCurState.h = h;
_mouseHotspotX = hotspot_x;
_mouseHotspotY = hotspot_y;
_mouseKeycolor = keycolor;
//??????????
_mouseData = (byte *) buf;
undraw_mouse();
if (_mouseData)
free(_mouseData);
_mouseData = (byte *) malloc(w * h);
memcpy(_mouseData, buf, w * h);
}
// Shaking is used in SCUMM. Set current shake position.
void OSystem_GP32::setShakePos(int shake_pos) {
_newShakePos = shake_pos;
mcshake = shake_pos;
}
// Get the number of milliseconds since the program was started.
uint32 OSystem_GP32::getMillis() {
return GpTickCountGet();
}
// Delay for a specified amount of milliseconds
void OSystem_GP32::delayMillis(uint msecs) {
int n = GpTickCountGet();
while ((GpTickCountGet() - n) < msecs);
}
// Get the next event.
// Returns true if an event was retrieved.
const signed char abc[] = "0123456789abcdefghijklmnopqrstuvwxyz";
signed int abcindex = -1;
void switchsurf(int surf);
void buildgammatab(int val);
/////////////////////////////////////////////////////////////////////////////
//
// GP32 Event Handlers.
//
/////////////////////////////////////////////////////////////////////////////
bool OSystem_GP32::pollEvent(Event & event) {
#define EVENT_COUNT 2 // >=1
//#define MOUSE_MIPS 2 // bg updates wrong if >1 ??
#define MOUSE_MIPS 1 // bg updates wrong if >1 ??
static int lastkey, eventcount = EVENT_COUNT, lastevent = 0;
static int simulate;
static bool backspace = true;
static uint32 t;
int key;
key = gpTrapKey();
if (simulate)
simulate--;
switch (simulate) {
case 5:
lastevent = event.type = EVENT_KEYDOWN;
event.kbd.keycode = event.kbd.ascii = 8;
return true;
break;
case 3:
lastevent = event.type = EVENT_KEYDOWN;
event.kbd.keycode = event.kbd.ascii = abc[abcindex];
return true;
break;
case 4:
case 2:
lastevent = event.type = EVENT_KEYUP;
//event.kbd.keycode = event.kbd.ascii =
return true;
break;
case 1:
lastkey = key = 0;
lastevent = 0;
event.type = (EventType) 0;
break;
}
if (lastevent == EVENT_KEYDOWN) {
lastevent = event.type = EVENT_KEYUP;
//event.kbd.keycode = event.kbd.ascii;
return true;
}
if (key == GPC_VK_NONE) {
lastevent = lastkey = 0;
return false;
}
if (key == lastkey) {
eventcount--;
if (eventcount)
return false;
}
eventcount = EVENT_COUNT;
event.type = EVENT_KEYDOWN;
if (key & GPC_VK_FL) { // L
if (_overlayVisible)
return false;
if (key & GPC_VK_UP) {
if (key == lastkey)
return false;
if (gindex < ARRAYSIZE(scrGamma) - 1)
gindex++;
buildgammatab(gindex);
_paletteDirtyStart = 0;
_paletteDirtyEnd = 255; //fixme?
lastevent = event.type;
lastkey = key;
return true;
} else
if (key & GPC_VK_DOWN) {
if (key == lastkey)
return false;
if (gindex > 0)
gindex--;
buildgammatab(gindex);
_paletteDirtyStart = 0;
_paletteDirtyEnd = 255; //fixme?
lastevent = event.type;
lastkey = key;
return true;
}
if (key == lastkey)
return false;
if (skindex > 0)
skindex--;
event.kbd.keycode = event.kbd.ascii = shortkey[skindex];
lastevent = event.type;
lastkey = key;
return true;
}
lastkey = key;
if (key & GPC_VK_FR) { // R
if (key & GPC_VK_UP) {
if (getMillis() < t)
return false;
//do key=GpKeyGet(); while (key & GPC_VK_UP);
//fixme -2/-1
t = getMillis() + 200;
if (abcindex == -1)
abcindex = 0;
else {
if (abcindex < sizeof(abc) - 2)
abcindex++;
else
abcindex = 0;
}
if (backspace)
simulate = 6;
else {
backspace = true;
simulate = 4;
}
return false;
}
if (key & GPC_VK_DOWN) {
if (getMillis() < t)
return false;
//do key=GpKeyGet(); while (key & GPC_VK_DOWN);
//fixme -2/-1
t = getMillis() + 200;
if (abcindex == -1)
abcindex = abcindex = sizeof(abc) - 2;
else {
if (abcindex > 0)
abcindex--;
else
abcindex = sizeof(abc) - 2;
}
if (backspace)
simulate = 6;
else {
backspace = true;
simulate = 4;
}
return false;
}
if (key & GPC_VK_LEFT) {
abcindex = -1;
event.kbd.keycode = event.kbd.ascii = 8;
lastevent = event.type;
do
key = gpTrapKey();
while (key & GPC_VK_LEFT);
return true;
} else if (key & GPC_VK_RIGHT) {
abcindex = -1;
backspace = false;
return false;
}
if (!_overlayVisible) {
if (lastevent == EVENT_KEYUP)
return false;
if (shortkey[skindex + 1])
skindex++;
event.kbd.keycode = event.kbd.ascii =
shortkey[skindex];
lastevent = event.type;
return true;
}
} else if (key & GPC_VK_START) { // START = menu/enter
if (_overlayVisible)
event.kbd.keycode = event.kbd.ascii = 13;
else {
event.kbd.keycode = event.kbd.ascii = 319;
//buildgammatab(ARRAYSIZE(scrGamma)-1); // moved to colortoRBG
}
lastevent = event.type;
return true;
}
if (key & GPC_VK_SELECT) { // SELECT == escape/skip
if (_overlayVisible) {
do
key = gpTrapKey();
while (key != GPC_VK_NONE); // prevent 2xESC
buildgammatab(gindex);
_paletteDirtyStart = 0;
_paletteDirtyEnd = 255; //fixme?
}
event.kbd.keycode = event.kbd.ascii = 27;
lastevent = event.type;
return true;
}
if (key & GPC_VK_FA) {
if (lastevent == EVENT_LBUTTONUP)
return false;
if (lastevent == EVENT_LBUTTONDOWN) {
lastevent = EVENT_LBUTTONUP;
event.type = EVENT_LBUTTONUP;
} else {
lastevent = EVENT_LBUTTONDOWN;
event.type = EVENT_LBUTTONDOWN;
}
return true;
}
if (key & GPC_VK_FB) {
if (lastevent == EVENT_RBUTTONUP)
return false;
if (lastevent == EVENT_RBUTTONDOWN) {
lastevent = EVENT_RBUTTONUP;
event.type = EVENT_RBUTTONUP;
} else {
lastevent = EVENT_RBUTTONDOWN;
event.type = EVENT_RBUTTONDOWN;
}
return true;
}
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 > _screenHeight - 1)
my = _screenHeight - 1;
}
event.type = EVENT_MOUSEMOVE;
km.x = event.mouse.x = mx;
km.y = event.mouse.y = my;
event.mouse.x /= _scaleFactor;
event.mouse.y /= _scaleFactor;
set_mouse_pos(event.mouse.x, event.mouse.y);
}
/////////////////////////////////////////////////////////////////////////////
//
// GP32 Graphics Stuff -
//
/////////////////////////////////////////////////////////////////////////////
int16 OSystem_GP32::RBGToColor(uint8 r, uint8 g, uint8 b) {
float rr, gg, bb;
rr = r * gammatab2[r];
gg = g * gammatab2[g];
bb = b * gammatab2[b];
if (rr > 255)
rr = 255;
if (gg > 255)
gg = 255;
if (bb > 255)
bb = 255;
r = (u8) rr;
g = (u8) gg;
b = (u8) bb;
//return ((((r>>3)&0x1F) << 11) | (((g>>2)&0x3F) << 5) | ((b>>3)&0x1F)); //ph0x
return (((((r) >> 3) & 0x1F) << 11) | ((((g) >> 3) & 0x1F) << 6) |
(((b) >> 3) & 0x1F) << 1);
}
void OSystem_GP32::colorToRBG(int16 color, uint8 &r, uint8 &g, uint8 &b) {
float rr, gg, bb;
r = ((((color) >> 11) & 0x1F) << 3); //(((color>>11)&0x1F) << 3);
g = ((((color) >> 6) & 0x1F) << 3); //(((color>>5)&0x3F) << 2);
b = ((((color) >> 1) & 0x1F) << 3); //((color&0x1F) << 3);
rr = r * gammatab2[r];
gg = g * gammatab2[g];
bb = b * gammatab2[b];
if (rr > 255)
rr = 255;
if (gg > 255)
gg = 255;
if (bb > 255)
bb = 255;
r = (u8) rr;
g = (u8) gg;
b = (u8) bb;
}
void switchsurf(int surf) {
GPLCDINFO lcd;
GpLcdInfoGet(&lcd);
if (surf == DEBUG_SURFACE) {
if (lcd.lcd_global.U8_lcd.bpp == 16)
GpGraphicModeSet(8, NULL);
currentsurf = DEBUG_SURFACE;
GpSurfaceFlip(&LCDbuffer[(int)currentsurf]);
//GpSetPaletteEntry ( 0, 0,0,0 );
//GpSetPaletteEntry ( 1, 0,0,0 );
//GpSetPaletteEntry ( 2, 255,255,255 );
} else if (surf == GAME_SURFACE) {
//if (lcd.lcd_global.U8_lcd.bpp == 8) GpGraphicModeSet(16, NULL);
currentsurf = GAME_SURFACE;
GpSurfaceFlip(&LCDbuffer[(int)currentsurf]);
//GpSetPaletteEntry ( 2, 0,0,0 );
//GpSetPaletteEntry ( 1, 0,107,84 );
//GpSetPaletteEntry ( 0, 255,255,255 );
} else
error("Switching to false stuface");
}
/////////////////////////////////////////////////////////////////////////////
//
// GP32 Sound Stuff -
//
/////////////////////////////////////////////////////////////////////////////
void OSystem_GP32::clearSoundCallback() {
// _sound_proc = NULL;
// _sound_proc_param = NULL;
}
typedef void SoundProc(void *param, byte *buf, int len);
typedef struct GPSOUNDBUF {
PCM_SR freq; /* Taken from gpmm.h */
PCM_BIT format; /* Taken from gpmm.h */
unsigned int samples; /* Buffer length (in samples) */
void *userdata; /* Userdata which gets passed to the callback function */
SoundProc *callback;
unsigned int pollfreq; /* Frequency of the timer interrupt which polls the playing position
* recommended value: 2*(playingfreq in Hz/GPSOUNDBUF.samples) */
unsigned int samplesize; /* Size of one sample (8bit mono->1, 16bit stereo->4) - don't touch this */
} GPSOUNDBUF;
GPSOUNDBUF gpsndbuf; // for scumm
/* Global variables */
unsigned int frame = 0;
unsigned int *soundPos = 0;
volatile int idx_buf;
unsigned int shiftVal = 0;
void *buffer;
GPSOUNDBUF soundBuf;
/* This routine gets called by the timer interrupt and
* polls the current playing position within the buffer.
*/
//void *blah; // holds "this" for mixer.cpp
void soundtimer(void) {
unsigned int t =
(((unsigned int)(*soundPos) - (unsigned int)buffer) >> shiftVal) >=
soundBuf.samples ? 1 : 0;
if (t != frame) {
unsigned int offs =
((frame == 1) ? (soundBuf.samples << shiftVal) : 0);
soundBuf.callback(soundBuf.userdata /*blah */ , (u8 *) ((unsigned int)buffer + offs), soundBuf.samples << shiftVal); //FIXME (*callback)(param) ?
frame = t;
}
}
int GpSoundBufStart(GPSOUNDBUF *sb) {
frame = 0;
/* Copy the structure */
memcpy(&soundBuf, sb, sizeof(GPSOUNDBUF));
/* Calculate size of a single sample in bytes
* and a corresponding shift value
*/
shiftVal = 0;
switch (soundBuf.freq) {
case PCM_S11:
break;
case PCM_S22:
break;
case PCM_S44:
shiftVal++;
break;
case PCM_M11:
break;
case PCM_M22:
break;
case PCM_M44:
shiftVal++;
break;
}
if (soundBuf.format == PCM_16BIT)
shiftVal++;
soundBuf.samplesize = 1 << shiftVal;
/* Allocate memory for the playing buffer */
buffer = malloc(soundBuf.samplesize * soundBuf.samples * 2);
memset(buffer, 0, soundBuf.samplesize * soundBuf.samples * 2);
/* Set timer interrupt #0 */
if (GpTimerOptSet(0, soundBuf.pollfreq, 0,
soundtimer) == GPOS_ERR_ALREADY_USED)
error("timer slot used");
GpTimerSet(0);
/* Start playing */
GpPcmPlay((unsigned short *)buffer,
soundBuf.samples * soundBuf.samplesize * 2, 1);
GpPcmLock((unsigned short *)buffer, (int *)&idx_buf,
(unsigned int *)&soundPos);
return 0;
}
void GpSoundBufStop(void) {
GpPcmStop();
GpPcmRemove((unsigned short *)buffer);
GpTimerKill(0);
free(buffer);
}
int OSystem_GP32::getOutputSampleRate() const {
return SAMPLES_PER_SEC;
}
// Set the function to be invoked whenever samples need to be generated
// Buffer Length and Poll Frequency changed. DJWillis
bool OSystem_GP32::setSoundCallback(SoundProc proc, void *param) {
gpsndbuf.freq = PCM_S22; // Taken from gpmm.h
gpsndbuf.format = PCM_16BIT; // Taken from gpmm.h
gpsndbuf.samples = 2048; //128; //fixme? // Buffer length (in samples)
//FIXME? crashes if not commented?!
//gpsndbuf.userdata=g_scumm; //param; //fixme? // Userdata which gets passed to the callback function
gpsndbuf.callback = proc; //mycallback; // Callback function (just like in SDL)
//2*((float)22025/(float)s.samples);
gpsndbuf.pollfreq = 8 * (SAMPLES_PER_SEC / gpsndbuf.samples); //fixme
// Frequency of the timer interrupt which polls the playing position
// recommended value: 2*(playingfreq in Hz/GPSOUNDBUF.samples)
//s.samplesize; // Size of one sample (8bit mono->1, 16bit stereo->4) - don't touch this
GpPcmInit(PCM_S22, PCM_16BIT);
GpSoundBufStart(&gpsndbuf);
return true;
}
/////////////////////////////////////////////////////////////////////////////
//
// GP32 Graphics Stuff
//
/////////////////////////////////////////////////////////////////////////////
void OSystem_GP32::get_screen_image(byte *buf) {
/* make sure the mouse is gone */
undraw_mouse();
///if (gpLockSurface(_screen) == -1)
/// error("gpLockSurface failed: %s.\n", gpGetError());
memcpy(buf, _screen->pixels, _screenWidth * _screenHeight);
///gpUnlockSurface(_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
gpSetColors(_screen, _currentPalette, 0, 256);
// blit image
copyRectToScreen(bak_mem, _screenWidth, 0, 0, _screenWidth,
_screenHeight);
free(bak_mem);
updateScreen();
}
// Get or set a property
//uint32 OSystem_GP32::property(int param, Property *value)
//{
// switch(param) {
//
// case PROP_GET_FULLSCREEN:
// return _full_screen;
//}
void OSystem_GP32::setWindowCaption(const char *caption) {
//gGameName = caption; // Would like to return game here like DC port. - DJWillis
}
// CDROM Code - All returns false as the GP32 has no CDROM ;-)
bool OSystem_GP32::openCD(int drive) {
return false;
}
bool OSystem_GP32::pollCD() {
return false;
}
void OSystem_GP32::playCD(int track, int num_loops, int start_frame, int duration) {
}
void OSystem_GP32::stopCD() {
}
void OSystem_GP32::updateCD() {
}
// End CDROM Code.
// Add a new callback timer
// ph0x FIXME: make members
int _timerinterval;
int (*_timercallback)(int);
void voidcallback() {
//printf("timer running");
_timercallback(_timerinterval); //FIXME ?? (*_timercallback)(_timerinterval);
}
void OSystem_GP32::setTimerCallback(TimerProc callback, int timer) {
int timerno = 1; //0 used by sound proc
if (!callback) {
GpTimerKill(timerno);
return;
}
if (GpTimerOptSet(timerno, timer, 0,
voidcallback) == GPOS_ERR_ALREADY_USED)
error("timer slot used");
_timerinterval = timer;
_timercallback = callback;
GpTimerSet(timerno);
}
// Mutex handling - DJWillis Hack
OSystem::MutexRef OSystem_GP32::createMutex(void) {
return NULL;
}
void OSystem_GP32::lockMutex(MutexRef) {
}
void OSystem_GP32::unlockMutex(MutexRef) {
}
void OSystem_GP32::deleteMutex(MutexRef) {
}
// Quit
void OSystem_GP32::quit() {
printf("Quitting...");
exit(0);
}
// Overlay
void OSystem_GP32::showOverlay() {
// hide the mouse
undraw_mouse();
u8 *s = (u8 *) _screen->pixels;
u16 *d = (u16 *) _tmpscreen->pixels;
u8 c;
// convert to 16 bit
for (int y = 0; y < _screenHeight; y++) {
for (int x = 0; x < 320; x++) {
c = *s;
*d++ =
(u16) gpRGB16(_currentPalette[c].r,
_currentPalette[c].g, _currentPalette[c].b);
s++;
}
d += 3; // tmpscreen width is screen+3
}
GpGraphicModeSet(16, NULL); //ph0x
// Test code.
//???????????
//GpRectFill(NULL,&LCDbuffer[GAME_SURFACE], 0, 0, 320, 240, 0); //black border
_overlayVisible = true;
clearOverlay();
}
void OSystem_GP32::hideOverlay() {
// hide the mouse
undraw_mouse();
GpGraphicModeSet(8, NULL); //ph0x
GpRectFill(NULL, &LCDbuffer[GAME_SURFACE], 0, 0, 320, 240, 0); //black border
_overlayVisible = false;
_forceFull = true;
}
void OSystem_GP32::clearOverlay() {
if (!_overlayVisible)
return;
// hide the mouse
undraw_mouse();
// Clear the overlay by making the game screen "look through" everywhere.
gpRect src, dst;
src.x = src.y = 0;
dst.x = dst.y = 1;
src.w = dst.w = _screenWidth;
src.h = dst.h = _screenHeight;
if (gpBlitSurface(_screen, &src, _tmpscreen, &dst) != 0) //FIXME
error("gpBlitSurface failed: %s", gpGetError());
_forceFull = true;
}
void OSystem_GP32::grabOverlay(int16 *buf, int pitch) {
if (!_overlayVisible)
return;
if (_tmpscreen == NULL)
return;
// hide the mouse
undraw_mouse();
///if (gpLockSurface(_tmpscreen) == -1)
/// error("gpLockSurface failed: %s.\n", gpGetError());
int16 *src = (int16 *) _tmpscreen->pixels + TMP_SCREEN_WIDTH + 1;
int h = _screenHeight;
do {
memcpy(buf, src, _screenWidth * 2);
src += TMP_SCREEN_WIDTH;
buf += pitch;
} while (--h);
///gpUnlockSurface(_tmpscreen);
}
void OSystem_GP32::copyRectToOverlay(const int16 * buf, int pitch, int x,
int y, int w, int h) {
if (!_overlayVisible)
return;
if (_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 (gpLockSurface(_tmpscreen) == -1)
/// error("gpLockSurface failed: %s.\n", gpGetError());
int16 *dst =
(int16 *) _tmpscreen->pixels + (y + 1) * TMP_SCREEN_WIDTH + (x +
1);
do {
memcpy(dst, buf, w * 2);
dst += TMP_SCREEN_WIDTH;
buf += pitch;
} while (--h);
///gpUnlockSurface(_tmpscreen);
}
void OSystem_GP32::internUpdateScreen() {
assert(_hwscreen != NULL);
// If the shake position changed, fill the dirty area with blackness
if (_currentShakePos != _newShakePos) {
gpRect blackrect =
{ 0, 0, _screenWidth * _scaleFactor,
_newShakePos * _scaleFactor };
//if (_adjustAspectRatio)
// blackrect.h = real2Aspect(blackrect.h - 1) + 1;
gpFillRect(_hwscreen, &blackrect, 0);
_currentShakePos = _newShakePos;
_forceFull = true;
}
// Make sure the mouse is drawn, if it should be drawn.
draw_mouse();
// Check whether the palette was changed in the meantime and update the
// screen surface accordingly.
if (_paletteDirtyEnd != 0) {
gpSetColors(_screen, _currentPalette + _paletteDirtyStart,
_paletteDirtyStart, _paletteDirtyEnd - _paletteDirtyStart);
_paletteDirtyEnd = 0;
_forceFull = true;
}
//#ifdef USE_OSD
// // OSD visible (i.e. non-transparent)?
// if (_osdAlpha != gpALPHA_TRANSPARENT) {
// // Updated alpha value
// const int diff = gpGetTicks() - _osdFadeStartTime;
// if (diff > 0) {
// if (diff >= kOSDFadeOutDuration) {
// // Back to full transparency
// _osdAlpha = gpALPHA_TRANSPARENT;
// } else {
// // Do a linear fade out...
// const int startAlpha = gpALPHA_TRANSPARENT + kOSDInitialAlpha * (gpALPHA_OPAQUE - gpALPHA_TRANSPARENT) / 100;
// _osdAlpha = startAlpha + diff * (gpALPHA_TRANSPARENT - startAlpha) / kOSDFadeOutDuration;
// }
// gpSetAlpha(_osdSurface, gpRLEACCEL | gpSRCCOLORKEY | gpSRCALPHA, _osdAlpha);
// _forceFull = true;
// }
// }
//#endif
// 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) {
gpRect *r;
gpRect dst;
uint32 srcPitch, dstPitch;
gpRect *last_rect = _dirty_rect_list + _num_dirty_rects;
if (_scaler_proc == Normal1x && !_adjustAspectRatio) {
gpSurface *target =
_overlayVisible ? _tmpscreen : _screen;
for (r = _dirty_rect_list; r != last_rect; ++r) {
dst = *r;
if (_overlayVisible) {
// FIXME: I don't understand why this is necessary...
dst.x--;
dst.y--;
}
dst.y += _currentShakePos;
if (gpBlitSurface(target, r, _hwscreen,
&dst) != 0)
error("gpBlitSurface failed: %s",
gpGetError());
}
} else {
if (!_overlayVisible) {
for (r = _dirty_rect_list; r != last_rect; ++r) {
dst = *r;
dst.x++; // Shift rect by one since 2xSai needs to acces the data around
dst.y++; // any pixel to scale it, and we want to avoid mem access crashes.
if (gpBlitSurface(_screen, r,
_tmpscreen, &dst) != 0)
error
("gpBlitSurface failed: %s",
gpGetError());
}
}
//gpLockSurface(_tmpscreen);
//gpLockSurface(_hwscreen);
srcPitch = _tmpscreen->pitch;
dstPitch = _hwscreen->pitch;
for (r = _dirty_rect_list; r != last_rect; ++r) {
register int dst_y = r->y + _currentShakePos;
register int dst_h = 0;
register int orig_dst_y = 0;
if (dst_y < _screenHeight) {
dst_h = r->h;
if (dst_h > _screenHeight - dst_y)
dst_h = _screenHeight - dst_y;
dst_y *= _scaleFactor;
if (_adjustAspectRatio) {
orig_dst_y = dst_y;
dst_y = real2Aspect(dst_y);
}
_scaler_proc((byte *) _tmpscreen->
pixels + (r->x * 2 + 2) + (r->y +
1) * srcPitch, srcPitch,
(byte *) _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;
if (_adjustAspectRatio
&& orig_dst_y / _scaleFactor <
_screenHeight)
r->h =
stretch200To240((uint8 *)
_hwscreen->pixels, dstPitch, r->w,
r->h, r->x, r->y, orig_dst_y);
}
//gpUnlockSurface(_tmpscreen);
//gpUnlockSurface(_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 = 240;
}
#ifdef USE_OSD
if (_osdAlpha != gpALPHA_TRANSPARENT) {
gpBlitSurface(_osdSurface, 0, _hwscreen, 0);
}
#endif
// Finally, blit all our changes to the screen
gpUpdateRects(_hwscreen, _num_dirty_rects, _dirty_rect_list);
}
_num_dirty_rects = 0;
_forceFull = false;
}
// assert(_hwscreen != NULL);
//
// // If the shake position changed, fill the dirty area with blackness
// if (_currentShakePos != _newShakePos) {
// gpRect blackrect = {0, 0, _screenWidth*_scaleFactor, _newShakePos*_scaleFactor};
// gpFillRect(_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) {
// gpSetColors(_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) {
//
// gpRect *r;
// uint32 srcPitch, dstPitch;
// gpRect *last_rect = _dirty_rect_list + _num_dirty_rects;
//
// // Convert appropriate parts of the 8bpp image into 16bpp
// if (!_overlayVisible) {
// gpRect 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 (gpBlitSurface(_screen, r, _hwscreen, &dst) != 0) //ph0x! gp_tmpscreen
// error("gpBlitSurface failed: %s", gpGetError());
// }
// }
//
// ///gp_LockSurface(gp_tmpscreen);
// ///gp_LockSurface(gp_hwscreen);
//
//// ph0x! (no scaling) cannot skip intro if commented?
//
// srcPitch = _tmpscreen->pitch;
// dstPitch = _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;
//
// if (_overlayVisible) //ph0x fixme?
// _scaler_proc((byte*)_tmpscreen->pixels + (r->x*2+2) + (r->y+1)*srcPitch, srcPitch,
// (byte*)_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;
// }
//
// ///gp_UnlockSurface(gp_tmpscreen);
// ///gp_UnlockSurface(gp_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 (_overlayVisible)
// gpUpdateRects(_hwscreen, _num_dirty_rects, _dirty_rect_list); //ph0x! gp_hwscreen
// else
// gpUpdateRects(_screen, _num_dirty_rects, _dirty_rect_list);
// }
//
// _num_dirty_rects = 0;
// _forceFull = false;
//}
void OSystem_GP32::setFeatureState(Feature f, bool enable) {
switch (f) {
case kFeatureFullscreenMode:
setFullscreenMode(enable);
break;
case kFeatureAspectRatioCorrection:
if (_screenHeight == 200 && _adjustAspectRatio != enable) {
Common::StackLock lock(_graphicsMutex);
//assert(_hwscreen != 0);
_adjustAspectRatio ^= true;
hotswap_gfx_mode();
#ifdef USE_OSD
char buffer[128];
if (_adjustAspectRatio)
sprintf(buffer,
"Enabled aspect ratio correction\n%d x %d -> %d x %d",
_screenWidth, _screenHeight, _hwscreen->w,
_hwscreen->h);
else
sprintf(buffer,
"Disabled aspect ratio correction\n%d x %d -> %d x %d",
_screenWidth, _screenHeight, _hwscreen->w,
_hwscreen->h);
displayMessageOnOSD(buffer);
#endif
// Blit everything to the screen
internUpdateScreen();
// Make sure that an EVENT_SCREEN_CHANGED gets sent later
_modeChanged = true;
}
break;
case kFeatureAutoComputeDirtyRects:
if (enable)
_mode_flags |= DF_WANT_RECT_OPTIM;
else
_mode_flags &= ~DF_WANT_RECT_OPTIM;
break;
default:
break;
}
}
bool OSystem_GP32::hasFeature(Feature f) {
return false;
(f == kFeatureFullscreenMode) || (f == kFeatureAspectRatioCorrection);
// ||
// (f == kFeatureAutoComputeDirtyRects);
}
bool OSystem_GP32::getFeatureState(Feature f) {
switch (f) {
case kFeatureFullscreenMode:
return _full_screen;
case kFeatureAspectRatioCorrection:
return _adjustAspectRatio;
case kFeatureAutoComputeDirtyRects:
return _mode_flags & DF_WANT_RECT_OPTIM;
default:
return false;
}
}
void OSystem_GP32::setFullscreenMode(bool enable) {
Common::StackLock lock(_graphicsMutex);
if (_full_screen != enable) {
assert(_hwscreen != 0);
_full_screen ^= true;
undraw_mouse();
//if (!gpWM_ToggleFullScreen(_hwscreen)) {
// if ToggleFullScreen fails, achieve the same effect with hotswap gfx mode
// hotswap_gfx_mode();
//}
#ifdef USE_OSD
if (_full_screen)
displayMessageOnOSD("Fullscreen mode");
else
displayMessageOnOSD("Windowed mode");
#endif
// Blit everything to the screen
internUpdateScreen();
// Make sure that an EVENT_SCREEN_CHANGED gets sent later
_modeChanged = true;
}
}
static const OSystem::GraphicsMode supportedGraphicsModes[] = {
{"1x", "320x240 16bpp", GFX_NORMAL},
{0, 0, 0}
};
const OSystem::GraphicsMode *OSystem_GP32::getSupportedGraphicsModes() const {
return supportedGraphicsModes;
}
int OSystem_GP32::getDefaultGraphicsMode() const {
return GFX_NORMAL;
}
bool OSystem_GP32::setGraphicsMode(int mode) {
Common::StackLock lock(_graphicsMutex);
int newScaleFactor = 1;
ScalerProc *newScalerProc;
switch (mode) {
case GFX_NORMAL:
newScaleFactor = 1;
newScalerProc = Normal1x;
break;
//case GFX_DOUBLESIZE:
// newScaleFactor = 2;
// newScalerProc = Normal2x;
// break;
//case GFX_TRIPLESIZE:
// newScaleFactor = 3;
// newScalerProc = Normal3x;
// break;
//case GFX_2XSAI:
// newScaleFactor = 2;
// newScalerProc = _2xSaI;
// break;
//case GFX_SUPER2XSAI:
// newScaleFactor = 2;
// newScalerProc = Super2xSaI;
// break;
//case GFX_SUPEREAGLE:
// newScaleFactor = 2;
// newScalerProc = SuperEagle;
// break;
//case GFX_ADVMAME2X:
// newScaleFactor = 2;
// newScalerProc = AdvMame2x;
// break;
//case GFX_ADVMAME3X:
// newScaleFactor = 3;
// newScalerProc = AdvMame3x;
// break;
//case GFX_HQ2X:
// newScaleFactor = 2;
// newScalerProc = HQ2x;
// break;
//case GFX_HQ3X:
// newScaleFactor = 3;
// newScalerProc = HQ3x;
// break;
//case GFX_TV2X:
// newScaleFactor = 2;
// newScalerProc = TV2x;
// break;
//case GFX_DOTMATRIX:
// newScaleFactor = 2;
// newScalerProc = DotMatrix;
// break;
default:
warning("unknown gfx mode %d", mode);
return false;
}
_mode = mode;
_scaler_proc = newScalerProc;
if (newScaleFactor != _scaleFactor) {
_scaleFactor = newScaleFactor;
hotswap_gfx_mode();
}
if (!_screen)
return true;
#ifdef USE_OSD
if (_osdSurface) {
const char *newScalerName = 0;
const GraphicsMode *g = s_supportedGraphicsModes;
while (g->name) {
if (g->id == mode) {
newScalerName = g->description;
break;
}
g++;
}
if (newScalerName) {
char buffer[128];
sprintf(buffer,
"Active graphics filter: %s\n%d x %d -> %d x %d",
newScalerName, _screenWidth, _screenHeight,
_hwscreen->w, _hwscreen->h);
displayMessageOnOSD(buffer);
}
}
#endif
// Blit everything to the screen
_forceFull = true;
internUpdateScreen();
// Make sure that an EVENT_SCREEN_CHANGED gets sent later
_modeChanged = true;
return true;
}
int OSystem_GP32::getGraphicsMode() const {
return _mode;
}
////OSystem *OSystem_GP32::create(int gfx_mode, bool full_screen)
//OSystem *OSystem_GP32::create()
//{
// //OSystem_GP32 *syst = new OSystem_GP32();
//
// //syst->_mode = gfx_mode;
// //syst->_full_screen = full_screen;
// //
// //// allocate palette storage
// //syst->_currentPalette = (gpColor*)calloc(sizeof(gpColor), 256);
//
// //// allocate the dirty rect storage
// //syst->_mouseBackup = (byte*)malloc(MAX_MOUSE_W * MAX_MOUSE_H * MAX_SCALING * 2);
// /*return syst;*/
// return new OSystem_GP32();
//}
//////////////////////////////////////////////////
// GP32 stuff
//////////////////////////////////////////////////
extern "C" int write(int fd, void *p, size_t n);
int write(int fd, void *p, size_t n) { //ph0x hack!
return 0;
}
// Converts 8bit rgb values to a GP32 palette value
void GpSetPaletteEntry(u8 i, u8 r, u8 g, u8 b) {
GP_PALETTEENTRY entry = gpRGB16(r, g, b);
GpPaletteEntryChange(i, 1, &entry, 0);
}
int gpprintf(const char *fmt, ...) {
static bool busy;
static int y;
char s[1024]; // ?
va_list marker;
if (busy)
return 0;
busy = true;
va_start(marker, fmt);
vsnprintf(s, 1024, fmt, marker);
va_end(marker);
#ifdef GPDEBUG
//dprintf("mem: %d ", gm_availablesize());
dprintf(s);
if (s[strlen(s) - 1] != '\n')
dprintf("\n");
//if (s[0]!='>') return r;
#endif
fprintf(stdout, s);
// print to lcd
GpTextOut(NULL, &LCDbuffer[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, &LCDbuffer[DEBUG_SURFACE], 0, 0, 320, 240, 2);
}
busy = false;
return 0;
}
int gpfprintf(FILE *stream, const char *fmt, ...) {
char s[256];
va_list marker;
va_start(marker, fmt);
vsnprintf(s, 256, fmt, marker);
va_end(marker);
return fwrite(s, 1, strlen(s), stream);
}
typedef struct {
FILE f;
ulong size;
ulong p; //cache position
} xfile;
#define XFILE(f) (*(xfile*)f)
#define FCACHE_SIZE 8*1024 // speed up writes
FILE *gpfopen(const char *filename, const char *mode) {
//FIXME: allocation, mode, malloc -> new
ulong m;
FILE *f;
ERR_CODE err;
char s[256];
if (!strchr(filename, '.')) {
sprintf(s, "%s.", filename);
filename = s;
}
//printf(">open %s as %s", filename, mode);
// FIXME add binary/text support
if (tolower(mode[0]) == 'r') {
f = (FILE *) malloc(sizeof(xfile));
m = OPEN_R;
GpFileGetSize(filename, &XFILE(f).size);
err = GpFileOpen(filename, m, f);
} else if (tolower(mode[0]) == 'w') {
//printf("open if as W");
f = (FILE *) malloc(sizeof(xfile) + FCACHE_SIZE);
XFILE(f).size = 0; // FIXME? new file has no size?
XFILE(f).p = 0;
m = OPEN_W;
err = GpFileCreate(filename, ALWAYS_CREATE, f);
} else
error("wrong file mode");
if (!f)
error("%s: cannot crate F_HANDLE", __FUNCTION__);
if (err) {
//printf("IOerr %d", err);
return NULL;
} else
return f;
}
int gpfclose(FILE *f) {
if (!f) {
//warning("closing null file");
return 1;
}
if (*(u32 *)((char *)f - sizeof(u32)) == 0x4321) {
debug(0, "Double closing", __FUNCTION__);
return 1;
} // return 1 ??
if (XFILE(f).p) {
GpFileWrite(*f, (char *)f + sizeof(xfile), XFILE(f).p); // flush cache
XFILE(f).p = 0;
}
ERR_CODE err = GpFileClose(*f);
free(f);
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 *f) {
int len = size * n;
if (!f) {
//warning("writing to null file");
return 0;
}
if (XFILE(f).p + len < FCACHE_SIZE) {
memcpy((char *)f + sizeof(xfile) + XFILE(f).p, ptr, len);
XFILE(f).p += len;
} else {
if (XFILE(f).p) {
GpFileWrite(*f, (char *)f + sizeof(xfile), XFILE(f).p); // flush cache
XFILE(f).p = 0;
}
ERR_CODE err = GpFileWrite(*f, ptr, len);
if (!err)
return n;
else
return -err;
}
return 0;
}
void gpclearerr(FILE *stream) {
//warning("fixme: %s", __FUNCTION__);
}
int gpfeof(FILE *f) { //fixme!
return ftell(f) >= XFILE(f).size;
}
char *gpfgets(char *s, int n, FILE *f) {
int 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;
}
char gpfgetc(FILE *f) {
char c[1];
fread(&c[0], 1, 1, f);
return c[0];
}
int gpfflush(FILE * stream) {
return 0;
}
/*
* GP32 Memory managment.
*/
void *gpmalloc(size_t size) {
u32 np;
u32 *up;
np = (u32) gm_malloc(size + sizeof(u32));
if (np) {
up = (u32 *) np;
*up = 0x1234;
return (void *)(np + sizeof(u32));
}
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) {
u32 np;
u32 *up;
if (!block) {
debug(0, "freeing null pointer");
return;
}
np = ((u32) block) - sizeof(u32);
up = (u32 *) np;
if (*up == 0x4321)
error("%s: double deallocation!", __FUNCTION__);
if (*up != 0x1234)
error("%s: corrupt block!", __FUNCTION__);
*up = 0x4321;
gm_free(up);
}
/*
char *gpstrdup(const char *s) {
char *p=(char*)malloc(strlen(s)+1);
memcpy(p, s, strlen(s)+1);
return p;
}
*/
char *gpstrdup(const char *strSource) {
char *strBuffer;
strBuffer = (char *)malloc(strlen(strSource) + 1);
if (strBuffer)
strcpy(strBuffer, strSource);
return strBuffer;
}
time_t gptime(time_t *timer) {
time_t t = GpTickCountGet() / 1000;
if (timer)
*timer = t;
return t;
}
void gpdeinit() {
fclose(fstdin);
fclose(fstdout);
fclose(fstderr);
}
void gpexit(int code) {
switchsurf(DEBUG_SURFACE);
if (!code) {
printf("----------------------------------------");
printf(" Your GP32 is now restarting... ");
printf("----------------------------------------");
gpdeinit();
// FIXME: use function :)
int n = GpTickCountGet();
while ((GpTickCountGet() - n) < 3000);
GpAppExit();
} else {
printf("Exit Code %d", code);
while (1);
}
}
/****************************************************************
Setup CPU Speed - Calls to CPUSPEED.S
****************************************************************/
void gpCPUSpeed(int freq) {
// To extend use: cpu_speed(CLK_SPEED, DIV_FACTOR, CLK_MODE);
if (freq == 166)
cpu_speed(165000000, 0x2f001, 3); // 40 Bus?
if (freq == 156)
cpu_speed(156000000, 0x2c001, 3); // 36 Bus
if (freq == 133)
cpu_speed(133500000, (81 << 12) | (2 << 4) | 1, 2); // 66 Bus?
if (freq == 132)
cpu_speed(132000000, 0x3a011, 3); // 33 Bus
if (freq == 120)
cpu_speed(120000000, 0x24001, 2);
if (freq == 100)
cpu_speed(102000000, (43 << 12) | (1 << 4) | 1, 2);
if (freq == 66)
cpu_speed(67500000, (37 << 12) | (0 << 4) | 2, 2);
if (freq == 40)
cpu_speed(40000000, 0x48013, 1); // Default
if (freq == 33)
cpu_speed(33750000, (37 << 12) | (0 << 4) | 3, 2); // Ultra slow
}
/****************************************************************
Pre-ScummVM Configuration Menu.
****************************************************************/
int ConfigMenu() {
//#ifndef GP32_GDB
// gpCPUSpeed(40);
//#endif /*GP32_GDB*/
GpSetPaletteEntry(2, 0, 0, 0);
GpSetPaletteEntry(1, 0, 0, 0);
GpSetPaletteEntry(0, 255, 255, 255);
int i, key, fg, bg, choice = 0, y = ENGFONT_H * 7;
int n = ARRAYSIZE(menu);
GpTextOut(NULL, &LCDbuffer[(int)currentsurf], 0, y,
"Configuration Menu", 1);
y += ENGFONT_H;
GpTextOut(NULL, &LCDbuffer[(int)currentsurf], 0, y,
"----------------------------------------", 1);
y += ENGFONT_H;
do {
for (i = 0; i < n; i++) {
if (i == choice) {
fg = 2;
bg = 1;
} else {
fg = 1;
bg = 2;
}
GpRectFill(NULL, &LCDbuffer[(int)currentsurf], 0,
y + i * ENGFONT_H, 320, ENGFONT_H, bg);
char s[256];
sprintf(s, "%s [%s]", menu[i].option,
menu[i].submenu[menu[i].index]);
GpTextOut(NULL, &LCDbuffer[(int)currentsurf], 0,
y + i * ENGFONT_H, s, fg);
}
do
key = gpTrapKey();
while (key == GPC_VK_NONE);
if (key & GPC_VK_DOWN) {
if (choice < n - 1)
choice++;
}
if (key & GPC_VK_UP) {
if (choice > 0)
choice--;
}
if (key & GPC_VK_LEFT) {
if (menu[choice].index > 0)
menu[choice].index--;
}
if (key & GPC_VK_RIGHT) {
if (menu[choice].submenu[menu[choice].index + 1])
menu[choice].index++;
}
//if (key & GPC_VK_START || key & GPC_VK_FA) return 1;
if (key & GPC_VK_FA)
return 1;
//if (key & GPC_VK_SELECT) return 0;
do
key = gpTrapKey();
while (key != GPC_VK_NONE);
} while (1);
}
/****************************************************************
Delay (very simple delay)
****************************************************************/
void Delay(unsigned int ms) {
unsigned int delay_by;
delay_by = GpTickCountGet();
while (GpTickCountGet() - delay_by < ms);
}
/****************************************************************
Triple buffering code
****************************************************************/
void FlipScreen() {
if (nflip == 0) {
GpSurfaceFlip(&LCDbuffer[0]);
nflip = 1;
} else if (nflip == 1) {
GpSurfaceFlip(&LCDbuffer[1]);
nflip = 2;
} else if (nflip == 2) {
GpSurfaceFlip(&LCDbuffer[2]);
nflip = 0;
}
}
/****************************************************************
Clear all the screen buffers
****************************************************************/
void ClearScreen() {
int i;
for (i = 0; i <= BUFFERCOUNT; i++) {
GpRectFill(NULL, &LCDbuffer[i], 0, 0, LCDbuffer[i].buf_w,
LCDbuffer[i].buf_h, 0x00);
}
}
/****************************************************************
Fade to black
****************************************************************/
void FadeToBlack(int delay_time) {
//Fade to black
int x;
for (x = 0; x < 30; x++) {
//Fade it further
GpLcdFade(-1, NULL);
//refresh screen
GpSurfaceFlip(&LCDbuffer[nflip]);
//wait a littel bit
Delay(delay_time);
}
//Now Clear all the buffers
ClearScreen();
//Turn the fading off
GpLcdNoFade(NULL);
//Now flip to end it all and leave it black
FlipScreen();
}
/****************************************************************
Fade to White
****************************************************************/
void FadeToWhite(int delay_time) {
//Fade to black
int x;
for (x = 0; x < 30; x++) {
//Fade it further
GpLcdFade(1, NULL);
//refresh screen
GpSurfaceFlip(&LCDbuffer[nflip]);
//wait a littel bit
Delay(delay_time);
}
//Now Clear all the buffers
ClearScreen();
//Turn the fading off
GpLcdNoFade(NULL);
//Now flip to end it all and leave it black
FlipScreen();
}
/****************************************************************
Initialise the File System
****************************************************************/
void InitFileSystem() {
//Initialises GP32 file system
GpFatInit();
GpRelativePathSet("gp:\\gpmm");
// Create folders on SMC if there not there
// For storing games, saves, config and scummvm.ini.
GpDirCreate("gp:\\data", NOT_IF_EXIST);
GpDirCreate("gp:\\data\\scummvm", NOT_IF_EXIST);
GpDirCreate("gp:\\data\\scummvm\\games", NOT_IF_EXIST);
GpDirCreate("gp:\\data\\scummvm\\config", NOT_IF_EXIST);
}
/****************************************************************
Splash Screen - show splash screen
****************************************************************/
void InitSplashPal() {
static GP_HPALETTE h_splash_pal = NULL;
if (h_splash_pal)
GpPaletteDelete(h_splash_pal);
h_splash_pal = GpPaletteCreate(gfx_splash_palnb, gfx_splash_Pal);
GpPaletteDelete(GpPaletteSelect(h_splash_pal));
GpPaletteRealize();
}
int SplashScreen() {
int key;
ClearScreen();
InitSplashPal();
// Show the screen (load into all buffers - ready for screen transition)
GpBitBlt(NULL, &LCDbuffer[0], 0, 0, gfx_splash_width,
gfx_splash_height, (unsigned char *)gfx_splash, 0, 0,
gfx_splash_width, gfx_splash_height);
GpBitBlt(NULL, &LCDbuffer[1], 0, 0, gfx_splash_width,
gfx_splash_height, (unsigned char *)gfx_splash, 0, 0,
gfx_splash_width, gfx_splash_height);
GpBitBlt(NULL, &LCDbuffer[2], 0, 0, gfx_splash_width,
gfx_splash_height, (unsigned char *)gfx_splash, 0, 0,
gfx_splash_width, gfx_splash_height);
// Refresh screen (show the logo)
FlipScreen();
// Initialise the File System
// Done during SpashScreen to hide folder create (if needed) from users.
InitFileSystem();
//TODO: Put branchs for Start and Select and act accordingly.
do {
do
key = gpTrapKey();
while (key == GPC_VK_NONE);
if (key & GPC_VK_START) {
FadeToBlack(20);
return 0;
}
if (key & GPC_VK_SELECT) {
FadeToWhite(20);
ConfigMenu();
return 0;
}
do
key = gpTrapKey();
while (key != GPC_VK_NONE);
} while (1);
//Fade the screen into GP32 setup or ScummVM.
//FadeToWhite(100);
}
/****************************************************************
Read and write the GP32 config file to the SMC
****************************************************************/
void ConfigRead() {
FILE *f;
f = fopen("gp:\\data\\scummvm\\config\\config.dat", "r");
if (f) {
for (unsigned int i = 0; i < ARRAYSIZE(menu); i++)
fread(&menu[i].index, 1, sizeof(menu[i].index), f);
fclose(f);
}
}
void ConfigWrite() {
FILE *f;
f = fopen("gp:\\data\\scummvm\\config\\config.dat", "w");
if (f) {
for (unsigned int i = 0; i < ARRAYSIZE(menu); i++)
fwrite(&menu[i].index, 1, sizeof(menu[i].index), f);
fclose(f);
}
}
/****************************************************************
Prepare GP32
****************************************************************/
void InitLCD() {
// Initialize graphics
GpGraphicModeSet(COLOUR_8BIT_MODE, NULL);
// Set the current buffer
nflip = 0;
short i;
for (i = 0; i <= BUFFERCOUNT; i++) {
GpLcdSurfaceGet(&LCDbuffer[i], i);
}
}
void Init() {
// Setup the LCD.
InitLCD();
// Load the Splash Screen and give the option of config or ScummVM.
// also sets up file system.
SplashScreen();
//GpSetPaletteEntry ( 2, 0,0,0 );
//GpSetPaletteEntry ( 1, 0,0,0 );
//GpSetPaletteEntry ( 0, 255,255,255 );
//// fixme - use get function
////currentsurf=DEBUG_SURFACE;
////GpSurfaceSet(&LCDbuffer[(int)currentsurf]);
//GpSurfaceSet(&LCDbuffer[nflip]);
//GpLcdEnable();
//stderr = fstdout = fopen("gp:\\data\\scummvm\\config\\debug.out", "w");
//stdin = NULL; //fixme?
////fstdin = fopen("stdin", "w");
////fstderr = fopen("stderr", "w");
//printf(" ScummVM for the GP32");
//printf("----------------------------------------");
//printf("PRIVATE BUILD - DO NOT PASS ON!");
//printf("ScummVM (c) 2001-4 The ScummVM Team");
//printf("GP32 Backend (c) 2004 by DJWillis");
//printf("Compiled %s, %s", __DATE__, __TIME__);
//printf("----------------------------------------");
//printf(" Press 'A' to Start ScummVM");
//printf("----------------------------------------");
///*
//ERR_CODE err;
//
//unsigned long bad;
//err = GpFormat("gp:", FORMAT_RESCUE, &bad);
//char s[256];
//GpRelativePathGet(s);
//*/
}
//void *gpmemset (void *s, int c, size_t n) {
// for (int i=n-1; i>=0; i--)
// ((char*)s)[i]=(char)c;
//}
//
//void *gpmemcpy (void *dest, const void *src, size_t n) {
// for (int i=n-1; i>=0; i--)
// ((char*)dest)[i]=((char*)src)[i];
//}
void buildgammatab(int val) {
float g = 1;
for (int i = 0; i < 256; i++) {
gammatab[255 - i] = g;
g *= scrGamma[val];
}
}
void buildgammatab2(int val) {
float g = 1;
for (int i = 0; i < 256; i++) {
gammatab2[255 - i] = g;
g *= scrGamma[val];
}
}
int stricmp(const char *string1, const char *string2) {
char src[4096];
char dest[4096];
int i;
for (i = 0; i < strlen(string1); i++)
if (string1[i] >= 'A' && string1[i] <= 'Z')
src[i] = string1[i] + 32;
else
src[i] = string1[i];
src[i] = 0;
for (i = 0; i < strlen(string2); i++)
if (string2[i] >= 'A' && string2[i] <= 'Z')
dest[i] = string2[i] + 32;
else
dest[i] = string2[i];
dest[i] = 0;
return strcmp(src, dest);
}
int strnicmp(const char *string1, const char *string2, int len) {
char src[4096];
char dest[4096];
int i;
for (i = 0; i < strlen(string1) && i < len; i++)
if (string1[i] >= 'A' && string1[i] <= 'Z')
src[i] = string1[i] + 32;
else
src[i] = string1[i];
src[i] = 0;
for (i = 0; i < strlen(string2) && i < len; i++)
if (string2[i] >= 'A' && string2[i] <= 'Z')
dest[i] = string2[i] + 32;
else
dest[i] = string2[i];
dest[i] = 0;
return strncmp(src, dest, len);
}
extern "C" void GpMain(void *arg);
extern "C" int scummvm_main(int argc, char *argv[]);
void GpMain(void *arg) {
#ifdef GP32_GDB
OpenUSB();
InstallISR();
#endif /*GP32_GDB */
// Wank up the GP32 good and propper ;-)
// asm volatile(" \n"
//" mov r0, #0x01 \n"
//" ldr r1, [r0] \n"
//" \n"
//:
//:
//:"r0", "r1");
// FIXME: causes crash?! (if not at first line of gpmain())
buildgammatab(gindex);
buildgammatab2(ARRAYSIZE(scrGamma) - 1);
Init();
// ConfigRead();
//if ()
//{
// ConfigWrite();
//}
//ConfigMenu();
//ConfigWrite();
// fixme - use get function
//currentsurf=GAME_SURFACE;
//GpSurfaceFlip(&LCDbuffer[(int)currentsurf]);
#ifndef GP32_GDB
int CPUSpeed =
atoi((const char *)menu[MENU_CPUSPEED].submenu[menu[MENU_CPUSPEED].
index]);
#endif /*GP32_GDB */
//static char *argv[] = { "scummvm", NULL, NULL, NULL };
// char *argv[] = { "scummvm", (char*)menu[MENU_MUSICDRV].submenu[menu[MENU_MUSICDRV].index]};
// static int argc = 4;
// Game Testing...
//int argc = 2;
//int argc = 4; char *argv[] = { "scummvm", "-enull", "-pgp:\\gpmm\\scummvm\\sky\\", "sky" };
int argc = 4;
char *argv[] = { "scummvm", "-enull", "", "" };
while (1) {
// Only set the CPU speed if the GDB Stub is NOT needed.
// No point calling ClearScreen(); as we want to see any odd stuff.
#ifndef GP32_GDB
gpCPUSpeed(CPUSpeed);
ClearScreen();
#endif /*GP32_GDB */
//FadeToWhite(200);
//exit(scummvm_main(argc, argv));
////////////////cast_argv = f(const_cast<double&>(d));
//////////////char* argv_;
////////////// argv_ = const_cast<*char*>(argv);
scummvm_main(argc, argv);
}
}