[Scummvm-git-logs] scummvm master -> 051e745ebb5ca84afcc2811eacf7ca825070097e

mduggan noreply at scummvm.org
Mon Apr 17 10:48:13 UTC 2023


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

Summary:
051e745ebb TETRAEDGE: Implement more TeWarp associated classes for Amerzone


Commit: 051e745ebb5ca84afcc2811eacf7ca825070097e
    https://github.com/scummvm/scummvm/commit/051e745ebb5ca84afcc2811eacf7ca825070097e
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-04-17T19:47:20+09:00

Commit Message:
TETRAEDGE: Implement more TeWarp associated classes for Amerzone

Changed paths:
  A engines/tetraedge/te/te_pick_mesh.cpp
  A engines/tetraedge/te/te_pick_mesh.h
  A engines/tetraedge/te/te_scene_warp.cpp
  A engines/tetraedge/te/te_scene_warp.h
  A engines/tetraedge/te/te_scene_warp_xml_parser.cpp
  A engines/tetraedge/te/te_scene_warp_xml_parser.h
  A engines/tetraedge/te/te_warp_bloc.cpp
  A engines/tetraedge/te/te_warp_bloc.h
    engines/tetraedge/game/amerzone_game.cpp
    engines/tetraedge/game/amerzone_game.h
    engines/tetraedge/game/application.cpp
    engines/tetraedge/game/dialog2.cpp
    engines/tetraedge/game/main_menu.cpp
    engines/tetraedge/game/notifier.cpp
    engines/tetraedge/game/splash_screens.cpp
    engines/tetraedge/module.mk
    engines/tetraedge/te/te_animation.cpp
    engines/tetraedge/te/te_button_layout.cpp
    engines/tetraedge/te/te_button_layout.h
    engines/tetraedge/te/te_camera.cpp
    engines/tetraedge/te/te_camera.h
    engines/tetraedge/te/te_core.cpp
    engines/tetraedge/te/te_core.h
    engines/tetraedge/te/te_image.cpp
    engines/tetraedge/te/te_image.h
    engines/tetraedge/te/te_marker.cpp
    engines/tetraedge/te/te_marker.h
    engines/tetraedge/te/te_visual_fade.cpp
    engines/tetraedge/te/te_visual_fade.h
    engines/tetraedge/te/te_warp.cpp
    engines/tetraedge/te/te_warp.h
    engines/tetraedge/te/te_warp_marker.h
    engines/tetraedge/tetraedge.cpp
    engines/tetraedge/tetraedge.h


diff --git a/engines/tetraedge/game/amerzone_game.cpp b/engines/tetraedge/game/amerzone_game.cpp
index 30854c48cb2..906a8eb2aaf 100644
--- a/engines/tetraedge/game/amerzone_game.cpp
+++ b/engines/tetraedge/game/amerzone_game.cpp
@@ -19,11 +19,16 @@
  *
  */
 
+#include "common/math.h"
+
 #include "tetraedge/tetraedge.h"
 #include "tetraedge/game/application.h"
 #include "tetraedge/game/amerzone_game.h"
 #include "tetraedge/game/lua_binds.h"
+#include "tetraedge/te/te_core.h"
 #include "tetraedge/te/te_input_mgr.h"
+#include "tetraedge/te/te_renderer.h"
+#include "tetraedge/te/te_scene_warp.h"
 #include "tetraedge/te/te_sound_manager.h"
 #include "tetraedge/te/te_warp.h"
 
@@ -31,7 +36,7 @@ namespace Tetraedge {
 
 AmerzoneGame::AmerzoneGame() : Tetraedge::Game(), _orientationX(0.0f), _orientationY(0.0f),
 _speedX(0.0f), _speedY(0.0f), _isInDrag(false), _edgeButtonRolloverCount(0),
-_warpX(nullptr), _warpY(nullptr) {
+_warpX(nullptr), _warpY(nullptr), _prevWarpY(nullptr) {
 
 }
 
@@ -49,7 +54,65 @@ void AmerzoneGame::changeSpeedToMouseDirection() {
 }
 
 bool AmerzoneGame::changeWarp(const Common::String &zone, const Common::String &scene, bool fadeFlag) {
-	error("TODO: Implement AmerzoneGame::changeWarp");
+	if (_warpY) {
+		_luaScript.execute("OnWarpLeave");
+		_warpY->markerValidatedSignal().add(this, &AmerzoneGame::onObjectClick);
+		_warpY->animFinishedSignal().add(this, &AmerzoneGame::onAnimationFinished);
+		saveBackup("save.xml");
+		_music.stop();
+	}
+	_prevWarpY = _warpY;
+	_warpY = nullptr;
+
+	Application *app = g_engine->getApplication();
+	TeCore *core = g_engine->getCore();
+
+	// TODO: There is a bunch of stuff here to cache the warp zone.
+	// Just reload each time for now.
+	if (!_warpY) {
+		_warpY = new TeWarp();
+		_warpY->setRotation(app->frontOrientationLayout().rotation());
+		_warpY->init();
+		float fov = 45.0f; //TODO: g_engine->getCore()->fileFlagSystemFlagsContains("HD") ? 60.0f : 45.0f;
+		_warpY->setFov(fov);
+	}
+	_warpY->load(zone, false);
+	_warpY->setVisible(true, false);
+	TeWarp::debug = false;
+	_warpY->activeMarkers(app->permanentHelp());
+	_warpY->animFinishedSignal().add(this, &AmerzoneGame::onAnimationFinished);
+	_luaContext.removeGlobal("OnWarpEnter");
+	_luaContext.removeGlobal("OnWarpLeave");
+	_luaContext.removeGlobal("OnWarpObjectHit");
+	_luaContext.removeGlobal("OnMovieFinished");
+	_luaContext.removeGlobal("OnAnimationFinished");
+	_luaContext.removeGlobal("OnDialogFinished");
+	_luaContext.removeGlobal("OnDocumentClosed");
+	_luaContext.removeGlobal("OnPuzzleWon");
+	Common::String sceneXml = zone;
+	size_t dotpos = sceneXml.rfind('.');
+	if (dotpos != Common::String::npos)
+		sceneXml = sceneXml.substr(0, dotpos);
+	sceneXml += ".xml";
+	TeSceneWarp sceneWarp;
+	sceneWarp.load(sceneXml, _warpY, false);
+
+	_xAngleMin = FLT_MAX;
+	_xAngleMax = FLT_MAX;
+	_yAngleMax = 45.0 - _orientationY;
+	_yAngleMin = _orientationY + 55.0;
+
+	dotpos = sceneXml.rfind('.');
+	Common::String sceneLua = sceneXml.substr(0, dotpos);
+	sceneLua += ".xml";
+	_luaScript.load(core->findFile(sceneLua));
+	_luaScript.execute();
+	_luaScript.execute("OnWarpEnter");
+	if (fadeFlag) {
+        startChangeWarpAnim();
+	} else {
+        onChangeWarpAnimFinished();
+	}
 	return false;
 }
 
@@ -121,19 +184,36 @@ void AmerzoneGame::finishGame() {
 	app->mainMenu().enter();
 }
 
+// This is actually GameWarp::Load
 void AmerzoneGame::initLoadedBackupData() {
 	_luaContext.destroy();
 	_luaContext.create();
 	_luaContext.addBindings(LuaBinds::LuaOpenBinds);
-	//if (!_loadName.empty()) {
-	//}
-	error("TODO: finish AmerzoneGame::initLoadedBackupData");
+	Application *app = g_engine->getApplication();
+	if (!_loadName.empty()) {
+		error("TODO: finish AmerzoneGame::initLoadedBackupData for direct load");
+	}
+	changeWarp(app->firstWarpPath(), app->firstScene(), true);
 }
 
 void AmerzoneGame::leave(bool flag) {
 	error("TODO: Implement AmerzoneGame::leave");
 }
 
+bool AmerzoneGame::onChangeWarpAnimFinished() {
+	if (_prevWarpY) {
+		// TODO: remove callback from movement3
+		_prevWarpY->setVisible(false, true);
+		_prevWarpY->clear();
+		_prevWarpY = nullptr;
+		// TODO: set some sprite not visible here.
+		error("TODO: Finish AmerzoneGame::onChangeWarpAnimFinished");
+	}
+	_warpY->markerValidatedSignal().remove(this, &AmerzoneGame::onObjectClick);
+	optimizeWarpResources();
+	return false;
+}
+
 bool AmerzoneGame::onHelpButtonValidated() {
 	g_engine->getSoundManager()->playFreeSound("Sounds/SFX/Clic_prec-suiv.ogg", 1.0f, "sfx");
 
@@ -146,6 +226,10 @@ bool AmerzoneGame::onHelpButtonValidated() {
 	return false;
 }
 
+bool AmerzoneGame::onAnimationFinished(const Common::String &anim) {
+	error("TODO: Implement AmerzoneGame::onAnimationFinished");
+}
+
 bool AmerzoneGame::onMouseLeftUp(const Common::Point &pt) {
 	error("TODO: Implement AmerzoneGame::onMouseLeftUp");
 }
@@ -154,6 +238,14 @@ bool AmerzoneGame::onMouseLeftDown(const Common::Point &pt) {
 	error("TODO: Implement AmerzoneGame::onMouseLeftDown");
 }
 
+bool AmerzoneGame::onObjectClick(const Common::String &obj) {
+	error("TODO: Implement AmerzoneGame::onObjectClick");
+}
+
+void AmerzoneGame::optimizeWarpResources() {
+	error("TODO: Implement AmerzoneGame::optimizeWarpResources");
+}
+
 void AmerzoneGame::setAngleX(float angle) {
 	float diff = angle - _orientationX;
 	float distFromMin = _xAngleMin - diff;
@@ -200,6 +292,27 @@ void AmerzoneGame::speedY(float speed) {
 	_speedY = CLIP(speed, -10000.0f, 10000.0f);
 }
 
+void AmerzoneGame::startChangeWarpAnim() {
+	_warpX->update();
+	_warpY->update();
+	if (_prevWarpY == nullptr) {
+		onChangeWarpAnimFinished();
+	} else {
+		TeRenderer *renderer = g_engine->getRenderer();
+		renderer->clearBuffer(TeRenderer::ColorBuffer);
+		renderer->clearBuffer(TeRenderer::DepthBuffer);
+		if (_warpX)
+			_warpX->render();
+		_prevWarpY->render();
+
+		// This is a much simpler version of what the original does
+		// as it reuses the fade code.
+		g_engine->getApplication()->captureFade();
+		_prevWarpY->unloadTextures();
+		g_engine->getApplication()->visualFade().animateFadeWithZoom();
+	}
+}
+
 void AmerzoneGame::update() {
 	TeInputMgr *inputMgr = g_engine->getInputMgr();
 
diff --git a/engines/tetraedge/game/amerzone_game.h b/engines/tetraedge/game/amerzone_game.h
index e739e6d8c73..291e61ae40a 100644
--- a/engines/tetraedge/game/amerzone_game.h
+++ b/engines/tetraedge/game/amerzone_game.h
@@ -55,8 +55,14 @@ private:
 	void speedY(float speed);
 
 	bool onHelpButtonValidated();
+	bool onAnimationFinished(const Common::String &anim);
 	bool onMouseLeftUp(const Common::Point &pt);
 	bool onMouseLeftDown(const Common::Point &pt);
+	bool onObjectClick(const Common::String &obj);
+
+	void optimizeWarpResources();
+	void startChangeWarpAnim();
+	bool onChangeWarpAnimFinished();
 
 	TeTimer _dragTimer;
 	float _orientationX;
@@ -77,6 +83,7 @@ private:
 	*/
 	TeWarp *_warpX;
 	TeWarp *_warpY;
+	TeWarp *_prevWarpY;
 };
 
 } // end namespace Tetraedge
diff --git a/engines/tetraedge/game/application.cpp b/engines/tetraedge/game/application.cpp
index 15245e6efde..c44ce88802e 100644
--- a/engines/tetraedge/game/application.cpp
+++ b/engines/tetraedge/game/application.cpp
@@ -88,10 +88,7 @@ _permanentHelp(false) {
 
 	// Note: original has an app run timer, but it's never used?
 
-	if (g_engine->gameType() == TetraedgeEngine::kAmerzone)
-		_defaultCursor = "2D/arrow6.png";
-	else
-		_defaultCursor = "pictures/cursor.png";
+	_defaultCursor = g_engine->gameIsAmerzone() ? "2D/arrow6.png" : "pictures/cursor.png";
 
 	loadOptions("options.xml");
 }
@@ -174,7 +171,7 @@ void Application::create() {
 	_loc.load(textFileNode);
 	core->addLoc(&_loc);
 
-	if (g_engine->gameType() != TetraedgeEngine::kAmerzone) {
+	if (!g_engine->gameIsAmerzone()) {
 		const Common::Path helpMenuPath("menus/help/help_");
 		Common::Path helpMenuFilePath;
 		i = 0;
diff --git a/engines/tetraedge/game/dialog2.cpp b/engines/tetraedge/game/dialog2.cpp
index b355096fc7c..b1b625480fb 100644
--- a/engines/tetraedge/game/dialog2.cpp
+++ b/engines/tetraedge/game/dialog2.cpp
@@ -98,7 +98,7 @@ void Dialog2::load() {
 	setSize(TeVector3f32(1.0f, 1.0f, usersz.z()));
 	size(); // refresh size? seems to do nothing with result
 	_music.repeat(false);
-	const char *luaPath = g_engine->gameType() == TetraedgeEngine::kAmerzone ? "GUI/dialog.lua" : "menus/dialog.lua";
+	const char *luaPath = g_engine->gameIsAmerzone() ? "GUI/dialog.lua" : "menus/dialog.lua";
 	_gui.load(luaPath);
 	size(); // refresh size? seems to do nothing with result
 	TeButtonLayout *dialogLockBtn = _gui.buttonLayoutChecked("dialogLockButton");
diff --git a/engines/tetraedge/game/main_menu.cpp b/engines/tetraedge/game/main_menu.cpp
index 1ef121427b5..f474f020f36 100644
--- a/engines/tetraedge/game/main_menu.cpp
+++ b/engines/tetraedge/game/main_menu.cpp
@@ -68,7 +68,7 @@ void MainMenu::enter() {
 	app->captureFade();
 
 	_entered = true;
-	const char *luaFile = (g_engine->gameType() == TetraedgeEngine::kAmerzone ? "GUI/MainMenu.lua" : "menus/mainMenu/mainMenu.lua");
+	const char *luaFile = g_engine->gameIsAmerzone() ? "GUI/MainMenu.lua" : "menus/mainMenu/mainMenu.lua";
 	load(luaFile);
 
 	TeLayout *menuLayout = layoutChecked("menu");
diff --git a/engines/tetraedge/game/notifier.cpp b/engines/tetraedge/game/notifier.cpp
index 0a4f8066e31..1e652f3c6cd 100644
--- a/engines/tetraedge/game/notifier.cpp
+++ b/engines/tetraedge/game/notifier.cpp
@@ -76,9 +76,9 @@ void Notifier::launchNextnotifier() {
 }
 
 void Notifier::load() {
-	const char *luaPath = g_engine->gameType() == TetraedgeEngine::kAmerzone ? "GUI/Notify.lua" : "menus/Notifier.lua";
+	const char *luaPath = g_engine->gameIsAmerzone() ? "GUI/Notify.lua" : "menus/Notifier.lua";
 	_gui.load(luaPath);
-	const char *layoutName = g_engine->gameType() == TetraedgeEngine::kAmerzone ? "notify" : "notifier";
+	const char *layoutName = g_engine->gameIsAmerzone() ? "notify" : "notifier";
 	TeLayout *notifierLayout = _gui.layoutChecked(layoutName);
 	Game *game = g_engine->getGame();
 	game->addNoScale2Child(notifierLayout);
diff --git a/engines/tetraedge/game/splash_screens.cpp b/engines/tetraedge/game/splash_screens.cpp
index be262fe6699..a7c54e0759a 100644
--- a/engines/tetraedge/game/splash_screens.cpp
+++ b/engines/tetraedge/game/splash_screens.cpp
@@ -38,9 +38,9 @@ void SplashScreens::enter()	{
 	if (!_entered) {
 		_entered = true;
 		_splashNo = 0;
-		const Common::Path scriptPath("menus/splashes/splash0.lua");
-		if (Common::File::exists(scriptPath)) {
-			TeLuaGUI::load(scriptPath.toString());
+		const char *scriptStr = g_engine->gameIsAmerzone() ? "GUI/PC-MacOSX/Splash0.lua" : "menus/splashes/splash0.lua";
+		if (Common::File::exists(scriptStr)) {
+			TeLuaGUI::load(scriptStr);
 			Application *app = g_engine->getApplication();
 			TeLayout *splash = layout("splash");
 			app->frontLayout().addChild(splash);
@@ -55,7 +55,8 @@ bool SplashScreens::onAlarm() {
 	app->visualFade().init();
 	app->captureFade();
 	TeLuaGUI::unload();
-	const Common::String scriptName = Common::String::format("menus/splashes/splash%d.lua", _splashNo);
+	const char *scriptStr = g_engine->gameIsAmerzone() ? "GUI/PC-MacOSX/Splash%d.lua" : "menus/splashes/splash%d.lua";
+	const Common::String scriptName = Common::String::format(scriptStr, _splashNo);
 	_splashNo++;
 
 	if (ConfMan.getBool("skip_splash")) {
diff --git a/engines/tetraedge/module.mk b/engines/tetraedge/module.mk
index 031499ba56c..40139375e88 100644
--- a/engines/tetraedge/module.mk
+++ b/engines/tetraedge/module.mk
@@ -94,6 +94,7 @@ MODULE_OBJS := \
 	te/te_obp.o \
 	te/te_palette.o \
 	te/te_particle.o \
+	te/te_pick_mesh.o \
 	te/te_pick_mesh2.o \
 	te/te_png.o \
 	te/te_quaternion.o \
@@ -103,6 +104,8 @@ MODULE_OBJS := \
 	te/te_resource.o \
 	te/te_resource_manager.o \
 	te/te_scene.o \
+	te/te_scene_warp.o \
+	te/te_scene_warp_xml_parser.o \
 	te/te_scrolling_layout.o \
 	te/te_scummvm_codec.o \
 	te/te_sound_manager.o \
@@ -122,6 +125,7 @@ MODULE_OBJS := \
 	te/te_vector3f32.o \
 	te/te_visual_fade.o \
 	te/te_warp.o \
+	te/te_warp_bloc.o \
 	te/te_warp_marker.o \
 	te/te_xml_parser.o \
 	te/te_xml_gui.o \
diff --git a/engines/tetraedge/te/te_animation.cpp b/engines/tetraedge/te/te_animation.cpp
index b5f8e35fd28..716245982c3 100644
--- a/engines/tetraedge/te/te_animation.cpp
+++ b/engines/tetraedge/te/te_animation.cpp
@@ -43,7 +43,15 @@ TeAnimation::~TeAnimation() {
 void TeAnimation::cont() {
 	if (!_runTimer.running()) {
 		_runTimer.start();
-		animations()->push_back(this);
+
+		Common::Array<TeAnimation *> *anims = animations();
+		Common::Array<TeAnimation *>::iterator iter;
+		for (iter = anims->begin(); iter != anims->end(); iter++) {
+			if (*iter == this) {
+				error("anim being resumed is already in active anims");
+			}
+		}
+		anims->push_back(this);
 		update(_runTimer.getTimeFromStart() / 1000.0);
 	}
 }
diff --git a/engines/tetraedge/te/te_button_layout.cpp b/engines/tetraedge/te/te_button_layout.cpp
index ce27136a237..37c9e932342 100644
--- a/engines/tetraedge/te/te_button_layout.cpp
+++ b/engines/tetraedge/te/te_button_layout.cpp
@@ -26,6 +26,7 @@
 #include "tetraedge/te/te_button_layout.h"
 #include "tetraedge/te/te_sound_manager.h"
 #include "tetraedge/te/te_input_mgr.h"
+#include "tetraedge/te/te_sprite_layout.h"
 
 namespace Tetraedge {
 
@@ -56,7 +57,7 @@ TeButtonLayout::TeButtonLayout() : _currentState(BUTTON_STATE_UP),
 _clickPassThrough(false), _validationSoundVolume(1.0),
 _ignoreMouseEvents(false), _doubleValidationProtectionEnabled(true),
 _upLayout(nullptr), _downLayout(nullptr), _rolloverLayout(nullptr),
-_disabledLayout(nullptr), _hitZoneLayout(nullptr)
+_disabledLayout(nullptr), _hitZoneLayout(nullptr), _ownedLayouts(false)
 {
 	_onMousePositionChangedMaxPriorityCallback.reset(new TeCallback1Param<TeButtonLayout, const Common::Point &>(this, &TeButtonLayout::onMousePositionChangedMaxPriority, FLT_MAX));
 
@@ -84,6 +85,18 @@ TeButtonLayout::~TeButtonLayout() {
 	inputmgr->_mouseLDownSignal.remove(_onMouseLeftDownCallback);
 	inputmgr->_mouseLUpSignal.remove(_onMouseLeftUpCallback);
 	inputmgr->_mouseLUpSignal.remove(_onMouseLeftUpMaxPriorityCallback);
+	if (_ownedLayouts) {
+		if (_upLayout)
+			delete _upLayout;
+		if (_downLayout)
+			delete _downLayout;
+		if (_rolloverLayout)
+			delete _rolloverLayout;
+		if (_hitZoneLayout)
+			delete _hitZoneLayout;
+		if (_disabledLayout)
+			delete _disabledLayout;
+	}
 }
 
 bool TeButtonLayout::isMouseIn(const TeVector2s32 &mouseloc) {
@@ -94,6 +107,32 @@ bool TeButtonLayout::isMouseIn(const TeVector2s32 &mouseloc) {
 	}
 }
 
+void TeButtonLayout::load(const Common::String &upImg, const Common::String &downImg, const Common::String &overImg) {
+	TeSpriteLayout *upSprite = nullptr;
+	if (upImg.size()) {
+		upSprite = new TeSpriteLayout();
+		upSprite->load(upImg);
+	}
+	setUpLayout(upSprite);
+
+	TeSpriteLayout *downSprite = nullptr;
+	if (downImg.size()) {
+		downSprite = new TeSpriteLayout();
+		downSprite->load(downImg);
+	}
+	setDownLayout(downSprite);
+
+	TeSpriteLayout *overSprite = nullptr;
+	if (overImg.size()) {
+		overSprite = new TeSpriteLayout();
+		overSprite->load(overImg);
+	}
+	setRollOverLayout(overSprite);
+	setHitZone(nullptr);
+	setDisabledLayout(nullptr);
+	_ownedLayouts = true;
+}
+
 bool TeButtonLayout::onMouseLeftDown(const Common::Point &pt) {
 	if (!worldVisible() || _currentState == BUTTON_STATE_DISABLED || _ignoreMouseEvents)
 		return false;
diff --git a/engines/tetraedge/te/te_button_layout.h b/engines/tetraedge/te/te_button_layout.h
index b546502cd73..18fb66cef68 100644
--- a/engines/tetraedge/te/te_button_layout.h
+++ b/engines/tetraedge/te/te_button_layout.h
@@ -97,6 +97,9 @@ public:
 	TeLayout *downLayout() { return _downLayout; }
 	void setIgnoreMouseEvents(bool val) { _ignoreMouseEvents = val; }
 
+	// From TeSpriteButton, a direct way to load the images.
+	void load(const Common::String &upImg, const Common::String &downImg, const Common::String &overImg);
+
 private:
 	static bool _mousePositionChangedCatched;
 	static TeTimer *getDoubleValidationProtectionTimer();
@@ -104,9 +107,10 @@ private:
 
 	bool _doubleValidationProtectionEnabled;
 	bool _ignoreMouseEvents;
+	bool _ownedLayouts;
 
-	State _currentState;
 	bool _clickPassThrough;
+	State _currentState;
 	Common::String _validationSound;
 	float _validationSoundVolume;
 
diff --git a/engines/tetraedge/te/te_camera.cpp b/engines/tetraedge/te/te_camera.cpp
index 59d7ff37bea..59bdac8f614 100644
--- a/engines/tetraedge/te/te_camera.cpp
+++ b/engines/tetraedge/te/te_camera.cpp
@@ -262,8 +262,21 @@ TeMatrix4x4 TeCamera::transformationMatrix() {
 }
 
 TeVector3f32 TeCamera::transformCoord(const TeVector3f32 &pt) {
-	warning("TODO: Implement TeCamera::transformCoord");
-	return pt;
+	_rotation.normalize();
+	TeQuaternion rot;
+	rot.x() = -_rotation.x();
+	rot.y() = -_rotation.y();
+	rot.z() = -_rotation.z();
+	rot.w() = _rotation.w();
+	const TeMatrix4x4 rotMatrix = rot.toTeMatrix();
+	const TeVector3f32 transPt = (_projectionMatrix * rotMatrix) * pt;
+	const int halfVPWidth = abs((int)(_viewportW / 2));
+	const int halfVPHeight = abs((int)(_viewportH / 2));
+	TeVector3f32 retval;
+	retval.x() = halfVPWidth * (transPt.x() + 1);
+	retval.y() = halfVPHeight * (transPt.y() + 1);
+	retval.z() = transPt.z();
+	return retval;
 }
 
 TeVector3f32 TeCamera::transformPoint2Dto3D(const TeVector3f32 &pt) {
diff --git a/engines/tetraedge/te/te_camera.h b/engines/tetraedge/te/te_camera.h
index aa89b35e80f..b17a1e69fa7 100644
--- a/engines/tetraedge/te/te_camera.h
+++ b/engines/tetraedge/te/te_camera.h
@@ -115,7 +115,6 @@ private:
 	TeMatrix4x4 _projectionMatrix;
 
 	TeSignal0Param _onViewportChangedSignal;
-
 };
 
 } // end namespace Tetraedge
diff --git a/engines/tetraedge/te/te_core.cpp b/engines/tetraedge/te/te_core.cpp
index 26ffc5ae042..8e5f11a9d4e 100644
--- a/engines/tetraedge/te/te_core.cpp
+++ b/engines/tetraedge/te/te_core.cpp
@@ -62,12 +62,7 @@ void TeCore::create() {
 	warning("TODO: TeCore::create: Finish implementing me.");
 }
 
-TeICodec *TeCore::createVideoCodec(const Common::FSNode &node) {
-	const Common::String filename = node.getName();
-	if (!filename.contains('.'))
-		return nullptr;
-	Common::String extn = filename.substr(filename.findFirstOf('.') + 1);
-	extn.toLowercase();
+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)) {
@@ -81,7 +76,19 @@ TeICodec *TeCore::createVideoCodec(const Common::FSNode &node) {
 	} else if (TeImagesSequence::matchExtension(extn)) {
 		return new TeImagesSequence();
 	}
-	error("TTeCore::createVideoCodec: Unrecognised format %s", node.getName().c_str());
+	return nullptr;
+}
+
+TeICodec *TeCore::createVideoCodec(const Common::FSNode &node) {
+	const Common::String filename = node.getName();
+	if (!filename.contains('.'))
+		return nullptr;
+	Common::String extn = filename.substr(filename.findFirstOf('.') + 1);
+	extn.toLowercase();
+	TeICodec *codec = createVideoCodec(extn);
+	if (!codec)
+		error("TTeCore::createVideoCodec: Unrecognised format %s", node.getName().c_str());
+	return codec;
 }
 
 const Common::String &TeCore::fileFlagSystemFlag(const Common::String &name) const {
diff --git a/engines/tetraedge/te/te_core.h b/engines/tetraedge/te/te_core.h
index f9f3ed661de..2fde075005d 100644
--- a/engines/tetraedge/te/te_core.h
+++ b/engines/tetraedge/te/te_core.h
@@ -42,6 +42,7 @@ public:
 	//void args(int argc, char **argv); // Probably not needed
 	void create();
 	TeICodec *createVideoCodec(const Common::FSNode &node);
+	TeICodec *createVideoCodec(const Common::String &extn);
 	const Common::String &fileFlagSystemFlag(const Common::String &name) const;
 	bool fileFlagSystemFlagsContains(const Common::String &name) const;
 	Common::Array<Common::String> fileFlagSystemPossibleFlags();
diff --git a/engines/tetraedge/te/te_image.cpp b/engines/tetraedge/te/te_image.cpp
index 06f9776b5f4..204cca4720c 100644
--- a/engines/tetraedge/te/te_image.cpp
+++ b/engines/tetraedge/te/te_image.cpp
@@ -25,6 +25,7 @@
 #include "tetraedge/te/te_core.h"
 #include "tetraedge/te/te_image.h"
 #include "tetraedge/te/te_i_codec.h"
+#include "tetraedge/te/te_scummvm_codec.h"
 
 namespace Tetraedge {
 
@@ -111,7 +112,14 @@ bool TeImage::load(const Common::FSNode &node) {
 	return true;
 }
 
-bool TeImage::load(Common::ReadStream &stream, const Common::Path &path) {
+bool TeImage::load(Common::SeekableReadStream &stream, const Common::String &type) {
+	TeCore *core = g_engine->getCore();
+	TeScummvmCodec *codec = dynamic_cast<TeScummvmCodec *>(core->createVideoCodec(type));
+	if (!codec || !codec->load(stream)) {
+		warning("TeImage::load: Failed to load stream");
+		delete codec;
+		return false;
+	}
 	error("TODO: Implement TeImage::load");
 }
 
diff --git a/engines/tetraedge/te/te_image.h b/engines/tetraedge/te/te_image.h
index 46aa02fa05d..4b4d73b8e93 100644
--- a/engines/tetraedge/te/te_image.h
+++ b/engines/tetraedge/te/te_image.h
@@ -75,7 +75,7 @@ public:
 	void getBuff(uint x, uint y, byte *pout, uint w, uint h);
 	bool isExtensionSupported(const Common::Path &path);
 	bool load(const Common::FSNode &node);
-	bool load(Common::ReadStream &stream, const Common::Path &path);
+	bool load(Common::SeekableReadStream &stream, const Common::String &type);
 	bool save(const Common::Path &path, enum SaveType type);
 	int serialize(Common::WriteStream &stream);
 	TeVector2s32 bufSize() const {
diff --git a/engines/tetraedge/te/te_marker.cpp b/engines/tetraedge/te/te_marker.cpp
index a0229cf9ae5..24177ad5063 100644
--- a/engines/tetraedge/te/te_marker.cpp
+++ b/engines/tetraedge/te/te_marker.cpp
@@ -34,11 +34,17 @@ void TeMarker::active(bool val) {
 void TeMarker::update(TeCamera *camera) {
 	if (!_visible)
 		return;
-	TeVector3f32 transformLoc = camera->transformCoord(_loc);
+	const TeVector3f32 transformLoc = camera->transformCoord(_loc);
+	const TeVector3f32 btnSize = _button.size();
 	if (transformLoc.z() < 0) {
-		error("TODO: Finish TeMarker::update (z < 0)");
+		_button.setPosition(TeVector3f32(btnSize.x(), btnSize.y(), _someFloat));
 	} else {
-		error("TODO: Finish TeMarker::update (z >= 0)");
+		TeVector3f32 transformLoc2(transformLoc.x() + btnSize.x() / 2, transformLoc.y() + btnSize.y() / 2, _someFloat);
+		// 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);
+		_button.setScale(newScale);
+		_button.setPosition(TeVector3f32(newScale.x() * transformLoc2.x(), newScale.y() * transformLoc2.y(), newScale.z()));
 	}
 }
 
diff --git a/engines/tetraedge/te/te_marker.h b/engines/tetraedge/te/te_marker.h
index fbc5cd3e781..5f38ae9b370 100644
--- a/engines/tetraedge/te/te_marker.h
+++ b/engines/tetraedge/te/te_marker.h
@@ -38,9 +38,14 @@ public:
 	void visible(bool val);
 
 	TeButtonLayout &button() { return _button; }
+	TeVector3f32 &loc() { return _loc; }
+
+	void setSomeFloat(float f) { _someFloat = f; }
+
 private:
 	bool _visible;
 	bool _isActive;
+	float _someFloat;
 	TeVector3f32 _loc;
 	// Note: this is a TeSpriteButton in the original, updated
 	// to use the newer ButtonLayout
diff --git a/engines/tetraedge/te/te_pick_mesh.cpp b/engines/tetraedge/te/te_pick_mesh.cpp
new file mode 100644
index 00000000000..696a85c8ac6
--- /dev/null
+++ b/engines/tetraedge/te/te_pick_mesh.cpp
@@ -0,0 +1,125 @@
+/* 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/math.h"
+
+#include "math/ray.h"
+
+#include "tetraedge/te/te_pick_mesh.h"
+
+namespace Tetraedge {
+
+TePickMesh::TePickMesh() : _flag(true), _verticies(nullptr), _nTriangles(0) {
+}
+
+TePickMesh::TePickMesh(const TePickMesh &other) : _flag(true), _verticies(nullptr),
+_nTriangles(0) {
+	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];
+	}
+}
+
+void TePickMesh::destroy() {
+	if (_verticies)
+		delete [] _verticies;
+	_verticies = nullptr;
+	_nTriangles = 0;
+}
+
+void TePickMesh::getTriangle(uint triNum, TeVector3f32 &v1, TeVector3f32 &v2, TeVector3f32 &v3) const {
+	assert(triNum < _nTriangles);
+	v1 = _verticies[triNum * 3];
+	v2 = _verticies[triNum * 3 + 1];
+	v3 = _verticies[triNum * 3 + 2];
+}
+
+bool TePickMesh::intersect(const TeVector3f32 &origin, const TeVector3f32 &dir, TeVector3f32 &ptOut, float &lenOut) {
+	if (!_flag || !_nTriangles)
+		return false;
+	float nearest = FLT_MAX;
+	const Math::Ray ray(origin, dir);
+	for (uint i = 0; i < _nTriangles; i++) {
+		float idist;
+		Math::Vector3d iloc;
+		if (ray.intersectTriangle(_verticies[i * 3], _verticies[i * 3 + 1], _verticies[i * 3 + 2], iloc, idist)) {
+			if (idist < nearest)
+				nearest = idist;
+		}
+	}
+	if (nearest != FLT_MAX) {
+		ptOut = origin + dir * nearest;
+		lenOut = nearest;
+		return true;
+	}
+	return false;
+}
+
+void TePickMesh::nbTriangles(uint nTriangles) {
+	destroy();
+	if (nTriangles) {
+		_verticies = new TeVector3f32[_nTriangles];
+		_nTriangles = nTriangles;
+	}
+}
+
+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;
+	}
+	return *this;
+}
+
+TePickMesh &TePickMesh::operator=(const TePickMesh &other) {
+	copy(other);
+	return *this;
+}
+
+void TePickMesh::setTriangle(uint triNum, const TeVector3f32 &v1, const TeVector3f32 &v2, const TeVector3f32 &v3) const {
+	assert(triNum < _nTriangles);
+	_verticies[triNum * 3] = v1;
+	_verticies[triNum * 3 + 1] = v2;
+	_verticies[triNum * 3 + 2] = v3;
+}
+
+} // end namespace Tetraedge
diff --git a/engines/tetraedge/te/te_pick_mesh.h b/engines/tetraedge/te/te_pick_mesh.h
new file mode 100644
index 00000000000..02e99bfbc51
--- /dev/null
+++ b/engines/tetraedge/te/te_pick_mesh.h
@@ -0,0 +1,61 @@
+/* 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_PICK_MESH_H
+#define TETRAEDGE_TE_TE_PICK_MESH_H
+
+#include "tetraedge/te/te_vector3f32.h"
+
+namespace Tetraedge {
+
+class TePickMesh {
+public:
+	TePickMesh();
+	TePickMesh(const TePickMesh &other);
+
+	void copy(const TePickMesh &other);
+	// void create(); // unused
+	void destroy();
+	void getTriangle(uint triNum, TeVector3f32 &v1, TeVector3f32 &v2, TeVector3f32 &v3) const;
+	bool intersect(const TeVector3f32 &origin, const TeVector3f32 &dir, TeVector3f32 &ptOut, float &lenOut);
+	void nbTriangles(uint nTriangles);
+	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 setName(const Common::String &name) { _name = name; }
+	void setFlag(bool val) { _flag = val; }
+	const Common::String &name() const { return _name; }
+
+private:
+	bool _flag;
+	TeVector3f32 *_verticies;
+	uint _nTriangles;
+	Common::String _name;
+	TeVector3f32 _v1;
+	TeVector3f32 _v2;
+	TeVector3f32 _v3;
+};
+
+} // end namespace Tetraedge
+
+#endif // TETRAEDGE_TE_TE_PICK_MESH_H
diff --git a/engines/tetraedge/te/te_scene_warp.cpp b/engines/tetraedge/te/te_scene_warp.cpp
new file mode 100644
index 00000000000..57fa1920ec4
--- /dev/null
+++ b/engines/tetraedge/te/te_scene_warp.cpp
@@ -0,0 +1,105 @@
+/* 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_scene_warp.h"
+#include "tetraedge/te/te_scene_warp_xml_parser.h"
+
+namespace Tetraedge {
+
+TeSceneWarp::TeSceneWarp() : _warp(nullptr) {
+}
+
+TeSceneWarp::~TeSceneWarp() {
+	close();
+}
+
+void TeSceneWarp::close() {
+	_objects.clear();
+	_animations.clear();
+	_exits.clear();
+	_warpEvents.clear();
+	_warp = nullptr;
+}
+
+const TeSceneWarp::Animation *TeSceneWarp::getAnimation(const Common::String &name) {
+	for (auto &anim : _animations)
+		if (anim._name == name)
+			return &anim;
+	return nullptr;
+}
+
+const TeSceneWarp::Exit *TeSceneWarp::getExit(const Common::String &linkedWarp) {
+	for (auto &exit : _exits)
+		if (exit._linkedWarp == linkedWarp)
+			return &exit;
+	return nullptr;
+}
+
+const TeSceneWarp::Object *TeSceneWarp::getObject(const Common::String &name) {
+	for (auto &object : _objects)
+		if (object._name == name)
+			return &object;
+	return nullptr;
+}
+
+const TeSceneWarp::WarpEvent *TeSceneWarp::getWarpEvent(const Common::String &name) {
+	for (auto &warpEvent : _warpEvents)
+		if (warpEvent._name == name)
+			return &warpEvent;
+	return nullptr;
+}
+
+bool TeSceneWarp::load(const Common::String &name, TeWarp *warp, bool flag) {
+	close();
+	_warp = warp;
+	_someInt = 0;
+	_name = name;
+
+	TeSceneWarpXmlParser parser(this, flag);
+
+	if (flag) {
+		// Line 357 ~ 426, plus other fixups
+		error("TODO: Finish TeSceneWarp::load for flag == true");
+	} else {
+		// This is done during parsing but this should work too.
+		for (const auto &sceneExit : _exits) {
+			TeWarp::Exit warpExit;
+			warpExit._name = sceneExit._name;
+			warpExit._camAngleX = sceneExit._camAngleX;
+			warpExit._camAngleY = sceneExit._camAngleY;
+			warpExit._linkedWarpPath = Common::String("3D\\") + sceneExit._linkedWarp;
+			warpExit._markerId = sceneExit._markerId;
+			for (const auto &bloc : sceneExit._warpBlocs) {
+				TeWarp::Block block;
+				block._offset = bloc.offset();
+				block._face = bloc.face();
+				block._x = sceneExit._nbWarpBlock;
+				block._y = sceneExit._nbWarpBlock;
+				warpExit._warpBlockList.push_back(block);
+			}
+			warp->sendExit(warpExit);
+		}
+		_warp->activeMarkers(_warp->markersActive());
+	}
+	return true;
+}
+
+} // end namespace Tetraedge
diff --git a/engines/tetraedge/te/te_scene_warp.h b/engines/tetraedge/te/te_scene_warp.h
new file mode 100644
index 00000000000..c12b3f0e4c3
--- /dev/null
+++ b/engines/tetraedge/te/te_scene_warp.h
@@ -0,0 +1,104 @@
+/* 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_SCENE_WARP_H
+#define TETRAEDGE_TE_TE_SCENE_WARP_H
+
+#include "tetraedge/te/te_camera.h"
+#include "tetraedge/te/te_warp.h"
+#include "tetraedge/te/te_warp_bloc.h"
+
+namespace Tetraedge {
+
+class TePickMesh;
+
+class TeSceneWarp {
+	friend class TeSceneWarpXmlParser;
+
+public:
+	class Animation {
+	public:
+		Animation() : _fps(0) {}
+		Common::String _name;
+		float _fps;
+	};
+	class Exit {
+	public:
+		Exit() : _nbWarpBlock(0) {}
+		Common::String _name;
+		Common::String _linkedWarp;
+		unsigned long _markerId;
+		int _nbWarpBlock;
+		float _camAngleX;
+		float _camAngleY;
+		Common::List<TeWarpBloc> _warpBlocs;
+		Common::List<Common::String> _strList;
+	};
+	class Object {
+	public:
+		Common::String _name;
+		Common::String _str2;
+		unsigned long _markerId;
+		Common::List<Common::String> _strList;
+	};
+	class WarpEvent {
+	public:
+		Common::String _name;
+		Common::List<Common::String> _strList;
+	};
+
+	TeSceneWarp();
+	~TeSceneWarp();
+
+	//void activeMarker(const Common::String &s1, const Common::String &s2) // unused
+	//Common::String addMarkerToAnimation(const Common::String &animName); // unused
+	void close();
+	//void createExit(); // unused
+	const Animation *getAnimation(const Common::String &name);
+	const Exit *getExit(const Common::String &linkedWarp);
+	const Object *getObject(const Common::String &name);
+	const WarpEvent *getWarpEvent(const Common::String &name); // TODO: what's the right return type?
+	bool load(const Common::String &name, TeWarp *warp, bool flag);
+	//void moveIndicator(const Common::String &, const Common::String &, const TeVector2s32 &)); // unused
+	//void popBlockToExit(const Common::String &name, TePickMesh *mesh); // unused
+	//void pushBlockToExit(const Common::String &name, TePickMesh *mesh); // unused 
+	//void removeExit(const Common::String &name); // unused
+	void render(const TeCamera &cam1, const TeCamera &cam2, const Common::String &str1, const Common::String &str2);
+	//void save(); // unused
+
+	void addObject(const Object &obj) { _objects.push_back(obj); }
+	void addExit(const Exit &exit) { _exits.push_back(exit); }
+	void addAnimation(const Animation &anim) { _animations.push_back(anim); }
+	void addWarpEvent(const WarpEvent &event) { _warpEvents.push_back(event); }
+
+private:
+	Common::List<Object> _objects;
+	Common::List<Exit> _exits;
+	Common::List<Animation> _animations;
+	Common::List<WarpEvent> _warpEvents;
+	Common::String _name;
+	TeWarp *_warp;
+	int _someInt;
+};
+
+} // end namespace Tetraedge
+
+#endif // TETRAEDGE_TE_TE_SCENE_WARP_H
diff --git a/engines/tetraedge/te/te_scene_warp_xml_parser.cpp b/engines/tetraedge/te/te_scene_warp_xml_parser.cpp
new file mode 100644
index 00000000000..69cc00dc561
--- /dev/null
+++ b/engines/tetraedge/te/te_scene_warp_xml_parser.cpp
@@ -0,0 +1,120 @@
+/* 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_scene_warp_xml_parser.h"
+
+namespace Tetraedge {
+
+bool TeSceneWarpXmlParser::parserCallback_exit(ParserNode *node) {
+	TeSceneWarp::Exit exit;
+	exit._name = Common::String::format("Exit_%02d", _sceneWarp->_exits.size());
+	exit._linkedWarp = node->values.getVal("linkedWarp");
+	exit._nbWarpBlock = parseUint(node, "nbWarpBlock");
+	_sceneWarp->_exits.push_back(exit);
+	_objType = kObjExit;
+	return true;
+}
+
+bool TeSceneWarpXmlParser::parserCallback_camera(ParserNode *node) {
+	if (_objType != kObjExit) {
+		parserError("block should only appear inside exit");
+		return false;
+	}
+	TeSceneWarp::Exit &exit = _sceneWarp->_exits.back();
+	exit._camAngleX = (float)parseDouble(node, "angleX");
+	exit._camAngleY = (float)parseDouble(node, "angleY");
+	return true;
+}
+
+bool TeSceneWarpXmlParser::parserCallback_marker(ParserNode *node) {
+	TeVector3f32 vec = parsePoint(node);
+	if (_objType == kObjExit) {
+		TeSceneWarp::Exit &exit = _sceneWarp->_exits.back();
+		TeMarker *marker = _sceneWarp->_warp->allocMarker(&exit._markerId);
+		marker->loc() = vec;
+		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", "");
+		} else {
+			marker->visible(false);
+		}
+		marker->setSomeFloat(999.0f);
+		_sceneWarp->_warp->sendMarker(exit._name, exit._markerId);
+	} else if (_objType == kObjObject) {
+		TeSceneWarp::Object &obj = _sceneWarp->_objects.back();
+		TeMarker *marker = _sceneWarp->_warp->allocMarker(&obj._markerId);
+		marker->loc() = vec;
+		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", "");
+		} else {
+			marker->visible(false);
+		}
+		marker->setSomeFloat(999.0f);
+		if (_sceneWarp->_warp->hasObjectOrAnim(obj._name)) {
+			_sceneWarp->_warp->sendMarker(obj._name, obj._markerId);
+		}
+	} else {
+		parserError("marker tag under invalid parent.");
+		return false;
+	}
+	return true;
+}
+
+bool TeSceneWarpXmlParser::parserCallback_block(ParserNode *node) {
+	if (_objType != kObjExit) {
+		parserError("block should only appear inside exit");
+		return false;
+	}
+	TeWarpBloc::CubeFace face = static_cast<TeWarpBloc::CubeFace>(parseUint(node, "face"));
+	TeVector2s32 offset;
+	offset._x = parseUint(node, "offsetX");
+	offset._y = parseUint(node, "offsetY");
+	TeSceneWarp::Exit &exit = _sceneWarp->_exits.back();
+	if (_flag) {
+		TeWarpBloc bloc;
+		bloc.create(face, exit._nbWarpBlock, exit._nbWarpBlock, offset);
+		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");
+}
+
+bool TeSceneWarpXmlParser::parserCallback_object(ParserNode *node) {
+	TeSceneWarp::Object obj;
+	obj._name = node->values.getVal("name");
+	_sceneWarp->_objects.push_back(obj);
+	_objType = kObjObject;
+	return true;
+}
+
+bool TeSceneWarpXmlParser::parserCallback_animation(ParserNode *node) {
+	TeSceneWarp::Animation anim;
+	anim._name = node->values.getVal("name");
+	anim._fps = (float)parseDouble(node, "fps");
+	_sceneWarp->_animations.push_back(anim);
+	_objType = kObjNone;
+	return true;
+}
+
+} // end namespace Tetraedge
diff --git a/engines/tetraedge/te/te_scene_warp_xml_parser.h b/engines/tetraedge/te/te_scene_warp_xml_parser.h
new file mode 100644
index 00000000000..1049ba97d32
--- /dev/null
+++ b/engines/tetraedge/te/te_scene_warp_xml_parser.h
@@ -0,0 +1,93 @@
+/* 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_SCENE_WARP_XML_PARSER_H
+#define TETRAEDGE_TE_TE_SCENE_WARP_XML_PARSER_H
+
+#include "tetraedge/te/te_xml_parser.h"
+#include "tetraedge/te/te_scene_warp.h"
+
+namespace Tetraedge {
+
+class TeSceneWarpXmlParser : public TeXmlParser {
+public:
+	enum ObjType {
+		kObjNone,
+		kObjExit,
+		kObjObject
+	};
+
+	TeSceneWarpXmlParser(TeSceneWarp *sceneWarp, bool flag) : _sceneWarp(sceneWarp),
+		_objType(kObjNone), _flag(flag) {}
+
+	// Parser
+	CUSTOM_XML_PARSER(TeSceneWarpXmlParser) {
+		XML_KEY(FileFormatVersion)
+		KEY_END()
+		XML_KEY(exit)
+			XML_PROP(linkedWarp, true)
+			XML_PROP(nbWarpBlock, true)
+			XML_KEY(camera)
+				XML_PROP(angleX, true)
+				XML_PROP(angleY, true)
+			KEY_END()
+			XML_KEY(marker)
+				XML_PROP(x, true)
+				XML_PROP(y, true)
+				XML_PROP(z, true)
+			KEY_END()
+			XML_KEY(block)
+				XML_PROP(face, true)
+				XML_PROP(offsetX, true)
+				XML_PROP(offsetY, true)
+			KEY_END()
+		KEY_END()
+		XML_KEY(animation)
+			XML_PROP(name, true)
+			XML_PROP(fps, true)
+		KEY_END()
+		XML_KEY(object)
+			XML_PROP(name, true)
+			XML_KEY(marker)
+				XML_PROP(x, true)
+				XML_PROP(y, true)
+				XML_PROP(z, true)
+			KEY_END()
+		KEY_END()
+	} PARSER_END()
+
+public:
+	bool parserCallback_FileFormatVersion(ParserNode *node) { return true; }
+	bool parserCallback_exit(ParserNode *node);
+	bool parserCallback_camera(ParserNode *node);
+	bool parserCallback_marker(ParserNode *node);
+	bool parserCallback_block(ParserNode *node);
+	bool parserCallback_object(ParserNode *node);
+	bool parserCallback_animation(ParserNode *node);
+
+	TeSceneWarp *_sceneWarp;
+	ObjType _objType;
+	bool _flag;
+};
+
+} // end namespace Tetraedge
+
+#endif // TETRAEDGE_TE_TE_SCENE_WARP_XML_PARSER_H
diff --git a/engines/tetraedge/te/te_visual_fade.cpp b/engines/tetraedge/te/te_visual_fade.cpp
index 2e9502fd9e0..69316621209 100644
--- a/engines/tetraedge/te/te_visual_fade.cpp
+++ b/engines/tetraedge/te/te_visual_fade.cpp
@@ -59,6 +59,7 @@ void TeVisualFade::animateBlackFade() {
 }
 
 void TeVisualFade::animateFade() {
+	double duration = g_engine->gameIsAmerzone() ? 1000 : 400;
 	_fadeCurveAnim.stop();
 	_fadeCurveAnim._runTimer.pausable(false);
 	_fadeCaptureSprite.setVisible(true);
@@ -68,12 +69,30 @@ void TeVisualFade::animateFade() {
 	curve.push_back(0.0);
 	curve.push_back(1.0);
 	_fadeCurveAnim.setCurve(curve);
-	_fadeCurveAnim._duration = 400.0;
+	_fadeCurveAnim._duration = duration;
 	_fadeCurveAnim._callbackObj = &_fadeCaptureSprite;
 	_fadeCurveAnim._callbackMethod = &TeSpriteLayout::setColor;
 	_fadeCurveAnim.play();
 }
 
+void TeVisualFade::animateFadeWithZoom() {
+	animateFade();
+	_fadeZoomAnim.stop();
+	_fadeZoomAnim._runTimer.pausable(false);
+	_fadeZoomAnim._startVal = TeVector3f32(1, 1, 1);
+	_fadeZoomAnim._endVal = TeVector3f32(3, 3, 3);
+	Common::Array<float> curve;
+	curve.push_back(0.0);
+	curve.push_back(0.33f);
+	curve.push_back(1.0);
+	curve.push_back(1.0);
+	_fadeZoomAnim.setCurve(curve);
+	_fadeZoomAnim._duration = 1000;
+	_fadeZoomAnim._callbackObj = &_fadeCaptureSprite;
+	_fadeZoomAnim._callbackMethod = &TeSpriteLayout::setScale;
+	_fadeZoomAnim.play();
+}
+
 void TeVisualFade::captureFrame() {
 	//debug("visual fade %p capture", this);
 	TeRenderer *renderer = g_engine->getRenderer();
diff --git a/engines/tetraedge/te/te_visual_fade.h b/engines/tetraedge/te/te_visual_fade.h
index f99a6ded32c..dde10a06982 100644
--- a/engines/tetraedge/te/te_visual_fade.h
+++ b/engines/tetraedge/te/te_visual_fade.h
@@ -37,6 +37,7 @@ public:
 
 	void animateBlackFade();
 	void animateFade();
+	void animateFadeWithZoom();
 	void captureFrame();
 	void clear() {};
 	void init();
@@ -57,6 +58,7 @@ private:
 	TeIntrusivePtr<Te3DTexture> _texturePtr;
 	TeCurveAnim2<TeSpriteLayout, TeColor> _fadeCurveAnim;
 	TeCurveAnim2<TeSpriteLayout, TeColor> _blackFadeCurveAnim;
+	TeCurveAnim2<TeSpriteLayout, TeVector3f32> _fadeZoomAnim;
 	TeImage _image;
 
 };
diff --git a/engines/tetraedge/te/te_warp.cpp b/engines/tetraedge/te/te_warp.cpp
index 1fa3ed159fb..29f57d1ff65 100644
--- a/engines/tetraedge/te/te_warp.cpp
+++ b/engines/tetraedge/te/te_warp.cpp
@@ -22,14 +22,22 @@
 #include "tetraedge/tetraedge.h"
 #include "tetraedge/game/application.h"
 #include "tetraedge/te/te_warp.h"
+#include "tetraedge/te/te_core.h"
 #include "tetraedge/te/te_input_mgr.h"
+#include "tetraedge/te/te_renderer.h"
 
 namespace Tetraedge {
 
 /*static*/
 bool TeWarp::debug = false;
 
-TeWarp::TeWarp() : _visible1(false) {
+TeWarp::TeWarp() : _visible1(false), _loaded(false), _preloaded(false),
+	_numAnims(0), _someXVal(0), _someYVal(0), _someMeshX(0), _someMeshY(0) {
+}
+
+TeWarp::~TeWarp() {
+	unload();
+	_file.close();
 }
 
 void TeWarp::activeMarkers(bool active) {
@@ -38,11 +46,212 @@ void TeWarp::activeMarkers(bool active) {
 		warpMarker->marker()->active(active);
 }
 
+uint TeWarp::addQuadToPickMesh(TePickMesh &pickmesh, uint trinum,
+		TeWarpBloc::CubeFace face, const TeVector2s32 &size, uint xscale, uint yscale) {
+	TeVector3f32 pt1;
+	TeVector3f32 pt2;
+	TeVector3f32 pt3;
+	TeVector3f32 pt4;
+
+    float x1 = size._x * (1000.0f / xscale) - 500.0f;
+    float x2 = 1000.0f / xscale + x1;
+	float y1 = size._y * (1000.0f / yscale) - 500.0f;
+    float y2 = 1000.0f / yscale + y1;
+
+	switch (face) {
+	case TeWarpBloc::Face0:
+		pt1 = TeVector3f32(-x1, 500, -y1);
+		pt2 = TeVector3f32(-x2, 500, -y1);
+		pt3 = TeVector3f32(-x2, 500, -y2);
+		pt4 = TeVector3f32(-x1, 500, -y2);
+		break;
+	case TeWarpBloc::Face1:
+		pt1 = TeVector3f32(-x1, -500, y1);
+		pt2 = TeVector3f32(-x2, -500, y1);
+		pt3 = TeVector3f32(-x2, -500, y2);
+		pt4 = TeVector3f32(-x1, -500, y2);
+		break;
+    case TeWarpBloc::Face2:
+		pt1 = TeVector3f32(-x1, y1, 500);
+		pt2 = TeVector3f32(-x2, y1, 500);
+		pt3 = TeVector3f32(-x2, y2, 500);
+		pt4 = TeVector3f32(-x1, y2, 500);
+		break;
+    case TeWarpBloc::Face3:
+		pt1 = TeVector3f32(x1, y1, -500);
+		pt2 = TeVector3f32(x2, y1, -500);
+		pt3 = TeVector3f32(x2, y2, -500);
+		pt4 = TeVector3f32(x1, y2, -500);
+		break;
+    case TeWarpBloc::Face4:
+		pt1 = TeVector3f32(500, y1, x1);
+		pt2 = TeVector3f32(500, y1, x2);
+		pt3 = TeVector3f32(500, y2, x2);
+		pt4 = TeVector3f32(500, y2, x1);
+		break;
+    case TeWarpBloc::Face5:
+		pt1 = TeVector3f32(-500, y1, -x1);
+		pt2 = TeVector3f32(-500, y1, -x2);
+		pt3 = TeVector3f32(-500, y2, -x2);
+		pt4 = TeVector3f32(-500, y2, -x1);
+	default:
+		break;
+	}
+
+	pickmesh.setTriangle(trinum, pt1, pt2, pt4);
+	pickmesh.setTriangle(trinum + 1, pt2, pt3, pt4);
+	return trinum + 1;
+}
+
+
+TeMarker *TeWarp::allocMarker(unsigned long *nMarkers) {
+	TeMarker *newMarker = new TeMarker();
+	TeWarpMarker *newWarpMarker = new TeWarpMarker();
+	newWarpMarker->marker(newMarker);
+	newWarpMarker->markerButtonSignal().add(this, &TeWarp::onMarkerValidated);
+	*nMarkers = _warpMarkers.size();
+	_warpMarkers.push_back(newWarpMarker);
+	return newMarker;
+}
+
+void TeWarp::checkObjectEvents() {
+	//const Common::Point lastMouse = g_engine->getInputMgr()->lastMousePos();
+	//Math::Ray mouseRay = _camera.getRay(lastMouse);
+	//for (uint i = 0; i < _numAnims; i++) {
+	//
+	//}
+	error("TODO: Implement TeWarp::checkObjectEvents");
+}
+
+void TeWarp::clear() {
+	_animDatas.clear();
+
+	error("TODO: Implement TeWarp::clear");
+}
+
+TeWarp::AnimData *TeWarp::findAnimation(const Common::String &name) {
+	for (uint i = 0; i < _numAnims; i++) {
+		if (_loadedAnimData[i]._name == name)
+			return _loadedAnimData.data() + i;
+	}
+	return nullptr;
+}
+
+bool TeWarp::hasObjectOrAnim(const Common::String &name) {
+	for (uint i = 0; i < _numAnims; i++) {
+		if (_loadedAnimData[i]._name == name)
+			return true;
+	}
+	return false;
+}
+
 void TeWarp::init() {
 	// This mostly sets up the camera.. maybe nothing to do?
 	warning("TODO: Implement TeWarp::init");
 }
 
+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 (_preloaded)
+		error("TODO: Support preloading in TeWarp::load");
+	Common::File file;
+	file.open(node);
+	char header[7];
+	header[6] = '\0';
+	file.read(header, 6);
+	if (Common::String(header) != "TeWarp")
+		error("Invalid header in warp data %s", _warpPath.c_str());
+	uint32 globalTexDataOffset = file.readUint32LE();
+	Common::String encodingType = file.readPascalString();
+	_xCount = file.readUint32LE();
+	_yCount = file.readUint32LE();
+	_numAnims = file.readUint32LE();
+	_someXVal = file.readUint32LE();
+	_someYVal = file.readUint32LE();
+	warning("TeWarp::load: TODO: Identify these ints..");
+	/*int someInt3 = */file.readUint32LE();
+	/*int someInt4 = */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());
+		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);
+			TeVector2s32 offset(offx, offy);
+			_warpBlocs[j].create(face, _xCount, _yCount, offset);
+		}
+	}
+	_loadedAnimData.resize(_numAnims);
+	_animDatas.reserve(_numAnims);
+	for (uint i = 0; i < _numAnims; i++) {
+		char aname[5];
+		file.read(aname, 4);
+		aname[4] = '\0';
+		_loadedAnimData[i]._name = aname;
+		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];
+			frameData._loadedTexCount = 0;
+			frameData._numWarpBlocs = 0;
+			Common::Array<TeWarpBloc> warpBlocs;
+			for (uint k = 0; k < numSomething; k++) {
+				uint blocCount = file.readUint32LE();
+				if (blocCount) {
+					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();
+						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();
+					TePickMesh tmpMesh;
+					tmpMesh.setName(aname);
+					tmpMesh.nbTriangles(meshSize * 2);
+					for (uint m = 0; m < meshSize; m++) {
+						uint xoff = file.readUint16LE();
+						uint yoff = file.readUint16LE();
+						addQuadToPickMesh(tmpMesh, m * 2, face, TeVector2s32(xoff, yoff), _someMeshX, _someMeshY);
+					}
+					tmpMesh.setFlag(true);
+					if (frameData._pickMesh.name().empty()) {
+						frameData._pickMesh = tmpMesh;
+					} else {
+						frameData._pickMesh += tmpMesh;
+					}
+				}
+			}
+			frameData._warpBlocs.resize(frameData._numWarpBlocs);
+
+			error("TODO: Finish line 323~343");
+		}
+
+	}
+
+	_loaded = true;
+	error("TODO: Finish TeWarp::load");
+}
+
+bool TeWarp::onMarkerValidated(const Common::String &name) {
+	_markerValidatedSignal.call(name);
+	return false;
+}
+
 bool TeWarp::onMouseLeftDown(const Common::Point &pt) {
 	error("TODO: Implement TeWarp::onMouseLeftDown");
 }
@@ -55,12 +264,42 @@ void TeWarp::update() {
 	error("TODO: Implement TeWarp::update");
 }
 
+void TeWarp::sendExit(TeWarp::Exit &exit) {
+	_paths.push_back(exit._linkedWarpPath);
+	TePickMesh *mesh = new TePickMesh();
+	mesh->setName(exit._linkedWarpPath);
+	mesh->nbTriangles(exit._warpBlockList.size() * 2);
+	uint trinum = 0;
+	for (auto &block : exit._warpBlockList) {
+		addQuadToPickMesh(*mesh, trinum, block._face, block._offset, block._x, block._y);
+		trinum += 2;
+	}
+	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->visible(false);
+	marker->setSomeFloat(-999.0f);
+	_exitList.push_back(exit);
+}
+
+void TeWarp::sendMarker(const Common::String &name, unsigned long markerId) {
+	AnimData *anim = findAnimation(name);
+	if (anim)
+		anim->_markerIds.push_back(markerId);
+}
+
+void TeWarp::setColor(const TeColor &col) {
+	Te3DObject2::setColor(col);
+	for (auto &warpMarker : _warpMarkers) {
+		warpMarker->marker()->button().setColor(col);
+	}
+}
+
 void TeWarp::setMouseLeftUpForMakers() {
-	// TODO:
-	//for (auto &marker : _warpMarkers) {
-	//	marker->marker()->sprite()->setEnable(true)
-	//}
-	error("TODO: Implement TeWarp::setMouseLeftUpForMakers");
+	for (auto &marker : _warpMarkers) {
+		marker->marker()->button().setEnable(true);
+	}
 }
 
 void TeWarp::setVisible(bool v1, bool v2) {
@@ -79,6 +318,38 @@ void TeWarp::setVisible(bool v1, bool v2) {
 	}
 }
 
+void TeWarp::render() {
+	if (!_visible1 || _scale.x() == 0.0f || _scale.y() == 0.0f ||
+			_scale.z() == 0.0f || !worldVisible() || color().a() == 0)
+		return;
+
+	TeRenderer *renderer = g_engine->getRenderer();
+	renderer->setMatrixMode(TeRenderer::MM_GL_PROJECTION);
+	renderer->pushMatrix();
+	renderer->setMatrixMode(TeRenderer::MM_GL_MODELVIEW);
+	renderer->pushMatrix();
+	_camera.apply();
+	renderer->disableZBuffer();
+	renderer->pushMatrix();
+
+	// TODO: Render the WarpBlocs here.
+
+	for (auto &warpMarker : _warpMarkers) {
+		warpMarker->marker()->update(&_camera);
+	}
+
+	renderer->setCurrentColor(TeColor(255, 255, 255, 255));
+	renderer->popMatrix();
+	renderer->enableZBuffer();
+	TeCamera::restore();
+	renderer->setMatrixMode(TeRenderer::MM_GL_PROJECTION);
+	renderer->popMatrix();
+	renderer->setMatrixMode(TeRenderer::MM_GL_MODELVIEW);
+	renderer->popMatrix();
+
+	error("TODO: Finish TeWarp::render");
+}
+
 void TeWarp::rotateCamera(const TeQuaternion &rot) {
 	TeQuaternion normRot = rot;
 	normRot.normalize();
@@ -89,4 +360,31 @@ void TeWarp::setFov(float fov) {
 	_camera.setFov(fov);
 }
 
+void TeWarp::unload() {
+	error("TODO: Implement TeWarp::unload");
+}
+
+void TeWarp::unloadTextures() {
+	for (uint i = 0; i < _xCount * _yCount * 6; i++) {
+		_warpBlocs[i].unloadTexture();
+	}
+
+	if (_numAnims)
+		error("TODO: Finish TeWarp::unloadTextures");
+
+	for (auto &animData : _loadedAnimData) {
+		for (auto &frameData : animData._frameDatas) {
+			for (auto &warpBloc : frameData._warpBlocs) {
+				warpBloc.unloadTexture();
+			}
+		}
+	}
+}
+
+void TeWarp::updateCamera(const TeVector3f32 &screen) {
+	_camera.viewport(0, 0, screen.x(), screen.y());
+	_camera.setOrthoPlanes(1, 4086);
+	_camera.setAspectRatio(screen.x() / screen.y());
+}
+
 } // end namespace Tetraedge
diff --git a/engines/tetraedge/te/te_warp.h b/engines/tetraedge/te/te_warp.h
index e783f3d67e5..94e6bc2ea05 100644
--- a/engines/tetraedge/te/te_warp.h
+++ b/engines/tetraedge/te/te_warp.h
@@ -27,43 +27,118 @@
 #include "tetraedge/te/te_3d_object2.h"
 #include "tetraedge/te/te_camera.h"
 #include "tetraedge/te/te_frustum.h"
+#include "tetraedge/te/te_pick_mesh.h"
 #include "tetraedge/te/te_quaternion.h"
 #include "tetraedge/te/te_warp_marker.h"
+#include "tetraedge/te/te_warp_bloc.h"
 
 namespace Tetraedge {
 
 // Note: Only used in Amerzone
 class TeWarp : public Te3DObject2 {
 public:
+	struct FrameData {
+		int _numWarpBlocs;
+		Common::Array<TeWarpBloc> _warpBlocs;
+		TePickMesh _pickMesh;
+		int _loadedTexCount;
+	};
+
 	class AnimData {
+	public:
+		AnimData() : _fps(15.0f), _flag(false) {}
+		Common::Array<unsigned long> _markerIds;
+		float _fps;
+		bool _flag;
+		TeTimer _timer;
+		Common::String _name;
+		Common::Array<FrameData> _frameDatas;
+	};
+
+	struct Block {
+		TeWarpBloc::CubeFace _face;
+		int _x;
+		int _y;
+		TeVector2s32 _offset;
+	};
+
+	struct Exit {
+		Common::String _name;
+		Common::String _linkedWarpPath;
+		float _camAngleX;
+		float _camAngleY;
+		long _markerId;
+		Common::List<Block> _warpBlockList;
 	};
 
 	TeWarp();
+	~TeWarp();
 
 	void activeMarkers(bool active);
+	uint addQuadToPickMesh(TePickMesh &pickmesh, uint trinum, TeWarpBloc::CubeFace face,
+		const TeVector2s32 &param_4, uint param_5, uint param_6);
+	TeMarker *allocMarker(unsigned long *nMarkers);
+	void configMarker(const Common::String objname, int markerImgNo, long markerId);
+	void checkObjectEvents();
+	void clear();
+	//void entry(); // unused
+	AnimData *findAnimation(const Common::String &name);
+	Exit *findExit(const Common::String &name, bool flag);
+	//int getAnimationFrame(const Common::String &name); // unused
+	bool hasObjectOrAnim(const Common::String &name);
 	void init();
+	void load(const Common::String &path, bool flag);
+	//void loadTextures(); // unused
+	//void preload(const Common::String &path); // unused
 	void update();
+	void render();
 	void rotateCamera(const TeQuaternion &rot);
+	void sendExit(Exit &exit);
+	void sendMarker(const Common::String &name, unsigned long markerId);
+	void setColor(const TeColor &col) override;
 	void setMarkersOpacity(float opacity);
 	void setMouseLeftUpForMakers();
 	void setFov(float fov);
 	void setVisible(bool v1, bool v2);
+	void unload();
+	void unloadTextures();
+	void updateCamera(const TeVector3f32 &screen);
 
 	static bool debug;
 
+	TeSignal1Param<const Common::String &> &markerValidatedSignal() { return _markerValidatedSignal; }
+	TeSignal1Param<const Common::String &> &animFinishedSignal() { return _animFinishedSignal; }
+	bool markersActive() const { return _markersActive; }
+
 private:
 	bool onMouseLeftDown(const Common::Point &pt);
+	bool onMarkerValidated(const Common::String &name);
 
 	Common::File _file;
 	Common::String _warpPath;
 	TeCamera _camera;
 	bool _markersActive;
 	bool _visible1;
+	bool _loaded;
+	bool _preloaded;
 
 	TeFrustum _frustum;
 
 	Common::Array<TeWarpMarker *> _warpMarkers;
-
+	Common::List<Common::String> _paths;
+	Common::Array<AnimData> _animDatas;
+	Common::List<TeWarp::Exit> _exitList;
+	uint _someXVal;
+	uint _someYVal;
+	uint _someMeshX;
+	uint _someMeshY;
+	uint _xCount;
+	uint _yCount;
+	uint _numAnims;
+	Common::Array<TeWarpBloc> _warpBlocs;
+	Common::Array<AnimData> _loadedAnimData;
+	TeSignal1Param<const Common::String &> _markerValidatedSignal;
+	TeSignal1Param<const Common::String &> _animFinishedSignal;
 };
 
 } // end namespace Tetraedge
diff --git a/engines/tetraedge/te/te_warp_bloc.cpp b/engines/tetraedge/te/te_warp_bloc.cpp
new file mode 100644
index 00000000000..9a31d46bf71
--- /dev/null
+++ b/engines/tetraedge/te/te_warp_bloc.cpp
@@ -0,0 +1,162 @@
+/* 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_warp_bloc.h"
+
+namespace Tetraedge {
+
+TeWarpBloc::TeWarpBloc() : _colors(nullptr), _cubeFace(FaceInvalid) {
+}
+
+TeWarpBloc::~TeWarpBloc() {
+	if (_colors)
+		delete _colors;
+}
+
+void TeWarpBloc::color(const TeColor &col) {
+	color(0, col);
+	color(1, col);
+	color(2, col);
+	color(3, col);
+}
+
+void TeWarpBloc::color(uint num, const TeColor &col) {
+	if (_colors == nullptr) {
+		_colors = new TeColor[4];
+	}
+	assert(num < 4);
+	_colors[num] = col;
+}
+
+void TeWarpBloc::create(CubeFace face, uint x, uint y, const TeVector2s32 &offset) {
+	_cubeFace = face;
+	_offset = offset;
+
+	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;
+	switch (face) {
+	case Face0:
+		_verticies[0] = TeVector3f32(-x1, 500, -y1);
+		_verticies[1] = TeVector3f32(-x2, 500, -y1);
+		_verticies[2] = TeVector3f32(-x2, 500, -y2);
+		_verticies[3] = TeVector3f32(-x1, 500, -y2);
+		break;
+	case Face1:
+		_verticies[0] = TeVector3f32(-x1, -500, y1);
+		_verticies[1] = TeVector3f32(-x2, -500, y1);
+		_verticies[2] = TeVector3f32(-x2, -500, y2);
+		_verticies[3] = TeVector3f32(-x1, -500, y2);
+		break;
+	case Face2:
+		_verticies[0] = TeVector3f32(-x1, y1, 500);
+		_verticies[1] = TeVector3f32(-x2, y1, 500);
+		_verticies[2] = TeVector3f32(-x2, y2, 500);
+		_verticies[3] = TeVector3f32(-x1, y2, 500);
+		break;
+	case Face3:
+		_verticies[0] = TeVector3f32(x1, y1, -500);
+		_verticies[1] = TeVector3f32(x2, y1, -500);
+		_verticies[2] = TeVector3f32(x2, y2, -500);
+		_verticies[3] = TeVector3f32(x1, y2, -500);
+		break;
+	case Face4:
+		_verticies[0] = TeVector3f32(500, y1, x1);
+		_verticies[1] = TeVector3f32(500, y1, x2);
+		_verticies[2] = TeVector3f32(500, y2, x2);
+		_verticies[3] = TeVector3f32(500, y2, x1);
+		break;
+	case Face5:
+		_verticies[0] = TeVector3f32(-500, y1, -x1);
+		_verticies[1] = TeVector3f32(-500, y1, -x2);
+		_verticies[2] = TeVector3f32(-500, y2, -x2);
+		_verticies[3] = TeVector3f32(-500, y2, -x1);
+		break;
+	default:
+		break;
+	}
+
+	_texCoords[0] = TeVector2f32(0, 0);
+	_texCoords[1] = TeVector2f32(1, 0);
+	_texCoords[2] = TeVector2f32(1, 1);
+	_texCoords[3] = TeVector2f32(0, 1);
+	_indexes[0] = 0;
+	_indexes[1] = 1;
+	_indexes[2] = 2;
+	_indexes[3] = 3;
+}
+
+void TeWarpBloc::create() {
+	_colors = nullptr;
+	_texture.release();
+}
+
+void TeWarpBloc::index(uint offset, uint val) {
+	assert(offset < 4);
+	_indexes[offset] = val;
+}
+
+bool TeWarpBloc::isLoaded() const {
+	return _texture.get() != nullptr;
+}
+
+void TeWarpBloc::loadTexture(Common::File &file, const Common::String &type) {
+	if (_texture)
+		return;
+
+	if (!file.seek(_textureDataFileOffset))
+		error("TeWarpBloc::LoadTexture: seek error");
+
+	TeImage img;
+	img.load(file, type);
+
+	_texture = Te3DTexture::makeInstance();
+	_texture->load(img);
+}
+
+void TeWarpBloc::render() {
+	error("Implement TeWarpBloc::render");
+}
+
+void TeWarpBloc::texture(uint idx, float x, float y) {
+	assert(idx < 4);
+	_texCoords[idx].setX(x);
+	_texCoords[idx].setY(y);
+}
+
+void TeWarpBloc::unloadTexture() {
+	_texture.release();
+}
+
+void TeWarpBloc::vertex(uint idx, float x, float y, float z) {
+	assert(idx < 4);
+	_verticies[idx].x() = x;
+	_verticies[idx].y() = y;
+	_verticies[idx].z() = z;
+}
+
+const TeVector3f32 &TeWarpBloc::vertex(uint idx) const {
+	assert(idx < 4);
+	return _verticies[idx];
+}
+
+} // end namespace Tetraedge
diff --git a/engines/tetraedge/te/te_warp_bloc.h b/engines/tetraedge/te/te_warp_bloc.h
new file mode 100644
index 00000000000..0a6532f1df7
--- /dev/null
+++ b/engines/tetraedge/te/te_warp_bloc.h
@@ -0,0 +1,84 @@
+/* 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_WARP_BLOC_H
+#define TETRAEDGE_TE_TE_WARP_BLOC_H
+
+#include "tetraedge/te/te_color.h"
+#include "tetraedge/te/te_vector2f32.h"
+#include "tetraedge/te/te_vector2s32.h"
+#include "tetraedge/te/te_vector3f32.h"
+#include "tetraedge/te/te_intrusive_ptr.h"
+#include "tetraedge/te/te_3d_texture.h"
+
+#include "common/file.h"
+
+namespace Tetraedge {
+
+class TeWarpBloc {
+public:
+	// TODO; Better names than this.
+	enum CubeFace {
+		Face0 = 0,
+		Face1 = 1,
+		Face2 = 2,
+		Face3 = 3,
+		Face4 = 4,
+		Face5 = 5,
+		FaceInvalid = 6,
+	};
+	TeWarpBloc();
+	~TeWarpBloc();
+
+	void color(const TeColor &col);
+	void color(uint num, const TeColor &col);
+	void create(CubeFace face, uint i, uint j, const TeVector2s32 &offset);
+	void create();
+	void index(uint offset, uint val);
+	bool isLoaded() const;
+	void loadTexture(Common::File &file, const Common::String &type);
+	//void operator=(const TeWarpBloc &other); // unused
+	//bool operator==(const TeWarpBloc &other); // unused
+	void render();
+	void texture(uint idx, float x, float y);
+	void unloadTexture();
+	void vertex(uint n, float x, float y, float z);
+	const TeVector3f32 &vertex(uint n) const;
+
+	const TeVector2s32 offset() const { return _offset; }
+	CubeFace face() const { return _cubeFace; }
+	void setCubeFace(CubeFace face) { _cubeFace = face; }
+	void setTextureFileOffset(long offset) { _textureDataFileOffset = offset; }
+
+private:
+	TeColor *_colors;
+	TeVector2s32 _offset;
+	TeIntrusivePtr<Te3DTexture> _texture;
+	CubeFace _cubeFace;
+	TeVector3f32 _verticies[4];
+	TeVector2f32 _texCoords[4];
+	short _indexes[4];
+	long _textureDataFileOffset;
+};
+
+} // end namespace Tetraedge
+
+#endif // TETRAEDGE_TE_TE_WARP_BLOC_H
diff --git a/engines/tetraedge/te/te_warp_marker.h b/engines/tetraedge/te/te_warp_marker.h
index 7bd06540c25..31d8f653972 100644
--- a/engines/tetraedge/te/te_warp_marker.h
+++ b/engines/tetraedge/te/te_warp_marker.h
@@ -37,6 +37,7 @@ public:
 	TeMarker *marker() { return _marker; }
 	void marker(TeMarker *marker);
 	bool onMarkerButtonValidated();
+	TeSignal1Param<const Common::String &> &markerButtonSignal() { return _markerButtonSignal; };
 
 private:
 	TeMarker *_marker;
diff --git a/engines/tetraedge/tetraedge.cpp b/engines/tetraedge/tetraedge.cpp
index 4ba0bce3a84..470b052d489 100644
--- a/engines/tetraedge/tetraedge.cpp
+++ b/engines/tetraedge/tetraedge.cpp
@@ -100,7 +100,7 @@ TeCore *TetraedgeEngine::getCore() {
 
 Game *TetraedgeEngine::getGame() {
 	if (_game == nullptr) {
-		if (gameType() == kAmerzone)
+		if (gameIsAmerzone())
 			_game = new AmerzoneGame();
 		else
 			_game = new SyberiaGame();
diff --git a/engines/tetraedge/tetraedge.h b/engines/tetraedge/tetraedge.h
index 3977eed6c4d..fa85516957f 100644
--- a/engines/tetraedge/tetraedge.h
+++ b/engines/tetraedge/tetraedge.h
@@ -140,6 +140,7 @@ public:
 	TeResourceManager *getResourceManager();
 	TeInputMgr *getInputMgr();
 	TetraedgeGameType gameType() const { return _gameType; }
+	bool gameIsAmerzone() const { return _gameType == kAmerzone; }
 
 	void openConfigDialog();
 	bool onKeyUp(const Common::KeyState &state);




More information about the Scummvm-git-logs mailing list