aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Gilbert2018-11-23 11:38:30 -0800
committerPaul Gilbert2018-12-08 19:05:59 -0800
commit0b1e695f249d695333279eaf711b779c43b7b13d (patch)
tree570cb74bd70a7a128815172a458ac0ab25cc45a9
parent720ef67a7d124f1d83fdea68879461bca9429a9b (diff)
downloadscummvm-rg350-0b1e695f249d695333279eaf711b779c43b7b13d.tar.gz
scummvm-rg350-0b1e695f249d695333279eaf711b779c43b7b13d.tar.bz2
scummvm-rg350-0b1e695f249d695333279eaf711b779c43b7b13d.zip
GLK: FROTZ: Beginnings of support for Infocom picture files
-rw-r--r--engines/glk/blorb.cpp5
-rw-r--r--engines/glk/conf.cpp4
-rw-r--r--engines/glk/frotz/glk_interface.cpp60
-rw-r--r--engines/glk/frotz/glk_interface.h35
-rw-r--r--engines/glk/frotz/pics.cpp116
-rw-r--r--engines/glk/frotz/pics.h107
-rw-r--r--engines/glk/glk_api.cpp2
-rw-r--r--engines/glk/glk_api.h2
-rw-r--r--engines/glk/module.mk1
9 files changed, 324 insertions, 8 deletions
diff --git a/engines/glk/blorb.cpp b/engines/glk/blorb.cpp
index ace0e91813..f8a8cbd7c3 100644
--- a/engines/glk/blorb.cpp
+++ b/engines/glk/blorb.cpp
@@ -40,6 +40,7 @@ enum {
ID_JPEG = MKTAG('J', 'P', 'E', 'G'),
ID_PNG = MKTAG('P', 'N', 'G', ' '),
+ ID_Rect = MKTAG('R', 'e', 'c', 't'),
ID_MIDI = MKTAG('M', 'I', 'D', 'I'),
ID_MP3 = MKTAG('M', 'P', '3', ' '),
@@ -138,9 +139,11 @@ Common::ErrorCode Blorb::load() {
if (ce._type == ID_Pict) {
ce._filename = Common::String::format("pic%u", ce._number);
if (ce._id == ID_JPEG)
- ce._filename += ".jpeg";
+ ce._filename += ".jpg";
else if (ce._id == ID_PNG)
ce._filename += ".png";
+ else if (ce._id == ID_Rect)
+ ce._filename += ".rect";
} else if (ce._type == ID_Snd) {
ce._filename = Common::String::format("snd%u", ce._number);
diff --git a/engines/glk/conf.cpp b/engines/glk/conf.cpp
index 89b08fb405..4775f26621 100644
--- a/engines/glk/conf.cpp
+++ b/engines/glk/conf.cpp
@@ -155,6 +155,10 @@ Conf::Conf(InterpreterType interpType) {
get("stylehint", _styleHint, 1);
get("safeclicks", _safeClicks);
+ // For simplicity's sake, only allow graphics when in non-paletted graphics modes
+ if (g_system->getScreenFormat().bytesPerPixel == 1)
+ _graphics = false;
+
Common::copy(T_STYLES, T_STYLES + style_NUMSTYLES, _tStyles);
Common::copy(G_STYLES, G_STYLES + style_NUMSTYLES, _gStyles);
diff --git a/engines/glk/frotz/glk_interface.cpp b/engines/glk/frotz/glk_interface.cpp
index a8b25a2d76..2790e3009d 100644
--- a/engines/glk/frotz/glk_interface.cpp
+++ b/engines/glk/frotz/glk_interface.cpp
@@ -21,13 +21,16 @@
*/
#include "glk/frotz/glk_interface.h"
+#include "glk/frotz/pics.h"
+#include "glk/conf.h"
+#include "glk/screen.h"
namespace Glk {
namespace Frotz {
GlkInterface::GlkInterface(OSystem *syst, const GlkGameDescription &gameDesc) :
GlkAPI(syst, gameDesc),
- oldstyle(0), curstyle(0), cury(1), curx(1), fixforced(0),
+ _pics(nullptr), oldstyle(0), curstyle(0), cury(1), curx(1), fixforced(0),
curr_fg(-2), curr_bg(-2), curr_font(1), prev_font(1), temp_font(0),
curr_status_ht(0), mach_status_ht(0), gos_status(nullptr), gos_upper(nullptr),
gos_lower(nullptr), gos_curwin(nullptr), gos_linepending(0), gos_linebuf(nullptr),
@@ -38,6 +41,10 @@ GlkInterface::GlkInterface(OSystem *syst, const GlkGameDescription &gameDesc) :
Common::fill(&statusline[0], &statusline[256], '\0');
}
+GlkInterface::~GlkInterface() {
+ delete _pics;
+}
+
void GlkInterface::initialize() {
uint width, height;
@@ -152,8 +159,13 @@ void GlkInterface::initialize() {
h_font_height = 1;
// Must be after screen dimensions are computed
- if (h_version == V6) {
- h_flags &= ~GRAPHICS_FLAG;
+ if (g_conf->_graphics) {
+ if (_blorb)
+ // Blorb file containers allow graphics
+ h_flags |= GRAPHICS_FLAG;
+ else if ((h_version == V6 || _storyId == BEYOND_ZORK) && initPictures())
+ // Earlier Infocom game with picture files
+ h_flags |= GRAPHICS_FLAG;
}
// Use the ms-dos interpreter number for v6, because that's the
@@ -170,6 +182,18 @@ void GlkInterface::initialize() {
}
}
+bool GlkInterface::initPictures() {
+ if (Pics::exists()) {
+ _pics = new Pics();
+ SearchMan.add("Pics", _pics, 99, false);
+ return true;
+ }
+
+ if (h_version == V6)
+ warning("Could not locate MG1 file");
+ return false;
+}
+
int GlkInterface::os_char_width(zchar z) {
return 1;
}
@@ -234,6 +258,18 @@ void GlkInterface::os_stop_sample(int a) {
void GlkInterface::os_beep(int volume) {
}
+bool GlkInterface::os_picture_data(int picture, glui32 *height, glui32 *width) {
+ if (_pics && picture == 0) {
+ *width = _pics->version();
+ *height = _pics->size();
+ return true;
+ } else {
+ return glk_image_get_info(picture, width, height);
+ }
+}
+
+
+
void GlkInterface::start_sample(int number, int volume, int repeats, zword eos) {
// TODO
}
@@ -405,6 +441,24 @@ void GlkInterface::gos_cancel_pending_line() {
gos_linepending = 0;
}
+void GlkInterface::os_restart_game(RestartAction stage) {
+ // Show Beyond Zork's title screen
+ if ((stage == RESTART_END) && (_storyId == BEYOND_ZORK)) {
+/*
+ uint w, h;
+ if (os_picture_data(1, &h, &w)) {
+ _screen->clear();
+ os_draw_picture(1, Common::Point(1, 1));
+ _events->waitForPress();
+ }
+ */
+ }
+}
+
+void GlkInterface::os_draw_picture(int picture, winid_t win, const Common::Point &pos) {
+ glk_image_draw(win, picture, pos.x - 1, pos.y - 1);
+}
+
zchar GlkInterface::os_read_key(int timeout, bool show_cursor) {
event_t ev;
winid_t win = gos_curwin ? gos_curwin : gos_lower;
diff --git a/engines/glk/frotz/glk_interface.h b/engines/glk/frotz/glk_interface.h
index 5e2fa62663..0dc88466f2 100644
--- a/engines/glk/frotz/glk_interface.h
+++ b/engines/glk/frotz/glk_interface.h
@@ -42,6 +42,7 @@ enum RestartAction {
RESTART_END = 2
};
+class Pics;
/**
* Implements an intermediate interface on top of the GLK layer, providing screen
@@ -49,6 +50,7 @@ enum RestartAction {
*/
class GlkInterface : public GlkAPI, public virtual UserOptions, public virtual Mem {
public:
+ Pics *_pics;
zchar statusline[256];
int oldstyle;
int curstyle;
@@ -93,6 +95,11 @@ public:
bool _soundLocked;
bool _soundPlaying;
+private:
+ /**
+ * Loads the pictures file for Infocom V6 games
+ */
+ bool initPictures();
protected:
/**
* Return the length of the character in screen units.
@@ -133,10 +140,30 @@ protected:
*/
void os_start_sample(int number, int volume, int repeats, zword eos);
+ /**
+ * Stop playing a given sound number
+ */
void os_stop_sample(int a);
+
+ /**
+ * Make a beep sound
+ */
void os_beep(int volume);
/**
+ * Return true if the given picture is available. If so, write the
+ * width and height of the picture into the appropriate variables.
+ * Only when picture 0 is asked for, write the number of available
+ * pictures and the release number instead.
+ */
+ bool os_picture_data(int picture, glui32 *height, glui32 *width);
+
+ /**
+ * Display a picture at the given coordinates. Top left is (1,1).
+ */
+ void os_draw_picture(int picture, winid_t win, const Common::Point &pos);
+
+ /**
* Call the IO interface to play a sample.
*/
void start_sample(int number, int volume, int repeats, zword eos);
@@ -165,7 +192,7 @@ protected:
/**
* Called during game restarts
*/
- void os_restart_game(RestartAction) {}
+ void os_restart_game(RestartAction stage);
/**
* Reads the mouse buttons
@@ -197,7 +224,11 @@ public:
* Constructor
*/
GlkInterface(OSystem *syst, const GlkGameDescription &gameDesc);
- virtual ~GlkInterface() {}
+
+ /**
+ * Destructor
+ */
+ virtual ~GlkInterface();
/**
* Initialization
diff --git a/engines/glk/frotz/pics.cpp b/engines/glk/frotz/pics.cpp
new file mode 100644
index 0000000000..29d2ec5e52
--- /dev/null
+++ b/engines/glk/frotz/pics.cpp
@@ -0,0 +1,116 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "glk/frotz/pics.h"
+#include "glk/glk.h"
+
+namespace Glk {
+namespace Frotz {
+
+enum {
+ PIC_FILE_HEADER_FLAGS = 1,
+ PIC_FILE_HEADER_NUM_IMAGES = 4,
+ PIC_FILE_HEADER_ENTRY_SIZE = 8,
+ PIC_FILE_HEADER_VERSION = 14
+};
+
+Pics::Pics() : Common::Archive(), _filename(getFilename()) {
+ Common::File f;
+ if (!f.open(_filename))
+ error("Error reading Pics file");
+
+ byte buffer[16];
+ f.read(buffer, 16);
+ _index.resize(READ_LE_UINT16(&buffer[PIC_FILE_HEADER_NUM_IMAGES]));
+ _entrySize = buffer[PIC_FILE_HEADER_ENTRY_SIZE];
+ _version = buffer[PIC_FILE_HEADER_FLAGS];
+
+ // Iterate through loading the index
+ for (uint idx = 0; idx < _index.size(); ++idx) {
+ Entry &e = _index[idx];
+ e._number = f.readUint16LE();
+ e._offset = f.pos();
+ e._size = _entrySize - 2;
+ f.skip(_entrySize - 2);
+
+ e._filename = Common::String::format("PIC%u", e._number);
+ }
+
+ f.close();
+}
+
+Common::String Pics::getFilename() {
+ Common::String filename = g_vm->getFilename();
+ while (filename.contains('.'))
+ filename.deleteLastChar();
+
+ return filename + ".mg1";
+}
+
+bool Pics::exists() {
+ return Common::File::exists(getFilename());
+}
+
+bool Pics::hasFile(const Common::String &name) const {
+ for (uint idx = 0; idx < _index.size(); ++idx) {
+ if (_index[idx]._filename.equalsIgnoreCase(name))
+ return true;
+ }
+
+ return false;
+}
+
+int Pics::listMembers(Common::ArchiveMemberList &list) const {
+ for (uint idx = 0; idx < _index.size(); ++idx) {
+ list.push_back(Common::ArchiveMemberList::value_type(new Common::GenericArchiveMember(_index[idx]._filename, this)));
+ }
+
+ return (int)_index.size();
+}
+
+const Common::ArchiveMemberPtr Pics::getMember(const Common::String &name) const {
+ if (!hasFile(name))
+ return Common::ArchiveMemberPtr();
+
+ return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, this));
+}
+
+Common::SeekableReadStream *Pics::createReadStreamForMember(const Common::String &name) const {
+ for (uint idx = 0; idx < _index.size(); ++idx) {
+ if (_index[idx]._filename.equalsIgnoreCase(name)) {
+ Common::File f;
+ if (!f.open(_filename))
+ error("Reading failed");
+
+ f.seek(_index[idx]._offset);
+ Common::SeekableReadStream *result = f.readStream(_index[idx]._size);
+ f.close();
+
+ return result;
+ }
+ }
+
+ return nullptr;
+}
+
+} // End of namespace Frotz
+} // End of namespace Glk
diff --git a/engines/glk/frotz/pics.h b/engines/glk/frotz/pics.h
new file mode 100644
index 0000000000..55e3c0dd03
--- /dev/null
+++ b/engines/glk/frotz/pics.h
@@ -0,0 +1,107 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GLK_FROTZ_PICS
+#define GLK_FROTZ_PICS
+
+#include "common/archive.h"
+#include "common/array.h"
+
+namespace Glk {
+namespace Frotz {
+
+/**
+ * Infocom graphics file manager
+ */
+class Pics : public Common::Archive {
+ /**
+ * Describes one chunk of the Blorb file.
+ */
+ struct Entry {
+ uint _number;
+ size_t _offset;
+ size_t _size;
+ Common::String _filename;
+ };
+private:
+ Common::String _filename;
+ Common::Array<Entry> _index; ///< list of entries
+ uint _entrySize;
+ uint _version;
+private:
+ /**
+ * Returns the filename for the pictures archive
+ */
+ static Common::String getFilename();
+public:
+ /**
+ * Returns true if an mg1 file exists for the game
+ */
+ static bool exists();
+public:
+ /**
+ * Constructor
+ */
+ Pics();
+
+ /**
+ * Return the number of entries in the file
+ */
+ size_t size() const { return _index.size(); }
+
+ /**
+ * Return the version of the file
+ */
+ uint version() const { return _version; }
+
+ /**
+ * Check if a member with the given name is present in the Archive.
+ * Patterns are not allowed, as this is meant to be a quick File::exists()
+ * replacement.
+ */
+ virtual bool hasFile(const Common::String &name) const override;
+
+ /**
+ * Add all members of the Archive to list.
+ * Must only append to list, and not remove elements from it.
+ *
+ * @return the number of names added to list
+ */
+ virtual int listMembers(Common::ArchiveMemberList &list) const override;
+
+ /**
+ * Returns a ArchiveMember representation of the given file.
+ */
+ virtual const Common::ArchiveMemberPtr getMember(const Common::String &name) const override;
+
+ /**
+ * Create a stream bound to a member with the specified name in the
+ * archive. If no member with this name exists, 0 is returned.
+ * @return the newly created input stream
+ */
+ virtual Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const override;
+};
+
+} // End of namespace Frotz
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/glk_api.cpp b/engines/glk/glk_api.cpp
index ec98ab6374..981c41ef54 100644
--- a/engines/glk/glk_api.cpp
+++ b/engines/glk/glk_api.cpp
@@ -920,7 +920,7 @@ glui32 GlkAPI::glk_image_draw_scaled(winid_t win, glui32 image, glsi32 val1, gls
return false;
}
-glui32 GlkAPI::glk_image_get_info(glui32 image, glui32 *width, glui32 *height) {
+bool GlkAPI::glk_image_get_info(glui32 image, glui32 *width, glui32 *height) {
if (!g_conf->_graphics)
return false;
diff --git a/engines/glk/glk_api.h b/engines/glk/glk_api.h
index b625f69bf7..5c19e09cb5 100644
--- a/engines/glk/glk_api.h
+++ b/engines/glk/glk_api.h
@@ -193,7 +193,7 @@ public:
glui32 glk_image_draw(winid_t win, glui32 image, glsi32 val1, glsi32 val2);
glui32 glk_image_draw_scaled(winid_t win, glui32 image,
glsi32 val1, glsi32 val2, glui32 width, glui32 height);
- glui32 glk_image_get_info(glui32 image, glui32 *width, glui32 *height);
+ bool glk_image_get_info(glui32 image, glui32 *width, glui32 *height);
void glk_window_flow_break(winid_t win);
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index eedab577a7..d1d9100f32 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -26,6 +26,7 @@ MODULE_OBJS := \
frotz/frotz.o \
frotz/glk_interface.o \
frotz/mem.o \
+ frotz/pics.o \
frotz/processor.o \
frotz/processor_buffer.o \
frotz/processor_input.o \