aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/graphics/plane32.h
blob: 964d20ca129c8cdd73e21db31c36c9239619dce8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
/* 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.
 *
 */

#ifndef SCI_GRAPHICS_PLANE32_H
#define SCI_GRAPHICS_PLANE32_H

#include "common/array.h"
#include "common/rect.h"
#include "sci/engine/vm_types.h"
#include "sci/graphics/helpers.h"
#include "sci/graphics/lists32.h"
#include "sci/graphics/screen_item32.h"

namespace Sci {
enum PlaneType {
	kPlaneTypeColored            = 0,
	kPlaneTypePicture            = 1,
	kPlaneTypeTransparent        = 2,
	kPlaneTypeOpaque             = 3,
	kPlaneTypeTransparentPicture = 4
};

enum PlanePictureCodes {
	// NOTE: Any value at or below 65531 means the plane
	// is a kPlaneTypePicture.
	kPlanePic                   = 65531,
	kPlanePicTransparentPicture = 65532,
	kPlanePicOpaque             = 65533,
	kPlanePicTransparent        = 65534,
	kPlanePicColored            = 65535
};

#pragma mark -
#pragma mark RectList

typedef StablePointerArray<Common::Rect, 200> RectListBase;
class RectList : public RectListBase {
public:
	void add(const Common::Rect &rect) {
		RectListBase::add(new Common::Rect(rect));
	}
};

#pragma mark -
#pragma mark DrawList

struct DrawItem {
	/**
	 * The screen item to draw.
	 */
	ScreenItem *screenItem;

	/**
	 * The target rectangle of the draw operation.
	 */
	Common::Rect rect;

	inline bool operator<(const DrawItem &other) const {
		return *screenItem < *other.screenItem;
	}
};

typedef StablePointerArray<DrawItem, 250> DrawListBase;
class DrawList : public DrawListBase {
private:
	inline static bool sortHelper(const DrawItem *a, const DrawItem *b) {
		return *a < *b;
	}
public:
	void add(ScreenItem *screenItem, const Common::Rect &rect);
	inline void sort() {
		pack();
		Common::sort(begin(), end(), sortHelper);
	}
};

class PlaneList;

#pragma mark -
#pragma mark Plane

/**
 * A plane is a grouped layer of screen items.
 */
class Plane {
private:
	/**
	 * A serial used for planes that are generated inside
	 * the graphics engine, rather than the interpreter.
	 */
	static uint16 _nextObjectId;

	/**
	 * For planes that are used to render picture data, the
	 * resource ID of the picture to be displayed. This
	 * value may also be one of the special
	 * PlanePictureCodes, in which case the plane becomes a
	 * non-picture plane.
	 */
	GuiResourceId _pictureId;

	/**
	 * Whether or not the contents of picture planes should
	 * be drawn horizontally mirrored. Only applies to
	 * planes of type kPlaneTypePicture.
	 */
	bool _mirrored;

	/**
	 * Whether the picture ID for this plane has changed.
	 * This flag is set when the plane is created or updated
	 * from a VM object, and is cleared when the plane is
	 * synchronised to another plane (which calls
	 * changePic).
	 */
	bool _pictureChanged;

	/**
	 * Converts the dimensions of the game rect used by
	 * scripts to the dimensions of the plane rect used to
	 * render content to the screen. Coordinates with
	 * remainders are rounded up to the next whole pixel.
	 */
	void convertGameRectToPlaneRect();

	/**
	 * Sets the type of the plane according to its assigned
	 * picture resource ID.
	 */
	void setType();

public:
	/**
	 * The type of the plane.
	 */
	PlaneType _type;

	/**
	 * The color to use when erasing the plane. Only
	 * applies to planes of type kPlaneTypeColored.
	 */
	byte _back;

	/**
	 * Whether the priority of this plane has changed.
	 * This flag is set when the plane is updated from
	 * another plane and cleared when draw list calculation
	 * occurs.
	 */
	int _priorityChanged;

	/**
	 * A handle to the VM object corresponding to this
	 * plane. Some planes are generated purely within the
	 * graphics engine and have a numeric object value.
	 */
	reg_t _object;

	/**
	 * The rendering priority of the plane. Higher
	 * priorities are drawn above lower priorities.
	 */
	int16 _priority;

	/**
	 * Whether or not all screen items in this plane should
	 * be redrawn on the next frameout, instead of just
	 * the screen items marked as updated. This is set when
	 * visual changes to the plane itself are made that
	 * affect the rendering of the entire plane, and cleared
	 * once those changes are rendered by `redrawAll`.
	 */
	int _redrawAllCount;

	/**
	 * Flags indicating the state of the plane.
	 * - `created` is set when the plane is first created,
	 *   either from a VM object or from within the engine
	 *   itself
	 * - `updated` is set when the plane is updated from
	 *   another plane and the two planes' `planeRect`s do
	 *   not match
	 * - `deleted` is set when the plane is deleted by a
	 *   kernel call
	 * - `moved` is set when the plane has been moved or
	 *   resized
	 */
	int _created, _updated, _deleted, _moved;

	/**
	 * The vanishing point for the plane. Used when
	 * automatically calculating the correct scaling of the
	 * plane's screen items according to their position.
	 */
	Common::Point _vanishingPoint;

	/**
	 * The position & dimensions of the plane in screen
	 * coordinates. This rect is not clipped to the screen,
	 * so may include coordinates that are offscreen.
	 */
	Common::Rect _planeRect;

	/**
	 * The position & dimensions of the plane in game script
	 * coordinates.
	 */
	Common::Rect _gameRect;

	/**
	 * The position & dimensions of the plane in screen
	 * coordinates. This rect is clipped to the screen.
	 */
	Common::Rect _screenRect;

	/**
	 * The list of screen items grouped within this plane.
	 */
	ScreenItemList _screenItemList;

public:
	/**
	 * Initialises static Plane members.
	 */
	static void init();

	// NOTE: This constructor signature originally did not accept a
	// picture ID, but some calls to construct planes with this signature
	// immediately set the picture ID and then called setType again, so
	// it made more sense to just make the picture ID a parameter instead.
	Plane(const Common::Rect &gameRect, PlanePictureCodes pictureId = kPlanePicColored);

	Plane(const reg_t object);

	Plane(const Plane &other);

	void operator=(const Plane &other);

	inline bool operator<(const Plane &other) const {
		if (_priority < other._priority) {
			return true;
		}

		if (_priority == other._priority) {
			return _object < other._object;
		}

		return false;
	}

	/**
	 * Clips the screen rect of this plane to fit within the
	 * given screen rect.
	 */
	inline void clipScreenRect(const Common::Rect &screenRect) {
		// LSL6 hires creates planes with invalid rects; SSCI does not
		// care about this, but `Common::Rect::clip` does, so we need to
		// check whether or not the rect is actually valid before clipping
		// and only clip valid rects
		if (_screenRect.isValidRect() && _screenRect.intersects(screenRect)) {
			_screenRect.clip(screenRect);
		} else {
			_screenRect.left = 0;
			_screenRect.top = 0;
			_screenRect.right = 0;
			_screenRect.bottom = 0;
		}
	}

	void printDebugInfo(Console *con) const;

	/**
	 * Compares the properties of the current plane against
	 * the properties of the `other` plane (which is the
	 * corresponding plane from the visible plane list) to
	 * discover which properties have been changed on this
	 * plane by a call to `update(reg_t)`.
	 *
	 * @note This method was originally called UpdatePlane
	 * in SCI engine.
	 */
	void sync(const Plane *other, const Common::Rect &screenRect);

	/**
	 * Updates the plane to match the state of the plane
	 * object from the virtual machine.
	 *
	 * @note This method was originally called UpdatePlane
	 * in SCI engine.
	 */
	void update(const reg_t object);

	/**
	 * Modifies the position of all non-pic screen items
	 * by the given delta. If `scrollPics` is true, pic
	 * items are also repositioned.
	 */
	void scrollScreenItems(const int16 deltaX, const int16 deltaY, const bool scrollPics);

#pragma mark -
#pragma mark Plane - Pic
private:
	/**
	 * Adds all cels from the specified picture resource to
	 * the plane as screen items. If a position is provided,
	 * the screen items will be given that position;
	 * otherwise, the default relative positions for each
	 * cel will be taken from the picture resource data.
	 */
	inline void addPicInternal(const GuiResourceId pictureId, const Common::Point *position, const bool mirrorX);

	/**
	 * Marks all screen items to be deleted that are within
	 * this plane and match the given picture ID.
	 */
	void deletePic(const GuiResourceId pictureId);

	/**
	 * Marks all screen items to be deleted that are within
	 * this plane and are picture cels.
	 */
	void deleteAllPics();

public:
	/**
	 * Marks all existing screen items matching the current
	 * picture to be deleted, then adds all cels from the
	 * new picture resource to the plane at the given
	 * position.
	 */
	GuiResourceId addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX, const bool deleteDuplicate = true);

	/**
	 * If the plane is a picture plane, re-adds all cels
	 * from its picture resource to the plane. Otherwise,
	 * just clears the _pictureChanged flag.
	 */
	void changePic();

	/**
	 * Marks all screen items to be deleted that are within
	 * this plane and match the given picture ID, then sets
	 * the picture ID of the plane to the new picture ID
	 * without adding any screen items.
	 */
	void deletePic(const GuiResourceId oldPictureId, const GuiResourceId newPictureId);

#pragma mark -
#pragma mark Plane - Rendering
private:
	/**
	 * Splits all rects in the given draw list at the edges
	 * of all higher-priority, non-transparent, intersecting
	 * planes.
	 */
	void breakDrawListByPlanes(DrawList &drawList, const PlaneList &planeList) const;

	/**
	 * Splits all rects in the given erase list at the
	 * edges of higher-priority, non-transparent,
	 * intersecting planes.
	 */
	void breakEraseListByPlanes(RectList &eraseList, const PlaneList &planeList) const;

	/**
	 * Adds the screen item at `index` into `drawList`,
	 * ensuring it is only drawn within the bounds of
	 * `rect`. If an existing draw list entry exists
	 * for this screen item, it will be modified.
	 * Otherwise, a new entry will be added.
	 */
	void mergeToDrawList(const DrawList::size_type index, const Common::Rect &rect, DrawList &drawList) const;

	/**
	 * Merges `rect` with an existing rect in `eraseList`,
	 * if possible. Otherwise, adds the rect as a new entry
	 * to `eraseList`.
	 */
	void mergeToRectList(const Common::Rect &rect, RectList &eraseList) const;

public:
	/**
	 * Calculates the location and dimensions of dirty rects
	 * of the screen items in this plane and adds them to
	 * the given draw and erase lists, and synchronises this
	 * plane's list of screen items to the given visible
	 * plane.
	 */
	void calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList &drawList, RectList &eraseList);

	/**
	 * Synchronises changes to screen items from the current
	 * plane to the visible plane and deletes screen items
	 * from the current plane that have been marked as
	 * deleted. If `forceUpdate` is true, all screen items
	 * on the visible plane will be updated, even if they
	 * are not marked as having changed.
	 */
	void decrementScreenItemArrayCounts(Plane *visiblePlane, const bool forceUpdate);

	/**
	 * This method is called from the highest priority plane
	 * to the lowest priority plane.
	 *
	 * Adds screen items from this plane to the draw list
	 * that must be redrawn because they intersect entries
	 * in the `higherEraseList`.
	 *
	 * If this plane is opaque, all intersecting erase rects
	 * in `lowerEraseList` are removed, as they would be
	 * completely overwritten by the contents of this plane.
	 *
	 * If this plane is transparent, erase rects from the
	 * `lowerEraseList` are added to the erase list for this
	 * plane, so that lower planes.
	 *
	 * @param drawList The draw list for this plane.
	 * @param eraseList The erase list for this plane.
	 * @param higherEraseList The erase list for a plane
	 * above this plane.
	 */
	void filterDownEraseRects(DrawList &drawList, RectList &eraseList, RectList &higherEraseList) const;

	/**
	 * This method is called from the lowest priority plane
	 * to the highest priority plane.
	 *
	 * Adds screen items from this plane to the draw list
	 * that must be drawn because the lower plane is being
	 * redrawn and potentially transparent screen items
	 * from this plane would draw over the lower priority
	 * plane's screen items.
	 *
	 * This method applies only to transparent planes.
	 *
	 * @param drawList The draw list for this plane.
	 * @param eraseList The erase list for a plane below
	 * this plane.
	 */
	void filterUpEraseRects(DrawList &drawList, const RectList &lowerEraseList) const;

	/**
	 * This method is called from the lowest priority plane
	 * to the highest priority plane.
	 *
	 * Adds screen items from this plane to the draw list
	 * that must be drawn because the lower plane is being
	 * redrawn and potentially transparent screen items
	 * from this plane would draw over the lower priority
	 * plane's screen items.
	 *
	 * This method applies only to transparent planes.
	 *
	 * @param drawList The draw list for this plane.
	 * @param lowerDrawList The draw list for a plane below
	 * this plane.
	 */
	void filterUpDrawRects(DrawList &drawList, const DrawList &lowerDrawList) const;

	/**
	 * Updates all of the plane's non-deleted screen items
	 * and adds them to the given draw and erase lists.
	 */
	void redrawAll(Plane *visiblePlane, const PlaneList &planeList, DrawList &drawList, RectList &eraseList);

	void remapMarkRedraw();
};

#pragma mark -
#pragma mark PlaneList

typedef Common::Array<Plane *> PlaneListBase;
class PlaneList : public PlaneListBase {
private:
	inline static bool sortHelper(const Plane *a, const Plane *b) {
		return *a < *b;
	}

	using PlaneListBase::push_back;

public:
	// A method for finding the index of a plane inside a
	// PlaneList is used because entries in the main plane
	// list and visible plane list of GfxFrameout are
	// synchronised by index
	int findIndexByObject(const reg_t object) const;
	Plane *findByObject(const reg_t object) const;

	/**
	 * Gets the priority of the top plane in the plane list.
	 */
	int16 getTopPlanePriority() const;

	/**
	 * Gets the priority of the top plane in the plane list
	 * created by a game script.
	 */
	int16 getTopSciPlanePriority() const;

	void add(Plane *plane);
	void clear();
	iterator erase(iterator it);
	void erase(Plane *plane);
	inline void sort() {
		Common::sort(begin(), end(), sortHelper);
	}
	void remove_at(size_type index);
};

} // End of namespace Sci

#endif