[Scummvm-git-logs] scummvm master -> 60fd2c4ed3ac00c138940ccb6dac26cb86964668

mduggan noreply at scummvm.org
Sat Feb 11 09:09:00 UTC 2023


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:
b181fb344e TETRAEDGE: Implement more functions for Syberia 2
c0ae694d0f TETRAEDGE: Add xml parsing features for Syberia 2
8688b32625 TETRAEDGE: Implement a few more lua callbacks for Syberia 2
543657e1a0 TETRAEDGE: Revert color scaling hack now TGL is fixed
60fd2c4ed3 TETRAEDGE: Many fixes for Syberia 2 scene loading


Commit: b181fb344ef663daeb77b82434585f0843371b0f
    https://github.com/scummvm/scummvm/commit/b181fb344ef663daeb77b82434585f0843371b0f
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-02-11T18:08:28+09:00

Commit Message:
TETRAEDGE: Implement more functions for Syberia 2

Changed paths:
    engines/tetraedge/game/documents_browser.cpp
    engines/tetraedge/game/documents_browser.h
    engines/tetraedge/game/in_game_scene.cpp
    engines/tetraedge/game/lua_binds.cpp
    engines/tetraedge/game/object3d.h


diff --git a/engines/tetraedge/game/documents_browser.cpp b/engines/tetraedge/game/documents_browser.cpp
index dea5f663947..f4d2a9bef77 100644
--- a/engines/tetraedge/game/documents_browser.cpp
+++ b/engines/tetraedge/game/documents_browser.cpp
@@ -165,6 +165,18 @@ bool DocumentsBrowser::onZoomedButton() {
 	return false;
 }
 
+int DocumentsBrowser::addDocument(Document *document) {
+	error("TODO: Implement DocumentsBrowser::addDocument");
+}
+
+void DocumentsBrowser::addDocument(const Common::String &str) {
+	Document *doc = new Document(this);
+	doc->load(str);
+	if (!addDocument(doc))
+		delete doc;
+}
+
+
 void DocumentsBrowser::showDocument(const Common::String &docName, int startPage) {
 	_curPage = startPage;
 	_startPage = startPage;
diff --git a/engines/tetraedge/game/documents_browser.h b/engines/tetraedge/game/documents_browser.h
index f438fd17afb..eadf96b0a8c 100644
--- a/engines/tetraedge/game/documents_browser.h
+++ b/engines/tetraedge/game/documents_browser.h
@@ -32,7 +32,7 @@ class DocumentsBrowser : public TeLayout {
 public:
 	DocumentsBrowser();
 
-	void addDocument(Document *document);
+	int addDocument(Document *document);
 	void addDocument(const Common::String &str);
 
 	void currentPage(int page);
diff --git a/engines/tetraedge/game/in_game_scene.cpp b/engines/tetraedge/game/in_game_scene.cpp
index f86627a3069..5b48c25092c 100644
--- a/engines/tetraedge/game/in_game_scene.cpp
+++ b/engines/tetraedge/game/in_game_scene.cpp
@@ -1182,13 +1182,14 @@ void InGameScene::update() {
 			obj->model()->setPosition(trans);
 		}
 		if (obj->_rotateTime >= 0) {
-			// Never actually used in the game.
-			error("TODO: handle _rotateTime > 0 in InGameScene::update");
+			float time = MIN((float)(obj->_rotateTimer.getTimeFromStart() / 1000000.0), obj->_rotateTime);
+			TeVector3f32 rot = (obj->_rotateAmount * (time / obj->_rotateTime));
+			TeQuaternion rotq = TeQuaternion::fromEuler(rot);
+			obj->model()->setRotation(obj->_rotateStart * rotq);
 		}
 	}
 }
 
-
 bool InGameScene::AnimObject::onFinished() {
 	Game *game = g_engine->getGame();
 	for (uint i = 0; i < game->yieldedCallbacks().size(); i++) {
diff --git a/engines/tetraedge/game/lua_binds.cpp b/engines/tetraedge/game/lua_binds.cpp
index e73ba461535..bb13f8e7017 100644
--- a/engines/tetraedge/game/lua_binds.cpp
+++ b/engines/tetraedge/game/lua_binds.cpp
@@ -206,6 +206,24 @@ static int tolua_ExportedFunctions_TakeObject00(lua_State *L) {
 	error("#ferror in function 'TakeObject': %d %d %s", err.index, err.array, err.type);
 }
 
+static void TakeObjectInHand(const Common::String &obj) {
+	Game *game = g_engine->getGame();
+	// TODO: Set global _lastHitObjectName?? How is it used?
+	//game->luaContext().setGlobal(_lastHitObjectName, true);
+	if (!obj.empty())
+		game->addToHand(obj);
+}
+
+static int tolua_ExportedFunctions_TakeObjectInHand00(lua_State *L) {
+	tolua_Error err;
+	if (tolua_isstring(L, 1, 0, &err) && tolua_isnoobj(L, 2, &err)) {
+		Common::String s1(tolua_tostring(L, 1, nullptr));
+		TakeObjectInHand(s1);
+		return 0;
+	}
+	error("#ferror in function 'TakeObjectInHand': %d %d %s", err.index, err.array, err.type);
+}
+
 static void RemoveObject(const Common::String &obj) {
 	Game *game = g_engine->getGame();
 	game->inventory().removeObject(obj);
@@ -267,6 +285,35 @@ static int tolua_ExportedFunctions_ShowDocument00(lua_State *L) {
 	error("#ferror in function 'ShowDocument': %d %d %s", err.index, err.array, err.type);
 }
 
+static void HideDocument() {
+	Game *game = g_engine->getGame();
+	game->documentsBrowser().hideDocument();
+}
+
+static int tolua_ExportedFunctions_HideDocument00(lua_State *L) {
+	tolua_Error err;
+	if (tolua_isnoobj(L, 1, &err)) {
+		HideDocument();
+		return 0;
+	}
+	error("#ferror in function 'HideDocument': %d %d %s", err.index, err.array, err.type);
+}
+
+static void AddDocument(const Common::String &name) {
+	Game *game = g_engine->getGame();
+	game->documentsBrowser().addDocument(name);
+}
+
+static int tolua_ExportedFunctions_AddDocument00(lua_State *L) {
+	tolua_Error err;
+	if (tolua_isstring(L, 1, 0, &err) && tolua_isnoobj(L, 2, &err)) {
+		Common::String s1(tolua_tostring(L, 1, nullptr));
+		AddDocument(s1);
+		return 0;
+	}
+	error("#ferror in function 'AddDocument': %d %d %s", err.index, err.array, err.type);
+}
+
 static void AddUnrecalAnim(const Common::String &newanim) {
 	Application *app = g_engine->getApplication();
 	Common::Array<Common::String> &anims = app->unrecalAnims();
@@ -457,6 +504,51 @@ static int tolua_ExportedFunctions_AddCallbackPlayer00(lua_State *L) {
 	error("#ferror in function 'AddCallbackPlayer': %d %d %s", err.index, err.array, err.type);
 }
 
+static void DeleteCallback(const Common::String &charName, const Common::String &animName, const Common::String &fnName, float triggerFrame) {
+	Game *game = g_engine->getGame();
+	Character *c = game->scene().character(charName);
+	if (c) {
+		c->deleteCallback(animName, fnName, triggerFrame);
+	} else {
+		warning("[DeleteCallback] Character's \"%s\" doesn't exist", charName.c_str());
+	}
+}
+
+static int tolua_ExportedFunctions_DeleteCallback00(lua_State *L) {
+	tolua_Error err;
+	if (tolua_isstring(L, 1, 0, &err) && tolua_isstring(L, 2, 0, &err)
+			&& tolua_isstring(L, 3, 0, &err) && tolua_isnumber(L, 4, 0, &err)
+			&& tolua_isnoobj(L, 5, &err)) {
+		Common::String s1(tolua_tostring(L, 1, nullptr));
+		Common::String s2(tolua_tostring(L, 2, nullptr));
+		Common::String s3(tolua_tostring(L, 3, nullptr));
+		double n1 = tolua_tonumber(L, 4, 0.0);
+		DeleteCallback(s1, s2, s3, n1);
+		return 0;
+	}
+	error("#ferror in function 'DeleteCallback': %d %d %s", err.index, err.array, err.type);
+}
+
+static void DeleteCallbackPlayer(const Common::String &animName, const Common::String &fnName, float triggerFrame) {
+	Game *game = g_engine->getGame();
+	Character *c = game->scene()._character;
+	assert(c);
+	c->deleteCallback(animName, fnName, triggerFrame);
+}
+
+static int tolua_ExportedFunctions_DeleteCallbackPlayer00(lua_State *L) {
+	tolua_Error err;
+	if (tolua_isstring(L, 1, 0, &err) && tolua_isstring(L, 2, 0, &err)
+			&& tolua_isnumber(L, 3, 0, &err) && tolua_isnoobj(L, 4, &err)) {
+		Common::String s2(tolua_tostring(L, 1, nullptr));
+		Common::String s3(tolua_tostring(L, 2, nullptr));
+		double n1 = tolua_tonumber(L, 3, 0.0);
+		DeleteCallbackPlayer(s2, s3, n1);
+		return 0;
+	}
+	error("#ferror in function 'DeleteCallbackPlayer': %d %d %s", err.index, err.array, err.type);
+}
+
 static void AddMarker(const Common::String &markerName, const Common::String &imgPath, float x, float y,
 				const Common::String &loctype, const Common::String &markerVal) {
 	Game *game = g_engine->getGame();
@@ -1007,6 +1099,34 @@ static int tolua_ExportedFunctions_TranslateGroundObject00(lua_State *L) {
 	error("#ferror in function 'TranslateGroundObject': %d %d %s", err.index, err.array, err.type);
 }
 
+static void RotateGroundObject(const Common::String &name, float x, float y, float z, float time) {
+	Game *game = g_engine->getGame();
+	Object3D *obj = game->scene().object3D(name);
+	if (!obj)
+		error("[RotateGroundObject] Object not found %s", name.c_str());
+	TeQuaternion rot = obj->model()->rotation();
+	obj->_rotateStart = rot;
+	obj->_rotateAmount = TeVector3f32(x, y, z);
+	obj->_rotateTimer.start();
+	obj->_rotateTime = time;
+}
+
+static int tolua_ExportedFunctions_RotateGroundObject00(lua_State *L) {
+	tolua_Error err;
+	if (tolua_isstring(L, 1, 0, &err) && tolua_isnumber(L, 2, 0, &err)
+		&& tolua_isnumber(L, 3, 0, &err) && tolua_isnumber(L, 4, 0, &err)
+		&& tolua_isnumber(L, 5, 0, &err) && tolua_isnoobj(L, 6, &err)) {
+		Common::String s1(tolua_tostring(L, 1, nullptr));
+		float f1 = tolua_tonumber(L, 2, 0.0);
+		float f2 = tolua_tonumber(L, 3, 0.0);
+		float f3 = tolua_tonumber(L, 4, 0.0);
+		float f4 = tolua_tonumber(L, 5, 0.0);
+		RotateGroundObject(s1, f1, f2, f3, f4);
+		return 0;
+	}
+	error("#ferror in function 'RotateGroundObject': %d %d %s", err.index, err.array, err.type);
+}
+
 static void EnableLight(uint lightno, bool enable) {
 	Game *game = g_engine->getGame();
 	if (lightno > game->scene().lights().size()) {
@@ -2150,14 +2270,14 @@ void LuaOpenBinds(lua_State *L) {
 	tolua_function(L, "SetSoundStep", tolua_ExportedFunctions_SetSoundStep00);
 	tolua_function(L, "Selected", tolua_ExportedFunctions_Selected00);
 	tolua_function(L, "TakeObject", tolua_ExportedFunctions_TakeObject00);
-	// tolua_function(L, "TakeObjectInHand", tolua_ExportedFunctions_TakeObjectInHand00); // Unused
+	tolua_function(L, "TakeObjectInHand", tolua_ExportedFunctions_TakeObjectInHand00); // Only used in Syberia 2
 	tolua_function(L, "RemoveObject", tolua_ExportedFunctions_RemoveObject00);
 	tolua_function(L, "RemoveObject", tolua_ExportedFunctions_RemoveObject01);
 	tolua_function(L, "AddNumber", tolua_ExportedFunctions_AddNumber00);
 	tolua_function(L, "ShowDocument", tolua_ExportedFunctions_ShowDocument00);
 	// tolua_function(L, "ShowDocumentAndWaitForEnd", tolua_ExportedFunctions_ShowDocumentAndWaitForEnd00); // Unused
-	// tolua_function(L, "HideDocument", tolua_ExportedFunctions_HideDocument00); // Unused
-	// tolua_function(L, "AddDocument", tolua_ExportedFunctions_AddDocument00); // Unused
+	tolua_function(L, "HideDocument", tolua_ExportedFunctions_HideDocument00); // Only used in Syberia 2
+	tolua_function(L, "AddDocument", tolua_ExportedFunctions_AddDocument00); // Only used in Syberia 2
 	tolua_function(L, "LoadCharacter", tolua_ExportedFunctions_LoadCharacter00);
 	tolua_function(L, "UnloadCharacter", tolua_ExportedFunctions_UnloadCharacter00);
 	// tolua_function(L, "GetRotationCharacter", tolua_ExportedFunctions_GetRotationCharacter00); // Unused
@@ -2193,8 +2313,8 @@ void LuaOpenBinds(lua_State *L) {
 	tolua_function(L, "AddCallback", tolua_ExportedFunctions_AddCallback00);
 	tolua_function(L, "AddCallbackPlayer", tolua_ExportedFunctions_AddCallbackPlayer00);
 	// tolua_function(L, "AddCallbackAnimation2D", tolua_ExportedFunctions_AddCallbackAnimation2D00); // Unused
-	// tolua_function(L, "DeleteCallback", tolua_ExportedFunctions_DeleteCallback00); // Unused
-	// tolua_function(L, "DeleteCallbackPlayer", tolua_ExportedFunctions_DeleteCallbackPlayer00); // Unused
+	tolua_function(L, "DeleteCallback", tolua_ExportedFunctions_DeleteCallback00); // Only used in Syberia 2
+	tolua_function(L, "DeleteCallbackPlayer", tolua_ExportedFunctions_DeleteCallbackPlayer00); // Only used in Syberia 2
 	// tolua_function(L, "DeleteCallbackAnimation2D", tolua_ExportedFunctions_DeleteCallbackAnimation2D00); // Unused
 	tolua_function(L, "SetObjectOnCharacter", tolua_ExportedFunctions_SetObjectOnCharacter00);
 	tolua_function(L, "SetObjectRotation", tolua_ExportedFunctions_SetObjectRotation00);
@@ -2206,7 +2326,7 @@ void LuaOpenBinds(lua_State *L) {
 	tolua_function(L, "SetGroundObjectPosition", tolua_ExportedFunctions_SetGroundObjectPosition00);
 	tolua_function(L, "SetGroundObjectRotation", tolua_ExportedFunctions_SetGroundObjectRotation00);
 	tolua_function(L, "TranslateGroundObject", tolua_ExportedFunctions_TranslateGroundObject00);
-	// tolua_function(L, "RotateGroundObject", tolua_ExportedFunctions_RotateGroundObject00); // Unused
+	tolua_function(L, "RotateGroundObject", tolua_ExportedFunctions_RotateGroundObject00); // Only used in Syberia 2
 	// tolua_function(L, "SetLightPlayerCharacter", tolua_ExportedFunctions_SetLightPlayerCharacter00); // Unused
 	// tolua_function(L, "SetLightPos", tolua_ExportedFunctions_SetLightPos00); // Unused
 	tolua_function(L, "EnableLight", tolua_ExportedFunctions_EnableLight00);
@@ -2251,6 +2371,29 @@ void LuaOpenBinds(lua_State *L) {
 	tolua_function(L, "EnableRunMode", tolua_ExportedFunctions_EnableRunMode00);
 	tolua_function(L, "SetModelPlayer", tolua_ExportedFunctions_SetModelPlayer00);
 
+	// TODO Syberia 2 functions..
+	//tolua_function(L,"BlendCharacterPlayerAnimation", tolua_ExportedFunctions_BlendCharacterPlayerAnimation00);
+	//tolua_function(L,"CurrentCharacterPlayerAnimation", tolua_ExportedFunctions_CurrentCharacterPlayerAnimation00);
+	//tolua_function(L,"SetCharacterPlayerRotation", tolua_ExportedFunctions_SetCharacterPlayerRotation00);
+	//tolua_function(L,"SetCharacterPlayerPosition", tolua_ExportedFunctions_SetCharacterPlayerPosition00);
+	//tolua_function(L,"PlaySnow", tolua_ExportedFunctions_PlaySnow00);
+	//tolua_function(L,"PlaySnowCustom", tolua_ExportedFunctions_PlaySnowCustom00);
+	//tolua_function(L,"SnowCustomVisible", tolua_ExportedFunctions_SnowCustomVisible00);
+	//tolua_function(L,"AddUnlockedAnim", tolua_ExportedFunctions_AddUnlockedAnim00);
+	//tolua_function(L,"RemoveRandomSound", tolua_ExportedFunctions_RemoveRandomSound00);
+	//tolua_function(L,"SetCharacterPlayerAnimation", tolua_ExportedFunctions_SetCharacterPlayerAnimation00);
+	//tolua_function(L,"SetYoukiFollowKate", tolua_ExportedFunctions_SetYoukiFollowKate00);
+	//tolua_function(L,"PlaySmoke", tolua_ExportedFunctions_PlaySmoke00);
+	//tolua_function(L,"SmokeVisible", tolua_ExportedFunctions_SmokeVisible00);
+	//tolua_function(L,"ActivateMask", tolua_ExportedFunctions_ActivateMask00);
+	//tolua_function(L,"AddRandomAnimation", tolua_ExportedFunctions_AddRandomAnimation00);
+	//tolua_function(L,"PlayRandomAnimation", tolua_ExportedFunctions_PlayRandomAnimation00);
+	//tolua_function(L,"SetObjectMoveDest", tolua_ExportedFunctions_SetObjectMoveDest00);
+	//tolua_function(L,"SetObjectMoveTime", tolua_ExportedFunctions_SetObjectMoveTime00);
+	//tolua_function(L,"PlayVerticalScrolling", tolua_ExportedFunctions_PlayVerticalScrolling00);
+	//tolua_function(L,"GetParticleIndex", tolua_GetParticleIndex);
+	//tolua_function(L,"EnableParticle", tolua_EnableParticle);
+
 	tolua_endmodule(L);
 }
 
diff --git a/engines/tetraedge/game/object3d.h b/engines/tetraedge/game/object3d.h
index 1cf9ef28343..c3bff423aef 100644
--- a/engines/tetraedge/game/object3d.h
+++ b/engines/tetraedge/game/object3d.h
@@ -54,7 +54,7 @@ public:
 
 	float _rotateTime;
 	TeTimer _rotateTimer;
-	TeVector3f32 _rotateStart;
+	TeQuaternion _rotateStart;
 	TeVector3f32 _rotateAmount;
 
 	float _translateTime;


Commit: c0ae694d0f4571453d59c9d8bc5c526c648afa2c
    https://github.com/scummvm/scummvm/commit/c0ae694d0f4571453d59c9d8bc5c526c648afa2c
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-02-11T18:08:28+09:00

Commit Message:
TETRAEDGE: Add xml parsing features for Syberia 2

Changed paths:
    engines/tetraedge/game/character_settings_xml_parser.cpp
    engines/tetraedge/game/character_settings_xml_parser.h
    engines/tetraedge/game/object_settings_xml_parser.cpp
    engines/tetraedge/game/object_settings_xml_parser.h


diff --git a/engines/tetraedge/game/character_settings_xml_parser.cpp b/engines/tetraedge/game/character_settings_xml_parser.cpp
index abb8fc55d68..0ced45aa8d9 100644
--- a/engines/tetraedge/game/character_settings_xml_parser.cpp
+++ b/engines/tetraedge/game/character_settings_xml_parser.cpp
@@ -132,6 +132,11 @@ bool CharacterSettingsXmlParser::parserCallback_body(ParserNode *node) {
 	return true;
 }
 
+bool CharacterSettingsXmlParser::parserCallback_invertNormals(ParserNode *node) {
+	_curCharacter->_invertNormals = true;
+	return true;
+}
+
 bool CharacterSettingsXmlParser::textCallback(const Common::String &val) {
 	switch (_curTextTag) {
 	case TagModelFileName:
@@ -164,4 +169,9 @@ bool CharacterSettingsXmlParser::textCallback(const Common::String &val) {
 	return true;
 }
 
+bool CharacterSettingsXmlParser::handleUnknownKey(ParserNode *node) {
+	warning("TODO: CharacterSettingsXmlParser handle unknown key %s", node->name.c_str());
+	return true;
+}
+
 } // end namespace Tetraedge
diff --git a/engines/tetraedge/game/character_settings_xml_parser.h b/engines/tetraedge/game/character_settings_xml_parser.h
index f7b41b58402..919135a8ea3 100644
--- a/engines/tetraedge/game/character_settings_xml_parser.h
+++ b/engines/tetraedge/game/character_settings_xml_parser.h
@@ -43,6 +43,8 @@ public:
 				KEY_END()
 				XML_KEY(defaultScale)
 				KEY_END()
+				XML_KEY(invertNormals)
+				KEY_END()
 				XML_KEY(walk)
 					XML_KEY(animationFileName)
 					KEY_END()
@@ -60,9 +62,13 @@ public:
 						KEY_END()
 						XML_KEY(endD)
 							XML_PROP(file, true)
+							XML_PROP(stepRight, false)
+							XML_PROP(stepLeft, false)
 						KEY_END()
 						XML_KEY(endG)
 							XML_PROP(file, true)
+							XML_PROP(stepRight, false)
+							XML_PROP(stepLeft, false)
 						KEY_END()
 					KEY_END()
 					XML_KEY(speed)
@@ -105,7 +111,10 @@ public:
 	bool parserCallback_eyes(ParserNode *node);
 	bool parserCallback_mouth(ParserNode *node);
 	bool parserCallback_body(ParserNode *node);
+	bool parserCallback_invertNormals(ParserNode *node);
+
 	bool textCallback(const Common::String &val) override;
+	bool handleUnknownKey(ParserNode *node) override;
 
 private:
 	Character::AnimSettings parseWalkAnimSettings(const ParserNode *node) const;
diff --git a/engines/tetraedge/game/object_settings_xml_parser.cpp b/engines/tetraedge/game/object_settings_xml_parser.cpp
index d5d617212b8..df1f6455faa 100644
--- a/engines/tetraedge/game/object_settings_xml_parser.cpp
+++ b/engines/tetraedge/game/object_settings_xml_parser.cpp
@@ -51,6 +51,16 @@ bool ObjectSettingsXmlParser::parserCallback_defaultScale(ParserNode *node) {
 	return true;
 }
 
+bool ObjectSettingsXmlParser::parserCallback_originOffset(ParserNode *node) {
+	_textTagType = TagOriginOffset;
+	return true;
+}
+
+bool ObjectSettingsXmlParser::parserCallback_invertNormals(ParserNode *node) {
+	_curObject._invertNormals = true;
+	return true;
+}
+
 bool ObjectSettingsXmlParser::textCallback(const Common::String &val) {
 	switch (_textTagType) {
 		case TagModelFileName:
@@ -63,6 +73,13 @@ bool ObjectSettingsXmlParser::textCallback(const Common::String &val) {
 				warning("Failed to parse Object defaultScale from %s", val.c_str());
 			break;
 		}
+		case TagOriginOffset:
+		{
+			bool result = _curObject._originOffset.parse(val);
+			if (!result)
+				warning("Failed to parse Object originOffset from %s", val.c_str());
+			break;
+		}
 		default:
 			error("should only see text for model file name or scale");
 	}
diff --git a/engines/tetraedge/game/object_settings_xml_parser.h b/engines/tetraedge/game/object_settings_xml_parser.h
index 328b4a04236..52b87d7231b 100644
--- a/engines/tetraedge/game/object_settings_xml_parser.h
+++ b/engines/tetraedge/game/object_settings_xml_parser.h
@@ -45,6 +45,10 @@ public:
 				KEY_END()
 				XML_KEY(defaultScale)
 				KEY_END()
+				XML_KEY(originOffset)
+				KEY_END()
+				XML_KEY(invertNormals)
+				KEY_END()
 			KEY_END()
 		KEY_END()
 	} PARSER_END()
@@ -55,11 +59,14 @@ private:
 	bool parserCallback_Object(ParserNode *node);
 	bool parserCallback_modelFileName(ParserNode *node);
 	bool parserCallback_defaultScale(ParserNode *node);
+	bool parserCallback_originOffset(ParserNode *node);
+	bool parserCallback_invertNormals(ParserNode *node);
 	bool textCallback(const Common::String &val) override;
 
 	enum TextTagType {
 		TagModelFileName,
-		TagDefaultScale
+		TagDefaultScale,
+		TagOriginOffset
 	};
 
 	TextTagType _textTagType;


Commit: 8688b32625023b8a22ab51cfbaf1ffb4f7a75660
    https://github.com/scummvm/scummvm/commit/8688b32625023b8a22ab51cfbaf1ffb4f7a75660
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-02-11T18:08:29+09:00

Commit Message:
TETRAEDGE: Implement a few more lua callbacks for Syberia 2

Changed paths:
    engines/tetraedge/game/in_game_scene.cpp
    engines/tetraedge/game/lua_binds.cpp


diff --git a/engines/tetraedge/game/in_game_scene.cpp b/engines/tetraedge/game/in_game_scene.cpp
index 5b48c25092c..22ef1940d21 100644
--- a/engines/tetraedge/game/in_game_scene.cpp
+++ b/engines/tetraedge/game/in_game_scene.cpp
@@ -1175,7 +1175,6 @@ void InGameScene::update() {
 	}
 
 	for (Object3D *obj : _object3Ds) {
-		// TODO: update object3ds if they are translating or rotating.
 		if (obj->_translateTime >= 0) {
 			float time = MIN((float)(obj->_translateTimer.getTimeFromStart() / 1000000.0), obj->_translateTime);
 			TeVector3f32 trans = obj->_translateStart + (obj->_translateAmount * (time / obj->_translateTime));
diff --git a/engines/tetraedge/game/lua_binds.cpp b/engines/tetraedge/game/lua_binds.cpp
index bb13f8e7017..7b29235c5d1 100644
--- a/engines/tetraedge/game/lua_binds.cpp
+++ b/engines/tetraedge/game/lua_binds.cpp
@@ -84,7 +84,7 @@ static void PlayMovie(const Common::String &vidpath, const Common::String &music
 
 static void PlayMovie(const Common::String &vidpath, const Common::String &musicpath, double f) {
 	Game *game = g_engine->getGame();
-	warning("TODO: handle float value in PlayMovie for Syberia 2");
+	warning("TODO: handle float value %f in PlayMovie for Syberia 2", f);
 
 	if (!game->playMovie(vidpath, musicpath)) {
 		warning("[PlayMovie] Movie \"%s\" doesn\'t exist.", vidpath.c_str());
@@ -435,7 +435,7 @@ static int tolua_ExportedFunctions_SetRunMode200(lua_State *L) {
 		SetRunMode2(s1, s2);
 		return 0;
 	}
-	error("#ferror in function 'AddMarker': %d %d %s", err.index, err.array, err.type);
+	error("#ferror in function 'SetRunMode2': %d %d %s", err.index, err.array, err.type);
 }
 
 static void SetCharacterShadow(const Common::String &charName, bool val) {
@@ -560,13 +560,20 @@ static int tolua_ExportedFunctions_AddMarker00(lua_State *L) {
 	if (tolua_isstring(L, 1, 0, &err) && tolua_isstring(L, 2, 0, &err)
 			&& tolua_isnumber(L, 3, 0, &err) && tolua_isnumber(L, 4, 0, &err)
 			&& tolua_isstring(L, 5, 1, &err) && tolua_isstring(L, 6, 1, &err)
-			&& tolua_isnoobj(L, 7, &err)) {
+			&& tolua_isnumber(L, 7, 1, &err) && tolua_isnumber(L, 8, 1, &err)
+			&& tolua_isnoobj(L, 9, &err)) {
+		// Syberia 1 version
 		Common::String s1(tolua_tostring(L, 1, nullptr));
 		Common::String s2(tolua_tostring(L, 2, nullptr));
 		double n1 = tolua_tonumber(L, 3, 0.0);
 		double n2 = tolua_tonumber(L, 4, 0.0);
 		Common::String s3(tolua_tostring(L, 5, ""));
 		Common::String s4(tolua_tostring(L, 6, ""));
+		double n3 = tolua_tonumber(L, 7, 0.0);
+		double n4 = tolua_tonumber(L, 8, 0.0);
+		if (n3 || n4) {
+			warning("TODO: handle extra params for AddMarker %f %f", n3, n4);
+		}
 		AddMarker(s1, s2, n1, n2, s3, s4);
 		return 0;
 	}
@@ -2178,6 +2185,8 @@ static int tolua_ExportedFunctions_MoveCharacterPlayerTo00(lua_State *L) {
 }
 
 static void EnableRunMode(bool val) {
+	//Game *game = g_engine->getGame();
+	//game->setRunMode(val);
 	warning("TODO: EnableRunMode %s", val ? "true" : "false");
 }
 
@@ -2186,6 +2195,7 @@ static int tolua_ExportedFunctions_EnableRunMode00(lua_State *L) {
 	if (tolua_isboolean(L, 1, 0, &err) && tolua_isnoobj(L, 2, &err)) {
 		bool b1 = tolua_toboolean(L, 1, 0);
 		EnableRunMode(b1);
+		return 0;
 	}
 	error("#ferror in function 'EnableRunMode': %d %d %s", err.index, err.array, err.type);
 }
@@ -2213,10 +2223,120 @@ static int tolua_ExportedFunctions_SetModelPlayer00(lua_State *L) {
 	if (tolua_isstring(L, 1, 0, &err) && tolua_isnoobj(L, 2, &err)) {
 		Common::String s1(tolua_tostring(L, 1, 0));
 		SetModelPlayer(s1);
+		return 0;
 	}
 	error("#ferror in function 'SetModelPlayer': %d %d %s", err.index, err.array, err.type);
 }
 
+static void BlendCharacterPlayerAnimation(const Common::String &anim, float amount, bool repeat, bool returnToIdle) {
+	Game *game = g_engine->getGame();
+	Character *character = game->scene()._character;
+	if (character) {
+		character->blendAnimation(anim, amount, repeat, returnToIdle);
+	} else {
+		warning("[BlendCharacterPlayerAnimation] Character doesn't exist");
+	}
+
+}
+
+static int tolua_ExportedFunctions_BlendCharacterPlayerAnimation00(lua_State *L) {
+	tolua_Error err;
+	if (tolua_isstring(L, 1, 0, &err) && tolua_isnumber(L, 2, 0, &err)
+		&& tolua_isboolean(L, 3, 0, &err) && tolua_isboolean(L, 4, 0, &err)
+		&& tolua_isnoobj(L, 6, &err)) {
+		Common::String s1(tolua_tostring(L, 1, nullptr));
+		float f1 = tolua_tonumber(L, 2, 0.0);
+		float b1 = tolua_toboolean(L, 3, 0.0);
+		float b2 = tolua_toboolean(L, 4, 0.0);
+		BlendCharacterPlayerAnimation(s1, f1, b1, b2);
+		return 0;
+	}
+	error("#ferror in function 'BlendCharacterPlayerAnimation': %d %d %s", err.index, err.array, err.type);
+}
+
+static bool CurrentCharacterPlayerAnimation(const Common::String &anim) {
+	Game *game = g_engine->getGame();
+	Character *character = game->scene()._character;
+	if (character) {
+		return character->curAnimName() == anim;
+	} else {
+		warning("[CurrentCharacterPlayerAnimation] Character doesn't exist");
+		return false;
+	}
+}
+
+static int tolua_ExportedFunctions_CurrentCharacterPlayerAnimation00(lua_State *L) {
+	tolua_Error err;
+	if (tolua_isstring(L, 1, 0, &err) && tolua_isnoobj(L, 2, &err)) {
+		Common::String s1(tolua_tostring(L, 1, nullptr));
+		bool result = CurrentCharacterPlayerAnimation(s1);
+		tolua_pushboolean(L, result);
+		return 1;
+	}
+	error("#ferror in function 'CurrentCharacterPlayerAnimation': %d %d %s", err.index, err.array, err.type);
+}
+
+static void SetCharacterPlayerPosition(float x, float y, float z) {
+	Game *game = g_engine->getGame();
+	Character *character = game->scene()._character;
+	if (character) {
+		SetCharacterRotation(character->_model->name(), x, y, z);
+	}
+}
+
+static int tolua_ExportedFunctions_SetCharacterPlayerRotation00(lua_State *L) {
+	tolua_Error err;
+	if (tolua_isnumber(L, 1, 0, &err) && tolua_isnumber(L, 2, 0, &err)
+		&& tolua_isnumber(L, 3, 0, &err) && tolua_isnoobj(L, 4, &err)) {
+		float f1 = tolua_tonumber(L, 1, 0.0);
+		float f2 = tolua_tonumber(L, 2, 0.0);
+		float f3 = tolua_tonumber(L, 3, 0.0);
+		SetCharacterPlayerPosition(f1, f2, f3);
+		return 0;
+	}
+	error("#ferror in function 'SetCharacterPlayerRotation': %d %d %s", err.index, err.array, err.type);
+}
+
+static void SetCharacterPlayerPosition(const Common::String &zone, float x, float y, float z) {
+	Game *game = g_engine->getGame();
+	Character *character = game->scene()._character;
+	if (character) {
+		SetCharacterPosition(character->_model->name(), zone, x, y, z);
+	}
+}
+
+static int tolua_ExportedFunctions_SetCharacterPlayerPosition00(lua_State *L) {
+	tolua_Error err;
+	if (tolua_isstring(L, 1, 0, &err) && tolua_isnumber(L, 2, 0, &err)
+		&& tolua_isnumber(L, 2, 0, &err) && tolua_isnumber(L, 4, 0, &err)
+		&& tolua_isnoobj(L, 5, &err)) {
+		Common::String s1(tolua_tostring(L, 1, nullptr));
+		float f1 = tolua_tonumber(L, 2, 0.0);
+		float f2 = tolua_tonumber(L, 3, 0.0);
+		float f3 = tolua_tonumber(L, 4, 0.0);
+		SetCharacterPlayerPosition(s1, f1, f2, f3);
+		return 0;
+	}
+	error("#ferror in function 'SetCharacterPlayerPosition': %d %d %s", err.index, err.array, err.type);
+}
+
+static void AddUnlockedAnim(const Common::String &name) {
+	// Note: does nothing, but we needed to add it..
+}
+
+static int tolua_ExportedFunctions_AddUnlockedAnim00(lua_State *L) {
+	tolua_Error err;
+	if (tolua_isstring(L, 1, 0, &err) && tolua_isnoobj(L, 2, &err)) {
+		Common::String s1(tolua_tostring(L, 1, 0));
+		AddUnlockedAnim(s1);
+		return 0;
+	}
+	error("#ferror in function 'AddUnlockedAnim': %d %d %s", err.index, err.array, err.type);
+}
+
+
+
+
 // ////////////////////////////////////////////////////////////////////////
 
 
@@ -2370,29 +2490,29 @@ void LuaOpenBinds(lua_State *L) {
 	// Syberia 2 specific functions.
 	tolua_function(L, "EnableRunMode", tolua_ExportedFunctions_EnableRunMode00);
 	tolua_function(L, "SetModelPlayer", tolua_ExportedFunctions_SetModelPlayer00);
+	tolua_function(L, "BlendCharacterPlayerAnimation", tolua_ExportedFunctions_BlendCharacterPlayerAnimation00);
+	tolua_function(L, "CurrentCharacterPlayerAnimation", tolua_ExportedFunctions_CurrentCharacterPlayerAnimation00);
+	tolua_function(L, "SetCharacterPlayerRotation", tolua_ExportedFunctions_SetCharacterPlayerRotation00);
+	tolua_function(L, "SetCharacterPlayerPosition", tolua_ExportedFunctions_SetCharacterPlayerPosition00);
+	tolua_function(L, "AddUnlockedAnim", tolua_ExportedFunctions_AddUnlockedAnim00);
 
 	// TODO Syberia 2 functions..
-	//tolua_function(L,"BlendCharacterPlayerAnimation", tolua_ExportedFunctions_BlendCharacterPlayerAnimation00);
-	//tolua_function(L,"CurrentCharacterPlayerAnimation", tolua_ExportedFunctions_CurrentCharacterPlayerAnimation00);
-	//tolua_function(L,"SetCharacterPlayerRotation", tolua_ExportedFunctions_SetCharacterPlayerRotation00);
-	//tolua_function(L,"SetCharacterPlayerPosition", tolua_ExportedFunctions_SetCharacterPlayerPosition00);
-	//tolua_function(L,"PlaySnow", tolua_ExportedFunctions_PlaySnow00);
-	//tolua_function(L,"PlaySnowCustom", tolua_ExportedFunctions_PlaySnowCustom00);
-	//tolua_function(L,"SnowCustomVisible", tolua_ExportedFunctions_SnowCustomVisible00);
-	//tolua_function(L,"AddUnlockedAnim", tolua_ExportedFunctions_AddUnlockedAnim00);
-	//tolua_function(L,"RemoveRandomSound", tolua_ExportedFunctions_RemoveRandomSound00);
-	//tolua_function(L,"SetCharacterPlayerAnimation", tolua_ExportedFunctions_SetCharacterPlayerAnimation00);
-	//tolua_function(L,"SetYoukiFollowKate", tolua_ExportedFunctions_SetYoukiFollowKate00);
-	//tolua_function(L,"PlaySmoke", tolua_ExportedFunctions_PlaySmoke00);
-	//tolua_function(L,"SmokeVisible", tolua_ExportedFunctions_SmokeVisible00);
-	//tolua_function(L,"ActivateMask", tolua_ExportedFunctions_ActivateMask00);
-	//tolua_function(L,"AddRandomAnimation", tolua_ExportedFunctions_AddRandomAnimation00);
-	//tolua_function(L,"PlayRandomAnimation", tolua_ExportedFunctions_PlayRandomAnimation00);
-	//tolua_function(L,"SetObjectMoveDest", tolua_ExportedFunctions_SetObjectMoveDest00);
-	//tolua_function(L,"SetObjectMoveTime", tolua_ExportedFunctions_SetObjectMoveTime00);
-	//tolua_function(L,"PlayVerticalScrolling", tolua_ExportedFunctions_PlayVerticalScrolling00);
-	//tolua_function(L,"GetParticleIndex", tolua_GetParticleIndex);
-	//tolua_function(L,"EnableParticle", tolua_EnableParticle);
+	//tolua_function(L, "PlaySnow", tolua_ExportedFunctions_PlaySnow00);
+	//tolua_function(L, "PlaySnowCustom", tolua_ExportedFunctions_PlaySnowCustom00);
+	//tolua_function(L, "SnowCustomVisible", tolua_ExportedFunctions_SnowCustomVisible00);
+	//tolua_function(L, "RemoveRandomSound", tolua_ExportedFunctions_RemoveRandomSound00);
+	//tolua_function(L, "SetCharacterPlayerAnimation", tolua_ExportedFunctions_SetCharacterPlayerAnimation00);
+	//tolua_function(L, "SetYoukiFollowKate", tolua_ExportedFunctions_SetYoukiFollowKate00);
+	//tolua_function(L, "PlaySmoke", tolua_ExportedFunctions_PlaySmoke00);
+	//tolua_function(L, "SmokeVisible", tolua_ExportedFunctions_SmokeVisible00);
+	//tolua_function(L, "ActivateMask", tolua_ExportedFunctions_ActivateMask00);
+	//tolua_function(L, "AddRandomAnimation", tolua_ExportedFunctions_AddRandomAnimation00);
+	//tolua_function(L, "PlayRandomAnimation", tolua_ExportedFunctions_PlayRandomAnimation00);
+	//tolua_function(L, "SetObjectMoveDest", tolua_ExportedFunctions_SetObjectMoveDest00);
+	//tolua_function(L, "SetObjectMoveTime", tolua_ExportedFunctions_SetObjectMoveTime00);
+	//tolua_function(L, "PlayVerticalScrolling", tolua_ExportedFunctions_PlayVerticalScrolling00);
+	//tolua_function(L, "GetParticleIndex", tolua_GetParticleIndex);
+	//tolua_function(L, "EnableParticle", tolua_EnableParticle);
 
 	tolua_endmodule(L);
 }


Commit: 543657e1a0ee34bda4e22d4ddff3ee004d641971
    https://github.com/scummvm/scummvm/commit/543657e1a0ee34bda4e22d4ddff3ee004d641971
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-02-11T18:08:29+09:00

Commit Message:
TETRAEDGE: Revert color scaling hack now TGL is fixed

Changed paths:
    engines/tetraedge/te/te_renderer_tinygl.cpp


diff --git a/engines/tetraedge/te/te_renderer_tinygl.cpp b/engines/tetraedge/te/te_renderer_tinygl.cpp
index 055316911d9..a82b25a1055 100644
--- a/engines/tetraedge/te/te_renderer_tinygl.cpp
+++ b/engines/tetraedge/te/te_renderer_tinygl.cpp
@@ -160,13 +160,7 @@ void TeRendererTinyGL::renderTransparentMeshes() {
 	tglVertexPointer(3, TGL_FLOAT, sizeof(TeVector3f32), _transparentMeshVertexes.data());
 	tglNormalPointer(TGL_FLOAT, sizeof(TeVector3f32), _transparentMeshNormals.data());
 	tglTexCoordPointer(2, TGL_FLOAT, sizeof(TeVector2f32), _transparentMeshCoords.data());
-	// TinyGL doesn't correctly scale BYTE color data, so provide it pre-scaled.
-	Common::Array<float> colorVals(_transparentMeshColors.size() * 4);
-	const byte *coldata = reinterpret_cast<const byte *>(_transparentMeshColors.data());
-	for (unsigned int i = 0; i < colorVals.size(); i++) {
-		colorVals[i] = (float)coldata[i] / 255.0f;
-	}
-	tglColorPointer(4, TGL_FLOAT, sizeof(float) * 4, colorVals.data());
+	tglColorPointer(4, TGL_UNSIGNED_BYTE, sizeof(TeColor), _transparentMeshColors.data());
 
 	TeMaterial lastMaterial;
 	TeMatrix4x4 lastMatrix;


Commit: 60fd2c4ed3ac00c138940ccb6dac26cb86964668
    https://github.com/scummvm/scummvm/commit/60fd2c4ed3ac00c138940ccb6dac26cb86964668
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-02-11T18:08:29+09:00

Commit Message:
TETRAEDGE: Many fixes for Syberia 2 scene loading

Changed paths:
  A engines/tetraedge/game/in_game_scene_xml_parser.cpp
  A engines/tetraedge/game/in_game_scene_xml_parser.h
  A engines/tetraedge/te/te_camera_xml_parser.cpp
  A engines/tetraedge/te/te_camera_xml_parser.h
    engines/tetraedge/game/characters_shadow.cpp
    engines/tetraedge/game/game.cpp
    engines/tetraedge/game/in_game_scene.cpp
    engines/tetraedge/game/in_game_scene.h
    engines/tetraedge/game/lua_binds.cpp
    engines/tetraedge/module.mk
    engines/tetraedge/te/te_3d_object2.cpp
    engines/tetraedge/te/te_3d_object2.h
    engines/tetraedge/te/te_camera.cpp
    engines/tetraedge/te/te_camera.h
    engines/tetraedge/te/te_free_move_zone.cpp
    engines/tetraedge/te/te_free_move_zone.h
    engines/tetraedge/te/te_lua_thread.cpp
    engines/tetraedge/te/te_vector2f32.cpp
    engines/tetraedge/te/te_vector2f32.h


diff --git a/engines/tetraedge/game/characters_shadow.cpp b/engines/tetraedge/game/characters_shadow.cpp
index 14be1f105c4..0a13a353115 100644
--- a/engines/tetraedge/game/characters_shadow.cpp
+++ b/engines/tetraedge/game/characters_shadow.cpp
@@ -44,7 +44,7 @@ void CharactersShadow::create(InGameScene *scene) {
 	renderer->enableTexture();
 	_camera = new TeCamera();
 	_camera->setProjMatrixType(2);
-	_camera->setPerspectiveVal(1.0);
+	_camera->setAspectRatio(1.0);
 	_camera->setName("_shadowCam");
 	_camera->viewport(0, 0, _texSize, _texSize);
 
diff --git a/engines/tetraedge/game/game.cpp b/engines/tetraedge/game/game.cpp
index 905c540563d..ec69c08b21f 100644
--- a/engines/tetraedge/game/game.cpp
+++ b/engines/tetraedge/game/game.cpp
@@ -544,7 +544,14 @@ bool Game::initWarp(const Common::String &zone, const Common::String &scene, boo
 	_scene.hitObjectGui().unload();
 	Common::Path geomPath(Common::String::format("scenes/%s/Geometry%s.bin",
 												 zone.c_str(), zone.c_str()));
-	_scene.load(core->findFile(geomPath));
+	Common::FSNode geomFile = core->findFile(geomPath);
+	if (geomFile.isReadable()) {
+		// Syberia 1, load geom bin
+		_scene.load(geomFile);
+	} else {
+		// Syberia 2, load from xml
+		_scene.loadXml(zone, scene);
+	}
 	_scene.loadBackground(setLuaNode);
 
 	Application *app = g_engine->getApplication();
@@ -920,6 +927,7 @@ bool Game::onCharacterAnimationPlayerFinished(const Common::String &anim) {
 	}
 	if (callScripts) {
 		_luaScript.execute("OnCharacterAnimationFinished", "Kate");
+		_luaScript.execute("OnCharacterAnimationPlayerFinished", anim);
 		_luaScript.execute("OnCellCharacterAnimationPlayerFinished", anim);
 	}
 
diff --git a/engines/tetraedge/game/in_game_scene.cpp b/engines/tetraedge/game/in_game_scene.cpp
index 22ef1940d21..7d4418a6acf 100644
--- a/engines/tetraedge/game/in_game_scene.cpp
+++ b/engines/tetraedge/game/in_game_scene.cpp
@@ -28,6 +28,7 @@
 #include "tetraedge/game/billboard.h"
 #include "tetraedge/game/game.h"
 #include "tetraedge/game/in_game_scene.h"
+#include "tetraedge/game/in_game_scene_xml_parser.h"
 #include "tetraedge/game/character.h"
 #include "tetraedge/game/characters_shadow.h"
 #include "tetraedge/game/object3d.h"
@@ -47,6 +48,9 @@
 
 namespace Tetraedge {
 
+/*static*/
+bool InGameScene::_collisionSlide = false;
+
 InGameScene::InGameScene() : _character(nullptr), _charactersShadow(nullptr),
 _shadowLightNo(-1), _waitTime(-1.0f), _shadowColor(0, 0, 0, 0x80), _shadowFov(20.0f),
 _shadowFarPlane(1000), _shadowNearPlane(1)
@@ -90,14 +94,14 @@ void InGameScene::addAnchorZone(const Common::String &s1, const Common::String &
 	_anchorZones.push_back(zone);
 }
 
-bool InGameScene::addMarker(const Common::String &markerName, const Common::String &imgPath, float x, float y, const Common::String &locType, const Common::String &markerVal) {
+bool InGameScene::addMarker(const Common::String &markerName, const Common::String &imgPath, float x, float y, const Common::String &locType, const Common::String &markerVal, float anchorX, float anchorY) {
 	const TeMarker *marker = findMarker(markerName);
 	if (!marker) {
 		Game *game = g_engine->getGame();
 		TeSpriteLayout *markerSprite = new TeSpriteLayout();
 		// Note: game checks paths here but seems to just use the original?
 		markerSprite->setName(markerName);
-		markerSprite->setAnchor(TeVector3f32(0.0f, 0.0f, 0.0f));
+		markerSprite->setAnchor(TeVector3f32(anchorX, anchorY, 0.0f));
 		markerSprite->load(imgPath);
 		markerSprite->setSizeType(TeILayout::RELATIVE_TO_PARENT);
 		markerSprite->setPositionType(TeILayout::RELATIVE_TO_PARENT);
@@ -286,7 +290,7 @@ void InGameScene::deserializeCam(Common::ReadStream &stream, TeIntrusivePtr<TeCa
 	// load name/position/rotation/scale
 	Te3DObject2::deserialize(stream, *cam);
 	cam->setFov(stream.readFloatLE());
-	cam->setPerspectiveVal(stream.readFloatLE());
+	cam->setAspectRatio(stream.readFloatLE());
 	// Original loads the second val then ignores it and sets 3000.
 	cam->setOrthoPlanes(stream.readFloatLE(), 3000.0);
 	stream.readFloatLE();
@@ -440,6 +444,7 @@ void InGameScene::freeGeometry() {
 	_dummies.clear();
 	cameras().clear();
 	_zoneModels.clear();
+	_masks.clear();
 	if (_charactersShadow) {
 		delete _charactersShadow;
 		_charactersShadow = nullptr;
@@ -541,24 +546,9 @@ bool InGameScene::isObjectBlocking(const Common::String &name) {
 }
 
 bool InGameScene::load(const Common::FSNode &sceneNode) {
-	_actZones.clear();
-	Common::File actzonefile;
-	if (actzonefile.open(getActZoneFileName())) {
-		if (Te3DObject2::loadAndCheckFourCC(actzonefile, "0TCA")) {
-			uint32 count = actzonefile.readUint32LE();
-			if (count > 1000000)
-				error("Improbable number of actzones %d", count);
-			_actZones.resize(count);
-			for (uint i = 0; i < _actZones.size(); i++) {
-				_actZones[i]._s1 = Te3DObject2::deserializeString(actzonefile);
-				_actZones[i]._s2 = Te3DObject2::deserializeString(actzonefile);
-				for (int j = 0; j < 4; j++)
-					TeVector2f32::deserialize(actzonefile, _actZones[i]._points[j]);
-				_actZones[i]._flag1 = (actzonefile.readByte() != 0);
-				_actZones[i]._flag2 = true;
-			}
-		}
-	}
+	// Syberia 1 has loadActZones function contents inline.
+	loadActZones();
+
 	if (!_lights.empty()) {
 		g_engine->getRenderer()->disableAllLights();
 		for (uint i = 0; i < _lights.size(); i++) {
@@ -674,6 +664,72 @@ bool InGameScene::load(const Common::FSNode &sceneNode) {
 	return true;
 }
 
+bool InGameScene::loadXml(const Common::String &zone, const Common::String &scene) {
+	_zoneName = zone;
+	_sceneName = scene;
+	_blockers.clear();
+	_rectBlockers.clear();
+	_collisionSlide = 0;
+	loadActZones();
+	loadBlockers();
+
+	Common::Path xmlpath = Common::Path("scenes").joinInPlace(zone).joinInPlace(scene).joinInPlace("Scene")
+												.appendInPlace(scene).appendInPlace(".xml");
+	Common::FSNode node = g_engine->getCore()->findFile(xmlpath);
+	InGameSceneXmlParser parser;
+	parser._scene = this;
+	parser.setAllowText();
+	if (!parser.loadFile(node))
+		error("InGameScene::loadXml: Can't load %s", node.getPath().c_str());
+	if (!parser.parse())
+		error("InGameScene::loadXml: Can't parse %s", node.getPath().c_str());
+
+	return true;
+}
+
+void InGameScene::loadActZones() {
+	_actZones.clear();
+	Common::File actzonefile;
+	if (actzonefile.open(getActZoneFileName())) {
+		if (Te3DObject2::loadAndCheckFourCC(actzonefile, "ACT0")) {
+			uint32 count = actzonefile.readUint32LE();
+			if (count > 1000000)
+				error("Improbable number of actzones %d", count);
+			_actZones.resize(count);
+			for (uint i = 0; i < _actZones.size(); i++) {
+				_actZones[i]._s1 = Te3DObject2::deserializeString(actzonefile);
+				_actZones[i]._s2 = Te3DObject2::deserializeString(actzonefile);
+				for (int j = 0; j < 4; j++)
+					TeVector2f32::deserialize(actzonefile, _actZones[i]._points[j]);
+				_actZones[i]._flag1 = (actzonefile.readByte() != 0);
+				_actZones[i]._flag2 = true;
+			}
+		} else {
+			warning("loadActZones: Incorrect header in %s", actzonefile.getName());
+		}
+	}
+}
+
+static Common::Path _sceneFileNameBase() {
+	Game *game = g_engine->getGame();
+	Common::Path retval("scenes");
+	retval.joinInPlace(game->currentZone());
+	retval.joinInPlace(game->currentScene());
+	return retval;
+}
+
+bool InGameScene::loadCamera(const Common::String &name) {
+	Common::Path p = _sceneFileNameBase().joinInPlace(name).appendInPlace(".xml");
+	TeCamera *cam = new TeCamera();
+	cam->loadXml(p);
+	// Original doesn't do this? but we seem to need it
+	cam->setName(name);
+	TeVector3f32 winSize = g_engine->getApplication()->getMainWindow().size();
+	cam->viewport(0, 0, winSize.x(), winSize.y());
+	cameras().push_back(TeIntrusivePtr<TeCamera>(cam));
+	return true;
+}
+
 bool InGameScene::loadCharacter(const Common::String &name) {
 	Character *c = character(name);
 	if (!c) {
@@ -691,6 +747,16 @@ bool InGameScene::loadCharacter(const Common::String &name) {
 	return true;
 }
 
+bool InGameScene::loadFreeMoveZone(const Common::String &name, TeVector2f32 &gridSize) {
+	TeFreeMoveZone *zone = new TeFreeMoveZone();
+	zone->setName(name);
+	Common::Path p = _sceneFileNameBase().joinInPlace(name).appendInPlace(".bin");
+	zone->loadBin(p, &_blockers, &_rectBlockers, &_actZones, gridSize);
+	_freeMoveZones.push_back(zone);
+	zone->setVisible(false);
+	return true;
+}
+
 bool InGameScene::loadLights(const Common::FSNode &node) {
 	SceneLightsXmlParser parser;
 
@@ -793,12 +859,105 @@ bool InGameScene::loadPlayerCharacter(const Common::String &name) {
 	return true;
 }
 
-static Common::Path _sceneFileNameBase() {
-	Game *game = g_engine->getGame();
-	Common::Path retval("scenes");
-	retval.joinInPlace(game->currentZone());
-	retval.joinInPlace(game->currentScene());
-	return retval;
+bool InGameScene::loadDynamicLightBloc(const Common::String &name, const Common::String &texture, const Common::String &zone, const Common::String &scene) {
+	const Common::Path pdat = Common::Path(zone).joinInPlace(scene).joinInPlace(name).appendInPlace(".bin");
+	const Common::Path ptex = Common::Path(zone).joinInPlace(scene).joinInPlace(texture);
+	Common::FSNode datnode = g_engine->getCore()->findFile(pdat);
+	Common::FSNode texnode = g_engine->getCore()->findFile(ptex);
+	if (!datnode.isReadable()) {
+		warning("[InGameScene::loadDynamicLightBloc] Can't open file : %s.", pdat.toString().c_str());
+		return false;
+	}
+
+	Common::File file;
+	file.open(datnode);
+
+	TeModel *model = new TeModel();
+	model->meshes().resize(1);
+	model->setName(datnode.getName());
+
+	TeVector3f32 vec;
+	TeVector2f32 vec2;
+	TeVector3f32::deserialize(file, vec);
+	// Read position/rotation/scale.
+	model->deserialize(file, *model);
+
+	uint32 verts = file.readUint32LE();
+	uint32 tricount = file.readUint32LE();
+	if (verts > 100000 || tricount > 10000)
+		error("Improbable number of verts (%d) or triangles (%d)", verts, tricount);
+
+	TeMesh *mesh = model->meshes()[0].get();
+	mesh->setConf(verts, tricount * 3, TeMesh::MeshMode_Triangles, 0, 0);
+
+	for (uint i = 0; i < verts; i++) {
+		TeVector3f32::deserialize(file, vec);
+		mesh->setVertex(i, vec);
+		mesh->setNormal(i, TeVector3f32(0, 0, 1));
+	}
+	for (uint i = 0; i < verts; i++) {
+		TeVector2f32::deserialize(file, vec2);
+		vec.y() = 1.0 - vec.y();
+		mesh->setTextureUV(i, vec2);
+	}
+
+	for (uint i = 0; i < tricount; i++)
+		mesh->setIndex(i, file.readUint16LE());
+
+	file.close();
+
+	if (texnode.isReadable()) {
+		TeIntrusivePtr<Te3DTexture> tex = Te3DTexture::makeInstance();
+		tex->load2(texnode, 0x500);
+		mesh->defaultMaterial(tex);
+	} else if (texture.size()) {
+		warning("loadDynamicLightBloc: Failed to load texture %s", texture.c_str());
+	}
+
+	model->setVisible(false);
+
+	_zoneModels.push_back(TeIntrusivePtr<TeModel>(model));
+	return true;
+}
+
+bool InGameScene::loadLight(const Common::String &fname, const Common::String &zone, const Common::String &scene) {
+	warning("TODO: Implement InGameScene::loadLight");
+	return true;
+}
+
+bool InGameScene::loadMask(const Common::String &name, const Common::String &texture, const Common::String &zone, const Common::String &scene) {
+	warning("TODO: Implement InGameScene::loadMask");
+	return true;
+}
+
+bool InGameScene::loadRBB(const Common::String &fname, const Common::String &zone, const Common::String &scene) {
+	warning("TODO: Implement InGameScene::loadRBB");
+	return true;
+}
+
+bool InGameScene::loadRippleMask(const Common::String &name, const Common::String &texture, const Common::String &zone, const Common::String &scene) {
+	warning("TODO: Implement InGameScene::loadRippleMask");
+	return true;
+}
+
+bool InGameScene::loadRObject(const Common::String &fname, const Common::String &zone, const Common::String &scene) {
+	warning("TODO: Implement InGameScene::loadRObject");
+	return true;
+}
+
+bool InGameScene::loadShadowMask(const Common::String &name, const Common::String &texture, const Common::String &zone, const Common::String &scene) {
+	warning("TODO: Implement InGameScene::loadShadowMask");
+	return true;
+}
+
+bool InGameScene::loadShadowReceivingObject(const Common::String &fname, const Common::String &zone, const Common::String &scene) {
+	warning("TODO: Implement InGameScene::loadShadowReceivingObject");
+	return true;
+}
+
+bool InGameScene::loadZBufferObject(const Common::String &fname, const Common::String &zone, const Common::String &scene) {
+	warning("TODO: Implement InGameScene::loadZBufferObject");
+	return true;
 }
 
 Common::Path InGameScene::getLightsFileName() const {
diff --git a/engines/tetraedge/game/in_game_scene.h b/engines/tetraedge/game/in_game_scene.h
index 183dd82dc57..7ff1955db76 100644
--- a/engines/tetraedge/game/in_game_scene.h
+++ b/engines/tetraedge/game/in_game_scene.h
@@ -45,6 +45,8 @@ class TeLayout;
 
 class InGameScene : public TeScene {
 public:
+	friend class InGameSceneXmlParser;
+
 	InGameScene();
 
 	struct AnimObject {
@@ -94,7 +96,7 @@ public:
 		_blockingObjects.push_back(obj);
 	}
 	void addCallbackAnimation2D(const Common::String &param_1, const Common::String &param_2, float param_3);
-	bool addMarker(const Common::String &name, const Common::String &imgPath, float x, float y, const Common::String &locType, const Common::String &markerVal);
+	bool addMarker(const Common::String &name, const Common::String &imgPath, float x, float y, const Common::String &locType, const Common::String &markerVal, float anchorX, float anchorY);
 	static float angularDistance(float a1, float a2);
 	bool aroundAnchorZone(const AnchorZone *zone);
 	TeLayout *background();
@@ -147,6 +149,25 @@ public:
 	bool loadObjectMaterials(const Common::String &path, const Common::String &name);
 	bool loadPlayerCharacter(const Common::String &cname);
 
+	// Syberia 2 specific data..
+	void loadActZones();
+	bool loadCamera(const Common::String &name);
+	bool loadDynamicLightBloc(const Common::String &name, const Common::String &texture, const Common::String &zone, const Common::String &scene);
+	// loadFlamme uses the xml doc
+	bool loadFreeMoveZone(const Common::String &name, TeVector2f32 &gridSize);
+	bool loadLight(const Common::String &fname, const Common::String &zone, const Common::String &scene);
+	bool loadMask(const Common::String &name, const Common::String &texture, const Common::String &zone, const Common::String &scene);
+	bool loadRBB(const Common::String &fname, const Common::String &zone, const Common::String &scene);
+	bool loadRippleMask(const Common::String &name, const Common::String &texture, const Common::String &zone, const Common::String &scene);
+	bool loadRObject(const Common::String &fname, const Common::String &zone, const Common::String &scene);
+	//bool loadSBB(const Common::String &fname, const Common::String &zone, const Common::String &scene); // Unused?
+	bool loadShadowMask(const Common::String &name, const Common::String &texture, const Common::String &zone, const Common::String &scene);
+	bool loadShadowReceivingObject(const Common::String &fname, const Common::String &zone, const Common::String &scene);
+	//bool loadSnowCone(const Common::String &fname, const Common::String &zone, const Common::String &scene) { return false; } // Unused?
+	//bool loadSnowCustom() // todo: from xml file?
+	bool loadXml(const Common::String &zone, const Common::String &scene);
+	bool loadZBufferObject(const Common::String &fname, const Common::String &zone, const Common::String &scene);
+
 	void moveCharacterTo(const Common::String &charName, const Common::String &curveName, float curveOffset, float curveEnd);
 	int object(const Common::String &oname);
 	Object3D *object3D(const Common::String &oname);
@@ -199,6 +220,11 @@ public:
 	TeTimer &waitTimeTimer() { return _waitTimeTimer; }
 	Common::Array<Common::SharedPtr<TeLight>> &lights() { return _lights; }
 
+	// Note: Zone name and scene name are only set in Syberia 2
+	const Common::String getZoneName() const { return _zoneName; }
+	const Common::String getSceneName() const { return _sceneName; }
+
+	void setCollisionSlide(bool val) { _collisionSlide = val; }
 
 private:
 	int _shadowLightNo;
@@ -231,6 +257,7 @@ private:
 	Common::Array<TeIntrusivePtr<TeBezierCurve>> _bezierCurves;
 	Common::Array<Dummy> _dummies;
 	Common::Array<TeIntrusivePtr<TeModel>> _zoneModels;
+	Common::Array<TeIntrusivePtr<TeModel>> _masks;
 
 	TeIntrusivePtr<TeModel> _playerCharacterModel;
 	TeIntrusivePtr<TeBezierCurve> _curve;
@@ -245,6 +272,13 @@ private:
 	TeVector2f32 _viewportSize;
 
 	Common::Path _loadedPath;
+
+	// Syberia 2 specific items
+	static bool _collisionSlide;
+	Common::String _sceneName;
+	Common::String _zoneName;
+
+
 };
 
 } // end namespace Tetraedge
diff --git a/engines/tetraedge/game/in_game_scene_xml_parser.cpp b/engines/tetraedge/game/in_game_scene_xml_parser.cpp
new file mode 100644
index 00000000000..3d29262a168
--- /dev/null
+++ b/engines/tetraedge/game/in_game_scene_xml_parser.cpp
@@ -0,0 +1,159 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "tetraedge/game/in_game_scene_xml_parser.h"
+#include "tetraedge/game/in_game_scene.h"
+
+namespace Tetraedge {
+
+bool InGameSceneXmlParser::parserCallback_camera(ParserNode *node) {
+	_scene->loadCamera(node->values["name"]);
+	return true;
+}
+
+bool InGameSceneXmlParser::parserCallback_pathZone(ParserNode *node) {
+	_fmzGridSize = TeVector2f32();
+	// Handled in closedKeyCallback
+	return true;
+}
+
+bool InGameSceneXmlParser::parserCallback_gridSize(ParserNode *node) {
+	_textNodeType = TextNodeGridSize;
+	return true;
+}
+
+bool InGameSceneXmlParser::parserCallback_curve(ParserNode *node) {
+	warning("TODO: handle curve tag in InGameSceneXmlParser");
+	return true;
+}
+
+bool InGameSceneXmlParser::parserCallback_dummy(ParserNode *node) {
+	warning("TODO: handle dummy tag in InGameSceneXmlParser");
+	return true;
+}
+
+bool InGameSceneXmlParser::parserCallback_position(ParserNode *node) {
+	_textNodeType = TextNodePosition;
+	return true;
+}
+
+bool InGameSceneXmlParser::parserCallback_mask(ParserNode *node) {
+	_scene->loadMask(node->values["name"], node->values["texture"],
+		_scene->getZoneName(), _scene->getSceneName());
+	return true;
+}
+
+bool InGameSceneXmlParser::parserCallback_dynamicLight(ParserNode *node) {
+	_scene->loadDynamicLightBloc(node->values["name"], node->values["texture"],
+		_scene->getZoneName(), _scene->getSceneName());
+	return true;
+}
+
+bool InGameSceneXmlParser::parserCallback_rippleMask(ParserNode *node) {
+	_scene->loadRippleMask(node->values["name"], node->values["texture"],
+		_scene->getZoneName(), _scene->getSceneName());
+	return true;
+}
+
+bool InGameSceneXmlParser::parserCallback_snowCone(ParserNode *node) {
+	// doesn't call the function in the game..
+	/*_scene->loadSnowCone(node->values["name"], node->values["texture"],
+		_scene->getZoneName(), _scene->getSceneName());*/
+	return true;
+}
+
+bool InGameSceneXmlParser::parserCallback_shadowMask(ParserNode *node) {
+	_scene->loadShadowMask(node->values["name"], node->values["texture"],
+		_scene->getZoneName(), _scene->getSceneName());
+	return true;
+}
+
+bool InGameSceneXmlParser::parserCallback_shadowReceivingObject(ParserNode *node) {
+	return true;
+}
+
+bool InGameSceneXmlParser::parserCallback_zBufferObject(ParserNode *node) {
+	_scene->loadZBufferObject(node->values["name"], _scene->getZoneName(), _scene->getSceneName());
+	return true;
+}
+
+bool InGameSceneXmlParser::parserCallback_rObject(ParserNode *node) {
+	_scene->loadRObject(node->values["name"], _scene->getZoneName(), _scene->getSceneName());
+	return true;
+}
+
+bool InGameSceneXmlParser::parserCallback_rBB(ParserNode *node) {
+	_scene->loadRBB(node->values["name"], _scene->getZoneName(), _scene->getSceneName());
+	return true;
+}
+
+bool InGameSceneXmlParser::parserCallback_light(ParserNode *node) {
+	_scene->loadLight(node->values["name"], _scene->getZoneName(), _scene->getSceneName());
+	return true;
+}
+
+bool InGameSceneXmlParser::parserCallback_collisionSlide(ParserNode *node) {
+	_scene->setCollisionSlide(true);
+	return true;
+}
+
+bool InGameSceneXmlParser::parserCallback_noCollisionSlide(ParserNode *node) {
+	_scene->setCollisionSlide(false);
+	return true;
+}
+
+bool InGameSceneXmlParser::closedKeyCallback(ParserNode *node) {
+	_textNodeType = TextNodeNone;
+	if (node->name == "pathZone") {
+		_scene->loadFreeMoveZone(node->values["name"], _fmzGridSize);
+	}
+	return true;
+}
+
+bool InGameSceneXmlParser::textCallback(const Common::String &val) {
+	switch (_textNodeType) {
+	case TextNodePosition: {
+		TeVector3f32 pos;
+		if (!pos.parse(val)) {
+			parserError("Can't parse dummy position");
+			return false;
+		}
+		_scene->_dummies.back()._position = pos;
+		break;
+	}
+	case TextNodeGridSize: {
+		TeVector2f32 sz;
+		if (!sz.parse(val)) {
+			parserError("Can't parse gridSize");
+			return false;
+		}
+		_fmzGridSize = sz;
+	}
+	default:
+		parserError("Unexpected text block");
+		return false;
+		break;
+	}
+	return true;
+}
+
+
+} // end namespace Tetraedge
diff --git a/engines/tetraedge/game/in_game_scene_xml_parser.h b/engines/tetraedge/game/in_game_scene_xml_parser.h
new file mode 100644
index 00000000000..d895d4418be
--- /dev/null
+++ b/engines/tetraedge/game/in_game_scene_xml_parser.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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/hashmap.h"
+#include "common/str.h"
+#include "common/formats/xmlparser.h"
+#include "tetraedge/game/in_game_scene.h"
+
+#ifndef TETRAEDGE_GAME_IN_GAME_SCENE_XML_PARSER_H
+#define TETRAEDGE_GAME_IN_GAME_SCENE_XML_PARSER_H
+
+namespace Tetraedge {
+
+class InGameSceneXmlParser : public Common::XMLParser {
+public:
+	// Parser
+	CUSTOM_XML_PARSER(InGameSceneXmlParser) {
+		XML_KEY(scene)
+			XML_KEY(camera)
+				XML_PROP(name, true)
+			KEY_END()
+			XML_KEY(pathZone)
+				XML_PROP(name, true)
+				XML_KEY(gridSize)
+				KEY_END()
+			KEY_END()
+			XML_KEY(curve)
+				XML_PROP(name, true)
+			KEY_END()
+			XML_KEY(dummy)
+				XML_PROP(name, true)
+				XML_KEY(position)
+				KEY_END()
+			KEY_END()
+			XML_KEY(mask)
+				XML_PROP(name, true)
+				XML_PROP(texture, true)
+			KEY_END()
+			XML_KEY(dynamicLight)
+				XML_PROP(name, true)
+				XML_PROP(texture, true)
+			KEY_END()
+			XML_KEY(rippleMask)
+				XML_PROP(name, true)
+				XML_PROP(texture, true)
+			KEY_END()
+			XML_KEY(snowCone)
+				XML_PROP(name, true)
+			KEY_END()
+			XML_KEY(shadowMask)
+				XML_PROP(name, true)
+				XML_PROP(texture, true)
+			KEY_END()
+			XML_KEY(shadowReceivingObject)
+				XML_PROP(name, true)
+			KEY_END()
+			XML_KEY(zBufferObject)
+				XML_PROP(name, true)
+			KEY_END()
+			XML_KEY(rObject)
+				XML_PROP(name, true)
+			KEY_END()
+			XML_KEY(rBB)
+				XML_PROP(name, true)
+			KEY_END()
+			XML_KEY(light)
+				XML_PROP(name, true)
+			KEY_END()
+			XML_KEY(collisionSlide)
+			KEY_END()
+			XML_KEY(noCollisionSlide)
+			KEY_END()
+		KEY_END()
+	} PARSER_END()
+
+	bool parserCallback_scene(ParserNode *node) { return true; }
+	bool parserCallback_camera(ParserNode *node);
+	bool parserCallback_pathZone(ParserNode *node);
+	bool parserCallback_gridSize(ParserNode *node);
+	bool parserCallback_curve(ParserNode *node);
+	bool parserCallback_dummy(ParserNode *node);
+	bool parserCallback_position(ParserNode *node);
+	bool parserCallback_mask(ParserNode *node);
+	bool parserCallback_dynamicLight(ParserNode *node);
+	bool parserCallback_rippleMask(ParserNode *node);
+	bool parserCallback_snowCone(ParserNode *node);
+	bool parserCallback_shadowMask(ParserNode *node);
+	bool parserCallback_shadowReceivingObject(ParserNode *node);
+	bool parserCallback_zBufferObject(ParserNode *node);
+	bool parserCallback_rObject(ParserNode *node);
+	bool parserCallback_rBB(ParserNode *node);
+	bool parserCallback_light(ParserNode *node);
+	bool parserCallback_collisionSlide(ParserNode *node);
+	bool parserCallback_noCollisionSlide(ParserNode *node);
+
+	virtual bool closedKeyCallback(ParserNode *node) override;
+	virtual bool textCallback(const Common::String &val) override;
+
+public:
+	InGameScene *_scene;
+
+	// Free Move Zones have to be handled separately just to handle a single
+	// corner case where the grid size is overridden.
+	TeVector2f32 _fmzGridSize;
+
+	enum TextNodeType {
+		TextNodeNone,
+		TextNodePosition,
+		TextNodeGridSize
+	};
+
+	TextNodeType _textNodeType;
+
+};
+
+} // end namespace Tetraedge
+
+#endif // TETRAEDGE_GAME_IN_GAME_SCENE_XML_PARSER_H
diff --git a/engines/tetraedge/game/lua_binds.cpp b/engines/tetraedge/game/lua_binds.cpp
index 7b29235c5d1..4b533ad5aab 100644
--- a/engines/tetraedge/game/lua_binds.cpp
+++ b/engines/tetraedge/game/lua_binds.cpp
@@ -550,9 +550,9 @@ static int tolua_ExportedFunctions_DeleteCallbackPlayer00(lua_State *L) {
 }
 
 static void AddMarker(const Common::String &markerName, const Common::String &imgPath, float x, float y,
-				const Common::String &loctype, const Common::String &markerVal) {
+				const Common::String &loctype, const Common::String &markerVal, float anchorX, float anchorY) {
 	Game *game = g_engine->getGame();
-	game->scene().addMarker(markerName, imgPath, x, y, loctype, markerVal);
+	game->scene().addMarker(markerName, imgPath, x, y, loctype, markerVal, anchorX, anchorY);
 }
 
 static int tolua_ExportedFunctions_AddMarker00(lua_State *L) {
@@ -562,7 +562,6 @@ static int tolua_ExportedFunctions_AddMarker00(lua_State *L) {
 			&& tolua_isstring(L, 5, 1, &err) && tolua_isstring(L, 6, 1, &err)
 			&& tolua_isnumber(L, 7, 1, &err) && tolua_isnumber(L, 8, 1, &err)
 			&& tolua_isnoobj(L, 9, &err)) {
-		// Syberia 1 version
 		Common::String s1(tolua_tostring(L, 1, nullptr));
 		Common::String s2(tolua_tostring(L, 2, nullptr));
 		double n1 = tolua_tonumber(L, 3, 0.0);
@@ -571,10 +570,7 @@ static int tolua_ExportedFunctions_AddMarker00(lua_State *L) {
 		Common::String s4(tolua_tostring(L, 6, ""));
 		double n3 = tolua_tonumber(L, 7, 0.0);
 		double n4 = tolua_tonumber(L, 8, 0.0);
-		if (n3 || n4) {
-			warning("TODO: handle extra params for AddMarker %f %f", n3, n4);
-		}
-		AddMarker(s1, s2, n1, n2, s3, s4);
+		AddMarker(s1, s2, n1, n2, s3, s4, n3, n4);
 		return 0;
 	}
 	error("#ferror in function 'AddMarker': %d %d %s", err.index, err.array, err.type);
@@ -2320,6 +2316,38 @@ static int tolua_ExportedFunctions_SetCharacterPlayerPosition00(lua_State *L) {
 	error("#ferror in function 'SetCharacterPlayerPosition': %d %d %s", err.index, err.array, err.type);
 }
 
+static void SetCharacterPlayerAnimation(const Common::String &animname, bool repeat, bool returnToIdle, int startframe, int endframe) {
+	Game *game = g_engine->getGame();
+	Character *c = game->scene()._character;
+	if (!c) {
+		warning("SetCharacterPlayerAnimation: no active character");
+		return;
+	}
+
+	bool result = c->setAnimation(animname, repeat, returnToIdle, false, startframe, endframe);
+	if (!result) {
+		warning("[SetCharacterPlayerAnimation] Character's animation \"%s\" doesn't exist",
+			animname.c_str());
+	}
+}
+
+static int tolua_ExportedFunctions_SetCharacterPlayerAnimation00(lua_State *L) {
+	tolua_Error err;
+	if (tolua_isstring(L, 1, 0, &err) && tolua_isboolean(L, 2, 1, &err)
+		&& tolua_isboolean(L, 3, 1, &err) && tolua_isnumber(L, 4, 1, &err)
+		&& tolua_isnumber(L, 5, 1, &err) && tolua_isnoobj(L, 6, &err)) {
+		Common::String s1(tolua_tostring(L, 1, nullptr));
+		bool b1 = tolua_toboolean(L, 2, 1);
+		bool b2 = tolua_toboolean(L, 3, 0);
+		double f3 = tolua_tonumber(L, 4, -1.0);
+		double f4 = tolua_tonumber(L, 5, 9999.0);
+		SetCharacterPlayerAnimation(s1, b1, b2, (int)f3, (int)f4);
+		return 0;
+	}
+	warning("#ferror in function 'SetCharacterPlayerAnimation': %d %d %s", err.index, err.array, err.type);
+	return 0;
+}
+
 static void AddUnlockedAnim(const Common::String &name) {
 	// Note: does nothing, but we needed to add it..
 }
@@ -2494,6 +2522,7 @@ void LuaOpenBinds(lua_State *L) {
 	tolua_function(L, "CurrentCharacterPlayerAnimation", tolua_ExportedFunctions_CurrentCharacterPlayerAnimation00);
 	tolua_function(L, "SetCharacterPlayerRotation", tolua_ExportedFunctions_SetCharacterPlayerRotation00);
 	tolua_function(L, "SetCharacterPlayerPosition", tolua_ExportedFunctions_SetCharacterPlayerPosition00);
+	tolua_function(L, "SetCharacterPlayerAnimation", tolua_ExportedFunctions_SetCharacterPlayerAnimation00);
 	tolua_function(L, "AddUnlockedAnim", tolua_ExportedFunctions_AddUnlockedAnim00);
 
 	// TODO Syberia 2 functions..
@@ -2501,7 +2530,6 @@ void LuaOpenBinds(lua_State *L) {
 	//tolua_function(L, "PlaySnowCustom", tolua_ExportedFunctions_PlaySnowCustom00);
 	//tolua_function(L, "SnowCustomVisible", tolua_ExportedFunctions_SnowCustomVisible00);
 	//tolua_function(L, "RemoveRandomSound", tolua_ExportedFunctions_RemoveRandomSound00);
-	//tolua_function(L, "SetCharacterPlayerAnimation", tolua_ExportedFunctions_SetCharacterPlayerAnimation00);
 	//tolua_function(L, "SetYoukiFollowKate", tolua_ExportedFunctions_SetYoukiFollowKate00);
 	//tolua_function(L, "PlaySmoke", tolua_ExportedFunctions_PlaySmoke00);
 	//tolua_function(L, "SmokeVisible", tolua_ExportedFunctions_SmokeVisible00);
diff --git a/engines/tetraedge/module.mk b/engines/tetraedge/module.mk
index 2ffb78d875b..500b51585c1 100644
--- a/engines/tetraedge/module.mk
+++ b/engines/tetraedge/module.mk
@@ -23,6 +23,7 @@ MODULE_OBJS := \
 	game/help_option_menu.o \
 	game/how_to.o \
 	game/in_game_scene.o \
+	game/in_game_scene_xml_parser.o \
 	game/inventory.o \
 	game/inventory_menu.o \
 	game/inventory_object.o \
@@ -47,6 +48,7 @@ MODULE_OBJS := \
 	te/te_bezier_curve.o \
 	te/te_button_layout.o \
 	te/te_camera.o \
+	te/te_camera_xml_parser.o \
 	te/te_checkbox_layout.o \
 	te/te_clip_layout.o \
 	te/te_color.o \
diff --git a/engines/tetraedge/te/te_3d_object2.cpp b/engines/tetraedge/te/te_3d_object2.cpp
index d9f78e4bd0d..51b2a7f7894 100644
--- a/engines/tetraedge/te/te_3d_object2.cpp
+++ b/engines/tetraedge/te/te_3d_object2.cpp
@@ -90,9 +90,11 @@ int Te3DObject2::childIndex(Te3DObject2 *c) const {
 }
 
 /*static*/
-void Te3DObject2::deserialize(Common::ReadStream &stream, Te3DObject2 &dest) {
-	Common::String str = deserializeString(stream);
-	dest.setName(str);
+void Te3DObject2::deserialize(Common::ReadStream &stream, Te3DObject2 &dest, bool includesName /* = true */) {
+	if (includesName) {
+		Common::String str = deserializeString(stream);
+		dest.setName(str);
+	}
 
 	TeVector3f32 vect;
 	TeVector3f32::deserialize(stream, vect);
diff --git a/engines/tetraedge/te/te_3d_object2.h b/engines/tetraedge/te/te_3d_object2.h
index efce9d64989..0af3b054ca1 100644
--- a/engines/tetraedge/te/te_3d_object2.h
+++ b/engines/tetraedge/te/te_3d_object2.h
@@ -64,7 +64,9 @@ public:
 		return _colorInheritance;
 	}
 
-	static void deserialize(Common::ReadStream &stream, Te3DObject2 &dest);
+	/* Note: Added control for includesName not in original as Syberia 2 data format uses
+	   the file name as the model name. */
+	static void deserialize(Common::ReadStream &stream, Te3DObject2 &dest, bool includesName = true);
 	static void serialize(Common::WriteStream &stream, Te3DObject2 &src);
 
 	virtual void draw() {}
diff --git a/engines/tetraedge/te/te_camera.cpp b/engines/tetraedge/te/te_camera.cpp
index 13177cf3eb4..67ea2b658ce 100644
--- a/engines/tetraedge/te/te_camera.cpp
+++ b/engines/tetraedge/te/te_camera.cpp
@@ -24,6 +24,8 @@
 
 #include "tetraedge/tetraedge.h"
 #include "tetraedge/te/te_camera.h"
+#include "tetraedge/te/te_camera_xml_parser.h"
+#include "tetraedge/te/te_core.h"
 #include "tetraedge/te/te_matrix4x4.h"
 #include "tetraedge/te/te_renderer.h"
 
@@ -32,7 +34,7 @@ namespace Tetraedge {
 TeCamera::TeCamera() : _projectionMatrixType(0), _orthogonalParamL(0.0f),
 	_orthogonalParamR(1.0f), _orthogonalParamT(1.0f), _orthogonalParamB(0.0f),
 	_orthNearVal(10.0f), _orthFarVal(4000.0f), _transformA(0), /*_transformB(0),*/
-	_fov(40.0f), _somePerspectiveVal(1.0f), _viewportX(0), _viewportY(0), _viewportW(0),
+	_fov(40.0f), _aspectRatio(1.0f), _viewportX(0), _viewportY(0), _viewportW(0),
 	_viewportH(0)
 {
 }
@@ -116,7 +118,7 @@ void TeCamera::buildPerspectiveMatrix2() {
 	_projectionMatrix = TeMatrix4x4();
 	float f = tanf(_fov * 0.5);
 	_projectionMatrix.setValue(0, 0, 1.0 / f);
-	_projectionMatrix.setValue(1, 1, _somePerspectiveVal / f);
+	_projectionMatrix.setValue(1, 1, _aspectRatio / f);
 	_projectionMatrix.setValue(2, 2, -(_orthNearVal + _orthFarVal) / (_orthNearVal - _orthFarVal));
 	_projectionMatrix.setValue(3, 2, 1.0);
 	_projectionMatrix.setValue(2, 3, (_orthFarVal * 2) * _orthNearVal / (_orthNearVal - _orthFarVal));
@@ -126,7 +128,7 @@ void TeCamera::buildPerspectiveMatrix2() {
 void TeCamera::buildPerspectiveMatrix3() {
 	_projectionMatrix = TeMatrix4x4();
 	float f = tanf(_fov * 0.5);
-	_projectionMatrix.setValue(0, 0, (1.0 / f) / _somePerspectiveVal);
+	_projectionMatrix.setValue(0, 0, (1.0 / f) / _aspectRatio);
 	_projectionMatrix.setValue(1, 1, 1.0 / f);
 	_projectionMatrix.setValue(2, 2, -(_orthNearVal + _orthFarVal) / (_orthNearVal - _orthFarVal));
 	_projectionMatrix.setValue(3, 2, 1.0);
@@ -163,13 +165,31 @@ Math::Ray TeCamera::getRay(const TeVector2s32 &pxloc) {
 	return ray;
 }
 
-void TeCamera::loadBin(const Common::String &path) {
+void TeCamera::loadXml(const Common::Path &path) {
+	setName(path.getLastComponent().toString());
+	_projectionMatrixType = 3;
+	TeCore *core = g_engine->getCore();
+	Common::FSNode node = core->findFile(path);
+	if (!node.isReadable()) {
+		warning("Can't open camera data %s", path.toString().c_str());
+	}
+	TeCameraXmlParser parser;
+	parser._cam = this;
+	if (!parser.loadFile(node))
+		error("TeCamera::loadXml: can't load file %s", node.getPath().c_str());
+	if (!parser.parse())
+		error("TeCamera::loadXml: error parsing %s", node.getPath().c_str());
+}
+
+/*
+void TeCamera::loadBin(const Common::Path &path) {
 	error("TODO: Implement TeCamera::loadBin");
 }
 
 void TeCamera::loadBin(const Common::ReadStream &stream) {
 	error("TODO: Implement TeCamera::loadBin");
 }
+*/
 
 void TeCamera::orthogonalParams(float left, float right, float top, float bottom) {
 	_orthogonalParamL = left;
diff --git a/engines/tetraedge/te/te_camera.h b/engines/tetraedge/te/te_camera.h
index 39c337ca908..320189e003c 100644
--- a/engines/tetraedge/te/te_camera.h
+++ b/engines/tetraedge/te/te_camera.h
@@ -49,8 +49,13 @@ public:
 
 	Math::Ray getRay(const TeVector2s32 &pxloc);
 
-	void loadBin(const Common::String &path);
-	void loadBin(const Common::ReadStream &stream);
+	// Syberia 2 redefines loadBin to actually load XML.
+	// We just have a separate function.
+	void loadXml(const Common::Path &path);
+
+	// Unused in Syberia 1.
+	//void loadBin(const Common::Path &path);
+	//void loadBin(const Common::ReadStream &stream);
 
 	//void lookAt(const TeVector3f32 &point) {} // empty and unused?
 
@@ -77,9 +82,11 @@ public:
 	}
 	void setProjMatrixType(int matrixType) { _projectionMatrixType = matrixType; }
 	int projMatrixType() const { return _projectionMatrixType; }
-	void setPerspectiveVal(float val) { _somePerspectiveVal = val; }
+	void setAspectRatio(float val) { _aspectRatio = val; }
 	float orthoNearPlane() const { return _orthNearVal; }
 	float orthoFarPlane() const { return _orthFarVal; }
+	void setOrthoNear(float f) { _orthNearVal = f; }
+	void setOrthoFar(float f) { _orthFarVal = f; }
 
 private:
 	void updateProjectionMatrix();
@@ -88,7 +95,7 @@ private:
 	float _orthNearVal;
 	float _orthFarVal;
 	float _fov;
-	float _somePerspectiveVal;
+	float _aspectRatio;
 
 	int _viewportX;
 	int _viewportY;
diff --git a/engines/tetraedge/te/te_camera_xml_parser.cpp b/engines/tetraedge/te/te_camera_xml_parser.cpp
new file mode 100644
index 00000000000..22749f87bd5
--- /dev/null
+++ b/engines/tetraedge/te/te_camera_xml_parser.cpp
@@ -0,0 +1,72 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "tetraedge/te/te_camera_xml_parser.h"
+
+namespace Tetraedge {
+
+bool TeCameraXmlParser::parserCallback_position(ParserNode *node) {
+	float x = atof(node->values["x"].c_str());
+	float y = atof(node->values["y"].c_str());
+	float z = atof(node->values["z"].c_str());
+	_cam->setPosition(TeVector3f32(x, y, z));
+	return true;
+}
+
+bool TeCameraXmlParser::parserCallback_rotation(ParserNode *node) {
+	float x = atof(node->values["x"].c_str());
+	float y = atof(node->values["y"].c_str());
+	float z = atof(node->values["z"].c_str());
+	float w = atof(node->values["w"].c_str());
+	_cam->setRotation(TeQuaternion(x, y, z, w));
+	return true;
+
+}
+
+bool TeCameraXmlParser::parserCallback_scale(ParserNode *node) {
+	float x = atof(node->values["x"].c_str());
+	float y = atof(node->values["y"].c_str());
+	float z = atof(node->values["z"].c_str());
+	_cam->setScale(TeVector3f32(x, y, z));
+	return true;
+}
+
+bool TeCameraXmlParser::parserCallback_fov(ParserNode *node) {
+	_cam->setFov(atof(node->values["value"].c_str()));
+	return true;
+}
+
+bool TeCameraXmlParser::parserCallback_aspect(ParserNode *node) {
+	_cam->setAspectRatio(atof(node->values["value"].c_str()));
+	return true;
+}
+
+bool TeCameraXmlParser::parserCallback_near(ParserNode *node) {
+	_cam->setOrthoNear(atof(node->values["value"].c_str()));
+	return true;
+}
+
+bool TeCameraXmlParser::parserCallback_far(ParserNode *node) {
+	_cam->setOrthoFar(atof(node->values["value"].c_str()));
+	return true;
+}
+
+} // end namespace Tetraedge
diff --git a/engines/tetraedge/te/te_camera_xml_parser.h b/engines/tetraedge/te/te_camera_xml_parser.h
new file mode 100644
index 00000000000..51da23e6707
--- /dev/null
+++ b/engines/tetraedge/te/te_camera_xml_parser.h
@@ -0,0 +1,83 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef TETRAEDGE_TE_TE_CAMERA_XML_PARSER_H
+#define TETRAEDGE_TE_TE_CAMERA_XML_PARSER_H
+
+#include "common/str.h"
+#include "common/formats/xmlparser.h"
+
+#include "tetraedge/te/te_camera.h"
+
+namespace Tetraedge {
+
+class TeCameraXmlParser : public Common::XMLParser {
+public:
+	// Parser
+	CUSTOM_XML_PARSER(TeCameraXmlParser) {
+		XML_KEY(camera)
+			XML_KEY(position)
+				XML_PROP(x, true)
+				XML_PROP(y, true)
+				XML_PROP(z, true)
+			KEY_END()
+			XML_KEY(rotation)
+				XML_PROP(x, true)
+				XML_PROP(y, true)
+				XML_PROP(z, true)
+				XML_PROP(w, true)
+			KEY_END()
+			XML_KEY(scale)
+				XML_PROP(x, true)
+				XML_PROP(y, true)
+				XML_PROP(z, true)
+			KEY_END()
+			XML_KEY(fov)
+				XML_PROP(value, true)
+			KEY_END()
+			XML_KEY(aspect)
+				XML_PROP(value, true)
+			KEY_END()
+			XML_KEY(near)
+				XML_PROP(value, true)
+			KEY_END()
+			XML_KEY(far)
+				XML_PROP(value, true)
+			KEY_END()
+		KEY_END()
+	} PARSER_END()
+
+public:
+	bool parserCallback_camera(ParserNode *node) { return true; }
+	bool parserCallback_position(ParserNode *node);
+	bool parserCallback_rotation(ParserNode *node);
+	bool parserCallback_scale(ParserNode *node);
+	bool parserCallback_fov(ParserNode *node);
+	bool parserCallback_aspect(ParserNode *node);
+	bool parserCallback_near(ParserNode *node);
+	bool parserCallback_far(ParserNode *node);
+
+	TeCamera *_cam;
+};
+
+} // end namespace Tetraedge
+
+#endif // TETRAEDGE_TE_TE_CAMERA_XML_PARSER_H
diff --git a/engines/tetraedge/te/te_free_move_zone.cpp b/engines/tetraedge/te/te_free_move_zone.cpp
index bfa55b8d9a6..9935ca83aea 100644
--- a/engines/tetraedge/te/te_free_move_zone.cpp
+++ b/engines/tetraedge/te/te_free_move_zone.cpp
@@ -21,10 +21,14 @@
 
 #include "tetraedge/tetraedge.h"
 
+#include "common/file.h"
+#include "common/compression/zlib.h"
+
 #include "tetraedge/te/te_free_move_zone.h"
 #include "tetraedge/te/micropather.h"
 #include "tetraedge/te/te_renderer.h"
 #include "tetraedge/te/te_ray_intersection.h"
+#include "tetraedge/te/te_core.h"
 
 namespace Tetraedge {
 
@@ -104,6 +108,13 @@ void TeFreeMoveZone::buildAStar() {
 	if (graphSize._x == 0 || graphSize._y == 0)
 		return;
 
+	bool regenerate = true;
+	if (!_aszGridPath.empty()) {
+		regenerate = !loadAStar(_aszGridPath, graphSize);
+	}
+	if (!regenerate)
+		return;
+
 	if (!_loadedFromBin) {
 		for (int x = 0; x < graphSize._x; x++) {
 			for (int y = 0; y < graphSize._y; y++) {
@@ -141,8 +152,67 @@ void TeFreeMoveZone::buildAStar() {
 	}
 }
 
+bool TeFreeMoveZone::loadAStar(const Common::Path &path, const TeVector2s32 &size) {
+	Common::FSNode node = g_engine->getCore()->findFile(path);
+	Common::File file;
+	if (!node.isReadable() || !file.open(node)) {
+		warning("[TeFreeMoveZone::loadAStar] Can't open file : %s.", path.toString().c_str());
+		return false;
+	}
+	TeVector2s32 readSize;
+	readSize.deserialize(file, readSize);
+	if (size != readSize) {
+		warning("[TeFreeMoveZone::loadAStar] Wrong file : %s.", path.toString().c_str());
+		return false;
+	}
+	uint32 bytes = file.readUint32LE();
+	if (bytes > 100000)
+		error("Improbable size %d for compressed astar data", bytes);
+
+	unsigned long decompBytes = size._x * size._y;
+	byte *buf = new byte[bytes];
+	byte *outBuf = new byte[decompBytes];
+	file.read(buf, bytes);
+	bool result = Common::uncompress(outBuf, &decompBytes, buf, bytes);
+	delete [] buf;
+	if (result) {
+		for (uint i = 0; i < decompBytes; i++)
+			_graph->_flags.data()[i] = outBuf[i];
+	}
+	delete [] outBuf;
+	return result;
+}
+
+
 void TeFreeMoveZone::calcGridMatrix() {
-	error("TODO: Implement TeFreeMoveZone::calcGridMatrix");
+	float angle = 0.0f;
+	float mul = 0.0f;
+	for (uint i = 0; i < _borders.size() - 1; i += 2) {
+		const TeVector3f32 &v1 = _verticies[_borders[i]];
+		const TeVector3f32 &v2 = _verticies[_borders[i + 1]];
+		const TeVector3f32 diff = v2 - v1;
+		const TeVector2f32 diff2(diff.x(), diff.z());
+		float len = diff2.length();
+		float f = fmod(atan2(diff.z(), diff.x()), M_PI_2);
+		if (f < 0)
+			f += M_PI_2;
+
+		if (f - angle < -M_PI_4) {
+			angle -= M_PI_2;
+		} else if (f - angle > M_PI_4) {
+			f -= M_PI_2;
+		}
+
+		angle *= mul;
+		mul += len;
+		angle = fmod((f * len + angle) / mul, M_PI_2);
+		if (angle < 0)
+			angle += M_PI_2;
+	}
+
+	const TeQuaternion rot = TeQuaternion::fromAxisAndAngle(TeVector3f32(0, 1, 0), angle);
+	const TeMatrix4x4 rotMatrix = rot.toTeMatrix();
+	_gridMatrix = TeMatrix4x4() * rotMatrix;
 }
 
 void TeFreeMoveZone::clear() {
@@ -239,8 +309,8 @@ TeIntrusivePtr<TeBezierCurve> TeFreeMoveZone::curve(const TeVector3f32 &startpt,
 }
 
 /*static*/
-void TeFreeMoveZone::deserialize(Common::ReadStream &stream, TeFreeMoveZone &dest, Common::Array<TeBlocker> *blockers,
-			Common::Array<TeRectBlocker> *rectblockers, Common::Array<TeActZone> *actzones) {
+void TeFreeMoveZone::deserialize(Common::ReadStream &stream, TeFreeMoveZone &dest, const Common::Array<TeBlocker> *blockers,
+			const Common::Array<TeRectBlocker> *rectblockers, const Common::Array<TeActZone> *actzones) {
 	dest.clear();
 	TePickMesh2::deserialize(stream, dest);
 	TeVector2f32::deserialize(stream, dest._gridSquareSize);
@@ -330,7 +400,6 @@ static int segmentIntersection(const TeVector2f32 &s1start, const TeVector2f32 &
 	return result;
 }
 
-
 byte TeFreeMoveZone::hasBlockerIntersection(const TeVector2s32 &pt) {
 	TeVector2f32 borders[4];
 
@@ -417,6 +486,59 @@ TeActZone *TeFreeMoveZone::isInZone(const TeVector3f32 &pt) {
 	error("TODO: Implement TeFreeMoveZone::isInZone");
 }
 
+bool TeFreeMoveZone::loadBin(const Common::Path &path, const Common::Array<TeBlocker> *blockers,
+		const Common::Array<TeRectBlocker> *rectblockers, const Common::Array<TeActZone> *actzones,
+		const TeVector2f32 &gridSize) {
+	Common::FSNode node = g_engine->getCore()->findFile(path);
+	if (!node.isReadable()) {
+		warning("[TeFreeMoveZone::loadBin] Can't open file : %s.", node.getName().c_str());
+		return false;
+	}
+	_aszGridPath = path.append(".aszgrid");
+	Common::File file;
+	file.open(node);
+	return loadBin(file, blockers, rectblockers, actzones, gridSize);
+}
+
+bool TeFreeMoveZone::loadBin(Common::ReadStream &stream, const Common::Array<TeBlocker> *blockers,
+		const Common::Array<TeRectBlocker> *rectblockers, const Common::Array<TeActZone> *actzones,
+		const TeVector2f32 &gridSize) {
+	_loadGridSize = gridSize;
+	_loadedFromBin = true;
+
+	// Load position, rotation, scale (not name)
+	Te3DObject2::deserialize(stream, *this, false);
+
+	Common::Array<TeVector3f32> vecs;
+	Te3DObject2::deserializeVectorArray(stream, vecs);
+
+	uint32 triangles = stream.readUint32LE();
+	_freeMoveZoneVerticies.resize(triangles * 3);
+	_gridDirty = true;
+	_transformedVerticiesDirty = true;
+	_bordersDirty = true;
+	_pickMeshDirty = true;
+	_projectedPointsDirty = true;
+
+	for (uint v = 0; v < triangles * 3; v++) {
+		uint16 s = stream.readUint16LE();
+		if (s >= vecs.size())
+			error("Invalid vertex offset %d (of %d) loading TeFreeMoveZone", s, vecs.size());
+		_freeMoveZoneVerticies[v] = vecs[s];
+	}
+	updateTransformedVertices();
+	updatePickMesh();
+
+	_blockers = blockers;
+	_rectBlockers = rectblockers;
+	_actzones = actzones;
+	updateGrid(false);
+	Common::Path p(name());
+	setName(p.getLastComponent().toString());
+
+	return true;
+}
+
 bool TeFreeMoveZone::onViewportChanged() {
 	_projectedPointsDirty = true;
 	return false;
@@ -443,6 +565,7 @@ void TeFreeMoveZone::preUpdateGrid() {
 
 		_gridTopLeft.setX(newVec.x());
 		_gridTopLeft.setY(newVec.z());
+		_gridBottomRight = _gridTopLeft;
 
 		_gridWorldY = newVec.y();
 	}
@@ -454,18 +577,16 @@ void TeFreeMoveZone::preUpdateGrid() {
 		else
 			newVec = gridInverse * _freeMoveZoneVerticies[vertNo];
 
-		if (_gridTopLeft.getX() <= newVec.x()) {
-			if (_gridBottomRight.getX() < newVec.x())
-				_gridBottomRight.setX(newVec.x());
-		} else {
+		if (_gridTopLeft.getX() > newVec.x()) {
 			_gridTopLeft.setX(newVec.x());
+		} else if (_gridBottomRight.getX() < newVec.x()) {
+			_gridBottomRight.setX(newVec.x());
 		}
 
-		if (_gridTopLeft.getY() <= newVec.z()) {
-			if (_gridBottomRight.getY() < newVec.z())
-				_gridBottomRight.setY(newVec.z());
-		} else {
+		if (_gridTopLeft.getY() > newVec.z()) {
 			_gridTopLeft.setY(newVec.z());
+		} else if (_gridBottomRight.getY() < newVec.z()) {
+			_gridBottomRight.setY(newVec.z());
 		}
 
 		if (newVec.y() < _gridWorldY)
@@ -478,17 +599,15 @@ void TeFreeMoveZone::preUpdateGrid() {
 		else
 			_gridSquareSize = TeVector2f32(2.0f, 2.0f);
 	} else {
+		/* Syberia 1 code, never actually used..
 		const TeVector2f32 gridVecDiff = _gridBottomRight - _gridTopLeft;
 		float minSide = MIN(gridVecDiff.getX(), gridVecDiff.getY()) / 20.0f;
 		_gridSquareSize.setX(minSide);
 		_gridSquareSize.setY(minSide);
-
-		error("FIXME: Finish preUpdateGrid for loaded-from-bin case.");
-		/*
-		// what's this field?
-		if (_field_0x414.x != 0.0)
-			_gridOffsetSomething = _field_0x414;
+		if (_loadGridSize.getX())
+			_gridSquareSize = _loadGridSize;
 		*/
+		_gridSquareSize = TeVector2f32(20.0f, 20.0f);
 	}
 
 	TeMatrix4x4 worldTrans = worldTransformationMatrix();
@@ -501,7 +620,11 @@ TeVector2s32 TeFreeMoveZone::projectOnAStarGrid(const TeVector3f32 &pt) {
 	if (!_loadedFromBin) {
 		offsetpt = TeVector2f32(pt.x() - _gridTopLeft.getX(), pt.z() - _gridTopLeft.getY());
 	} else {
-		error("TODO: Implement TeFreeMoveZone::projectOnAStarGrid for _loadedFromBin");
+		TeMatrix4x4 invGrid = _gridMatrix;
+		invGrid.inverse();
+		TeVector3f32 transPt = invGrid * (_inverseWorldTransform * pt);
+		offsetpt.setX(transPt.x() - _gridTopLeft.getX());
+		offsetpt.setY(transPt.y() - _gridTopLeft.getY());
 	}
 	const TeVector2f32 projected = offsetpt / _gridSquareSize;
 	return TeVector2s32((int)projected.getX(), (int)projected.getY());
@@ -613,36 +736,34 @@ void TeFreeMoveZone::updateBorders() {
 
 	updatePickMesh();
 
-	if (_verticies.size() > 2) {
-		for (uint triNo1 = 0; triNo1 < _verticies.size() / 3; triNo1++) {
-			for (uint vecNo1 = 0; vecNo1 < 3; vecNo1++) {
-				uint left1 = triNo1 * 3 + vecNo1;
-				uint left2 = triNo1 * 3 + (vecNo1 == 2 ? 0 : vecNo1 + 1);
-				const TeVector3f32 vleft1 = _verticies[left1];
-				const TeVector3f32 vleft2 = _verticies[left2];
-
-				bool skip = false;
-				for (uint triNo2 = 0; triNo2 < _verticies.size() / 3; triNo2++) {
-					if (skip)
-						break;
+	for (uint triNo1 = 0; triNo1 < _verticies.size() / 3; triNo1++) {
+		for (uint vecNo1 = 0; vecNo1 < 3; vecNo1++) {
+			uint left1 = triNo1 * 3 + vecNo1;
+			uint left2 = triNo1 * 3 + (vecNo1 == 2 ? 0 : vecNo1 + 1);
+			const TeVector3f32 vleft1 = _verticies[left1];
+			const TeVector3f32 vleft2 = _verticies[left2];
 
-					for (uint vecNo2 = 0; vecNo2 < 3; vecNo2++) {
-						if (triNo2 == triNo1)
-							continue;
-						uint right1 = triNo2 * 3 + vecNo2;
-						uint right2 = triNo2 * 3 + (vecNo2 == 2 ? 0 : vecNo2 + 1);
-						TeVector3f32 vright1 = _verticies[right1];
-						TeVector3f32 vright2 = _verticies[right2];
-						if (vright1 == vleft1 && vright2 == vleft2 && vright1 == vleft2 && vright2 == vleft1) {
-							skip = true;
-							break;
-						}
+			bool skip = false;
+			for (uint triNo2 = 0; triNo2 < _verticies.size() / 3; triNo2++) {
+				if (skip)
+					break;
+				if (triNo2 == triNo1)
+					continue;
+
+				for (uint vecNo2 = 0; vecNo2 < 3; vecNo2++) {
+					uint right1 = triNo2 * 3 + vecNo2;
+					uint right2 = triNo2 * 3 + (vecNo2 == 2 ? 0 : vecNo2 + 1);
+					const TeVector3f32 vright1 = _verticies[right1];
+					const TeVector3f32 vright2 = _verticies[right2];
+					if ((vright1 == vleft1 && vright2 == vleft2) || (vright1 == vleft2 && vright2 == vleft1)) {
+						skip = true;
+						break;
 					}
 				}
-				if (!skip) {
-					_borders.push_back(left1);
-					_borders.push_back(left2);
-				}
+			}
+			if (!skip) {
+				_borders.push_back(left1);
+				_borders.push_back(left2);
 			}
 		}
 	}
@@ -674,7 +795,7 @@ void TeFreeMoveZone::updatePickMesh() {
 		_pickMesh.push_back(vecNo + 1);
 		_pickMesh.push_back(vecNo + 2);
 		vecNo += 3;
-}
+	}
 
 	debug("[TeFreeMoveZone::updatePickMesh] %s nb triangles reduced from : %d to : %d", name().c_str(),
 			 _freeMoveZoneVerticies.size() / 3, _pickMesh.size() / 3);
diff --git a/engines/tetraedge/te/te_free_move_zone.h b/engines/tetraedge/te/te_free_move_zone.h
index 3dd60bd6f52..e2b77ce7660 100644
--- a/engines/tetraedge/te/te_free_move_zone.h
+++ b/engines/tetraedge/te/te_free_move_zone.h
@@ -81,6 +81,14 @@ public:
 
 	TeActZone *isInZone(const TeVector3f32 &pt);
 
+	bool loadAStar(const Common::Path &path, const TeVector2s32 &size);
+	bool loadBin(const Common::Path &path, const Common::Array<TeBlocker> *blockers,
+			const Common::Array<TeRectBlocker> *rectblockers, const Common::Array<TeActZone> *actzones,
+			const TeVector2f32 &gridSize);
+	bool loadBin(Common::ReadStream &stream, const Common::Array<TeBlocker> *blockers,
+			const Common::Array<TeRectBlocker> *rectblockers, const Common::Array<TeActZone> *actzones,
+			const TeVector2f32 &gridSize);
+
 	// loadBin() 2 versions, seem unused
 
 	// name(), onPositionChanged(), position(), rotate(), rotation(), scale(),
@@ -107,8 +115,8 @@ public:
 	void updateTransformedVertices();
 
 	static float normalizeAngle(float angle);
-	static void deserialize(Common::ReadStream &stream, TeFreeMoveZone &dest, Common::Array<TeBlocker> *blockers,
-			Common::Array<TeRectBlocker> *rectblockers, Common::Array<TeActZone> *actzones);
+	static void deserialize(Common::ReadStream &stream, TeFreeMoveZone &dest, const Common::Array<TeBlocker> *blockers,
+			const Common::Array<TeRectBlocker> *rectblockers, const Common::Array<TeActZone> *actzones);
 	static void serialize(Common::WriteStream &stream, const TeFreeMoveZone &src, bool updateFirst);
 
 	static TePickMesh2 *findNearestMesh(TeIntrusivePtr<TeCamera> &camera, const TeVector2s32 &frompt,
@@ -119,9 +127,9 @@ public:
 private:
 	TeVector2s32 aStarResolution() const;
 
-	Common::Array<TeActZone> *_actzones;
-	Common::Array<TeBlocker> *_blockers;
-	Common::Array<TeRectBlocker> *_rectBlockers;
+	const Common::Array<TeActZone> *_actzones;
+	const Common::Array<TeBlocker> *_blockers;
+	const Common::Array<TeRectBlocker> *_rectBlockers;
 
 	Common::Array<TeVector3f32> _freeMoveZoneVerticies;
 	Common::Array<uint> _pickMesh;
@@ -131,6 +139,7 @@ private:
 	TeVector2f32 _gridSquareSize;
 	TeVector2f32 _gridTopLeft;
 	TeVector2f32 _gridBottomRight;
+	TeVector2f32 _loadGridSize; // At least, it seems unused?
 	TeMatrix4x4 _gridMatrix;
 	TeMatrix4x4 _inverseWorldTransform;
 
@@ -151,6 +160,8 @@ private:
 
 	micropather::MicroPather *_micropather;
 	TeTimer _updateTimer;
+
+	Common::Path _aszGridPath;
 };
 
 } // end namespace Tetraedge
diff --git a/engines/tetraedge/te/te_lua_thread.cpp b/engines/tetraedge/te/te_lua_thread.cpp
index 45bc41a5861..417a5ad8ff0 100644
--- a/engines/tetraedge/te/te_lua_thread.cpp
+++ b/engines/tetraedge/te/te_lua_thread.cpp
@@ -92,7 +92,11 @@ void TeLuaThread::execute(const Common::String &fname, const TeVariant &p1) {
 		pushValue(p1);
 		_resume(1);
 	} else {
-		if (!fname.contains("Update"))
+		// Don't report Update (as original) or some other functions which are not
+		// implemented in both games
+		if (!fname.contains("Update") && !fname.equals("OnCellCharacterAnimationPlayerFinished")
+				&& !fname.equals("OnCharacterAnimationFinished") && !fname.equals("OnCellDialogFinished")
+				&& !fname.equals("OnCellFreeSoundFinished"))
 			debug("[TeLuaThread::Execute1] Function: \"%s\" does not exist", fname.c_str());
 		lua_settop(_luaThread, -2);
 	}
diff --git a/engines/tetraedge/te/te_vector2f32.cpp b/engines/tetraedge/te/te_vector2f32.cpp
index 5cc007f5413..2aaaaa328c0 100644
--- a/engines/tetraedge/te/te_vector2f32.cpp
+++ b/engines/tetraedge/te/te_vector2f32.cpp
@@ -22,6 +22,7 @@
 #include "tetraedge/te/te_vector2f32.h"
 #include "tetraedge/te/te_vector2s32.h"
 #include "tetraedge/te/te_vector3f32.h"
+#include "tetraedge/tetraedge.h"
 
 namespace Tetraedge {
 
@@ -30,5 +31,14 @@ TeVector2f32::TeVector2f32(const TeVector2s32 &other) {
 	setY(other._y);
 }
 
+bool TeVector2f32::parse(const Common::String &val) {
+	const Common::StringArray parts = TetraedgeEngine::splitString(val, ',');
+	if (parts.size() != 2)
+		return false;
+	setX(atof(parts[0].c_str()));
+	setY(atof(parts[1].c_str()));
+	return true;
+}
+
 
 } // end namespace Tetraedge
diff --git a/engines/tetraedge/te/te_vector2f32.h b/engines/tetraedge/te/te_vector2f32.h
index 66408fce170..a86dc3c8e84 100644
--- a/engines/tetraedge/te/te_vector2f32.h
+++ b/engines/tetraedge/te/te_vector2f32.h
@@ -61,6 +61,8 @@ public:
 		return sqrt(getX() * getX() + getY() * getY());
 	}
 
+	bool parse(const Common::String &val);
+
 	/*
 	TODO: do we need anything that isn't already in Vector2d here?
 	TeVector2f32(const TeVector2f32 &other);




More information about the Scummvm-git-logs mailing list