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