From 79c9f14aec52c0fa1b3c2b1850ab3c6a9124a313 Mon Sep 17 00:00:00 2001
From: Perttu Ahola <celeron55@gmail.com>
Date: Sun, 13 Nov 2011 12:31:05 +0200
Subject: [PATCH] Generalize selection boxes

---
 src/content_mapnode.cpp       |  10 ++
 src/game.cpp                  | 186 +++++++---------------------------
 src/mapnode_contentfeatures.h |  32 ++++++
 3 files changed, 80 insertions(+), 148 deletions(-)

diff --git a/src/content_mapnode.cpp b/src/content_mapnode.cpp
index a365f2ae9..0ba59fcbb 100644
--- a/src/content_mapnode.cpp
+++ b/src/content_mapnode.cpp
@@ -335,6 +335,7 @@ void content_mapnode_init()
 	f->solidness = 0; // drawn separately, makes no faces
 	f->air_equivalent = true; // grass grows underneath
 	f->walkable = false;
+	f->selection_box.type = NODEBOX_FIXED;
 	setDirtLikeDiggingProperties(f->digging_properties, 0.75);
 
 	i = CONTENT_LADDER;
@@ -350,6 +351,7 @@ void content_mapnode_init()
 	f->air_equivalent = true;
 	f->walkable = false;
 	f->climbable = true;
+	f->selection_box.type = NODEBOX_WALLMOUNTED;
 	setWoodLikeDiggingProperties(f->digging_properties, 0.5);
 
 	// Deprecated
@@ -606,6 +608,13 @@ void content_mapnode_init()
 	f->air_equivalent = true;
 	f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
 	f->light_source = LIGHT_MAX-1;
+	f->selection_box.type = NODEBOX_WALLMOUNTED;
+	f->selection_box.wall_top = core::aabbox3d<f32>(
+			-BS/10, BS/2-BS/3.333*2, -BS/10, BS/10, BS/2, BS/10);
+	f->selection_box.wall_bottom = core::aabbox3d<f32>(
+			-BS/10, -BS/2, -BS/10, BS/10, -BS/2+BS/3.333*2, BS/10);
+	f->selection_box.wall_side = core::aabbox3d<f32>(
+			-BS/2, -BS/3.333, -BS/10, -BS/2+BS/3.333, BS/3.333, BS/10);
 	f->digging_properties.set("", DiggingProperties(true, 0.0, 0));
 	
 	i = CONTENT_SIGN_WALL;
@@ -623,6 +632,7 @@ void content_mapnode_init()
 	if(f->initial_metadata == NULL)
 		f->initial_metadata = new SignNodeMetadata("Some sign");
 	f->digging_properties.set("", DiggingProperties(true, 0.5, 0));
+	f->selection_box.type = NODEBOX_WALLMOUNTED;
 	
 	i = CONTENT_CHEST;
 	f = &content_features(i);
diff --git a/src/game.cpp b/src/game.cpp
index d7efbeae9..30bd1bcf7 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -43,7 +43,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "gettext.h"
 #include "log.h"
 #include "filesys.h"
-// Needed for some special cases for CONTENT_TORCH and CONTENT_SIGN_WALL
+// Needed for writing to signs (CONTENT_SIGN_WALL)
 // TODO: A generic way for handling such should be created
 #include "content_mapnode.h"
 // Needed for sign text input
@@ -343,43 +343,15 @@ void getPointedNode(Client *client, v3f player_position,
 			v3s16(-1,0,0), // left
 		};
 		
-		/*
-			Meta-objects
-		*/
-		if(n.getContent() == CONTENT_TORCH)
+		ContentFeatures &f = content_features(n);
+		
+		if(f.selection_box.type == NODEBOX_FIXED)
 		{
-			v3s16 dir = unpackDir(n.param2);
-			v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
-			dir_f *= BS/2 - BS/6 - BS/20;
-			v3f cpf = npf + dir_f;
-			f32 distance = (cpf - camera_position).getLength();
+			f32 distance = (npf - camera_position).getLength();
 
-			core::aabbox3d<f32> box;
-			
-			// bottom
-			if(dir == v3s16(0,-1,0))
-			{
-				box = core::aabbox3d<f32>(
-					npf - v3f(BS/6, BS/2, BS/6),
-					npf + v3f(BS/6, -BS/2+BS/3*2, BS/6)
-				);
-			}
-			// top
-			else if(dir == v3s16(0,1,0))
-			{
-				box = core::aabbox3d<f32>(
-					npf - v3f(BS/6, -BS/2+BS/3*2, BS/6),
-					npf + v3f(BS/6, BS/2, BS/6)
-				);
-			}
-			// side
-			else
-			{
-				box = core::aabbox3d<f32>(
-					cpf - v3f(BS/6, BS/3, BS/6),
-					cpf + v3f(BS/6, BS/3, BS/6)
-				);
-			}
+			core::aabbox3d<f32> box = f.selection_box.fixed;
+			box.MinEdge += npf;
+			box.MaxEdge += npf;
 
 			if(distance < mindistance)
 			{
@@ -393,7 +365,7 @@ void getPointedNode(Client *client, v3f player_position,
 				}
 			}
 		}
-		else if(n.getContent() == CONTENT_SIGN_WALL)
+		else if(f.selection_box.type == NODEBOX_WALLMOUNTED)
 		{
 			v3s16 dir = unpackDir(n.param2);
 			v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
@@ -401,122 +373,43 @@ void getPointedNode(Client *client, v3f player_position,
 			v3f cpf = npf + dir_f;
 			f32 distance = (cpf - camera_position).getLength();
 
-			v3f vertices[4] =
-			{
-				v3f(BS*0.42,-BS*0.35,-BS*0.4),
-				v3f(BS*0.49, BS*0.35, BS*0.4),
-			};
-
-			for(s32 i=0; i<2; i++)
-			{
-				if(dir == v3s16(1,0,0))
-					vertices[i].rotateXZBy(0);
-				if(dir == v3s16(-1,0,0))
-					vertices[i].rotateXZBy(180);
-				if(dir == v3s16(0,0,1))
-					vertices[i].rotateXZBy(90);
-				if(dir == v3s16(0,0,-1))
-					vertices[i].rotateXZBy(-90);
-				if(dir == v3s16(0,-1,0))
-					vertices[i].rotateXYBy(-90);
-				if(dir == v3s16(0,1,0))
-					vertices[i].rotateXYBy(90);
-
-				vertices[i] += npf;
-			}
-
 			core::aabbox3d<f32> box;
-
-			box = core::aabbox3d<f32>(vertices[0]);
-			box.addInternalPoint(vertices[1]);
-
-			if(distance < mindistance)
-			{
-				if(box.intersectsWithLine(shootline))
-				{
-					nodefound = true;
-					nodepos = np;
-					neighbourpos = np;
-					mindistance = distance;
-					nodehilightbox = box;
-				}
+			
+			// top
+			if(dir == v3s16(0,1,0)){
+				box = f.selection_box.wall_top;
 			}
-		}
-
-		else if(n.getContent() == CONTENT_LADDER)
-		{
-			v3s16 dir = unpackDir(n.param2);
-			v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
-			dir_f *= BS/2 - BS/6 - BS/20;
-			v3f cpf = npf + dir_f;
-			f32 distance = (cpf - camera_position).getLength();
-
-			v3f vertices[4] =
-			{
-				v3f(BS*0.42,-BS/2,-BS/2),
-				v3f(BS*0.49, BS/2, BS/2),
-			};
-
-			for(s32 i=0; i<2; i++)
-			{
-				if(dir == v3s16(1,0,0))
-					vertices[i].rotateXZBy(0);
-				if(dir == v3s16(-1,0,0))
-					vertices[i].rotateXZBy(180);
-				if(dir == v3s16(0,0,1))
-					vertices[i].rotateXZBy(90);
-				if(dir == v3s16(0,0,-1))
-					vertices[i].rotateXZBy(-90);
-				if(dir == v3s16(0,-1,0))
-					vertices[i].rotateXYBy(-90);
-				if(dir == v3s16(0,1,0))
-					vertices[i].rotateXYBy(90);
-
-				vertices[i] += npf;
+			// bottom
+			else if(dir == v3s16(0,-1,0)){
+				box = f.selection_box.wall_bottom;
 			}
+			// side
+			else{
+				v3f vertices[2] =
+				{
+					f.selection_box.wall_side.MinEdge,
+					f.selection_box.wall_side.MaxEdge
+				};
 
-			core::aabbox3d<f32> box;
-
-			box = core::aabbox3d<f32>(vertices[0]);
-			box.addInternalPoint(vertices[1]);
-
-			if(distance < mindistance)
-			{
-				if(box.intersectsWithLine(shootline))
+				for(s32 i=0; i<2; i++)
 				{
-					nodefound = true;
-					nodepos = np;
-					neighbourpos = np;
-					mindistance = distance;
-					nodehilightbox = box;
+					if(dir == v3s16(-1,0,0))
+						vertices[i].rotateXZBy(0);
+					if(dir == v3s16(1,0,0))
+						vertices[i].rotateXZBy(180);
+					if(dir == v3s16(0,0,-1))
+						vertices[i].rotateXZBy(90);
+					if(dir == v3s16(0,0,1))
+						vertices[i].rotateXZBy(-90);
 				}
-			}
-		}
-		else if(n.getContent() == CONTENT_RAIL)
-		{
-			v3s16 dir = unpackDir(n.param0);
-			v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
-			dir_f *= BS/2 - BS/6 - BS/20;
-			v3f cpf = npf + dir_f;
-			f32 distance = (cpf - camera_position).getLength();
 
-			float d = (float)BS/16;
-			v3f vertices[4] =
-			{
-				v3f(BS/2, -BS/2+d, -BS/2),
-				v3f(-BS/2, -BS/2, BS/2),
-			};
-
-			for(s32 i=0; i<2; i++)
-			{
-				vertices[i] += npf;
+				box = core::aabbox3d<f32>(vertices[0]);
+				box.addInternalPoint(vertices[1]);
 			}
 
-			core::aabbox3d<f32> box;
-
-			box = core::aabbox3d<f32>(vertices[0]);
-			box.addInternalPoint(vertices[1]);
-
+			box.MinEdge += npf;
+			box.MaxEdge += npf;
+			
 			if(distance < mindistance)
 			{
 				if(box.intersectsWithLine(shootline))
@@ -529,10 +422,7 @@ void getPointedNode(Client *client, v3f player_position,
 				}
 			}
 		}
-		/*
-			Regular blocks
-		*/
-		else
+		else // NODEBOX_REGULAR
 		{
 			for(u16 i=0; i<6; i++)
 			{
diff --git a/src/mapnode_contentfeatures.h b/src/mapnode_contentfeatures.h
index b60fc8d8b..7dd9df13b 100644
--- a/src/mapnode_contentfeatures.h
+++ b/src/mapnode_contentfeatures.h
@@ -57,6 +57,35 @@ enum LiquidType
 	LIQUID_SOURCE
 };
 
+enum NodeBoxType
+{
+	NODEBOX_REGULAR, // Regular block; allows buildable_to
+	NODEBOX_FIXED, // Static separately defined box
+	NODEBOX_WALLMOUNTED, // Box for wall_mounted nodes; (top, bottom, side)
+};
+
+struct NodeBox
+{
+	enum NodeBoxType type;
+	// NODEBOX_REGULAR (no parameters)
+	// NODEBOX_FIXED
+	core::aabbox3d<f32> fixed;
+	// NODEBOX_WALLMOUNTED
+	core::aabbox3d<f32> wall_top;
+	core::aabbox3d<f32> wall_bottom;
+	core::aabbox3d<f32> wall_side; // being at the -X side
+
+	NodeBox():
+		type(NODEBOX_REGULAR),
+		// default is rail-like
+		fixed(-BS/2, -BS/2, -BS/2, BS/2, -BS/2+BS/16., BS/2),
+		// default is sign/ladder-like
+		wall_top(-BS/2, BS/2-BS/16., -BS/2, BS/2, BS/2, BS/2),
+		wall_bottom(-BS/2, -BS/2, -BS/2, BS/2, -BS/2+BS/16., BS/2),
+		wall_side(-BS/2, -BS/2, -BS/2, -BS/2+BS/16., BS/2, BS/2)
+	{}
+};
+
 struct MapNode;
 class NodeMetadata;
 
@@ -149,6 +178,8 @@ struct ContentFeatures
 	DiggingPropertiesList digging_properties;
 
 	u32 damage_per_second;
+
+	NodeBox selection_box;
 	
 	// NOTE: Move relevant properties to here from elsewhere
 
@@ -186,6 +217,7 @@ struct ContentFeatures
 		light_source = 0;
 		digging_properties.clear();
 		damage_per_second = 0;
+		selection_box = NodeBox();
 	}
 
 	ContentFeatures()
-- 
GitLab