From 7ea40e45b1bf893aa693c179cbe8612ede86faee Mon Sep 17 00:00:00 2001
From: RealBadAngel <maciej.kasatkin@o2.pl>
Date: Fri, 12 Feb 2016 12:25:20 +0100
Subject: [PATCH] Use vertices with tangents only when its needed.

---
 src/client.cpp        |   6 +-
 src/client.h          |   1 +
 src/mapblock_mesh.cpp | 178 +++++++++++++++++++++++++++---------------
 src/mapblock_mesh.h   |  13 ++-
 4 files changed, 131 insertions(+), 67 deletions(-)

diff --git a/src/client.cpp b/src/client.cpp
index 2dc537782..ed5ff96fe 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -263,6 +263,9 @@ Client::Client(
 
 	m_cache_smooth_lighting = g_settings->getBool("smooth_lighting");
 	m_cache_enable_shaders  = g_settings->getBool("enable_shaders");
+	m_cache_use_tangent_vertices = m_cache_enable_shaders && (
+		g_settings->getBool("enable_bumpmapping") || 
+		g_settings->getBool("enable_parallax_occlusion"));
 }
 
 void Client::Stop()
@@ -1582,7 +1585,8 @@ void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
 		Create a task to update the mesh of the block
 	*/
 
-	MeshMakeData *data = new MeshMakeData(this, m_cache_enable_shaders);
+	MeshMakeData *data = new MeshMakeData(this, m_cache_enable_shaders,
+		m_cache_use_tangent_vertices);
 
 	{
 		//TimeTaker timer("data fill");
diff --git a/src/client.h b/src/client.h
index 98a8bc129..c16e9b77a 100644
--- a/src/client.h
+++ b/src/client.h
@@ -677,6 +677,7 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
 	// TODO: Add callback to update these when g_settings changes
 	bool m_cache_smooth_lighting;
 	bool m_cache_enable_shaders;
+	bool m_cache_use_tangent_vertices;
 
 	DISABLE_CLASS_COPY(Client);
 };
diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp
index 9486220e0..8b3d3c0dd 100644
--- a/src/mapblock_mesh.cpp
+++ b/src/mapblock_mesh.cpp
@@ -33,24 +33,26 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "util/directiontables.h"
 #include <IMeshManipulator.h>
 
-static void applyFacesShading(video::SColor& color, float factor)
+static void applyFacesShading(video::SColor &color, const float factor)
 {
-	color.setRed(core::clamp(core::round32(color.getRed()*factor), 0, 255));
-	color.setGreen(core::clamp(core::round32(color.getGreen()*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));
 }
 
 /*
 	MeshMakeData
 */
 
-MeshMakeData::MeshMakeData(IGameDef *gamedef, bool use_shaders):
+MeshMakeData::MeshMakeData(IGameDef *gamedef, bool use_shaders,
+		bool use_tangent_vertices):
 	m_vmanip(),
 	m_blockpos(-1337,-1337,-1337),
 	m_crack_pos_relative(-1337, -1337, -1337),
 	m_smooth_lighting(false),
 	m_show_hud(false),
 	m_gamedef(gamedef),
-	m_use_shaders(use_shaders)
+	m_use_shaders(use_shaders),
+	m_use_tangent_vertices(use_tangent_vertices)
 {}
 
 void MeshMakeData::fill(MapBlock *block)
@@ -1032,6 +1034,7 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
 	m_daynight_diffs()
 {
 	m_enable_shaders = data->m_use_shaders;
+	m_use_tangent_vertices = data->m_use_tangent_vertices;
 
 	if (g_settings->getBool("enable_minimap")) {
 		m_minimap_mapblock = new MinimapMapblock;
@@ -1064,15 +1067,14 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
 		Convert FastFaces to MeshCollector
 	*/
 
-	MeshCollector collector;
+	MeshCollector collector(m_use_tangent_vertices);
 
 	{
 		// avg 0ms (100ms spikes when loading textures the first time)
 		// (NOTE: probably outdated)
 		//TimeTaker timer2("MeshCollector building");
 
-		for(u32 i=0; i<fastfaces_new.size(); i++)
-		{
+		for (u32 i = 0; i < fastfaces_new.size(); i++) {
 			FastFace &f = fastfaces_new[i];
 
 			const u16 indices[] = {0,1,2,2,3,0};
@@ -1150,35 +1152,43 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
 			p.tile.texture = animation_frame.texture;
 		}
 
-		for(u32 j = 0; j < p.vertices.size(); j++)
-		{
-			video::S3DVertex *vertex = &p.vertices[j];
+		u32 vertex_count = m_use_tangent_vertices ?
+			p.tangent_vertices.size() : p.vertices.size();
+		for (u32 j = 0; j < vertex_count; j++) {
+			v3f *Normal;
+			video::SColor *vc;
+			if (m_use_tangent_vertices) {
+				vc = &p.tangent_vertices[j].Color;
+				Normal = &p.tangent_vertices[j].Normal;
+			} else {
+				vc = &p.vertices[j].Color;
+				Normal = &p.vertices[j].Normal;
+			}
 			// Note applyFacesShading second parameter is precalculated sqrt
 			// value for speed improvement
 			// Skip it for lightsources and top faces.
-			video::SColor &vc = vertex->Color;
-			if (!vc.getBlue()) {
-				if (vertex->Normal.Y < -0.5) {
-					applyFacesShading (vc, 0.447213);
-				} else if (vertex->Normal.X > 0.5) {
-					applyFacesShading (vc, 0.670820);
-				} else if (vertex->Normal.X < -0.5) {
-					applyFacesShading (vc, 0.670820);
-				} else if (vertex->Normal.Z > 0.5) {
-					applyFacesShading (vc, 0.836660);
-				} else if (vertex->Normal.Z < -0.5) {
-					applyFacesShading (vc, 0.836660);
+			if (!vc->getBlue()) {
+				if (Normal->Y < -0.5) {
+					applyFacesShading(*vc, 0.447213);
+				} else if (Normal->X > 0.5) {
+					applyFacesShading(*vc, 0.670820);
+				} else if (Normal->X < -0.5) {
+					applyFacesShading(*vc, 0.670820);
+				} else if (Normal->Z > 0.5) {
+					applyFacesShading(*vc, 0.836660);
+				} else if (Normal->Z < -0.5) {
+					applyFacesShading(*vc, 0.836660);
 				}
 			}
-			if(!m_enable_shaders)
-			{
+			if (!m_enable_shaders) {
 				// - Classic lighting (shaders handle this by themselves)
 				// Set initial real color and store for later updates
-				u8 day = vc.getRed();
-				u8 night = vc.getGreen();
-				finalColorBlend(vc, day, night, 1000);
-				if(day != night)
+				u8 day = vc->getRed();
+				u8 night = vc->getGreen();
+				finalColorBlend(*vc, day, night, 1000);
+				if (day != night) {
 					m_daynight_diffs[i][j] = std::make_pair(day, night);
+				}
 			}
 		}
 
@@ -1201,34 +1211,46 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
 			p.tile.applyMaterialOptions(material);
 		}
 
-	// Create meshbuffer
-	scene::SMeshBuffer *buf = new scene::SMeshBuffer();
-	// Set material
-	buf->Material = material;
-	// Add to mesh
-	scene::SMesh *mesh = (scene::SMesh *)m_mesh;
-	mesh->addMeshBuffer(buf);
-	// Mesh grabbed it
-	buf->drop();
-	buf->append(&p.vertices[0], p.vertices.size(),
-		&p.indices[0], p.indices.size());
-}
-	m_camera_offset = camera_offset;
+		scene::SMesh *mesh = (scene::SMesh *)m_mesh;
+
+		// Create meshbuffer, add to mesh
+		if (m_use_tangent_vertices) {
+			scene::SMeshBufferTangents *buf = new scene::SMeshBufferTangents();
+			// Set material
+			buf->Material = material;
+			// Add to mesh
+			mesh->addMeshBuffer(buf);
+			// Mesh grabbed it
+			buf->drop();
+			buf->append(&p.tangent_vertices[0], p.tangent_vertices.size(),
+				&p.indices[0], p.indices.size());
+		} else {
+			scene::SMeshBuffer *buf = new scene::SMeshBuffer();
+			// Set material
+			buf->Material = material;
+			// Add to mesh
+			mesh->addMeshBuffer(buf);
+			// Mesh grabbed it
+			buf->drop();
+			buf->append(&p.vertices[0], p.vertices.size(),
+				&p.indices[0], p.indices.size());
+		}
+	}
 
 	/*
 		Do some stuff to the mesh
 	*/
+	m_camera_offset = camera_offset;
+	translateMesh(m_mesh,
+		intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
 
-	translateMesh(m_mesh, intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
-
-	if (m_enable_shaders) {
-		scene::IMeshManipulator* meshmanip = m_gamedef->getSceneManager()->getMeshManipulator();
-		scene::IMesh* tangentMesh = meshmanip->createMeshWithTangents(m_mesh);
-		m_mesh->drop();
-		m_mesh = tangentMesh;
+	if (m_use_tangent_vertices) {
+		scene::IMeshManipulator* meshmanip =
+			m_gamedef->getSceneManager()->getMeshManipulator();
+		meshmanip->recalculateTangents(m_mesh, true, false, false);
 	}
 
-	if(m_mesh)
+	if (m_mesh)
 	{
 #if 0
 		// Usually 1-700 faces and 1-7 materials
@@ -1400,17 +1422,30 @@ void MeshCollector::append(const TileSpec &tile,
 		p = &prebuffers[prebuffers.size() - 1];
 	}
 
-	u32 vertex_count = p->vertices.size();
-	for (u32 i = 0; i < numIndices; i++)	{
+	u32 vertex_count;
+	if (m_use_tangent_vertices) {
+		vertex_count = p->tangent_vertices.size();
+		p->tangent_vertices.reserve(vertex_count + numVertices);
+		for (u32 i = 0; i < numVertices; i++) {
+			video::S3DVertexTangents vert(vertices[i].Pos, vertices[i].Normal,
+				vertices[i].Color, vertices[i].TCoords);
+			p->tangent_vertices.push_back(vert);
+		}
+	} else {
+		vertex_count = p->vertices.size();
+		p->vertices.reserve(vertex_count + numVertices);
+		for (u32 i = 0; i < numVertices; i++) {
+			video::S3DVertex vert(vertices[i].Pos, vertices[i].Normal,
+				vertices[i].Color, vertices[i].TCoords);
+			p->vertices.push_back(vert);
+		}
+	} 
+
+	p->indices.reserve(p->indices.size() + numIndices);
+	for (u32 i = 0; i < numIndices; i++) {
 		u32 j = indices[i] + vertex_count;
 		p->indices.push_back(j);
 	}
-
-	for (u32 i = 0; i < numVertices; i++) {
-		video::S3DVertex vert(vertices[i].Pos, vertices[i].Normal,
-			vertices[i].Color, vertices[i].TCoords);
-		p->vertices.push_back(vert);
-	}
 }
 
 /*
@@ -1446,15 +1481,28 @@ void MeshCollector::append(const TileSpec &tile,
 		p = &prebuffers[prebuffers.size() - 1];
 	}
 
-	u32 vertex_count = p->vertices.size();
+	u32 vertex_count;
+	if (m_use_tangent_vertices) {
+		vertex_count = p->tangent_vertices.size();
+		p->tangent_vertices.reserve(vertex_count + numVertices);
+		for (u32 i = 0; i < numVertices; i++) {
+			video::S3DVertexTangents vert(vertices[i].Pos + pos,
+				vertices[i].Normal, c, vertices[i].TCoords);
+			p->tangent_vertices.push_back(vert);
+		}
+	} else {
+		vertex_count = p->vertices.size();
+		p->vertices.reserve(vertex_count + numVertices);
+		for (u32 i = 0; i < numVertices; i++) {
+			video::S3DVertex vert(vertices[i].Pos + pos,
+				vertices[i].Normal, c, vertices[i].TCoords);
+			p->vertices.push_back(vert);
+		}
+	} 
+
+	p->indices.reserve(p->indices.size() + numIndices);
 	for (u32 i = 0; i < numIndices; i++) {
 		u32 j = indices[i] + vertex_count;
 		p->indices.push_back(j);
 	}
-
-	for (u32 i = 0; i < numVertices; i++) {
-		video::S3DVertex vert(vertices[i].Pos + pos, vertices[i].Normal,
-			c, vertices[i].TCoords);
-		p->vertices.push_back(vert);
-	}
 }
diff --git a/src/mapblock_mesh.h b/src/mapblock_mesh.h
index 421e8f2b3..987490408 100644
--- a/src/mapblock_mesh.h
+++ b/src/mapblock_mesh.h
@@ -46,8 +46,10 @@ struct MeshMakeData
 
 	IGameDef *m_gamedef;
 	bool m_use_shaders;
+	bool m_use_tangent_vertices;
 
-	MeshMakeData(IGameDef *gamedef, bool use_shaders);
+	MeshMakeData(IGameDef *gamedef, bool use_shaders,
+			bool use_tangent_vertices = false);
 
 	/*
 		Copy central data directly from block, and other data from
@@ -130,6 +132,7 @@ class MapBlockMesh
 	IShaderSource *m_shdrsrc;
 
 	bool m_enable_shaders;
+	bool m_use_tangent_vertices;
 
 	// Must animate() be called before rendering?
 	bool m_has_animation;
@@ -167,11 +170,19 @@ struct PreMeshBuffer
 	TileSpec tile;
 	std::vector<u16> indices;
 	std::vector<video::S3DVertex> vertices;
+	std::vector<video::S3DVertexTangents> tangent_vertices;
 };
 
 struct MeshCollector
 {
 	std::vector<PreMeshBuffer> prebuffers;
+	bool m_use_tangent_vertices;
+
+	MeshCollector(bool use_tangent_vertices):
+		m_use_tangent_vertices(use_tangent_vertices)
+	{
+	}
+
 	void append(const TileSpec &material,
 			const video::S3DVertex *vertices, u32 numVertices,
 			const u16 *indices, u32 numIndices);
-- 
GitLab