1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14 
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 
20 #include "mapblock_mesh.h"
21 #include "client.h"
22 #include "mapblock.h"
23 #include "map.h"
24 #include "profiler.h"
25 #include "shader.h"
26 #include "mesh.h"
27 #include "minimap.h"
28 #include "content_mapblock.h"
29 #include "util/directiontables.h"
30 #include "client/meshgen/collector.h"
31 #include "client/renderingengine.h"
32 #include <array>
33 
34 /*
35 	MeshMakeData
36 */
37 
MeshMakeData(Client * client,bool use_shaders)38 MeshMakeData::MeshMakeData(Client *client, bool use_shaders):
39 	m_client(client),
40 	m_use_shaders(use_shaders)
41 {}
42 
fillBlockDataBegin(const v3s16 & blockpos)43 void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos)
44 {
45 	m_blockpos = blockpos;
46 
47 	v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
48 
49 	m_vmanip.clear();
50 	VoxelArea voxel_area(blockpos_nodes - v3s16(1,1,1) * MAP_BLOCKSIZE,
51 			blockpos_nodes + v3s16(1,1,1) * MAP_BLOCKSIZE*2-v3s16(1,1,1));
52 	m_vmanip.addArea(voxel_area);
53 }
54 
fillBlockData(const v3s16 & block_offset,MapNode * data)55 void MeshMakeData::fillBlockData(const v3s16 &block_offset, MapNode *data)
56 {
57 	v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
58 	VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
59 
60 	v3s16 bp = m_blockpos + block_offset;
61 	v3s16 blockpos_nodes = bp * MAP_BLOCKSIZE;
62 	m_vmanip.copyFrom(data, data_area, v3s16(0,0,0), blockpos_nodes, data_size);
63 }
64 
fill(MapBlock * block)65 void MeshMakeData::fill(MapBlock *block)
66 {
67 	fillBlockDataBegin(block->getPos());
68 
69 	fillBlockData(v3s16(0,0,0), block->getData());
70 
71 	// Get map for reading neighbor blocks
72 	Map *map = block->getParent();
73 
74 	for (const v3s16 &dir : g_26dirs) {
75 		v3s16 bp = m_blockpos + dir;
76 		MapBlock *b = map->getBlockNoCreateNoEx(bp);
77 		if(b)
78 			fillBlockData(dir, b->getData());
79 	}
80 }
81 
setCrack(int crack_level,v3s16 crack_pos)82 void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
83 {
84 	if (crack_level >= 0)
85 		m_crack_pos_relative = crack_pos - m_blockpos*MAP_BLOCKSIZE;
86 }
87 
setSmoothLighting(bool smooth_lighting)88 void MeshMakeData::setSmoothLighting(bool smooth_lighting)
89 {
90 	m_smooth_lighting = smooth_lighting;
91 }
92 
93 /*
94 	Light and vertex color functions
95 */
96 
97 /*
98 	Calculate non-smooth lighting at interior of node.
99 	Single light bank.
100 */
getInteriorLight(enum LightBank bank,MapNode n,s32 increment,const NodeDefManager * ndef)101 static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
102 	const NodeDefManager *ndef)
103 {
104 	u8 light = n.getLight(bank, ndef);
105 	if (light > 0)
106 		light = rangelim(light + increment, 0, LIGHT_SUN);
107 	return decode_light(light);
108 }
109 
110 /*
111 	Calculate non-smooth lighting at interior of node.
112 	Both light banks.
113 */
getInteriorLight(MapNode n,s32 increment,const NodeDefManager * ndef)114 u16 getInteriorLight(MapNode n, s32 increment, const NodeDefManager *ndef)
115 {
116 	u16 day = getInteriorLight(LIGHTBANK_DAY, n, increment, ndef);
117 	u16 night = getInteriorLight(LIGHTBANK_NIGHT, n, increment, ndef);
118 	return day | (night << 8);
119 }
120 
121 /*
122 	Calculate non-smooth lighting at face of node.
123 	Single light bank.
124 */
getFaceLight(enum LightBank bank,MapNode n,MapNode n2,v3s16 face_dir,const NodeDefManager * ndef)125 static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
126 	v3s16 face_dir, const NodeDefManager *ndef)
127 {
128 	u8 light;
129 	u8 l1 = n.getLight(bank, ndef);
130 	u8 l2 = n2.getLight(bank, ndef);
131 	if(l1 > l2)
132 		light = l1;
133 	else
134 		light = l2;
135 
136 	// Boost light level for light sources
137 	u8 light_source = MYMAX(ndef->get(n).light_source,
138 			ndef->get(n2).light_source);
139 	if(light_source > light)
140 		light = light_source;
141 
142 	return decode_light(light);
143 }
144 
145 /*
146 	Calculate non-smooth lighting at face of node.
147 	Both light banks.
148 */
getFaceLight(MapNode n,MapNode n2,const v3s16 & face_dir,const NodeDefManager * ndef)149 u16 getFaceLight(MapNode n, MapNode n2, const v3s16 &face_dir,
150 	const NodeDefManager *ndef)
151 {
152 	u16 day = getFaceLight(LIGHTBANK_DAY, n, n2, face_dir, ndef);
153 	u16 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, face_dir, ndef);
154 	return day | (night << 8);
155 }
156 
157 /*
158 	Calculate smooth lighting at the XYZ- corner of p.
159 	Both light banks
160 */
getSmoothLightCombined(const v3s16 & p,const std::array<v3s16,8> & dirs,MeshMakeData * data)161 static u16 getSmoothLightCombined(const v3s16 &p,
162 	const std::array<v3s16,8> &dirs, MeshMakeData *data)
163 {
164 	const NodeDefManager *ndef = data->m_client->ndef();
165 
166 	u16 ambient_occlusion = 0;
167 	u16 light_count = 0;
168 	u8 light_source_max = 0;
169 	u16 light_day = 0;
170 	u16 light_night = 0;
171 	bool direct_sunlight = false;
172 
173 	auto add_node = [&] (u8 i, bool obstructed = false) -> bool {
174 		if (obstructed) {
175 			ambient_occlusion++;
176 			return false;
177 		}
178 		MapNode n = data->m_vmanip.getNodeNoExNoEmerge(p + dirs[i]);
179 		if (n.getContent() == CONTENT_IGNORE)
180 			return true;
181 		const ContentFeatures &f = ndef->get(n);
182 		if (f.light_source > light_source_max)
183 			light_source_max = f.light_source;
184 		// Check f.solidness because fast-style leaves look better this way
185 		if (f.param_type == CPT_LIGHT && f.solidness != 2) {
186 			u8 light_level_day = n.getLightNoChecks(LIGHTBANK_DAY, &f);
187 			u8 light_level_night = n.getLightNoChecks(LIGHTBANK_NIGHT, &f);
188 			if (light_level_day == LIGHT_SUN)
189 				direct_sunlight = true;
190 			light_day += decode_light(light_level_day);
191 			light_night += decode_light(light_level_night);
192 			light_count++;
193 		} else {
194 			ambient_occlusion++;
195 		}
196 		return f.light_propagates;
197 	};
198 
199 	bool obstructed[4] = { true, true, true, true };
200 	add_node(0);
201 	bool opaque1 = !add_node(1);
202 	bool opaque2 = !add_node(2);
203 	bool opaque3 = !add_node(3);
204 	obstructed[0] = opaque1 && opaque2;
205 	obstructed[1] = opaque1 && opaque3;
206 	obstructed[2] = opaque2 && opaque3;
207 	for (u8 k = 0; k < 3; ++k)
208 		if (add_node(k + 4, obstructed[k]))
209 			obstructed[3] = false;
210 	if (add_node(7, obstructed[3])) { // wrap light around nodes
211 		ambient_occlusion -= 3;
212 		for (u8 k = 0; k < 3; ++k)
213 			add_node(k + 4, !obstructed[k]);
214 	}
215 
216 	if (light_count == 0) {
217 		light_day = light_night = 0;
218 	} else {
219 		light_day /= light_count;
220 		light_night /= light_count;
221 	}
222 
223 	// boost direct sunlight, if any
224 	if (direct_sunlight)
225 		light_day = 0xFF;
226 
227 	// Boost brightness around light sources
228 	bool skip_ambient_occlusion_day = false;
229 	if (decode_light(light_source_max) >= light_day) {
230 		light_day = decode_light(light_source_max);
231 		skip_ambient_occlusion_day = true;
232 	}
233 
234 	bool skip_ambient_occlusion_night = false;
235 	if(decode_light(light_source_max) >= light_night) {
236 		light_night = decode_light(light_source_max);
237 		skip_ambient_occlusion_night = true;
238 	}
239 
240 	if (ambient_occlusion > 4) {
241 		static thread_local const float ao_gamma = rangelim(
242 			g_settings->getFloat("ambient_occlusion_gamma"), 0.25, 4.0);
243 
244 		// Table of gamma space multiply factors.
245 		static thread_local const float light_amount[3] = {
246 			powf(0.75, 1.0 / ao_gamma),
247 			powf(0.5,  1.0 / ao_gamma),
248 			powf(0.25, 1.0 / ao_gamma)
249 		};
250 
251 		//calculate table index for gamma space multiplier
252 		ambient_occlusion -= 5;
253 
254 		if (!skip_ambient_occlusion_day)
255 			light_day = rangelim(core::round32(
256 					light_day * light_amount[ambient_occlusion]), 0, 255);
257 		if (!skip_ambient_occlusion_night)
258 			light_night = rangelim(core::round32(
259 					light_night * light_amount[ambient_occlusion]), 0, 255);
260 	}
261 
262 	return light_day | (light_night << 8);
263 }
264 
265 /*
266 	Calculate smooth lighting at the given corner of p.
267 	Both light banks.
268 	Node at p is solid, and thus the lighting is face-dependent.
269 */
getSmoothLightSolid(const v3s16 & p,const v3s16 & face_dir,const v3s16 & corner,MeshMakeData * data)270 u16 getSmoothLightSolid(const v3s16 &p, const v3s16 &face_dir, const v3s16 &corner, MeshMakeData *data)
271 {
272 	return getSmoothLightTransparent(p + face_dir, corner - 2 * face_dir, data);
273 }
274 
275 /*
276 	Calculate smooth lighting at the given corner of p.
277 	Both light banks.
278 	Node at p is not solid, and the lighting is not face-dependent.
279 */
getSmoothLightTransparent(const v3s16 & p,const v3s16 & corner,MeshMakeData * data)280 u16 getSmoothLightTransparent(const v3s16 &p, const v3s16 &corner, MeshMakeData *data)
281 {
282 	const std::array<v3s16,8> dirs = {{
283 		// Always shine light
284 		v3s16(0,0,0),
285 		v3s16(corner.X,0,0),
286 		v3s16(0,corner.Y,0),
287 		v3s16(0,0,corner.Z),
288 
289 		// Can be obstructed
290 		v3s16(corner.X,corner.Y,0),
291 		v3s16(corner.X,0,corner.Z),
292 		v3s16(0,corner.Y,corner.Z),
293 		v3s16(corner.X,corner.Y,corner.Z)
294 	}};
295 	return getSmoothLightCombined(p, dirs, data);
296 }
297 
get_sunlight_color(video::SColorf * sunlight,u32 daynight_ratio)298 void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio){
299 	f32 rg = daynight_ratio / 1000.0f - 0.04f;
300 	f32 b = (0.98f * daynight_ratio) / 1000.0f + 0.078f;
301 	sunlight->r = rg;
302 	sunlight->g = rg;
303 	sunlight->b = b;
304 }
305 
final_color_blend(video::SColor * result,u16 light,u32 daynight_ratio)306 void final_color_blend(video::SColor *result,
307 		u16 light, u32 daynight_ratio)
308 {
309 	video::SColorf dayLight;
310 	get_sunlight_color(&dayLight, daynight_ratio);
311 	final_color_blend(result,
312 		encode_light(light, 0), dayLight);
313 }
314 
final_color_blend(video::SColor * result,const video::SColor & data,const video::SColorf & dayLight)315 void final_color_blend(video::SColor *result,
316 		const video::SColor &data, const video::SColorf &dayLight)
317 {
318 	static const video::SColorf artificialColor(1.04f, 1.04f, 1.04f);
319 
320 	video::SColorf c(data);
321 	f32 n = 1 - c.a;
322 
323 	f32 r = c.r * (c.a * dayLight.r + n * artificialColor.r) * 2.0f;
324 	f32 g = c.g * (c.a * dayLight.g + n * artificialColor.g) * 2.0f;
325 	f32 b = c.b * (c.a * dayLight.b + n * artificialColor.b) * 2.0f;
326 
327 	// Emphase blue a bit in darker places
328 	// Each entry of this array represents a range of 8 blue levels
329 	static const u8 emphase_blue_when_dark[32] = {
330 		1, 4, 6, 6, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0,
331 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
332 	};
333 
334 	b += emphase_blue_when_dark[irr::core::clamp((s32) ((r + g + b) / 3 * 255),
335 		0, 255) / 8] / 255.0f;
336 
337 	result->setRed(core::clamp((s32) (r * 255.0f), 0, 255));
338 	result->setGreen(core::clamp((s32) (g * 255.0f), 0, 255));
339 	result->setBlue(core::clamp((s32) (b * 255.0f), 0, 255));
340 }
341 
342 /*
343 	Mesh generation helpers
344 */
345 
346 // This table is moved outside getNodeVertexDirs to avoid the compiler using
347 // a mutex to initialize this table at runtime right in the hot path.
348 // For details search the internet for "cxa_guard_acquire".
349 static const v3s16 vertex_dirs_table[] = {
350 	// ( 1, 0, 0)
351 	v3s16( 1,-1, 1), v3s16( 1,-1,-1),
352 	v3s16( 1, 1,-1), v3s16( 1, 1, 1),
353 	// ( 0, 1, 0)
354 	v3s16( 1, 1,-1), v3s16(-1, 1,-1),
355 	v3s16(-1, 1, 1), v3s16( 1, 1, 1),
356 	// ( 0, 0, 1)
357 	v3s16(-1,-1, 1), v3s16( 1,-1, 1),
358 	v3s16( 1, 1, 1), v3s16(-1, 1, 1),
359 	// invalid
360 	v3s16(), v3s16(), v3s16(), v3s16(),
361 	// ( 0, 0,-1)
362 	v3s16( 1,-1,-1), v3s16(-1,-1,-1),
363 	v3s16(-1, 1,-1), v3s16( 1, 1,-1),
364 	// ( 0,-1, 0)
365 	v3s16( 1,-1, 1), v3s16(-1,-1, 1),
366 	v3s16(-1,-1,-1), v3s16( 1,-1,-1),
367 	// (-1, 0, 0)
368 	v3s16(-1,-1,-1), v3s16(-1,-1, 1),
369 	v3s16(-1, 1, 1), v3s16(-1, 1,-1)
370 };
371 
372 /*
373 	vertex_dirs: v3s16[4]
374 */
getNodeVertexDirs(const v3s16 & dir,v3s16 * vertex_dirs)375 static void getNodeVertexDirs(const v3s16 &dir, v3s16 *vertex_dirs)
376 {
377 	/*
378 		If looked from outside the node towards the face, the corners are:
379 		0: bottom-right
380 		1: bottom-left
381 		2: top-left
382 		3: top-right
383 	*/
384 
385 	// Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
386 	// (0,0,1), (0,0,-1)
387 	assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z == 1);
388 
389 	// Convert direction to single integer for table lookup
390 	u8 idx = (dir.X + 2 * dir.Y + 3 * dir.Z) & 7;
391 	idx = (idx - 1) * 4;
392 
393 #if defined(__GNUC__) && !defined(__clang__)
394 #pragma GCC diagnostic push
395 #if __GNUC__ > 7
396 #pragma GCC diagnostic ignored "-Wclass-memaccess"
397 #endif
398 #endif
399 	memcpy(vertex_dirs, &vertex_dirs_table[idx], 4 * sizeof(v3s16));
400 #if defined(__GNUC__) && !defined(__clang__)
401 #pragma GCC diagnostic pop
402 #endif
403 }
404 
getNodeTextureCoords(v3f base,const v3f & scale,const v3s16 & dir,float * u,float * v)405 static void getNodeTextureCoords(v3f base, const v3f &scale, const v3s16 &dir, float *u, float *v)
406 {
407 	if (dir.X > 0 || dir.Y != 0 || dir.Z < 0)
408 		base -= scale;
409 	if (dir == v3s16(0,0,1)) {
410 		*u = -base.X - 1;
411 		*v = -base.Y - 1;
412 	} else if (dir == v3s16(0,0,-1)) {
413 		*u = base.X + 1;
414 		*v = -base.Y - 2;
415 	} else if (dir == v3s16(1,0,0)) {
416 		*u = base.Z + 1;
417 		*v = -base.Y - 2;
418 	} else if (dir == v3s16(-1,0,0)) {
419 		*u = -base.Z - 1;
420 		*v = -base.Y - 1;
421 	} else if (dir == v3s16(0,1,0)) {
422 		*u = base.X + 1;
423 		*v = -base.Z - 2;
424 	} else if (dir == v3s16(0,-1,0)) {
425 		*u = base.X + 1;
426 		*v = base.Z + 1;
427 	}
428 }
429 
430 struct FastFace
431 {
432 	TileSpec tile;
433 	video::S3DVertex vertices[4]; // Precalculated vertices
434 	/*!
435 	 * The face is divided into two triangles. If this is true,
436 	 * vertices 0 and 2 are connected, othervise vertices 1 and 3
437 	 * are connected.
438 	 */
439 	bool vertex_0_2_connected;
440 };
441 
makeFastFace(const TileSpec & tile,u16 li0,u16 li1,u16 li2,u16 li3,const v3f & tp,const v3f & p,const v3s16 & dir,const v3f & scale,std::vector<FastFace> & dest)442 static void makeFastFace(const TileSpec &tile, u16 li0, u16 li1, u16 li2, u16 li3,
443 	const v3f &tp, const v3f &p, const v3s16 &dir, const v3f &scale, std::vector<FastFace> &dest)
444 {
445 	// Position is at the center of the cube.
446 	v3f pos = p * BS;
447 
448 	float x0 = 0.0f;
449 	float y0 = 0.0f;
450 	float w = 1.0f;
451 	float h = 1.0f;
452 
453 	v3f vertex_pos[4];
454 	v3s16 vertex_dirs[4];
455 	getNodeVertexDirs(dir, vertex_dirs);
456 	if (tile.world_aligned)
457 		getNodeTextureCoords(tp, scale, dir, &x0, &y0);
458 
459 	v3s16 t;
460 	u16 t1;
461 	switch (tile.rotation) {
462 	case 0:
463 		break;
464 	case 1: //R90
465 		t = vertex_dirs[0];
466 		vertex_dirs[0] = vertex_dirs[3];
467 		vertex_dirs[3] = vertex_dirs[2];
468 		vertex_dirs[2] = vertex_dirs[1];
469 		vertex_dirs[1] = t;
470 		t1  = li0;
471 		li0 = li3;
472 		li3 = li2;
473 		li2 = li1;
474 		li1 = t1;
475 		break;
476 	case 2: //R180
477 		t = vertex_dirs[0];
478 		vertex_dirs[0] = vertex_dirs[2];
479 		vertex_dirs[2] = t;
480 		t = vertex_dirs[1];
481 		vertex_dirs[1] = vertex_dirs[3];
482 		vertex_dirs[3] = t;
483 		t1  = li0;
484 		li0 = li2;
485 		li2 = t1;
486 		t1  = li1;
487 		li1 = li3;
488 		li3 = t1;
489 		break;
490 	case 3: //R270
491 		t = vertex_dirs[0];
492 		vertex_dirs[0] = vertex_dirs[1];
493 		vertex_dirs[1] = vertex_dirs[2];
494 		vertex_dirs[2] = vertex_dirs[3];
495 		vertex_dirs[3] = t;
496 		t1  = li0;
497 		li0 = li1;
498 		li1 = li2;
499 		li2 = li3;
500 		li3 = t1;
501 		break;
502 	case 4: //FXR90
503 		t = vertex_dirs[0];
504 		vertex_dirs[0] = vertex_dirs[3];
505 		vertex_dirs[3] = vertex_dirs[2];
506 		vertex_dirs[2] = vertex_dirs[1];
507 		vertex_dirs[1] = t;
508 		t1  = li0;
509 		li0 = li3;
510 		li3 = li2;
511 		li2 = li1;
512 		li1 = t1;
513 		y0 += h;
514 		h *= -1;
515 		break;
516 	case 5: //FXR270
517 		t = vertex_dirs[0];
518 		vertex_dirs[0] = vertex_dirs[1];
519 		vertex_dirs[1] = vertex_dirs[2];
520 		vertex_dirs[2] = vertex_dirs[3];
521 		vertex_dirs[3] = t;
522 		t1  = li0;
523 		li0 = li1;
524 		li1 = li2;
525 		li2 = li3;
526 		li3 = t1;
527 		y0 += h;
528 		h *= -1;
529 		break;
530 	case 6: //FYR90
531 		t = vertex_dirs[0];
532 		vertex_dirs[0] = vertex_dirs[3];
533 		vertex_dirs[3] = vertex_dirs[2];
534 		vertex_dirs[2] = vertex_dirs[1];
535 		vertex_dirs[1] = t;
536 		t1  = li0;
537 		li0 = li3;
538 		li3 = li2;
539 		li2 = li1;
540 		li1 = t1;
541 		x0 += w;
542 		w *= -1;
543 		break;
544 	case 7: //FYR270
545 		t = vertex_dirs[0];
546 		vertex_dirs[0] = vertex_dirs[1];
547 		vertex_dirs[1] = vertex_dirs[2];
548 		vertex_dirs[2] = vertex_dirs[3];
549 		vertex_dirs[3] = t;
550 		t1  = li0;
551 		li0 = li1;
552 		li1 = li2;
553 		li2 = li3;
554 		li3 = t1;
555 		x0 += w;
556 		w *= -1;
557 		break;
558 	case 8: //FX
559 		y0 += h;
560 		h *= -1;
561 		break;
562 	case 9: //FY
563 		x0 += w;
564 		w *= -1;
565 		break;
566 	default:
567 		break;
568 	}
569 
570 	for (u16 i = 0; i < 4; i++) {
571 		vertex_pos[i] = v3f(
572 				BS / 2 * vertex_dirs[i].X,
573 				BS / 2 * vertex_dirs[i].Y,
574 				BS / 2 * vertex_dirs[i].Z
575 		);
576 	}
577 
578 	for (v3f &vpos : vertex_pos) {
579 		vpos.X *= scale.X;
580 		vpos.Y *= scale.Y;
581 		vpos.Z *= scale.Z;
582 		vpos += pos;
583 	}
584 
585 	f32 abs_scale = 1.0f;
586 	if      (scale.X < 0.999f || scale.X > 1.001f) abs_scale = scale.X;
587 	else if (scale.Y < 0.999f || scale.Y > 1.001f) abs_scale = scale.Y;
588 	else if (scale.Z < 0.999f || scale.Z > 1.001f) abs_scale = scale.Z;
589 
590 	v3f normal(dir.X, dir.Y, dir.Z);
591 
592 	u16 li[4] = { li0, li1, li2, li3 };
593 	u16 day[4];
594 	u16 night[4];
595 
596 	for (u8 i = 0; i < 4; i++) {
597 		day[i] = li[i] >> 8;
598 		night[i] = li[i] & 0xFF;
599 	}
600 
601 	bool vertex_0_2_connected = abs(day[0] - day[2]) + abs(night[0] - night[2])
602 			< abs(day[1] - day[3]) + abs(night[1] - night[3]);
603 
604 	v2f32 f[4] = {
605 		core::vector2d<f32>(x0 + w * abs_scale, y0 + h),
606 		core::vector2d<f32>(x0, y0 + h),
607 		core::vector2d<f32>(x0, y0),
608 		core::vector2d<f32>(x0 + w * abs_scale, y0) };
609 
610 	// equivalent to dest.push_back(FastFace()) but faster
611 	dest.emplace_back();
612 	FastFace& face = *dest.rbegin();
613 
614 	for (u8 i = 0; i < 4; i++) {
615 		video::SColor c = encode_light(li[i], tile.emissive_light);
616 		if (!tile.emissive_light)
617 			applyFacesShading(c, normal);
618 
619 		face.vertices[i] = video::S3DVertex(vertex_pos[i], normal, c, f[i]);
620 	}
621 
622 	/*
623 		Revert triangles for nicer looking gradient if the
624 		brightness of vertices 1 and 3 differ less than
625 		the brightness of vertices 0 and 2.
626 		*/
627 	face.vertex_0_2_connected = vertex_0_2_connected;
628 	face.tile = tile;
629 }
630 
631 /*
632 	Nodes make a face if contents differ and solidness differs.
633 	Return value:
634 		0: No face
635 		1: Face uses m1's content
636 		2: Face uses m2's content
637 	equivalent: Whether the blocks share the same face (eg. water and glass)
638 
639 	TODO: Add 3: Both faces drawn with backface culling, remove equivalent
640 */
face_contents(content_t m1,content_t m2,bool * equivalent,const NodeDefManager * ndef)641 static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
642 	const NodeDefManager *ndef)
643 {
644 	*equivalent = false;
645 
646 	if (m1 == m2 || m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
647 		return 0;
648 
649 	const ContentFeatures &f1 = ndef->get(m1);
650 	const ContentFeatures &f2 = ndef->get(m2);
651 
652 	// Contents don't differ for different forms of same liquid
653 	if (f1.sameLiquid(f2))
654 		return 0;
655 
656 	u8 c1 = f1.solidness;
657 	u8 c2 = f2.solidness;
658 
659 	if (c1 == c2)
660 		return 0;
661 
662 	if (c1 == 0)
663 		c1 = f1.visual_solidness;
664 	else if (c2 == 0)
665 		c2 = f2.visual_solidness;
666 
667 	if (c1 == c2) {
668 		*equivalent = true;
669 		// If same solidness, liquid takes precense
670 		if (f1.isLiquid())
671 			return 1;
672 		if (f2.isLiquid())
673 			return 2;
674 	}
675 
676 	if (c1 > c2)
677 		return 1;
678 
679 	return 2;
680 }
681 
682 /*
683 	Gets nth node tile (0 <= n <= 5).
684 */
getNodeTileN(MapNode mn,const v3s16 & p,u8 tileindex,MeshMakeData * data,TileSpec & tile)685 void getNodeTileN(MapNode mn, const v3s16 &p, u8 tileindex, MeshMakeData *data, TileSpec &tile)
686 {
687 	const NodeDefManager *ndef = data->m_client->ndef();
688 	const ContentFeatures &f = ndef->get(mn);
689 	tile = f.tiles[tileindex];
690 	bool has_crack = p == data->m_crack_pos_relative;
691 	for (TileLayer &layer : tile.layers) {
692 		if (layer.texture_id == 0)
693 			continue;
694 		if (!layer.has_color)
695 			mn.getColor(f, &(layer.color));
696 		// Apply temporary crack
697 		if (has_crack)
698 			layer.material_flags |= MATERIAL_FLAG_CRACK;
699 	}
700 }
701 
702 /*
703 	Gets node tile given a face direction.
704 */
getNodeTile(MapNode mn,const v3s16 & p,const v3s16 & dir,MeshMakeData * data,TileSpec & tile)705 void getNodeTile(MapNode mn, const v3s16 &p, const v3s16 &dir, MeshMakeData *data, TileSpec &tile)
706 {
707 	const NodeDefManager *ndef = data->m_client->ndef();
708 
709 	// Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
710 	// (0,0,1), (0,0,-1) or (0,0,0)
711 	assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z <= 1);
712 
713 	// Convert direction to single integer for table lookup
714 	//  0 = (0,0,0)
715 	//  1 = (1,0,0)
716 	//  2 = (0,1,0)
717 	//  3 = (0,0,1)
718 	//  4 = invalid, treat as (0,0,0)
719 	//  5 = (0,0,-1)
720 	//  6 = (0,-1,0)
721 	//  7 = (-1,0,0)
722 	u8 dir_i = ((dir.X + 2 * dir.Y + 3 * dir.Z) & 7) * 2;
723 
724 	// Get rotation for things like chests
725 	u8 facedir = mn.getFaceDir(ndef, true);
726 
727 	static const u16 dir_to_tile[24 * 16] =
728 	{
729 		// 0     +X    +Y    +Z           -Z    -Y    -X   ->   value=tile,rotation
730 		   0,0,  2,0 , 0,0 , 4,0 ,  0,0,  5,0 , 1,0 , 3,0 ,  // rotate around y+ 0 - 3
731 		   0,0,  4,0 , 0,3 , 3,0 ,  0,0,  2,0 , 1,1 , 5,0 ,
732 		   0,0,  3,0 , 0,2 , 5,0 ,  0,0,  4,0 , 1,2 , 2,0 ,
733 		   0,0,  5,0 , 0,1 , 2,0 ,  0,0,  3,0 , 1,3 , 4,0 ,
734 
735 		   0,0,  2,3 , 5,0 , 0,2 ,  0,0,  1,0 , 4,2 , 3,1 ,  // rotate around z+ 4 - 7
736 		   0,0,  4,3 , 2,0 , 0,1 ,  0,0,  1,1 , 3,2 , 5,1 ,
737 		   0,0,  3,3 , 4,0 , 0,0 ,  0,0,  1,2 , 5,2 , 2,1 ,
738 		   0,0,  5,3 , 3,0 , 0,3 ,  0,0,  1,3 , 2,2 , 4,1 ,
739 
740 		   0,0,  2,1 , 4,2 , 1,2 ,  0,0,  0,0 , 5,0 , 3,3 ,  // rotate around z- 8 - 11
741 		   0,0,  4,1 , 3,2 , 1,3 ,  0,0,  0,3 , 2,0 , 5,3 ,
742 		   0,0,  3,1 , 5,2 , 1,0 ,  0,0,  0,2 , 4,0 , 2,3 ,
743 		   0,0,  5,1 , 2,2 , 1,1 ,  0,0,  0,1 , 3,0 , 4,3 ,
744 
745 		   0,0,  0,3 , 3,3 , 4,1 ,  0,0,  5,3 , 2,3 , 1,3 ,  // rotate around x+ 12 - 15
746 		   0,0,  0,2 , 5,3 , 3,1 ,  0,0,  2,3 , 4,3 , 1,0 ,
747 		   0,0,  0,1 , 2,3 , 5,1 ,  0,0,  4,3 , 3,3 , 1,1 ,
748 		   0,0,  0,0 , 4,3 , 2,1 ,  0,0,  3,3 , 5,3 , 1,2 ,
749 
750 		   0,0,  1,1 , 2,1 , 4,3 ,  0,0,  5,1 , 3,1 , 0,1 ,  // rotate around x- 16 - 19
751 		   0,0,  1,2 , 4,1 , 3,3 ,  0,0,  2,1 , 5,1 , 0,0 ,
752 		   0,0,  1,3 , 3,1 , 5,3 ,  0,0,  4,1 , 2,1 , 0,3 ,
753 		   0,0,  1,0 , 5,1 , 2,3 ,  0,0,  3,1 , 4,1 , 0,2 ,
754 
755 		   0,0,  3,2 , 1,2 , 4,2 ,  0,0,  5,2 , 0,2 , 2,2 ,  // rotate around y- 20 - 23
756 		   0,0,  5,2 , 1,3 , 3,2 ,  0,0,  2,2 , 0,1 , 4,2 ,
757 		   0,0,  2,2 , 1,0 , 5,2 ,  0,0,  4,2 , 0,0 , 3,2 ,
758 		   0,0,  4,2 , 1,1 , 2,2 ,  0,0,  3,2 , 0,3 , 5,2
759 
760 	};
761 	u16 tile_index = facedir * 16 + dir_i;
762 	getNodeTileN(mn, p, dir_to_tile[tile_index], data, tile);
763 	tile.rotation = tile.world_aligned ? 0 : dir_to_tile[tile_index + 1];
764 }
765 
getTileInfo(MeshMakeData * data,const v3s16 & p,const v3s16 & face_dir,bool & makes_face,v3s16 & p_corrected,v3s16 & face_dir_corrected,u16 * lights,u8 & waving,TileSpec & tile)766 static void getTileInfo(
767 		// Input:
768 		MeshMakeData *data,
769 		const v3s16 &p,
770 		const v3s16 &face_dir,
771 		// Output:
772 		bool &makes_face,
773 		v3s16 &p_corrected,
774 		v3s16 &face_dir_corrected,
775 		u16 *lights,
776 		u8 &waving,
777 		TileSpec &tile
778 	)
779 {
780 	VoxelManipulator &vmanip = data->m_vmanip;
781 	const NodeDefManager *ndef = data->m_client->ndef();
782 	v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
783 
784 	const MapNode &n0 = vmanip.getNodeRefUnsafe(blockpos_nodes + p);
785 
786 	// Don't even try to get n1 if n0 is already CONTENT_IGNORE
787 	if (n0.getContent() == CONTENT_IGNORE) {
788 		makes_face = false;
789 		return;
790 	}
791 
792 	const MapNode &n1 = vmanip.getNodeRefUnsafeCheckFlags(blockpos_nodes + p + face_dir);
793 
794 	if (n1.getContent() == CONTENT_IGNORE) {
795 		makes_face = false;
796 		return;
797 	}
798 
799 	// This is hackish
800 	bool equivalent = false;
801 	u8 mf = face_contents(n0.getContent(), n1.getContent(),
802 			&equivalent, ndef);
803 
804 	if (mf == 0) {
805 		makes_face = false;
806 		return;
807 	}
808 
809 	makes_face = true;
810 
811 	MapNode n = n0;
812 
813 	if (mf == 1) {
814 		p_corrected = p;
815 		face_dir_corrected = face_dir;
816 	} else {
817 		n = n1;
818 		p_corrected = p + face_dir;
819 		face_dir_corrected = -face_dir;
820 	}
821 
822 	getNodeTile(n, p_corrected, face_dir_corrected, data, tile);
823 	const ContentFeatures &f = ndef->get(n);
824 	waving = f.waving;
825 	tile.emissive_light = f.light_source;
826 
827 	// eg. water and glass
828 	if (equivalent) {
829 		for (TileLayer &layer : tile.layers)
830 			layer.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
831 	}
832 
833 	if (!data->m_smooth_lighting) {
834 		lights[0] = lights[1] = lights[2] = lights[3] =
835 				getFaceLight(n0, n1, face_dir, ndef);
836 	} else {
837 		v3s16 vertex_dirs[4];
838 		getNodeVertexDirs(face_dir_corrected, vertex_dirs);
839 
840 		v3s16 light_p = blockpos_nodes + p_corrected;
841 		for (u16 i = 0; i < 4; i++)
842 			lights[i] = getSmoothLightSolid(light_p, face_dir_corrected, vertex_dirs[i], data);
843 	}
844 }
845 
846 /*
847 	startpos:
848 	translate_dir: unit vector with only one of x, y or z
849 	face_dir: unit vector with only one of x, y or z
850 */
updateFastFaceRow(MeshMakeData * data,const v3s16 && startpos,v3s16 translate_dir,const v3f && translate_dir_f,const v3s16 && face_dir,std::vector<FastFace> & dest)851 static void updateFastFaceRow(
852 		MeshMakeData *data,
853 		const v3s16 &&startpos,
854 		v3s16 translate_dir,
855 		const v3f &&translate_dir_f,
856 		const v3s16 &&face_dir,
857 		std::vector<FastFace> &dest)
858 {
859 	static thread_local const bool waving_liquids =
860 		g_settings->getBool("enable_shaders") &&
861 		g_settings->getBool("enable_waving_water");
862 
863 	v3s16 p = startpos;
864 
865 	u16 continuous_tiles_count = 1;
866 
867 	bool makes_face = false;
868 	v3s16 p_corrected;
869 	v3s16 face_dir_corrected;
870 	u16 lights[4] = {0, 0, 0, 0};
871 	u8 waving = 0;
872 	TileSpec tile;
873 
874 	// Get info of first tile
875 	getTileInfo(data, p, face_dir,
876 			makes_face, p_corrected, face_dir_corrected,
877 			lights, waving, tile);
878 
879 	// Unroll this variable which has a significant build cost
880 	TileSpec next_tile;
881 	for (u16 j = 0; j < MAP_BLOCKSIZE; j++) {
882 		// If tiling can be done, this is set to false in the next step
883 		bool next_is_different = true;
884 
885 		bool next_makes_face = false;
886 		v3s16 next_p_corrected;
887 		v3s16 next_face_dir_corrected;
888 		u16 next_lights[4] = {0, 0, 0, 0};
889 
890 		// If at last position, there is nothing to compare to and
891 		// the face must be drawn anyway
892 		if (j != MAP_BLOCKSIZE - 1) {
893 			p += translate_dir;
894 
895 			getTileInfo(data, p, face_dir,
896 					next_makes_face, next_p_corrected,
897 					next_face_dir_corrected, next_lights,
898 					waving,
899 					next_tile);
900 
901 			if (next_makes_face == makes_face
902 					&& next_p_corrected == p_corrected + translate_dir
903 					&& next_face_dir_corrected == face_dir_corrected
904 					&& memcmp(next_lights, lights, sizeof(lights)) == 0
905 					// Don't apply fast faces to waving water.
906 					&& (waving != 3 || !waving_liquids)
907 					&& next_tile.isTileable(tile)) {
908 				next_is_different = false;
909 				continuous_tiles_count++;
910 			}
911 		}
912 		if (next_is_different) {
913 			/*
914 				Create a face if there should be one
915 			*/
916 			if (makes_face) {
917 				// Floating point conversion of the position vector
918 				v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
919 				// Center point of face (kind of)
920 				v3f sp = pf - ((f32)continuous_tiles_count * 0.5f - 0.5f)
921 					* translate_dir_f;
922 				v3f scale(1, 1, 1);
923 
924 				if (translate_dir.X != 0)
925 					scale.X = continuous_tiles_count;
926 				if (translate_dir.Y != 0)
927 					scale.Y = continuous_tiles_count;
928 				if (translate_dir.Z != 0)
929 					scale.Z = continuous_tiles_count;
930 
931 				makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
932 						pf, sp, face_dir_corrected, scale, dest);
933 				g_profiler->avg("Meshgen: Tiles per face [#]", continuous_tiles_count);
934 			}
935 
936 			continuous_tiles_count = 1;
937 		}
938 
939 		makes_face = next_makes_face;
940 		p_corrected = next_p_corrected;
941 		face_dir_corrected = next_face_dir_corrected;
942 		memcpy(lights, next_lights, sizeof(lights));
943 		if (next_is_different)
944 			tile = std::move(next_tile); // faster than copy
945 	}
946 }
947 
updateAllFastFaceRows(MeshMakeData * data,std::vector<FastFace> & dest)948 static void updateAllFastFaceRows(MeshMakeData *data,
949 		std::vector<FastFace> &dest)
950 {
951 	/*
952 		Go through every y,z and get top(y+) faces in rows of x+
953 	*/
954 	for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
955 	for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
956 		updateFastFaceRow(data,
957 				v3s16(0, y, z),
958 				v3s16(1, 0, 0), //dir
959 				v3f  (1, 0, 0),
960 				v3s16(0, 1, 0), //face dir
961 				dest);
962 
963 	/*
964 		Go through every x,y and get right(x+) faces in rows of z+
965 	*/
966 	for (s16 x = 0; x < MAP_BLOCKSIZE; x++)
967 	for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
968 		updateFastFaceRow(data,
969 				v3s16(x, y, 0),
970 				v3s16(0, 0, 1), //dir
971 				v3f  (0, 0, 1),
972 				v3s16(1, 0, 0), //face dir
973 				dest);
974 
975 	/*
976 		Go through every y,z and get back(z+) faces in rows of x+
977 	*/
978 	for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
979 	for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
980 		updateFastFaceRow(data,
981 				v3s16(0, y, z),
982 				v3s16(1, 0, 0), //dir
983 				v3f  (1, 0, 0),
984 				v3s16(0, 0, 1), //face dir
985 				dest);
986 }
987 
applyTileColor(PreMeshBuffer & pmb)988 static void applyTileColor(PreMeshBuffer &pmb)
989 {
990 	video::SColor tc = pmb.layer.color;
991 	if (tc == video::SColor(0xFFFFFFFF))
992 		return;
993 	for (video::S3DVertex &vertex : pmb.vertices) {
994 		video::SColor *c = &vertex.Color;
995 		c->set(c->getAlpha(),
996 			c->getRed() * tc.getRed() / 255,
997 			c->getGreen() * tc.getGreen() / 255,
998 			c->getBlue() * tc.getBlue() / 255);
999 	}
1000 }
1001 
1002 /*
1003 	MapBlockMesh
1004 */
1005 
MapBlockMesh(MeshMakeData * data,v3s16 camera_offset)1006 MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
1007 	m_minimap_mapblock(NULL),
1008 	m_tsrc(data->m_client->getTextureSource()),
1009 	m_shdrsrc(data->m_client->getShaderSource()),
1010 	m_animation_force_timer(0), // force initial animation
1011 	m_last_crack(-1),
1012 	m_last_daynight_ratio((u32) -1)
1013 {
1014 	for (auto &m : m_mesh)
1015 		m = new scene::SMesh();
1016 	m_enable_shaders = data->m_use_shaders;
1017 	m_enable_vbo = g_settings->getBool("enable_vbo");
1018 
1019 	if (data->m_client->getMinimap()) {
1020 		m_minimap_mapblock = new MinimapMapblock;
1021 		m_minimap_mapblock->getMinimapNodes(
1022 			&data->m_vmanip, data->m_blockpos * MAP_BLOCKSIZE);
1023 	}
1024 
1025 	// 4-21ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1026 	// 24-155ms for MAP_BLOCKSIZE=32  (NOTE: probably outdated)
1027 	//TimeTaker timer1("MapBlockMesh()");
1028 
1029 	std::vector<FastFace> fastfaces_new;
1030 	fastfaces_new.reserve(512);
1031 
1032 	/*
1033 		We are including the faces of the trailing edges of the block.
1034 		This means that when something changes, the caller must
1035 		also update the meshes of the blocks at the leading edges.
1036 
1037 		NOTE: This is the slowest part of this method.
1038 	*/
1039 	{
1040 		// 4-23ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1041 		//TimeTaker timer2("updateAllFastFaceRows()");
1042 		updateAllFastFaceRows(data, fastfaces_new);
1043 	}
1044 	// End of slow part
1045 
1046 	/*
1047 		Convert FastFaces to MeshCollector
1048 	*/
1049 
1050 	MeshCollector collector;
1051 
1052 	{
1053 		// avg 0ms (100ms spikes when loading textures the first time)
1054 		// (NOTE: probably outdated)
1055 		//TimeTaker timer2("MeshCollector building");
1056 
1057 		for (const FastFace &f : fastfaces_new) {
1058 			static const u16 indices[] = {0, 1, 2, 2, 3, 0};
1059 			static const u16 indices_alternate[] = {0, 1, 3, 2, 3, 1};
1060 			const u16 *indices_p =
1061 				f.vertex_0_2_connected ? indices : indices_alternate;
1062 			collector.append(f.tile, f.vertices, 4, indices_p, 6);
1063 		}
1064 	}
1065 
1066 	/*
1067 		Add special graphics:
1068 		- torches
1069 		- flowing water
1070 		- fences
1071 		- whatever
1072 	*/
1073 
1074 	{
1075 		MapblockMeshGenerator generator(data, &collector);
1076 		generator.generate();
1077 	}
1078 
1079 	/*
1080 		Convert MeshCollector to SMesh
1081 	*/
1082 
1083 	for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
1084 		for(u32 i = 0; i < collector.prebuffers[layer].size(); i++)
1085 		{
1086 			PreMeshBuffer &p = collector.prebuffers[layer][i];
1087 
1088 			applyTileColor(p);
1089 
1090 			// Generate animation data
1091 			// - Cracks
1092 			if (p.layer.material_flags & MATERIAL_FLAG_CRACK) {
1093 				// Find the texture name plus ^[crack:N:
1094 				std::ostringstream os(std::ios::binary);
1095 				os << m_tsrc->getTextureName(p.layer.texture_id) << "^[crack";
1096 				if (p.layer.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1097 					os << "o";  // use ^[cracko
1098 				u8 tiles = p.layer.scale;
1099 				if (tiles > 1)
1100 					os << ":" << (u32)tiles;
1101 				os << ":" << (u32)p.layer.animation_frame_count << ":";
1102 				m_crack_materials.insert(std::make_pair(
1103 						std::pair<u8, u32>(layer, i), os.str()));
1104 				// Replace tile texture with the cracked one
1105 				p.layer.texture = m_tsrc->getTextureForMesh(
1106 						os.str() + "0",
1107 						&p.layer.texture_id);
1108 			}
1109 			// - Texture animation
1110 			if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
1111 				// Add to MapBlockMesh in order to animate these tiles
1112 				m_animation_tiles[std::pair<u8, u32>(layer, i)] = p.layer;
1113 				m_animation_frames[std::pair<u8, u32>(layer, i)] = 0;
1114 				if (g_settings->getBool(
1115 						"desynchronize_mapblock_texture_animation")) {
1116 					// Get starting position from noise
1117 					m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] =
1118 							100000 * (2.0 + noise3d(
1119 							data->m_blockpos.X, data->m_blockpos.Y,
1120 							data->m_blockpos.Z, 0));
1121 				} else {
1122 					// Play all synchronized
1123 					m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] = 0;
1124 				}
1125 				// Replace tile texture with the first animation frame
1126 				p.layer.texture = (*p.layer.frames)[0].texture;
1127 			}
1128 
1129 			if (!m_enable_shaders) {
1130 				// Extract colors for day-night animation
1131 				// Dummy sunlight to handle non-sunlit areas
1132 				video::SColorf sunlight;
1133 				get_sunlight_color(&sunlight, 0);
1134 				u32 vertex_count = p.vertices.size();
1135 				for (u32 j = 0; j < vertex_count; j++) {
1136 					video::SColor *vc = &p.vertices[j].Color;
1137 					video::SColor copy = *vc;
1138 					if (vc->getAlpha() == 0) // No sunlight - no need to animate
1139 						final_color_blend(vc, copy, sunlight); // Finalize color
1140 					else // Record color to animate
1141 						m_daynight_diffs[std::pair<u8, u32>(layer, i)][j] = copy;
1142 
1143 					// The sunlight ratio has been stored,
1144 					// delete alpha (for the final rendering).
1145 					vc->setAlpha(255);
1146 				}
1147 			}
1148 
1149 			// Create material
1150 			video::SMaterial material;
1151 			material.setFlag(video::EMF_LIGHTING, false);
1152 			material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1153 			material.setFlag(video::EMF_BILINEAR_FILTER, false);
1154 			material.setFlag(video::EMF_FOG_ENABLE, true);
1155 			material.setTexture(0, p.layer.texture);
1156 
1157 			if (m_enable_shaders) {
1158 				material.MaterialType = m_shdrsrc->getShaderInfo(
1159 						p.layer.shader_id).material;
1160 				p.layer.applyMaterialOptionsWithShaders(material);
1161 				if (p.layer.normal_texture)
1162 					material.setTexture(1, p.layer.normal_texture);
1163 				material.setTexture(2, p.layer.flags_texture);
1164 			} else {
1165 				p.layer.applyMaterialOptions(material);
1166 			}
1167 
1168 			scene::SMesh *mesh = (scene::SMesh *)m_mesh[layer];
1169 
1170 			scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1171 			buf->Material = material;
1172 			buf->append(&p.vertices[0], p.vertices.size(),
1173 				&p.indices[0], p.indices.size());
1174 			mesh->addMeshBuffer(buf);
1175 			buf->drop();
1176 		}
1177 
1178 		if (m_mesh[layer]) {
1179 			// Use VBO for mesh (this just would set this for ever buffer)
1180 			if (m_enable_vbo)
1181 				m_mesh[layer]->setHardwareMappingHint(scene::EHM_STATIC);
1182 		}
1183 	}
1184 
1185 	//std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1186 
1187 	// Check if animation is required for this mesh
1188 	m_has_animation =
1189 		!m_crack_materials.empty() ||
1190 		!m_daynight_diffs.empty() ||
1191 		!m_animation_tiles.empty();
1192 }
1193 
~MapBlockMesh()1194 MapBlockMesh::~MapBlockMesh()
1195 {
1196 	for (scene::IMesh *m : m_mesh) {
1197 		if (m_enable_vbo) {
1198 			for (u32 i = 0; i < m->getMeshBufferCount(); i++) {
1199 				scene::IMeshBuffer *buf = m->getMeshBuffer(i);
1200 				RenderingEngine::get_video_driver()->removeHardwareBuffer(buf);
1201 			}
1202 		}
1203 		m->drop();
1204 	}
1205 	delete m_minimap_mapblock;
1206 }
1207 
animate(bool faraway,float time,int crack,u32 daynight_ratio)1208 bool MapBlockMesh::animate(bool faraway, float time, int crack,
1209 	u32 daynight_ratio)
1210 {
1211 	if (!m_has_animation) {
1212 		m_animation_force_timer = 100000;
1213 		return false;
1214 	}
1215 
1216 	m_animation_force_timer = myrand_range(5, 100);
1217 
1218 	// Cracks
1219 	if (crack != m_last_crack) {
1220 		for (auto &crack_material : m_crack_materials) {
1221 			scene::IMeshBuffer *buf = m_mesh[crack_material.first.first]->
1222 				getMeshBuffer(crack_material.first.second);
1223 			std::string basename = crack_material.second;
1224 
1225 			// Create new texture name from original
1226 			std::ostringstream os;
1227 			os << basename << crack;
1228 			u32 new_texture_id = 0;
1229 			video::ITexture *new_texture =
1230 					m_tsrc->getTextureForMesh(os.str(), &new_texture_id);
1231 			buf->getMaterial().setTexture(0, new_texture);
1232 
1233 			// If the current material is also animated,
1234 			// update animation info
1235 			auto anim_iter = m_animation_tiles.find(crack_material.first);
1236 			if (anim_iter != m_animation_tiles.end()) {
1237 				TileLayer &tile = anim_iter->second;
1238 				tile.texture = new_texture;
1239 				tile.texture_id = new_texture_id;
1240 				// force animation update
1241 				m_animation_frames[crack_material.first] = -1;
1242 			}
1243 		}
1244 
1245 		m_last_crack = crack;
1246 	}
1247 
1248 	// Texture animation
1249 	for (auto &animation_tile : m_animation_tiles) {
1250 		const TileLayer &tile = animation_tile.second;
1251 		// Figure out current frame
1252 		int frameoffset = m_animation_frame_offsets[animation_tile.first];
1253 		int frame = (int)(time * 1000 / tile.animation_frame_length_ms
1254 				+ frameoffset) % tile.animation_frame_count;
1255 		// If frame doesn't change, skip
1256 		if (frame == m_animation_frames[animation_tile.first])
1257 			continue;
1258 
1259 		m_animation_frames[animation_tile.first] = frame;
1260 
1261 		scene::IMeshBuffer *buf = m_mesh[animation_tile.first.first]->
1262 			getMeshBuffer(animation_tile.first.second);
1263 
1264 		const FrameSpec &animation_frame = (*tile.frames)[frame];
1265 		buf->getMaterial().setTexture(0, animation_frame.texture);
1266 		if (m_enable_shaders) {
1267 			if (animation_frame.normal_texture)
1268 				buf->getMaterial().setTexture(1,
1269 					animation_frame.normal_texture);
1270 			buf->getMaterial().setTexture(2, animation_frame.flags_texture);
1271 		}
1272 	}
1273 
1274 	// Day-night transition
1275 	if (!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio)) {
1276 		// Force reload mesh to VBO
1277 		if (m_enable_vbo)
1278 			for (scene::IMesh *m : m_mesh)
1279 				m->setDirty();
1280 		video::SColorf day_color;
1281 		get_sunlight_color(&day_color, daynight_ratio);
1282 
1283 		for (auto &daynight_diff : m_daynight_diffs) {
1284 			scene::IMeshBuffer *buf = m_mesh[daynight_diff.first.first]->
1285 				getMeshBuffer(daynight_diff.first.second);
1286 			video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
1287 			for (const auto &j : daynight_diff.second)
1288 				final_color_blend(&(vertices[j.first].Color), j.second,
1289 						day_color);
1290 		}
1291 		m_last_daynight_ratio = daynight_ratio;
1292 	}
1293 
1294 	return true;
1295 }
1296 
encode_light(u16 light,u8 emissive_light)1297 video::SColor encode_light(u16 light, u8 emissive_light)
1298 {
1299 	// Get components
1300 	u32 day = (light & 0xff);
1301 	u32 night = (light >> 8);
1302 	// Add emissive light
1303 	night += emissive_light * 2.5f;
1304 	if (night > 255)
1305 		night = 255;
1306 	// Since we don't know if the day light is sunlight or
1307 	// artificial light, assume it is artificial when the night
1308 	// light bank is also lit.
1309 	if (day < night)
1310 		day = 0;
1311 	else
1312 		day = day - night;
1313 	u32 sum = day + night;
1314 	// Ratio of sunlight:
1315 	u32 r;
1316 	if (sum > 0)
1317 		r = day * 255 / sum;
1318 	else
1319 		r = 0;
1320 	// Average light:
1321 	float b = (day + night) / 2;
1322 	return video::SColor(r, b, b, b);
1323 }
1324