aboutsummaryrefslogtreecommitdiff
path: root/engines/glk/frotz
diff options
context:
space:
mode:
authorPaul Gilbert2018-11-24 12:21:58 -0800
committerPaul Gilbert2018-12-08 19:05:59 -0800
commit62af5ea8919a5148154413eaec80a9e686d64114 (patch)
treebd48be729682c64f30d54b1cae56bd80be96a257 /engines/glk/frotz
parent3700919881a9636ae02478691d8c7c73a6d5084b (diff)
downloadscummvm-rg350-62af5ea8919a5148154413eaec80a9e686d64114.tar.gz
scummvm-rg350-62af5ea8919a5148154413eaec80a9e686d64114.tar.bz2
scummvm-rg350-62af5ea8919a5148154413eaec80a9e686d64114.zip
GLK: FROTZ: More work on displaying Beyond Zork title screen
Diffstat (limited to 'engines/glk/frotz')
-rw-r--r--engines/glk/frotz/glk_interface.cpp36
-rw-r--r--engines/glk/frotz/pics.cpp23
-rw-r--r--engines/glk/frotz/pics.h20
-rw-r--r--engines/glk/frotz/pics_decoder.cpp219
-rw-r--r--engines/glk/frotz/pics_decoder.h18
5 files changed, 280 insertions, 36 deletions
diff --git a/engines/glk/frotz/glk_interface.cpp b/engines/glk/frotz/glk_interface.cpp
index 4e7a503d82..c046bb4d1e 100644
--- a/engines/glk/frotz/glk_interface.cpp
+++ b/engines/glk/frotz/glk_interface.cpp
@@ -97,10 +97,8 @@ void GlkInterface::initialize() {
glk_stylehint_set(wintype_AllTypes, style_Note, stylehint_Oblique, 1);
/*
- * Open game windows
+ * Get the screen size
*/
- if (_storyId == BEYOND_ZORK)
- showBeyondZorkTitle();
gos_lower = glk_window_open(0, 0, 0, wintype_TextGrid, 0);
if (!gos_lower)
@@ -108,20 +106,8 @@ void GlkInterface::initialize() {
glk_window_get_size(gos_lower, &width, &height);
glk_window_close(gos_lower, nullptr);
- gos_lower = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
- gos_upper = glk_window_open(gos_lower,
- winmethod_Above | winmethod_Fixed,
- 0,
- wintype_TextGrid, 0);
-
gos_channel = nullptr;
- glk_set_window(gos_lower);
- gos_curwin = gos_lower;
-
- // Set the screen colors
- garglk_set_zcolors(_defaultForeground, _defaultBackground);
-
/*
* Icky magic bit setting
*/
@@ -186,6 +172,24 @@ void GlkInterface::initialize() {
if (h_flags & COLOUR_FLAG)
h_flags &= ~COLOUR_FLAG;
}
+
+ /*
+ * Open the windows
+ */
+ if (_storyId == BEYOND_ZORK)
+ showBeyondZorkTitle();
+
+ gos_lower = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
+ gos_upper = glk_window_open(gos_lower,
+ winmethod_Above | winmethod_Fixed,
+ 0,
+ wintype_TextGrid, 0);
+
+ glk_set_window(gos_lower);
+ gos_curwin = gos_lower;
+
+ // Set the screen colors
+ garglk_set_zcolors(_defaultForeground, _defaultBackground);
}
bool GlkInterface::initPictures() {
@@ -274,8 +278,6 @@ bool GlkInterface::os_picture_data(int picture, glui32 *height, glui32 *width) {
}
}
-
-
void GlkInterface::start_sample(int number, int volume, int repeats, zword eos) {
// TODO
}
diff --git a/engines/glk/frotz/pics.cpp b/engines/glk/frotz/pics.cpp
index 976c2b2cde..4953f047b9 100644
--- a/engines/glk/frotz/pics.cpp
+++ b/engines/glk/frotz/pics.cpp
@@ -46,7 +46,7 @@ Pics::Pics() : Common::Archive(), _filename(getFilename()) {
_index.resize(READ_LE_UINT16(&buffer[PIC_FILE_HEADER_NUM_IMAGES]));
_entrySize = buffer[PIC_FILE_HEADER_ENTRY_SIZE];
_version = buffer[PIC_FILE_HEADER_FLAGS];
- assert(_entrySize >= 6 && _entrySize <= 14);
+ assert(_entrySize >= 8 && _entrySize <= 14);
// Iterate through loading the index
for (uint idx = 0; idx < _index.size(); ++idx) {
@@ -56,6 +56,7 @@ Pics::Pics() : Common::Archive(), _filename(getFilename()) {
e._number = READ_LE_UINT16(buffer);
e._width = READ_LE_UINT16(buffer + 2);
e._height = READ_LE_UINT16(buffer + 4);
+ e._flags = READ_LE_UINT16(buffer + 6);
if (_entrySize >= 11) {
e._dataOffset = READ_BE_UINT32(buffer + 7) & 0xffffff;
@@ -64,8 +65,6 @@ Pics::Pics() : Common::Archive(), _filename(getFilename()) {
if (_entrySize == 14) {
e._paletteOffset = READ_BE_UINT32(buffer + 10) & 0xffffff;
- e._paletteSize = e._dataOffset - e._paletteOffset;
- assert((e._paletteSize % 3) == 0);
}
}
@@ -132,25 +131,29 @@ Common::SeekableReadStream *Pics::createReadStreamForMember(const Common::String
for (uint idx = 0; idx < _index.size(); ++idx) {
const Entry &e = _index[idx];
if (e._filename.equalsIgnoreCase(name)) {
+ Common::Array<byte> palette;
Common::File f;
+ Common::SeekableReadStream *dest;
if (!f.open(_filename))
error("Reading failed");
// Read in the image's palette
- assert(e._paletteSize);
- Common::Array<byte> palette;
- palette.resize(e._paletteSize);
+ assert(e._paletteOffset);
f.seek(e._paletteOffset);
- f.read(&palette[0], e._paletteSize);
+ palette.resize(f.readByte() * 3);
+ f.read(&palette[0], palette.size());
+ PictureDecoder decoder;
if (e._dataSize) {
Common::SeekableReadStream *src = f.readStream(e._dataSize);
- f.close();
- return PictureDecoder::decode(*src, &palette[0]);
-
+ dest = decoder.decode(*src, e._flags, palette, MCGA, e._width, e._height);
+ delete src;
} else {
error("TODO: Empty rect renderings");
}
+
+ f.close();
+ return dest;
}
}
diff --git a/engines/glk/frotz/pics.h b/engines/glk/frotz/pics.h
index b05acc5e9f..2c6d17a49e 100644
--- a/engines/glk/frotz/pics.h
+++ b/engines/glk/frotz/pics.h
@@ -29,24 +29,36 @@
namespace Glk {
namespace Frotz {
+enum PicturesMode {
+ MONO = 0,
+ TEXT = 1,
+ CGA = 2,
+ MCGA = 3,
+ EGA = 4,
+ AMIGA = 5
+};
+
/**
* Infocom graphics file manager
*/
class Pics : public Common::Archive {
/**
- * Describes one chunk of the Blorb file.
+ * Describes a single index entry
*/
struct Entry {
uint _number;
size_t _width, _height;
+ uint _flags;
size_t _dataOffset;
size_t _dataSize;
size_t _paletteOffset;
- size_t _paletteSize;
Common::String _filename;
- Entry() : _number(0), _width(0), _height(0), _dataOffset(0), _dataSize(0),
- _paletteOffset(0), _paletteSize(0) {}
+ /**
+ * Constructor
+ */
+ Entry() : _number(0), _width(0), _height(0), _flags(0), _dataOffset(0), _dataSize(0),
+ _paletteOffset(0) {}
};
private:
Common::String _filename;
diff --git a/engines/glk/frotz/pics_decoder.cpp b/engines/glk/frotz/pics_decoder.cpp
index a67ed12f0c..dbe8aed627 100644
--- a/engines/glk/frotz/pics_decoder.cpp
+++ b/engines/glk/frotz/pics_decoder.cpp
@@ -21,13 +21,226 @@
*/
#include "glk/frotz/pics_decoder.h"
+#include "glk/frotz/pics.h"
+#include "common/memstream.h"
namespace Glk {
namespace Frotz {
-Common::MemoryReadStream *PictureDecoder::decode(Common::ReadStream &src, const byte *palette) {
- // TODO
- return nullptr;
+PictureDecoder::PictureDecoder() {
+ _tableVal = new byte[3 * 3840];
+ _tableRef = (uint16 *)(_tableVal + 3840);
+}
+
+PictureDecoder::~PictureDecoder() {
+ delete[] _tableVal;
+}
+
+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;
+// int first_colour;
+ int code, prev_code = 0;
+ int next_entry;
+ int bits_per_code;
+ int bits_shift;
+ int bits;
+ int bufpos = 0;
+ int i;
+
+ /*
+ * Write out dimensions of image
+ */
+ 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 CGA:
+ colour_shift = -2;
+ break;
+ case EGA:
+ colour_shift = 0;
+ break;
+ case MCGA:
+ colour_shift = 32;
+ first_colour = 34;
+ break;
+ case AMIGA:
+ colour_shift = -1;
+ first_colour = 65;
+ break;
+ default:
+ break;
+ }
+ */
+ out.writeUint16LE(palette.size() / 3);
+ 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;
+ 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) {
+ 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;
+
+ prev_code = code;
+
+ while (code >= 0) {
+ buf[bufpos++] = _tableVal[code];
+ code = (short) _tableRef[code];
+ }
+
+ 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 == CGA && transparent == 0xff) {
+ // TODO
+ } else {
+ byte v = code;
+
+ if (v != transparent) {
+ //v += colour_shift;
+
+ if (display != MCGA) {
+ // TODO
+ } else {
+ // position shift
+ }
+
+ out.writeByte(v);
+
+ if (display == AMIGA) {
+ // TODO
+ }
+ }
+ }
+
+ /* 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;
}
} // End of namespace Frotz
diff --git a/engines/glk/frotz/pics_decoder.h b/engines/glk/frotz/pics_decoder.h
index 41484a1ffd..3d2165fc01 100644
--- a/engines/glk/frotz/pics_decoder.h
+++ b/engines/glk/frotz/pics_decoder.h
@@ -23,8 +23,8 @@
#ifndef GLK_FROTZ_PICS_DECODER_H
#define GLK_FROTZ_PICS_DECODER_H
-#include "common/memstream.h"
#include "common/stream.h"
+#include "common/array.h"
namespace Glk {
namespace Frotz {
@@ -34,11 +34,25 @@ namespace Frotz {
* Glk engine is capable of then loading into a picture object
*/
class PictureDecoder {
+private:
+ byte *_tableVal;
+ uint16 *_tableRef;
public:
/**
+ * Constructor
+ */
+ PictureDecoder();
+
+ /**
+ * Destructor
+ */
+ ~PictureDecoder();
+
+ /**
* Decode method
*/
- static Common::MemoryReadStream *decode(Common::ReadStream &src, const byte *palette);
+ Common::SeekableReadStream *decode(Common::ReadStream &src, uint flags,
+ const Common::Array<byte> &palette, uint display, size_t width, size_t height);
};
} // End of namespace Frotz