[Scummvm-git-logs] scummvm master -> 5f5ac6b475599da5c11df98852f1dbd1e62db8b5

dreammaster paulfgilbert at gmail.com
Tue May 7 07:27:36 CEST 2019


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

Summary:
724137d696 GLK: MAGNETIC: General initialization
7c536e1026 GLK: MAGNETIC: Graphics initialization
193b7683d8 GLK: MAGNETIC: Sound initialization
1f956a2164 GLK: MAGNETIC: Added graphics & sound methods
5f5ac6b475 GLK: MAGNETIC: Hook up Magnetic sub-engine


Commit: 724137d696f36a0630c4ec0ddeaea6312a041a8b
    https://github.com/scummvm/scummvm/commit/724137d696f36a0630c4ec0ddeaea6312a041a8b
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-05-07T15:02:00+10:00

Commit Message:
GLK: MAGNETIC: General initialization

Changed paths:
  A engines/glk/magnetic/emu.cpp
  A engines/glk/magnetic/magnetic_types.h
    engines/glk/magnetic/magnetic.cpp
    engines/glk/magnetic/magnetic.h
    engines/glk/module.mk


diff --git a/engines/glk/magnetic/emu.cpp b/engines/glk/magnetic/emu.cpp
new file mode 100644
index 0000000..b3d6445
--- /dev/null
+++ b/engines/glk/magnetic/emu.cpp
@@ -0,0 +1,267 @@
+/* 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/magnetic/magnetic.h"
+
+namespace Glk {
+namespace Magnetic {
+
+static const char *no_hints = "[Hints are not available.]\n";
+static const char *not_supported = "[This function is not supported.]\n";
+
+int Magnetic::ms_init(bool restarting) {
+	byte header[42], header2[8];
+	uint32 i, dict_size, string2_size, code_size, dec;
+
+	ms_stop();
+
+	if (restarting) {
+		if (!restart)
+			return 0;
+		else {
+			memcpy(code, restart, undo_size);
+			undo_stat[0] = undo_stat[1] = 0;
+			ms_showpic(0, 0);
+		}
+	} else {
+		undo_stat[0] = undo_stat[1] = 0;
+
+		if (_gameFile.read(header, 42) != 42 || READ_BE_UINT32(header) != MKTAG('M', 'a', 'S', 'c')
+			|| READ_LE_UINT32(header + 8) != 42)
+			return 0;
+
+		ms_freemem();
+		version = header[13];
+		code_size = READ_LE_UINT32(header + 14);
+		string_size = READ_LE_UINT32(header + 18);
+		string2_size = READ_LE_UINT32(header + 22);
+		dict_size = READ_LE_UINT32(header + 26);
+		undo_size = READ_LE_UINT32(header + 34);
+		undo_pc = READ_LE_UINT32(header + 38);
+
+		if ((version < 4) && (code_size < 65536))
+			mem_size = 65536;
+		else
+			mem_size = code_size;
+
+		sd = (byte)((dict_size != 0L) ? 1 : 0);			// if (sd) => separate dict
+
+		if (!(code = new byte[mem_size]) || !(string2 = new byte[string2_size]) ||
+			!(restart = new byte[undo_size]) || (sd &&
+				!(dict = new byte[dict_size]))) {
+			ms_freemem();
+			return 0;
+		}
+		if (string_size > MAX_STRING_SIZE) {
+			if (!(string = new byte[MAX_STRING_SIZE]) ||
+				!(string3 = new byte[string_size - MAX_STRING_SIZE])) {
+				ms_freemem();
+				return 0;
+			}
+		} else {
+			if (!(string = new byte[string_size])) {
+				ms_freemem();
+				return 0;
+			}
+		}
+		if (!(undo[0] = new byte[undo_size]) || !(undo[1] = new byte[undo_size])) {
+			ms_freemem();
+			return 0;
+		}
+		if (_gameFile.read(code, code_size) != code_size) {
+			ms_freemem();
+			return 0;
+		}
+
+		memcpy(restart, code, undo_size);	// fast restarts
+		if (string_size > MAX_STRING_SIZE) {
+			if (_gameFile.read(string, MAX_STRING_SIZE) != MAX_STRING_SIZE) {
+				ms_freemem();
+				return 0;
+			}
+			if (_gameFile.read(string3, string_size - MAX_STRING_SIZE) != (string_size - MAX_STRING_SIZE)) {
+				ms_freemem();
+				return 0;
+			}
+		} else {
+			if (_gameFile.read(string, string_size) != string_size) {
+				ms_freemem();
+				return 0;
+			}
+		}
+		if (_gameFile.read(string2, string2_size) != string2_size) {
+			ms_freemem();
+			return 0;
+		}
+		if (sd && _gameFile.read(dict, dict_size) != dict_size) {
+			ms_freemem();
+			return 0;
+		}
+
+		dec = READ_LE_UINT32(header + 30);
+		if (dec >= string_size) {
+			decode_table = string2 + dec - string_size;
+		} else {
+			if (dec >= MAX_STRING_SIZE)
+				decode_table = string3 + dec - MAX_STRING_SIZE;
+			else
+				decode_table = string + dec;
+		}
+	}
+
+	for (i = 0; i < 8; i++)
+		dreg[i] = areg[i] = 0;
+	write_reg(8 + 7, 2, 0xfffe);	// Stack-pointer, -2 due to MS-DOS segments
+	pc = 0;
+	zflag = nflag = cflag = vflag = 0;
+	i_count = 0;
+	running = 1;
+
+	if (restarting)
+		return (byte)(gfx_buf ? 2 : 1);		// Restarted
+
+	if (version == 4) {
+		// Try loading a hint file
+		if (_hintFile.isOpen()) {
+			_hintFile.seek(0);
+
+			if (_hintFile.readUint32BE() == MKTAG('M', 'a', 'H', 't')) {
+				byte buf[8];
+				uint16 i, j, blkcnt, elcnt, ntype, elsize, conidx;
+
+				// Allocate memory for hints
+				hints = new ms_hint[MAX_HINTS];
+				hint_contents = new byte[MAX_HCONTENTS];
+
+				if ((hints != 0) && (hint_contents != 0)) {
+					// Read number of blocks
+					blkcnt = _hintFile.readUint16LE();
+
+					conidx = 0;
+					for (i = 0; i < blkcnt; i++) {
+						// Read number of elements
+						elcnt = _hintFile.readUint16LE();
+						hints[i].elcount = elcnt;
+
+						// Read node type
+						ntype = _hintFile.readUint16LE();
+						hints[i].nodetype = ntype;
+						hints[i].content = hint_contents + conidx;
+
+						for (j = 0; j < elcnt; j++) {
+							elsize = _hintFile.readUint16LE();
+							if (_hintFile.read(hint_contents + conidx, elsize) != elsize || _hintFile.eos())
+								return 0;
+							hint_contents[conidx + elsize - 1] = '\0';
+
+							conidx += elsize;
+						}
+
+						// Do we need a jump table?
+						if (ntype == 1) {
+							for (j = 0; j < elcnt; j++) {
+								hints[i].links[j] = _hintFile.readUint16LE();
+							}
+						}
+
+						// Read the parent block
+						hints[i].parent = _hintFile.readUint16LE();
+
+					}
+				} else {
+					delete[] hints;
+					delete[] hint_contents;
+					hints = nullptr;
+					hint_contents = nullptr;
+				}
+			}
+		}
+
+		// Try loading a music file
+		if (_sndFile.isOpen() && _sndFile.size() >= 8) {
+			_sndFile.seek(0);
+
+			if (_sndFile.readUint32BE() != MKTAG('M', 'a', 'S', 'd'))
+				return 0;
+
+			init_snd(_sndFile.readUint32LE());
+		}
+	}
+
+	if (!_gfxFile.isOpen() || _gfxFile.size() < 8)
+		return 1;
+	_gfxFile.seek(0);
+	_gfxFile.read(header2, 8);
+
+	if (version < 4 && READ_BE_UINT32(header2) == MKTAG('M', 'a', 'P', 'i'))
+		return init_gfx1(header2);
+	else if (version == 4 && READ_BE_UINT32(header2) == MKTAG('M', 'a', 'P', '2'))
+		return init_gfx2(header2);
+
+	return 1;
+}
+
+void Magnetic::ms_freemem() {
+	delete[] code;
+	delete[] string;
+	delete[] string2;
+	delete[] string3;
+	delete[] dict;
+	delete[] undo[0];
+	delete[] undo[1];
+	delete[] restart;
+	code = string = string2 = string3 = dict = nullptr;
+	undo[0] = undo[1] = restart = nullptr;
+
+	delete[] gfx_data;
+	delete[] gfx_buf;
+	delete[] gfx2_hdr;
+	delete[] gfx2_buf;
+	gfx_data = gfx_buf = gfx2_hdr = gfx2_buf = 0;
+
+	gfx_fp.close();
+
+	gfx2_name.clear();
+	gfx_ver = 0;
+	gfxtable = table_dist = 0;
+
+	pos_table_size = 0;
+	command_index = 0;
+	anim_repeat = 0;
+	pos_table_index = -1;
+	pos_table_max = -1;
+
+	lastchar = 0;
+	delete[] hints;
+	delete[] hint_contents;
+	hints = nullptr;
+	hint_contents = nullptr;
+
+	delete[] snd_hdr;
+	delete[] snd_buf;
+	snd_hdr = nullptr;
+	snd_hsize = 0;
+	snd_buf = nullptr;
+}
+
+} // End of namespace Magnetic
+} // End of namespace Glk
diff --git a/engines/glk/magnetic/magnetic.cpp b/engines/glk/magnetic/magnetic.cpp
index 9bfdc48..c658b8c 100644
--- a/engines/glk/magnetic/magnetic.cpp
+++ b/engines/glk/magnetic/magnetic.cpp
@@ -28,7 +28,27 @@ namespace Glk {
 namespace Magnetic {
 
 Magnetic::Magnetic(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc),
-		vm_exited_cleanly(false) {
+	
+		vm_exited_cleanly(false), dlimit(0xffffffff), slimit(0xffffffff), log_on(0),
+		i_count(0), string_size(0), rseed(0), pc(0), arg1i(0), mem_size(0), properties(0), fl_sub(0),
+		fl_tab(0), fl_size(0), fp_tab(0), fp_size(0), zflag(0), nflag(0), cflag(0), vflag(0), byte1(0),
+		byte2(0), regnr(0), admode(0), opsize(0), arg1(nullptr), arg2(nullptr), is_reversible(0),
+		lastchar(0), version(0), sd(0), decode_table(nullptr), restart(nullptr), code(nullptr),
+		string(nullptr), string2(nullptr), string3(nullptr), dict(nullptr), quick_flag(0), gfx_ver(0),
+		gfx_buf(nullptr), gfx_data(nullptr), gfx2_hdr(0), gfx2_buf(nullptr), gfx2_hsize(0),
+		snd_buf(nullptr), snd_hdr(nullptr), snd_hsize(0), undo_pc(0), undo_size(0),
+		gfxtable(0), table_dist(0), v4_id(0), next_table(1), pos_table_size(0),
+		command_table(nullptr), command_index(-1), pos_table_index(-1), pos_table_max(-1),
+		anim_repeat(0) {
+
+	// Emu fields
+	undo[0] = undo[1] = nullptr;
+	undo_stat[0] = undo_stat[1] = 0;
+	Common::fill(&dreg[0], &dreg[8], 0);
+	Common::fill(&areg[0], &areg[8], 0);
+	Common::fill(&tmparg[0], &tmparg[4], 0);
+	Common::fill(&undo_regs[0][0], &undo_regs[2][18], 0), 
+	Common::fill(&pos_table_count[0], &pos_table_count[MAX_POSITIONS], 0);
 }
 
 void Magnetic::runGame() {
@@ -60,7 +80,7 @@ bool Magnetic::is_gamefile_valid() {
 	}
 
 	// We support version 2.0 through 3.1.*
-	uint version = _gameFile.readUint32BE();
+	version = _gameFile.readUint32BE();
 	if (version < 0x20000) {
 		GUIErrorMessage(_("This Glulx file is too old a version to execute."));
 		return false;
diff --git a/engines/glk/magnetic/magnetic.h b/engines/glk/magnetic/magnetic.h
index 024ef51..a791ca8 100644
--- a/engines/glk/magnetic/magnetic.h
+++ b/engines/glk/magnetic/magnetic.h
@@ -20,11 +20,12 @@
  *
  */
 
-#ifndef GLK_GLULXE
-#define GLK_GLULXE
+#ifndef GLK_MAGNETIC_MAGNETIC
+#define GLK_MAGNETIC_MAGNETIC
 
 #include "common/scummsys.h"
 #include "glk/glk_api.h"
+#include "glk/magnetic/magnetic_types.h"
 
 namespace Glk {
 namespace Magnetic {
@@ -34,12 +35,107 @@ namespace Magnetic {
  */
 class Magnetic : public GlkAPI {
 public:
+	Common::File _hintFile;
+	Common::File _gfxFile;
+	Common::File _sndFile;
 	bool vm_exited_cleanly;
+	uint dlimit, slimit;
+	int log_on;
+
+	// Emu fields
+	uint32 dreg[8], areg[8], i_count, string_size, rseed, pc, arg1i, mem_size;
+	uint16 properties, fl_sub, fl_tab, fl_size, fp_tab, fp_size;
+	byte zflag, nflag, cflag, vflag, byte1, byte2, regnr, admode, opsize;
+	byte *arg1, *arg2, is_reversible, running, tmparg[4];
+	byte lastchar, version, sd;
+	byte *decode_table, *restart, *code, *string, *string2;
+	byte *string3, *dict;
+	byte quick_flag, gfx_ver, *gfx_buf, *gfx_data;
+	byte *gfx2_hdr, *gfx2_buf;
+	Common::String gfx2_name;
+	uint16 gfx2_hsize;
+	byte *snd_buf, *snd_hdr;
+	uint16 snd_hsize;
+	Common::File gfx_fp;
+	uint32 undo_regs[2][18], undo_pc, undo_size;
+	byte *undo[2], undo_stat[2];
+	uint16 gfxtable, table_dist;
+	uint16 v4_id, next_table;
+
+	ms_hint *hints;
+	byte *hint_contents;
+	picture anim_frame_table[MAX_ANIMS];
+	uint16 pos_table_size;
+	uint16 pos_table_count[MAX_POSITIONS];
+	ms_position pos_table[MAX_POSITIONS][MAX_ANIMS];
+	byte *command_table;
+	int command_index;
+	lookup anim_table[MAX_POSITIONS];
+	int pos_table_index;
+	int pos_table_max;
+	ms_position pos_array[MAX_FRAMES];
+	byte anim_repeat;
+
+
 private:
 	/**
 	 * Validates the game file, and if it's invalid, displays an error dialog
 	 */
 	bool is_gamefile_valid();
+
+	/**
+	 * Loads the interpreter with a game
+	 * @return	0 = failure, 1 = success(without graphics or graphics failed),
+	 *		2 = success(with graphics)
+	 */
+	int ms_init(bool restarting = false);
+
+	/**
+	 * Stops further processing of opcodes
+	 */
+	void ms_stop() { running = false; }
+
+	/**
+	 * Detects if game is running
+	 */
+	bool ms_is_running() const { return running; }
+
+	/**
+	 * Frees all allocated ressources
+	 */
+	void ms_freemem();
+
+	// Graphics
+
+	/**
+	 * Displays or hides a picture
+	 * @param c			number of image to be displayed
+	 * @param mode		0 = means gfx off, 1 gfx on thumbnails, 2 gfx on normal
+	 *
+	 * @remarks		For retrieving the raw data of a picture call ms_extract
+	 */
+	void ms_showpic(int c, byte mode) {
+		// TODO
+	}
+
+	void write_reg(int i, int s, uint32 val) {
+		// TODO
+	}
+
+	// Sound
+
+	void init_snd(uint param) {
+		// TODO
+	}
+
+	byte init_gfx1(byte *header) {
+		// TODO
+		return 0;
+	}
+	byte init_gfx2(byte *header) {
+		// TODO
+		return 0;
+	}
 public:
 	/**
 	 * Constructor
diff --git a/engines/glk/magnetic/magnetic_types.h b/engines/glk/magnetic/magnetic_types.h
new file mode 100644
index 0000000..b9933a3
--- /dev/null
+++ b/engines/glk/magnetic/magnetic_types.h
@@ -0,0 +1,136 @@
+/* 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_MAGNETIC_TYPES
+#define GLK_MAGNETIC_TYPES
+
+#include "common/scummsys.h"
+
+namespace Glk {
+namespace Magnetic {
+
+#define MAX_HINTS 260
+#define MAX_HCONTENTS 30000
+
+#define MAX_POSITIONS 20
+#define MAX_ANIMS 200
+#define MAX_FRAMES 20
+#define MAX_STRING_SIZE  0xFF00
+#define MAX_PICTURE_SIZE 0xC800
+#define MAX_MUSIC_SIZE   0x4E20
+#define MAX_HITEMS 25
+
+struct lookup {
+	uint16 flag;
+	uint16 count;
+
+	lookup() : flag(0), count(0) {}
+};
+
+struct picture {
+	byte * data;
+	uint32 data_size;
+	uint16 width;
+	uint16 height;
+	uint16 wbytes;
+	uint16 plane_step;
+	byte *mask;
+
+	picture() : data(nullptr), data_size(0), width(0), height(0), wbytes(0), plane_step(0),
+		mask(nullptr) {}
+};
+
+/**
+ * Magnetic animated pictures support
+ *
+ * Note: Some of the pictures for Wonderland and the Collection Volume 1 games
+ * are animations. To detect these, pass a pointer to a type8 as the is_anim
+ * argument to ms_extract().
+ *
+ * There are two types of animated images, however almost all images are type1.
+ * A type1 image consists of four main elements:
+ * 1) A static picture which is loaded straight at the beginning
+ * 2) A set of frames with a mask. These frames are just "small pictures", which
+ *    are coded like the normal static pictures. The image mask determines
+ *    how the frame is removed after it has been displayed. A mask is exactly
+ *    1/8 the size of the image and holds 1 bit per pixel, saying "remove pixel"
+ *    or leave pixel set when frame gets removed. It might be a good idea to check
+ *    your system documentation for masking operations as your system might be
+ *    able to use this mask data directly.
+ * 3) Positioning tables. These hold animation sequences consisting of commands
+ *    like "Draw frame 12 at (123,456)"
+ * 4) A playback script, which determines how to use the positioning tables.
+ *    These scripts are handled inside Magnetic, so no need to worry about.
+ *    However, details can be found in the ms_animate() function.
+ *
+ * A type2 image is like a type1 image, but it does not have a static
+ * picture, nor does it have frame masking. It just consists of frames.
+ *
+ * How to support animations?
+ * After getting is_anim == 1 you should call ms_animate() immediately, and at
+ * regular intervals until ms_animate() returns 0. An appropriate interval
+ * between calls is about 100 milliseconds.
+ * Each call to ms_animate() will fill in the arguments with the address
+ * and size of an array of ms_position structures (see below), each of
+ * which holds an an animation frame number and x and y co-ordinates. To
+ * display the animation, decode all the animation frames (discussed below)
+ * from a single call to ms_animate() and display each one over the main picture.
+ * If your port does not support animations, define NO_ANIMATION.
+ */
+struct ms_position {
+	int16 x, y;
+	int16 number;
+
+	ms_position() : x(0), y(0), number(0) {}
+};
+
+/**
+ * Magnetic Windows hint support
+ *
+ * The windowed Magnetic Scolls games included online hints. To add support
+ * for the hints to your magnetic port, you should implement the ms_showhints
+ * function. It retrieves a pointer to an array of ms_hint structs
+ * The root element is always hints[0]. The elcount determines the number
+ * of items in this topic. You probably want to display those in some kind
+ * of list interface. The content pointer points to the actual description of
+ * the items, separated by '\0' terminators. The nodetype is 1 if the items are
+ * "folders" and 2 if the items are hints. Hints should be displayed one after
+ * another. For "folder" items, the links array holds the index of the hint in
+ * the array which is to be displayed on selection. One hint block has exactly
+ * one type. The parent element determines the "back" target.
+ */
+struct ms_hint {
+	uint16 elcount;
+	uint16 nodetype;
+	byte *content;
+	uint16 links[MAX_HITEMS];
+	uint16 parent;
+
+	ms_hint() : elcount(0), nodetype(0), content(nullptr), parent(0) {
+		Common::fill(&links[0], &links[MAX_HITEMS], 0);
+	}
+};
+
+} // End of namespace Magnetic
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index be66caf..4c546ff 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -72,6 +72,7 @@ MODULE_OBJS := \
 	glulxe/string.o \
 	glulxe/vm.o \
 	magnetic/detection.o \
+	magnetic/emu.o \
 	magnetic/magnetic.o \
 	scott/detection.o \
 	scott/scott.o \


Commit: 7c536e1026971bc83048582ea137f290e5328747
    https://github.com/scummvm/scummvm/commit/7c536e1026971bc83048582ea137f290e5328747
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-05-07T15:02:00+10:00

Commit Message:
GLK: MAGNETIC: Graphics initialization

Changed paths:
  A engines/glk/magnetic/graphics.cpp
    engines/glk/magnetic/emu.cpp
    engines/glk/magnetic/magnetic.h
    engines/glk/module.mk


diff --git a/engines/glk/magnetic/emu.cpp b/engines/glk/magnetic/emu.cpp
index b3d6445..76d0fa7 100644
--- a/engines/glk/magnetic/emu.cpp
+++ b/engines/glk/magnetic/emu.cpp
@@ -29,8 +29,8 @@ static const char *no_hints = "[Hints are not available.]\n";
 static const char *not_supported = "[This function is not supported.]\n";
 
 int Magnetic::ms_init(bool restarting) {
-	byte header[42], header2[8];
-	uint32 i, dict_size, string2_size, code_size, dec;
+	byte header[42];
+	uint32 i, j, dict_size, string2_size, code_size, dec;
 
 	ms_stop();
 
@@ -145,8 +145,7 @@ int Magnetic::ms_init(bool restarting) {
 			_hintFile.seek(0);
 
 			if (_hintFile.readUint32BE() == MKTAG('M', 'a', 'H', 't')) {
-				byte buf[8];
-				uint16 i, j, blkcnt, elcnt, ntype, elsize, conidx;
+				uint16 blkcnt, elcnt, ntype, elsize, conidx;
 
 				// Allocate memory for hints
 				hints = new ms_hint[MAX_HINTS];
@@ -210,12 +209,12 @@ int Magnetic::ms_init(bool restarting) {
 	if (!_gfxFile.isOpen() || _gfxFile.size() < 8)
 		return 1;
 	_gfxFile.seek(0);
-	_gfxFile.read(header2, 8);
+	uint tag = _gfxFile.readUint32BE();
 
-	if (version < 4 && READ_BE_UINT32(header2) == MKTAG('M', 'a', 'P', 'i'))
-		return init_gfx1(header2);
-	else if (version == 4 && READ_BE_UINT32(header2) == MKTAG('M', 'a', 'P', '2'))
-		return init_gfx2(header2);
+	if (version < 4 && tag == MKTAG('M', 'a', 'P', 'i'))
+		return init_gfx1(_gfxFile.readUint32LE() - 8);
+	else if (version == 4 && tag == MKTAG('M', 'a', 'P', '2'))
+		return init_gfx2(_gfxFile.readUint16LE());
 
 	return 1;
 }
diff --git a/engines/glk/magnetic/graphics.cpp b/engines/glk/magnetic/graphics.cpp
new file mode 100644
index 0000000..d10dc3d
--- /dev/null
+++ b/engines/glk/magnetic/graphics.cpp
@@ -0,0 +1,79 @@
+/* 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/magnetic/magnetic.h"
+
+namespace Glk {
+namespace Magnetic {
+
+
+byte Magnetic::init_gfx1(size_t size) {
+	if (!(gfx_buf = new byte[MAX_PICTURE_SIZE]))
+		return 1;
+
+	if (!(gfx_data = new byte[size])) {
+		delete[] gfx_buf;
+		gfx_buf = nullptr;
+		return 1;
+	}
+
+	if (_gfxFile.read(gfx_data, size) != size) {
+		delete[] gfx_data;
+		delete[] gfx_buf;
+		gfx_data = gfx_buf = nullptr;
+		return 1;
+	}
+
+	gfx_ver = 1;
+	return 2;
+}
+
+byte Magnetic::init_gfx2(size_t size) {
+	if (!(gfx_buf = new byte[MAX_PICTURE_SIZE])) {
+		return 1;
+	}
+
+	gfx2_hsize = size;
+	if (!(gfx2_hdr = new byte[gfx2_hsize])) {
+		delete[] gfx_buf;
+		gfx_buf = nullptr;
+		return 1;
+	}
+
+	if (_gfxFile.read(gfx2_hdr, gfx2_hsize) != gfx2_hsize) {
+		delete[] gfx_buf;
+		delete[] gfx2_hdr;
+		gfx_buf = nullptr;
+		gfx2_hdr = nullptr;
+		return 1;
+	}
+
+	gfx_ver = 2;
+	return 2;
+}
+
+void Magnetic::ms_showpic(int c, byte mode) {
+	// TODO
+}
+
+} // End of namespace Magnetic
+} // End of namespace Glk
diff --git a/engines/glk/magnetic/magnetic.h b/engines/glk/magnetic/magnetic.h
index a791ca8..ebebbc1 100644
--- a/engines/glk/magnetic/magnetic.h
+++ b/engines/glk/magnetic/magnetic.h
@@ -84,6 +84,11 @@ private:
 	bool is_gamefile_valid();
 
 	/**
+	 * \defgroup Emu
+	 * @{
+	 */
+
+	/**
 	 * Loads the interpreter with a game
 	 * @return	0 = failure, 1 = success(without graphics or graphics failed),
 	 *		2 = success(with graphics)
@@ -105,7 +110,16 @@ private:
 	 */
 	void ms_freemem();
 
-	// Graphics
+	/**@}*/
+
+	/**
+	 * \defgroup Graphics support methods
+	 * @{
+	 */
+
+	byte init_gfx1(size_t size);
+
+	byte init_gfx2(size_t size);
 
 	/**
 	 * Displays or hides a picture
@@ -114,28 +128,25 @@ private:
 	 *
 	 * @remarks		For retrieving the raw data of a picture call ms_extract
 	 */
-	void ms_showpic(int c, byte mode) {
-		// TODO
-	}
+	void ms_showpic(int c, byte mode);
 
 	void write_reg(int i, int s, uint32 val) {
 		// TODO
 	}
 
-	// Sound
+	/**@}*/
+
+	/**
+	 * \defgroup Sound support methods
+	 * @{
+	 */
+
 
 	void init_snd(uint param) {
 		// TODO
 	}
 
-	byte init_gfx1(byte *header) {
-		// TODO
-		return 0;
-	}
-	byte init_gfx2(byte *header) {
-		// TODO
-		return 0;
-	}
+	/**@}*/
 public:
 	/**
 	 * Constructor
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index 4c546ff..ac4f6f2 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -73,6 +73,7 @@ MODULE_OBJS := \
 	glulxe/vm.o \
 	magnetic/detection.o \
 	magnetic/emu.o \
+	magnetic/graphics.o \
 	magnetic/magnetic.o \
 	scott/detection.o \
 	scott/scott.o \


Commit: 193b7683d835fba7806119095fc9245cb0e365c4
    https://github.com/scummvm/scummvm/commit/193b7683d835fba7806119095fc9245cb0e365c4
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-05-07T15:02:00+10:00

Commit Message:
GLK: MAGNETIC: Sound initialization

Changed paths:
  A engines/glk/magnetic/sound.cpp
    engines/glk/magnetic/magnetic.h
    engines/glk/module.mk


diff --git a/engines/glk/magnetic/magnetic.h b/engines/glk/magnetic/magnetic.h
index ebebbc1..27bdda0 100644
--- a/engines/glk/magnetic/magnetic.h
+++ b/engines/glk/magnetic/magnetic.h
@@ -106,6 +106,11 @@ private:
 	bool ms_is_running() const { return running; }
 
 	/**
+	 * Returns true if running a Magnetic Windows game
+	 */
+	bool ms_is_magwin() const { return version == 4; }
+
+	/**
 	 * Frees all allocated ressources
 	 */
 	void ms_freemem();
@@ -141,10 +146,7 @@ private:
 	 * @{
 	 */
 
-
-	void init_snd(uint param) {
-		// TODO
-	}
+	byte init_snd(size_t size);
 
 	/**@}*/
 public:
diff --git a/engines/glk/magnetic/sound.cpp b/engines/glk/magnetic/sound.cpp
new file mode 100644
index 0000000..7977920
--- /dev/null
+++ b/engines/glk/magnetic/sound.cpp
@@ -0,0 +1,52 @@
+/* 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/magnetic/magnetic.h"
+
+namespace Glk {
+namespace Magnetic {
+
+byte Magnetic::init_snd(size_t size) {
+	if (!(snd_buf = new byte[MAX_MUSIC_SIZE])) {
+		return 1;
+	}
+
+	snd_hsize = _sndFile.readUint16LE();
+	if (!(snd_hdr = new byte[snd_hsize])) {
+		delete[] snd_buf;
+		snd_buf = nullptr;
+		return 1;
+	}
+
+	if (_sndFile.read(snd_hdr, snd_hsize) != snd_hsize) {
+		delete[] snd_buf;
+		delete[] snd_hdr;
+		snd_buf = nullptr;
+		snd_hdr = nullptr;
+		return 1;
+	}
+
+	return 2;
+}
+
+} // End of namespace Magnetic
+} // End of namespace Glk
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index ac4f6f2..f8367c7 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -75,6 +75,7 @@ MODULE_OBJS := \
 	magnetic/emu.o \
 	magnetic/graphics.o \
 	magnetic/magnetic.o \
+	magnetic/sound.o \
 	scott/detection.o \
 	scott/scott.o \
 	tads/detection.o \


Commit: 1f956a216475947335d2967f9a2f795976abf050
    https://github.com/scummvm/scummvm/commit/1f956a216475947335d2967f9a2f795976abf050
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-05-07T15:02:01+10:00

Commit Message:
GLK: MAGNETIC: Added graphics & sound methods

Changed paths:
    engines/glk/magnetic/graphics.cpp
    engines/glk/magnetic/magnetic.h
    engines/glk/magnetic/magnetic_types.h
    engines/glk/magnetic/sound.cpp


diff --git a/engines/glk/magnetic/graphics.cpp b/engines/glk/magnetic/graphics.cpp
index d10dc3d..1c63578 100644
--- a/engines/glk/magnetic/graphics.cpp
+++ b/engines/glk/magnetic/graphics.cpp
@@ -25,7 +25,6 @@
 namespace Glk {
 namespace Magnetic {
 
-
 byte Magnetic::init_gfx1(size_t size) {
 	if (!(gfx_buf = new byte[MAX_PICTURE_SIZE]))
 		return 1;
@@ -75,5 +74,431 @@ void Magnetic::ms_showpic(int c, byte mode) {
 	// TODO
 }
 
+bool Magnetic::is_blank(uint16 line, uint16 width) const {
+	int i;
+
+	for (i = line * width; i < (line + 1) * width; i++)
+		if (gfx_buf[i])
+			return false;
+	return true;
+}
+
+byte *Magnetic::ms_extract1(byte pic, uint16 * w, uint16 * h, uint16 * pal) {
+	byte *table, *data, bit, val, *buffer;
+	uint16 tablesize, count;
+	uint32 i, j, datasize, upsize, offset;
+
+	offset = READ_LE_UINT32(gfx_data + 4 * pic);
+	buffer = gfx_data + offset - 8;
+
+	for (i = 0; i < 16; i++)
+		pal[i] = READ_LE_UINT16(buffer + 0x1c + 2 * i);
+	w[0] = (uint16)(READ_LE_UINT16(buffer + 4) - READ_LE_UINT16(buffer + 2));
+	h[0] = READ_LE_UINT16(buffer + 6);
+
+	tablesize = READ_LE_UINT16(buffer + 0x3c);
+	datasize = READ_LE_UINT32(buffer + 0x3e);
+	table = buffer + 0x42;
+	data = table + tablesize * 2 + 2;
+	upsize = h[0] * w[0];
+
+	for (i = 0, j = 0, count = 0, val = 0, bit = 7; i < upsize; i++, count--) {
+		if (!count) {
+			count = tablesize;
+			while (count < 0x80) {
+				if (data[j] & (1 << bit))
+					count = table[2 * count];
+				else
+					count = table[2 * count + 1];
+				if (!bit)
+					j++;
+				bit = (byte)(bit ? bit - 1 : 7);
+			}
+			count &= 0x7f;
+			if (count >= 0x10)
+				count -= 0x10;
+			else
+			{
+				val = (byte)count;
+				count = 1;
+			}
+		}
+		gfx_buf[i] = val;
+	}
+	for (j = w[0]; j < upsize; j++)
+		gfx_buf[j] ^= gfx_buf[j - w[0]];
+
+	for (; h[0] > 0 && is_blank((uint16)(h[0] - 1), w[0]); h[0]--);
+	for (i = 0; h[0] > 0 && is_blank((uint16)i, w[0]); h[0]--, i++);
+	return gfx_buf + i * w[0];
+}
+
+
+byte *Magnetic::ms_extract2(const char *name, uint16 *w, uint16 *h, uint16 *pal, byte *is_anim) {
+	struct picture main_pic;
+	uint32 offset = 0, length = 0, i;
+	int16 header_pos = -1;
+	byte* anim_data;
+	uint32 j;
+
+	if (is_anim != 0)
+		*is_anim = 0;
+	gfx2_name = name;
+
+	pos_table_size = 0;
+
+	// Find the uppercase (no animation) version of the picture first
+	header_pos = find_name_in_header(name, 1);
+
+	if (header_pos < 0)
+		header_pos = find_name_in_header(name, 0);
+	if (header_pos < 0)
+		return 0;
+
+	offset = READ_LE_UINT32(gfx2_hdr + header_pos + 8);
+	length = READ_LE_UINT32(gfx2_hdr + header_pos + 12);
+
+	if (offset != 0) {
+		if (gfx2_buf) {
+			delete[] gfx2_buf;
+			gfx2_buf = nullptr;
+		}
+
+		gfx2_buf = new byte[length];
+		if (!gfx2_buf)
+			return 0;
+
+		if (!_gfxFile.seek(offset) || _gfxFile.read(gfx2_buf, length) != length) {
+			delete[] gfx2_buf;
+			gfx2_buf = nullptr;
+			return 0;
+		}
+
+		for (i = 0; i < 16; i++)
+			pal[i] = READ_LE_UINT16(gfx2_buf + 4 + (2 * i));
+
+		main_pic.data = gfx2_buf + 48;
+		main_pic.data_size = READ_LE_UINT32(gfx2_buf + 38);
+		main_pic.width = READ_LE_UINT16(gfx2_buf + 42);
+		main_pic.height = READ_LE_UINT16(gfx2_buf + 44);
+		main_pic.wbytes = (uint16)(main_pic.data_size / main_pic.height);
+		main_pic.plane_step = (uint16)(main_pic.wbytes / 4);
+		main_pic.mask = (byte*)0;
+		extract_frame(&main_pic);
+
+		*w = main_pic.width;
+		*h = main_pic.height;
+
+		// Check for an animation
+		anim_data = gfx2_buf + 48 + main_pic.data_size;
+		if ((anim_data[0] != 0xD0) || (anim_data[1] != 0x5E)) {
+			byte *current;
+			uint16 frame_count, command_count;
+			uint16 value1, value2;
+
+			if (is_anim != 0)
+				*is_anim = 1;
+
+			current = anim_data + 6;
+			frame_count = READ_LE_UINT16(anim_data + 2);
+			if (frame_count > MAX_ANIMS)
+			{
+				error("animation frame array too short");
+				return 0;
+			}
+
+			/* Loop through each animation frame */
+			for (i = 0; i < frame_count; i++)
+			{
+				anim_frame_table[i].data = current + 10;
+				anim_frame_table[i].data_size = READ_LE_UINT32(current);
+				anim_frame_table[i].width = READ_LE_UINT16(current + 4);
+				anim_frame_table[i].height = READ_LE_UINT16(current + 6);
+				anim_frame_table[i].wbytes = (uint16)(anim_frame_table[i].data_size / anim_frame_table[i].height);
+				anim_frame_table[i].plane_step = (uint16)(anim_frame_table[i].wbytes / 4);
+				anim_frame_table[i].mask = (byte*)0;
+
+				current += anim_frame_table[i].data_size + 12;
+				value1 = READ_LE_UINT16(current - 2);
+				value2 = READ_LE_UINT16(current);
+
+				/* Get the mask */
+				if ((value1 == anim_frame_table[i].width) && (value2 == anim_frame_table[i].height))
+				{
+					uint16 skip;
+
+					anim_frame_table[i].mask = (byte*)(current + 4);
+					skip = READ_LE_UINT16(current + 2);
+					current += skip + 6;
+				}
+			}
+
+			/* Get the positioning tables */
+			pos_table_size = READ_LE_UINT16(current - 2);
+			if (pos_table_size > MAX_POSITIONS)
+			{
+				error("animation position array too short");
+				return 0;
+			}
+
+			for (i = 0; i < pos_table_size; i++) {
+				pos_table_count[i] = READ_LE_UINT16(current + 2);
+				current += 4;
+
+				if (pos_table_count[i] > MAX_ANIMS)
+				{
+					error("animation position array too short");
+					return 0;
+				}
+
+				for (j = 0; j < pos_table_count[i]; j++)
+				{
+					pos_table[i][j].x = READ_LE_UINT16(current);
+					pos_table[i][j].y = READ_LE_UINT16(current + 2);
+					pos_table[i][j].number = READ_LE_UINT16(current + 4) - 1;
+					current += 8;
+				}
+			}
+
+			// Get the command sequence table
+			command_count = READ_LE_UINT16(current);
+			command_table = current + 2;
+
+			for (i = 0; i < MAX_POSITIONS; i++)
+			{
+				anim_table[i].flag = -1;
+				anim_table[i].count = -1;
+			}
+			command_index = 0;
+			anim_repeat = 0;
+			pos_table_index = -1;
+			pos_table_max = -1;
+		}
+
+		return gfx_buf;
+	}
+
+	return nullptr;
+}
+
+int16 Magnetic::find_name_in_header(const Common::String &name, bool upper) {
+	int16 header_pos = 0;
+	Common::String pic_name(name.c_str(), name.c_str() + 6);
+
+	if (upper)
+		pic_name.toUppercase();
+
+	while (header_pos < gfx2_hsize) {
+		const char *hname = (const char *)(gfx2_hdr + header_pos);
+		if (strncmp(hname, pic_name.c_str(), 6) == 0)
+			return header_pos;
+		header_pos += 16;
+	}
+
+	return -1;
+}
+
+void Magnetic::extract_frame(const picture *pic) {
+	uint32 i, x, y, bit_x, mask, ywb, yw, value, values[4];
+
+	if (pic->width * pic->height > MAX_PICTURE_SIZE) {
+		error("picture too large");
+		return;
+	}
+
+	for (y = 0; y < pic->height; y++) {
+		ywb = y * pic->wbytes;
+		yw = y * pic->width;
+
+		for (x = 0; x < pic->width; x++) {
+			if ((x % 8) == 0) {
+				for (i = 0; i < 4; i++)
+					values[i] = pic->data[ywb + (x / 8) + (pic->plane_step * i)];
+			}
+
+			bit_x = 7 - (x & 7);
+			mask = 1 << bit_x;
+			value = ((values[0] & mask) >> bit_x) << 0 |
+				((values[1] & mask) >> bit_x) << 1 |
+				((values[2] & mask) >> bit_x) << 2 |
+				((values[3] & mask) >> bit_x) << 3;
+			value &= 15;
+
+			gfx_buf[yw + x] = (byte)value;
+		}
+	}
+}
+
+byte *Magnetic::ms_extract(uint32 pic, uint16 *w, uint16 *h, uint16 *pal, byte *is_anim) {
+	if (is_anim)
+		*is_anim = 0;
+
+	if (gfx_buf) {
+		switch (gfx_ver) {
+		case 1:
+			return ms_extract1((byte)pic, w, h, pal);
+		case 2:
+			return ms_extract2((const char *)(code + pic), w, h, pal, is_anim);
+		}
+	}
+
+	return nullptr;
+}
+
+byte Magnetic::ms_animate(ms_position **positions, uint16 *count) {
+	byte got_anim = 0;
+	uint16 i, j, ttable;
+
+	if ((gfx_buf == 0) || (gfx2_buf == 0) || (gfx_ver != 2))
+		return 0;
+	if ((pos_table_size == 0) || (command_index < 0))
+		return 0;
+
+	*count = 0;
+	*positions = (struct ms_position*)0;
+
+	while (got_anim == 0)
+	{
+		if (pos_table_max >= 0)
+		{
+			if (pos_table_index < pos_table_max)
+			{
+				for (i = 0; i < pos_table_size; i++)
+				{
+					if (anim_table[i].flag > -1)
+					{
+						if (*count >= MAX_FRAMES)
+						{
+							error("returned animation array too short");
+							return 0;
+						}
+
+						pos_array[*count] = pos_table[i][anim_table[i].flag];
+
+						(*count)++;
+
+						if (anim_table[i].flag < (pos_table_count[i] - 1))
+							anim_table[i].flag++;
+						if (anim_table[i].count > 0)
+							anim_table[i].count--;
+						else
+							anim_table[i].flag = -1;
+					}
+				}
+				if (*count > 0)
+				{
+					*positions = pos_array;
+					got_anim = 1;
+				}
+				pos_table_index++;
+			}
+		}
+
+		if (got_anim == 0)
+		{
+			byte command = command_table[command_index];
+			command_index++;
+
+			pos_table_max = -1;
+			pos_table_index = -1;
+
+			switch (command)
+			{
+			case 0x00:
+				command_index = -1;
+				return 0;
+			case 0x01:
+				ttable = command_table[command_index];
+				command_index++;
+
+				if (ttable - 1 >= MAX_POSITIONS)
+				{
+					error("animation table too short");
+					return 0;
+				}
+
+				anim_table[ttable - 1].flag = (int16)(command_table[command_index] - 1);
+				command_index++;
+				anim_table[ttable - 1].count = (int16)(command_table[command_index] - 1);
+				command_index++;
+
+				/* Workaround for Wonderland "catter" animation */
+				if (v4_id == 0)
+				{
+					if (gfx2_name == "catter") {
+						if (command_index == 96)
+							anim_table[ttable - 1].count = 9;
+						if (command_index == 108)
+							anim_table[ttable - 1].flag = -1;
+						if (command_index == 156)
+							anim_table[ttable - 1].flag = -1;
+					}
+				}
+				break;
+			case 0x02:
+				pos_table_max = command_table[command_index];
+				pos_table_index = 0;
+				command_index++;
+				break;
+			case 0x03:
+				if (v4_id == 0)
+				{
+					command_index = -1;
+					return 0;
+				}
+				else
+				{
+					command_index = 0;
+					anim_repeat = 1;
+					pos_table_index = -1;
+					pos_table_max = -1;
+					for (j = 0; j < MAX_POSITIONS; j++)
+					{
+						anim_table[j].flag = -1;
+						anim_table[j].count = -1;
+					}
+				}
+				break;
+
+			case 0x04:
+				command_index += 3;
+				return 0;
+			case 0x05:
+				ttable = next_table;
+				command_index++;
+
+				anim_table[ttable - 1].flag = 0;
+				anim_table[ttable - 1].count = command_table[command_index];
+
+				pos_table_max = command_table[command_index];
+				pos_table_index = 0;
+				command_index++;
+				command_index++;
+				next_table++;
+				break;
+			default:
+				error("unknown animation command");
+				command_index = -1;
+				return 0;
+			}
+		}
+	}
+
+	return got_anim;
+}
+
+byte *Magnetic::ms_get_anim_frame(int16 number, uint16 *width, uint16 *height, byte **mask) {
+	if (number >= 0)
+	{
+		extract_frame(anim_frame_table + number);
+		*width = anim_frame_table[number].width;
+		*height = anim_frame_table[number].height;
+		*mask = anim_frame_table[number].mask;
+		return gfx_buf;
+	}
+
+	return nullptr;
+}
+
 } // End of namespace Magnetic
 } // End of namespace Glk
diff --git a/engines/glk/magnetic/magnetic.h b/engines/glk/magnetic/magnetic.h
index 27bdda0..6cf05c9 100644
--- a/engines/glk/magnetic/magnetic.h
+++ b/engines/glk/magnetic/magnetic.h
@@ -135,6 +135,27 @@ private:
 	 */
 	void ms_showpic(int c, byte mode);
 
+	/**
+	 * Returns true if a given line is blank
+	 */
+	bool is_blank(uint16 line, uint16 width) const;
+
+	byte *ms_extract1(byte pic, uint16 *w, uint16 *h, uint16 *pal);
+
+	int16 find_name_in_header(const Common::String &name, bool upper);
+
+	void extract_frame(const picture *pic);
+
+	byte *ms_extract2(const char *name, uint16 *w, uint16 *h, uint16 *pal, byte *is_anim);
+
+	byte *ms_extract(uint32 pic, uint16 *w, uint16 *h, uint16 *pal, byte *is_anim);
+
+	byte ms_animate(ms_position **positions, uint16 *count);
+
+	byte *ms_get_anim_frame(int16 number, uint16 *width, uint16 *height, byte **mask);
+
+	bool ms_anim_is_repeating() const { return anim_repeat;	}
+
 	void write_reg(int i, int s, uint32 val) {
 		// TODO
 	}
@@ -148,6 +169,10 @@ private:
 
 	byte init_snd(size_t size);
 
+	int16 find_name_in_sndheader(const Common::String &name);
+
+	byte *sound_extract(const Common::String &name, uint32 *length, uint16 *tempo);
+
 	/**@}*/
 public:
 	/**
diff --git a/engines/glk/magnetic/magnetic_types.h b/engines/glk/magnetic/magnetic_types.h
index b9933a3..cfef765 100644
--- a/engines/glk/magnetic/magnetic_types.h
+++ b/engines/glk/magnetic/magnetic_types.h
@@ -40,8 +40,8 @@ namespace Magnetic {
 #define MAX_HITEMS 25
 
 struct lookup {
-	uint16 flag;
-	uint16 count;
+	int16 flag;
+	int16 count;
 
 	lookup() : flag(0), count(0) {}
 };
diff --git a/engines/glk/magnetic/sound.cpp b/engines/glk/magnetic/sound.cpp
index 7977920..3ea74fb 100644
--- a/engines/glk/magnetic/sound.cpp
+++ b/engines/glk/magnetic/sound.cpp
@@ -48,5 +48,45 @@ byte Magnetic::init_snd(size_t size) {
 	return 2;
 }
 
+int16 Magnetic::find_name_in_sndheader(const Common::String &name) {
+	int16 header_pos = 0;
+
+	while (header_pos < snd_hsize) {
+		const char *hname = (const char *)(snd_hdr + header_pos);
+		if (name == hname)
+			return header_pos;
+		header_pos += 18;
+	}
+
+	return -1;
+}
+
+byte *Magnetic::sound_extract(const Common::String &name, uint32 *length, uint16 *tempo) {
+	uint32 offset = 0;
+	int16 header_pos = -1;
+
+	if (header_pos < 0)
+		header_pos = find_name_in_sndheader(name);
+	if (header_pos < 0)
+		return 0;
+
+	*tempo = READ_BE_UINT16(snd_hdr + header_pos + 8);
+	offset = READ_BE_UINT32(snd_hdr + header_pos + 10);
+	*length = READ_BE_UINT32(snd_hdr + header_pos + 14);
+
+	if (offset != 0) {
+		if (!snd_buf)
+			return nullptr;
+		if (!_sndFile.seek(offset))
+			return nullptr;
+		if (_sndFile.read(snd_buf, *length) != *length)
+			return nullptr;
+
+		return snd_buf;
+	}
+
+	return nullptr;
+}
+
 } // End of namespace Magnetic
 } // End of namespace Glk


Commit: 5f5ac6b475599da5c11df98852f1dbd1e62db8b5
    https://github.com/scummvm/scummvm/commit/5f5ac6b475599da5c11df98852f1dbd1e62db8b5
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-05-07T15:27:14+10:00

Commit Message:
GLK: MAGNETIC: Hook up Magnetic sub-engine

Changed paths:
    engines/glk/detection.cpp
    engines/glk/magnetic/detection.cpp
    engines/glk/magnetic/detection.h
    engines/glk/magnetic/detection_tables.h


diff --git a/engines/glk/detection.cpp b/engines/glk/detection.cpp
index f9b06a2..193d439 100644
--- a/engines/glk/detection.cpp
+++ b/engines/glk/detection.cpp
@@ -28,6 +28,8 @@
 #include "glk/frotz/frotz.h"
 #include "glk/glulxe/detection.h"
 #include "glk/glulxe/glulxe.h"
+#include "glk/magnetic/detection.h"
+#include "glk/magnetic/magnetic.h"
 #include "glk/scott/detection.h"
 #include "glk/scott/scott.h"
 #include "glk/tads/detection.h"
@@ -108,10 +110,11 @@ Common::Error GlkMetaEngine::createInstance(OSystem *syst, Engine **engine) cons
 	// Create the correct engine
 	*engine = nullptr;
 	if ((*engine = create<Glk::Frotz::FrotzMetaEngine, Glk::Frotz::Frotz>(syst, gameDesc)) != nullptr) {}
+	else if ((*engine = create<Glk::Glulxe::GlulxeMetaEngine, Glk::Glulxe::Glulxe>(syst, gameDesc)) != nullptr) {}
 	else if ((*engine = create<Glk::Scott::ScottMetaEngine, Glk::Scott::Scott>(syst, gameDesc)) != nullptr) {}
 #ifndef RELEASE_BUILD
 	else if ((*engine = create<Glk::Alan2::Alan2MetaEngine, Glk::Alan2::Alan2>(syst, gameDesc)) != nullptr) {}
-	else if ((*engine = create<Glk::Glulxe::GlulxeMetaEngine, Glk::Glulxe::Glulxe>(syst, gameDesc)) != nullptr) {}
+	else if ((*engine = create<Glk::Magnetic::MagneticMetaEngine, Glk::Magnetic::Magnetic>(syst, gameDesc)) != nullptr) {}
 	else if ((td = Glk::TADS::TADSMetaEngine::findGame(gameDesc._gameId.c_str()))._description) {
 		if (td._options & Glk::TADS::OPTION_TADS3)
 			*engine = new Glk::TADS::TADS3::TADS3(syst, gameDesc);
@@ -151,10 +154,11 @@ Common::String GlkMetaEngine::findFileByGameId(const Common::String &gameId) con
 PlainGameList GlkMetaEngine::getSupportedGames() const {
 	PlainGameList list;
 	Glk::Frotz::FrotzMetaEngine::getSupportedGames(list);
+	Glk::Glulxe::GlulxeMetaEngine::getSupportedGames(list);
 	Glk::Scott::ScottMetaEngine::getSupportedGames(list);
 #ifndef RELEASE_BUILD
 	Glk::Alan2::Alan2MetaEngine::getSupportedGames(list);
-	Glk::Glulxe::GlulxeMetaEngine::getSupportedGames(list);
+	Glk::Magnetic::MagneticMetaEngine::getSupportedGames(list);
 	Glk::TADS::TADSMetaEngine::getSupportedGames(list);
 #endif
 
@@ -165,6 +169,9 @@ PlainGameDescriptor GlkMetaEngine::findGame(const char *gameId) const {
 	Glk::GameDescriptor gd = Glk::Frotz::FrotzMetaEngine::findGame(gameId);
 	if (gd._description) return gd;
 
+	gd = Glk::Glulxe::GlulxeMetaEngine::findGame(gameId);
+	if (gd._description) return gd;
+
 	gd = Glk::Scott::ScottMetaEngine::findGame(gameId);
 	if (gd._description) return gd;
 
@@ -172,7 +179,7 @@ PlainGameDescriptor GlkMetaEngine::findGame(const char *gameId) const {
 	gd = Glk::Alan2::Alan2MetaEngine::findGame(gameId);
 	if (gd._description) return gd;
 
-	gd = Glk::Glulxe::GlulxeMetaEngine::findGame(gameId);
+	gd = Glk::Magnetic::MagneticMetaEngine::findGame(gameId);
 	if (gd._description) return gd;
 
 	gd = Glk::TADS::TADSMetaEngine::findGame(gameId);
@@ -187,11 +194,12 @@ DetectedGames GlkMetaEngine::detectGames(const Common::FSList &fslist) const {
 
 	DetectedGames detectedGames;
 	Glk::Frotz::FrotzMetaEngine::detectGames(fslist, detectedGames);
+	Glk::Glulxe::GlulxeMetaEngine::detectGames(fslist, detectedGames);
 	Glk::Scott::ScottMetaEngine::detectGames(fslist, detectedGames);
 
 #ifndef RELEASE_BUILD
 	Glk::Alan2::Alan2MetaEngine::detectGames(fslist, detectedGames);
-	Glk::Glulxe::GlulxeMetaEngine::detectGames(fslist, detectedGames);
+	Glk::Magnetic::MagneticMetaEngine::detectGames(fslist, detectedGames);
 	Glk::TADS::TADSMetaEngine::detectGames(fslist, detectedGames);
 #endif
 
@@ -201,11 +209,12 @@ DetectedGames GlkMetaEngine::detectGames(const Common::FSList &fslist) const {
 void GlkMetaEngine::detectClashes() const {
 	Common::StringMap map;
 	Glk::Frotz::FrotzMetaEngine::detectClashes(map);
+	Glk::Glulxe::GlulxeMetaEngine::detectClashes(map);
 	Glk::Scott::ScottMetaEngine::detectClashes(map);
 
 #ifndef RELEASE_BUILD
 	Glk::Alan2::Alan2MetaEngine::detectClashes(map);
-	Glk::Glulxe::GlulxeMetaEngine::detectClashes(map);
+	Glk::Magnetic::MagneticMetaEngine::detectClashes(map);
 	Glk::TADS::TADSMetaEngine::detectClashes(map);
 #endif
 }
diff --git a/engines/glk/magnetic/detection.cpp b/engines/glk/magnetic/detection.cpp
index cfd0102..db899a2 100644
--- a/engines/glk/magnetic/detection.cpp
+++ b/engines/glk/magnetic/detection.cpp
@@ -31,22 +31,22 @@ namespace Glk {
 namespace Magnetic {
 
 void MagneticMetaEngine::getSupportedGames(PlainGameList &games) {
-	for (const MagneticDescriptor *pd = MAGNETIC_GAME_LIST; pd->gameId; ++pd) {
+	for (const PlainGameDescriptor *pd = MAGNETIC_GAME_LIST; pd->gameId; ++pd) {
 		games.push_back(*pd);
 	}
 }
 
-MagneticDescriptor MagneticMetaEngine::findGame(const char *gameId) {
-	for (const MagneticDescriptor *pd = MAGNETIC_GAME_LIST; pd->gameId; ++pd) {
+GameDescriptor MagneticMetaEngine::findGame(const char *gameId) {
+	for (const PlainGameDescriptor *pd = MAGNETIC_GAME_LIST; pd->gameId; ++pd) {
 		if (!strcmp(gameId, pd->gameId))
 			return *pd;
 	}
 
-	return MagneticDescriptor();
+	return PlainGameDescriptor();
 }
 
 bool MagneticMetaEngine::detectGames(const Common::FSList &fslist, DetectedGames &gameList) {
-	const char *const EXTENSIONS[] = { ".magnetic", nullptr };
+	const char *const EXTENSIONS[] = { ".rsc", nullptr };
 
 	// Loop through the files of the folder
 	for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
@@ -64,6 +64,12 @@ bool MagneticMetaEngine::detectGames(const Common::FSList &fslist, DetectedGames
 		Common::File gameFile;
 		if (!gameFile.open(*file))
 			continue;
+		if (gameFile.readUint32BE() != MKTAG('M', 'a', 'S', 'c')) {
+			gameFile.close();
+			continue;
+		}
+
+		gameFile.seek(0);
 		Common::String md5 = Common::computeStreamMD5AsString(gameFile, 5000);
 		size_t filesize = gameFile.size();
 		gameFile.close();
@@ -76,18 +82,10 @@ bool MagneticMetaEngine::detectGames(const Common::FSList &fslist, DetectedGames
 		DetectedGame gd;
 		if (!p->_gameId) {
 			if (gDebugLevel > 0) {
-				// Print an entry suitable for putting into the detection_tables.h, using the
-				// name of the parent folder the game is in as the presumed game Id
-				Common::String folderName = file->getParent().getName();
-				if (folderName.hasSuffix("\\"))
-					folderName.deleteLastChar();
-				Common::String fname = filename;
-				const char *dot = strchr(fname.c_str(), '.');
-				if (dot)
-					fname = Common::String(fname.c_str(), dot);
-
-				debug("ENTRY0(\"%s\", \"%s\", %u),", fname.c_str(), md5.c_str(), (uint)filesize);
+				// Print an entry suitable for putting into the detection_tables.h
+				debug("ENTRY0(\"%s\", \"%s\", %u),", filename.c_str(), md5.c_str(), (uint)filesize);
 			}
+
 			const PlainGameDescriptor &desc = MAGNETIC_GAME_LIST[0];
 			gd = DetectedGame(desc.gameId, desc.description, Common::UNK_LANG, Common::kPlatformUnknown);
 		} else {
@@ -104,7 +102,7 @@ bool MagneticMetaEngine::detectGames(const Common::FSList &fslist, DetectedGames
 }
 
 void MagneticMetaEngine::detectClashes(Common::StringMap &map) {
-	for (const MagneticDescriptor *pd = MAGNETIC_GAME_LIST; pd->gameId; ++pd) {
+	for (const PlainGameDescriptor *pd = MAGNETIC_GAME_LIST; pd->gameId; ++pd) {
 		if (map.contains(pd->gameId))
 			error("Duplicate game Id found - %s", pd->gameId);
 		map[pd->gameId] = "";
diff --git a/engines/glk/magnetic/detection.h b/engines/glk/magnetic/detection.h
index 3ea8810..28ea70f 100644
--- a/engines/glk/magnetic/detection.h
+++ b/engines/glk/magnetic/detection.h
@@ -20,32 +20,18 @@
  *
  */
 
-#ifndef GLK_GLULXE_DETECTION
-#define GLK_GLULXE_DETECTION
+#ifndef GLK_MAGNETIC_DETECTION
+#define GLK_MAGNETIC_DETECTION
 
 #include "common/fs.h"
 #include "common/hash-str.h"
 #include "engines/game.h"
+#include "glk/detection.h"
 
 namespace Glk {
 namespace Magnetic {
 
 /**
- * Magnetic game descriptior
- */
-struct MagneticDescriptor {
-	const char *gameId;
-	const char *description;
-
-	operator PlainGameDescriptor() const {
-		PlainGameDescriptor pd;
-		pd.gameId = gameId;
-		pd.description = description;
-		return pd;
-	}
-};
-
-/**
  * Meta engine for Magnetic interpreter
  */
 class MagneticMetaEngine {
@@ -58,7 +44,7 @@ public:
 	/**
 	 * Returns a game description for the given game Id, if it's supported
 	 */
-	static MagneticDescriptor findGame(const char *gameId);
+	static GameDescriptor findGame(const char *gameId);
 
 	/**
 	 * Detect supported games
diff --git a/engines/glk/magnetic/detection_tables.h b/engines/glk/magnetic/detection_tables.h
index a67d2a9..18d3b84 100644
--- a/engines/glk/magnetic/detection_tables.h
+++ b/engines/glk/magnetic/detection_tables.h
@@ -38,7 +38,7 @@ struct MagneticGameDescription {
 	Common::Language _language;
 };
 
-const MagneticDescriptor MAGNETIC_GAME_LIST[] = {
+const PlainGameDescriptor MAGNETIC_GAME_LIST[] = {
 	{ "magnetic", "Magnetic Scrolls Game" },
 
 	{ nullptr, nullptr }





More information about the Scummvm-git-logs mailing list