Ticket #8993: bs2psx-RC2.diff

File bs2psx-RC2.diff, 86.3 KB (added by hkzlab, 15 years ago)

Broken Sword 2 PSX support patch

  • scummvm-bs2psx/engines/sword2/protocol.cpp

     
    2525 * $Id$
    2626 */
    2727
     28#include "common/file.h"
     29#include "common/endian.h"
    2830
    29 
    3031#include "sword2/sword2.h"
    3132#include "sword2/header.h"
    3233#include "sword2/resman.h"
     34#include "sword2/logic.h"
    3335
    3436namespace Sword2 {
    3537
     
    3941 */
    4042
    4143byte *Sword2Engine::fetchPalette(byte *screenFile) {
    42         MultiScreenHeader mscreenHeader;
     44        byte *palette;
    4345
    44         mscreenHeader.read(screenFile + ResHeader::size());
     46        if(isPsx()) { // PSX version doesn't have a "MultiScreenHeader", instead there's a ScreenHeader and a tag
     47                palette = screenFile + ResHeader::size() + ScreenHeader::size() + 2;
     48        } else {
     49                MultiScreenHeader mscreenHeader;
    4550
    46         byte *palette = screenFile + ResHeader::size() + mscreenHeader.palette;
     51                mscreenHeader.read(screenFile + ResHeader::size());
     52                palette = screenFile + ResHeader::size() + mscreenHeader.palette;
     53        }
    4754
    4855        // Always set colour 0 to black, because while most background screen
    4956        // palettes have a bright colour 0 it should come out as black in the
     
    6067/**
    6168 * Returns a pointer to the start of the palette match table, given the pointer
    6269 * to the start of the screen file.
     70 * It returns NULL when used with PSX version, as there are no palette match tables in
     71 * the resource files.
    6372 */
    6473
    6574byte *Sword2Engine::fetchPaletteMatchTable(byte *screenFile) {
     75       
     76        if (isPsx()) return NULL;
     77
    6678        MultiScreenHeader mscreenHeader;
    6779
    6880        mscreenHeader.read(screenFile + ResHeader::size());
     
    7688 */
    7789
    7890byte *Sword2Engine::fetchScreenHeader(byte *screenFile) {
    79         MultiScreenHeader mscreenHeader;
     91        if (isPsx()) { // In PSX version there's no MultiScreenHeader, so just skip resource header
     92                return screenFile + ResHeader::size();
     93        } else {
     94                MultiScreenHeader mscreenHeader;
    8095
    81         mscreenHeader.read(screenFile + ResHeader::size());
    82 
    83         return screenFile + ResHeader::size() + mscreenHeader.screen;
     96                mscreenHeader.read(screenFile + ResHeader::size());
     97                return screenFile + ResHeader::size() + mscreenHeader.screen;
     98        }
    8499}
    85100
    86101/**
     
    97112        assert(layerNo < screenHead.noLayers);
    98113#endif
    99114
    100         MultiScreenHeader mscreenHeader;
    101 
    102         mscreenHeader.read(screenFile + ResHeader::size());
    103 
    104         return screenFile + ResHeader::size() + mscreenHeader.layers + layerNo * LayerHeader::size();
     115        if (isPsx()) {
     116                return screenFile + ResHeader::size() + ScreenHeader::size() + 2 + 0x400 + layerNo * LayerHeader::size();
     117        } else {
     118                MultiScreenHeader mscreenHeader;
     119       
     120                mscreenHeader.read(screenFile + ResHeader::size());
     121                return screenFile + ResHeader::size() + mscreenHeader.layers + layerNo * LayerHeader::size();
     122        }
    105123}
    106124
    107125/**
    108126 * Returns a pointer to the start of the shading mask, given the pointer to the
    109127 * start of the screen file.
     128 * If we are non PSX, this will return NULL, as we don't have shading masks.
    110129 */
    111130
    112131byte *Sword2Engine::fetchShadingMask(byte *screenFile) {
     132        if (isPsx()) return NULL;
     133
    113134        MultiScreenHeader mscreenHeader;
    114135
    115136        mscreenHeader.read(screenFile + ResHeader::size());
     
    139160        animHead.read(fetchAnimHeader(animFile));
    140161
    141162        if (frameNo > animHead->noAnimFrames - 1)
    142                 error("fetchCdtEntry(animFile,%d) - anim only %d frames", frameNo, animHead.noAnimFrames);
     163                error("fetchCdtEntry(animFile,%d) - anim only %d frames", frameNo, animHead->noAnimFrames);
    143164#endif
    144165
    145166        return fetchAnimHeader(animFile) + AnimHeader::size() + frameNo * CdtEntry::size();
     
    153174
    154175byte *Sword2Engine::fetchFrameHeader(byte *animFile, uint16 frameNo) {
    155176        // required address = (address of the start of the anim header) + frameOffset
     177       
    156178        CdtEntry cdt;
    157179
    158180        cdt.read(fetchCdtEntry(animFile, frameNo));
     
    165187 */
    166188
    167189byte *Sword2Engine::fetchBackgroundParallaxLayer(byte *screenFile, int layer) {
    168         MultiScreenHeader mscreenHeader;
     190        if (isPsx()) {
     191                byte *psxParallax = _screen->getPsxScrCache(0);
    169192
    170         mscreenHeader.read(screenFile + ResHeader::size());
    171         assert(mscreenHeader.bg_parallax[layer]);
     193                // Manage cache for background psx parallaxes
     194                if (!_screen->getPsxScrCacheStatus(0)) { // This parallax layer is not present
     195                        return NULL;
     196                } else if (psxParallax != NULL) { // Parallax layer present, and already in cache
     197                        return psxParallax;
     198                } else { // Present, but not cached
     199                        uint32 locNo = _logic->getLocationNum();
    172200
    173         return screenFile + ResHeader::size() + mscreenHeader.bg_parallax[layer];
     201                        // At game startup, we have a wrong location number stored
     202                        // in game vars (0, instead of 3), work around this.
     203                        locNo = (locNo == 0) ? 3 : locNo;
     204
     205                        psxParallax = fetchPsxParallax(locNo, 0);
     206                        _screen->setPsxScrCache(psxParallax, 0);
     207                        return psxParallax;
     208                }
     209        } else {
     210                MultiScreenHeader mscreenHeader;
     211
     212                mscreenHeader.read(screenFile + ResHeader::size());
     213                assert(mscreenHeader.bg_parallax[layer]);
     214                return screenFile + ResHeader::size() + mscreenHeader.bg_parallax[layer];
     215        }
    174216}
    175217
    176218byte *Sword2Engine::fetchBackgroundLayer(byte *screenFile) {
    177         MultiScreenHeader mscreenHeader;
     219        if (isPsx()) {
     220                byte *psxBackground = _screen->getPsxScrCache(1);
    178221
    179         mscreenHeader.read(screenFile + ResHeader::size());
    180         assert(mscreenHeader.screen);
     222                // Manage cache for psx backgrounds
     223                if (psxBackground) { // Background is cached
     224                        return psxBackground;
     225                } else { // Background not cached
     226                        uint32 locNo = _logic->getLocationNum();
    181227
    182         return screenFile + ResHeader::size() + mscreenHeader.screen + ScreenHeader::size();
     228                        // We have a wrong location number at start, fix that
     229                        locNo = (locNo == 0) ? 3 : locNo;
     230
     231                        psxBackground = fetchPsxBackground(locNo);
     232                        _screen->setPsxScrCache(psxBackground, 1);
     233                        return psxBackground;
     234                }               
     235        } else {
     236                MultiScreenHeader mscreenHeader;
     237
     238                mscreenHeader.read(screenFile + ResHeader::size());
     239                assert(mscreenHeader.screen);
     240                return screenFile + ResHeader::size() + mscreenHeader.screen + ScreenHeader::size();
     241        }
    183242}
    184243
    185244byte *Sword2Engine::fetchForegroundParallaxLayer(byte *screenFile, int layer) {
    186         MultiScreenHeader mscreenHeader;
     245        if (isPsx()) {
     246                byte *psxParallax = _screen->getPsxScrCache(2);
    187247
    188         mscreenHeader.read(screenFile + ResHeader::size());
    189         assert(mscreenHeader.fg_parallax[layer]);
     248                // Manage cache for psx parallaxes
     249                if (!_screen->getPsxScrCacheStatus(2)) { // This parallax layer is not present
     250                        return NULL;
     251                } else if (psxParallax) { // Parallax layer present and cached
     252                        return psxParallax;
     253                } else { // Present, but still not cached
     254                        uint32 locNo = _logic->getLocationNum();
    190255
    191         return screenFile + ResHeader::size() + mscreenHeader.fg_parallax[layer];
     256                        // We have a wrong location number at start, fix that
     257                        locNo = (locNo == 0) ? 3 : locNo;
     258
     259                        psxParallax = fetchPsxParallax(locNo, 1);
     260                        _screen->setPsxScrCache(psxParallax, 2);
     261                        return psxParallax;
     262                }               
     263        } else {
     264                MultiScreenHeader mscreenHeader;
     265
     266                mscreenHeader.read(screenFile + ResHeader::size());
     267                assert(mscreenHeader.fg_parallax[layer]);
     268                return screenFile + ResHeader::size() + mscreenHeader.fg_parallax[layer];
     269        }
    192270}
    193271
    194272byte *Sword2Engine::fetchTextLine(byte *file, uint32 text_line) {
     
    211289        return file + READ_LE_UINT32(file + ResHeader::size() + 4 + 4 * text_line);
    212290}
    213291
     292/**
     293 * Returns a pointer to psx background data for passed location number
     294 * At the beginning of the passed data there's an artificial header composed by
     295 * uint16: background X resolution
     296 * uint16: background Y resolution
     297 * uint32: offset to subtract from offset table entries
     298 */
     299
     300byte *Sword2Engine::fetchPsxBackground(uint32 location) {
     301        Common::File file;
     302        PSXScreensEntry header;
     303        uint32 screenOffset, dataOffset;
     304        uint32 totSize; // Total size of background, counting data, offset table and additional header
     305        byte *buffer;
     306
     307        if (!file.open("screens.clu")) {
     308                GUIErrorMessage("Broken Sword 2: Cannot open screens.clu");
     309                return NULL;
     310        }
     311
     312        file.seek(location * 4, SEEK_SET);
     313        screenOffset = file.readUint32LE();     
     314
     315        if (screenOffset == 0) { // We don't have screen data for this location number.
     316                file.close();
     317                return NULL;
     318        }
     319
     320        // Get to the beginning of PSXScreensEntry
     321        file.seek(screenOffset + ResHeader::size(), SEEK_SET);
     322       
     323        buffer = (byte *)malloc(PSXScreensEntry::size());
     324        file.read(buffer, PSXScreensEntry::size());
     325       
     326        // Prepare the header
     327        header.read(buffer);
     328        free(buffer);
     329
     330        file.seek(screenOffset + header.bgOffset + 4, SEEK_SET);
     331        dataOffset = file.readUint32LE();
     332
     333        file.seek(screenOffset + header.bgOffset, SEEK_SET);
     334
     335        totSize = header.bgSize + (dataOffset - header.bgOffset) + 8;
     336        buffer = (byte *)malloc(totSize);
     337
     338        // Write some informations before background data
     339        WRITE_LE_UINT16(buffer, header.bgXres);
     340        WRITE_LE_UINT16(buffer + 2, header.bgYres);
     341        WRITE_LE_UINT32(buffer + 4, header.bgOffset);
     342
     343        file.read(buffer + 8, totSize - 8); // Do not write on the header
     344        file.close();
     345
     346        return buffer;
     347}
     348
     349/**
     350 * Returns a pointer to selected psx parallax data for passed location number
     351 * At the beginning of the passed data there's an artificial header composed by
     352 * uint16: parallax X resolution
     353 * uint16: parallax Y resolution
     354 * uint16: width in 64x16 tiles of parallax
     355 * uint16: height in 64x16 tiles of parallax
     356 */
     357
     358byte *Sword2Engine::fetchPsxParallax(uint32 location, uint8 level) {
     359        Common::File file;
     360        PSXScreensEntry header;
     361        uint32 screenOffset;
     362        uint16 horTiles; // Number of horizontal tiles in the parallax grid
     363        uint16 verTiles; // Number of vertical tiles in parallax grid
     364        uint32 totSize; // Total size of parallax, counting data, grid, and additional header
     365        byte *buffer;
     366
     367        uint16 plxXres;
     368        uint16 plxYres;
     369        uint32 plxOffset;
     370        uint32 plxSize;
     371
     372        if (level > 1)
     373                return NULL;
     374
     375        if (!file.open("screens.clu")) {
     376                GUIErrorMessage("Broken Sword 2: Cannot open screens.clu");
     377                return NULL;
     378        }
     379
     380        file.seek(location * 4, SEEK_SET);
     381        screenOffset = file.readUint32LE();     
     382
     383        if (screenOffset == 0) // There is no screen here
     384                return NULL;
     385
     386        // Get to the beginning of PSXScreensEntry
     387        file.seek(screenOffset + ResHeader::size(), SEEK_SET);
     388       
     389        buffer = (byte *)malloc(PSXScreensEntry::size());
     390        file.read(buffer, PSXScreensEntry::size());
     391       
     392        // Initialize the header
     393        header.read(buffer);
     394        free(buffer);
     395
     396        // We are fetching...
     397        if (level == 0) { // a background parallax
     398                plxXres = header.bgPlxXres;
     399                plxYres = header.bgPlxYres;
     400                plxOffset = header.bgPlxOffset;
     401                plxSize = header.bgPlxSize;
     402        } else {  // a foreground parallax
     403                plxXres = header.fgPlxXres;
     404                plxYres = header.fgPlxYres;
     405                plxOffset = header.fgPlxOffset;
     406                plxSize = header.fgPlxSize;
     407        }
     408
     409        if (plxXres == 0 || plxYres == 0 || plxSize == 0) // This screen has no parallax data.
     410                return NULL;
     411
     412        debug(2, "fetchPsxParallax() -> %s parallax, xRes: %u, yRes: %u", (level == 0) ? "Background" : "Foreground", plxXres, plxYres);
     413
     414        // Calculate the number of tiles which compose the parallax grid.
     415        horTiles = plxXres % 64 ? (plxXres / 64) + 1 : plxXres / 64;
     416        verTiles = plxYres % 16 ? (plxYres / 16) + 1 : plxYres / 16;
     417
     418        totSize = plxSize + horTiles * verTiles * 4 + 8;
     419
     420        file.seek(screenOffset + plxOffset, SEEK_SET);
     421        buffer = (byte *)malloc(totSize);
     422
     423        // Insert parallax resolution information in the buffer,
     424        // preceding parallax data.
     425        WRITE_LE_UINT16(buffer, plxXres);
     426        WRITE_LE_UINT16(buffer + 2, plxYres);
     427        WRITE_LE_UINT16(buffer + 4, horTiles);
     428        WRITE_LE_UINT16(buffer + 6, verTiles);
     429
     430        // Read parallax data from file and store it inside the buffer,
     431        // skipping the generated header.
     432        file.read(buffer + 8, totSize - 8);
     433        file.close();
     434
     435        return buffer;
     436}
     437
    214438// Used for testing text & speech (see fnISpeak in speech.cpp)
    215439
    216440bool Sword2Engine::checkTextLine(byte *file, uint32 text_line) {
  • scummvm-bs2psx/engines/sword2/controls.cpp

     
    268268
    269269        // Usually the mouse pointer will already be "normal", but not always.
    270270        _vm->_mouse->setMouse(NORMAL_MOUSE_ID);
     271
     272        // Force mouse mode as system menu: normally not needed,
     273        // but value is not correct in case of game start dialog
     274        // (when asking to restart or load a game).
     275        // This is forced to avoid GMM loading/saving being enabled
     276        // during initial dialog.
     277        _vm->_mouse->setMouseMode(MOUSE_system_menu);
    271278}
    272279
    273280Dialog::~Dialog() {
  • scummvm-bs2psx/engines/sword2/menu.cpp

     
    4242void Mouse::clearIconArea(int menu, int pocket, Common::Rect *r) {
    4343        byte *buf = _vm->_screen->getScreen();
    4444        int16 screenWide = _vm->_screen->getScreenWide();
     45        byte menuIconWidth;
     46       
     47        // Initialize menu icon width at correct size
     48        // depending if we are using pc or psx version.
     49        if (Sword2Engine::isPsx())
     50                menuIconWidth = RDMENU_PSXICONWIDE;
     51        else
     52                menuIconWidth = RDMENU_ICONWIDE;
    4553
     54
    4655        r->top = menu * (RENDERDEEP + MENUDEEP) + (MENUDEEP - RDMENU_ICONDEEP) / 2;
    4756        r->bottom = r->top + RDMENU_ICONDEEP;
    48         r->left = RDMENU_ICONSTART + pocket * (RDMENU_ICONWIDE + RDMENU_ICONSPACING);
    49         r->right = r->left + RDMENU_ICONWIDE;
     57        r->left = RDMENU_ICONSTART + pocket * (menuIconWidth + RDMENU_ICONSPACING);
     58        r->right = r->left + menuIconWidth;
    5059
    5160        byte *dst = buf + r->top * screenWide + r->left;
    5261
    5362        for (int i = 0; i < RDMENU_ICONDEEP; i++) {
    54                 memset(dst, 0, RDMENU_ICONWIDE);
     63                memset(dst, 0, menuIconWidth);
    5564                dst += screenWide;
    5665        }
    5766}
     
    7180
    7281        byte *buf = _vm->_screen->getScreen();
    7382        int16 screenWide = _vm->_screen->getScreenWide();
     83        byte menuIconWidth;
     84       
     85        if (Sword2Engine::isPsx())
     86                menuIconWidth = RDMENU_PSXICONWIDE;
     87        else
     88                menuIconWidth = RDMENU_ICONWIDE;
    7489
     90
    7591        if (lastTime == 0) {
    7692                lastTime = _vm->getMillis();
    7793                frameCount = 1;
     
    141157                        _menuStatus[menu] = RDMENU_HIDDEN;
    142158
    143159                // Draw the menu here.
    144                 int32 curx = RDMENU_ICONSTART + RDMENU_ICONWIDE / 2;
     160                int32 curx = RDMENU_ICONSTART + menuIconWidth / 2;
    145161                int32 cury = (MENUDEEP / 2) + (RENDERDEEP + MENUDEEP) * menu;
    146162
    147163                for (i = 0; i < RDMENU_MAXPOCKETS; i++) {
     
    154170                                clearIconArea(menu, i, &r1);
    155171
    156172                                if (_pocketStatus[menu][i] == MAXMENUANIMS) {
    157                                         xoff = (RDMENU_ICONWIDE / 2);
     173                                        xoff = (menuIconWidth / 2);
    158174                                        r2.left = curx - xoff;
    159                                         r2.right = r2.left + RDMENU_ICONWIDE;
     175                                        r2.right = r2.left + menuIconWidth;
    160176                                        yoff = (RDMENU_ICONDEEP / 2);
    161177                                        r2.top = cury - yoff;
    162178                                        r2.bottom = r2.top + RDMENU_ICONDEEP;
    163179                                } else {
    164                                         xoff = (RDMENU_ICONWIDE / 2) * _pocketStatus[menu][i] / MAXMENUANIMS;
     180                                        xoff = (menuIconWidth / 2) * _pocketStatus[menu][i] / MAXMENUANIMS;
    165181                                        r2.left = curx - xoff;
    166182                                        r2.right = curx + xoff;
    167183                                        yoff = (RDMENU_ICONDEEP / 2) * _pocketStatus[menu][i] / MAXMENUANIMS;
     
    176192                                        if (_pocketStatus[menu][i] != MAXMENUANIMS) {
    177193                                                _vm->_screen->scaleImageFast(
    178194                                                        dst, screenWide, r2.right - r2.left, r2.bottom - r2.top,
    179                                                         src, RDMENU_ICONWIDE, RDMENU_ICONWIDE, RDMENU_ICONDEEP);
     195                                                        src, menuIconWidth, menuIconWidth, RDMENU_ICONDEEP);
    180196                                        } else {
    181197                                                for (j = 0; j < RDMENU_ICONDEEP; j++) {
    182                                                         memcpy(dst, src, RDMENU_ICONWIDE);
    183                                                         src += RDMENU_ICONWIDE;
     198                                                        memcpy(dst, src, menuIconWidth);
     199                                                        src += menuIconWidth;
    184200                                                        dst += screenWide;
    185201                                                }
    186202                                        }
    187203                                }
    188204                                _vm->_screen->updateRect(&r1);
    189205                        }
    190                         curx += (RDMENU_ICONSPACING + RDMENU_ICONWIDE);
     206                        curx += (RDMENU_ICONSPACING + menuIconWidth);
    191207                }
    192208        }
    193209}
     
    199215 */
    200216
    201217int32 Mouse::showMenu(uint8 menu) {
     218
     219        // Do not show menu in PSX version, as there was really
     220        // nothing similar in the original game (menu was started
     221        // using SELECT button in psx pad)
     222        if (Sword2Engine::isPsx() && menu == RDMENU_TOP)
     223                return RD_OK;
     224
    202225        // Check for invalid menu parameter
    203226        if (menu > RDMENU_BOTTOM)
    204227                return RDERR_INVALIDMENU;
     
    219242 */
    220243
    221244int32 Mouse::hideMenu(uint8 menu) {
     245
     246        // In PSX version, do nothing. There is no such menu.
     247        if (Sword2Engine::isPsx() && menu == RDMENU_TOP)
     248                return RD_OK;
     249
    222250        // Check for invalid menu parameter
    223251        if (menu > RDMENU_BOTTOM)
    224252                return RDERR_INVALIDMENU;
     
    267295
    268296int32 Mouse::setMenuIcon(uint8 menu, uint8 pocket, byte *icon) {
    269297        Common::Rect r;
     298        byte menuIconWidth;
     299       
     300        if (Sword2Engine::isPsx())
     301                menuIconWidth = RDMENU_PSXICONWIDE;
     302        else
     303                menuIconWidth = RDMENU_ICONWIDE;
    270304
    271305        // Check for invalid menu parameter.
    272306        if (menu > RDMENU_BOTTOM)
     
    288322        // Only put the icon in the pocket if it is not NULL
    289323        if (icon != NULL) {
    290324                _iconCount++;
    291                 _icons[menu][pocket] = (byte *)malloc(RDMENU_ICONWIDE * RDMENU_ICONDEEP);
     325                _icons[menu][pocket] = (byte *)malloc(menuIconWidth * RDMENU_ICONDEEP);
    292326                if (_icons[menu][pocket] == NULL)
    293327                        return RDERR_OUTOFMEMORY;
    294                 memcpy(_icons[menu][pocket], icon, RDMENU_ICONWIDE * RDMENU_ICONDEEP);
     328                memcpy(_icons[menu][pocket], icon, menuIconWidth * RDMENU_ICONDEEP);
    295329        }
    296330
    297331        return RD_OK;
  • scummvm-bs2psx/engines/sword2/render.cpp

     
    252252 */
    253253
    254254void Screen::renderParallax(byte *ptr, int16 l) {
    255         Parallax p;
    256255        int16 x, y;
     256        uint16 xRes, yRes;
    257257        Common::Rect r;
    258258
    259         p.read(ptr);
     259        if (!ptr)
     260                return;
    260261
     262        // Fetch resolution data from parallax
     263       
     264        if (Sword2Engine::isPsx()) {
     265                xRes = READ_LE_UINT16(ptr);
     266                yRes = READ_LE_UINT16(ptr + 2) * 2;
     267        } else {
     268                Parallax p;
     269               
     270                p.read(ptr);
     271                xRes = p.w;
     272                yRes = p.h;
     273        }
     274
    261275        if (_locationWide == _screenWide)
    262276                x = 0;
    263277        else
    264                 x = ((int32)((p.w - _screenWide) * _scrollX) / (int32)(_locationWide - _screenWide));
     278                x = ((int32)((xRes - _screenWide) * _scrollX) / (int32)(_locationWide - _screenWide));
    265279
    266280        if (_locationDeep == _screenDeep - MENUDEEP * 2)
    267281                y = 0;
    268282        else
    269                 y = ((int32)((p.h - (_screenDeep - MENUDEEP * 2)) * _scrollY) / (int32)(_locationDeep - (_screenDeep - MENUDEEP * 2)));
     283                y = ((int32)((yRes - (_screenDeep - MENUDEEP * 2)) * _scrollY) / (int32)(_locationDeep - (_screenDeep - MENUDEEP * 2)));
    270284
    271285        Common::Rect clipRect;
    272286
     
    537551}
    538552
    539553/**
     554 * This converts PSX format background data into a format that
     555 * can be understood by renderParallax functions.
     556 * PSX Backgrounds are divided into tiles of 64x32 (with aspect
     557 * ratio correction), while PC backgrounds are in tiles of 64x64.
     558 */
     559
     560int32 Screen::initialisePsxBackgroundLayer(byte *parallax) {
     561        uint16 bgXres, bgYres;
     562        uint16 trueXres, stripeNumber, totStripes;
     563        uint32 baseAddress, stripePos;
     564        uint16 i, j;
     565        byte *dst;
     566
     567        debug(2, "initialisePsxBackgroundLayer");
     568
     569        assert(_layer < MAXLAYERS);
     570
     571        if (!parallax) {
     572                _layer++;
     573                return RD_OK;
     574        }
     575
     576        // Fetch data from buffer
     577
     578        bgXres = READ_LE_UINT16(parallax);
     579        bgYres = READ_LE_UINT16(parallax + 2) * 2;
     580        baseAddress = READ_LE_UINT32(parallax + 4);
     581        parallax += 8;
     582
     583        // Calculate TRUE resolution of background, must be
     584        // a multiple of 64
     585
     586        trueXres = (bgXres % 64) ? ((bgXres/64) + 1) * 64 : bgXres;
     587        totStripes = trueXres / 64;
     588
     589        _xBlocks[_layer] = (bgXres + BLOCKWIDTH - 1) / BLOCKWIDTH;
     590        _yBlocks[_layer] = (bgYres + BLOCKHEIGHT - 1) / BLOCKHEIGHT;
     591       
     592        uint16 remLines = bgYres % 64;
     593
     594        byte *tileChunk = (byte *)malloc(BLOCKHEIGHT * BLOCKWIDTH);
     595        if (!tileChunk)
     596                return RDERR_OUTOFMEMORY;
     597
     598        _blockSurfaces[_layer] = (BlockSurface **)calloc(_xBlocks[_layer] * _yBlocks[_layer], sizeof(BlockSurface *));
     599        if (!_blockSurfaces[_layer])
     600                return RDERR_OUTOFMEMORY;
     601
     602        // Group PSX background (64x32, when stretched vertically) tiles together,
     603        // to make them compatible with pc version (composed by 64x64 tiles)
     604
     605        stripeNumber = 0;
     606        stripePos = 0;
     607        for (i = 0; i < _xBlocks[_layer] * _yBlocks[_layer]; i++) {
     608                bool block_has_data = false;
     609                bool block_is_transparent = false;
     610
     611                int posX = i / _yBlocks[_layer];
     612                int posY = i % _yBlocks[_layer];
     613
     614                uint32 stripeOffset = READ_LE_UINT32(parallax + stripeNumber * 8 + 4) + stripePos - baseAddress;
     615
     616                memset(tileChunk, 1, BLOCKHEIGHT * BLOCKWIDTH);
     617
     618                if (!(remLines && posY == _yBlocks[_layer] - 1))
     619                        remLines = 32;
     620
     621                for(j = 0; j < remLines; j++) {
     622                        memcpy(tileChunk + j * BLOCKWIDTH * 2, parallax + stripeOffset + j * BLOCKWIDTH, BLOCKWIDTH);
     623                        memcpy(tileChunk + j * BLOCKWIDTH * 2 + BLOCKWIDTH, parallax + stripeOffset + j * BLOCKWIDTH, BLOCKWIDTH);
     624                }
     625
     626                for (j = 0; j < BLOCKHEIGHT * BLOCKWIDTH; j++) {
     627                        if (tileChunk[j])
     628                                block_has_data = true;
     629                        else
     630                                block_is_transparent = true;
     631                }       
     632
     633                int tileIndex = totStripes * posY + posX;
     634
     635                //  Only assign a surface to the block if it contains data.
     636
     637                if (block_has_data) {
     638                        _blockSurfaces[_layer][tileIndex] = (BlockSurface *)malloc(sizeof(BlockSurface));
     639
     640                        //  Copy the data into the surfaces.
     641                        dst = _blockSurfaces[_layer][tileIndex]->data;
     642                        memcpy(dst, tileChunk, BLOCKWIDTH * BLOCKHEIGHT);
     643
     644                        _blockSurfaces[_layer][tileIndex]->transparent = block_is_transparent;
     645
     646                } else
     647                        _blockSurfaces[_layer][tileIndex] = NULL;
     648
     649                if (posY == _yBlocks[_layer] - 1) {
     650                        stripeNumber++;
     651                        stripePos = 0;
     652                } else {
     653                        stripePos += 0x800;
     654                }
     655        }
     656
     657        free(tileChunk);
     658        _layer++;
     659
     660        return RD_OK;   
     661}
     662
     663/**
     664 * This converts PSX format parallax data into a format that
     665 * can be understood by renderParallax functions.
     666 */
     667
     668int32 Screen::initialisePsxParallaxLayer(byte *parallax) {
     669        uint16 plxXres, plxYres;
     670        uint16 xTiles, yTiles;
     671        uint16 i, j, k;
     672        byte *data;
     673        byte *dst;
     674
     675        debug(2, "initialisePsxParallaxLayer");
     676
     677        assert(_layer < MAXLAYERS);
     678
     679        if (!parallax) {
     680                _layer++;
     681                return RD_OK;
     682        }
     683
     684        plxXres = READ_LE_UINT16(parallax);
     685        plxYres = READ_LE_UINT16(parallax + 2);
     686        xTiles = READ_LE_UINT16(parallax + 4);
     687        yTiles = READ_LE_UINT16(parallax + 6);
     688
     689        // Beginning of parallax table composed by uint32,
     690        // if word is 0, corresponding tile contains no data and must be skipped,
     691        // if word is 0x400 tile contains data.
     692        parallax += 8;
     693
     694        // Beginning if tiles data.
     695        data = parallax + xTiles * yTiles * 4;
     696
     697        _xBlocks[_layer] = xTiles;
     698        _yBlocks[_layer] = (yTiles / 2) + (yTiles % 2 ? 1 : 0);
     699        bool oddTiles = (yTiles % 2 ? true : false);
     700
     701        _blockSurfaces[_layer] = (BlockSurface **)calloc(_xBlocks[_layer] * _yBlocks[_layer], sizeof(BlockSurface *));
     702        if (!_blockSurfaces[_layer])
     703                return RDERR_OUTOFMEMORY;
     704
     705        // We have to check two tiles for every block in PSX version, if one of those
     706        // has data in it, the whole block has data. Also, tiles must be doublelined to
     707        // get correct aspect ratio.
     708        for (i = 0; i < _xBlocks[_layer] * _yBlocks[_layer]; i++) {
     709                bool block_has_data = false;
     710                bool block_is_transparent = false;
     711                bool firstTilePresent, secondTilePresent;
     712
     713                int posX = i / _yBlocks[_layer];
     714                int posY = i % _yBlocks[_layer];
     715
     716                if (oddTiles && posY == _yBlocks[_layer] - 1) {
     717                        firstTilePresent = READ_LE_UINT32(parallax) == 0x400;
     718                        secondTilePresent = false;
     719                        parallax += 4;
     720                } else {
     721                        firstTilePresent = READ_LE_UINT32(parallax) == 0x400;
     722                        secondTilePresent = READ_LE_UINT32(parallax + 4) == 0x400;
     723                        parallax += 8;
     724                }
     725
     726                // If one of the two grouped tiles has data, then the whole block has data
     727                if (firstTilePresent || secondTilePresent) {
     728                        block_has_data = true;
     729
     730                        // If one of the two grouped blocks is without data, then we also have transparency
     731                        if(!firstTilePresent || !secondTilePresent)
     732                                block_is_transparent = true;
     733                }
     734
     735                // Now do a second check to see if we have a partially transparent block
     736                if (block_has_data && !block_is_transparent) {
     737                        byte *block = data;
     738                        if (firstTilePresent) {
     739                                for (k = 0; k < 0x400; k++) {
     740                                        if ( *(block + k) == 0) {
     741                                                block_is_transparent = true;
     742                                                break;
     743                                        }
     744                                }
     745                                block += 0x400; // On to next block...
     746                        }
     747
     748                        // If we didn't find transparency in first block and we have
     749                        // a second tile, check it
     750                        if (secondTilePresent && !block_is_transparent) {
     751                                for (k = 0; k < 0x400; k++) {
     752                                        if ( *(block + k) == 0) {
     753                                                block_is_transparent = true;
     754                                                break;
     755                                        }
     756                                }
     757                        }
     758                }
     759
     760                int tileIndex = xTiles * posY + posX;
     761
     762                //  Only assign a surface to the block if it contains data.
     763
     764                if (block_has_data) {
     765                        _blockSurfaces[_layer][tileIndex] = (BlockSurface *)malloc(sizeof(BlockSurface));
     766                        memset(_blockSurfaces[_layer][tileIndex], 0, BLOCKHEIGHT * BLOCKWIDTH);
     767
     768                        //  Copy the data into the surfaces.
     769                        dst = _blockSurfaces[_layer][tileIndex]->data;
     770
     771                        if (firstTilePresent) { //There is data in the first tile
     772                                for (j = 0; j < 16; j++) {
     773                                        memcpy(dst, data, BLOCKWIDTH);
     774                                        dst += BLOCKWIDTH;
     775                                        memcpy(dst, data, BLOCKWIDTH);
     776                                        dst += BLOCKWIDTH;
     777                                        data += BLOCKWIDTH;
     778                                }
     779                        } else {
     780                                dst += 0x800;
     781                        }
     782
     783                        if (secondTilePresent) {
     784                                for (j = 0; j < 16; j++) {
     785                                        memcpy(dst, data, BLOCKWIDTH);
     786                                        dst += BLOCKWIDTH;
     787                                        memcpy(dst, data, BLOCKWIDTH);
     788                                        dst += BLOCKWIDTH;
     789                                        data += BLOCKWIDTH;
     790                                }
     791                        }
     792
     793                        _blockSurfaces[_layer][tileIndex]->transparent = block_is_transparent;
     794                } else
     795                        _blockSurfaces[_layer][tileIndex] = NULL;
     796        }
     797
     798        _layer++;
     799
     800        return RD_OK;
     801}
     802
     803/**
    540804 * Should be called once after leaving the room to free up memory.
    541805 */
    542806
    543807void Screen::closeBackgroundLayer() {
    544808        debug(2, "CloseBackgroundLayer");
    545809
     810        if (Sword2Engine::isPsx())
     811                flushPsxScrCache();
     812
    546813        for (int i = 0; i < MAXLAYERS; i++) {
    547814                if (_blockSurfaces[i]) {
    548815                        for (int j = 0; j < _xBlocks[i] * _yBlocks[i]; j++)
  • scummvm-bs2psx/engines/sword2/sword2.cpp

     
    5151#include "sword2/router.h"
    5252#include "sword2/screen.h"
    5353#include "sword2/sound.h"
     54#include "sword2/saveload.h"
    5455
    5556namespace Sword2 {
    5657
     
    104105bool Sword2::Sword2Engine::hasFeature(EngineFeature f) const {
    105106        return
    106107                (f == kSupportsRTL) ||
    107                 (f == kSupportsSubtitleOptions);
     108                (f == kSupportsSubtitleOptions) ||
     109                (f == kSupportsSavingDuringRuntime) ||
     110                (f == kSupportsLoadingDuringRuntime);
    108111}
    109112
    110113GameList Sword2MetaEngine::getSupportedGames() const {
     
    299302        _gameCycle = 0;
    300303        _gameSpeed = 1;
    301304
     305        _gmmLoadSlot = -1; // Used to manage GMM Loading
     306
    302307        syst->getEventManager()->registerRandomSource(_rnd, "sword2");
    303308}
    304309
     
    429434                        if (!dialog.runModal())
    430435                                startGame();
    431436                }
    432         } else if (!_bootParam && saveExists()) {
    433                 int32 pars[2] = { 221, FX_LOOP };
     437        } else if (!_bootParam && saveExists() && !isPsx()) { // Initial load/restart panel disabled in PSX
     438                int32 pars[2] = { 221, FX_LOOP };                 // version because of missing panel resources
    434439                bool result;
    435440
    436441                _mouse->setMouse(NORMAL_MOUSE_ID);
     
    465470                }
    466471#endif
    467472
     473                // Handle GMM Loading
     474                if (_gmmLoadSlot != -1) {
     475                       
     476                        // Hide mouse cursor and fade screen
     477                        _mouse->hideMouse();
     478                        _screen->fadeDown();
     479                       
     480                        // Clean up and load game
     481                        _logic->_router->freeAllRouteMem();
     482
     483                        // TODO: manage error handling
     484                        restoreGame(_gmmLoadSlot);
     485
     486                        // Reset load slot
     487                        _gmmLoadSlot = -1;
     488
     489                        // Show mouse
     490                        _mouse->addHuman();
     491                }
     492
    468493                KeyboardEvent *ke = keyboardEvent();
    469494
    470495                if (ke) {
     
    805830        return _system->getMillis();
    806831}
    807832
     833Common::Error Sword2Engine::saveGameState(int slot, const char *desc) {
     834        uint32 saveVal = saveGame(slot, (byte *)desc);
     835
     836        if (saveVal == SR_OK)
     837                return Common::kNoError;
     838        else if (saveVal == SR_ERR_WRITEFAIL || saveVal == SR_ERR_FILEOPEN)
     839                return Common::kWritingFailed;
     840        else
     841                return Common::kUnknownError;
     842}
     843
     844bool Sword2Engine::canSaveGameStateCurrently() {
     845        bool canSave = true;
     846
     847        // No save if dead
     848        if (_logic->readVar(DEAD))
     849                canSave = false;
     850
     851        // No save if mouse not shown
     852        else if (_mouse->getMouseStatus())
     853                canSave = false;
     854        // No save if inside a menu
     855        else if (_mouse->getMouseMode() == MOUSE_system_menu)
     856                canSave = false;
     857
     858        // No save if fading
     859        else if (_screen->getFadeStatus())
     860                canSave = false;
     861
     862        return canSave;
     863}
     864
     865Common::Error Sword2Engine::loadGameState(int slot) {
     866
     867        // Prepare the game to load through GMM
     868        _gmmLoadSlot = slot;
     869
     870        // TODO: error handling.
     871        return Common::kNoError;
     872}
     873
     874bool Sword2Engine::canLoadGameStateCurrently() {
     875        bool canLoad = true;
     876
     877        // No load if mouse is disabled
     878        if (_mouse->getMouseStatus())
     879                canLoad = false;
     880        // No load if mouse is in system menu
     881        else if (_mouse->getMouseMode() == MOUSE_system_menu)
     882                canLoad = false;
     883        // No load if we are fading
     884        else if (_screen->getFadeStatus())
     885                canLoad = false;
     886
     887        // But if we are dead, ignore previous conditions
     888        if (_logic->readVar(DEAD))
     889                canLoad = true;
     890
     891        return canLoad;
     892}
     893
    808894} // End of namespace Sword2
  • scummvm-bs2psx/engines/sword2/music.cpp

     
    4040#include "sound/flac.h"
    4141#include "sound/rate.h"
    4242#include "sound/wave.h"
     43#include "sound/vag.h"
    4344
    4445#include "sword2/sword2.h"
    4546#include "sword2/defs.h"
     
    8384}
    8485
    8586static Audio::AudioStream *makeCLUStream(Common::File *fp, int size);
     87static Audio::AudioStream *makePSXCLUStream(Common::File *fp, int size);
    8688
    8789static Audio::AudioStream *getAudioStream(SoundFileHandle *fh, const char *base, int cd, uint32 id, uint32 *numSamples) {
    8890        bool alreadyOpen;
     
    189191
    190192        switch (fh->fileType) {
    191193        case kCLUMode:
    192                 return makeCLUStream(&fh->file, enc_len);
     194                if (Sword2Engine::isPsx())
     195                        return makePSXCLUStream(&fh->file, enc_len);
     196                else
     197                        return makeCLUStream(&fh->file, enc_len);
    193198#ifdef USE_MAD
    194199        case kMP3Mode:
    195200                tmp = new SafeSubReadStream(&fh->file, pos, pos + enc_len, false);
     
    289294        return new CLUInputStream(file, size);
    290295}
    291296
     297Audio::AudioStream *makePSXCLUStream(Common::File *file, int size) {
     298       
     299        // Buffer audio file data, and ask MemoryReadStream to dispose of it
     300        // when not needed anymore.
     301
     302        byte *buffer = (byte *)malloc(size);
     303        file->read(buffer, size);
     304        return new Audio::VagStream(new Common::MemoryReadStream(buffer, size, true));
     305}
     306
    292307// ----------------------------------------------------------------------------
    293308// Another custom AudioStream class, to wrap around the various AudioStream
    294309// classes used for music decompression, and to add looping, fading, etc.
  • scummvm-bs2psx/engines/sword2/maketext.cpp

     
    5959#define MAX_LINES       30      // max character lines in output sprite
    6060
    6161#define BORDER_COL      200     // source colour for character border (only
    62                                 // needed for remapping colours)
     62                                                // needed for remapping colours)
     63
    6364#define LETTER_COL      193     // source colour for bulk of character ( " )
     65#define LETTER_COL_PSX1 33
     66#define LETTER_COL_PSX2 34
    6467#define SPACE           ' '
    6568#define FIRST_CHAR      SPACE   // first character in character set
    6669#define LAST_CHAR       255     // last character in character set
     
    9194        // of the resource.
    9295
    9396        if (fontRes == _vm->_speechFontId) {
    94                 _lineSpacing = -6;
     97                if (Sword2Engine::isPsx())
     98                        _lineSpacing = -4; // Text would be unreadable with psx font if linespacing is higher
     99                else
     100                        _lineSpacing = -6;
    95101                _charSpacing = -3;
    96102        } else if (fontRes == CONSOLE_FONT_ID) {
    97103                _lineSpacing = 0;
     
    214220                if (line[i].width > spriteWidth)
    215221                        spriteWidth = line[i].width;
    216222
     223
     224        // Check that text sprite has even horizontal resolution in PSX version
     225        // (needed to work around a problem in some sprites, which reports an odd
     226        // number as horiz resolution, but then have the next even number as true width)
     227        if (Sword2Engine::isPsx())
     228                spriteWidth = (spriteWidth % 2) ? spriteWidth + 1 : spriteWidth;
     229
    217230        // Find the total height of the text sprite: the total height of the
    218231        // text lines, plus the total height of the spacing between them.
    219232
     
    234247        frame_head.width = spriteWidth;
    235248        frame_head.height = spriteHeight;
    236249
     250        // Normally for PSX frame header we double the height
     251        // of the sprite artificially to regain correct aspect
     252        // ratio, but this is an "artificially generated" text
     253        // sprite, which gets created with correct aspect, so
     254        // fix the height.
     255        if (Sword2Engine::isPsx())
     256                frame_head.height /= 2;
     257
    237258        frame_head.write(textSprite);
    238259
    239260        debug(4, "Text sprite size: %ux%u", spriteWidth, spriteHeight);
     
    264285
    265286                        assert(frame_head.height == char_height);
    266287                        copyChar(charPtr, spritePtr, spriteWidth, pen);
     288
     289                        // We must remember to free memory for generated character in psx,
     290                        // as it is extracted differently than pc version (copyed from a
     291                        // char atlas).
     292                        if (Sword2Engine::isPsx())
     293                                free(charPtr);
     294
    267295                        spritePtr += frame_head.width + _charSpacing;
    268296                }
    269297
    270298                // Skip space at end of last word in this line
    271299                pos++;
    272 
    273                 linePtr += (char_height + _lineSpacing) * spriteWidth;
     300               
     301                if (Sword2Engine::isPsx())
     302                        linePtr += (char_height / 2 + _lineSpacing) * spriteWidth;
     303                else
     304                        linePtr += (char_height + _lineSpacing) * spriteWidth;
    274305        }
    275306
    276307        _vm->_resman->closeResource(fontRes);
     
    286317
    287318uint16 FontRenderer::charWidth(byte ch, uint32 fontRes) {
    288319        byte *charSet = _vm->_resman->openResource(fontRes);
     320        byte *charBuf;
    289321
    290322        FrameHeader frame_head;
    291323
    292         frame_head.read(findChar(ch, charSet));
     324        charBuf = findChar(ch, charSet);
     325
     326        frame_head.read(charBuf);
     327
     328        if(Sword2Engine::isPsx())
     329                free(charBuf);
     330
    293331        _vm->_resman->closeResource(fontRes);
    294332
    295333        return frame_head.width;
     
    307345
    308346uint16 FontRenderer::charHeight(uint32 fontRes) {
    309347        byte *charSet = _vm->_resman->openResource(fontRes);
     348        byte *charbuf;
    310349
    311350        FrameHeader frame_head;
    312351
    313         frame_head.read(findChar(FIRST_CHAR, charSet));
     352        charbuf = findChar(FIRST_CHAR, charSet);
     353
     354        frame_head.read(charbuf);
     355
     356        if(Sword2Engine::isPsx())
     357                free(charbuf);
     358
    314359        _vm->_resman->closeResource(fontRes);
    315360
    316361        return frame_head.height;
     
    324369 */
    325370
    326371byte *FontRenderer::findChar(byte ch, byte *charSet) {
    327         if (ch < FIRST_CHAR)
    328                 ch = DUD;
    329         return _vm->fetchFrameHeader(charSet, ch - FIRST_CHAR);
     372       
     373        // PSX version doesn't use an animation table to keep all letters,
     374        // instead a big sprite (char atlas) is used, and the single char
     375        // must be extracted from that.
     376       
     377        if (Sword2Engine::isPsx()) {
     378                byte *buffer;
     379                PSXFontEntry header;
     380                FrameHeader bogusHeader;
     381
     382                charSet += ResHeader::size() + 2;
     383
     384                if (ch < FIRST_CHAR)
     385                        ch = DUD;
     386
     387                // Read font entry of the corresponding char.
     388                header.read(charSet + PSXFontEntry::size() * (ch - 32));
     389
     390                // We have no such character, generate an empty one
     391                // on the fly, size 6x12.
     392                if (header.charWidth == 0) {
     393                       
     394                        // Prepare a "bogus" FrameHeader to be returned with
     395                        // "empty" character data.
     396                        bogusHeader.compSize = 0;
     397                        bogusHeader.width = 6;
     398                        bogusHeader.height = 12;
     399
     400                        buffer = (byte *)malloc(24 * 3 + FrameHeader::size());
     401                        memset(buffer, 0, 24 * 3 + FrameHeader::size());
     402                        bogusHeader.write(buffer);
     403                       
     404                        return buffer;
     405                }
     406
     407                buffer = (byte *)malloc(FrameHeader::size() + header.charWidth * header.charHeight * 4);
     408                byte *tempchar = (byte *)malloc(header.charWidth * header.charHeight);
     409
     410                // Prepare the "bogus" header to be returned with character
     411                bogusHeader.compSize = 0;
     412                bogusHeader.width = header.charWidth * 2;
     413                bogusHeader.height = header.charHeight;
     414
     415                // Go to the beginning of char atlas
     416                charSet += 2062;
     417
     418                memset(buffer, 0, FrameHeader::size() + header.charWidth * header.charHeight * 4);
     419
     420                bogusHeader.write(buffer);
     421
     422                // Copy and stretch the char into destination buffer
     423                for (int idx = 0; idx < header.charHeight; idx++) {
     424                        memcpy(tempchar + header.charWidth * idx, charSet + header.offset + 128 * (header.skipLines + idx), header.charWidth);
     425                }
     426
     427                for (int line = 0; line < header.charHeight; line++) {
     428                        for (int col = 0; col < header.charWidth; col++) {
     429                                *(buffer + FrameHeader::size() + line * bogusHeader.width + col * 2) = *(tempchar + line * header.charWidth + col);
     430                                *(buffer + FrameHeader::size() + line * bogusHeader.width + col * 2 + 1) = *(tempchar + line * header.charWidth + col);
     431                        }
     432                }
     433
     434                free(tempchar);
     435
     436                return buffer;
     437
     438        } else {
     439                if (ch < FIRST_CHAR)
     440                        ch = DUD;
     441                return _vm->fetchFrameHeader(charSet, ch - FIRST_CHAR);
     442        }
    330443}
    331444
    332445/**
     
    354467                        // Use the specified colours
    355468                        for (uint j = 0; j < frame.width; j++) {
    356469                                switch (*source++) {
     470                                case 0:
     471                                        // Do nothing if source pixel is zero,
     472                                        // ie. transparent
     473                                        break;
     474                                case LETTER_COL_PSX1: // Values for colored zone
     475                                case LETTER_COL_PSX2:
    357476                                case LETTER_COL:
    358477                                        *dest = pen;
    359478                                        break;
    360479                                case BORDER_COL:
     480                                default:
    361481                                        // Don't do a border pixel if there's
    362482                                        // already a bit of another character
    363483                                        // underneath (for overlapping!)
    364484                                        if (!*dest)
    365485                                                *dest = _borderPen;
    366486                                        break;
    367                                 default:
    368                                         // Do nothing if source pixel is zero,
    369                                         // ie. transparent
    370                                         break;
    371487                                }
    372488                                dest++;
    373489                        }
     
    400516        assert(i < MAX_text_blocs);
    401517
    402518        // Create and position the sprite
    403 
     519       
    404520        _blocList[i].text_mem = makeTextSprite(ascii, width, pen, fontRes);
    405521
    406522        // 'NO_JUSTIFICATION' means print sprite with top-left at (x,y)
     
    498614                        spriteInfo.blend = 0;
    499615                        spriteInfo.data = _blocList[i].text_mem + FrameHeader::size();
    500616                        spriteInfo.colourTable = 0;
     617                        spriteInfo.isText = true;
    501618
    502619                        uint32 rv = _vm->_screen->drawSprite(&spriteInfo);
    503620                        if (rv)
  • scummvm-bs2psx/engines/sword2/screen.h

     
    173173        uint16 blend;           // holds the blending values.
    174174        byte *data;             // pointer to the sprite data
    175175        byte *colourTable;      // pointer to 16-byte colour table, only applicable to 16-col compression type
     176        bool isText;            // It is a engine-generated sprite containing text
    176177};
    177178
    178179struct BlockSurface {
     
    214215        // positions, etc.
    215216
    216217        ScreenInfo _thisScreen;
    217 
     218       
    218219        int32 _renderCaps;
    219220        int8 _renderLevel;
    220221
     
    330331
    331332        void mirrorSprite(byte *dst, byte *src, int16 w, int16 h);
    332333        int32 decompressRLE256(byte *dst, byte *src, int32 decompSize);
    333         void unwindRaw16(byte *dst, byte *src, uint8 blockSize, byte *colTable);
     334        void unwindRaw16(byte *dst, byte *src, uint16 blockSize, byte *colTable);
    334335        int32 decompressRLE16(byte *dst, byte *src, int32 decompSize, byte *colTable);
    335336        void renderParallax(byte *ptr, int16 layer);
    336337
     338
    337339        void markAsDirty(int16 x0, int16 y0, int16 x1, int16 y1);
    338340
    339341        uint8 _xBlocks[MAXLAYERS];
    340342        uint8 _yBlocks[MAXLAYERS];
    341343
     344        // This is used to cache PSX backgrounds and parallaxes
     345        // data, as they are kept in a file unmanageable from
     346        // resource manager. These gets freed everytime an user
     347        // exits from a room.
     348        byte *_psxScrCache[3];
     349        bool _psxCacheEnabled[3];
     350
    342351        // An array of sub-blocks, one for each of the parallax layers.
    343352
    344353        BlockSurface **_blockSurfaces[MAXLAYERS];
     
    396405
    397406        void setLocationMetrics(uint16 w, uint16 h);
    398407        int32 initialiseBackgroundLayer(byte *parallax);
     408        int32 initialisePsxParallaxLayer(byte *parallax);   // These are used to initialize psx backgrounds and
     409        int32 initialisePsxBackgroundLayer(byte *parallax); // parallaxes, which are different from pc counterparts.
    399410        void closeBackgroundLayer();
    400411
    401412        void initialiseRenderCycle();
    402413
    403414        void initBackground(int32 res, int32 new_palette);
     415        void initPsxBackground(int32 res, int32 new_palette);
    404416        void registerFrame(byte *ob_mouse, byte *ob_graph, byte *ob_mega);
    405417
    406418        void setScrollFraction(uint8 f) { _scrollFraction = f; }
     
    446458
    447459        void rollCredits();
    448460        void splashScreen();
     461
     462        // Some sprites are compressed in HIF format
     463        static uint32 decompressHIF(byte *src, byte *dst, uint32 *skipData = NULL);
     464        // This is used to resize psx sprites back to original resolution
     465        static void resizePsxSprite(byte *dst, byte *src, uint16 destW, uint16 destH);
     466        // Some sprites are divided into 254 pixel wide stripes, this recomposes them
     467        // and generates a "normal" sprite.
     468        static void recomposePsxSprite(SpriteInfo *s);
     469        static void recomposeCompPsxSprite(SpriteInfo *s);
     470
     471        // These functions manage the PSX screen cache
     472        void setPsxScrCache(byte *psxScrCache, uint8 level);
     473        byte *getPsxScrCache(uint8 level);
     474        bool getPsxScrCacheStatus(uint8 level);
     475        void flushPsxScrCache();
     476
    449477};
    450478
    451479} // End of namespace Sword2
  • scummvm-bs2psx/engines/sword2/mouse.cpp

     
    280280
    281281int Mouse::menuClick(int menu_items) {
    282282        int x = getX();
     283        byte menuIconWidth;
    283284
     285        if (Sword2Engine::isPsx())
     286                menuIconWidth = RDMENU_PSXICONWIDE;
     287        else
     288                menuIconWidth = RDMENU_ICONWIDE;
     289
     290
    284291        if (x < RDMENU_ICONSTART)
    285292                return -1;
    286293
    287         if (x > RDMENU_ICONSTART + menu_items * (RDMENU_ICONWIDE + RDMENU_ICONSPACING) - RDMENU_ICONSPACING)
     294        if (x > RDMENU_ICONSTART + menu_items * (menuIconWidth + RDMENU_ICONSPACING) - RDMENU_ICONSPACING)
    288295                return -1;
    289296
    290         return (x - RDMENU_ICONSTART) / (RDMENU_ICONWIDE + RDMENU_ICONSPACING);
     297        return (x - RDMENU_ICONSTART) / (menuIconWidth + RDMENU_ICONSPACING);
    291298}
    292299
    293300void Mouse::systemMenuMouse() {
     
    330337        if (hit < 0)
    331338                return;
    332339
     340        // Do nothing if using PSX version and are on TOP menu.
     341
     342        if ((icon_list[hit] == OPTIONS_ICON || icon_list[hit] == QUIT_ICON
     343                || icon_list[hit] == SAVE_ICON || icon_list[hit] == RESTORE_ICON
     344                || icon_list[hit] == RESTART_ICON ) && Sword2Engine::isPsx() )
     345                return;
     346
    333347        // No save when dead
    334348
    335349        if (icon_list[hit] == SAVE_ICON && _vm->_logic->readVar(DEAD))
     
    857871        // Unlike the other mouse "engines", this one is called directly by the
    858872        // fnChoose() opcode.
    859873
     874        byte menuIconWidth;
     875
     876        if (Sword2Engine::isPsx())
     877                menuIconWidth = RDMENU_PSXICONWIDE;
     878        else
     879                menuIconWidth = RDMENU_ICONWIDE;
     880
     881
    860882        uint i;
    861883
    862884        _vm->_logic->writeVar(AUTO_SELECTED, 0);
     
    912934                        error("fnChoose with no subjects");
    913935
    914936                for (i = 0; i < in_subject; i++) {
    915                         icon = _vm->_resman->openResource(_subjectList[i].res) + ResHeader::size() + RDMENU_ICONWIDE * RDMENU_ICONDEEP;
     937                        icon = _vm->_resman->openResource(_subjectList[i].res) + ResHeader::size() + menuIconWidth * RDMENU_ICONDEEP;
    916938                        setMenuIcon(RDMENU_BOTTOM, i, icon);
    917939                        _vm->_resman->closeResource(_subjectList[i].res);
    918940                }
     
    14851507        int x = 0;
    14861508        int y = 0;
    14871509
    1488         comp = comp + READ_LE_UINT32(comp + frame * 4) - MOUSE_ANIM_HEADER_SIZE;
     1510        if (Sword2Engine::isPsx()) {
     1511                comp = comp + READ_LE_UINT32(comp + 2 + frame * 4) - MOUSE_ANIM_HEADER_SIZE;
    14891512
    1490         while (i < size) {
    1491                 if (*comp > 183) {
    1492                         decomp[(y + yOff) * pitch + x + xOff] = *comp++;
    1493                         if (++x >= width) {
    1494                                 x = 0;
    1495                                 y++;
     1513                yOff /= 2; // Without this, distance of object from cursor is too big.
     1514
     1515                byte *buffer;
     1516
     1517                buffer = (byte *)malloc(size);
     1518                Screen::decompressHIF(comp, buffer);
     1519
     1520                for (int line = 0; line < height; line++) {
     1521                        memcpy(decomp + (line + yOff) * pitch + xOff, buffer + line * width, width);
     1522                }
     1523
     1524                free(buffer);
     1525       
     1526        } else {
     1527                comp = comp + READ_LE_UINT32(comp + frame * 4) - MOUSE_ANIM_HEADER_SIZE;       
     1528
     1529                while (i < size) {
     1530                        if (*comp > 183) {
     1531                                decomp[(y + yOff) * pitch + x + xOff] = *comp++;
     1532                                if (++x >= width) {
     1533                                        x = 0;
     1534                                        y++;
     1535                                }
     1536                                i++;
     1537                        } else {
     1538                                x += *comp;
     1539                                while (x >= width) {
     1540                                        y++;
     1541                                        x -= width;
     1542                                }
     1543                                i += *comp++;
    14961544                        }
    1497                         i++;
    1498                 } else {
    1499                         x += *comp;
    1500                         while (x >= width) {
    1501                                 y++;
    1502                                 x -= width;
    1503                         }
    1504                         i += *comp++;
    15051545                }
    15061546        }
    15071547}
     
    15631603                decompressMouse(mouseData, _mouseAnim.data, _mouseFrame,
    15641604                        _mouseAnim.mousew, _mouseAnim.mouseh, mouse_width);
    15651605
     1606        // Fix height for mouse sprite in PSX version
     1607        if (Sword2Engine::isPsx()) {
     1608                mouse_height *= 2;
     1609               
     1610                byte *buffer = (byte *)malloc(mouse_width * mouse_height);
     1611                Screen::resizePsxSprite(buffer, mouseData, mouse_width, mouse_height);
     1612               
     1613                free(mouseData);
     1614                mouseData = buffer;
     1615        }
     1616
    15661617        CursorMan.replaceCursor(mouseData, mouse_width, mouse_height, hotspot_x, hotspot_y, 0);
    15671618
    15681619        free(mouseData);
     
    16751726        return RD_OK;
    16761727}
    16771728
     1729int Mouse::getMouseMode() {
     1730        return _mouseMode;
     1731}
     1732
     1733void Mouse::setMouseMode(int mouseMode) {
     1734        _mouseMode = mouseMode;
     1735}
     1736
    16781737} // End of namespace Sword2
  • scummvm-bs2psx/engines/sword2/resman.h

     
    6464        void removeFromCacheList(Resource *res);
    6565        void addToCacheList(Resource *res);
    6666        void checkMemUsage();
    67 
     67       
    6868        Sword2Engine *_vm;
    6969
    7070        int _curCD;
     
    9696
    9797        bool checkValid(uint32 res);
    9898        uint32 fetchLen(uint32 res);
     99        uint8 fetchType(byte *ptr);
    99100        uint8 fetchType(uint32 res) {
    100101                byte *ptr = openResource(res);
    101                 uint8 type = ptr[0];
     102                uint8 type = fetchType(ptr);
    102103                closeResource(res);
    103104
    104105                return type;
    105106        }
    106107
    107         uint8 fetchType(byte *ptr) {
    108                 return ptr[0];
    109         }
    110 
    111108        byte *fetchName(uint32 res, byte *buf = NULL) {
    112109                static byte tempbuf[NAME_LEN];
    113110
  • scummvm-bs2psx/engines/sword2/sound.h

     
    231231        int readBuffer(int16 *buffer, const int numSamples);
    232232        bool isStereo() const { return false; }
    233233        bool endOfData() const;
    234         int getRate() const { return 22050; }
     234        int getRate() const { return Sword2Engine::isPsx() ? 11025 : 22050; }
    235235
    236236        // End of AudioStream API
    237237
  • scummvm-bs2psx/engines/sword2/palette.cpp

     
    4848
    4949        byte *screenFile = _vm->_resman->openResource(_thisScreen.background_layer_id);
    5050
    51         memcpy(_paletteMatch, _vm->fetchPaletteMatchTable(screenFile), PALTABLESIZE);
     51        // Don't fetch palette match table while using PSX version,
     52        // because it is not present.
     53        if(!Sword2Engine::isPsx())
     54                memcpy(_paletteMatch, _vm->fetchPaletteMatchTable(screenFile), PALTABLESIZE);
     55       
    5256        setPalette(0, 256, _vm->fetchPalette(screenFile), RDPAL_FADE);
    5357
    5458        // Indicating that it's a screen palette
     
    116120        } else {
    117121                if (_thisScreen.background_layer_id) {
    118122                        byte *data = _vm->_resman->openResource(_thisScreen.background_layer_id);
    119                         memcpy(_paletteMatch, _vm->fetchPaletteMatchTable(data), PALTABLESIZE);
     123                       
     124                        // Do not fetch palette match table when using PSX version,
     125                        // because it is not present.
     126                        if (!Sword2Engine::isPsx()) 
     127                                memcpy(_paletteMatch, _vm->fetchPaletteMatchTable(data), PALTABLESIZE);
     128                       
    120129                        setPalette(0, 256, _vm->fetchPalette(data), RDPAL_INSTANT);
    121130                        _vm->_resman->closeResource(_thisScreen.background_layer_id);
    122131                } else
  • scummvm-bs2psx/engines/sword2/layers.cpp

     
    179179        }
    180180
    181181        // Background parallax layers
    182 
     182       
    183183        for (i = 0; i < 2; i++) {
    184184                if (screenLayerTable.bg_parallax[i])
    185185                        initialiseBackgroundLayer(_vm->fetchBackgroundParallaxLayer(file, i));
     
    188188        }
    189189
    190190        // Normal backround layer
    191 
     191       
    192192        initialiseBackgroundLayer(_vm->fetchBackgroundLayer(file));
    193193
    194194        // Foreground parallax layers
    195 
     195       
    196196        for (i = 0; i < 2; i++) {
    197197                if (screenLayerTable.fg_parallax[i])
    198198                        initialiseBackgroundLayer(_vm->fetchForegroundParallaxLayer(file, i));
     
    203203        _vm->_resman->closeResource(_thisScreen.background_layer_id);
    204204}
    205205
     206/**
     207 * This function is called when entering a new room, PSX edition
     208 * @param res resource id of the normal background layer
     209 * @param new_palette 1 for new palette, otherwise 0
     210 */
     211
     212void Screen::initPsxBackground(int32 res, int32 new_palette) {
     213        int i;
     214
     215        assert(res);
     216
     217        _vm->_sound->clearFxQueue(false);
     218        waitForFade();
     219
     220        debug(1, "CHANGED TO LOCATION \"%s\"", _vm->_resman->fetchName(res));
     221
     222        _vm->_logic->writeVar(EXIT_CLICK_ID, 0);
     223
     224        // Close the previous screen, if one is open
     225        if (_thisScreen.background_layer_id)
     226                closeBackgroundLayer();
     227
     228        _thisScreen.background_layer_id = res;
     229        _thisScreen.new_palette = new_palette;
     230
     231        // ok, now read the resource and pull out all the normal sort layer
     232        // info/and set them up at the beginning of the sort list - why do it
     233        // each cycle
     234
     235        byte *file = _vm->_resman->openResource(_thisScreen.background_layer_id);
     236        ScreenHeader screen_head;
     237
     238        screen_head.read(_vm->fetchScreenHeader(file));
     239        screen_head.height *= 2;
     240
     241        // set number of special sort layers
     242        _thisScreen.number_of_layers = screen_head.noLayers;
     243        _thisScreen.screen_wide = screen_head.width;
     244        _thisScreen.screen_deep = screen_head.height;
     245
     246        debug(2, "layers=%d width=%d depth=%d", screen_head.noLayers, screen_head.width, screen_head.height);
     247
     248        // initialise the driver back buffer
     249        setLocationMetrics(screen_head.width, screen_head.height);
     250
     251        for (i = 0; i < screen_head.noLayers; i++) {
     252                debug(3, "init layer %d", i);
     253
     254                LayerHeader layer;
     255
     256                layer.read(_vm->fetchLayerHeader(file, i));
     257                _sortList[i].layer_number = i + 1;
     258                _sortList[i].sort_y = layer.y + layer.height;
     259        }
     260
     261        // reset scroll offsets
     262        _thisScreen.scroll_offset_x = 0;
     263        _thisScreen.scroll_offset_y = 0;
     264
     265        if (screen_head.width > _screenWide || screen_head.height > _screenDeep) {
     266                _thisScreen.scroll_flag = 2;
     267
     268                _thisScreen.max_scroll_offset_x = screen_head.width - _screenWide;
     269                _thisScreen.max_scroll_offset_y = screen_head.height - (_screenDeep - (MENUDEEP * 2));
     270        } else {
     271                // The later fits on the phyiscal screen. Switch off scrolling.
     272                _thisScreen.scroll_flag = 0;
     273        }
     274
     275        resetRenderEngine();
     276
     277        // These are the physical screen coords where the system will try to
     278        // maintain George's actual feet coords.
     279
     280        _thisScreen.feet_x = 320;
     281        _thisScreen.feet_y = 340;
     282
     283        // Background parallax layers
     284        initialisePsxParallaxLayer(_vm->fetchBackgroundParallaxLayer(file, 0));
     285        initialisePsxParallaxLayer(NULL);
     286
     287        // Normal backround layer
     288        initialisePsxBackgroundLayer(_vm->fetchBackgroundLayer(file));
     289
     290        // Foreground parallax layers
     291        initialisePsxParallaxLayer(_vm->fetchForegroundParallaxLayer(file, 1));
     292        initialisePsxParallaxLayer(NULL);
     293
     294        _vm->_resman->closeResource(_thisScreen.background_layer_id);
     295
     296}
     297
    206298} // End of namespace Sword2
  • scummvm-bs2psx/engines/sword2/console.cpp

     
    274274
    275275bool Debugger::Cmd_ResList(int argc, const char **argv) {
    276276        // By default, list only resources that are being held open.
    277         uint minCount = 1;
     277        uint32 minCount = 1;
    278278
    279279        if (argc > 1)
    280280                minCount = atoi(argv[1]);
  • scummvm-bs2psx/engines/sword2/logic.h

     
    314314        void resetKillList();
    315315
    316316        void pauseMovie(bool pause);
     317
     318        // Read location number from script vars
     319        uint32 getLocationNum();
    317320};
    318321
    319322} // End of namespace Sword2
  • scummvm-bs2psx/engines/sword2/sprite.cpp

     
    2525 * $Id$
    2626 */
    2727
     28#include "common/endian.h"
    2829
    29 
    3030#include "sword2/sword2.h"
    3131#include "sword2/defs.h"
    3232#include "sword2/screen.h"
     
    138138 * Unwinds a run of 16-colour data into 256-colour palette data.
    139139 */
    140140
    141 void Screen::unwindRaw16(byte *dst, byte *src, uint8 blockSize, byte *colTable) {
     141void Screen::unwindRaw16(byte *dst, byte *src, uint16 blockSize, byte *colTable) {
    142142        // for each pair of pixels
    143143        while (blockSize > 1) {
    144                 // 1st colour = number in table at position given by upper
    145                 // nibble of source byte
    146                 *dst++ = colTable[(*src) >> 4];
     144               
     145                if (Sword2Engine::isPsx()) {
     146                        // 1st colour = number in table at position given by upper
     147                        // nibble of source byte
     148                        *dst++ = colTable[(*src) & 0x0f];
    147149
    148                 // 2nd colour = number in table at position given by lower
    149                 // nibble of source byte
    150                 *dst++ = colTable[(*src) & 0x0f];
     150                        // 2nd colour = number in table at position given by lower
     151                        // nibble of source byte
     152                        *dst++ = colTable[(*src) >> 4];
     153                } else {
     154                        *dst++ = colTable[(*src) >> 4];
     155                        *dst++ = colTable[(*src) & 0x0f];
     156                }
    151157
     158
    152159                // point to next source byte
    153160                src++;
    154161
     
    245252}
    246253
    247254/**
     255 * This function takes a compressed HIF image and decompresses it.
     256 * Used for PSX version sprites.
     257 * @param dst destination buffer
     258 * @param src source buffer
     259 * @param skipData if pointer != NULL, value of pointed var
     260 * is set to number of bytes composing the compressed data.
     261 */
     262
     263uint32 Screen::decompressHIF(byte *src, byte *dst, uint32 *skipData) {
     264        uint32 decompSize = 0;
     265        uint32 readByte = 0;
     266
     267        for (;;) { // Main loop
     268                byte control_byte = *src++;
     269                readByte++;
     270                uint32 byte_count = 0;
     271                while (byte_count < 8) {
     272                        if (control_byte & 0x80) {
     273                                uint16 info_word = READ_BE_UINT16(src); // Read the info word
     274                                src += 2;
     275                                readByte += 2;
     276                                if (info_word == 0xFFFF) { // Got 0xFFFF code, finished.
     277                                        if (skipData != NULL) *(skipData) = readByte;
     278                                        return decompSize;
     279                                }
     280
     281                                int32 repeat_count = (info_word >> 12) + 2; // How many time data needs to be refetched
     282                                while(repeat_count >= 0) {
     283                                        uint16 refetchData = (info_word & 0xFFF) + 1;
     284                                        if (refetchData > decompSize) return 0; // We have a problem here...
     285                                        uint8 *old_data_src = dst - refetchData;
     286                                        *dst++ = *old_data_src;
     287                                        decompSize++;
     288                                        repeat_count--;
     289                                }
     290                        } else {
     291                                *dst++ = *src++;
     292                                readByte++;
     293                                decompSize++;
     294                        }
     295                        byte_count++;
     296                        control_byte <<= 1; // Shifting left the control code one bit
     297                }
     298        }
     299}
     300
     301// Double line image to keep aspect ratio.
     302// Used in PSX version.
     303void Screen::resizePsxSprite(byte *dst, byte *src, uint16 destW, uint16 destH) {
     304        for (int i = 0; i < destH / 2; i++) {
     305                memcpy(dst + i * destW * 2, src + i * destW, destW);
     306                memcpy(dst + i * destW * 2 + destW, src + i * destW, destW);
     307        }
     308}
     309
     310// Sprites wider than 254px in PSX version are divided
     311// into slices, this recomposes the image.
     312void Screen::recomposePsxSprite(SpriteInfo *s) {
     313        if (!s)
     314                return;
     315
     316        uint16 noStripes = (s->w / 254) + ((s->w % 254) ? 1 : 0);
     317        uint16 lastStripeSize = (s->w % 254) ? s->w % 254 : 254;
     318        byte *buffer = (byte *)malloc(s->w * s->h / 2);
     319
     320        memset(buffer, 0, s->w * s->h / 2);
     321
     322        for (int idx = 0; idx < noStripes; idx++) {
     323                uint16 stripeSize = (idx == noStripes - 1) ? lastStripeSize : 254;
     324                for (int line = 0; line < s->h / 2; line++) {
     325                        memcpy(buffer + idx * 254 + line * s->w, s->data, stripeSize);
     326                        s->data += stripeSize;
     327                }
     328        }
     329
     330        s->data = buffer;
     331
     332}
     333
     334// Recomposes sprites wider than 254 pixels but also
     335// compressed with HIF.
     336// Used in PSX version.
     337void Screen::recomposeCompPsxSprite(SpriteInfo *s) {
     338        if (!s)
     339                return;
     340
     341        uint16 noStripes = (s->w / 254) + ((s->w % 254) ? 1 : 0);
     342        uint16 lastStripeSize = (s->w % 254) ? s->w % 254 : 254;
     343        byte *buffer = (byte *)malloc(s->w * s->h / 2);
     344        byte *stripeBuffer = (byte *)malloc(254 * s->h);;
     345
     346        memset(buffer, 0, s->w * s->h / 2);
     347        uint32 skipData = 0;
     348        uint32 compBytes = 0;
     349
     350        for (int idx = 0; idx < noStripes; idx++) {
     351                uint16 stripeSize = (idx == noStripes - 1) ? lastStripeSize : 254;
     352
     353                decompressHIF((s->data) + skipData, stripeBuffer, &compBytes);
     354                skipData += compBytes;
     355
     356                for (int line = 0; line < s->h / 2; line++) {
     357                        memcpy(buffer + idx * 254 + line * s->w, stripeBuffer + line * stripeSize, stripeSize);
     358                }
     359        }
     360
     361        free(stripeBuffer);
     362        s->data = buffer;
     363
     364}
     365
     366/**
    248367 * Creates a sprite surface. Sprite surfaces are used by the in-game dialogs
    249368 * and for displaying cutscene subtitles, which makes them much easier to draw
    250369 * than standard sprites.
     
    378497        // -----------------------------------------------------------------
    379498        // Decompression and mirroring
    380499        // -----------------------------------------------------------------
     500        if (s->type & RDSPR_NOCOMPRESSION) {
     501                if(Sword2Engine::isPsx()) { // PSX Uncompressed sprites
     502                        if (s->w > 254 && !s->isText) { // We need to recompose these frames
     503                                recomposePsxSprite(s);
     504                        }
    381505
    382         if (s->type & RDSPR_NOCOMPRESSION)
    383                 sprite = s->data;
    384         else {
    385                 sprite = (byte *)malloc(s->w * s->h);
     506                        freeSprite = true;
     507                        byte *tempBuf = (byte *)malloc(s->w * s->h * 2);
     508                        memset(tempBuf, 0, s->w * s->h * 2);
     509                        resizePsxSprite(tempBuf, s->data, s->w, s->h);
     510
     511                        if (s->w > 254 && !s->isText) {
     512                                free(s->data);
     513                        }
     514
     515                        sprite = tempBuf;
     516                } else { // PC Uncompressed sprites
     517                        sprite = s->data;
     518                }
     519        } else {
    386520                freeSprite = true;
    387                 if (!sprite)
    388                         return RDERR_OUTOFMEMORY;
     521
    389522                if ((s->type & 0xff00) == RDSPR_RLE16) {
    390                         if (decompressRLE16(sprite, s->data, s->w * s->h, s->colourTable)) {
    391                                 free(sprite);
    392                                 return RDERR_DECOMPRESSION;
     523                        if (Sword2Engine::isPsx()) { // PSX HIF16 sprites
     524                                uint32 decompData;
     525                                byte *tempBuf = (byte *)malloc(s->w * s->h);
     526                                memset(tempBuf, 0, s->w * s->h);
     527
     528                                decompData = decompressHIF(s->data, tempBuf);
     529
     530                                s->w = (decompData / (s->h / 2)) * 2;
     531                                byte *tempBuf2 = (byte *)malloc(s->w * s->h * 10);
     532                                memset(tempBuf2, 0, s->w * s->h * 2);
     533
     534                                unwindRaw16(tempBuf2, tempBuf, (s->w * (s->h / 2)), s->colourTable);
     535                                sprite = (byte *)malloc(s->w * s->h);
     536
     537                                if (!sprite)
     538                                        return RDERR_OUTOFMEMORY;
     539
     540                                resizePsxSprite(sprite, tempBuf2, s->w, s->h);
     541
     542                                free(tempBuf2);
     543                                free(tempBuf);
     544                        } else { // PC RLE16 sprites
     545                                sprite = (byte *)malloc(s->w * s->h);
     546                               
     547                                if (!sprite)
     548                                        return RDERR_OUTOFMEMORY;
     549
     550                                if (decompressRLE16(sprite, s->data, s->w * s->h, s->colourTable)) {
     551                                        free(sprite);
     552                                        return RDERR_DECOMPRESSION;
     553                                }
    393554                        }
    394555                } else {
    395                         if (decompressRLE256(sprite, s->data, s->w * s->h)) {
    396                                 free(sprite);
    397                                 return RDERR_DECOMPRESSION;
     556                        if (Sword2Engine::isPsx()) { // PSX HIF256 sprites
     557                                if (s->w > 255) {
     558                                        sprite = (byte *)malloc(s->w * s->h);
     559                                        recomposeCompPsxSprite(s);
     560                                        resizePsxSprite(sprite, s->data, s->w, s->h);
     561                                        free(s->data);
     562                                } else {
     563                                        byte *tempBuf = (byte *)malloc(s->w * s->h);
     564                                        uint32 decompData = decompressHIF(s->data, tempBuf);
     565                                        s->w = (decompData / (s->h / 2));
     566                                        sprite = (byte *)malloc(s->w * s->h);
     567                               
     568                                        if (!sprite)
     569                                                return RDERR_OUTOFMEMORY;
     570
     571                                        resizePsxSprite(sprite, tempBuf, s->w, s->h);
     572                                        free(tempBuf);
     573                                }
     574                        } else { // PC RLE256 sprites
     575                                sprite = (byte *)malloc(s->w * s->h);
     576
     577                                if (!sprite)
     578                                        return RDERR_OUTOFMEMORY;
     579
     580                                if (decompressRLE256(sprite, s->data, s->w * s->h)) {
     581                                        free(sprite);
     582                                        return RDERR_DECOMPRESSION;
     583                                }
    398584                        }
    399585                }
    400586        }
     
    500686                        return RDERR_OUTOFMEMORY;
    501687                }
    502688
    503                 if (_renderCaps & RDBLTFX_EDGEBLEND)
     689                // We cannot use good scaling for PSX version, as we are missing
     690                // some required data.
     691                if (_renderCaps & RDBLTFX_EDGEBLEND && !Sword2Engine::isPsx())
    504692                        scaleImageGood(newSprite, s->scaledWidth, s->scaledWidth, s->scaledHeight, sprite, s->w, s->w, s->h, _buffer + _screenWide * rd.top + rd.left);
    505693                else
    506694                        scaleImageFast(newSprite, s->scaledWidth, s->scaledWidth, s->scaledHeight, sprite, s->w, s->w, s->h);
     
    518706        // The light mask is an optional layer that covers the entire room
    519707        // and which is used to simulate light and shadows. Scaled sprites
    520708        // (actors, presumably) are always affected.
     709        // Light masking makes use of palette match table, so it's unavailable
     710        // in PSX version.
    521711
    522         if ((_renderCaps & RDBLTFX_SHADOWBLEND) && _lightMask && (scale != 256 || (s->type & RDSPR_SHADOW))) {
     712        if ((_renderCaps & RDBLTFX_SHADOWBLEND) && _lightMask && (scale != 256 || ((s->type & RDSPR_SHADOW) && !Sword2Engine::isPsx()) )) {
    523713                byte *lightMap;
    524714
    525715                // Make sure that we never apply the shadow to the original
     
    557747        src = sprite + rs.top * srcPitch + rs.left;
    558748        dst = _buffer + _screenWide * rd.top + rd.left;
    559749
    560         if (s->type & RDSPR_BLEND) {
     750        if (s->type & RDSPR_BLEND && !Sword2Engine::isPsx()) { // Blending is unavailable in PSX version
    561751                // The original code had two different blending cases. One for
    562752                // s->blend & 0x01 and one for s->blend & 0x02. However, the
    563753                // only values that actually appear in the cluster files are
     
    639829        if (!_lightMask)
    640830                return RDERR_OUTOFMEMORY;
    641831
     832        if (s->data == NULL) // Check, as there's no mask in psx version
     833                return RDERR_NOTOPEN;
     834
    642835        if (decompressRLE256(_lightMask, s->data, s->w * s->h))
    643836                return RDERR_DECOMPRESSION;
    644837
  • scummvm-bs2psx/engines/sword2/anims.cpp

     
    103103
    104104                // point to anim header
    105105                anim_head.read(_vm->fetchAnimHeader(anim_file));
    106 
     106               
    107107                // now running an anim, looping back to this call again
    108108                obLogic.setLooping(1);
    109109                obGraph.setAnimResource(animRes);
  • scummvm-bs2psx/engines/sword2/icons.cpp

     
    7777
    7878void Mouse::buildMenu() {
    7979        uint32 i, j;
     80        byte menuIconWidth;
    8081
     82        if (Sword2Engine::isPsx())
     83                menuIconWidth = RDMENU_PSXICONWIDE;
     84        else
     85                menuIconWidth = RDMENU_ICONWIDE;
     86
    8187        // Clear the temporary inventory list, since we are going to build a
    8288        // new one from scratch.
    8389
     
    178184                        // greyed out one.
    179185
    180186                        if (icon_coloured)
    181                                 icon += (RDMENU_ICONWIDE * RDMENU_ICONDEEP);
     187                                icon += (menuIconWidth * RDMENU_ICONDEEP);
    182188                }
    183189
    184190                setMenuIcon(RDMENU_BOTTOM, i, icon);
     
    203209                RESTART_ICON
    204210        };
    205211
     212        byte menuIconWidth;
     213
     214        if (Sword2Engine::isPsx())
     215                menuIconWidth = RDMENU_PSXICONWIDE;
     216        else
     217                menuIconWidth = RDMENU_ICONWIDE;
     218
    206219        // Build them all high in full colour - when one is clicked on all the
    207220        // rest will grey out.
    208221
     
    213226                // is dead. Then SAVE is not available.
    214227
    215228                if (!_vm->_logic->readVar(DEAD) || icon_list[i] != SAVE_ICON)
    216                         icon += (RDMENU_ICONWIDE * RDMENU_ICONDEEP);
     229                        icon += (menuIconWidth * RDMENU_ICONDEEP);
    217230
    218231                setMenuIcon(RDMENU_TOP, i, icon);
    219232                _vm->_resman->closeResource(icon_list[i]);
  • scummvm-bs2psx/engines/sword2/animation.cpp

     
    3535#include "sword2/maketext.h"
    3636#include "sword2/resman.h"
    3737#include "sword2/sound.h"
     38#include "sword2/screen.h"
    3839#include "sword2/animation.h"
    3940
    4041#include "gui/message.h"
     
    207208                text->_textSprite.h = frame.height;
    208209                text->_textSprite.type = RDSPR_DISPLAYALIGN | RDSPR_NOCOMPRESSION;
    209210                text->_textSprite.data = text->_textMem + FrameHeader::size();
     211                text->_textSprite.isText = true;
    210212                _vm->_screen->createSurface(&text->_textSprite, &_textSurface);
    211213
    212214                _textX = 320 - text->_textSprite.w / 2;
     
    239241                uint16 width = text->_textSprite.w;
    240242                uint16 height = text->_textSprite.h;
    241243
     244                // Resize text sprites for PSX version
     245                if (Sword2Engine::isPsx()) {
     246                        height *= 2;
     247                        byte *buffer = (byte *)malloc(width * height);
     248                        Screen::resizePsxSprite(buffer, src, width, height);
     249                        src = buffer;
     250                }
     251
    242252                byte *dst = screen + _textY * _decoder->getWidth() + _textX;
    243253
    244254                for (int y = 0; y < height; y++) {
  • scummvm-bs2psx/engines/sword2/screen.cpp

     
    7676        _needFullRedraw = false;
    7777
    7878        memset(&_thisScreen, 0, sizeof(_thisScreen));
    79 
     79       
    8080        _fps = 0;
    8181        _frameCount = 0;
    8282        _cycleTime = 0;
     
    100100
    101101        _pauseTicks = 0;
    102102        _pauseStartTick = 0;
     103
     104        // Clean the cache for PSX version SCREENS.CLU
     105        _psxScrCache[0] = NULL;
     106        _psxScrCache[1] = NULL;
     107        _psxScrCache[2] = NULL;
     108        _psxCacheEnabled[0] = true;
     109        _psxCacheEnabled[1] = true;
     110        _psxCacheEnabled[2] = true;
    103111}
    104112
    105113Screen::~Screen() {
     114        flushPsxScrCache();
    106115        free(_buffer);
    107116        free(_dirtyGrid);
    108117        closeBackgroundLayer();
     
    277286
    278287        MultiScreenHeader screenLayerTable;
    279288
    280         screenLayerTable.read(file + ResHeader::size());
     289        if (!Sword2Engine::isPsx()) // On PSX version, there would be nothing to read here
     290                screenLayerTable.read(file + ResHeader::size());
    281291
    282292        // Render at least one frame, but if the screen is scrolling, and if
    283293        // there is time left, we will render extra frames to smooth out the
     
    285295
    286296        do {
    287297                // first background parallax + related anims
    288                 if (screenLayerTable.bg_parallax[0]) {
     298                if (Sword2Engine::isPsx() || screenLayerTable.bg_parallax[0]) { // No need to check on PSX version
    289299                        renderParallax(_vm->fetchBackgroundParallaxLayer(file, 0), 0);
    290300                        drawBackPar0Frames();
    291301                }
    292302
    293303                // second background parallax + related anims
    294                 if (screenLayerTable.bg_parallax[1]) {
     304                if (!Sword2Engine::isPsx() && screenLayerTable.bg_parallax[1]) { // Nothing here in PSX version
    295305                        renderParallax(_vm->fetchBackgroundParallaxLayer(file, 1), 1);
    296306                        drawBackPar1Frames();
    297307                }
     
    306316
    307317                // first foreground parallax + related anims
    308318
    309                 if (screenLayerTable.fg_parallax[0]) {
     319                if (Sword2Engine::isPsx() || screenLayerTable.fg_parallax[0]) {
    310320                        renderParallax(_vm->fetchForegroundParallaxLayer(file, 0), 3);
    311321                        drawForePar0Frames();
    312322                }
    313323
    314324                // second foreground parallax + related anims
    315325
    316                 if (screenLayerTable.fg_parallax[1]) {
     326                if (!Sword2Engine::isPsx() && screenLayerTable.fg_parallax[1]) {
    317327                        renderParallax(_vm->fetchForegroundParallaxLayer(file, 1), 4);
    318328                        drawForePar1Frames();
    319329                }
     
    333343        } while (!endRenderCycle());
    334344
    335345        _vm->_resman->closeResource(_thisScreen.background_layer_id);
     346
    336347}
    337348
    338349/**
     
    381392        spriteInfo.blend = 0;
    382393        spriteInfo.data = text_spr + FrameHeader::size();
    383394        spriteInfo.colourTable = 0;
     395        spriteInfo.isText = true;
    384396
    385397        uint32 rv = drawSprite(&spriteInfo);
    386398        if (rv)
     
    490502}
    491503
    492504void Screen::processLayer(byte *file, uint32 layer_number) {
     505
    493506        LayerHeader layer_head;
    494507
    495508        layer_head.read(_vm->fetchLayerHeader(file, layer_number));
     
    503516        spriteInfo.scaledWidth = 0;
    504517        spriteInfo.scaledHeight = 0;
    505518        spriteInfo.h = layer_head.height;
    506         spriteInfo.type = RDSPR_TRANS | RDSPR_RLE256FAST;
     519        spriteInfo.isText = false;
     520
     521        // Layers are uncompressed in PSX version, RLE256 compressed
     522        // in PC version.
     523        if (Sword2Engine::isPsx()) {
     524                spriteInfo.type = RDSPR_TRANS | RDSPR_NOCOMPRESSION;
     525                spriteInfo.data = file + layer_head.offset;
     526        } else {
     527                spriteInfo.type = RDSPR_TRANS | RDSPR_RLE256FAST;
     528                spriteInfo.data = file + ResHeader::size() + layer_head.offset;
     529        }
     530
    507531        spriteInfo.blend = 0;
    508         spriteInfo.data = file + ResHeader::size() + layer_head.offset;
    509532        spriteInfo.colourTable = 0;
    510533
    511534        // check for largest layer for debug info
     
    575598                        // points to just after last cdt_entry, ie.
    576599                        // start of colour table
    577600                        colTablePtr = _vm->fetchAnimHeader(file) + AnimHeader::size() + anim_head.noAnimFrames * CdtEntry::size();
     601                        if (Sword2Engine::isPsx())
     602                                colTablePtr++; // There is one additional byte to skip before the table in psx version
    578603                        break;
    579604                }
    580605        }
     
    598623        // points to just after frame header, ie. start of sprite data
    599624        spriteInfo.data = frame + FrameHeader::size();
    600625        spriteInfo.colourTable = colTablePtr;
     626        spriteInfo.isText = false;
    601627
    602628        // check for largest layer for debug info
    603629        uint32 current_sprite_area = frame_head.width * frame_head.height;
     
    864890        //     that this is a coincidence, but let's use the image palette
    865891        //     directly anyway, just to be safe.
    866892        //
    867         // credits.clu  - The credits text
     893        // credits.clu  - The credits text (credits.txt in PSX version)
    868894        //
    869895        //     This is simply a text file with CRLF line endings.
    870896        //     '^' is not shown, but used to mark the center of the line.
     
    883909        Common::File f;
    884910        int i;
    885911
     912        spriteInfo.isText = false;
     913
    886914        // Read the "Smacker" logo
    887915
    888916        uint16 logoWidth = 0;
     
    925953        int paragraphStart = 0;
    926954        bool hasCenterMark = false;
    927955
    928         if (!f.open("credits.clu")) {
    929                 warning("Can't find credits.clu");
    930                 return;
     956        if (Sword2Engine::isPsx()) {
     957                if (!f.open("credits.txt")) {
     958                        warning("Can't find credits.txt");
     959                        return;
     960                }
     961        } else {
     962                if (!f.open("credits.clu")) {
     963                        warning("Can't find credits.clu");
     964                        return;
     965                }
    931966        }
    932967
    933968        while (1) {
     
    10881123                                spriteInfo.w = frame.width;
    10891124                                spriteInfo.h = frame.height;
    10901125                                spriteInfo.data = creditsLines[i]->sprite + FrameHeader::size();
     1126                                spriteInfo.isText = true;
    10911127
    10921128                                switch (creditsLines[i]->type) {
    10931129                                case LINE_LEFT:
     
    12141250        barSprite.blend = 0;
    12151251        barSprite.colourTable = 0;
    12161252        barSprite.data = frame + FrameHeader::size();
     1253        barSprite.isText = false;
    12171254
    12181255        drawSprite(&barSprite);
    12191256
     
    12341271        waitForFade();
    12351272}
    12361273
     1274// Following functions are used to manage screen cache for psx version.
     1275
     1276void Screen::setPsxScrCache(byte *psxScrCache, uint8 level) {
     1277                if (level < 3) {
     1278                        if (psxScrCache)
     1279                                _psxCacheEnabled[level] = true;
     1280                        else
     1281                                _psxCacheEnabled[level] = false;
     1282
     1283                        _psxScrCache[level] = psxScrCache;
     1284                }
     1285}
     1286
     1287byte *Screen::getPsxScrCache(uint8 level) {
     1288        if (level > 3) {
     1289                level = 0;
     1290        }
     1291
     1292        if (_psxCacheEnabled[level])
     1293                return _psxScrCache[level];
     1294        else
     1295                return NULL;
     1296}
     1297
     1298bool Screen::getPsxScrCacheStatus(uint8 level) {
     1299        if (level > 3) {
     1300                level = 0;
     1301        }
     1302       
     1303        return _psxCacheEnabled[level];
     1304}
     1305
     1306void Screen::flushPsxScrCache() {
     1307        for (uint8 i = 0; i < 3; i++) {
     1308                free(_psxScrCache[i]);
     1309                _psxScrCache[i] = NULL;
     1310                _psxCacheEnabled[i] = true;
     1311        }
     1312}
     1313
    12371314} // End of namespace Sword2
  • scummvm-bs2psx/engines/sword2/function.cpp

     
    7171
    7272        // params:      0 res id of normal background layer - cannot be 0
    7373        //              1 1 yes 0 no for a new palette
    74 
    75         _vm->_screen->initBackground(params[0], params[1]);
     74       
     75        if (Sword2Engine::isPsx())
     76                _vm->_screen->initPsxBackground(params[0], params[1]);
     77        else
     78                _vm->_screen->initBackground(params[0], params[1]);
    7679        return IR_CONT;
    7780}
    7881
     
    392395        assert(_vm->_resman->fetchType(res) == ANIMATION_FILE);
    393396
    394397        // set up pointer to the animation header
    395         AnimHeader anim_head;
    396 
     398        AnimHeader anim_head;   
     399       
    397400        anim_head.read(_vm->fetchAnimHeader(anim_file));
    398 
     401       
    399402        // set up anim resource in graphic object
    400403        ObjectGraphic obGraph(decodePtr(params[0]));
    401 
     404       
    402405        obGraph.setAnimResource(res);
    403406        obGraph.setAnimPc(params[2] ? anim_head.noAnimFrames - 1 : 0);
    404407
  • scummvm-bs2psx/engines/sword2/resman.cpp

     
    159159
    160160        file.close();
    161161
    162         if (!file.open("cd.inf")) {
     162        // Check that we have cd.inf file, unless we are running PSX
     163        // version, which has all files on one disc.
     164
     165        if (!file.open("cd.inf") && !Sword2Engine::isPsx()) {
    163166                GUIErrorMessage("Broken Sword 2: Cannot open cd.inf");
    164167                return false;
    165168        }
     
    167170        CdInf *cdInf = new CdInf[_totalClusters];
    168171
    169172        for (i = 0; i < _totalClusters; i++) {
    170                 file.read(cdInf[i].clusterName, sizeof(cdInf[i].clusterName));
    171173
    172                 cdInf[i].cd = file.readByte();
     174                if (Sword2Engine::isPsx()) { // We are running PSX version, artificially fill CdInf structure
     175                        cdInf[i].cd = CD1;
     176                } else { // We are running PC version, read cd.inf file
     177                        file.read(cdInf[i].clusterName, sizeof(cdInf[i].clusterName));
    173178
    174                 if (file.ioFailed()) {
    175                         delete cdInf;
    176                         file.close();
    177                         GUIErrorMessage("Broken Sword 2: Cannot read cd.inf");
    178                         return false;
     179                        cdInf[i].cd = file.readByte();
     180
     181                        if (file.ioFailed()) {
     182                                delete cdInf;
     183                                file.close();
     184                                GUIErrorMessage("Broken Sword 2: Cannot read cd.inf");
     185                                return false;
     186                        }
     187
    179188                }
    180189
    181190                // It has been reported that there are two different versions
     
    208217
    209218        file.close();
    210219
    211         for (i = 0; i < _totalClusters; i++) {
    212                 for (j = 0; j < _totalClusters; j++) {
    213                         if (scumm_stricmp((char *)cdInf[j].clusterName, _resFiles[i].fileName) == 0)
    214                                 break;
    215                 }
     220        // We check the presence of resource files in cd.inf
     221        // This is ok in PC version, but in PSX version we don't
     222        // have cd.inf so we'll have to skip this.
     223        if (!Sword2Engine::isPsx()) {
     224                for (i = 0; i < _totalClusters; i++) {
     225                        for (j = 0; j < _totalClusters; j++) {
     226                                if (scumm_stricmp((char *)cdInf[j].clusterName, _resFiles[i].fileName) == 0)
     227                                        break;
     228                        }
    216229
    217                 if (j == _totalClusters) {
    218                         delete[] cdInf;
    219                         GUIErrorMessage(Common::String(_resFiles[i].fileName) + " is not in cd.inf");
    220                         return false;
     230                        if (j == _totalClusters) {
     231                                delete[] cdInf;
     232                                GUIErrorMessage(Common::String(_resFiles[i].fileName) + " is not in cd.inf");
     233                                return false;
     234                        }
     235
     236                        _resFiles[i].cd = cdInf[j].cd;
    221237                }
    222 
    223                 _resFiles[i].cd = cdInf[j].cd;
    224238        }
    225239
    226240        delete[] cdInf;
     
    247261byte *ResourceManager::openResource(uint32 res, bool dump) {
    248262        assert(res < _totalResFiles);
    249263
     264
     265        // FIXME: In PSX edition, not all top menu icons are present (TOP menu is not used).
     266        // Though, at present state, the engine still ask for the resources.
     267        if (Sword2Engine::isPsx()) { // We need to "rewire" missing icons
     268                if (res == 342) res = 364; // Rewire RESTORE ICON to SAVE ICON
     269        }
     270
    250271        // Is the resource in memory already? If not, load it.
    251272
    252273        if (!_resList[res].ptr) {
    253274                // Fetch the correct file and read in the correct portion.
    254275                uint16 cluFileNum = _resConvTable[res * 2]; // points to the number of the ascii filename
     276               
    255277                assert(cluFileNum != 0xffff);
    256278
    257279                // Relative resource within the file
     
    264286                // of the CDs, remember which one so that we can play the
    265287                // correct speech and music.
    266288
    267                 setCD(_resFiles[cluFileNum].cd);
     289                if (Sword2Engine::isPsx()) // We have only one disk in PSX version
     290                        setCD(CD1);
     291                else
     292                        setCD(_resFiles[cluFileNum].cd);
    268293
    269294                // Actually, as long as the file can be found we don't really
    270295                // care which CD it's on. But if we can't find it, keep asking
     
    481506}
    482507
    483508/**
     509 * Fetch resource type
     510 */
     511
     512uint8 ResourceManager::fetchType(byte *ptr) {
     513        if (!Sword2Engine::isPsx()) {
     514                return ptr[0];
     515        } else { // in PSX version, some files got a "garbled" resource header, with type stored in ninth byte
     516                if (ptr[0]) {
     517                        return ptr[0];
     518                } else if (ptr[8]) {
     519                        return ptr[8];
     520                } else  {            // In PSX version there is no resource header for audio files,
     521                        return WAV_FILE; // but hopefully all audio files got first 16 bytes zeroed,
     522                }                    // Allowing us to check for this condition.
     523
     524        }
     525}
     526
     527/**
    484528 * Returns the total file length of a resource - i.e. all headers are included
    485529 * too.
    486530 */
  • scummvm-bs2psx/engines/sword2/sword2.h

     
    120120        bool _useSubtitles;
    121121        int _gameSpeed;
    122122
     123        // Used to trigger GMM Loading
     124        int _gmmLoadSlot;
     125
    123126        StartUp _startList[MAX_starts];
    124127
     128        // We need these to fetch data from SCREENS.CLU, which is
     129        // a resource file with custom format keeping background and
     130        // parallax data (which is removed from multiscreen files).
     131        byte *fetchPsxBackground(uint32 location);
     132        byte *fetchPsxParallax(uint32 location, uint8 level); // level: 0 -> bg, 1 -> fg
     133
    125134        // Original game platform (PC/PSX)
    126135        static Common::Platform _platform;
    127136
     
    150159        bool getSubtitles() { return _useSubtitles; }
    151160        void setSubtitles(bool b) { _useSubtitles = b; }
    152161
     162        // GMM Loading/Saving
     163        Common::Error saveGameState(int slot, const char *desc);
     164        bool canSaveGameStateCurrently();
     165        Common::Error loadGameState(int slot);
     166        bool canLoadGameStateCurrently();       
     167
    153168        uint32 _features;
    154169
    155170        MemoryManager *_memory;
     
    203218        byte *fetchTextLine(byte *file, uint32 text_line);
    204219        bool checkTextLine(byte *file, uint32 text_line);
    205220        byte *fetchPaletteMatchTable(byte *screenFile);
    206 
     221       
    207222        uint32 saveGame(uint16 slotNo, byte *description);
    208223        uint32 restoreGame(uint16 slotNo);
    209224        uint32 getSaveDescription(uint16 slotNo, byte *description);
  • scummvm-bs2psx/engines/sword2/sound.cpp

     
    4747#include "sword2/sound.h"
    4848
    4949#include "sound/wave.h"
     50#include "sound/vag.h"
    5051
    5152namespace Sword2 {
    5253
     
    209210        }
    210211
    211212        byte *data = _vm->_resman->openResource(res);
    212         uint32 len = _vm->_resman->fetchLen(res) - ResHeader::size();
    213 
     213        uint32 len = _vm->_resman->fetchLen(res);
     214       
    214215        assert(_vm->_resman->fetchType(data) == WAV_FILE);
    215         data += ResHeader::size();
     216       
     217        // In PSX version we have nothing to skip here, as data starts right away
     218        if (!Sword2Engine::isPsx()) {
     219                data += ResHeader::size();
     220                len -= ResHeader::size();
     221        }
    216222
    217223        _vm->_sound->playFx(handle, data, len, Audio::Mixer::kMaxChannelVolume, 0, false, Audio::Mixer::kMusicSoundType);
    218224}
     
    263269
    264270                        assert(_vm->_resman->fetchType(data) == WAV_FILE);
    265271
    266                         uint32 len = _vm->_resman->fetchLen(res) - ResHeader::size();
     272                        uint32 len = _vm->_resman->fetchLen(res);
    267273
     274                        // Skip the header if using PC version
     275                        if (!Sword2Engine::isPsx())
     276                                len -= ResHeader::size();
     277
    268278                        if (type == FX_RANDOM) {
    269279                                // For spot effects and loops the delay is the
    270280                                // number of frames to wait. For random
     
    281291                                pan = -pan;
    282292
    283293                        _fxQueue[i].resource = res;
    284                         _fxQueue[i].data = data + ResHeader::size();
     294
     295                        if (Sword2Engine::isPsx())
     296                                _fxQueue[i].data = data;
     297                        else
     298                                _fxQueue[i].data = data + ResHeader::size();
     299                       
    285300                        _fxQueue[i].len = len;
    286301                        _fxQueue[i].delay = delay;
    287302                        _fxQueue[i].volume = volume;
     
    311326        if (_vm->_mixer->isSoundHandleActive(*handle))
    312327                return RDERR_FXALREADYOPEN;
    313328
    314         Common::MemoryReadStream stream(data, len);
     329        Common::MemoryReadStream *stream = new Common::MemoryReadStream(data, len);
    315330        int rate, size;
    316331        byte flags;
    317332
    318         if (!Audio::loadWAVFromStream(stream, size, rate, flags)) {
    319                 warning("playFX: Not a valid WAV file");
    320                 return RDERR_INVALIDWAV;
    321         }
     333        if (Sword2Engine::isPsx()) {
     334                _vm->_mixer->playInputStream(soundType, handle, new Audio::VagStream(stream, loop), -1, vol, pan, true, false, isReverseStereo());
     335        } else {
     336                if (!Audio::loadWAVFromStream(*stream, size, rate, flags)) {
     337                        warning("playFX: Not a valid WAV file");
     338                        return RDERR_INVALIDWAV;
     339                }
    322340
    323         if (isReverseStereo())
    324                 flags |= Audio::Mixer::FLAG_REVERSE_STEREO;
     341                if (isReverseStereo())
     342                        flags |= Audio::Mixer::FLAG_REVERSE_STEREO;
    325343
    326         if (loop)
    327                 flags |= Audio::Mixer::FLAG_LOOP;
     344                if (loop)
     345                        flags |= Audio::Mixer::FLAG_LOOP;
    328346
    329         _vm->_mixer->playRaw(soundType, handle, data + stream.pos(), size, rate, flags, -1, vol, pan, 0, 0);
     347                _vm->_mixer->playRaw(soundType, handle, data + stream->pos(), size, rate, flags, -1, vol, pan, 0, 0);
     348        }
     349
    330350        return RD_OK;
    331351}
    332352
  • scummvm-bs2psx/engines/sword2/mouse.h

     
    7070};
    7171
    7272#define RDMENU_ICONWIDE         35
     73#define RDMENU_PSXICONWIDE      36
    7374#define RDMENU_ICONDEEP         30
    7475#define RDMENU_ICONSTART        24
    7576#define RDMENU_ICONSPACING      5
     
    269270        uint32 chooseMouse();
    270271
    271272        int menuClick(int menu_items);
     273
     274        int getMouseMode();
     275
     276        void setMouseMode(int mouseMode); // Used to force mouse mode
    272277};
    273278
    274279} // End of namespace Sword2
  • scummvm-bs2psx/engines/sword2/logic.cpp

     
    284284                _moviePlayer->pauseMovie(pause);
    285285}
    286286
     287/**
     288 * Read current location number from script vars
     289 */
     290
     291uint32 Logic::getLocationNum() {
     292        return readVar(LOCATION);
     293}
     294
    287295} // End of namespace Sword2
  • scummvm-bs2psx/engines/sword2/header.h

     
    159159        void read(byte *addr) {
    160160                Common::MemoryReadStream readS(addr, size());
    161161
    162                 runTimeComp = readS.readByte();
    163                 noAnimFrames = readS.readUint16LE();
    164                 feetStartX = readS.readUint16LE();
    165                 feetStartY = readS.readUint16LE();
    166                 feetStartDir = readS.readByte();
    167                 feetEndX = readS.readUint16LE();
    168                 feetEndY = readS.readUint16LE();
    169                 feetEndDir = readS.readByte();
    170                 blend = readS.readUint16LE();
     162                if (Sword2Engine::isPsx()) {
     163                        noAnimFrames = readS.readUint16LE();
     164                        feetStartX = readS.readUint16LE();
     165                        feetStartY = readS.readUint16LE();
     166                        feetEndX = readS.readUint16LE();
     167                        feetEndY = readS.readUint16LE();
     168                        blend = readS.readUint16LE();
     169                        runTimeComp = readS.readByte();
     170                        feetStartDir = readS.readByte();
     171                        feetEndDir = readS.readByte(); 
     172                } else {
     173                        runTimeComp = readS.readByte();
     174                        noAnimFrames = readS.readUint16LE();
     175                        feetStartX = readS.readUint16LE();
     176                        feetStartY = readS.readUint16LE();
     177                        feetStartDir = readS.readByte();
     178                        feetEndX = readS.readUint16LE();
     179                        feetEndY = readS.readUint16LE();
     180                        feetEndDir = readS.readByte();
     181                        blend = readS.readUint16LE();
     182                }
    171183        }
    172184
    173185        void write(byte *addr) {
     
    210222                                // corner at (x,y), otherwise see below...
    211223
    212224        static int size() {
    213                 return 9;
     225                if (Sword2Engine::isPsx())
     226                        return 12;
     227                else
     228                        return 9;
    214229        }
    215230
    216231        void read(byte *addr) {
    217232                Common::MemoryReadStream readS(addr, size());
    218233
    219                 x = readS.readUint16LE();
    220                 y = readS.readUint16LE();
    221                 frameOffset = readS.readUint32LE();
    222                 frameType = readS.readByte();
     234                if (Sword2Engine::isPsx()) {
     235                        readS.readByte(); // Skip a byte in psx version
     236                        x = readS.readUint16LE();
     237                        y = readS.readUint16LE();
     238                        frameOffset = readS.readUint32LE();
     239                        frameType = readS.readByte();
     240                } else {
     241                        x = readS.readUint16LE();
     242                        y = readS.readUint16LE();
     243                        frameOffset = readS.readUint32LE();
     244                        frameType = readS.readByte();
     245                }
    223246        }
    224247
    225248        void write(byte *addr) {
     
    260283                compSize = readS.readUint32LE();
    261284                width = readS.readUint16LE();
    262285                height = readS.readUint16LE();
     286
     287                if (Sword2Engine::isPsx()) { // In PSX version, frames are half height
     288                        height *= 2;
     289                        width = (width % 2) ? width + 1 : width;
     290                }
    263291        }
    264292
    265293        void write(byte *addr) {
     
    504532//      line of text,0
    505533//      line of text,0
    506534
     535//----------------------------------------------------------
     536// SCREENS.CLU file
     537//----------------------------------------------------------
     538// This file is present in PSX version of the game only.
     539// It keeps parallax and background images, aligned at 1024 bytes
     540// for faster access by the psx cd drive.
     541//
     542// SCREENS.CLU structure:
     543// In first 2048 Bytes there's an offset table. Each entry is an
     544// 32bit offset for a background/parallax group. If entry is 0, screen
     545// does not exist.
     546// To find matching screen for the location, you must count LOCATION_NO
     547// words and then go to the corresponding offset indicated by last 32bit
     548// word.
     549// Each screen then begins with a PSXScreensEntry entry:
     550
     551struct PSXScreensEntry {
     552        uint16 fgPlxXres; // If these values are 0, subsequent fgPlx* values must be
     553        uint16 fgPlxYres; // ignored, as this means foreground parallax is not present.
     554        uint32 fgPlxOffset; // This offset is relative, counting from the beginning of Resource Header
     555        uint32 fgPlxSize; // Size of parallax, the size is aligned at 1024 bytes.
     556                                          // fgPlxSize/1024 gives number of sector the parallax is divided into.
     557        uint16 bgXres;
     558        uint16 bgYres;
     559        uint32 bgOffset; // relative
     560        uint32 bgSize;
     561        uint16 bgPlxXres; // same considerations for fg parallaxes apply
     562        uint16 bgPlxYres;
     563        uint32 bgPlxOffset; // relative
     564        uint32 bgPlxSize;
     565
     566        static int size() {
     567                return 36;
     568        }
     569
     570        void read(byte *addr) {
     571                Common::MemoryReadStream readS(addr, size());
     572
     573                bgPlxXres = readS.readUint16LE();
     574                bgPlxYres = readS.readUint16LE();
     575                bgPlxOffset = readS.readUint32LE();
     576                bgPlxSize = readS.readUint32LE();
     577                bgXres = readS.readUint16LE();
     578                bgYres = readS.readUint16LE();
     579                bgOffset = readS.readUint32LE();
     580                bgSize = readS.readUint32LE();
     581                fgPlxXres = readS.readUint16LE();
     582                fgPlxYres = readS.readUint16LE();
     583                fgPlxOffset = readS.readUint32LE();
     584                fgPlxSize = readS.readUint32LE();
     585        }
     586
     587        void write(byte *addr) {
     588                Common::MemoryWriteStream writeS(addr, size());
     589
     590                writeS.writeUint16LE(bgPlxXres);
     591                writeS.writeUint16LE(bgPlxYres);
     592                writeS.writeUint32LE(bgPlxOffset);
     593                writeS.writeUint32LE(bgPlxSize);
     594                writeS.writeUint16LE(bgXres);
     595                writeS.writeUint16LE(bgYres);
     596                writeS.writeUint32LE(bgOffset);
     597                writeS.writeUint32LE(bgSize);
     598                writeS.writeUint16LE(fgPlxXres);
     599                writeS.writeUint16LE(fgPlxYres);
     600                writeS.writeUint32LE(fgPlxOffset);
     601                writeS.writeUint32LE(fgPlxSize);
     602        }
     603};
     604
     605// PSXFontEntry is present in font resource file, it is used
     606// to address a single char in the character atlas image.
     607
     608struct PSXFontEntry {
     609        uint16 offset;
     610        uint16 skipLines;
     611        uint16 charWidth;
     612        uint16 charHeight;
     613
     614        static int size() {
     615                return 8;
     616        }
     617
     618        void read(byte *addr) {
     619                Common::MemoryReadStream readS(addr, size());
     620
     621                offset = readS.readUint16LE() / 2;
     622                skipLines = readS.readUint16LE();
     623                charWidth = readS.readUint16LE() / 2;
     624                charHeight = readS.readUint16LE();
     625        }
     626
     627        void write(byte *addr) {
     628                Common::MemoryWriteStream writeS(addr, size());
     629
     630                writeS.writeUint16LE(offset);
     631                writeS.writeUint16LE(skipLines);
     632                writeS.writeUint16LE(charWidth);
     633                writeS.writeUint16LE(charHeight);
     634        }       
     635};
     636
    507637} // End of namespace Sword2
    508638
    509639#endif