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