1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #ifndef SCUMM_GFX_H 24 #define SCUMM_GFX_H 25 26 #include "common/system.h" 27 #include "common/list.h" 28 29 #include "graphics/surface.h" 30 31 namespace Scumm { 32 33 class ScummEngine; 34 35 enum HerculesDimensions { 36 kHercWidth = 720, 37 kHercHeight = 350 38 }; 39 40 /** Camera modes */ 41 enum { 42 kNormalCameraMode = 1, 43 kFollowActorCameraMode = 2, 44 kPanningCameraMode = 3 45 }; 46 47 /** Camera state data */ 48 struct CameraData { 49 Common::Point _cur; 50 Common::Point _dest; 51 Common::Point _accel; 52 Common::Point _last; 53 int _leftTrigger, _rightTrigger; 54 byte _follows, _mode; 55 bool _movingToActor; 56 resetCameraData57 void reset() { 58 _cur.x = _cur.y = 0; 59 _dest.x = _dest.y = 0; 60 _accel.x = _accel.y = 0; 61 _last.x = _last.y = 0; 62 _leftTrigger = 0; 63 _rightTrigger = 0; 64 _follows = 0; 65 _mode = 0; 66 _movingToActor = 0; 67 } 68 }; 69 70 /** Virtual screen identifiers */ 71 enum VirtScreenNumber { 72 kMainVirtScreen = 0, // The 'stage' 73 kTextVirtScreen = 1, // In V0-V3 games: the area where text is printed 74 kVerbVirtScreen = 2, // The verb area 75 kUnkVirtScreen = 3 // ?? Not sure what this one is good for... 76 }; 77 78 /** 79 * In all Scumm games, one to four virtual screen (or 'windows') together make 80 * up the content of the actual screen. Thinking of virtual screens as fixed 81 * size, fixed location windows might help understanding them. Typical, in all 82 * scumm games there is either one single virtual screen covering the entire 83 * real screen (mostly in all newer games, e.g. Sam & Max, and all V7+ games). 84 * The classic setup consists of three virtual screens: one at the top of the 85 * screen, where all conversation texts are printed; then the main one (which 86 * I like calling 'the stage', since all the actors are doing their stuff 87 * there), and finally the lower part of the real screen is taken up by the 88 * verb area. 89 * Finally, in V5 games and some V6 games, it's almost the same as in the 90 * original games, except that there is no separate conversation area. 91 * 92 * If you now wonder what the last screen is/was good for: I am not 100% sure, 93 * but it appears that it was used by the original engine to display stuff 94 * like the pause message, or questions ("Do you really want to restart?"). 95 * It seems that it is not used at all by ScummVM, so we probably could just 96 * get rid of it and save a couple kilobytes of RAM. 97 * 98 * Each of these virtual screens has a fixed number or id (see also 99 * \ref VirtScreenNumber). 100 */ 101 struct VirtScreen : Graphics::Surface { 102 /** 103 * The unique id of this screen (corresponds to its position in the 104 * ScummEngine:_virtscr array). 105 */ 106 VirtScreenNumber number; 107 108 /** 109 * Vertical position of the virtual screen. Tells how much the virtual 110 * screen is shifted along the y axis relative to the real screen. 111 */ 112 uint16 topline; 113 114 /** 115 * Horizontal scroll offset, tells how far the screen is scrolled to the 116 * right. Only used for the main screen. After all, verbs and the 117 * conversation text box don't have to scroll. 118 */ 119 uint16 xstart; 120 121 /** 122 * Flag indicating whether this screen has a back buffer or not. This is 123 * yet another feature which is only used by the main screen. 124 * Strictly spoken one could remove this variable and replace checks 125 * on it with checks on backBuf. But since some code needs to temporarily 126 * disable the backBuf (so it can abuse drawBitmap; see drawVerbBitmap() 127 * and useIm01Cursor()), we keep it (at least for now). 128 */ 129 bool hasTwoBuffers; 130 131 /** 132 * Pointer to the screen's back buffer, if it has one (see also 133 * the hasTwoBuffers member). 134 * The backBuf is used by drawBitmap to store the background graphics of 135 * the active room. This eases redrawing: whenever a portion of the screen 136 * has to be redrawn, first a copy from the backBuf content to screenPtr is 137 * performed. Then, any objects/actors in that area are redrawn atop that. 138 */ 139 byte *backBuf; 140 141 /** 142 * Array containing for each visible strip of this virtual screen the 143 * coordinate at which the dirty region of that strip starts. 144 * 't' stands for 'top' - the top coordinate of the dirty region. 145 * This together with bdirty is used to do efficient redrawing of 146 * the screen. 147 */ 148 uint16 tdirty[80 + 1]; 149 150 /** 151 * Array containing for each visible strip of this virtual screen the 152 * coordinate at which the dirty region of that strip end. 153 * 'b' stands for 'bottom' - the bottom coordinate of the dirty region. 154 * This together with tdirty is used to do efficient redrawing of 155 * the screen. 156 */ 157 uint16 bdirty[80 + 1]; 158 clearVirtScreen159 void clear() { 160 // FIXME: Call Graphics::Surface clear / constructor? 161 number = kMainVirtScreen; 162 topline = 0; 163 xstart = 0; 164 hasTwoBuffers = false; 165 backBuf = nullptr; 166 for (uint i = 0; i < ARRAYSIZE(tdirty); i++) tdirty[i] = 0; 167 for (uint i = 0; i < ARRAYSIZE(bdirty); i++) bdirty[i] = 0; 168 } 169 170 /** 171 * Convenience method to set the whole tdirty and bdirty arrays to one 172 * specific value each. This is mostly used to mark every as dirty in 173 * a single step, like so: 174 * vs->setDirtyRange(0, vs->height); 175 * or to mark everything as clean, like so: 176 * vs->setDirtyRange(0, 0); 177 */ setDirtyRangeVirtScreen178 void setDirtyRange(int top, int bottom) { 179 for (int i = 0; i < 80 + 1; i++) { 180 tdirty[i] = top; 181 bdirty[i] = bottom; 182 } 183 } 184 getPixelsVirtScreen185 byte *getPixels(int x, int y) const { 186 return (byte *)pixels + y * pitch + (xstart + x) * format.bytesPerPixel; 187 } 188 getBackPixelsVirtScreen189 byte *getBackPixels(int x, int y) const { 190 return (byte *)backBuf + y * pitch + (xstart + x) * format.bytesPerPixel; 191 } 192 }; 193 194 /** Palette cycles */ 195 struct ColorCycle { 196 uint16 delay; 197 uint16 counter; 198 uint16 flags; 199 byte start; 200 byte end; 201 }; 202 203 struct StripTable; 204 205 #define CHARSET_MASK_TRANSPARENCY 0xFD 206 #define CHARSET_MASK_TRANSPARENCY_32 0xFDFDFDFD 207 208 class Gdi { 209 protected: 210 ScummEngine *_vm; 211 212 byte _paletteMod; 213 byte *_roomPalette; 214 byte _transparentColor; 215 byte _decomp_shr, _decomp_mask; 216 uint32 _vertStripNextInc; 217 218 bool _zbufferDisabled; 219 220 /** Flag which is true when an object is being rendered, false otherwise. */ 221 bool _objectMode; 222 223 public: 224 /** Flag which is true when loading objects or titles for distaff, in PCEngine version of Loom. */ 225 bool _distaff; 226 227 int _numZBuffer; 228 int _imgBufOffs[8]; 229 int32 _numStrips; 230 231 protected: 232 /* Bitmap decompressors */ 233 bool decompressBitmap(byte *dst, int dstPitch, const byte *src, int numLinesToProcess); 234 235 void drawStripEGA(byte *dst, int dstPitch, const byte *src, int height) const; 236 237 void drawStripComplex(byte *dst, int dstPitch, const byte *src, int height, const bool transpCheck) const; 238 void drawStripBasicH(byte *dst, int dstPitch, const byte *src, int height, const bool transpCheck) const; 239 void drawStripBasicV(byte *dst, int dstPitch, const byte *src, int height, const bool transpCheck) const; 240 241 void drawStripRaw(byte *dst, int dstPitch, const byte *src, int height, const bool transpCheck) const; 242 void unkDecode8(byte *dst, int dstPitch, const byte *src, int height) const; 243 void unkDecode9(byte *dst, int dstPitch, const byte *src, int height) const; 244 void unkDecode10(byte *dst, int dstPitch, const byte *src, int height) const; 245 void unkDecode11(byte *dst, int dstPitch, const byte *src, int height) const; 246 void drawStrip3DO(byte *dst, int dstPitch, const byte *src, int height, const bool transpCheck) const; 247 248 void drawStripHE(byte *dst, int dstPitch, const byte *src, int width, int height, const bool transpCheck) const; 249 virtual void writeRoomColor(byte *dst, byte color) const; 250 251 /* Mask decompressors */ 252 void decompressMaskImgOr(byte *dst, const byte *src, int height) const; 253 void decompressMaskImg(byte *dst, const byte *src, int height) const; 254 255 /* Misc */ 256 int getZPlanes(const byte *smap_ptr, const byte *zplane_list[9], bool bmapImage) const; 257 258 virtual bool drawStrip(byte *dstPtr, VirtScreen *vs, 259 int x, int y, const int width, const int height, 260 int stripnr, const byte *smap_ptr); 261 262 virtual void decodeMask(int x, int y, const int width, const int height, 263 int stripnr, int numzbuf, const byte *zplane_list[9], 264 bool transpStrip, byte flag); 265 266 virtual void prepareDrawBitmap(const byte *ptr, VirtScreen *vs, 267 const int x, const int y, const int width, const int height, 268 int stripnr, int numstrip); 269 270 public: 271 Gdi(ScummEngine *vm); 272 virtual ~Gdi(); 273 274 virtual void init(); 275 virtual void roomChanged(byte *roomptr); 276 virtual void loadTiles(byte *roomptr); setTransparentColor(byte transparentColor)277 void setTransparentColor(byte transparentColor) { _transparentColor = transparentColor; } 278 279 void drawBitmap(const byte *ptr, VirtScreen *vs, int x, int y, const int width, const int height, 280 int stripnr, int numstrip, byte flag); 281 282 #ifdef ENABLE_HE 283 void drawBMAPBg(const byte *ptr, VirtScreen *vs); 284 void drawBMAPObject(const byte *ptr, VirtScreen *vs, int obj, int x, int y, int w, int h); 285 #endif 286 287 byte *getMaskBuffer(int x, int y, int z); disableZBuffer()288 void disableZBuffer() { _zbufferDisabled = true; } enableZBuffer()289 void enableZBuffer() { _zbufferDisabled = false; } 290 291 void resetBackground(int top, int bottom, int strip); 292 293 enum DrawBitmapFlags { 294 dbAllowMaskOr = 1 << 0, 295 dbDrawMaskOnAll = 1 << 1, 296 dbObjectMode = 2 << 2 297 }; 298 }; 299 300 class GdiHE : public Gdi { 301 protected: 302 const byte *_tmskPtr; 303 304 protected: 305 void decompressTMSK(byte *dst, const byte *tmsk, const byte *src, int height) const; 306 307 void decodeMask(int x, int y, const int width, const int height, 308 int stripnr, int numzbuf, const byte *zplane_list[9], 309 bool transpStrip, byte flag) override; 310 311 void prepareDrawBitmap(const byte *ptr, VirtScreen *vs, 312 const int x, const int y, const int width, const int height, 313 int stripnr, int numstrip) override; 314 public: 315 GdiHE(ScummEngine *vm); 316 }; 317 318 class GdiNES : public Gdi { 319 protected: 320 struct { 321 byte nametable[16][64], nametableObj[16][64]; 322 byte attributes[64], attributesObj[64]; 323 byte masktable[16][8], masktableObj[16][8]; 324 int objX; 325 bool hasmask; 326 } _NES; 327 328 protected: 329 void decodeNESGfx(const byte *room); 330 void decodeNESObject(const byte *ptr, int xpos, int ypos, int width, int height); 331 332 void drawStripNES(byte *dst, byte *mask, int dstPitch, int stripnr, int top, int height); 333 void drawStripNESMask(byte *dst, int stripnr, int top, int height) const; 334 335 bool drawStrip(byte *dstPtr, VirtScreen *vs, 336 int x, int y, const int width, const int height, 337 int stripnr, const byte *smap_ptr) override; 338 339 void decodeMask(int x, int y, const int width, const int height, 340 int stripnr, int numzbuf, const byte *zplane_list[9], 341 bool transpStrip, byte flag) override; 342 343 void prepareDrawBitmap(const byte *ptr, VirtScreen *vs, 344 const int x, const int y, const int width, const int height, 345 int stripnr, int numstrip) override; 346 347 public: 348 GdiNES(ScummEngine *vm); 349 350 void roomChanged(byte *roomptr) override; 351 }; 352 353 #ifdef USE_RGB_COLOR 354 class GdiPCEngine : public Gdi { 355 protected: 356 struct { 357 uint16 nametable[4096], nametableObj[512]; 358 byte colortable[4096], colortableObj[512]; 359 uint16 masktable[4096], masktableObj[512]; 360 int maskIDSize; 361 int numTiles; 362 int numMasks; 363 byte *roomTiles, *staffTiles; 364 byte *masks; 365 } _PCE; 366 367 protected: 368 void decodePCEngineGfx(const byte *room); 369 void decodeStrip(const byte *ptr, uint16 *tiles, byte *colors, uint16 *masks, int numRows, bool isObject); 370 void setTileData(byte *tile, int index, byte byte0, byte byte1); 371 void decodePCEngineTileData(const byte *ptr); 372 void decodePCEngineMaskData(const byte *ptr); 373 void decodePCEngineObject(const byte *ptr, int xpos, int ypos, int width, int height); 374 375 void drawStripPCEngine(byte *dst, byte *mask, int dstPitch, int stripnr, int top, int height); 376 void drawStripPCEngineMask(byte *dst, int stripnr, int top, int height) const; 377 378 bool drawStrip(byte *dstPtr, VirtScreen *vs, 379 int x, int y, const int width, const int height, 380 int stripnr, const byte *smap_ptr) override; 381 382 void decodeMask(int x, int y, const int width, const int height, 383 int stripnr, int numzbuf, const byte *zplane_list[9], 384 bool transpStrip, byte flag) override; 385 386 void prepareDrawBitmap(const byte *ptr, VirtScreen *vs, 387 const int x, const int y, const int width, const int height, 388 int stripnr, int numstrip) override; 389 390 public: 391 GdiPCEngine(ScummEngine *vm); 392 ~GdiPCEngine() override; 393 394 void loadTiles(byte *roomptr) override; 395 void roomChanged(byte *roomptr) override; 396 }; 397 #endif 398 399 class GdiV1 : public Gdi { 400 protected: 401 /** Render settings which are specific to the v0/v1 graphic decoders. */ 402 struct { 403 byte colors[4]; 404 byte charMap[2048], objectMap[2048], picMap[4096], colorMap[4096]; 405 byte maskMap[4096], maskChar[4096]; 406 } _V1; 407 408 protected: 409 void decodeV1Gfx(const byte *src, byte *dst, int size) const; 410 411 void drawStripV1Object(byte *dst, int dstPitch, int stripnr, int width, int height); 412 void drawStripV1Background(byte *dst, int dstPitch, int stripnr, int height); 413 void drawStripV1Mask(byte *dst, int stripnr, int width, int height) const; 414 415 bool drawStrip(byte *dstPtr, VirtScreen *vs, 416 int x, int y, const int width, const int height, 417 int stripnr, const byte *smap_ptr) override; 418 419 void decodeMask(int x, int y, const int width, const int height, 420 int stripnr, int numzbuf, const byte *zplane_list[9], 421 bool transpStrip, byte flag) override; 422 423 void prepareDrawBitmap(const byte *ptr, VirtScreen *vs, 424 const int x, const int y, const int width, const int height, 425 int stripnr, int numstrip) override; 426 427 public: 428 GdiV1(ScummEngine *vm); 429 430 void roomChanged(byte *roomptr) override; 431 }; 432 433 class GdiV2 : public Gdi { 434 protected: 435 /** For V2 games, we cache offsets into the room graphics, to speed up things. */ 436 StripTable *_roomStrips; 437 438 protected: 439 StripTable *generateStripTable(const byte *src, int width, int height, StripTable *table) const; 440 441 bool drawStrip(byte *dstPtr, VirtScreen *vs, 442 int x, int y, const int width, const int height, 443 int stripnr, const byte *smap_ptr) override; 444 445 void decodeMask(int x, int y, const int width, const int height, 446 int stripnr, int numzbuf, const byte *zplane_list[9], 447 bool transpStrip, byte flag) override; 448 449 void prepareDrawBitmap(const byte *ptr, VirtScreen *vs, 450 const int x, const int y, const int width, const int height, 451 int stripnr, int numstrip) override; 452 453 public: 454 GdiV2(ScummEngine *vm); 455 ~GdiV2() override; 456 457 void roomChanged(byte *roomptr) override; 458 }; 459 460 #ifdef USE_RGB_COLOR 461 class GdiHE16bit : public GdiHE { 462 protected: 463 void writeRoomColor(byte *dst, byte color) const override; 464 public: 465 GdiHE16bit(ScummEngine *vm); 466 }; 467 #endif 468 469 #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE 470 // Helper class for FM-Towns output (required for specific hardware effects like switching graphics layers on and off). 471 class TownsScreen { 472 public: 473 enum { 474 kDirtyRectsMax = 20, 475 kFullRedraw = (kDirtyRectsMax + 1) 476 }; 477 public: 478 TownsScreen(OSystem *system); 479 ~TownsScreen(); 480 481 void setupLayer(int layer, int width, int height, int scaleW, int scaleH, int numCol, void *srcPal = 0); 482 void clearLayer(int layer); 483 void fillLayerRect(int layer, int x, int y, int w, int h, int col); 484 void addDirtyRect(int x, int y, int w, int h); 485 void toggleLayers(int flags); 486 void scrollLayers(int flags, int offset); 487 void update(); 488 bool isScrolling(int direction, int threshold = 0) const { return (direction == 0) ? _scrollRemainder != threshold : (direction == 1 ? _scrollRemainder > threshold : _scrollRemainder < threshold); } 489 490 uint8 *getLayerPixels(int layer, int x, int y) const; getLayerPitch(int layer)491 int getLayerPitch(int layer) const { return (layer >= 0 && layer < 2) ? _layers[layer].pitch : 0; } getLayerWidth(int layer)492 int getLayerWidth(int layer) const { return (layer >= 0 && layer < 2) ? _layers[layer].width : 0; } getLayerHeight(int layer)493 int getLayerHeight(int layer) const { return (layer >= 0 && layer < 2) ? _layers[layer].height : 0; } getLayerBpp(int layer)494 int getLayerBpp(int layer) const { return (layer >= 0 && layer < 2) ? _layers[layer].bpp : 0; } getLayerScaleW(int layer)495 int getLayerScaleW(int layer) const { return (layer >= 0 && layer < 2) ? _layers[layer].scaleW : 0; } getLayerScaleH(int layer)496 int getLayerScaleH(int layer) const { return (layer >= 0 && layer < 2) ? _layers[layer].scaleH : 0; } 497 498 private: 499 struct TownsScreenLayer { 500 uint8 *pixels; 501 uint8 *palette; 502 int pitch; 503 int width; 504 int height; 505 int bpp; 506 int numCol; 507 int hScroll; 508 uint8 scaleW; 509 uint8 scaleH; 510 bool onBottom; 511 bool enabled; 512 bool ready; 513 514 uint16 *bltTmpPal; 515 } _layers[2]; 516 517 template<typename dstPixelType, typename srcPixelType, int scaleW, int scaleH, bool col4bit> void transferRect(uint8 *dst, TownsScreenLayer *l, int x, int y, int w, int h); 518 template<typename dstPixelType> void updateScreenBuffer(); 519 520 #ifdef USE_RGB_COLOR 521 void update16BitPalette(); 522 uint16 calc16BitColor(const uint8 *palEntry); 523 #endif 524 525 int _height; 526 int _width; 527 int _pitch; 528 uint16 _scrollOffset; 529 int _scrollRemainder; 530 Graphics::PixelFormat _pixelFormat; 531 532 int _numDirtyRects; 533 Common::List<Common::Rect> _dirtyRects; 534 OSystem *_system; 535 }; 536 #endif // DISABLE_TOWNS_DUAL_LAYER_MODE 537 538 } // End of namespace Scumm 539 540 #endif 541