]> git.lizzy.rs Git - dragonfireclient.git/blob - src/client/mapblock_mesh.cpp
Fix some minor code issues all over the place
[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;
426                 *v = base.Z;
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         v3s16 p = startpos;
864
865         u16 continuous_tiles_count = 1;
866
867         bool makes_face = false;
868         v3s16 p_corrected;
869         v3s16 face_dir_corrected;
870         u16 lights[4] = {0, 0, 0, 0};
871         u8 waving = 0;
872         TileSpec tile;
873
874         // Get info of first tile
875         getTileInfo(data, p, face_dir,
876                         makes_face, p_corrected, face_dir_corrected,
877                         lights, waving, tile);
878
879         // Unroll this variable which has a significant build cost
880         TileSpec next_tile;
881         for (u16 j = 0; j < MAP_BLOCKSIZE; j++) {
882                 // If tiling can be done, this is set to false in the next step
883                 bool next_is_different = true;
884
885                 bool next_makes_face = false;
886                 v3s16 next_p_corrected;
887                 v3s16 next_face_dir_corrected;
888                 u16 next_lights[4] = {0, 0, 0, 0};
889
890                 // If at last position, there is nothing to compare to and
891                 // the face must be drawn anyway
892                 if (j != MAP_BLOCKSIZE - 1) {
893                         p += translate_dir;
894
895                         getTileInfo(data, p, face_dir,
896                                         next_makes_face, next_p_corrected,
897                                         next_face_dir_corrected, next_lights,
898                                         waving,
899                                         next_tile);
900
901                         if (next_makes_face == makes_face
902                                         && next_p_corrected == p_corrected + translate_dir
903                                         && next_face_dir_corrected == face_dir_corrected
904                                         && memcmp(next_lights, lights, sizeof(lights)) == 0
905                                         // Don't apply fast faces to waving water.
906                                         && (waving != 3 || !waving_liquids)
907                                         && next_tile.isTileable(tile)) {
908                                 next_is_different = false;
909                                 continuous_tiles_count++;
910                         }
911                 }
912                 if (next_is_different) {
913                         /*
914                                 Create a face if there should be one
915                         */
916                         if (makes_face) {
917                                 // Floating point conversion of the position vector
918                                 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
919                                 // Center point of face (kind of)
920                                 v3f sp = pf - ((f32)continuous_tiles_count * 0.5f - 0.5f)
921                                         * translate_dir_f;
922                                 v3f scale(1, 1, 1);
923
924                                 if (translate_dir.X != 0)
925                                         scale.X = continuous_tiles_count;
926                                 if (translate_dir.Y != 0)
927                                         scale.Y = continuous_tiles_count;
928                                 if (translate_dir.Z != 0)
929                                         scale.Z = continuous_tiles_count;
930
931                                 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
932                                                 pf, sp, face_dir_corrected, scale, dest);
933                                 g_profiler->avg("Meshgen: Tiles per face [#]", continuous_tiles_count);
934                         }
935
936                         continuous_tiles_count = 1;
937                 }
938
939                 makes_face = next_makes_face;
940                 p_corrected = next_p_corrected;
941                 face_dir_corrected = next_face_dir_corrected;
942                 memcpy(lights, next_lights, sizeof(lights));
943                 if (next_is_different)
944                         tile = std::move(next_tile); // faster than copy
945         }
946 }
947
948 static void updateAllFastFaceRows(MeshMakeData *data,
949                 std::vector<FastFace> &dest)
950 {
951         /*
952                 Go through every y,z and get top(y+) faces in rows of x+
953         */
954         for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
955         for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
956                 updateFastFaceRow(data,
957                                 v3s16(0, y, z),
958                                 v3s16(1, 0, 0), //dir
959                                 v3f  (1, 0, 0),
960                                 v3s16(0, 1, 0), //face dir
961                                 dest);
962
963         /*
964                 Go through every x,y and get right(x+) faces in rows of z+
965         */
966         for (s16 x = 0; x < MAP_BLOCKSIZE; x++)
967         for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
968                 updateFastFaceRow(data,
969                                 v3s16(x, y, 0),
970                                 v3s16(0, 0, 1), //dir
971                                 v3f  (0, 0, 1),
972                                 v3s16(1, 0, 0), //face dir
973                                 dest);
974
975         /*
976                 Go through every y,z and get back(z+) faces in rows of x+
977         */
978         for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
979         for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
980                 updateFastFaceRow(data,
981                                 v3s16(0, y, z),
982                                 v3s16(1, 0, 0), //dir
983                                 v3f  (1, 0, 0),
984                                 v3s16(0, 0, 1), //face dir
985                                 dest);
986 }
987
988 static void applyTileColor(PreMeshBuffer &pmb)
989 {
990         video::SColor tc = pmb.layer.color;
991         if (tc == video::SColor(0xFFFFFFFF))
992                 return;
993         for (video::S3DVertex &vertex : pmb.vertices) {
994                 video::SColor *c = &vertex.Color;
995                 c->set(c->getAlpha(),
996                         c->getRed() * tc.getRed() / 255,
997                         c->getGreen() * tc.getGreen() / 255,
998                         c->getBlue() * tc.getBlue() / 255);
999         }
1000 }
1001
1002 /*
1003         MapBlockMesh
1004 */
1005
1006 MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
1007         m_minimap_mapblock(NULL),
1008         m_tsrc(data->m_client->getTextureSource()),
1009         m_shdrsrc(data->m_client->getShaderSource()),
1010         m_animation_force_timer(0), // force initial animation
1011         m_last_crack(-1),
1012         m_last_daynight_ratio((u32) -1)
1013 {
1014         for (auto &m : m_mesh)
1015                 m = new scene::SMesh();
1016         m_enable_shaders = data->m_use_shaders;
1017         m_enable_vbo = g_settings->getBool("enable_vbo");
1018
1019         if (data->m_client->getMinimap()) {
1020                 m_minimap_mapblock = new MinimapMapblock;
1021                 m_minimap_mapblock->getMinimapNodes(
1022                         &data->m_vmanip, data->m_blockpos * MAP_BLOCKSIZE);
1023         }
1024
1025         // 4-21ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1026         // 24-155ms for MAP_BLOCKSIZE=32  (NOTE: probably outdated)
1027         //TimeTaker timer1("MapBlockMesh()");
1028
1029         std::vector<FastFace> fastfaces_new;
1030         fastfaces_new.reserve(512);
1031
1032         /*
1033                 We are including the faces of the trailing edges of the block.
1034                 This means that when something changes, the caller must
1035                 also update the meshes of the blocks at the leading edges.
1036
1037                 NOTE: This is the slowest part of this method.
1038         */
1039         {
1040                 // 4-23ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1041                 //TimeTaker timer2("updateAllFastFaceRows()");
1042                 updateAllFastFaceRows(data, fastfaces_new);
1043         }
1044         // End of slow part
1045
1046         /*
1047                 Convert FastFaces to MeshCollector
1048         */
1049
1050         MeshCollector collector;
1051
1052         {
1053                 // avg 0ms (100ms spikes when loading textures the first time)
1054                 // (NOTE: probably outdated)
1055                 //TimeTaker timer2("MeshCollector building");
1056
1057                 for (const FastFace &f : fastfaces_new) {
1058                         static const u16 indices[] = {0, 1, 2, 2, 3, 0};
1059                         static const u16 indices_alternate[] = {0, 1, 3, 2, 3, 1};
1060                         const u16 *indices_p =
1061                                 f.vertex_0_2_connected ? indices : indices_alternate;
1062                         collector.append(f.tile, f.vertices, 4, indices_p, 6);
1063                 }
1064         }
1065
1066         /*
1067                 Add special graphics:
1068                 - torches
1069                 - flowing water
1070                 - fences
1071                 - whatever
1072         */
1073
1074         {
1075                 MapblockMeshGenerator generator(data, &collector);
1076                 generator.generate();
1077         }
1078
1079         /*
1080                 Convert MeshCollector to SMesh
1081         */
1082
1083         for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
1084                 for(u32 i = 0; i < collector.prebuffers[layer].size(); i++)
1085                 {
1086                         PreMeshBuffer &p = collector.prebuffers[layer][i];
1087
1088                         applyTileColor(p);
1089
1090                         // Generate animation data
1091                         // - Cracks
1092                         if (p.layer.material_flags & MATERIAL_FLAG_CRACK) {
1093                                 // Find the texture name plus ^[crack:N:
1094                                 std::ostringstream os(std::ios::binary);
1095                                 os << m_tsrc->getTextureName(p.layer.texture_id) << "^[crack";
1096                                 if (p.layer.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1097                                         os << "o";  // use ^[cracko
1098                                 u8 tiles = p.layer.scale;
1099                                 if (tiles > 1)
1100                                         os << ":" << (u32)tiles;
1101                                 os << ":" << (u32)p.layer.animation_frame_count << ":";
1102                                 m_crack_materials.insert(std::make_pair(
1103                                                 std::pair<u8, u32>(layer, i), os.str()));
1104                                 // Replace tile texture with the cracked one
1105                                 p.layer.texture = m_tsrc->getTextureForMesh(
1106                                                 os.str() + "0",
1107                                                 &p.layer.texture_id);
1108                         }
1109                         // - Texture animation
1110                         if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
1111                                 // Add to MapBlockMesh in order to animate these tiles
1112                                 m_animation_tiles[std::pair<u8, u32>(layer, i)] = p.layer;
1113                                 m_animation_frames[std::pair<u8, u32>(layer, i)] = 0;
1114                                 if (g_settings->getBool(
1115                                                 "desynchronize_mapblock_texture_animation")) {
1116                                         // Get starting position from noise
1117                                         m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] =
1118                                                         100000 * (2.0 + noise3d(
1119                                                         data->m_blockpos.X, data->m_blockpos.Y,
1120                                                         data->m_blockpos.Z, 0));
1121                                 } else {
1122                                         // Play all synchronized
1123                                         m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] = 0;
1124                                 }
1125                                 // Replace tile texture with the first animation frame
1126                                 p.layer.texture = (*p.layer.frames)[0].texture;
1127                         }
1128
1129                         if (!m_enable_shaders) {
1130                                 // Extract colors for day-night animation
1131                                 // Dummy sunlight to handle non-sunlit areas
1132                                 video::SColorf sunlight;
1133                                 get_sunlight_color(&sunlight, 0);
1134                                 u32 vertex_count = p.vertices.size();
1135                                 for (u32 j = 0; j < vertex_count; j++) {
1136                                         video::SColor *vc = &p.vertices[j].Color;
1137                                         video::SColor copy = *vc;
1138                                         if (vc->getAlpha() == 0) // No sunlight - no need to animate
1139                                                 final_color_blend(vc, copy, sunlight); // Finalize color
1140                                         else // Record color to animate
1141                                                 m_daynight_diffs[std::pair<u8, u32>(layer, i)][j] = copy;
1142
1143                                         // The sunlight ratio has been stored,
1144                                         // delete alpha (for the final rendering).
1145                                         vc->setAlpha(255);
1146                                 }
1147                         }
1148
1149                         // Create material
1150                         video::SMaterial material;
1151                         material.setFlag(video::EMF_LIGHTING, false);
1152                         material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1153                         material.setFlag(video::EMF_BILINEAR_FILTER, false);
1154                         material.setFlag(video::EMF_FOG_ENABLE, true);
1155                         material.setTexture(0, p.layer.texture);
1156
1157                         if (m_enable_shaders) {
1158                                 material.MaterialType = m_shdrsrc->getShaderInfo(
1159                                                 p.layer.shader_id).material;
1160                                 p.layer.applyMaterialOptionsWithShaders(material);
1161                                 if (p.layer.normal_texture)
1162                                         material.setTexture(1, p.layer.normal_texture);
1163                                 material.setTexture(2, p.layer.flags_texture);
1164                         } else {
1165                                 p.layer.applyMaterialOptions(material);
1166                         }
1167
1168                         scene::SMesh *mesh = (scene::SMesh *)m_mesh[layer];
1169
1170                         scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1171                         buf->Material = material;
1172                         buf->append(&p.vertices[0], p.vertices.size(),
1173                                 &p.indices[0], p.indices.size());
1174                         mesh->addMeshBuffer(buf);
1175                         buf->drop();
1176                 }
1177
1178                 if (m_mesh[layer]) {
1179 #if 0
1180                         // Usually 1-700 faces and 1-7 materials
1181                         std::cout << "Updated MapBlock has " << fastfaces_new.size()
1182                                         << " faces and uses " << m_mesh[layer]->getMeshBufferCount()
1183                                         << " materials (meshbuffers)" << std::endl;
1184 #endif
1185
1186                         // Use VBO for mesh (this just would set this for ever buffer)
1187                         if (m_enable_vbo)
1188                                 m_mesh[layer]->setHardwareMappingHint(scene::EHM_STATIC);
1189                 }
1190         }
1191
1192         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1193
1194         // Check if animation is required for this mesh
1195         m_has_animation =
1196                 !m_crack_materials.empty() ||
1197                 !m_daynight_diffs.empty() ||
1198                 !m_animation_tiles.empty();
1199 }
1200
1201 MapBlockMesh::~MapBlockMesh()
1202 {
1203         for (scene::IMesh *m : m_mesh) {
1204                 if (m_enable_vbo) {
1205                         for (u32 i = 0; i < m->getMeshBufferCount(); i++) {
1206                                 scene::IMeshBuffer *buf = m->getMeshBuffer(i);
1207                                 RenderingEngine::get_video_driver()->removeHardwareBuffer(buf);
1208                         }
1209                 }
1210                 m->drop();
1211         }
1212         delete m_minimap_mapblock;
1213 }
1214
1215 bool MapBlockMesh::animate(bool faraway, float time, int crack,
1216         u32 daynight_ratio)
1217 {
1218         if (!m_has_animation) {
1219                 m_animation_force_timer = 100000;
1220                 return false;
1221         }
1222
1223         m_animation_force_timer = myrand_range(5, 100);
1224
1225         // Cracks
1226         if (crack != m_last_crack) {
1227                 for (auto &crack_material : m_crack_materials) {
1228                         scene::IMeshBuffer *buf = m_mesh[crack_material.first.first]->
1229                                 getMeshBuffer(crack_material.first.second);
1230                         std::string basename = crack_material.second;
1231
1232                         // Create new texture name from original
1233                         std::ostringstream os;
1234                         os << basename << crack;
1235                         u32 new_texture_id = 0;
1236                         video::ITexture *new_texture =
1237                                         m_tsrc->getTextureForMesh(os.str(), &new_texture_id);
1238                         buf->getMaterial().setTexture(0, new_texture);
1239
1240                         // If the current material is also animated,
1241                         // update animation info
1242                         auto anim_iter = m_animation_tiles.find(crack_material.first);
1243                         if (anim_iter != m_animation_tiles.end()) {
1244                                 TileLayer &tile = anim_iter->second;
1245                                 tile.texture = new_texture;
1246                                 tile.texture_id = new_texture_id;
1247                                 // force animation update
1248                                 m_animation_frames[crack_material.first] = -1;
1249                         }
1250                 }
1251
1252                 m_last_crack = crack;
1253         }
1254
1255         // Texture animation
1256         for (auto &animation_tile : m_animation_tiles) {
1257                 const TileLayer &tile = animation_tile.second;
1258                 // Figure out current frame
1259                 int frameoffset = m_animation_frame_offsets[animation_tile.first];
1260                 int frame = (int)(time * 1000 / tile.animation_frame_length_ms
1261                                 + frameoffset) % tile.animation_frame_count;
1262                 // If frame doesn't change, skip
1263                 if (frame == m_animation_frames[animation_tile.first])
1264                         continue;
1265
1266                 m_animation_frames[animation_tile.first] = frame;
1267
1268                 scene::IMeshBuffer *buf = m_mesh[animation_tile.first.first]->
1269                         getMeshBuffer(animation_tile.first.second);
1270
1271                 const FrameSpec &animation_frame = (*tile.frames)[frame];
1272                 buf->getMaterial().setTexture(0, animation_frame.texture);
1273                 if (m_enable_shaders) {
1274                         if (animation_frame.normal_texture)
1275                                 buf->getMaterial().setTexture(1,
1276                                         animation_frame.normal_texture);
1277                         buf->getMaterial().setTexture(2, animation_frame.flags_texture);
1278                 }
1279         }
1280
1281         // Day-night transition
1282         if (!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio)) {
1283                 // Force reload mesh to VBO
1284                 if (m_enable_vbo)
1285                         for (scene::IMesh *m : m_mesh)
1286                                 m->setDirty();
1287                 video::SColorf day_color;
1288                 get_sunlight_color(&day_color, daynight_ratio);
1289
1290                 for (auto &daynight_diff : m_daynight_diffs) {
1291                         scene::IMeshBuffer *buf = m_mesh[daynight_diff.first.first]->
1292                                 getMeshBuffer(daynight_diff.first.second);
1293                         video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
1294                         for (const auto &j : daynight_diff.second)
1295                                 final_color_blend(&(vertices[j.first].Color), j.second,
1296                                                 day_color);
1297                 }
1298                 m_last_daynight_ratio = daynight_ratio;
1299         }
1300
1301         return true;
1302 }
1303
1304 video::SColor encode_light(u16 light, u8 emissive_light)
1305 {
1306         // Get components
1307         u32 day = (light & 0xff);
1308         u32 night = (light >> 8);
1309         // Add emissive light
1310         night += emissive_light * 2.5f;
1311         if (night > 255)
1312                 night = 255;
1313         // Since we don't know if the day light is sunlight or
1314         // artificial light, assume it is artificial when the night
1315         // light bank is also lit.
1316         if (day < night)
1317                 day = 0;
1318         else
1319                 day = day - night;
1320         u32 sum = day + night;
1321         // Ratio of sunlight:
1322         u32 r;
1323         if (sum > 0)
1324                 r = day * 255 / sum;
1325         else
1326                 r = 0;
1327         // Average light:
1328         float b = (day + night) / 2;
1329         return video::SColor(r, b, b, b);
1330 }