[Scummvm-git-logs] scummvm master -> 2e64b2202da4833fd4c2d5040599a8a3b7460dc5

sev- sev at scummvm.org
Mon Jan 9 00:54:31 CET 2017


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

Summary:
3359ea9c99 DIRECTOR: CASt members have Children in D4.
8c3c9df350 DIRECTOR: System beep and Mouse Cursors.
41ee83e3f0 DIRECTOR: D4 Image Decoding, Buttons, Text, Shapes.
2e64b2202d Merge pull request #887 from stevenhoefel/master


Commit: 3359ea9c99eba7f7e630a2b8057ec4df55fed83c
    https://github.com/scummvm/scummvm/commit/3359ea9c99eba7f7e630a2b8057ec4df55fed83c
Author: stevenhoefel (stevenhoefel at hotmail.com)
Date: 2017-01-09T00:00:04+01:00

Commit Message:
DIRECTOR: CASt members have Children in D4.

Changed paths:
    engines/director/archive.cpp
    engines/director/archive.h
    engines/director/cast.cpp
    engines/director/cast.h
    engines/director/director.h
    engines/director/resource.cpp
    engines/director/score.cpp
    engines/director/score.h


diff --git a/engines/director/archive.cpp b/engines/director/archive.cpp
index 5b1a26f..398b287 100644
--- a/engines/director/archive.cpp
+++ b/engines/director/archive.cpp
@@ -100,6 +100,18 @@ Common::SeekableSubReadStreamEndian *Archive::getResource(uint32 tag, uint16 id)
 	return new Common::SeekableSubReadStreamEndian(_stream, res.offset, res.offset + res.size, _isBigEndian, DisposeAfterUse::NO);
 }
 
+Resource Archive::getResourceDetail(uint32 tag, uint16 id) {
+	if (!_types.contains(tag))
+		error("Archive does not contain '%s' %04x", tag2str(tag), id);
+
+	const ResourceMap &resMap = _types[tag];
+
+	if (!resMap.contains(id))
+		error("Archive does not contain '%s' %04x", tag2str(tag), id);
+
+	return resMap[id];
+}
+
 uint32 Archive::getOffset(uint32 tag, uint16 id) const {
 	if (!_types.contains(tag))
 		error("Archive does not contain '%s' %04x", tag2str(tag), id);
@@ -365,6 +377,7 @@ bool RIFXArchive::openStream(Common::SeekableReadStream *stream, uint32 startOff
 	subStream.readUint32(); // unknown
 
 	Common::Array<Resource> resources;
+	resources.reserve(2048);
 
 	// Need to look for these two resources
 	const Resource *keyRes = 0;
@@ -395,6 +408,8 @@ bool RIFXArchive::openStream(Common::SeekableReadStream *stream, uint32 startOff
 			keyRes = &resources[resources.size() - 1];
 		else if (tag == MKTAG('C', 'A', 'S', '*'))
 			casRes = &resources[resources.size() - 1];
+		else
+			_types[tag][i] = res;
 	}
 
 	// We need to have found the 'File' resource already
@@ -409,6 +424,8 @@ bool RIFXArchive::openStream(Common::SeekableReadStream *stream, uint32 startOff
 		return false;
 	}
 
+	uint castTag = MKTAG('C', 'A', 'S', 't');
+
 	// Parse the CAS*, if present
 	if (casRes) {
 		Common::SeekableSubReadStreamEndian casStream(stream, casRes->offset + 8, casRes->offset + 8 + casRes->size, _isBigEndian, DisposeAfterUse::NO);
@@ -420,8 +437,10 @@ bool RIFXArchive::openStream(Common::SeekableReadStream *stream, uint32 startOff
 		for (uint i = 0; i < casSize; i++) {
 			uint32 index = casStream.readUint32();
 
-			const Resource &res = resources[index];
-			_types[MKTAG('C', 'A', 'S', 't')][i + 1] = res;
+			Resource &res = resources[index];
+			res.index = index;
+			res.castId = i + 1;
+			_types[castTag][res.castId] = res;
 
 			debugCN(2, kDebugLoading, "%d ", index);
 		}
@@ -444,10 +463,20 @@ bool RIFXArchive::openStream(Common::SeekableReadStream *stream, uint32 startOff
 
 		debugC(2, kDebugLoading, "KEY*: index: %d id: %d resTag: %s", index, id, tag2str(resTag));
 
-		const Resource &res = resources[index];
+		Resource &res = resources[index];
 		debug(3, "Found RIFX resource: '%s' id: 0x%04x, %d @ 0x%08x (%d)", tag2str(resTag), id, res.size, res.offset, res.offset);
 		_types[resTag][id] = res;
-		_types[resTag][1024 + i + 1] = res;
+		//_types[resTag][1024 + i + 1] = res;
+
+		if (id < 1024) {
+			for (uint cast = 0; cast < _types[castTag].size(); cast++) {
+				if (_types[castTag][cast].index == id) {
+					res.index = index;
+					_types[castTag][cast].children.push_back(res);
+					break;
+				}
+			}
+		}
 	}
 
 	_stream = stream;
@@ -471,5 +500,17 @@ Common::SeekableSubReadStreamEndian *RIFXArchive::getResource(uint32 tag, uint16
 	return new Common::SeekableSubReadStreamEndian(_stream, offset, offset + size, true, DisposeAfterUse::NO);
 }
 
+Resource RIFXArchive::getResourceDetail(uint32 tag, uint16 id) {
+	if (!_types.contains(tag))
+		error("Archive does not contain '%s' %04x", tag2str(tag), id);
+
+	const ResourceMap &resMap = _types[tag];
+
+	if (!resMap.contains(id))
+		error("Archive does not contain '%s' %04x", tag2str(tag), id);
+
+	return resMap[id];
+}
+
 
 } // End of namespace Director
diff --git a/engines/director/archive.h b/engines/director/archive.h
index 93f4ce7..b77bace 100644
--- a/engines/director/archive.h
+++ b/engines/director/archive.h
@@ -33,6 +33,15 @@ class MacResManager;
 namespace Director {
 
 // Completely ripped off of Mohawk's Archive code
+	
+struct Resource {
+	uint32 index;
+	uint32 offset;
+	uint32 size;
+	uint32 castId;
+	Common::String name;
+	Common::Array<Resource> children;
+};
 
 class Archive {
 public:
@@ -50,6 +59,7 @@ public:
 	bool hasResource(uint32 tag, uint16 id) const;
 	bool hasResource(uint32 tag, const Common::String &resName) const;
 	virtual Common::SeekableSubReadStreamEndian *getResource(uint32 tag, uint16 id);
+	virtual Resource getResourceDetail(uint32 tag, uint16 id);
 	uint32 getOffset(uint32 tag, uint16 id) const;
 	uint16 findResourceID(uint32 tag, const Common::String &resName) const;
 	Common::String getName(uint32 tag, uint16 id) const;
@@ -61,11 +71,6 @@ public:
 
 protected:
 	Common::SeekableReadStream *_stream;
-	struct Resource {
-		uint32 offset;
-		uint32 size;
-		Common::String name;
-	};
 	typedef Common::HashMap<uint16, Resource> ResourceMap;
 	typedef Common::HashMap<uint32, ResourceMap> TypeMap;
 	TypeMap _types;
@@ -103,6 +108,7 @@ public:
 
 	bool openStream(Common::SeekableReadStream *stream, uint32 startOffset = 0);
 	Common::SeekableSubReadStreamEndian *getResource(uint32 tag, uint16 id);
+	Resource getResourceDetail(uint32 tag, uint16 id);
 };
 
 } // End of namespace Director
diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
index 892ac48..81637b9 100644
--- a/engines/director/cast.cpp
+++ b/engines/director/cast.cpp
@@ -41,6 +41,9 @@ BitmapCast::BitmapCast(Common::ReadStreamEndian &stream, uint16 version) {
 			unk2 = stream.readUint16();
 		}
 	} else {
+		stream.readByte();
+		stream.readByte();
+
 		initialRect = Score::readRect(stream);
 		boundingRect = Score::readRect(stream);
 		regX = stream.readUint16();
@@ -59,8 +62,10 @@ BitmapCast::BitmapCast(Common::ReadStreamEndian &stream, uint16 version) {
 }
 
 TextCast::TextCast(Common::ReadStreamEndian &stream, uint16 version) {
-	if (version < 4) {
-		flags1 = stream.readByte();
+	if (version < 5) {
+		if (version <= 3)
+			flags1 = stream.readByte();
+
 		borderSize = static_cast<SizeType>(stream.readByte());
 		gutterSize = static_cast<SizeType>(stream.readByte());
 		boxShadow = static_cast<SizeType>(stream.readByte());
@@ -109,6 +114,9 @@ ShapeCast::ShapeCast(Common::ReadStreamEndian &stream, uint16 version) {
 		lineThickness = stream.readByte();
 		lineDirection = stream.readByte();
 	} else {
+		stream.readByte();
+		stream.readByte();
+
 		initialRect = Score::readRect(stream);
 		boundingRect = Score::readRect(stream);
 	}
@@ -119,8 +127,13 @@ ButtonCast::ButtonCast(Common::ReadStreamEndian &stream, uint16 version) : TextC
 	if (version < 4) {
 		buttonType = static_cast<ButtonType>(stream.readUint16BE());
 	} else {
+		stream.readByte();
+		stream.readByte();
+
 		initialRect = Score::readRect(stream);
 		boundingRect = Score::readRect(stream);
+
+		buttonType = static_cast<ButtonType>(stream.readUint16BE());
 	}
 	modified = 0;
 }
@@ -129,6 +142,9 @@ ScriptCast::ScriptCast(Common::ReadStreamEndian &stream, uint16 version) {
 	if (version < 4) {
 		error("Unhandled Script cast");
 	} else {
+		stream.readByte();
+		stream.readByte();
+
 		initialRect = Score::readRect(stream);
 		boundingRect = Score::readRect(stream);
 
diff --git a/engines/director/cast.h b/engines/director/cast.h
index 69edf8c..a739ccc 100644
--- a/engines/director/cast.h
+++ b/engines/director/cast.h
@@ -25,6 +25,7 @@
 
 #include "common/rect.h"
 #include "common/substream.h"
+#include "director/archive.h"
 
 namespace Director {
 
@@ -46,6 +47,7 @@ struct Cast {
 	CastType type;
 	Common::Rect initialRect;
 	Common::Rect boundingRect;
+	Common::Array<Resource> children;
 
 	byte modified;
 };
diff --git a/engines/director/director.h b/engines/director/director.h
index 7ec9608..ead1437 100644
--- a/engines/director/director.h
+++ b/engines/director/director.h
@@ -73,6 +73,7 @@ public:
 	Common::Language getLanguage() const;
 	Common::String getEXEName() const;
 	DirectorSound *getSoundManager() const { return _soundManager; }
+	Graphics::MacWindowManager *getMacWindowManager() const { return _wm; }
 	Archive *getMainArchive() const { return _mainArchive; }
 	Lingo *getLingo() const { return _lingo; }
 	Score *getCurrentScore() const { return _currentScore; }
diff --git a/engines/director/resource.cpp b/engines/director/resource.cpp
index 2f8ef3e..711ce04 100644
--- a/engines/director/resource.cpp
+++ b/engines/director/resource.cpp
@@ -217,7 +217,7 @@ void DirectorEngine::loadSharedCastsFrom(Common::String filename) {
 	Common::Array<uint16> cast = shardcst->getResourceIDList(MKTAG('C','A','S','t'));
 	if (cast.size() > 0) {
 		for (Common::Array<uint16>::iterator iterator = cast.begin(); iterator != cast.end(); ++iterator)
-			castScore->loadCastData(*shardcst->getResource(MKTAG('C','A','S','t'), *iterator), *iterator);
+			castScore->loadCastData(*shardcst->getResource(MKTAG('C','A','S','t'), *iterator), *iterator, NULL);
 	}
 
 	castScore->setSpriteCasts();
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 8a80e30..b3aee97 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -216,16 +216,19 @@ void Score::loadArchive() {
 
 	Common::Array<uint16> cast = _movieArchive->getResourceIDList(MKTAG('C','A','S','t'));
 	if (cast.size() > 0) {
-		for (Common::Array<uint16>::iterator iterator = cast.begin(); iterator != cast.end(); ++iterator)
-			loadCastData(*_movieArchive->getResource(MKTAG('C','A','S','t'), *iterator), *iterator);
+		for (Common::Array<uint16>::iterator iterator = cast.begin(); iterator != cast.end(); ++iterator) {
+			Common::SeekableSubReadStreamEndian *stream = _movieArchive->getResource(MKTAG('C', 'A', 'S', 't'), *iterator);
+			Resource res = _movieArchive->getResourceDetail(MKTAG('C', 'A', 'S', 't'), *iterator);
+			loadCastData(*stream, *iterator, &res);
+		}
 	}
 
 	setSpriteCasts();
 
-	Common::Array<uint16> stxt = _movieArchive->getResourceIDList(MKTAG('S','T','X','T'));
-	if (stxt.size() > 0) {
-		loadScriptText(*_movieArchive->getResource(MKTAG('S','T','X','T'), *stxt.begin()));
-	}
+	//Common::Array<uint16> stxt = _movieArchive->getResourceIDList(MKTAG('S','T','X','T'));
+	//if (stxt.size() > 0) {
+	//	loadScriptText(*_movieArchive->getResource(MKTAG('S','T','X','T'), *stxt.begin()));
+	//}
 }
 
 Score::~Score() {
@@ -397,7 +400,7 @@ void Score::setSpriteCasts() {
 	}
 }
 
-void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream, uint16 id) {
+void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream, uint16 id, Resource *res) {
 	// d4+ variant
 	if (stream.size() == 0)
 		return;
@@ -415,7 +418,7 @@ void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream, uint16 id)
 	uint32 size1, size2, size3, castType;
 	byte unk1 = 0, unk2 = 0, unk3 = 0;
 
-	if (_vm->getVersion() < 5) {
+	if (_vm->getVersion() < 4) {
 		size1 = stream.readUint16();
 		size2 = stream.readUint32();
 		size3 = 0;
@@ -423,6 +426,12 @@ void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream, uint16 id)
 		unk1 = stream.readByte();
 		unk2 = stream.readByte();
 		unk3 = stream.readByte();
+	} else if (_vm->getVersion() < 5) {
+		size1 = stream.readUint16() + 2;
+		size2 = stream.readUint32();
+		size3 = 0;
+		castType = stream.readByte();
+		unk1 = stream.readByte();
 	} else {
 		// FIXME: only the cast type and the strings are good
 		castType = stream.readUint32();
@@ -436,7 +445,7 @@ void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream, uint16 id)
 	debugC(3, kDebugLoading, "CASt: id: %d type: %x size1: %d size2: %d (%x) size3: %d unk1: %d unk2: %d unk3: %d",
 				id, castType, size1, size2, size2, size3, unk1, unk2, unk3);
 
-	byte *data = (byte *)calloc(size1, 1); // 16 is for bounding rects
+	byte *data = (byte *)calloc(size1 + 16, 1); // 16 is for bounding rects
 	stream.read(data, size1 + 16);
 
 	Common::MemoryReadStreamEndian castStream(data, size1 + 16, stream.isBE());
@@ -469,6 +478,9 @@ void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream, uint16 id)
 		_casts[id]->type = kCastButton;
 		break;
 	case kCastScript:
+		warning("CASt: Script");
+		Common::hexdump(data, size1 + 16);
+
 		_casts[id] = new ScriptCast(castStream, _vm->getVersion());
 		_casts[id]->type = kCastScript;
 		break;
@@ -477,6 +489,11 @@ void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream, uint16 id)
 		break;
 	}
 
+	if (res != NULL) {
+		for (uint child = 0; child < res->children.size(); child++)
+			_casts[id]->children.push_back(res->children[child]);
+	}
+
 	free(data);
 
 	if (size2) {
@@ -500,6 +517,11 @@ void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream, uint16 id)
 		ci->fileName = castStrings[3];
 		ci->type = castStrings[4];
 
+		if (!ci->script.empty()) {
+			//the script type here could be wrong!
+			_lingo->addCode(ci->script.c_str(), _casts[id]->type == kCastScript ? kFrameScript : kSpriteScript, id);
+		}
+
 		_castsInfo[id] = ci;
 	}
 
@@ -802,7 +824,7 @@ Common::Array<Common::String> Score::loadStrings(Common::SeekableSubReadStreamEn
 	byte *data = (byte *)malloc(entries[count - 1]);
 	stream.read(data, entries[count - 1]);
 
-	for (uint i = 0; i < count - 1; i++) {
+	for (uint16 i = 0; i < count - 1; i++) {
 		Common::String entryString;
 
 		for (uint j = entries[i]; j < entries[i + 1]; j++)
@@ -821,6 +843,9 @@ Common::Array<Common::String> Score::loadStrings(Common::SeekableSubReadStreamEn
 }
 
 void Score::loadFontMap(Common::SeekableSubReadStreamEndian &stream) {
+	if (stream.size() == 0)
+		return;
+
 	uint16 count = stream.readUint16();
 	uint32 offset = (count * 2) + 2;
 	uint16 currentRawPosition = offset;
@@ -908,9 +933,11 @@ void Score::update() {
 	_currentFrame++;
 
 	Common::SortedArray<Label *>::iterator i;
-	for (i = _labels->begin(); i != _labels->end(); ++i) {
-		if ((*i)->number == _currentFrame) {
-			_currentLabel = (*i)->name;
+	if (_labels != NULL) {
+		for (i = _labels->begin(); i != _labels->end(); ++i) {
+			if ((*i)->number == _currentFrame) {
+				_currentLabel = (*i)->name;
+			}
 		}
 	}
 
diff --git a/engines/director/score.h b/engines/director/score.h
index 49e4f35..b665842 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -25,6 +25,7 @@
 
 #include "common/substream.h"
 #include "common/rect.h"
+#include "director/archive.h"
 
 namespace Graphics {
 	class ManagedSurface;
@@ -67,7 +68,7 @@ public:
 	Archive *getArchive() const { return _movieArchive; };
 	void loadConfig(Common::SeekableSubReadStreamEndian &stream);
 	void loadCastDataVWCR(Common::SeekableSubReadStreamEndian &stream);
-	void loadCastData(Common::SeekableSubReadStreamEndian &stream, uint16 id);
+	void loadCastData(Common::SeekableSubReadStreamEndian &stream, uint16 id, Resource *res);
 	void setCurrentFrame(uint16 frameId) { _currentFrame = frameId; }
 	int getCurrentFrame() { return _currentFrame; }
 	Common::String getMacName() const { return _macName; }


Commit: 8c3c9df3508bdb18f0b083de93f0e88983660028
    https://github.com/scummvm/scummvm/commit/8c3c9df3508bdb18f0b083de93f0e88983660028
Author: stevenhoefel (stevenhoefel at hotmail.com)
Date: 2017-01-09T00:00:17+01:00

Commit Message:
DIRECTOR: System beep and Mouse Cursors.

Changed paths:
    engines/director/lingo/lingo-builtins.cpp
    engines/director/lingo/lingo-funcs.cpp
    engines/director/lingo/lingo.h
    engines/director/sound.cpp
    engines/director/sound.h
    graphics/macgui/macwindowmanager.cpp
    graphics/macgui/macwindowmanager.h


diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index 1d93b9a..a536013 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -615,7 +615,7 @@ void Lingo::b_alert(int nargs) {
 void Lingo::b_cursor(int nargs) {
 	Datum d = g_lingo->pop();
 	d.toInt();
-	warning("STUB: b_cursor(%d)", d.u.i);
+	g_lingo->func_cursor(d.u.i);
 }
 
 void Lingo::b_showGlobals(int nargs) {
@@ -767,7 +767,7 @@ void Lingo::b_point(int nargs) {
 ///////////////////
 void Lingo::b_beep(int nargs) {
 	Datum d = g_lingo->pop();
-	warning("STUB: b_beep(%d)", d.u.i);
+	g_lingo->func_beep(d.u.i);
 }
 
 void Lingo::b_mci(int nargs) {
diff --git a/engines/director/lingo/lingo-funcs.cpp b/engines/director/lingo/lingo-funcs.cpp
index e22044c..6becd14 100644
--- a/engines/director/lingo/lingo-funcs.cpp
+++ b/engines/director/lingo/lingo-funcs.cpp
@@ -26,6 +26,7 @@
 #include "common/util.h"
 #include "director/lingo/lingo-gr.h"
 #include "director/sound.h"
+#include "graphics/macgui/macwindowmanager.h"
 
 namespace Director {
 
@@ -210,4 +211,38 @@ void Lingo::func_gotoprevious() {
 	_vm->_currentScore->gotoprevious();
 }
 
+void Lingo::func_cursor(int c) {
+	if (_cursorOnStack) {
+		//pop cursor
+		_vm->getMacWindowManager()->popCursor();
+	}
+
+	//and then push cursor.
+	switch (c) {
+	case 0:
+	case -1:
+		_vm->getMacWindowManager()->pushArrowCursor();
+		break;
+	case 1:
+		_vm->getMacWindowManager()->pushBeamCursor();
+		break;
+	case 2:
+		_vm->getMacWindowManager()->pushCrossHairCursor();
+		break;
+	case 3:
+		_vm->getMacWindowManager()->pushCrossBarCursor();
+		break;
+	case 4:
+		_vm->getMacWindowManager()->pushWatchCursor();
+		break;
+	}
+
+	warning("STUB: func_cursor(%d)", c);
+}
+
+void Lingo::func_beep(int repeats) {
+	for (int r = 0; r <= repeats; r++)
+		_vm->getSoundManager()->systemBeep();
+}
+
 }
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index 5e7242a..67ab57a 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -401,10 +401,12 @@ public:
 
 	void func_mci(Common::String &s);
 	void func_mciwait(Common::String &s);
+	void func_beep(int repeats);
 	void func_goto(Datum &frame, Datum &movie);
 	void func_gotoloop();
 	void func_gotonext();
 	void func_gotoprevious();
+	void func_cursor(int c);
 
 public:
 	void setTheEntity(int entity, Datum &id, int field, Datum &d);
@@ -440,6 +442,8 @@ public:
 
 	bool _exitRepeat;
 
+	bool _cursorOnStack;
+
 private:
 	int parse(const char *code);
 	void parseMenu(const char *code);
diff --git a/engines/director/sound.cpp b/engines/director/sound.cpp
index 1bd70d2..0fc1a43 100644
--- a/engines/director/sound.cpp
+++ b/engines/director/sound.cpp
@@ -34,6 +34,11 @@ DirectorSound::DirectorSound() {
 	_sound2 = new Audio::SoundHandle();
 	_scriptSound = new Audio::SoundHandle();
 	_mixer = g_system->getMixer();
+
+	_speaker = new Audio::PCSpeaker();
+	_pcSpeakerHandle = new Audio::SoundHandle();
+	_mixer->playStream(Audio::Mixer::kSFXSoundType,
+		_pcSpeakerHandle, _speaker, -1, 50, 0, DisposeAfterUse::NO, true);
 }
 
 DirectorSound::~DirectorSound() {
@@ -100,6 +105,11 @@ bool DirectorSound::isChannelActive(uint8 channelID) {
 void DirectorSound::stopSound() {
 	_mixer->stopHandle(*_sound1);
 	_mixer->stopHandle(*_sound2);
+	_mixer->stopHandle(*_pcSpeakerHandle);
+}
+
+void DirectorSound::systemBeep() {
+	_speaker->play(Audio::PCSpeaker::kWaveFormSquare, 500, 150);
 }
 
 } // End of namespace Director
diff --git a/engines/director/sound.h b/engines/director/sound.h
index 0472da0..6a77031 100644
--- a/engines/director/sound.h
+++ b/engines/director/sound.h
@@ -22,6 +22,7 @@
 
 #include "audio/audiostream.h"
 #include "audio/mixer.h"
+#include "audio/softsynth/pcspk.h"
 
 #ifndef DIRECTOR_SOUND_H
 #define DIRECTOR_SOUND_H
@@ -35,6 +36,8 @@ private:
 	Audio::SoundHandle *_sound2;
 	Audio::SoundHandle *_scriptSound;
 	Audio::Mixer *_mixer;
+	Audio::PCSpeaker *_speaker;
+	Audio::SoundHandle *_pcSpeakerHandle;
 
 public:
 	DirectorSound();
@@ -43,6 +46,7 @@ public:
 	void playWAV(Common::String filename, uint8 channelID);
 	void playAIFF(Common::String filename, uint8 channelID);
 	void playMCI(Audio::AudioStream &stream, uint32 from, uint32 to);
+	void systemBeep();
 	bool isChannelActive(uint8 channelID);
 	void stopSound();
 };
diff --git a/graphics/macgui/macwindowmanager.cpp b/graphics/macgui/macwindowmanager.cpp
index 42cab7c..bad4ad3 100644
--- a/graphics/macgui/macwindowmanager.cpp
+++ b/graphics/macgui/macwindowmanager.cpp
@@ -88,6 +88,60 @@ static const byte macCursorBeam[] = {
 	3, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3,
 	0, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3,
 };
+static const byte macCursorCrossHair[] = {
+	0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
+	0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+};
+static const byte macCursorWatch[] = {
+	0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 
+	0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 
+	0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 
+	0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 
+	0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 
+	1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 
+	1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 
+	1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 
+	1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 
+	1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 
+	1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 
+	0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 
+	0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 
+	0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 
+	0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 
+	0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 
+};
+static const byte macCursorCrossBar[] = {
+	0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
+	0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0,
+	0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0,
+	0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0,
+	1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0,
+	1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1,
+	1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1,
+	1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1,
+	0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1,
+	0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0,
+	0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0,
+	0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
+	0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
 
 MacWindowManager::MacWindowManager() {
 	_screen = 0;
@@ -327,6 +381,22 @@ void MacWindowManager::pushArrowCursor() {
 	CursorMan.pushCursor(macCursorArrow, 11, 16, 1, 1, 3);
 }
 
+void MacWindowManager::pushBeamCursor() {
+	CursorMan.pushCursor(macCursorBeam, 11, 16, 1, 1, 3);
+}
+
+void MacWindowManager::pushCrossHairCursor() {
+	CursorMan.pushCursor(macCursorCrossHair, 11, 16, 1, 1, 3);
+}
+
+void MacWindowManager::pushCrossBarCursor() {
+	CursorMan.pushCursor(macCursorCrossBar, 11, 16, 1, 1, 3);
+}
+
+void MacWindowManager::pushWatchCursor() {
+	CursorMan.pushCursor(macCursorWatch, 11, 16, 1, 1, 3);
+}
+
 void MacWindowManager::popCursor() {
 	CursorMan.popCursor();
 }
diff --git a/graphics/macgui/macwindowmanager.h b/graphics/macgui/macwindowmanager.h
index 3449ab1..9f62403 100644
--- a/graphics/macgui/macwindowmanager.h
+++ b/graphics/macgui/macwindowmanager.h
@@ -146,6 +146,10 @@ public:
 	void drawFilledRoundRect(ManagedSurface *surface, Common::Rect &rect, int arc, int color);
 
 	void pushArrowCursor();
+	void pushBeamCursor();
+	void pushCrossHairCursor();
+	void pushCrossBarCursor();
+	void pushWatchCursor();
 	void popCursor();
 
 public:


Commit: 41ee83e3f02144da364b98b8f5b974087e6dac89
    https://github.com/scummvm/scummvm/commit/41ee83e3f02144da364b98b8f5b974087e6dac89
Author: stevenhoefel (stevenhoefel at hotmail.com)
Date: 2017-01-09T00:05:06+01:00

Commit Message:
DIRECTOR: D4 Image Decoding, Buttons, Text, Shapes.

Changed paths:
    engines/director/frame.cpp
    engines/director/frame.h
    engines/director/images.cpp
    engines/director/images.h
    engines/director/sprite.h


diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp
index de0de6d..7c52cf8 100644
--- a/engines/director/frame.cpp
+++ b/engines/director/frame.cpp
@@ -114,54 +114,61 @@ void Frame::readChannel(Common::SeekableSubReadStreamEndian &stream, uint16 offs
 }
 
 void Frame::readChannels(Common::ReadStreamEndian *stream) {
-	_actionId = stream->readByte();
-	_soundType1 = stream->readByte(); // type: 0x17 for sounds (sound is cast id), 0x16 for MIDI (sound is cmd id)
-	uint8 transFlags = stream->readByte(); // 0x80 is whole stage (vs changed area), rest is duration in 1/4ths of a second
-
-	if (transFlags & 0x80)
-		_transArea = 1;
-	else
-		_transArea = 0;
-	_transDuration = transFlags & 0x7f;
-
-	_transChunkSize = stream->readByte();
-	_tempo = stream->readByte();
-	_transType = static_cast<TransitionType>(stream->readByte());
-	_sound1 = stream->readUint16();
-	if (_vm->getPlatform() == Common::kPlatformMacintosh) {
-		_sound2 = stream->readUint16();
-		_soundType2 = stream->readByte();
-	} else {
-		byte unk[3];
-		stream->read(unk, 3);
-		warning("unk1: %x unk2: %x unk3: %x", unk[0], unk[1], unk[2]);
-	}
-	_skipFrameFlag = stream->readByte();
-	_blend = stream->readByte();
+	byte unk[16];
 
-	if (_vm->getPlatform() != Common::kPlatformMacintosh) {
-		_sound2 = stream->readUint16();
-		_soundType2 = stream->readByte();
-	}
+	if (_vm->getVersion() < 4) {
+		_actionId = stream->readByte();
+		_soundType1 = stream->readByte(); // type: 0x17 for sounds (sound is cast id), 0x16 for MIDI (sound is cmd id)
+		uint8 transFlags = stream->readByte(); // 0x80 is whole stage (vs changed area), rest is duration in 1/4ths of a second
 
-	uint16 palette = stream->readUint16();
+		if (transFlags & 0x80)
+			_transArea = 1;
+		else
+			_transArea = 0;
+		_transDuration = transFlags & 0x7f;
+
+		_transChunkSize = stream->readByte();
+		_tempo = stream->readByte();
+		_transType = static_cast<TransitionType>(stream->readByte());
+		_sound1 = stream->readUint16();
+		if (_vm->getPlatform() == Common::kPlatformMacintosh) {
+			_sound2 = stream->readUint16();
+			_soundType2 = stream->readByte();
+		} else {
+			stream->read(unk, 3);
+			warning("unk1: %x unk2: %x unk3: %x", unk[0], unk[1], unk[2]);
+		}
+		_skipFrameFlag = stream->readByte();
+		_blend = stream->readByte();
 
-	if (palette) {
-		warning("STUB: Palette info");
-	}
+		if (_vm->getPlatform() != Common::kPlatformMacintosh) {
+			_sound2 = stream->readUint16();
+			_soundType2 = stream->readByte();
+		}
 
-	debugC(kDebugLoading, 8, "%d %d %d %d %d %d %d %d %d %d %d", _actionId, _soundType1, _transDuration, _transChunkSize, _tempo, _transType, _sound1, _skipFrameFlag, _blend, _sound2, _soundType2);
+		uint16 palette = stream->readUint16();
 
-	_palette = new PaletteInfo();
-	_palette->firstColor = stream->readByte(); // for cycles. note: these start at 0x80 (for pal entry 0)!
-	_palette->lastColor = stream->readByte();
-	_palette->flags = stream->readByte();
-	_palette->speed = stream->readByte();
-	_palette->frameCount = stream->readUint16();
+		if (palette) {
+			warning("STUB: Palette info");
+		}
+
+		debugC(kDebugLoading, 8, "%d %d %d %d %d %d %d %d %d %d %d", _actionId, _soundType1, _transDuration, _transChunkSize, _tempo, _transType, _sound1, _skipFrameFlag, _blend, _sound2, _soundType2);
+
+		_palette = new PaletteInfo();
+		_palette->firstColor = stream->readByte(); // for cycles. note: these start at 0x80 (for pal entry 0)!
+		_palette->lastColor = stream->readByte();
+		_palette->flags = stream->readByte();
+		_palette->speed = stream->readByte();
+		_palette->frameCount = stream->readUint16();
+
+		_palette->cycleCount = stream->readUint16();
+	} else if (_vm->getVersion() < 5) {
+		stream->read(unk, 16);
+		_actionId = stream->readUint16();
+		stream->read(unk, 5);
+	}
 
-	_palette->cycleCount = stream->readUint16();
 
-	byte unk[11];
 	stream->read(unk, 6);
 
 	if (_vm->getPlatform() == Common::kPlatformMacintosh) {
@@ -181,8 +188,9 @@ void Frame::readChannels(Common::ReadStreamEndian *stream) {
 	for (int i = 0; i < CHANNEL_COUNT; i++) {
 		Sprite &sprite = *_sprites[i + 1];
 
-		sprite._x1 = stream->readByte();
-		sprite._enabled = (stream->readByte() != 0);
+		sprite._scriptId = stream->readByte();
+		sprite._spriteType = stream->readByte();
+		sprite._enabled = sprite._spriteType != 0;
 		sprite._x2 = stream->readUint16();
 
 		sprite._flags = stream->readUint16();
@@ -199,8 +207,6 @@ void Frame::readChannels(Common::ReadStreamEndian *stream) {
 		sprite._height = stream->readUint16();
 		sprite._width = stream->readUint16();
 
-		debugC(kDebugLoading, 8, "%03d(%d)[%x,%x,%04x,%d/%d/%d/%d]", sprite._castId, sprite._enabled, sprite._x1, sprite._x2, sprite._flags, sprite._startPoint.x, sprite._startPoint.y, sprite._width, sprite._height);
-
 		if (_vm->getPlatform() == Common::kPlatformMacintosh && _vm->getVersion() >= 4) {
 			sprite._scriptId = stream->readUint16();
 			sprite._flags2 = stream->readByte(); // 0x40 editable, 0x80 moveable
@@ -209,6 +215,10 @@ void Frame::readChannels(Common::ReadStreamEndian *stream) {
 			if (_vm->getVersion() >= 5)
 				sprite._unk3 = stream->readUint32();
 		}
+
+		debugC(kDebugLoading, 8, "%03d(%d)[%x,%x,%04x,%d/%d/%d/%d] script:%d",
+			sprite._castId, sprite._enabled, sprite._x1, sprite._x2, sprite._flags,
+			sprite._startPoint.x, sprite._startPoint.y, sprite._width, sprite._height, sprite._scriptId);
 	}
 }
 
@@ -360,6 +370,7 @@ void Frame::readSprite(Common::SeekableSubReadStreamEndian &stream, uint16 offse
 }
 
 void Frame::prepareFrame(Score *score) {
+	_drawRects.clear();
 	renderSprites(*score->_surface, false);
 	renderSprites(*score->_trailSurface, true);
 
@@ -529,82 +540,144 @@ void Frame::renderSprites(Graphics::ManagedSurface &surface, bool renderTrail) {
 			if ((_sprites[i]->_trails == 0 && renderTrail) || (_sprites[i]->_trails == 1 && !renderTrail))
 				continue;
 
+			CastType castType;
 			Cast *cast;
-			if (!_vm->_currentScore->_casts.contains(_sprites[i]->_castId)) {
-				if (!_vm->getSharedCasts()->contains(_sprites[i]->_castId)) {
-					warning("Cast id %d not found", _sprites[i]->_castId);
-					continue;
-				} else {
-					warning("Getting cast id %d from shared cast", _sprites[i]->_castId);
-					cast = _vm->getSharedCasts()->getVal(_sprites[i]->_castId);
+			if (_vm->getVersion() < 4) {
+				switch (_sprites[i]->_spriteType) {
+				case 0x01:
+				case 0x0c: //this is actually a mouse-over shape? I don't think it's a real button.
+					castType = kCastBitmap;
+					break;
+				case 0x02:
+					castType = kCastShape;
+					break;
+				case 0x07:
+					castType = kCastText;
+					break;
 				}
 			} else {
-				cast = _vm->_currentScore->_casts[_sprites[i]->_castId];
-			}
-
-			if (cast->type == kCastText) {
-				renderText(surface, i);
-				continue;
+				if (!_vm->_currentScore->_casts.contains(_sprites[i]->_castId)) {
+					if (!_vm->getSharedCasts()->contains(_sprites[i]->_castId)) {
+						warning("Cast id %d not found", _sprites[i]->_castId);
+						continue;
+					} else {
+						warning("Getting cast id %d from shared cast", _sprites[i]->_castId);
+						cast = _vm->getSharedCasts()->getVal(_sprites[i]->_castId);
+					}
+				} else {
+					cast = _vm->_currentScore->_casts[_sprites[i]->_castId];
+				}
+				castType = cast->type;
 			}
 
-			Image::ImageDecoder *img = getImageFrom(_sprites[i]->_castId);
+			//this needs precedence to be hit first... D3 does something really tricky with cast IDs for shapes.
+			//I don't like this implementation 100% as the 'cast' above might not actually hit a member and be null?
+			if (castType == kCastShape) {
+				renderShape(surface, i);
+			} else if (castType == kCastText) {
+				renderText(surface, i, _vm->getVersion() < 4 ? _sprites[i]->_castId + 1024 : cast->children[0].index);
+			} else if (castType == kCastButton) {
+				renderButton(surface, i, _vm->getVersion() < 4 ? _sprites[i]->_castId + 1024 : cast->children[0].index);
+			} else {
+				Image::ImageDecoder *img = getImageFrom(_sprites[i]->_castId);
 
-			if (!img) {
-				warning("Image with id %d not found", _sprites[i]->_castId);
-				continue;
-			}
+				if (!img) {
+					warning("Image with id %d not found", _sprites[i]->_castId);
+					continue;
+				}
 
-			if (!img->getSurface()) {
-				warning("Frame::renderSprites: Could not load image %d", _sprites[i]->_castId);
-				continue;
-			}
+				if (!img->getSurface()) {
+					warning("Frame::renderSprites: Could not load image %d", _sprites[i]->_castId);
+					continue;
+				}
 
-			assert(_sprites[i]->_cast);
-
-			uint32 regX = static_cast<BitmapCast *>(_sprites[i]->_cast)->regX;
-			uint32 regY = static_cast<BitmapCast *>(_sprites[i]->_cast)->regY;
-			uint32 rectLeft = static_cast<BitmapCast *>(_sprites[i]->_cast)->initialRect.left;
-			uint32 rectTop = static_cast<BitmapCast *>(_sprites[i]->_cast)->initialRect.top;
-
-			int x = _sprites[i]->_startPoint.x - regX + rectLeft;
-			int y = _sprites[i]->_startPoint.y - regY + rectTop;
-			int height = _sprites[i]->_height;
-			int width = _sprites[i]->_width;
-
-			Common::Rect drawRect = Common::Rect(x, y, x + width, y + height);
-			_drawRects.push_back(drawRect);
-
-			switch (_sprites[i]->_ink) {
-			case kInkTypeCopy:
-				surface.blitFrom(*img->getSurface(), Common::Point(x, y));
-				break;
-			case kInkTypeTransparent:
-				// FIXME: is it always white (last entry in pallette)?
-				surface.transBlitFrom(*img->getSurface(), Common::Point(x, y), _vm->getPaletteColorCount() - 1);
-				break;
-			case kInkTypeBackgndTrans:
-				drawBackgndTransSprite(surface, *img->getSurface(), drawRect);
-				break;
-			case kInkTypeMatte:
-				drawMatteSprite(surface, *img->getSurface(), drawRect);
-				break;
-			case kInkTypeGhost:
-				drawGhostSprite(surface, *img->getSurface(), drawRect);
-				break;
-			case kInkTypeReverse:
-				drawReverseSprite(surface, *img->getSurface(), drawRect);
-				break;
-			default:
-				warning("Unhandled ink type %d", _sprites[i]->_ink);
-				surface.blitFrom(*img->getSurface(), Common::Point(x, y));
-				break;
+				assert(_sprites[i]->_cast);
+
+				uint32 regX = static_cast<BitmapCast *>(_sprites[i]->_cast)->regX;
+				uint32 regY = static_cast<BitmapCast *>(_sprites[i]->_cast)->regY;
+				uint32 rectLeft = static_cast<BitmapCast *>(_sprites[i]->_cast)->initialRect.left;
+				uint32 rectTop = static_cast<BitmapCast *>(_sprites[i]->_cast)->initialRect.top;
+
+				int x = _sprites[i]->_startPoint.x - regX + rectLeft;
+				int y = _sprites[i]->_startPoint.y - regY + rectTop;
+				int height = _sprites[i]->_height;
+				int width = _sprites[i]->_width;
+
+				Common::Rect drawRect = Common::Rect(x, y, x + width, y + height);
+				_drawRects[i] = drawRect;
+
+				switch (_sprites[i]->_ink) {
+				case kInkTypeCopy:
+					surface.blitFrom(*img->getSurface(), Common::Point(x, y));
+					break;
+				case kInkTypeTransparent:
+					// FIXME: is it always white (last entry in pallette)?
+					surface.transBlitFrom(*img->getSurface(), Common::Point(x, y), _vm->getPaletteColorCount() - 1);
+					break;
+				case kInkTypeBackgndTrans:
+					drawBackgndTransSprite(surface, *img->getSurface(), drawRect);
+					break;
+				case kInkTypeMatte:
+					drawMatteSprite(surface, *img->getSurface(), drawRect);
+					break;
+				case kInkTypeGhost:
+					drawGhostSprite(surface, *img->getSurface(), drawRect);
+					break;
+				case kInkTypeReverse:
+					drawReverseSprite(surface, *img->getSurface(), drawRect);
+					break;
+				default:
+					warning("Unhandled ink type %d", _sprites[i]->_ink);
+					surface.blitFrom(*img->getSurface(), Common::Point(x, y));
+					break;
+				}
 			}
 		}
 	}
 }
 
-void Frame::renderButton(Graphics::ManagedSurface &surface, uint16 spriteId) {
-	renderText(surface, spriteId);
+void Frame::renderShape(Graphics::ManagedSurface &surface, uint16 spriteID) {
+	Common::Rect r = Common::Rect(_sprites[spriteID]->_startPoint.x, 
+		_sprites[spriteID]->_startPoint.y,
+		_sprites[spriteID]->_startPoint.x + _sprites[spriteID]->_width, 
+		_sprites[spriteID]->_startPoint.y + _sprites[spriteID]->_height);
+
+	Graphics::Surface tmpSurface;
+	tmpSurface.create(r.width(), r.height(), Graphics::PixelFormat::createFormatCLUT8());
+
+	tmpSurface.fillRect(Common::Rect(r.width(), r.height()), 0);
+
+	switch (_sprites[spriteID]->_ink) {
+	case kInkTypeCopy:
+		surface.blitFrom(tmpSurface, Common::Point(_sprites[spriteID]->_startPoint.x, _sprites[spriteID]->_startPoint.y));
+		break;
+	case kInkTypeTransparent:
+		// FIXME: is it always white (last entry in pallette)?
+		surface.transBlitFrom(tmpSurface, Common::Point(_sprites[spriteID]->_startPoint.x, _sprites[spriteID]->_startPoint.y), _vm->getPaletteColorCount() - 1);
+		break;
+	case kInkTypeBackgndTrans:
+		drawBackgndTransSprite(surface, tmpSurface, r);
+		break;
+	case kInkTypeMatte:
+		drawMatteSprite(surface, tmpSurface, r);
+		break;
+	case kInkTypeGhost:
+		drawGhostSprite(surface, tmpSurface, r);
+		break;
+	case kInkTypeReverse:
+		drawReverseSprite(surface, tmpSurface, r);
+		break;
+	default:
+		warning("Unhandled ink type %d", _sprites[spriteID]->_ink);
+		surface.blitFrom(tmpSurface, Common::Point(_sprites[spriteID]->_startPoint.x, _sprites[spriteID]->_startPoint.y));
+		break;
+	}
+
+	_drawRects[spriteID] = r;
+}
+
+void Frame::renderButton(Graphics::ManagedSurface &surface, uint16 spriteId, uint16 textId) {
+	renderText(surface, spriteId, _vm->getMainArchive()->getResource(MKTAG('S', 'T', 'X', 'T'), textId), true);
 
 	uint16 castID = _sprites[spriteId]->_castId;
 	ButtonCast *button = static_cast<ButtonCast *>(_vm->_currentScore->_casts[castID]);
@@ -617,13 +690,19 @@ void Frame::renderButton(Graphics::ManagedSurface &surface, uint16 spriteId) {
 	int height = _sprites[spriteId]->_height;
 	int width = _sprites[spriteId]->_width;
 
+	Common::Rect _rect;
+
 	switch (button->buttonType) {
 	case kTypeCheckBox:
 		// Magic numbers: checkbox square need to move left about 5px from text and 12px side size (D4)
-		surface.frameRect(Common::Rect(x - 17, y, x + 12, y + 12), 0);
+		_rect = Common::Rect(x - 17, y, x + 12, y + 12);
+		surface.frameRect(_rect, 0);
+		_drawRects[spriteId] = _rect;
 		break;
 	case kTypeButton:
-		surface.frameRect(Common::Rect(x, y, x + width, y + height), 0);
+		_rect = Common::Rect(x, y, x + width, y + height);
+		surface.frameRect(_rect, 0);
+		_drawRects[spriteId] = _rect;
 		break;
 	case kTypeRadio:
 		warning("STUB: renderButton: kTypeRadio");
@@ -633,6 +712,10 @@ void Frame::renderButton(Graphics::ManagedSurface &surface, uint16 spriteId) {
 
 Image::ImageDecoder *Frame::getImageFrom(uint16 spriteId) {
 	uint16 imgId = spriteId + 1024;
+
+	if (_vm->getVersion() >= 4 && _vm->_currentScore->_casts[spriteId]->children.size() > 0)
+		imgId = _vm->_currentScore->_casts[spriteId]->children[0].index;
+
 	Image::ImageDecoder *img = NULL;
 
 	if (_vm->_currentScore->getArchive()->hasResource(MKTAG('D', 'I', 'B', ' '), imgId)) {
@@ -650,13 +733,20 @@ Image::ImageDecoder *Frame::getImageFrom(uint16 spriteId) {
 	if (_vm->_currentScore->getArchive()->hasResource(MKTAG('B', 'I', 'T', 'D'), imgId)) {
 		Common::SeekableReadStream *pic = _vm->_currentScore->getArchive()->getResource(MKTAG('B', 'I', 'T', 'D'), imgId);
 
-		if (_vm->getVersion() <= 4) {
+		if (_vm->getVersion() < 4) {
 			BitmapCast *bc = static_cast<BitmapCast *>(_vm->_currentScore->_casts[spriteId]);
 			int w = bc->initialRect.width(), h = bc->initialRect.height();
 
 			debugC(2, kDebugImages, "id: %d, w: %d, h: %d, flags: %x, some: %x, unk1: %d, unk2: %d",
 				imgId, w, h, bc->flags, bc->someFlaggyThing, bc->unk1, bc->unk2);
 			img = new BITDDecoder(w, h);
+		} else if (_vm->getVersion() < 6) {
+			BitmapCast *bc = static_cast<BitmapCast *>(_vm->_currentScore->_casts[spriteId]);
+			int w = bc->initialRect.width(), h = bc->initialRect.height();
+
+			debugC(2, kDebugImages, "id: %d, w: %d, h: %d, flags: %x, some: %x, unk1: %d, unk2: %d",
+				imgId, w, h, bc->flags, bc->someFlaggyThing, bc->unk1, bc->unk2);
+			img = new BITDDecoderV4(w, h);
 		} else {
 			img = new Image::BitmapDecoder();
 		}
@@ -666,6 +756,7 @@ Image::ImageDecoder *Frame::getImageFrom(uint16 spriteId) {
 			byte buf[1024];
 			int n = s->read(buf, 1024);
 			Common::hexdump(buf, n);
+			s->seek(0);
 		}
 
 		img->loadStream(*pic);
@@ -683,17 +774,26 @@ Image::ImageDecoder *Frame::getImageFrom(uint16 spriteId) {
 }
 
 
-void Frame::renderText(Graphics::ManagedSurface &surface, uint16 spriteID) {
-	uint16 castID = _sprites[spriteID]->_castId;
-
-	TextCast *textCast = static_cast<TextCast *>(_vm->_currentScore->_casts[castID]);
-	Common::SeekableSubReadStreamEndian *textStream;
+void Frame::renderText(Graphics::ManagedSurface &surface, uint16 spriteID, uint16 castID) {
+	Common::SeekableSubReadStreamEndian *textStream = NULL;
 
-	if (_vm->_currentScore->_movieArchive->hasResource(MKTAG('S','T','X','T'), castID + 1024)) {
-		textStream = _vm->_currentScore->_movieArchive->getResource(MKTAG('S','T','X','T'), castID + 1024);
-	} else {
+	if (_vm->_currentScore->_movieArchive->hasResource(MKTAG('S', 'T', 'X', 'T'), castID)) {
+		textStream = _vm->_currentScore->_movieArchive->getResource(MKTAG('S', 'T', 'X', 'T'), castID);
+	} else if (_vm->getSharedSTXT() != nullptr) {
 		textStream = _vm->getSharedSTXT()->getVal(spriteID + 1024);
 	}
+
+	renderText(surface, spriteID, textStream, false);
+}
+
+void Frame::renderText(Graphics::ManagedSurface &surface, uint16 spriteID, Common::SeekableSubReadStreamEndian *textStream, bool isButtonLabel) {
+	if (textStream == NULL) return; 
+	
+	uint16 castID = _sprites[spriteID]->_castId;
+	TextCast *textCast = static_cast<TextCast *>(_vm->_currentScore->_casts[castID]);
+
+	
+
 	uint32 unk1 = textStream->readUint32();
 	uint32 strLen = textStream->readUint32();
 	uint32 dataLen = textStream->readUint32();
@@ -711,11 +811,11 @@ void Frame::renderText(Graphics::ManagedSurface &surface, uint16 spriteID) {
 	if (strLen < 200)
 		debugC(3, kDebugText, "text: '%s'", text.c_str());
 
-	uint32 rectLeft = static_cast<TextCast *>(_sprites[spriteID]->_cast)->initialRect.left;
-	uint32 rectTop = static_cast<TextCast *>(_sprites[spriteID]->_cast)->initialRect.top;
+	uint32 rectLeft = textCast->initialRect.left;
+	uint32 rectTop = textCast->initialRect.top;
 
-	int x = _sprites[spriteID]->_startPoint.x + rectLeft;
-	int y = _sprites[spriteID]->_startPoint.y + rectTop;
+	int x = _sprites[spriteID]->_startPoint.x;// +rectLeft;
+	int y = _sprites[spriteID]->_startPoint.y;// +rectTop;
 	int height = _sprites[spriteID]->_height;
 	int width = _sprites[spriteID]->_width;
 
@@ -730,7 +830,11 @@ void Frame::renderText(Graphics::ManagedSurface &surface, uint16 spriteID) {
 
 	debugC(3, kDebugText, "renderText: x: %d y: %d w: %d h: %d font: '%s'", x, y, width, height, _vm->_wm->_fontMan->getFontName(macFont));
 
-	font->drawString(&surface, text, x, y, width, 0);
+	//TODO: the colour is wrong here... need to determine the correct colour for all versions!
+	font->drawString(&surface, text, x, y, width, (_sprites[spriteID]->_ink == kInkTypeReverse ? 255 : 0), (Graphics::TextAlign)textCast->textAlign);
+
+	if (isButtonLabel)
+		return;
 
 	if (textCast->borderSize != kSizeNone) {
 		uint16 size = textCast->borderSize;
@@ -884,10 +988,10 @@ void Frame::drawMatteSprite(Graphics::ManagedSurface &target, const Graphics::Su
 
 uint16 Frame::getSpriteIDFromPos(Common::Point pos) {
 	// Find first from top to bottom
-	for (uint16 i = _drawRects.size() - 1; i > 0; i--) {
-		if (_drawRects[i].contains(pos))
-			return i;
-	}
+	//TODO: THIS NEEDS TO BE REVERSED!
+	for (Common::HashMap<uint16, Common::Rect>::const_iterator dr = _drawRects.begin(); dr != _drawRects.end(); dr++)
+		if (dr->_value.contains(pos))
+			return dr->_key;
 
 	return 0;
 }
diff --git a/engines/director/frame.h b/engines/director/frame.h
index ce82fa5..29ae9dd 100644
--- a/engines/director/frame.h
+++ b/engines/director/frame.h
@@ -119,8 +119,10 @@ private:
 	void playTransition(Score *score);
 	void playSoundChannel();
 	void renderSprites(Graphics::ManagedSurface &surface, bool renderTrail);
-	void renderText(Graphics::ManagedSurface &surface, uint16 spriteId);
-	void renderButton(Graphics::ManagedSurface &surface, uint16 spriteId);
+	void renderText(Graphics::ManagedSurface &surface, uint16 spriteId, uint16 castID);
+	void renderText(Graphics::ManagedSurface &surface, uint16 spriteID, Common::SeekableSubReadStreamEndian *textStream, bool isButtonLabel);
+	void renderShape(Graphics::ManagedSurface &surface, uint16 spriteID);
+	void renderButton(Graphics::ManagedSurface &surface, uint16 spriteId, uint16 textId);
 	void readPaletteInfo(Common::SeekableSubReadStreamEndian &stream);
 	void readSprite(Common::SeekableSubReadStreamEndian &stream, uint16 offset, uint16 size);
 	void readMainChannels(Common::SeekableSubReadStreamEndian &stream, uint16 offset, uint16 size);
@@ -148,7 +150,7 @@ public:
 	uint8 _skipFrameFlag;
 	uint8 _blend;
 	Common::Array<Sprite *> _sprites;
-	Common::Array<Common::Rect > _drawRects;
+	Common::HashMap<uint16, Common::Rect> _drawRects;
 	DirectorEngine *_vm;
 };
 
diff --git a/engines/director/images.cpp b/engines/director/images.cpp
index 0ec84af..9b55402 100644
--- a/engines/director/images.cpp
+++ b/engines/director/images.cpp
@@ -201,4 +201,122 @@ bool BITDDecoder::loadStream(Common::SeekableReadStream &stream) {
 	return true;
 }
 
+/****************************
+* BITD V4+
+****************************/
+
+BITDDecoderV4::BITDDecoderV4(int w, int h) {
+	_surface = new Graphics::Surface();
+
+	// We make the surface pitch a multiple of 16.
+	int pitch = w;
+	if (w % 16)
+		pitch += 16 - (w % 16);
+
+	// HACK: Create a padded surface by adjusting w after create()
+	_surface->create(pitch, h, Graphics::PixelFormat::createFormatCLUT8());
+	_surface->w = w;
+
+	_palette = new byte[256 * 3];
+
+	_palette[0] = _palette[1] = _palette[2] = 0;
+	_palette[255 * 3 + 0] = _palette[255 * 3 + 1] = _palette[255 * 3 + 2] = 0xff;
+
+	_paletteColorCount = 2;
+}
+
+BITDDecoderV4::~BITDDecoderV4() {
+	destroy();
+}
+
+void BITDDecoderV4::destroy() {
+	_surface = 0;
+
+	delete[] _palette;
+	_palette = 0;
+	_paletteColorCount = 0;
+}
+
+void BITDDecoderV4::loadPalette(Common::SeekableReadStream &stream) {
+	// no op
+}
+
+bool BITDDecoderV4::loadStream(Common::SeekableReadStream &stream) {
+	int x = 0, y = 0;
+
+	// If the stream has exactly the required number of bits for this image,
+	// we assume it is uncompressed.
+	if (stream.size() * 8 == _surface->pitch * _surface->h) {
+		debugC(3, kDebugImages, "Skipping compression");
+		for (y = 0; y < _surface->h; y++) {
+			for (x = 0; x < _surface->pitch; ) {
+				byte color = stream.readByte();
+				for (int c = 0; c < 8; c++)
+					*((byte *)_surface->getBasePtr(x++, y)) = (color & (1 << (7 - c))) ? 0 : 0xff;
+			}
+		}
+
+		return true;
+	}
+
+	Common::Array<int> pixels;
+	pixels.reserve(4096);
+
+	while (!stream.eos()) {
+		int data = stream.readByte();
+		int len = data + 1;
+		if ((data & 0x80) != 0) {
+			len = ((data ^ 0xFF) & 0xff) + 2;
+			data = stream.readByte();
+			for (int p = 0; p < len; p++) {
+				pixels.push_back(data);
+				//*((byte *)_surface->getBasePtr(x, y)) = data;
+			}
+			//data = stream.readByte();
+		} else {
+			for (int p = 0; p < len; p++) {
+				data = stream.readByte();
+				pixels.push_back(data);
+			}
+		}
+		//if (bpp == 32 && pixels.Count % (w * 3) == 0)
+		//	source += 2;
+	}
+
+	if (pixels.size() > 0) {
+		//this needs to be calculated a lot earlier!
+		int bpp = pixels.size() / (_surface->w * _surface->h);
+		switch (bpp) {
+		case 1:
+			for (uint pix = 0; pix < pixels.size(); pix++) {
+				//this calculation is wrong.. need a demo with colours.
+				*((byte *)_surface->getBasePtr(x, y)) = 0xff - pixels[pix];
+				x++;
+				if (x == _surface->w) {
+					y++;
+					x = 0;
+				}
+			}
+			break;
+		/*
+		case 32:
+			SetPixel(x, y, Color.FromArgb(
+			pixels[((y * dxr.nodes[c].w) * 3) + x],
+			pixels[(((y * dxr.nodes[c].w) * 3) + (dxr.nodes[c].w)) + x],
+			pixels[(((y * dxr.nodes[c].w) * 3) + (2 * dxr.nodes[c].w)) + x]));
+			break;
+		case 16:
+			SetPixel(x, y, Color.FromArgb(
+			(pixels[((y * dxr.nodes[c].w) * 2) + x] & 0x7c) << 1,
+			(pixels[((y * dxr.nodes[c].w) * 2) + x] & 0x03) << 6 |
+			(pixels[((y * dxr.nodes[c].w) * 2) + (dxr.nodes[c].w) + x] & 0xe0) >> 2,
+			(pixels[((y * dxr.nodes[c].w) * 2) + (dxr.nodes[c].w) + x] & 0x1f) << 3));
+			break;
+		*/
+		}
+	}
+
+	return true;
+}
+
 } // End of namespace Director
diff --git a/engines/director/images.h b/engines/director/images.h
index 54e8245..3be0e11 100644
--- a/engines/director/images.h
+++ b/engines/director/images.h
@@ -81,6 +81,25 @@ private:
 	uint8 _paletteColorCount;
 };
 
+class BITDDecoderV4 : public Image::ImageDecoder {
+public:
+	BITDDecoderV4(int w, int h);
+	virtual ~BITDDecoderV4();
+
+	// ImageDecoder API
+	void destroy();
+	virtual bool loadStream(Common::SeekableReadStream &stream);
+	virtual const Graphics::Surface *getSurface() const { return _surface; }
+	const byte *getPalette() const { return _palette; }
+	void loadPalette(Common::SeekableReadStream &stream);
+	uint16 getPaletteColorCount() const { return _paletteColorCount; }
+
+private:
+	Graphics::Surface *_surface;
+	byte *_palette;
+	uint8 _paletteColorCount;
+};
+
 } // End of namespace Director
 
 #endif
diff --git a/engines/director/sprite.h b/engines/director/sprite.h
index d248036..d9b7729 100644
--- a/engines/director/sprite.h
+++ b/engines/director/sprite.h
@@ -106,7 +106,8 @@ public:
 	uint32 _unk3;
 
 	bool _enabled;
-	byte _castId;
+	uint16 _castId;
+	byte _spriteType;
 	InkType _ink;
 	uint16 _trails;
 	Cast *_cast;


Commit: 2e64b2202da4833fd4c2d5040599a8a3b7460dc5
    https://github.com/scummvm/scummvm/commit/2e64b2202da4833fd4c2d5040599a8a3b7460dc5
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2017-01-09T00:54:27+01:00

Commit Message:
Merge pull request #887 from stevenhoefel/master

DIRECTOR: Support for D4 cast and images

Changed paths:
    engines/director/archive.cpp
    engines/director/archive.h
    engines/director/cast.cpp
    engines/director/cast.h
    engines/director/director.h
    engines/director/frame.cpp
    engines/director/frame.h
    engines/director/images.cpp
    engines/director/images.h
    engines/director/lingo/lingo-builtins.cpp
    engines/director/lingo/lingo-funcs.cpp
    engines/director/lingo/lingo.h
    engines/director/resource.cpp
    engines/director/score.cpp
    engines/director/score.h
    engines/director/sound.cpp
    engines/director/sound.h
    engines/director/sprite.h
    graphics/macgui/macwindowmanager.cpp
    graphics/macgui/macwindowmanager.h







More information about the Scummvm-git-logs mailing list