mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-17 23:44:22 +00:00
parent
c62834cc0c
commit
5aa50ec889
@ -271,6 +271,7 @@ const PlatformDescription g_platforms[] = {
|
||||
{"nes", "nes", "nes", "NES", kPlatformNES},
|
||||
{"segacd", "segacd", "sega", "SegaCD", kPlatformSegaCD},
|
||||
{"windows", "win", "win", "Windows", kPlatformWindows},
|
||||
{"playstation", "psx", "PSX", "Playstation", kPlatformPSX},
|
||||
|
||||
|
||||
{0, 0, 0, "Default", kPlatformUnknown}
|
||||
|
@ -201,6 +201,7 @@ enum Platform {
|
||||
kPlatformApple2GS,
|
||||
kPlatformPC98,
|
||||
kPlatformWii,
|
||||
kPlatformPSX,
|
||||
|
||||
kPlatformUnknown = -1
|
||||
};
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "sword1/sword1.h"
|
||||
#include "sword1/sworddefs.h"
|
||||
#include "sword1/swordres.h"
|
||||
#include "sword1/screen.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
@ -120,10 +121,11 @@ ControlButton::ControlButton(uint16 x, uint16 y, uint32 resId, uint8 id, uint8 f
|
||||
_resMan->resOpen(_resId);
|
||||
FrameHeader *tmp = _resMan->fetchFrame(_resMan->fetchRes(_resId), 0);
|
||||
_width = _resMan->getUint16(tmp->width);
|
||||
_width = (_width > SCREEN_WIDTH) ? SCREEN_WIDTH : _width;
|
||||
_height = _resMan->getUint16(tmp->height);
|
||||
if ((x == 0) && (y == 0)) { // center the frame (used for panels);
|
||||
_x = (640 - _width) / 2;
|
||||
_y = (480 - _height) / 2;
|
||||
_x = (((640 - _width) / 2) < 0)? 0 : ((640 - _width) / 2) ;
|
||||
_y = (((480 - _height) / 2) < 0)? 0 : ((480 - _height) / 2);
|
||||
}
|
||||
_dstBuf = screenBuf + _y * SCREEN_WIDTH + _x;
|
||||
_system = system;
|
||||
@ -141,13 +143,78 @@ void ControlButton::draw(void) {
|
||||
FrameHeader *fHead = _resMan->fetchFrame(_resMan->fetchRes(_resId), _frameIdx);
|
||||
uint8 *src = (uint8*)fHead + sizeof(FrameHeader);
|
||||
uint8 *dst = _dstBuf;
|
||||
for (uint16 cnt = 0; cnt < _resMan->readUint16(&fHead->height); cnt++) {
|
||||
for (uint16 cntx = 0; cntx < _resMan->readUint16(&fHead->width); cntx++)
|
||||
if (src[cntx])
|
||||
dst[cntx] = src[cntx];
|
||||
dst += SCREEN_WIDTH;
|
||||
src += _resMan->readUint16(&fHead->width);
|
||||
}
|
||||
|
||||
if (SwordEngine::isPsx() && _resId) {
|
||||
uint8 *HIFbuf = (uint8*)malloc(_resMan->readUint16(&fHead->height) * _resMan->readUint16(&fHead->width));
|
||||
memset(HIFbuf, 0, _resMan->readUint16(&fHead->height) * _resMan->readUint16(&fHead->width));
|
||||
Screen::decompressHIF(src, HIFbuf);
|
||||
src = HIFbuf;
|
||||
|
||||
if (_resMan->readUint16(&fHead->width) < 300)
|
||||
for (uint16 cnt = 0; cnt < _resMan->readUint16(&fHead->height); cnt++) {
|
||||
for (uint16 cntx = 0; cntx < _resMan->readUint16(&fHead->width); cntx++)
|
||||
if (src[cntx])
|
||||
dst[cntx] = src[cntx];
|
||||
|
||||
dst += SCREEN_WIDTH;
|
||||
for (uint16 cntx = 0; cntx < _resMan->readUint16(&fHead->width); cntx++)
|
||||
if (src[cntx])
|
||||
dst[cntx] = src[cntx];
|
||||
|
||||
dst += SCREEN_WIDTH;
|
||||
src += _resMan->readUint16(&fHead->width);
|
||||
}
|
||||
else if (_resId == SR_DEATHPANEL) { //Hardcoded goodness for death panel psx version
|
||||
for (uint16 cnt = 0; cnt < _resMan->readUint16(&fHead->height)/2; cnt++) {
|
||||
//Stretched panel is bigger than 640px, check we don't draw outside screen
|
||||
for (uint16 cntx = 0; (cntx < (_resMan->readUint16(&fHead->width))/3) && (cntx < (SCREEN_WIDTH-3) ); cntx++)
|
||||
if (src[cntx]) {
|
||||
dst[cntx * 3] = src[cntx];
|
||||
dst[cntx * 3 + 1] = src[cntx];
|
||||
dst[cntx * 3 + 2] = src[cntx];
|
||||
}
|
||||
dst+= SCREEN_WIDTH;
|
||||
|
||||
for (uint16 cntx = 0; cntx < (_resMan->readUint16(&fHead->width))/3; cntx++)
|
||||
if (src[cntx]) {
|
||||
dst[cntx * 3] = src[cntx];
|
||||
dst[cntx * 3 + 1] = src[cntx];
|
||||
dst[cntx * 3 + 2] = src[cntx];
|
||||
}
|
||||
dst += SCREEN_WIDTH;
|
||||
src += _resMan->readUint16(&fHead->width)/3;
|
||||
}
|
||||
} else { //NASTY HACK, save slots needs to be multiplied my 4 in height... need a better way to identify these images
|
||||
for (uint16 cnt = 0; cnt < _resMan->readUint16(&fHead->height); cnt++) {
|
||||
for (uint16 cntx = 0; cntx < _resMan->readUint16(&fHead->width) / 2; cntx++)
|
||||
if (src[cntx]) {
|
||||
dst[cntx * 2] = src[cntx];
|
||||
dst[cntx * 2 + 1] = src[cntx];
|
||||
}
|
||||
|
||||
dst += SCREEN_WIDTH;
|
||||
for (uint16 cntx = 0; cntx < _resMan->readUint16(&fHead->width) / 2; cntx++)
|
||||
if (src[cntx]) {
|
||||
dst[cntx * 2] = src[cntx];
|
||||
dst[cntx * 2 + 1] = src[cntx];
|
||||
}
|
||||
|
||||
dst += SCREEN_WIDTH;
|
||||
src += _resMan->readUint16(&fHead->width)/2;
|
||||
}
|
||||
}
|
||||
|
||||
free(HIFbuf);
|
||||
} else
|
||||
for (uint16 cnt = 0; cnt < _resMan->readUint16(&fHead->height); cnt++) {
|
||||
for (uint16 cntx = 0; cntx < _resMan->readUint16(&fHead->width); cntx++)
|
||||
if (src[cntx])
|
||||
dst[cntx] = src[cntx];
|
||||
|
||||
dst += SCREEN_WIDTH;
|
||||
src += _resMan->readUint16(&fHead->width);
|
||||
}
|
||||
|
||||
_system->copyRectToScreen(_dstBuf, SCREEN_WIDTH, _x, _y, _width, _height);
|
||||
}
|
||||
|
||||
@ -940,17 +1007,37 @@ void Control::renderText(const uint8 *str, uint16 x, uint16 y, uint8 mode) {
|
||||
|
||||
FrameHeader *chSpr = _resMan->fetchFrame(font, *str - 32);
|
||||
uint8 *sprData = (uint8*)chSpr + sizeof(FrameHeader);
|
||||
uint8 *HIFbuf = NULL;
|
||||
|
||||
if (SwordEngine::isPsx()) { //Text fonts are compressed in psx version
|
||||
HIFbuf = (uint8 *)malloc(_resMan->getUint16(chSpr->height) * _resMan->getUint16(chSpr->width));
|
||||
memset(HIFbuf, 0, _resMan->getUint16(chSpr->height) * _resMan->getUint16(chSpr->width));
|
||||
Screen::decompressHIF(sprData, HIFbuf);
|
||||
sprData = HIFbuf;
|
||||
}
|
||||
|
||||
for (uint16 cnty = 0; cnty < _resMan->getUint16(chSpr->height); cnty++) {
|
||||
for (uint16 cntx = 0; cntx < _resMan->getUint16(chSpr->width); cntx++) {
|
||||
if (sprData[cntx])
|
||||
dst[cntx] = sprData[cntx];
|
||||
}
|
||||
|
||||
if(SwordEngine::isPsx()) { //On PSX version we need to double horizontal lines
|
||||
dst += SCREEN_WIDTH;
|
||||
for (uint16 cntx = 0; cntx < _resMan->getUint16(chSpr->width); cntx++)
|
||||
if (sprData[cntx])
|
||||
dst[cntx] = sprData[cntx];
|
||||
}
|
||||
|
||||
sprData += _resMan->getUint16(chSpr->width);
|
||||
dst += SCREEN_WIDTH;
|
||||
}
|
||||
destX += _resMan->getUint16(chSpr->width) - 3;
|
||||
str++;
|
||||
|
||||
free(HIFbuf);
|
||||
}
|
||||
|
||||
_system->copyRectToScreen(_screenBuf + y * SCREEN_WIDTH + x, SCREEN_WIDTH, x, y, (destX - x) + 3, 28);
|
||||
}
|
||||
|
||||
@ -963,14 +1050,34 @@ void Control::renderVolumeBar(uint8 id, uint8 volL, uint8 volR) {
|
||||
FrameHeader *frHead = _resMan->fetchFrame(_resMan->openFetchRes(SR_VLIGHT), (vol + 15) >> 4);
|
||||
uint8 *destMem = _screenBuf + destY * SCREEN_WIDTH + destX;
|
||||
uint8 *srcMem = (uint8*)frHead + sizeof(FrameHeader);
|
||||
for (uint16 cnty = 0; cnty < _resMan->getUint16(frHead->height); cnty++) {
|
||||
uint16 barHeight = _resMan->getUint16(frHead->height);
|
||||
uint8 *psxVolBuf = NULL;
|
||||
|
||||
if (SwordEngine::isPsx()) {
|
||||
psxVolBuf = (uint8 *)malloc(_resMan->getUint16(frHead->height) / 2 * _resMan->getUint16(frHead->width));
|
||||
memset(psxVolBuf, 0, _resMan->getUint16(frHead->height) / 2 * _resMan->getUint16(frHead->width));
|
||||
Screen::decompressHIF(srcMem, psxVolBuf);
|
||||
srcMem = psxVolBuf;
|
||||
barHeight /= 2;
|
||||
}
|
||||
|
||||
for (uint16 cnty = 0; cnty < barHeight; cnty++) {
|
||||
memcpy(destMem, srcMem, _resMan->getUint16(frHead->width));
|
||||
|
||||
if(SwordEngine::isPsx()) { //linedoubling
|
||||
destMem += SCREEN_WIDTH;
|
||||
memcpy(destMem, srcMem, _resMan->getUint16(frHead->width));
|
||||
}
|
||||
|
||||
srcMem += _resMan->getUint16(frHead->width);
|
||||
destMem += SCREEN_WIDTH;
|
||||
}
|
||||
|
||||
_system->copyRectToScreen(_screenBuf + destY * SCREEN_WIDTH + destX, SCREEN_WIDTH, destX, destY, _resMan->getUint16(frHead->width), _resMan->getUint16(frHead->height));
|
||||
_resMan->resClose(SR_VLIGHT);
|
||||
destX += 32;
|
||||
|
||||
free(psxVolBuf);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,8 @@ static const PlainGameDescriptor sword1MacFullSettings =
|
||||
{"sword1mac", "Broken Sword 1: The Shadow of the Templars (Mac)"};
|
||||
static const PlainGameDescriptor sword1MacDemoSettings =
|
||||
{"sword1macdemo", "Broken Sword 1: The Shadow of the Templars (Mac demo)"};
|
||||
static const PlainGameDescriptor sword1PSXSettings =
|
||||
{"sword1psx", "Broken Sword 1: The Shadow of the Templars (PlayStation)"};
|
||||
|
||||
// check these subdirectories (if present)
|
||||
static const char *g_dirNames[] = { "clusters", "speech" };
|
||||
@ -52,20 +54,23 @@ static const char *g_dirNames[] = { "clusters", "speech" };
|
||||
#define NUM_COMMON_FILES_TO_CHECK 1
|
||||
#define NUM_PC_FILES_TO_CHECK 3
|
||||
#define NUM_MAC_FILES_TO_CHECK 4
|
||||
#define NUM_PSX_FILES_TO_CHECK 2
|
||||
#define NUM_DEMO_FILES_TO_CHECK 1
|
||||
#define NUM_MAC_DEMO_FILES_TO_CHECK 1
|
||||
#define NUM_FILES_TO_CHECK NUM_COMMON_FILES_TO_CHECK + NUM_PC_FILES_TO_CHECK + NUM_MAC_FILES_TO_CHECK + NUM_DEMO_FILES_TO_CHECK + NUM_MAC_DEMO_FILES_TO_CHECK
|
||||
#define NUM_FILES_TO_CHECK NUM_COMMON_FILES_TO_CHECK + NUM_PC_FILES_TO_CHECK + NUM_MAC_FILES_TO_CHECK + NUM_PSX_FILES_TO_CHECK + NUM_DEMO_FILES_TO_CHECK + NUM_MAC_DEMO_FILES_TO_CHECK
|
||||
static const char *g_filesToCheck[NUM_FILES_TO_CHECK] = { // these files have to be found
|
||||
"swordres.rif", // Mac and PC version
|
||||
"general.clu", // PC version only
|
||||
"compacts.clu", // PC version only
|
||||
"scripts.clu", // PC version only
|
||||
"swordres.rif", // Mac, PC and PSX version
|
||||
"general.clu", // PC and PSX version
|
||||
"compacts.clu", // PC and PSX version
|
||||
"scripts.clu", // PC and PSX version
|
||||
"general.clm", // Mac version only
|
||||
"compacts.clm", // Mac version only
|
||||
"scripts.clm", // Mac version only
|
||||
"paris2.clm", // Mac version (full game only)
|
||||
"cows.mad", // this one should only exist in the demo version
|
||||
"scripts.clm", // Mac version both demo and full game
|
||||
"speech.dat", // PSX version only
|
||||
"tunes.dat", // PSX version only
|
||||
// the engine needs several more files to work, but checking these should be sufficient
|
||||
};
|
||||
|
||||
@ -123,6 +128,8 @@ GameDescriptor SwordMetaEngine::findGame(const char *gameid) const {
|
||||
return sword1MacFullSettings;
|
||||
if (0 == scumm_stricmp(gameid, sword1MacDemoSettings.gameid))
|
||||
return sword1MacDemoSettings;
|
||||
if (0 == scumm_stricmp(gameid, sword1PSXSettings.gameid))
|
||||
return sword1PSXSettings;
|
||||
return GameDescriptor();
|
||||
}
|
||||
|
||||
@ -157,6 +164,7 @@ GameList SwordMetaEngine::detectGames(const Common::FSList &fslist) const {
|
||||
bool macFilesFound = true;
|
||||
bool demoFilesFound = true;
|
||||
bool macDemoFilesFound = true;
|
||||
bool psxFilesFound = true;
|
||||
for (i = 0; i < NUM_COMMON_FILES_TO_CHECK; i++)
|
||||
if (!filesFound[i])
|
||||
mainFilesFound = false;
|
||||
@ -172,10 +180,15 @@ GameList SwordMetaEngine::detectGames(const Common::FSList &fslist) const {
|
||||
for (j = 0; j < NUM_DEMO_FILES_TO_CHECK; i++, j++)
|
||||
if (!filesFound[i])
|
||||
macDemoFilesFound = false;
|
||||
for (j = 0; j < NUM_PSX_FILES_TO_CHECK; i++, j++)
|
||||
if (!filesFound[i])
|
||||
psxFilesFound = false;
|
||||
|
||||
if (mainFilesFound && pcFilesFound && demoFilesFound)
|
||||
detectedGames.push_back(sword1DemoSettings);
|
||||
else if (mainFilesFound && pcFilesFound)
|
||||
else if (mainFilesFound && pcFilesFound && psxFilesFound)
|
||||
detectedGames.push_back(sword1PSXSettings);
|
||||
else if (mainFilesFound && pcFilesFound && !psxFilesFound)
|
||||
detectedGames.push_back(sword1FullSettings);
|
||||
else if (mainFilesFound && macFilesFound)
|
||||
detectedGames.push_back(sword1MacFullSettings);
|
||||
|
@ -112,6 +112,10 @@ void Logic::newScreen(uint32 screen) {
|
||||
fnFullSetFrame(cpt, SAND_25, IMPPLSCDT, IMPPLS, 0, 0, 0, 0); // impression filled with plaster
|
||||
}
|
||||
|
||||
// work around, at screen 69 in psx version TOP menu gets stuck at disabled, fix it at next screen (71)
|
||||
if( (screen == 71) && (SwordEngine::isPsx()))
|
||||
_scriptVars[TOP_MENU_DISABLED] = 0;
|
||||
|
||||
if (SwordEngine::_systemVars.justRestoredGame) { // if we've just restored a game - we want George to be exactly as saved
|
||||
fnAddHuman(NULL, 0, 0, 0, 0, 0, 0, 0);
|
||||
if (_scriptVars[GEORGE_WALKING]) { // except that if George was walking when we saveed the game
|
||||
|
@ -18,7 +18,8 @@ MODULE_OBJS := \
|
||||
sound.o \
|
||||
staticres.o \
|
||||
sword1.o \
|
||||
text.o
|
||||
text.o \
|
||||
vag.o
|
||||
|
||||
# This module can be built as a plugin
|
||||
ifeq ($(ENABLE_SWORD1), DYNAMIC_PLUGIN)
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "sword1/sworddefs.h"
|
||||
#include "sword1/swordres.h"
|
||||
#include "sword1/menu.h"
|
||||
#include "sword1/sword1.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
@ -201,13 +202,30 @@ void Mouse::createPointer(uint32 ptrId, uint32 luggageId) {
|
||||
if (ptrId) {
|
||||
MousePtr *lugg = NULL;
|
||||
MousePtr *ptr = (MousePtr*)_resMan->openFetchRes(ptrId);
|
||||
uint16 resSizeX = _resMan->getLEUint16(ptr->sizeX);
|
||||
uint16 resSizeY = _resMan->getLEUint16(ptr->sizeY);
|
||||
uint16 noFrames = _resMan->getLEUint16(ptr->numFrames);
|
||||
uint16 ptrSizeX = _resMan->getLEUint16(ptr->sizeX);
|
||||
uint16 ptrSizeY = _resMan->getLEUint16(ptr->sizeY);
|
||||
uint16 luggSizeX;
|
||||
uint16 luggSizeY;
|
||||
uint16 resSizeX;
|
||||
uint16 resSizeY;
|
||||
|
||||
if (SwordEngine::isPsx()) //PSX pointers are half height
|
||||
ptrSizeY *= 2;
|
||||
|
||||
if (luggageId) {
|
||||
lugg = (MousePtr*)_resMan->openFetchRes(luggageId);
|
||||
resSizeX = MAX(resSizeX, (uint16)((resSizeX / 2) + _resMan->getLEUint16(lugg->sizeX)));
|
||||
resSizeY = MAX(resSizeY, (uint16)((resSizeY / 2) + _resMan->getLEUint16(lugg->sizeY)));
|
||||
luggSizeX = _resMan->getLEUint16(lugg->sizeX);
|
||||
luggSizeY = _resMan->getLEUint16(lugg->sizeY);
|
||||
|
||||
if (SwordEngine::isPsx())
|
||||
luggSizeY *= 2;
|
||||
|
||||
resSizeX = MAX(ptrSizeX, (uint16)((ptrSizeX / 2) + luggSizeX));
|
||||
resSizeY = MAX(ptrSizeY, (uint16)((ptrSizeY / 2) + luggSizeY));
|
||||
} else {
|
||||
resSizeX = ptrSizeX;
|
||||
resSizeY = ptrSizeY;
|
||||
}
|
||||
_currentPtr = (MousePtr*)malloc(sizeof(MousePtr) + resSizeX * resSizeY * noFrames);
|
||||
_currentPtr->hotSpotX = _resMan->getLEUint16(ptr->hotSpotX);
|
||||
@ -218,31 +236,48 @@ void Mouse::createPointer(uint32 ptrId, uint32 luggageId) {
|
||||
uint8 *ptrData = (uint8*)_currentPtr + sizeof(MousePtr);
|
||||
memset(ptrData, 255, resSizeX * resSizeY * noFrames);
|
||||
if (luggageId) {
|
||||
uint8 *dstData = ptrData + resSizeX - _resMan->getLEUint16(lugg->sizeX);
|
||||
uint8 *dstData = ptrData + resSizeX - luggSizeX;
|
||||
for (uint32 frameCnt = 0; frameCnt < noFrames; frameCnt++) {
|
||||
uint8 *luggSrc = (uint8*)lugg + sizeof(MousePtr);
|
||||
dstData += (resSizeY - _resMan->getLEUint16(lugg->sizeY)) * resSizeX;
|
||||
for (uint32 cnty = 0; cnty < _resMan->getLEUint16(lugg->sizeY); cnty++) {
|
||||
for (uint32 cntx = 0; cntx < _resMan->getLEUint16(lugg->sizeX); cntx++)
|
||||
dstData += (resSizeY - luggSizeY) * resSizeX;
|
||||
for (uint32 cnty = 0; cnty < (SwordEngine::isPsx() ? luggSizeY / 2 : luggSizeY); cnty++) {
|
||||
for (uint32 cntx = 0; cntx < luggSizeX; cntx++)
|
||||
if (luggSrc[cntx])
|
||||
dstData[cntx] = luggSrc[cntx];
|
||||
|
||||
if(SwordEngine::isPsx()) {
|
||||
dstData += resSizeX;
|
||||
for (uint32 cntx = 0; cntx < luggSizeX; cntx++)
|
||||
if (luggSrc[cntx])
|
||||
dstData[cntx] = luggSrc[cntx];
|
||||
}
|
||||
|
||||
dstData += resSizeX;
|
||||
luggSrc += _resMan->getLEUint16(lugg->sizeX);
|
||||
luggSrc += luggSizeX;
|
||||
}
|
||||
}
|
||||
_resMan->resClose(luggageId);
|
||||
}
|
||||
|
||||
uint8 *dstData = ptrData;
|
||||
uint8 *srcData = (uint8*)ptr + sizeof(MousePtr);
|
||||
for (uint32 frameCnt = 0; frameCnt < noFrames; frameCnt++) {
|
||||
for (uint32 cnty = 0; cnty < _resMan->getLEUint16(ptr->sizeY); cnty++) {
|
||||
for (uint32 cntx = 0; cntx < _resMan->getLEUint16(ptr->sizeX); cntx++)
|
||||
for (uint32 cnty = 0; cnty < (SwordEngine::isPsx() ? ptrSizeY / 2 : ptrSizeY); cnty++) {
|
||||
for (uint32 cntx = 0; cntx < ptrSizeX; cntx++)
|
||||
if (srcData[cntx])
|
||||
dstData[cntx] = srcData[cntx];
|
||||
srcData += _resMan->getLEUint16(ptr->sizeX);
|
||||
|
||||
if(SwordEngine::isPsx()) {
|
||||
dstData +=resSizeX;
|
||||
for (uint32 cntx = 0; cntx < ptrSizeX; cntx++)
|
||||
if (srcData[cntx])
|
||||
dstData[cntx] = srcData[cntx];
|
||||
}
|
||||
|
||||
srcData += ptrSizeX;
|
||||
dstData += resSizeX;
|
||||
}
|
||||
dstData += (resSizeY - _resMan->getLEUint16(ptr->sizeY)) * resSizeX;
|
||||
dstData += (resSizeY - ptrSizeY) * resSizeX;
|
||||
}
|
||||
_resMan->resClose(ptrId);
|
||||
}
|
||||
|
@ -29,7 +29,10 @@
|
||||
#include "common/util.h"
|
||||
#include "common/system.h"
|
||||
|
||||
#include "sword1/sword1.h"
|
||||
#include "sword1/music.h"
|
||||
#include "sword1/vag.h"
|
||||
|
||||
#include "sound/aiff.h"
|
||||
#include "sound/flac.h"
|
||||
#include "sound/mixer.h"
|
||||
@ -252,6 +255,35 @@ bool MusicHandle::play(const char *fileBase, bool loop) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MusicHandle::playPSX(uint16 id, bool loop) {
|
||||
stop();
|
||||
|
||||
if (!_file.isOpen())
|
||||
if (!_file.open("tunes.dat"))
|
||||
return false;
|
||||
|
||||
Common::File tableFile;
|
||||
if (!tableFile.open("tunes.tab"))
|
||||
return false;
|
||||
|
||||
tableFile.seek((id - 1) * 8, SEEK_SET);
|
||||
uint32 offset = tableFile.readUint32LE() * 0x800;
|
||||
uint32 size = tableFile.readUint32LE();
|
||||
|
||||
tableFile.close();
|
||||
|
||||
if (size != 0xffffffff) {
|
||||
_file.seek(offset, SEEK_SET);
|
||||
_audioSource = new VagStream(_file.readStream(size), loop);
|
||||
fadeUp();
|
||||
} else {
|
||||
_audioSource = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MusicHandle::fadeDown() {
|
||||
if (streaming()) {
|
||||
if (_fading < 0)
|
||||
@ -276,8 +308,7 @@ bool MusicHandle::endOfData() const {
|
||||
return !streaming();
|
||||
}
|
||||
|
||||
// is we don't have an audiosource, return some dummy values.
|
||||
// shouldn't happen anyways.
|
||||
// if we don't have an audiosource, return some dummy values.
|
||||
bool MusicHandle::streaming(void) const {
|
||||
return (_audioSource) ? (!_audioSource->endOfStream()) : false;
|
||||
}
|
||||
@ -411,7 +442,13 @@ void Music::startMusic(int32 tuneId, int32 loopFlag) {
|
||||
/* The handle will load the music file now. It can take a while, so unlock
|
||||
the mutex before, to have the soundthread playing normally.
|
||||
As the corresponding _converter is NULL, the handle will be ignored by the playing thread */
|
||||
if (_handles[newStream].play(_tuneList[tuneId], loopFlag != 0)) {
|
||||
if (SwordEngine::isPsx()) { ;
|
||||
if (_handles[newStream].playPSX(tuneId, loopFlag != 0)) {
|
||||
_mutex.lock();
|
||||
_converter[newStream] = Audio::makeRateConverter(_handles[newStream].getRate(), _mixer->getOutputRate(), _handles[newStream].isStereo(), false);
|
||||
_mutex.unlock();
|
||||
}
|
||||
} else if (_handles[newStream].play(_tuneList[tuneId], loopFlag != 0)) {
|
||||
_mutex.lock();
|
||||
_converter[newStream] = Audio::makeRateConverter(_handles[newStream].getRate(), _mixer->getOutputRate(), _handles[newStream].isStereo(), false);
|
||||
_mutex.unlock();
|
||||
|
@ -47,6 +47,7 @@ public:
|
||||
MusicHandle() : _fading(0), _audioSource(NULL) {}
|
||||
virtual int readBuffer(int16 *buffer, const int numSamples);
|
||||
bool play(const char *filename, bool loop);
|
||||
bool playPSX(uint16 id, bool loop);
|
||||
void stop();
|
||||
void fadeUp();
|
||||
void fadeDown();
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "sword1/resman.h"
|
||||
#include "sword1/objectman.h"
|
||||
#include "sword1/menu.h"
|
||||
#include "sword1/swordres.h"
|
||||
#include "sword1/sword1.h"
|
||||
|
||||
#ifdef BACKEND_8BIT
|
||||
@ -137,7 +138,7 @@ void Screen::fnSetPalette(uint8 start, uint16 length, uint32 id, bool fadeUp) {
|
||||
if (start == 0) // force color 0 to black
|
||||
palData[0] = palData[1] = palData[2] = 0;
|
||||
|
||||
if (SwordEngine::_systemVars.isMac) { // see bug #1701058
|
||||
if (SwordEngine::isMac()) { // see bug #1701058
|
||||
if (start != 0 && start + length == 256) // and force color 255 to black as well
|
||||
palData[(length-1)*3+0] = palData[(length-1)*3+1] = palData[(length-1)*3+2] = 0;
|
||||
}
|
||||
@ -358,24 +359,45 @@ void Screen::quitScreen(void) {
|
||||
|
||||
void Screen::draw(void) {
|
||||
uint8 cnt;
|
||||
|
||||
debug(8, "Screen::draw() -> _currentScreen %u", _currentScreen);
|
||||
|
||||
if (_currentScreen == 54) {
|
||||
// rm54 has a BACKGROUND parallax layer in parallax[0]
|
||||
if (_parallax[0])
|
||||
if (_parallax[0] && !SwordEngine::isPsx() ) //Avoid drawing this parallax on PSX edition, it gets occluded by background
|
||||
renderParallax(_parallax[0]);
|
||||
uint8 *src = _layerBlocks[0];
|
||||
uint8 *dest = _screenBuf;
|
||||
uint8 *indxScreen = NULL;
|
||||
|
||||
if(SwordEngine::isPsx()) {
|
||||
indxScreen = psxShrinkedBackgroundToIndexed(_layerBlocks[0], _scrnSizeX, _scrnSizeY);
|
||||
src = indxScreen;
|
||||
}
|
||||
|
||||
for (uint16 cnty = 0; cnty < _scrnSizeY; cnty++)
|
||||
for (uint16 cntx = 0; cntx < _scrnSizeX; cntx++) {
|
||||
if (*src)
|
||||
if (!SwordEngine::_systemVars.isMac || *src != 255) // see bug #1701058
|
||||
if (!(SwordEngine::isMac()) || *src != 255) // see bug #1701058
|
||||
*dest = *src;
|
||||
dest++;
|
||||
src++;
|
||||
}
|
||||
|
||||
} else
|
||||
free(indxScreen);
|
||||
|
||||
} else if (!(SwordEngine::isPsx())) {
|
||||
memcpy(_screenBuf, _layerBlocks[0], _scrnSizeX * _scrnSizeY);
|
||||
} else { //We are using PSX version
|
||||
uint8 *indxScreen;
|
||||
if(_currentScreen == 45 || _currentScreen == 55 ||
|
||||
_currentScreen == 57 || _currentScreen == 63 || _currentScreen == 71) // Width shrinked backgrounds
|
||||
indxScreen = psxShrinkedBackgroundToIndexed(_layerBlocks[0], _scrnSizeX, _scrnSizeY);
|
||||
else
|
||||
indxScreen = psxBackgroundToIndexed(_layerBlocks[0], _scrnSizeX, _scrnSizeY);
|
||||
memcpy(_screenBuf, indxScreen, _scrnSizeX * _scrnSizeY);
|
||||
free(indxScreen);
|
||||
}
|
||||
|
||||
for (cnt = 0; cnt < _backLength; cnt++)
|
||||
processImage(_backList[cnt]);
|
||||
@ -393,6 +415,18 @@ void Screen::draw(void) {
|
||||
if (_parallax[1])
|
||||
renderParallax(_parallax[1]);
|
||||
|
||||
// PSX version has parallax layer for this room in an external file (TRAIN.PLX)
|
||||
if(SwordEngine::isPsx() && _currentScreen == 63) {
|
||||
Common::File parallax;
|
||||
uint8 *trainPLX = NULL;
|
||||
parallax.open("TRAIN.PLX");
|
||||
trainPLX = (uint8*) malloc(parallax.size());
|
||||
parallax.read(trainPLX, parallax.size());
|
||||
parallax.close();
|
||||
renderParallax(trainPLX);
|
||||
free(trainPLX);
|
||||
}
|
||||
|
||||
for (cnt = 0; cnt < _foreLength; cnt++)
|
||||
processImage(_foreList[cnt]);
|
||||
|
||||
@ -403,8 +437,9 @@ void Screen::processImage(uint32 id) {
|
||||
Object *compact;
|
||||
FrameHeader *frameHead;
|
||||
int scale;
|
||||
|
||||
|
||||
compact = _objMan->fetchObject(id);
|
||||
|
||||
if (compact->o_type == TYPE_TEXT)
|
||||
frameHead = _textMan->giveSpriteData((uint8)compact->o_target);
|
||||
else
|
||||
@ -414,6 +449,7 @@ void Screen::processImage(uint32 id) {
|
||||
|
||||
uint16 spriteX = compact->o_anim_x;
|
||||
uint16 spriteY = compact->o_anim_y;
|
||||
|
||||
if (compact->o_status & STAT_SHRINK) {
|
||||
scale = (compact->o_scale_a * compact->o_ycoord + compact->o_scale_b) / 256;
|
||||
spriteX += ((int16)_resMan->readUint16(&frameHead->offsetX) * scale) / 256;
|
||||
@ -425,7 +461,13 @@ void Screen::processImage(uint32 id) {
|
||||
}
|
||||
|
||||
uint8 *tonyBuf = NULL;
|
||||
if (frameHead->runTimeComp[3] == '7') { // RLE7 encoded?
|
||||
uint8 *hifBuf = NULL;
|
||||
if (SwordEngine::isPsx() && compact->o_type != TYPE_TEXT) { // PSX sprites are compressed with HIF
|
||||
hifBuf = (uint8*)malloc(_resMan->readUint16(&frameHead->width) * _resMan->readUint16(&frameHead->height)/2);
|
||||
memset(hifBuf, 0x00, (_resMan->readUint16(&frameHead->width) * _resMan->readUint16(&frameHead->height)/2));
|
||||
decompressHIF(sprData, hifBuf);
|
||||
sprData = hifBuf;
|
||||
} else if (frameHead->runTimeComp[3] == '7') { // RLE7 encoded?
|
||||
decompressRLE7(sprData, _resMan->readUint32(&frameHead->compSize), _rleBuffer);
|
||||
sprData = _rleBuffer;
|
||||
} else if (frameHead->runTimeComp[3] == '0') { // RLE0 encoded?
|
||||
@ -439,14 +481,29 @@ void Screen::processImage(uint32 id) {
|
||||
|
||||
uint16 sprSizeX, sprSizeY;
|
||||
if (compact->o_status & STAT_SHRINK) {
|
||||
sprSizeX = (scale * _resMan->readUint16(&frameHead->width)) / 256;
|
||||
sprSizeY = (scale * _resMan->readUint16(&frameHead->height)) / 256;
|
||||
fastShrink(sprData, _resMan->readUint16(&frameHead->width), _resMan->readUint16(&frameHead->height), scale, _shrinkBuffer);
|
||||
memset(_shrinkBuffer, 0, SHRINK_BUFFER_SIZE); //Clean shrink buffer to avoid corruption
|
||||
if( SwordEngine::isPsx() && (compact->o_resource != GEORGE_MEGA)) { //PSX Height shrinked sprites
|
||||
sprSizeX = (scale * _resMan->readUint16(&frameHead->width)) / 256;
|
||||
sprSizeY = (scale * (_resMan->readUint16(&frameHead->height))) / 256 / 2;
|
||||
fastShrink(sprData, _resMan->readUint16(&frameHead->width), (_resMan->readUint16(&frameHead->height)) / 2, scale, _shrinkBuffer);
|
||||
} else if (SwordEngine::isPsx()) { //PSX width/height shrinked sprites
|
||||
sprSizeX = (scale * _resMan->readUint16(&frameHead->width)) / 256 / 2;
|
||||
sprSizeY = (scale * _resMan->readUint16(&frameHead->height)) / 256 / 2;
|
||||
fastShrink(sprData, _resMan->readUint16(&frameHead->width) / 2, _resMan->readUint16(&frameHead->height) / 2, scale, _shrinkBuffer);
|
||||
} else {
|
||||
sprSizeX = (scale * _resMan->readUint16(&frameHead->width)) / 256;
|
||||
sprSizeY = (scale * _resMan->readUint16(&frameHead->height)) / 256;
|
||||
fastShrink(sprData, _resMan->readUint16(&frameHead->width), _resMan->readUint16(&frameHead->height), scale, _shrinkBuffer);
|
||||
}
|
||||
sprData = _shrinkBuffer;
|
||||
} else {
|
||||
sprSizeX = _resMan->readUint16(&frameHead->width);
|
||||
sprSizeY = _resMan->readUint16(&frameHead->height);
|
||||
if(SwordEngine::isPsx()) { //PSX sprites are half height
|
||||
sprSizeY = _resMan->readUint16(&frameHead->height) / 2;
|
||||
} else
|
||||
sprSizeY = (_resMan->readUint16(&frameHead->height));
|
||||
}
|
||||
|
||||
if (!(compact->o_status & STAT_OVERRIDE)) {
|
||||
//mouse size linked to exact size & coordinates of sprite box - shrink friendly
|
||||
if (_resMan->readUint16(&frameHead->offsetX) || _resMan->readUint16(&frameHead->offsetY)) {
|
||||
@ -463,24 +520,45 @@ void Screen::processImage(uint32 id) {
|
||||
compact->o_mouse_y2 = spriteY + sprSizeY;
|
||||
}
|
||||
}
|
||||
|
||||
uint16 sprPitch = sprSizeX;
|
||||
uint16 incr;
|
||||
spriteClipAndSet(&spriteX, &spriteY, &sprSizeX, &sprSizeY, &incr);
|
||||
|
||||
if ((sprSizeX > 0) && (sprSizeY > 0)) {
|
||||
drawSprite(sprData + incr, spriteX, spriteY, sprSizeX, sprSizeY, sprPitch);
|
||||
if (!(compact->o_status&STAT_FORE))
|
||||
if( (!(SwordEngine::isPsx()) || (compact->o_type == TYPE_TEXT)
|
||||
|| (compact->o_resource == LVSFLY) || !(compact->o_resource == GEORGE_MEGA) && (sprSizeX < 260)))
|
||||
drawSprite(sprData + incr, spriteX, spriteY, sprSizeX, sprSizeY, sprPitch);
|
||||
else if (((sprSizeX >= 260) && (sprSizeX < 450)) || ((compact->o_resource == GMWRITH) && (sprSizeX < 515)) // a psx shrinked sprite (1/2 width)
|
||||
|| ((compact->o_resource == GMPOWER) && (sprSizeX < 515)) ) // some needs to be hardcoded, headers don't give useful infos
|
||||
drawPsxHalfShrinkedSprite(sprData + incr, spriteX, spriteY, sprSizeX / 2, sprSizeY, sprPitch / 2);
|
||||
else if (sprSizeX >= 450) // A PSX double shrinked sprite (1/3 width)
|
||||
drawPsxFullShrinkedSprite(sprData + incr, spriteX, spriteY, sprSizeX / 3, sprSizeY, sprPitch / 3);
|
||||
else // This is for psx half shrinked, walking george and remaining sprites
|
||||
drawPsxHalfShrinkedSprite(sprData + incr, spriteX, spriteY, sprSizeX, sprSizeY, sprPitch);
|
||||
if (!(compact->o_status&STAT_FORE) && !(SwordEngine::isPsx() && (compact->o_resource == MOUBUSY))) // Check fixes moue sprite being masked by layer, happens only on psx
|
||||
verticalMask(spriteX, spriteY, sprSizeX, sprSizeY);
|
||||
}
|
||||
|
||||
if (compact->o_type != TYPE_TEXT)
|
||||
_resMan->resClose(compact->o_resource);
|
||||
|
||||
if (tonyBuf)
|
||||
free(tonyBuf);
|
||||
|
||||
if (hifBuf)
|
||||
free(hifBuf);
|
||||
}
|
||||
|
||||
void Screen::verticalMask(uint16 x, uint16 y, uint16 bWidth, uint16 bHeight) {
|
||||
if (_roomDefTable[_currentScreen].totalLayers <= 1)
|
||||
return;
|
||||
|
||||
if (SwordEngine::isPsx()) { // PSX sprites are vertical shrinked, and some width shrinked
|
||||
bHeight *= 2;
|
||||
bWidth *= 2;
|
||||
}
|
||||
|
||||
bWidth = (bWidth + (x & (SCRNGRID_X - 1)) + (SCRNGRID_X - 1)) / SCRNGRID_X;
|
||||
bHeight = (bHeight + (y & (SCRNGRID_Y - 1)) + (SCRNGRID_Y - 1)) / SCRNGRID_Y;
|
||||
|
||||
@ -504,7 +582,11 @@ void Screen::verticalMask(uint16 x, uint16 y, uint16 bWidth, uint16 bHeight) {
|
||||
uint16 *grid = _layerGrid[level] + gridX + blkx + gridY * lGridSizeX;
|
||||
for (int16 blky = bHeight - 1; blky >= 0; blky--) {
|
||||
if (*grid) {
|
||||
uint8 *blkData = _layerBlocks[level + 1] + (_resMan->readUint16(grid) - 1) * 128;
|
||||
uint8 *blkData;
|
||||
if (SwordEngine::isPsx())
|
||||
blkData = _layerBlocks[level + 1] + (_resMan->readUint16(grid) - 1) * 64; //PSX layers are half height too...
|
||||
else
|
||||
blkData = _layerBlocks[level + 1] + (_resMan->readUint16(grid) - 1) * 128;
|
||||
blitBlockClear(x + blkx, y + blky, blkData);
|
||||
} else
|
||||
break;
|
||||
@ -517,23 +599,45 @@ void Screen::verticalMask(uint16 x, uint16 y, uint16 bWidth, uint16 bHeight) {
|
||||
|
||||
void Screen::blitBlockClear(uint16 x, uint16 y, uint8 *data) {
|
||||
uint8 *dest = _screenBuf + (y * SCRNGRID_Y) * _scrnSizeX + (x * SCRNGRID_X);
|
||||
for (uint8 cnty = 0; cnty < SCRNGRID_Y; cnty++) {
|
||||
|
||||
for (uint8 cnty = 0; cnty < (SwordEngine::isPsx() ? SCRNGRID_Y / 2 : SCRNGRID_Y); cnty++) {
|
||||
for (uint8 cntx = 0; cntx < SCRNGRID_X; cntx++)
|
||||
if (data[cntx])
|
||||
dest[cntx] = data[cntx];
|
||||
|
||||
if (SwordEngine::isPsx()) {
|
||||
dest += _scrnSizeX;
|
||||
for (uint8 cntx = 0; cntx < SCRNGRID_X; cntx++)
|
||||
if (data[cntx])
|
||||
dest[cntx] = data[cntx];
|
||||
}
|
||||
|
||||
data += SCRNGRID_X;
|
||||
dest += _scrnSizeX;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::renderParallax(uint8 *data) {
|
||||
ParallaxHeader *header = (ParallaxHeader*)data;
|
||||
uint32 *lineIndexes = (uint32*)(data + sizeof(ParallaxHeader));
|
||||
assert((_resMan->getUint16(header->sizeX) >= SCREEN_WIDTH) && (_resMan->getUint16(header->sizeY) >= SCREEN_DEPTH));
|
||||
|
||||
uint16 paraScrlX, paraScrlY;
|
||||
uint16 scrnScrlX, scrnScrlY;
|
||||
uint16 scrnWidth, scrnHeight;
|
||||
uint16 paraSizeX, paraSizeY;
|
||||
uint8 *psxPlx = NULL;
|
||||
ParallaxHeader *header = NULL;
|
||||
uint32 *lineIndexes = NULL;
|
||||
|
||||
if (SwordEngine::isPsx()) { //Parallax headers are different in PSX version
|
||||
psxPlx = psxParallaxToIndexed(data);
|
||||
paraSizeX = READ_LE_UINT16(psxPlx);
|
||||
paraSizeY = READ_LE_UINT16(psxPlx+2);
|
||||
} else {
|
||||
header = (ParallaxHeader*)data;
|
||||
lineIndexes = (uint32*)(data + sizeof(ParallaxHeader));
|
||||
paraSizeX = _resMan->getUint16(header->sizeX);
|
||||
paraSizeY = _resMan->getUint16(header->sizeY);
|
||||
}
|
||||
|
||||
assert((paraSizeX >= SCREEN_WIDTH) && (paraSizeY >= SCREEN_DEPTH));
|
||||
|
||||
// we have to render more than the visible screen part for displaying scroll frames
|
||||
scrnScrlX = MIN((uint32)_oldScrollX, Logic::_scriptVars[SCROLL_OFFSET_X]);
|
||||
@ -541,71 +645,141 @@ void Screen::renderParallax(uint8 *data) {
|
||||
scrnScrlY = MIN((uint32)_oldScrollY, Logic::_scriptVars[SCROLL_OFFSET_Y]);
|
||||
scrnHeight = SCREEN_DEPTH + ABS((int32)_oldScrollY - (int32)Logic::_scriptVars[SCROLL_OFFSET_Y]);
|
||||
|
||||
|
||||
if (_scrnSizeX != SCREEN_WIDTH) {
|
||||
double scrlfx = (_resMan->getUint16(header->sizeX) - SCREEN_WIDTH) / ((double)(_scrnSizeX - SCREEN_WIDTH));
|
||||
double scrlfx = (paraSizeX - SCREEN_WIDTH) / ((double)(_scrnSizeX - SCREEN_WIDTH));
|
||||
paraScrlX = (uint16)(scrnScrlX * scrlfx);
|
||||
} else
|
||||
paraScrlX = 0;
|
||||
|
||||
if (_scrnSizeY != SCREEN_DEPTH) {
|
||||
double scrlfy = (_resMan->getUint16(header->sizeY) - SCREEN_DEPTH) / ((double)(_scrnSizeY - SCREEN_DEPTH));
|
||||
double scrlfy = (paraSizeY - SCREEN_DEPTH) / ((double)(_scrnSizeY - SCREEN_DEPTH));
|
||||
paraScrlY = (uint16)(scrnScrlY * scrlfy);
|
||||
} else
|
||||
paraScrlY = 0;
|
||||
|
||||
for (uint16 cnty = 0; cnty < scrnHeight; cnty++) {
|
||||
uint8 *src = data + _resMan->readUint32(lineIndexes + cnty + paraScrlY);
|
||||
uint8 *dest = _screenBuf + scrnScrlX + (cnty + scrnScrlY) * _scrnSizeX;
|
||||
uint16 remain = paraScrlX;
|
||||
uint16 xPos = 0;
|
||||
while (remain) { // skip past the first part of the parallax to get to the right scrolling position
|
||||
uint8 doSkip = *src++;
|
||||
if (doSkip <= remain)
|
||||
remain -= doSkip;
|
||||
else {
|
||||
xPos = doSkip - remain;
|
||||
dest += xPos;
|
||||
remain = 0;
|
||||
}
|
||||
uint8 doCopy = *src++;
|
||||
if (doCopy <= remain) {
|
||||
remain -= doCopy;
|
||||
src += doCopy;
|
||||
} else {
|
||||
uint16 remCopy = doCopy - remain;
|
||||
memcpy(dest, src + remain, remCopy);
|
||||
dest += remCopy;
|
||||
src += doCopy;
|
||||
xPos = remCopy;
|
||||
remain = 0;
|
||||
}
|
||||
if(SwordEngine::isPsx())
|
||||
for (uint16 cnty = 0; (cnty < SCREEN_DEPTH) && (cnty < paraSizeY); cnty++) {
|
||||
uint8 *src = psxPlx + 4 + paraScrlY * paraSizeX + cnty * paraSizeX + paraScrlX;
|
||||
uint8 *dest = _screenBuf + scrnScrlX + (cnty + scrnScrlY) * _scrnSizeX/* * 2*/;
|
||||
uint8 pix;
|
||||
for (uint16 idx = 0; (idx < SCREEN_WIDTH) && (idx < paraSizeX); idx++) // make sure we don't write outside screen
|
||||
if (pix = *(src + idx)) //If data is 0x00, don't write (transparency)
|
||||
*(dest + idx) = pix;
|
||||
}
|
||||
while (xPos < scrnWidth) {
|
||||
if (uint8 skip = *src++) {
|
||||
dest += skip;
|
||||
xPos += skip;
|
||||
}
|
||||
if (xPos < scrnWidth) {
|
||||
if (uint8 doCopy = *src++) {
|
||||
if (xPos + doCopy > scrnWidth)
|
||||
doCopy = scrnWidth - xPos;
|
||||
memcpy(dest, src, doCopy);
|
||||
dest += doCopy;
|
||||
xPos += doCopy;
|
||||
else
|
||||
for (uint16 cnty = 0; cnty < scrnHeight; cnty++) {
|
||||
uint8 *src = data + _resMan->readUint32(lineIndexes + cnty + paraScrlY);
|
||||
uint8 *dest = _screenBuf + scrnScrlX + (cnty + scrnScrlY) * _scrnSizeX;
|
||||
uint16 remain = paraScrlX;
|
||||
uint16 xPos = 0;
|
||||
while (remain) { // skip past the first part of the parallax to get to the right scrolling position
|
||||
uint8 doSkip = *src++;
|
||||
if (doSkip <= remain)
|
||||
remain -= doSkip;
|
||||
else {
|
||||
xPos = doSkip - remain;
|
||||
dest += xPos;
|
||||
remain = 0;
|
||||
}
|
||||
uint8 doCopy = *src++;
|
||||
if (doCopy <= remain) {
|
||||
remain -= doCopy;
|
||||
src += doCopy;
|
||||
} else {
|
||||
uint16 remCopy = doCopy - remain;
|
||||
memcpy(dest, src + remain, remCopy);
|
||||
dest += remCopy;
|
||||
src += doCopy;
|
||||
xPos = remCopy;
|
||||
remain = 0;
|
||||
}
|
||||
}
|
||||
while (xPos < scrnWidth) {
|
||||
if (uint8 skip = *src++) {
|
||||
dest += skip;
|
||||
xPos += skip;
|
||||
}
|
||||
if (xPos < scrnWidth) {
|
||||
if (uint8 doCopy = *src++) {
|
||||
if (xPos + doCopy > scrnWidth)
|
||||
doCopy = scrnWidth - xPos;
|
||||
memcpy(dest, src, doCopy);
|
||||
dest += doCopy;
|
||||
xPos += doCopy;
|
||||
src += doCopy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (psxPlx)
|
||||
free(psxPlx);
|
||||
}
|
||||
|
||||
void Screen::drawSprite(uint8 *sprData, uint16 sprX, uint16 sprY, uint16 sprWidth, uint16 sprHeight, uint16 sprPitch) {
|
||||
uint8 *dest = _screenBuf + (sprY * _scrnSizeX) + sprX;
|
||||
|
||||
|
||||
for (uint16 cnty = 0; cnty < sprHeight; cnty++) {
|
||||
for (uint16 cntx = 0; cntx < sprWidth; cntx++)
|
||||
if (sprData[cntx])
|
||||
dest[cntx] = sprData[cntx];
|
||||
|
||||
if (SwordEngine::isPsx()) { //On PSX version we need to double horizontal lines
|
||||
dest += _scrnSizeX;
|
||||
for (uint16 cntx = 0; cntx < sprWidth; cntx++)
|
||||
if (sprData[cntx])
|
||||
dest[cntx] = sprData[cntx];
|
||||
}
|
||||
|
||||
sprData += sprPitch;
|
||||
dest += _scrnSizeX;
|
||||
}
|
||||
}
|
||||
|
||||
// Used to draw psx sprites which are 1/2 of original width
|
||||
void Screen::drawPsxHalfShrinkedSprite(uint8 *sprData, uint16 sprX, uint16 sprY, uint16 sprWidth, uint16 sprHeight, uint16 sprPitch) {
|
||||
uint8 *dest = _screenBuf + (sprY * _scrnSizeX) + sprX;
|
||||
|
||||
for (uint16 cnty = 0; cnty < sprHeight; cnty++) {
|
||||
for (uint16 cntx = 0; cntx < sprWidth; cntx++)
|
||||
if (sprData[cntx]) {
|
||||
dest[cntx * 2] = sprData[cntx]; //In these sprites we need to double vetical lines too...
|
||||
dest[cntx * 2 + 1] = sprData[cntx];
|
||||
}
|
||||
|
||||
dest += _scrnSizeX;
|
||||
for (uint16 cntx = 0; cntx < sprWidth; cntx++)
|
||||
if (sprData[cntx]) {
|
||||
dest[cntx * 2] = sprData[cntx];
|
||||
dest[cntx * 2 + 1] = sprData[cntx];
|
||||
}
|
||||
|
||||
sprData += sprPitch;
|
||||
dest += _scrnSizeX;
|
||||
}
|
||||
}
|
||||
|
||||
// Used to draw psx sprites which are 1/3 of original width
|
||||
void Screen::drawPsxFullShrinkedSprite(uint8 *sprData, uint16 sprX, uint16 sprY, uint16 sprWidth, uint16 sprHeight, uint16 sprPitch) {
|
||||
uint8 *dest = _screenBuf + (sprY * _scrnSizeX) + sprX;
|
||||
|
||||
for (uint16 cnty = 0; cnty < sprHeight; cnty++) {
|
||||
for (uint16 cntx = 0; cntx < sprWidth ; cntx++)
|
||||
if (sprData[cntx]) {
|
||||
dest[cntx * 3] = sprData[cntx]; //In these sprites we need to double vertical lines too...
|
||||
dest[cntx * 3 + 1] = sprData[cntx];
|
||||
dest[cntx * 3 + 2] = sprData[cntx];
|
||||
}
|
||||
|
||||
dest += _scrnSizeX;
|
||||
for (uint16 cntx = 0; cntx < sprWidth; cntx++)
|
||||
if (sprData[cntx]) {
|
||||
dest[cntx * 3] = sprData[cntx];
|
||||
dest[cntx * 3 + 1] = sprData[cntx];
|
||||
dest[cntx * 3 + 2] = sprData[cntx];
|
||||
}
|
||||
|
||||
sprData += sprPitch;
|
||||
dest += _scrnSizeX;
|
||||
}
|
||||
@ -618,6 +792,7 @@ void Screen::fastShrink(uint8 *src, uint32 width, uint32 height, uint32 scale, u
|
||||
uint32 step = 0x10000 / scale;
|
||||
uint8 columnTab[160];
|
||||
uint32 res = step >> 1;
|
||||
|
||||
for (uint16 cnt = 0; cnt < resWidth; cnt++) {
|
||||
columnTab[cnt] = (uint8)(res >> 8);
|
||||
res += step;
|
||||
@ -675,6 +850,188 @@ void Screen::addToGraphicList(uint8 listId, uint32 objId) {
|
||||
}
|
||||
}
|
||||
|
||||
uint8* Screen::psxBackgroundToIndexed(uint8* psxBackground, uint32 bakXres, uint32 bakYres) {
|
||||
uint32 xresInTiles = bakXres / 16;
|
||||
uint32 yresInTiles = ((bakYres / 2) % 16) ? (bakYres / 32) + 1 : (bakYres / 32);
|
||||
uint32 totTiles = xresInTiles * yresInTiles;
|
||||
uint32 tileYpos = 0; //tile position in a virtual xresInTiles * yresInTiles grid
|
||||
uint32 tileXpos = 0;
|
||||
uint32 tag = READ_LE_UINT32(psxBackground);
|
||||
|
||||
uint8 *decomp_tile = (uint8 *)malloc(16 * 16); //Tiles are always 16 * 16
|
||||
uint8 *halfres_buffer = (uint8 *)malloc(totTiles * 16 * 16); //This buffer will contain the half vertical res image
|
||||
|
||||
bool isCompressed = (tag == 0x434F4D50);
|
||||
|
||||
psxBackground += 4; //We skip the id tag
|
||||
|
||||
for (uint32 currentTile = 0; currentTile < totTiles; currentTile++) {
|
||||
uint32 tileOffset = READ_LE_UINT32(psxBackground + 4 * currentTile);
|
||||
|
||||
if(isCompressed)
|
||||
decompressHIF(psxBackground + tileOffset - 4, decomp_tile); //Decompress the tile into decomp_tile
|
||||
else
|
||||
memcpy(decomp_tile, psxBackground + tileOffset - 4, 16*16);
|
||||
|
||||
if (currentTile > 0 && !(currentTile % xresInTiles)) { //Finished a line of tiles, going down
|
||||
tileYpos++;
|
||||
tileXpos = 0;
|
||||
}
|
||||
|
||||
for (byte tileLine=0; tileLine<16; tileLine++)
|
||||
memcpy(halfres_buffer + tileLine * bakXres + tileXpos * 16 + tileYpos * bakXres * 16, decomp_tile + tileLine * 16, 16); //Copy data to destination buffer
|
||||
|
||||
tileXpos++;
|
||||
}
|
||||
|
||||
free(decomp_tile);
|
||||
|
||||
uint8 *fullres_buffer = (uint8 *)malloc(bakXres * yresInTiles * 32);
|
||||
memset(fullres_buffer, 0x00, bakXres * yresInTiles * 32);
|
||||
|
||||
//Let's linedouble the image (to keep correct aspect ratio)
|
||||
for (uint32 currentLine = 0; currentLine < (bakYres/2); currentLine++) {
|
||||
memcpy(fullres_buffer + currentLine * bakXres * 2, halfres_buffer + currentLine * bakXres, bakXres); // destination_line is 2*original_line
|
||||
memcpy(fullres_buffer + currentLine * bakXres * 2 + bakXres, halfres_buffer + currentLine * bakXres, bakXres); // destination_line+1
|
||||
}
|
||||
|
||||
free(halfres_buffer);
|
||||
|
||||
return fullres_buffer;
|
||||
}
|
||||
|
||||
// needed because some psx backgrounds are half width and half height
|
||||
uint8* Screen::psxShrinkedBackgroundToIndexed(uint8* psxBackground, uint32 bakXres, uint32 bakYres) {
|
||||
uint32 xresInTiles = (bakXres / 2) % 16 ? (bakXres / 32) + 1 : (bakXres / 32);
|
||||
uint32 yresInTiles = (bakYres / 2) % 16 ? (bakYres / 32) + 1 : (bakYres / 32);
|
||||
uint32 totTiles = xresInTiles * yresInTiles;
|
||||
uint32 tileYpos = 0; //tile position in a virtual xresInTiles * yresInTiles grid
|
||||
uint32 tileXpos = 0;
|
||||
uint32 dataBegin = READ_LE_UINT32(psxBackground + 4);
|
||||
uint32 realWidth = xresInTiles * 16;
|
||||
|
||||
uint8 *decomp_tile = (uint8 *)malloc(16 * 16); //Tiles are always 16 * 16
|
||||
uint8 *halfres_buffer = (uint8*) malloc(totTiles * 16 * 16); //This buffer will contain the half vertical res image
|
||||
memset(halfres_buffer, 0, totTiles * 16 * 16);
|
||||
|
||||
bool isCompressed = (READ_LE_UINT32(psxBackground) == MKID_BE('COMP'));
|
||||
|
||||
totTiles -= xresInTiles;
|
||||
psxBackground += 4; //We skip the id tag
|
||||
|
||||
uint32 currentTile;
|
||||
for (currentTile = 0; currentTile < totTiles; currentTile++) {
|
||||
uint32 tileOffset = READ_LE_UINT32(psxBackground + 4 * currentTile);
|
||||
|
||||
if(isCompressed)
|
||||
decompressHIF(psxBackground + tileOffset - 4, decomp_tile); //Decompress the tile into decomp_tile
|
||||
else
|
||||
memcpy(decomp_tile, psxBackground + tileOffset - 4, 16 * 16);
|
||||
|
||||
if (currentTile > 0 && !(currentTile % xresInTiles)) { //Finished a line of tiles, going down
|
||||
tileYpos++;
|
||||
tileXpos = 0;
|
||||
}
|
||||
|
||||
for (byte tileLine = 0; tileLine < 16; tileLine++)
|
||||
memcpy(halfres_buffer + (tileLine * realWidth) + (tileXpos * 16) + (tileYpos * realWidth * 16), decomp_tile + (tileLine * 16), 16); //Copy data to destination buffer
|
||||
|
||||
tileXpos++;
|
||||
}
|
||||
|
||||
uint8 *fullres_buffer = (uint8 *)malloc(bakXres * (yresInTiles + 1) * 32);
|
||||
memset(fullres_buffer, 0x00, bakXres * (yresInTiles + 1) * 32);
|
||||
|
||||
for (uint32 currentLine = 0; currentLine < ((yresInTiles - 1) * 16); currentLine++) {
|
||||
for (uint32 cntx = 0; cntx < realWidth; cntx++) {
|
||||
fullres_buffer[currentLine * 2 * bakXres + cntx * 2] = halfres_buffer[currentLine * realWidth + cntx];
|
||||
fullres_buffer[currentLine * 2 * bakXres + cntx * 2 + 1] = halfres_buffer[currentLine * realWidth + cntx];
|
||||
}
|
||||
for (uint32 cntx = 0; cntx < realWidth; cntx++) {
|
||||
fullres_buffer[(currentLine * 2 + 1) * bakXres + cntx * 2] = halfres_buffer[currentLine * realWidth + cntx];
|
||||
fullres_buffer[(currentLine * 2 + 1) * bakXres + cntx * 2 + 1] = halfres_buffer[currentLine * realWidth + cntx];
|
||||
}
|
||||
}
|
||||
free(halfres_buffer);
|
||||
|
||||
//Calculate number of remaining tiles
|
||||
uint32 remainingTiles = (dataBegin - (currentTile * 4 + 4)) / 4;
|
||||
|
||||
// Last line of tiles is FULL WIDTH!
|
||||
uint32 tileHeight = (remainingTiles == xresInTiles * 2) ? 16 : 8;
|
||||
|
||||
halfres_buffer = (uint8*) malloc(bakXres * 16 * 2);
|
||||
memset(halfres_buffer, 0, bakXres * 16 * 2);
|
||||
|
||||
tileXpos = 0;
|
||||
for (; currentTile < totTiles + remainingTiles; currentTile++) {
|
||||
uint32 tileOffset = READ_LE_UINT32(psxBackground + 4 * currentTile);
|
||||
|
||||
if(isCompressed)
|
||||
decompressHIF(psxBackground + tileOffset - 4, decomp_tile); //Decompress the tile into decomp_tile
|
||||
else
|
||||
memcpy(decomp_tile, psxBackground + tileOffset - 4, 256);
|
||||
|
||||
for (byte tileLine = 0; tileLine < tileHeight; tileLine++)
|
||||
memcpy(halfres_buffer + tileLine * bakXres * 2 + tileXpos * 16, decomp_tile + tileLine * 16, 16);
|
||||
|
||||
tileXpos++;
|
||||
}
|
||||
|
||||
free(decomp_tile);
|
||||
|
||||
for (uint32 currentLine = 0; currentLine < tileHeight; currentLine++) {
|
||||
memcpy(fullres_buffer + (currentLine + (yresInTiles - 1) * 16) * bakXres * 2, halfres_buffer + currentLine * bakXres * 2, bakXres * 2);
|
||||
memcpy(fullres_buffer + (currentLine + (yresInTiles - 1) * 16) * bakXres * 2 + bakXres, halfres_buffer + currentLine * bakXres * 2, bakXres * 2);
|
||||
}
|
||||
|
||||
free(halfres_buffer);
|
||||
|
||||
return fullres_buffer;
|
||||
}
|
||||
|
||||
uint8* Screen::psxParallaxToIndexed(uint8* psxParallax) {
|
||||
uint16 xresInTiles = READ_LE_UINT16(psxParallax + 10);
|
||||
uint16 yresInTiles = READ_LE_UINT16(psxParallax + 12);
|
||||
uint16 totTiles = READ_LE_UINT16(psxParallax + 14);
|
||||
uint32 plxXres = xresInTiles * 16;
|
||||
uint32 plxYres = yresInTiles * 16;
|
||||
|
||||
uint8 *plxPos = psxParallax + 16;
|
||||
uint8 *plxOff = psxParallax + 16 + totTiles * 2;
|
||||
uint8 *plxData = psxParallax + 16 + totTiles * 2 + totTiles * 4;
|
||||
|
||||
uint8 *decomp_tile = (uint8 *)malloc(16 * 16); // Tiles are always 16 * 16
|
||||
uint8 *halfres_buffer = (uint8 *)malloc(4 + yresInTiles * xresInTiles * 16 * 16); //This buffer will contain the half vertical res image
|
||||
memset(halfres_buffer, 0, 4 + yresInTiles * xresInTiles * 16 * 16); //Clean the buffer
|
||||
|
||||
for (uint16 currentTile = 0; currentTile < totTiles - 1; currentTile++) {
|
||||
uint32 tileOffset = READ_LE_UINT32(plxOff + 4 * currentTile);
|
||||
uint8 tileXpos = *(plxPos + 2 * currentTile); //Fetch tile position in grid
|
||||
uint8 tileYpos = *(plxPos + 2 * currentTile + 1);
|
||||
decompressHIF(plxData + tileOffset, decomp_tile); //Decompress the tile into decomp_tile
|
||||
|
||||
for (byte tileLine = 0; tileLine < 16; tileLine++)
|
||||
memcpy(halfres_buffer + tileLine * plxXres + tileXpos * 16 + tileYpos * plxXres * 16, decomp_tile + tileLine * 16, 16); //Copy data to destination buffer
|
||||
}
|
||||
|
||||
free(decomp_tile);
|
||||
|
||||
uint8 *dest_buffer = (uint8*) malloc (plxXres * plxYres * 2 + 4);
|
||||
WRITE_LE_UINT16(dest_buffer, plxXres); //Insert resolution information
|
||||
WRITE_LE_UINT16(dest_buffer + 2, plxYres*2);
|
||||
|
||||
//Let's linedouble the image (to keep correct aspect ratio)
|
||||
for (uint32 currentLine = 0; currentLine < plxYres; currentLine++) {
|
||||
memcpy(dest_buffer + 4 + currentLine * plxXres * 2, halfres_buffer + currentLine * plxXres, plxXres); // destination_line is 2*original_line
|
||||
memcpy(dest_buffer + 4 + currentLine * plxXres * 2 + plxXres, halfres_buffer + currentLine * plxXres, plxXres); // destination_line+1
|
||||
}
|
||||
|
||||
free(halfres_buffer);
|
||||
|
||||
return dest_buffer;
|
||||
}
|
||||
|
||||
void Screen::decompressTony(uint8 *src, uint32 compSize, uint8 *dest) {
|
||||
uint8 *endOfData = src + compSize;
|
||||
while (src < endOfData) {
|
||||
@ -721,6 +1078,30 @@ void Screen::decompressRLE0(uint8 *src, uint32 compSize, uint8 *dest) {
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::decompressHIF(uint8 *src, uint8 *dest) {
|
||||
for (;;) { //Main loop
|
||||
byte control_byte = *src++;
|
||||
uint32 byte_count = 0;
|
||||
while (byte_count < 8) {
|
||||
if (control_byte & 0x80) {
|
||||
uint16 info_word = READ_BE_UINT16(src); //Read the info word
|
||||
src += 2;
|
||||
if (info_word == 0xFFFF) return; //Got 0xFFFF code, finished.
|
||||
|
||||
int32 repeat_count = (info_word >> 12) + 2; //How many time data needs to be refetched
|
||||
while(repeat_count >= 0) {
|
||||
uint8 *old_data_src = dest - ((info_word & 0xFFF) + 1);
|
||||
*dest++ = *old_data_src;
|
||||
repeat_count--;
|
||||
}
|
||||
} else
|
||||
*dest++ = *src++;
|
||||
byte_count++;
|
||||
control_byte <<= 1; //Shifting left the control code one bit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::fadePalette(void) {
|
||||
if (_fadingStep == 16)
|
||||
memcpy(_currentPalette, _targetPalette, 256 * 4);
|
||||
@ -773,6 +1154,7 @@ void Screen::spriteClipAndSet(uint16 *pSprX, uint16 *pSprY, uint16 *pSprWidth, u
|
||||
*pSprWidth = 0;
|
||||
else
|
||||
*pSprWidth = (uint16)sprW;
|
||||
|
||||
*pSprX = (uint16)sprX;
|
||||
*pSprY = (uint16)sprY;
|
||||
|
||||
@ -780,6 +1162,19 @@ void Screen::spriteClipAndSet(uint16 *pSprX, uint16 *pSprY, uint16 *pSprWidth, u
|
||||
// sprite will be drawn, so mark it in the grid buffer
|
||||
uint16 gridH = (*pSprHeight + (sprY & (SCRNGRID_Y - 1)) + (SCRNGRID_Y - 1)) / SCRNGRID_Y;
|
||||
uint16 gridW = (*pSprWidth + (sprX & (SCRNGRID_X - 1)) + (SCRNGRID_X - 1)) / SCRNGRID_X;
|
||||
|
||||
if(SwordEngine::isPsx()) {
|
||||
gridH *= 2; // This will correct the PSX sprite being cut at half height
|
||||
gridW *= 2; // and masking problems when sprites are stretched in width
|
||||
|
||||
uint16 bottomSprPos = (*pSprY + (*pSprHeight) * 2); //Position of bottom line of sprite
|
||||
if ( bottomSprPos > _scrnSizeY ) { //Check that resized psx sprite isn't drawn outside of screen boundaries
|
||||
uint16 outScreen = bottomSprPos - _scrnSizeY;
|
||||
*pSprHeight -= (outScreen % 2) ? (outScreen + 1) / 2 : outScreen / 2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint16 gridX = sprX / SCRNGRID_X;
|
||||
uint16 gridY = sprY / SCRNGRID_Y;
|
||||
uint8 *gridBuf = _screenGrid + gridX + gridY * _gridSizeX;
|
||||
@ -806,16 +1201,32 @@ void Screen::showFrame(uint16 x, uint16 y, uint32 resId, uint32 frameNo, const b
|
||||
uint8 frame[40 * 40];
|
||||
int i, j;
|
||||
|
||||
memset(frame, 199, sizeof(frame)); // Dark gray background
|
||||
if(SwordEngine::isPsx())
|
||||
memset(frame, 0, sizeof(frame)); // PSX top menu is black
|
||||
else
|
||||
memset(frame, 199, sizeof(frame)); // Dark gray background
|
||||
|
||||
if (resId != 0xffffffff) {
|
||||
FrameHeader *frameHead = _resMan->fetchFrame(_resMan->openFetchRes(resId), frameNo);
|
||||
uint8 *frameData = ((uint8*)frameHead) + sizeof(FrameHeader);
|
||||
|
||||
for (i = 0; i < _resMan->getUint16(frameHead->height); i++) {
|
||||
for (j = 0; j < _resMan->getUint16(frameHead->height); j++) {
|
||||
frame[(i + 4) * 40 + j + 2] = frameData[i * _resMan->getUint16(frameHead->width) + j];
|
||||
if (SwordEngine::isPsx()) { //We need to decompress PSX frames
|
||||
uint8 *frameBufferPSX = (uint8 *)malloc(_resMan->getUint16(frameHead->width) * _resMan->getUint16(frameHead->height)/2);
|
||||
decompressHIF(frameData, frameBufferPSX);
|
||||
|
||||
for (i = 0; i < _resMan->getUint16(frameHead->height) / 2; i++) {
|
||||
for (j = 0; j < _resMan->getUint16(frameHead->width); j++) {
|
||||
uint8 data = frameBufferPSX[i * _resMan->getUint16(frameHead->width) + j];
|
||||
frame[(i * 2 + 4) * 40 + j + 2] = data;
|
||||
frame[(i * 2 + 1 + 4) * 40 + j + 2] = data; //Linedoubling the sprite
|
||||
}
|
||||
}
|
||||
|
||||
free(frameBufferPSX);
|
||||
} else {
|
||||
for (i = 0; i < _resMan->getUint16(frameHead->height); i++)
|
||||
for (j = 0; j < _resMan->getUint16(frameHead->height); j++)
|
||||
frame[(i + 4) * 40 + j + 2] = frameData[i * _resMan->getUint16(frameHead->width) + j];
|
||||
}
|
||||
|
||||
_resMan->resClose(resId);
|
||||
|
@ -96,6 +96,8 @@ public:
|
||||
void fnFlash(uint8 color);
|
||||
void fnBorder(uint8 color);
|
||||
|
||||
static void decompressHIF(uint8 *src, uint8 *dest);
|
||||
|
||||
#ifdef BACKEND_8BIT
|
||||
void plotYUV(byte *lut, int width, int height, byte *const *dat);
|
||||
#endif
|
||||
@ -116,6 +118,11 @@ private:
|
||||
void processImage(uint32 id);
|
||||
void spriteClipAndSet(uint16 *pSprX, uint16 *pSprY, uint16 *sprWidth, uint16 *sprHeight, uint16 *incr);
|
||||
void drawSprite(uint8 *sprData, uint16 sprX, uint16 sprY, uint16 sprWidth, uint16 sprHeight, uint16 sprPitch);
|
||||
void drawPsxHalfShrinkedSprite(uint8 *sprData, uint16 sprX, uint16 sprY, uint16 sprWidth, uint16 sprHeight, uint16 sprPitch);
|
||||
void drawPsxFullShrinkedSprite(uint8 *sprData, uint16 sprX, uint16 sprY, uint16 sprWidth, uint16 sprHeight, uint16 sprPitch);
|
||||
uint8* psxBackgroundToIndexed(uint8* psxBackground, uint32 bakXres, uint32 bakYres);
|
||||
uint8* psxShrinkedBackgroundToIndexed(uint8* psxBackground, uint32 bakXres, uint32 bakYres);
|
||||
uint8* psxParallaxToIndexed(uint8* psxParallax);
|
||||
void decompressRLE7(uint8 *src, uint32 compSize, uint8 *dest);
|
||||
void decompressRLE0(uint8 *src, uint32 compSize, uint8 *dest);
|
||||
void decompressTony(uint8 *src, uint32 compSize, uint8 *dest);
|
||||
@ -160,3 +167,5 @@ private:
|
||||
|
||||
#endif //BSSCREEN_H
|
||||
|
||||
|
||||
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "sword1/resman.h"
|
||||
#include "sword1/logic.h"
|
||||
#include "sword1/sword1.h"
|
||||
#include "sword1/vag.h"
|
||||
|
||||
#include "sound/flac.h"
|
||||
#include "sound/mp3.h"
|
||||
@ -160,22 +161,29 @@ void Sound::playSample(QueueElement *elem) {
|
||||
if (_fxList[elem->id].roomVolList[cnt].roomNo) {
|
||||
if ((_fxList[elem->id].roomVolList[cnt].roomNo == (int)Logic::_scriptVars[SCREEN]) ||
|
||||
(_fxList[elem->id].roomVolList[cnt].roomNo == -1)) {
|
||||
|
||||
|
||||
uint8 volL = (_fxList[elem->id].roomVolList[cnt].leftVol * 10 * _sfxVolL) / 255;
|
||||
uint8 volR = (_fxList[elem->id].roomVolList[cnt].rightVol * 10 * _sfxVolR) / 255;
|
||||
int8 pan = (volR - volL) / 2;
|
||||
uint8 volume = (volR + volL) / 2;
|
||||
uint32 size = READ_LE_UINT32(sampleData + 0x28);
|
||||
uint8 flags;
|
||||
if (READ_LE_UINT16(sampleData + 0x22) == 16)
|
||||
flags = Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_LITTLE_ENDIAN;
|
||||
else
|
||||
flags = Audio::Mixer::FLAG_UNSIGNED;
|
||||
if (READ_LE_UINT16(sampleData + 0x16) == 2)
|
||||
flags |= Audio::Mixer::FLAG_STEREO;
|
||||
if (_fxList[elem->id].type == FX_LOOP)
|
||||
flags |= Audio::Mixer::FLAG_LOOP;
|
||||
_mixer->playRaw(Audio::Mixer::kSFXSoundType, &elem->handle, sampleData + 0x2C, size, 11025, flags, elem->id, volume, pan);
|
||||
|
||||
if (SwordEngine::isPsx()) { ;
|
||||
uint32 size = READ_LE_UINT32(sampleData);
|
||||
Audio::AudioStream *audStream = new VagStream(new Common::MemoryReadStream(sampleData + 4, size-4), _fxList[elem->id].type == FX_LOOP);
|
||||
_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &elem->handle, audStream, elem->id, volume, pan, false, false, false);
|
||||
} else {
|
||||
uint32 size = READ_LE_UINT32(sampleData + 0x28);
|
||||
uint8 flags;
|
||||
if (READ_LE_UINT16(sampleData + 0x22) == 16)
|
||||
flags = Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_LITTLE_ENDIAN;
|
||||
else
|
||||
flags = Audio::Mixer::FLAG_UNSIGNED;
|
||||
if (READ_LE_UINT16(sampleData + 0x16) == 2)
|
||||
flags |= Audio::Mixer::FLAG_STEREO;
|
||||
if (_fxList[elem->id].type == FX_LOOP)
|
||||
flags |= Audio::Mixer::FLAG_LOOP;
|
||||
_mixer->playRaw(Audio::Mixer::kSFXSoundType, &elem->handle, sampleData + 0x2C, size, 11025, flags, elem->id, volume, pan);
|
||||
}
|
||||
}
|
||||
} else
|
||||
break;
|
||||
@ -187,11 +195,69 @@ bool Sound::startSpeech(uint16 roomNo, uint16 localNo) {
|
||||
warning("Sound::startSpeech: COW file isn't open");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 locIndex = 0xFFFFFFFF;
|
||||
uint32 sampleSize = 0;
|
||||
uint32 index = 0;
|
||||
|
||||
uint32 locIndex = _cowHeader[roomNo] >> 2;
|
||||
uint32 sampleSize = _cowHeader[locIndex + (localNo * 2)];
|
||||
uint32 index = _cowHeader[locIndex + (localNo * 2) - 1];
|
||||
if (_cowMode == CowPSX) {
|
||||
Common::File file;
|
||||
uint16 i;
|
||||
|
||||
if (!file.open("speech.lis")) {
|
||||
warning ("Could not open speech.lis");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; !file.eos() && !file.err(); i++)
|
||||
if (file.readUint16LE() == roomNo) {
|
||||
locIndex = i;
|
||||
break;
|
||||
}
|
||||
file.close();
|
||||
|
||||
if (locIndex == 0xFFFFFFFF) {
|
||||
warning ("Could not find room %d in speech.lis", roomNo);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file.open("speech.inf")) {
|
||||
warning ("Could not open speech.inf");
|
||||
return false;
|
||||
}
|
||||
|
||||
file.seek(locIndex * 4 + 2); // 4 bytes per room, skip first 2 bytes
|
||||
|
||||
uint16 numLines = file.readUint16LE();
|
||||
uint16 roomOffset = file.readUint16LE();
|
||||
|
||||
file.seek(0x112 + roomOffset * 2); // The offset is in terms of uint16's, so multiply by 2. Skip the 0x112 byte header too.
|
||||
|
||||
locIndex = 0xFFFFFFFF;
|
||||
|
||||
for (i = 0; i < numLines; i++)
|
||||
if (file.readUint16LE() == localNo) {
|
||||
locIndex = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (locIndex == 0xFFFFFFFF) {
|
||||
warning ("Could not find local number %d in room %d in speech.inf", roomNo, localNo);
|
||||
return false;
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
index = _cowHeader[(roomOffset + locIndex) * 2];
|
||||
sampleSize = _cowHeader[(roomOffset + locIndex) * 2 + 1];
|
||||
} else {
|
||||
locIndex = _cowHeader[roomNo] >> 2;
|
||||
sampleSize = _cowHeader[locIndex + (localNo * 2)];
|
||||
index = _cowHeader[locIndex + (localNo * 2) - 1];
|
||||
}
|
||||
|
||||
debug(6, "startSpeech(%d, %d): locIndex %d, sampleSize %d, index %d", roomNo, localNo, locIndex, sampleSize, index);
|
||||
|
||||
if (sampleSize) {
|
||||
uint8 speechVol = (_speechVolR + _speechVolL) / 2;
|
||||
int8 speechPan = (_speechVolR - _speechVolL) / 2;
|
||||
@ -200,6 +266,14 @@ bool Sound::startSpeech(uint16 roomNo, uint16 localNo) {
|
||||
int16 *data = uncompressSpeech(index + _cowHeaderSize, sampleSize, &size);
|
||||
if (data)
|
||||
_mixer->playRaw(Audio::Mixer::kSpeechSoundType, &_speechHandle, data, size, 11025, SPEECH_FLAGS, SOUND_SPEECH_ID, speechVol, speechPan);
|
||||
} else if (_cowMode == CowPSX && sampleSize != 0xffffffff) {
|
||||
_cowFile.seek(index * 2048);
|
||||
_mixer->playInputStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, new VagStream(_cowFile.readStream(sampleSize)), SOUND_SPEECH_ID, speechVol, speechPan);
|
||||
// with compressed audio, we can't calculate the wave volume.
|
||||
// so default to talking.
|
||||
for (int cnt = 0; cnt < 480; cnt++)
|
||||
_waveVolume[cnt] = true;
|
||||
_waveVolPos = 0;
|
||||
}
|
||||
#ifdef USE_FLAC
|
||||
else if (_cowMode == CowFlac) {
|
||||
@ -419,21 +493,47 @@ void Sound::initCowSystem(void) {
|
||||
debug(1, "Using uncompressed Speech Cluster");
|
||||
_cowMode = CowWave;
|
||||
}
|
||||
|
||||
if (SwordEngine::isPsx()) {
|
||||
// There's only one file on the PSX, so set it to the current disc.
|
||||
_currentCowFile = SwordEngine::_systemVars.currentCD;
|
||||
if (!_cowFile.isOpen()) {
|
||||
if (!_cowFile.open("speech.dat"))
|
||||
error ("Could not open speech.dat");
|
||||
_cowMode = CowPSX;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_cowFile.isOpen())
|
||||
_cowFile.open("speech.clu");
|
||||
|
||||
if (!_cowFile.isOpen()) {
|
||||
_cowFile.open("cows.mad");
|
||||
if (_cowFile.isOpen())
|
||||
_cowMode = CowDemo;
|
||||
}
|
||||
|
||||
if (_cowFile.isOpen()) {
|
||||
_cowHeaderSize = _cowFile.readUint32LE();
|
||||
_cowHeader = (uint32*)malloc(_cowHeaderSize);
|
||||
if (_cowHeaderSize & 3)
|
||||
error("Unexpected cow header size %d", _cowHeaderSize);
|
||||
for (uint32 cnt = 0; cnt < (_cowHeaderSize / 4) - 1; cnt++)
|
||||
_cowHeader[cnt] = _cowFile.readUint32LE();
|
||||
_currentCowFile = SwordEngine::_systemVars.currentCD;
|
||||
if (SwordEngine::isPsx()) {
|
||||
// Get data from the external table file
|
||||
Common::File tableFile;
|
||||
if (!tableFile.open("speech.tab"))
|
||||
error ("Could not open speech.tab");
|
||||
_cowHeaderSize = tableFile.size();
|
||||
_cowHeader = (uint32 *)malloc(_cowHeaderSize);
|
||||
if (_cowHeaderSize & 3)
|
||||
error("Unexpected cow header size %d", _cowHeaderSize);
|
||||
for (uint32 cnt = 0; cnt < _cowHeaderSize / 4; cnt++)
|
||||
_cowHeader[cnt] = tableFile.readUint32LE();
|
||||
} else {
|
||||
_cowHeaderSize = _cowFile.readUint32LE();
|
||||
_cowHeader = (uint32*)malloc(_cowHeaderSize);
|
||||
if (_cowHeaderSize & 3)
|
||||
error("Unexpected cow header size %d", _cowHeaderSize);
|
||||
for (uint32 cnt = 0; cnt < (_cowHeaderSize / 4) - 1; cnt++)
|
||||
_cowHeader[cnt] = _cowFile.readUint32LE();
|
||||
_currentCowFile = SwordEngine::_systemVars.currentCD;
|
||||
}
|
||||
} else
|
||||
warning("Sound::initCowSystem: Can't open SPEECH%d.CLU", SwordEngine::_systemVars.currentCD);
|
||||
}
|
||||
|
@ -69,7 +69,8 @@ enum CowMode {
|
||||
CowFlac,
|
||||
CowVorbis,
|
||||
CowMp3,
|
||||
CowDemo
|
||||
CowDemo,
|
||||
CowPSX
|
||||
};
|
||||
|
||||
class Sound {
|
||||
|
@ -84,14 +84,16 @@ Common::Error SwordEngine::init() {
|
||||
|
||||
if ( 0 == scumm_stricmp(ConfMan.get("gameid").c_str(), "sword1mac") ||
|
||||
0 == scumm_stricmp(ConfMan.get("gameid").c_str(), "sword1macdemo") )
|
||||
_systemVars.isMac = true;
|
||||
_systemVars.platform = Common::kPlatformMacintosh;
|
||||
else if (0 == scumm_stricmp(ConfMan.get("gameid").c_str(), "sword1psx"))
|
||||
_systemVars.platform = Common::kPlatformPSX;
|
||||
else
|
||||
_systemVars.isMac = false;
|
||||
_systemVars.platform = Common::kPlatformWindows;
|
||||
|
||||
checkCdFiles();
|
||||
|
||||
debug(5, "Starting resource manager");
|
||||
_resMan = new ResMan("swordres.rif", _systemVars.isMac);
|
||||
_resMan = new ResMan("swordres.rif", _systemVars.platform == Common::kPlatformMacintosh);
|
||||
debug(5, "Starting object manager");
|
||||
_objectMan = new ObjectMan(_resMan);
|
||||
_mouse = new Mouse(_system, _resMan, _objectMan);
|
||||
@ -308,12 +310,34 @@ const CdFile SwordEngine::_macCdFileList[] = {
|
||||
#endif
|
||||
};
|
||||
|
||||
const CdFile SwordEngine::_psxCdFileList[] = { // PSX edition has only one cd
|
||||
{ "paris2.clu", FLAG_CD1 },
|
||||
{ "ireland.clu", FLAG_CD1 },
|
||||
{ "paris3.clu", FLAG_CD1 },
|
||||
{ "paris4.clu", FLAG_CD1 },
|
||||
{ "scotland.clu", FLAG_CD1 },
|
||||
{ "spain.clu", FLAG_CD1 },
|
||||
{ "syria.clu", FLAG_CD1 },
|
||||
{ "train.clu", FLAG_CD1 },
|
||||
{ "train.plx", FLAG_CD1 },
|
||||
{ "compacts.clu", FLAG_CD1 | FLAG_IMMED },
|
||||
{ "general.clu", FLAG_CD1 | FLAG_IMMED },
|
||||
{ "maps.clu", FLAG_CD1 },
|
||||
{ "paris1.clu", FLAG_CD1 },
|
||||
{ "scripts.clu", FLAG_CD1 | FLAG_IMMED },
|
||||
{ "swordres.rif", FLAG_CD1 | FLAG_IMMED },
|
||||
{ "text.clu", FLAG_CD1 },
|
||||
{ "speech.dat", FLAG_SPEECH1 },
|
||||
{ "speech.tab", FLAG_SPEECH1 },
|
||||
{ "speech.inf", FLAG_SPEECH1 },
|
||||
{ "speech.lis", FLAG_SPEECH1 }
|
||||
};
|
||||
|
||||
void SwordEngine::showFileErrorMsg(uint8 type, bool *fileExists) {
|
||||
char msg[1024];
|
||||
int missCnt = 0, missNum = 0;
|
||||
|
||||
if (_systemVars.isMac) {
|
||||
if (SwordEngine::isMac()) {
|
||||
for (int i = 0; i < ARRAYSIZE(_macCdFileList); i++)
|
||||
if (!fileExists[i]) {
|
||||
missCnt++;
|
||||
@ -335,6 +359,27 @@ void SwordEngine::showFileErrorMsg(uint8 type, bool *fileExists) {
|
||||
pos += sprintf(pos, "\"%s\" (CD %d)\n", _macCdFileList[i].name, (_macCdFileList[i].flags & FLAG_CD2) ? 2 : 1);
|
||||
}
|
||||
}
|
||||
} else if (SwordEngine::isPsx()) {
|
||||
for (int i = 0; i < ARRAYSIZE(_psxCdFileList); i++)
|
||||
if (!fileExists[i]) {
|
||||
missCnt++;
|
||||
missNum = i;
|
||||
}
|
||||
assert(missCnt > 0); // this function shouldn't get called if there's nothing missing.
|
||||
warning("%d files missing", missCnt);
|
||||
int msgId = (type == TYPE_IMMED) ? 0 : 2;
|
||||
if (missCnt == 1) {
|
||||
sprintf(msg, errorMsgs[msgId], _psxCdFileList[missNum].name, 1);
|
||||
warning("%s", msg);
|
||||
} else {
|
||||
char *pos = msg + sprintf(msg, errorMsgs[msgId + 1], missCnt);
|
||||
warning("%s", msg);
|
||||
for (int i = 0; i < ARRAYSIZE(_psxCdFileList); i++)
|
||||
if (!fileExists[i]) {
|
||||
warning("\"%s\"", _macCdFileList[i].name);
|
||||
pos += sprintf(pos, "\"%s\"\n", _macCdFileList[i].name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < ARRAYSIZE(_pcCdFileList); i++)
|
||||
if (!fileExists[i]) {
|
||||
@ -374,7 +419,7 @@ void SwordEngine::checkCdFiles(void) { // check if we're running from cd, hdd or
|
||||
_systemVars.playSpeech = true;
|
||||
|
||||
// check all files and look out if we can find a file that wouldn't exist if this was the demo version
|
||||
if (_systemVars.isMac) {
|
||||
if (SwordEngine::isMac()) {
|
||||
for (int fcnt = 0; fcnt < ARRAYSIZE(_macCdFileList); fcnt++) {
|
||||
if (Common::File::exists(_macCdFileList[fcnt].name)) {
|
||||
fileExists[fcnt] = true;
|
||||
@ -388,6 +433,18 @@ void SwordEngine::checkCdFiles(void) { // check if we're running from cd, hdd or
|
||||
fileExists[fcnt] = false;
|
||||
}
|
||||
}
|
||||
} else if (SwordEngine::isPsx()) {
|
||||
for (int fcnt = 0; fcnt < ARRAYSIZE(_psxCdFileList); fcnt++) {
|
||||
if (Common::File::exists(_psxCdFileList[fcnt].name)) {
|
||||
fileExists[fcnt] = true;
|
||||
flagsToBool(foundTypes, _psxCdFileList[fcnt].flags);
|
||||
isFullVersion = true;
|
||||
cd2FilesFound = true;
|
||||
} else {
|
||||
flagsToBool(missingTypes, _psxCdFileList[fcnt].flags);
|
||||
fileExists[fcnt] = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int fcnt = 0; fcnt < ARRAYSIZE(_pcCdFileList); fcnt++) {
|
||||
if (Common::File::exists(_pcCdFileList[fcnt].name)) {
|
||||
@ -422,7 +479,7 @@ void SwordEngine::checkCdFiles(void) { // check if we're running from cd, hdd or
|
||||
somethingMissing |= missingTypes[i];
|
||||
if (somethingMissing) { // okay, there *are* files missing
|
||||
// first, update the fileExists[] array depending on our changed missingTypes
|
||||
if (_systemVars.isMac) {
|
||||
if (SwordEngine::isMac()) {
|
||||
for (int fileCnt = 0; fileCnt < ARRAYSIZE(_macCdFileList); fileCnt++)
|
||||
if (!fileExists[fileCnt]) {
|
||||
fileExists[fileCnt] = true;
|
||||
@ -430,6 +487,14 @@ void SwordEngine::checkCdFiles(void) { // check if we're running from cd, hdd or
|
||||
if (missingTypes[flagCnt] && ((_macCdFileList[fileCnt].flags & (1 << flagCnt)) != 0))
|
||||
fileExists[fileCnt] = false; // this is one of the files we were looking for
|
||||
}
|
||||
} else if (SwordEngine::isPsx()) {
|
||||
for (int fileCnt = 0; fileCnt < ARRAYSIZE(_psxCdFileList); fileCnt++)
|
||||
if (!fileExists[fileCnt]) {
|
||||
fileExists[fileCnt] = true;
|
||||
for (int flagCnt = 0; flagCnt < 8; flagCnt++)
|
||||
if (missingTypes[flagCnt] && ((_psxCdFileList[fileCnt].flags & (1 << flagCnt)) != 0))
|
||||
fileExists[fileCnt] = false; // this is one of the files we were looking for
|
||||
}
|
||||
} else {
|
||||
for (int fileCnt = 0; fileCnt < ARRAYSIZE(_pcCdFileList); fileCnt++)
|
||||
if (!fileExists[fileCnt]) {
|
||||
|
@ -66,7 +66,7 @@ struct SystemVars {
|
||||
uint8 showText;
|
||||
uint8 language;
|
||||
bool isDemo;
|
||||
bool isMac;
|
||||
Common::Platform platform;
|
||||
};
|
||||
|
||||
class SwordEngine : public Engine {
|
||||
@ -79,6 +79,9 @@ public:
|
||||
uint32 _features;
|
||||
|
||||
bool mouseIsActive();
|
||||
|
||||
static bool isMac() { return _systemVars.platform == Common::kPlatformMacintosh; }
|
||||
static bool isPsx() { return _systemVars.platform == Common::kPlatformPSX; }
|
||||
|
||||
protected:
|
||||
// Engine APIs
|
||||
@ -119,6 +122,7 @@ private:
|
||||
static const uint8 _cdList[TOTAL_SECTIONS];
|
||||
static const CdFile _pcCdFileList[];
|
||||
static const CdFile _macCdFileList[];
|
||||
static const CdFile _psxCdFileList[];
|
||||
};
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
@ -32,6 +32,8 @@
|
||||
#include "sword1/objectman.h"
|
||||
#include "sword1/swordres.h"
|
||||
#include "sword1/sworddefs.h"
|
||||
#include "sword1/screen.h"
|
||||
#include "sword1/sword1.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
@ -78,12 +80,13 @@ uint32 Text::lowTextManager(uint8 *ascii, int32 width, uint8 pen) {
|
||||
void Text::makeTextSprite(uint8 slot, uint8 *text, uint16 maxWidth, uint8 pen) {
|
||||
LineInfo lines[MAX_LINES];
|
||||
uint16 numLines = analyzeSentence(text, maxWidth, lines);
|
||||
|
||||
|
||||
uint16 sprWidth = 0;
|
||||
uint16 lineCnt;
|
||||
for (lineCnt = 0; lineCnt < numLines; lineCnt++)
|
||||
if (lines[lineCnt].width > sprWidth)
|
||||
sprWidth = lines[lineCnt].width;
|
||||
|
||||
uint16 sprHeight = _charHeight * numLines;
|
||||
uint32 sprSize = sprWidth * sprHeight;
|
||||
assert(!_textBlocks[slot]); // if this triggers, the speechDriver failed to call Text::releaseText.
|
||||
@ -100,10 +103,13 @@ void Text::makeTextSprite(uint8 slot, uint8 *text, uint16 maxWidth, uint8 pen) {
|
||||
memset(linePtr, NO_COL, sprSize);
|
||||
for (lineCnt = 0; lineCnt < numLines; lineCnt++) {
|
||||
uint8 *sprPtr = linePtr + (sprWidth - lines[lineCnt].width) / 2; // center the text
|
||||
for (uint16 pos = 0; pos < lines[lineCnt].length; pos++)
|
||||
for (uint16 pos = 0; pos < lines[lineCnt].length; pos++)
|
||||
sprPtr += copyChar(*text++, sprPtr, sprWidth, pen) - OVERLAP;
|
||||
text++; // skip space at the end of the line
|
||||
linePtr += _charHeight * sprWidth;
|
||||
if(SwordEngine::isPsx()) //Chars are half height in psx version
|
||||
linePtr += (_charHeight / 2) * sprWidth;
|
||||
else
|
||||
linePtr += _charHeight * sprWidth;
|
||||
}
|
||||
}
|
||||
|
||||
@ -157,16 +163,34 @@ uint16 Text::copyChar(uint8 ch, uint8 *sprPtr, uint16 sprWidth, uint8 pen) {
|
||||
FrameHeader *chFrame = _resMan->fetchFrame(_font, ch - SPACE);
|
||||
uint8 *chData = ((uint8*)chFrame) + sizeof(FrameHeader);
|
||||
uint8 *dest = sprPtr;
|
||||
for (uint16 cnty = 0; cnty < _resMan->getUint16(chFrame->height); cnty++) {
|
||||
uint8 *decBuf = NULL;
|
||||
uint8 *decChr;
|
||||
uint16 frameHeight = 0;
|
||||
|
||||
if(SwordEngine::isPsx()) {
|
||||
frameHeight = _resMan->getUint16(chFrame->height)/2;
|
||||
if(_fontId == CZECH_GAME_FONT) { //Czech game fonts are compressed
|
||||
decBuf = (uint8*) malloc((_resMan->getUint16(chFrame->width))*(_resMan->getUint16(chFrame->height)/2));
|
||||
Screen::decompressHIF(chData, decBuf);
|
||||
decChr = decBuf;
|
||||
} else //Normal game fonts are not compressed
|
||||
decChr = chData;
|
||||
} else {
|
||||
frameHeight = _resMan->getUint16(chFrame->height);
|
||||
decChr = chData;
|
||||
}
|
||||
|
||||
for (uint16 cnty = 0; cnty < frameHeight; cnty++) {
|
||||
for (uint16 cntx = 0; cntx < _resMan->getUint16(chFrame->width); cntx++) {
|
||||
if (*chData == LETTER_COL)
|
||||
if (*decChr == LETTER_COL)
|
||||
dest[cntx] = pen;
|
||||
else if ((*chData == BORDER_COL) && (!dest[cntx])) // don't do a border if there's already a color underneath (chars can overlap)
|
||||
else if (((*decChr == BORDER_COL) || (*decChr == BORDER_COL_PSX)) && (!dest[cntx])) // don't do a border if there's already a color underneath (chars can overlap)
|
||||
dest[cntx] = BORDER_COL;
|
||||
chData++;
|
||||
decChr++;
|
||||
}
|
||||
dest += sprWidth;
|
||||
}
|
||||
free(decBuf);
|
||||
return _resMan->getUint16(chFrame->width);
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,7 @@ namespace Sword1 {
|
||||
#define MAX_TEXT_OBS 3
|
||||
|
||||
#define BORDER_COL 200
|
||||
#define BORDER_COL_PSX 199
|
||||
#define LETTER_COL 193
|
||||
#define NO_COL 0 // sprite background - 0 for transparency
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user