scummvm/engines/tinsel/background.cpp
2014-02-18 02:39:39 +01:00

254 lines
7.1 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/graphics.h"
#include "tinsel/sched.h" // process sheduler defs
#include "tinsel/object.h"
#include "tinsel/pid.h" // process identifiers
#include "tinsel/tinsel.h"
namespace Tinsel {
// FIXME: Avoid non-const global vars
// current background
const BACKGND *g_pCurBgnd = NULL;
/**
* Called to initialize a background.
* @param pBgnd Pointer to data struct for current background
*/
void InitBackground(const BACKGND *pBgnd) {
int i; // playfield counter
PLAYFIELD *pPlayfield; // pointer to current playfield
// set current background
g_pCurBgnd = pBgnd;
// init background sky color
SetBgndColor(pBgnd->rgbSkyColor);
// start of playfield array
pPlayfield = pBgnd->fieldArray;
// for each background playfield
for (i = 0; i < pBgnd->numPlayfields; i++, pPlayfield++) {
// init playfield pos
pPlayfield->fieldX = intToFrac(pBgnd->ptInitWorld.x);
pPlayfield->fieldY = intToFrac(pBgnd->ptInitWorld.y);
// no scrolling
pPlayfield->fieldXvel = intToFrac(0);
pPlayfield->fieldYvel = intToFrac(0);
// clear playfield display list
pPlayfield->pDispList = NULL;
// clear playfield moved flag
pPlayfield->bMoved = false;
}
}
/**
* 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 PlayfieldSetPos(int which, int newXpos, int newYpos) {
PLAYFIELD *pPlayfield; // pointer to relavent playfield
// make sure there is a background
assert(g_pCurBgnd != NULL);
// make sure the playfield number is in range
assert(which >= 0 && which < g_pCurBgnd->numPlayfields);
// get playfield pointer
pPlayfield = g_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 PlayfieldGetPos(int which, int *pXpos, int *pYpos) {
PLAYFIELD *pPlayfield; // pointer to relavent playfield
// make sure there is a background
assert(g_pCurBgnd != NULL);
// make sure the playfield number is in range
assert(which >= 0 && which < g_pCurBgnd->numPlayfields);
// get playfield pointer
pPlayfield = g_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 PlayfieldGetCenterX(int which) {
PLAYFIELD *pPlayfield; // pointer to relavent playfield
// make sure there is a background
assert(g_pCurBgnd != NULL);
// make sure the playfield number is in range
assert(which >= 0 && which < g_pCurBgnd->numPlayfields);
// get playfield pointer
pPlayfield = g_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 **GetPlayfieldList(int which) {
PLAYFIELD *pPlayfield; // pointer to relavent playfield
// make sure there is a background
assert(g_pCurBgnd != NULL);
// make sure the playfield number is in range
assert(which >= 0 && which < g_pCurBgnd->numPlayfields);
// get playfield pointer
pPlayfield = g_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 DrawBackgnd() {
int i; // playfield counter
PLAYFIELD *pPlay; // playfield pointer
int prevX, prevY; // save interger part of position
Common::Point ptWin; // window top left
if (g_pCurBgnd == NULL)
return; // no current background
// scroll each background playfield
for (i = 0; i < g_pCurBgnd->numPlayfields; i++) {
// get pointer to correct playfield
pPlay = g_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 (i = 0; i < g_pCurBgnd->numPlayfields; i++) {
Common::Rect rcPlayClip; // clip rect for this playfield
// get pointer to correct playfield
pPlay = g_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);
}
}
// 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();
}
} // End of namespace Tinsel