[Scummvm-git-logs] scummvm master -> cde7a021644774262f25d833303507ca180d8508

dreammaster paulfgilbert at gmail.com
Sun Jan 6 03:01:33 CET 2019


This automated email contains information about 3 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
bde5042813 GLK: FROTZ: Fix decoding of MG1 graphics
81541a5f04 GLK: FROTZ: Properly handle picture transparency
cde7a02164 GLK: FROTX: Draw pictures at the correct position


Commit: bde504281311953bd99db087471b798da39ed143
    https://github.com/scummvm/scummvm/commit/bde504281311953bd99db087471b798da39ed143
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-01-05T16:12:58-08:00

Commit Message:
GLK: FROTZ: Fix decoding of MG1 graphics

The prior code was based on the Frotz decoder, which was partially
written in PC assembly, so was hard to represent. This new version
uses code from the ztools pix2gif code

Changed paths:
    engines/glk/frotz/pics_decoder.cpp


diff --git a/engines/glk/frotz/pics_decoder.cpp b/engines/glk/frotz/pics_decoder.cpp
index dba1335..73032df 100644
--- a/engines/glk/frotz/pics_decoder.cpp
+++ b/engines/glk/frotz/pics_decoder.cpp
@@ -27,6 +27,71 @@
 namespace Glk {
 namespace Frotz {
 
+#define MAX_BIT 512		/* Must be less than or equal to CODE_TABLE_SIZE */
+#define CODE_SIZE 8
+#define CODE_TABLE_SIZE 4096
+#define PREFIX 0
+#define PIXEL 1
+
+/**
+ * Support class used for picture decompression
+ */
+class Compress {
+private:
+	byte _codeBuffer[CODE_TABLE_SIZE];
+public:
+	short _nextCode;
+	short _sLen;
+	short _sPtr;
+	short _tLen;
+	short _tPtr;
+
+	Compress() : _nextCode(0), _sLen(0), _sPtr(0), _tLen(0), _tPtr(0) {}
+
+	/**
+	 * Read a code
+	 */
+	short readCode(Common::ReadStream &src);
+};
+
+static short MASK[16] = {
+	0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f,
+	0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff
+};
+
+short Compress::readCode(Common::ReadStream &src) {
+	short code, bsize, tlen, tptr;
+
+	code = 0;
+	tlen = _tLen;
+	tptr = 0;
+
+	while (tlen) {
+		if (_sLen == 0) {
+			if ((_sLen = src.read(_codeBuffer, MAX_BIT)) == 0) {
+				error("fread");
+			}
+			_sLen *= 8;
+			_sPtr = 0;
+		}
+		bsize = ((_sPtr + 8) & ~7) - _sPtr;
+		bsize = (tlen > bsize) ? bsize : tlen;
+		code |= (((uint)_codeBuffer[_sPtr >> 3] >> (_sPtr & 7)) & MASK[bsize]) << tptr;
+
+		tlen -= bsize;
+		tptr += bsize;
+		_sLen -= bsize;
+		_sPtr += bsize;
+	}
+
+	if ((_nextCode == MASK[_tLen]) && (_tLen < 12))
+		_tLen++;
+
+	return code;
+}
+
+/*--------------------------------------------------------------------------*/
+
 PictureDecoder::PictureDecoder() {
 	_tableVal = new byte[3 * 3840];
 	_tableRef = (uint16 *)(_tableVal + 3840);
@@ -38,219 +103,65 @@ PictureDecoder::~PictureDecoder() {
 
 Common::SeekableReadStream *PictureDecoder::decode(Common::ReadStream &src, uint flags,
 		const Common::Array<byte> &palette, uint display, size_t width, size_t height) {
-	static const int raise_bits[4] = { 0x0100, 0x0300, 0x0700, 0x0000 };
 	Common::MemoryWriteStreamDynamic out(DisposeAfterUse::NO);
-	byte buf[512];
-	byte transparent;
-	int colour_shift = 0;
-	int first_colour = 0;
-	int code, prev_code = 0;
-	int next_entry;
-	int bits_per_code;
-	int bits_shift;
-	int bits;
-	int bufpos = 0;
+	short code_table[CODE_TABLE_SIZE][2];
+	byte buffer[CODE_TABLE_SIZE];
 
-	/*
-	 * Write out dimensions of image
-	 */
+	// Write out dimensions
 	out.writeUint16LE(width);
 	out.writeUint16LE(height);
 
-	/* Set up the color mapping. This is only used for MCGA pictures; the colour
-	 * map affects every picture on the screen. The first colour to be defined is
-	 * colour 2. Every map defines up to 14 colours (colour 2 to 15). These colours
-	 * are not related to the standard Z-machine colour scheme which remains unchanged.
-	 * (This is based on the Amiga interpreter which had to work with 16 colours.
-	 * Colours 0 and 1 were used for text; changing the text colours actually changed
-	 * palette entries 0 and 1. This interface uses the same trick in Amiga mode.)
-	 */
-
-	switch (display) {
-	case kCGA:
-		colour_shift = -2;
-		break;
-	case kEGA:
-		colour_shift = 0;
-		break;
-	case kMCGA:
-		colour_shift = 32;
-		first_colour = 34;
-		break;
-	case kAmiga:
-		colour_shift = -1;
-		first_colour = 65;
-		break;
-	default:
-		error("Unsupported mode");
-		break;
-	}
-
-	// Note: we don't actually use paletted indexes, so adjust colour_shift
-	// relative to first_colour
-	colour_shift -= first_colour;
-
-	out.writeUint16LE(palette.size() / 3);
+	// Write out palette
+	out.writeUint16LE(palette.size() / 3 + 2);
+	for (int idx = 0; idx < 6; ++idx)
+		out.writeByte(0);
 	if (!palette.empty())
 		out.write(&palette[0], palette.size());
 
-	/* Bit 0 of "flags" indicates that the picture uses a transparent colour,
-	 * the top four bits tell us which colour it is. For CGA and MCGA pictures
-	 * this is always 0; for EGA pictures it can be any colour between 0 and 15.
-	 */
-	transparent = 0xff;
+	byte transparent = 0xff;
 	if (flags & 1)
 		transparent = flags >> 12;
 	out.writeByte(transparent);
 
-	/* The uncompressed picture is a long sequence of bytes. Every byte holds
-	 * the colour of a pixel, starting at the top left, stopping at the bottom right.
-	 * We keep track of our position in the current line. (There is a special case:
-	 * CGA pictures with no transparent colour are stored as bit patterns, i.e.
-	 * every byte holds the pattern for eight pixels. A pixel must be white if the
-	 * corresponding bit is set, otherwise it must be black.)
-	 */
-//    current_x = 1 + width;
-//    current_y = 1 - 1;
-
-	/* The compressed picture is a stream of bits. We read the file byte-wise,
-	 * storing the current byte in the variable "bits". Several bits make one code;
-	 * the variable "bits_shift" helps us to build the next code.
-	 */
-	bits_shift = 0;
-	bits = 0;
-
-reset_table:
-	/* Clear the table. We use a table of 3840 entries. Each entry consists of both
-	 * a value and a reference to another table entry. Following these references
-	 * we get a sequence of values. At the start of decompression all table entries
-	 * are undefined. Later we see how entries are set and used.
-	 */
-	next_entry = 1;
-
-	/* At the start of decompression 9 bits make one code; during the process this can
-	 * rise to 12 bits per code. 9 bits are sufficient to address both 256 literal values
-	 * and 256 table entries; 12 bits are sufficient to address both 256 literal values
-	 * and all 3840 table entries. The number of bits per code rises with the number of
-	 * table entries. When the table is cleared, the number of bits per code drops back to 9.
-	 */
-	bits_per_code = 9;
-
-next_code:
-
-	/* Read the next code from the graphics file. This requires some confusing bit operations.
-	 * Note that low bits always come first. Usually there are a few bits left over from
-	 * the previous code; these bits must be used before further bits are read from the
-	 * graphics file.
-	 */
-	code = bits >> (8 - bits_shift);
-
-	do {
-		bits = src.readByte();
-		code |= bits << bits_shift;
-
-		bits_shift += 8;
-	} while (bits_shift < bits_per_code);
-
-	bits_shift -= bits_per_code;
-
-	code &= 0xfff >> (12 - bits_per_code);
-
-	/* There are two codes with a special meaning. The first one is 256 which clears
-	 * the table and sets the number of bits per code to 9. (This is necessary when
-	 * the table is full.) The second one is 257 which marks the end of the picture.
-	 * For the sake of efficiency, we drecement the code by 256.
-	 */
-	code -= 256;
-
-	if (code == 0)
-		goto reset_table;
-	if (code == 1) {
-		bool t[256];
-		// *******DEBUG*******
-		Common::fill(&t[0], &t[256], false);
-		for (uint idx = 0; idx < out.size(); ++idx)
-			t[*((byte *)out.getData() + idx)] = true;
-
-		return new Common::MemoryReadStream(out.getData(), out.size(), DisposeAfterUse::YES);
-	}
-
-	/* Codes from 0 to 255 are literals, i.e. they represent a plain byte value.
-	 * Codes from 258 onwards are references to table entries, i.e. they represent
-	 * a sequence of byte values (see the remarks on the table above). This means
-	 * that for each code one or several byte values are added to the decompressed
-	 * picture. But there is yet more work to do: Every time we read a code one
-	 * table entry is set. As we said above, a table entry consist of both a value
-	 * and a reference to another table entry. If the current code is a literal,
-	 * then the value has to be set to this literal; but if the code refers to a
-	 * sequence of byte values, then the value has to be set to the last byte of
-	 * this sequence. In any case, the reference is set to the previous code.
-	 * Finally, one should be aware that a code may legally refer to the table entry
-	 * which is currently being set. This requires some extra care.
-	 */
-	_tableRef[next_entry] = prev_code;
+	int i;
+	short code, old = 0, first, clear_code;
+	Compress comp;
 
-	prev_code = code;
+	clear_code = 1 << CODE_SIZE;
+	comp._nextCode = clear_code + 2;
+	comp._tLen = CODE_SIZE + 1;
+	comp._tPtr = 0;
 
-	while (code >= 0) {
-		buf[bufpos++] = _tableVal[code];
-		code = (short) _tableRef[code];
+	for (i = 0; i < CODE_TABLE_SIZE; i++) {
+		code_table[i][PREFIX] = CODE_TABLE_SIZE;
+		code_table[i][PIXEL] = i;
 	}
 
-	if (next_entry == prev_code)
-		buf[0] = code;
-
-	_tableVal[next_entry] = code;
-
-	/* The number of bits per code is incremented when the current number of bits
-	 * no longer suffices to address all defined table entries; but in any case
-	 * the number of bits may never be greater than 12.
-	 */
-	next_entry++;
-
-	if (next_entry == raise_bits[bits_per_code - 9])
-		bits_per_code++;
-
-reverse_buffer:
-	/* Output the sequence of byte values (pixels). The order of the sequence
-	 * must be reversed. (This is why we have stored the sequence in a buffer;
-	 * experiments show that a buffer of 512 bytes suffices.)
-	 *
-	 * Either add a single pixel or a pattern of eight bits (b/w CGA pictures without
-	 * a transparent colour) to the current line. Increment our position by 1 or 8
-	 * respectively. The pixel may have to be painted several times if the scaling
-	 * factor is greater than one.
-	 */
-	if (display == kCGA && transparent == 0xff) {
-		// TODO
-	} else {
-		byte v = code;
-
-		if (v != transparent) {
-			v += colour_shift;
-
-			if (display != kMCGA) {
-				// TODO
-			} else {
-				// position shift
-			}
-
-			out.writeByte(v);
-
-			if (display == kAmiga) {
-				// TODO
-			}
+	for (;;) {
+		if ((code = comp.readCode(src)) == (clear_code + 1))
+			break;
+		if (code == clear_code) {
+			comp._tLen = CODE_SIZE + 1;
+			comp._nextCode = clear_code + 2;
+			code = comp.readCode(src);
+		} else {
+			first = (code == comp._nextCode) ? old : code;
+			while (code_table[first][PREFIX] != CODE_TABLE_SIZE)
+				first = code_table[first][PREFIX];
+			code_table[comp._nextCode][PREFIX] = old;
+			code_table[comp._nextCode++][PIXEL] = code_table[first][PIXEL];
 		}
+		old = code;
+		i = 0;
+		do
+			buffer[i++] = (unsigned char)code_table[code][PIXEL];
+		while ((code = code_table[code][PREFIX]) != CODE_TABLE_SIZE);
+		do
+			out.writeByte(buffer[--i]);
+		while (i > 0);
 	}
 
-	/* If there are no more values in the buffer then read the next code from the file.
-	 * Otherwise fetch the next byte value from the buffer and continue outputing the picture.
-	 */
-	if (bufpos == 0)
-		goto next_code;
-
-	code = (code & ~0xff) | buf[--bufpos];
-	goto reverse_buffer;
+	return new Common::MemoryReadStream(out.getData(), out.size(), DisposeAfterUse::YES);
 }
 
 } // End of namespace Frotz


Commit: 81541a5f049c4dd8ec10a9c13b163cf478bdc921
    https://github.com/scummvm/scummvm/commit/81541a5f049c4dd8ec10a9c13b163cf478bdc921
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-01-05T17:16:42-08:00

Commit Message:
GLK: FROTZ: Properly handle picture transparency

Changed paths:
    engines/glk/frotz/pics_decoder.cpp
    engines/glk/picture.cpp
    engines/glk/picture.h
    engines/glk/raw_decoder.cpp
    engines/glk/raw_decoder.h
    engines/glk/window_graphics.cpp


diff --git a/engines/glk/frotz/pics_decoder.cpp b/engines/glk/frotz/pics_decoder.cpp
index 73032df..375abf2 100644
--- a/engines/glk/frotz/pics_decoder.cpp
+++ b/engines/glk/frotz/pics_decoder.cpp
@@ -114,7 +114,7 @@ Common::SeekableReadStream *PictureDecoder::decode(Common::ReadStream &src, uint
 	// Write out palette
 	out.writeUint16LE(palette.size() / 3 + 2);
 	for (int idx = 0; idx < 6; ++idx)
-		out.writeByte(0);
+		out.writeByte((idx < 3) ? 0x77 : 0);
 	if (!palette.empty())
 		out.write(&palette[0], palette.size());
 
diff --git a/engines/glk/picture.cpp b/engines/glk/picture.cpp
index 2cebcb2..59ee50c 100644
--- a/engines/glk/picture.cpp
+++ b/engines/glk/picture.cpp
@@ -110,6 +110,7 @@ Picture *Pictures::load(uint32 id) {
 	const Graphics::Surface *img;
 	const byte *palette = nullptr;
 	uint palCount = 0;
+	int transColor = -1;
 	Picture *pic;
 
 	// Check if the picture is already in the store
@@ -131,6 +132,7 @@ Picture *Pictures::load(uint32 id) {
 		img = raw.getSurface();
 		palette = raw.getPalette();
 		palCount = raw.getPaletteColorCount();
+		transColor = raw.getTransparentColor();
 	} else if (f.open(Common::String::format("pic%u.rect", id))) {
 		rectImg.w = f.readUint16LE();
 		rectImg.h = f.readUint16LE();
@@ -144,6 +146,8 @@ Picture *Pictures::load(uint32 id) {
 	pic->_refCount = 1;
     pic->_id = id;
     pic->_scaled = false;
+	if (transColor != -1)
+		pic->clear(pic->getTransparentColor());
 
 	if (!img->getPixels()) {
 		// Area definition without any content
@@ -158,11 +162,13 @@ Picture *Pictures::load(uint32 id) {
 		const byte *srcP = (const byte *)img->getPixels();
 		byte *destP = (byte *)pic->getPixels();
 		for (int idx = 0; idx < img->w * img->h; ++idx, srcP++, destP += pic->format.bytesPerPixel) {
-			uint val = (*srcP >= palCount) ? 0 : pal[*srcP];
-			if (pic->format.bytesPerPixel == 2)
-				WRITE_LE_UINT16(destP, val);
-			else
-				WRITE_LE_UINT32(destP, val);
+			if ((int)*srcP != transColor) {
+				uint val = (*srcP >= palCount) ? 0 : pal[*srcP];
+				if (pic->format.bytesPerPixel == 2)
+					WRITE_LE_UINT16(destP, val);
+				else
+					WRITE_LE_UINT32(destP, val);
+			}
 		}
 	}
 
@@ -188,6 +194,13 @@ Picture *Pictures::scale(Picture *src, size_t sx, size_t sy) {
 
 /*--------------------------------------------------------------------------*/
 
+Picture::Picture(int width, int height, const Graphics::PixelFormat &fmt) :
+		Graphics::ManagedSurface(width, height, fmt), _refCount(0), _id(0), _scaled(false) {
+
+	// Default transparent color chosen at random
+	_transColor = format.RGBToColor(0x77, 0x77, 0x77);
+}
+
 void Picture::increment() {
 	++_refCount;
 }
diff --git a/engines/glk/picture.h b/engines/glk/picture.h
index 7c9bcc6..e3b6560 100644
--- a/engines/glk/picture.h
+++ b/engines/glk/picture.h
@@ -32,6 +32,8 @@ namespace Glk {
  * Picture/image class
  */
 struct Picture : Graphics::ManagedSurface {
+private:
+	int _transColor;
 public:
 	int _refCount;
 	uint _id;
@@ -40,14 +42,12 @@ public:
 	/**
 	 * Constructor
 	 */
-	Picture() : Graphics::ManagedSurface(), _refCount(0), _id(0), _scaled(false) {}
+	Picture() : Graphics::ManagedSurface(), _refCount(0), _id(0), _scaled(false), _transColor(0x7777) {}
 
 	/**
 	 * Constructor
 	 */
-	Picture(int width, int height, const Graphics::PixelFormat &fmt) :
-		Graphics::ManagedSurface(width, height, fmt), _refCount(0), _id(0), _scaled(false) {}
-
+	Picture(int width, int height, const Graphics::PixelFormat &fmt);
 	/**
 	 * Increment reference counter
 	 */
@@ -62,6 +62,16 @@ public:
 	 * Draw the picture
 	 */
 	void drawPicture(const Common::Point &destPos, const Common::Rect &box);
+
+	/**
+	 * Get the transparency color
+	 */
+	uint getTransparentColor() const { return _transColor; }
+
+	/**
+	 * Set the transparency color
+	 */
+	void setTransparentColor(uint color) { _transColor = color; }
 };
 
 /**
diff --git a/engines/glk/raw_decoder.cpp b/engines/glk/raw_decoder.cpp
index 659b333..cf37003 100644
--- a/engines/glk/raw_decoder.cpp
+++ b/engines/glk/raw_decoder.cpp
@@ -26,7 +26,8 @@
 
 namespace Glk {
 
-RawDecoder::RawDecoder() : Image::ImageDecoder(), _palette(nullptr), _paletteColorCount(0) {
+RawDecoder::RawDecoder() : Image::ImageDecoder(), _palette(nullptr), _paletteColorCount(0),
+	_transColor(0) {
 }
 
 RawDecoder::~RawDecoder() {
@@ -52,11 +53,15 @@ bool RawDecoder::loadStream(Common::SeekableReadStream &stream) {
 	_palette = new byte[_paletteColorCount * 3];
 	stream.read(_palette, _paletteColorCount * 3);
 
+	// Get the transparent color
+	byte transColor = stream.readByte();
+	if (transColor < _paletteColorCount)
+		_transColor = transColor;
+
 	// Set up the surface and read it in
-	stream.readByte();
 	_surface.create(width, height, Graphics::PixelFormat::createFormatCLUT8());
 
-	assert((stream.size() - stream.pos()) <= (int)(width * height));
+	assert((stream.size() - stream.pos()) == (int)(width * height));
 	byte *pixels = (byte *)_surface.getPixels();
 	stream.read(pixels, width * height);
 
diff --git a/engines/glk/raw_decoder.h b/engines/glk/raw_decoder.h
index 96f25c2..086cf25 100644
--- a/engines/glk/raw_decoder.h
+++ b/engines/glk/raw_decoder.h
@@ -45,6 +45,7 @@ private:
 	Graphics::Surface _surface;
 	byte *_palette;
 	uint16 _paletteColorCount;
+	int _transColor;
 public:
 	RawDecoder();
 	~RawDecoder();
@@ -54,6 +55,7 @@ public:
 	virtual const Graphics::Surface *getSurface() const override { return &_surface; }
 	virtual const byte *getPalette() const override { return _palette; }
 	virtual uint16 getPaletteColorCount() const override { return _paletteColorCount; }
+	int getTransparentColor() const { return _transColor; }
 };
 
 } // End of namespace Glk
diff --git a/engines/glk/window_graphics.cpp b/engines/glk/window_graphics.cpp
index bc762f5..063a590 100644
--- a/engines/glk/window_graphics.cpp
+++ b/engines/glk/window_graphics.cpp
@@ -230,7 +230,7 @@ void GraphicsWindow::drawPicture(Picture *src,  int x0, int y0, int width, int h
 	w = sx1 - sx0;
 	h = sy1 - sy0;
 
-	_surface->blitFrom(*src, Rect(sx0, sy0, sx0 + w, sy0 + h), Point(0, 0));
+	_surface->transBlitFrom(*src, Rect(sx0, sy0, sx0 + w, sy0 + h), Point(0, 0), src->getTransparentColor());
 }
 
 void GraphicsWindow::getSize(uint *width, uint *height) const {


Commit: cde7a021644774262f25d833303507ca180d8508
    https://github.com/scummvm/scummvm/commit/cde7a021644774262f25d833303507ca180d8508
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-01-05T18:00:17-08:00

Commit Message:
GLK: FROTX: Draw pictures at the correct position

Changed paths:
    engines/glk/frotz/glk_interface.cpp
    engines/glk/window_graphics.cpp


diff --git a/engines/glk/frotz/glk_interface.cpp b/engines/glk/frotz/glk_interface.cpp
index cf90ddc..959ab31 100644
--- a/engines/glk/frotz/glk_interface.cpp
+++ b/engines/glk/frotz/glk_interface.cpp
@@ -498,11 +498,15 @@ void GlkInterface::showBeyondZorkTitle() {
 }
 
 void GlkInterface::os_draw_picture(int picture, const Common::Point &pos) {
-	glk_image_draw(_wp._background, picture, pos.x - 1, pos.y - 1);
+	glk_image_draw(_wp._background, picture,
+		(pos.x - 1) * g_conf->_monoInfo._cellW,
+		(pos.y - 1) * g_conf->_monoInfo._cellH);
 }
 
 void GlkInterface::os_draw_picture(int picture, const Common::Rect &r) {
-	glk_image_draw_scaled(_wp._background, picture, r.left, r.top, r.width(), r.height());
+	Point cell(g_conf->_monoInfo._cellW, g_conf->_monoInfo._cellH);
+	glk_image_draw_scaled(_wp._background, picture, (r.left - 1) * cell.x, (r.top - 1) * cell.y,
+		r.width() * cell.x, r.height() * cell.y);
 }
 
 zchar GlkInterface::os_read_key(int timeout, bool show_cursor) {
diff --git a/engines/glk/window_graphics.cpp b/engines/glk/window_graphics.cpp
index 063a590..049d314 100644
--- a/engines/glk/window_graphics.cpp
+++ b/engines/glk/window_graphics.cpp
@@ -230,7 +230,7 @@ void GraphicsWindow::drawPicture(Picture *src,  int x0, int y0, int width, int h
 	w = sx1 - sx0;
 	h = sy1 - sy0;
 
-	_surface->transBlitFrom(*src, Rect(sx0, sy0, sx0 + w, sy0 + h), Point(0, 0), src->getTransparentColor());
+	_surface->transBlitFrom(*src, Rect(sx0, sy0, sx0 + w, sy0 + h), Point(x0, y0), src->getTransparentColor());
 }
 
 void GraphicsWindow::getSize(uint *width, uint *height) const {





More information about the Scummvm-git-logs mailing list