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