From dd4c21c1808acedfbcf8402c09ce9129b6ac31c7 Mon Sep 17 00:00:00 2001
From: RealBadAngel <maciej.kasatkin@o2.pl>
Date: Tue, 28 Oct 2014 08:02:28 +0100
Subject: [PATCH] Add option to enable mesh caching, add wallmounted for
 meshes.

---
 minetest.conf.example    |  2 ++
 src/content_mapblock.cpp | 36 ++++++++++++++++++++++++++++++++++--
 src/defaultsettings.cpp  |  1 +
 src/itemdef.cpp          |  5 ++++-
 src/nodedef.cpp          | 30 ++++++++++++++++++++----------
 5 files changed, 61 insertions(+), 13 deletions(-)

diff --git a/minetest.conf.example b/minetest.conf.example
index 2ceb0a142..af85d26a2 100644
--- a/minetest.conf.example
+++ b/minetest.conf.example
@@ -201,6 +201,8 @@
 #enable_waving_leaves = false
 # Set to true enables waving plants. Requires shaders enabled.
 #enable_waving_plants = false
+# Enables caching of facedir rotated meshes
+#enable_mesh_cache = true
 # The time in seconds it takes between repeated
 # right clicks when holding the right mouse button
 #repeat_rightclick_time = 0.25
diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp
index ef1f1d858..9f0d8aa5f 100644
--- a/src/content_mapblock.cpp
+++ b/src/content_mapblock.cpp
@@ -25,6 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "settings.h"
 #include "nodedef.h"
 #include "tile.h"
+#include "mesh.h"
+#include <IMeshManipulator.h>
 #include "gamedef.h"
 #include "log.h"
 
@@ -171,6 +173,8 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 {
 	INodeDefManager *nodedef = data->m_gamedef->ndef();
 	ITextureSource *tsrc = data->m_gamedef->tsrc();
+	scene::ISceneManager* smgr = data->m_gamedef->getSceneManager();
+	scene::IMeshManipulator* meshmanip = smgr->getMeshManipulator();
 
 	// 0ms
 	//TimeTaker timer("mapblock_mesh_generate_special()");
@@ -178,6 +182,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 	/*
 		Some settings
 	*/
+	bool enable_mesh_cache	= g_settings->getBool("enable_mesh_cache");
 	bool new_style_water = g_settings->getBool("new_style_water");
 
 	float node_liquid_level = 1.0;
@@ -1719,14 +1724,41 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 		{
 			v3f pos = intToFloat(p, BS);
 			video::SColor c = MapBlock_LightColor(255, getInteriorLight(n, 1, nodedef), f.light_source);
-			u8 facedir = n.getFaceDir(nodedef);
+
+			u8 facedir = 0;
+			if (f.param_type_2 == CPT2_FACEDIR) {
+				facedir = n.getFaceDir(nodedef);
+			} else if (f.param_type_2 == CPT2_WALLMOUNTED) {
+				//convert wallmounted to 6dfacedir.
+				//when cache enabled, it is already converted
+				facedir = n.getWallMounted(nodedef);				
+				if (!enable_mesh_cache) {
+					static const u8 wm_to_6d[6] = 	{20, 0, 16, 12, 8, 4};
+					facedir = wm_to_6d[facedir];
+				}
+			}
+
 			if (f.mesh_ptr[facedir]) {
-				for(u16 j = 0; j < f.mesh_ptr[facedir]->getMeshBufferCount(); j++) {
+				// use cached meshes
+				for(u16 j = 0; j < f.mesh_ptr[0]->getMeshBufferCount(); j++) {
 					scene::IMeshBuffer *buf = f.mesh_ptr[facedir]->getMeshBuffer(j);
 					collector.append(getNodeTileN(n, p, j, data),
 						(video::S3DVertex *)buf->getVertices(), buf->getVertexCount(),
 						buf->getIndices(), buf->getIndexCount(), pos, c);
 				}
+			} else if (f.mesh_ptr[0]) {
+				// no cache, clone and rotate mesh
+				scene::IMesh* mesh = cloneMesh(f.mesh_ptr[0]);
+				rotateMeshBy6dFacedir(mesh, facedir);
+				recalculateBoundingBox(mesh);
+				meshmanip->recalculateNormals(mesh, true, false);
+				for(u16 j = 0; j < mesh->getMeshBufferCount(); j++) {
+					scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
+					collector.append(getNodeTileN(n, p, j, data),
+						(video::S3DVertex *)buf->getVertices(), buf->getVertexCount(),
+						buf->getIndices(), buf->getIndexCount(), pos, c);
+				}
+				mesh->drop();
 			}
 		break;}
 		}
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index 2d6851c2c..e3d2dc7b7 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -153,6 +153,7 @@ void set_default_settings(Settings *settings)
 	settings->setDefault("enable_shaders", "true");
 	settings->setDefault("repeat_rightclick_time", "0.25");
 	settings->setDefault("enable_particles", "true");
+	settings->setDefault("enable_mesh_cache", "true");
 
 	settings->setDefault("curl_timeout", "5000");
 	settings->setDefault("curl_parallel_limit", "8");
diff --git a/src/itemdef.cpp b/src/itemdef.cpp
index 10e1afe2d..f976c3eb7 100644
--- a/src/itemdef.cpp
+++ b/src/itemdef.cpp
@@ -400,7 +400,10 @@ class CItemDefManager: public IWritableItemDefManager
 				g_settings->setBool("enable_shaders",false);
 			}
 			MeshMakeData mesh_make_data(gamedef);
-			MapNode mesh_make_node(id, param1, 0);
+			u8 param2 = 0;
+			if (f.param_type_2 == CPT2_WALLMOUNTED)
+				param2 = 1;
+			MapNode mesh_make_node(id, param1, param2);
 			mesh_make_data.fillSingleNode(&mesh_make_node);
 			MapBlockMesh mapblock_mesh(&mesh_make_data, v3s16(0, 0, 0));
 			scene::IMesh *node_mesh = mapblock_mesh.getMesh();
diff --git a/src/nodedef.cpp b/src/nodedef.cpp
index 820f4eb30..7dbaaee9c 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -714,6 +714,7 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef)
 	bool enable_shaders            = g_settings->getBool("enable_shaders");
 	bool enable_bumpmapping        = g_settings->getBool("enable_bumpmapping");
 	bool enable_parallax_occlusion = g_settings->getBool("enable_parallax_occlusion");
+	bool enable_mesh_cache         = g_settings->getBool("enable_mesh_cache");
 
 	bool use_normal_texture = enable_shaders &&
 		(enable_bumpmapping || enable_parallax_occlusion);
@@ -847,23 +848,21 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef)
 				f->tiledef_special[j].backface_culling, f->alpha, material_type);
 		}
 
-		// Meshnode drawtype
-		// Read the mesh and apply scale
 		if ((f->drawtype == NDT_MESH) && (f->mesh != "")) {
+			// Meshnode drawtype
+			// Read the mesh and apply scale
 			f->mesh_ptr[0] = gamedef->getMesh(f->mesh);
 			if (f->mesh_ptr[0]){
 				v3f scale = v3f(1.0, 1.0, 1.0) * BS * f->visual_scale;
 				scaleMesh(f->mesh_ptr[0], scale);
 				recalculateBoundingBox(f->mesh_ptr[0]);
 			}
-		}
-
-		//Convert regular nodebox nodes to meshnodes
-		//Change the drawtype and apply scale
-		else if ((f->drawtype == NDT_NODEBOX) && 
+		} else if ((f->drawtype == NDT_NODEBOX) && 
 				((f->node_box.type == NODEBOX_REGULAR) ||
 				(f->node_box.type == NODEBOX_FIXED)) &&
 				(!f->node_box.fixed.empty())) {
+			//Convert regular nodebox nodes to meshnodes
+			//Change the drawtype and apply scale
 			f->drawtype = NDT_MESH;
 			f->mesh_ptr[0] = convertNodeboxNodeToMesh(f);
 			v3f scale = v3f(1.0, 1.0, 1.0) * f->visual_scale;
@@ -871,14 +870,25 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef)
 			recalculateBoundingBox(f->mesh_ptr[0]);
 		}
 
-		//Cache 6dfacedir rotated clones of meshes
-		if (f->mesh_ptr[0] && (f->param_type_2 == CPT2_FACEDIR)) {
+		//Cache 6dfacedir and wallmounted rotated clones of meshes
+		if (enable_mesh_cache && f->mesh_ptr[0] && (f->param_type_2 == CPT2_FACEDIR)) {
 			for (u16 j = 1; j < 24; j++) {
 				f->mesh_ptr[j] = cloneMesh(f->mesh_ptr[0]);
 				rotateMeshBy6dFacedir(f->mesh_ptr[j], j);
 				recalculateBoundingBox(f->mesh_ptr[j]);
-				meshmanip->recalculateNormals(f->mesh_ptr[j], false, false);
+				meshmanip->recalculateNormals(f->mesh_ptr[j], true, false);
+			}
+		} else if (enable_mesh_cache && f->mesh_ptr[0] && (f->param_type_2 == CPT2_WALLMOUNTED)) {
+			static const u8 wm_to_6d[6] = 	{20, 0, 16, 12, 8, 4}; 
+			for (u16 j = 1; j < 6; j++) {
+				f->mesh_ptr[j] = cloneMesh(f->mesh_ptr[0]);
+				rotateMeshBy6dFacedir(f->mesh_ptr[j], wm_to_6d[j]);
+				recalculateBoundingBox(f->mesh_ptr[j]);
+				meshmanip->recalculateNormals(f->mesh_ptr[j], true, false);
 			}
+			rotateMeshBy6dFacedir(f->mesh_ptr[0], wm_to_6d[0]);
+			recalculateBoundingBox(f->mesh_ptr[0]);
+			meshmanip->recalculateNormals(f->mesh_ptr[0], true, false);			
 		}
 	}
 #endif
-- 
GitLab