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