scummvm/engines/tinsel/background.cpp
2021-05-04 11:46:30 +03:00

300 lines
8.4 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Background handling code.
*/
#include "tinsel/background.h"
#include "tinsel/cliprect.h" // object clip rect defs
#include "tinsel/font.h"
#include "tinsel/graphics.h"
#include "tinsel/multiobj.h"
#include "tinsel/sched.h" // process sheduler defs
#include "tinsel/object.h"
#include "tinsel/pid.h" // process identifiers
#include "tinsel/tinsel.h"
namespace Tinsel {
Background::Background(Font* font) : _font(font), _pCurBgnd(nullptr), _hBgPal(0), _BGspeed(0), _hBackground(0), _bDoFadeIn(false), _bgReels(0) {
for (int i = 0; i < MAX_BG; i++) {
_pBG[i] = nullptr;
_thisAnim[i].pObject = nullptr;
}
}
/**
* Called to initialize a background.
*/
void Background::InitBackground() {
// set current background
_pCurBgnd = new BACKGND();
_pCurBgnd->rgbSkyColor = BLACK;
_pCurBgnd->ptInitWorld = Common::Point(0, 0);
_pCurBgnd->rcScrollLimits = Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
_pCurBgnd->refreshRate = 0; // no background update process
_pCurBgnd->pXscrollTable = nullptr;
_pCurBgnd->pYscrollTable = nullptr;
_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);
}
/**
* Sets the xy position of the specified playfield in the current background.
* @param which Which playfield
* @param newXpos New x position
* @param newYpos New y position
*/
void Background::PlayfieldSetPos(unsigned int which, int newXpos, int newYpos) {
PLAYFIELD *pPlayfield; // pointer to relavent playfield
// make sure there is a background
assert(_pCurBgnd != NULL);
// make sure the playfield number is in range
assert(which < _pCurBgnd->fieldArray.size());
// get playfield pointer
pPlayfield = &_pCurBgnd->fieldArray[which];
// set new integer position
pPlayfield->fieldX = intToFrac(newXpos);
pPlayfield->fieldY = intToFrac(newYpos);
// set moved flag
pPlayfield->bMoved = true;
}
/**
* Returns the xy position of the specified playfield in the current background.
* @param which Which playfield
* @param pXpos Returns current x position
* @param pYpos Returns current y position
*/
void Background::PlayfieldGetPos(unsigned int which, int *pXpos, int *pYpos) {
PLAYFIELD *pPlayfield; // pointer to relavent playfield
// make sure there is a background
assert(_pCurBgnd != NULL);
// make sure the playfield number is in range
assert(which < _pCurBgnd->fieldArray.size());
// get playfield pointer
pPlayfield = &_pCurBgnd->fieldArray[which];
// get current integer position
*pXpos = fracToInt(pPlayfield->fieldX);
*pYpos = fracToInt(pPlayfield->fieldY);
}
/**
* Returns the x position of the center of the specified playfield
* @param which Which playfield
*/
int Background::PlayfieldGetCenterX(unsigned int which) {
PLAYFIELD *pPlayfield; // pointer to relavent playfield
// make sure there is a background
assert(_pCurBgnd != NULL);
// make sure the playfield number is in range
assert(which < _pCurBgnd->fieldArray.size());
// get playfield pointer
pPlayfield = &_pCurBgnd->fieldArray[which];
// get current integer position
return fracToInt(pPlayfield->fieldX) + SCREEN_WIDTH/2;
}
/**
* Returns the display list for the specified playfield.
* @param which Which playfield
*/
OBJECT **Background::GetPlayfieldList(unsigned int which) {
PLAYFIELD *pPlayfield; // pointer to relavent playfield
// make sure there is a background
assert(_pCurBgnd != NULL);
// make sure the playfield number is in range
assert(which < _pCurBgnd->fieldArray.size());
// get playfield pointer
pPlayfield = &_pCurBgnd->fieldArray[which];
// return the display list pointer for this playfield
return &pPlayfield->pDispList;
}
/**
* Draws all the playfield object lists for the current background.
* The playfield velocity is added to the playfield position in order
* to scroll each playfield before it is drawn.
*/
void Background::DrawBackgnd() {
PLAYFIELD *pPlay; // playfield pointer
int prevX, prevY; // save interger part of position
Common::Point ptWin; // window top left
if (_pCurBgnd == NULL)
return; // no current background
// scroll each background playfield
for (unsigned int i = 0; i < _pCurBgnd->fieldArray.size(); i++) {
// get pointer to correct playfield
pPlay = &_pCurBgnd->fieldArray[i];
// save integer part of position
prevX = fracToInt(pPlay->fieldX);
prevY = fracToInt(pPlay->fieldY);
// update scrolling
pPlay->fieldX += pPlay->fieldXvel;
pPlay->fieldY += pPlay->fieldYvel;
// convert fixed point window pos to a int
ptWin.x = fracToInt(pPlay->fieldX);
ptWin.y = fracToInt(pPlay->fieldY);
// set the moved flag if the playfield has moved
if (prevX != ptWin.x || prevY != ptWin.y)
pPlay->bMoved = true;
// sort the display list for this background - just in case somebody has changed object Z positions
SortObjectList(&pPlay->pDispList);
// generate clipping rects for all objects that have moved etc.
FindMovingObjects(&pPlay->pDispList, &ptWin,
&pPlay->rcClip, false, pPlay->bMoved);
// clear playfield moved flag
pPlay->bMoved = false;
}
// merge the clipping rectangles
MergeClipRect();
// redraw all playfields within the clipping rectangles
const RectList &clipRects = GetClipRects();
for (RectList::const_iterator r = clipRects.begin(); r != clipRects.end(); ++r) {
// clear the clip rectangle on the virtual screen
// for each background playfield
for (unsigned int i = 0; i < _pCurBgnd->fieldArray.size(); i++) {
Common::Rect rcPlayClip; // clip rect for this playfield
// get pointer to correct playfield
pPlay = &_pCurBgnd->fieldArray[i];
// convert fixed point window pos to a int
ptWin.x = fracToInt(pPlay->fieldX);
ptWin.y = fracToInt(pPlay->fieldY);
if (IntersectRectangle(rcPlayClip, pPlay->rcClip, *r))
// redraw all objects within this clipping rect
UpdateClipRect(&pPlay->pDispList, &ptWin, &rcPlayClip);
}
}
if (!TinselV3) {
// transfer any new palettes to the video DAC
PalettesToVideoDAC();
}
// update the screen within the clipping rectangles
for (RectList::const_iterator r = clipRects.begin(); r != clipRects.end(); ++r) {
UpdateScreenRect(*r);
}
g_system->updateScreen();
// delete all the clipping rectangles
ResetClipRect();
}
int Background::BgWidth() {
assert(_pBG[0]);
return MultiRightmost(_pBG[0]) + 1;
}
int Background::BgHeight() {
assert(_pBG[0]);
return MultiLowest(_pBG[0]) + 1;
}
void Background::SetBackPal(SCNHANDLE hPal) {
_hBgPal = hPal;
_font->FettleFontPal(_hBgPal);
CreateTranslucentPalette(_hBgPal);
}
void Background::DropBackground() {
_pBG[0] = nullptr; // No background
if (!TinselV2)
_hBgPal = 0; // No background palette
}
void Background::ChangePalette(SCNHANDLE hPal) {
SwapPalette(FindPalette(_hBgPal), 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