aboutsummaryrefslogtreecommitdiff
path: root/backends/psp/osys_psp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'backends/psp/osys_psp.cpp')
-rw-r--r--backends/psp/osys_psp.cpp657
1 files changed, 657 insertions, 0 deletions
diff --git a/backends/psp/osys_psp.cpp b/backends/psp/osys_psp.cpp
new file mode 100644
index 0000000000..1437bcfa91
--- /dev/null
+++ b/backends/psp/osys_psp.cpp
@@ -0,0 +1,657 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2005 The ScummVM project
+ * Copyright (C) 2005 Joost Peters PSP Backend
+ * Copyright (C) 2005 Thomas Mayer PSP Backend
+ * Copyright (C) 2005 Paolo Costabel PSP 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "common/scummsys.h"
+
+#include "common/rect.h"
+#include "backends/psp/osys_psp.h"
+
+#include "common/config-manager.h"
+
+#include <pspgu.h>
+
+#include "./trace.h"
+
+#define SCREEN_WIDTH 480
+#define SCREEN_HEIGHT 272
+
+extern bool g_quit;
+
+unsigned short *DrawBuffer = (unsigned short *)0x44044000;
+unsigned short *DisplayBuffer = (unsigned short *)0x44000000;
+
+unsigned long RGBToColour(unsigned long r, unsigned long g, unsigned long b) {
+ return (((b >> 3) << 10) | ((g >> 3) << 5) | ((r >> 3) << 0)) | 0x8000;
+}
+
+void putPixel(uint16 x, uint16 y, unsigned long colour) {
+ *(unsigned short *)(DrawBuffer + (y << 9) + x ) = colour;
+}
+
+const OSystem::GraphicsMode OSystem_PSP::s_supportedGraphicsModes[] = {
+ { "320x200 (centered)", "320x200 16-bit centered", CENTERED_320X200 },
+ { "353x272 (best-fit, centered)", "353x272 16-bit centered", CENTERED_435X272 },
+ { "480x272 (full screen)", "480x272 16-bit stretched", STRETCHED_480X272 },
+ { "362x272 (4:3, centered)", "362x272 16-bit centered", CENTERED_362X272 },
+ {0, 0, 0}
+};
+
+
+OSystem_PSP::OSystem_PSP() : _screenWidth(0), _screenHeight(0), _offscreen(0), _overlayBuffer(0), _overlayVisible(false), _shakePos(0), _mouseBuf(0), _prevButtons(0), _lastPadCheck(0), _padAccel(0) {
+
+ memset(_palette, 0, sizeof(_palette));
+
+ _samplesPerSec = 0;
+
+ //init SDL
+ uint32 sdlFlags = SDL_INIT_AUDIO | SDL_INIT_TIMER;
+ SDL_Init(sdlFlags);
+
+ sceDisplaySetMode(0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ sceDisplaySetFrameBuf((char *)DisplayBuffer, 512, 1, 1);
+ sceDisplayWaitVblankStart();
+}
+
+OSystem_PSP::~OSystem_PSP() {
+ if (_offscreen) free(_offscreen);
+ if (_overlayBuffer) free(_overlayBuffer);
+ if (_mouseBuf) free(_mouseBuf);
+}
+
+bool OSystem_PSP::hasFeature(Feature f)
+{
+ return false;
+}
+
+void OSystem_PSP::setFeatureState(Feature f, bool enable)
+{
+}
+
+bool OSystem_PSP::getFeatureState(Feature f)
+{
+ return false;
+}
+
+const OSystem::GraphicsMode* OSystem_PSP::getSupportedGraphicsModes() const
+{
+ return s_supportedGraphicsModes;
+}
+
+
+int OSystem_PSP::getDefaultGraphicsMode() const
+{
+ return -1;
+}
+
+bool OSystem_PSP::setGraphicsMode(int mode)
+{
+ return true;
+}
+
+bool OSystem_PSP::setGraphicsMode(const char *name)
+{
+ return true;
+}
+
+int OSystem_PSP::getGraphicsMode() const
+{
+ return -1;
+}
+
+void OSystem_PSP::initSize(uint width, uint height, int overlayScale) {
+ _screenWidth = width;
+ _screenHeight = height;
+ _offscreen = (byte *)malloc(width * height);
+
+ if(overlayScale == -1)
+ overlayScale = 1;
+
+ _overlayScale = overlayScale;
+ _overlayBuffer = (OverlayColor *)malloc(width * overlayScale * height * overlayScale * sizeof(OverlayColor));
+ bzero(_offscreen, width * height);
+ bzero(_overlayBuffer, width * overlayScale * height * overlayScale);
+
+ _mouseVisible = false;
+}
+
+int16 OSystem_PSP::getHeight() {
+ return _screenHeight;
+}
+
+int16 OSystem_PSP::getWidth() {
+ return _screenWidth;
+}
+
+void OSystem_PSP::setPalette(const byte *colors, uint start, uint num) {
+ const byte *b = colors;
+
+ for (uint i = 0; i < num; ++i) {
+ _palette[start + i] = RGBToColour(b[0], b[1], b[2]);
+ b += 4;
+ }
+}
+
+void OSystem_PSP::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) {
+ //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;
+
+
+ byte *dst = _offscreen + y * _screenWidth + x;
+ if (_screenWidth == pitch && pitch == w) {
+ memcpy(dst, buf, h * w);
+ } else {
+ do {
+ memcpy(dst, buf, w);
+ buf += pitch;
+ dst += _screenWidth;
+ } while (--h);
+ }
+}
+
+void OSystem_PSP::updateScreen() {
+ unsigned short *temp;
+
+ uint xStart = (SCREEN_WIDTH >> 1) - (_screenWidth >> 1);
+ uint yStart = (SCREEN_HEIGHT >> 1) - (_screenHeight >> 1);
+
+ for (int i = 0; i < _screenHeight; ++i) {
+ for (int j = 0; j < _screenWidth; ++j) {
+ putPixel(xStart + j, yStart + i, _palette[_offscreen[i * _screenWidth +j]]);
+ }
+ }
+
+ if(_overlayVisible) {
+ for (int i = 0; i < _screenHeight * _overlayScale; ++i) {
+ for (int j = 0; j < _screenWidth * _overlayScale; ++j) {
+
+ OverlayColor pixel = _overlayBuffer[(i * _screenWidth +j)];
+
+ if(pixel & 0x8000)
+ putPixel(xStart + j, yStart + i, pixel);
+ }
+ }
+ }
+
+ //draw mouse on top
+ if (_mouseVisible) {
+ for (int y = 0; y < _mouseHeight; ++y) {
+ for (int x = 0; x < _mouseWidth; ++x) {
+ if (_mouseBuf[y * _mouseHeight + x] != _mouseKeyColour) {
+ int my = _mouseY + y; // + _mouseHotspotY;
+ int mx = _mouseX + x; // + _mouseHotspotX;
+
+ if (mx >= 0 && mx < _screenWidth && my >= 0 && my < _screenHeight)
+ putPixel(xStart + mx, yStart + my, _palette[_mouseBuf[y * _mouseHeight + x]]);
+ }
+ }
+ }
+ }
+
+
+ // switch buffers
+ temp = DrawBuffer;
+ DrawBuffer = DisplayBuffer;
+ DisplayBuffer = temp;
+ sceDisplayWaitVblankStart();
+ sceDisplaySetFrameBuf((char *)DisplayBuffer, 512, 1, 1);
+
+}
+
+void OSystem_PSP::setShakePos(int shakeOffset) {
+ _shakePos = shakeOffset;
+}
+
+void OSystem_PSP::showOverlay ()
+{
+ _overlayVisible = true;
+}
+
+void OSystem_PSP::hideOverlay ()
+{
+ PSPDebugTrace("OSystem_PSP::hideOverlay called\n");
+ _overlayVisible = false;
+}
+
+void OSystem_PSP::clearOverlay ()
+{
+ PSPDebugTrace("clearOverlay\n");
+ bzero(_overlayBuffer, _screenWidth * _overlayScale * _screenHeight * _overlayScale * sizeof(OverlayColor));
+}
+
+void OSystem_PSP::grabOverlay (OverlayColor *buf, int pitch)
+{
+}
+
+void OSystem_PSP::copyRectToOverlay (const OverlayColor *buf, int pitch, int x, int y, int w, int h)
+{
+ PSPDebugTrace("copyRectToOverlay\n");
+
+ //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*_overlayScale - x) {
+ w = _screenWidth*_overlayScale - x;
+ }
+
+ if (h > _screenHeight*_overlayScale - y) {
+ h = _screenHeight*_overlayScale - y;
+ }
+
+ if (w <= 0 || h <= 0)
+ return;
+
+
+ OverlayColor *dst = _overlayBuffer +( y * _screenWidth * _overlayScale + x);
+ if (_screenWidth == pitch && pitch == w) {
+ memcpy(dst, buf, h * _overlayScale * w * _overlayScale * sizeof(OverlayColor));
+ } else {
+ do {
+ memcpy(dst, buf, w * _overlayScale * sizeof(OverlayColor));
+ buf += pitch;
+ dst += _screenWidth * _overlayScale;
+ } while (--h);
+ }
+}
+
+int16 OSystem_PSP::getOverlayHeight()
+{
+ return getHeight() * _overlayScale;
+}
+
+int16 OSystem_PSP::getOverlayWidth()
+{
+ return getWidth() * _overlayScale;
+}
+
+OverlayColor OSystem_PSP::RGBToColor(uint8 r, uint8 g, uint8 b)
+{
+ return (((r >> 3) & 0x1F) | (((g >> 3) & 0x1F) << 5) | (((b >> 3) & 0x1F) << 10 ) ) | 0x8000;
+}
+
+void OSystem_PSP::colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b)
+{
+ r = ((color & 0x1F) << 3);
+ g = (((color >> 5) & 0x1F) << 3);
+ b = (((color >> 10) & 0x1F) << 3);
+}
+
+OverlayColor OSystem_PSP::ARGBToColor(uint8 a, uint8 r, uint8 g, uint8 b)
+{
+ OverlayColor color = RGBToColor(r, g, b);
+
+ if(a == 255)
+ color |= 0x8000;
+
+ return color;
+}
+
+void OSystem_PSP::colorToARGB(OverlayColor color, uint8 &a, uint8 &r, uint8 &g, uint8 &b)
+{
+ colorToRGB(color, r, g, b);
+ if(color & 0x8000)
+ a = 255;
+ else
+ a = 0;
+}
+
+void OSystem_PSP::grabPalette(byte *colors, uint start, uint num)
+{
+ uint i;
+ uint16 color;
+
+ for(i=start; i < start+num; i++)
+ {
+ color = _palette[i];
+ *colors++ = ((color & 0x1F) << 3);
+ *colors++ = (((color >> 5) & 0x1F) << 3);
+ *colors++ = (((color >> 10) & 0x1F) << 3);
+ *colors++ = (color & 0x8000 ? 255 : 0);
+ }
+}
+
+bool OSystem_PSP::showMouse(bool visible) {
+ bool last = _mouseVisible;
+ _mouseVisible = visible;
+ return last;
+}
+
+void OSystem_PSP::warpMouse(int x, int y) {
+ //assert(x > 0 && x < _screenWidth);
+ //assert(y > 0 && y < _screenHeight);
+ _mouseX = x;
+ _mouseY = y;
+}
+
+void OSystem_PSP::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor, int cursorTargetScale) {
+ //TODO: handle cursorTargetScale
+ _mouseWidth = w;
+ _mouseHeight = h;
+
+ _mouseHotspotX = hotspotX;
+ _mouseHotspotY = hotspotY;
+
+ _mouseKeyColour = keycolor;
+
+ if (_mouseBuf)
+ free(_mouseBuf);
+
+ _mouseBuf = (byte *)malloc(w * h);
+ memcpy(_mouseBuf, buf, w * h);
+}
+
+#define PAD_CHECK_TIME 40
+#define PAD_DIR_MASK (PSP_CTRL_UP | PSP_CTRL_DOWN | PSP_CTRL_LEFT | PSP_CTRL_RIGHT)
+
+bool OSystem_PSP::pollEvent(Event &event) {
+ s8 analogStepAmountX = 0;
+ s8 analogStepAmountY = 0;
+/*
+ SceCtrlData pad;
+
+ sceCtrlSetSamplingCycle(0);
+ sceCtrlSetSamplingMode(1);
+ sceCtrlReadBufferPositive(&pad, 1);
+*/
+ uint32 buttonsChanged = pad.Buttons ^ _prevButtons;
+
+ /* check if user exited using the Home button */
+ if (g_quit) {
+ g_quit = false; //set g_quit back to false or else pollEvent keeps looping..
+
+ warning("g_quit signal caught, sending EVENT_QUIT to VM engine");
+ event.type = OSystem::EVENT_QUIT;
+ return true;
+ }
+
+ if (buttonsChanged & (PSP_CTRL_CROSS | PSP_CTRL_CIRCLE | PSP_CTRL_LTRIGGER | PSP_CTRL_RTRIGGER | PSP_CTRL_START | PSP_CTRL_SELECT | PSP_CTRL_SQUARE)) {
+ if (buttonsChanged & PSP_CTRL_CROSS) {
+ event.type = (pad.Buttons & PSP_CTRL_CROSS) ? OSystem::EVENT_LBUTTONDOWN : OSystem::EVENT_LBUTTONUP;
+ }
+ else if (buttonsChanged & PSP_CTRL_CIRCLE) {
+ event.type = (pad.Buttons & PSP_CTRL_CIRCLE) ? OSystem::EVENT_RBUTTONDOWN : OSystem::EVENT_RBUTTONUP;
+ }
+ else {
+ //any of the other buttons.
+ event.type = buttonsChanged & pad.Buttons ? OSystem::EVENT_KEYDOWN : OSystem::EVENT_KEYUP;
+ event.kbd.flags = 0;
+
+ if (buttonsChanged & PSP_CTRL_LTRIGGER) {
+ event.kbd.keycode = SDLK_ESCAPE;
+ event.kbd.ascii = 27;
+ } else if (buttonsChanged & PSP_CTRL_RTRIGGER) {
+ event.kbd.keycode = SDLK_RETURN;
+ event.kbd.ascii = 13;
+ } else if (buttonsChanged & PSP_CTRL_START) {
+ event.kbd.keycode = SDLK_F5;
+ event.kbd.ascii = 319;
+/* } else if (buttonsChanged & PSP_CTRL_SELECT) {
+ event.kbd.keycode = SDLK_0;
+ event.kbd.ascii = '0';
+*/ } else if (buttonsChanged & PSP_CTRL_SQUARE) {
+ event.kbd.keycode = SDLK_PERIOD;
+ event.kbd.ascii = '.';
+ }
+
+ }
+
+ event.mouse.x = _mouseX;
+ event.mouse.y = _mouseY;
+ _prevButtons = pad.Buttons;
+ return true;
+ }
+
+ uint32 time = getMillis();
+ if (time - _lastPadCheck > PAD_CHECK_TIME) {
+ _lastPadCheck = time;
+ int16 newX = _mouseX;
+ int16 newY = _mouseY;
+
+ if (pad.Lx < 100) {
+ analogStepAmountX = pad.Lx - 100;
+ }
+ else if (pad.Lx > 155) {
+ analogStepAmountX = pad.Lx - 155;
+ }
+
+ if (pad.Ly < 100) {
+ analogStepAmountY = pad.Ly - 100;
+ }
+ else if (pad.Ly > 155) {
+ analogStepAmountY = pad.Ly - 155;
+ }
+
+ if (pad.Buttons & PAD_DIR_MASK ||
+ analogStepAmountX != 0 || analogStepAmountY != 0) {
+ if (_prevButtons & PAD_DIR_MASK) {
+ if (_padAccel < 16) _padAccel++;
+ } else _padAccel = 0;
+
+ _prevButtons = pad.Buttons;
+
+ if (pad.Buttons & PSP_CTRL_LEFT)
+ newX -= _padAccel >> 2;
+ if (pad.Buttons & PSP_CTRL_RIGHT)
+ newX += _padAccel >> 2;
+ if (pad.Buttons & PSP_CTRL_UP)
+ newY -= _padAccel >> 2;
+ if (pad.Buttons & PSP_CTRL_DOWN)
+ newY += _padAccel >> 2;
+
+ // If no movement then this has no effect
+ if (pad.Buttons & PSP_CTRL_TRIANGLE) {
+ // Fine control mode for analog
+ if (analogStepAmountX != 0)
+ if (analogStepAmountX > 0)
+ newX += analogStepAmountX - (analogStepAmountX - 1);
+ else
+ newX -= -analogStepAmountX - (-analogStepAmountX - 1);
+
+ if (analogStepAmountY != 0)
+ if (analogStepAmountY > 0)
+ newY += analogStepAmountY - (analogStepAmountY - 1);
+ else
+ newY -= -analogStepAmountY - (-analogStepAmountY - 1);
+ }
+ else {
+ newX += analogStepAmountX >> ((_screenWidth == 640 || (_overlayVisible && _overlayScale > 1)) ? 2 : 3);
+ newY += analogStepAmountY >> ((_screenWidth == 640 || (_overlayVisible && _overlayScale > 1)) ? 2 : 3);
+ }
+
+ if (newX < 0) newX = 0;
+ if (newY < 0) newY = 0;
+ if(_overlayVisible)
+ {
+ if (newX >= _screenWidth*_overlayScale) newX = _screenWidth*_overlayScale - 1;
+ if (newY >= _screenHeight*_overlayScale) newY = _screenHeight*_overlayScale - 1;
+ }
+ else
+ {
+ if (newX >= _screenWidth) newX = _screenWidth - 1;
+ if (newY >= _screenHeight) newY = _screenHeight - 1;
+ }
+
+ if ((_mouseX != newX) || (_mouseY != newY)) {
+ event.type = OSystem::EVENT_MOUSEMOVE;
+ event.mouse.x = _mouseX = newX;
+ event.mouse.y = _mouseY = newY;
+ return true;
+ }
+ } else {
+ //reset pad acceleration
+ _padAccel = 0;
+ }
+ }
+
+ return false;
+}
+
+uint32 OSystem_PSP::getMillis() {
+ return SDL_GetTicks();
+}
+
+void OSystem_PSP::delayMillis(uint msecs) {
+ sceKernelDelayThread(1); // Sleep thread for 1 millionth of a second to allow callback threads to run
+ SDL_Delay(msecs);
+}
+
+void OSystem_PSP::setTimerCallback(TimerProc callback, int interval) {
+ SDL_SetTimer(interval, (SDL_TimerCallback)callback);
+}
+
+OSystem::MutexRef OSystem_PSP::createMutex(void) {
+ return (MutexRef)SDL_CreateMutex();
+}
+
+void OSystem_PSP::lockMutex(MutexRef mutex) {
+ SDL_mutexP((SDL_mutex *)mutex);
+}
+
+void OSystem_PSP::unlockMutex(MutexRef mutex) {
+ SDL_mutexV((SDL_mutex *)mutex);
+}
+
+void OSystem_PSP::deleteMutex(MutexRef mutex) {
+ SDL_DestroyMutex((SDL_mutex *)mutex);
+}
+
+bool OSystem_PSP::setSoundCallback(SoundProc proc, void *param) {
+ SDL_AudioSpec desired;
+ SDL_AudioSpec obtained;
+
+ memset(&desired, 0, sizeof(desired));
+
+ if (ConfMan.hasKey("output_rate"))
+ _samplesPerSec = ConfMan.getInt("output_rate");
+ else
+ _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.
+
+ uint16 samples = 0x8000;
+
+ for (;;) {
+ if (samples / (_samplesPerSec / 1000) < 100)
+ break;
+ samples >>= 1;
+ }
+
+ desired.freq = _samplesPerSec;
+ desired.format = AUDIO_S16SYS;
+ desired.channels = 2;
+ desired.samples = samples;
+ desired.callback = proc;
+ desired.userdata = param;
+ if (SDL_OpenAudio(&desired, &obtained) != 0) {
+ return false;
+ }
+ // Note: This should be the obtained output rate, but it seems that at
+ // least on some platforms SDL will lie and claim it did get the rate
+ // even if it didn't. Probably only happens for "weird" rates, though.
+ _samplesPerSec = obtained.freq;
+ SDL_PauseAudio(0);
+ return true;
+}
+
+void OSystem_PSP::clearSoundCallback() {
+ SDL_CloseAudio();
+}
+
+int OSystem_PSP::getOutputSampleRate() const {
+ return _samplesPerSec;
+}
+
+bool OSystem_PSP::openCD(int drive) {
+ return false;
+}
+
+bool OSystem_PSP::pollCD() {
+ return false;
+}
+
+void OSystem_PSP::playCD(int track, int num_loops, int start_frame, int duration) {
+}
+
+void OSystem_PSP::stopCD() {
+}
+
+void OSystem_PSP::updateCD() {
+}
+
+void OSystem_PSP::quit() {
+ clearSoundCallback();
+ SDL_Quit();
+ sceGuTerm();
+ sceKernelExitGame();
+}
+
+void OSystem_PSP::setWindowCaption(const char *caption) {
+}
+
+void OSystem_PSP::displayMessageOnOSD(const char *msg) {
+}
+
+
+/* moved to psp-gu.cpp */
+/*
+OSystem *OSystem_PSP_create() {
+ return new OSystem_PSP();
+}
+*/
+// Correct pixel format ABBBBBGGGGGRRRRR
+int gBitFormat = 1555;
+