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

gp32_osys.cpp

/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-0-11-1/backends/platform/gp32/gp32_osys.cpp $
 * $Id: gp32_osys.cpp 30944 2008-02-23 22:50:18Z sev $
 *
 */

#include "common/scummsys.h"
#include "common/system.h"

#include "common/rect.h"
#include "common/savefile.h"
#include "common/config-manager.h"
#include "graphics/surface.h"

#include "gp32_osys.h"
#include "globals.h"

static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
      {0, 0, 0}
};

OSystem_GP32::OSystem_GP32() :
            _screenWidth(0), _screenHeight(0), _gameScreen(NULL), _hwScreen(NULL),
            _overlayVisible(false), _forceFull(false), _adjustAspectRatio(false),
            /*_paletteDirtyStart(0), _paletteDirtyEnd(0),*/
            _mouseBuf(NULL), _mouseHeight(0), _mouseWidth(0), _mouseKeyColor(0),
            _mouseHotspotX(0), _mouseHotspotY(0) {
      NP("OSys::OSystem_GP32()");
      // allocate palette storage
      memset(_currentPalette, 0, 256 * sizeof(uint16));

      memset(&_km, 0, sizeof(_km));

      // HACK: bring mouse cursor to center
      _mouseX = 160;
      _mouseY = 120;
}

OSystem_GP32::~OSystem_GP32() {
      NP("OSys::~OSystem_GP32()");
}

bool OSystem_GP32::hasFeature(Feature f) {
      NP("OSys::hasFeature()");
      return false;
}

void OSystem_GP32::setFeatureState(Feature f, bool enable) {
      NP("OSys::setFeatureState()");
}

bool OSystem_GP32::getFeatureState(Feature f) {
      NP("OSys::getFeatureState()");
      return false;
}

const OSystem::GraphicsMode* OSystem_GP32::getSupportedGraphicsModes() const {
      NP("OSys::getSupportedGraphicsModes()");
      return s_supportedGraphicsModes;
}


int OSystem_GP32::getDefaultGraphicsMode() const {
      NP("OSys::getSupportedGraphicsModes()");
      return -1;
}

bool OSystem_GP32::setGraphicsMode(int mode) {
      NP("OSys::setGraphicsMode()");
      return true;
}

bool OSystem_GP32::setGraphicsMode(const char *name) {
      NP("OSys::setGraphicsMode()");
      return true;
}

int OSystem_GP32::getGraphicsMode() const {
      NP("OSys::getGraphicsMode()");
      return -1;
}

void OSystem_GP32::initSize(uint width, uint height) {
      NP("OSys::initSize()");

      if (width == _screenWidth && height == _screenHeight)
            return;

      _screenWidth = width;
      _screenHeight = height;

      if (height != 200)
            _adjustAspectRatio = false;

      _overlayWidth = width;
      _overlayHeight = height;
//    _overlayWidth = 320;
//    _overlayHeight = 240;

      // Create the surface that contains the 8 bit game data
      _gameScreen = new uint8[_screenWidth * _screenHeight];

      // Create the surface that contains the scaled graphics in 16 bit mode
      _tmpScreen = frameBuffer2;

      // Create the surface that is connected with hardware screen
      _hwScreen = frameBuffer1;

      _overlayBuffer = new OverlayColor[_overlayWidth * _overlayHeight];

      _km.x_max = _screenWidth - 1;
      _km.y_max = _screenHeight - 1;
      _km.x = _mouseX;
      _km.y = _mouseY;
      _km.delay_time = 25;
      _km.last_time = 0;

      // Clear Screen
      gp_fillRect(_hwScreen, 0, 0, 320, 240, 0xFFFF);
}

int16 OSystem_GP32::getHeight() {
      //NP("OSys::getHeight()");
      return _screenHeight;
}

int16 OSystem_GP32::getWidth() {
      //NP("OSys::getWidth()");
      return _screenWidth;
}

void OSystem_GP32::setPalette(const byte *colors, uint start, uint num) {
      //NP("OSys::setPalette()");
      const byte *b = colors;
      uint i;
      uint16 *base = _currentPalette + start;
      for (i = 0; i < num; i++) {
            base[i] = gp_RGBTo16(b[0], b[1], b[2]);
            b += 4;
      }

//    if (start < _paletteDirtyStart)
//          _paletteDirtyStart = start;

//    if (start + num > _paletteDirtyEnd)
//          _paletteDirtyEnd = start + num;
}

void OSystem_GP32::grabPalette(byte *colors, uint start, uint num) {
      NP("OSys::grabPalette()");
}

void OSystem_GP32::copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h) {
      //NP("OSys::copyRectToScreen()");
      //Clip the coordinates
      if (x < 0) {
            w += x;
            src -= x;
            x = 0;
      }

      if (y < 0) {
            h += y;
            src -= y * pitch;
            y = 0;
      }

      if (w > _screenWidth - x) {
            w = _screenWidth - x;
      }

      if (h > _screenHeight - y) {
            h = _screenHeight - y;
      }

      if (w <= 0 || h <= 0)
            return;
      
      byte *dst = _gameScreen + y * _screenWidth + x;

      if (_screenWidth == pitch && pitch == w) {
            memcpy(dst, src, h * w);
      } else {
            do {
                  memcpy(dst, src, w);
                  src += pitch;
                  dst += _screenWidth;
            } while (--h);
      }
}

Graphics::Surface *OSystem_GP32::lockScreen() {
      _framebuffer.pixels = _gameScreen;
      _framebuffer.w = _screenWidth;
      _framebuffer.h = _screenHeight;
      _framebuffer.pitch = _screenWidth;
      _framebuffer.bytesPerPixel = 1;

      return &_framebuffer;
}

void OSystem_GP32::unlockScreen() {
      // The screen is always completely update anyway, so we don't have to force a full update here.
}

//TODO: Implement Dirty rect?
void OSystem_GP32::updateScreen() {
      uint16 *buffer;
      //TODO: adjust shakePos

      // draw gamescreen
      buffer = &_tmpScreen[240 - _screenHeight];
      for (int x = 0; x < _screenWidth; x++) {
            for (int y = 0; y < _screenHeight; y++) {
                  *buffer++ = _currentPalette[_gameScreen[((_screenHeight - 1) - y) * _screenWidth + x]];
            }
            buffer += 240 - _screenHeight;
      }

      // draw overlay
      if (_overlayVisible) {
            buffer = &_tmpScreen[240 - _overlayHeight];
            for (int x = 0; x < _overlayWidth; x++) {
                  for (int y = 0; y < _overlayHeight; y++) {
                        *buffer++ = _overlayBuffer[((_overlayHeight - 1) - y) * _overlayWidth + x];
                  }
                  buffer += 240 - _overlayHeight;
            }
      }

      // draw mouse
      //adjust cursor position
      int mX = _mouseX - _mouseHotspotX;
      int mY = _mouseY - _mouseHotspotY;
      //if (_overlayVisible)
      //else
      if (_mouseVisible)
            for (int y = 0; y < _mouseHeight; y++) {
                  for (int x = 0; x < _mouseWidth; x++) {
                        if (mX + x < _screenWidth && mY + y < _screenHeight && mX + x >= 0 && mY + y >= 0)
                              if (_mouseBuf[y * _mouseWidth + x] != _mouseKeyColor)
                                    gpd_drawPixel16(_tmpScreen, mX + x, mY + y, _currentPalette[_mouseBuf[y * _mouseWidth + x]]);
                  }
            }

      //TODO: draw softkeyboard
      //gp_flipScreen();
      //_hwScreen = frameBuffer1;
      //_tmpScreen = frameBuffer2;
      memcpy(_hwScreen, _tmpScreen, LCD_WIDTH * LCD_HEIGHT * sizeof(uint16));
}

void OSystem_GP32::setShakePos(int shakeOffset) {
      //NP("OSys::setShakePos()");
}

void OSystem_GP32::showOverlay() {
      //NP("OSys::showOverlay()");
      _overlayVisible = true;
      clearOverlay();
}

void OSystem_GP32::hideOverlay() {
      //NP("OSys::hideOverlay()");
      _overlayVisible = false;
      clearOverlay();
      _forceFull = true;
}

// Clear overlay with game screen
//TODO: Optimize?
void OSystem_GP32::clearOverlay() {
      //NP("OSys::clearOverlay()");
      if (!_overlayVisible)
            return;

      uint8 *s = _gameScreen;
      OverlayColor *d = _overlayBuffer;
      uint8 c;
      for (int y = 0; y < _overlayHeight; y++) {
            for (int x = 0; x < _overlayWidth; x++) {
                  c = *s;
                  *d++ = _currentPalette[c];
                  s++;
            }
      }

      _forceFull = true;
}

void OSystem_GP32::grabOverlay(OverlayColor *buf, int pitch) {
      //NP("OSys::grabOverlay()");
      int h = _overlayHeight;
      OverlayColor *src = _overlayBuffer;

      do {
            memcpy(buf, src, _overlayWidth * sizeof(OverlayColor));
            src += _overlayWidth;
            buf += pitch;
      } while (--h);
}

void OSystem_GP32::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) {
      //NP("OSys::copyRectToOverlay()");

      //Clip the coordinates
      if (x < 0) {
            w += x;
            buf -= x;
            x = 0;
      }

      if (y < 0) {
            h += y;
            buf -= y * pitch;
            y = 0;
      }

      if (w > _overlayWidth - x) {
            w = _overlayWidth - x;
      }

      if (h > _overlayHeight - y) {
            h = _overlayHeight - y;
      }

      if (w <= 0 || h <= 0)
            return;

      
      OverlayColor *dst = _overlayBuffer + y * _overlayWidth + x;
      if (_overlayWidth == pitch && pitch == w) {
            memcpy(dst, buf, h * w * sizeof(OverlayColor));
      } else {
            do {
                  memcpy(dst, buf, w * sizeof(OverlayColor));
                  buf += pitch;
                  dst += _overlayWidth;
            } while (--h);
      }
}

int16 OSystem_GP32::getOverlayHeight() {
      return getHeight();
}

int16 OSystem_GP32::getOverlayWidth() {
      return getWidth();
}

OverlayColor OSystem_GP32::RGBToColor(uint8 r, uint8 g, uint8 b) {
      return gp_RGBTo16(r, g, b);
}

void OSystem_GP32::colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b) {
      gp_16ToRGB(color, &r, &g, &b);
}

bool OSystem_GP32::showMouse(bool visible) {
      NP("OSys::showMouse()");
      if (_mouseVisible == visible)
            return visible;

      bool last = _mouseVisible;
      _mouseVisible = visible;

      updateScreen();

      return last;
}

void OSystem_GP32::warpMouse(int x, int y) {
      //NP("OSys::warpMouse()");
      //assert(x > 0 && x < _screenWidth);
      //assert(y > 0 && y < _screenHeight);
      _mouseX = x;
      _mouseY = y;
}

void OSystem_GP32::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor, int cursorTargetScale) {
      //NP("OSys::setMouseCursor()");
      _mouseWidth = w;
      _mouseHeight = h;

      _mouseHotspotX = hotspotX;
      _mouseHotspotY = hotspotY;

      _mouseKeyColor = keycolor;

      if (_mouseBuf)
            free(_mouseBuf);

      _mouseBuf = (byte *)malloc(w * h);
      memcpy(_mouseBuf, buf, w * h);
}

void OSystem_GP32::handleKbdMouse() {
      uint32 curTime = getMillis();
      if (curTime >= _km.last_time + _km.delay_time) {
            _km.last_time = curTime;
            if (_km.x_down_count == 1) {
                  _km.x_down_time = curTime;
                  _km.x_down_count = 2;
            }
            if (_km.y_down_count == 1) {
                  _km.y_down_time = curTime;
                  _km.y_down_count = 2;
            }

            if (_km.x_vel || _km.y_vel) {
                  if (_km.x_down_count) {
                        if (curTime > _km.x_down_time + _km.delay_time * 12) {
                              if (_km.x_vel > 0)
                                    _km.x_vel++;
                              else
                                    _km.x_vel--;
                        } else if (curTime > _km.x_down_time + _km.delay_time * 8) {
                              if (_km.x_vel > 0)
                                    _km.x_vel = 5;
                              else
                                    _km.x_vel = -5;
                        }
                  }
                  if (_km.y_down_count) {
                        if (curTime > _km.y_down_time + _km.delay_time * 12) {
                              if (_km.y_vel > 0)
                                    _km.y_vel++;
                              else
                                    _km.y_vel--;
                        } else if (curTime > _km.y_down_time + _km.delay_time * 8) {
                              if (_km.y_vel > 0)
                                    _km.y_vel = 5;
                              else
                                    _km.y_vel = -5;
                        }
                  }

                  //GPDEBUG("%d %d - %d %d", _km.x, _km.y, _km.x_vel, _km.y_vel);
                  _km.x += _km.x_vel;
                  _km.y += _km.y_vel;

                  if (_km.x < 0) {
                        _km.x = 0;
                        _km.x_vel = -1;
                        _km.x_down_count = 1;
                  } else if (_km.x > _km.x_max) {
                        _km.x = _km.x_max;
                        _km.x_vel = 1;
                        _km.x_down_count = 1;
                  }

                  if (_km.y < 0) {
                        _km.y = 0;
                        _km.y_vel = -1;
                        _km.y_down_count = 1;
                  } else if (_km.y > _km.y_max) {
                        _km.y = _km.y_max;
                        _km.y_vel = 1;
                        _km.y_down_count = 1;
                  }

                  warpMouse(_km.x, _km.y);
            }
      }
}

void OSystem_GP32::fillMouseEvent(Common::Event &event, int x, int y) {
      event.mouse.x = x;
      event.mouse.y = y;

      // Update the "keyboard mouse" coords
      _km.x = x;
      _km.y = y;

      // Optionally perform aspect ratio adjusting
      //if (_adjustAspectRatio)
      //    event.mouse.y = aspect2Real(event.mouse.y);
}

bool OSystem_GP32::pollEvent(Common::Event &event) {
      //NP("OSys::pollEvent()");
      GP32BtnEvent ev;

      handleKbdMouse();

      if (!gp_pollButtonEvent(&ev))
            return false;
      
      switch(ev.type) {
      case BUTTON_DOWN:
            if (ev.button == GPC_VK_LEFT) {
                  _km.x_vel = -1;
                  _km.x_down_count = 1;
            }
            if (ev.button == GPC_VK_RIGHT) {
                  _km.x_vel =  1;
                  _km.x_down_count = 1;
            }
            if (ev.button == GPC_VK_UP) {
                  _km.y_vel = -1;
                  _km.y_down_count = 1;
            }
            if (ev.button == GPC_VK_DOWN) {
                  _km.y_vel =  1;
                  _km.y_down_count = 1;
            }
            if (ev.button == GPC_VK_START) {    // START = menu/enter
                  event.type = Common::EVENT_KEYDOWN;
                  if (_overlayVisible)
                        event.kbd.keycode = event.kbd.ascii = 13;
                  else {
                        event.kbd.keycode = Common::KEYCODE_F5;
                        event.kbd.ascii = Common::ASCII_F5;
                  }
                  return true;
            }
            if (ev.button == GPC_VK_SELECT) {   // SELECT = pause
                  event.type = Common::EVENT_KEYDOWN;
                  event.kbd.keycode = event.kbd.ascii = 32;
                  return true;
            }
            if (ev.button == GPC_VK_FL) {
                  event.type = Common::EVENT_KEYDOWN;
                  event.kbd.keycode = event.kbd.ascii = '0';
                  return true;
            }
            if (ev.button == GPC_VK_FR) { // R = ESC
                  event.type = Common::EVENT_KEYDOWN;
                  event.kbd.keycode = event.kbd.ascii = 27;
                  return true;
            }
            if (ev.button == GPC_VK_FA) {
                  event.type = Common::EVENT_LBUTTONDOWN;
                  fillMouseEvent(event, _km.x, _km.y);
                  return true;
            }
            if (ev.button == GPC_VK_FB) {
                  event.type = Common::EVENT_RBUTTONDOWN;
                  fillMouseEvent(event, _km.x, _km.y);
                  return true;
            }
            break;
      case BUTTON_UP:
            if (ev.button == GPC_VK_LEFT) {
                  if (_km.x_vel < 0) {
                        _km.x_vel = 0;
                        _km.x_down_count = 0;
                  }
                  event.type = Common::EVENT_MOUSEMOVE;
                  fillMouseEvent(event, _km.x, _km.y);
                  return true;
            }
            if (ev.button == GPC_VK_RIGHT) {
                  if (_km.x_vel > 0) {
                        _km.x_vel = 0;
                        _km.x_down_count = 0;
                  }
                  event.type = Common::EVENT_MOUSEMOVE;
                  fillMouseEvent(event, _km.x, _km.y);
                  return true;
            }
            if (ev.button == GPC_VK_UP) {
                  if (_km.y_vel < 0) {
                        _km.y_vel = 0;
                        _km.y_down_count = 0;
                  }
                  event.type = Common::EVENT_MOUSEMOVE;
                  fillMouseEvent(event, _km.x, _km.y);
                  return true;
            }
            if (ev.button == GPC_VK_DOWN) {
                  if (_km.y_vel > 0) {
                        _km.y_vel = 0;
                        _km.y_down_count = 0;
                  }
                  event.type = Common::EVENT_MOUSEMOVE;
                  fillMouseEvent(event, _km.x, _km.y);
                  return true;
            }

            if (ev.button == GPC_VK_START) {
                  event.type = Common::EVENT_KEYUP;
                  if (_overlayVisible)
                        event.kbd.keycode = event.kbd.ascii = 13;
                  else {
                        event.kbd.keycode = Common::KEYCODE_F5;
                        event.kbd.ascii = Common::ASCII_F5;
                  }
                  return true;
            }
            if (ev.button == GPC_VK_SELECT) {
                  event.type = Common::EVENT_KEYUP;
                  event.kbd.keycode = event.kbd.ascii = 32;
                  return true;
            }
            if (ev.button == GPC_VK_FL) {
                  event.type = Common::EVENT_KEYUP;
                  event.kbd.keycode = event.kbd.ascii = '0';
                  return true;
            }
            if (ev.button == GPC_VK_FR) {
                  event.type = Common::EVENT_KEYUP;
                  event.kbd.keycode = event.kbd.ascii = 27;
                  return true;
            }
            if (ev.button == GPC_VK_FA) {
                  event.type = Common::EVENT_LBUTTONUP;
                  fillMouseEvent(event, _km.x, _km.y);
                  return true;
            }
            if (ev.button == GPC_VK_FB) {
                  event.type = Common::EVENT_RBUTTONUP;
                  fillMouseEvent(event, _km.x, _km.y);
                  return true;
            }
            break;
      default:
            error("Unknown Common::Event!");
      }

      if (gp_getButtonPressed(GPC_VK_LEFT) ||
            gp_getButtonPressed(GPC_VK_RIGHT) ||
            gp_getButtonPressed(GPC_VK_UP) ||
            gp_getButtonPressed(GPC_VK_DOWN)) {
            event.type = Common::EVENT_MOUSEMOVE;
            fillMouseEvent(event, _km.x, _km.y);
            return true;
      }
      return false;
}

uint32 OSystem_GP32::getMillis() {
      return GpTickCountGet();
}

void OSystem_GP32::delayMillis(uint msecs) {
      int startTime = GpTickCountGet();
      while (GpTickCountGet() < startTime + msecs);
}

// Add a new callback timer
//FIXME: Add to member
int _timerInterval;
int (*_timerCallback)(int);

static void _timerCallbackVoid() {
      //NP("timer running");
      _timerCallback(_timerInterval);     //FIXME ?? (*_timercallback)(_timerinterval);
}

void OSystem_GP32::setTimerCallback(TimerProc callback, int interval) {
      //NP("OSys::setTimerCallback()");

      int timerNo = 1;

      if (callback == NULL) {
            GpTimerKill(timerNo);
            return;
      }

      if (GpTimerOptSet(timerNo, interval, 0, _timerCallbackVoid) == GPOS_ERR_ALREADY_USED) {
            error("Timer slot is already used");
      }

      _timerInterval = interval;
      _timerCallback = callback;

      GpTimerSet(timerNo);
}

OSystem::MutexRef OSystem_GP32::createMutex() {
//    NP("OSys::createMutex()");
      return NULL;
}

void OSystem_GP32::lockMutex(MutexRef mutex) {
//    NP("OSys::lockMutex()");
}

void OSystem_GP32::unlockMutex(MutexRef mutex) {
//    NP("OSys::unlockMutex()");
}

void OSystem_GP32::deleteMutex(MutexRef mutex) {
//    NP("OSys::deleteMutex()");
}

bool OSystem_GP32::setSoundCallback(SoundProc proc, void *param) {
      //NP("OSys::setSoundCallback()");

      GPSOUNDBUF gpSoundBuf;

      ConfMan.setBool("FM_medium_quality", (g_vars.fmQuality == FM_QUALITY_MED));
      ConfMan.setBool("FM_high_quality", (g_vars.fmQuality == FM_QUALITY_HI));
      //ConfMan.set("output_rate", (int)g_vars.sampleRate);

      if (ConfMan.hasKey("output_rate"))
            _samplesPerSec = ConfMan.getInt("output_rate");
            
      _samplesPerSec = (int)g_vars.sampleRate; //hack
      
      if (_samplesPerSec == 0) {
            return false;
      }

      if (_samplesPerSec < 0)
            _samplesPerSec = SAMPLES_PER_SEC;

      // Originally, we always used 2048 samples. This loop will produce the
      // same result at 22050 Hz, and should hopefully produce something
      // sensible for other frequencies. Note that it must be a power of two.

      uint32 samples = 0x8000;

      for (;;) {
            if ((1000 * samples) / _samplesPerSec < 100)
                  break;
            samples >>= 1;
      }

      switch(_samplesPerSec) {
            case 44100:
            case 22050:
            case 11025:
                  break;
            default:
                  _samplesPerSec = 11025;
      }

      gpSoundBuf.freq = _samplesPerSec;
      gpSoundBuf.format = 16;
      gpSoundBuf.channels = 2;
      gpSoundBuf.samples = samples;
      gpSoundBuf.userdata = param;
      gpSoundBuf.callback = proc;
      gp_soundBufStart(&gpSoundBuf);

      // For Safety...
      GPDEBUG("_samplesPerSec = %d, samples = %d", _samplesPerSec, samples);
      gp_delay(1000);
      return true;
}

void OSystem_GP32::clearSoundCallback() {
      //NP("OSys::clearSoundCallback()");
      if (_samplesPerSec != 0)
            gp_soundBufStop();
}

int OSystem_GP32::getOutputSampleRate() const {
      //NP("OSys::getOutputSampleRate()");
      return _samplesPerSec;
}

void OSystem_GP32::quit() {
      //NP("OSys::quit()");
      clearSoundCallback();
      setTimerCallback(0, 0);
      exit(0);
}

void OSystem_GP32::setWindowCaption(const char *caption) {
      NP("OSys::setWindowCaption(%s)", caption);
}

void OSystem_GP32::displayMessageOnOSD(const char *msg) {
      NP("OSys::displayMessageOnOSD(%s)", msg);
}

OSystem *OSystem_GP32_create() {
      NP("OSys::OSystem_GP32_create()");
      return new OSystem_GP32();
}

Generated by  Doxygen 1.6.0   Back to index