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