Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

gp32.cpp

/* 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: /cvsroot/scummvm/scummvm/backends/gp32/gp32.cpp,v 1.27.2.1 2005/10/18 02:11:16 sev Exp $
 *
 */

/*
 *
 * 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);
      }
}

Generated by  Doxygen 1.6.0   Back to index