scummvm/engines/sci/graphics/plane32.h
Colin Snover 31e1d0932c SCI32: Clean up Plane
* Rewrap comments to 80 columns
* Clarify comments where possible
2017-10-06 22:11:03 -05:00

510 lines
15 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.
*
*/
#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 {
// 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);
#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