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