File: gfx.h

package info (click to toggle)
scummvm 2.9.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 450,580 kB
  • sloc: cpp: 4,299,825; asm: 28,322; python: 12,901; sh: 11,302; java: 9,289; xml: 7,895; perl: 2,639; ansic: 2,465; yacc: 1,670; javascript: 1,020; makefile: 933; lex: 578; awk: 275; objc: 82; sed: 11; php: 1
file content (655 lines) | stat: -rw-r--r-- 21,513 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
/* 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 3 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, see <http://www.gnu.org/licenses/>.
 *
 */

#ifndef SCUMM_GFX_H
#define SCUMM_GFX_H

#include "common/system.h"
#include "common/list.h"

#include "graphics/surface.h"

namespace Scumm {

class ScummEngine;

/*
 *  Bitmap compression algorithm labels
 */

#define BMCOMP_RAW256           1   // Raw pixels
#define BMCOMP_TOWNS_2          2
#define BMCOMP_TOWNS_3          3
#define BMCOMP_TOWNS_4          4
#define BMCOMP_TOWNS_7          7
#define BMCOMP_TRLE8BIT         8
#define BMCOMP_RLE8BIT          9

#define BMCOMP_PIX32            10  // Amiga 16/32 color compression

#define BMCOMP_ZIGZAG_V0        10  // Vertical
#define BMCOMP_ZIGZAG_V4        14
#define BMCOMP_ZIGZAG_V5        15
#define BMCOMP_ZIGZAG_V6        16
#define BMCOMP_ZIGZAG_V7        17
#define BMCOMP_ZIGZAG_V8        18

#define BMCOMP_ZIGZAG_H0        20  // Horizontal
#define BMCOMP_ZIGZAG_H4        24
#define BMCOMP_ZIGZAG_H5        25
#define BMCOMP_ZIGZAG_H6        26
#define BMCOMP_ZIGZAG_H7        27
#define BMCOMP_ZIGZAG_H8        28

#define BMCOMP_ZIGZAG_VT0       30  // Vertical with transparency
#define BMCOMP_ZIGZAG_VT4       34
#define BMCOMP_ZIGZAG_VT5       35
#define BMCOMP_ZIGZAG_VT6       36
#define BMCOMP_ZIGZAG_VT7       37
#define BMCOMP_ZIGZAG_VT8       38

#define BMCOMP_ZIGZAG_HT0       40  // Horizontal with transparency
#define BMCOMP_ZIGZAG_HT4       44
#define BMCOMP_ZIGZAG_HT5       45
#define BMCOMP_ZIGZAG_HT6       46
#define BMCOMP_ZIGZAG_HT7       47
#define BMCOMP_ZIGZAG_HT8       48

#define BMCOMP_MAJMIN_H0        60  // Major-Minor jump algorithm (-4 to +3)
#define BMCOMP_MAJMIN_H4        64
#define BMCOMP_MAJMIN_H5        65
#define BMCOMP_MAJMIN_H6        66
#define BMCOMP_MAJMIN_H7        67
#define BMCOMP_MAJMIN_H8        68

#define BMCOMP_MAJMIN_HT0       80  // Major-Minor jump algorithm (-4 to +3, with transparency)
#define BMCOMP_MAJMIN_HT4       84
#define BMCOMP_MAJMIN_HT5       85
#define BMCOMP_MAJMIN_HT6       86
#define BMCOMP_MAJMIN_HT7       87
#define BMCOMP_MAJMIN_HT8       88

#define BMCOMP_RMAJMIN_H0       100 // Run Major-Minor jump algorithm (-4 to +3)
#define BMCOMP_RMAJMIN_H4       104
#define BMCOMP_RMAJMIN_H5       105
#define BMCOMP_RMAJMIN_H6       106
#define BMCOMP_RMAJMIN_H7       107
#define BMCOMP_RMAJMIN_H8       108

#define BMCOMP_RMAJMIN_HT0      120 // Run Major-Minor jump algorithm (-4 to +3, with transparency)
#define BMCOMP_RMAJMIN_HT4      124
#define BMCOMP_RMAJMIN_HT5      125
#define BMCOMP_RMAJMIN_HT6      126
#define BMCOMP_RMAJMIN_HT7      127
#define BMCOMP_RMAJMIN_HT8      128

#define BMCOMP_NMAJMIN_H0       130 // New Major-Minor jump algorithm (-4 to +4)
#define BMCOMP_NMAJMIN_H4       134
#define BMCOMP_NMAJMIN_H5       135
#define BMCOMP_NMAJMIN_H6       136
#define BMCOMP_NMAJMIN_H7       137
#define BMCOMP_NMAJMIN_H8       138

#define BMCOMP_NMAJMIN_HT0      140 // New Major-Minor jump algorithm (-4 to +4, with transparency)
#define BMCOMP_NMAJMIN_HT4      144
#define BMCOMP_NMAJMIN_HT5      145
#define BMCOMP_NMAJMIN_HT6      146
#define BMCOMP_NMAJMIN_HT7      147
#define BMCOMP_NMAJMIN_HT8      148

#define BMCOMP_TPIX256          149 // Transparent raw pixels

#define BMCOMP_SOLID_COLOR_FILL 150

#define BMCOMP_CUSTOM_RU_TR     143


enum HerculesDimensions {
	kHercWidth = 720,
	kHercHeight = 350
};

/** Camera modes */
enum {
	kNormalCameraMode = 1,
	kFollowActorCameraMode = 2,
	kPanningCameraMode = 3
};

/** Camera state data */
struct CameraData {
	Common::Point _cur;
	Common::Point _dest;
	Common::Point _accel;
	Common::Point _last;
	int _leftTrigger, _rightTrigger;
	byte _follows, _mode;
	bool _movingToActor;

	void reset() {
		_cur.x = _cur.y = 0;
		_dest.x = _dest.y = 0;
		_accel.x = _accel.y = 0;
		_last.x = _last.y = 0;
		_leftTrigger = 0;
		_rightTrigger = 0;
		_follows = 0;
		_mode = 0;
		_movingToActor = 0;
	}
};

/** Virtual screen identifiers */
enum VirtScreenNumber {
	kMainVirtScreen = 0,	// The 'stage'
	kTextVirtScreen = 1,	// In V0-V3 games: the area where text is printed
	kVerbVirtScreen = 2,	// The verb area
	kBannerVirtScreen = 3	// The centered pause/restart/message banner area
};

/**
 * In all Scumm games, one to four virtual screen (or 'windows') together make
 * up the content of the actual screen. Thinking of virtual screens as fixed
 * size, fixed location windows might help understanding them. Typical, in all
 * scumm games there is either one single virtual screen covering the entire
 * real screen (mostly in all newer games, e.g. Sam & Max, and all V7+ games).
 * The classic setup consists of three virtual screens: one at the top of the
 * screen, where all conversation texts are printed; then the main one (which
 * I like calling 'the stage', since all the actors are doing their stuff
 * there), and finally the lower part of the real screen is taken up by the
 * verb area.
 * Finally, in V5 games and some V6 games, it's almost the same as in the
 * original games, except that there is no separate conversation area.
 *
 * Each of these virtual screens has a fixed number or id (see also
 * \ref VirtScreenNumber).
 */
struct VirtScreen : Graphics::Surface {
	/**
	 * The unique id of this screen (corresponds to its position in the
	 * ScummEngine:_virtscr array).
	 */
	VirtScreenNumber number;

	/**
	 * Vertical position of the virtual screen. Tells how much the virtual
	 * screen is shifted along the y axis relative to the real screen.
	 */
	uint16 topline;

	/**
	 * Horizontal scroll offset, tells how far the screen is scrolled to the
	 * right. Only used for the main screen. After all, verbs and the
	 * conversation text box don't have to scroll.
	 */
	uint16 xstart;

	/**
	 * Flag indicating whether this screen has a back buffer or not. This is
	 * yet another feature which is only used by the main screen.
	 * Strictly spoken one could remove this variable and replace checks
	 * on it with checks on backBuf. But since some code needs to temporarily
	 * disable the backBuf (so it can abuse drawBitmap; see drawVerbBitmap()
	 * and useIm01Cursor()), we keep it (at least for now).
	 */
	bool hasTwoBuffers;

	/**
	 * Pointer to the screen's back buffer, if it has one (see also
	 * the hasTwoBuffers member).
	 * The backBuf is used by drawBitmap to store the background graphics of
	 * the active room. This eases redrawing: whenever a portion of the screen
	 * has to be redrawn, first a copy from the backBuf content to screenPtr is
	 * performed. Then, any objects/actors in that area are redrawn atop that.
	 */
	byte *backBuf;

	/**
	 * Array containing for each visible strip of this virtual screen the
	 * coordinate at which the dirty region of that strip starts.
	 * 't' stands for 'top' - the top coordinate of the dirty region.
	 * This together with bdirty is used to do efficient redrawing of
	 * the screen.
	 */
	uint16 tdirty[80 + 1];

	/**
	 * Array containing for each visible strip of this virtual screen the
	 * coordinate at which the dirty region of that strip end.
	 * 'b' stands for 'bottom' - the bottom coordinate of the dirty region.
	 * This together with tdirty is used to do efficient redrawing of
	 * the screen.
	 */
	uint16 bdirty[80 + 1];

	void clear() {
		// FIXME: Call Graphics::Surface clear / constructor?
		number = kMainVirtScreen;
		topline = 0;
		xstart = 0;
		hasTwoBuffers = false;
		backBuf = nullptr;
		for (uint i = 0; i < ARRAYSIZE(tdirty); i++) tdirty[i] = 0;
		for (uint i = 0; i < ARRAYSIZE(bdirty); i++) bdirty[i] = 0;
	}

	/**
	 * Convenience method to set the whole tdirty and bdirty arrays to one
	 * specific value each. This is mostly used to mark every as dirty in
	 * a single step, like so:
	 *   vs->setDirtyRange(0, vs->height);
	 * or to mark everything as clean, like so:
	 *   vs->setDirtyRange(0, 0);
	 */
	void setDirtyRange(int top, int bottom) {
		for (int i = 0; i < 80 + 1; i++) {
			tdirty[i] = top;
			bdirty[i] = bottom;
		}
	}

	byte *getPixels(int x, int y) const {
		return (byte *)pixels + y * pitch + (xstart + x) * format.bytesPerPixel;
	}

	byte *getBackPixels(int x, int y) const {
		return (backBuf != nullptr) ? (byte *)backBuf + y * pitch + (xstart + x) * format.bytesPerPixel : nullptr;
	}
};

/** Palette cycles */
struct ColorCycle {
	uint16 delay;
	uint16 counter;
	uint16 flags;
	byte start;
	byte end;
};

struct StripTable;

#define CHARSET_MASK_TRANSPARENCY	 0xFD
#define CHARSET_MASK_TRANSPARENCY_32 0xFDFDFDFD

class Gdi {
protected:
	ScummEngine *_vm;

	byte _paletteMod;
	byte *_roomPalette;
	byte _transparentColor;
	byte _decomp_shr, _decomp_mask;
	uint32 _vertStripNextInc;

	bool _zbufferDisabled;

	/** Flag which is true when an object is being rendered, false otherwise. */
	bool _objectMode;

public:
	/** Flag which is true when loading objects or titles for distaff, in PCEngine version of Loom. */
	bool _distaff;

	int _numZBuffer;
	int _imgBufOffs[8];
	int32 _numStrips;

protected:
	/* Bitmap decompressors */
	bool decompressBitmap(byte *dst, int dstPitch, const byte *src, int numLinesToProcess);

	void drawStripEGA(byte *dst, int dstPitch, const byte *src, int height) const;

	void drawStripComplex(byte *dst, int dstPitch, const byte *src, int height, const bool transpCheck) const;
	void drawStripBasicH(byte *dst, int dstPitch, const byte *src, int height, const bool transpCheck) const;
	void drawStripBasicV(byte *dst, int dstPitch, const byte *src, int height, const bool transpCheck) const;

	void drawStripRaw(byte *dst, int dstPitch, const byte *src, int height, const bool transpCheck) const;
	void unkDecode8(byte *dst, int dstPitch, const byte *src, int height) const;
	void unkDecode9(byte *dst, int dstPitch, const byte *src, int height) const;
	void unkDecode10(byte *dst, int dstPitch, const byte *src, int height) const;
	void unkDecode11(byte *dst, int dstPitch, const byte *src, int height) const;
	void drawStrip3DO(byte *dst, int dstPitch, const byte *src, int height, const bool transpCheck) const;

	void drawStripHE(byte *dst, int dstPitch, const byte *src, int width, int height, const bool transpCheck) const;
	virtual void writeRoomColor(byte *dst, byte color) const;

	/* Mask decompressors */
	void decompressMaskImgOr(byte *dst, const byte *src, int height) const;
	void decompressMaskImg(byte *dst, const byte *src, int height) const;

	/* Misc */
	int getZPlanes(const byte *smap_ptr, const byte *zplane_list[9], bool bmapImage) const;

	virtual bool drawStrip(byte *dstPtr, VirtScreen *vs,
					int x, int y, const int width, const int height,
					int stripnr, const byte *smap_ptr);

	virtual void decodeMask(int x, int y, const int width, const int height,
	                int stripnr, int numzbuf, const byte *zplane_list[9],
	                bool transpStrip, byte flag);

	virtual void prepareDrawBitmap(const byte *ptr, VirtScreen *vs,
					const int x, const int y, const int width, const int height,
	                int stripnr, int numstrip);

public:
	Gdi(ScummEngine *vm);
	virtual ~Gdi();

	virtual void setRenderModeColorMap(const byte *map) {}
	virtual byte remapColorToRenderMode(byte col) const { return col; }

	virtual void init();
	virtual void roomChanged(byte *roomptr);
	virtual void loadTiles(byte *roomptr);
	void setTransparentColor(byte transparentColor) { _transparentColor = transparentColor; }

	void drawBitmap(const byte *ptr, VirtScreen *vs, int x, int y, const int width, const int height,
	                int stripnr, int numstrip, byte flag);

#ifdef ENABLE_HE
	void drawBMAPBg(const byte *ptr, VirtScreen *vs);
	void drawBMAPObject(const byte *ptr, VirtScreen *vs, int obj, int x, int y, int w, int h);
#endif

	byte *getMaskBuffer(int x, int y, int z);
	void disableZBuffer() { _zbufferDisabled = true; }
	void enableZBuffer() { _zbufferDisabled = false; }

	void resetBackground(int top, int bottom, int strip);

	enum DrawBitmapFlags {
		dbAllowMaskOr   = 1 << 0,
		dbDrawMaskOnAll = 1 << 1,
		dbObjectMode    = 2 << 2
	};
};

class GdiHE : public Gdi {
protected:
	const byte *_tmskPtr;

protected:
	void decompressTMSK(byte *dst, const byte *tmsk, const byte *src, int height) const;

	void decodeMask(int x, int y, const int width, const int height,
	                int stripnr, int numzbuf, const byte *zplane_list[9],
	                bool transpStrip, byte flag) override;

	void prepareDrawBitmap(const byte *ptr, VirtScreen *vs,
					const int x, const int y, const int width, const int height,
	                int stripnr, int numstrip) override;
public:
	GdiHE(ScummEngine *vm);
};

class GdiNES : public Gdi {
protected:
	struct {
		byte nametable[16][64], nametableObj[16][64];
		byte attributes[64], attributesObj[64];
		byte masktable[16][8], masktableObj[16][8];
		int  objX;
		bool hasmask;
	} _NES;

protected:
	void decodeNESGfx(const byte *room);
	void decodeNESObject(const byte *ptr, int xpos, int ypos, int width, int height);

	void drawStripNES(byte *dst, byte *mask, int dstPitch, int stripnr, int top, int height);
	void drawStripNESMask(byte *dst, int stripnr, int top, int height) const;

	bool drawStrip(byte *dstPtr, VirtScreen *vs,
					int x, int y, const int width, const int height,
					int stripnr, const byte *smap_ptr) override;

	void decodeMask(int x, int y, const int width, const int height,
	                int stripnr, int numzbuf, const byte *zplane_list[9],
	                bool transpStrip, byte flag) override;

	void prepareDrawBitmap(const byte *ptr, VirtScreen *vs,
					const int x, const int y, const int width, const int height,
	                int stripnr, int numstrip) override;

public:
	GdiNES(ScummEngine *vm);

	void roomChanged(byte *roomptr) override;
};

#ifdef USE_RGB_COLOR
class GdiPCEngine : public Gdi {
protected:
	struct {
		uint16 nametable[4096], nametableObj[512];
		byte colortable[4096], colortableObj[512];
		uint16 masktable[4096], masktableObj[512];
		int maskIDSize;
		int numTiles;
		int numMasks;
		byte *roomTiles, *staffTiles;
		byte *masks;
	} _PCE;

protected:
	void decodePCEngineGfx(const byte *room);
	void decodeStrip(const byte *ptr, uint16 *tiles, byte *colors, uint16 *masks, int numRows, bool isObject);
	void setTileData(byte *tile, int index, byte byte0, byte byte1);
	void decodePCEngineTileData(const byte *ptr);
	void decodePCEngineMaskData(const byte *ptr);
	void decodePCEngineObject(const byte *ptr, int xpos, int ypos, int width, int height);

	void drawStripPCEngine(byte *dst, byte *mask, int dstPitch, int stripnr, int top, int height);
	void drawStripPCEngineMask(byte *dst, int stripnr, int top, int height) const;

	bool drawStrip(byte *dstPtr, VirtScreen *vs,
					int x, int y, const int width, const int height,
					int stripnr, const byte *smap_ptr) override;

	void decodeMask(int x, int y, const int width, const int height,
	                int stripnr, int numzbuf, const byte *zplane_list[9],
	                bool transpStrip, byte flag) override;

	void prepareDrawBitmap(const byte *ptr, VirtScreen *vs,
					const int x, const int y, const int width, const int height,
	                int stripnr, int numstrip) override;

public:
	GdiPCEngine(ScummEngine *vm);
	~GdiPCEngine() override;

	void loadTiles(byte *roomptr) override;
	void roomChanged(byte *roomptr) override;
};
#endif

class GdiV1 : public Gdi {
protected:
	/** Render settings which are specific to the v0/v1 graphic decoders. */
	struct {
		byte colors[4];
		byte charMap[2048], objectMap[2048], picMap[4096], colorMap[4096];
		byte maskMap[4096], maskChar[4096];
	} _V1;

	const byte *_colorMap = 0;

protected:
	void decodeV1Gfx(const byte *src, byte *dst, int size) const;

	void drawStripV1Object(byte *dst, int dstPitch, int stripnr, int width, int height);
	void drawStripV1Background(byte *dst, int dstPitch, int stripnr, int height);
	void drawStripV1Mask(byte *dst, int stripnr, int width, int height) const;

	bool drawStrip(byte *dstPtr, VirtScreen *vs,
					int x, int y, const int width, const int height,
					int stripnr, const byte *smap_ptr) override;

	void decodeMask(int x, int y, const int width, const int height,
	                int stripnr, int numzbuf, const byte *zplane_list[9],
	                bool transpStrip, byte flag) override;

	void prepareDrawBitmap(const byte *ptr, VirtScreen *vs,
					const int x, const int y, const int width, const int height,
	                int stripnr, int numstrip) override;

public:
	GdiV1(ScummEngine *vm);

	void setRenderModeColorMap(const byte *map) override;
	byte remapColorToRenderMode(byte col) const override;

	void roomChanged(byte *roomptr) override;
};

class GdiV2 : public Gdi {
protected:
	/** For V2 games, we cache offsets into the room graphics, to speed up things. */
	StripTable *_roomStrips;

protected:
	StripTable *generateStripTable(const byte *src, int width, int height, StripTable *table) const;

	bool drawStrip(byte *dstPtr, VirtScreen *vs,
					int x, int y, const int width, const int height,
					int stripnr, const byte *smap_ptr) override;

	void decodeMask(int x, int y, const int width, const int height,
	                int stripnr, int numzbuf, const byte *zplane_list[9],
	                bool transpStrip, byte flag) override;

	void prepareDrawBitmap(const byte *ptr, VirtScreen *vs,
					const int x, const int y, const int width, const int height,
	                int stripnr, int numstrip) override;

public:
	GdiV2(ScummEngine *vm);
	~GdiV2() override;

	void roomChanged(byte *roomptr) override;
};

#ifdef USE_RGB_COLOR
class GdiHE16bit : public GdiHE {
protected:
	void writeRoomColor(byte *dst, byte color) const override;
public:
	GdiHE16bit(ScummEngine *vm);
};
#endif

#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
// Helper class for FM-Towns output (required for specific hardware effects like switching graphics layers on and off).
class TownsScreen {
public:
	enum {
		kDirtyRectsMax = 50,
		kFullRedraw = (kDirtyRectsMax + 1)
	};
public:
	TownsScreen(OSystem *system);
	~TownsScreen();

	void setupLayer(int layer, int width, int height, int scaleW, int scaleH, int numCol, void *srcPal = 0);
	void clearLayer(int layer);
	void fillRect(int layer, int x, int y, int w, int h, int col);
	void swapAreaWithBuffer(int layer, int x, int y, int w, int h, byte *buffer);
	void addDirtyRect(int x, int y, int w, int h);
	void toggleLayers(int flags);
	void scrollLayer(int layer, int offset, int top, int bottom, bool fast);
	void update();
	bool isScrolling(int layer, int direction, int threshold = 0) const {
		return (layer & ~1) ? false :
			(direction == 0 ? (_layers[layer].scrollRemainder != threshold) :
				(direction == 1 ? (_layers[layer].scrollRemainder > threshold) : (_layers[layer].scrollRemainder < threshold)));
	}

	uint8 *getLayerPixels(int layer, int x, int y) const;
	int getLayerPitch(int layer) const { assert (layer >= 0 && layer < 2); return _layers[layer].pitch; }
	int getLayerWidth(int layer) const { assert (layer >= 0 && layer < 2); return _layers[layer].width; }
	int getLayerHeight(int layer) const { assert (layer >= 0 && layer < 2); return _layers[layer].height; }
	int getLayerBpp(int layer) const { assert (layer >= 0 && layer < 2); return _layers[layer].bpp; }
	int getLayerScaleW(int layer) const { assert (layer >= 0 && layer < 2); return _layers[layer].scaleW; }
	int getLayerScaleH(int layer) const { assert (layer >= 0 && layer < 2); return _layers[layer].scaleH; }

private:
	struct TownsScreenLayer {
		uint8 *pixels = nullptr;
		uint8 *palette = nullptr;
		int pitch = 0;
		int width = 0;
		int height = 0;
		int bpp = 0;
		int numCol = 0;
		uint16 hScroll = 0;
		uint8 scaleW = 0;
		uint8 scaleH = 0;
		int scrollRemainder = 0;
		bool onBottom = false;
		bool enabled = false;
		bool ready = false;
		uint16 *bltTmpPal= nullptr;
	} _layers[2];

	template<typename dstPixelType, typename srcPixelType, int scaleW, int scaleH, bool col4bit> void transferRect(uint8 *dst, int pitch, TownsScreenLayer *l, int x, int y, int w, int h);
	template<typename dstPixelType> void updateScreenBuffer();

#ifdef USE_RGB_COLOR
	void update16BitPalette();
	uint16 calc16BitColor(const uint8 *palEntry);
#endif

	int _height;
	int _width;
	bool _semiSmoothScroll;
	Graphics::PixelFormat _pixelFormat;

	int _numDirtyRects;
	Common::List<Common::Rect> _dirtyRects;
	OSystem *_system;
};
#endif // DISABLE_TOWNS_DUAL_LAYER_MODE

class MajMinCodec {
public:

	struct {
		bool repeatMode;
		int repeatCount;
		byte color;
		byte shift;
		uint16 bits;
		byte numBits;
		const byte *dataPtr;
		byte buffer[336];
	} _majMinData;

	void setupBitReader(byte shift, const byte *src);
	void skipData(int32 numSkip);
	void decodeLine(byte *buf, int32 numBytes, int32 dir);
	inline byte readBits(byte n);
};

} // End of namespace Scumm

#endif