From 6f8d40ef5d24e26a70c7a0bdf6d2992e0bea9a63 Mon Sep 17 00:00:00 2001
From: RealBadAngel <mk@realbadangel.pl>
Date: Sat, 23 Mar 2013 19:17:00 +0100
Subject: [PATCH] 6d facedir

---
 doc/lua_api.txt          |   4 +
 src/content_mapblock.cpp | 114 ++++++++++++++++++++++-----
 src/mapblock_mesh.cpp    | 163 +++++++++++++++++++++++++++------------
 src/mapnode.cpp          | 136 ++++++++++++++++++++++++++++----
 src/tile.h               |   4 +-
 5 files changed, 335 insertions(+), 86 deletions(-)

diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index af8b1cc9a..3d47785ba 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -310,6 +310,10 @@ param2 is reserved for the engine when any of these are used:
   paramtype2 == "facedir"
   ^ The rotation of the node is stored in param2. Furnaces and chests are
     rotated this way. Can be made by using minetest.dir_to_facedir().
+    Values range 0 - 23
+    facedir modulo 4 = axisdir
+    0 = y+    1 = z+    2 = z-    3 = x+    4 = x-    5 = y-
+    facedir's two less significant bits are rotation around the axis
 
 Nodes can also contain extra data. See "Node Metadata".
 
diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp
index 0fbdda303..84d5f067c 100644
--- a/src/content_mapblock.cpp
+++ b/src/content_mapblock.cpp
@@ -42,14 +42,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 //              (compatible with ContentFeatures). If you specified 0,0,1,1
 //              for each face, that would be the same as passing NULL.
 void makeCuboid(MeshCollector *collector, const aabb3f &box,
-	const TileSpec *tiles, int tilecount,
+	TileSpec *tiles, int tilecount,
 	video::SColor &c, const f32* txc)
 {
 	assert(tilecount >= 1 && tilecount <= 6);
 
 	v3f min = box.MinEdge;
 	v3f max = box.MaxEdge;
-
+ 
+ 
+ 
 	if(txc == NULL)
 	{
 		static const f32 txc_default[24] = {
@@ -97,15 +99,70 @@ void makeCuboid(MeshCollector *collector, const aabb3f &box,
 		video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c, txc[20],txc[23]),
 	};
 
-	for(s32 j=0; j<24; j++)
+	v2f t;
+	for(int i = 0; i < tilecount; i++)
+				{
+				switch (tiles[i].rotation)
+				{
+				case 0:
+					break;
+				case 1: //R90
+					for (int x = 0; x < 4; x++)
+						vertices[i*4+x].TCoords.rotateBy(90,irr::core::vector2df(0, 0));
+					break;
+				case 2: //R180
+					for (int x = 0; x < 4; x++)
+						vertices[i*4+x].TCoords.rotateBy(180,irr::core::vector2df(0, 0));
+					break;
+				case 3: //R270
+					for (int x = 0; x < 4; x++)
+						vertices[i*4+x].TCoords.rotateBy(270,irr::core::vector2df(0, 0));
+					break;
+				case 4: //FXR90
+					for (int x = 0; x < 4; x++)
+						vertices[i*4+x].TCoords.rotateBy(90,irr::core::vector2df(0, 0));
+
+					tiles[i].texture.pos.Y += tiles[i].texture.size.Y;
+					tiles[i].texture.size.Y *= -1;
+					break;
+				case 5: //FXR270
+					for (int x = 0; x < 4; x++)
+						vertices[i*4+x].TCoords.rotateBy(270,irr::core::vector2df(0, 0));
+					t=vertices[i*4].TCoords;
+					tiles[i].texture.pos.Y += tiles[i].texture.size.Y;
+					tiles[i].texture.size.Y *= -1;
+					break;
+				case 6: //FYR90
+					for (int x = 0; x < 4; x++)
+						vertices[i*4+x].TCoords.rotateBy(90,irr::core::vector2df(0, 0));
+					tiles[i].texture.pos.X += tiles[i].texture.size.X;
+					tiles[i].texture.size.X *= -1;
+					break;
+				case 7: //FYR270
+					for (int x = 0; x < 4; x++)
+						vertices[i*4+x].TCoords.rotateBy(270,irr::core::vector2df(0, 0));
+					tiles[i].texture.pos.X += tiles[i].texture.size.X;
+					tiles[i].texture.size.X *= -1;
+					break;
+				case 8: //FX
+					tiles[i].texture.pos.Y += tiles[i].texture.size.Y;
+					tiles[i].texture.size.Y *= -1;
+					break;
+				case 9: //FY
+					tiles[i].texture.pos.X += tiles[i].texture.size.X;
+					tiles[i].texture.size.X *= -1;
+					break;
+				default:
+					break;
+				}
+			}
+		for(s32 j=0; j<24; j++)
 	{
 		int tileindex = MYMIN(j/4, tilecount-1);
 		vertices[j].TCoords *= tiles[tileindex].texture.size;
 		vertices[j].TCoords += tiles[tileindex].texture.pos;
 	}
-
 	u16 indices[] = {0,1,2,2,3,0};
-
 	// Add to mesh collector
 	for(s32 j=0; j<24; j+=4)
 	{
@@ -1154,14 +1211,8 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 				v3s16(0, 0, 1),
 				v3s16(0, 0, -1)
 			};
-
 			TileSpec tiles[6];
-			for(int i = 0; i < 6; i++)
-			{
-				// Handles facedir rotation for textures
-				tiles[i] = getNodeTile(n, p, tile_dirs[i], data);
-			}
-
+			
 			u16 l = getInteriorLight(n, 0, data);
 			video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source));
 
@@ -1172,17 +1223,43 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 					i = boxes.begin();
 					i != boxes.end(); i++)
 			{
+			for(int j = 0; j < 6; j++)
+				{
+				// Handles facedir rotation for textures
+				tiles[j] = getNodeTile(n, p, tile_dirs[j], data);
+				}
 				aabb3f box = *i;
 				box.MinEdge += pos;
 				box.MaxEdge += pos;
+				
+				f32 temp;
+				if (box.MinEdge.X > box.MaxEdge.X)
+				{
+					temp=box.MinEdge.X;
+					box.MinEdge.X=box.MaxEdge.X;
+					box.MaxEdge.X=temp;
+				}
+				if (box.MinEdge.Y > box.MaxEdge.Y)
+				{
+					temp=box.MinEdge.Y;
+					box.MinEdge.Y=box.MaxEdge.Y;
+					box.MaxEdge.Y=temp;
+				}
+				if (box.MinEdge.Z > box.MaxEdge.Z)
+				{
+					temp=box.MinEdge.Z;
+					box.MinEdge.Z=box.MaxEdge.Z;
+					box.MaxEdge.Z=temp;
+				}
 
+				//
 				// Compute texture coords
-				f32 tx1 = (i->MinEdge.X/BS)+0.5;
-				f32 ty1 = (i->MinEdge.Y/BS)+0.5;
-				f32 tz1 = (i->MinEdge.Z/BS)+0.5;
-				f32 tx2 = (i->MaxEdge.X/BS)+0.5;
-				f32 ty2 = (i->MaxEdge.Y/BS)+0.5;
-				f32 tz2 = (i->MaxEdge.Z/BS)+0.5;
+				f32 tx1 = (box.MinEdge.X/BS)+0.5;
+				f32 ty1 = (box.MinEdge.Y/BS)+0.5;
+				f32 tz1 = (box.MinEdge.Z/BS)+0.5;
+				f32 tx2 = (box.MaxEdge.X/BS)+0.5;
+				f32 ty2 = (box.MaxEdge.Y/BS)+0.5;
+				f32 tz2 = (box.MaxEdge.Z/BS)+0.5;
 				f32 txc[24] = {
 					// up
 					tx1, 1-tz2, tx2, 1-tz1,
@@ -1197,7 +1274,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 					// front
 					tx1, 1-ty2, tx2, 1-ty1,
 				};
-
 				makeCuboid(&collector, box, tiles, 6, c, txc);
 			}
 		break;}
diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp
index d098065f8..f68a79e41 100644
--- a/src/mapblock_mesh.cpp
+++ b/src/mapblock_mesh.cpp
@@ -455,6 +455,80 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
 	v3f vertex_pos[4];
 	v3s16 vertex_dirs[4];
 	getNodeVertexDirs(dir, vertex_dirs);
+	v3s16 t;
+	switch (tile.rotation)
+	{
+	case 0:
+		break;
+	case 1: //R90
+		t = vertex_dirs[0];
+		vertex_dirs[0] = vertex_dirs[3];
+		vertex_dirs[3] = vertex_dirs[2];
+		vertex_dirs[2] = vertex_dirs[1];
+		vertex_dirs[1] = t;
+		break;
+	case 2: //R180
+		t = vertex_dirs[0];
+		vertex_dirs[0] = vertex_dirs[2];
+		vertex_dirs[2] = t;
+		t = vertex_dirs[1];
+		vertex_dirs[1] = vertex_dirs[3];
+		vertex_dirs[3] = t;
+		break;
+	case 3: //R270
+		t = vertex_dirs[0];
+		vertex_dirs[0] = vertex_dirs[1];
+		vertex_dirs[1] = vertex_dirs[2];
+		vertex_dirs[2] = vertex_dirs[3];
+		vertex_dirs[3] = t;
+		break;
+	case 4: //FXR90
+		t = vertex_dirs[0];
+		vertex_dirs[0] = vertex_dirs[3];
+		vertex_dirs[3] = vertex_dirs[2];
+		vertex_dirs[2] = vertex_dirs[1];
+		vertex_dirs[1] = t;
+		tile.texture.pos.Y += tile.texture.size.Y;
+		tile.texture.size.Y *= -1;
+		break;
+	case 5: //FXR270
+		t = vertex_dirs[0];
+		vertex_dirs[0] = vertex_dirs[1];
+		vertex_dirs[1] = vertex_dirs[2];
+		vertex_dirs[2] = vertex_dirs[3];
+		vertex_dirs[3] = t;
+		tile.texture.pos.Y += tile.texture.size.Y;
+		tile.texture.size.Y *= -1;
+		break;
+	case 6: //FYR90
+		t = vertex_dirs[0];
+		vertex_dirs[0] = vertex_dirs[3];
+		vertex_dirs[3] = vertex_dirs[2];
+		vertex_dirs[2] = vertex_dirs[1];
+		vertex_dirs[1] = t;
+		tile.texture.pos.X += tile.texture.size.X;
+		tile.texture.size.X *= -1;
+		break;
+	case 7: //FYR270
+		t = vertex_dirs[0];
+		vertex_dirs[0] = vertex_dirs[1];
+		vertex_dirs[1] = vertex_dirs[2];
+		vertex_dirs[2] = vertex_dirs[3];
+		vertex_dirs[3] = t;
+		tile.texture.pos.X += tile.texture.size.X;
+		tile.texture.size.X *= -1;
+		break;
+	case 8: //FX
+		tile.texture.pos.Y += tile.texture.size.Y;
+		tile.texture.size.Y *= -1;
+		break;
+	case 9: //FY
+		tile.texture.pos.X += tile.texture.size.X;
+		tile.texture.size.X *= -1;
+		break;
+	default:
+		break;
+	}
 	for(u16 i=0; i<4; i++)
 	{
 		vertex_pos[i] = v3f(
@@ -601,60 +675,50 @@ TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data)
 	//  5 = (0,0,-1)
 	//  6 = (0,-1,0)
 	//  7 = (-1,0,0)
-	u8 dir_i = (dir.X + 2 * dir.Y + 3 * dir.Z) & 7;
+	u8 dir_i = ((dir.X + 2 * dir.Y + 3 * dir.Z) & 7)*2;
 
 	// Get rotation for things like chests
 	u8 facedir = mn.getFaceDir(ndef);
-	assert(facedir <= 3);
-	
-	static const u8 dir_to_tile[4 * 8] =
+	assert(facedir <= 23);
+	static const u16 dir_to_tile[24 * 16] =
 	{
-		// 0  +X  +Y  +Z   0  -Z  -Y  -X
-		   0,  2,  0,  4,  0,  5,  1,  3,  // facedir = 0
-		   0,  4,  0,  3,  0,  2,  1,  5,  // facedir = 1
-		   0,  3,  0,  5,  0,  4,  1,  2,  // facedir = 2
-		   0,  5,  0,  2,  0,  3,  1,  4,  // facedir = 3
+		// 0     +X    +Y    +Z           -Z    -Y    -X   ->   value=tile,rotation  
+		   0,0,  2,0 , 0,0 , 4,0 ,  0,0,  5,0 , 1,0 , 3,0 ,  // rotate around y+ 0 - 3
+		   0,0,  4,0 , 0,3 , 3,0 ,  0,0,  2,0 , 1,1 , 5,0 ,
+		   0,0,  3,0 , 0,2 , 5,0 ,  0,0,  4,0 , 1,2 , 2,0 ,
+		   0,0,  5,0 , 0,1 , 2,0 ,  0,0,  3,0 , 1,3 , 4,0 ,
+
+		   0,0,  2,3 , 5,0 , 0,2 ,  0,0,  1,0 , 4,2 , 3,1 ,  // rotate around z+ 4 - 7
+		   0,0,  4,3 , 2,0 , 0,3 ,  0,0,  1,1 , 3,2 , 5,1 ,
+		   0,0,  3,3 , 4,0 , 0,0 ,  0,0,  1,2 , 5,2 , 2,1 ,
+		   0,0,  5,3 , 3,0 , 0,1 ,  0,0,  1,3 , 2,2 , 4,1 ,
+
+		   0,0,  2,1 , 4,2 , 1,2 ,  0,0,  0,0 , 5,0 , 3,3 ,  // rotate around z- 8 - 11
+		   0,0,  4,1 , 3,2 , 1,3 ,  0,0,  0,3 , 2,0 , 5,3 ,
+		   0,0,  3,1 , 5,2 , 1,0 ,  0,0,  0,2 , 4,0 , 2,3 ,
+		   0,0,  5,1 , 2,2 , 1,1 ,  0,0,  0,1 , 3,0 , 4,3 ,
+
+		   0,0,  0,3 , 3,3 , 4,1 ,  0,0,  5,3 , 2,3 , 1,3 ,  // rotate around x+ 12 - 15
+		   0,0,  0,2 , 5,3 , 3,1 ,  0,0,  2,3 , 4,3 , 1,0 ,
+		   0,0,  0,1 , 2,3 , 5,1 ,  0,0,  4,3 , 3,3 , 1,1 ,
+		   0,0,  0,0 , 4,3 , 2,1 ,  0,0,  3,3 , 5,3 , 1,2 ,
+		   
+		   0,0,  1,1 , 2,1 , 4,3 ,  0,0,  5,1 , 3,1 , 0,1 ,  // rotate around x- 16 - 19  
+		   0,0,  1,2 , 4,1 , 3,3 ,  0,0,  2,1 , 5,1 , 0,0 ,
+		   0,0,  1,3 , 3,1 , 5,3 ,  0,0,  4,1 , 2,1 , 0,3 ,  
+		   0,0,  1,0 , 5,1 , 2,3 ,  0,0,  3,1 , 4,1 , 0,2 ,  
+		
+		   0,0,  3,2 , 1,2 , 4,2 ,  0,0,  5,2 , 0,2 , 2,2 ,  // rotate around y- 20 - 23
+		   0,0,  5,2 , 1,3 , 3,2 ,  0,0,  2,2 , 0,1 , 4,2 ,  
+		   0,0,  2,2 , 1,0 , 5,2 ,  0,0,  4,2 , 0,0 , 3,2 ,  
+		   0,0,  4,2 , 1,1 , 2,2 ,  0,0,  3,2 , 0,3 , 5,2   
+		   
 	};
-	u8 tileindex = dir_to_tile[facedir*8 + dir_i];
-
-	// If not rotated or is side tile, we're done
-	if(facedir == 0 || (tileindex != 0 && tileindex != 1))
-		return getNodeTileN(mn, p, tileindex, data);
-
-	// This is the top or bottom tile, and it shall be rotated; thus rotate it
-	TileSpec spec = getNodeTileN(mn, p, tileindex, data);
-	if(tileindex == 0){
-		if(facedir == 1){ // -90
-			std::string name = data->m_gamedef->tsrc()->getTextureName(spec.texture.id);
-			name += "^[transformR270";
-			spec.texture = data->m_gamedef->tsrc()->getTexture(name);
-		}
-		else if(facedir == 2){ // 180
-			spec.texture.pos += spec.texture.size;
-			spec.texture.size *= -1;
-		}
-		else if(facedir == 3){ // 90
-			std::string name = data->m_gamedef->tsrc()->getTextureName(spec.texture.id);
-			name += "^[transformR90";
-			spec.texture = data->m_gamedef->tsrc()->getTexture(name);
-		}
-	}
-	else if(tileindex == 1){
-		if(facedir == 1){ // -90
-			std::string name = data->m_gamedef->tsrc()->getTextureName(spec.texture.id);
-			name += "^[transformR90";
-			spec.texture = data->m_gamedef->tsrc()->getTexture(name);
-		}
-		else if(facedir == 2){ // 180
-			spec.texture.pos += spec.texture.size;
-			spec.texture.size *= -1;
-		}
-		else if(facedir == 3){ // 90
-			std::string name = data->m_gamedef->tsrc()->getTextureName(spec.texture.id);
-			name += "^[transformR270";
-			spec.texture = data->m_gamedef->tsrc()->getTexture(name);
-		}
-	}
+	u16 tile_index=facedir*16 + dir_i;
+	TileSpec spec = getNodeTileN(mn, p, dir_to_tile[tile_index], data);
+	spec.rotation=dir_to_tile[tile_index + 1];
+	std::string name = data->m_gamedef->tsrc()->getTextureName(spec.texture.id);
+	spec.texture = data->m_gamedef->tsrc()->getTexture(name);
 	return spec;
 }
 
@@ -794,6 +858,7 @@ static void updateFastFaceRow(
 					&& next_lights[2] == lights[2]
 					&& next_lights[3] == lights[3]
 					&& next_tile == tile
+					&& tile.rotation == 0
 					&& next_light_source == light_source)
 			{
 				next_is_different = false;
diff --git a/src/mapnode.cpp b/src/mapnode.cpp
index 0513e688c..bba845fcc 100644
--- a/src/mapnode.cpp
+++ b/src/mapnode.cpp
@@ -107,7 +107,7 @@ u8 MapNode::getFaceDir(INodeDefManager *nodemgr) const
 {
 	const ContentFeatures &f = nodemgr->get(*this);
 	if(f.param_type_2 == CPT2_FACEDIR)
-		return getParam2() & 0x03;
+		return getParam2() & 0x1F;
 	return 0;
 }
 
@@ -140,29 +140,131 @@ static std::vector<aabb3f> transformNodeBox(const MapNode &n,
 	{
 		const std::vector<aabb3f> &fixed = nodebox.fixed;
 		int facedir = n.getFaceDir(nodemgr);
+		u8 axisdir = facedir>>2;
+		facedir&=0x03;
 		for(std::vector<aabb3f>::const_iterator
 				i = fixed.begin();
 				i != fixed.end(); i++)
 		{
 			aabb3f box = *i;
-			if(facedir == 1)
+			switch (axisdir)
 			{
-				box.MinEdge.rotateXZBy(-90);
-				box.MaxEdge.rotateXZBy(-90);
-				box.repair();
-			}
-			else if(facedir == 2)
-			{
-				box.MinEdge.rotateXZBy(180);
-				box.MaxEdge.rotateXZBy(180);
-				box.repair();
-			}
-			else if(facedir == 3)
-			{
-				box.MinEdge.rotateXZBy(90);
-				box.MaxEdge.rotateXZBy(90);
-				box.repair();
+			case 0:
+				if(facedir == 1)
+				{
+					box.MinEdge.rotateXZBy(-90);
+					box.MaxEdge.rotateXZBy(-90);
+				}
+				else if(facedir == 2)
+				{
+					box.MinEdge.rotateXZBy(180);
+					box.MaxEdge.rotateXZBy(180);
+				}
+				else if(facedir == 3)
+				{
+					box.MinEdge.rotateXZBy(90);
+					box.MaxEdge.rotateXZBy(90);
+				}
+				break;
+			case 1: // z+
+				box.MinEdge.rotateYZBy(90);
+				box.MaxEdge.rotateYZBy(90);
+				if(facedir == 1)
+				{
+					box.MinEdge.rotateXYBy(90);
+					box.MaxEdge.rotateXYBy(90);
+				}
+				else if(facedir == 2)
+				{
+					box.MinEdge.rotateXYBy(180);
+					box.MaxEdge.rotateXYBy(180);
+				}
+				else if(facedir == 3)
+				{
+					box.MinEdge.rotateXYBy(-90);
+					box.MaxEdge.rotateXYBy(-90);
+				}
+				break;
+			case 2: //z-
+				box.MinEdge.rotateYZBy(-90);
+				box.MaxEdge.rotateYZBy(-90);
+				if(facedir == 1)
+				{
+					box.MinEdge.rotateXYBy(-90);
+					box.MaxEdge.rotateXYBy(-90);
+				}
+				else if(facedir == 2)
+				{
+					box.MinEdge.rotateXYBy(180);
+					box.MaxEdge.rotateXYBy(180);
+				}
+				else if(facedir == 3)
+				{
+					box.MinEdge.rotateXYBy(90);
+					box.MaxEdge.rotateXYBy(90);
+				}
+				break;
+			case 3:  //x+
+				box.MinEdge.rotateXYBy(-90);
+				box.MaxEdge.rotateXYBy(-90);
+				if(facedir == 1)
+				{
+					box.MinEdge.rotateYZBy(90);
+					box.MaxEdge.rotateYZBy(90);
+				}
+				else if(facedir == 2)
+				{
+					box.MinEdge.rotateYZBy(180);
+					box.MaxEdge.rotateYZBy(180);
+				}
+				else if(facedir == 3)
+				{
+					box.MinEdge.rotateYZBy(-90);
+					box.MaxEdge.rotateYZBy(-90);
+				}
+				break;
+			case 4:  //x-
+				box.MinEdge.rotateXYBy(90);
+				box.MaxEdge.rotateXYBy(90);
+				if(facedir == 1)
+				{
+					box.MinEdge.rotateYZBy(-90);
+					box.MaxEdge.rotateYZBy(-90);
+				}
+				else if(facedir == 2)
+				{
+					box.MinEdge.rotateYZBy(180);
+					box.MaxEdge.rotateYZBy(180);
+				}
+				else if(facedir == 3)
+				{
+					box.MinEdge.rotateYZBy(90);
+					box.MaxEdge.rotateYZBy(90);
+				}
+				break;
+			case 5:
+				box.MinEdge.rotateXYBy(-180);
+				box.MaxEdge.rotateXYBy(-180);
+				if(facedir == 1)
+				{
+					box.MinEdge.rotateXZBy(90);
+					box.MaxEdge.rotateXZBy(90);
+				}
+				else if(facedir == 2)
+				{
+					box.MinEdge.rotateXZBy(180);
+					box.MaxEdge.rotateXZBy(180);
+				}
+				else if(facedir == 3)
+				{
+					box.MinEdge.rotateXZBy(-90);
+					box.MaxEdge.rotateXZBy(-90);
+				}
+				break;
+			default:
+				break;
 			}
+			box.repair();
 			boxes.push_back(box);
 		}
 	}
diff --git a/src/tile.h b/src/tile.h
index 07e5bcb56..c5c7f9303 100644
--- a/src/tile.h
+++ b/src/tile.h
@@ -205,7 +205,8 @@ struct TileSpec
 			texture == other.texture &&
 			alpha == other.alpha &&
 			material_type == other.material_type &&
-			material_flags == other.material_flags
+			material_flags == other.material_flags &&
+			rotation == other.rotation
 		);
 	}
 
@@ -264,6 +265,7 @@ struct TileSpec
 	// Animation parameters
 	u8 animation_frame_count;
 	u16 animation_frame_length_ms;
+	u8 rotation;
 };
 
 #endif
-- 
GitLab