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