TINSEL: Updated addional drawing routines for v3

Implemented playing of films of objects (not movies).
Fixed rendering of the main menu.
Increased the size of parameters of coroutines.
This commit is contained in:
Peter Kohaut 2021-03-04 20:06:15 +01:00
parent bc3424bbcf
commit e59a470db3
8 changed files with 228 additions and 74 deletions

View file

@ -284,7 +284,7 @@ public:
/** Size of process-specific information. */
#define CORO_PARAM_SIZE 32
#define CORO_PARAM_SIZE 40
/** Maximum number of processes. */
#define CORO_NUM_PROCESS 100

View file

@ -44,25 +44,6 @@ Background::Background(Font* font) : _font(font), _pCurBgnd(nullptr), _hBgPal(0)
* Called to initialize a background.
*/
void Background::InitBackground() {
PLAYFIELD worldPlayfield = {
NULL, // display list
0, // init field x
0, // init field y
0, // x vel
0, // y vel
Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), // clip rect
false // moved flag
};
PLAYFIELD statusPlayfield = {
NULL, // display list
0, // init field x
0, // init field y
0, // x vel
0, // y vel
Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), // clip rect
false // moved flag
};
// set current background
_pCurBgnd = new BACKGND();
_pCurBgnd->rgbSkyColor = BLACK;
@ -71,10 +52,25 @@ void Background::InitBackground() {
_pCurBgnd->refreshRate = 0; // no background update process
_pCurBgnd->pXscrollTable = nullptr;
_pCurBgnd->pYscrollTable = nullptr;
_pCurBgnd->fieldArray.push_back(worldPlayfield);
_pCurBgnd->fieldArray.push_back(statusPlayfield);
_pCurBgnd->bAutoErase = false;
int numPlayFields = 2;
if (TinselV3) {
numPlayFields = 9;
}
for (int i = 0; i < numPlayFields; ++i) {
PLAYFIELD playfield = {
NULL, // display list
0, // init field x
0, // init field y
0, // x vel
0, // y vel
Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), // clip rect
false // moved flag
};
_pCurBgnd->fieldArray.push_back(playfield);
}
// init background sky color
SetBgndColor(_pCurBgnd->rgbSkyColor);
}
@ -287,4 +283,17 @@ void Background::ChangePalette(SCNHANDLE hPal) {
SetBackPal(hPal);
}
void Background::WaitForBG(CORO_PARAM) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
CORO_BEGIN_CODE(_ctx);
while (_pBG[0] == nullptr) {
CORO_SLEEP(1);
}
CORO_END_CODE;
}
} // End of namespace Tinsel

View file

@ -145,6 +145,8 @@ public:
int getBgSpeed() { return _BGspeed; }
void WaitForBG(CORO_PARAM);
private:
Font *_font;

View file

@ -56,8 +56,8 @@ typedef int HPOLYGON;
// inventory object handle (if there are inventory objects)
#define INV_OBJ_SCNHANDLE (TinselV0 ? (2 << SCNHANDLE_SHIFT) : (1 << SCNHANDLE_SHIFT))
#define FIELD_WORLD 0
#define FIELD_STATUS 1
#define FIELD_WORLD (TinselV3 ? 2 : 0)
#define FIELD_STATUS (TinselV3 ? 8 : 1)
#define ZSHIFT 10

View file

@ -608,6 +608,114 @@ static void t2WrtNonZero(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP, bool apply
}
}
static void t3WrtNonZero(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP) {
bool applyClipping = (pObj->flags & DMA_CLIP) != 0;
bool horizFlipped = (pObj->flags & DMA_FLIPH) != 0;
if (pObj->isRLE)
{
int yClip = applyClipping ? pObj->topClip : 0;
if (applyClipping) {
pObj->height -= pObj->botClip;
}
for (int y = 0; y < pObj->height; ++y) {
uint8 *tempP = destP;
int leftClip = applyClipping ? pObj->leftClip : 0;
int rightClip = applyClipping ? pObj->rightClip : 0;
if (horizFlipped) {
SWAP(leftClip, rightClip);
}
int x = 0;
while (x < pObj->width) {
int numPixels = READ_LE_UINT16(srcP);
srcP += 2;
if (numPixels & 0x8000) {
numPixels &= 0x7FFF;
int clipAmount = MIN(numPixels, leftClip);
leftClip -= clipAmount;
x += clipAmount;
int runLength = numPixels - clipAmount;
uint16 color = READ_LE_UINT16(srcP);
srcP += 2;
if ((yClip == 0) && (runLength > 0)) {
runLength = MIN(runLength, pObj->width - rightClip - x);
for (int xp = 0; xp < runLength; ++xp) {
if (color != 0b1111100000011111) {
WRITE_UINT16(tempP, color);
}
tempP += (horizFlipped ? -2 : 2);
}
}
x += numPixels - clipAmount;
} else {
int clipAmount = MIN(numPixels, leftClip);
leftClip -= clipAmount;
srcP += clipAmount * 2;
int runLength = numPixels - clipAmount;
x += numPixels - runLength;
for (int xp = 0; xp < runLength; ++xp) {
if ((yClip == 0) && (x < (pObj->width - rightClip))) {
uint16 color = READ_LE_UINT16(srcP);
if (color != 0b1111100000011111) {
WRITE_UINT16(tempP, color);
}
tempP += (horizFlipped ? -2 : 2);
}
srcP += 2;
++x;
}
}
}
// assert(x == pObj->width);
if (yClip > 0) {
--yClip;
} else {
destP += SCREEN_WIDTH * 2;
}
}
return;
}
if (applyClipping) {
srcP += (pObj->topClip * pObj->width * 2);
pObj->height -= pObj->topClip + pObj->botClip;
pObj->width -= pObj->leftClip + pObj->rightClip;
}
for (int y = 0; y < pObj->height; ++y) {
uint8 *tempP = destP;
srcP += pObj->leftClip * 2;
for (int x = 0; x < pObj->width; ++x) {
uint16 color = READ_LE_UINT16(srcP);
srcP += 2;
if (color != 0b1111100000011111) { // "zero" for Tinsel 3 - magenta in 565
WRITE_UINT16(tempP, color);
}
tempP += 2;
}
srcP += pObj->rightClip * 2;
destP += SCREEN_WIDTH * 2;
}
}
/**
* Fill the destination area with a constant color
*/
@ -635,29 +743,24 @@ static void WrtConst(DRAWOBJECT *pObj, uint8 *destP, bool applyClipping) {
static void t3TransWNZ(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP) {
bool applyClipping = (pObj->flags & DMA_CLIP) != 0;
int leftClip = 0;
int rightClip = 0;
if (applyClipping) {
srcP += (pObj->topClip * pObj->width * 2);
if (applyClipping)
{
pObj->height -= pObj->topClip;
pObj->height -= pObj->topClip + pObj->botClip;
pObj->width -= pObj->leftClip + pObj->rightClip;
leftClip = pObj->leftClip;
rightClip = pObj->rightClip;
}
for (int y = 0; y < pObj->height; ++y) {
// Get the position to start writing out from
uint8 *tempP = destP;
srcP += leftClip * 2;
srcP += pObj->leftClip * 2;
for (int x = 0; x < pObj->width; ++x) {
uint32 color = READ_UINT16(srcP); //uint32 for checking overflow in blending
uint32 color = READ_LE_UINT16(srcP); //uint32 for checking overflow in blending
if (color != 0b1111100000011111) { // "zero" for Tinsel 3 - magenta in 565
uint8 srcR, srcG, srcB;
t3getRGB(color, srcR, srcG, srcB);
uint16 dstColor = READ_UINT16(tempP);
uint16 dstColor = READ_LE_UINT16(tempP);
uint8 dstR, dstG, dstB;
t3getRGB(dstColor, dstR, dstG, dstB);
@ -694,7 +797,7 @@ static void t3TransWNZ(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP) {
tempP += 2;
srcP += 2;
}
srcP += rightClip * 2;
srcP += pObj->rightClip * 2;
destP += SCREEN_WIDTH * 2;
}
}
@ -756,7 +859,7 @@ static void t3WrtAll(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP) {
int objWidth = pObj->width;
if (applyClipping) {
srcP += ((pObj->topClip * pObj->width) + pObj->leftClip) * 2;
srcP += (pObj->topClip * pObj->width * 2) + (pObj->leftClip * 2);
pObj->height -= pObj->topClip + pObj->botClip;
pObj->width -= pObj->leftClip + pObj->rightClip;
@ -1030,7 +1133,9 @@ void DrawObject(DRAWOBJECT *pObj) {
case 0x51: // TinselV2, draw sprite with clipping, flipped horizontally
assert(TinselV2 || (typeId == 0x01 || typeId == 0x41));
if (TinselV2)
if (TinselV3)
t3WrtNonZero(pObj, srcPtr, destPtr);
else if (TinselV2)
t2WrtNonZero(pObj, srcPtr, destPtr, (typeId & DMA_CLIP) != 0, (typeId & DMA_FLIPH) != 0);
else if (TinselV1PSX)
PsxDrawTiles(pObj, srcPtr, destPtr, typeId == 0x41, psxFourBitClut, psxSkipBytes, psxMapperTable, true);

View file

@ -56,6 +56,8 @@ struct PPINIT {
uint8 escOn;
int32 myescEvent;
OBJECT** playfield; // TinselV3, the playfield to insert the film
};
//----------------- LOCAL GLOBAL DATA --------------------
@ -684,8 +686,7 @@ static void t1PlayReel(CORO_PARAM, const PPINIT *ppi) {
* @param hFilm The 'film'
* @param column Column number, first column = 0
*/
static void t2PlayReel(CORO_PARAM, int x, int y, bool bRestore, int speed, SCNHANDLE hFilm,
int column, int myescEvent, bool bTop) {
static void t2PlayReel(CORO_PARAM, int x, int y, bool bRestore, int speed, SCNHANDLE hFilm, int column, int myescEvent, bool bTop, OBJECT** playfield) {
CORO_BEGIN_CONTEXT;
bool bReplaced;
bool bGotHidden;
@ -767,8 +768,10 @@ static void t2PlayReel(CORO_PARAM, int x, int y, bool bRestore, int speed, SCNHA
/*
* Insert the object
*/
// Poke in the background palette
PokeInPalette(_ctx->pmi);
if (!TinselV3) {
// Poke in the background palette
PokeInPalette(_ctx->pmi);
}
// Set ghost bit if wanted
if (_vm->_actor->ActorIsGhost(_ctx->reelActor)) {
@ -778,10 +781,14 @@ static void t2PlayReel(CORO_PARAM, int x, int y, bool bRestore, int speed, SCNHA
// Set up and insert the multi-object
_ctx->pPlayObj = MultiInitObject(_ctx->pmi);
if (!bTop)
MultiInsertObject(_vm->_bg->GetPlayfieldList(FIELD_WORLD), _ctx->pPlayObj);
else
MultiInsertObject(_vm->_bg->GetPlayfieldList(FIELD_STATUS), _ctx->pPlayObj);
if (TinselV3) {
MultiInsertObject(playfield, _ctx->pPlayObj);
} else {
if (!bTop)
MultiInsertObject(_vm->_bg->GetPlayfieldList(FIELD_WORLD), _ctx->pPlayObj);
else
MultiInsertObject(_vm->_bg->GetPlayfieldList(FIELD_STATUS), _ctx->pPlayObj);
}
/*
* More action for moving actors
@ -922,10 +929,15 @@ static void t2PlayReel(CORO_PARAM, int x, int y, bool bRestore, int speed, SCNHA
_vm->_actor->NotPlayingReel(_ctx->reelActor, _ctx->filmNumber, column);
// Ditch the object
if (!bTop)
MultiDeleteObject(_vm->_bg->GetPlayfieldList(FIELD_WORLD), _ctx->pPlayObj);
else
MultiDeleteObject(_vm->_bg->GetPlayfieldList(FIELD_STATUS), _ctx->pPlayObj);
if (TinselV3) {
MultiDeleteObject(playfield, _ctx->pPlayObj);
} else {
if (!bTop) {
MultiDeleteObject(_vm->_bg->GetPlayfieldList(FIELD_WORLD), _ctx->pPlayObj);
} else {
MultiDeleteObject(_vm->_bg->GetPlayfieldList(FIELD_STATUS), _ctx->pPlayObj);
}
}
// Restore moving actor is nessesary
if (_ctx->pMover != NULL && _ctx->bPrinciple && !_ctx->bReplaced)
@ -946,7 +958,7 @@ static void PlayProcess(CORO_PARAM, const void *param) {
if (TinselV2)
CORO_INVOKE_ARGS(t2PlayReel, (CORO_SUBCTX, ppi->x, ppi->y, ppi->bRestore, ppi->speed,
ppi->hFilm, ppi->column, ppi->myescEvent, ppi->bTop));
ppi->hFilm, ppi->column, ppi->myescEvent, ppi->bTop, ppi->playfield));
else
CORO_INVOKE_1(t1PlayReel, ppi);
@ -975,8 +987,7 @@ void NewestFilm(SCNHANDLE film, const FREEL *reel) {
* NOTE: The processes are started in reverse order so that the first
* column's process kicks in first.
*/
void PlayFilm(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int actorid, bool splay, bool sfact, bool escOn,
int myescEvent, bool bTop) {
void PlayFilm(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int actorid, bool splay, bool sfact, bool escOn, int myescEvent, bool bTop, OBJECT** playfield) {
assert(hFilm != 0); // Trying to play NULL film
const FILM *pFilm;
@ -1004,6 +1015,7 @@ void PlayFilm(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int actorid, bool splay
ppi.sf = sfact;
ppi.escOn = escOn;
ppi.myescEvent = myescEvent;
ppi.playfield = playfield;
// Start display process for each reel in the film
for (int i = FROM_32(pFilm->numreels) - 1; i >= 0; i--) {
@ -1026,16 +1038,15 @@ void PlayFilm(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int actorid, bool splay
CORO_END_CODE;
}
void PlayFilm(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int myescEvent, bool bTop) {
PlayFilm(coroParam, hFilm, x, y, 0, false, false, false, myescEvent, bTop);
void PlayFilm(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int myescEvent, bool bTop, OBJECT** playfield) {
PlayFilm(coroParam, hFilm, x, y, 0, false, false, false, myescEvent, bTop, playfield);
}
/**
* Start up a play process for each slave column in a film.
* Play the first column directly from the parent process.
*/
void PlayFilmc(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int actorid, bool splay, bool sfact,
bool escOn, int myescEvent, bool bTop) {
void PlayFilmc(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int actorid, bool splay, bool sfact, bool escOn, int myescEvent, bool bTop, OBJECT** playfield) {
CORO_BEGIN_CONTEXT;
PPINIT ppi;
int i;
@ -1065,6 +1076,7 @@ void PlayFilmc(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int actorid, bool spla
_ctx->ppi.sf = sfact;
_ctx->ppi.escOn = escOn;
_ctx->ppi.myescEvent = myescEvent;
_ctx->ppi.playfield = playfield;
// Start display process for each secondary reel in the film in Tinsel 1,
// or all of them in Tinsel 2

View file

@ -39,13 +39,11 @@ struct SOUNDREELS {
};
typedef SOUNDREELS *PSOUNDREELS;
void PlayFilm(CORO_PARAM, SCNHANDLE film, int x, int y, int actorid, bool splay, bool sfact, bool escOn,
int myescEvent, bool bTop);
void PlayFilm(CORO_PARAM, SCNHANDLE film, int x, int y, int actorid, bool splay, bool sfact, bool escOn, int myescEvent, bool bTop, OBJECT** playfield);
void PlayFilm(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int myescEvent, bool bTop);
void PlayFilm(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int myescEvent, bool bTop, OBJECT** playfield);
void PlayFilmc(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int actorid, bool splay, bool sfact,
bool escOn, int myescEvent, bool bTop);
void PlayFilmc(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int actorid, bool splay, bool sfact, bool escOn, int myescEvent, bool bTop, OBJECT** playfield);
void RestoreActorReels(SCNHANDLE hFilm, short reelnum, short z, int x, int y);
void RestoreActorReels(SCNHANDLE hFilm, int actor, int x, int y);

View file

@ -1537,12 +1537,12 @@ static void Play(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int compit, int acto
if (compit == 1) {
// Play to completion before returning
CORO_INVOKE_ARGS(PlayFilmc, (CORO_SUBCTX, hFilm, x, y, actorid, splay, sfact, escOn, myEscape, bTop));
CORO_INVOKE_ARGS(PlayFilmc, (CORO_SUBCTX, hFilm, x, y, actorid, splay, sfact, escOn, myEscape, bTop, nullptr));
} else if (compit == 2) {
error("play(): compit == 2 - please advise John");
} else {
// Kick off the play and return.
CORO_INVOKE_ARGS(PlayFilm, (CORO_SUBCTX, hFilm, x, y, actorid, splay, sfact, escOn, myEscape, bTop));
CORO_INVOKE_ARGS(PlayFilm, (CORO_SUBCTX, hFilm, x, y, actorid, splay, sfact, escOn, myEscape, bTop, nullptr));
}
CORO_END_CODE;
}
@ -1550,8 +1550,7 @@ static void Play(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int compit, int acto
/**
* Play a film
*/
static void Play(CORO_PARAM, SCNHANDLE hFilm, int x, int y, bool bComplete, int myEscape,
bool bTop, TINSEL_EVENT event, HPOLYGON hPoly, int taggedActor) {
static void Play(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int compit, int myEscape, bool bTop, TINSEL_EVENT event, HPOLYGON hPoly, int taggedActor) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@ -1565,6 +1564,10 @@ static void Play(CORO_PARAM, SCNHANDLE hFilm, int x, int y, bool bComplete, int
return;
}
if (TinselV3) {
CORO_INVOKE_0(_vm->_bg->WaitForBG);
}
if (event == TALKING) {
int actor;
if (hPoly == NOPOLY) {
@ -1586,12 +1589,27 @@ static void Play(CORO_PARAM, SCNHANDLE hFilm, int x, int y, bool bComplete, int
_vm->_actor->SetActorTalkFilm(actor, hFilm);
}
OBJECT** playfield;
bool bComplete;
playfield = nullptr;
bComplete = compit;
if (TinselV3) {
bComplete = compit & 0x20;
if (bTop) {
playfield = _vm->_bg->GetPlayfieldList(FIELD_STATUS);
} else {
playfield = _vm->_bg->GetPlayfieldList(compit & 0x0F);
}
}
if (bComplete) {
// Play to completion before returning
CORO_INVOKE_ARGS(PlayFilmc, (CORO_SUBCTX, hFilm, x, y, 0, false, false, myEscape != 0, myEscape, bTop));
CORO_INVOKE_ARGS(PlayFilmc, (CORO_SUBCTX, hFilm, x, y, 0, false, false, myEscape != 0, myEscape, bTop, playfield));
} else {
// Kick off the play and return.
CORO_INVOKE_ARGS(PlayFilm, (CORO_SUBCTX, hFilm, x, y, myEscape, bTop));
CORO_INVOKE_ARGS(PlayFilm, (CORO_SUBCTX, hFilm, x, y, myEscape, bTop, playfield));
}
CORO_END_CODE;
@ -2934,7 +2952,7 @@ void Stand(CORO_PARAM, int actor, int x, int y, SCNHANDLE hFilm) {
assert(hFilm != 0); // Trying to play NULL film
// Kick off the play and return.
CORO_INVOKE_ARGS(PlayFilm, (CORO_SUBCTX, hFilm, x, y, actor, false, 0, false, 0, false));
CORO_INVOKE_ARGS(PlayFilm, (CORO_SUBCTX, hFilm, x, y, actor, false, 0, false, 0, false, nullptr));
}
CORO_END_CODE;
@ -3163,7 +3181,7 @@ static void FinishTalkingReel(CORO_PARAM, PMOVER pMover, int actor) {
AlterMover(pMover, 0, AR_POPREEL);
} else {
_vm->_actor->SetActorTalking(actor, false);
CORO_INVOKE_ARGS(PlayFilm, (CORO_SUBCTX, _vm->_actor->GetActorPlayFilm(actor), -1, -1, 0, false, 0, false, 0, false));
CORO_INVOKE_ARGS(PlayFilm, (CORO_SUBCTX, _vm->_actor->GetActorPlayFilm(actor), -1, -1, 0, false, 0, false, 0, false, _vm->_bg->GetPlayfieldList(FIELD_WORLD)));
}
CORO_END_CODE;
@ -3290,7 +3308,7 @@ static void TalkOrSay(CORO_PARAM, SPEECH_TYPE speechType, SCNHANDLE hText, int x
} else {
_vm->_actor->SetActorTalking(_ctx->actor, true);
_vm->_actor->SetActorTalkFilm(_ctx->actor, hFilm);
CORO_INVOKE_ARGS(PlayFilm, (CORO_SUBCTX, hFilm, -1, -1, 0, false, 0, escOn, myEscape, false));
CORO_INVOKE_ARGS(PlayFilm, (CORO_SUBCTX, hFilm, -1, -1, 0, false, 0, escOn, myEscape, false, _vm->_bg->GetPlayfieldList(FIELD_WORLD)));
}
_ctx->bTalkReel = true;
CORO_SLEEP(1); // Allow the play to come in
@ -5184,15 +5202,25 @@ int CallLibraryRoutine(CORO_PARAM, int operand, int32 *pp, const INT_CONTEXT *pi
case PLAY:
// Common to DW1 / DW2 / Noir
if (TinselV3) {
warning("TODO: Implement PLAY");
if (*pResumeState == RES_1 && _vm->_handle->IsCdPlayHandle(pp[0])) {
*pResumeState = RES_NOT;
if ((pp[0] & 0x10) != 0) {
return -4;
}
return -2;
} else if ((pp[0] & 0x10) != 0) {
Play(coroParam, pp[-1], pp[-3], pp[-2], pp[0], pic->myEscape, false, pic->event, pic->hPoly, pic->idActor);
return -4;
}
Play(coroParam, pp[-1], -1, -1, pp[0], pic->myEscape, false, pic->event, pic->hPoly, pic->idActor);
return -2;
} if (TinselV2) {
pp -= 3; // 4 parameters
if (*pResumeState == RES_1 && _vm->_handle->IsCdPlayHandle(pp[0]))
*pResumeState = RES_NOT;
else {
Play(coroParam, pp[0], pp[1], pp[2], pp[3], pic->myEscape, false,
pic->event, pic->hPoly, pic->idActor);
Play(coroParam, pp[0], pp[1], pp[2], pp[3], pic->myEscape, false, pic->event, pic->hPoly, pic->idActor);
}
return -4;