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