]> git.lizzy.rs Git - minetest.git/blob - src/client/mapblock_mesh.cpp
Remove unused functions reported by cppcheck (#10463)
[minetest.git] / src / client / mapblock_mesh.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "mapblock_mesh.h"
21 #include "client.h"
22 #include "mapblock.h"
23 #include "map.h"
24 #include "profiler.h"
25 #include "shader.h"
26 #include "mesh.h"
27 #include "minimap.h"
28 #include "content_mapblock.h"
29 #include "util/directiontables.h"
30 #include "client/meshgen/collector.h"
31 #include "client/renderingengine.h"
32 #include <array>
33
34 /*
35         MeshMakeData
36 */
37
38 MeshMakeData::MeshMakeData(Client *client, bool use_shaders,
39                 bool use_tangent_vertices):
40         m_client(client),
41         m_use_shaders(use_shaders),
42         m_use_tangent_vertices(use_tangent_vertices)
43 {}
44
45 void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos)
46 {
47         m_blockpos = blockpos;
48
49         v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
50
51         m_vmanip.clear();
52         VoxelArea voxel_area(blockpos_nodes - v3s16(1,1,1) * MAP_BLOCKSIZE,
53                         blockpos_nodes + v3s16(1,1,1) * MAP_BLOCKSIZE*2-v3s16(1,1,1));
54         m_vmanip.addArea(voxel_area);
55 }
56
57 void MeshMakeData::fillBlockData(const v3s16 &block_offset, MapNode *data)
58 {
59         v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
60         VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
61
62         v3s16 bp = m_blockpos + block_offset;
63         v3s16 blockpos_nodes = bp * MAP_BLOCKSIZE;
64         m_vmanip.copyFrom(data, data_area, v3s16(0,0,0), blockpos_nodes, data_size);
65 }
66
67 void MeshMakeData::fill(MapBlock *block)
68 {
69         fillBlockDataBegin(block->getPos());
70
71         fillBlockData(v3s16(0,0,0), block->getData());
72
73         // Get map for reading neighbor blocks
74         Map *map = block->getParent();
75
76         for (const v3s16 &dir : g_26dirs) {
77                 v3s16 bp = m_blockpos + dir;
78                 MapBlock *b = map->getBlockNoCreateNoEx(bp);
79                 if(b)
80                         fillBlockData(dir, b->getData());
81         }
82 }
83
84 void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
85 {
86         if (crack_level >= 0)
87                 m_crack_pos_relative = crack_pos - m_blockpos*MAP_BLOCKSIZE;
88 }
89
90 void MeshMakeData::setSmoothLighting(bool smooth_lighting)
91 {
92         m_smooth_lighting = smooth_lighting;
93 }
94
95 /*
96         Light and vertex color functions
97 */
98
99 /*
100         Calculate non-smooth lighting at interior of node.
101         Single light bank.
102 */
103 static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
104         const NodeDefManager *ndef)
105 {
106         u8 light = n.getLight(bank, ndef);
107         if (light > 0)
108                 light = rangelim(light + increment, 0, LIGHT_SUN);
109         return decode_light(light);
110 }
111
112 /*
113         Calculate non-smooth lighting at interior of node.
114         Both light banks.
115 */
116 u16 getInteriorLight(MapNode n, s32 increment, const NodeDefManager *ndef)
117 {
118         u16 day = getInteriorLight(LIGHTBANK_DAY, n, increment, ndef);
119         u16 night = getInteriorLight(LIGHTBANK_NIGHT, n, increment, ndef);
120         return day | (night << 8);
121 }
122
123 /*
124         Calculate non-smooth lighting at face of node.
125         Single light bank.
126 */
127 static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
128         v3s16 face_dir, const NodeDefManager *ndef)
129 {
130         u8 light;
131         u8 l1 = n.getLight(bank, ndef);
132         u8 l2 = n2.getLight(bank, ndef);
133         if(l1 > l2)
134                 light = l1;
135         else
136                 light = l2;
137
138         // Boost light level for light sources
139         u8 light_source = MYMAX(ndef->get(n).light_source,
140                         ndef->get(n2).light_source);
141         if(light_source > light)
142                 light = light_source;
143
144         return decode_light(light);
145 }
146
147 /*
148         Calculate non-smooth lighting at face of node.
149         Both light banks.
150 */
151 u16 getFaceLight(MapNode n, MapNode n2, const v3s16 &face_dir,
152         const NodeDefManager *ndef)
153 {
154         u16 day = getFaceLight(LIGHTBANK_DAY, n, n2, face_dir, ndef);
155         u16 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, face_dir, ndef);
156         return day | (night << 8);
157 }
158
159 /*
160         Calculate smooth lighting at the XYZ- corner of p.
161         Both light banks
162 */
163 static u16 getSmoothLightCombined(const v3s16 &p,
164         const std::array<v3s16,8> &dirs, MeshMakeData *data)
165 {
166         const NodeDefManager *ndef = data->m_client->ndef();
167
168         u16 ambient_occlusion = 0;
169         u16 light_count = 0;
170         u8 light_source_max = 0;
171         u16 light_day = 0;
172         u16 light_night = 0;
173         bool direct_sunlight = false;
174
175         auto add_node = [&] (u8 i, bool obstructed = false) -> bool {
176                 if (obstructed) {
177                         ambient_occlusion++;
178                         return false;
179                 }
180                 MapNode n = data->m_vmanip.getNodeNoExNoEmerge(p + dirs[i]);
181                 if (n.getContent() == CONTENT_IGNORE)
182                         return true;
183                 const ContentFeatures &f = ndef->get(n);
184                 if (f.light_source > light_source_max)
185                         light_source_max = f.light_source;
186                 // Check f.solidness because fast-style leaves look better this way
187                 if (f.param_type == CPT_LIGHT && f.solidness != 2) {
188                         u8 light_level_day = n.getLightNoChecks(LIGHTBANK_DAY, &f);
189                         u8 light_level_night = n.getLightNoChecks(LIGHTBANK_NIGHT, &f);
190                         if (light_level_day == LIGHT_SUN)
191                                 direct_sunlight = true;
192                         light_day += decode_light(light_level_day);
193                         light_night += decode_light(light_level_night);
194                         light_count++;
195                 } else {
196                         ambient_occlusion++;
197                 }
198                 return f.light_propagates;
199         };
200
201         bool obstructed[4] = { true, true, true, true };
202         add_node(0);
203         bool opaque1 = !add_node(1);
204         bool opaque2 = !add_node(2);
205         bool opaque3 = !add_node(3);
206         obstructed[0] = opaque1 && opaque2;
207         obstructed[1] = opaque1 && opaque3;
208         obstructed[2] = opaque2 && opaque3;
209         for (u8 k = 0; k < 3; ++k)
210                 if (add_node(k + 4, obstructed[k]))
211                         obstructed[3] = false;
212         if (add_node(7, obstructed[3])) { // wrap light around nodes
213                 ambient_occlusion -= 3;
214                 for (u8 k = 0; k < 3; ++k)
215                         add_node(k + 4, !obstructed[k]);
216         }
217
218         if (light_count == 0) {
219                 light_day = light_night = 0;
220         } else {
221                 light_day /= light_count;
222                 light_night /= light_count;
223         }
224
225         // boost direct sunlight, if any
226         if (direct_sunlight)
227                 light_day = 0xFF;
228
229         // Boost brightness around light sources
230         bool skip_ambient_occlusion_day = false;
231         if (decode_light(light_source_max) >= light_day) {
232                 light_day = decode_light(light_source_max);
233                 skip_ambient_occlusion_day = true;
234         }
235
236         bool skip_ambient_occlusion_night = false;
237         if(decode_light(light_source_max) >= light_night) {
238                 light_night = decode_light(light_source_max);
239                 skip_ambient_occlusion_night = true;
240         }
241
242         if (ambient_occlusion > 4) {
243                 static thread_local const float ao_gamma = rangelim(
244                         g_settings->getFloat("ambient_occlusion_gamma"), 0.25, 4.0);
245
246                 // Table of gamma space multiply factors.
247                 static thread_local const float light_amount[3] = {
248                         powf(0.75, 1.0 / ao_gamma),
249                         powf(0.5,  1.0 / ao_gamma),
250                         powf(0.25, 1.0 / ao_gamma)
251                 };
252
253                 //calculate table index for gamma space multiplier
254                 ambient_occlusion -= 5;
255
256                 if (!skip_ambient_occlusion_day)
257                         light_day = rangelim(core::round32(
258                                         light_day * light_amount[ambient_occlusion]), 0, 255);
259                 if (!skip_ambient_occlusion_night)
260                         light_night = rangelim(core::round32(
261                                         light_night * light_amount[ambient_occlusion]), 0, 255);
262         }
263
264         return light_day | (light_night << 8);
265 }
266
267 /*
268         Calculate smooth lighting at the given corner of p.
269         Both light banks.
270         Node at p is solid, and thus the lighting is face-dependent.
271 */
272 u16 getSmoothLightSolid(const v3s16 &p, const v3s16 &face_dir, const v3s16 &corner, MeshMakeData *data)
273 {
274         return getSmoothLightTransparent(p + face_dir, corner - 2 * face_dir, data);
275 }
276
277 /*
278         Calculate smooth lighting at the given corner of p.
279         Both light banks.
280         Node at p is not solid, and the lighting is not face-dependent.
281 */
282 u16 getSmoothLightTransparent(const v3s16 &p, const v3s16 &corner, MeshMakeData *data)
283 {
284         const std::array<v3s16,8> dirs = {{
285                 // Always shine light
286                 v3s16(0,0,0),
287                 v3s16(corner.X,0,0),
288                 v3s16(0,corner.Y,0),
289                 v3s16(0,0,corner.Z),
290
291                 // Can be obstructed
292                 v3s16(corner.X,corner.Y,0),
293                 v3s16(corner.X,0,corner.Z),
294                 v3s16(0,corner.Y,corner.Z),
295                 v3s16(corner.X,corner.Y,corner.Z)
296         }};
297         return getSmoothLightCombined(p, dirs, data);
298 }
299
300 void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio){
301         f32 rg = daynight_ratio / 1000.0f - 0.04f;
302         f32 b = (0.98f * daynight_ratio) / 1000.0f + 0.078f;
303         sunlight->r = rg;
304         sunlight->g = rg;
305         sunlight->b = b;
306 }
307
308 void final_color_blend(video::SColor *result,
309                 u16 light, u32 daynight_ratio)
310 {
311         video::SColorf dayLight;
312         get_sunlight_color(&dayLight, daynight_ratio);
313         final_color_blend(result,
314                 encode_light(light, 0), dayLight);
315 }
316
317 void final_color_blend(video::SColor *result,
318                 const video::SColor &data, const video::SColorf &dayLight)
319 {
320         static const video::SColorf artificialColor(1.04f, 1.04f, 1.04f);
321
322         video::SColorf c(data);
323         f32 n = 1 - c.a;
324
325         f32 r = c.r * (c.a * dayLight.r + n * artificialColor.r) * 2.0f;
326         f32 g = c.g * (c.a * dayLight.g + n * artificialColor.g) * 2.0f;
327         f32 b = c.b * (c.a * dayLight.b + n * artificialColor.b) * 2.0f;
328
329         // Emphase blue a bit in darker places
330         // Each entry of this array represents a range of 8 blue levels
331         static const u8 emphase_blue_when_dark[32] = {
332                 1, 4, 6, 6, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0,
333                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
334         };
335
336         b += emphase_blue_when_dark[irr::core::clamp((s32) ((r + g + b) / 3 * 255),
337                 0, 255) / 8] / 255.0f;
338
339         result->setRed(core::clamp((s32) (r * 255.0f), 0, 255));
340         result->setGreen(core::clamp((s32) (g * 255.0f), 0, 255));
341         result->setBlue(core::clamp((s32) (b * 255.0f), 0, 255));
342 }
343
344 /*
345         Mesh generation helpers
346 */
347
348 // This table is moved outside getNodeVertexDirs to avoid the compiler using
349 // a mutex to initialize this table at runtime right in the hot path.
350 // For details search the internet for "cxa_guard_acquire".
351 static const v3s16 vertex_dirs_table[] = {
352         // ( 1, 0, 0)
353         v3s16( 1,-1, 1), v3s16( 1,-1,-1),
354         v3s16( 1, 1,-1), v3s16( 1, 1, 1),
355         // ( 0, 1, 0)
356         v3s16( 1, 1,-1), v3s16(-1, 1,-1),
357         v3s16(-1, 1, 1), v3s16( 1, 1, 1),
358         // ( 0, 0, 1)
359         v3s16(-1,-1, 1), v3s16( 1,-1, 1),
360         v3s16( 1, 1, 1), v3s16(-1, 1, 1),
361         // invalid
362         v3s16(), v3s16(), v3s16(), v3s16(),
363         // ( 0, 0,-1)
364         v3s16( 1,-1,-1), v3s16(-1,-1,-1),
365         v3s16(-1, 1,-1), v3s16( 1, 1,-1),
366         // ( 0,-1, 0)
367         v3s16( 1,-1, 1), v3s16(-1,-1, 1),
368         v3s16(-1,-1,-1), v3s16( 1,-1,-1),
369         // (-1, 0, 0)
370         v3s16(-1,-1,-1), v3s16(-1,-1, 1),
371         v3s16(-1, 1, 1), v3s16(-1, 1,-1)
372 };
373
374 /*
375         vertex_dirs: v3s16[4]
376 */
377 static void getNodeVertexDirs(const v3s16 &dir, v3s16 *vertex_dirs)
378 {
379         /*
380                 If looked from outside the node towards the face, the corners are:
381                 0: bottom-right
382                 1: bottom-left
383                 2: top-left
384                 3: top-right
385         */
386
387         // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
388         // (0,0,1), (0,0,-1)
389         assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z == 1);
390
391         // Convert direction to single integer for table lookup
392         u8 idx = (dir.X + 2 * dir.Y + 3 * dir.Z) & 7;
393         idx = (idx - 1) * 4;
394
395 #if defined(__GNUC__) && !defined(__clang__)
396 #pragma GCC diagnostic push
397 #pragma GCC diagnostic ignored "-Wclass-memaccess"
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_use_tangent_vertices = data->m_use_tangent_vertices;
1018         m_enable_vbo = g_settings->getBool("enable_vbo");
1019
1020         if (data->m_client->getMinimap()) {
1021                 m_minimap_mapblock = new MinimapMapblock;
1022                 m_minimap_mapblock->getMinimapNodes(
1023                         &data->m_vmanip, data->m_blockpos * MAP_BLOCKSIZE);
1024         }
1025
1026         // 4-21ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1027         // 24-155ms for MAP_BLOCKSIZE=32  (NOTE: probably outdated)
1028         //TimeTaker timer1("MapBlockMesh()");
1029
1030         std::vector<FastFace> fastfaces_new;
1031         fastfaces_new.reserve(512);
1032
1033         /*
1034                 We are including the faces of the trailing edges of the block.
1035                 This means that when something changes, the caller must
1036                 also update the meshes of the blocks at the leading edges.
1037
1038                 NOTE: This is the slowest part of this method.
1039         */
1040         {
1041                 // 4-23ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1042                 //TimeTaker timer2("updateAllFastFaceRows()");
1043                 updateAllFastFaceRows(data, fastfaces_new);
1044         }
1045         // End of slow part
1046
1047         /*
1048                 Convert FastFaces to MeshCollector
1049         */
1050
1051         MeshCollector collector;
1052
1053         {
1054                 // avg 0ms (100ms spikes when loading textures the first time)
1055                 // (NOTE: probably outdated)
1056                 //TimeTaker timer2("MeshCollector building");
1057
1058                 for (const FastFace &f : fastfaces_new) {
1059                         static const u16 indices[] = {0, 1, 2, 2, 3, 0};
1060                         static const u16 indices_alternate[] = {0, 1, 3, 2, 3, 1};
1061                         const u16 *indices_p =
1062                                 f.vertex_0_2_connected ? indices : indices_alternate;
1063                         collector.append(f.tile, f.vertices, 4, indices_p, 6);
1064                 }
1065         }
1066
1067         /*
1068                 Add special graphics:
1069                 - torches
1070                 - flowing water
1071                 - fences
1072                 - whatever
1073         */
1074
1075         {
1076                 MapblockMeshGenerator generator(data, &collector);
1077                 generator.generate();
1078         }
1079
1080         /*
1081                 Convert MeshCollector to SMesh
1082         */
1083
1084         for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
1085                 for(u32 i = 0; i < collector.prebuffers[layer].size(); i++)
1086                 {
1087                         PreMeshBuffer &p = collector.prebuffers[layer][i];
1088
1089                         applyTileColor(p);
1090
1091                         // Generate animation data
1092                         // - Cracks
1093                         if (p.layer.material_flags & MATERIAL_FLAG_CRACK) {
1094                                 // Find the texture name plus ^[crack:N:
1095                                 std::ostringstream os(std::ios::binary);
1096                                 os << m_tsrc->getTextureName(p.layer.texture_id) << "^[crack";
1097                                 if (p.layer.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1098                                         os << "o";  // use ^[cracko
1099                                 u8 tiles = p.layer.scale;
1100                                 if (tiles > 1)
1101                                         os << ":" << (u32)tiles;
1102                                 os << ":" << (u32)p.layer.animation_frame_count << ":";
1103                                 m_crack_materials.insert(std::make_pair(
1104                                                 std::pair<u8, u32>(layer, i), os.str()));
1105                                 // Replace tile texture with the cracked one
1106                                 p.layer.texture = m_tsrc->getTextureForMesh(
1107                                                 os.str() + "0",
1108                                                 &p.layer.texture_id);
1109                         }
1110                         // - Texture animation
1111                         if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
1112                                 // Add to MapBlockMesh in order to animate these tiles
1113                                 m_animation_tiles[std::pair<u8, u32>(layer, i)] = p.layer;
1114                                 m_animation_frames[std::pair<u8, u32>(layer, i)] = 0;
1115                                 if (g_settings->getBool(
1116                                                 "desynchronize_mapblock_texture_animation")) {
1117                                         // Get starting position from noise
1118                                         m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] =
1119                                                         100000 * (2.0 + noise3d(
1120                                                         data->m_blockpos.X, data->m_blockpos.Y,
1121                                                         data->m_blockpos.Z, 0));
1122                                 } else {
1123                                         // Play all synchronized
1124                                         m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] = 0;
1125                                 }
1126                                 // Replace tile texture with the first animation frame
1127                                 p.layer.texture = (*p.layer.frames)[0].texture;
1128                         }
1129
1130                         if (!m_enable_shaders) {
1131                                 // Extract colors for day-night animation
1132                                 // Dummy sunlight to handle non-sunlit areas
1133                                 video::SColorf sunlight;
1134                                 get_sunlight_color(&sunlight, 0);
1135                                 u32 vertex_count = p.vertices.size();
1136                                 for (u32 j = 0; j < vertex_count; j++) {
1137                                         video::SColor *vc = &p.vertices[j].Color;
1138                                         video::SColor copy = *vc;
1139                                         if (vc->getAlpha() == 0) // No sunlight - no need to animate
1140                                                 final_color_blend(vc, copy, sunlight); // Finalize color
1141                                         else // Record color to animate
1142                                                 m_daynight_diffs[std::pair<u8, u32>(layer, i)][j] = copy;
1143
1144                                         // The sunlight ratio has been stored,
1145                                         // delete alpha (for the final rendering).
1146                                         vc->setAlpha(255);
1147                                 }
1148                         }
1149
1150                         // Create material
1151                         video::SMaterial material;
1152                         material.setFlag(video::EMF_LIGHTING, false);
1153                         material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1154                         material.setFlag(video::EMF_BILINEAR_FILTER, false);
1155                         material.setFlag(video::EMF_FOG_ENABLE, true);
1156                         material.setTexture(0, p.layer.texture);
1157
1158                         if (m_enable_shaders) {
1159                                 material.MaterialType = m_shdrsrc->getShaderInfo(
1160                                                 p.layer.shader_id).material;
1161                                 p.layer.applyMaterialOptionsWithShaders(material);
1162                                 if (p.layer.normal_texture)
1163                                         material.setTexture(1, p.layer.normal_texture);
1164                                 material.setTexture(2, p.layer.flags_texture);
1165                         } else {
1166                                 p.layer.applyMaterialOptions(material);
1167                         }
1168
1169                         scene::SMesh *mesh = (scene::SMesh *)m_mesh[layer];
1170
1171                         // Create meshbuffer, add to mesh
1172                         if (m_use_tangent_vertices) {
1173                                 scene::SMeshBufferTangents *buf =
1174                                                 new scene::SMeshBufferTangents();
1175                                 buf->Material = material;
1176                                 buf->Vertices.reallocate(p.vertices.size());
1177                                 buf->Indices.reallocate(p.indices.size());
1178                                 for (const video::S3DVertex &v: p.vertices)
1179                                         buf->Vertices.push_back(video::S3DVertexTangents(v.Pos, v.Color, v.TCoords));
1180                                 for (u16 i: p.indices)
1181                                         buf->Indices.push_back(i);
1182                                 buf->recalculateBoundingBox();
1183                                 mesh->addMeshBuffer(buf);
1184                                 buf->drop();
1185                         } else {
1186                                 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1187                                 buf->Material = material;
1188                                 buf->append(&p.vertices[0], p.vertices.size(),
1189                                         &p.indices[0], p.indices.size());
1190                                 mesh->addMeshBuffer(buf);
1191                                 buf->drop();
1192                         }
1193                 }
1194
1195                 /*
1196                         Do some stuff to the mesh
1197                 */
1198                 m_camera_offset = camera_offset;
1199                 translateMesh(m_mesh[layer],
1200                         intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
1201
1202                 if (m_use_tangent_vertices) {
1203                         scene::IMeshManipulator* meshmanip =
1204                                 RenderingEngine::get_scene_manager()->getMeshManipulator();
1205                         meshmanip->recalculateTangents(m_mesh[layer], true, false, false);
1206                 }
1207
1208                 if (m_mesh[layer]) {
1209 #if 0
1210                         // Usually 1-700 faces and 1-7 materials
1211                         std::cout << "Updated MapBlock has " << fastfaces_new.size()
1212                                         << " faces and uses " << m_mesh[layer]->getMeshBufferCount()
1213                                         << " materials (meshbuffers)" << std::endl;
1214 #endif
1215
1216                         // Use VBO for mesh (this just would set this for ever buffer)
1217                         if (m_enable_vbo)
1218                                 m_mesh[layer]->setHardwareMappingHint(scene::EHM_STATIC);
1219                 }
1220         }
1221
1222         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1223
1224         // Check if animation is required for this mesh
1225         m_has_animation =
1226                 !m_crack_materials.empty() ||
1227                 !m_daynight_diffs.empty() ||
1228                 !m_animation_tiles.empty();
1229 }
1230
1231 MapBlockMesh::~MapBlockMesh()
1232 {
1233         for (scene::IMesh *m : m_mesh) {
1234                 if (m_enable_vbo && m)
1235                         for (u32 i = 0; i < m->getMeshBufferCount(); i++) {
1236                                 scene::IMeshBuffer *buf = m->getMeshBuffer(i);
1237                                 RenderingEngine::get_video_driver()->removeHardwareBuffer(buf);
1238                         }
1239                 m->drop();
1240                 m = NULL;
1241         }
1242         delete m_minimap_mapblock;
1243 }
1244
1245 bool MapBlockMesh::animate(bool faraway, float time, int crack,
1246         u32 daynight_ratio)
1247 {
1248         if (!m_has_animation) {
1249                 m_animation_force_timer = 100000;
1250                 return false;
1251         }
1252
1253         m_animation_force_timer = myrand_range(5, 100);
1254
1255         // Cracks
1256         if (crack != m_last_crack) {
1257                 for (auto &crack_material : m_crack_materials) {
1258                         scene::IMeshBuffer *buf = m_mesh[crack_material.first.first]->
1259                                 getMeshBuffer(crack_material.first.second);
1260                         std::string basename = crack_material.second;
1261
1262                         // Create new texture name from original
1263                         std::ostringstream os;
1264                         os << basename << crack;
1265                         u32 new_texture_id = 0;
1266                         video::ITexture *new_texture =
1267                                         m_tsrc->getTextureForMesh(os.str(), &new_texture_id);
1268                         buf->getMaterial().setTexture(0, new_texture);
1269
1270                         // If the current material is also animated,
1271                         // update animation info
1272                         auto anim_iter = m_animation_tiles.find(crack_material.first);
1273                         if (anim_iter != m_animation_tiles.end()) {
1274                                 TileLayer &tile = anim_iter->second;
1275                                 tile.texture = new_texture;
1276                                 tile.texture_id = new_texture_id;
1277                                 // force animation update
1278                                 m_animation_frames[crack_material.first] = -1;
1279                         }
1280                 }
1281
1282                 m_last_crack = crack;
1283         }
1284
1285         // Texture animation
1286         for (auto &animation_tile : m_animation_tiles) {
1287                 const TileLayer &tile = animation_tile.second;
1288                 // Figure out current frame
1289                 int frameoffset = m_animation_frame_offsets[animation_tile.first];
1290                 int frame = (int)(time * 1000 / tile.animation_frame_length_ms
1291                                 + frameoffset) % tile.animation_frame_count;
1292                 // If frame doesn't change, skip
1293                 if (frame == m_animation_frames[animation_tile.first])
1294                         continue;
1295
1296                 m_animation_frames[animation_tile.first] = frame;
1297
1298                 scene::IMeshBuffer *buf = m_mesh[animation_tile.first.first]->
1299                         getMeshBuffer(animation_tile.first.second);
1300
1301                 const FrameSpec &animation_frame = (*tile.frames)[frame];
1302                 buf->getMaterial().setTexture(0, animation_frame.texture);
1303                 if (m_enable_shaders) {
1304                         if (animation_frame.normal_texture)
1305                                 buf->getMaterial().setTexture(1,
1306                                         animation_frame.normal_texture);
1307                         buf->getMaterial().setTexture(2, animation_frame.flags_texture);
1308                 }
1309         }
1310
1311         // Day-night transition
1312         if (!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio)) {
1313                 // Force reload mesh to VBO
1314                 if (m_enable_vbo)
1315                         for (scene::IMesh *m : m_mesh)
1316                                 m->setDirty();
1317                 video::SColorf day_color;
1318                 get_sunlight_color(&day_color, daynight_ratio);
1319
1320                 for (auto &daynight_diff : m_daynight_diffs) {
1321                         scene::IMeshBuffer *buf = m_mesh[daynight_diff.first.first]->
1322                                 getMeshBuffer(daynight_diff.first.second);
1323                         video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
1324                         for (const auto &j : daynight_diff.second)
1325                                 final_color_blend(&(vertices[j.first].Color), j.second,
1326                                                 day_color);
1327                 }
1328                 m_last_daynight_ratio = daynight_ratio;
1329         }
1330
1331         return true;
1332 }
1333
1334 void MapBlockMesh::updateCameraOffset(v3s16 camera_offset)
1335 {
1336         if (camera_offset != m_camera_offset) {
1337                 for (scene::IMesh *layer : m_mesh) {
1338                         translateMesh(layer,
1339                                 intToFloat(m_camera_offset - camera_offset, BS));
1340                         if (m_enable_vbo)
1341                                 layer->setDirty();
1342                 }
1343                 m_camera_offset = camera_offset;
1344         }
1345 }
1346
1347 video::SColor encode_light(u16 light, u8 emissive_light)
1348 {
1349         // Get components
1350         u32 day = (light & 0xff);
1351         u32 night = (light >> 8);
1352         // Add emissive light
1353         night += emissive_light * 2.5f;
1354         if (night > 255)
1355                 night = 255;
1356         // Since we don't know if the day light is sunlight or
1357         // artificial light, assume it is artificial when the night
1358         // light bank is also lit.
1359         if (day < night)
1360                 day = 0;
1361         else
1362                 day = day - night;
1363         u32 sum = day + night;
1364         // Ratio of sunlight:
1365         u32 r;
1366         if (sum > 0)
1367                 r = day * 255 / sum;
1368         else
1369                 r = 0;
1370         // Average light:
1371         float b = (day + night) / 2;
1372         return video::SColor(r, b, b, b);
1373 }