aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorPaul Gilbert2019-01-01 18:31:07 -0800
committerPaul Gilbert2019-01-01 18:31:07 -0800
commitc43f625fd814e2f3baf61d76441121bbe3554f91 (patch)
tree1861cdb7a246f21144c463bf0435fdeef0dc0ac3 /engines
parent4568e498cabd2c8523a5c0717e57c71d334f26e7 (diff)
downloadscummvm-rg350-c43f625fd814e2f3baf61d76441121bbe3554f91.tar.gz
scummvm-rg350-c43f625fd814e2f3baf61d76441121bbe3554f91.tar.bz2
scummvm-rg350-c43f625fd814e2f3baf61d76441121bbe3554f91.zip
GLK: FROTZ: Added skeleton classes for ZMachine windows
Diffstat (limited to 'engines')
-rw-r--r--engines/glk/frotz/glk_interface.cpp153
-rw-r--r--engines/glk/frotz/glk_interface.h4
-rw-r--r--engines/glk/frotz/processor_screen.cpp70
-rw-r--r--engines/glk/frotz/processor_windows.cpp11
-rw-r--r--engines/glk/frotz/windows.cpp97
-rw-r--r--engines/glk/frotz/windows.h97
-rw-r--r--engines/glk/module.mk1
7 files changed, 313 insertions, 120 deletions
diff --git a/engines/glk/frotz/glk_interface.cpp b/engines/glk/frotz/glk_interface.cpp
index 4aa2ba4e78..514435aaf0 100644
--- a/engines/glk/frotz/glk_interface.cpp
+++ b/engines/glk/frotz/glk_interface.cpp
@@ -33,13 +33,11 @@ namespace Frotz {
GlkInterface::GlkInterface(OSystem *syst, const GlkGameDescription &gameDesc) :
GlkAPI(syst, gameDesc),
- _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),
- gos_linewin(nullptr), gos_channel(nullptr), cwin(0), mwin(0), mouse_x(0), mouse_y(0),
- menu_selected(0), enable_wrapping(false), enable_scripting(false),
- enable_scrolling(false), enable_buffering(false), next_sample(0), next_volume(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_curwin(nullptr), gos_linepending(0), gos_linebuf(nullptr), gos_linewin(nullptr),
+ gos_channel(nullptr), cwin(0), mwin(0), mouse_x(0), mouse_y(0), menu_selected(0), enable_wrapping(false),
+ enable_scripting(false), enable_scrolling(false), enable_buffering(false), next_sample(0), next_volume(0),
_soundLocked(false), _soundPlaying(false) {
Common::fill(&statusline[0], &statusline[256], '\0');
}
@@ -103,47 +101,14 @@ void GlkInterface::initialize() {
* Get the screen size
*/
- gos_lower = glk_window_open(0, 0, 0, wintype_TextGrid, 0);
- if (!gos_lower)
- gos_lower = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
- glk_window_get_size(gos_lower, &width, &height);
- glk_window_close(gos_lower, nullptr);
+ _wp._lower = glk_window_open(0, 0, 0, wintype_TextGrid, 0);
+ if (!_wp._lower)
+ _wp._lower = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
+ glk_window_get_size(_wp._lower, &width, &height);
+ glk_window_close(_wp._lower, nullptr);
gos_channel = nullptr;
- /*
- * Icky magic bit setting
- */
-
- if (h_version == V3 && _tandyBit)
- h_config |= CONFIG_TANDY;
-
- if (h_version == V3 && gos_upper)
- h_config |= CONFIG_SPLITSCREEN;
-
- if (h_version == V3 && !gos_upper)
- h_config |= CONFIG_NOSTATUSLINE;
-
- if (h_version >= V4)
- h_config |= CONFIG_BOLDFACE | CONFIG_EMPHASIS |
- CONFIG_FIXED | CONFIG_TIMEDINPUT | CONFIG_COLOUR;
-
- if (h_version >= V5)
- h_flags &= ~(GRAPHICS_FLAG | MOUSE_FLAG | MENU_FLAG);
-
- if ((h_version >= 5) && (h_flags & SOUND_FLAG))
- h_flags |= SOUND_FLAG;
-
- if ((h_version == 3) && (h_flags & OLD_SOUND_FLAG))
- h_flags |= OLD_SOUND_FLAG;
-
- if ((h_version == 6) && (_sound != 0))
- h_config |= CONFIG_SOUND;
-
- if (h_version >= V5 && (h_flags & UNDO_FLAG))
- if (_undo_slots == 0)
- h_flags &= ~UNDO_FLAG;
-
h_screen_cols = width;
h_screen_rows = height;
@@ -180,14 +145,48 @@ void GlkInterface::initialize() {
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);
+ _wp._lower = glk_window_open(0, 0, 0, wintype_TextBuffer, 0);
+ _wp._upper = glk_window_open(_wp._lower, winmethod_Above | winmethod_Fixed, 0, wintype_TextGrid, 0);
- glk_set_window(gos_lower);
- gos_curwin = gos_lower;
+ glk_set_window(_wp._lower);
+ gos_curwin = _wp._lower;
+
+ /*
+ * Icky magic bit setting
+ */
+
+ if (h_version == V3 && _tandyBit)
+ h_config |= CONFIG_TANDY;
+
+ if (h_version == V3 && _wp._upper)
+ h_config |= CONFIG_SPLITSCREEN;
+
+ if (h_version == V3 && !_wp._upper)
+ h_config |= CONFIG_NOSTATUSLINE;
+
+ if (h_version >= V4)
+ h_config |= CONFIG_BOLDFACE | CONFIG_EMPHASIS |
+ CONFIG_FIXED | CONFIG_TIMEDINPUT | CONFIG_COLOUR;
+
+ if (h_version >= V5)
+ h_flags &= ~(GRAPHICS_FLAG | MOUSE_FLAG | MENU_FLAG);
+
+ if ((h_version >= 5) && (h_flags & SOUND_FLAG))
+ h_flags |= SOUND_FLAG;
+
+ if ((h_version == 3) && (h_flags & OLD_SOUND_FLAG))
+ h_flags |= OLD_SOUND_FLAG;
+
+ if ((h_version == 6) && (_sound != 0))
+ h_config |= CONFIG_SOUND;
+
+ if (h_version >= V5 && (h_flags & UNDO_FLAG))
+ if (_undo_slots == 0)
+ h_flags &= ~UNDO_FLAG;
+
+ /*
+ * Miscellaneous
+ */
// Set the screen colors
garglk_set_zcolors(_defaultForeground, _defaultBackground);
@@ -199,7 +198,7 @@ void GlkInterface::initialize() {
// since the arrow keys the original used are in use now for cycling prior commands
if (_storyId == BEYOND_ZORK) {
uint32 KEYCODES[2] = { keycode_PageUp, keycode_PageDown };
- glk_set_terminators_line_event(gos_lower, KEYCODES, 2);
+ glk_set_terminators_line_event(_wp._lower, KEYCODES, 2);
}
}
@@ -322,12 +321,12 @@ void GlkInterface::start_next_sample() {
void GlkInterface::gos_update_width() {
uint width;
- if (gos_upper) {
- glk_window_get_size(gos_upper, &width, nullptr);
+ if (_wp._upper) {
+ glk_window_get_size(_wp._upper, &width, nullptr);
h_screen_cols = width;
SET_BYTE(H_SCREEN_COLS, width);
if ((uint)curx > width) {
- glk_window_move_cursor(gos_upper, 0, cury - 1);
+ glk_window_move_cursor(_wp._upper, 0, cury - 1);
curx = 1;
}
}
@@ -337,8 +336,8 @@ void GlkInterface::gos_update_height() {
uint height_upper;
uint height_lower;
if (gos_curwin) {
- glk_window_get_size(gos_upper, nullptr, &height_upper);
- glk_window_get_size(gos_lower, nullptr, &height_lower);
+ glk_window_get_size(_wp._upper, nullptr, &height_upper);
+ glk_window_get_size(_wp._lower, nullptr, &height_lower);
h_screen_rows = height_upper + height_lower + 1;
SET_BYTE(H_SCREEN_ROWS, h_screen_rows);
}
@@ -346,11 +345,11 @@ void GlkInterface::gos_update_height() {
void GlkInterface::reset_status_ht() {
uint height;
- if (gos_upper) {
- glk_window_get_size(gos_upper, nullptr, &height);
+ if (_wp._upper) {
+ glk_window_get_size(_wp._upper, nullptr, &height);
if ((uint)mach_status_ht != height) {
glk_window_set_arrangement(
- glk_window_get_parent(gos_upper),
+ glk_window_get_parent(_wp._upper),
winmethod_Above | winmethod_Fixed,
mach_status_ht, nullptr);
}
@@ -359,23 +358,21 @@ void GlkInterface::reset_status_ht() {
void GlkInterface::erase_window(zword w) {
if (w == 0)
- glk_window_clear(gos_lower);
- else if (gos_upper) {
+ glk_window_clear(_wp._lower);
+ else if (_wp._upper) {
#ifdef GARGLK
- garglk_set_reversevideo_stream(
- glk_window_get_stream(gos_upper),
- true);
+ garglk_set_reversevideo_stream(glk_window_get_stream(_wp._upper), true);
#endif /* GARGLK */
memset(statusline, ' ', sizeof statusline);
- glk_window_clear(gos_upper);
+ glk_window_clear(_wp._upper);
reset_status_ht();
curr_status_ht = 0;
}
}
void GlkInterface::split_window(zword lines) {
- if (!gos_upper)
+ if (!_wp._upper)
return;
// The top line is always set for V1 to V3 games
@@ -385,10 +382,10 @@ void GlkInterface::split_window(zword lines) {
if (!lines || lines > curr_status_ht) {
uint height;
- glk_window_get_size(gos_upper, nullptr, &height);
+ glk_window_get_size(_wp._upper, nullptr, &height);
if (lines != height)
glk_window_set_arrangement(
- glk_window_get_parent(gos_upper),
+ glk_window_get_parent(_wp._upper),
winmethod_Above | winmethod_Fixed,
lines, nullptr);
curr_status_ht = lines;
@@ -396,13 +393,13 @@ void GlkInterface::split_window(zword lines) {
mach_status_ht = lines;
if (cury > lines)
{
- glk_window_move_cursor(gos_upper, 0, 0);
+ glk_window_move_cursor(_wp._upper, 0, 0);
curx = cury = 1;
}
gos_update_width();
if (h_version == V3)
- glk_window_clear(gos_upper);
+ glk_window_clear(_wp._upper);
}
void GlkInterface::restart_screen() {
@@ -471,9 +468,9 @@ void GlkInterface::smartstatusline() {
memcpy(buf + 1 + scoreofs, c, scorelen * sizeof(zchar));
memcpy(buf + 1, a, roomlen * sizeof(zchar));
- glk_window_move_cursor(gos_upper, 0, 0);
+ glk_window_move_cursor(_wp._upper, 0, 0);
glk_put_buffer_uni(buf, h_screen_cols);
- glk_window_move_cursor(gos_upper, cury - 1, curx - 1);
+ glk_window_move_cursor(_wp._upper, cury - 1, curx - 1);
}
void GlkInterface::gos_cancel_pending_line() {
@@ -510,7 +507,7 @@ void GlkInterface::os_draw_picture(int picture, winid_t win, const Common::Rect
zchar GlkInterface::os_read_key(int timeout, bool show_cursor) {
event_t ev;
- winid_t win = gos_curwin ? gos_curwin : gos_lower;
+ winid_t win = gos_curwin ? gos_curwin : _wp._lower;
if (gos_linepending)
gos_cancel_pending_line();
@@ -536,7 +533,7 @@ zchar GlkInterface::os_read_key(int timeout, bool show_cursor) {
glk_request_timer_events(0);
- if (gos_upper && mach_status_ht < curr_status_ht)
+ if (_wp._upper && mach_status_ht < curr_status_ht)
reset_status_ht();
curr_status_ht = 0;
@@ -558,7 +555,7 @@ zchar GlkInterface::os_read_key(int timeout, bool show_cursor) {
zchar GlkInterface::os_read_line(int max, zchar *buf, int timeout, int width, int continued) {
event_t ev;
- winid_t win = gos_curwin ? gos_curwin : gos_lower;
+ winid_t win = gos_curwin ? gos_curwin : _wp._lower;
if (!continued && gos_linepending)
gos_cancel_pending_line();
@@ -592,7 +589,7 @@ zchar GlkInterface::os_read_line(int max, zchar *buf, int timeout, int width, in
buf[ev.val1] = '\0';
// If the upper status line area was expanded to show a text box/quotation, restore it back
- if (gos_upper && mach_status_ht < curr_status_ht)
+ if (_wp._upper && mach_status_ht < curr_status_ht)
reset_status_ht();
curr_status_ht = 0;
diff --git a/engines/glk/frotz/glk_interface.h b/engines/glk/frotz/glk_interface.h
index 4d69151560..5027edb4d5 100644
--- a/engines/glk/frotz/glk_interface.h
+++ b/engines/glk/frotz/glk_interface.h
@@ -25,6 +25,7 @@
#include "glk/glk_api.h"
#include "glk/frotz/mem.h"
+#include "glk/frotz/windows.h"
namespace Glk {
namespace Frotz {
@@ -67,9 +68,8 @@ public:
int curr_status_ht;
int mach_status_ht;
+ Windows _wp;
winid_t gos_status;
- winid_t gos_upper;
- winid_t gos_lower;
winid_t gos_curwin;
int gos_linepending;
zchar *gos_linebuf;
diff --git a/engines/glk/frotz/processor_screen.cpp b/engines/glk/frotz/processor_screen.cpp
index 33c91081ca..60672c85ab 100644
--- a/engines/glk/frotz/processor_screen.cpp
+++ b/engines/glk/frotz/processor_screen.cpp
@@ -26,7 +26,7 @@ namespace Glk {
namespace Frotz {
void Processor::screen_mssg_on() {
- if (gos_curwin == gos_lower) {
+ if (gos_curwin == _wp._lower) {
oldstyle = curstyle;
glk_set_style(style_Preformatted);
glk_put_string("\n ");
@@ -34,7 +34,7 @@ void Processor::screen_mssg_on() {
}
void Processor::screen_mssg_off() {
- if (gos_curwin == gos_lower) {
+ if (gos_curwin == _wp._lower) {
glk_put_char('\n');
zargs[0] = 0;
z_set_text_style();
@@ -98,7 +98,7 @@ uint32 Processor::zchar_to_unicode_rune(zchar c) {
void Processor::screen_char(zchar c) {
if (gos_linepending && (gos_curwin == gos_linewin)) {
gos_cancel_pending_line();
- if (gos_curwin == gos_upper) {
+ if (gos_curwin == _wp._upper) {
curx = 1;
cury ++;
}
@@ -119,7 +119,7 @@ void Processor::screen_char(zchar c) {
fixforced = false;
}
- if (gos_upper && gos_curwin == gos_upper) {
+ if (_wp._upper && gos_curwin == _wp._upper) {
if (c == '\n' || c == ZC_RETURN) {
glk_put_char('\n');
curx = 1;
@@ -151,7 +151,7 @@ void Processor::screen_char(zchar c) {
curx++;
}
}
- } else if (gos_curwin == gos_lower) {
+ } else if (gos_curwin == _wp._lower) {
if (c == ZC_RETURN)
glk_put_char('\n');
else {
@@ -200,7 +200,7 @@ store((zword)os_buffer_screen((zargs[0] == (zword)-1) ? -1 : zargs[0]));
void Processor::z_erase_line() {
int i;
- if (gos_upper && gos_curwin == gos_upper) {
+ if (_wp._upper && gos_curwin == _wp._upper) {
for (i = 0; i < h_screen_cols + 1 - curx; i++)
glk_put_char(' ');
glk_window_move_cursor(gos_curwin, curx - 1, cury - 1);
@@ -211,34 +211,33 @@ void Processor::z_erase_window() {
short w = zargs[0];
if (w == -2)
{
- if (gos_upper) {
- glk_set_window(gos_upper);
+ if (_wp._upper) {
+ glk_set_window(_wp._upper);
#ifdef GARGLK
garglk_set_zcolors(curr_fg, curr_bg);
#endif /* GARGLK */
- glk_window_clear(gos_upper);
+ glk_window_clear(_wp._upper);
glk_set_window(gos_curwin);
}
- glk_window_clear(gos_lower);
+ glk_window_clear(_wp._lower);
}
if (w == -1)
{
- if (gos_upper) {
- glk_set_window(gos_upper);
+ if (_wp._upper) {
+ glk_set_window(_wp._upper);
#ifdef GARGLK
garglk_set_zcolors(curr_fg, curr_bg);
#endif /* GARGLK */
- glk_window_clear(gos_upper);
+ glk_window_clear(_wp._upper);
}
- glk_window_clear(gos_lower);
+ glk_window_clear(_wp._lower);
split_window(0);
- glk_set_window(gos_lower);
- gos_curwin = gos_lower;
+ glk_set_window(_wp._lower);
+ gos_curwin = _wp._lower;
}
- if (w == 0)
- glk_window_clear(gos_lower);
- if (w == 1 && gos_upper)
- glk_window_clear(gos_upper);
+
+ if (w >= 0 && _wp[w])
+ glk_window_clear(_wp[w]);
}
void Processor::z_get_cursor() {
@@ -260,7 +259,7 @@ void Processor::z_print_table() {
// Write text in width x height rectangle
for (i = 0; i < zargs[2]; i++, curx = xs, cury++) {
- glk_window_move_cursor(cwin == 0 ? gos_lower : gos_upper, xs - 1, cury - 1);
+ glk_window_move_cursor(_wp[cwin], xs - 1, cury - 1);
for (j = 0; j < zargs[1]; j++) {
LOW_BYTE(addr, c);
@@ -384,7 +383,7 @@ void Processor::z_set_font() {
void Processor::z_set_cursor() {
int x = (int16)zargs[1], y = (int16)zargs[0];
- assert(gos_upper);
+ assert(_wp._upper);
flush_buffer();
@@ -394,7 +393,8 @@ void Processor::z_set_cursor() {
}
if (!x || !y) {
- Point cursorPos = gos_upper->getCursor();
+ winid_t win = _wp._upper;
+ Point cursorPos = win->getCursor();
if (!x)
x = cursorPos.x;
if (!y)
@@ -409,7 +409,7 @@ void Processor::z_set_cursor() {
reset_status_ht();
}
- glk_window_move_cursor(gos_upper, curx - 1, cury - 1);
+ glk_window_move_cursor(_wp._upper, curx - 1, cury - 1);
}
void Processor::z_set_text_style() {
@@ -468,12 +468,12 @@ void Processor::z_set_window() {
cwin = zargs[0];
if (cwin == 0) {
- glk_set_window(gos_lower);
- gos_curwin = gos_lower;
+ glk_set_window(_wp._lower);
+ gos_curwin = _wp._lower;
} else {
- if (gos_upper)
- glk_set_window(gos_upper);
- gos_curwin = gos_upper;
+ if (_wp._upper)
+ glk_set_window(_wp._upper);
+ gos_curwin = _wp._upper;
}
if (cwin == 0)
@@ -500,7 +500,7 @@ void Processor::z_show_status() {
bool brief = false;
- if (!gos_upper)
+ if (!_wp._upper)
return;
// One V5 game (Wishbringer Solid Gold) contains this opcode by accident,
@@ -519,15 +519,15 @@ void Processor::z_show_status() {
LOW_WORD(addr, global2);
// Move to top of the status window, and print in reverse style.
- glk_set_window(gos_upper);
- gos_curwin = gos_upper;
+ glk_set_window(_wp._upper);
+ gos_curwin = _wp._upper;
#ifdef GARGLK
garglk_set_reversevideo(true);
#endif /* GARGLK */
curx = cury = 1;
- glk_window_move_cursor(gos_upper, 0, 0);
+ glk_window_move_cursor(_wp._upper, 0, 0);
// If the screen width is below 55 characters then we have to use
// the brief status line format
@@ -580,8 +580,8 @@ void Processor::z_show_status() {
pad_status_line (0);
// Return to the lower window
- glk_set_window(gos_lower);
- gos_curwin = gos_lower;
+ glk_set_window(_wp._lower);
+ gos_curwin = _wp._lower;
}
void Processor::z_split_window() {
diff --git a/engines/glk/frotz/processor_windows.cpp b/engines/glk/frotz/processor_windows.cpp
index c0a1e3feee..ad16bbafe6 100644
--- a/engines/glk/frotz/processor_windows.cpp
+++ b/engines/glk/frotz/processor_windows.cpp
@@ -51,7 +51,8 @@ void Processor::z_draw_picture() {
if (!x || !y) {
// Currently I only support getting the cursor for the text grid area
assert(cwin == 1);
- Point cursPos = gos_upper->getCursor();
+ winid_t win = _wp._upper;
+ Point cursPos = win->getCursor();
// use cursor column if x-coordinate is 0
if (!x)
x = cursPos.x;
@@ -82,18 +83,18 @@ void Processor::z_draw_picture() {
if (_storyId == ARTHUR && pic == 54)
delta = h_screen_width / 160;
- os_draw_picture(mapper[i].pic1, gos_lower, Point(x + delta, y + height1));
- os_draw_picture(mapper[i].pic2, gos_lower, Point(x + width1 - width2 - delta, y + height1));
+ os_draw_picture(mapper[i].pic1, _wp._lower, Point(x + delta, y + height1));
+ os_draw_picture(mapper[i].pic2, _wp._lower, Point(x + width1 - width2 - delta, y + height1));
}
}
- os_draw_picture(pic, gos_lower, Point(x, y));
+ os_draw_picture(pic, _wp._lower, Point(x, y));
if (_storyId == SHOGUN && pic == 3) {
uint height, width;
os_picture_data(59, &height, &width);
- os_draw_picture(59, gos_lower, Point(h_screen_width - width + 1, y));
+ os_draw_picture(59, _wp._lower, Point(h_screen_width - width + 1, y));
}
}
diff --git a/engines/glk/frotz/windows.cpp b/engines/glk/frotz/windows.cpp
new file mode 100644
index 0000000000..8bdfafd879
--- /dev/null
+++ b/engines/glk/frotz/windows.cpp
@@ -0,0 +1,97 @@
+/* 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/screen.h"
+#include "glk/conf.h"
+#include "common/file.h"
+#include "graphics/fonts/ttf.h"
+#include "image/bmp.h"
+
+namespace Glk {
+namespace Frotz {
+
+FrotzScreen::FrotzScreen() : Glk::Screen() {
+ g_conf->_tStyles[style_User1].font = CUSTOM;
+ g_conf->_gStyles[style_User1].font = CUSTOM;
+ g_conf->_tStyles[style_User2].font = CUSTOM2;
+}
+
+void FrotzScreen::loadFonts(Common::Archive *archive) {
+ Screen::loadFonts(archive);
+
+ // Add character graphics font
+ Image::BitmapDecoder decoder;
+ Common::File f;
+ if (!f.open("infocom_graphics.bmp", *archive))
+ error("Could not load font");
+
+ Common::Point fontSize(_fonts[0]->getMaxCharWidth(), _fonts[0]->getFontHeight());
+ decoder.loadStream(f);
+ _fonts.push_back(new Frotz::BitmapFont(*decoder.getSurface(), fontSize));
+ f.close();
+
+ // Add Runic font. It provides cleaner versions of the runic characters in the
+ // character graphics font
+ if (!f.open("NotoSansRunic-Regular.ttf", *archive))
+ error("Could not load font");
+
+ _fonts.push_back(Graphics::loadTTFFont(f, g_conf->_propInfo._size, Graphics::kTTFSizeModeCharacter));
+ f.close();
+}
+
+/*--------------------------------------------------------------------------*/
+
+BitmapFont::BitmapFont(const Graphics::Surface &src, const Common::Point &size,
+ uint srcWidth, uint srcHeight, unsigned char startingChar) :
+ _startingChar(startingChar), _size(size) {
+ assert(src.format.bytesPerPixel == 1);
+ assert((src.w % srcWidth) == 0);
+ assert((src.h % srcHeight) == 0);
+
+ // Set up a characters array
+ _chars.resize((src.w / srcWidth) * (src.h / srcHeight));
+
+ // Iterate through loading characters
+ Common::Rect r(srcWidth, srcHeight);
+ int charsPerRow = src.w / srcWidth;
+ for (uint idx = 0; idx < _chars.size(); ++idx) {
+ r.moveTo((idx % charsPerRow) * srcWidth, (idx / charsPerRow) * srcHeight);
+
+ _chars[idx].create(size.x, size.y, src.format);
+ _chars[idx].transBlitFrom(src, r, Common::Rect(0, 0, size.x, size.y));
+ }
+}
+
+void BitmapFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
+ const Graphics::ManagedSurface &c = _chars[chr - _startingChar];
+ for (int yCtr = 0; yCtr < c.h; ++yCtr) {
+ const byte *srcP = (const byte *)c.getBasePtr(0, yCtr);
+
+ for (int xCtr = 0; xCtr < c.w; ++xCtr, ++srcP) {
+ if (!*srcP)
+ dst->hLine(x + xCtr, y + yCtr, x + xCtr, color);
+ }
+ }
+}
+
+} // End of namespace Scott
+} // End of namespace Glk
diff --git a/engines/glk/frotz/windows.h b/engines/glk/frotz/windows.h
new file mode 100644
index 0000000000..566d2fd5c8
--- /dev/null
+++ b/engines/glk/frotz/windows.h
@@ -0,0 +1,97 @@
+/* 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_WINDOWS
+#define GLK_FROTZ_WINDOWS
+
+namespace Glk {
+namespace Frotz {
+
+/**
+ * Represents one of the virtual windows
+ */
+class Window {
+private:
+ winid_t _win;
+public:
+ /**
+ * Constructor
+ */
+ Window() : _win(nullptr) {}
+
+ /**
+ * Assignment operator
+ */
+ Window &operator=(winid_t win) {
+ _win = win;
+ return *this;
+ }
+
+ /**
+ * Cast operator for getting a Glk window
+ */
+ operator winid_t() const { return _win; }
+
+ /**
+ * Cast operator for testing if the window is valid (present)
+ */
+ operator bool() const { return _win != nullptr; }
+
+ /**
+ * Property access. There are the following properties defined by the spec:
+ * 0 y coordinate 6 left margin size 12 font number
+ * 1 x coordinate 7 right margin size 13 font size
+ * 2 y size 8 newline interrupt routine 14 attributes
+ * 3 x size 9 interrupt countdown 15 line count
+ * 4 y cursor 10 text style 16 true foreground colour
+ * 5 x cursor 11 colour data 17 true background colour
+ */
+};
+
+/**
+ * The Z-machine has 8 virtual windows
+ */
+class Windows {
+private:
+ Window _windows[8];
+public:
+ Window &_lower;
+ Window &_upper;
+public:
+ /**
+ * Constructor
+ */
+ Windows() : _lower(_windows[0]), _upper(_windows[1]) {}
+
+ /**
+ * Array access
+ */
+ Window &operator[](uint idx) {
+ assert(idx < 8);
+ return _windows[idx];
+ }
+};
+
+} // End of namespace Frotz
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index da3de68fde..38f19c5a8a 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -53,6 +53,7 @@ MODULE_OBJS := \
frotz/quetzal.o \
frotz/screen.o \
frotz/sound_folder.o \
+ frotz/windows.o \
glulxe/detection.o \
glulxe/glulxe.o \
magnetic/detection.o \