From f0db6c4423db86203db83538704cc34152c59a09 Mon Sep 17 00:00:00 2001
From: RealBadAngel <maciej.kasatkin@o2.pl>
Date: Tue, 15 Jul 2014 09:07:52 +0200
Subject: [PATCH] Speedup mapblock_mesh

---
 src/mapblock_mesh.cpp | 106 ++++++++++++------------------------------
 src/nodedef.cpp       |  65 ++++++++++++++++----------
 src/tile.cpp          |  22 +++++++++
 src/tile.h            |  21 +++++++++
 4 files changed, 114 insertions(+), 100 deletions(-)

diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp
index 080131a6f..b29d07319 100644
--- a/src/mapblock_mesh.cpp
+++ b/src/mapblock_mesh.cpp
@@ -32,14 +32,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "settings.h"
 #include "util/directiontables.h"
 
-void applyContrast(video::SColor& color, float Factor)
+static void applyContrast(video::SColor& color, float factor)
 {
-	float r = color.getRed();
-	float g = color.getGreen();
-	float b = color.getBlue();
-	color.setRed(irr::core::clamp((int)sqrt(r * r * Factor), 0, 255));
-	color.setGreen(irr::core::clamp((int)sqrt(g * g * Factor), 0, 255));
-	color.setBlue(irr::core::clamp((int)sqrt(b * b * Factor), 0, 255));
+	color.setRed(core::clamp(core::round32(color.getRed()*factor), 0, 255));
+	color.setGreen(core::clamp(core::round32(color.getGreen()*factor), 0, 255));
+	color.setBlue(core::clamp(core::round32(color.getBlue()*factor), 0, 255));
 }
 
 /*
@@ -1099,8 +1096,6 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
 	IShaderSource *shdrsrc = m_gamedef->getShaderSource();
 
 	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");
 
 	for(u32 i = 0; i < collector.prebuffers.size(); i++)
 	{
@@ -1141,33 +1136,31 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
 				m_animation_frame_offsets[i] = 0;
 			}
 			// Replace tile texture with the first animation frame
-			std::ostringstream os(std::ios::binary);
-			os<<tsrc->getTextureName(p.tile.texture_id);
-			os<<"^[verticalframe:"<<(int)p.tile.animation_frame_count<<":0";
-			p.tile.texture = tsrc->getTexture(
-					os.str(),
-					&p.tile.texture_id);
+			FrameSpec animation_frame = p.tile.frames.find(0)->second;
+			p.tile.texture = animation_frame.texture;
 		}
 
 		for(u32 j = 0; j < p.vertices.size(); j++)
 		{
+			// Note applyContrast second parameter is precalculated sqrt from original
+			// values for speed improvement
 			video::SColor &vc = p.vertices[j].Color;
 			if(p.vertices[j].Normal.Y > 0.5) {
-				applyContrast (vc, 1.2);
+				applyContrast (vc, 1.095445);
 			} else if (p.vertices[j].Normal.Y < -0.5) {
-				applyContrast (vc, 0.3);
+				applyContrast (vc, 0.547723);
 			} else if (p.vertices[j].Normal.X > 0.5) {
-				applyContrast (vc, 0.5);
+				applyContrast (vc, 0.707107);
 			} else if (p.vertices[j].Normal.X < -0.5) {
-				applyContrast (vc, 0.5);
+				applyContrast (vc, 0.707107);
 			} else if (p.vertices[j].Normal.Z > 0.5) {
-				applyContrast (vc, 0.8);			
+				applyContrast (vc, 0.894427);
 			} else if (p.vertices[j].Normal.Z < -0.5) {
-				applyContrast (vc, 0.8);	
+				applyContrast (vc, 0.894427);
 			}
 			if(!enable_shaders)
 			{
-				// - Classic lighting (shaders handle this by themselves)		
+				// - Classic lighting (shaders handle this by themselves)
 				// Set initial real color and store for later updates
 				u8 day = vc.getRed();
 				u8 night = vc.getGreen();
@@ -1191,34 +1184,17 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
 		if (enable_shaders) {
 			material.MaterialType = shdrsrc->getShaderInfo(p.tile.shader_id).material;
 			p.tile.applyMaterialOptionsWithShaders(material);
-			material.setTexture(2, tsrc->getTexture("disable_img.png"));
-			if (enable_bumpmapping || enable_parallax_occlusion) {
-				if (tsrc->isKnownSourceImage("override_normal.png")){
-					material.setTexture(1, tsrc->getTexture("override_normal.png"));
-					material.setTexture(2, tsrc->getTexture("enable_img.png"));
-				} else {
-					std::string fname_base = tsrc->getTextureName(p.tile.texture_id);
-					std::string normal_ext = "_normal.png";
-					size_t pos = fname_base.find(".");
-					std::string fname_normal = fname_base.substr(0, pos) + normal_ext;
-
-					if (tsrc->isKnownSourceImage(fname_normal)) {
-						// look for image extension and replace it
-						size_t i = 0;
-						while ((i = fname_base.find(".", i)) != std::string::npos) {
-							fname_base.replace(i, 4, normal_ext);
-							i += normal_ext.length();
-						}
-						material.setTexture(1, tsrc->getTexture(fname_base));
-						material.setTexture(2, tsrc->getTexture("enable_img.png"));
-					}
-				}
+			if (p.tile.normal_texture) {
+				material.setTexture(1, p.tile.normal_texture);
+				material.setTexture(2, tsrc->getTexture("enable_img.png"));
+			} else {
+				material.setTexture(2, tsrc->getTexture("disable_img.png"));
 			}
 		} else {
 			p.tile.applyMaterialOptions(material);
 		}
-		// Create meshbuffer
 
+		// Create meshbuffer
 		// This is a "Standard MeshBuffer",
 		// it's a typedeffed CMeshBuffer<video::S3DVertex>
 		scene::SMeshBuffer *buf = new scene::SMeshBuffer();
@@ -1278,8 +1254,6 @@ MapBlockMesh::~MapBlockMesh()
 bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_ratio)
 {
 	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");
 
 	if(!m_has_animation)
 	{
@@ -1342,35 +1316,15 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat
 
 		scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
 		ITextureSource *tsrc = m_gamedef->getTextureSource();
-		IShaderSource *shdrsrc = m_gamedef->getShaderSource();
-
-		// Create new texture name from original
-		std::ostringstream os(std::ios::binary);
-		os<<tsrc->getTextureName(tile.texture_id);
-		os<<"^[verticalframe:"<<(int)tile.animation_frame_count<<":"<<frame;
-		// Set the texture
-		buf->getMaterial().setTexture(0, tsrc->getTexture(os.str()));
-		if (enable_shaders){
-			buf->getMaterial().setTexture(2, tsrc->getTexture("disable_img.png"));
-			buf->getMaterial().MaterialType = shdrsrc->getShaderInfo(tile.shader_id).material;
-			if (enable_bumpmapping || enable_parallax_occlusion){
-				if (tsrc->isKnownSourceImage("override_normal.png")){
-					buf->getMaterial().setTexture(1, tsrc->getTexture("override_normal.png"));
-					buf->getMaterial().setTexture(2, tsrc->getTexture("enable_img.png"));
-				} else {
-					std::string fname_base,fname_normal;
-					fname_base = tsrc->getTextureName(tile.texture_id);
-					unsigned pos;
-					pos = fname_base.find(".");
-					fname_normal = fname_base.substr (0, pos);
-					fname_normal += "_normal.png";
-					if (tsrc->isKnownSourceImage(fname_normal)){
-						os.str("");
-						os<<fname_normal<<"^[verticalframe:"<<(int)tile.animation_frame_count<<":"<<frame;
-						buf->getMaterial().setTexture(1, tsrc->getTexture(os.str()));
-						buf->getMaterial().setTexture(2, tsrc->getTexture("enable_img.png"));
-					}
-				}
+
+		FrameSpec animation_frame = tile.frames.find(frame)->second;
+		buf->getMaterial().setTexture(0, animation_frame.texture);
+		if (enable_shaders) {
+			if (animation_frame.normal_texture) {
+				buf->getMaterial().setTexture(1, animation_frame.normal_texture);
+				buf->getMaterial().setTexture(2, tsrc->getTexture("enable_img.png"));
+			} else {
+				buf->getMaterial().setTexture(2, tsrc->getTexture("disable_img.png"));
 			}
 		}
 	}
diff --git a/src/nodedef.cpp b/src/nodedef.cpp
index f62c9e82c..e972ab927 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -607,6 +607,9 @@ class CNodeDefManager: public IWritableNodeDefManager
 		bool new_style_water = g_settings->getBool("new_style_water");
 		bool new_style_leaves = g_settings->getBool("new_style_leaves");
 		bool opaque_water = g_settings->getBool("opaque_water");
+		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");
 
 		for(u32 i=0; i<m_content_features.size(); i++)
 		{
@@ -716,6 +719,9 @@ class CNodeDefManager: public IWritableNodeDefManager
 				f->tiles[j].texture = tsrc->getTexture(
 						tiledef[j].name,
 						&f->tiles[j].texture_id);
+				// Normal texture
+				if (enable_shaders && (enable_bumpmapping || enable_parallax_occlusion))
+					f->tiles[j].normal_texture = tsrc->getNormalTexture(tiledef[j].name);
 				// Alpha
 				f->tiles[j].alpha = f->alpha;
 				// Material type
@@ -727,28 +733,32 @@ class CNodeDefManager: public IWritableNodeDefManager
 				if(tiledef[j].animation.type == TAT_VERTICAL_FRAMES)
 					f->tiles[j].material_flags |= MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
 				// Animation parameters
-				if(f->tiles[j].material_flags &
-						MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
-				{
+				int frame_count = 1;
+				if(f->tiles[j].material_flags &	MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES) {
 					// Get texture size to determine frame count by
 					// aspect ratio
 					v2u32 size = f->tiles[j].texture->getOriginalSize();
 					int frame_height = (float)size.X /
 							(float)tiledef[j].animation.aspect_w *
 							(float)tiledef[j].animation.aspect_h;
-					int frame_count = size.Y / frame_height;
+					frame_count = size.Y / frame_height;
 					int frame_length_ms = 1000.0 *
 							tiledef[j].animation.length / frame_count;
 					f->tiles[j].animation_frame_count = frame_count;
 					f->tiles[j].animation_frame_length_ms = frame_length_ms;
-
-					// If there are no frames for an animation, switch
-					// animation off (so that having specified an animation
-					// for something but not using it in the texture pack
-					// gives no overhead)
-					if(frame_count == 1){
-						f->tiles[j].material_flags &=
-								~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
+				}
+				if(frame_count == 1) {
+					f->tiles[j].material_flags &= ~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
+				} else {
+					std::ostringstream os(std::ios::binary);
+					for (int i = 0; i < frame_count; i++) {
+						FrameSpec frame;
+						os.str("");
+						os<<tiledef[j].name<<"^[verticalframe:"<<frame_count<<":"<<i;
+						frame.texture = tsrc->getTexture(os.str(), &frame.texture_id);
+						if (f->tiles[j].normal_texture)
+							frame.normal_texture = tsrc->getNormalTexture(os.str());
+						f->tiles[j].frames[i]=frame;
 					}
 				}
 			}
@@ -760,6 +770,9 @@ class CNodeDefManager: public IWritableNodeDefManager
 				f->special_tiles[j].texture = tsrc->getTexture(
 						f->tiledef_special[j].name,
 						&f->special_tiles[j].texture_id);
+				// Normal texture
+				if (enable_shaders && (enable_bumpmapping || enable_parallax_occlusion))
+					f->special_tiles[j].normal_texture = tsrc->getNormalTexture(f->tiledef_special[j].name);
 				// Alpha
 				f->special_tiles[j].alpha = f->alpha;
 				// Material type
@@ -771,28 +784,32 @@ class CNodeDefManager: public IWritableNodeDefManager
 				if(f->tiledef_special[j].animation.type == TAT_VERTICAL_FRAMES)
 					f->special_tiles[j].material_flags |= MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
 				// Animation parameters
-				if(f->special_tiles[j].material_flags &
-						MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
-				{
+				int frame_count = 1;
+				if(f->special_tiles[j].material_flags &	MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES) {
 					// Get texture size to determine frame count by
 					// aspect ratio
 					v2u32 size = f->special_tiles[j].texture->getOriginalSize();
 					int frame_height = (float)size.X /
 							(float)f->tiledef_special[j].animation.aspect_w *
 							(float)f->tiledef_special[j].animation.aspect_h;
-					int frame_count = size.Y / frame_height;
+					frame_count = size.Y / frame_height;
 					int frame_length_ms = 1000.0 *
 							f->tiledef_special[j].animation.length / frame_count;
 					f->special_tiles[j].animation_frame_count = frame_count;
 					f->special_tiles[j].animation_frame_length_ms = frame_length_ms;
-
-					// If there are no frames for an animation, switch
-					// animation off (so that having specified an animation
-					// for something but not using it in the texture pack
-					// gives no overhead)
-					if(frame_count == 1){
-						f->special_tiles[j].material_flags &=
-								~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
+				}
+				if(frame_count == 1) {
+					f->special_tiles[j].material_flags &= ~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
+				} else {
+					std::ostringstream os(std::ios::binary);
+					for (int i = 0; i < frame_count; i++) {
+						FrameSpec frame;
+						os.str("");
+						os<<f->tiledef_special[j].name<<"^[verticalframe:"<<frame_count<<":"<<i;
+						frame.texture = tsrc->getTexture(os.str(), &frame.texture_id);
+						if (f->special_tiles[j].normal_texture)
+							frame.normal_texture = tsrc->getNormalTexture(os.str());
+						f->special_tiles[j].frames[i]=frame;
 					}
 				}
 			}
diff --git a/src/tile.cpp b/src/tile.cpp
index 17ec51614..7cb39eabf 100644
--- a/src/tile.cpp
+++ b/src/tile.cpp
@@ -389,6 +389,7 @@ class TextureSource : public IWritableTextureSource
 	// Shall be called from the main thread.
 	bool generateImage(std::string part_of_name, video::IImage *& baseimg);
 
+	video::ITexture* getNormalTexture(const std::string &name);
 private:
 
 	// The id of the thread that is allowed to use irrlicht directly
@@ -1872,3 +1873,24 @@ void imageTransform(u32 transform, video::IImage *src, video::IImage *dst)
 		dst->setPixel(dx,dy,c);
 	}
 }
+
+video::ITexture* TextureSource::getNormalTexture(const std::string &name)
+{
+	u32 id;
+	if (isKnownSourceImage("override_normal.png"))
+		return getTexture("override_normal.png", &id);
+	std::string fname_base = name;
+	std::string normal_ext = "_normal.png";
+	size_t pos = fname_base.find(".");
+	std::string fname_normal = fname_base.substr(0, pos) + normal_ext;
+	if (isKnownSourceImage(fname_normal)) {
+		// look for image extension and replace it
+		size_t i = 0;
+		while ((i = fname_base.find(".", i)) != std::string::npos) {
+			fname_base.replace(i, 4, normal_ext);
+			i += normal_ext.length();
+		}
+		return getTexture(fname_base, &id);
+		}
+	return NULL;
+}
diff --git a/src/tile.h b/src/tile.h
index 29c6b69f2..f3250669e 100644
--- a/src/tile.h
+++ b/src/tile.h
@@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include <IrrlichtDevice.h>
 #include "threads.h"
 #include <string>
+#include <map>
 
 class IGameDef;
 
@@ -106,6 +107,7 @@ class ITextureSource : public ISimpleTextureSource
 	virtual bool isKnownSourceImage(const std::string &name)=0;
 	virtual video::ITexture* generateTextureFromMesh(
 			const TextureFromMeshParams &params)=0;
+	virtual video::ITexture* getNormalTexture(const std::string &name)=0;
 };
 
 class IWritableTextureSource : public ITextureSource
@@ -127,6 +129,7 @@ class IWritableTextureSource : public ITextureSource
 	virtual void processQueue()=0;
 	virtual void insertSourceImage(const std::string &name, video::IImage *img)=0;
 	virtual void rebuildImagesAndTextures()=0;
+	virtual video::ITexture* getNormalTexture(const std::string &name)=0;
 };
 
 IWritableTextureSource* createTextureSource(IrrlichtDevice *device);
@@ -175,11 +178,25 @@ enum MaterialType{
 	This fully defines the looks of a tile.
 	The SMaterial of a tile is constructed according to this.
 */
+struct FrameSpec
+{
+	FrameSpec():
+		texture_id(0),
+		texture(NULL),
+		normal_texture(NULL)
+	{
+	}
+	u32 texture_id;
+	video::ITexture *texture;
+	video::ITexture *normal_texture;
+};
+
 struct TileSpec
 {
 	TileSpec():
 		texture_id(0),
 		texture(NULL),
+		normal_texture(NULL),
 		alpha(255),
 		material_type(TILE_MATERIAL_BASIC),
 		material_flags(
@@ -243,6 +260,8 @@ struct TileSpec
 	
 	u32 texture_id;
 	video::ITexture *texture;
+	video::ITexture *normal_texture;
+	
 	// Vertex alpha (when MATERIAL_ALPHA_VERTEX is used)
 	u8 alpha;
 	// Material parameters
@@ -252,6 +271,8 @@ struct TileSpec
 	// Animation parameters
 	u8 animation_frame_count;
 	u16 animation_frame_length_ms;
+	std::map<u32, FrameSpec> frames;
+
 	u8 rotation;
 };
 
-- 
GitLab