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