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