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
|
/* 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/features.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 {
// 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;
/**
* A serial used to identify the creation order of planes, to ensure a
* stable sort order for planes with identical priorities.
*/
static uint32 _nextCreationId;
/**
* The creation order number, which ensures a stable sort when planes with
* identical priorities are added to the plane list.
*/
uint32 _creationId;
/**
* 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();
// In SSCI this constructor signature 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) {
// This is different than SSCI; see ScreenItem::operator< for an
// explanation
return _creationId < other._creationId;
}
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 called UpdatePlane in SSCI.
*/
void sync(const Plane *other, const Common::Rect &screenRect);
/**
* Updates the plane to match the state of the plane object from the VM.
*
* @note This method was called UpdatePlane in SSCI.
*/
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);
/**
* The default plane is the first plane generated inside the graphics engine.
*/
inline bool isDefaultPlane() {
return _object.isNumber() && _object.getOffset() == (uint32)g_sci->_features->detectPlaneIdBase();
}
#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);
/**
* Marks all non-deleted remapped screen items within the plane as needing
* to be updated during the next frameout.
*/
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
|