diff options
Diffstat (limited to 'engines/sci/graphics/celobj32.h')
-rw-r--r-- | engines/sci/graphics/celobj32.h | 607 |
1 files changed, 607 insertions, 0 deletions
diff --git a/engines/sci/graphics/celobj32.h b/engines/sci/graphics/celobj32.h new file mode 100644 index 0000000000..eb6ce3a3c9 --- /dev/null +++ b/engines/sci/graphics/celobj32.h @@ -0,0 +1,607 @@ +/* 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_CELOBJ32_H +#define SCI_GRAPHICS_CELOBJ32_H + +#include "common/rational.h" +#include "common/rect.h" +#include "sci/resource.h" +#include "sci/engine/vm_types.h" + +namespace Sci { +typedef Common::Rational Ratio; + +// SCI32 has four different coordinate systems: +// 1. low resolution, 2. game/script resolution, +// 3. text/bitmap resolution, 4. screen resolution +// +// In CelObj, these values are used when there is +// no baked in resolution of cels. +// +// In ScreenItem, it is used when deciding which +// path to take to calculate dimensions. +enum { + kLowResX = 320, + kLowResY = 200 +}; + +enum CelType { + kCelTypeView = 0, + kCelTypePic = 1, + kCelTypeMem = 2, + kCelTypeColor = 3 +}; + +enum CelCompressionType { + kCelCompressionNone = 0, + kCelCompressionRLE = 138, + kCelCompressionInvalid = 1000 +}; + +/** + * A CelInfo32 object describes the basic properties of a + * cel object. + */ +struct CelInfo32 { + /** + * The type of the cel object. + */ + CelType type; + + /** + * For cel objects that draw from resources, the ID of + * the resource to load. + */ + GuiResourceId resourceId; + + /** + * For CelObjView, the loop number to draw from the + * view resource. + */ + int16 loopNo; + + /** + * For CelObjView and CelObjPic, the cel number to draw + * from the view or pic resource. + */ + int16 celNo; + + /** + * For CelObjMem, a segment register pointing to a heap + * resource containing headered bitmap data. + */ + reg_t bitmap; + + /** + * For CelObjColor, the fill color. + */ + uint8 color; + + // NOTE: In at least SCI2.1/SQ6, color is left + // uninitialised. + CelInfo32() : + type(kCelTypeMem), + resourceId(0), + loopNo(0), + celNo(0), + bitmap(NULL_REG) {} + + // NOTE: This is the equivalence criteria used by + // CelObj::searchCache in at least SCI2.1/SQ6. Notably, + // it does not check the color field. + inline bool operator==(const CelInfo32 &other) { + return ( + type == other.type && + resourceId == other.resourceId && + loopNo == other.loopNo && + celNo == other.celNo && + bitmap == other.bitmap + ); + } + + inline bool operator!=(const CelInfo32 &other) { + return !(*this == other); + } +}; + +class CelObj; +struct CelCacheEntry { + /** + * A monotonically increasing cache ID used to identify + * the least recently used item in the cache for + * replacement. + */ + int id; + CelObj *celObj; + CelCacheEntry() : id(0), celObj(nullptr) {} +}; + +typedef Common::Array<CelCacheEntry> CelCache; + +#pragma mark - +#pragma mark CelScaler + +struct CelScalerTable { + /** + * A lookup table of indexes that should be used to find + * the correct column to read from the source bitmap + * when drawing a scaled version of the source bitmap. + */ + int valuesX[1024]; + + /** + * The ratio used to generate the x-values. + */ + Ratio scaleX; + + /** + * A lookup table of indexes that should be used to find + * the correct row to read from a source bitmap when + * drawing a scaled version of the source bitmap. + */ + int valuesY[1024]; + + /** + * The ratio used to generate the y-values. + */ + Ratio scaleY; +}; + +class CelScaler { + /** + * Cached scale tables. + */ + CelScalerTable _scaleTables[2]; + + /** + * The index of the most recently used scale table. + */ + int _activeIndex; + + /** + * Activates a scale table for the given X and Y ratios. + * If there is no table that matches the given ratios, + * the least most recently used table will be replaced + * and activated. + */ + void activateScaleTables(const Ratio &scaleX, const Ratio &scaleY); + + /** + * Builds a pixel lookup table in `table` for the given + * ratio. The table will be filled up to the specified + * size, which should be large enough to draw across the + * entire target buffer. + */ + void buildLookupTable(int *table, const Ratio &ratio, const int size); + +public: + CelScaler() : + _scaleTables(), + _activeIndex(0) { + CelScalerTable &table = _scaleTables[0]; + table.scaleX = Ratio(); + table.scaleY = Ratio(); + for (int i = 0; i < ARRAYSIZE(table.valuesX); ++i) { + table.valuesX[i] = i; + table.valuesY[i] = i; + } + for (int i = 1; i < ARRAYSIZE(_scaleTables); ++i) { + _scaleTables[i] = _scaleTables[0]; + } + } + + /** + * Retrieves scaler tables for the given X and Y ratios. + */ + const CelScalerTable *getScalerTable(const Ratio &scaleX, const Ratio &scaleY); +}; + +#pragma mark - +#pragma mark CelObj + +class ScreenItem; +/** + * A cel object is the lowest-level rendering primitive in + * the SCI engine and draws itself directly to a target + * pixel buffer. + */ +class CelObj { +protected: + /** + * When true, every second line of the cel will be + * rendered as a black line. + * + * @see ScreenItem::_drawBlackLines + * @note Using a static member because otherwise this + * would otherwise need to be copied down through + * several calls. (SSCI did similar, using a global + * variable.) + */ + static bool _drawBlackLines; + + /** + * When true, this cel will be horizontally mirrored + * when it is drawn. This is an internal flag that is + * set by draw methods based on the combination of the + * cel's `_mirrorX` property and the owner screen item's + * `_mirrorX` property. + */ + bool _drawMirrored; + +public: + static CelScaler *_scaler; + + /** + * The basic identifying information for this cel. This + * information effectively acts as a composite key for + * a cel object, and any cel object can be recreated + * from this data alone. + */ + CelInfo32 _info; + + /** + * The offset to the cel header for this cel within the + * raw resource data. + */ + uint32 _celHeaderOffset; + + /** + * The offset to the embedded palette for this cel + * within the raw resource data. + */ + uint32 _hunkPaletteOffset; + + /** + * The natural dimensions of the cel. + */ + uint16 _width, _height; + + /** + * TODO: Documentation + */ + Common::Point _displace; + + /** + * The dimensions of the original coordinate system for + * the cel. Used to scale cels from their native size + * to the correct size on screen. + * + * @note This is set to scriptWidth/Height for + * CelObjColor. For other cel objects, the value comes + * from the raw resource data. For text bitmaps, this is + * the width/height of the coordinate system used to + * generate the text, which also defaults to + * scriptWidth/Height but seems to typically be changed + * to more closely match the native screen resolution. + */ + uint16 _scaledWidth, _scaledHeight; + + /** + * The skip (transparent) color for the cel. When + * compositing, any pixels matching this color will not + * be copied to the buffer. + */ + uint8 _transparentColor; + + /** + * Whether or not this cel has any transparent regions. + * This is used for optimised drawing of non-transparent + * cels. + */ + bool _transparent; // TODO: probably "skip"? + + /** + * The compression type for the pixel data for this cel. + */ + CelCompressionType _compressionType; + + /** + * Whether or not this cel should be palette-remapped? + */ + bool _remap; + + /** + * If true, the cel contains pre-mirrored picture data. + * This value comes directly from the resource data and + * is XORed with the `_mirrorX` property of the owner + * screen item when rendering. + */ + bool _mirrorX; + + /** + * Initialises static CelObj members. + */ + static void init(); + + /** + * Frees static CelObj members. + */ + static void deinit(); + + virtual ~CelObj() {}; + + /** + * Draws the cel to the target buffer using the priority + * and positioning information from the given screen + * item. The mirroring of the cel will be unchanged from + * any previous call to draw. + */ + void draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect) const; + + /** + * Draws the cel to the target buffer using the priority + * and positioning information from the given screen + * item and the given mirror flag. + * + * @note In SCI engine, this function was a virtual + * function, but CelObjView, CelObjPic, and CelObjMem + * all used the same function and the compiler + * deduplicated the copies; we deduplicate the source by + * putting the implementation on CelObj instead of + * copying it to 3/4 of the subclasses. + */ + virtual void draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect, const bool mirrorX); + + /** + * Draws the cel to the target buffer using the + * positioning and mirroring information from the + * provided arguments. + * + * @note In SCI engine, this function was a virtual + * function, but CelObjView, CelObjPic, and CelObjMem + * all used the same function and the compiler + * deduplicated the copies; we deduplicate the source by + * putting the implementation on CelObj instead of + * copying it to 3/4 of the subclasses. + */ + virtual void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const bool mirrorX); + + /** + * Draws the cel to the target buffer using the given + * position and scaling parameters. The mirroring of the + * cel will be unchanged from any previous call to draw. + */ + void drawTo(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const Ratio &scaleX, const Ratio &scaleY) const; + + /** + * Creates a copy of this cel on the free store and + * returns a pointer to the new object. The new cel will + * point to a shared copy of bitmap/resource data. + */ + virtual CelObj *duplicate() const = 0; + + /** + * Retrieves a pointer to the raw resource data for this + * cel. This method cannot be used with a CelObjColor. + */ + virtual byte *getResPointer() const = 0; + + /** + * Reads the pixel at the given coordinates. This method + * is valid only for CelObjView and CelObjPic. + */ + virtual uint8 readPixel(uint16 x, uint16 y, bool mirrorX) const; + + /** + * Submits the palette from this cel to the palette + * manager for integration into the master screen + * palette. + */ + void submitPalette() const; + +#pragma mark - +#pragma mark CelObj - Drawing +private: + template<typename MAPPER, typename SCALER> + void render(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + + template<typename MAPPER, typename SCALER> + void render(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const Ratio &scaleX, const Ratio &scaleY) const; + + void drawHzFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + void drawNoFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + void drawUncompNoFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + void drawUncompHzFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + void scaleDraw(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + void scaleDrawUncomp(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + + void drawHzFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + void drawNoFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + void drawUncompNoFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + void drawUncompHzFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + void scaleDrawMap(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + void scaleDrawUncompMap(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + // NOTE: The original includes versions of the above functions with priority parameters, which were not actually used in SCI32 + + void drawHzFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + void drawNoFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + void drawUncompNoFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + void drawUncompNoFlipNoMDNoSkip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + void drawUncompHzFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + void drawUncompHzFlipNoMDNoSkip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + void scaleDrawNoMD(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + void scaleDrawUncompNoMD(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const; + // NOTE: The original includes versions of the above functions with priority parameters, which were not actually used in SCI32 + +#pragma mark - +#pragma mark CelObj - Caching +protected: + /** + * A monotonically increasing cache ID used to identify + * the least recently used item in the cache for + * replacement. + */ + static int _nextCacheId; + + /** + * A cache of cel objects used to avoid reinitialisation + * overhead for cels with the same CelInfo32. + */ + // NOTE: At least SQ6 uses a fixed cache size of 100. + static CelCache *_cache; + + /** + * Searches the cel cache for a CelObj matching the + * provided CelInfo32. If not found, -1 is returned. + * nextInsertIndex will receive the index of the oldest + * item in the cache, which can be used to replace + * the oldest item with a newer item. + */ + int searchCache(const CelInfo32 &celInfo, int *nextInsertIndex) const; + + /** + * Puts a copy of this CelObj into the cache at the + * given cache index. + */ + void putCopyInCache(int index) const; +}; + +#pragma mark - +#pragma mark CelObjView + +/** + * A CelObjView is the drawing primitive for a View type + * resource. Each CelObjView corresponds to a single cel + * within a single loop of a view. + */ +class CelObjView : public CelObj { +private: + /** + * Analyses resources without baked-in remap flags + * to determine whether or not they should be remapped. + */ + bool analyzeUncompressedForRemap() const; + + /** + * Analyses compressed resources without baked-in remap + * flags to determine whether or not they should be + * remapped. + */ + bool analyzeForRemap() const; + +public: + CelObjView(const GuiResourceId viewId, const int16 loopNo, const int16 celNo); + virtual ~CelObjView() override {}; + + using CelObj::draw; + + /** + * Draws the cel to the target buffer using the + * positioning, mirroring, and scaling information from + * the provided arguments. + */ + void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, bool mirrorX, const Ratio &scaleX, const Ratio &scaleY); + + virtual CelObjView *duplicate() const override; + virtual byte *getResPointer() const override; +}; + +#pragma mark - +#pragma mark CelObjPic + +/** + * A CelObjPic is the drawing primitive for a Picture type + * resource. Each CelObjPic corresponds to a single cel + * within a picture. + */ +class CelObjPic : public CelObj { +private: + /** + * Analyses uncompressed resources without baked-in skip + * flags to determine whether or not they can use fast + * blitting. + */ + bool analyzeUncompressedForSkip() const; + +public: + /** + * The number of cels in the original picture resource. + */ + uint8 _celCount; + + /** + * The position of this cel relative to the top-left + * corner of the picture. + */ + Common::Point _relativePosition; + + /** + * The z-buffer priority for this cel. Higher prorities + * are drawn on top of lower priorities. + */ + int16 _priority; + + CelObjPic(const GuiResourceId pictureId, const int16 celNo); + virtual ~CelObjPic() override {}; + + using CelObj::draw; + virtual void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const bool mirrorX) override; + + virtual CelObjPic *duplicate() const override; + virtual byte *getResPointer() const override; +}; + +#pragma mark - +#pragma mark CelObjMem + +/** + * A CelObjMem is the drawing primitive for arbitrary + * bitmaps generated in memory. Generated bitmaps in SCI32 + * include text & vector drawings and per-pixel screen + * transitions like dissolves. + */ +class CelObjMem : public CelObj { +public: + CelObjMem(const reg_t bitmap); + virtual ~CelObjMem() override {}; + + virtual CelObjMem *duplicate() const override; + virtual byte *getResPointer() const override; +}; + +#pragma mark - +#pragma mark CelObjColor + +/** + * A CelObjColor is the drawing primitive for fast, + * low-memory, flat color fills. + */ +class CelObjColor : public CelObj { +public: + CelObjColor(const uint8 color, const int16 width, const int16 height); + virtual ~CelObjColor() override {}; + + using CelObj::draw; + /** + * Block fills the target buffer with the cel color. + */ + void draw(Buffer &target, const Common::Rect &targetRect) const; + virtual void draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect, const bool mirrorX) override; + virtual void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const bool mirrorX) override; + + virtual CelObjColor *duplicate() const override; + virtual byte *getResPointer() const override; +}; +} // End of namespace Sci + +#endif |