diff options
author | Paul Gilbert | 2018-11-24 12:21:58 -0800 |
---|---|---|
committer | Paul Gilbert | 2018-12-08 19:05:59 -0800 |
commit | 62af5ea8919a5148154413eaec80a9e686d64114 (patch) | |
tree | bd48be729682c64f30d54b1cae56bd80be96a257 /engines/glk/frotz | |
parent | 3700919881a9636ae02478691d8c7c73a6d5084b (diff) | |
download | scummvm-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.cpp | 36 | ||||
-rw-r--r-- | engines/glk/frotz/pics.cpp | 23 | ||||
-rw-r--r-- | engines/glk/frotz/pics.h | 20 | ||||
-rw-r--r-- | engines/glk/frotz/pics_decoder.cpp | 219 | ||||
-rw-r--r-- | engines/glk/frotz/pics_decoder.h | 18 |
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 |