]> 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
1208         m_buffer->Indices.clear();
1209         if (!m_vertex_indexes.empty()) {
1210                 for (auto index : m_vertex_indexes)
1211                         m_buffer->Indices.push_back(index);
1212         }
1213         m_buffer->setDirty(scene::EBT_INDEX);
1214 }
1215
1216 /*
1217         MapBlockMesh
1218 */
1219
1220 MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
1221         m_minimap_mapblock(NULL),
1222         m_tsrc(data->m_client->getTextureSource()),
1223         m_shdrsrc(data->m_client->getShaderSource()),
1224         m_animation_force_timer(0), // force initial animation
1225         m_last_crack(-1),
1226         m_last_daynight_ratio((u32) -1)
1227 {
1228         for (auto &m : m_mesh)
1229                 m = new scene::SMesh();
1230         m_enable_shaders = data->m_use_shaders;
1231         m_enable_vbo = g_settings->getBool("enable_vbo");
1232
1233         if (data->m_client->getMinimap()) {
1234                 m_minimap_mapblock = new MinimapMapblock;
1235                 m_minimap_mapblock->getMinimapNodes(
1236                         &data->m_vmanip, data->m_blockpos * MAP_BLOCKSIZE);
1237         }
1238
1239         // 4-21ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1240         // 24-155ms for MAP_BLOCKSIZE=32  (NOTE: probably outdated)
1241         //TimeTaker timer1("MapBlockMesh()");
1242
1243         std::vector<FastFace> fastfaces_new;
1244         fastfaces_new.reserve(512);
1245         /*
1246                 X-Ray
1247         */
1248         bool xray = g_settings->getBool("xray");
1249         std::set<content_t> xraySet, nodeESPSet;
1250         if (xray)
1251                 xraySet = splitToContentT(g_settings->get("xray_nodes"), data->m_client->ndef());
1252
1253         nodeESPSet = splitToContentT(g_settings->get("node_esp_nodes"), data->m_client->ndef());
1254
1255         /*
1256                 We are including the faces of the trailing edges of the block.
1257                 This means that when something changes, the caller must
1258                 also update the meshes of the blocks at the leading edges.
1259
1260                 NOTE: This is the slowest part of this method.
1261         */
1262         {
1263                 // 4-23ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1264                 //TimeTaker timer2("updateAllFastFaceRows()");
1265                 updateAllFastFaceRows(data, fastfaces_new, xray, xraySet);
1266         }
1267         // End of slow part
1268
1269         /*
1270                 NodeESP
1271         */
1272         {
1273                 v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
1274                 for (s16 x = 0; x < MAP_BLOCKSIZE; x++) {
1275                         for (s16 y = 0; y < MAP_BLOCKSIZE; y++) {
1276                                 for (s16 z = 0; z < MAP_BLOCKSIZE; z++) {
1277                                         v3s16 pos = v3s16(x, y, z) + blockpos_nodes;
1278                                         const MapNode &node = data->m_vmanip.getNodeRefUnsafeCheckFlags(pos);
1279                                         if (nodeESPSet.find(node.getContent()) != nodeESPSet.end())
1280                                                 esp_nodes.insert(pos);
1281                                 }
1282                         }
1283                 }
1284         }
1285
1286         /*
1287                 Convert FastFaces to MeshCollector
1288         */
1289
1290         MeshCollector collector;
1291
1292         {
1293                 // avg 0ms (100ms spikes when loading textures the first time)
1294                 // (NOTE: probably outdated)
1295                 //TimeTaker timer2("MeshCollector building");
1296
1297                 for (const FastFace &f : fastfaces_new) {
1298                         static const u16 indices[] = {0, 1, 2, 2, 3, 0};
1299                         static const u16 indices_alternate[] = {0, 1, 3, 2, 3, 1};
1300                         const u16 *indices_p =
1301                                 f.vertex_0_2_connected ? indices : indices_alternate;
1302                         collector.append(f.tile, f.vertices, 4, indices_p, 6);
1303                 }
1304         }
1305
1306         /*
1307                 Add special graphics:
1308                 - torches
1309                 - flowing water
1310                 - fences
1311                 - whatever
1312         */
1313
1314         {
1315                 MapblockMeshGenerator(data, &collector,
1316                         data->m_client->getSceneManager()->getMeshManipulator()).generate();
1317         }
1318
1319         /*
1320                 Convert MeshCollector to SMesh
1321         */
1322
1323         const bool desync_animations = g_settings->getBool(
1324                 "desynchronize_mapblock_texture_animation");
1325
1326         for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
1327                 for(u32 i = 0; i < collector.prebuffers[layer].size(); i++)
1328                 {
1329                         PreMeshBuffer &p = collector.prebuffers[layer][i];
1330
1331                         applyTileColor(p);
1332
1333                         // Generate animation data
1334                         // - Cracks
1335                         if (p.layer.material_flags & MATERIAL_FLAG_CRACK) {
1336                                 // Find the texture name plus ^[crack:N:
1337                                 std::ostringstream os(std::ios::binary);
1338                                 os << m_tsrc->getTextureName(p.layer.texture_id) << "^[crack";
1339                                 if (p.layer.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1340                                         os << "o";  // use ^[cracko
1341                                 u8 tiles = p.layer.scale;
1342                                 if (tiles > 1)
1343                                         os << ":" << (u32)tiles;
1344                                 os << ":" << (u32)p.layer.animation_frame_count << ":";
1345                                 m_crack_materials.insert(std::make_pair(
1346                                                 std::pair<u8, u32>(layer, i), os.str()));
1347                                 // Replace tile texture with the cracked one
1348                                 p.layer.texture = m_tsrc->getTextureForMesh(
1349                                                 os.str() + "0",
1350                                                 &p.layer.texture_id);
1351                         }
1352                         // - Texture animation
1353                         if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
1354                                 // Add to MapBlockMesh in order to animate these tiles
1355                                 auto &info = m_animation_info[{layer, i}];
1356                                 info.tile = p.layer;
1357                                 info.frame = 0;
1358                                 if (desync_animations) {
1359                                         // Get starting position from noise
1360                                         info.frame_offset =
1361                                                         100000 * (2.0 + noise3d(
1362                                                         data->m_blockpos.X, data->m_blockpos.Y,
1363                                                         data->m_blockpos.Z, 0));
1364                                 } else {
1365                                         // Play all synchronized
1366                                         info.frame_offset = 0;
1367                                 }
1368                                 // Replace tile texture with the first animation frame
1369                                 p.layer.texture = (*p.layer.frames)[0].texture;
1370                         }
1371
1372                         if (!m_enable_shaders) {
1373                                 // Extract colors for day-night animation
1374                                 // Dummy sunlight to handle non-sunlit areas
1375                                 video::SColorf sunlight;
1376                                 get_sunlight_color(&sunlight, 0);
1377
1378                                 std::map<u32, video::SColor> colors;
1379                                 const u32 vertex_count = p.vertices.size();
1380                                 for (u32 j = 0; j < vertex_count; j++) {
1381                                         video::SColor *vc = &p.vertices[j].Color;
1382                                         video::SColor copy = *vc;
1383                                         if (vc->getAlpha() == 0) // No sunlight - no need to animate
1384                                                 final_color_blend(vc, copy, sunlight); // Finalize color
1385                                         else // Record color to animate
1386                                                 colors[j] = copy;
1387
1388                                         // The sunlight ratio has been stored,
1389                                         // delete alpha (for the final rendering).
1390                                         vc->setAlpha(255);
1391                                 }
1392                                 if (!colors.empty())
1393                                         m_daynight_diffs[{layer, i}] = std::move(colors);
1394                         }
1395
1396                         // Create material
1397                         video::SMaterial material;
1398                         material.setFlag(video::EMF_LIGHTING, false);
1399                         material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1400                         material.setFlag(video::EMF_BILINEAR_FILTER, false);
1401                         material.setFlag(video::EMF_FOG_ENABLE, true);
1402                         material.setTexture(0, p.layer.texture);
1403
1404                         if (m_enable_shaders) {
1405                                 material.MaterialType = m_shdrsrc->getShaderInfo(
1406                                                 p.layer.shader_id).material;
1407                                 p.layer.applyMaterialOptionsWithShaders(material);
1408                                 if (p.layer.normal_texture)
1409                                         material.setTexture(1, p.layer.normal_texture);
1410                                 material.setTexture(2, p.layer.flags_texture);
1411                         } else {
1412                                 p.layer.applyMaterialOptions(material);
1413                         }
1414
1415                         scene::SMesh *mesh = (scene::SMesh *)m_mesh[layer];
1416
1417                         scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1418                         buf->Material = material;
1419                         switch (p.layer.material_type) {
1420                         // list of transparent materials taken from tile.h
1421                         case TILE_MATERIAL_ALPHA:
1422                         case TILE_MATERIAL_LIQUID_TRANSPARENT:
1423                         case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
1424                                 {
1425                                         buf->append(&p.vertices[0], p.vertices.size(),
1426                                                 &p.indices[0], 0);
1427
1428                                         MeshTriangle t;
1429                                         t.buffer = buf;
1430                                         for (u32 i = 0; i < p.indices.size(); i += 3) {
1431                                                 t.p1 = p.indices[i];
1432                                                 t.p2 = p.indices[i + 1];
1433                                                 t.p3 = p.indices[i + 2];
1434                                                 t.updateAttributes();
1435                                                 m_transparent_triangles.push_back(t);
1436                                         }
1437                                 }
1438                                 break;
1439                         default:
1440                                 buf->append(&p.vertices[0], p.vertices.size(),
1441                                         &p.indices[0], p.indices.size());
1442                                 break;
1443                         }
1444                         mesh->addMeshBuffer(buf);
1445                         buf->drop();
1446                 }
1447
1448                 if (m_mesh[layer]) {
1449                         // Use VBO for mesh (this just would set this for ever buffer)
1450                         if (m_enable_vbo)
1451                                 m_mesh[layer]->setHardwareMappingHint(scene::EHM_STATIC);
1452                 }
1453         }
1454
1455         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1456         m_bsp_tree.buildTree(&m_transparent_triangles);
1457
1458         // Check if animation is required for this mesh
1459         m_has_animation =
1460                 !m_crack_materials.empty() ||
1461                 !m_daynight_diffs.empty() ||
1462                 !m_animation_info.empty();
1463 }
1464
1465 MapBlockMesh::~MapBlockMesh()
1466 {
1467         for (scene::IMesh *m : m_mesh) {
1468 #if IRRLICHT_VERSION_MT_REVISION < 5
1469                 if (m_enable_vbo) {
1470                         for (u32 i = 0; i < m->getMeshBufferCount(); i++) {
1471                                 scene::IMeshBuffer *buf = m->getMeshBuffer(i);
1472                                 RenderingEngine::get_video_driver()->removeHardwareBuffer(buf);
1473                         }
1474                 }
1475 #endif
1476                 m->drop();
1477         }
1478         delete m_minimap_mapblock;
1479 }
1480
1481 bool MapBlockMesh::animate(bool faraway, float time, int crack,
1482         u32 daynight_ratio)
1483 {
1484         if (!m_has_animation) {
1485                 m_animation_force_timer = 100000;
1486                 return false;
1487         }
1488
1489         m_animation_force_timer = myrand_range(5, 100);
1490
1491         // Cracks
1492         if (crack != m_last_crack) {
1493                 for (auto &crack_material : m_crack_materials) {
1494                         scene::IMeshBuffer *buf = m_mesh[crack_material.first.first]->
1495                                 getMeshBuffer(crack_material.first.second);
1496
1497                         // Create new texture name from original
1498                         std::string s = crack_material.second + itos(crack);
1499                         u32 new_texture_id = 0;
1500                         video::ITexture *new_texture =
1501                                         m_tsrc->getTextureForMesh(s, &new_texture_id);
1502                         buf->getMaterial().setTexture(0, new_texture);
1503
1504                         // If the current material is also animated, update animation info
1505                         auto anim_it = m_animation_info.find(crack_material.first);
1506                         if (anim_it != m_animation_info.end()) {
1507                                 TileLayer &tile = anim_it->second.tile;
1508                                 tile.texture = new_texture;
1509                                 tile.texture_id = new_texture_id;
1510                                 // force animation update
1511                                 anim_it->second.frame = -1;
1512                         }
1513                 }
1514
1515                 m_last_crack = crack;
1516         }
1517
1518         // Texture animation
1519         for (auto &it : m_animation_info) {
1520                 const TileLayer &tile = it.second.tile;
1521                 // Figure out current frame
1522                 int frameno = (int)(time * 1000 / tile.animation_frame_length_ms
1523                                 + it.second.frame_offset) % tile.animation_frame_count;
1524                 // If frame doesn't change, skip
1525                 if (frameno == it.second.frame)
1526                         continue;
1527
1528                 it.second.frame = frameno;
1529
1530                 scene::IMeshBuffer *buf = m_mesh[it.first.first]->getMeshBuffer(it.first.second);
1531
1532                 const FrameSpec &frame = (*tile.frames)[frameno];
1533                 buf->getMaterial().setTexture(0, frame.texture);
1534                 if (m_enable_shaders) {
1535                         if (frame.normal_texture)
1536                                 buf->getMaterial().setTexture(1, frame.normal_texture);
1537                         buf->getMaterial().setTexture(2, frame.flags_texture);
1538                 }
1539         }
1540
1541         // Day-night transition
1542         if (!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio)) {
1543                 // Force reload mesh to VBO
1544                 if (m_enable_vbo)
1545                         for (scene::IMesh *m : m_mesh)
1546                                 m->setDirty();
1547                 video::SColorf day_color;
1548                 get_sunlight_color(&day_color, daynight_ratio);
1549
1550                 for (auto &daynight_diff : m_daynight_diffs) {
1551                         scene::IMeshBuffer *buf = m_mesh[daynight_diff.first.first]->
1552                                 getMeshBuffer(daynight_diff.first.second);
1553                         video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
1554                         for (const auto &j : daynight_diff.second)
1555                                 final_color_blend(&(vertices[j.first].Color), j.second,
1556                                                 day_color);
1557                 }
1558                 m_last_daynight_ratio = daynight_ratio;
1559         }
1560
1561         return true;
1562 }
1563
1564 void MapBlockMesh::updateTransparentBuffers(v3f camera_pos, v3s16 block_pos)
1565 {
1566         // nothing to do if the entire block is opaque
1567         if (m_transparent_triangles.empty())
1568                 return;
1569
1570         v3f block_posf = intToFloat(block_pos * MAP_BLOCKSIZE, BS);
1571         v3f rel_camera_pos = camera_pos - block_posf;
1572
1573         std::vector<s32> triangle_refs;
1574         m_bsp_tree.traverse(rel_camera_pos, triangle_refs);
1575
1576         // arrange index sequences into partial buffers
1577         m_transparent_buffers.clear();
1578
1579         scene::SMeshBuffer *current_buffer = nullptr;
1580         std::vector<u16> current_strain;
1581         for (auto i : triangle_refs) {
1582                 const auto &t = m_transparent_triangles[i];
1583                 if (current_buffer != t.buffer) {
1584                         if (current_buffer) {
1585                                 m_transparent_buffers.emplace_back(current_buffer, current_strain);
1586                                 current_strain.clear();
1587                         }
1588                         current_buffer = t.buffer;
1589                 }
1590                 current_strain.push_back(t.p1);
1591                 current_strain.push_back(t.p2);
1592                 current_strain.push_back(t.p3);
1593         }
1594
1595         if (!current_strain.empty())
1596                 m_transparent_buffers.emplace_back(current_buffer, current_strain);
1597 }
1598
1599 void MapBlockMesh::consolidateTransparentBuffers()
1600 {
1601         m_transparent_buffers.clear();
1602
1603         scene::SMeshBuffer *current_buffer = nullptr;
1604         std::vector<u16> current_strain;
1605
1606         // use the fact that m_transparent_triangles is already arranged by buffer
1607         for (const auto &t : m_transparent_triangles) {
1608                 if (current_buffer != t.buffer) {
1609                         if (current_buffer != nullptr) {
1610                                 this->m_transparent_buffers.emplace_back(current_buffer, current_strain);
1611                                 current_strain.clear();
1612                         }
1613                         current_buffer = t.buffer;
1614                 }
1615                 current_strain.push_back(t.p1);
1616                 current_strain.push_back(t.p2);
1617                 current_strain.push_back(t.p3);
1618         }
1619
1620         if (!current_strain.empty()) {
1621                 this->m_transparent_buffers.emplace_back(current_buffer, current_strain);
1622         }
1623 }
1624
1625 video::SColor encode_light(u16 light, u8 emissive_light)
1626 {
1627         // Get components
1628         u32 day = (light & 0xff);
1629         u32 night = (light >> 8);
1630         // Add emissive light
1631         night += emissive_light * 2.5f;
1632         if (night > 255)
1633                 night = 255;
1634         // Since we don't know if the day light is sunlight or
1635         // artificial light, assume it is artificial when the night
1636         // light bank is also lit.
1637         if (day < night)
1638                 day = 0;
1639         else
1640                 day = day - night;
1641         u32 sum = day + night;
1642         // Ratio of sunlight:
1643         u32 r;
1644         if (sum > 0)
1645                 r = day * 255 / sum;
1646         else
1647                 r = 0;
1648         // Average light:
1649         float b = (day + night) / 2;
1650         return video::SColor(r, b, b, b);
1651 }