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