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