/* 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_SCREEN_ITEM32_H #define SCI_GRAPHICS_SCREEN_ITEM32_H #include "common/rect.h" #include "sci/graphics/celobj32.h" #include "sci/graphics/lists32.h" namespace Sci { enum ScaleSignals32 { kScaleSignalNone = 0, kScaleSignalManual = 1, kScaleSignalVanishingPoint = 2 }; struct ScaleInfo { int x, y, max; ScaleSignals32 signal; ScaleInfo() : x(128), y(128), max(100), signal(kScaleSignalNone) {} }; class CelObj; class Plane; class SegManager; #pragma mark - #pragma mark ScreenItem /** * A ScreenItem is the engine-side representation of a game script View. */ class ScreenItem { private: /** * A serial used for screen items that are generated inside the graphics * engine, rather than the interpreter. */ static uint16 _nextObjectId; /** * A serial used to identify the creation order of screen items, to ensure a * stable sort order for screen items with identical priorities and * z-indexes. */ static uint32 _nextCreationId; public: /** * The parent plane of this screen item. */ reg_t _plane; /** * Scaling data used to calculate the final screen dimensions of the screen * item as well as the scaling ratios used when drawing the item to screen. */ ScaleInfo _scale; private: /** * The position & dimensions of the screen item in screen coordinates. This * rect includes the offset of the parent plane, but is not clipped to the * screen, so may include coordinates that are offscreen. */ Common::Rect _screenItemRect; /** * If true, the `_insetRect` rectangle will be used when calculating the * dimensions of the screen item instead of the cel's intrinsic width and * height. * * In other words, using an inset rect means that the cel is cropped to the * dimensions given in `_insetRect`. */ bool _useInsetRect; /** * The cropping rectangle used when `_useInsetRect` is true. * * `_insetRect` is also used to describe the fill rectangle of a screen item * with a CelObjColor cel. */ Common::Rect _insetRect; /** * The z-index of the screen item in pseudo-3D space. Higher values are * drawn on top of lower values. */ int _z; /** * Sets the common properties of a screen item that must be set both during * creation and update of a screen item. */ void setFromObject(SegManager *segMan, const reg_t object, const bool updateCel, const bool updateBitmap); public: /** * The creation order number, which ensures a stable sort when screen items * with identical priorities and z-indexes are added to the screen item * list. */ uint32 _creationId; /** * A descriptor for the cel object represented by the screen item. */ CelInfo32 _celInfo; /** * The cel object used to actually render the screen item. This member is * populated by calling `getCelObj`. */ mutable Common::ScopedPtr _celObj; /** * If set, the priority for this screen item is fixed in place. Otherwise, * the priority of the screen item is calculated from its y-position + * z-index. */ bool _fixedPriority; /** * The rendering priority of the screen item, relative only to the other * screen items within the same plane. Higher priorities are drawn above * lower priorities. */ int16 _priority; /** * The top-left corner of the screen item, in game script coordinates, * relative to the parent plane. */ Common::Point _position; /** * The associated View script object that was used to create the ScreenItem, * or a numeric value in the case of a ScreenItem that was generated by the * kernel. */ reg_t _object; /** * For screen items representing picture resources, the resource ID of the * picture. */ GuiResourceId _pictureId; /** * Flags indicating the state of the screen item. * - `created` is set when the screen item is first created, either from a * VM object or from within the kernel * - `updated` is set when `created` is not already set and the screen item * is updated from a VM object * - `deleted` is set by the parent plane, if the parent plane is a pic type * and its picture resource ID has changed */ int _created, _updated, _deleted; /** * For screen items that represent picture cels, this value is set to match * the `_mirrorX` property of the parent plane and indicates that the cel * should be * drawn horizontally mirrored. For final drawing, it is XORed with the * `_mirrorX` property of the cel object. The cel object's `_mirrorX` * property comes from the resource data. */ bool _mirrorX; /** * The scaling ratios to use when drawing this screen item. These values are * calculated according to the scale info whenever the screen item is * updated. */ Ratio _ratioX, _ratioY; /** * The top-left corner of the screen item, in screen coordinates. */ Common::Point _scaledPosition; /** * The position & dimensions of the screen item in screen coordinates. This * rect includes the offset of the parent plane and is clipped to the * screen. */ Common::Rect _screenRect; /** * Whether or not the screen item should be drawn with black lines drawn * every second line. This is used when pixel doubling videos to improve * apparent sharpness at the cost of your eyesight. */ bool _drawBlackLines; /** * Initialises static Plane members. */ static void init(); ScreenItem(const reg_t screenItem); ScreenItem(const reg_t plane, const CelInfo32 &celInfo); ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Rect &rect); ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Point &position, const ScaleInfo &scaleInfo); ScreenItem(const ScreenItem &other); void operator=(const ScreenItem &); inline bool operator<(const ScreenItem &other) const { if (_priority < other._priority) { return true; } if (_priority == other._priority) { if (_position.y + _z < other._position.y + other._z) { return true; } if (_position.y + _z == other._position.y + other._z) { // Synthetic object IDs (numeric IDs) are used for screen items // generated by the kernel, like the screen items generated by // plane pics. In SSCI, these synthetic IDs started at 20000 so // would deterministically always sort higher than any // script-generated view in SSCI at the same position and // priority. if (other._object.isNumber() && !_object.isNumber()) { return true; } // SSCI's last resort comparison here is to compare the _object // IDs, but this is wrong and randomly breaks (at least): // // (1) the death dialog at the end of Phant1, where the ID of // the text is often higher than the ID of the border; // (2) text-based buttons and dialogues in Hoyle5, where the ID // of the text is often lower than the ID of the // button/dialogue background. // // This occurs because object IDs (in both ScummVM and SSCI) are // reused, so objects created later may receive a lower ID, // which makes them sort lower when the programmer intended them // to sort higher. // // To fix this problem, we give each ScreenItem a monotonically // increasing insertion ID at construction time, and compare // these insertion IDs instead. They are more stable and cause // objects with identical priority and z-index to be rendered in // the order that they were created. // // This also applies to ScreenItem::hasPriorityAbove. return _creationId < other._creationId; } } return false; } inline bool operator>(const ScreenItem &other) const { if (_priority > other._priority) { return true; } if (_priority == other._priority) { if (_position.y + _z > other._position.y + other._z) { return true; } if (_position.y + _z == other._position.y + other._z) { if (_object.isNumber() && !other._object.isNumber()) { return true; } // This is different than SSCI; see ScreenItem::operator< for an // explanation return _creationId > other._creationId; } } return false; } inline bool hasPriorityAbove(const ScreenItem &other) const { if (_priority > other._priority) { return true; } if (_priority == other._priority) { if (_object.isNumber() && !other._object.isNumber()) { return true; } // This is different than SSCI; see ScreenItem::operator< for an // explanation return _creationId > other._creationId; } return false; } /** * Calculates the dimensions and scaling parameters for the screen item, * using the given plane as the parent plane for screen rect positioning. * * @note This method was called Update in SSCI. */ void calcRects(const Plane &plane); /** * Retrieves the corresponding cel object for this screen item. If a cel * object does not already exist, one will be created and assigned. */ CelObj &getCelObj() const; void printDebugInfo(Console *con) const; /** * Updates the properties of the screen item from a VM object. */ void update(const reg_t object); /** * Updates the properties of the screen item for one not belonging to a VM * object. Originally GraphicsMgr::UpdateScreenItem. */ void update(); /** * Gets the "now seen" rect for the screen item, which represents the * current size and position of the screen item on the screen in script * coordinates. */ Common::Rect getNowSeenRect(const Plane &plane) const; }; #pragma mark - #pragma mark ScreenItemList typedef StablePointerArray ScreenItemListBase; class ScreenItemList : public ScreenItemListBase { private: size_type _unsorted[250]; public: ScreenItem *findByObject(const reg_t object) const; void sort(); void unsort(); }; } // End of namespace Sci #endif