[Scummvm-git-logs] scummvm master -> a981967321b34a233fc0dfee5cfa1b1b7092a6ea

mduggan noreply at scummvm.org
Sun Mar 5 22:29:37 UTC 2023


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

Summary:
7baf3da962 TETRAEDGE: Fix potential OOB access
e88685a379 TETRAEDGE: Don't apply spot cutoff in Syberia 2
48de219950 TETRAEDGE: Fix some bugs in Syberia 2 light config
68e14e6558 TETRAEDGE: Implement collisionSlide for Syberia 2
a981967321 TETRAEDGE: Implement proper pathfinding for Syberia 2


Commit: 7baf3da9621c2c9414f493cbae2df95bb85d9d9c
    https://github.com/scummvm/scummvm/commit/7baf3da9621c2c9414f493cbae2df95bb85d9d9c
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-03-06T07:28:56+09:00

Commit Message:
TETRAEDGE: Fix potential OOB access

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


diff --git a/engines/tetraedge/game/lua_binds.cpp b/engines/tetraedge/game/lua_binds.cpp
index bec4a1aeb4e..749e47af820 100644
--- a/engines/tetraedge/game/lua_binds.cpp
+++ b/engines/tetraedge/game/lua_binds.cpp
@@ -1135,7 +1135,7 @@ static int tolua_ExportedFunctions_RotateGroundObject00(lua_State *L) {
 
 static void EnableLight(uint lightno, bool enable) {
 	Game *game = g_engine->getGame();
-	if (lightno > game->scene().lights().size()) {
+	if (lightno >= game->scene().lights().size()) {
 		error("[EnableLight] Light not found %d", lightno);
 	}
 	Common::SharedPtr<TeLight> light = game->scene().lights()[lightno];


Commit: e88685a3793dcc4b7c5026b50e4553ed94fc21f5
    https://github.com/scummvm/scummvm/commit/e88685a3793dcc4b7c5026b50e4553ed94fc21f5
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-03-06T07:28:57+09:00

Commit Message:
TETRAEDGE: Don't apply spot cutoff in Syberia 2

Changed paths:
    engines/tetraedge/te/te_light.cpp
    engines/tetraedge/te/te_light.h
    engines/tetraedge/te/te_light_opengl.cpp
    engines/tetraedge/te/te_light_tinygl.cpp


diff --git a/engines/tetraedge/te/te_light.cpp b/engines/tetraedge/te/te_light.cpp
index d8e8b2f584c..915a7b16f87 100644
--- a/engines/tetraedge/te/te_light.cpp
+++ b/engines/tetraedge/te/te_light.cpp
@@ -89,6 +89,11 @@ Common::String TeLight::dump() const {
 		_quadraticAtten, _cutoff, _exponent, _displaySize);
 }
 
+void TeLight::correctAttenuation() {
+	if (!_constAtten && !_linearAtten && !_quadraticAtten)
+		_constAtten = 1.0;
+}
+
 /*static*/
 TeLight *TeLight::makeInstance() {
 	Graphics::RendererType r = g_engine->preferredRendererType();
diff --git a/engines/tetraedge/te/te_light.h b/engines/tetraedge/te/te_light.h
index 64b75f5c31c..85838637c9b 100644
--- a/engines/tetraedge/te/te_light.h
+++ b/engines/tetraedge/te/te_light.h
@@ -72,6 +72,7 @@ public:
 	const TeVector3f32 &position3d() const { return _position3d; }
 
 	Common::String dump() const;
+	void correctAttenuation();
 
 	static TeLight *makeInstance();
 
diff --git a/engines/tetraedge/te/te_light_opengl.cpp b/engines/tetraedge/te/te_light_opengl.cpp
index 4d94992fa1e..8dfe56fe5fe 100644
--- a/engines/tetraedge/te/te_light_opengl.cpp
+++ b/engines/tetraedge/te/te_light_opengl.cpp
@@ -22,6 +22,7 @@
 #include "common/math.h"
 
 #include "tetraedge/te/te_light_opengl.h"
+#include "tetraedge/tetraedge.h"
 #include "tetraedge/te/te_color.h"
 #include "tetraedge/te/te_quaternion.h"
 #include "tetraedge/te/te_vector3f32.h"
@@ -69,11 +70,11 @@ void TeLightOpenGL::update(uint lightno) {
 	const uint glLight = _toGlLight(lightno);
 
 	const float ambient[4] = {_colAmbient.r() / 255.0f, _colAmbient.g() / 255.0f,
-			_colAmbient.b() / 255.0f, 1.0};
+			_colAmbient.b() / 255.0f, 1.0f};
 	glLightfv(glLight, GL_AMBIENT, ambient);
 
 	const float diff[4] = {_colDiffuse.r() / 255.0f, _colDiffuse.g() / 255.0f,
-			_colDiffuse.b() / 255.0f, 1.0};
+			_colDiffuse.b() / 255.0f, 1.0f};
 	glLightfv(glLight, GL_DIFFUSE, diff);
 
 	// WORKAROUND: Original game sets 0.01 as threshold here to avoid enabling
@@ -84,7 +85,7 @@ void TeLightOpenGL::update(uint lightno) {
 		glDisable(glLight);
 
 	const float spec[4] = {_colSpecular.r() / 255.0f, _colSpecular.g() / 255.0f,
-			_colSpecular.b() / 255.0f, 1.0};
+			_colSpecular.b() / 255.0f, 1.0f};
 	glLightfv(glLight, GL_SPECULAR, spec);
 
 	if (_type == LightTypeSpot || _type == LightTypePoint) {
@@ -105,10 +106,12 @@ void TeLightOpenGL::update(uint lightno) {
 		const TeVector3f32 dirv = directionVector();
 		const float dir[4] = {dirv.x(), dirv.y(), dirv.z(), 0.0f};
 		glLightfv(glLight, GL_SPOT_DIRECTION, dir);
-		glLightf(glLight, GL_SPOT_CUTOFF, (_cutoff * 180.0) / M_PI);
-		glLightf(glLight, GL_SPOT_EXPONENT, _exponent);
+		glLightf(glLight, GL_SPOT_CUTOFF, (_cutoff * 180.0f) / M_PI);
+		// Exponent doesn't get set in Syberia 2
+		if (g_engine->gameType() == TetraedgeEngine::kSyberia)
+			glLightf(glLight, GL_SPOT_EXPONENT, _exponent);
 	} else {
-		glLightf(glLight, GL_SPOT_CUTOFF, 180.0);
+		glLightf(glLight, GL_SPOT_CUTOFF, 180.0f);
 	}
 }
 
@@ -116,7 +119,7 @@ void TeLightOpenGL::update(uint lightno) {
 void TeLightOpenGL::updateGlobal() {
 	const TeColor globalAmbient(_globalAmbientColor);
 	const float col[4] = {globalAmbient.r() / 255.0f,
-			globalAmbient.g() / 255.0f, globalAmbient.b() / 255.0f, 1.0};
+			globalAmbient.g() / 255.0f, globalAmbient.b() / 255.0f, 1.0f};
 	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
 }
 
diff --git a/engines/tetraedge/te/te_light_tinygl.cpp b/engines/tetraedge/te/te_light_tinygl.cpp
index b4cedd1f472..3d6c3d04210 100644
--- a/engines/tetraedge/te/te_light_tinygl.cpp
+++ b/engines/tetraedge/te/te_light_tinygl.cpp
@@ -24,6 +24,7 @@
 #include "graphics/tinygl/tinygl.h"
 
 #include "tetraedge/te/te_light_tinygl.h"
+#include "tetraedge/tetraedge.h"
 #include "tetraedge/te/te_color.h"
 #include "tetraedge/te/te_quaternion.h"
 #include "tetraedge/te/te_vector3f32.h"
@@ -68,11 +69,11 @@ void TeLightTinyGL::update(uint lightno) {
 	const uint glLight = _toGlLight(lightno);
 
 	const float ambient[4] = {_colAmbient.r() / 255.0f, _colAmbient.g() / 255.0f,
-			_colAmbient.b() / 255.0f, 1.0};
+			_colAmbient.b() / 255.0f, 1.0f};
 	tglLightfv(glLight, TGL_AMBIENT, ambient);
 
 	const float diff[4] = {_colDiffuse.r() / 255.0f, _colDiffuse.g() / 255.0f,
-			_colDiffuse.b() / 255.0f, 1.0};
+			_colDiffuse.b() / 255.0f, 1.0f};
 	tglLightfv(glLight, TGL_DIFFUSE, diff);
 
 	// WORKAROUND: Original game sets 0.01 as threshold here to avoid enabling
@@ -83,7 +84,7 @@ void TeLightTinyGL::update(uint lightno) {
 		tglDisable(glLight);
 
 	const float spec[4] = {_colSpecular.r() / 255.0f, _colSpecular.g() / 255.0f,
-			_colSpecular.b() / 255.0f, 1.0};
+			_colSpecular.b() / 255.0f, 1.0f};
 	tglLightfv(glLight, TGL_SPECULAR, spec);
 
 	if (_type == LightTypeSpot || _type == LightTypePoint) {
@@ -104,10 +105,12 @@ void TeLightTinyGL::update(uint lightno) {
 		const TeVector3f32 dirv = directionVector();
 		const float dir[4] = {dirv.x(), dirv.y(), dirv.z(), 0.0f};
 		tglLightfv(glLight, TGL_SPOT_DIRECTION, dir);
-		tglLightf(glLight, TGL_SPOT_CUTOFF, (_cutoff * 180.0) / M_PI);
-		tglLightf(glLight, TGL_SPOT_EXPONENT, _exponent);
+		tglLightf(glLight, TGL_SPOT_CUTOFF, (_cutoff * 180.0f) / M_PI);
+		// Exponent doesn't get set in Syberia 2
+		if (g_engine->gameType() == TetraedgeEngine::kSyberia)
+			tglLightf(glLight, TGL_SPOT_EXPONENT, _exponent);
 	} else {
-		tglLightf(glLight, TGL_SPOT_CUTOFF, 180.0);
+		tglLightf(glLight, TGL_SPOT_CUTOFF, 180.0f);
 	}
 }
 
@@ -115,7 +118,7 @@ void TeLightTinyGL::update(uint lightno) {
 void TeLightTinyGL::updateGlobal() {
 	const TeColor globalAmbient(_globalAmbientColor);
 	const float col[4] = {globalAmbient.r() / 255.0f,
-			globalAmbient.g() / 255.0f, globalAmbient.b() / 255.0f, 1.0};
+			globalAmbient.g() / 255.0f, globalAmbient.b() / 255.0f, 1.0f};
 	tglLightModelfv(TGL_LIGHT_MODEL_AMBIENT, col);
 }
 


Commit: 48de219950797dd680677b194f33d24677635a51
    https://github.com/scummvm/scummvm/commit/48de219950797dd680677b194f33d24677635a51
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-03-06T07:28:57+09:00

Commit Message:
TETRAEDGE: Fix some bugs in Syberia 2 light config

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


diff --git a/engines/tetraedge/game/in_game_scene.cpp b/engines/tetraedge/game/in_game_scene.cpp
index 9b69000e778..3584b6c2cc6 100644
--- a/engines/tetraedge/game/in_game_scene.cpp
+++ b/engines/tetraedge/game/in_game_scene.cpp
@@ -862,8 +862,6 @@ bool InGameScene::loadXml(const Common::String &zone, const Common::String &scen
 	if (lightsNode.isReadable())
 		loadLights(lightsNode);
 
-	// TODO: Should we set particle matrix to current cam matrix here?
-	// If we are loading a new scene it seems redundant..
 	Common::Path pxmlpath = _sceneFileNameBase(zone, scene).joinInPlace("particles.xml");
 	Common::FSNode pnode = g_engine->getCore()->findFile(pxmlpath);
 	if (pnode.isReadable()) {
@@ -875,7 +873,6 @@ bool InGameScene::loadXml(const Common::String &zone, const Common::String &scen
 			error("InGameScene::loadXml: Can't parse %s", pnode.getPath().c_str());
 	}
 
-
 	TeMatrix4x4 camMatrix = currentCamera() ?
 		currentCamera()->worldTransformationMatrix() : TeMatrix4x4();
 	for (auto &particle : _particles) {
@@ -969,9 +966,21 @@ bool InGameScene::loadLights(const Common::FSNode &node) {
 
 	g_engine->getRenderer()->enableAllLights();
 	for (uint i = 0; i < _lights.size(); i++) {
+		//
+		// WORKAROUND: Some lights in Syberia 2 have 0 for all attenuation
+		// values, which causes textures to all be black.  eg,
+		// scenes/A2_Sommet/25210/lights.xml, light 0.
+		// Correct them to have the default attenuation of 1, 0, 0.
+		//
+		_lights[i]->correctAttenuation();
 		_lights[i]->enable(i);
 	}
 
+	if (_shadowLightNo >= (int)_lights.size()) {
+		warning("Disabling scene shadows: invalid shadow light no.");
+		_shadowLightNo = -1;
+	}
+
 #ifdef TETRAEDGE_DEBUG_LIGHTS
 	debug("--- Scene lights ---");
 	debug("Shadow: %s no:%d far:%.02f near:%.02f fov:%.02f", _shadowColor.dump().c_str(), _shadowLightNo, _shadowFarPlane, _shadowNearPlane, _shadowFov);
diff --git a/engines/tetraedge/game/scene_lights_xml_parser.cpp b/engines/tetraedge/game/scene_lights_xml_parser.cpp
index c6b01c8ee77..48ff45c6f85 100644
--- a/engines/tetraedge/game/scene_lights_xml_parser.cpp
+++ b/engines/tetraedge/game/scene_lights_xml_parser.cpp
@@ -112,8 +112,11 @@ bool SceneLightsXmlParser::parserCallback_Cutoff(ParserNode *node) {
 
 bool SceneLightsXmlParser::parserCallback_Exponent(ParserNode *node) {
 	float expon = parseDouble(node);
-	if (expon < 0.0f || expon > 128.0f)
-		warning("Loaded invalid lighting exponent value %f", expon);
+	if (expon < 0.0f || expon > 128.0f) {
+		// Print debug but don't bother warning - the value is not used anyway.
+		debug("Loaded invalid lighting exponent value %f, default to 1.0", expon);
+		expon = 1.0;
+	}
 	_lights->back()->setExponent(expon);
 	return true;
 }


Commit: 68e14e655896054e1c8065477f609dcf239e6b2b
    https://github.com/scummvm/scummvm/commit/68e14e655896054e1c8065477f609dcf239e6b2b
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-03-06T07:28:57+09:00

Commit Message:
TETRAEDGE: Implement collisionSlide for Syberia 2

Changed paths:
    engines/tetraedge/game/in_game_scene.cpp
    engines/tetraedge/game/in_game_scene.h
    engines/tetraedge/game/in_game_scene_xml_parser.cpp
    engines/tetraedge/te/te_free_move_zone.cpp
    engines/tetraedge/te/te_free_move_zone.h
    engines/tetraedge/te/te_pick_mesh2.cpp
    engines/tetraedge/te/te_pick_mesh2.h


diff --git a/engines/tetraedge/game/in_game_scene.cpp b/engines/tetraedge/game/in_game_scene.cpp
index 3584b6c2cc6..b69cafea936 100644
--- a/engines/tetraedge/game/in_game_scene.cpp
+++ b/engines/tetraedge/game/in_game_scene.cpp
@@ -49,9 +49,6 @@
 
 namespace Tetraedge {
 
-/*static*/
-bool InGameScene::_collisionSlide = false;
-
 /*static*/
 const int InGameScene::MAX_FIRE = 50;
 const int InGameScene::MAX_SNOW = 250;
@@ -800,8 +797,7 @@ bool InGameScene::loadXml(const Common::String &zone, const Common::String &scen
 	_sceneName = scene;
 	_blockers.clear();
 	_rectBlockers.clear();
-	_collisionSlide = false;
-	loadActZones();
+	TeFreeMoveZone::setCollisionSlide(false);
 	loadBlockers();
 
 	Common::Path xmlpath = _sceneFileNameBase(zone, scene).joinInPlace("Scene")
diff --git a/engines/tetraedge/game/in_game_scene.h b/engines/tetraedge/game/in_game_scene.h
index 1498d9c56ac..01653c96aa4 100644
--- a/engines/tetraedge/game/in_game_scene.h
+++ b/engines/tetraedge/game/in_game_scene.h
@@ -277,7 +277,6 @@ public:
 	const Common::String getZoneName() const { return _zoneName; }
 	const Common::String getSceneName() const { return _sceneName; }
 
-	void setCollisionSlide(bool val) { _collisionSlide = val; }
 	void activateMask(const Common::String &name, bool val);
 	YoukiManager &youkiManager() { return _youkiManager; }
 
diff --git a/engines/tetraedge/game/in_game_scene_xml_parser.cpp b/engines/tetraedge/game/in_game_scene_xml_parser.cpp
index be34e3added..267ea3d3f13 100644
--- a/engines/tetraedge/game/in_game_scene_xml_parser.cpp
+++ b/engines/tetraedge/game/in_game_scene_xml_parser.cpp
@@ -113,7 +113,7 @@ bool InGameSceneXmlParser::parserCallback_light(ParserNode *node) {
 }
 
 bool InGameSceneXmlParser::parserCallback_collisionSlide(ParserNode *node) {
-	_scene->setCollisionSlide(true);
+	TeFreeMoveZone::setCollisionSlide(true);
 	return true;
 }
 
@@ -122,12 +122,12 @@ bool InGameSceneXmlParser::parserCallback_collisionSlide(ParserNode *node) {
 // for collisionSlide.  Fix it to do what it was intended to do.
 //
 bool InGameSceneXmlParser::parserCallback_coliisionSlide(ParserNode *node) {
-	_scene->setCollisionSlide(true);
+	TeFreeMoveZone::setCollisionSlide(true);
 	return true;
 }
 
 bool InGameSceneXmlParser::parserCallback_noCollisionSlide(ParserNode *node) {
-	_scene->setCollisionSlide(false);
+	TeFreeMoveZone::setCollisionSlide(false);
 	return true;
 }
 
diff --git a/engines/tetraedge/te/te_free_move_zone.cpp b/engines/tetraedge/te/te_free_move_zone.cpp
index 462fadc4ebd..c396fc4af0a 100644
--- a/engines/tetraedge/te/te_free_move_zone.cpp
+++ b/engines/tetraedge/te/te_free_move_zone.cpp
@@ -35,6 +35,9 @@ namespace Tetraedge {
 /*static*/
 //TeIntrusivePtr<TeCamera> TeFreeMoveZone::_globalCamera;
 
+/*static*/
+bool TeFreeMoveZone::_collisionSlide = false;
+
 class TeFreeMoveZoneGraph : micropather::Graph {
 	friend class TeFreeMoveZone;
 
@@ -264,9 +267,13 @@ TeVector3f32 TeFreeMoveZone::correctCharacterPosition(const TeVector3f32 &pos, b
 	TeVector3f32 testPos(pos.x(), 0, pos.z());
 	if (!intersect(testPos, TeVector3f32(0, -1, 0), intersectPoint, f, intersectFlag, nullptr)) {
 		if (!intersect(testPos, TeVector3f32(0, 1, 0), intersectPoint, f, intersectFlag, nullptr)) {
-			if (*flagout)
-				*flagout = false;
-			return pos;
+			// Note: This flag should only ever get set in Syberia 2.
+			if (!_collisionSlide) {
+				if (*flagout)
+					*flagout = false;
+				return pos;
+			}
+			return slide(pos);
 		}
 	}
 	if (flagout)
diff --git a/engines/tetraedge/te/te_free_move_zone.h b/engines/tetraedge/te/te_free_move_zone.h
index e2b77ce7660..ee111ab04fd 100644
--- a/engines/tetraedge/te/te_free_move_zone.h
+++ b/engines/tetraedge/te/te_free_move_zone.h
@@ -124,6 +124,8 @@ public:
 
 	const Common::Array<TeVector3f32> freeMoveZoneVerticies() const { return _freeMoveZoneVerticies; }
 
+	static void setCollisionSlide(bool val) { _collisionSlide = val; }
+
 private:
 	TeVector2s32 aStarResolution() const;
 
@@ -162,6 +164,8 @@ private:
 	TeTimer _updateTimer;
 
 	Common::Path _aszGridPath;
+
+	static bool _collisionSlide;
 };
 
 } // end namespace Tetraedge
diff --git a/engines/tetraedge/te/te_pick_mesh2.cpp b/engines/tetraedge/te/te_pick_mesh2.cpp
index 5b3cca60128..f73c774885b 100644
--- a/engines/tetraedge/te/te_pick_mesh2.cpp
+++ b/engines/tetraedge/te/te_pick_mesh2.cpp
@@ -176,6 +176,66 @@ void TePickMesh2::setTriangle(uint num, const TeVector3f32 &v1, const TeVector3f
 	_verticies[num * 3 + 2] = v3;
 }
 
+static float linePointIntersection(const TeVector3f32 &v1, const TeVector3f32 &v2, const TeVector3f32 &v3) {
+	const TeVector3f32 line = v2 - v1;
+	float dot = line.dotProduct(line);
+	float retval = 0;
+	if (dot != 0) {
+		const TeVector3f32 segment = v3 - v1;
+		retval = segment.dotProduct(line);
+	}
+	return retval;
+}
+
+static float segmentPointIntersection(const TeVector3f32 &v1, const TeVector3f32 &v2, const TeVector3f32 &v3) {
+	float intersect = linePointIntersection(v1, v2, v3);
+	float retval;
+	if (intersect < 0)
+		retval = 0;
+	else if (intersect > 1)
+		retval = 1;
+	else
+		retval = intersect;
+	return retval;
+}
+
+TeVector3f32 TePickMesh2::slide(const TeVector3f32 &pos) {
+	const TeMatrix4x4 worldTransform = worldTransformationMatrix();
+	float shortest = 0;
+	TeVector3f32 retval;
+    for (uint i = 0; i < _verticies.size() / 3; i += 3) {
+		TeVector3f32 v1 = _verticies[i];
+		TeVector3f32 v2 = _verticies[i + 1];
+		TeVector3f32 v3 = _verticies[i + 2];
+
+		v1 = worldTransform * v1;
+		v2 = worldTransform * v2;
+		v3 = worldTransform * v3;
+
+		const TeVector3f32 pt1 = (v1 + (v2 - v1) * segmentPointIntersection(v1, v2, pos));
+		const TeVector3f32 off1 = pos - pt1;
+		if (i == 0 || off1.squaredLength() < shortest) {
+			retval = pt1;
+			shortest = off1.squaredLength();
+		}
+
+		const TeVector3f32 pt2 = v2 + (v3 - v2) * segmentPointIntersection(v2, v3, pos);
+		const TeVector3f32 off2 = pos - pt2;
+		if (off2.squaredLength() < shortest) {
+			retval = pt2;
+			shortest = off2.squaredLength();
+		}
+
+		const TeVector3f32 pt3 = v3 + (v1 - v3) * segmentPointIntersection(v3, v1, pos);
+		const TeVector3f32 off3 = pos - pt3;
+		if (off3.squaredLength() < shortest) {
+			retval = pt3;
+			shortest = off3.squaredLength();
+		}
+	}
+	return retval;
+}
+
 /*static*/
 void TePickMesh2::serialize(Common::WriteStream &stream, const TePickMesh2 &mesh) {
 	error("TODO: Implement TePickMesh2::serialize");
diff --git a/engines/tetraedge/te/te_pick_mesh2.h b/engines/tetraedge/te/te_pick_mesh2.h
index 929478fbda1..b384b071b17 100644
--- a/engines/tetraedge/te/te_pick_mesh2.h
+++ b/engines/tetraedge/te/te_pick_mesh2.h
@@ -47,6 +47,8 @@ public:
 	void setTriangle(uint num, const TeVector3f32 &v1, const TeVector3f32 &v2, const TeVector3f32 &v3);
 	void triangle(uint num, TeVector3f32 &v1out, TeVector3f32 &v2out, TeVector3f32 &v3out) const;
 
+	TeVector3f32 slide(const TeVector3f32 &pos);
+
 	static void serialize(Common::WriteStream &stream, const TePickMesh2 &mesh);
 	static void deserialize(Common::ReadStream &stream, TePickMesh2 &mesh);
 


Commit: a981967321b34a233fc0dfee5cfa1b1b7092a6ea
    https://github.com/scummvm/scummvm/commit/a981967321b34a233fc0dfee5cfa1b1b7092a6ea
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2023-03-06T07:28:57+09:00

Commit Message:
TETRAEDGE: Implement proper pathfinding for Syberia 2

Changed paths:
    engines/tetraedge/te/te_camera.cpp
    engines/tetraedge/te/te_camera.h
    engines/tetraedge/te/te_free_move_zone.cpp
    engines/tetraedge/te/te_free_move_zone.h
    engines/tetraedge/te/te_renderer_opengl.cpp
    engines/tetraedge/te/te_renderer_tinygl.cpp


diff --git a/engines/tetraedge/te/te_camera.cpp b/engines/tetraedge/te/te_camera.cpp
index 0b8af94cc62..59d7ff37bea 100644
--- a/engines/tetraedge/te/te_camera.cpp
+++ b/engines/tetraedge/te/te_camera.cpp
@@ -227,8 +227,17 @@ TeMatrix4x4 TeCamera::projectionMatrix() {
 	return _projectionMatrix;
 }
 
-TeVector3f32 TeCamera::projectPoint(const TeVector3f32 &pt) {
-	error("TODO: Implement TeCamera::projectPoint");
+TeVector2f32 TeCamera::projectPoint(const TeVector3f32 &pt) {
+	_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 TeVector2f32(projectedX, projectedY);
 }
 
 TeVector3f32 TeCamera::projectPoint3f32(const TeVector3f32 &pt) {
diff --git a/engines/tetraedge/te/te_camera.h b/engines/tetraedge/te/te_camera.h
index 320189e003c..aa89b35e80f 100644
--- a/engines/tetraedge/te/te_camera.h
+++ b/engines/tetraedge/te/te_camera.h
@@ -62,7 +62,7 @@ public:
 	void orthogonalParams(float f1, float f2, float f3, float f4);
 	TeMatrix4x4 projectionMatrix();
 
-	TeVector3f32 projectPoint(const TeVector3f32 &pt);
+	TeVector2f32 projectPoint(const TeVector3f32 &pt);
 	TeVector3f32 projectPoint3f32(const TeVector3f32 &pt);
 
 	static void restore();
@@ -87,6 +87,8 @@ public:
 	float orthoFarPlane() const { return _orthFarVal; }
 	void setOrthoNear(float f) { _orthNearVal = f; }
 	void setOrthoFar(float f) { _orthFarVal = f; }
+	float getViewportHeight() const { return _viewportH; }
+	float getViewportWidth() const { return _viewportW; }
 
 private:
 	void updateProjectionMatrix();
diff --git a/engines/tetraedge/te/te_free_move_zone.cpp b/engines/tetraedge/te/te_free_move_zone.cpp
index c396fc4af0a..d5d6615a141 100644
--- a/engines/tetraedge/te/te_free_move_zone.cpp
+++ b/engines/tetraedge/te/te_free_move_zone.cpp
@@ -30,6 +30,8 @@
 #include "tetraedge/te/te_ray_intersection.h"
 #include "tetraedge/te/te_core.h"
 
+//#define TETRAEDGE_DUMP_PATHFINDING_DATA 1
+
 namespace Tetraedge {
 
 /*static*/
@@ -144,7 +146,7 @@ void TeFreeMoveZone::buildAStar() {
 						else
 							_graph->_flags[graphSize._x * y + x] = 0;
 					} else {
-					_graph->_flags[graphSize._x * y + x] = 2;
+						_graph->_flags[graphSize._x * y + x] = 2;
 					}
 				}
 			}
@@ -281,6 +283,7 @@ TeVector3f32 TeFreeMoveZone::correctCharacterPosition(const TeVector3f32 &pos, b
 	return intersectPoint;
 }
 
+
 TeIntrusivePtr<TeBezierCurve> TeFreeMoveZone::curve(const TeVector3f32 &startpt, const TeVector2s32 &clickPt, float param_5, bool findMeshFlag) {
 	updateGrid(false);
 	Common::Array<TePickMesh2 *> meshes;
@@ -288,8 +291,13 @@ TeIntrusivePtr<TeBezierCurve> TeFreeMoveZone::curve(const TeVector3f32 &startpt,
 	meshes.push_back(this);
 
 	TePickMesh2 *nearest = findNearestMesh(_camera, clickPt, meshes, &newend, findMeshFlag);
-	if (!nearest)
-		return TeIntrusivePtr<TeBezierCurve>();
+	if (!nearest) {
+		if (g_engine->gameType() == TetraedgeEngine::kSyberia2) {
+			newend = findNearestPointOnBorder(TeVector2f32(clickPt));
+		} else {
+			return TeIntrusivePtr<TeBezierCurve>();
+		}
+	}
 
 	return curve(startpt, newend);
 }
@@ -301,7 +309,6 @@ TeIntrusivePtr<TeBezierCurve> TeFreeMoveZone::curve(const TeVector3f32 &startpt,
 	const int xsize = _graph->_size._x;
 	char *graphData = _graph->_flags.data();
 	float cost = 0;
-	// Passing an int to void*, yuck? but it's what the original does..
 	Common::Array<void *> path;
 	int pathResult = _micropather->Solve(graphData + xsize * projectedStart._y + projectedStart._x,
 			graphData + xsize * projectedEnd._y + projectedEnd._x, &path, &cost);
@@ -325,10 +332,27 @@ TeIntrusivePtr<TeBezierCurve> TeFreeMoveZone::curve(const TeVector3f32 &startpt,
 		}
 		pts3d.push_back(endpt);
 
+#ifdef TETRAEDGE_DUMP_PATHFINDING_DATA
+		debug("curve: pathfind from %s to %s", startpt.dump().c_str(), endpt.dump().c_str());
+		debug("curve: %d grid points:", points.size());
+		for (uint i = 0; i < points.size(); i++)
+			debug("curve: gridpt %2d: %d, %d", i, points[i]._x, points[i]._y);
+		debug("curve: %d 3d (world) points:", pts3d.size());
+		for (uint i = 0; i < pts3d.size(); i++)
+			debug("curve: wrldpt %2d: %s", i, pts3d[i].dump().c_str());
+		uint firstsz = pts3d.size();
+#endif
+
 		removeInsignificantPoints(pts3d);
+
+#ifdef TETRAEDGE_DUMP_PATHFINDING_DATA
+		debug("curve: removed insignificant pts, %d -> %d", firstsz, pts3d.size());
+#endif
+
 		retval = new TeBezierCurve();
 		retval->setControlPoints(pts3d);
 	} else {
+		// No path found, just use start and end points.
 		Common::Array<TeVector3f32> points;
 		points.push_back(startpt);
 		points.push_back(endpt);
@@ -391,46 +415,116 @@ void TeFreeMoveZone::draw() {
 	renderer->multiplyMatrix(worldTransformationMatrix());
 	renderer->setCurrentColor(TeColor(0, 0x80, 0xff, 0xff));
 	mesh->draw();
-	renderer->popMatrix();
-	renderer->setCurrentColor(prevColor);
 
-	// TODO: do a bunch of other drawing stuff here.
+	if (!_loadedFromBin)
+		renderer->popMatrix();
+
+	if (!_gridDirty && false) {
+		const TeVector2s32 aStarRes = aStarResolution();
+		// Note: original iterates through the graph first here and
+		// calls flag but doesn't do anything with it.. not sure why?
+		for (int x = 0; x < aStarRes._x; x++) {
+			for (int y = 0; y < aStarRes._y; y++) {
+				float left = _gridSquareSize.getX() * x + _gridTopLeft.getX();
+				float top  = _gridSquareSize.getY() * y + _gridTopLeft.getY();
+				const TeVector3f32 tl(left, _gridWorldY, top);
+				const TeVector3f32 tr(left + _gridSquareSize.getX(), _gridWorldY, top);
+				const TeVector3f32 bl(left, _gridWorldY, top + _gridSquareSize.getY());
+				const TeVector3f32 br(left + _gridSquareSize.getX(), _gridWorldY, top + _gridSquareSize.getY());
+
+				int flag = _graph->flag(TeVector2s32(x, y));
+				if (flag == 1) {
+					renderer->setCurrentColor(TeColor(0xff, 0xff, 0xff, 0xff));
+				} else if (flag == 2) {
+					renderer->setCurrentColor(TeColor(0xff, 0xff, 0, 0xff));
+				} else {
+					renderer->setCurrentColor(TeColor(0, 0xff, 0, 0xff));
+				}
 
-	renderer->disableWireFrame();
-}
+				renderer->drawLine(tl, tr);
+				renderer->drawLine(tr, br);
+				renderer->drawLine(tl, br);
+				renderer->drawLine(tr, bl);
+			}
+		}
+	}
 
-TeVector3f32 TeFreeMoveZone::findNearestPointOnBorder(const TeVector2f32 &pt) {
-	error("TODO: Implement TeFreeMoveZone::findNearestPointOnBorder");
+	// TODO: do a bunch of other drawing stuff here (line 294 on)
+
+	if (_loadedFromBin)
+		renderer->popMatrix();
+	renderer->setCurrentColor(prevColor);
+	renderer->disableWireFrame();
 }
 
 static int segmentIntersection(const TeVector2f32 &s1start, const TeVector2f32 &s1end,
 						const TeVector2f32 &s2start, const TeVector2f32 &s2end,
 						TeVector2f32 *sout, float *fout1, float *fout2) {
-	TeVector2f32 s1len = s1end - s1start;
-	TeVector2f32 s2len = s2end - s2start;
-	float squarelen = s1len.getX() * s2len.getX() + s1len.getY() * s2len.getY();
+	const TeVector2f32 s1len = s1end - s1start;
+	const TeVector2f32 s2len = s2end - s2start;
+	float dotprod = s1len.getX() * s2len.getX() + s1len.getY() * s2len.getY();
 	int result = 0;
-	if (squarelen != 0) {
+	if (dotprod != 0) {
 		result = 1;
-		float intersection1 = -((s1len.getY() * s1start.getX() +
+		float intersect1 = -((s1len.getY() * s1start.getX() +
 						(s1len.getX() * s2start.getY() - s1len.getX() * s1start.getY())) -
-						 s1len.getY() * s2start.getX()) / squarelen;
-		if (intersection1 >= 0.0f && intersection1 <= 1.0f) {
-			float intersection2 = -((s2len.getY() * s2start.getY() +
+						 s1len.getY() * s2start.getX()) / dotprod;
+		if (intersect1 >= 0.0f && intersect1 <= 1.0f) {
+			float intersect2 = -((s2len.getY() * s2start.getY() +
 						(s2len.getX() * s1start.getX() - s2len.getX() * s2start.getX())) -
-						 s2len.getY() * s1start.getY()) / squarelen;
-			if (intersection2 >= 0.0f && intersection2 <= 1.0f) {
+						 s2len.getY() * s1start.getY()) / dotprod;
+			if (intersect2 >= 0.0f && intersect2 <= 1.0f) {
 				result = 2;
-				if (sout || fout1 || fout2) {
-					// Seems like these are always null?
-					error("TODO: implement output in segmentIntersection");
-				}
+				if (sout)
+					*sout = s1start + s1len * intersect2;
+				if (fout1)
+					*fout1 = intersect2;
+				if (fout2)
+					*fout2 = intersect1;
 			}
 		}
 	}
 	return result;
 }
 
+TeVector3f32 TeFreeMoveZone::findNearestPointOnBorder(const TeVector2f32 &pt) {
+	TeVector3f32 retval;
+	const TeVector2f32 pt_x0(pt.getX(), 0);
+	const TeVector2f32 pt_x1(pt.getX(), _camera->getViewportHeight());
+	const TeVector2f32 pt_y0(0, pt.getY());
+	const TeVector2f32 pt_y1(_camera->getViewportWidth(), pt.getY());
+
+	updateProjectedPoints();
+	updateBorders();
+
+	float leastDist = FLT_MAX;
+	for (uint i = 0; i < _borders.size() / 2; i++) {
+		uint b1 = _borders[i * 2];
+		uint b2 = _borders[i * 2 + 1];
+		const TeVector2f32 &projb1 = _projectedPoints[b1];
+		const TeVector2f32 &projb2 = _projectedPoints[b2];
+		const TeVector3f32 &transb1 = _transformedVerticies[_pickMesh[b1]];
+		const TeVector3f32 &transb2 = _transformedVerticies[_pickMesh[b2]];
+		float dist = 0;
+		TeVector2f32 dir;
+		if (segmentIntersection(pt_x0, pt_x1, projb1, projb2, &dir, nullptr, &dist) == 2) {
+			float sqLen = (dir - pt).getSquareMagnitude();
+			if (sqLen < leastDist) {
+				retval = transb1 + (transb2 - transb1) * dist;
+				leastDist = sqLen;
+			}
+		}
+        if (segmentIntersection(pt_y0, pt_y1, projb1, projb2, &dir, nullptr, &dist) == 2) {
+			float sqLen = (dir - pt).getSquareMagnitude();
+			if (sqLen < leastDist) {
+				retval = transb1 + (transb2 - transb1) * dist;
+				leastDist = sqLen;
+			}
+		}
+	}
+	return retval;
+}
+
 byte TeFreeMoveZone::hasBlockerIntersection(const TeVector2s32 &pt) {
 	TeVector2f32 borders[4];
 
@@ -655,7 +749,7 @@ TeVector2s32 TeFreeMoveZone::projectOnAStarGrid(const TeVector3f32 &pt) {
 		invGrid.inverse();
 		TeVector3f32 transPt = invGrid * (_inverseWorldTransform * pt);
 		offsetpt.setX(transPt.x() - _gridTopLeft.getX());
-		offsetpt.setY(transPt.y() - _gridTopLeft.getY());
+		offsetpt.setY(transPt.z() - _gridTopLeft.getY());
 	}
 	const TeVector2f32 projected = offsetpt / _gridSquareSize;
 	return TeVector2s32((int)projected.getX(), (int)projected.getY());
@@ -740,9 +834,9 @@ void TeFreeMoveZone::setVertex(uint offset, const TeVector3f32 &vertex) {
 
 TeVector3f32 TeFreeMoveZone::transformAStarGridInWorldSpace(const TeVector2s32 &gridpt) {
 	float offsetx = (float)gridpt._x * _gridSquareSize.getX() + _gridTopLeft.getX() +
-				_gridSquareSize.getX() / 2;
+				_gridSquareSize.getX() / 2.0f;
 	float offsety = (float)gridpt._y * _gridSquareSize.getY() + _gridTopLeft.getY() +
-				_gridSquareSize.getY() / 2;
+				_gridSquareSize.getY() / 2.0f;
 	if (!_loadedFromBin) {
 		return TeVector3f32(offsetx, _gridWorldY, offsety);
 	} else {
@@ -848,7 +942,20 @@ void TeFreeMoveZone::updateProjectedPoints() {
 	if (!_projectedPointsDirty)
 		return;
 
-	error("TODO: Implement TeFreeMoveZone::updateProjectedPoints");
+    updateTransformedVertices();
+    updatePickMesh();
+    if (!_camera) {
+		_projectedPoints.clear();
+		_projectedPointsDirty = false;
+		return;
+	}
+
+	_projectedPoints.resize(_pickMesh.size());
+	for (uint i = 0; i < _pickMesh.size(); i++) {
+		_projectedPoints[i] = _camera->projectPoint(_transformedVerticies[_pickMesh[i]]);
+		_projectedPoints[i].setY(_camera->getViewportHeight() - _projectedPoints[i].getY());
+    }
+    _projectedPointsDirty = false;
 }
 
 void TeFreeMoveZone::updateTransformedVertices() {
diff --git a/engines/tetraedge/te/te_free_move_zone.h b/engines/tetraedge/te/te_free_move_zone.h
index ee111ab04fd..3f9e6eba982 100644
--- a/engines/tetraedge/te/te_free_move_zone.h
+++ b/engines/tetraedge/te/te_free_move_zone.h
@@ -137,6 +137,7 @@ private:
 	Common::Array<uint> _pickMesh;
 	Common::Array<TeVector3f32> _transformedVerticies;
 	Common::Array<uint> _borders;
+	Common::Array<TeVector2f32> _projectedPoints;
 
 	TeVector2f32 _gridSquareSize;
 	TeVector2f32 _gridTopLeft;
diff --git a/engines/tetraedge/te/te_renderer_opengl.cpp b/engines/tetraedge/te/te_renderer_opengl.cpp
index c21b0fb4162..0f373b24120 100644
--- a/engines/tetraedge/te/te_renderer_opengl.cpp
+++ b/engines/tetraedge/te/te_renderer_opengl.cpp
@@ -71,7 +71,20 @@ void TeRendererOpenGL::disableZBuffer() {
 }
 
 void TeRendererOpenGL::drawLine(const TeVector3f32 &from, const TeVector3f32 &to) {
-	error("TODO: Implement TeRenderer::drawLine");
+	const TeVector3f32 pts[2] = {from, to};
+	const TeVector3f32 norms(0, 0, 1);
+	const unsigned short idxs[2] = {0, 1};
+	setMatrixMode(MM_GL_MODELVIEW);
+	glPushMatrix();
+	loadCurrentMatrixToGL();
+	glEnableClientState(GL_VERTEX_ARRAY);
+	glEnableClientState(GL_NORMAL_ARRAY);
+	glVertexPointer(3, GL_FLOAT, sizeof(TeVector3f32), pts);
+	glNormalPointer(GL_FLOAT, sizeof(TeVector3f32), &norms);
+	glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, idxs);
+	glDisableClientState(GL_VERTEX_ARRAY);
+	glDisableClientState(GL_NORMAL_ARRAY);
+	glPopMatrix();
 }
 
 void TeRendererOpenGL::enableAllLights() {
diff --git a/engines/tetraedge/te/te_renderer_tinygl.cpp b/engines/tetraedge/te/te_renderer_tinygl.cpp
index 8e0c9626ffc..eaa1dce076c 100644
--- a/engines/tetraedge/te/te_renderer_tinygl.cpp
+++ b/engines/tetraedge/te/te_renderer_tinygl.cpp
@@ -72,7 +72,7 @@ void TeRendererTinyGL::disableZBuffer() {
 }
 
 void TeRendererTinyGL::drawLine(const TeVector3f32 &from, const TeVector3f32 &to) {
-	error("TODO: Implement TeRenderer::drawLine");
+	error("TODO: Implement TeRendererTinyGL::drawLine");
 }
 
 void TeRendererTinyGL::enableAllLights() {




More information about the Scummvm-git-logs mailing list