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