[Scummvm-git-logs] scummvm master -> 33666221d3a6a362dc4aebaaa10d74369296c272

mduggan noreply at scummvm.org
Sat Apr 29 11:30:50 UTC 2023


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

Summary:
c40b1ee4f8 TETRAEDGE: Fix loading of Amerzone warp textures
06d844c08d TETRAEDGE: Fix some coverity issues
6f4322da24 TETRAEDGE: Fix scene rendering and camera movement
68d987ee9c TETRAEDGE: Implement inventory for Amerzone.
7a515a4a89 TETRAEDGE: Progress implementing animated Amerzone markers
c202f5600e TETRAEDGE: More fixes for warp
33666221d3 TETRAEDGE: More support for Amerzone, can now navigate


Commit: c40b1ee4f83331f0ce780105e8c90f66e6cc2f20
    https://github.com/scummvm/scummvm/commit/c40b1ee4f83331f0ce780105e8c90f66e6cc2f20
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-04-29T20:30:27+09:00

Commit Message:
TETRAEDGE: Fix loading of Amerzone warp textures

Changed paths:
  A engines/tetraedge/te/te_zlib_jpeg.cpp
  A engines/tetraedge/te/te_zlib_jpeg.h
    engines/tetraedge/game/amerzone_game.cpp
    engines/tetraedge/game/amerzone_game.h
    engines/tetraedge/game/application.h
    engines/tetraedge/game/game.cpp
    engines/tetraedge/game/game.h
    engines/tetraedge/game/syberia_game.cpp
    engines/tetraedge/module.mk
    engines/tetraedge/te/te_core.cpp
    engines/tetraedge/te/te_frustum.cpp
    engines/tetraedge/te/te_image.cpp
    engines/tetraedge/te/te_scene_warp.cpp
    engines/tetraedge/te/te_scene_warp.h
    engines/tetraedge/te/te_warp.cpp
    engines/tetraedge/te/te_warp_bloc.cpp


diff --git a/engines/tetraedge/game/amerzone_game.cpp b/engines/tetraedge/game/amerzone_game.cpp
index e8c80951d80..eb4ed6386be 100644
--- a/engines/tetraedge/game/amerzone_game.cpp
+++ b/engines/tetraedge/game/amerzone_game.cpp
@@ -35,7 +35,7 @@
 namespace Tetraedge {
 
 AmerzoneGame::AmerzoneGame() : Tetraedge::Game(), _orientationX(0.0f), _orientationY(0.0f),
-_speedX(0.0f), _speedY(0.0f), _isInDrag(false), _edgeButtonRolloverCount(0),
+_speedX(0.0f), _speedY(0.0f), _isInDrag(false), _musicOn(false), _edgeButtonRolloverCount(0),
 _warpX(nullptr), _warpY(nullptr), _prevWarpY(nullptr) {
 
 }
@@ -59,7 +59,7 @@ bool AmerzoneGame::changeWarp(const Common::String &zone, const Common::String &
 		_warpY->markerValidatedSignal().add(this, &AmerzoneGame::onObjectClick);
 		_warpY->animFinishedSignal().add(this, &AmerzoneGame::onAnimationFinished);
 		saveBackup("save.xml");
-		_music.stop();
+		_videoMusic.stop();
 	}
 	_prevWarpY = _warpY;
 	_warpY = nullptr;
@@ -99,8 +99,8 @@ bool AmerzoneGame::changeWarp(const Common::String &zone, const Common::String &
 
 	_xAngleMin = FLT_MAX;
 	_xAngleMax = FLT_MAX;
-	_yAngleMax = 45.0 - _orientationY;
-	_yAngleMin = _orientationY + 55.0;
+	_yAngleMax = 45.0f - _orientationY;
+	_yAngleMin = _orientationY + 55.0f;
 
 	dotpos = sceneXml.rfind('.');
 	Common::String sceneLua = sceneXml.substr(0, dotpos);
@@ -260,7 +260,7 @@ void AmerzoneGame::leave(bool flag) {
 	_luaContext.destroy();
 	_running = false;
 	_playedTimer.stop();
-	_music.stop();
+	_videoMusic.stop();
 }
 
 bool AmerzoneGame::onChangeWarpAnimFinished() {
@@ -480,7 +480,6 @@ void AmerzoneGame::update() {
 		_warpX->update();
 	if (_warpY)
 		_warpY->update();
-
 }
 
 bool AmerzoneGame::onDialogFinished(const Common::String &val) {
@@ -494,12 +493,10 @@ bool AmerzoneGame::onVideoFinished() {
 	TeSpriteLayout *video = _inGameGui.spriteLayoutChecked("video");
 	Common::String vidPath = video->_tiledSurfacePtr->loadedPath();
 	video->setVisible(false);
-	_music.stop();
-	// TODO:
-	//Application *app = g_engine->getApplication();
-	//if (app->musicOn()) {
-	//	app->music().play();
-	//}
+	Application *app = g_engine->getApplication();
+	_videoMusic.stop();
+	if (_musicOn)
+		app->music().play();
 	_running = true;
 	_luaScript.execute("OnMovieFinished", vidPath);
 	return false;
diff --git a/engines/tetraedge/game/amerzone_game.h b/engines/tetraedge/game/amerzone_game.h
index 71bae1c9c13..b3135416970 100644
--- a/engines/tetraedge/game/amerzone_game.h
+++ b/engines/tetraedge/game/amerzone_game.h
@@ -81,6 +81,7 @@ private:
 	float _speedX;
 	float _speedY;
 	bool _isInDrag;
+	bool _musicOn;
 	int _edgeButtonRolloverCount;
 	Common::Point _mouseDragStart;
 	Common::Point _mouseDragLast;
diff --git a/engines/tetraedge/game/application.h b/engines/tetraedge/game/application.h
index 513def1c88b..f24ccd069d0 100644
--- a/engines/tetraedge/game/application.h
+++ b/engines/tetraedge/game/application.h
@@ -88,7 +88,6 @@ public:
 	MainMenu &mainMenu() { return _mainMenu; }
 	OptionsMenu &optionsMenu() { return _optionsMenu; }
 	TeMusic &music() { return _music; }
-	TeMusic &videoMusic() { return _videoMusic; }
 	Credits &credits() { return _credits; }
 	UpsellScreen &upsellScreen() { return _upsellScreen; }
 	TeVisualFade &visualFade() { return _visFade; }
@@ -132,7 +131,6 @@ private:
 
 	TeVisualFade _visFade;
 	TeMusic _music;
-	TeMusic _videoMusic; // Only used in Amerzone
 	TeSpriteLayout _appSpriteLayout;
 	TeSpriteLayout _mouseCursorLayout;
 	TeSpriteLayout _autoSaveIcon1;
diff --git a/engines/tetraedge/game/game.cpp b/engines/tetraedge/game/game.cpp
index 3b7870f4c0e..3864719d286 100644
--- a/engines/tetraedge/game/game.cpp
+++ b/engines/tetraedge/game/game.cpp
@@ -276,7 +276,7 @@ bool Game::onSkipVideoButtonValidated() {
 
 /* Unused
 void Game::pauseMovie() {
-	_music.pause();
+	_videoMusic.pause();
 	TeSpriteLayout *sprite = _inGameGui.spriteLayoutChecked("video");
 	sprite->pause();
 }
@@ -291,12 +291,12 @@ bool Game::playMovie(const Common::String &vidPath, const Common::String &musicP
 	TeButtonLayout *skipVideoButton = _inGameGui.buttonLayoutChecked("skipVideoButton");
 	skipVideoButton->setVisible(false);
 
-	TeMusic &music = (g_engine->gameIsAmerzone() ? app->videoMusic() : app->music());
-	music.stop();
-	music.setChannelName("video");
-	music.repeat(false);
-	music.volume(volume);
-	music.load(musicPath);
+	app->music().stop();
+	_videoMusic.stop();
+	_videoMusic.setChannelName("video");
+	_videoMusic.repeat(false);
+	_videoMusic.volume(volume);
+	_videoMusic.load(musicPath);
 
 	_running = false;
 
@@ -314,13 +314,13 @@ bool Game::playMovie(const Common::String &vidPath, const Common::String &musicP
 		}
 
 		videoSpriteLayout->setVisible(true);
-		music.play();
+		_videoMusic.play();
 		videoSpriteLayout->play();
 
 		// Stop the movie and sound early for testing if skip_videos set
 		if (ConfMan.getBool("skip_videos")) {
 			videoSpriteLayout->_tiledSurfacePtr->_frameAnim.setNbFrames(10);
-			music.stop();
+			_videoMusic.stop();
 		}
 
 		app->fade();
@@ -383,7 +383,7 @@ void Game::removeNoScale2Child(TeLayout *layout) {
 }
 
 void Game::resumeMovie() {
-	_music.play();
+	_videoMusic.play();
 	_inGameGui.spriteLayout("video")->play();
 }
 
@@ -482,10 +482,10 @@ Common::Error Game::syncGame(Common::Serializer &s) {
 		s.syncAsByte(_objectsTakenBits[i]);
 	s.syncAsUint32LE(_dialogsTold);
 	s.syncString(_prevSceneName);
-	Common::String mpath = _music.rawPath();
+	Common::String mpath = _videoMusic.rawPath();
 	s.syncString(mpath);
 	if (s.isLoading())
-		_music.load(mpath);
+		_videoMusic.load(mpath);
 	s.syncString(_scene._character->walkModeStr());
 	s.syncAsByte(_firstInventory);
 	s.syncAsByte(app->tutoActivated());
diff --git a/engines/tetraedge/game/game.h b/engines/tetraedge/game/game.h
index 6e187124b98..451c7c28cd1 100644
--- a/engines/tetraedge/game/game.h
+++ b/engines/tetraedge/game/game.h
@@ -160,7 +160,7 @@ protected:
 	TeLuaScript _luaScript;
 	TeLuaContext _luaContext;
 	TeLuaScript _gameEnterScript;
-	TeMusic _music;
+	TeMusic _videoMusic;
 	Notifier _notifier;
 	DocumentsBrowser _documentsBrowser;
 
diff --git a/engines/tetraedge/game/syberia_game.cpp b/engines/tetraedge/game/syberia_game.cpp
index 14dda809a1b..79bf868853d 100644
--- a/engines/tetraedge/game/syberia_game.cpp
+++ b/engines/tetraedge/game/syberia_game.cpp
@@ -1119,7 +1119,7 @@ bool SyberiaGame::onMouseClick(const Common::Point &pt) {
 
 bool SyberiaGame::onVideoFinished() {
 	if (!_inGameGui.loaded()) {
-		_music.stop();
+		_videoMusic.stop();
 		return false;
 	}
 
@@ -1134,7 +1134,7 @@ bool SyberiaGame::onVideoFinished() {
 	btn = _inGameGui.buttonLayoutChecked("skipVideoButton");
 	btn->setVisible(false);
 	video->setVisible(false);
-	_music.stop();
+	_videoMusic.stop();
 	_running = true;
 	bool resumed = false;
 	for (uint i = 0; i < _yieldedCallbacks.size(); i++) {
diff --git a/engines/tetraedge/module.mk b/engines/tetraedge/module.mk
index 40139375e88..6abed82f33e 100644
--- a/engines/tetraedge/module.mk
+++ b/engines/tetraedge/module.mk
@@ -128,6 +128,7 @@ MODULE_OBJS := \
 	te/te_warp_bloc.o \
 	te/te_warp_marker.o \
 	te/te_xml_parser.o \
+	te/te_zlib_jpeg.o \
 	te/te_xml_gui.o \
 	metaengine.o
 
diff --git a/engines/tetraedge/te/te_core.cpp b/engines/tetraedge/te/te_core.cpp
index 430136e7b59..ae7f2c6935f 100644
--- a/engines/tetraedge/te/te_core.cpp
+++ b/engines/tetraedge/te/te_core.cpp
@@ -32,6 +32,7 @@
 #include "tetraedge/te/te_png.h"
 #include "tetraedge/te/te_images_sequence.h"
 #include "tetraedge/te/te_jpeg.h"
+#include "tetraedge/te/te_zlib_jpeg.h"
 #include "tetraedge/te/te_theora.h"
 #include "tetraedge/te/te_tga.h"
 
@@ -69,6 +70,8 @@ TeICodec *TeCore::createVideoCodec(const Common::String &extn) {
 		return new TePng();
 	} else if (TeJpeg::matchExtension(extn)) {
 		return new TeJpeg();
+	} else if (TeZlibJpeg::matchExtension(extn)) {
+		return new TeZlibJpeg();
 	} else if (TeTheora::matchExtension(extn)) {
 		return new TeTheora();
 	} else if (TeTga::matchExtension(extn)) {
diff --git a/engines/tetraedge/te/te_frustum.cpp b/engines/tetraedge/te/te_frustum.cpp
index de82898b9d5..e55e08a4378 100644
--- a/engines/tetraedge/te/te_frustum.cpp
+++ b/engines/tetraedge/te/te_frustum.cpp
@@ -81,9 +81,9 @@ void TeFrustum::update(TeCamera *camera) {
 	const TeMatrix4x4 camMatrix = camera->worldTransformationMatrix();
 	for (unsigned int plane = 0; plane < 6; plane++) {
 		if (plane % 2)
-			extractPlanAdd(camMatrix, plane / 2, plane);
+			extractPlanAdd(camMatrix, plane, plane / 2);
 		else
-			extractPlanSub(camMatrix, plane / 2, plane);
+			extractPlanSub(camMatrix, plane, plane / 2);
 		float len = planeLen(plane);
 		float *p = _m + plane * 4;
 		for (int i = 0; i < 4; i++)
diff --git a/engines/tetraedge/te/te_image.cpp b/engines/tetraedge/te/te_image.cpp
index 204cca4720c..d06526dd71e 100644
--- a/engines/tetraedge/te/te_image.cpp
+++ b/engines/tetraedge/te/te_image.cpp
@@ -120,7 +120,15 @@ bool TeImage::load(Common::SeekableReadStream &stream, const Common::String &typ
 		delete codec;
 		return false;
 	}
-	error("TODO: Implement TeImage::load");
+
+	Common::SharedPtr<TePalette> nullpal;
+	createImg(codec->width(), codec->height(), nullpal, codec->imageFormat(), codec->width(), codec->height());
+
+	if (!codec->update(0, *this)) {
+		error("TeImage::load: Failed to update from stream");
+	}
+	delete codec;
+	return true;
 }
 
 bool TeImage::save(const Common::Path &path, enum SaveType type) {
diff --git a/engines/tetraedge/te/te_scene_warp.cpp b/engines/tetraedge/te/te_scene_warp.cpp
index 57fa1920ec4..ac1c5acbed9 100644
--- a/engines/tetraedge/te/te_scene_warp.cpp
+++ b/engines/tetraedge/te/te_scene_warp.cpp
@@ -70,7 +70,7 @@ const TeSceneWarp::WarpEvent *TeSceneWarp::getWarpEvent(const Common::String &na
 bool TeSceneWarp::load(const Common::String &name, TeWarp *warp, bool flag) {
 	close();
 	_warp = warp;
-	_someInt = 0;
+	_numExitsCreated = 0;
 	_name = name;
 
 	TeSceneWarpXmlParser parser(this, flag);
diff --git a/engines/tetraedge/te/te_scene_warp.h b/engines/tetraedge/te/te_scene_warp.h
index c12b3f0e4c3..44e4579ff6d 100644
--- a/engines/tetraedge/te/te_scene_warp.h
+++ b/engines/tetraedge/te/te_scene_warp.h
@@ -96,7 +96,7 @@ private:
 	Common::List<WarpEvent> _warpEvents;
 	Common::String _name;
 	TeWarp *_warp;
-	int _someInt;
+	int _numExitsCreated;
 };
 
 } // end namespace Tetraedge
diff --git a/engines/tetraedge/te/te_warp.cpp b/engines/tetraedge/te/te_warp.cpp
index 8bba4ac728b..89f81265a72 100644
--- a/engines/tetraedge/te/te_warp.cpp
+++ b/engines/tetraedge/te/te_warp.cpp
@@ -228,43 +228,42 @@ void TeWarp::load(const Common::String &path, bool flag) {
 
 	if (_preloaded)
 		error("TODO: Support preloading in TeWarp::load");
-	Common::File file;
-	file.open(node);
+	_file.open(node);
 	char header[7];
 	header[6] = '\0';
-	file.read(header, 6);
+	_file.read(header, 6);
 	if (Common::String(header) != "TeWarp")
 		error("Invalid header in warp data %s", _warpPath.c_str());
-	uint32 globalTexDataOffset = file.readUint32LE();
-	_texEncodingType = file.readPascalString();
-	_xCount = file.readUint32LE();
-	_yCount = file.readUint32LE();
-	_numAnims = file.readUint32LE();
-	_someXVal = file.readUint32LE();
-	_someYVal = file.readUint32LE();
-	_someMeshX = file.readUint32LE();
-	_someMeshY = file.readUint32LE();
+	uint32 globalTexDataOffset = _file.readUint32LE();
+	_texEncodingType = _file.readPascalString();
+	_xCount = _file.readUint32LE();
+	_yCount = _file.readUint32LE();
+	_numAnims = _file.readUint32LE();
+	_someXVal = _file.readUint32LE();
+	_someYVal = _file.readUint32LE();
+	_someMeshX = _file.readUint32LE();
+	_someMeshY = _file.readUint32LE();
 	_warpBlocs.resize(_xCount * _yCount * 6);
 	for (uint i = 0; i < _xCount * _yCount * 6; i++) {
-		TeWarpBloc::CubeFace face = static_cast<TeWarpBloc::CubeFace>(file.readByte());
+		TeWarpBloc::CubeFace face = static_cast<TeWarpBloc::CubeFace>(_file.readByte());
 		for (uint j = 0; j < _xCount * _yCount; j++) {
-			unsigned short offx = file.readUint16LE();
-			unsigned short offy = file.readUint16LE();
-			unsigned int blocTexOffset = file.readUint32LE();
-			_warpBlocs[j].setTextureFileOffset(globalTexDataOffset + blocTexOffset);
+			unsigned short offx = _file.readUint16LE();
+			unsigned short offy = _file.readUint16LE();
+			unsigned int blocTexOffset = _file.readUint32LE();
+			_warpBlocs[i].setTextureFileOffset(globalTexDataOffset + blocTexOffset);
 			TeVector2s32 offset(offx, offy);
-			_warpBlocs[j].create(face, _xCount, _yCount, offset);
+			_warpBlocs[i].create(face, _xCount, _yCount, offset);
 		}
 	}
 	_loadedAnimData.resize(_numAnims);
 	_putAnimData.reserve(_numAnims);
 	for (uint i = 0; i < _numAnims; i++) {
 		char aname[5];
-		file.read(aname, 4);
+		_file.read(aname, 4);
 		aname[4] = '\0';
 		_loadedAnimData[i]._name = aname;
-		uint numFrames = file.readUint32LE();
-		byte numSomething = file.readByte();
+		uint numFrames = _file.readUint32LE();
+		byte numSomething = _file.readByte();
 		_loadedAnimData[i]._frameDatas.resize(numFrames);
 		for (uint j = 0; j < numFrames; j++) {
 			FrameData &frameData = _loadedAnimData[i]._frameDatas[j];
@@ -272,26 +271,26 @@ void TeWarp::load(const Common::String &path, bool flag) {
 			frameData._numWarpBlocs = 0;
 			Common::Array<TeWarpBloc> warpBlocs;
 			for (uint k = 0; k < numSomething; k++) {
-				uint blocCount = file.readUint32LE();
+				uint blocCount = _file.readUint32LE();
 				if (blocCount) {
-					TeWarpBloc::CubeFace face = static_cast<TeWarpBloc::CubeFace>(file.readByte());
+					TeWarpBloc::CubeFace face = static_cast<TeWarpBloc::CubeFace>(_file.readByte());
 					warpBlocs.resize(frameData._numWarpBlocs + blocCount);
 					for (auto &warpBloc : warpBlocs) {
-						uint xoff = file.readUint16LE();
-						uint yoff = file.readUint16LE();
-						uint32 texDataOff = file.readUint32LE();
+						uint xoff = _file.readUint16LE();
+						uint yoff = _file.readUint16LE();
+						uint32 texDataOff = _file.readUint32LE();
 						warpBloc.setTextureFileOffset(globalTexDataOffset + texDataOff);
 						warpBloc.create(face, _someXVal, _someYVal, TeVector2s32(xoff, yoff));
 						if (flag)
 							warpBloc.color(TeColor(255, 0, 0, 255));
 					}
-					uint meshSize = file.readUint32LE();
+					uint meshSize = _file.readUint32LE();
 					TePickMesh tmpMesh;
 					tmpMesh.setName(aname);
 					tmpMesh.nbTriangles(meshSize * 2);
 					for (uint m = 0; m < meshSize; m++) {
-						uint xoff = file.readUint16LE();
-						uint yoff = file.readUint16LE();
+						uint xoff = _file.readUint16LE();
+						uint yoff = _file.readUint16LE();
 						addQuadToPickMesh(tmpMesh, m * 2, face, TeVector2s32(xoff, yoff), _someMeshX, _someMeshY);
 					}
 					tmpMesh.setFlag(true);
diff --git a/engines/tetraedge/te/te_warp_bloc.cpp b/engines/tetraedge/te/te_warp_bloc.cpp
index 815d2a12499..9051276bd30 100644
--- a/engines/tetraedge/te/te_warp_bloc.cpp
+++ b/engines/tetraedge/te/te_warp_bloc.cpp
@@ -98,10 +98,15 @@ void TeWarpBloc::create(CubeFace face, uint x, uint y, const TeVector2s32 &offse
 	_mesh->setTextureUV(1, TeVector2f32(1, 0));
 	_mesh->setTextureUV(2, TeVector2f32(1, 1));
 	_mesh->setTextureUV(3, TeVector2f32(0, 1));
+	_mesh->setNormal(0, TeVector3f32(0, 0, 1));
+	_mesh->setNormal(1, TeVector3f32(0, 0, 1));
+	_mesh->setNormal(2, TeVector3f32(0, 0, 1));
+	_mesh->setNormal(3, TeVector3f32(0, 0, 1));
 	_mesh->setIndex(0, 0);
 	_mesh->setIndex(1, 1);
 	_mesh->setIndex(2, 2);
 	_mesh->setIndex(3, 3);
+	_mesh->setColor(TeColor(255, 255, 255, 255));
 }
 
 void TeWarpBloc::create() {
@@ -127,9 +132,9 @@ void TeWarpBloc::loadTexture(Common::File &file, const Common::String &type) {
 	TeImage img;
 	img.load(file, type);
 
-	_mesh->materials().resize(1);
-	_mesh->material(0)->_texture = Te3DTexture::makeInstance();
-	_mesh->material(0)->_texture->load(img);
+	TeIntrusivePtr<Te3DTexture> tex = Te3DTexture::makeInstance();
+	tex->load(img);
+	_mesh->defaultMaterial(tex);
 }
 
 void TeWarpBloc::render() {
diff --git a/engines/tetraedge/te/te_zlib_jpeg.cpp b/engines/tetraedge/te/te_zlib_jpeg.cpp
new file mode 100644
index 00000000000..49c04bdf40b
--- /dev/null
+++ b/engines/tetraedge/te/te_zlib_jpeg.cpp
@@ -0,0 +1,53 @@
+/* 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_zlib_jpeg.h"
+#include "common/substream.h"
+#include "common/compression/zlib.h"
+
+namespace Tetraedge {
+
+TeZlibJpeg::TeZlibJpeg() {
+}
+
+TeZlibJpeg::~TeZlibJpeg() {
+}
+
+bool TeZlibJpeg::load(Common::SeekableReadStream &stream) {
+	uint32 compressedSize = stream.readUint32LE();
+	if (compressedSize > stream.size()) {
+		warning("[TeImage::load] invalid size %d (file size %d)", compressedSize, (int)stream.size());
+		return false;
+	}
+	uint32 uncompressedSize = stream.readUint32LE();
+	Common::SeekableSubReadStream *substream = new Common::SeekableSubReadStream(&stream, stream.pos(), stream.size());
+	Common::SeekableReadStream *zlibStream = Common::wrapCompressedReadStream(substream, uncompressedSize);
+	bool result = TeJpeg::load(*zlibStream);
+	delete zlibStream;
+	return result;
+}
+
+/*static*/
+bool TeZlibJpeg::matchExtension(const Common::String &extn) {
+	return extn == "jpeg.zlib";
+}
+
+} // end namespace Tetraedge
diff --git a/engines/tetraedge/te/te_zlib_jpeg.h b/engines/tetraedge/te/te_zlib_jpeg.h
new file mode 100644
index 00000000000..3459269fce1
--- /dev/null
+++ b/engines/tetraedge/te/te_zlib_jpeg.h
@@ -0,0 +1,42 @@
+/* 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_ZLIB_JPEG_H
+#define TETRAEDGE_TE_TE_ZLIB_JPEG_H
+
+#include "common/str.h"
+#include "tetraedge/te/te_jpeg.h"
+
+namespace Tetraedge {
+
+class TeZlibJpeg : public TeJpeg {
+public:
+	TeZlibJpeg();
+	virtual ~TeZlibJpeg();
+
+	virtual bool load(Common::SeekableReadStream &stream) override;
+
+	static bool matchExtension(const Common::String &extn);
+};
+
+} // end namespace Tetraedge
+
+#endif // TETRAEDGE_TE_TE_ZLIB_JPEG_H


Commit: 06d844c08df2e4f5cca92896eca8df7acf61a1f9
    https://github.com/scummvm/scummvm/commit/06d844c08df2e4f5cca92896eca8df7acf61a1f9
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-04-29T20:30:27+09:00

Commit Message:
TETRAEDGE: Fix some coverity issues

Changed paths:
    engines/tetraedge/te/te_scene_warp.cpp
    engines/tetraedge/te/te_scene_warp.h
    engines/tetraedge/te/te_warp.h


diff --git a/engines/tetraedge/te/te_scene_warp.cpp b/engines/tetraedge/te/te_scene_warp.cpp
index ac1c5acbed9..a96bb8220d3 100644
--- a/engines/tetraedge/te/te_scene_warp.cpp
+++ b/engines/tetraedge/te/te_scene_warp.cpp
@@ -24,7 +24,7 @@
 
 namespace Tetraedge {
 
-TeSceneWarp::TeSceneWarp() : _warp(nullptr) {
+TeSceneWarp::TeSceneWarp() : _warp(nullptr), _numExitsCreated(0) {
 }
 
 TeSceneWarp::~TeSceneWarp() {
diff --git a/engines/tetraedge/te/te_scene_warp.h b/engines/tetraedge/te/te_scene_warp.h
index 44e4579ff6d..a1ba4a586cc 100644
--- a/engines/tetraedge/te/te_scene_warp.h
+++ b/engines/tetraedge/te/te_scene_warp.h
@@ -42,7 +42,7 @@ public:
 	};
 	class Exit {
 	public:
-		Exit() : _nbWarpBlock(0) {}
+		Exit() : _nbWarpBlock(0), _markerId(0) {}
 		Common::String _name;
 		Common::String _linkedWarp;
 		unsigned long _markerId;
@@ -54,6 +54,7 @@ public:
 	};
 	class Object {
 	public:
+		Object() : _markerId(0) {}
 		Common::String _name;
 		Common::String _str2;
 		unsigned long _markerId;
diff --git a/engines/tetraedge/te/te_warp.h b/engines/tetraedge/te/te_warp.h
index 4da38eb91f0..bfad102a480 100644
--- a/engines/tetraedge/te/te_warp.h
+++ b/engines/tetraedge/te/te_warp.h
@@ -64,6 +64,7 @@ public:
 	};
 
 	struct Exit {
+		Exit() : _camAngleX(0), _camAngleY(0), _markerId(0) {}
 		Common::String _name;
 		Common::String _linkedWarpPath;
 		float _camAngleX;


Commit: 6f4322da247a194fd20ba9ea2553555a663f0b62
    https://github.com/scummvm/scummvm/commit/6f4322da247a194fd20ba9ea2553555a663f0b62
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-04-29T20:30:27+09:00

Commit Message:
TETRAEDGE: Fix scene rendering and camera movement

Can now scan around the first scene - no markers rendered yet.

Changed paths:
    engines/tetraedge/game/amerzone_game.cpp
    engines/tetraedge/game/lua_binds.cpp
    engines/tetraedge/te/te_warp.cpp
    engines/tetraedge/te/te_warp_bloc.cpp


diff --git a/engines/tetraedge/game/amerzone_game.cpp b/engines/tetraedge/game/amerzone_game.cpp
index eb4ed6386be..f5a8d191edc 100644
--- a/engines/tetraedge/game/amerzone_game.cpp
+++ b/engines/tetraedge/game/amerzone_game.cpp
@@ -99,8 +99,8 @@ bool AmerzoneGame::changeWarp(const Common::String &zone, const Common::String &
 
 	_xAngleMin = FLT_MAX;
 	_xAngleMax = FLT_MAX;
-	_yAngleMax = 45.0f - _orientationY;
-	_yAngleMin = _orientationY + 55.0f;
+	_yAngleMin = 45.0f - _orientationY;
+	_yAngleMax = _orientationY + 55.0f;
 
 	dotpos = sceneXml.rfind('.');
 	Common::String sceneLua = sceneXml.substr(0, dotpos);
@@ -333,7 +333,7 @@ void AmerzoneGame::setAngleX(float angle) {
 	_xAngleMin -= diff;
 	_xAngleMax += diff;
 
-	float roundedAngle = (int)(angle / 360.0f) * 360;
+	float roundedAngle = angle - (int)(angle / 360.0f) * 360;
 	_orientationX = roundedAngle;
 	if (roundedAngle > 360.0f || roundedAngle < -360.0f)
 		_orientationX = 0;
@@ -352,10 +352,7 @@ void AmerzoneGame::setAngleY(float angle) {
 	_yAngleMin -= diff;
 	_yAngleMax += diff;
 
-	if (angle < -55.0f)
-		_orientationY = -55.0f;
-	else if (_orientationY > 45.0f)
-		_orientationY = 45.0f;
+	_orientationY = CLIP(angle, -55.0f, 45.0f);
 }
 
 void AmerzoneGame::showPuzzle(int puzzleNo, int puzParam1, int puzParam2) {
@@ -428,8 +425,7 @@ void AmerzoneGame::startDecelerationAnim() {
 void AmerzoneGame::update() {
 	TeInputMgr *inputMgr = g_engine->getInputMgr();
 
-	// TODO:
-	// if (!inputMgr->isLeftDown())
+	//if (!inputMgr->>isLeftDown())
 	//     isInDrag(false);
 
 	Application *app = g_engine->getApplication();
@@ -469,8 +465,12 @@ void AmerzoneGame::update() {
 			_warpY->setMouseLeftUpForMakers();
 	}
 
+	// Rotate x around the Y axis (spinning left/right on the spot)
 	TeQuaternion xRot = TeQuaternion::fromAxisAndAngle(TeVector3f32(0, 1, 0), (float)(_orientationX * M_PI) / 180);
-	TeQuaternion yRot = TeQuaternion::fromAxisAndAngle(TeVector3f32(1, 0, 0), (float)(_orientationY * M_PI) / 180);
+	// Rotate y around the axis perpendicular to the x rotation
+	TeVector3f32 yRotAxis = TeVector3f32(1, 0, 0);
+	xRot.inverse().transform(yRotAxis);
+	TeQuaternion yRot = TeQuaternion::fromAxisAndAngle(yRotAxis, (float)(_orientationY * M_PI) / 180);
 
 	if (_warpX)
 		_warpX->rotateCamera(xRot * yRot);
diff --git a/engines/tetraedge/game/lua_binds.cpp b/engines/tetraedge/game/lua_binds.cpp
index ed01d3ab476..4beac108d20 100644
--- a/engines/tetraedge/game/lua_binds.cpp
+++ b/engines/tetraedge/game/lua_binds.cpp
@@ -2004,7 +2004,7 @@ static void PlayMusic(const Common::String &path, float volume) {
 	// very slightly different to original because we can't
 	// change repeat value after starting.
 	music.stop();
-	music.repeat(false);
+	music.repeat(g_engine->gameIsAmerzone());
 	music.load(path);
 	music.play();
 	music.volume(volume);
diff --git a/engines/tetraedge/te/te_warp.cpp b/engines/tetraedge/te/te_warp.cpp
index 89f81265a72..5339b5a514b 100644
--- a/engines/tetraedge/te/te_warp.cpp
+++ b/engines/tetraedge/te/te_warp.cpp
@@ -37,7 +37,7 @@ bool TeWarp::debug = false;
 TeWarp::TeWarp() : _visible1(false), _loaded(false), _preloaded(false),
 	_numAnims(0), _someXVal(0), _someYVal(0), _someMeshX(0), _someMeshY(0),
 	_renderWarpBlocs(true), _xCount(0), _yCount(0), _clickedPickMesh(nullptr),
-	_clickedAnimData(nullptr) {
+	_clickedAnimData(nullptr), _markersActive(true) {
 }
 
 TeWarp::~TeWarp() {
@@ -214,7 +214,12 @@ bool TeWarp::hasObjectOrAnim(const Common::String &objname) {
 
 void TeWarp::init() {
 	// This mostly sets up the camera.. maybe nothing to do?
-	warning("TODO: Implement TeWarp::init?");
+	TeVector3f32 winSize = g_engine->getApplication()->getMainWindow().size();
+	_camera.setProjMatrixType(3);
+	_camera.viewport(0, 0, (int)winSize.x(), (int)winSize.y());
+	_camera.setOrthoPlanes(1, 4096);
+	_camera.setAspectRatio(winSize.x() / winSize.y());
+	warning("TODO: Finish TeWarp::init?");
 }
 
 void TeWarp::load(const Common::String &path, bool flag) {
@@ -538,7 +543,7 @@ void TeWarp::unloadTextures() {
 
 void TeWarp::updateCamera(const TeVector3f32 &screen) {
 	_camera.viewport(0, 0, screen.x(), screen.y());
-	_camera.setOrthoPlanes(1, 4086);
+	_camera.setOrthoPlanes(1, 4096);
 	_camera.setAspectRatio(screen.x() / screen.y());
 }
 
diff --git a/engines/tetraedge/te/te_warp_bloc.cpp b/engines/tetraedge/te/te_warp_bloc.cpp
index 9051276bd30..02b6665d325 100644
--- a/engines/tetraedge/te/te_warp_bloc.cpp
+++ b/engines/tetraedge/te/te_warp_bloc.cpp
@@ -25,7 +25,7 @@
 
 namespace Tetraedge {
 
-TeWarpBloc::TeWarpBloc() : _cubeFace(FaceInvalid) {
+TeWarpBloc::TeWarpBloc() : _cubeFace(FaceInvalid), _textureDataFileOffset(0) {
 	_mesh.reset(TeMesh::makeInstance());
 }
 
@@ -49,10 +49,11 @@ void TeWarpBloc::create(CubeFace face, uint x, uint y, const TeVector2s32 &offse
 
 	_mesh->setConf(4, 4, TeMesh::MeshMode_TriangleStrip, 0, 0);
 
-	float y1 = offset._y * (1000.0f / y) - 500.0f;
-	float y2 = y1 + 1000.0f / y;
 	float x1 = offset._x * (1000.0f / x) - 500.0f;
-	float x2 = x1 + 1000.0f / x;
+	float x2 = 1000.0f / x + x1;
+	float y1 = offset._y * (1000.0f / y) - 500.0f;
+	float y2 = 1000.0f / y + y1;
+
 	switch (face) {
 	case Face0:
 		_mesh->setVertex(0, TeVector3f32(-x1, 500, -y1));
@@ -104,8 +105,8 @@ void TeWarpBloc::create(CubeFace face, uint x, uint y, const TeVector2s32 &offse
 	_mesh->setNormal(3, TeVector3f32(0, 0, 1));
 	_mesh->setIndex(0, 0);
 	_mesh->setIndex(1, 1);
-	_mesh->setIndex(2, 2);
-	_mesh->setIndex(3, 3);
+	_mesh->setIndex(2, 3);
+	_mesh->setIndex(3, 2);
 	_mesh->setColor(TeColor(255, 255, 255, 255));
 }
 
@@ -135,6 +136,7 @@ void TeWarpBloc::loadTexture(Common::File &file, const Common::String &type) {
 	TeIntrusivePtr<Te3DTexture> tex = Te3DTexture::makeInstance();
 	tex->load(img);
 	_mesh->defaultMaterial(tex);
+	_mesh->materials()[0]._enableLights = false;
 }
 
 void TeWarpBloc::render() {


Commit: 68d987ee9cb1434714c7224ca570b511068d8c71
    https://github.com/scummvm/scummvm/commit/68d987ee9cb1434714c7224ca570b511068d8c71
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-04-29T20:30:27+09:00

Commit Message:
TETRAEDGE: Implement inventory for Amerzone.

Changed paths:
  A engines/tetraedge/game/documents_browser_xml_parser.cpp
  A engines/tetraedge/game/documents_browser_xml_parser.h
    engines/tetraedge/game/amerzone_game.cpp
    engines/tetraedge/game/application.cpp
    engines/tetraedge/game/documents_browser.cpp
    engines/tetraedge/game/documents_browser.h
    engines/tetraedge/game/game.cpp
    engines/tetraedge/game/game.h
    engines/tetraedge/game/inventory.cpp
    engines/tetraedge/game/inventory.h
    engines/tetraedge/game/inventory_menu.cpp
    engines/tetraedge/game/inventory_objects_xml_parser.h
    engines/tetraedge/game/main_menu.cpp
    engines/tetraedge/module.mk
    engines/tetraedge/te/te_button_layout.cpp
    engines/tetraedge/te/te_marker.cpp
    engines/tetraedge/te/te_marker.h
    engines/tetraedge/te/te_scene_warp.cpp
    engines/tetraedge/te/te_scene_warp_xml_parser.cpp
    engines/tetraedge/te/te_scene_warp_xml_parser.h
    engines/tetraedge/te/te_warp.cpp
    engines/tetraedge/tetraedge.cpp


diff --git a/engines/tetraedge/game/amerzone_game.cpp b/engines/tetraedge/game/amerzone_game.cpp
index f5a8d191edc..506947e504a 100644
--- a/engines/tetraedge/game/amerzone_game.cpp
+++ b/engines/tetraedge/game/amerzone_game.cpp
@@ -71,7 +71,7 @@ bool AmerzoneGame::changeWarp(const Common::String &zone, const Common::String &
 	// Just reload each time for now.
 	if (!_warpY) {
 		_warpY = new TeWarp();
-		_warpY->setRotation(app->frontOrientationLayout().rotation());
+		_warpY->setRotation(app->frontLayout().rotation());
 		_warpY->init();
 		float fov = 45.0f; //TODO: g_engine->getCore()->fileFlagSystemFlagsContains("HD") ? 60.0f : 45.0f;
 		_warpY->setFov(fov);
@@ -132,10 +132,10 @@ void AmerzoneGame::enter() {
 	_inGameGui.load("GUI/InGame.lua");
 
 	TeLayout *inGame = _inGameGui.layoutChecked("inGame");
-	// Note:
-	app->frontOrientationLayout().addChild(inGame);
+	app->frontLayout().addChild(inGame);
+	// DocumentsBrowser and Inventory get added as children of InventoryMenu
 	_inventoryMenu.load();
-	app->frontOrientationLayout().addChild(&_inventoryMenu);
+	app->frontLayout().addChild(&_inventoryMenu);
 
 	TeButtonLayout *invbtn = _inGameGui.buttonLayoutChecked("inventoryButton");
 	invbtn->onMouseClickValidated().add(this, &AmerzoneGame::onInventoryButtonValidated);
@@ -151,7 +151,7 @@ void AmerzoneGame::enter() {
 	vid->_tiledSurfacePtr->_frameAnim.onStop().add(this, &Game::onVideoFinished);
 	vid->setVisible(false);
 	_dialog2.load();
-	app->frontOrientationLayout().addChild(&_dialog2);
+	app->frontLayout().addChild(&_dialog2);
 	_question2.load();
 
 	TeInputMgr *inputMgr = g_engine->getInputMgr();
@@ -167,7 +167,7 @@ void AmerzoneGame::enter() {
 
 	_notifier.load();
 	_warpX = new TeWarp();
-	_warpX->setRotation(app->frontOrientationLayout().rotation());
+	_warpX->setRotation(app->frontLayout().rotation());
 	_warpX->init();
 	// TODO: Set FOV here?
 	_warpX->setVisible(true, false);
@@ -222,7 +222,7 @@ void AmerzoneGame::isInDrag(bool inDrag) {
 			TeVector3f32 mouseDir(mousePt.x - _mouseDragLast.x, mousePt.y - _mouseDragLast.y, 0);
 			if (app->inverseLook())
 				mouseDir = mouseDir * -1.0f;
-			const TeMatrix4x4 layoutRot = app->frontOrientationLayout().rotation().toTeMatrix();
+			const TeMatrix4x4 layoutRot = app->frontLayout().rotation().toTeMatrix();
 			TeVector3f32 dest = layoutRot * mouseDir;
 			dest.x() /= 2;
 			dest.y() /= 2;
@@ -237,7 +237,7 @@ void AmerzoneGame::leave(bool flag) {
 	_inGameGui.unload();
 	_question2.unload();
 	Application *app = g_engine->getApplication();
-	app->frontOrientationLayout().removeChild(&_dialog2);
+	app->frontLayout().removeChild(&_dialog2);
 	_dialog2.unload();
 	if (_warpX) {
 		delete _warpX;
@@ -246,7 +246,7 @@ void AmerzoneGame::leave(bool flag) {
 	if (_warpY) {
 		saveBackup("save.xml");
 	}
-	app->frontOrientationLayout().removeChild(&_inventoryMenu);
+	app->frontLayout().removeChild(&_inventoryMenu);
 	_inventoryMenu.unload();
 
 	// TODO: game does this.. doesn't this leak?
@@ -433,7 +433,7 @@ void AmerzoneGame::update() {
 		if (_isInDrag) {
 			TeVector2s32 mousePos = TeVector2s32(inputMgr->lastMousePos());
 			TeVector3f32 offset = TeVector3f32(mousePos - _mouseDragLast);
-			TeMatrix4x4 orientLayoutMatrix = app->frontOrientationLayout().rotation().toTeMatrix();
+			TeMatrix4x4 orientLayoutMatrix = app->frontLayout().rotation().toTeMatrix();
 			TeVector3f32 rotOffset = orientLayoutMatrix * offset;
 			if (app->inverseLook()) {
 				setAngleX(_orientationX + rotOffset.x() / 2);
diff --git a/engines/tetraedge/game/application.cpp b/engines/tetraedge/game/application.cpp
index aa097cc4896..6c126b54bc3 100644
--- a/engines/tetraedge/game/application.cpp
+++ b/engines/tetraedge/game/application.cpp
@@ -49,7 +49,7 @@ bool Application::_dontUpdateWhenApplicationPaused = false;
 Application::Application() : _finishedGame(false), _finishedFremium(false),
 _captureFade(false), _difficulty(1), _created(false), _tutoActivated(false),
 _drawShadows(true), _compassLook(false), _inverseLook(false),
-_permanentHelp(false) {
+_permanentHelp(true) {
 	//
 	// TODO: Game defaults _ratioStretched to false, but then
 	// the horizontally scrolling scenes don't scroll properly.
@@ -432,7 +432,7 @@ static void dumpLayout(TeLayout *layout, Common::String indent = "++") {
 	assert(layout);
 	if (!layout->worldVisible())
 		return;
-	debug("%s %s  pos:%s  worldScale:%s  userSize:%s  size:%s  col:%s", indent.c_str(), layout->name().c_str(),
+	debug("%s '%s'%s  pos:%s  worldScale:%s  userSize:%s  size:%s  col:%s", indent.c_str(), layout->name().c_str(), (layout->worldVisible() ? "" : " (invis)"),
 			layout->position().dump().c_str(), layout->worldScale().dump().c_str(),
 			layout->userSize().dump().c_str(), layout->size().dump().c_str(),
 			layout->color().dump().c_str());
diff --git a/engines/tetraedge/game/documents_browser.cpp b/engines/tetraedge/game/documents_browser.cpp
index 7921550242e..e368394c155 100644
--- a/engines/tetraedge/game/documents_browser.cpp
+++ b/engines/tetraedge/game/documents_browser.cpp
@@ -23,6 +23,7 @@
 
 #include "tetraedge/tetraedge.h"
 #include "tetraedge/game/application.h"
+#include "tetraedge/game/documents_browser_xml_parser.h"
 #include "tetraedge/game/syberia_game.h"
 #include "tetraedge/te/te_core.h"
 #include "tetraedge/te/te_lua_thread.h"
@@ -42,14 +43,14 @@ void DocumentsBrowser::enter() {
 void DocumentsBrowser::hideDocument() {
 	Common::String docName = _curDocName;
 	_curDocName.clear();
-	TeSpriteLayout *zoomedSprite = _gui1.spriteLayout("zoomedSprite");
+	TeSpriteLayout *zoomedSprite = _gui.spriteLayout("zoomedSprite");
 	if (!zoomedSprite)
 		return;
 	Application *app = g_engine->getApplication();
 	app->captureFade();
 	zoomedSprite->unload();
-	_gui1.buttonLayoutChecked("zoomed")->setVisible(false);
-	_gui2.unload();
+	_gui.buttonLayoutChecked("zoomed")->setVisible(false);
+	_zoomedDocGui.unload();
 	Game *game = g_engine->getGame();
 
 	bool callFn = true;
@@ -81,28 +82,30 @@ void DocumentsBrowser::leave() {
 
 void DocumentsBrowser::load() {
 	setVisible(false);
-	setName("documentsBrowser");
-
+	setName("_documentsBrowser");
 	setSizeType(RELATIVE_TO_PARENT);
-	const TeVector3f32 userSz = TeLayout::userSize();
-	setSize(TeVector3f32(1.0f, 1.0f, userSz.z()));
+	setSize(TeVector3f32(1.0f, 1.0f, userSize().z()));
 
-	_gui1.load("DocumentsBrowser/DocumentsBrowser.lua");
+	_gui.load("DocumentsBrowser/DocumentsBrowser.lua");
 
-	TeLayout *docBrowser = _gui1.layout("documentBrowser");
+	TeLayout *docBrowser = _gui.layout("documentBrowser");
 	if (docBrowser)
 		addChild(docBrowser);
 
-	TeButtonLayout *button = _gui1.buttonLayoutChecked("previousPage");
+	TeButtonLayout *button = _gui.buttonLayoutChecked("previousPage");
 	button->onMouseClickValidated().add(this, &DocumentsBrowser::onPreviousPage);
-	button = _gui1.buttonLayoutChecked("nextPage");
+	button = _gui.buttonLayoutChecked("nextPage");
 	button->onMouseClickValidated().add(this, &DocumentsBrowser::onNextPage);
-	button = _gui1.buttonLayoutChecked("zoomed");
+	button = _gui.buttonLayoutChecked("zoomed");
 	button->onMouseClickValidated().add(this, &DocumentsBrowser::onZoomedButton);
 	button->setVisible(false);
 
-	// Game tries to load a file that doesn't exist..
-	// TODO?? DocumentsBrowser::load: Game opens Documents.xml here
+	if (g_engine->gameIsAmerzone()) {
+		TeLayout *bglayout = _gui.layoutChecked("background");
+		bglayout->setRatioMode(RATIO_MODE_NONE);
+
+		loadXMLFile("DocumentsBrowser/Documents/Documents.xml");
+	}
 	_timer.start();
 }
 
@@ -110,13 +113,33 @@ void DocumentsBrowser::loadZoomed() {
 	_zoomedLayout.setSizeType(RELATIVE_TO_PARENT);
 	TeVector3f32 usersz = userSize();
 	_zoomedLayout.setSize(TeVector3f32(1.0f, 1.0f, usersz.z()));
-	TeLayout *zoomedChild = _gui1.layout("zoomed");
+	TeLayout *zoomedChild = _gui.layout("zoomed");
 	_zoomedLayout.addChild(zoomedChild);
 }
 
+void DocumentsBrowser::loadXMLFile(const Common::String &path) {
+	Common::FSNode node = g_engine->getCore()->findFile(path);
+	Common::File xmlfile;
+	xmlfile.open(node);
+	int64 fileLen = xmlfile.size();
+	char *buf = new char[fileLen + 1];
+	buf[fileLen] = '\0';
+	xmlfile.read(buf, fileLen);
+	const Common::String xmlContents = Common::String::format("<?xml version=\"1.0\" encoding=\"UTF-8\"?><document>%s</document>", buf);
+	delete [] buf;
+	xmlfile.close();
+
+	DocumentsBrowserXmlParser parser;
+	if (!parser.loadBuffer((const byte *)xmlContents.c_str(), xmlContents.size()))
+		error("Couldn't load inventory xml.");
+	if (!parser.parse())
+		error("Couldn't parse inventory xml.");
+	_documentData = parser._objects;
+}
+
 void DocumentsBrowser::currentPage(int setPage) {
 	const Common::String setPageName = Common::String::format("page%d", setPage);
-	TeLayout *pageLayout = _gui1.layout(setPageName);
+	TeLayout *pageLayout = _gui.layout(setPageName);
 	if (!pageLayout)
 		return;
 
@@ -125,12 +148,12 @@ void DocumentsBrowser::currentPage(int setPage) {
 	int pageNo = 0;
 	while (true) {
 		const Common::String pageName = Common::String::format("page%d", pageNo);
-		pageLayout = _gui1.layout(pageName);
+		pageLayout = _gui.layout(pageName);
 		if (!pageLayout)
 			break;
 		pageLayout->setVisible(pageNo == setPage);
 		const Common::String diodeName = Common::String::format("diode%d", pageNo);
-		_gui1.buttonLayoutChecked(diodeName)->setEnable(pageNo == setPage);
+		_gui.buttonLayoutChecked(diodeName)->setEnable(pageNo == setPage);
 		pageNo++;
 	}
 }
@@ -172,13 +195,13 @@ bool DocumentsBrowser::addDocument(Document *document) {
 	int pageno = 0;
 	while (true) {
 		Common::String pageName = Common::String::format("page%d", pageno);
-		TeLayout *page = _gui1.layout(pageName);
+		TeLayout *page = _gui.layout(pageName);
 		if (!page)
 			break;
 		int slotno = 0;
 		while (true) {
 			Common::String pageSlotName = Common::String::format("page%dSlot%d", pageno, slotno);
-			TeLayout *slot = _gui1.layout(pageSlotName);
+			TeLayout *slot = _gui.layout(pageSlotName);
 			if (!slot)
 				break;
 			if (slot->childCount() == 0) {
@@ -199,9 +222,15 @@ void DocumentsBrowser::addDocument(const Common::String &str) {
 		delete doc;
 }
 
-Common::String DocumentsBrowser::documentName(const Common::String &name) {
-	// Note: this returns a value from an xml file,
-	// but the xml file doesn't exist in either game.
+Common::String DocumentsBrowser::documentDescription(const Common::String &key) const {
+	if (_documentData.contains(key))
+		return _documentData.getVal(key)._description;
+	return "";
+}
+
+Common::String DocumentsBrowser::documentName(const Common::String &key) const {
+	if (_documentData.contains(key))
+		return _documentData.getVal(key)._name;
 	return "";
 }
 
@@ -209,7 +238,7 @@ void DocumentsBrowser::showDocument(const Common::String &docName, int startPage
 	_curPage = startPage;
 	_startPage = startPage;
 	_curDocName = docName;
-	_gui2.unload();
+	_zoomedDocGui.unload();
 	TeCore *core = g_engine->getCore();
 	const Common::Path docPathBase(Common::String::format("DocumentsBrowser/Documents/Documents/%s_zoomed_%d", docName.c_str(), (int)startPage));
 	Common::Path docPath = docPathBase.append(".png");
@@ -227,7 +256,7 @@ void DocumentsBrowser::showDocument(const Common::String &docName, int startPage
 	}
 	Application *app = g_engine->getApplication();
 	app->captureFade();
-	TeSpriteLayout *sprite = _gui1.spriteLayoutChecked("zoomedSprite");
+	TeSpriteLayout *sprite = _gui.spriteLayoutChecked("zoomedSprite");
 	//sprite->setSizeType(ABSOLUTE);
 	sprite->load(docNode);
 	TeVector2s32 spriteSize = sprite->_tiledSurfacePtr->tiledTexture()->totalSize();
@@ -235,17 +264,17 @@ void DocumentsBrowser::showDocument(const Common::String &docName, int startPage
 	TeVector3f32 winSize = app->getMainWindow().size();
 	sprite->setSize(TeVector3f32(1.0f, (4.0f / (winSize.y() / winSize.x() * 4.0f)) *
 							((float)spriteSize._y / (float)spriteSize._x), 0.0f));
-	TeScrollingLayout *scroll = _gui1.scrollingLayout("scroll");
+	TeScrollingLayout *scroll = _gui.scrollingLayout("scroll");
 	if (!scroll)
 		error("DocumentsBrowser::showDocument Couldn't fetch scroll object");
 	scroll->resetScrollPosition();
 	scroll->playAutoScroll();
 	Common::FSNode luaNode = core->findFile(docPathBase.append(".lua"));
 	if (luaNode.exists()) {
-		_gui2.load(luaNode);
+		_zoomedDocGui.load(luaNode);
 		error("Finish DocumentsBrowser::showDocument");
 	}
-	_gui1.layoutChecked("zoomed")->setVisible(true);
+	_gui.layoutChecked("zoomed")->setVisible(true);
 	_zoomCount = 0;
 	app->fade();
 }
@@ -255,13 +284,13 @@ void DocumentsBrowser::unload() {
 	int pageno = 0;
 	while (true) {
 		Common::String pageName = Common::String::format("page%d", pageno);
-		TeLayout *page = _gui1.layout(pageName);
+		TeLayout *page = _gui.layout(pageName);
 		if (!page)
 			break;
 		int slotno = 0;
 		while (true) {
 			Common::String pageSlotName = Common::String::format("page%dSlot%d", pageno, slotno);
-			TeLayout *slot = _gui1.layout(pageSlotName);
+			TeLayout *slot = _gui.layout(pageSlotName);
 			if (!slot)
 				break;
 			for (int i = 0; i < slot->childCount(); i++) {
@@ -273,7 +302,7 @@ void DocumentsBrowser::unload() {
 		}
 		pageno++;
 	}
-	_gui1.unload();
+	_gui.unload();
 }
 
 } // end namespace Tetraedge
diff --git a/engines/tetraedge/game/documents_browser.h b/engines/tetraedge/game/documents_browser.h
index 2504d2e3d6f..db6143063c6 100644
--- a/engines/tetraedge/game/documents_browser.h
+++ b/engines/tetraedge/game/documents_browser.h
@@ -30,6 +30,12 @@ namespace Tetraedge {
 
 class DocumentsBrowser : public TeLayout {
 public:
+	struct DocumentData {
+		Common::String _id;
+		Common::String _name;
+		Common::String _description; // seems always empty..
+	};
+
 	DocumentsBrowser();
 
 	bool addDocument(Document *document);
@@ -40,8 +46,8 @@ public:
 		return 1;
 	}
 
-	Common::String documentDescription(const Common::String &name);
-	Common::String documentName(const Common::String &name);
+	Common::String documentDescription(const Common::String &name) const;
+	Common::String documentName(const Common::String &name) const;
 
 	void enter();
 	void hideDocument();
@@ -51,6 +57,16 @@ public:
 	void loadZoomed();
 	// void saveToBackup(TiXmlNode *node);
 
+	void showDocument(const Common::String &str, int startPage);
+	void unload();
+
+	TeLayout &zoomedLayout() { return _zoomedLayout; }
+
+	TeLuaGUI &gui() { return _gui; }
+
+private:
+	void loadXMLFile(const Common::String &path);
+
 	void onDocumentSelected(Document *doc);
 	bool onNextPage();
 	bool onPreviousPage();
@@ -79,14 +95,7 @@ public:
 	bool onShowedDocumentButton18();
 	bool onShowedDocumentButton19();
 
-	void showDocument(const Common::String &str, int startPage);
-	void unload();
-
-	TeLayout &zoomedLayout() { return _zoomedLayout; }
-
-	TeLuaGUI &gui1() { return _gui1; }
 
-private:
 	TeTimer _timer;
 	TeLayout _zoomedLayout;
 	uint64 _curPage;
@@ -94,9 +103,10 @@ private:
 	int _zoomCount;
 	Common::String _curDocName;
 
-	TeLuaGUI _gui1;
-	TeLuaGUI _gui2;
-	// TiXmlDocument _xmldoc;
+	TeLuaGUI _gui;
+	TeLuaGUI _zoomedDocGui;
+
+	Common::HashMap<Common::String, DocumentData> _documentData;
 };
 
 } // end namespace Tetraedge
diff --git a/engines/tetraedge/game/documents_browser_xml_parser.cpp b/engines/tetraedge/game/documents_browser_xml_parser.cpp
new file mode 100644
index 00000000000..0797a935029
--- /dev/null
+++ b/engines/tetraedge/game/documents_browser_xml_parser.cpp
@@ -0,0 +1,34 @@
+/* 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/documents_browser_xml_parser.h"
+
+namespace Tetraedge {
+
+bool DocumentsBrowserXmlParser::parserCallback_Document(ParserNode *node) {
+	DocumentsBrowser::DocumentData data;
+	data._id = node->values["id"];
+	data._name = node->values["name"];
+	_objects.setVal(data._id, data);
+	return true;
+}
+
+} // end namespace Tetraedge
diff --git a/engines/tetraedge/game/documents_browser_xml_parser.h b/engines/tetraedge/game/documents_browser_xml_parser.h
new file mode 100644
index 00000000000..d2c5cf413e3
--- /dev/null
+++ b/engines/tetraedge/game/documents_browser_xml_parser.h
@@ -0,0 +1,55 @@
+/* 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/documents_browser.h"
+
+#ifndef TETRAEDGE_GAME_DOCUMENTS_BROWSER_XML_PARSER_H
+#define TETRAEDGE_GAME_DOCUMENTS_BROWSER_XML_PARSER_H
+
+namespace Tetraedge {
+
+class DocumentsBrowserXmlParser : public Common::XMLParser {
+public:
+	// Parser
+	CUSTOM_XML_PARSER(DocumentsBrowserXmlParser) {
+		XML_KEY(document)
+			XML_KEY(Document)
+				XML_PROP(id, true)
+				XML_PROP(name, true)
+				XML_PROP(description, false)
+			KEY_END()
+		KEY_END()
+	} PARSER_END()
+
+	bool parserCallback_document(ParserNode *node) { return true; };
+	bool parserCallback_Document(ParserNode *node);
+
+public:
+	Common::HashMap<Common::String, DocumentsBrowser::DocumentData> _objects;
+
+};
+
+} // end namespace Tetraedge
+
+#endif // TETRAEDGE_GAME_DOCUMENTS_BROWSER_XML_PARSER_H
diff --git a/engines/tetraedge/game/game.cpp b/engines/tetraedge/game/game.cpp
index 3864719d286..3826d9c0338 100644
--- a/engines/tetraedge/game/game.cpp
+++ b/engines/tetraedge/game/game.cpp
@@ -97,7 +97,7 @@ TeSpriteLayout *Game::findSpriteLayoutByName(TeLayout *parent, const Common::Str
 }
 
 bool Game::isDocumentOpened() {
-	return _documentsBrowser.gui1().layoutChecked("zoomed")->visible();
+	return _documentsBrowser.gui().layoutChecked("zoomed")->visible();
 }
 
 bool Game::isMoviePlaying() {
diff --git a/engines/tetraedge/game/game.h b/engines/tetraedge/game/game.h
index 451c7c28cd1..24c94cad39b 100644
--- a/engines/tetraedge/game/game.h
+++ b/engines/tetraedge/game/game.h
@@ -101,6 +101,7 @@ public:
 	DocumentsBrowser &documentsBrowser() { return _documentsBrowser; }
 	bool entered() const { return _entered; }
 	bool running() const { return _running; }
+	void setRunning(bool val) { _running = val; }
 	bool luaShowOwnerError() const { return _luaShowOwnerError; }
 
 	bool _returnToMainMenu;
diff --git a/engines/tetraedge/game/inventory.cpp b/engines/tetraedge/game/inventory.cpp
index e75ad1f090d..52253dd53d9 100644
--- a/engines/tetraedge/game/inventory.cpp
+++ b/engines/tetraedge/game/inventory.cpp
@@ -34,27 +34,34 @@
 
 namespace Tetraedge {
 
-Inventory::Inventory() : _cellphone(nullptr), _selectedObject(nullptr) {
+Inventory::Inventory() : _cellphone(nullptr), _selectedObject(nullptr), _currentPage(0) {
 }
 
 Inventory::~Inventory() {
-	if (_cellphone)
+	if (_cellphone) {
 		_cellphone->unload();
-	delete _cellphone;
+		delete _cellphone;
+	}
 }
 
 void Inventory::enter() {
 	setVisible(true);
-	Game *game = g_engine->getGame();
-	Character *character = game->scene()._character;
-	character->stop();
-	character->setAnimation(character->characterSettings()._idleAnimFileName, true);
-	_gui.layoutChecked("textObject")->setVisible(false);
-
-	if (!game->_firstInventory) {
-		_gui.buttonLayoutChecked("Aide")->setVisible(false);
+	
+	if (g_engine->gameIsAmerzone()) {
+		currentPage(_currentPage);
 	} else {
-		game->_firstInventory = false;
+		Game *game = g_engine->getGame();
+		Character *character = game->scene()._character;
+		character->stop();
+		character->setAnimation(character->characterSettings()._idleAnimFileName, true);
+
+		_gui.layoutChecked("textObject")->setVisible(false);
+
+		if (!game->_firstInventory && !g_engine->gameIsAmerzone()) {
+			_gui.buttonLayoutChecked("Aide")->setVisible(false);
+		} else {
+			game->_firstInventory = false;
+		}
 	}
 
 	if (_selectedObject)
@@ -71,39 +78,52 @@ void Inventory::leave() {
 }
 
 void Inventory::load() {
-	setName("inventory");
+	setName("_inventory");
 	setSizeType(RELATIVE_TO_PARENT);
 	setSize(TeVector3f32(1.0f, 1.0f, userSize().z()));
 	_gui.load("Inventory/Inventory.lua");
 	TeLayout *invlayout = _gui.layoutChecked("inventory");
 	addChild(invlayout);
 
-	TeButtonLayout *btn;
-	btn = _gui.buttonLayoutChecked("cellphone");
-	btn->onMouseClickValidated().add(this, &Inventory::onVisibleCellphone);
+	if (g_engine->gameIsAmerzone()) {
+		TeLayout *bglayout = _gui.layoutChecked("background");
+		bglayout->setRatioMode(RATIO_MODE_NONE);
 
-	btn = _gui.buttonLayoutChecked("prendre");
-	btn->setVisible(false);
-	btn->onMouseClickValidated().add(this, &Inventory::onTakeObjectSelected);
+		TeButtonLayout *btn;
+		btn = _gui.buttonLayoutChecked("previousPage");
+		btn->onMouseClickValidated().add(this, &Inventory::onPreviousPage);
+	
+		btn = _gui.buttonLayoutChecked("nextPage");
+		btn->onMouseClickValidated().add(this, &Inventory::onNextPage);
+	} else {
+		TeButtonLayout *btn;
+		btn = _gui.buttonLayoutChecked("cellphone");
+		btn->onMouseClickValidated().add(this, &Inventory::onVisibleCellphone);
+
+		btn = _gui.buttonLayoutChecked("prendre");
+		btn->setVisible(false);
+		btn->onMouseClickValidated().add(this, &Inventory::onTakeObjectSelected);
 
-	btn = _gui.buttonLayoutChecked("lire");
-	btn->setEnable(false);
-	btn->onMouseClickValidated().add(this, &Inventory::onZoomed);
+		btn = _gui.buttonLayoutChecked("lire");
+		btn->setEnable(false);
+		btn->onMouseClickValidated().add(this, &Inventory::onZoomed);
 
-	btn = _gui.buttonLayoutChecked("quitButton");
-	btn->setVisible(true);
-	btn->onMouseClickValidated().add(this, &Inventory::onQuitButton);
+		btn = _gui.buttonLayoutChecked("quitButton");
+		btn->setVisible(true);
+		btn->onMouseClickValidated().add(this, &Inventory::onQuitButton);
 
-	btn = _gui.buttonLayoutChecked("quitBackground");
-	btn->setVisible(true);
-	btn->onMouseClickValidated().add(this, &Inventory::onQuitButton);
+		btn = _gui.buttonLayoutChecked("quitBackground");
+		btn->setVisible(true);
+		btn->onMouseClickValidated().add(this, &Inventory::onQuitButton);
 
-	btn = _gui.buttonLayoutChecked("mainMenuButton");
-	btn->setVisible(true);
-	btn->onMouseClickValidated().add(this, &Inventory::onMainMenuButton);
+		btn = _gui.buttonLayoutChecked("mainMenuButton");
+		btn->setVisible(true);
+		btn->onMouseClickValidated().add(this, &Inventory::onMainMenuButton);
 
+		loadCellphone();
+	}
+	_currentPage = 0;
 	_selectedObject = nullptr;
-	loadCellphone();
 
 	const Common::Path objectsPathPrefix("Inventory/Objects/Objects_");
 	const Common::String &lang = g_engine->getCore()->language();
@@ -120,7 +140,7 @@ void Inventory::load() {
 
 	loadXMLFile(langXmlPath);
 
-	TeLayout *layout = _gui.layout("selectionSprite");
+	TeLayout *layout = _gui.layoutChecked("selectionSprite");
 	layout->setVisible(false);
 	_invObjects.clear();
 
@@ -290,6 +310,35 @@ Common::String Inventory::objectName(const Common::String &objId) {
 	return _objectData.getVal(objId)._name;
 }
 
+void Inventory::currentPage(uint page) {
+	TeLayout *pageLayout = _gui.layout(Common::String::format("page%d", page));
+	if (pageLayout) {
+		_currentPage = page;
+		uint p = 0;
+		while (true) {
+			pageLayout = _gui.layout(Common::String::format("page%d", p));
+			if (!pageLayout)
+				break;
+			pageLayout->setVisible(p == _currentPage);
+			TeButtonLayout *diodeLayout = _gui.buttonLayoutChecked(Common::String::format("diode%d", p));
+			diodeLayout->setEnable(p != _currentPage);
+			p++;
+		}
+		if (_selectedObject)
+			selectedObject(_selectedObject);
+	}
+}
+
+bool Inventory::onPreviousPage() {
+	currentPage(_currentPage - 1);
+	return false;
+}
+
+bool Inventory::onNextPage() {
+	currentPage(_currentPage + 1);
+	return false;
+}
+
 bool Inventory::onMainMenuButton() {
 	leave();
 	Game *game = g_engine->getGame();
diff --git a/engines/tetraedge/game/inventory.h b/engines/tetraedge/game/inventory.h
index 62e98a1b02e..4a3eb2ea126 100644
--- a/engines/tetraedge/game/inventory.h
+++ b/engines/tetraedge/game/inventory.h
@@ -59,13 +59,6 @@ public:
 	Common::String objectDescription(const Common::String &objname);
 	Common::String objectName(const Common::String &objname);
 
-	bool onMainMenuButton();
-	bool onObjectSelected(InventoryObject &obj);
-	bool onQuitButton();
-	bool onTakeObjectSelected();
-	bool onVisibleCellphone();
-	bool onZoomed();
-
 	void pauseAnims();
 	void unPauseAnims();
 
@@ -85,6 +78,19 @@ public:
 	Cellphone *cellphone() { return _cellphone; }
 
 private:
+	// Amerzone navigation events
+	void currentPage(uint page);
+	bool onPreviousPage();
+	bool onNextPage();
+
+	// Syberia navigation events
+	bool onMainMenuButton();
+	bool onObjectSelected(InventoryObject &obj);
+	bool onQuitButton();
+	bool onTakeObjectSelected();
+	bool onVisibleCellphone();
+	bool onZoomed();
+
 	void loadXMLFile(const Common::Path &path);
 
 	TeLuaGUI _gui;
@@ -95,6 +101,8 @@ private:
 
 	// This is used when we need a reference to a blank str in selectedObject()
 	const Common::String _blankStr;
+	
+	uint _currentPage;
 
 	TeTimer _selectedTimer;
 };
diff --git a/engines/tetraedge/game/inventory_menu.cpp b/engines/tetraedge/game/inventory_menu.cpp
index ef7c2182373..7e502226eb1 100644
--- a/engines/tetraedge/game/inventory_menu.cpp
+++ b/engines/tetraedge/game/inventory_menu.cpp
@@ -31,8 +31,11 @@ InventoryMenu::InventoryMenu() {
 
 void InventoryMenu::enter() {
 	Application *app = g_engine->getApplication();
+	if (g_engine->gameIsAmerzone())
+		g_engine->getGame()->setRunning(false);
 	app->mouseCursorLayout().load(app->defaultCursor());
 
+	_gui.buttonLayoutChecked("quitButton")->setEnable(true);
 	_gui.layoutChecked("inventoryMenu")->setVisible(true);
 	onInventoryButton();
 }
@@ -44,16 +47,29 @@ void InventoryMenu::leave() {
 	TeLayout *invMenu = _gui.layout("inventoryMenu");
 	if (invMenu)
 		invMenu->setVisible(false);
+	if (g_engine->gameIsAmerzone())
+		game->setRunning(true);
 }
 
 void InventoryMenu::load() {
-	setName("inventoryMenu");
+	setName("_inventoryMenu");
 	setSizeType(RELATIVE_TO_PARENT);
 	TeVector3f32 usersz = userSize();
 	setSize(TeVector3f32(1.0f, 1.0f, usersz.z()));
 
 	_gui.load("InventoryMenu/InventoryMenu.lua");
+
+	Game *game = g_engine->getGame();
+	if (g_engine->gameIsAmerzone()) {
+		_gui.layoutChecked("inventoryMenu")->setRatioMode(RATIO_MODE_NONE);
+		game->inventory().load();
+		game->documentsBrowser().load();
+		addChild(&game->inventory());
+		addChild(&game->documentsBrowser());
+	}
+
 	addChild(_gui.layoutChecked("inventoryMenu"));
+
 	_gui.buttonLayoutChecked("quitButton")->onMouseClickValidated()
 				.add(this, &InventoryMenu::onQuitButton);
 	// Quit background is only in Syberia 1 and 2 (not amerzone)
@@ -69,7 +85,9 @@ void InventoryMenu::load() {
 
 	_gui.layoutChecked("inventoryMenu")->setVisible(false);
 
-	setVisible(false);
+	if (g_engine->gameIsAmerzone()) {
+		game->documentsBrowser().loadZoomed();
+	}
 }
 
 void InventoryMenu::unload() {
diff --git a/engines/tetraedge/game/inventory_objects_xml_parser.h b/engines/tetraedge/game/inventory_objects_xml_parser.h
index 904fb1d7d87..f8c5bec0f77 100644
--- a/engines/tetraedge/game/inventory_objects_xml_parser.h
+++ b/engines/tetraedge/game/inventory_objects_xml_parser.h
@@ -38,6 +38,7 @@ public:
 				XML_PROP(id, true)
 				XML_PROP(name, true)
 				XML_PROP(isDocument, false)
+				XML_PROP(description, false)
 			KEY_END()
 		KEY_END()
 	} PARSER_END()
diff --git a/engines/tetraedge/game/main_menu.cpp b/engines/tetraedge/game/main_menu.cpp
index f474f020f36..c2b03298510 100644
--- a/engines/tetraedge/game/main_menu.cpp
+++ b/engines/tetraedge/game/main_menu.cpp
@@ -78,6 +78,7 @@ void MainMenu::enter() {
 	// WORKAROUND: This is set to PanScan ratio 1.0, but with our code
 	// but that shrinks it down to pillarboxed.  Force back to full size.
 	//
+	
 	TeLayout *background;
 	if (layout("background"))
 		background = layoutChecked("background");
@@ -86,7 +87,6 @@ void MainMenu::enter() {
 	assert(background);
 	background->setRatioMode(TeILayout::RATIO_MODE_NONE);
 
-
 	app->mouseCursorLayout().setVisible(true);
 	app->mouseCursorLayout().load(app->defaultCursor());
 
diff --git a/engines/tetraedge/module.mk b/engines/tetraedge/module.mk
index 6abed82f33e..28a2947c196 100644
--- a/engines/tetraedge/module.mk
+++ b/engines/tetraedge/module.mk
@@ -16,6 +16,7 @@ MODULE_OBJS := \
 	game/dialog2.o \
 	game/document.o \
 	game/documents_browser.o \
+	game/documents_browser_xml_parser.o \
 	game/gallery_menu.o \
 	game/game.o \
 	game/game_achievements.o \
diff --git a/engines/tetraedge/te/te_button_layout.cpp b/engines/tetraedge/te/te_button_layout.cpp
index 37c9e932342..9d07c32948d 100644
--- a/engines/tetraedge/te/te_button_layout.cpp
+++ b/engines/tetraedge/te/te_button_layout.cpp
@@ -111,21 +111,24 @@ void TeButtonLayout::load(const Common::String &upImg, const Common::String &dow
 	TeSpriteLayout *upSprite = nullptr;
 	if (upImg.size()) {
 		upSprite = new TeSpriteLayout();
-		upSprite->load(upImg);
+		if (!upSprite->load(upImg))
+			warning("Failed to load button up img %s", upImg.c_str());
 	}
 	setUpLayout(upSprite);
 
 	TeSpriteLayout *downSprite = nullptr;
 	if (downImg.size()) {
 		downSprite = new TeSpriteLayout();
-		downSprite->load(downImg);
+		if (!downSprite->load(upImg))
+			warning("Failed to load button down img %s", downImg.c_str());
 	}
 	setDownLayout(downSprite);
 
 	TeSpriteLayout *overSprite = nullptr;
 	if (overImg.size()) {
 		overSprite = new TeSpriteLayout();
-		overSprite->load(overImg);
+		if (!overSprite->load(overImg))
+			warning("Failed to load button over img %s", overImg.c_str());
 	}
 	setRollOverLayout(overSprite);
 	setHitZone(nullptr);
@@ -263,6 +266,7 @@ void TeButtonLayout::setDisabledLayout(TeLayout *disabledLayout) {
 
 	_disabledLayout = disabledLayout;
 	if (_disabledLayout) {
+		_sizeChanged = true;
 		addChild(_disabledLayout);
 		//_disabledLayout->setColor(TeColor(0, 0, 0, 0));
 		//_disabledLayout->setName(name() + "_disabledLayout");
@@ -277,6 +281,7 @@ void TeButtonLayout::setHitZone(TeLayout *hitZoneLayout) {
 
 	_hitZoneLayout = hitZoneLayout;
 	if (_hitZoneLayout) {
+		_sizeChanged = true;
 		addChild(_hitZoneLayout);
 		//_hitZoneLayout->setColor(TeColor(0, 0, 0xff, 0xff));
 		//_hitZoneLayout->setName(name() + "_hitZoneLayout");
@@ -291,7 +296,7 @@ void TeButtonLayout::setDownLayout(TeLayout *downLayout) {
 		addChild(downLayout);
 	_downLayout = downLayout;
 
-	if (sizeType() == RELATIVE_TO_PARENT &&
+	if (sizeType() == ABSOLUTE &&
 			size().x() == 1.0f && size().y() == 1.0f &&
 			!_upLayout && _downLayout) {
 		setSize(_downLayout->size());
@@ -331,7 +336,7 @@ void TeButtonLayout::setUpLayout(TeLayout *upLayout) {
 		addChild(upLayout);
 	_upLayout = upLayout;
 
-	if (sizeType() == RELATIVE_TO_PARENT &&
+	if (sizeType() == ABSOLUTE &&
 			size().x() == 1.0f && size().y() == 1.0f &&
 			!_downLayout && _upLayout) {
 		setSize(_upLayout->size());
diff --git a/engines/tetraedge/te/te_marker.cpp b/engines/tetraedge/te/te_marker.cpp
index 24177ad5063..292a70b02ce 100644
--- a/engines/tetraedge/te/te_marker.cpp
+++ b/engines/tetraedge/te/te_marker.cpp
@@ -28,23 +28,27 @@ TeMarker::TeMarker() : _visible(true), _isActive(false) {
 
 void TeMarker::active(bool val) {
 	_isActive = val;
-	_button.setVisible(!_visible && val);
+	_button.setVisible(_visible && val);
 }
 
-void TeMarker::update(TeCamera *camera) {
+void TeMarker::update(TeCamera &camera) {
+	_button.setVisible(true);
 	if (!_visible)
 		return;
-	const TeVector3f32 transformLoc = camera->transformCoord(_loc);
+	const TeVector3f32 transformLoc = camera.transformCoord(_loc);
 	const TeVector3f32 btnSize = _button.size();
-	if (transformLoc.z() < 0) {
-		_button.setPosition(TeVector3f32(btnSize.x(), btnSize.y(), _someFloat));
+	_button.setPositionType(TeILayout::ABSOLUTE);
+	if (transformLoc.z() < 1.0f) {
+		// Behind the camera, move off-screen.
+		_button.setPosition(TeVector3f32(-btnSize.x(), -btnSize.y(), _zLoc));
 	} else {
-		TeVector3f32 transformLoc2(transformLoc.x() + btnSize.x() / 2, transformLoc.y() + btnSize.y() / 2, _someFloat);
+		TeVector3f32 buttonMiddle(transformLoc.x() - btnSize.x() / 2, transformLoc.y() - btnSize.y() / 2, _zLoc);
 		// TODO: device rotation (maybe?) is taken account of here
 		// in original, should we do that?
-		TeVector3f32 newScale(480.0f / camera->getViewportWidth(), 320.0f / camera->getViewportHeight(), 1.0);
+		TeVector3f32 newScale(480.0f / camera.getViewportWidth(), 320.0f / camera.getViewportHeight(), 1.0);
 		_button.setScale(newScale);
-		_button.setPosition(TeVector3f32(newScale.x() * transformLoc2.x(), newScale.y() * transformLoc2.y(), newScale.z()));
+		_button.setPosition(TeVector3f32(/*newScale.x() * */ buttonMiddle.x(), /*newScale.y() * */ buttonMiddle.y(), buttonMiddle.z()));
+		//debug("Updated button pos to %s (scale %s middle %s)", _button.position().dump().c_str(), newScale.dump().c_str(), buttonMiddle.dump().c_str());
 	}
 }
 
diff --git a/engines/tetraedge/te/te_marker.h b/engines/tetraedge/te/te_marker.h
index 5f38ae9b370..33491100e41 100644
--- a/engines/tetraedge/te/te_marker.h
+++ b/engines/tetraedge/te/te_marker.h
@@ -34,18 +34,18 @@ public:
 	TeMarker();
 
 	void active(bool val);
-	void update(TeCamera *camera);
+	void update(TeCamera &camera);
 	void visible(bool val);
 
 	TeButtonLayout &button() { return _button; }
 	TeVector3f32 &loc() { return _loc; }
 
-	void setSomeFloat(float f) { _someFloat = f; }
+	void setZLoc(float f) { _zLoc = f; }
 
 private:
 	bool _visible;
 	bool _isActive;
-	float _someFloat;
+	float _zLoc;
 	TeVector3f32 _loc;
 	// Note: this is a TeSpriteButton in the original, updated
 	// to use the newer ButtonLayout
diff --git a/engines/tetraedge/te/te_scene_warp.cpp b/engines/tetraedge/te/te_scene_warp.cpp
index a96bb8220d3..cb427b6f3d2 100644
--- a/engines/tetraedge/te/te_scene_warp.cpp
+++ b/engines/tetraedge/te/te_scene_warp.cpp
@@ -19,6 +19,8 @@
  *
  */
 
+#include "tetraedge/tetraedge.h"
+#include "tetraedge/te/te_core.h"
 #include "tetraedge/te/te_scene_warp.h"
 #include "tetraedge/te/te_scene_warp_xml_parser.h"
 
@@ -74,6 +76,10 @@ bool TeSceneWarp::load(const Common::String &name, TeWarp *warp, bool flag) {
 	_name = name;
 
 	TeSceneWarpXmlParser parser(this, flag);
+	TeCore *core = g_engine->getCore();
+	Common::FSNode node = core->findFile(name);
+	parser.loadFile(node);
+	parser.parse();
 
 	if (flag) {
 		// Line 357 ~ 426, plus other fixups
diff --git a/engines/tetraedge/te/te_scene_warp_xml_parser.cpp b/engines/tetraedge/te/te_scene_warp_xml_parser.cpp
index 69cc00dc561..dfa54465b0f 100644
--- a/engines/tetraedge/te/te_scene_warp_xml_parser.cpp
+++ b/engines/tetraedge/te/te_scene_warp_xml_parser.cpp
@@ -57,7 +57,7 @@ bool TeSceneWarpXmlParser::parserCallback_marker(ParserNode *node) {
 		} else {
 			marker->visible(false);
 		}
-		marker->setSomeFloat(999.0f);
+		marker->setZLoc(999.0f);
 		_sceneWarp->_warp->sendMarker(exit._name, exit._markerId);
 	} else if (_objType == kObjObject) {
 		TeSceneWarp::Object &obj = _sceneWarp->_objects.back();
@@ -70,7 +70,7 @@ bool TeSceneWarpXmlParser::parserCallback_marker(ParserNode *node) {
 		} else {
 			marker->visible(false);
 		}
-		marker->setSomeFloat(999.0f);
+		marker->setZLoc(999.0f);
 		if (_sceneWarp->_warp->hasObjectOrAnim(obj._name)) {
 			_sceneWarp->_warp->sendMarker(obj._name, obj._markerId);
 		}
@@ -97,7 +97,7 @@ bool TeSceneWarpXmlParser::parserCallback_block(ParserNode *node) {
 		bloc.color(TeColor(0, 0, 0xff, 0x80));
 		exit._warpBlocs.push_back(bloc);
 	} // else, create a TeWarp::Block which we do after parsing.
-	error("TODO: Finish TeSceneWarpXmlParser::parserCallback_block");
+	return true;
 }
 
 bool TeSceneWarpXmlParser::parserCallback_object(ParserNode *node) {
diff --git a/engines/tetraedge/te/te_scene_warp_xml_parser.h b/engines/tetraedge/te/te_scene_warp_xml_parser.h
index 1049ba97d32..6bf6b3f8ebe 100644
--- a/engines/tetraedge/te/te_scene_warp_xml_parser.h
+++ b/engines/tetraedge/te/te_scene_warp_xml_parser.h
@@ -41,6 +41,8 @@ public:
 	// Parser
 	CUSTOM_XML_PARSER(TeSceneWarpXmlParser) {
 		XML_KEY(FileFormatVersion)
+			XML_PROP(major, true)
+			XML_PROP(minor, true)
 		KEY_END()
 		XML_KEY(exit)
 			XML_PROP(linkedWarp, true)
diff --git a/engines/tetraedge/te/te_warp.cpp b/engines/tetraedge/te/te_warp.cpp
index 5339b5a514b..9a524621d34 100644
--- a/engines/tetraedge/te/te_warp.cpp
+++ b/engines/tetraedge/te/te_warp.cpp
@@ -153,8 +153,10 @@ void TeWarp::configMarker(const Common::String &objname, int markerImgNo, long m
 		foundId = exit->_markerId;
 	} else {
 		AnimData *anim = findAnimation(objname);
-		if (!anim || anim->_markerIds.empty())
+		if (!anim || anim->_markerIds.empty()) {
+			warning("configMarker: Didn't find marker %s", objname.c_str());
 			return;
+		}
 		foundId = anim->_markerIds[0];
 	}
 	assert(foundId >= 0 && foundId < _warpMarkers.size());
@@ -175,10 +177,14 @@ void TeWarp::configMarker(const Common::String &objname, int markerImgNo, long m
 		if (!btnUp)
 			error("Loading button image %s failed", markerPath.c_str());
 		warning("TeWarp::configMarker: set anim values and something else here?");
-		//btnUp->_tiledSurfacePtr->_frameAnim._repeatCount = -1;
-		//btnUp->_tiledSurfacePtr->_frameAnim.setFrameRate(8.0);
+		btnUp->_tiledSurfacePtr->_frameAnim._repeatCount = -1;
+		btnUp->_tiledSurfacePtr->_frameAnim.setFrameRate(8.0);
 		btnUp->play();
 		warpMarker->marker()->visible(true);
+		// The game uses TeSprite, but we use the layout system instead.
+		TeLayout &frontLayout = g_engine->getApplication()->frontLayout();
+		// Ensure markers appear below menus and videos.
+		frontLayout.addChildBefore(&warpMarker->marker()->button(), frontLayout.child(0));
 	}
 }
 
@@ -198,7 +204,7 @@ TeWarp::Exit *TeWarp::findExit(const Common::String &objname, bool flag) {
 		fullName = Common::String("3D\\") + objname;
 
 	for (auto &e : _exitList) {
-		if (e._name == fullName)
+		if (e._linkedWarpPath.contains(fullName))
 			return &e;
 	}
 	return nullptr;
@@ -409,7 +415,7 @@ void TeWarp::sendExit(TeWarp::Exit &exit) {
 	assert(marker);
 	marker->button().load("2D/Menus/InGame/Marker_0.png", "2D/Menus/InGame/Marker_0_over.png", "");
 	marker->visible(false);
-	marker->setSomeFloat(-999.0f);
+	marker->setZLoc(-999.0f);
 	_exitList.push_back(exit);
 }
 
@@ -493,7 +499,7 @@ void TeWarp::render() {
 	}
 
 	for (auto &warpMarker : _warpMarkers) {
-		warpMarker->marker()->update(&_camera);
+		warpMarker->marker()->update(_camera);
 	}
 
 	renderer->setCurrentColor(TeColor(255, 255, 255, 255));
diff --git a/engines/tetraedge/tetraedge.cpp b/engines/tetraedge/tetraedge.cpp
index 470b052d489..2291f43d52c 100644
--- a/engines/tetraedge/tetraedge.cpp
+++ b/engines/tetraedge/tetraedge.cpp
@@ -195,11 +195,11 @@ void TetraedgeEngine::configureSearchPaths() {
 }
 
 int TetraedgeEngine::getDefaultScreenWidth() const {
-	return 800;
+	return gameIsAmerzone() ? 1365 : 800;
 }
 
 int TetraedgeEngine::getDefaultScreenHeight() const {
-	return 600;
+	return gameIsAmerzone() ? 768 : 600;
 }
 
 bool TetraedgeEngine::onKeyUp(const Common::KeyState &state) {


Commit: 7a515a4a89056a220ade520d82213a37056b9b2c
    https://github.com/scummvm/scummvm/commit/7a515a4a89056a220ade520d82213a37056b9b2c
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-04-29T20:30:27+09:00

Commit Message:
TETRAEDGE: Progress implementing animated Amerzone markers

Changed paths:
    engines/tetraedge/game/amerzone_game.cpp
    engines/tetraedge/te/te_camera.cpp
    engines/tetraedge/te/te_core.cpp
    engines/tetraedge/te/te_core.h
    engines/tetraedge/te/te_frame_anim.h
    engines/tetraedge/te/te_image.cpp
    engines/tetraedge/te/te_marker.cpp
    engines/tetraedge/te/te_png.cpp
    engines/tetraedge/te/te_png.h
    engines/tetraedge/te/te_scene_warp_xml_parser.cpp
    engines/tetraedge/te/te_scummvm_codec.cpp
    engines/tetraedge/te/te_scummvm_codec.h
    engines/tetraedge/te/te_sprite_layout.cpp
    engines/tetraedge/te/te_tiled_surface.cpp
    engines/tetraedge/te/te_warp.cpp


diff --git a/engines/tetraedge/game/amerzone_game.cpp b/engines/tetraedge/game/amerzone_game.cpp
index 506947e504a..bd5c465e1d8 100644
--- a/engines/tetraedge/game/amerzone_game.cpp
+++ b/engines/tetraedge/game/amerzone_game.cpp
@@ -73,8 +73,8 @@ bool AmerzoneGame::changeWarp(const Common::String &zone, const Common::String &
 		_warpY = new TeWarp();
 		_warpY->setRotation(app->frontLayout().rotation());
 		_warpY->init();
-		float fov = 45.0f; //TODO: g_engine->getCore()->fileFlagSystemFlagsContains("HD") ? 60.0f : 45.0f;
-		_warpY->setFov(fov);
+		float fov = 60.0f; //TODO: g_engine->getCore()->fileFlagSystemFlagsContains("HD") ? 60.0f : 45.0f;
+		_warpY->setFov((float)(fov * M_PI / 180.0));
 	}
 	_warpY->load(zone, false);
 	_warpY->setVisible(true, false);
@@ -169,7 +169,8 @@ void AmerzoneGame::enter() {
 	_warpX = new TeWarp();
 	_warpX->setRotation(app->frontLayout().rotation());
 	_warpX->init();
-	// TODO: Set FOV here?
+	float fov = 60.0f; //TODO: g_engine->getCore()->fileFlagSystemFlagsContains("HD") ? 60.0f : 45.0f;
+	_warpX->setFov((float)(fov * M_PI / 180.0));
 	_warpX->setVisible(true, false);
 	_luaContext.create();
 	_luaScript.attachToContext(&_luaContext);
@@ -207,6 +208,7 @@ void AmerzoneGame::isInDrag(bool inDrag) {
 	const Common::Point mousePt = g_engine->getInputMgr()->lastMousePos();
 	if (inDrag != _isInDrag) {
 		_isInDrag = inDrag;
+		g_system->lockMouse(inDrag);
 		if (inDrag) {
 			// Start drag operation
 			_mouseDragStart = mousePt;
diff --git a/engines/tetraedge/te/te_camera.cpp b/engines/tetraedge/te/te_camera.cpp
index 59bdac8f614..3ddfd35e179 100644
--- a/engines/tetraedge/te/te_camera.cpp
+++ b/engines/tetraedge/te/te_camera.cpp
@@ -263,11 +263,7 @@ TeMatrix4x4 TeCamera::transformationMatrix() {
 
 TeVector3f32 TeCamera::transformCoord(const TeVector3f32 &pt) {
 	_rotation.normalize();
-	TeQuaternion rot;
-	rot.x() = -_rotation.x();
-	rot.y() = -_rotation.y();
-	rot.z() = -_rotation.z();
-	rot.w() = _rotation.w();
+	TeQuaternion rot(-_rotation.x(), -_rotation.y(), -_rotation.z(), _rotation.w());
 	const TeMatrix4x4 rotMatrix = rot.toTeMatrix();
 	const TeVector3f32 transPt = (_projectionMatrix * rotMatrix) * pt;
 	const int halfVPWidth = abs((int)(_viewportW / 2));
diff --git a/engines/tetraedge/te/te_core.cpp b/engines/tetraedge/te/te_core.cpp
index ae7f2c6935f..1f0e6dff86a 100644
--- a/engines/tetraedge/te/te_core.cpp
+++ b/engines/tetraedge/te/te_core.cpp
@@ -67,7 +67,8 @@ TeICodec *TeCore::createVideoCodec(const Common::String &extn) {
 	// The original engine has more formats and even checks for alpha maps,
 	// but it never uses them.
 	if (TePng::matchExtension(extn)) {
-		return new TePng();
+		// png codec needs to know extension
+		return new TePng(extn);
 	} else if (TeJpeg::matchExtension(extn)) {
 		return new TeJpeg();
 	} else if (TeZlibJpeg::matchExtension(extn)) {
@@ -82,15 +83,15 @@ TeICodec *TeCore::createVideoCodec(const Common::String &extn) {
 	return nullptr;
 }
 
-TeICodec *TeCore::createVideoCodec(const Common::FSNode &node) {
-	const Common::String filename = node.getName();
+TeICodec *TeCore::createVideoCodec(const Common::Path &path) {
+	const Common::String filename = path.getLastComponent().toString();
 	if (!filename.contains('.'))
 		return nullptr;
-	Common::String extn = filename.substr(filename.findFirstOf('.') + 1);
+	Common::String extn = filename.substr(filename.findLastOf('.') + 1);
 	extn.toLowercase();
 	TeICodec *codec = createVideoCodec(extn);
 	if (!codec)
-		error("TTeCore::createVideoCodec: Unrecognised format %s", node.getName().c_str());
+		error("TTeCore::createVideoCodec: Unrecognised format %s", filename.c_str());
 	return codec;
 }
 
@@ -146,7 +147,6 @@ static Common::FSNode _findSubPath(const Common::FSNode &parent, const Common::P
 	return Common::FSNode();
 }
 
-
 Common::FSNode TeCore::findFile(const Common::Path &path) const {
 	Common::FSNode node(path);
 	if (node.exists())
@@ -156,11 +156,15 @@ Common::FSNode TeCore::findFile(const Common::Path &path) const {
 	if (!gameRoot.isDirectory())
 		error("Game directory should be a directory");
 	const Common::FSNode resNode = (g_engine->getGamePlatform() == Common::kPlatformMacintosh
-			?  gameRoot.getChild("Resources") : gameRoot);
+			? gameRoot.getChild("Resources") : gameRoot);
 	if (!resNode.isDirectory())
 		error("Resources directory should exist in game");
 
-	const Common::Path fname = path.getLastComponent();
+	Common::String fname = path.getLastComponent().toString();
+
+	// Slight HACK: Remove 'comments' used to specify animated pngs
+	if (fname.contains('#'))
+		fname = fname.substr(0, fname.find('#'));
 	const Common::Path dir = path.getParent();
 
 	static const char *pathSuffixes[] = {
diff --git a/engines/tetraedge/te/te_core.h b/engines/tetraedge/te/te_core.h
index 2fde075005d..4501a7b1707 100644
--- a/engines/tetraedge/te/te_core.h
+++ b/engines/tetraedge/te/te_core.h
@@ -41,7 +41,7 @@ public:
 	void addLoc(TeILoc *loc);
 	//void args(int argc, char **argv); // Probably not needed
 	void create();
-	TeICodec *createVideoCodec(const Common::FSNode &node);
+	TeICodec *createVideoCodec(const Common::Path &path);
 	TeICodec *createVideoCodec(const Common::String &extn);
 	const Common::String &fileFlagSystemFlag(const Common::String &name) const;
 	bool fileFlagSystemFlagsContains(const Common::String &name) const;
diff --git a/engines/tetraedge/te/te_frame_anim.h b/engines/tetraedge/te/te_frame_anim.h
index cfe2cb5fc54..2aedd8c2524 100644
--- a/engines/tetraedge/te/te_frame_anim.h
+++ b/engines/tetraedge/te/te_frame_anim.h
@@ -48,6 +48,7 @@ public:
 
 private:
 	float _frameRate;
+	// TODO: Isn't this the same as TeAnimation::_repeatCount??
 	int _loopCount;
 	int _nbFrames;
 	int _numFramesToShow;
diff --git a/engines/tetraedge/te/te_image.cpp b/engines/tetraedge/te/te_image.cpp
index d06526dd71e..ba3781add49 100644
--- a/engines/tetraedge/te/te_image.cpp
+++ b/engines/tetraedge/te/te_image.cpp
@@ -95,7 +95,7 @@ bool TeImage::isExtensionSupported(const Common::Path &path) {
 
 bool TeImage::load(const Common::FSNode &node) {
 	TeCore *core = g_engine->getCore();
-	TeICodec *codec = core->createVideoCodec(node);
+	TeICodec *codec = core->createVideoCodec(Common::Path(node.getPath()));
 	if (!node.isReadable() || !codec->load(node)) {
 		warning("TeImage::load: Failed to load %s.", node.getPath().c_str());
 		delete codec;
diff --git a/engines/tetraedge/te/te_marker.cpp b/engines/tetraedge/te/te_marker.cpp
index 292a70b02ce..673ef074145 100644
--- a/engines/tetraedge/te/te_marker.cpp
+++ b/engines/tetraedge/te/te_marker.cpp
@@ -38,17 +38,19 @@ void TeMarker::update(TeCamera &camera) {
 	const TeVector3f32 transformLoc = camera.transformCoord(_loc);
 	const TeVector3f32 btnSize = _button.size();
 	_button.setPositionType(TeILayout::ABSOLUTE);
+	float vpWidth = camera.getViewportWidth();
+	float vpHeight = camera.getViewportHeight();
 	if (transformLoc.z() < 1.0f) {
 		// Behind the camera, move off-screen.
-		_button.setPosition(TeVector3f32(-btnSize.x(), -btnSize.y(), _zLoc));
+		_button.setPosition(TeVector3f32(-btnSize.x() - vpWidth / 2, -btnSize.y() - vpHeight / 2, _zLoc));
 	} else {
 		TeVector3f32 buttonMiddle(transformLoc.x() - btnSize.x() / 2, transformLoc.y() - btnSize.y() / 2, _zLoc);
 		// TODO: device rotation (maybe?) is taken account of here
 		// in original, should we do that?
-		TeVector3f32 newScale(480.0f / camera.getViewportWidth(), 320.0f / camera.getViewportHeight(), 1.0);
+		TeVector3f32 newScale(480.0f / vpWidth, 320.0f / vpHeight, 1.0);
 		_button.setScale(newScale);
-		_button.setPosition(TeVector3f32(/*newScale.x() * */ buttonMiddle.x(), /*newScale.y() * */ buttonMiddle.y(), buttonMiddle.z()));
-		//debug("Updated button pos to %s (scale %s middle %s)", _button.position().dump().c_str(), newScale.dump().c_str(), buttonMiddle.dump().c_str());
+		_button.setPosition(TeVector3f32(newScale.x() * buttonMiddle.x(), newScale.y() * buttonMiddle.y(), buttonMiddle.z()));
+		debug("Updated button pos to %s (transformed %s scale %s middle %s)", _button.position().dump().c_str(), transformLoc.dump().c_str(), newScale.dump().c_str(), buttonMiddle.dump().c_str());
 	}
 }
 
diff --git a/engines/tetraedge/te/te_png.cpp b/engines/tetraedge/te/te_png.cpp
index d1332a18a81..6c57837e1e2 100644
--- a/engines/tetraedge/te/te_png.cpp
+++ b/engines/tetraedge/te/te_png.cpp
@@ -27,7 +27,13 @@
 
 namespace Tetraedge {
 
-TePng::TePng() {
+TePng::TePng(const Common::String &extn) {
+	if (extn == "png#anim") {
+		_nbFrames = 8;
+		_frameRate = 8.0f;
+	} else {
+		_nbFrames = 1;
+	}
 }
 
 TePng::~TePng() {
@@ -35,7 +41,16 @@ TePng::~TePng() {
 
 /*static*/
 bool TePng::matchExtension(const Common::String &extn) {
-	return extn == "png";
+	return extn == "png" || extn == "png#anim";
+}
+
+bool TePng::load(const Common::FSNode &node) {
+	if (!TeScummvmCodec::load(node))
+		return false;
+
+	_height = _loadedSurface->h / _nbFrames;
+
+	return true;
 }
 
 bool TePng::load(Common::SeekableReadStream &stream) {
@@ -51,6 +66,29 @@ bool TePng::load(Common::SeekableReadStream &stream) {
 	return true;
 }
 
+bool TePng::update(uint i, TeImage &imgout) {
+	if (_nbFrames == 1)
+		return TeScummvmCodec::update(i, imgout);
+
+	uint relFrame = i % _nbFrames;
+	if (imgout.w == _loadedSurface->w && imgout.h == _height) {
+		Common::Rect srcRect;
+		srcRect.left = 0;
+		srcRect.right = _loadedSurface->w;
+		srcRect.top = relFrame * _height;
+		srcRect.bottom = (relFrame + 1) * _height;
+		imgout.blitFrom(*_loadedSurface, srcRect, Common::Point());
+		return true;
+	}
+
+	error("TODO: Update animated png for different size");
+}
+
+// TODO: should this return true if last frame was 7?
+bool TePng::isAtEnd() {
+	return false;
+}
+
 TeImage::Format TePng::imageFormat() {
 	if (_loadedSurface) {
 		if (_loadedSurface->format == Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24))
diff --git a/engines/tetraedge/te/te_png.h b/engines/tetraedge/te/te_png.h
index 490a3c22167..a4342d6b6bc 100644
--- a/engines/tetraedge/te/te_png.h
+++ b/engines/tetraedge/te/te_png.h
@@ -33,16 +33,26 @@ namespace Tetraedge {
 
 class TePng : public TeScummvmCodec {
 public:
-	TePng();
+	TePng(const Common::String &extn);
 	virtual ~TePng();
 
+	virtual bool load(const Common::FSNode &node) override;
 	virtual bool load(Common::SeekableReadStream &stream) override;
 
 	TeImage::Format imageFormat() override;
 
+	// We support "animated" PNGs which contain 8
+	// frames stacked vertically.
+	virtual int nbFrames() override { return _nbFrames; }
+	virtual uint height() override { return _height; }
+	virtual bool isAtEnd() override;
+	virtual bool update(uint i, TeImage &imgout) override;
+
 	static bool matchExtension(const Common::String &extn);
 
 private:
+	int _nbFrames;
+	int16 _height;
 };
 
 } // end namespace Tetraedge
diff --git a/engines/tetraedge/te/te_scene_warp_xml_parser.cpp b/engines/tetraedge/te/te_scene_warp_xml_parser.cpp
index dfa54465b0f..53c458a9aa2 100644
--- a/engines/tetraedge/te/te_scene_warp_xml_parser.cpp
+++ b/engines/tetraedge/te/te_scene_warp_xml_parser.cpp
@@ -53,7 +53,7 @@ bool TeSceneWarpXmlParser::parserCallback_marker(ParserNode *node) {
 		if (_flag) {
 			marker->loc().normalize();
 			marker->loc() *= 500.0f;
-			marker->button().load("2D/Menus/InGame/Marker_2.png", "2D/Menus/InGame/Marker_2_over.png", "");
+			marker->button().load("2D/Menus/InGame/Marker_2.png#anim", "2D/Menus/InGame/Marker_2_over.png", "");
 		} else {
 			marker->visible(false);
 		}
@@ -66,7 +66,7 @@ bool TeSceneWarpXmlParser::parserCallback_marker(ParserNode *node) {
 		if (_flag) {
 			marker->loc().normalize();
 			marker->loc() *= 500.0f;
-			marker->button().load("2D/Menus/InGame/Marker_2.png", "2D/Menus/InGame/Marker_2_over.png", "");
+			marker->button().load("2D/Menus/InGame/Marker_2.png#anim", "2D/Menus/InGame/Marker_2_over.png", "");
 		} else {
 			marker->visible(false);
 		}
diff --git a/engines/tetraedge/te/te_scummvm_codec.cpp b/engines/tetraedge/te/te_scummvm_codec.cpp
index 9bac0a054fe..d3b72822e22 100644
--- a/engines/tetraedge/te/te_scummvm_codec.cpp
+++ b/engines/tetraedge/te/te_scummvm_codec.cpp
@@ -27,7 +27,8 @@
 
 namespace Tetraedge {
 
-TeScummvmCodec::TeScummvmCodec() : _loadedSurface(nullptr) {
+TeScummvmCodec::TeScummvmCodec() : _loadedSurface(nullptr), _frameRate(0.0f),
+_bottomBorder(0), _topBorder(0) {
 }
 
 TeScummvmCodec::~TeScummvmCodec() {
@@ -69,10 +70,11 @@ bool TeScummvmCodec::update(uint i, TeImage &imgout) {
 	if (!_loadedPath.empty())
 		imgout.setAccessName(_loadedPath);
 
-	if (imgout.w == _loadedSurface->w && imgout.h == _loadedSurface->h && imgout.format == _loadedSurface->format) {
+	if (imgout.w == _loadedSurface->w && imgout.h == _loadedSurface->h && imgout.format == _loadedSurface->format && !_bottomBorder && !_topBorder) {
 		imgout.copyFrom(*_loadedSurface);
 		return true;
-	} else if (imgout.w == _loadedSurface->w && imgout.h == _loadedSurface->h) {
+	} else if (imgout.w == _loadedSurface->w && imgout.h == _loadedSurface->h
+		&& !_bottomBorder && !_topBorder) {
 		Graphics::PixelFormat destfmt = imgout.format;
 		imgout.copyFrom(*_loadedSurface);
 		imgout.convertToInPlace(destfmt);
@@ -82,4 +84,20 @@ bool TeScummvmCodec::update(uint i, TeImage &imgout) {
 	error("TODO: Implement TeScummvmCodec::update for different sizes");
 }
 
+void TeScummvmCodec::setLeftBorderSize(uint val) {
+	error("left border not supported.");
+}
+
+void TeScummvmCodec::setRightBorderSize(uint val) {
+	error("left border not supported.");
+}
+
+void TeScummvmCodec::setBottomBorderSize(uint val) {
+	_bottomBorder = val;
+}
+
+void TeScummvmCodec::setTopBorderSize(uint val) {
+	_topBorder = val;
+}
+
 } // end namespace Tetraedge
diff --git a/engines/tetraedge/te/te_scummvm_codec.h b/engines/tetraedge/te/te_scummvm_codec.h
index 72112febf5e..c8fe269814e 100644
--- a/engines/tetraedge/te/te_scummvm_codec.h
+++ b/engines/tetraedge/te/te_scummvm_codec.h
@@ -38,15 +38,15 @@ public:
 	virtual uint height() override;
 	virtual int nbFrames() override { return 1; }
 	virtual TeImage::Format imageFormat() override;
-	virtual void setLeftBorderSize(uint val) override { }
+	virtual void setLeftBorderSize(uint val) override;
 	virtual uint leftBorderSize() override { return 0; }
-	virtual void setRightBorderSize(uint val) override  { }
+	virtual void setRightBorderSize(uint val) override;
 	virtual uint rightBorderSize() override { return 0; }
-	virtual void setBottomBorderSize(uint val) override  { }
+	virtual void setBottomBorderSize(uint val) override;
 	virtual uint bottomBorderSize() override { return 0; }
-	virtual void setTopBorderSize(uint val) override  { }
+	virtual void setTopBorderSize(uint val) override;
 	virtual uint topBorderSize() override { return 0; }
-	virtual float frameRate() override { return 0.0; }
+	virtual float frameRate() override { return _frameRate; }
 	virtual bool update(uint i, TeImage &imgout) override;
 	virtual bool isAtEnd() override { return true; }
 	virtual void setColorKeyActivated(bool val) override { }
@@ -56,7 +56,9 @@ public:
 protected:
 	Graphics::Surface *_loadedSurface;
 	Common::String _loadedPath;
-
+	float _frameRate;
+	uint _bottomBorder;
+	uint _topBorder;
 };
 
 } // end namespace Tetraedge
diff --git a/engines/tetraedge/te/te_sprite_layout.cpp b/engines/tetraedge/te/te_sprite_layout.cpp
index c23d4f45be6..02fad7f0863 100644
--- a/engines/tetraedge/te/te_sprite_layout.cpp
+++ b/engines/tetraedge/te/te_sprite_layout.cpp
@@ -81,17 +81,19 @@ bool TeSpriteLayout::load(const Common::String &path) {
 
 	TeCore *core = g_engine->getCore();
 	Common::FSNode node = core->findFile(path);
+	_tiledSurfacePtr->setLoadedPath(path);
 	if (load(node)) {
-		_tiledSurfacePtr->setLoadedPath(path);
 		return true;
+	} else {
+		_tiledSurfacePtr->setLoadedPath("");
+		return false;
 	}
-	return false;
 }
 
 bool TeSpriteLayout::load(const Common::FSNode &node) {
 	if (!node.exists()) {
 		_tiledSurfacePtr = new TeTiledSurface();
-		return true;
+		return false;
 	}
 
 	stop();
diff --git a/engines/tetraedge/te/te_tiled_surface.cpp b/engines/tetraedge/te/te_tiled_surface.cpp
index 51180abb89a..414a5e169f1 100644
--- a/engines/tetraedge/te/te_tiled_surface.cpp
+++ b/engines/tetraedge/te/te_tiled_surface.cpp
@@ -64,7 +64,8 @@ bool TeTiledSurface::load(const Common::FSNode &node) {
 	unload();
 
 	TeResourceManager *resmgr = g_engine->getResourceManager();
-	_loadedPath = node.getPath();
+	if (_loadedPath.empty())
+		_loadedPath = node.getPath();
 
 	TeIntrusivePtr<TeTiledTexture> texture;
 	if (resmgr->exists(_loadedPath + ".tt")) {
@@ -74,7 +75,7 @@ bool TeTiledSurface::load(const Common::FSNode &node) {
 
 	if (!texture) {
 		TeCore *core = g_engine->getCore();
-		_codec = core->createVideoCodec(node);
+		_codec = core->createVideoCodec(Common::Path(_loadedPath));
 		if (!_codec)
 			return false;
 
@@ -171,6 +172,7 @@ bool TeTiledSurface::onFrameAnimCurrentFrameChanged() {
 
 	Common::SharedPtr<TePalette> nullPal;
 	img.createImg(vidSize._x, vidSize._y, nullPal, _imgFormat, bufxsize, bufysize);
+
 	if (_codec->update(_frameAnim.lastFrameShown(), img))
 		update(img);
 	return _codec->isAtEnd();
@@ -184,8 +186,8 @@ void TeTiledSurface::play() {
 	if (_codec) {
 		_frameAnim.setNbFrames(_codec->nbFrames());
 		_frameAnim.setFrameRate(_codec->frameRate());
-		_frameAnim.play();
 	}
+	_frameAnim.play();
 }
 
 void TeTiledSurface::setColorKey(const TeColor &col) {
diff --git a/engines/tetraedge/te/te_warp.cpp b/engines/tetraedge/te/te_warp.cpp
index 9a524621d34..1f9ced81b4b 100644
--- a/engines/tetraedge/te/te_warp.cpp
+++ b/engines/tetraedge/te/te_warp.cpp
@@ -165,7 +165,7 @@ void TeWarp::configMarker(const Common::String &objname, int markerImgNo, long m
 	if (markerImgNo == -1) {
 		warpMarker->marker()->visible(false);
 	} else {
-		Common::String markerPath = Common::String::format("2D/Menus/InGame/Marker_%d.png", markerImgNo);
+		Common::String markerPath = Common::String::format("2D/Menus/InGame/Marker_%d.png#anim", markerImgNo);
 		Common::String markerPathOver = Common::String::format("2D/Menus/InGame/Marker_%d_over.png", markerImgNo);
 		if (exit)
 			warpMarker->setName(objname);
@@ -177,8 +177,7 @@ void TeWarp::configMarker(const Common::String &objname, int markerImgNo, long m
 		if (!btnUp)
 			error("Loading button image %s failed", markerPath.c_str());
 		warning("TeWarp::configMarker: set anim values and something else here?");
-		btnUp->_tiledSurfacePtr->_frameAnim._repeatCount = -1;
-		btnUp->_tiledSurfacePtr->_frameAnim.setFrameRate(8.0);
+		btnUp->_tiledSurfacePtr->_frameAnim.setLoopCount(-1);
 		btnUp->play();
 		warpMarker->marker()->visible(true);
 		// The game uses TeSprite, but we use the layout system instead.
@@ -219,12 +218,13 @@ bool TeWarp::hasObjectOrAnim(const Common::String &objname) {
 }
 
 void TeWarp::init() {
-	// This mostly sets up the camera.. maybe nothing to do?
 	TeVector3f32 winSize = g_engine->getApplication()->getMainWindow().size();
-	_camera.setProjMatrixType(3);
+	_camera.setProjMatrixType(1);
 	_camera.viewport(0, 0, (int)winSize.x(), (int)winSize.y());
 	_camera.setOrthoPlanes(1, 4096);
 	_camera.setAspectRatio(winSize.x() / winSize.y());
+	// update proj matrix
+	_camera.projectionMatrix();
 	warning("TODO: Finish TeWarp::init?");
 }
 
@@ -413,7 +413,7 @@ void TeWarp::sendExit(TeWarp::Exit &exit) {
 	exit._warpBlockList.clear();
 	TeMarker *marker = _warpMarkers[exit._markerId]->marker();
 	assert(marker);
-	marker->button().load("2D/Menus/InGame/Marker_0.png", "2D/Menus/InGame/Marker_0_over.png", "");
+	marker->button().load("2D/Menus/InGame/Marker_0.png#anim", "2D/Menus/InGame/Marker_0_over.png", "");
 	marker->visible(false);
 	marker->setZLoc(-999.0f);
 	_exitList.push_back(exit);
@@ -520,6 +520,8 @@ void TeWarp::rotateCamera(const TeQuaternion &rot) {
 
 void TeWarp::setFov(float fov) {
 	_camera.setFov(fov);
+	// update proj matrix
+	_camera.projectionMatrix();
 }
 
 void TeWarp::takeObject(const Common::String &name) {
@@ -551,6 +553,8 @@ void TeWarp::updateCamera(const TeVector3f32 &screen) {
 	_camera.viewport(0, 0, screen.x(), screen.y());
 	_camera.setOrthoPlanes(1, 4096);
 	_camera.setAspectRatio(screen.x() / screen.y());
+	// update proj matrix
+	_camera.projectionMatrix();
 }
 
 } // end namespace Tetraedge


Commit: c202f5600eaeb40954a7ba3c0db98a6728157502
    https://github.com/scummvm/scummvm/commit/c202f5600eaeb40954a7ba3c0db98a6728157502
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-04-29T20:30:27+09:00

Commit Message:
TETRAEDGE: More fixes for warp

Can now click on the warp marker and skip to the second scene.

Changed paths:
    engines/tetraedge/game/amerzone_game.cpp
    engines/tetraedge/game/amerzone_game.h
    engines/tetraedge/game/lua_binds.cpp
    engines/tetraedge/te/te_button_layout.cpp
    engines/tetraedge/te/te_camera.cpp
    engines/tetraedge/te/te_marker.cpp
    engines/tetraedge/te/te_marker.h
    engines/tetraedge/te/te_sprite_layout.cpp
    engines/tetraedge/te/te_sprite_layout.h
    engines/tetraedge/te/te_warp.cpp
    engines/tetraedge/tetraedge.cpp


diff --git a/engines/tetraedge/game/amerzone_game.cpp b/engines/tetraedge/game/amerzone_game.cpp
index bd5c465e1d8..5350c220178 100644
--- a/engines/tetraedge/game/amerzone_game.cpp
+++ b/engines/tetraedge/game/amerzone_game.cpp
@@ -56,8 +56,8 @@ void AmerzoneGame::changeSpeedToMouseDirection() {
 bool AmerzoneGame::changeWarp(const Common::String &zone, const Common::String &scene, bool fadeFlag) {
 	if (_warpY) {
 		_luaScript.execute("OnWarpLeave");
-		_warpY->markerValidatedSignal().add(this, &AmerzoneGame::onObjectClick);
-		_warpY->animFinishedSignal().add(this, &AmerzoneGame::onAnimationFinished);
+		_warpY->markerValidatedSignal().remove(this, &AmerzoneGame::onObjectClick);
+		_warpY->animFinishedSignal().remove(this, &AmerzoneGame::onAnimationFinished);
 		saveBackup("save.xml");
 		_videoMusic.stop();
 	}
@@ -126,6 +126,8 @@ void AmerzoneGame::draw() {
 }
 
 void AmerzoneGame::enter() {
+	if (_entered)
+		return;
 	Application *app = g_engine->getApplication();
 	// TODO:
 	//_puzzleDisjoncteur.setState(5);
@@ -182,6 +184,7 @@ void AmerzoneGame::enter() {
 	_edgeButtonRolloverCount = 0;
 
 	initLoadedBackupData();
+	_entered = true;
 }
 
 void AmerzoneGame::finishGame() {
@@ -271,10 +274,10 @@ bool AmerzoneGame::onChangeWarpAnimFinished() {
 		_prevWarpY->setVisible(false, true);
 		_prevWarpY->clear();
 		_prevWarpY = nullptr;
-		// TODO: set some sprite not visible here.
-		error("TODO: Finish AmerzoneGame::onChangeWarpAnimFinished");
+		// TODO: set fade sprite not visible here?
+		//error("TODO: Finish AmerzoneGame::onChangeWarpAnimFinished");
 	}
-	_warpY->markerValidatedSignal().remove(this, &AmerzoneGame::onObjectClick);
+	_warpY->markerValidatedSignal().add(this, &AmerzoneGame::onObjectClick);
 	optimizeWarpResources();
 	return false;
 }
@@ -310,7 +313,9 @@ bool AmerzoneGame::onMouseLeftDown(const Common::Point &pt) {
 }
 
 bool AmerzoneGame::onObjectClick(const Common::String &obj) {
-	error("TODO: Implement AmerzoneGame::onObjectClick");
+	_lastHitObjectName = obj;
+	_luaScript.execute("OnWarpObjectHit", obj);
+	return true;
 }
 
 bool AmerzoneGame::onPuzzleEnterAnimLoadTime() {
diff --git a/engines/tetraedge/game/amerzone_game.h b/engines/tetraedge/game/amerzone_game.h
index b3135416970..3a494a43f56 100644
--- a/engines/tetraedge/game/amerzone_game.h
+++ b/engines/tetraedge/game/amerzone_game.h
@@ -47,7 +47,7 @@ public:
 	virtual bool onVideoFinished() override;
 
 	TeWarp *warpY() { return _warpY; }
-	const Common::String lastObjectHitName() const { return _lastObjectHitName; }
+	const Common::String lastHitObjectName() const { return _lastHitObjectName; }
 
 	void setAngleX(float angle);
 	void setAngleY(float angle);
@@ -93,7 +93,7 @@ private:
 	TeWarp *_warpX;
 	TeWarp *_warpY;
 	TeWarp *_prevWarpY;
-	Common::String _lastObjectHitName;
+	Common::String _lastHitObjectName;
 };
 
 } // end namespace Tetraedge
diff --git a/engines/tetraedge/game/lua_binds.cpp b/engines/tetraedge/game/lua_binds.cpp
index 4beac108d20..02d90421d82 100644
--- a/engines/tetraedge/game/lua_binds.cpp
+++ b/engines/tetraedge/game/lua_binds.cpp
@@ -208,8 +208,8 @@ static int tolua_ExportedFunctions_Selected00(lua_State *L) {
 static void TakeObject_Amerzone(const Common::String &obj) {
 	AmerzoneGame *game = dynamic_cast<AmerzoneGame *>(g_engine->getGame());
 	assert(game);
-	game->luaContext().setGlobal(game->lastObjectHitName(), true);
-	game->warpY()->takeObject(game->lastObjectHitName());
+	game->luaContext().setGlobal(game->lastHitObjectName(), true);
+	game->warpY()->takeObject(game->lastHitObjectName());
 	if (!obj.empty()) {
 		game->addToBag(obj);
 		g_engine->getSoundManager()->playFreeSound("Sounds/SFX/N_prendre.ogg", 1.0, "sfx");
diff --git a/engines/tetraedge/te/te_button_layout.cpp b/engines/tetraedge/te/te_button_layout.cpp
index 9d07c32948d..6e804cf8155 100644
--- a/engines/tetraedge/te/te_button_layout.cpp
+++ b/engines/tetraedge/te/te_button_layout.cpp
@@ -355,10 +355,10 @@ void TeButtonLayout::setDoubleValidationProtectionEnabled(bool enable) {
 }
 
 void TeButtonLayout::setEnable(bool enable) {
-	if (enable) {
+	if (enable && _currentState == BUTTON_STATE_DISABLED) {
 		_currentState = BUTTON_STATE_UP;
 		setState(_currentState);
-	} else {
+	} else if (!enable && _currentState != BUTTON_STATE_DISABLED) {
 		_currentState = BUTTON_STATE_DISABLED;
 		setState(_currentState);
 	}
@@ -373,9 +373,11 @@ void TeButtonLayout::setPosition(const TeVector3f32 &pos) {
 			// probably not needed as we reimplememted how this works.
 			error("TODO: Implement setPosition logic for up/down state");
 		}
-		if (!_ignoreMouseEvents) {
-			setState(somethingCount ? BUTTON_STATE_DOWN : BUTTON_STATE_UP);
-		}
+		// Original does something like this, but that breaks in
+		// Amerzone where the button position can move during a click.
+		//if (!_ignoreMouseEvents) {
+		//	setState(somethingCount ? BUTTON_STATE_DOWN : BUTTON_STATE_UP);
+		//}
 	}
 }
 
diff --git a/engines/tetraedge/te/te_camera.cpp b/engines/tetraedge/te/te_camera.cpp
index 3ddfd35e179..bd294b1f1b4 100644
--- a/engines/tetraedge/te/te_camera.cpp
+++ b/engines/tetraedge/te/te_camera.cpp
@@ -241,7 +241,16 @@ TeVector2f32 TeCamera::projectPoint(const TeVector3f32 &pt) {
 }
 
 TeVector3f32 TeCamera::projectPoint3f32(const TeVector3f32 &pt) {
-	error("TODO: Implement TeCamera::projectPoint3f32");
+	_rotation.normalize();
+	TeMatrix4x4 worldInverse = worldTransformationMatrix();
+	worldInverse.inverse();
+	const TeVector3f32 projectedPt = _projectionMatrix * worldInverse * pt;
+	int halfViewportW = (int)_viewportW / 2;
+	int halfViewportH = (int)_viewportH / 2;
+
+	float projectedX = halfViewportW * (projectedPt.x() + 1.0) + _viewportX;
+	float projectedY = halfViewportH * (1.0 - projectedPt.y()) + _viewportY;
+	return TeVector3f32(projectedX, projectedY, projectedPt.z());
 }
 
 void TeCamera::restore() {
diff --git a/engines/tetraedge/te/te_marker.cpp b/engines/tetraedge/te/te_marker.cpp
index 673ef074145..8ab37780d40 100644
--- a/engines/tetraedge/te/te_marker.cpp
+++ b/engines/tetraedge/te/te_marker.cpp
@@ -35,7 +35,7 @@ void TeMarker::update(TeCamera &camera) {
 	_button.setVisible(true);
 	if (!_visible)
 		return;
-	const TeVector3f32 transformLoc = camera.transformCoord(_loc);
+	const TeVector3f32 transformLoc = camera.projectPoint3f32(_loc);
 	const TeVector3f32 btnSize = _button.size();
 	_button.setPositionType(TeILayout::ABSOLUTE);
 	float vpWidth = camera.getViewportWidth();
@@ -44,13 +44,14 @@ void TeMarker::update(TeCamera &camera) {
 		// Behind the camera, move off-screen.
 		_button.setPosition(TeVector3f32(-btnSize.x() - vpWidth / 2, -btnSize.y() - vpHeight / 2, _zLoc));
 	} else {
-		TeVector3f32 buttonMiddle(transformLoc.x() - btnSize.x() / 2, transformLoc.y() - btnSize.y() / 2, _zLoc);
-		// TODO: device rotation (maybe?) is taken account of here
-		// in original, should we do that?
-		TeVector3f32 newScale(480.0f / vpWidth, 320.0f / vpHeight, 1.0);
-		_button.setScale(newScale);
-		_button.setPosition(TeVector3f32(newScale.x() * buttonMiddle.x(), newScale.y() * buttonMiddle.y(), buttonMiddle.z()));
-		debug("Updated button pos to %s (transformed %s scale %s middle %s)", _button.position().dump().c_str(), transformLoc.dump().c_str(), newScale.dump().c_str(), buttonMiddle.dump().c_str());
+		TeVector3f32 buttonMiddle(transformLoc.x() - btnSize.x() / 2 - vpWidth / 2, transformLoc.y() - btnSize.y() / 2  - vpHeight / 2, _zLoc);
+		// Note: device rotation is taken account of here in original, skip that.
+		// Original also uses scales 480 and 320, but that makes it too small
+		// in HD.
+		//TeVector3f32 newScale(480.0f / vpWidth, 320.0f / vpHeight, 1.0);
+		//_button.setScale(newScale);
+		_button.setPosition(TeVector3f32(buttonMiddle.x(), buttonMiddle.y(), buttonMiddle.z()));
+		debug("Updated button pos to %s (transformed %s middle %s)", _button.position().dump().c_str(), transformLoc.dump().c_str(), buttonMiddle.dump().c_str());
 	}
 }
 
diff --git a/engines/tetraedge/te/te_marker.h b/engines/tetraedge/te/te_marker.h
index 33491100e41..eaa8e87e4d1 100644
--- a/engines/tetraedge/te/te_marker.h
+++ b/engines/tetraedge/te/te_marker.h
@@ -29,7 +29,7 @@
 namespace Tetraedge {
 
 // Note: Only used in Amerzone
-class TeMarker {
+class TeMarker : public TeObject {
 public:
 	TeMarker();
 
@@ -50,7 +50,6 @@ private:
 	// Note: this is a TeSpriteButton in the original, updated
 	// to use the newer ButtonLayout
 	TeButtonLayout _button;
-
 };
 
 } // end namespace Tetraedge
diff --git a/engines/tetraedge/te/te_sprite_layout.cpp b/engines/tetraedge/te/te_sprite_layout.cpp
index 02fad7f0863..e794a4a6fbf 100644
--- a/engines/tetraedge/te/te_sprite_layout.cpp
+++ b/engines/tetraedge/te/te_sprite_layout.cpp
@@ -81,16 +81,12 @@ bool TeSpriteLayout::load(const Common::String &path) {
 
 	TeCore *core = g_engine->getCore();
 	Common::FSNode node = core->findFile(path);
-	_tiledSurfacePtr->setLoadedPath(path);
-	if (load(node)) {
-		return true;
-	} else {
-		_tiledSurfacePtr->setLoadedPath("");
+	if (!load(node, &path))
 		return false;
-	}
+	return true;
 }
 
-bool TeSpriteLayout::load(const Common::FSNode &node) {
+bool TeSpriteLayout::load(const Common::FSNode &node, const Common::String *forcePath) {
 	if (!node.exists()) {
 		_tiledSurfacePtr = new TeTiledSurface();
 		return false;
@@ -99,6 +95,7 @@ bool TeSpriteLayout::load(const Common::FSNode &node) {
 	stop();
 	unload();
 
+	_tiledSurfacePtr->setLoadedPath(forcePath ? *forcePath : Common::String());
 	if (_tiledSurfacePtr->load(node)) {
 		const TeVector2s32 texSize = _tiledSurfacePtr->tiledTexture()->totalSize();
 		if (texSize._y <= 0) {
@@ -112,6 +109,7 @@ bool TeSpriteLayout::load(const Common::FSNode &node) {
 		updateMesh();
 	} else {
 		debug("Failed to load TeSpriteLayout %s", node.getPath().c_str());
+		_tiledSurfacePtr->setLoadedPath("");
 	}
 	return true;
 }
diff --git a/engines/tetraedge/te/te_sprite_layout.h b/engines/tetraedge/te/te_sprite_layout.h
index bc4e9f7f338..50a8eac3a07 100644
--- a/engines/tetraedge/te/te_sprite_layout.h
+++ b/engines/tetraedge/te/te_sprite_layout.h
@@ -38,7 +38,7 @@ public:
 	virtual bool onParentWorldColorChanged() override;
 
 	bool load(const Common::String &path);
-	bool load(const Common::FSNode &node);
+	bool load(const Common::FSNode &node, const Common::String *forcePath = nullptr);
 	bool load(TeImage &img);
 	bool load(TeIntrusivePtr<Te3DTexture> &texture);
 
diff --git a/engines/tetraedge/te/te_warp.cpp b/engines/tetraedge/te/te_warp.cpp
index 1f9ced81b4b..bf9e264e58e 100644
--- a/engines/tetraedge/te/te_warp.cpp
+++ b/engines/tetraedge/te/te_warp.cpp
@@ -41,6 +41,7 @@ TeWarp::TeWarp() : _visible1(false), _loaded(false), _preloaded(false),
 }
 
 TeWarp::~TeWarp() {
+	_markerValidatedSignal.clear();
 	unload();
 	_file.close();
 }
@@ -143,7 +144,11 @@ void TeWarp::checkObjectEvents() {
 void TeWarp::clear() {
 	_putAnimData.clear();
 
-	error("TODO: Implement TeWarp::clear");
+	for (auto &data : _loadedAnimData)
+		data._flag = false;
+
+	for (auto *marker : _warpMarkers)
+		marker->marker()->visible(false);
 }
 
 void TeWarp::configMarker(const Common::String &objname, int markerImgNo, long markerId) {
@@ -167,7 +172,7 @@ void TeWarp::configMarker(const Common::String &objname, int markerImgNo, long m
 	} else {
 		Common::String markerPath = Common::String::format("2D/Menus/InGame/Marker_%d.png#anim", markerImgNo);
 		Common::String markerPathOver = Common::String::format("2D/Menus/InGame/Marker_%d_over.png", markerImgNo);
-		if (exit)
+		if (!exit)
 			warpMarker->setName(objname);
 		else
 			warpMarker->setName(Common::String("3D\\") + objname);
@@ -232,10 +237,17 @@ void TeWarp::load(const Common::String &path, bool flag) {
 	if (_warpPath == path && _loaded)
 		return;
 	_warpPath = path;
+
 	TeCore *core = g_engine->getCore();
 	Common::FSNode node = core->findFile(_warpPath);
-	if (!node.isReadable())
-		error("Couldn't find TeWarp path '%s'", _warpPath.c_str());
+	if (!node.isReadable()) {
+		// Try with '\'s..
+		Common::Path warpPathPath(_warpPath, '\\');
+		node = core->findFile(warpPathPath);
+		if (!node.isReadable()) {
+			error("Couldn't find TeWarp path data '%s'", _warpPath.c_str());
+		}
+	}
 
 	if (_preloaded)
 		error("TODO: Support preloading in TeWarp::load");
@@ -415,7 +427,7 @@ void TeWarp::sendExit(TeWarp::Exit &exit) {
 	assert(marker);
 	marker->button().load("2D/Menus/InGame/Marker_0.png#anim", "2D/Menus/InGame/Marker_0_over.png", "");
 	marker->visible(false);
-	marker->setZLoc(-999.0f);
+	marker->setZLoc(200.0f);
 	_exitList.push_back(exit);
 }
 
@@ -452,7 +464,14 @@ void TeWarp::setVisible(bool v1, bool v2) {
 		inputMgr->_mouseLDownSignal.add(this, &TeWarp::onMouseLeftDown);
 	} else {
 		if (v2) {
-			error("TODO: Implement TeWarp::setVisible for v2==true");
+			for (auto *marker : _warpMarkers) {
+				TeMarker *m = marker->marker();
+				delete marker;
+				// May be still handling the button click
+				if (m)
+					m->deleteLater();
+			}
+			_warpMarkers.clear();
 		}
 		inputMgr->_mouseLDownSignal.remove(this, &TeWarp::onMouseLeftDown);
 	}
@@ -525,11 +544,33 @@ void TeWarp::setFov(float fov) {
 }
 
 void TeWarp::takeObject(const Common::String &name) {
-	error("TODO: Implement TeWarp::takeObject");
+	for (auto &animData : _loadedAnimData) {
+		if (animData._name != name)
+			continue;
+		error("TODO: Finish TeWarp::takeObject");
+	}
+	warning("Impossible de trouver l\'objet %s dans le Warp", name.c_str());
 }
 
 void TeWarp::unload() {
-	error("TODO: Implement TeWarp::unload");
+	unloadTextures();
+	_xCount = 0;
+	_yCount = 0;
+	_loadedAnimData.clear();
+	_putAnimData.clear();
+	_paths.clear();
+	_pickMeshes2.clear();
+	_exitList.clear();
+	for (auto *marker : _warpMarkers) {
+		TeMarker *m = marker->marker();
+		delete marker;
+		// May be still handling the button click
+		if (m)
+			m->deleteLater();
+	}
+	_warpMarkers.clear();
+	_preloaded = false;
+	_loaded = false;
 }
 
 void TeWarp::unloadTextures() {
diff --git a/engines/tetraedge/tetraedge.cpp b/engines/tetraedge/tetraedge.cpp
index 2291f43d52c..060e29b84ce 100644
--- a/engines/tetraedge/tetraedge.cpp
+++ b/engines/tetraedge/tetraedge.cpp
@@ -195,11 +195,11 @@ void TetraedgeEngine::configureSearchPaths() {
 }
 
 int TetraedgeEngine::getDefaultScreenWidth() const {
-	return gameIsAmerzone() ? 1365 : 800;
+	return gameIsAmerzone() ? 1280 : 800;
 }
 
 int TetraedgeEngine::getDefaultScreenHeight() const {
-	return gameIsAmerzone() ? 768 : 600;
+	return gameIsAmerzone() ? 800 : 600;
 }
 
 bool TetraedgeEngine::onKeyUp(const Common::KeyState &state) {


Commit: 33666221d3a6a362dc4aebaaa10d74369296c272
    https://github.com/scummvm/scummvm/commit/33666221d3a6a362dc4aebaaa10d74369296c272
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-04-29T20:30:27+09:00

Commit Message:
TETRAEDGE: More support for Amerzone, can now navigate

Changed paths:
    engines/tetraedge/game/amerzone_game.cpp
    engines/tetraedge/game/document.h
    engines/tetraedge/game/documents_browser.cpp
    engines/tetraedge/game/documents_browser.h
    engines/tetraedge/game/game_sound.cpp
    engines/tetraedge/game/inventory_menu.cpp
    engines/tetraedge/game/lua_binds.cpp
    engines/tetraedge/game/splash_screens.cpp
    engines/tetraedge/te/te_core.cpp
    engines/tetraedge/te/te_frustum.cpp
    engines/tetraedge/te/te_frustum.h
    engines/tetraedge/te/te_marker.cpp
    engines/tetraedge/te/te_pick_mesh.cpp
    engines/tetraedge/te/te_pick_mesh.h
    engines/tetraedge/te/te_warp.cpp
    engines/tetraedge/te/te_warp.h
    engines/tetraedge/te/te_warp_marker.cpp


diff --git a/engines/tetraedge/game/amerzone_game.cpp b/engines/tetraedge/game/amerzone_game.cpp
index 5350c220178..b3ee48f7b9d 100644
--- a/engines/tetraedge/game/amerzone_game.cpp
+++ b/engines/tetraedge/game/amerzone_game.cpp
@@ -53,7 +53,7 @@ void AmerzoneGame::changeSpeedToMouseDirection() {
 	error("TODO: Implement AmerzoneGame::changeSpeedToMouseDirection");
 }
 
-bool AmerzoneGame::changeWarp(const Common::String &zone, const Common::String &scene, bool fadeFlag) {
+bool AmerzoneGame::changeWarp(const Common::String &rawZone, const Common::String &scene, bool fadeFlag) {
 	if (_warpY) {
 		_luaScript.execute("OnWarpLeave");
 		_warpY->markerValidatedSignal().remove(this, &AmerzoneGame::onObjectClick);
@@ -76,6 +76,14 @@ bool AmerzoneGame::changeWarp(const Common::String &zone, const Common::String &
 		float fov = 60.0f; //TODO: g_engine->getCore()->fileFlagSystemFlagsContains("HD") ? 60.0f : 45.0f;
 		_warpY->setFov((float)(fov * M_PI / 180.0));
 	}
+
+	Common::String zone = rawZone;
+	if (rawZone.contains('\\')) {
+		// Replace '\'s which our core understands
+		Common::Path converted(rawZone, '\\');
+		zone = converted.toString();
+	}
+
 	_warpY->load(zone, false);
 	_warpY->setVisible(true, false);
 	TeWarp::debug = false;
@@ -113,7 +121,7 @@ bool AmerzoneGame::changeWarp(const Common::String &zone, const Common::String &
 	} else {
         onChangeWarpAnimFinished();
 	}
-	return false;
+	return true;
 }
 
 void AmerzoneGame::draw() {
@@ -149,6 +157,12 @@ void AmerzoneGame::enter() {
 	TeButtonLayout *skipvidbtn = _inGameGui.buttonLayoutChecked("skipVideoButton");
 	skipvidbtn->setVisible(false);
 	skipvidbtn->onMouseClickValidated().add(this, &AmerzoneGame::onSkipVideoButtonValidated);
+
+	TeButtonLayout *vidbgbtn = _inGameGui.buttonLayoutChecked("videoBackgroundButton");
+	vidbgbtn->setVisible(false);
+	vidbgbtn->onMouseClickValidated().remove(this, &AmerzoneGame::onLockVideoButtonValidated);
+	vidbgbtn->onMouseClickValidated().add(this, &AmerzoneGame::onLockVideoButtonValidated);
+
 	TeSpriteLayout *vid = _inGameGui.spriteLayoutChecked("video");
 	vid->_tiledSurfacePtr->_frameAnim.onStop().add(this, &Game::onVideoFinished);
 	vid->setVisible(false);
@@ -295,7 +309,8 @@ bool AmerzoneGame::onHelpButtonValidated() {
 }
 
 bool AmerzoneGame::onAnimationFinished(const Common::String &anim) {
-	error("TODO: Implement AmerzoneGame::onAnimationFinished");
+	_luaScript.execute("OnAnimationFinished", anim);
+	return false;
 }
 
 bool AmerzoneGame::onMouseLeftUp(const Common::Point &pt) {
@@ -473,11 +488,13 @@ void AmerzoneGame::update() {
 	}
 
 	// Rotate x around the Y axis (spinning left/right on the spot)
-	TeQuaternion xRot = TeQuaternion::fromAxisAndAngle(TeVector3f32(0, 1, 0), (float)(_orientationX * M_PI) / 180);
+	TeQuaternion xRot = TeQuaternion::fromAxisAndAngle(TeVector3f32(0, 1, 0), (float)(_orientationX * M_PI) / 180.0f);
 	// Rotate y around the axis perpendicular to the x rotation
+	// Note: slightly different from original because of the way
+	// rotation works in the Amerzone Tetraedge engine.
 	TeVector3f32 yRotAxis = TeVector3f32(1, 0, 0);
 	xRot.inverse().transform(yRotAxis);
-	TeQuaternion yRot = TeQuaternion::fromAxisAndAngle(yRotAxis, (float)(_orientationY * M_PI) / 180);
+	TeQuaternion yRot = TeQuaternion::fromAxisAndAngle(yRotAxis, (float)(_orientationY * M_PI) / 180.0f);
 
 	if (_warpX)
 		_warpX->rotateCamera(xRot * yRot);
diff --git a/engines/tetraedge/game/document.h b/engines/tetraedge/game/document.h
index 307e1f4f882..1a5feabd824 100644
--- a/engines/tetraedge/game/document.h
+++ b/engines/tetraedge/game/document.h
@@ -52,6 +52,8 @@ public:
 	Common::Path spritePath() const;
 	void unload();
 
+	TeSignal1Param<Document &> &onButtonDownSignal() { return _onButtonDownSignal; }
+
 private:
 	DocumentsBrowser *_browser;
 	TeLuaGUI _gui;
diff --git a/engines/tetraedge/game/documents_browser.cpp b/engines/tetraedge/game/documents_browser.cpp
index e368394c155..cc58fb6eab3 100644
--- a/engines/tetraedge/game/documents_browser.cpp
+++ b/engines/tetraedge/game/documents_browser.cpp
@@ -110,11 +110,16 @@ void DocumentsBrowser::load() {
 }
 
 void DocumentsBrowser::loadZoomed() {
-	_zoomedLayout.setSizeType(RELATIVE_TO_PARENT);
-	TeVector3f32 usersz = userSize();
-	_zoomedLayout.setSize(TeVector3f32(1.0f, 1.0f, usersz.z()));
 	TeLayout *zoomedChild = _gui.layout("zoomed");
-	_zoomedLayout.addChild(zoomedChild);
+	if (g_engine->gameIsAmerzone()) {
+		zoomedChild->setRatioMode(RATIO_MODE_NONE);
+		g_engine->getGame()->inventoryMenu().addChild(zoomedChild);
+	} else {
+		_zoomedLayout.setSizeType(RELATIVE_TO_PARENT);
+		TeVector3f32 usersz = userSize();
+		_zoomedLayout.setSize(TeVector3f32(1.0f, 1.0f, usersz.z()));
+		_zoomedLayout.addChild(zoomedChild);
+	}
 }
 
 void DocumentsBrowser::loadXMLFile(const Common::String &path) {
@@ -206,6 +211,9 @@ bool DocumentsBrowser::addDocument(Document *document) {
 				break;
 			if (slot->childCount() == 0) {
 				slot->addChild(document);
+				if (g_engine->gameIsAmerzone()) {
+					document->onButtonDownSignal().add(this, &DocumentsBrowser::onDocumentSelected);
+				}
 				return true;
 			}
 			slotno++;
@@ -234,13 +242,70 @@ Common::String DocumentsBrowser::documentName(const Common::String &key) const {
 	return "";
 }
 
+bool DocumentsBrowser::onDocumentSelected(Document &doc) {
+	showDocument(doc.name(), 0);
+	return false;
+}
+
+Common::String DocumentsBrowser::zoomedPageName() const {
+	return Common::String::format("%s_zoomed_%d", _curDocName.c_str(), (int)_curPage);
+}
+
+bool DocumentsBrowser::onShowedDocumentButton0() {
+	g_engine->getGame()->luaScript().execute("OnShowedDocumentButtonValidated", zoomedPageName(), "button0");
+	return false;
+}
+bool DocumentsBrowser::onShowedDocumentButton1() {
+	g_engine->getGame()->luaScript().execute("OnShowedDocumentButtonValidated", zoomedPageName(), "button1");
+	return false;
+}
+bool DocumentsBrowser::onShowedDocumentButton2() {
+	g_engine->getGame()->luaScript().execute("OnShowedDocumentButtonValidated", zoomedPageName(), "button2");
+	return false;
+}
+bool DocumentsBrowser::onShowedDocumentButton3() {
+	g_engine->getGame()->luaScript().execute("OnShowedDocumentButtonValidated", zoomedPageName(), "button3");
+	return false;
+}
+bool DocumentsBrowser::onShowedDocumentButton4() {
+	g_engine->getGame()->luaScript().execute("OnShowedDocumentButtonValidated", zoomedPageName(), "button4");
+	return false;
+}
+bool DocumentsBrowser::onShowedDocumentButton5() {
+	g_engine->getGame()->luaScript().execute("OnShowedDocumentButtonValidated", zoomedPageName(), "button5");
+	return false;
+}
+bool DocumentsBrowser::onShowedDocumentButton6() {
+	g_engine->getGame()->luaScript().execute("OnShowedDocumentButtonValidated", zoomedPageName(), "button6");
+	return false;
+}
+bool DocumentsBrowser::onShowedDocumentButton7() {
+	g_engine->getGame()->luaScript().execute("OnShowedDocumentButtonValidated", zoomedPageName(), "button7");
+	return false;
+}
+bool DocumentsBrowser::onShowedDocumentButton8() {
+	g_engine->getGame()->luaScript().execute("OnShowedDocumentButtonValidated", zoomedPageName(), "button8");
+	return false;
+}
+bool DocumentsBrowser::onShowedDocumentButton9() {
+	g_engine->getGame()->luaScript().execute("OnShowedDocumentButtonValidated", zoomedPageName(), "button9");
+	return false;
+}
+
 void DocumentsBrowser::showDocument(const Common::String &docName, int startPage) {
 	_curPage = startPage;
 	_startPage = startPage;
 	_curDocName = docName;
 	_zoomedDocGui.unload();
+
+	if (docName.empty()) {
+		hideDocument();
+		return;
+	}
+
 	TeCore *core = g_engine->getCore();
-	const Common::Path docPathBase(Common::String::format("DocumentsBrowser/Documents/Documents/%s_zoomed_%d", docName.c_str(), (int)startPage));
+	const char *pathPattern = g_engine->gameIsAmerzone() ? "DocumentsBrowser/Documents/%s_zoomed_%d" : "DocumentsBrowser/Documents/Documents/%s_zoomed_%d";
+	const Common::Path docPathBase(Common::String::format(pathPattern, docName.c_str(), (int)startPage));
 	Common::Path docPath = docPathBase.append(".png");
 	Common::FSNode docNode = core->findFile(docPath);
 	if (!docNode.exists()) {
@@ -257,24 +322,64 @@ void DocumentsBrowser::showDocument(const Common::String &docName, int startPage
 	Application *app = g_engine->getApplication();
 	app->captureFade();
 	TeSpriteLayout *sprite = _gui.spriteLayoutChecked("zoomedSprite");
-	//sprite->setSizeType(ABSOLUTE);
 	sprite->load(docNode);
 	TeVector2s32 spriteSize = sprite->_tiledSurfacePtr->tiledTexture()->totalSize();
-	sprite->setSizeType(RELATIVE_TO_PARENT);
-	TeVector3f32 winSize = app->getMainWindow().size();
-	sprite->setSize(TeVector3f32(1.0f, (4.0f / (winSize.y() / winSize.x() * 4.0f)) *
-							((float)spriteSize._y / (float)spriteSize._x), 0.0f));
-	TeScrollingLayout *scroll = _gui.scrollingLayout("scroll");
-	if (!scroll)
-		error("DocumentsBrowser::showDocument Couldn't fetch scroll object");
-	scroll->resetScrollPosition();
-	scroll->playAutoScroll();
+
 	Common::FSNode luaNode = core->findFile(docPathBase.append(".lua"));
 	if (luaNode.exists()) {
 		_zoomedDocGui.load(luaNode);
-		error("Finish DocumentsBrowser::showDocument");
+		sprite->addChild(_zoomedDocGui.layoutChecked("root"));
+
+		TeButtonLayout *btn;
+		btn = _zoomedDocGui.buttonLayout("button0");
+		if (btn)
+			btn->onMouseClickValidated().add(this, &DocumentsBrowser::onShowedDocumentButton0);
+		btn = _zoomedDocGui.buttonLayout("button1");
+		if (btn)
+			btn->onMouseClickValidated().add(this, &DocumentsBrowser::onShowedDocumentButton1);
+		btn = _zoomedDocGui.buttonLayout("button2");
+		if (btn)
+			btn->onMouseClickValidated().add(this, &DocumentsBrowser::onShowedDocumentButton2);
+		btn = _zoomedDocGui.buttonLayout("button3");
+		if (btn)
+			btn->onMouseClickValidated().add(this, &DocumentsBrowser::onShowedDocumentButton3);
+		btn = _zoomedDocGui.buttonLayout("button4");
+		if (btn)
+			btn->onMouseClickValidated().add(this, &DocumentsBrowser::onShowedDocumentButton4);
+		btn = _zoomedDocGui.buttonLayout("button5");
+		if (btn)
+			btn->onMouseClickValidated().add(this, &DocumentsBrowser::onShowedDocumentButton5);
+		btn = _zoomedDocGui.buttonLayout("button6");
+		if (btn)
+			btn->onMouseClickValidated().add(this, &DocumentsBrowser::onShowedDocumentButton6);
+		btn = _zoomedDocGui.buttonLayout("button7");
+		if (btn)
+			btn->onMouseClickValidated().add(this, &DocumentsBrowser::onShowedDocumentButton7);
+		btn = _zoomedDocGui.buttonLayout("button8");
+		if (btn)
+			btn->onMouseClickValidated().add(this, &DocumentsBrowser::onShowedDocumentButton8);
+		btn = _zoomedDocGui.buttonLayout("button9");
+		if (btn)
+			btn->onMouseClickValidated().add(this, &DocumentsBrowser::onShowedDocumentButton9);
+	}
+
+	sprite->setSizeType(RELATIVE_TO_PARENT);
+
+	if (!g_engine->gameIsAmerzone()) {
+		TeVector3f32 winSize = app->getMainWindow().size();
+		sprite->setSize(TeVector3f32(1.0f, (4.0f / (winSize.y() / winSize.x() * 4.0f)) *
+								((float)spriteSize._y / (float)spriteSize._x), 0.0f));
+		TeScrollingLayout *scroll = _gui.scrollingLayout("scroll");
+		if (!scroll)
+			error("DocumentsBrowser::showDocument Couldn't fetch scroll object");
+		scroll->resetScrollPosition();
+		scroll->playAutoScroll();
+	} else {
+		sprite->setRatioMode(RATIO_MODE_NONE);
+		sprite->updateSize();
 	}
-	_gui.layoutChecked("zoomed")->setVisible(true);
+
+	_gui.buttonLayoutChecked("zoomed")->setVisible(true);
 	_zoomCount = 0;
 	app->fade();
 }
diff --git a/engines/tetraedge/game/documents_browser.h b/engines/tetraedge/game/documents_browser.h
index db6143063c6..6e53d38bc51 100644
--- a/engines/tetraedge/game/documents_browser.h
+++ b/engines/tetraedge/game/documents_browser.h
@@ -67,12 +67,14 @@ public:
 private:
 	void loadXMLFile(const Common::String &path);
 
-	void onDocumentSelected(Document *doc);
+	bool onDocumentSelected(Document &doc);
 	bool onNextPage();
 	bool onPreviousPage();
 	bool onQuitDocumentDoubleClickTimer();
 	bool onZoomedButton();
 
+	Common::String zoomedPageName() const;
+
 	// Sorry, this is how the original does it...
 	bool onShowedDocumentButton0();
 	bool onShowedDocumentButton1();
@@ -84,6 +86,8 @@ private:
 	bool onShowedDocumentButton7();
 	bool onShowedDocumentButton8();
 	bool onShowedDocumentButton9();
+	/*
+	These are defined but unused in any game..
 	bool onShowedDocumentButton10();
 	bool onShowedDocumentButton11();
 	bool onShowedDocumentButton12();
@@ -94,7 +98,7 @@ private:
 	bool onShowedDocumentButton17();
 	bool onShowedDocumentButton18();
 	bool onShowedDocumentButton19();
-
+	*/
 
 	TeTimer _timer;
 	TeLayout _zoomedLayout;
diff --git a/engines/tetraedge/game/game_sound.cpp b/engines/tetraedge/game/game_sound.cpp
index b0b0b6261a5..755c38bd611 100644
--- a/engines/tetraedge/game/game_sound.cpp
+++ b/engines/tetraedge/game/game_sound.cpp
@@ -32,8 +32,7 @@ GameSound::GameSound() {
 
 bool GameSound::onSoundStopped() {
 	SyberiaGame *game = dynamic_cast<SyberiaGame *>(g_engine->getGame());
-	assert(game);
-	if (!game->luaContext().isCreated())
+	if (!game || !game->luaContext().isCreated())
 		return false;
 
 	Common::Array<SyberiaGame::YieldedCallback> &callbacks = game->yieldedCallbacks();
diff --git a/engines/tetraedge/game/inventory_menu.cpp b/engines/tetraedge/game/inventory_menu.cpp
index 7e502226eb1..8c91fa80073 100644
--- a/engines/tetraedge/game/inventory_menu.cpp
+++ b/engines/tetraedge/game/inventory_menu.cpp
@@ -126,7 +126,8 @@ bool InventoryMenu::onMainMenuButton() {
 	Game *game = g_engine->getGame();
 	game->_returnToMainMenu = true;
 	app->fade();
-	return false;
+	// Don't process any more events.
+	return true;
 }
 
 bool InventoryMenu::onQuitButton() {
diff --git a/engines/tetraedge/game/lua_binds.cpp b/engines/tetraedge/game/lua_binds.cpp
index 02d90421d82..e72ebb469a3 100644
--- a/engines/tetraedge/game/lua_binds.cpp
+++ b/engines/tetraedge/game/lua_binds.cpp
@@ -2876,10 +2876,11 @@ static int tolua_ExportedFunctions_PutObject00(lua_State *L) {
 	error("#ferror in function 'PutObject': %d %d %s", err.index, err.array, err.type);
 }
 
-static void SetAnimationPart(const Common::String &name, int x, int y, int z, bool flag) {
+static void StartAnimationPart(const Common::String &name, int startFrame, int endFrame, int repCount, bool flag) {
 	AmerzoneGame *game = dynamic_cast<AmerzoneGame *>(g_engine->getGame());
 	assert(game);
-	game->warpY()->setAnimationPart(name, x, y, z, flag);
+	// Note parameter order changes
+	game->warpY()->startAnimationPart(name, repCount, startFrame, endFrame, flag);
 }
 
 static int tolua_ExportedFunctions_StartAnimationPart00(lua_State *L) {
@@ -2892,7 +2893,7 @@ static int tolua_ExportedFunctions_StartAnimationPart00(lua_State *L) {
 		double d2 = tolua_tonumber(L, 3, 0.0);
 		double d3 = tolua_tonumber(L, 4, -1.0);
 		bool b1 = tolua_tonumber(L, 5, 0);
-		SetAnimationPart(s1, (int)d1, (int)d2, (int)d3, b1);
+		StartAnimationPart(s1, (int)d1, (int)d2, (int)d3, b1);
 		return 0;
 	}
 	error("#ferror in function 'SetAnimationPart': %d %d %s", err.index, err.array, err.type);
diff --git a/engines/tetraedge/game/splash_screens.cpp b/engines/tetraedge/game/splash_screens.cpp
index a7c54e0759a..715d4ecd596 100644
--- a/engines/tetraedge/game/splash_screens.cpp
+++ b/engines/tetraedge/game/splash_screens.cpp
@@ -40,9 +40,14 @@ void SplashScreens::enter()	{
 		_splashNo = 0;
 		const char *scriptStr = g_engine->gameIsAmerzone() ? "GUI/PC-MacOSX/Splash0.lua" : "menus/splashes/splash0.lua";
 		if (Common::File::exists(scriptStr)) {
-			TeLuaGUI::load(scriptStr);
+			load(scriptStr);
 			Application *app = g_engine->getApplication();
-			TeLayout *splash = layout("splash");
+			TeLayout *splash = layoutChecked("splash");
+			if (g_engine->gameIsAmerzone()) {
+				TeLayout *splashImg = dynamic_cast<TeLayout *>(splash->child(0));
+				splashImg->setRatioMode(TeILayout::RATIO_MODE_NONE);
+				splashImg->updateSize();
+			}
 			app->frontLayout().addChild(splash);
 			app->performRender();
 		}
@@ -69,10 +74,14 @@ bool SplashScreens::onAlarm() {
 	} else {
 		load(scriptName);
 
-		TeButtonLayout *btnLayout = buttonLayoutChecked("splash");
-		btnLayout->onMouseClickValidated().add(this, &SplashScreens::onQuitSplash);
+		TeButtonLayout *splash = buttonLayoutChecked("splash");
+		splash->onMouseClickValidated().add(this, &SplashScreens::onQuitSplash);
 
-		TeLayout *splash = layout("splash");
+		if (g_engine->gameIsAmerzone()) {
+			TeLayout *splashImg = dynamic_cast<TeLayout *>(splash->child(0));
+			splashImg->setRatioMode(TeILayout::RATIO_MODE_NONE);
+			splashImg->updateSize();
+		}
 		app->frontLayout().addChild(splash);
 
 		_timer.start();
diff --git a/engines/tetraedge/te/te_core.cpp b/engines/tetraedge/te/te_core.cpp
index 1f0e6dff86a..971aa0589cf 100644
--- a/engines/tetraedge/te/te_core.cpp
+++ b/engines/tetraedge/te/te_core.cpp
@@ -200,7 +200,12 @@ Common::FSNode TeCore::findFile(const Common::Path &path) const {
 		"Android-iPhone-iPad/iPhone-iPad",		// iOS Syb 2
 		"PC-MacOSX-Android-iPhone-iPad",		// iOS Syb 2
 		"Full/HD",								// Amerzone
-		"Part1-Full/PC-MacOSX/DefaultDistributor" // Amerzone
+		"Part1-Full/PC-MacOSX/DefaultDistributor", // Amerzone
+		"Part1-Part2-Part3-Full/HD",			// Amerzone
+		"Part1-Part2-Part3-Full",				// Amerzone
+		"Part1-Full/HD",						// Amerzone
+		"Part2-Full/HD",						// Amerzone
+		"Part3-Full/HD",						// Amerzone
 	};
 
 	const Common::Path langs[] = {
diff --git a/engines/tetraedge/te/te_frustum.cpp b/engines/tetraedge/te/te_frustum.cpp
index e55e08a4378..a2630ff81de 100644
--- a/engines/tetraedge/te/te_frustum.cpp
+++ b/engines/tetraedge/te/te_frustum.cpp
@@ -44,7 +44,7 @@ void TeFrustum::extractPlanSub(const TeMatrix4x4 &matrix, uint dest, uint col) {
 	_m[dest * 4 + 3] = matrix(3, 3) + matrix(3, col);
 }
 
-bool TeFrustum::pointIsIn(const TeVector3f32 &pt) {
+bool TeFrustum::pointIsIn(const TeVector3f32 &pt) const {
 	error("TODO: Implement TeFrustum::pointIsIn");
 }
 
@@ -57,15 +57,15 @@ float TeFrustum::planeLen(int num) const {
 	return result;
 }
 
-bool TeFrustum::sphereIsIn(const TeVector3f32 &vec, float f) {
+bool TeFrustum::sphereIsIn(const TeVector3f32 &vec, float f) const {
 	error("TODO: Implement TeFrustum::sphereIsIn");
 }
 
-bool TeFrustum::triangleIsIn(const TeVector3f32 *verts) {
+bool TeFrustum::triangleIsIn(const TeVector3f32 *verts) const {
 	for (unsigned int p = 0; p < 6; p++) {
 		bool inside = true;
 		for (unsigned int v = 0; v < 3; v++) {
-			float *pm = _m + p * 4;
+			const float *pm = _m + p * 4;
 			if(pm[0] * verts[v].x() + pm[1] * verts[v].y() +
 				pm[2] * verts[v].z() + pm[3] >= 0.0)
 					inside = false;
diff --git a/engines/tetraedge/te/te_frustum.h b/engines/tetraedge/te/te_frustum.h
index dbbc7a9a077..d06d2eac23c 100644
--- a/engines/tetraedge/te/te_frustum.h
+++ b/engines/tetraedge/te/te_frustum.h
@@ -35,9 +35,9 @@ public:
 	void computeNormal(unsigned int val);
 	void extractPlanAdd(const TeMatrix4x4 &matrix, uint param_2, uint param_3);
 	void extractPlanSub(const TeMatrix4x4 &matrix, uint param_2, uint param_3);
-	bool pointIsIn(const TeVector3f32 &pt);
-	bool sphereIsIn(const TeVector3f32 &vec, float f);
-	bool triangleIsIn(const TeVector3f32 *vertexes);
+	bool pointIsIn(const TeVector3f32 &pt) const;
+	bool sphereIsIn(const TeVector3f32 &vec, float f) const;
+	bool triangleIsIn(const TeVector3f32 *vertexes) const;
 	void update(TeCamera *camera);
 
 private:
diff --git a/engines/tetraedge/te/te_marker.cpp b/engines/tetraedge/te/te_marker.cpp
index 8ab37780d40..7ef35775c6a 100644
--- a/engines/tetraedge/te/te_marker.cpp
+++ b/engines/tetraedge/te/te_marker.cpp
@@ -51,7 +51,7 @@ void TeMarker::update(TeCamera &camera) {
 		//TeVector3f32 newScale(480.0f / vpWidth, 320.0f / vpHeight, 1.0);
 		//_button.setScale(newScale);
 		_button.setPosition(TeVector3f32(buttonMiddle.x(), buttonMiddle.y(), buttonMiddle.z()));
-		debug("Updated button pos to %s (transformed %s middle %s)", _button.position().dump().c_str(), transformLoc.dump().c_str(), buttonMiddle.dump().c_str());
+		/*debug("Updated button pos to %s (transformed %s middle %s)", _button.position().dump().c_str(), transformLoc.dump().c_str(), buttonMiddle.dump().c_str());*/
 	}
 }
 
diff --git a/engines/tetraedge/te/te_pick_mesh.cpp b/engines/tetraedge/te/te_pick_mesh.cpp
index df7e31ed1ee..49ea1d975e6 100644
--- a/engines/tetraedge/te/te_pick_mesh.cpp
+++ b/engines/tetraedge/te/te_pick_mesh.cpp
@@ -27,50 +27,38 @@
 
 namespace Tetraedge {
 
-TePickMesh::TePickMesh() : _flag(true), _verticies(nullptr), _nTriangles(0) {
+TePickMesh::TePickMesh() : _flag(true) {
 }
 
-TePickMesh::TePickMesh(const TePickMesh &other) : _flag(true), _verticies(nullptr),
-_nTriangles(0) {
+TePickMesh::TePickMesh(const TePickMesh &other) : _flag(true) {
 	copy(other);
 }
 
 void TePickMesh::copy(const TePickMesh &other) {
-	if (_verticies)
-		delete [] _verticies;
-	_verticies = nullptr;
-	_nTriangles = other._nTriangles;
 	_flag = other._flag;
 	_name = other._name;
 	_v1 = other._v1;
 	_v2 = other._v2;
 	_v3 = other._v3;
-	if (other._nTriangles) {
-		_verticies = new TeVector3f32[_nTriangles];
-		for (uint i = 0; i < _nTriangles * 3; i++)
-			_verticies[i] = other._verticies[i];
-	}
+	_verticies = other._verticies;
 }
 
 void TePickMesh::destroy() {
-	if (_verticies)
-		delete [] _verticies;
-	_verticies = nullptr;
-	_nTriangles = 0;
+	_verticies.clear();
 }
 
 void TePickMesh::getTriangle(uint triNum, TeVector3f32 &v1, TeVector3f32 &v2, TeVector3f32 &v3) const {
-	assert(triNum < _nTriangles);
+	assert(triNum < nTriangles());
 	v1 = _verticies[triNum * 3];
 	v2 = _verticies[triNum * 3 + 1];
 	v3 = _verticies[triNum * 3 + 2];
 }
 
 bool TePickMesh::intersect(const Math::Ray &ray, TeVector3f32 &ptOut, float &lenOut) {
-	if (!_flag || !_nTriangles)
+	if (!_flag || _verticies.empty())
 		return false;
 	float nearest = FLT_MAX;
-	for (uint i = 0; i < _nTriangles; i++) {
+	for (uint i = 0; i < _verticies.size() / 3; i++) {
 		float idist;
 		Math::Vector3d iloc;
 		if (ray.intersectTriangle(_verticies[i * 3], _verticies[i * 3 + 1], _verticies[i * 3 + 2], iloc, idist)) {
@@ -88,24 +76,14 @@ bool TePickMesh::intersect(const Math::Ray &ray, TeVector3f32 &ptOut, float &len
 
 void TePickMesh::nbTriangles(uint nTriangles) {
 	destroy();
-	if (nTriangles) {
-		_verticies = new TeVector3f32[_nTriangles];
-		_nTriangles = nTriangles;
-	}
+	_verticies.clear();
+	_verticies.resize(nTriangles * 3);
 }
 
 TePickMesh &TePickMesh::operator+=(const TePickMesh &other) {
-	if (other._nTriangles > 0) {
-		TeVector3f32 *newVecs = new TeVector3f32[(_nTriangles + other._nTriangles) * 3];
-		for (uint i = 0; i < _nTriangles * 3; i++)
-			newVecs[i] = _verticies[i];
-		for (uint i = 0; i < other._nTriangles * 3; i++)
-			newVecs[_nTriangles * 3 + i] = other._verticies[i];
-		if (_verticies)
-			delete _verticies;
-		_verticies = newVecs;
-		_nTriangles += other._nTriangles;
-	}
+	if (other.nTriangles())
+		_verticies.push_back(other._verticies);
+
 	return *this;
 }
 
@@ -114,8 +92,8 @@ TePickMesh &TePickMesh::operator=(const TePickMesh &other) {
 	return *this;
 }
 
-void TePickMesh::setTriangle(uint triNum, const TeVector3f32 &v1, const TeVector3f32 &v2, const TeVector3f32 &v3) const {
-	assert(triNum < _nTriangles);
+void TePickMesh::setTriangle(uint triNum, const TeVector3f32 &v1, const TeVector3f32 &v2, const TeVector3f32 &v3) {
+	assert(triNum < nTriangles());
 	_verticies[triNum * 3] = v1;
 	_verticies[triNum * 3 + 1] = v2;
 	_verticies[triNum * 3 + 2] = v3;
diff --git a/engines/tetraedge/te/te_pick_mesh.h b/engines/tetraedge/te/te_pick_mesh.h
index 7e8f0c8aab9..6bd868a4fc5 100644
--- a/engines/tetraedge/te/te_pick_mesh.h
+++ b/engines/tetraedge/te/te_pick_mesh.h
@@ -40,18 +40,17 @@ public:
 	TePickMesh &operator+=(const TePickMesh &other);
 	TePickMesh &operator=(const TePickMesh &other);
 	// bool operator==(const TePickMesh &other) const; // unused
-	void setTriangle(uint triNum, const TeVector3f32 &v1, const TeVector3f32 &v2, const TeVector3f32 &v3) const;
+	void setTriangle(uint triNum, const TeVector3f32 &v1, const TeVector3f32 &v2, const TeVector3f32 &v3);
 
 	void setName(const Common::String &name) { _name = name; }
 	void setFlag(bool val) { _flag = val; }
 	bool flag() const { return _flag; }
 	const Common::String &name() const { return _name; }
-	uint nTriangles() const { return _nTriangles; }
+	uint nTriangles() const { return _verticies.size() / 3; }
 
 private:
 	bool _flag;
-	TeVector3f32 *_verticies;
-	uint _nTriangles;
+	Common::Array<TeVector3f32> _verticies;
 	Common::String _name;
 	TeVector3f32 _v1;
 	TeVector3f32 _v2;
diff --git a/engines/tetraedge/te/te_warp.cpp b/engines/tetraedge/te/te_warp.cpp
index bf9e264e58e..31797c9f5ff 100644
--- a/engines/tetraedge/te/te_warp.cpp
+++ b/engines/tetraedge/te/te_warp.cpp
@@ -25,6 +25,7 @@
 #include "tetraedge/game/application.h"
 #include "tetraedge/te/te_warp.h"
 #include "tetraedge/te/te_core.h"
+#include "tetraedge/te/te_frustum.h"
 #include "tetraedge/te/te_input_mgr.h"
 #include "tetraedge/te/te_renderer.h"
 #include "tetraedge/te/te_ray_intersection.h"
@@ -125,7 +126,7 @@ void TeWarp::checkObjectEvents() {
 	Math::Ray mouseRay = _camera.getRay(lastMouse);
 	for (auto &animData : _loadedAnimData) {
 		if (_clickedAnimData == &animData) {
-			TePickMesh &pickMesh = animData._frameDatas[animData._curFrameMaybe]._pickMesh;
+			TePickMesh &pickMesh = animData._frameDatas[animData._curFrameNo]._pickMesh;
 			TeVector3f32 intersectPt;
 			float intersectLen;
 			if (pickMesh.flag() && pickMesh.intersect(mouseRay, intersectPt, intersectLen)) {
@@ -145,7 +146,7 @@ void TeWarp::clear() {
 	_putAnimData.clear();
 
 	for (auto &data : _loadedAnimData)
-		data._flag = false;
+		data._enabled = false;
 
 	for (auto *marker : _warpMarkers)
 		marker->marker()->visible(false);
@@ -167,26 +168,27 @@ void TeWarp::configMarker(const Common::String &objname, int markerImgNo, long m
 	assert(foundId >= 0 && foundId < _warpMarkers.size());
 
 	TeWarpMarker *warpMarker = _warpMarkers[foundId];
+	// The game uses TeSprite, but we use the layout system instead.
+	TeLayout &frontLayout = g_engine->getApplication()->frontLayout();
 	if (markerImgNo == -1) {
 		warpMarker->marker()->visible(false);
+		frontLayout.removeChild(&warpMarker->marker()->button());
 	} else {
 		Common::String markerPath = Common::String::format("2D/Menus/InGame/Marker_%d.png#anim", markerImgNo);
-		Common::String markerPathOver = Common::String::format("2D/Menus/InGame/Marker_%d_over.png", markerImgNo);
+		Common::String markerPathDown = Common::String::format("2D/Menus/InGame/Marker_%d_over.png", markerImgNo);
 		if (!exit)
 			warpMarker->setName(objname);
 		else
 			warpMarker->setName(Common::String("3D\\") + objname);
 
-		warpMarker->marker()->button().load(markerPath, markerPathOver, markerPathOver);
+		warpMarker->marker()->button().load(markerPath, markerPathDown, "");
 		TeSpriteLayout *btnUp = dynamic_cast<TeSpriteLayout*>(warpMarker->marker()->button().upLayout());
 		if (!btnUp)
 			error("Loading button image %s failed", markerPath.c_str());
-		warning("TeWarp::configMarker: set anim values and something else here?");
+		//warning("TeWarp::configMarker: set anim values and something else here?");
 		btnUp->_tiledSurfacePtr->_frameAnim.setLoopCount(-1);
 		btnUp->play();
 		warpMarker->marker()->visible(true);
-		// The game uses TeSprite, but we use the layout system instead.
-		TeLayout &frontLayout = g_engine->getApplication()->frontLayout();
 		// Ensure markers appear below menus and videos.
 		frontLayout.addChildBefore(&warpMarker->marker()->button(), frontLayout.child(0));
 	}
@@ -241,12 +243,7 @@ void TeWarp::load(const Common::String &path, bool flag) {
 	TeCore *core = g_engine->getCore();
 	Common::FSNode node = core->findFile(_warpPath);
 	if (!node.isReadable()) {
-		// Try with '\'s..
-		Common::Path warpPathPath(_warpPath, '\\');
-		node = core->findFile(warpPathPath);
-		if (!node.isReadable()) {
-			error("Couldn't find TeWarp path data '%s'", _warpPath.c_str());
-		}
+		error("Couldn't find TeWarp path data '%s'", _warpPath.c_str());
 	}
 
 	if (_preloaded)
@@ -348,7 +345,7 @@ bool TeWarp::onMouseLeftDown(const Common::Point &pt) {
 	bool hitAnimData = false;
 	FrameData *frameData = nullptr;
 	for (auto &animData : _loadedAnimData) {
-		frameData = &(animData._frameDatas[animData._curFrameMaybe]);
+		frameData = &(animData._frameDatas[animData._curFrameNo]);
 		TeVector3f32 interesctPt;
 		float intersectDist;
 		if (frameData->_pickMesh.flag() && frameData->_pickMesh.intersect(mouseRay, interesctPt, intersectDist)) {
@@ -375,9 +372,10 @@ bool TeWarp::onMouseLeftDown(const Common::Point &pt) {
 }
 
 void TeWarp::putObject(const Common::String &name, bool enable) {
+	bool found = false;
 	for (auto &animData : _loadedAnimData) {
 		if (animData._name != name || animData._frameDatas.size() != 1
-				|| animData._curFrameMaybe != 0)
+				|| animData._curFrameNo != 0)
 			continue;
 		bool alreadyAdded = false;
 		for (auto putAnim : _putAnimData) {
@@ -391,9 +389,10 @@ void TeWarp::putObject(const Common::String &name, bool enable) {
 		for (auto &frameData : animData._frameDatas) {
 			frameData._pickMesh.setFlag(enable);
 		}
-		return;
+		found = true;
 	}
-	warning("Impossible de trouver l\'objet %s dans le Warp", name.c_str());
+	if (!found)
+		warning("putObject: Impossible de trouver l\'objet %s dans le Warp", name.c_str());
 }
 
 void TeWarp::update() {
@@ -405,11 +404,28 @@ void TeWarp::update() {
 		_warpBlocs[i].loadTexture(_file, _texEncodingType);
 	}
 
-	if (!_loadedAnimData.empty())
-		error("TODO: Finish updating anims in TeWarp::update");
-	// for (uint i = 0; i < _loadedAnimData.size(); i++) {
-	//
-	// }
+	for (auto &anim : _loadedAnimData) {
+		if (anim._repCount && anim._frameDatas.size() > 1) {
+			uint64 elapsed = anim._timer.getTimeFromStart();
+			int frameNow = elapsed * anim._fps / 1000000.0;
+			int lastFrame = anim._curFrameNo;
+			if (anim._repCount != -1) {
+				anim._repCount = anim._repCount - frameNow / (anim._endFrameNo - anim._firstFrameNo);
+				if (anim._repCount < 1) {
+					anim._repCount = 0;
+					frameNow = anim._endFrameNo - 1;
+					_animFinishedSignal.call(anim._name);
+				}
+			}
+			
+			anim._curFrameNo = anim._firstFrameNo + ((frameNow - anim._firstFrameNo) % (anim._endFrameNo - anim._firstFrameNo));
+			if (anim._curFrameNo != lastFrame) {
+				anim._frameDatas[lastFrame].unloadTextures();
+				anim._frameDatas[lastFrame]._loadedTexCount = 0;
+			}
+		}
+		anim._frameDatas[anim._curFrameNo];
+	}
 }
 
 void TeWarp::sendExit(TeWarp::Exit &exit) {
@@ -437,8 +453,36 @@ void TeWarp::sendMarker(const Common::String &name, unsigned long markerId) {
 		anim->_markerIds.push_back(markerId);
 }
 
-void TeWarp::setAnimationPart(const Common::String &name, int x, int y, int z, bool flag) {
-	error("TODO: Implement TeWarp::setAnimationPart");
+void TeWarp::startAnimationPart(const Common::String &name, int x, int startFrame, int endFrame, bool flag) {
+	bool started = false;
+	for (auto &animData : _loadedAnimData) {
+		if (animData._name != name)
+			continue;
+		animData._enabled = true;
+		bool alreadyPut = false;
+		for (auto *putAnim : _putAnimData) {
+			if (putAnim == &animData)
+				alreadyPut = true;
+		}
+		if (!alreadyPut)
+			_putAnimData.push_back(&animData);
+
+		animData._repCount = x;
+		animData._timer.stop();
+		animData._firstFrameNo = startFrame;
+		if (endFrame < 0)
+			endFrame += animData._frameDatas.size();
+		animData._endFrameNo = endFrame;
+		for (auto &frameData : animData._frameDatas) {
+			// TODO: Is this setting the right thing?
+			frameData._pickMesh.setFlag(flag);
+		}
+		
+		animData._timer.start();
+		started = true;
+	}
+	if (!started)
+		warning("startAnimationPartImpossible de trouver l\'animation %s dans le Warp.", name.c_str());
 }
 
 void TeWarp::setColor(const TeColor &col) {
@@ -500,6 +544,8 @@ void TeWarp::render() {
 	TeVector3f32 vertexes[6];
 	for (uint i = 0; i < _putAnimData.size(); i++) {
 		AnimData *animData = _putAnimData[i];
+		if (!animData->_enabled)
+			continue;
 		for (uint j = 0; j < animData->_frameDatas.size(); j++) {
 			FrameData &frameData = animData->_frameDatas[j];
 			for (uint k = 0; k < frameData._warpBlocs.size(); k++) {
@@ -544,12 +590,25 @@ void TeWarp::setFov(float fov) {
 }
 
 void TeWarp::takeObject(const Common::String &name) {
+	bool found = false;
 	for (auto &animData : _loadedAnimData) {
 		if (animData._name != name)
 			continue;
-		error("TODO: Finish TeWarp::takeObject");
+		animData._curFrameNo = 0;
+		animData._enabled = false;
+		for (uint i = 0; i < _putAnimData.size(); i++) {
+			if (_putAnimData[i] == &animData) {
+				_putAnimData.remove_at(i);
+				break;
+			}
+		}
+		for (auto &frame : animData._frameDatas) {
+			frame._pickMesh.setFlag(false);
+		}
+		found = true;
 	}
-	warning("Impossible de trouver l\'objet %s dans le Warp", name.c_str());
+	if (!found)
+		warning("takeObject: Impossible de trouver l\'objet %s dans le Warp", name.c_str());
 }
 
 void TeWarp::unload() {
@@ -598,4 +657,28 @@ void TeWarp::updateCamera(const TeVector3f32 &screen) {
 	_camera.projectionMatrix();
 }
 
+void TeWarp::FrameData::loadTextures(const TeFrustum &frustum, Common::File &file, const Common::String &fileType) {
+	TeVector3f32 triangle1[3];
+	TeVector3f32 triangle2[3];
+	for (int b = 0; b < _numWarpBlocs; b++) {
+		TeWarpBloc &bloc = _warpBlocs[b];
+		if (bloc.isLoaded())
+			continue;
+		triangle1[0] = bloc.vertex(0);
+		triangle1[1] = bloc.vertex(1);
+		triangle1[2] = bloc.vertex(3);
+		triangle2[0] = bloc.vertex(1);
+		triangle2[1] = bloc.vertex(2);
+		triangle2[2] = bloc.vertex(3);
+		if (frustum.triangleIsIn(triangle1) || frustum.triangleIsIn(triangle2)) {
+			bloc.loadTexture(file, fileType);
+		}
+	}
+}
+
+void TeWarp::FrameData::unloadTextures() {
+	for (auto &bloc : _warpBlocs)
+		bloc.unloadTexture();
+}
+
 } // end namespace Tetraedge
diff --git a/engines/tetraedge/te/te_warp.h b/engines/tetraedge/te/te_warp.h
index bfad102a480..fb92c9a3727 100644
--- a/engines/tetraedge/te/te_warp.h
+++ b/engines/tetraedge/te/te_warp.h
@@ -42,15 +42,22 @@ public:
 		Common::Array<TeWarpBloc> _warpBlocs;
 		TePickMesh _pickMesh;
 		int _loadedTexCount;
+		// Note: dropped "minblock" param from original as it's only
+		// ever set to 0
+		void loadTextures(const TeFrustum &frustum, Common::File &file, const Common::String &fileType);
+		void unloadTextures();
 	};
 
 	class AnimData {
 	public:
-		AnimData() : _fps(15.0f), _flag(false), _curFrameMaybe(0) {}
+		AnimData() : _fps(15.0f), _enabled(false), _curFrameNo(0), _repCount(0), _firstFrameNo(0), _endFrameNo(0) {}
 		Common::Array<unsigned long> _markerIds;
 		float _fps;
-		int _curFrameMaybe;
-		bool _flag;
+		int _repCount;
+		int _firstFrameNo;
+		int _endFrameNo;
+		int _curFrameNo;
+		bool _enabled;
 		TeTimer _timer;
 		Common::String _name;
 		Common::Array<FrameData> _frameDatas;
@@ -98,12 +105,12 @@ public:
 	void rotateCamera(const TeQuaternion &rot);
 	void sendExit(Exit &exit);
 	void sendMarker(const Common::String &name, unsigned long markerId);
-	void setAnimationPart(const Common::String &name, int x, int y, int z, bool flag);
 	void setColor(const TeColor &col) override;
 	void setMarkersOpacity(float opacity);
 	void setMouseLeftUpForMakers();
 	void setFov(float fov);
 	void setVisible(bool v1, bool v2);
+	void startAnimationPart(const Common::String &name, int x, int y, int z, bool flag);
 	void takeObject(const Common::String &name);
 	void unload();
 	void unloadTextures();
diff --git a/engines/tetraedge/te/te_warp_marker.cpp b/engines/tetraedge/te/te_warp_marker.cpp
index 676663972ba..1b327e4ceda 100644
--- a/engines/tetraedge/te/te_warp_marker.cpp
+++ b/engines/tetraedge/te/te_warp_marker.cpp
@@ -27,16 +27,22 @@ TeWarpMarker::TeWarpMarker() : _marker(nullptr) {
 }
 
 TeWarpMarker::~TeWarpMarker() {
-	if (_marker)
+	if (_marker) {
 		_marker->button().onMouseClickValidated().remove(this, &TeWarpMarker::onMarkerButtonValidated);
+		_marker->button().setVisible(false);
+	}
 }
 
 void TeWarpMarker::marker(TeMarker *marker) {
-	if (_marker)
+	if (_marker) {
 		_marker->button().onMouseClickValidated().remove(this, &TeWarpMarker::onMarkerButtonValidated);
+		_marker->button().setVisible(false);
+	}
 	_marker = marker;
-	if (_marker)
+	if (_marker) {
 		_marker->button().onMouseClickValidated().add(this, &TeWarpMarker::onMarkerButtonValidated);
+		_marker->button().setName(_name + "_btn");
+	}
 }
 
 bool TeWarpMarker::onMarkerButtonValidated() {




More information about the Scummvm-git-logs mailing list