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