1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  * Background handling code.
22  */
23 
24 #include "tinsel/background.h"
25 #include "tinsel/cliprect.h"	// object clip rect defs
26 #include "tinsel/graphics.h"
27 #include "tinsel/sched.h"	// process sheduler defs
28 #include "tinsel/object.h"
29 #include "tinsel/pid.h"	// process identifiers
30 #include "tinsel/tinsel.h"
31 
32 namespace Tinsel {
33 
34 // FIXME: Avoid non-const global vars
35 
36 // current background
37 const BACKGND *g_pCurBgnd = NULL;
38 
39 /**
40  * Called to initialize a background.
41  * @param pBgnd			Pointer to data struct for current background
42  */
43 
InitBackground(const BACKGND * pBgnd)44 void InitBackground(const BACKGND *pBgnd) {
45 	int i;			// playfield counter
46 	PLAYFIELD *pPlayfield;	// pointer to current playfield
47 
48 	// set current background
49 	g_pCurBgnd = pBgnd;
50 
51 	// init background sky color
52 	SetBgndColor(pBgnd->rgbSkyColor);
53 
54 	// start of playfield array
55 	pPlayfield = pBgnd->fieldArray;
56 
57 	// for each background playfield
58 	for (i = 0; i < pBgnd->numPlayfields; i++, pPlayfield++) {
59 		// init playfield pos
60 		pPlayfield->fieldX = intToFrac(pBgnd->ptInitWorld.x);
61 		pPlayfield->fieldY = intToFrac(pBgnd->ptInitWorld.y);
62 
63 		// no scrolling
64 		pPlayfield->fieldXvel = intToFrac(0);
65 		pPlayfield->fieldYvel = intToFrac(0);
66 
67 		// clear playfield display list
68 		pPlayfield->pDispList = NULL;
69 
70 		// clear playfield moved flag
71 		pPlayfield->bMoved = false;
72 	}
73 }
74 
75 /**
76  * Sets the xy position of the specified playfield in the current background.
77  * @param which			Which playfield
78  * @param newXpos		New x position
79  * @param newYpos		New y position
80  */
81 
PlayfieldSetPos(int which,int newXpos,int newYpos)82 void PlayfieldSetPos(int which, int newXpos, int newYpos) {
83 	PLAYFIELD *pPlayfield;	// pointer to relavent playfield
84 
85 	// make sure there is a background
86 	assert(g_pCurBgnd != NULL);
87 
88 	// make sure the playfield number is in range
89 	assert(which >= 0 && which < g_pCurBgnd->numPlayfields);
90 
91 	// get playfield pointer
92 	pPlayfield = g_pCurBgnd->fieldArray + which;
93 
94 	// set new integer position
95 	pPlayfield->fieldX = intToFrac(newXpos);
96 	pPlayfield->fieldY = intToFrac(newYpos);
97 
98 	// set moved flag
99 	pPlayfield->bMoved = true;
100 }
101 
102 /**
103  * Returns the xy position of the specified playfield in the current background.
104  * @param which			Which playfield
105  * @param pXpos			Returns current x position
106  * @param pYpos			Returns current y position
107  */
108 
PlayfieldGetPos(int which,int * pXpos,int * pYpos)109 void PlayfieldGetPos(int which, int *pXpos, int *pYpos) {
110 	PLAYFIELD *pPlayfield;	// pointer to relavent playfield
111 
112 	// make sure there is a background
113 	assert(g_pCurBgnd != NULL);
114 
115 	// make sure the playfield number is in range
116 	assert(which >= 0 && which < g_pCurBgnd->numPlayfields);
117 
118 	// get playfield pointer
119 	pPlayfield = g_pCurBgnd->fieldArray + which;
120 
121 	// get current integer position
122 	*pXpos = fracToInt(pPlayfield->fieldX);
123 	*pYpos = fracToInt(pPlayfield->fieldY);
124 }
125 
126 /**
127  * Returns the x position of the center of the specified playfield
128  * @param which			Which playfield
129  */
130 
PlayfieldGetCenterX(int which)131 int PlayfieldGetCenterX(int which) {
132 	PLAYFIELD *pPlayfield; // pointer to relavent playfield
133 
134 	// make sure there is a background
135 	assert(g_pCurBgnd != NULL);
136 
137 	// make sure the playfield number is in range
138 	assert(which >= 0 && which < g_pCurBgnd->numPlayfields);
139 
140 	// get playfield pointer
141 	pPlayfield = g_pCurBgnd->fieldArray + which;
142 
143 	// get current integer position
144 	return fracToInt(pPlayfield->fieldX) + SCREEN_WIDTH/2;
145 }
146 
147 /**
148  * Returns the display list for the specified playfield.
149  * @param which			Which playfield
150  */
151 
GetPlayfieldList(int which)152 OBJECT **GetPlayfieldList(int which) {
153 	PLAYFIELD *pPlayfield;	// pointer to relavent playfield
154 
155 	// make sure there is a background
156 	assert(g_pCurBgnd != NULL);
157 
158 	// make sure the playfield number is in range
159 	assert(which >= 0 && which < g_pCurBgnd->numPlayfields);
160 
161 	// get playfield pointer
162 	pPlayfield = g_pCurBgnd->fieldArray + which;
163 
164 	// return the display list pointer for this playfield
165 	return &pPlayfield->pDispList;
166 }
167 
168 /**
169  * Draws all the playfield object lists for the current background.
170  * The playfield velocity is added to the playfield position in order
171  * to scroll each playfield before it is drawn.
172  */
173 
DrawBackgnd()174 void DrawBackgnd() {
175 	int i;			// playfield counter
176 	PLAYFIELD *pPlay;	// playfield pointer
177 	int prevX, prevY;	// save interger part of position
178 	Common::Point ptWin;	// window top left
179 
180 	if (g_pCurBgnd == NULL)
181 		return;		// no current background
182 
183 	// scroll each background playfield
184 	for (i = 0; i < g_pCurBgnd->numPlayfields; i++) {
185 		// get pointer to correct playfield
186 		pPlay = g_pCurBgnd->fieldArray + i;
187 
188 		// save integer part of position
189 		prevX = fracToInt(pPlay->fieldX);
190 		prevY = fracToInt(pPlay->fieldY);
191 
192 		// update scrolling
193 		pPlay->fieldX += pPlay->fieldXvel;
194 		pPlay->fieldY += pPlay->fieldYvel;
195 
196 		// convert fixed point window pos to a int
197 		ptWin.x = fracToInt(pPlay->fieldX);
198 		ptWin.y = fracToInt(pPlay->fieldY);
199 
200 		// set the moved flag if the playfield has moved
201 		if (prevX != ptWin.x || prevY != ptWin.y)
202 			pPlay->bMoved = true;
203 
204 		// sort the display list for this background - just in case somebody has changed object Z positions
205 		SortObjectList(&pPlay->pDispList);
206 
207 		// generate clipping rects for all objects that have moved etc.
208 		FindMovingObjects(&pPlay->pDispList, &ptWin,
209 			&pPlay->rcClip,	false, pPlay->bMoved);
210 
211 		// clear playfield moved flag
212 		pPlay->bMoved = false;
213 	}
214 
215 	// merge the clipping rectangles
216 	MergeClipRect();
217 
218 	// redraw all playfields within the clipping rectangles
219 	const RectList &clipRects = GetClipRects();
220 	for (RectList::const_iterator r = clipRects.begin(); r != clipRects.end(); ++r) {
221 		// clear the clip rectangle on the virtual screen
222 		// for each background playfield
223 		for (i = 0; i < g_pCurBgnd->numPlayfields; i++) {
224 			Common::Rect rcPlayClip;	// clip rect for this playfield
225 
226 			// get pointer to correct playfield
227 			pPlay = g_pCurBgnd->fieldArray + i;
228 
229 			// convert fixed point window pos to a int
230 			ptWin.x = fracToInt(pPlay->fieldX);
231 			ptWin.y = fracToInt(pPlay->fieldY);
232 
233 			if (IntersectRectangle(rcPlayClip, pPlay->rcClip, *r))
234 				// redraw all objects within this clipping rect
235 				UpdateClipRect(&pPlay->pDispList, &ptWin,	&rcPlayClip);
236 		}
237 	}
238 
239 	// transfer any new palettes to the video DAC
240 	PalettesToVideoDAC();
241 
242 	// update the screen within the clipping rectangles
243 	for (RectList::const_iterator r = clipRects.begin(); r != clipRects.end(); ++r) {
244 		UpdateScreenRect(*r);
245 	}
246 
247 	g_system->updateScreen();
248 
249 	// delete all the clipping rectangles
250 	ResetClipRect();
251 }
252 
253 } // End of namespace Tinsel
254