From 7354c74fb8f409336db3a6d70455fbc10232ae64 Mon Sep 17 00:00:00 2001
From: Daniel Karbach <daniel.karbach@localhorst.tv>
Date: Mon, 9 Nov 2015 14:15:36 +0100
Subject: [PATCH] simplify ray/chunk intersection test

---
 doc/todo            |  8 ++++++++
 src/ai/ai.cpp       |  4 ++--
 src/ui/ui.cpp       |  4 ++--
 src/world/Chunk.hpp | 15 +++++++++++----
 src/world/World.hpp |  6 ++----
 src/world/chunk.cpp |  8 ++++++--
 src/world/world.cpp |  8 +++-----
 7 files changed, 34 insertions(+), 19 deletions(-)

diff --git a/doc/todo b/doc/todo
index 39cb8a7..921221a 100644
--- a/doc/todo
+++ b/doc/todo
@@ -29,6 +29,9 @@ persistence
 
 	store some kind of byte order mark?
 
+	world and player names should be normalized so they can safely
+	be used in path names
+
 networking
 
 	definitely needs throttling for the internets
@@ -36,6 +39,11 @@ networking
 	players stats (who's connected, their ping, and game-relevant
 	things) should be sent to clients
 
+	some method for authenticating a player might be nice
+
+	maybe stale and inexistent chunks should be visualized (e.g. by
+	drawing a semi-transparent box around them)
+
 threading
 
 	(clientside) networking and disk IO are prime candidates for threading
diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp
index a2f5938..0d4c9e9 100644
--- a/src/ai/ai.cpp
+++ b/src/ai/ai.cpp
@@ -169,7 +169,7 @@ Player *AIController::ClosestVisiblePlayer(const Entity &e) noexcept {
 
 		// LOS test, assumes all entities are see-through
 		WorldCollision col;
-		if (world.Intersection(aim, glm::mat4(1.0f), reference, col) && col.depth < dist) {
+		if (world.Intersection(aim, reference, col) && col.depth < dist) {
 			continue;
 		}
 
@@ -189,7 +189,7 @@ bool AIController::LineOfSight(const Entity &from, const Entity &to) const noexc
 		return false;
 	}
 	WorldCollision col;
-	if (world.Intersection(aim, glm::mat4(1.0f), reference, col) && col.depth < dist) {
+	if (world.Intersection(aim, reference, col) && col.depth < dist) {
 		return false;
 	}
 	return true;
diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp
index c45b34b..02f2781 100644
--- a/src/ui/ui.cpp
+++ b/src/ui/ui.cpp
@@ -97,10 +97,10 @@ void PlayerController::Invalidate() noexcept {
 void PlayerController::UpdatePlayer() noexcept {
 	if (dirty) {
 		Ray aim = player.Aim();
-		if (!world.Intersection(aim, glm::mat4(1.0f), player.GetEntity().ChunkCoords(), aim_world)) {
+		if (!world.Intersection(aim, player.GetEntity().ChunkCoords(), aim_world)) {
 			aim_world = WorldCollision();
 		}
-		if (!world.Intersection(aim, glm::mat4(1.0f), player.GetEntity(), aim_entity)) {
+		if (!world.Intersection(aim, player.GetEntity(), aim_entity)) {
 			aim_entity = EntityCollision();
 		}
 		if (aim_world && aim_entity) {
diff --git a/src/world/Chunk.hpp b/src/world/Chunk.hpp
index 4938c1b..d0dcf94 100644
--- a/src/world/Chunk.hpp
+++ b/src/world/Chunk.hpp
@@ -69,7 +69,11 @@ public:
 			(idx / (side * side))
 		);
 	}
-	glm::mat4 ToTransform(const RoughLocation::Fine &pos, int idx) const noexcept;
+	/// get a chunk-local transform for block at given position and index
+	/// (position and index are redundant)
+	glm::mat4 ToTransform(const RoughLocation::Fine &position, int index) const noexcept;
+	/// same as above, but also apply offset to given reference
+	glm::mat4 ToTransform(const ExactLocation::Coarse &ref, const RoughLocation::Fine &pos, int idx) const noexcept;
 
 	ExactLocation::Fine ToSceneCoords(const ExactLocation::Coarse &base, const ExactLocation::Fine &pos) const noexcept {
 		return ExactLocation::Fine((position - base) * ExactLocation::Extent()) + pos;
@@ -130,15 +134,17 @@ public:
 
 	bool Intersection(
 		const Ray &ray,
-		const glm::mat4 &M,
+		const ExactLocation::Coarse &reference,
 		float &dist
 	) const noexcept {
-		return blank::Intersection(ray, Bounds(), M, &dist);
+		return blank::Intersection(ray, Bounds(), Transform(reference), &dist);
 	}
 
+	/// check if given ray intersects any block of this chunk
+	/// given reference indicated the chunk offset of the ray in world space
 	bool Intersection(
 		const Ray &,
-		const glm::mat4 &M,
+		const ExactLocation::Coarse &reference,
 		WorldCollision &) noexcept;
 
 	bool Intersection(
@@ -155,6 +161,7 @@ public:
 
 	void Position(const ExactLocation::Coarse &pos) noexcept { position = pos; }
 	const ExactLocation::Coarse &Position() const noexcept { return position; }
+
 	glm::mat4 Transform(const ExactLocation::Coarse &offset) const noexcept {
 		return glm::translate((position - offset) * ExactLocation::Extent());
 	}
diff --git a/src/world/World.hpp b/src/world/World.hpp
index 8754d39..767f527 100644
--- a/src/world/World.hpp
+++ b/src/world/World.hpp
@@ -45,19 +45,17 @@ public:
 	/// check if this ray hits a block
 	/// depth in the collision is the distance between the ray's
 	/// origin and the intersection point
-	/// M is the global transform for given reference chunk
+	/// reference is the chunk offset of the ray in world space
 	bool Intersection(
 		const Ray &,
-		const glm::mat4 &M,
 		const ExactLocation::Coarse &reference,
 		WorldCollision &);
 
 	/// check if this ray hits an entity
 	/// intersections with the reference are not tested
-	/// M is the global transform for the chunk of given reference entity
+	/// the ray is assumed to be in world space offset by entity's chunk coords
 	bool Intersection(
 		const Ray &,
-		const glm::mat4 &M,
 		const Entity &reference,
 		EntityCollision &);
 
diff --git a/src/world/chunk.cpp b/src/world/chunk.cpp
index cc305cd..9e95458 100644
--- a/src/world/chunk.cpp
+++ b/src/world/chunk.cpp
@@ -359,7 +359,7 @@ bool Chunk::IsSurface(const RoughLocation::Fine &pos) const noexcept {
 
 bool Chunk::Intersection(
 	const Ray &ray,
-	const glm::mat4 &M,
+	const ExactLocation::Coarse &reference,
 	WorldCollision &coll
 ) noexcept {
 	int idx = 0;
@@ -375,7 +375,7 @@ bool Chunk::Intersection(
 				}
 				float cur_dist;
 				glm::vec3 cur_norm;
-				if (type.shape->Intersects(ray, M * ToTransform(RoughLocation::Fine(x, y, z), idx), cur_dist, cur_norm)) {
+				if (type.shape->Intersects(ray, ToTransform(reference, RoughLocation::Fine(x, y, z), idx), cur_dist, cur_norm)) {
 					if (cur_dist < coll.depth) {
 						coll.block = idx;
 						coll.depth = cur_dist;
@@ -560,6 +560,10 @@ glm::mat4 Chunk::ToTransform(const RoughLocation::Fine &pos, int idx) const noex
 	return glm::translate(ToCoords(pos)) * BlockAt(idx).Transform();
 }
 
+glm::mat4 Chunk::ToTransform(const ExactLocation::Coarse &ref, const RoughLocation::Fine &pos, int idx) const noexcept {
+	return glm::translate(ExactLocation::Fine((position - ref) * ExactLocation::Extent()) + ToCoords(pos)) * BlockAt(idx).Transform();
+}
+
 
 BlockLookup::BlockLookup(Chunk *c, const RoughLocation::Fine &p) noexcept
 : chunk(c), pos(p) {
diff --git a/src/world/world.cpp b/src/world/world.cpp
index c43747a..5e3420d 100644
--- a/src/world/world.cpp
+++ b/src/world/world.cpp
@@ -459,7 +459,6 @@ std::vector<Candidate> candidates;
 
 bool World::Intersection(
 	const Ray &ray,
-	const glm::mat4 &M,
 	const ExactLocation::Coarse &reference,
 	WorldCollision &coll
 ) {
@@ -467,7 +466,7 @@ bool World::Intersection(
 
 	for (Chunk &cur_chunk : chunks) {
 		float cur_dist;
-		if (cur_chunk.Intersection(ray, M * cur_chunk.Transform(reference), cur_dist)) {
+		if (cur_chunk.Intersection(ray, reference, cur_dist)) {
 			candidates.push_back({ &cur_chunk, cur_dist });
 		}
 	}
@@ -483,7 +482,7 @@ bool World::Intersection(
 	for (Candidate &cand : candidates) {
 		if (cand.dist > coll.depth) continue;
 		WorldCollision cur_coll;
-		if (cand.chunk->Intersection(ray, M * cand.chunk->Transform(reference), cur_coll)) {
+		if (cand.chunk->Intersection(ray, reference, cur_coll)) {
 			if (cur_coll.depth < coll.depth) {
 				coll = cur_coll;
 			}
@@ -495,7 +494,6 @@ bool World::Intersection(
 
 bool World::Intersection(
 	const Ray &ray,
-	const glm::mat4 &M,
 	const Entity &reference,
 	EntityCollision &coll
 ) {
@@ -507,7 +505,7 @@ bool World::Intersection(
 		}
 		float cur_dist;
 		glm::vec3 cur_normal;
-		if (blank::Intersection(ray, cur_entity.Bounds(), M * cur_entity.Transform(reference.ChunkCoords()), &cur_dist, &cur_normal)) {
+		if (blank::Intersection(ray, cur_entity.Bounds(), cur_entity.Transform(reference.ChunkCoords()), &cur_dist, &cur_normal)) {
 			// TODO: fine grained check goes here? maybe?
 			if (cur_dist < coll.depth) {
 				coll.entity = &cur_entity;
-- 
2.39.5