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