diff options
Diffstat (limited to 'backends/platform/psp')
24 files changed, 832 insertions, 1740 deletions
diff --git a/backends/platform/psp/Makefile b/backends/platform/psp/Makefile index 7f9ae153eb..dab3c34b51 100644 --- a/backends/platform/psp/Makefile +++ b/backends/platform/psp/Makefile @@ -67,7 +67,7 @@ endif # Variables for common Scummvm makefile CXX = psp-g++ CXXFLAGS = -O3 -Wall -Wno-multichar -fno-exceptions -fno-rtti -DEFINES = -D__PSP__ -DNONSTANDARD_PORT -DDISABLE_TEXT_CONSOLE -DDISABLE_COMMAND_LINE -DUSE_ZLIB -DDISABLE_DOSBOX_OPL -DUSE_RGB_COLOR +DEFINES = -D__PSP__ -DNONSTANDARD_PORT -DDISABLE_TEXT_CONSOLE -DDISABLE_COMMAND_LINE -DUSE_ZLIB -DDISABLE_DOSBOX_OPL -DUSE_RGB_COLOR -DUSE_ELF_LOADER -DMIPS_TARGET LDFLAGS := INCDIR := $(srcdir) . $(srcdir)/engines/ $(PSPSDK)/include @@ -87,8 +87,8 @@ CXX_UPDATE_DEP_FLAG = -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP # Variables for dynamic plugin building PLUGIN_PREFIX = PLUGIN_SUFFIX = .plg -PLUGIN_EXTRA_DEPS = plugin.syms scummvm-psp.elf -PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,--just-symbols=scummvm-psp.org.elf,-Tplugin.ld,--retain-symbols-file,plugin.syms -lstdc++ -lc +PLUGIN_EXTRA_DEPS = $(srcdir)/backends/plugins/elf/plugin.syms scummvm-psp.elf +PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,--just-symbols=scummvm-psp.org.elf,-T$(srcdir)/backends/plugins/psp/plugin.ld,--retain-symbols-file,$(srcdir)/backends/plugins/elf/plugin.syms -lstdc++ -lc # PSP-specific variables STRIP = psp-strip @@ -126,7 +126,8 @@ endif # PSP LIBS PSPLIBS = -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk \ -lpsputility -lpspuser -lpsppower -lpsphprm -lpspsdk -lpsprtc -lpspaudio -lpspaudiocodec \ - -lpspkernel + -lpspkernel -lpspnet_inet + # Add in PSPSDK includes and libraries. LIBS += -lpng -lz -lstdc++ -lc -lm $(PSPLIBS) @@ -142,14 +143,16 @@ OBJS := powerman.o \ input.o \ cursor.o \ trace.o \ - psploader.o \ pspkeyboard.o \ audio.o \ thread.o \ rtc.o \ mp3.o \ png_loader.o \ - tests.o + image_viewer.o \ + tests.o \ + dummy.o + BACKEND := psp @@ -167,7 +170,7 @@ PSP_EBOOT_PIC1 = pic1.png PSP_EBOOT_SND0 = NULL PSP_EBOOT_PSAR = NULL -LDFLAGS += -Wl,-Tmain_prog.ld +LDFLAGS += -Wl,-T../../plugins/psp/main_prog.ld all: $(PSP_EBOOT) diff --git a/backends/platform/psp/README.PSP b/backends/platform/psp/README.PSP index 0849d68c78..b83f1cab6d 100644 --- a/backends/platform/psp/README.PSP +++ b/backends/platform/psp/README.PSP @@ -6,6 +6,7 @@ Installation - Copy the relevant game datafiles to your memory stick (location doesn't matter). - Install ScummVM like any other homebrew. - Run ScummVM and use the launcher to add games and run them. + - Press Start to return to the launcher and play another game. Controls ======== @@ -20,9 +21,10 @@ Cross - Left Mouse Button (usually the main button) Circle - Right Mouse Button (secondary button in some games) Square - '.' (skip dialogue in some games e.g. Scumm) Right trigger + Square - Spacebar (useful in Gobli*ns and SCI games) -Start - Global Menu. Allows you to 'Return To Launcher' to play another game Right trigger + Start - F5 (Main Menu in some games) Select - Show/Hide Virtual Keyboard. Hold down to move keyboard onscreen (with D-Pad). +Right trigger + Select - Show Image Viewer (see below) +Start - Global Menu. Allows you to 'Return To Launcher' to play another game Virtual Keyboard Mode ===================== @@ -37,6 +39,34 @@ Buttons/Triggers - Choose a specific character in the square. The four center c Analog - Moves in a direction (left/right/up/down) (Useful to keep moving while typing in AGI games among other things) + +Image Viewer +============ +For your convenience, I've included a simple image viewer in the PSP port. +You can view anything you want while playing a game. +There are a few simple rules to follow: + +- Images must be of PNG format. If you have images in another format, many + graphics utilities will convert them for you. +- Images must be named psp_image1.png, psp_image2.png etc. This is to make + sure there's no possible conflict between image files and game files. +- Images must be placed in the game directories. When using the image viewer, + only the images of the particular game being played will be available for viewing. +- Don't place any images in the ScummVM directory, or you won't be able to see + the images in the game directories. +- There's no guarantee that you'll be able to view your image. This is because + big images take a lot of memory (more than the size of the image on disk). If there + isn't enough memory left to show the image, ScummVM will tell you so. Try to make the + image smaller by either shrinking it or reducing the colors to 256 color palette mode. + +Image Viewer Controls: +===================== +Left/Right - previous/next image (e.g. go from psp_image1.png to psp_image2.png) +Up/down - zoom in/out +Analog - move around the image +Triggers, Start: - exit image viewer + + 1st Person Game Mode (Can be ignored by most users) ==================== This is a special mode built for 1st person games like Lands of Lore. If you don't have these games you can @@ -49,9 +79,12 @@ Square - Is the modifier key instead of Right Trigger. Left/Right Trigger - Strafe left/right D-Pad Left/Right - Turn left/right Square + D-Pad - F1/F2/F3/F4 +Square + Select - Image Viewer Square + Start - Esc (shows game menu) + + Notes ===== - Notice that you can switch between games! This is much faster than quitting diff --git a/backends/platform/psp/display_client.cpp b/backends/platform/psp/display_client.cpp index 916b6c1aae..9d4f573e28 100644 --- a/backends/platform/psp/display_client.cpp +++ b/backends/platform/psp/display_client.cpp @@ -347,7 +347,6 @@ void Buffer::copyFromRect(const byte *buf, uint32 pitch, int destX, int destY, u PspMemory::fastCopy(dst, buf, _pixelFormat.pixelsToBytes(recHeight * recWidth)); } else { do { - //memcpy(dst, buf, recWidthInBytes); if (_pixelFormat.swapRB) PspMemorySwap::fastSwap(dst, buf, recWidthInBytes, _pixelFormat); else @@ -379,45 +378,45 @@ void Buffer::copyToArray(byte *dst, int pitch) { } while (--h); } -/* We can size the buffer either by texture size (multiple of 2^n) or source size. The GU can - really handle both, but is supposed to get only 2^n size buffers */ void Buffer::setSize(uint32 width, uint32 height, HowToSize textureOrSource/*=kSizeByTextureSize*/) { DEBUG_ENTER_FUNC(); - PSP_DEBUG_PRINT("w[%u], h[%u], %s\n", width, height, textureOrSource ? "size by source" : "size by texture"); - + + // We can size the buffer either by texture size (multiple of 2^n) or source size. + // At higher sizes, increasing the texture size to 2^n is a waste of space. At these sizes kSizeBySourceSize should be used. + _sourceSize.width = width; _sourceSize.height = height; - _textureSize.width = scaleUpToPowerOfTwo(width); + _textureSize.width = scaleUpToPowerOfTwo(width); // can only scale up to 512 _textureSize.height = scaleUpToPowerOfTwo(height); - + if (textureOrSource == kSizeByTextureSize) { _width = _textureSize.width; _height = _textureSize.height; - } else { /* kSizeBySourceSize */ - _width = _sourceSize.width; + } else { // sizeBySourceSize + _width = _sourceSize.width; _height = _sourceSize.height; + + // adjust allocated width to be divisible by 32. + // The GU can only handle multiples of 16 bytes. A 4 bit image x 32 will give us 16 bytes + // We don't necessarily know the depth of the pixels here. So just make it divisible by 32. + uint32 checkDiv = _width & 31; + if (checkDiv) + _width += 32 - checkDiv; } + + PSP_DEBUG_PRINT("width[%u], height[%u], texW[%u], texH[%u], sourceW[%d], sourceH[%d] %s\n", _width, _height, _textureSize.width, _textureSize.height, _sourceSize.width, _sourceSize.height, textureOrSource ? "size by source" : "size by texture"); } -/* Scale a dimension (width/height) up to power of 2 for the texture */ +// Scale a dimension (width/height) up to power of 2 for the texture +// Will only go up to 512 since that's the maximum PSP texture size uint32 Buffer::scaleUpToPowerOfTwo(uint32 size) { - uint32 textureDimension = 0; - if (size <= 16) - textureDimension = 16; - else if (size <= 32) - textureDimension = 32; - else if (size <= 64) - textureDimension = 64; - else if (size <= 128) - textureDimension = 128; - else if (size <= 256) - textureDimension = 256; - else - textureDimension = 512; + uint32 textureDimension = 16; + while (size > textureDimension && textureDimension < 512) + textureDimension <<= 1; - PSP_DEBUG_PRINT("power of 2 = %u\n", textureDimension); + PSP_DEBUG_PRINT("size[%u]. power of 2[%u]\n", size, textureDimension); return textureDimension; } @@ -540,51 +539,41 @@ void GuRenderer::render() { DEBUG_ENTER_FUNC(); PSP_DEBUG_PRINT("Buffer[%p] Palette[%p]\n", _buffer->getPixels(), _palette->getRawValues()); - setMaxTextureOffsetByIndex(0, 0); - guProgramDrawBehavior(); if (_buffer->hasPalette()) guLoadPalette(); guProgramTextureFormat(); - guLoadTexture(); - - Vertex *vertices = guGetVertices(); - fillVertices(vertices); - - guDrawVertices(vertices); - - if (_buffer->getSourceWidth() > 512) { - setMaxTextureOffsetByIndex(1, 0); - guLoadTexture(); - - vertices = guGetVertices(); - fillVertices(vertices); - - guDrawVertices(vertices); + // Loop over patches of 512x512 pixel textures and draw them + for (uint32 j = 0; j < _buffer->getSourceHeight(); j += 512) { + _textureLoadOffset.y = j; + + for (uint32 i = 0; i < _buffer->getSourceWidth(); i += 512) { + _textureLoadOffset.x = i; + + guLoadTexture(); + Vertex *vertices = guGetVertices(); + fillVertices(vertices); + + guDrawVertices(vertices); + } } } -inline void GuRenderer::setMaxTextureOffsetByIndex(uint32 x, uint32 y) { - DEBUG_ENTER_FUNC(); - const uint32 maxTextureSizeShift = 9; /* corresponds to 512 = max texture size*/ - - _maxTextureOffset.x = x << maxTextureSizeShift; /* x times 512 */ - _maxTextureOffset.y = y << maxTextureSizeShift; /* y times 512 */ -} - inline void GuRenderer::guProgramDrawBehavior() { DEBUG_ENTER_FUNC(); - PSP_DEBUG_PRINT("blending[%s] colorTest[%s] reverseAlpha[%s] keyColor[%u]\n", _blending ? "on" : "off", _colorTest ? "on" : "off", _alphaReverse ? "on" : "off", _keyColor); + PSP_DEBUG_PRINT("blending[%s] colorTest[%s] reverseAlpha[%s] keyColor[%u]\n", + _blending ? "on" : "off", _colorTest ? "on" : "off", + _alphaReverse ? "on" : "off", _keyColor); if (_blending) { sceGuEnable(GU_BLEND); - if (_alphaReverse) // Reverse the alpha value (0 is 1) + if (_alphaReverse) // Reverse the alpha value (ie. 0 is 1) easier to do in some cases sceGuBlendFunc(GU_ADD, GU_ONE_MINUS_SRC_ALPHA, GU_SRC_ALPHA, 0, 0); - else // Normal alpha values + else // Normal alpha values sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); } else @@ -592,7 +581,9 @@ inline void GuRenderer::guProgramDrawBehavior() { if (_colorTest) { sceGuEnable(GU_COLOR_TEST); - sceGuColorFunc(GU_NOTEQUAL, _keyColor, 0x00ffffff); + sceGuColorFunc(GU_NOTEQUAL, // show only colors not equal to this color + _keyColor, + 0x00ffffff); // match everything but alpha } else sceGuDisable(GU_COLOR_TEST); } @@ -613,7 +604,8 @@ inline void GuRenderer::guLoadPalette() { PSP_DEBUG_PRINT("bpp[%d], pixelformat[%d], mask[%x]\n", _buffer->getBitsPerPixel(), _palette->getPixelFormat(), mask); sceGuClutMode(convertToGuPixelFormat(_palette->getPixelFormat()), 0, mask, 0); - sceGuClutLoad(_palette->getNumOfEntries() >> 3, _palette->getRawValues()); + sceGuClutLoad(_palette->getNumOfEntries() >> 3, // it's in batches of 8 for some reason + _palette->getRawValues()); } inline void GuRenderer::guProgramTextureFormat() { @@ -659,7 +651,17 @@ inline uint32 GuRenderer::convertToGuPixelFormat(PSPPixelFormat::Type format) { inline void GuRenderer::guLoadTexture() { DEBUG_ENTER_FUNC(); - sceGuTexImage(0, _buffer->getTextureWidth(), _buffer->getTextureHeight(), _buffer->getWidth(), _buffer->getPixels() + _buffer->_pixelFormat.pixelsToBytes(_maxTextureOffset.x)); + byte *startPoint = _buffer->getPixels(); + if (_textureLoadOffset.x) + startPoint += _buffer->_pixelFormat.pixelsToBytes(_textureLoadOffset.x); + if (_textureLoadOffset.y) + startPoint += _buffer->getWidthInBytes() * _textureLoadOffset.y; + + sceGuTexImage(0, + _buffer->getTextureWidth(), // texture width (must be power of 2) + _buffer->getTextureHeight(), // texture height (must be power of 2) + _buffer->getWidth(), // width of a line of the image (to get to the next line) + startPoint); // where to start reading } inline Vertex *GuRenderer::guGetVertices() { @@ -677,40 +679,40 @@ void GuRenderer::fillVertices(Vertex *vertices) { uint32 outputWidth = _displayManager->getOutputWidth(); uint32 outputHeight = _displayManager->getOutputHeight(); - float textureStartX, textureStartY, textureEndX, textureEndY; - // Texture adjustments for eliminating half-pixel artifacts from scaling // Not necessary if we don't scale - float textureAdjustment = 0.0f; + float textureFix = 0.0f; if (_useGlobalScaler && - (_displayManager->getScaleX() != 1.0f || _displayManager->getScaleX() != 1.0f)) - textureAdjustment = 0.5f; - - textureStartX = textureAdjustment + _offsetInBuffer.x; //debug - textureStartY = textureAdjustment + _offsetInBuffer.y; - // We subtract maxTextureOffset because our shifted texture starts at 512 and will go to 640 - textureEndX = _offsetInBuffer.x + _drawSize.width - textureAdjustment - _maxTextureOffset.x; - textureEndY = _offsetInBuffer.y + _drawSize.height - textureAdjustment; - + (_displayManager->getScaleX() != 1.0f || _displayManager->getScaleY() != 1.0f)) + textureFix = 0.5f; + + // These coordinates describe an area within the texture. ie. we already loaded a square of texture, + // now the coordinates within it are 0 to the edge of the area of the texture we want to draw + float textureStartX = textureFix + _offsetInBuffer.x; + float textureStartY = textureFix + _offsetInBuffer.y; + // even when we draw one of several textures, we use the whole drawsize of the image. The GU + // will draw what it can with the texture it has and scale it properly for us. + float textureEndX = -textureFix + _offsetInBuffer.x + _drawSize.width - _textureLoadOffset.x; + float textureEndY = -textureFix + _offsetInBuffer.y + _drawSize.height - _textureLoadOffset.y; // For scaling to the final image size, calculate the gaps on both sides uint32 gapX = _useGlobalScaler ? (PSP_SCREEN_WIDTH - outputWidth) >> 1 : 0; uint32 gapY = _useGlobalScaler ? (PSP_SCREEN_HEIGHT - outputHeight) >> 1 : 0; // Save scaled offset on screen - float scaledOffsetOnScreenX = scaleSourceToOutputX(_offsetOnScreen.x); - float scaledOffsetOnScreenY = scaleSourceToOutputY(_offsetOnScreen.y); - - float imageStartX, imageStartY, imageEndX, imageEndY; + float scaledOffsetOnScreenX = scaleSourceToOutput(true, _offsetOnScreen.x); + float scaledOffsetOnScreenY = scaleSourceToOutput(false, _offsetOnScreen.y); - imageStartX = gapX + scaledOffsetOnScreenX + (scaleSourceToOutputX(_maxTextureOffset.x)); - imageStartY = gapY + scaledOffsetOnScreenY; + float imageStartX = gapX + scaledOffsetOnScreenX + (scaleSourceToOutput(true, stretch(true, _textureLoadOffset.x))); + float imageStartY = gapY + scaledOffsetOnScreenY + (scaleSourceToOutput(false, stretch(false, _textureLoadOffset.y))); + float imageEndX, imageEndY; + if (_fullScreen) { // shortcut imageEndX = PSP_SCREEN_WIDTH - gapX + scaledOffsetOnScreenX; imageEndY = PSP_SCREEN_HEIGHT - gapY + scaledOffsetOnScreenY; // needed for screen shake } else { /* !fullScreen */ - imageEndX = imageStartX + scaleSourceToOutputX(_drawSize.width); - imageEndY = imageStartY + scaleSourceToOutputY(_drawSize.height); + imageEndX = gapX + scaledOffsetOnScreenX + scaleSourceToOutput(true, stretch(true, _drawSize.width)); + imageEndY = gapY + scaledOffsetOnScreenY + scaleSourceToOutput(false, stretch(false, _drawSize.height)); } vertices[0].u = textureStartX; @@ -729,8 +731,8 @@ void GuRenderer::fillVertices(Vertex *vertices) { PSP_DEBUG_PRINT("ImageStart: X[%f] Y[%f] ImageEnd: X[%.1f] Y[%.1f]\n", imageStartX, imageStartY, imageEndX, imageEndY); } -/* Scale the input X offset to appear in proper position on the screen */ -inline float GuRenderer::scaleSourceToOutputX(float offset) { +/* Scale the input X/Y offset to appear in proper position on the screen */ +inline float GuRenderer::scaleSourceToOutput(bool x, float offset) { float result; if (!_useGlobalScaler) @@ -738,28 +740,22 @@ inline float GuRenderer::scaleSourceToOutputX(float offset) { else if (!offset) result = 0.0f; else - result = offset * _displayManager->getScaleX(); + result = x ? offset * _displayManager->getScaleX() : offset * _displayManager->getScaleY(); return result; } -/* Scale the input Y offset to appear in proper position on the screen */ -inline float GuRenderer::scaleSourceToOutputY(float offset) { - float result; - - if (!_useGlobalScaler) - result = offset; - else if (!offset) - result = 0.0f; - else - result = offset * _displayManager->getScaleY(); - - return result; +/* Scale the input X/Y offset to appear in proper position on the screen */ +inline float GuRenderer::stretch(bool x, float size) { + if (!_stretch) + return size; + return (x ? size * _stretchX : size * _stretchY); } inline void GuRenderer::guDrawVertices(Vertex *vertices) { DEBUG_ENTER_FUNC(); + // This function shouldn't need changing. The '32' here refers to floating point vertices. sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, 2, 0, vertices); } diff --git a/backends/platform/psp/display_client.h b/backends/platform/psp/display_client.h index feec477282..005fc76c7c 100644 --- a/backends/platform/psp/display_client.h +++ b/backends/platform/psp/display_client.h @@ -174,8 +174,13 @@ protected: class GuRenderer { public: // Constructors - GuRenderer() : _useGlobalScaler(false), _buffer(0), _palette(0), _blending(false), _alphaReverse(false), _colorTest(false), _keyColor(0), _fullScreen(false) {} - GuRenderer(Buffer *buffer, Palette *palette) : _useGlobalScaler(false), _buffer(buffer), _palette(palette), _blending(false), _alphaReverse(false), _colorTest(false), _keyColor(0), _fullScreen(false) {} + GuRenderer() : _useGlobalScaler(false), _buffer(0), _palette(0), + _blending(false), _alphaReverse(false), _colorTest(false), + _keyColor(0), _fullScreen(false), _stretch(false), _stretchX(1.0f), _stretchY(1.0f) {} + GuRenderer(Buffer *buffer, Palette *palette) : + _useGlobalScaler(false), _buffer(buffer), _palette(palette), + _blending(false), _alphaReverse(false), _colorTest(false), + _keyColor(0), _fullScreen(false), _stretch(false), _stretchX(1.0f), _stretchY(1.0f) {} static void setDisplayManager(DisplayManager *dm) { _displayManager = dm; } // Called by the Display Manager // Setters @@ -190,8 +195,7 @@ public: } void setBuffer(Buffer *buffer) { _buffer = buffer; } void setPalette(Palette *palette) { _palette = palette; } - void setMaxTextureOffsetByIndex(uint32 x, uint32 y); // For drawing multiple textures - void setOffsetOnScreen(uint32 x, uint32 y) { _offsetOnScreen.x = x; _offsetOnScreen.y = y; } + void setOffsetOnScreen(int x, int y) { _offsetOnScreen.x = x; _offsetOnScreen.y = y; } void setOffsetInBuffer(uint32 x, uint32 y) { _offsetInBuffer.x = x; _offsetInBuffer.y = y; } void setColorTest(bool value) { _colorTest = value; } void setKeyColor(uint32 value) { _keyColor = _buffer->_pixelFormat.convertTo32BitColor(value); } @@ -199,6 +203,8 @@ public: void setAlphaReverse(bool value) { _alphaReverse = value; } void setFullScreen(bool value) { _fullScreen = value; } // Shortcut for rendering void setUseGlobalScaler(bool value) { _useGlobalScaler = value; } // Scale to screen + void setStretch(bool active) { _stretch = active; } + void setStretchXY(float x, float y) { _stretchX = x; _stretchY = y; } static void cacheInvalidate(void *pointer, uint32 size); @@ -216,11 +222,11 @@ protected: void guDrawVertices(Vertex *vertices); uint32 convertToGuPixelFormat(PSPPixelFormat::Type format); - float scaleSourceToOutputX(float offset); - float scaleSourceToOutputY(float offset); + float scaleSourceToOutput(bool x, float offset); + float stretch(bool x, float size); friend class MasterGuRenderer; - Point _maxTextureOffset; ///> For rendering textures > 512 pixels + Point _textureLoadOffset; ///> For rendering textures > 512 pixels Point _offsetOnScreen; ///> Where on screen to draw Point _offsetInBuffer; ///> Where in the texture to draw bool _useGlobalScaler; ///> Scale to the output size on screen @@ -233,6 +239,8 @@ protected: bool _colorTest; uint32 _keyColor; ///> Color to test against for color test. in 32 bits. bool _fullScreen; ///> Speeds up for fullscreen rendering + bool _stretch; ///> Whether zooming is activated + float _stretchX, _stretchY; }; #endif /* PSP_SCREEN_H */ diff --git a/backends/platform/psp/display_manager.cpp b/backends/platform/psp/display_manager.cpp index 5d75ac531e..2c94882a63 100644 --- a/backends/platform/psp/display_manager.cpp +++ b/backends/platform/psp/display_manager.cpp @@ -34,6 +34,7 @@ #include "backends/platform/psp/default_display_client.h" #include "backends/platform/psp/cursor.h" #include "backends/platform/psp/pspkeyboard.h" +#include "backends/platform/psp/image_viewer.h" #define USE_DISPLAY_CALLBACK // to use callback for finishing the render #include "backends/platform/psp/display_manager.h" @@ -385,10 +386,12 @@ bool DisplayManager::renderAll() { #endif /* USE_DISPLAY_CALLBACK */ // This is cheaper than checking time, so we do it first + // Any one of these being dirty causes everything to draw if (!_screen->isDirty() && - (!_overlay->isDirty()) && - (!_cursor->isDirty()) && - (!_keyboard->isDirty())) { + !_overlay->isDirty() && + !_cursor->isDirty() && + !_keyboard->isDirty() && + !_imageViewer->isDirty()) { PSP_DEBUG_PRINT("Nothing dirty\n"); return true; // nothing to render } @@ -396,34 +399,35 @@ bool DisplayManager::renderAll() { if (!isTimeToUpdate()) return false; // didn't render - PSP_DEBUG_PRINT("screen[%s], overlay[%s], cursor[%s], keyboard[%s]\n", + PSP_DEBUG_PRINT("dirty: screen[%s], overlay[%s], cursor[%s], keyboard[%s], imageViewer[%s]\n", _screen->isDirty() ? "true" : "false", _overlay->isDirty() ? "true" : "false", _cursor->isDirty() ? "true" : "false", - _keyboard->isDirty() ? "true" : "false" + _keyboard->isDirty() ? "true" : "false", + _imageViewer->isDirty() ? "true" : "false", ); _masterGuRenderer.guPreRender(); // Set up rendering _screen->render(); - _screen->setClean(); // clean out dirty bit + + if (_imageViewer->isVisible()) + _imageViewer->render(); + _imageViewer->setClean(); if (_overlay->isVisible()) - _overlay->render(); - + _overlay->render(); _overlay->setClean(); if (_cursor->isVisible()) _cursor->render(); - _cursor->setClean(); if (_keyboard->isVisible()) _keyboard->render(); - _keyboard->setClean(); - + _masterGuRenderer.guPostRender(); return true; // rendered successfully diff --git a/backends/platform/psp/display_manager.h b/backends/platform/psp/display_manager.h index 00d3851243..4537af0096 100644 --- a/backends/platform/psp/display_manager.h +++ b/backends/platform/psp/display_manager.h @@ -96,6 +96,7 @@ class Screen; class Overlay; class Cursor; class PSPKeyboard; +class ImageViewer; /** * Class that manages all display clients @@ -107,7 +108,8 @@ public: KEEP_ASPECT_RATIO, STRETCHED_FULL_SCREEN }; - DisplayManager() : _screen(0), _cursor(0), _overlay(0), _keyboard(0), _lastUpdateTime(0), _graphicsMode(0) {} + DisplayManager() : _screen(0), _cursor(0), _overlay(0), _keyboard(0), + _imageViewer(0), _lastUpdateTime(0), _graphicsMode(0) {} ~DisplayManager(); void init(); @@ -118,11 +120,13 @@ public: uint32 getDefaultGraphicsMode() const { return STRETCHED_FULL_SCREEN; } const OSystem::GraphicsMode* getSupportedGraphicsModes() const { return _supportedModes; } - // Setters + // Setters for pointers void setScreen(Screen *screen) { _screen = screen; } void setCursor(Cursor *cursor) { _cursor = cursor; } void setOverlay(Overlay *overlay) { _overlay = overlay; } void setKeyboard(PSPKeyboard *keyboard) { _keyboard = keyboard; } + void setImageViewer(ImageViewer *imageViewer) { _imageViewer = imageViewer; } + void setSizeAndPixelFormat(uint width, uint height, const Graphics::PixelFormat *format); // Getters @@ -148,6 +152,7 @@ private: Cursor *_cursor; Overlay *_overlay; PSPKeyboard *_keyboard; + ImageViewer *_imageViewer; MasterGuRenderer _masterGuRenderer; uint32 _lastUpdateTime; // For limiting FPS diff --git a/backends/platform/psp/dummy.cpp b/backends/platform/psp/dummy.cpp new file mode 100644 index 0000000000..4236734d4b --- /dev/null +++ b/backends/platform/psp/dummy.cpp @@ -0,0 +1,59 @@ +/* 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/trunk/backends/platform/psp/osys_psp.cpp $ + * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $ + * + */ + + //#include "common/scummsys.h" + #include <time.h> + #include <stdlib.h> + #include <stdio.h> + #include <png.h> + #include <sys/socket.h> + +//void userWriteFn(png_structp png_ptr, png_bytep data, png_size_t length) { +//} + +//void userFlushFn(png_structp png_ptr) { +//} + + // Dummy functions are pulled in so that we don't need to build the plugins with certain libs + + int dummyFunc() { + + // For Broken Sword 2.5 + volatile int i; + i = clock(); + rename("dummyA", "dummyB"); + + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + png_set_write_fn(png_ptr, NULL, NULL, NULL); + png_infop info_ptr; + png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + png_destroy_write_struct(&png_ptr, &info_ptr); + + // For lua's usage of libc: very heavy usage so it pulls in sockets? + setsockopt(0, 0, 0, NULL, 0); + getsockopt(0, 0, 0, NULL, NULL); + + return i; +}
\ No newline at end of file diff --git a/backends/platform/psp/elf32.h b/backends/platform/psp/elf32.h deleted file mode 100644 index 616cc4b4d2..0000000000 --- a/backends/platform/psp/elf32.h +++ /dev/null @@ -1,209 +0,0 @@ -/* 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$ - * $Id$ - * - */ - -#ifndef BACKENDS_ELF_H -#define BACKENDS_ELF_H - -/* ELF stuff */ - -typedef unsigned short Elf32_Half, Elf32_Section; -typedef unsigned int Elf32_Word, Elf32_Addr, Elf32_Off; -typedef signed int Elf32_Sword; -typedef Elf32_Half Elf32_Versym; - -#define EI_NIDENT (16) -#define SELFMAG 6 - -/* ELF File format structures. Look up ELF structure for more details */ - -// ELF header (contains info about the file) -typedef struct { - unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ - Elf32_Half e_type; /* Object file type */ - Elf32_Half e_machine; /* Architecture */ - Elf32_Word e_version; /* Object file version */ - Elf32_Addr e_entry; /* Entry point virtual address */ - Elf32_Off e_phoff; /* Program header table file offset */ - Elf32_Off e_shoff; /* Section header table file offset */ - Elf32_Word e_flags; /* Processor-specific flags */ - Elf32_Half e_ehsize; /* ELF header size in bytes */ - Elf32_Half e_phentsize; /* Program header table entry size */ - Elf32_Half e_phnum; /* Program header table entry count */ - Elf32_Half e_shentsize; /* Section header table entry size */ - Elf32_Half e_shnum; /* Section header table entry count */ - Elf32_Half e_shstrndx; /* Section header string table index */ -} Elf32_Ehdr; - -// Should be in e_ident -#define ELFMAG "\177ELF\1\1" /* ELF Magic number */ - -// e_type values -#define ET_NONE 0 /* no file type */ -#define ET_REL 1 /* relocatable */ -#define ET_EXEC 2 /* executable */ -#define ET_DYN 3 /* shared object */ -#define ET_CORE 4 /* core file */ - -// e_machine values -#define EM_MIPS 8 - - -// Program header (contains info about segment) -typedef struct { - Elf32_Word p_type; /* Segment type */ - Elf32_Off p_offset; /* Segment file offset */ - Elf32_Addr p_vaddr; /* Segment virtual address */ - Elf32_Addr p_paddr; /* Segment physical address */ - Elf32_Word p_filesz; /* Segment size in file */ - Elf32_Word p_memsz; /* Segment size in memory */ - Elf32_Word p_flags; /* Segment flags */ - Elf32_Word p_align; /* Segment alignment */ -} Elf32_Phdr; - -// p_type values -#define PT_NULL 0 /* ignored */ -#define PT_LOAD 1 /* loadable segment */ -#define PT_DYNAMIC 2 /* dynamic linking info */ -#define PT_INTERP 3 /* info about interpreter */ -#define PT_NOTE 4 /* note segment */ -#define PT_SHLIB 5 /* reserved */ -#define PT_PHDR 6 /* Program header table */ -#define PT_MIPS_REGINFO 0x70000000 /* register usage info */ - -// p_flags value -#define PF_X 1 /* execute */ -#define PF_W 2 /* write */ -#define PF_R 4 /* read */ - -// Section header (contains info about section) -typedef struct { - Elf32_Word sh_name; /* Section name (string tbl index) */ - Elf32_Word sh_type; /* Section type */ - Elf32_Word sh_flags; /* Section flags */ - Elf32_Addr sh_addr; /* Section virtual addr at execution */ - Elf32_Off sh_offset; /* Section file offset */ - Elf32_Word sh_size; /* Section size in bytes */ - Elf32_Word sh_link; /* Link to another section */ - Elf32_Word sh_info; /* Additional section information */ - Elf32_Word sh_addralign; /* Section alignment */ - Elf32_Word sh_entsize; /* Entry size if section holds table */ -} Elf32_Shdr; - -// sh_type values -#define SHT_NULL 0 /* Inactive section */ -#define SHT_PROGBITS 1 /* Proprietary */ -#define SHT_SYMTAB 2 /* Symbol table */ -#define SHT_STRTAB 3 /* String table */ -#define SHT_RELA 4 /* Relocation entries with addend */ -#define SHT_HASH 5 /* Symbol hash table */ -#define SHT_DYNAMIC 6 /* Info for dynamic linking */ -#define SHT_NOTE 7 /* Note section */ -#define SHT_NOBITS 8 /* Occupies no space */ -#define SHT_REL 9 /* Relocation entries without addend */ -#define SHT_SHLIB 10 /* Reserved */ -#define SHT_DYNSYM 11 /* Minimal set of dynamic linking symbols */ -#define SHT_MIPS_LIBLSIT 0x70000000 /* Info about dynamic shared object libs */ -#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicts btw executables and shared objects */ -#define SHT_MIPS_GPTAB 0x70000003 /* Global pointer table */ - -// sh_flags values -#define SHF_WRITE 0 /* writable section */ -#define SHF_ALLOC 2 /* section occupies memory */ -#define SHF_EXECINSTR 4 /* machine instructions */ -#define SHF_MIPS_GPREL 0x10000000 /* Must be made part of global data area */ - - -// Symbol entry (contain info about a symbol) -typedef struct { - Elf32_Word st_name; /* Symbol name (string tbl index) */ - Elf32_Addr st_value; /* Symbol value */ - Elf32_Word st_size; /* Symbol size */ - unsigned char st_info; /* Symbol type and binding */ - unsigned char st_other; /* Symbol visibility */ - Elf32_Section st_shndx; /* Section index */ -} Elf32_Sym; - -// Extract from the st_info -#define SYM_TYPE(x) ((x)&0xF) -#define SYM_BIND(x) ((x)>>4) - - -// Symbol binding values from st_info -#define STB_LOCAL 0 /* Symbol not visible outside object */ -#define STB_GLOBAL 1 /* Symbol visible to all object files */ -#define STB_WEAK 2 /* Similar to STB_GLOBAL */ - -// Symbol type values from st_info -#define STT_NOTYPE 0 /* Not specified */ -#define STT_OBJECT 1 /* Data object e.g. variable */ -#define STT_FUNC 2 /* Function */ -#define STT_SECTION 3 /* Section */ -#define STT_FILE 4 /* Source file associated with object file */ - -// Special section header index values from st_shndex -#define SHN_UNDEF 0 -#define SHN_LOPROC 0xFF00 /* Extended values */ -#define SHN_ABS 0xFFF1 /* Absolute value: don't relocate */ -#define SHN_COMMON 0xFFF2 /* Common block. Not allocated yet */ -#define SHN_HIPROC 0xFF1F -#define SHN_HIRESERVE 0xFFFF - -// Relocation entry (info about how to relocate) -typedef struct { - Elf32_Addr r_offset; /* Address */ - Elf32_Word r_info; /* Relocation type and symbol index */ -} Elf32_Rel; - -// Access macros for the relocation info -#define REL_TYPE(x) ((x)&0xFF) /* Extract relocation type */ -#define REL_INDEX(x) ((x)>>8) /* Extract relocation index into symbol table */ - -// MIPS relocation types -#define R_MIPS_NONE 0 -#define R_MIPS_16 1 -#define R_MIPS_32 2 -#define R_MIPS_REL32 3 -#define R_MIPS_26 4 -#define R_MIPS_HI16 5 -#define R_MIPS_LO16 6 -#define R_MIPS_GPREL16 7 -#define R_MIPS_LITERAL 8 -#define R_MIPS_GOT16 9 -#define R_MIPS_PC16 10 -#define R_MIPS_CALL16 11 -#define R_MIPS_GPREL32 12 -#define R_MIPS_GOTHI16 13 -#define R_MIPS_GOTLO16 14 -#define R_MIPS_CALLHI16 15 -#define R_MIPS_CALLLO16 16 - -// Mock function to get value of global pointer -#define getGP() ({ \ - unsigned int __valgp; \ - __asm__ ("add %0, $gp, $0" : "=r"(__valgp) : ); \ - __valgp; \ -}) - -#endif /* BACKENDS_ELF_H */ diff --git a/backends/platform/psp/image_viewer.cpp b/backends/platform/psp/image_viewer.cpp new file mode 100644 index 0000000000..26b7f31c97 --- /dev/null +++ b/backends/platform/psp/image_viewer.cpp @@ -0,0 +1,327 @@ +/* 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/trunk/backends/platform/psp/osys_psp.cpp $ + * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $ + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "common/scummsys.h" +#include "common/str.h" +#include "common/stream.h" +#include "common/archive.h" +#include "common/events.h" +#include "common/ptr.h" +#include "gui/message.h" +#include "engines/engine.h" +#include "backends/platform/psp/input.h" +#include "backends/platform/psp/display_manager.h" +#include "backends/platform/psp/display_client.h" +#include "backends/platform/psp/image_viewer.h" +#include "backends/platform/psp/png_loader.h" +#include "backends/platform/psp/thread.h" + +static const char *imageName = "psp_image"; +#define PSP_SCREEN_HEIGHT 272 +#define PSP_SCREEN_WIDTH 480 + +bool ImageViewer::load(int imageNum) { + if (_init) + unload(); + + // build string + char number[8]; + sprintf(number, "%d", imageNum); + Common::String imageNameStr(imageName); + Common::String specificImageName = imageNameStr + Common::String(number) + Common::String(".png"); + + // search for image file + if (!SearchMan.hasFile(specificImageName)) { + PSP_ERROR("file %s not found\n", specificImageName.c_str()); + return false; + } + + Common::ScopedPtr<Common::SeekableReadStream> file(SearchMan.createReadStreamForMember(specificImageName)); + + _buffer = new Buffer(); + _palette = new Palette(); + _renderer = new GuRenderer(); + + assert(_buffer); + assert(_palette); + assert(_renderer); + + // Load a PNG into our buffer and palette. Size it by the actual size of the image + PngLoader image(file, *_buffer, *_palette, Buffer::kSizeBySourceSize); + + PngLoader::Status status = image.allocate(); // allocate the buffers for the file + + char error[100]; + if (status == PngLoader::BAD_FILE) { + sprintf(error, "Cannot display %s. Not a proper PNG file", specificImageName.c_str()); + GUI::TimedMessageDialog dialog(error, 4000); + dialog.runModal(); + return false; + } else if (status == PngLoader::OUT_OF_MEMORY) { + sprintf(error, "Out of memory loading %s. Try making the image smaller", specificImageName.c_str()); + GUI::TimedMessageDialog dialog(error, 4000); + dialog.runModal(); + return false; + } + // try to load the image file + if (!image.load()) { + sprintf(error, "Cannot display %s. Not a proper PNG file", specificImageName.c_str()); + GUI::TimedMessageDialog dialog(error, 4000); + dialog.runModal(); + return false; + } + + setConstantRendererOptions(); + setFullScreenImageParams(); // prepare renderer for full screen view + + _imageNum = imageNum; // now we can say we displayed this image + _init = true; + + return true; +} + +void ImageViewer::setConstantRendererOptions() { + _renderer->setBuffer(_buffer); + _renderer->setPalette(_palette); + + _renderer->setAlphaBlending(false); + _renderer->setColorTest(false); + _renderer->setUseGlobalScaler(false); + _renderer->setStretch(true); + _renderer->setOffsetInBuffer(0, 0); + _renderer->setDrawWholeBuffer(); +} + +void ImageViewer::unload() { + _init = false; + delete _buffer; + delete _palette; + delete _renderer; + _buffer = 0; + _palette = 0; + _renderer = 0; +} + +void ImageViewer::resetOnEngineDone() { + _imageNum = 0; +} + +void ImageViewer::setVisible(bool visible) { + DEBUG_ENTER_FUNC(); + + if (_visible == visible) + return; + + // from here on, we're making the loader visible + if (visible && g_engine) { // we can only run the image viewer when there's an engine + g_engine->pauseEngine(true); + + load(_imageNum ? _imageNum : 1); // load the 1st image or the current + } + + if (visible && _init) { // we managed to load + _visible = true; + setViewerButtons(true); + + { // so dialog goes out of scope, destroying all allocations + GUI::TimedMessageDialog dialog("Image Viewer", 1000); + dialog.runModal(); + } + + runLoop(); // only listen to viewer events + } else { // we were asked to make invisible or failed to load + _visible = false; + unload(); + setViewerButtons(false); + + if (g_engine && g_engine->isPaused()) + g_engine->pauseEngine(false); + } + setDirty(); +} + +// This is the only way we can truly pause the games +// Sad but true. +void ImageViewer::runLoop() { + while (_visible) { + Common::Event event; + PspThread::delayMillis(30); + _inputHandler->getAllInputs(event); + _displayManager->renderAll(); + } +} + +void ImageViewer::setViewerButtons(bool active) { + _inputHandler->setImageViewerMode(active); +} + +void ImageViewer::loadNextImage() { + if (!load(_imageNum+1)) { // try to load the next image + if (!load(_imageNum)) // we failed, so reload the current image + setVisible(false); // just hide + } + setDirty(); +} + +void ImageViewer::loadLastImage() { + if (_imageNum - 1 > 0) { + if (!load(_imageNum-1)) + if (!load(_imageNum)) + setVisible(false); // we can't even show the old image so hide + } + setDirty(); +} + +void ImageViewer::setFullScreenImageParams() { + // we try to fit the image fullscreen at least in one dimension + uint32 width = _buffer->getSourceWidth(); + uint32 height = _buffer->getSourceHeight(); + + _centerX = PSP_SCREEN_WIDTH / 2.0f; + _centerY = PSP_SCREEN_HEIGHT / 2.0f; + + // see if we fit width wise + if (PSP_SCREEN_HEIGHT >= (int)((height * PSP_SCREEN_WIDTH) / (float)width)) { + setZoom(PSP_SCREEN_WIDTH / (float)width); + } else { + setZoom(PSP_SCREEN_HEIGHT / (float)height); + } +} + +void ImageViewer::render() { + if (_init) { + assert(_buffer); + assert(_renderer); + + // move the image slightly. Note that we count on the renderer's timing + switch (_movement) { + case EVENT_MOVE_LEFT: + moveImageX(-_visibleWidth / 100.0f); + break; + case EVENT_MOVE_UP: + moveImageY(-_visibleHeight / 100.0f); + break; + case EVENT_MOVE_RIGHT: + moveImageX(_visibleWidth / 100.0f); + break; + case EVENT_MOVE_DOWN: + moveImageY(_visibleHeight / 100.0f); + break; + default: + break; + } + _renderer->render(); + } +} + +void ImageViewer::modifyZoom(bool up) { + float factor = _zoomFactor; + if (up) + factor += 0.1f; + else // down + factor -= 0.1f; + + setZoom(factor); +} + +void ImageViewer::setZoom(float value) { + if (value <= 0.0f) // don't want 0 or negative zoom + return; + + _zoomFactor = value; + _renderer->setStretchXY(value, value); + setOffsetParams(); +} + +void ImageViewer::moveImageX(float val) { + float newVal = _centerX + val; + + if (newVal - (_visibleWidth / 2) > PSP_SCREEN_WIDTH - 4 || newVal + (_visibleWidth / 2) < 4) + return; + _centerX = newVal; + setOffsetParams(); +} + +void ImageViewer::moveImageY(float val) { + float newVal = _centerY + val; + + if (newVal - (_visibleHeight / 2) > PSP_SCREEN_HEIGHT - 4 || newVal + (_visibleHeight / 2) < 4) + return; + _centerY = newVal; + setOffsetParams(); +} + +// Set the renderer with the proper offset on the screen +// +void ImageViewer::setOffsetParams() { + _visibleWidth = _zoomFactor * _buffer->getSourceWidth(); + _visibleHeight = _zoomFactor * _buffer->getSourceHeight(); + + int offsetX = _centerX - (int)(_visibleWidth * 0.5f); + int offsetY = _centerY - (int)(_visibleHeight * 0.5f); + + _renderer->setOffsetOnScreen(offsetX, offsetY); + setDirty(); +} + +// Handler events coming in from the inputHandler +// +void ImageViewer::handleEvent(uint32 event) { + DEBUG_ENTER_FUNC(); + + switch (event) { + case EVENT_HIDE: + setVisible(false); + break; + case EVENT_SHOW: + setVisible(true); + break; + case EVENT_ZOOM_IN: + modifyZoom(true); + break; + case EVENT_ZOOM_OUT: + modifyZoom(false); + break; + case EVENT_MOVE_LEFT: + case EVENT_MOVE_UP: + case EVENT_MOVE_RIGHT: + case EVENT_MOVE_DOWN: + case EVENT_MOVE_STOP: + _movement = (Event)event; + break; + case EVENT_NEXT_IMAGE: + loadNextImage(); + break; + case EVENT_LAST_IMAGE: + loadLastImage(); + break; + default: + PSP_ERROR("Unknown event %d\n", event); + break; + } +}
\ No newline at end of file diff --git a/backends/platform/psp/image_viewer.h b/backends/platform/psp/image_viewer.h new file mode 100644 index 0000000000..ef8b196dbe --- /dev/null +++ b/backends/platform/psp/image_viewer.h @@ -0,0 +1,105 @@ +/* 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/trunk/backends/platform/psp/osys_psp.cpp $ + * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $ + * + */ + +#ifndef PSP_IMAGE_VIEWER_H +#define PSP_IMAGE_VIEWER_H + +class InputHandler; + +class ImageViewer : public DisplayClient { +public: + enum Event { + EVENT_NONE = -1, + EVENT_HIDE = 0, + EVENT_SHOW = 1, + EVENT_ZOOM_IN, + EVENT_ZOOM_OUT, + EVENT_MOVE_LEFT, + EVENT_MOVE_UP, + EVENT_MOVE_RIGHT, + EVENT_MOVE_DOWN, + EVENT_MOVE_STOP, + EVENT_NEXT_IMAGE, + EVENT_LAST_IMAGE, + }; + +private: + Buffer *_buffer; + Palette *_palette; + GuRenderer *_renderer; + bool _visible; + bool _dirty; + bool _init; + uint32 _imageNum; // current image number + float _zoomFactor; // how much we're zooming in/out on the image + float _visibleHeight, _visibleWidth; + float _centerX, _centerY; + Event _movement; + + InputHandler *_inputHandler; + DisplayManager *_displayManager; + + void setFullScreenImageParams(); + void loadNextImage(); + void loadLastImage(); + void setViewerButtons(bool active); + void setConstantRendererOptions(); + void moveImageX(float val); + void moveImageY(float val); + bool load(int imageNum); + void unload(); + void runLoop(); // to get total pausing we have to do our own loop + + void setZoom(float value); + void setOffsetParams(); + void modifyZoom(bool up); // up or down + void setVisible(bool visible); + +public: + + ImageViewer() : _buffer(0), _palette(0), _visible(false), + _dirty(false), _init(false), _imageNum(0), + _zoomFactor(0.0f), _visibleHeight(0.0f), _visibleWidth(0.0f), + _centerX(0.0f), _centerY(0.0f), _movement(EVENT_MOVE_STOP), + _inputHandler(0), _displayManager(0) {} + ~ImageViewer() { unload(); } // deallocate images + bool load(); + void render(); + bool isVisible() { return _visible; } + bool isDirty() { return _dirty; } + void setDirty() { _dirty = true; } + void setClean() { if (!_visible) // otherwise we want to keep rendering + _dirty = false; + } + void resetOnEngineDone(); + + void handleEvent(uint32 event); + + // pointer setters + void setInputHandler(InputHandler *inputHandler) { _inputHandler = inputHandler; } + void setDisplayManager(DisplayManager *displayManager) { _displayManager = displayManager; } +}; + +#endif /* PSP_IMAGE_VIEWER_H */
\ No newline at end of file diff --git a/backends/platform/psp/input.cpp b/backends/platform/psp/input.cpp index ed868ef375..0dad31e5ae 100644 --- a/backends/platform/psp/input.cpp +++ b/backends/platform/psp/input.cpp @@ -95,7 +95,7 @@ const uint32 ButtonPad::_buttonMap[] = { }; ButtonPad::ButtonPad() : _prevButtonState(0), _shifted(UNSHIFTED), _padMode(PAD_MODE_NORMAL), - _comboMode(false) { + _comboMode(false), _combosEnabled(true) { for (int i = UNSHIFTED; i < SHIFTED_MODE_LAST; i++) _buttonsChanged[i] = 0; clearButtons(); @@ -154,6 +154,7 @@ void ButtonPad::initButtonsNormalMode() { _button[BTN_START][SHIFTED].setKey(Common::KEYCODE_F5, Common::ASCII_F5); _button[BTN_START][UNSHIFTED].setKey(Common::KEYCODE_F5, Common::ASCII_F5, Common::KBD_CTRL); _button[BTN_SELECT][UNSHIFTED].setPspEvent(PSP_EVENT_SHOW_VIRTUAL_KB, true, PSP_EVENT_NONE, 0); + _button[BTN_SELECT][SHIFTED].setPspEvent(PSP_EVENT_IMAGE_VIEWER, true, PSP_EVENT_NONE, 0); } void ButtonPad::initButtonsLolMode() { @@ -199,7 +200,8 @@ bool ButtonPad::getEvent(Common::Event &event, PspEvent &pspEvent, SceCtrlData & uint32 curButtonState = PSP_ALL_BUTTONS & pad.Buttons; // we only care about these - modifyButtonsForCombos(pad); // change buttons for combos + if (_combosEnabled) + modifyButtonsForCombos(pad); // change buttons for combos return getEventFromButtonState(event, pspEvent, curButtonState); } @@ -369,6 +371,7 @@ void InputHandler::init() { sceCtrlSetSamplingMode(1); // analog _buttonPad.initButtons(); + _nub.init(); } bool InputHandler::getAllInputs(Common::Event &event) { @@ -460,6 +463,12 @@ bool InputHandler::handlePspEvent(Common::Event &event, PspEvent &pspEvent) { /*case PSP_EVENT_CHANGE_SPEED: handleSpeedChange(pspEvent.data); break;*/ + case PSP_EVENT_IMAGE_VIEWER: + _imageViewer->handleEvent(pspEvent.data); + break; + case PSP_EVENT_IMAGE_VIEWER_SET_BUTTONS: + setImageViewerMode(pspEvent.data); + break; default: PSP_ERROR("Unhandled PSP Event[%d]\n", pspEvent.type); break; @@ -509,3 +518,56 @@ void InputHandler::handleSpeedChange(bool up) { GUI::TimedMessageDialog dialog(_padModeText[_padMode], 1500); dialog.runModal(); }*/ + +void InputHandler::setImageViewerMode(bool active) { + if (_buttonPad.isButtonDown() || _nub.isButtonDown()) { // can't switch yet + PSP_DEBUG_PRINT("postponing image viewer on event\n"); + _pendingPspEvent.type = PSP_EVENT_IMAGE_VIEWER_SET_BUTTONS; // queue it to be done later + _pendingPspEvent.data = active; + } else if (active) { + _nub.setDpadMode(true); + _buttonPad.enableCombos(false); // disable combos + setButtonsForImageViewer(); + } else { // deactivate + _nub.setDpadMode(false); + _nub.init(); + _buttonPad.enableCombos(true); // re-enable combos + _buttonPad.initButtons(); + } +} + +void InputHandler::setButtonsForImageViewer() { + DEBUG_ENTER_FUNC(); + + // Dpad + _buttonPad.clearButtons(); + _buttonPad.getButton(ButtonPad::BTN_UP, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_ZOOM_IN, + PSP_EVENT_NONE, false); + _buttonPad.getButton(ButtonPad::BTN_DOWN, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_ZOOM_OUT, + PSP_EVENT_NONE, false); + _buttonPad.getButton(ButtonPad::BTN_LEFT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_LAST_IMAGE, + PSP_EVENT_NONE, false); + _buttonPad.getButton(ButtonPad::BTN_RIGHT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_NEXT_IMAGE, + PSP_EVENT_NONE, false); + _buttonPad.getButton(ButtonPad::BTN_LTRIGGER, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_HIDE, + PSP_EVENT_NONE, false); + _buttonPad.getButton(ButtonPad::BTN_RTRIGGER, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_HIDE, + PSP_EVENT_NONE, false); + _buttonPad.getButton(ButtonPad::BTN_START, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_HIDE, + PSP_EVENT_NONE, false); + _buttonPad.getButton(ButtonPad::BTN_SELECT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_HIDE, + PSP_EVENT_NONE, false); + + //Nub + _nub.getPad().clearButtons(); + _nub.getPad().getButton(ButtonPad::BTN_UP, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_UP, + PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_STOP); + _nub.getPad().getButton(ButtonPad::BTN_DOWN, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_DOWN, + PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_STOP); + _nub.getPad().getButton(ButtonPad::BTN_LEFT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_LEFT, + PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_STOP); + _nub.getPad().getButton(ButtonPad::BTN_RIGHT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_RIGHT, + PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_STOP); +} + + diff --git a/backends/platform/psp/input.h b/backends/platform/psp/input.h index acca04f376..9a1ab6faab 100644 --- a/backends/platform/psp/input.h +++ b/backends/platform/psp/input.h @@ -30,6 +30,7 @@ #include "common/events.h" #include "backends/platform/psp/pspkeyboard.h" #include "backends/platform/psp/cursor.h" +#include "backends/platform/psp/image_viewer.h" #include <pspctrl.h> enum PspEventType { @@ -40,10 +41,11 @@ enum PspEventType { PSP_EVENT_RBUTTON, PSP_EVENT_MODE_SWITCH, PSP_EVENT_CHANGE_SPEED, + PSP_EVENT_IMAGE_VIEWER, + PSP_EVENT_IMAGE_VIEWER_SET_BUTTONS, PSP_EVENT_LAST }; - struct PspEvent { PspEventType type; uint32 data; @@ -112,59 +114,77 @@ private: ShiftMode _shifted; PspPadMode _padMode; bool _comboMode; // are we in the middle of combos - static const uint32 _buttonMap[]; // maps the buttons to their values + bool _combosEnabled; // can we do combos + static const uint32 _buttonMap[]; // maps the buttons to their values void initButtonsNormalMode(); void initButtonsLolMode(); void modifyButtonsForCombos(SceCtrlData &pad); - void clearButtons(); public: ButtonPad(); + void initButtons(); // set the buttons to the mode that's selected + void clearButtons(); // empty the buttons of all events + bool getEvent(Common::Event &event, PspEvent &pspEvent, SceCtrlData &pad); bool getEventFromButtonState(Common::Event &event, PspEvent &pspEvent, uint32 buttonState); + void setShifted(ShiftMode shifted) { _shifted = shifted; } void setPadMode(PspPadMode mode) { _padMode = mode; } bool isButtonDown() { return _prevButtonState; } - void initButtons(); + + void enableCombos(bool value) { _combosEnabled = value; } + Button &getButton(ButtonType type, ShiftMode mode) { return _button[type][mode]; } }; class Nub { private: Cursor *_cursor; // to enable changing/getting cursor position - ButtonPad _buttonPad; // private buttonpad for dpad mode ShiftMode _shifted; bool _dpadMode; - + + ButtonPad _buttonPad; // private buttonpad for dpad mode + + int32 modifyNubAxisMotion(int32 input); + void translateToDpadState(int dpadX, int dpadY, uint32 &buttonState); // convert nub data to dpad data public: - Nub() : _shifted(UNSHIFTED), _dpadMode(false) { _buttonPad.initButtons(); } + Nub() : _shifted(UNSHIFTED), _dpadMode(false) { } + void init() { _buttonPad.initButtons(); } void setCursor(Cursor *cursor) { _cursor = cursor; } + + // setters void setDpadMode(bool active) { _dpadMode = active; } void setShifted(ShiftMode shifted) { _shifted = shifted; } - bool isButtonDown(); + // getters + bool isButtonDown(); bool getEvent(Common::Event &event, PspEvent &pspEvent, SceCtrlData &pad); - int32 modifyNubAxisMotion(int32 input); - void translateToDpadState(int dpadX, int dpadY, uint32 &buttonState); // convert nub data to dpad data + ButtonPad &getPad() { return _buttonPad; } }; class InputHandler { public: - InputHandler() : _keyboard(0), _cursor(0), _padMode(PAD_MODE_NORMAL), _lastPadCheckTime(0) {} + InputHandler() : _keyboard(0), _cursor(0), _imageViewer(0), _padMode(PAD_MODE_NORMAL), + _lastPadCheckTime(0) {} + // pointer setters void setKeyboard(PSPKeyboard *keyboard) { _keyboard = keyboard; } void setCursor(Cursor *cursor) { _cursor = cursor; _nub.setCursor(cursor); } + void setImageViewer(ImageViewer *imageViewer) { _imageViewer = imageViewer; } void init(); bool getAllInputs(Common::Event &event); + void setImageViewerMode(bool active); private: + Nub _nub; + ButtonPad _buttonPad; + + // Pointers to relevant other classes PSPKeyboard *_keyboard; Cursor *_cursor; - - Nub _nub; - ButtonPad _buttonPad; + ImageViewer *_imageViewer; PspPadMode _padMode; // whice mode we're in PspEvent _pendingPspEvent; // an event that can't be handled yet @@ -176,6 +196,7 @@ private: void handleMouseEvent(Common::Event &event, Common::EventType type, const char *string); void handleShiftEvent(ShiftMode shifted); void handleModeSwitchEvent(); + void setButtonsForImageViewer(); }; #endif /* PSP_INPUT_H */ diff --git a/backends/platform/psp/main_prog.ld b/backends/platform/psp/main_prog.ld deleted file mode 100644 index 4216e7f0ab..0000000000 --- a/backends/platform/psp/main_prog.ld +++ /dev/null @@ -1,253 +0,0 @@ -OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", - "elf32-littlemips") -OUTPUT_ARCH(mips:allegrex) -ENTRY(_start) -/* Do we need any of these for elf? - __DYNAMIC = 0; */ -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - PROVIDE (__executable_start = 0x08900000); . = 0x08900000; - .interp : { *(.interp) } - .reginfo : { *(.reginfo) } - .dynamic : { *(.dynamic) } - .hash : { *(.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .gnu.version : { *(.gnu.version) } - .gnu.version_d : { *(.gnu.version_d) } - .gnu.version_r : { *(.gnu.version_r) } - .rel.init : { *(.rel.init) } - .rela.init : { *(.rela.init) } - .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } - .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } - .rel.fini : { *(.rel.fini) } - .rela.fini : { *(.rela.fini) } - /* PSP-specific relocations. */ - .rel.sceStub.text : { *(.rel.sceStub.text) *(SORT(.rel.sceStub.text.*)) } - .rel.lib.ent.top : { *(.rel.lib.ent.top) } - .rel.lib.ent : { *(.rel.lib.ent) } - .rel.lib.ent.btm : { *(.rel.lib.ent.btm) } - .rel.lib.stub.top : { *(.rel.lib.stub.top) } - .rel.lib.stub : { *(.rel.lib.stub) } - .rel.lib.stub.btm : { *(.rel.lib.stub.btm) } - .rel.rodata.sceModuleInfo : { *(.rel.rodata.sceModuleInfo) } - .rel.rodata.sceResident : { *(.rel.rodata.sceResident) } - .rel.rodata.sceNid : { *(.rel.rodata.sceNid) } - .rel.rodata.sceVstub : { *(.rel.rodata.sceVstub) *(SORT(.rel.rodata.sceVstub.*)) } - .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } - .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } - .rel.data.rel.ro : { *(.rel.data.rel.ro*) } - .rela.data.rel.ro : { *(.rel.data.rel.ro*) } - .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } - .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } - .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } - .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } - .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } - .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } - .rel.ctors : { *(.rel.ctors) } - .rela.ctors : { *(.rela.ctors) } - .rel.dtors : { *(.rel.dtors) } - .rela.dtors : { *(.rela.dtors) } - .rel.got : { *(.rel.got) } - .rela.got : { *(.rela.got) } - .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } - .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } - .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } - .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } - .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } - .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } - .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } - .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } - .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } - .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } - .init : - { - KEEP (*(.init)) - } =0 - .plt : { *(.plt) } - .text : - { - _ftext = . ; - *(.text .stub .text.* .gnu.linkonce.t.*) - KEEP (*(.text.*personality*)) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - *(.mips16.fn.*) *(.mips16.call.*) - } =0 - .fini : - { - KEEP (*(.fini)) - } =0 - /* PSP library stub functions. */ - .sceStub.text : { *(.sceStub.text) *(SORT(.sceStub.text.*)) } - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - /* PSP library entry table and library stub table. */ - .lib.ent.top : { *(.lib.ent.top) } - .lib.ent : { *(.lib.ent) } - .lib.ent.btm : { *(.lib.ent.btm) } - .lib.stub.top : { *(.lib.stub.top) } - .lib.stub : { *(.lib.stub) } - .lib.stub.btm : { *(.lib.stub.btm) } - /* PSP read-only data for module info, NIDs, and Vstubs. The - .rodata.sceModuleInfo section must appear before the .rodata section - otherwise it would get absorbed into .rodata and the PSP bootloader - would be unable to locate the module info structure. */ - .rodata.sceModuleInfo : { *(.rodata.sceModuleInfo) } - .rodata.sceResident : { *(.rodata.sceResident) } - .rodata.sceNid : { *(.rodata.sceNid) } - .rodata.sceVstub : { *(.rodata.sceVstub) *(SORT(.rodata.sceVstub.*)) } - .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } - .rodata1 : { *(.rodata1) } - .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) } - .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } - .eh_frame_hdr : { *(.eh_frame_hdr) } - .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RO { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) } - /* Adjust the address for the data segment. We want to adjust up to - the same address within the page on the next page up. */ - . = ALIGN(256) + (. & (256 - 1)); - /* Exception handling */ - .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RW { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) } - /* Thread Local Storage sections */ - .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } - .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } - /* Ensure the __preinit_array_start label is properly aligned. We - could instead move the label definition inside the section, but - the linker would then create the section even if it turns out to - be empty, which isn't pretty. */ - . = ALIGN(32 / 8); - PROVIDE (__preinit_array_start = .); - .preinit_array : { KEEP (*(.preinit_array)) } - PROVIDE (__preinit_array_end = .); - PROVIDE (__init_array_start = .); - .init_array : { KEEP (*(.init_array)) } - PROVIDE (__init_array_end = .); - PROVIDE (__fini_array_start = .); - .fini_array : { KEEP (*(.fini_array)) } - PROVIDE (__fini_array_end = .); - .ctors : - { - /* gcc uses crtbegin.o to find the start of - the constructors, so we make sure it is - first. Because this is a wildcard, it - doesn't matter if the user does not - actually link against crtbegin.o; the - linker won't look for a file to match a - wildcard. The wildcard also means that it - doesn't matter which directory crtbegin.o - is in. */ - KEEP (*crtbegin*.o(.ctors)) - /* We don't want to include the .ctor section from - from the crtend.o file until after the sorted ctors. - The .ctor section from the crtend file contains the - end of ctors marker and it must be last */ - KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - } - .dtors : - { - KEEP (*crtbegin*.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - } - .jcr : { KEEP (*(.jcr)) } - .data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) } - .data : - { - _fdata = . ; - *(.data .data.* .gnu.linkonce.d.*) - KEEP (*(.gnu.linkonce.d.*personality*)) - SORT(CONSTRUCTORS) - } - .data1 : { *(.data1) } - . = .; - _gp = ALIGN(16) + 0x7ff0; - .got : { *(.got.plt) *(.got) } - /* We want the small data sections together, so single-instruction offsets - can access them all, and initialized data all before uninitialized, so - we can shorten the on-disk segment size. */ - .sdata : - { - *(.sdata .sdata.* .gnu.linkonce.s.*) - } - .lit8 : { *(.lit8) } - .lit4 : { *(.lit4) } - _edata = .; - PROVIDE (edata = .); - __bss_start = .; - _fbss = .; - .sbss : - { - PROVIDE (__sbss_start = .); - PROVIDE (___sbss_start = .); - *(.dynsbss) - *(.sbss .sbss.* .gnu.linkonce.sb.*) - *(.scommon) - PROVIDE (__sbss_end = .); - PROVIDE (___sbss_end = .); - } - /* make a gap to put the plugins' short data here */ - __plugin_hole_start = .; - . = _gp + 0x7ff0; - __plugin_hole_end = .; - COMMON : - { - *(COMMON) - } - . = ALIGN(32 / 8); - .bss : - { - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - /* Align here to ensure that the .bss section occupies space up to - _end. Align after .bss to ensure correct alignment even if the - .bss section disappears because there are no input sections. */ - . = ALIGN(32 / 8); - } - . = ALIGN(32 / 8); - _end = .; - PROVIDE (end = .); - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - /DISCARD/ : { *(.comment) *(.pdr) } - /DISCARD/ : { *(.note.GNU-stack) } -} diff --git a/backends/platform/psp/module.mk b/backends/platform/psp/module.mk index f96c4ef583..e3eac153dd 100644 --- a/backends/platform/psp/module.mk +++ b/backends/platform/psp/module.mk @@ -11,14 +11,15 @@ MODULE_OBJS := powerman.o \ input.o \ cursor.o \ trace.o \ - psploader.o \ pspkeyboard.o \ audio.o \ thread.o \ rtc.o \ mp3.o \ png_loader.o \ - tests.o + image_viewer.o \ + tests.o \ + dummy.o # We don't use rules.mk but rather manually update OBJS and MODULE_DIRS. MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) diff --git a/backends/platform/psp/osys_psp.cpp b/backends/platform/psp/osys_psp.cpp index 047ec1957f..40c074ae00 100644 --- a/backends/platform/psp/osys_psp.cpp +++ b/backends/platform/psp/osys_psp.cpp @@ -76,12 +76,18 @@ void OSystem_PSP::initBackend() { _displayManager.setScreen(&_screen); _displayManager.setOverlay(&_overlay); _displayManager.setKeyboard(&_keyboard); + _displayManager.setImageViewer(&_imageViewer); _displayManager.init(); // Set pointers for input handler _inputHandler.setCursor(&_cursor); _inputHandler.setKeyboard(&_keyboard); + _inputHandler.setImageViewer(&_imageViewer); _inputHandler.init(); + + // Set pointers for image viewer + _imageViewer.setInputHandler(&_inputHandler); + _imageViewer.setDisplayManager(&_displayManager); _savefile = new PSPSaveFileManager; @@ -97,6 +103,12 @@ void OSystem_PSP::initBackend() { OSystem::initBackend(); } +// Let's us know an engine +void OSystem_PSP::engineDone() { + // for now, all we need is to reset the image number on the viewer + _imageViewer.resetOnEngineDone(); +} + bool OSystem_PSP::hasFeature(Feature f) { return (f == kFeatureOverlaySupportsAlpha || f == kFeatureCursorHasPalette); } diff --git a/backends/platform/psp/osys_psp.h b/backends/platform/psp/osys_psp.h index 5721296c94..52b8f4e887 100644 --- a/backends/platform/psp/osys_psp.h +++ b/backends/platform/psp/osys_psp.h @@ -32,10 +32,12 @@ #include "sound/mixer_intern.h" #include "backends/base-backend.h" #include "backends/fs/psp/psp-fs-factory.h" + #include "backends/platform/psp/display_client.h" #include "backends/platform/psp/default_display_client.h" #include "backends/platform/psp/cursor.h" #include "backends/platform/psp/pspkeyboard.h" +#include "backends/platform/psp/image_viewer.h" #include "backends/platform/psp/display_manager.h" #include "backends/platform/psp/input.h" #include "backends/platform/psp/audio.h" @@ -60,6 +62,7 @@ private: InputHandler _inputHandler; PspAudio _audio; PspTimer _pspTimer; + ImageViewer _imageViewer; public: OSystem_PSP() : _savefile(0), _mixer(0), _timer(0), _pendingUpdate(false), _pendingUpdateCounter(0) {} @@ -146,6 +149,7 @@ public: Common::SaveFileManager *getSavefileManager() { return _savefile; } FilesystemFactory *getFilesystemFactory() { return &PSPFilesystemFactory::instance(); } void getTimeAndDate(TimeDate &t) const; + virtual void engineDone(); void quit(); diff --git a/backends/platform/psp/plugin.ld b/backends/platform/psp/plugin.ld deleted file mode 100644 index 7534c15290..0000000000 --- a/backends/platform/psp/plugin.ld +++ /dev/null @@ -1,239 +0,0 @@ -OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", - "elf32-littlemips") -OUTPUT_ARCH(mips:allegrex) -PHDRS -{ - plugin PT_LOAD ; - shorts PT_LOAD ; -} -/* Do we need any of these for elf? - __DYNAMIC = 0; */ -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - . = 0; - .interp : { *(.interp) } : plugin - .reginfo : { *(.reginfo) } : plugin - .dynamic : { *(.dynamic) } - .hash : { *(.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .gnu.version : { *(.gnu.version) } - .gnu.version_d : { *(.gnu.version_d) } - .gnu.version_r : { *(.gnu.version_r) } - .rel.init : { *(.rel.init) } - .rela.init : { *(.rela.init) } - .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } - .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } - .rel.fini : { *(.rel.fini) } - .rela.fini : { *(.rela.fini) } - /* PSP-specific relocations. */ - .rel.sceStub.text : { *(.rel.sceStub.text) *(SORT(.rel.sceStub.text.*)) } - .rel.lib.ent.top : { *(.rel.lib.ent.top) } - .rel.lib.ent : { *(.rel.lib.ent) } - .rel.lib.ent.btm : { *(.rel.lib.ent.btm) } - .rel.lib.stub.top : { *(.rel.lib.stub.top) } - .rel.lib.stub : { *(.rel.lib.stub) } - .rel.lib.stub.btm : { *(.rel.lib.stub.btm) } - .rel.rodata.sceModuleInfo : { *(.rel.rodata.sceModuleInfo) } - .rel.rodata.sceResident : { *(.rel.rodata.sceResident) } - .rel.rodata.sceNid : { *(.rel.rodata.sceNid) } - .rel.rodata.sceVstub : { *(.rel.rodata.sceVstub) *(SORT(.rel.rodata.sceVstub.*)) } - .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } - .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } - .rel.data.rel.ro : { *(.rel.data.rel.ro*) } - .rela.data.rel.ro : { *(.rel.data.rel.ro*) } - .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } - .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } - .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } - .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } - .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } - .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } - .rel.ctors : { *(.rel.ctors) } - .rela.ctors : { *(.rela.ctors) } - .rel.dtors : { *(.rel.dtors) } - .rela.dtors : { *(.rela.dtors) } - .rel.got : { *(.rel.got) } - .rela.got : { *(.rela.got) } - .rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) } - .rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) } - .rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) } - .rela.sbss : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) } - .rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) } - .rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) } - .rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) } - .rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) } - .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } - .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } - .init : - { - KEEP (*(.init)) - } =0 - .plt : { *(.plt) } - .text : - { - _ftext = . ; - *(.text .stub .text.* .gnu.linkonce.t.*) - KEEP (*(.text.*personality*)) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - *(.mips16.fn.*) *(.mips16.call.*) - } =0 - .fini : - { - KEEP (*(.fini)) - } =0 - /* PSP library stub functions. */ - .sceStub.text : { *(.sceStub.text) *(SORT(.sceStub.text.*)) } - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - /* PSP library entry table and library stub table. */ - .lib.ent.top : { *(.lib.ent.top) } - .lib.ent : { *(.lib.ent) } - .lib.ent.btm : { *(.lib.ent.btm) } - .lib.stub.top : { *(.lib.stub.top) } - .lib.stub : { *(.lib.stub) } - .lib.stub.btm : { *(.lib.stub.btm) } - /* PSP read-only data for module info, NIDs, and Vstubs. The - .rodata.sceModuleInfo section must appear before the .rodata section - otherwise it would get absorbed into .rodata and the PSP bootloader - would be unable to locate the module info structure. */ - .rodata.sceModuleInfo : { *(.rodata.sceModuleInfo) } - .rodata.sceResident : { *(.rodata.sceResident) } - .rodata.sceNid : { *(.rodata.sceNid) } - .rodata.sceVstub : { *(.rodata.sceVstub) *(SORT(.rodata.sceVstub.*)) } - .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } - .rodata1 : { *(.rodata1) } - .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) } - .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } - .eh_frame_hdr : { *(.eh_frame_hdr) } - .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RO { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) } - /* Adjust the address for the data segment. We want to adjust up to - the same address within the page on the next page up. */ - . = ALIGN(256) + (. & (256 - 1)); - /* Exception handling */ - .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RW { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) } - /* Thread Local Storage sections */ - .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } - .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } - /* Ensure the __preinit_array_start label is properly aligned. We - could instead move the label definition inside the section, but - the linker would then create the section even if it turns out to - be empty, which isn't pretty. */ - . = ALIGN(32 / 8); - PROVIDE (__preinit_array_start = .); - .preinit_array : { KEEP (*(.preinit_array)) } - PROVIDE (__preinit_array_end = .); - PROVIDE (__init_array_start = .); - .init_array : { KEEP (*(.init_array)) } - PROVIDE (__init_array_end = .); - PROVIDE (__fini_array_start = .); - .fini_array : { KEEP (*(.fini_array)) } - PROVIDE (__fini_array_end = .); - .ctors : - { - ___plugin_ctors = .; - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - ___plugin_ctors_end = .; - } - .dtors : - { - ___plugin_dtors = .; - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - ___plugin_dtors_end = .; - } - .jcr : { KEEP (*(.jcr)) } - .data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) } - .data : - { - _fdata = . ; - *(.data .data.* .gnu.linkonce.d.*) - KEEP (*(.gnu.linkonce.d.*personality*)) - SORT(CONSTRUCTORS) - } - .data1 : { *(.data1) } - . = .; - .bss : - { - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - /* Align here to ensure that the .bss section occupies space up to - _end. Align after .bss to ensure correct alignment even if the - .bss section disappears because there are no input sections. */ - . = ALIGN(32 / 8); - } - . = ALIGN(32 / 8); - _end = .; - PROVIDE (end = .); - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - /DISCARD/ : { *(.comment) *(.pdr) } - /DISCARD/ : { *(.note.GNU-stack) } - - . = __plugin_hole_start; - .got : { *(.got.plt) *(.got) } : shorts - /* We want the small data sections together, so single-instruction offsets - can access them all, and initialized data all before uninitialized, so - we can shorten the on-disk segment size. */ - .sdata : - { - *(.sdata .sdata.* .gnu.linkonce.s.*) - } - .lit8 : { *(.lit8) } - .lit4 : { *(.lit4) } - _edata = .; - PROVIDE (edata = .); - __bss_start = .; - _fbss = .; - .sbss : - { - PROVIDE (__sbss_start = .); - PROVIDE (___sbss_start = .); - *(.dynsbss) - *(.sbss .sbss.* .gnu.linkonce.sb.*) - *(.scommon) - PROVIDE (__sbss_end = .); - PROVIDE (___sbss_end = .); - } - - -} diff --git a/backends/platform/psp/plugin.syms b/backends/platform/psp/plugin.syms deleted file mode 100644 index 24ee1a19dc..0000000000 --- a/backends/platform/psp/plugin.syms +++ /dev/null @@ -1,8 +0,0 @@ -PLUGIN_getVersion -PLUGIN_getType -PLUGIN_getTypeVersion -PLUGIN_getObject -___plugin_ctors -___plugin_ctors_end -___plugin_dtors -___plugin_dtors_end diff --git a/backends/platform/psp/png_loader.cpp b/backends/platform/psp/png_loader.cpp index 978db3eaf9..08f370f36d 100644 --- a/backends/platform/psp/png_loader.cpp +++ b/backends/platform/psp/png_loader.cpp @@ -23,32 +23,43 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + #include "common/scummsys.h" #include "common/stream.h" #include "backends/platform/psp/psppixelformat.h" #include "backends/platform/psp/display_client.h" #include "backends/platform/psp/png_loader.h" +//#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */ +//#define __PSP_DEBUG_PRINT__ /* For debug printouts */ + +#include "backends/platform/psp/trace.h" + PngLoader::Status PngLoader::allocate() { + DEBUG_ENTER_FUNC(); + if (!findImageDimensions()) { PSP_ERROR("failed to get image dimensions\n"); return BAD_FILE; } - PSP_DEBUG_PRINT("width[%d], height[%d], paletteSize[%d], bitDepth[%d]\n", _width, _height, _paletteSize, _bitDepth); _buffer->setSize(_width, _height, _sizeBy); + uint32 bitsPerPixel = _bitDepth * _channels; + if (_paletteSize) { // 8 or 4-bit image - if (_paletteSize <= 16) { // 4 bit + if (bitsPerPixel == 4) { _buffer->setPixelFormat(PSPPixelFormat::Type_Palette_4bit); _palette->setPixelFormats(PSPPixelFormat::Type_4444, PSPPixelFormat::Type_Palette_4bit); - _paletteSize = 16; - } else if (_paletteSize <= 256) { // 8-bit image - _paletteSize = 256; + _paletteSize = 16; // round up + } else if (bitsPerPixel == 8) { // 8-bit image _buffer->setPixelFormat(PSPPixelFormat::Type_Palette_8bit); _palette->setPixelFormats(PSPPixelFormat::Type_4444, PSPPixelFormat::Type_Palette_8bit); + _paletteSize = 256; // round up } else { - PSP_ERROR("palette of %d too big!\n", _paletteSize); + PSP_ERROR("too many bits per pixel[%d] for a palette\n", bitsPerPixel); return BAD_FILE; } @@ -60,7 +71,7 @@ PngLoader::Status PngLoader::allocate() { PSP_ERROR("failed to allocate buffer\n"); return OUT_OF_MEMORY; } - if (!_palette->allocate()) { + if (_buffer->hasPalette() && !_palette->allocate()) { PSP_ERROR("failed to allocate palette\n"); return OUT_OF_MEMORY; } @@ -68,6 +79,7 @@ PngLoader::Status PngLoader::allocate() { } bool PngLoader::load() { + DEBUG_ENTER_FUNC(); // Try to load the image _file->seek(0); // Go back to start @@ -98,6 +110,7 @@ void PngLoader::libReadFunc(png_structp pngPtr, png_bytep data, png_size_t lengt } bool PngLoader::basicImageLoad() { + DEBUG_ENTER_FUNC(); _pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!_pngPtr) return false; @@ -119,7 +132,8 @@ bool PngLoader::basicImageLoad() { int interlaceType; png_get_IHDR(_pngPtr, _infoPtr, (png_uint_32 *)&_width, (png_uint_32 *)&_height, &_bitDepth, &_colorType, &interlaceType, int_p_NULL, int_p_NULL); - + _channels = png_get_channels(_pngPtr, _infoPtr); + if (_colorType & PNG_COLOR_MASK_PALETTE) _paletteSize = _infoPtr->num_palette; @@ -130,11 +144,11 @@ bool PngLoader::basicImageLoad() { bool PngLoader::findImageDimensions() { DEBUG_ENTER_FUNC(); - if (!basicImageLoad()) - return false; + bool status = basicImageLoad(); + PSP_DEBUG_PRINT("width[%d], height[%d], paletteSize[%d], bitDepth[%d], channels[%d], rowBytes[%d]\n", _width, _height, _paletteSize, _bitDepth, _channels, _infoPtr->rowbytes); png_destroy_read_struct(&_pngPtr, &_infoPtr, png_infopp_NULL); - return true; + return status; } // @@ -143,16 +157,16 @@ bool PngLoader::findImageDimensions() { bool PngLoader::loadImageIntoBuffer() { DEBUG_ENTER_FUNC(); - if (!basicImageLoad()) + if (!basicImageLoad()) { + png_destroy_read_struct(&_pngPtr, &_infoPtr, png_infopp_NULL); return false; - - // Strip off 16 bit channels. Not really needed but whatever - png_set_strip_16(_pngPtr); + } + png_set_strip_16(_pngPtr); // Strip off 16 bit channels in case they occur if (_paletteSize) { // Copy the palette png_colorp srcPal = _infoPtr->palette; - for (int i = 0; i < (int)_paletteSize; i++) { + for (int i = 0; i < _infoPtr->num_palette; i++) { unsigned char alphaVal = (i < _infoPtr->num_trans) ? _infoPtr->trans[i] : 0xFF; // Load alpha if it's there _palette->setSingleColorRGBA(i, srcPal->red, srcPal->green, srcPal->blue, alphaVal); srcPal++; @@ -163,10 +177,21 @@ bool PngLoader::loadImageIntoBuffer() { if (png_get_valid(_pngPtr, _infoPtr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(_pngPtr); // Convert trans channel to alpha for 32 bits - png_set_filler(_pngPtr, 0xff, PNG_FILLER_AFTER); // Filler for alpha? + png_set_add_alpha(_pngPtr, 0xff, PNG_FILLER_AFTER); // Filler for alpha if none exists } - unsigned char *line = (unsigned char*) malloc(_infoPtr->rowbytes); + uint32 rowBytes = png_get_rowbytes(_pngPtr, _infoPtr); + + // there seems to be a bug in libpng where it doesn't increase the rowbytes or the + // channel even after we add the alpha channel + if (_channels == 3 && (rowBytes / _width) == 3) { + _channels = 4; + rowBytes = _width * _channels; + } + + PSP_DEBUG_PRINT("rowBytes[%d], channels[%d]\n", rowBytes, _channels); + + unsigned char *line = (unsigned char*) malloc(rowBytes); if (!line) { png_destroy_read_struct(&_pngPtr, png_infopp_NULL, png_infopp_NULL); PSP_ERROR("Couldn't allocate line\n"); @@ -175,11 +200,9 @@ bool PngLoader::loadImageIntoBuffer() { for (size_t y = 0; y < _height; y++) { png_read_row(_pngPtr, line, png_bytep_NULL); - _buffer->copyFromRect(line, _infoPtr->rowbytes, 0, y, _width, 1); // Copy into buffer + _buffer->copyFromRect(line, rowBytes, 0, y, _width, 1); // Copy into buffer } - free(line); - png_read_end(_pngPtr, _infoPtr); png_destroy_read_struct(&_pngPtr, &_infoPtr, png_infopp_NULL); diff --git a/backends/platform/psp/png_loader.h b/backends/platform/psp/png_loader.h index 6b0282621a..4119bfef2b 100644 --- a/backends/platform/psp/png_loader.h +++ b/backends/platform/psp/png_loader.h @@ -44,11 +44,14 @@ private: uint32 _width; uint32 _height; uint32 _paletteSize; - int _bitDepth; Buffer::HowToSize _sizeBy; + + // PNG lib values + int _bitDepth; png_structp _pngPtr; png_infop _infoPtr; int _colorType; + uint32 _channels; public: enum Status { @@ -61,7 +64,8 @@ public: Buffer::HowToSize sizeBy = Buffer::kSizeByTextureSize) : _file(file), _buffer(&buffer), _palette(&palette), _width(0), _height(0), _paletteSize(0), - _bitDepth(0), _sizeBy(sizeBy), _pngPtr(0), _infoPtr(0), _colorType(0) {} + _bitDepth(0), _sizeBy(sizeBy), _pngPtr(0), + _infoPtr(0), _colorType(0), _channels(0) {} PngLoader::Status allocate(); bool load(); diff --git a/backends/platform/psp/psp.spec b/backends/platform/psp/psp.spec index ac325b7fd6..7177413373 100644 --- a/backends/platform/psp/psp.spec +++ b/backends/platform/psp/psp.spec @@ -1,3 +1,3 @@ %rename lib old_lib *lib: -%(old_lib) -lz -lstdc++ -lc -lm -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk -lpsputility -lpspuser -lpsppower -lpsphprm -lpsprtc -lpspaudio -lpspaudiocodec -lpspkernel +%(old_lib) -lz -lstdc++ -lc -lm -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk -lpsputility -lpspuser -lpsppower -lpsphprm -lpsprtc -lpspaudio -lpspaudiocodec -lpspkernel -lpspnet_inet diff --git a/backends/platform/psp/pspkeyboard.cpp b/backends/platform/psp/pspkeyboard.cpp index 3dd5e9789b..f210726692 100644 --- a/backends/platform/psp/pspkeyboard.cpp +++ b/backends/platform/psp/pspkeyboard.cpp @@ -23,6 +23,9 @@ * */ +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + //#define PSP_KB_SHELL /* Need a hack to properly load the keyboard from the PSP shell */ #ifdef PSP_KB_SHELL @@ -78,9 +81,9 @@ short PSPKeyboard::_modeChar[MODE_COUNT][5][6] = { }, { //numbers { K('1'), K('2'), K('3'), K('4'), K(0), K(0) }, - { C(F5), C(F8), C(F7), C(F6), C(F9), C(F10) }, + { C(F5), C(F6), C(F7), C(F8), C(F9), C(F10) }, { K('5'), K('6'), K('7'), K('8'), K(0), K(0) }, - { C(F1), C(F4), C(F3), C(F2), K(0), K(0) }, + { C(F1), C(F2), C(F3), C(F4), K(0), K(0) }, { K('\b'), K('0'), K(' '), K('9'), K(0), K(0) } }, { //symbols diff --git a/backends/platform/psp/psploader.cpp b/backends/platform/psp/psploader.cpp deleted file mode 100644 index 464e20770c..0000000000 --- a/backends/platform/psp/psploader.cpp +++ /dev/null @@ -1,732 +0,0 @@ -/* 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$ - * $Id$ - * - */ - -#if defined(DYNAMIC_MODULES) && defined(__PSP__) - -#include <string.h> -#include <stdarg.h> -#include <stdio.h> -#include <malloc.h> -#include <unistd.h> -#include <sys/_default_fcntl.h> - -#include <psputils.h> - -#include "backends/platform/psp/psploader.h" -#include "backends/platform/psp/powerman.h" - -//#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */ -//#define __PSP_DEBUG_PRINT__ - -#include "backends/platform/psp/trace.h" - -extern char __plugin_hole_start; // Indicates start of hole in program file for shorts -extern char __plugin_hole_end; // Indicates end of hole in program file -extern char _gp[]; // Value of gp register - -DECLARE_SINGLETON(ShortSegmentManager) // For singleton - -// Get rid of symbol table in memory -void DLObject::discard_symtab() { - DEBUG_ENTER_FUNC(); - free(_symtab); - free(_strtab); - _symtab = NULL; - _strtab = NULL; - _symbol_cnt = 0; -} - -// Unload all objects from memory -void DLObject::unload() { - DEBUG_ENTER_FUNC(); - discard_symtab(); - free(_segment); - _segment = NULL; - - if (_shortsSegment) { - ShortsMan.deleteSegment(_shortsSegment); - _shortsSegment = NULL; - } -} - -/** - * Follow the instruction of a relocation section. - * - * @param fd File Descriptor - * @param offset Offset into the File - * @param size Size of relocation section - * @param relSegment Base address of relocated segment in memory (memory offset) - * - */ -bool DLObject::relocate(int fd, unsigned long offset, unsigned long size, void *relSegment) { - DEBUG_ENTER_FUNC(); - Elf32_Rel *rel = NULL; // relocation entry - - // Allocate memory for relocation table - if (!(rel = (Elf32_Rel *)malloc(size))) { - PSP_ERROR("Out of memory."); - return false; - } - - // Read in our relocation table - if (lseek(fd, offset, SEEK_SET) < 0 || - read(fd, rel, size) != (ssize_t)size) { - PSP_ERROR("Relocation table load failed."); - free(rel); - return false; - } - - // Treat each relocation entry. Loop over all of them - int cnt = size / sizeof(*rel); - - PSP_DEBUG_PRINT("Loaded relocation table. %d entries. base address=%p\n", cnt, relSegment); - - bool seenHi16 = false; // For treating HI/LO16 commands - int firstHi16 = -1; // Mark the point of the first hi16 seen - Elf32_Addr ahl = 0; // Calculated addend - int a = 0; // Addend: taken from the target - - unsigned int *lastTarget = 0; // For processing hi16 when lo16 arrives - unsigned int relocation = 0; - int debugRelocs[10] = {0}; // For debugging - int extendedHi16 = 0; // Count extended hi16 treatments - Elf32_Addr lastHiSymVal = 0; - bool hi16InShorts = false; - -#define DEBUG_NUM 2 - - // Loop over relocation entries - for (int i = 0; i < cnt; i++) { - // Get the symbol this relocation entry is referring to - Elf32_Sym *sym = (Elf32_Sym *)(_symtab) + (REL_INDEX(rel[i].r_info)); - - // Get the target instruction in the code - unsigned int *target = (unsigned int *)((char *)relSegment + rel[i].r_offset); - - PSP_DEBUG_DO(unsigned int origTarget = *target); // Save for debugging - - // Act differently based on the type of relocation - switch (REL_TYPE(rel[i].r_info)) { - - case R_MIPS_HI16: // Absolute addressing. - if (sym->st_shndx < SHN_LOPROC && // Only shift for plugin section (ie. has a real section index) - firstHi16 < 0) { // Only process first in block of HI16s - firstHi16 = i; // Keep the first Hi16 we saw - seenHi16 = true; - ahl = (*target & 0xffff) << 16; // Take lower 16 bits shifted up - - lastHiSymVal = sym->st_value; - hi16InShorts = (ShortsMan.inGeneralSegment((char *)sym->st_value)); // Fix for problem with switching btw segments - if (debugRelocs[0]++ < DEBUG_NUM) // Print only a set number - PSP_DEBUG_PRINT("R_MIPS_HI16: i=%d, offset=%x, ahl = %x, target = %x\n", - i, rel[i].r_offset, ahl, *target); - } - break; - - case R_MIPS_LO16: // Absolute addressing. Needs a HI16 to come before it - if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section. (ie. has a real section index) - if (!seenHi16) { // We MUST have seen HI16 first - PSP_ERROR("R_MIPS_LO16 w/o preceding R_MIPS_HI16 at relocation %d!\n", i); - free(rel); - return false; - } - - // Fix: bug in gcc makes LO16s connect to wrong HI16s sometimes (shorts and regular segment) - // Note that we can check the entire shorts segment because the executable's shorts don't belong to this plugin section - // and will be screened out above - bool lo16InShorts = ShortsMan.inGeneralSegment((char *)sym->st_value); - - // Correct the bug by getting the proper value in ahl (taken from the current symbol) - if ((hi16InShorts && !lo16InShorts) || (!hi16InShorts && lo16InShorts)) { - ahl -= (lastHiSymVal & 0xffff0000); // We assume gcc meant the same offset - ahl += (sym->st_value & 0xffff0000); - } - - ahl &= 0xffff0000; // Clean lower 16 bits for repeated LO16s - a = *target & 0xffff; // Take lower 16 bits of the target - a = (a << 16) >> 16; // Sign extend them - ahl += a; // Add lower 16 bits. AHL is now complete - - // Fix: we can have LO16 access to the short segment sometimes - if (lo16InShorts) { - relocation = ahl + _shortsSegment->getOffset(); // Add in the short segment offset - } else // It's in the regular segment - relocation = ahl + (Elf32_Addr)_segment; // Add in the new offset for the segment - - if (firstHi16 >= 0) { // We haven't treated the HI16s yet so do it now - for (int j = firstHi16; j < i; j++) { - if (REL_TYPE(rel[j].r_info) != R_MIPS_HI16) continue; // Skip over non-Hi16s - - lastTarget = (unsigned int *)((char *)relSegment + rel[j].r_offset); // get hi16 target - *lastTarget &= 0xffff0000; // Clear the lower 16 bits of the last target - *lastTarget |= (relocation >> 16) & 0xffff; // Take the upper 16 bits of the relocation - if (relocation & 0x8000)(*lastTarget)++; // Subtle: we need to add 1 to the HI16 in this case - } - firstHi16 = -1; // Reset so we'll know we treated it - } else { - extendedHi16++; - } - - *target &= 0xffff0000; // Clear the lower 16 bits of current target - *target |= relocation & 0xffff; // Take the lower 16 bits of the relocation - - if (debugRelocs[1]++ < DEBUG_NUM) - PSP_DEBUG_PRINT("R_MIPS_LO16: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x\n", - i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target); - if (lo16InShorts && debugRelocs[2]++ < DEBUG_NUM) - PSP_DEBUG_PRINT("R_MIPS_LO16s: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x\n", - i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target); - } - break; - - case R_MIPS_26: // Absolute addressing (for jumps and branches only) - if (sym->st_shndx < SHN_LOPROC) { // Only relocate for main segment - a = *target & 0x03ffffff; // Get 26 bits' worth of the addend - a = (a << 6) >> 6; // Sign extend a - relocation = ((a << 2) + (Elf32_Addr)_segment) >> 2; // a already points to the target. Subtract our offset - *target &= 0xfc000000; // Clean lower 26 target bits - *target |= (relocation & 0x03ffffff); - - if (debugRelocs[3]++ < DEBUG_NUM) - PSP_DEBUG_PRINT("R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x\n", - i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target); - } else { - if (debugRelocs[4]++ < DEBUG_NUM) - PSP_DEBUG_PRINT("R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x\n", - i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target); - } - break; - - case R_MIPS_GPREL16: // GP Relative addressing - if (_shortsSegment->getOffset() != 0 && // Only relocate if we shift the shorts section - ShortsMan.inGeneralSegment((char *)sym->st_value)) { // Only relocate things in the plugin hole - a = *target & 0xffff; // Get 16 bits' worth of the addend - a = (a << 16) >> 16; // Sign extend it - - relocation = a + _shortsSegment->getOffset(); - - *target &= 0xffff0000; // Clear the lower 16 bits of the target - *target |= relocation & 0xffff; - - if (debugRelocs[5]++ < DEBUG_NUM) - PSP_DEBUG_PRINT("R_MIPS_GPREL16: i=%d, a=%x, gpVal=%x, origTarget=%x, target=%x, offset=%x\n", - i, a, _gpVal, origTarget, *target, _shortsSegment->getOffset()); - } - - break; - - case R_MIPS_32: // Absolute addressing - if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section. - a = *target; // Get full 32 bits of addend - - if (ShortsMan.inGeneralSegment((char *)sym->st_value)) // Check if we're in the shorts segment - relocation = a + _shortsSegment->getOffset(); // Shift by shorts offset - else // We're in the main section - relocation = a + (Elf32_Addr)_segment; // Shift by main offset - *target = relocation; - - if (debugRelocs[6]++ < DEBUG_NUM) - PSP_DEBUG_PRINT("R_MIPS_32: i=%d, a=%x, origTarget=%x, target=%x\n", i, a, origTarget, *target); - } - break; - - default: - PSP_ERROR("Unknown relocation type %x at relocation %d.\n", REL_TYPE(rel[i].r_info), i); - free(rel); - return false; - } - } - - PSP_DEBUG_PRINT("Done with relocation. extendedHi16=%d\n\n", extendedHi16); - - free(rel); - return true; -} - -bool DLObject::readElfHeader(int fd, Elf32_Ehdr *ehdr) { - DEBUG_ENTER_FUNC(); - // Start reading the elf header. Check for errors - if (read(fd, ehdr, sizeof(*ehdr)) != sizeof(*ehdr) || - memcmp(ehdr->e_ident, ELFMAG, SELFMAG) || // Check MAGIC - ehdr->e_type != ET_EXEC || // Check for executable - ehdr->e_machine != EM_MIPS || // Check for MIPS machine type - ehdr->e_phentsize < sizeof(Elf32_Phdr) || // Check for size of program header - ehdr->e_shentsize != sizeof(Elf32_Shdr)) { // Check for size of section header - PSP_ERROR("Invalid file type."); - return false; - } - - PSP_DEBUG_PRINT("phoff = %d, phentsz = %d, phnum = %d\n", - ehdr->e_phoff, ehdr->e_phentsize, ehdr->e_phnum); - - return true; -} - -bool DLObject::readProgramHeaders(int fd, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num) { - DEBUG_ENTER_FUNC(); - // Read program header - if (lseek(fd, ehdr->e_phoff + sizeof(*phdr)*num, SEEK_SET) < 0 || - read(fd, phdr, sizeof(*phdr)) != sizeof(*phdr)) { - PSP_ERROR("Program header load failed."); - return false; - } - - // Check program header values - if (phdr->p_type != PT_LOAD || phdr->p_filesz > phdr->p_memsz) { - PSP_ERROR("Invalid program header."); - return false; - } - - PSP_DEBUG_PRINT("offs = %x, filesz = %x, memsz = %x, align = %x\n", - phdr->p_offset, phdr->p_filesz, phdr->p_memsz, phdr->p_align); - - return true; - -} - -bool DLObject::loadSegment(int fd, Elf32_Phdr *phdr) { - DEBUG_ENTER_FUNC(); - - char *baseAddress = 0; - - // We need to take account of non-allocated segment for shorts - if (phdr->p_flags & PF_X) { // This is a relocated segment - - // Attempt to allocate memory for segment - int extra = phdr->p_vaddr % phdr->p_align; // Get extra length TODO: check logic here - PSP_DEBUG_PRINT("extra mem is %x\n", extra); - - if (phdr->p_align < 0x10000) phdr->p_align = 0x10000; // Fix for wrong alignment on e.g. AGI - - if (!(_segment = (char *)memalign(phdr->p_align, phdr->p_memsz + extra))) { - PSP_ERROR("Out of memory.\n"); - return false; - } - PSP_DEBUG_PRINT("allocated segment @ %p\n", _segment); - - // Get offset to load segment into - baseAddress = (char *)_segment + phdr->p_vaddr; - _segmentSize = phdr->p_memsz + extra; - } else { // This is a shorts section. - _shortsSegment = ShortsMan.newSegment(phdr->p_memsz, (char *)phdr->p_vaddr); - - baseAddress = _shortsSegment->getStart(); - PSP_DEBUG_PRINT("shorts segment @ %p to %p. Segment wants to be at %x. Offset=%x\n", - _shortsSegment->getStart(), _shortsSegment->getEnd(), phdr->p_vaddr, _shortsSegment->getOffset()); - - } - - // Set bss segment to 0 if necessary (assumes bss is at the end) - if (phdr->p_memsz > phdr->p_filesz) { - PSP_DEBUG_PRINT("Setting %p to %p to 0 for bss\n", baseAddress + phdr->p_filesz, baseAddress + phdr->p_memsz); - memset(baseAddress + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); - } - // Read the segment into memory - if (lseek(fd, phdr->p_offset, SEEK_SET) < 0 || - read(fd, baseAddress, phdr->p_filesz) != (ssize_t)phdr->p_filesz) { - PSP_ERROR("Segment load failed."); - return false; - } - - return true; -} - - -Elf32_Shdr * DLObject::loadSectionHeaders(int fd, Elf32_Ehdr *ehdr) { - DEBUG_ENTER_FUNC(); - - Elf32_Shdr *shdr = NULL; - - // Allocate memory for section headers - if (!(shdr = (Elf32_Shdr *)malloc(ehdr->e_shnum * sizeof(*shdr)))) { - PSP_ERROR("Out of memory."); - return NULL; - } - - // Read from file into section headers - if (lseek(fd, ehdr->e_shoff, SEEK_SET) < 0 || - read(fd, shdr, ehdr->e_shnum * sizeof(*shdr)) != - (ssize_t)(ehdr->e_shnum * sizeof(*shdr))) { - PSP_ERROR("Section headers load failed."); - return NULL; - } - - return shdr; -} - -int DLObject::loadSymbolTable(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) { - DEBUG_ENTER_FUNC(); - - // Loop over sections, looking for symbol table linked to a string table - for (int i = 0; i < ehdr->e_shnum; i++) { - PSP_DEBUG_PRINT("Section %d: type = %x, size = %x, entsize = %x, link = %x\n", - i, shdr[i].sh_type, shdr[i].sh_size, shdr[i].sh_entsize, shdr[i].sh_link); - - if (shdr[i].sh_type == SHT_SYMTAB && - shdr[i].sh_entsize == sizeof(Elf32_Sym) && - shdr[i].sh_link < ehdr->e_shnum && - shdr[shdr[i].sh_link].sh_type == SHT_STRTAB && - _symtab_sect < 0) { - _symtab_sect = i; - } - } - - // Check for no symbol table - if (_symtab_sect < 0) { - PSP_ERROR("No symbol table."); - return -1; - } - - PSP_DEBUG_PRINT("Symbol section at section %d, size %x\n", _symtab_sect, shdr[_symtab_sect].sh_size); - - // Allocate memory for symbol table - if (!(_symtab = malloc(shdr[_symtab_sect].sh_size))) { - PSP_ERROR("Out of memory."); - return -1; - } - - // Read symbol table into memory - if (lseek(fd, shdr[_symtab_sect].sh_offset, SEEK_SET) < 0 || - read(fd, _symtab, shdr[_symtab_sect].sh_size) != - (ssize_t)shdr[_symtab_sect].sh_size) { - PSP_ERROR("Symbol table load failed."); - return -1; - } - - // Set number of symbols - _symbol_cnt = shdr[_symtab_sect].sh_size / sizeof(Elf32_Sym); - PSP_DEBUG_PRINT("Loaded %d symbols.\n", _symbol_cnt); - - return _symtab_sect; - -} - -bool DLObject::loadStringTable(int fd, Elf32_Shdr *shdr) { - DEBUG_ENTER_FUNC(); - - int string_sect = shdr[_symtab_sect].sh_link; - - // Allocate memory for string table - if (!(_strtab = (char *)malloc(shdr[string_sect].sh_size))) { - PSP_ERROR("Out of memory."); - return false; - } - - // Read string table into memory - if (lseek(fd, shdr[string_sect].sh_offset, SEEK_SET) < 0 || - read(fd, _strtab, shdr[string_sect].sh_size) != - (ssize_t)shdr[string_sect].sh_size) { - PSP_ERROR("Symbol table strings load failed."); - return false; - } - return true; -} - -void DLObject::relocateSymbols(Elf32_Addr offset, Elf32_Addr shortsOffset) { - DEBUG_ENTER_FUNC(); - - int shortsCount = 0, othersCount = 0; - PSP_DEBUG_PRINT("Relocating symbols by %x. Shorts offset=%x\n", offset, shortsOffset); - - // Loop over symbols, add relocation offset - Elf32_Sym *s = (Elf32_Sym *)_symtab; - for (int c = _symbol_cnt; c--; s++) { - // Make sure we don't relocate special valued symbols - if (s->st_shndx < SHN_LOPROC) { - if (!ShortsMan.inGeneralSegment((char *)s->st_value)) { - othersCount++; - s->st_value += offset; - if (s->st_value < (Elf32_Addr)_segment || s->st_value > (Elf32_Addr)_segment + _segmentSize) - PSP_ERROR("Symbol out of bounds! st_value = %x\n", s->st_value); - } else { // shorts section - shortsCount++; - s->st_value += shortsOffset; - if (!_shortsSegment->inSegment((char *)s->st_value)) - PSP_ERROR("Symbol out of bounds! st_value = %x\n", s->st_value); - } - - } - - } - - PSP_DEBUG_PRINT("Relocated %d short symbols, %d others.\n", shortsCount, othersCount); -} - -bool DLObject::relocateRels(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) { - DEBUG_ENTER_FUNC(); - - // Loop over sections, finding relocation sections - for (int i = 0; i < ehdr->e_shnum; i++) { - - Elf32_Shdr *curShdr = &(shdr[i]); - //Elf32_Shdr *linkShdr = &(shdr[curShdr->sh_info]); - - if (curShdr->sh_type == SHT_REL && // Check for a relocation section - curShdr->sh_entsize == sizeof(Elf32_Rel) && // Check for proper relocation size - (int)curShdr->sh_link == _symtab_sect && // Check that the sh_link connects to our symbol table - curShdr->sh_info < ehdr->e_shnum && // Check that the relocated section exists - (shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) { // Check if relocated section resides in memory - if (!ShortsMan.inGeneralSegment((char *)shdr[curShdr->sh_info].sh_addr)) { // regular segment - if (!relocate(fd, curShdr->sh_offset, curShdr->sh_size, _segment)) { - return false; - } - } else { // In Shorts segment - if (!relocate(fd, curShdr->sh_offset, curShdr->sh_size, (void *)_shortsSegment->getOffset())) { - return false; - } - } - - } - } - - return true; -} - - -bool DLObject::load(int fd) { - DEBUG_ENTER_FUNC(); - - Elf32_Ehdr ehdr; // ELF header - Elf32_Phdr phdr; // Program header - Elf32_Shdr *shdr; // Section header - bool ret = true; - - if (readElfHeader(fd, &ehdr) == false) { - return false; - } - - for (int i = 0; i < ehdr.e_phnum; i++) { // Load our 2 segments - PSP_DEBUG_PRINT("Loading segment %d\n", i); - - if (readProgramHeaders(fd, &ehdr, &phdr, i) == false) - return false; - - if (!loadSegment(fd, &phdr)) - return false; - } - - if ((shdr = loadSectionHeaders(fd, &ehdr)) == NULL) - ret = false; - - if (ret && ((_symtab_sect = loadSymbolTable(fd, &ehdr, shdr)) < 0)) - ret = false; - - if (ret && (loadStringTable(fd, shdr) == false)) - ret = false; - - if (ret) - relocateSymbols((Elf32_Addr)_segment, _shortsSegment->getOffset()); // Offset by our segment allocated address - - if (ret && (relocateRels(fd, &ehdr, shdr) == false)) - ret = false; - - free(shdr); - - return ret; -} - -bool DLObject::open(const char *path) { - DEBUG_ENTER_FUNC(); - int fd; - void *ctors_start, *ctors_end; - - PSP_DEBUG_PRINT("open(\"%s\")\n", path); - - // Get the address of the global pointer - _gpVal = (unsigned int) & _gp; - PSP_DEBUG_PRINT("_gpVal is %x\n", _gpVal); - - PowerMan.beginCriticalSection(); - - if ((fd = ::open(path, O_RDONLY)) < 0) { - PSP_ERROR("%s not found.", path); - return false; - } - - // Try to load and relocate - if (!load(fd)) { - ::close(fd); - unload(); - return false; - } - - ::close(fd); - - PowerMan.endCriticalSection(); - - // flush data cache - sceKernelDcacheWritebackAll(); - - // Get the symbols for the global constructors and destructors - ctors_start = symbol("___plugin_ctors"); - ctors_end = symbol("___plugin_ctors_end"); - _dtors_start = symbol("___plugin_dtors"); - _dtors_end = symbol("___plugin_dtors_end"); - - if (ctors_start == NULL || ctors_end == NULL || _dtors_start == NULL || - _dtors_end == NULL) { - PSP_ERROR("Missing ctors/dtors."); - _dtors_start = _dtors_end = NULL; - unload(); - return false; - } - - PSP_DEBUG_PRINT("Calling constructors.\n"); - for (void (**f)(void) = (void (**)(void))ctors_start; f != ctors_end; f++) - (**f)(); - - PSP_DEBUG_PRINT("%s opened ok.\n", path); - return true; -} - -bool DLObject::close() { - DEBUG_ENTER_FUNC(); - if (_dtors_start != NULL && _dtors_end != NULL) - for (void (**f)(void) = (void (**)(void))_dtors_start; f != _dtors_end; f++) - (**f)(); - _dtors_start = _dtors_end = NULL; - unload(); - return true; -} - -void *DLObject::symbol(const char *name) { - DEBUG_ENTER_FUNC(); - PSP_DEBUG_PRINT("symbol(\"%s\")\n", name); - - if (_symtab == NULL || _strtab == NULL || _symbol_cnt < 1) { - PSP_ERROR("No symbol table loaded."); - return NULL; - } - - Elf32_Sym *s = (Elf32_Sym *)_symtab; - for (int c = _symbol_cnt; c--; s++) { - - // We can only import symbols that are global or weak in the plugin - if ((SYM_BIND(s->st_info) == STB_GLOBAL || SYM_BIND(s->st_info) == STB_WEAK) && - /*_strtab[s->st_name] == '_' && */ // Try to make this more efficient - !strcmp(name, _strtab + s->st_name)) { - - // We found the symbol - PSP_DEBUG_PRINT("=> %p\n", (void*)s->st_value); - return (void*)s->st_value; - } - } - - PSP_ERROR("Symbol \"%s\" not found.", name); - return NULL; -} - - - -ShortSegmentManager::ShortSegmentManager() { - DEBUG_ENTER_FUNC(); - _shortsStart = &__plugin_hole_start ; - _shortsEnd = &__plugin_hole_end; -} - -ShortSegmentManager::Segment *ShortSegmentManager::newSegment(int size, char *origAddr) { - DEBUG_ENTER_FUNC(); - char *lastAddress = origAddr; - Common::List<Segment *>::iterator i; - - // Find a block that fits, starting from the beginning - for (i = _list.begin(); i != _list.end(); ++i) { - char *currAddress = (*i)->getStart(); - - if ((int)(currAddress - lastAddress) >= size) break; - - lastAddress = (*i)->getEnd(); - } - - if ((Elf32_Addr)lastAddress & 3) - lastAddress += 4 - ((Elf32_Addr)lastAddress & 3); // Round up to multiple of 4 - - if (lastAddress + size > _shortsEnd) { - PSP_ERROR("No space in shorts segment for %x bytes. Last address is %p, max address is %p.\n", - size, lastAddress, _shortsEnd); - return NULL; - } - - Segment *seg = new Segment(lastAddress, size, origAddr); // Create a new segment - - if (lastAddress + size > _highestAddress) _highestAddress = lastAddress + size; // Keep track of maximum - - _list.insert(i, seg); - - PSP_DEBUG_PRINT("Shorts segment size %x allocated. End = %p. Remaining space = %x. Highest so far is %p.\n", - size, lastAddress + size, _shortsEnd - _list.back()->getEnd(), _highestAddress); - - return seg; -} - -void ShortSegmentManager::deleteSegment(ShortSegmentManager::Segment *seg) { - DEBUG_ENTER_FUNC(); - PSP_DEBUG_PRINT("Deleting shorts segment from %p to %p.\n\n", seg->getStart(), seg->getEnd()); - _list.remove(seg); - delete seg; -} - -static char dlerr[MAXDLERRLEN]; - -void *dlopen(const char *filename, int flags) { - DLObject *obj = new DLObject(dlerr); - if (obj->open(filename)) - return (void *)obj; - delete obj; - return NULL; -} - -int dlclose(void *handle) { - DLObject *obj = (DLObject *)handle; - if (obj == NULL) { - strcpy(dlerr, "Handle is NULL."); - return -1; - } - if (obj->close()) { - delete obj; - return 0; - } - return -1; -} - -void *dlsym(void *handle, const char *symbol) { - if (handle == NULL) { - strcpy(dlerr, "Handle is NULL."); - return NULL; - } - return ((DLObject *)handle)->symbol(symbol); -} - -const char *dlerror() { - return dlerr; -} - -void dlforgetsyms(void *handle) { - if (handle != NULL) - ((DLObject *)handle)->discard_symtab(); -} - - -#endif /* DYNAMIC_MODULES && __PSP__ */ diff --git a/backends/platform/psp/psploader.h b/backends/platform/psp/psploader.h deleted file mode 100644 index 13dcf6ef98..0000000000 --- a/backends/platform/psp/psploader.h +++ /dev/null @@ -1,137 +0,0 @@ -/* 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$ - * $Id$ - * - */ - -#ifndef PSPLOADER_H -#define PSPLOADER_H - -#include "elf32.h" -#include "common/list.h" -#include "common/singleton.h" - -#define MAXDLERRLEN 80 - -#define ShortsMan ShortSegmentManager::instance() - -class ShortSegmentManager : public Common::Singleton<ShortSegmentManager> { -private: - char *_shortsStart; - char *_shortsEnd; - -public: - char *getShortsStart() { - return _shortsStart; - } - bool inGeneralSegment(char *addr) { - return ((char *)addr >= _shortsStart && (char *)addr < _shortsEnd); - } - - class Segment { - private: - friend class ShortSegmentManager; - Segment(char *start, int size, char *origAddr) : _startAddress(start), _size(size), _origAddress(origAddr) {} - ~Segment() {} - char *_startAddress; // Start of shorts segment in memory - int _size; // Size of shorts segment - char *_origAddress; // Original address this segment was supposed to be at - public: - char *getStart() { - return _startAddress; - } - char *getEnd() { - return (_startAddress + _size); - } - Elf32_Addr getOffset() { - return (Elf32_Addr)(_startAddress - _origAddress); - } - bool inSegment(char *addr) { - return ((char *)addr >= _startAddress && (char *)addr <= _startAddress + _size); - } - }; - - Segment *newSegment(int size, char *origAddr); - void deleteSegment(Segment *); - -private: - ShortSegmentManager(); - friend class Common::Singleton<ShortSegmentManager>; - Common::List<Segment *> _list; - char *_highestAddress; -}; - - - - -class DLObject { -protected: - char *_errbuf; /* For error messages, at least MAXDLERRLEN in size */ - - ShortSegmentManager::Segment *_shortsSegment; // For assigning shorts ranges - void *_segment, *_symtab; - char *_strtab; - int _symbol_cnt; - int _symtab_sect; - void *_dtors_start, *_dtors_end; - - unsigned int _gpVal; // Value of Global Pointer - int _segmentSize; - - void seterror(const char *fmt, ...); - void unload(); - bool relocate(int fd, unsigned long offset, unsigned long size, void *); - bool load(int fd); - - bool readElfHeader(int fd, Elf32_Ehdr *ehdr); - bool readProgramHeaders(int fd, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num); - bool loadSegment(int fd, Elf32_Phdr *phdr); - Elf32_Shdr *loadSectionHeaders(int fd, Elf32_Ehdr *ehdr); - int loadSymbolTable(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr); - bool loadStringTable(int fd, Elf32_Shdr *shdr); - void relocateSymbols(Elf32_Addr offset, Elf32_Addr shortsOffset); - bool relocateRels(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr); - -public: - bool open(const char *path); - bool close(); - void *symbol(const char *name); - void discard_symtab(); - - DLObject(char *errbuf = NULL) : _errbuf(_errbuf), _shortsSegment(NULL), _segment(NULL), _symtab(NULL), - _strtab(NULL), _symbol_cnt(0), _symtab_sect(-1), _dtors_start(NULL), _dtors_end(NULL), _gpVal(0) , - _segmentSize(0) {} -}; - - - -#define RTLD_LAZY 0 - -extern "C" { - void *dlopen(const char *filename, int flags); - int dlclose(void *handle); - void *dlsym(void *handle, const char *symbol); - const char *dlerror(); - void dlforgetsyms(void *handle); -} - -#endif /* PSPLOADER_H */ |