Node definition manager refactor (#7016)
[oweals/minetest.git] / src / 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/renderingengine.h"
31 #include <array>
32
33 /*
34         MeshMakeData
35 */
36
37 MeshMakeData::MeshMakeData(Client *client, bool use_shaders,
38                 bool use_tangent_vertices):
39         m_client(client),
40         m_use_shaders(use_shaders),
41         m_use_tangent_vertices(use_tangent_vertices)
42 {}
43
44 void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos)
45 {
46         m_blockpos = blockpos;
47
48         v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
49
50         m_vmanip.clear();
51         VoxelArea voxel_area(blockpos_nodes - v3s16(1,1,1) * MAP_BLOCKSIZE,
52                         blockpos_nodes + v3s16(1,1,1) * MAP_BLOCKSIZE*2-v3s16(1,1,1));
53         m_vmanip.addArea(voxel_area);
54 }
55
56 void MeshMakeData::fillBlockData(const v3s16 &block_offset, MapNode *data)
57 {
58         v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
59         VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
60
61         v3s16 bp = m_blockpos + block_offset;
62         v3s16 blockpos_nodes = bp * MAP_BLOCKSIZE;
63         m_vmanip.copyFrom(data, data_area, v3s16(0,0,0), blockpos_nodes, data_size);
64 }
65
66 void MeshMakeData::fill(MapBlock *block)
67 {
68         fillBlockDataBegin(block->getPos());
69
70         fillBlockData(v3s16(0,0,0), block->getData());
71
72         // Get map for reading neighbor blocks
73         Map *map = block->getParent();
74
75         for (const v3s16 &dir : g_26dirs) {
76                 v3s16 bp = m_blockpos + dir;
77                 MapBlock *b = map->getBlockNoCreateNoEx(bp);
78                 if(b)
79                         fillBlockData(dir, b->getData());
80         }
81 }
82
83 void MeshMakeData::fillSingleNode(MapNode *node)
84 {
85         m_blockpos = v3s16(0,0,0);
86
87         v3s16 blockpos_nodes = v3s16(0,0,0);
88         VoxelArea area(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
89                         blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1));
90         s32 volume = area.getVolume();
91         s32 our_node_index = area.index(1,1,1);
92
93         // Allocate this block + neighbors
94         m_vmanip.clear();
95         m_vmanip.addArea(area);
96
97         // Fill in data
98         MapNode *data = new MapNode[volume];
99         for(s32 i = 0; i < volume; i++)
100         {
101                 if (i == our_node_index)
102                         data[i] = *node;
103                 else
104                         data[i] = MapNode(CONTENT_AIR, LIGHT_MAX, 0);
105         }
106         m_vmanip.copyFrom(data, area, area.MinEdge, area.MinEdge, area.getExtent());
107         delete[] data;
108 }
109
110 void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
111 {
112         if (crack_level >= 0)
113                 m_crack_pos_relative = crack_pos - m_blockpos*MAP_BLOCKSIZE;
114 }
115
116 void MeshMakeData::setSmoothLighting(bool smooth_lighting)
117 {
118         m_smooth_lighting = smooth_lighting;
119 }
120
121 /*
122         Light and vertex color functions
123 */
124
125 /*
126         Calculate non-smooth lighting at interior of node.
127         Single light bank.
128 */
129 static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
130         const NodeDefManager *ndef)
131 {
132         u8 light = n.getLight(bank, ndef);
133
134         while(increment > 0)
135         {
136                 light = undiminish_light(light);
137                 --increment;
138         }
139         while(increment < 0)
140         {
141                 light = diminish_light(light);
142                 ++increment;
143         }
144
145         return decode_light(light);
146 }
147
148 /*
149         Calculate non-smooth lighting at interior of node.
150         Both light banks.
151 */
152 u16 getInteriorLight(MapNode n, s32 increment, const NodeDefManager *ndef)
153 {
154         u16 day = getInteriorLight(LIGHTBANK_DAY, n, increment, ndef);
155         u16 night = getInteriorLight(LIGHTBANK_NIGHT, n, increment, ndef);
156         return day | (night << 8);
157 }
158
159 /*
160         Calculate non-smooth lighting at face of node.
161         Single light bank.
162 */
163 static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
164         v3s16 face_dir, const NodeDefManager *ndef)
165 {
166         u8 light;
167         u8 l1 = n.getLight(bank, ndef);
168         u8 l2 = n2.getLight(bank, ndef);
169         if(l1 > l2)
170                 light = l1;
171         else
172                 light = l2;
173
174         // Boost light level for light sources
175         u8 light_source = MYMAX(ndef->get(n).light_source,
176                         ndef->get(n2).light_source);
177         if(light_source > light)
178                 light = light_source;
179
180         return decode_light(light);
181 }
182
183 /*
184         Calculate non-smooth lighting at face of node.
185         Both light banks.
186 */
187 u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir,
188         const NodeDefManager *ndef)
189 {
190         u16 day = getFaceLight(LIGHTBANK_DAY, n, n2, face_dir, ndef);
191         u16 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, face_dir, ndef);
192         return day | (night << 8);
193 }
194
195 /*
196         Calculate smooth lighting at the XYZ- corner of p.
197         Both light banks
198 */
199 static u16 getSmoothLightCombined(const v3s16 &p,
200         const std::array<v3s16,8> &dirs, MeshMakeData *data)
201 {
202         const NodeDefManager *ndef = data->m_client->ndef();
203
204         u16 ambient_occlusion = 0;
205         u16 light_count = 0;
206         u8 light_source_max = 0;
207         u16 light_day = 0;
208         u16 light_night = 0;
209
210         auto add_node = [&] (u8 i, bool obstructed = false) -> bool {
211                 if (obstructed) {
212                         ambient_occlusion++;
213                         return false;
214                 }
215                 MapNode n = data->m_vmanip.getNodeNoExNoEmerge(p + dirs[i]);
216                 if (n.getContent() == CONTENT_IGNORE)
217                         return true;
218                 const ContentFeatures &f = ndef->get(n);
219                 if (f.light_source > light_source_max)
220                         light_source_max = f.light_source;
221                 // Check f.solidness because fast-style leaves look better this way
222                 if (f.param_type == CPT_LIGHT && f.solidness != 2) {
223                         light_day += decode_light(n.getLightNoChecks(LIGHTBANK_DAY, &f));
224                         light_night += decode_light(n.getLightNoChecks(LIGHTBANK_NIGHT, &f));
225                         light_count++;
226                 } else {
227                         ambient_occlusion++;
228                 }
229                 return f.light_propagates;
230         };
231
232         std::array<bool, 4> obstructed = {{ 1, 1, 1, 1 }};
233         add_node(0);
234         bool opaque1 = !add_node(1);
235         bool opaque2 = !add_node(2);
236         bool opaque3 = !add_node(3);
237         obstructed[0] = opaque1 && opaque2;
238         obstructed[1] = opaque1 && opaque3;
239         obstructed[2] = opaque2 && opaque3;
240         for (u8 k = 0; k < 3; ++k)
241                 if (add_node(k + 4, obstructed[k]))
242                         obstructed[3] = false;
243         if (add_node(7, obstructed[3])) { // wrap light around nodes
244                 ambient_occlusion -= 3;
245                 for (u8 k = 0; k < 3; ++k)
246                         add_node(k + 4, !obstructed[k]);
247         }
248
249         if (light_count == 0) {
250                 light_day = light_night = 0;
251         } else {
252                 light_day /= light_count;
253                 light_night /= light_count;
254         }
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(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, 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         TileLayer layer;
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         u8 layernum;
463         bool world_aligned;
464 };
465
466 static void makeFastFace(const TileSpec &tile, u16 li0, u16 li1, u16 li2, u16 li3,
467         v3f tp, v3f p, v3s16 dir, v3f scale, std::vector<FastFace> &dest)
468 {
469         // Position is at the center of the cube.
470         v3f pos = p * BS;
471
472         float x0 = 0.0f;
473         float y0 = 0.0f;
474         float w = 1.0f;
475         float h = 1.0f;
476
477         v3f vertex_pos[4];
478         v3s16 vertex_dirs[4];
479         getNodeVertexDirs(dir, vertex_dirs);
480         if (tile.world_aligned)
481                 getNodeTextureCoords(tp, scale, dir, &x0, &y0);
482
483         v3s16 t;
484         u16 t1;
485         switch (tile.rotation) {
486         case 0:
487                 break;
488         case 1: //R90
489                 t = vertex_dirs[0];
490                 vertex_dirs[0] = vertex_dirs[3];
491                 vertex_dirs[3] = vertex_dirs[2];
492                 vertex_dirs[2] = vertex_dirs[1];
493                 vertex_dirs[1] = t;
494                 t1  = li0;
495                 li0 = li3;
496                 li3 = li2;
497                 li2 = li1;
498                 li1 = t1;
499                 break;
500         case 2: //R180
501                 t = vertex_dirs[0];
502                 vertex_dirs[0] = vertex_dirs[2];
503                 vertex_dirs[2] = t;
504                 t = vertex_dirs[1];
505                 vertex_dirs[1] = vertex_dirs[3];
506                 vertex_dirs[3] = t;
507                 t1  = li0;
508                 li0 = li2;
509                 li2 = t1;
510                 t1  = li1;
511                 li1 = li3;
512                 li3 = t1;
513                 break;
514         case 3: //R270
515                 t = vertex_dirs[0];
516                 vertex_dirs[0] = vertex_dirs[1];
517                 vertex_dirs[1] = vertex_dirs[2];
518                 vertex_dirs[2] = vertex_dirs[3];
519                 vertex_dirs[3] = t;
520                 t1  = li0;
521                 li0 = li1;
522                 li1 = li2;
523                 li2 = li3;
524                 li3 = t1;
525                 break;
526         case 4: //FXR90
527                 t = vertex_dirs[0];
528                 vertex_dirs[0] = vertex_dirs[3];
529                 vertex_dirs[3] = vertex_dirs[2];
530                 vertex_dirs[2] = vertex_dirs[1];
531                 vertex_dirs[1] = t;
532                 t1  = li0;
533                 li0 = li3;
534                 li3 = li2;
535                 li2 = li1;
536                 li1 = t1;
537                 y0 += h;
538                 h *= -1;
539                 break;
540         case 5: //FXR270
541                 t = vertex_dirs[0];
542                 vertex_dirs[0] = vertex_dirs[1];
543                 vertex_dirs[1] = vertex_dirs[2];
544                 vertex_dirs[2] = vertex_dirs[3];
545                 vertex_dirs[3] = t;
546                 t1  = li0;
547                 li0 = li1;
548                 li1 = li2;
549                 li2 = li3;
550                 li3 = t1;
551                 y0 += h;
552                 h *= -1;
553                 break;
554         case 6: //FYR90
555                 t = vertex_dirs[0];
556                 vertex_dirs[0] = vertex_dirs[3];
557                 vertex_dirs[3] = vertex_dirs[2];
558                 vertex_dirs[2] = vertex_dirs[1];
559                 vertex_dirs[1] = t;
560                 t1  = li0;
561                 li0 = li3;
562                 li3 = li2;
563                 li2 = li1;
564                 li1 = t1;
565                 x0 += w;
566                 w *= -1;
567                 break;
568         case 7: //FYR270
569                 t = vertex_dirs[0];
570                 vertex_dirs[0] = vertex_dirs[1];
571                 vertex_dirs[1] = vertex_dirs[2];
572                 vertex_dirs[2] = vertex_dirs[3];
573                 vertex_dirs[3] = t;
574                 t1  = li0;
575                 li0 = li1;
576                 li1 = li2;
577                 li2 = li3;
578                 li3 = t1;
579                 x0 += w;
580                 w *= -1;
581                 break;
582         case 8: //FX
583                 y0 += h;
584                 h *= -1;
585                 break;
586         case 9: //FY
587                 x0 += w;
588                 w *= -1;
589                 break;
590         default:
591                 break;
592         }
593
594         for (u16 i = 0; i < 4; i++) {
595                 vertex_pos[i] = v3f(
596                                 BS / 2 * vertex_dirs[i].X,
597                                 BS / 2 * vertex_dirs[i].Y,
598                                 BS / 2 * vertex_dirs[i].Z
599                 );
600         }
601
602         for (v3f &vpos : vertex_pos) {
603                 vpos.X *= scale.X;
604                 vpos.Y *= scale.Y;
605                 vpos.Z *= scale.Z;
606                 vpos += pos;
607         }
608
609         f32 abs_scale = 1.0f;
610         if      (scale.X < 0.999f || scale.X > 1.001f) abs_scale = scale.X;
611         else if (scale.Y < 0.999f || scale.Y > 1.001f) abs_scale = scale.Y;
612         else if (scale.Z < 0.999f || scale.Z > 1.001f) abs_scale = scale.Z;
613
614         v3f normal(dir.X, dir.Y, dir.Z);
615
616         u16 li[4] = { li0, li1, li2, li3 };
617         u16 day[4];
618         u16 night[4];
619
620         for (u8 i = 0; i < 4; i++) {
621                 day[i] = li[i] >> 8;
622                 night[i] = li[i] & 0xFF;
623         }
624
625         bool vertex_0_2_connected = abs(day[0] - day[2]) + abs(night[0] - night[2])
626                         < abs(day[1] - day[3]) + abs(night[1] - night[3]);
627
628         v2f32 f[4] = {
629                 core::vector2d<f32>(x0 + w * abs_scale, y0 + h),
630                 core::vector2d<f32>(x0, y0 + h),
631                 core::vector2d<f32>(x0, y0),
632                 core::vector2d<f32>(x0 + w * abs_scale, y0) };
633
634         for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
635                 const TileLayer *layer = &tile.layers[layernum];
636                 if (layer->texture_id == 0)
637                         continue;
638
639                 // equivalent to dest.push_back(FastFace()) but faster
640                 dest.emplace_back();
641                 FastFace& face = *dest.rbegin();
642
643                 for (u8 i = 0; i < 4; i++) {
644                         video::SColor c = encode_light(li[i], tile.emissive_light);
645                         if (!tile.emissive_light)
646                                 applyFacesShading(c, normal);
647
648                         face.vertices[i] = video::S3DVertex(vertex_pos[i], normal, c, f[i]);
649                 }
650
651                 /*
652                  Revert triangles for nicer looking gradient if the
653                  brightness of vertices 1 and 3 differ less than
654                  the brightness of vertices 0 and 2.
655                  */
656                 face.vertex_0_2_connected = vertex_0_2_connected;
657
658                 face.layer = *layer;
659                 face.layernum = layernum;
660
661                 face.world_aligned = tile.world_aligned;
662         }
663 }
664
665 /*
666         Nodes make a face if contents differ and solidness differs.
667         Return value:
668                 0: No face
669                 1: Face uses m1's content
670                 2: Face uses m2's content
671         equivalent: Whether the blocks share the same face (eg. water and glass)
672
673         TODO: Add 3: Both faces drawn with backface culling, remove equivalent
674 */
675 static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
676         const NodeDefManager *ndef)
677 {
678         *equivalent = false;
679
680         if (m1 == m2 || m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
681                 return 0;
682
683         const ContentFeatures &f1 = ndef->get(m1);
684         const ContentFeatures &f2 = ndef->get(m2);
685
686         // Contents don't differ for different forms of same liquid
687         if (f1.sameLiquid(f2))
688                 return 0;
689
690         u8 c1 = f1.solidness;
691         u8 c2 = f2.solidness;
692
693         if (c1 == c2)
694                 return 0;
695
696         if (c1 == 0)
697                 c1 = f1.visual_solidness;
698         else if (c2 == 0)
699                 c2 = f2.visual_solidness;
700
701         if (c1 == c2) {
702                 *equivalent = true;
703                 // If same solidness, liquid takes precense
704                 if (f1.isLiquid())
705                         return 1;
706                 if (f2.isLiquid())
707                         return 2;
708         }
709
710         if (c1 > c2)
711                 return 1;
712
713         return 2;
714 }
715
716 /*
717         Gets nth node tile (0 <= n <= 5).
718 */
719 void getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data, TileSpec &tile)
720 {
721         const NodeDefManager *ndef = data->m_client->ndef();
722         const ContentFeatures &f = ndef->get(mn);
723         tile = f.tiles[tileindex];
724         bool has_crack = p == data->m_crack_pos_relative;
725         for (TileLayer &layer : tile.layers) {
726                 if (layer.texture_id == 0)
727                         continue;
728                 if (!layer.has_color)
729                         mn.getColor(f, &(layer.color));
730                 // Apply temporary crack
731                 if (has_crack)
732                         layer.material_flags |= MATERIAL_FLAG_CRACK;
733         }
734 }
735
736 /*
737         Gets node tile given a face direction.
738 */
739 void getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data, TileSpec &tile)
740 {
741         const NodeDefManager *ndef = data->m_client->ndef();
742
743         // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
744         // (0,0,1), (0,0,-1) or (0,0,0)
745         assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z <= 1);
746
747         // Convert direction to single integer for table lookup
748         //  0 = (0,0,0)
749         //  1 = (1,0,0)
750         //  2 = (0,1,0)
751         //  3 = (0,0,1)
752         //  4 = invalid, treat as (0,0,0)
753         //  5 = (0,0,-1)
754         //  6 = (0,-1,0)
755         //  7 = (-1,0,0)
756         u8 dir_i = ((dir.X + 2 * dir.Y + 3 * dir.Z) & 7) * 2;
757
758         // Get rotation for things like chests
759         u8 facedir = mn.getFaceDir(ndef);
760
761         static const u16 dir_to_tile[24 * 16] =
762         {
763                 // 0     +X    +Y    +Z           -Z    -Y    -X   ->   value=tile,rotation
764                    0,0,  2,0 , 0,0 , 4,0 ,  0,0,  5,0 , 1,0 , 3,0 ,  // rotate around y+ 0 - 3
765                    0,0,  4,0 , 0,3 , 3,0 ,  0,0,  2,0 , 1,1 , 5,0 ,
766                    0,0,  3,0 , 0,2 , 5,0 ,  0,0,  4,0 , 1,2 , 2,0 ,
767                    0,0,  5,0 , 0,1 , 2,0 ,  0,0,  3,0 , 1,3 , 4,0 ,
768
769                    0,0,  2,3 , 5,0 , 0,2 ,  0,0,  1,0 , 4,2 , 3,1 ,  // rotate around z+ 4 - 7
770                    0,0,  4,3 , 2,0 , 0,1 ,  0,0,  1,1 , 3,2 , 5,1 ,
771                    0,0,  3,3 , 4,0 , 0,0 ,  0,0,  1,2 , 5,2 , 2,1 ,
772                    0,0,  5,3 , 3,0 , 0,3 ,  0,0,  1,3 , 2,2 , 4,1 ,
773
774                    0,0,  2,1 , 4,2 , 1,2 ,  0,0,  0,0 , 5,0 , 3,3 ,  // rotate around z- 8 - 11
775                    0,0,  4,1 , 3,2 , 1,3 ,  0,0,  0,3 , 2,0 , 5,3 ,
776                    0,0,  3,1 , 5,2 , 1,0 ,  0,0,  0,2 , 4,0 , 2,3 ,
777                    0,0,  5,1 , 2,2 , 1,1 ,  0,0,  0,1 , 3,0 , 4,3 ,
778
779                    0,0,  0,3 , 3,3 , 4,1 ,  0,0,  5,3 , 2,3 , 1,3 ,  // rotate around x+ 12 - 15
780                    0,0,  0,2 , 5,3 , 3,1 ,  0,0,  2,3 , 4,3 , 1,0 ,
781                    0,0,  0,1 , 2,3 , 5,1 ,  0,0,  4,3 , 3,3 , 1,1 ,
782                    0,0,  0,0 , 4,3 , 2,1 ,  0,0,  3,3 , 5,3 , 1,2 ,
783
784                    0,0,  1,1 , 2,1 , 4,3 ,  0,0,  5,1 , 3,1 , 0,1 ,  // rotate around x- 16 - 19
785                    0,0,  1,2 , 4,1 , 3,3 ,  0,0,  2,1 , 5,1 , 0,0 ,
786                    0,0,  1,3 , 3,1 , 5,3 ,  0,0,  4,1 , 2,1 , 0,3 ,
787                    0,0,  1,0 , 5,1 , 2,3 ,  0,0,  3,1 , 4,1 , 0,2 ,
788
789                    0,0,  3,2 , 1,2 , 4,2 ,  0,0,  5,2 , 0,2 , 2,2 ,  // rotate around y- 20 - 23
790                    0,0,  5,2 , 1,3 , 3,2 ,  0,0,  2,2 , 0,1 , 4,2 ,
791                    0,0,  2,2 , 1,0 , 5,2 ,  0,0,  4,2 , 0,0 , 3,2 ,
792                    0,0,  4,2 , 1,1 , 2,2 ,  0,0,  3,2 , 0,3 , 5,2
793
794         };
795         u16 tile_index = facedir * 16 + dir_i;
796         getNodeTileN(mn, p, dir_to_tile[tile_index], data, tile);
797         tile.rotation = tile.world_aligned ? 0 : dir_to_tile[tile_index + 1];
798 }
799
800 static void getTileInfo(
801                 // Input:
802                 MeshMakeData *data,
803                 const v3s16 &p,
804                 const v3s16 &face_dir,
805                 // Output:
806                 bool &makes_face,
807                 v3s16 &p_corrected,
808                 v3s16 &face_dir_corrected,
809                 u16 *lights,
810                 TileSpec &tile
811         )
812 {
813         VoxelManipulator &vmanip = data->m_vmanip;
814         const NodeDefManager *ndef = data->m_client->ndef();
815         v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
816
817         const MapNode &n0 = vmanip.getNodeRefUnsafe(blockpos_nodes + p);
818
819         // Don't even try to get n1 if n0 is already CONTENT_IGNORE
820         if (n0.getContent() == CONTENT_IGNORE) {
821                 makes_face = false;
822                 return;
823         }
824
825         const MapNode &n1 = vmanip.getNodeRefUnsafeCheckFlags(blockpos_nodes + p + face_dir);
826
827         if (n1.getContent() == CONTENT_IGNORE) {
828                 makes_face = false;
829                 return;
830         }
831
832         // This is hackish
833         bool equivalent = false;
834         u8 mf = face_contents(n0.getContent(), n1.getContent(),
835                         &equivalent, ndef);
836
837         if (mf == 0) {
838                 makes_face = false;
839                 return;
840         }
841
842         makes_face = true;
843
844         MapNode n = n0;
845
846         if (mf == 1) {
847                 p_corrected = p;
848                 face_dir_corrected = face_dir;
849         } else {
850                 n = n1;
851                 p_corrected = p + face_dir;
852                 face_dir_corrected = -face_dir;
853         }
854
855         getNodeTile(n, p_corrected, face_dir_corrected, data, tile);
856         const ContentFeatures &f = ndef->get(n);
857         tile.emissive_light = f.light_source;
858
859         // eg. water and glass
860         if (equivalent) {
861                 for (TileLayer &layer : tile.layers)
862                         layer.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
863         }
864
865         if (!data->m_smooth_lighting) {
866                 lights[0] = lights[1] = lights[2] = lights[3] =
867                                 getFaceLight(n0, n1, face_dir, ndef);
868         } else {
869                 v3s16 vertex_dirs[4];
870                 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
871
872                 v3s16 light_p = blockpos_nodes + p_corrected;
873                 for (u16 i = 0; i < 4; i++)
874                         lights[i] = getSmoothLightSolid(light_p, face_dir_corrected, vertex_dirs[i], data);
875         }
876 }
877
878 /*
879         startpos:
880         translate_dir: unit vector with only one of x, y or z
881         face_dir: unit vector with only one of x, y or z
882 */
883 static void updateFastFaceRow(
884                 MeshMakeData *data,
885                 const v3s16 &&startpos,
886                 v3s16 translate_dir,
887                 const v3f &&translate_dir_f,
888                 const v3s16 &&face_dir,
889                 std::vector<FastFace> &dest)
890 {
891         v3s16 p = startpos;
892
893         u16 continuous_tiles_count = 1;
894
895         bool makes_face = false;
896         v3s16 p_corrected;
897         v3s16 face_dir_corrected;
898         u16 lights[4] = {0, 0, 0, 0};
899         TileSpec tile;
900         getTileInfo(data, p, face_dir,
901                         makes_face, p_corrected, face_dir_corrected,
902                         lights, tile);
903
904         // Unroll this variable which has a significant build cost
905         TileSpec next_tile;
906         for (u16 j = 0; j < MAP_BLOCKSIZE; j++) {
907                 // If tiling can be done, this is set to false in the next step
908                 bool next_is_different = true;
909
910                 v3s16 p_next;
911
912                 bool next_makes_face = false;
913                 v3s16 next_p_corrected;
914                 v3s16 next_face_dir_corrected;
915                 u16 next_lights[4] = {0, 0, 0, 0};
916
917                 // If at last position, there is nothing to compare to and
918                 // the face must be drawn anyway
919                 if (j != MAP_BLOCKSIZE - 1) {
920                         p_next = p + translate_dir;
921
922                         getTileInfo(data, p_next, face_dir,
923                                         next_makes_face, next_p_corrected,
924                                         next_face_dir_corrected, next_lights,
925                                         next_tile);
926
927                         if (next_makes_face == makes_face
928                                         && next_p_corrected == p_corrected + translate_dir
929                                         && next_face_dir_corrected == face_dir_corrected
930                                         && memcmp(next_lights, lights, ARRLEN(lights) * sizeof(u16)) == 0
931                                         && next_tile.isTileable(tile)) {
932                                 next_is_different = false;
933                                 continuous_tiles_count++;
934                         }
935                 }
936                 if (next_is_different) {
937                         /*
938                                 Create a face if there should be one
939                         */
940                         if (makes_face) {
941                                 // Floating point conversion of the position vector
942                                 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
943                                 // Center point of face (kind of)
944                                 v3f sp = pf - ((f32)continuous_tiles_count * 0.5f - 0.5f)
945                                         * translate_dir_f;
946                                 v3f scale(1, 1, 1);
947
948                                 if (translate_dir.X != 0)
949                                         scale.X = continuous_tiles_count;
950                                 if (translate_dir.Y != 0)
951                                         scale.Y = continuous_tiles_count;
952                                 if (translate_dir.Z != 0)
953                                         scale.Z = continuous_tiles_count;
954
955                                 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
956                                                 pf, sp, face_dir_corrected, scale, dest);
957
958                                 g_profiler->avg("Meshgen: faces drawn by tiling", 0);
959                                 for (int i = 1; i < continuous_tiles_count; i++)
960                                         g_profiler->avg("Meshgen: faces drawn by tiling", 1);
961                         }
962
963                         continuous_tiles_count = 1;
964                 }
965
966                 makes_face = next_makes_face;
967                 p_corrected = next_p_corrected;
968                 face_dir_corrected = next_face_dir_corrected;
969                 std::memcpy(lights, next_lights, ARRLEN(lights) * sizeof(u16));
970                 if (next_is_different)
971                         tile = next_tile;
972                 p = p_next;
973         }
974 }
975
976 static void updateAllFastFaceRows(MeshMakeData *data,
977                 std::vector<FastFace> &dest)
978 {
979         /*
980                 Go through every y,z and get top(y+) faces in rows of x+
981         */
982         for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
983         for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
984                 updateFastFaceRow(data,
985                                 v3s16(0, y, z),
986                                 v3s16(1, 0, 0), //dir
987                                 v3f  (1, 0, 0),
988                                 v3s16(0, 1, 0), //face dir
989                                 dest);
990
991         /*
992                 Go through every x,y and get right(x+) faces in rows of z+
993         */
994         for (s16 x = 0; x < MAP_BLOCKSIZE; x++)
995         for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
996                 updateFastFaceRow(data,
997                                 v3s16(x, y, 0),
998                                 v3s16(0, 0, 1), //dir
999                                 v3f  (0, 0, 1),
1000                                 v3s16(1, 0, 0), //face dir
1001                                 dest);
1002
1003         /*
1004                 Go through every y,z and get back(z+) faces in rows of x+
1005         */
1006         for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
1007         for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
1008                 updateFastFaceRow(data,
1009                                 v3s16(0, y, z),
1010                                 v3s16(1, 0, 0), //dir
1011                                 v3f  (1, 0, 0),
1012                                 v3s16(0, 0, 1), //face dir
1013                                 dest);
1014 }
1015
1016 /*
1017         MapBlockMesh
1018 */
1019
1020 MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
1021         m_minimap_mapblock(NULL),
1022         m_tsrc(data->m_client->getTextureSource()),
1023         m_shdrsrc(data->m_client->getShaderSource()),
1024         m_animation_force_timer(0), // force initial animation
1025         m_last_crack(-1),
1026         m_last_daynight_ratio((u32) -1)
1027 {
1028         for (auto &m : m_mesh)
1029                 m = new scene::SMesh();
1030         m_enable_shaders = data->m_use_shaders;
1031         m_use_tangent_vertices = data->m_use_tangent_vertices;
1032         m_enable_vbo = g_settings->getBool("enable_vbo");
1033
1034         if (g_settings->getBool("enable_minimap")) {
1035                 m_minimap_mapblock = new MinimapMapblock;
1036                 m_minimap_mapblock->getMinimapNodes(
1037                         &data->m_vmanip, data->m_blockpos * MAP_BLOCKSIZE);
1038         }
1039
1040         // 4-21ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1041         // 24-155ms for MAP_BLOCKSIZE=32  (NOTE: probably outdated)
1042         //TimeTaker timer1("MapBlockMesh()");
1043
1044         std::vector<FastFace> fastfaces_new;
1045         fastfaces_new.reserve(512);
1046
1047         /*
1048                 We are including the faces of the trailing edges of the block.
1049                 This means that when something changes, the caller must
1050                 also update the meshes of the blocks at the leading edges.
1051
1052                 NOTE: This is the slowest part of this method.
1053         */
1054         {
1055                 // 4-23ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1056                 //TimeTaker timer2("updateAllFastFaceRows()");
1057                 updateAllFastFaceRows(data, fastfaces_new);
1058         }
1059         // End of slow part
1060
1061         /*
1062                 Convert FastFaces to MeshCollector
1063         */
1064
1065         MeshCollector collector(m_use_tangent_vertices);
1066
1067         {
1068                 // avg 0ms (100ms spikes when loading textures the first time)
1069                 // (NOTE: probably outdated)
1070                 //TimeTaker timer2("MeshCollector building");
1071
1072                 for (const FastFace &f : fastfaces_new) {
1073                         static const u16 indices[] = {0, 1, 2, 2, 3, 0};
1074                         static const u16 indices_alternate[] = {0, 1, 3, 2, 3, 1};
1075
1076                         if (!f.layer.texture)
1077                                 continue;
1078
1079                         const u16 *indices_p =
1080                                 f.vertex_0_2_connected ? indices : indices_alternate;
1081
1082                         collector.append(f.layer, f.vertices, 4, indices_p, 6,
1083                                 f.layernum, f.world_aligned);
1084                 }
1085         }
1086
1087         /*
1088                 Add special graphics:
1089                 - torches
1090                 - flowing water
1091                 - fences
1092                 - whatever
1093         */
1094
1095         {
1096                 MapblockMeshGenerator generator(data, &collector);
1097                 generator.generate();
1098         }
1099
1100         collector.applyTileColors();
1101
1102         /*
1103                 Convert MeshCollector to SMesh
1104         */
1105
1106         for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
1107                 for(u32 i = 0; i < collector.prebuffers[layer].size(); i++)
1108                 {
1109                         PreMeshBuffer &p = collector.prebuffers[layer][i];
1110
1111                         // Generate animation data
1112                         // - Cracks
1113                         if (p.layer.material_flags & MATERIAL_FLAG_CRACK) {
1114                                 // Find the texture name plus ^[crack:N:
1115                                 std::ostringstream os(std::ios::binary);
1116                                 os << m_tsrc->getTextureName(p.layer.texture_id) << "^[crack";
1117                                 if (p.layer.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1118                                         os << "o";  // use ^[cracko
1119                                 u8 tiles = p.layer.scale;
1120                                 if (tiles > 1)
1121                                         os << ":" << (u32)tiles;
1122                                 os << ":" << (u32)p.layer.animation_frame_count << ":";
1123                                 m_crack_materials.insert(std::make_pair(
1124                                                 std::pair<u8, u32>(layer, i), os.str()));
1125                                 // Replace tile texture with the cracked one
1126                                 p.layer.texture = m_tsrc->getTextureForMesh(
1127                                                 os.str() + "0",
1128                                                 &p.layer.texture_id);
1129                         }
1130                         // - Texture animation
1131                         if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
1132                                 // Add to MapBlockMesh in order to animate these tiles
1133                                 m_animation_tiles[std::pair<u8, u32>(layer, i)] = p.layer;
1134                                 m_animation_frames[std::pair<u8, u32>(layer, i)] = 0;
1135                                 if (g_settings->getBool(
1136                                                 "desynchronize_mapblock_texture_animation")) {
1137                                         // Get starting position from noise
1138                                         m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] =
1139                                                         100000 * (2.0 + noise3d(
1140                                                         data->m_blockpos.X, data->m_blockpos.Y,
1141                                                         data->m_blockpos.Z, 0));
1142                                 } else {
1143                                         // Play all synchronized
1144                                         m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] = 0;
1145                                 }
1146                                 // Replace tile texture with the first animation frame
1147                                 p.layer.texture = (*p.layer.frames)[0].texture;
1148                         }
1149
1150                         if (!m_enable_shaders) {
1151                                 // Extract colors for day-night animation
1152                                 // Dummy sunlight to handle non-sunlit areas
1153                                 video::SColorf sunlight;
1154                                 get_sunlight_color(&sunlight, 0);
1155                                 u32 vertex_count = m_use_tangent_vertices ?
1156                                                 p.tangent_vertices.size() : p.vertices.size();
1157                                 for (u32 j = 0; j < vertex_count; j++) {
1158                                         video::SColor *vc;
1159                                         if (m_use_tangent_vertices) {
1160                                                 vc = &p.tangent_vertices[j].Color;
1161                                         } else {
1162                                                 vc = &p.vertices[j].Color;
1163                                         }
1164                                         video::SColor copy(*vc);
1165                                         if (vc->getAlpha() == 0) // No sunlight - no need to animate
1166                                                 final_color_blend(vc, copy, sunlight); // Finalize color
1167                                         else // Record color to animate
1168                                                 m_daynight_diffs[std::pair<u8, u32>(layer, i)][j] = copy;
1169
1170                                         // The sunlight ratio has been stored,
1171                                         // delete alpha (for the final rendering).
1172                                         vc->setAlpha(255);
1173                                 }
1174                         }
1175
1176                         // Create material
1177                         video::SMaterial material;
1178                         material.setFlag(video::EMF_LIGHTING, false);
1179                         material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1180                         material.setFlag(video::EMF_BILINEAR_FILTER, false);
1181                         material.setFlag(video::EMF_FOG_ENABLE, true);
1182                         material.setTexture(0, p.layer.texture);
1183
1184                         if (m_enable_shaders) {
1185                                 material.MaterialType = m_shdrsrc->getShaderInfo(
1186                                                 p.layer.shader_id).material;
1187                                 p.layer.applyMaterialOptionsWithShaders(material);
1188                                 if (p.layer.normal_texture)
1189                                         material.setTexture(1, p.layer.normal_texture);
1190                                 material.setTexture(2, p.layer.flags_texture);
1191                         } else {
1192                                 p.layer.applyMaterialOptions(material);
1193                         }
1194
1195                         scene::SMesh *mesh = (scene::SMesh *)m_mesh[layer];
1196
1197                         // Create meshbuffer, add to mesh
1198                         if (m_use_tangent_vertices) {
1199                                 scene::SMeshBufferTangents *buf =
1200                                                 new scene::SMeshBufferTangents();
1201                                 // Set material
1202                                 buf->Material = material;
1203                                 // Add to mesh
1204                                 mesh->addMeshBuffer(buf);
1205                                 // Mesh grabbed it
1206                                 buf->drop();
1207                                 buf->append(&p.tangent_vertices[0], p.tangent_vertices.size(),
1208                                         &p.indices[0], p.indices.size());
1209                         } else {
1210                                 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1211                                 // Set material
1212                                 buf->Material = material;
1213                                 // Add to mesh
1214                                 mesh->addMeshBuffer(buf);
1215                                 // Mesh grabbed it
1216                                 buf->drop();
1217                                 buf->append(&p.vertices[0], p.vertices.size(),
1218                                         &p.indices[0], p.indices.size());
1219                         }
1220                 }
1221
1222                 /*
1223                         Do some stuff to the mesh
1224                 */
1225                 m_camera_offset = camera_offset;
1226                 translateMesh(m_mesh[layer],
1227                         intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
1228
1229                 if (m_use_tangent_vertices) {
1230                         scene::IMeshManipulator* meshmanip =
1231                                 RenderingEngine::get_scene_manager()->getMeshManipulator();
1232                         meshmanip->recalculateTangents(m_mesh[layer], true, false, false);
1233                 }
1234
1235                 if (m_mesh[layer]) {
1236 #if 0
1237                         // Usually 1-700 faces and 1-7 materials
1238                         std::cout << "Updated MapBlock has " << fastfaces_new.size()
1239                                         << " faces and uses " << m_mesh[layer]->getMeshBufferCount()
1240                                         << " materials (meshbuffers)" << std::endl;
1241 #endif
1242
1243                         // Use VBO for mesh (this just would set this for ever buffer)
1244                         if (m_enable_vbo)
1245                                 m_mesh[layer]->setHardwareMappingHint(scene::EHM_STATIC);
1246                 }
1247         }
1248
1249         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1250
1251         // Check if animation is required for this mesh
1252         m_has_animation =
1253                 !m_crack_materials.empty() ||
1254                 !m_daynight_diffs.empty() ||
1255                 !m_animation_tiles.empty();
1256 }
1257
1258 MapBlockMesh::~MapBlockMesh()
1259 {
1260         for (scene::IMesh *m : m_mesh) {
1261                 if (m_enable_vbo && m)
1262                         for (u32 i = 0; i < m->getMeshBufferCount(); i++) {
1263                                 scene::IMeshBuffer *buf = m->getMeshBuffer(i);
1264                                 RenderingEngine::get_video_driver()->removeHardwareBuffer(buf);
1265                         }
1266                 m->drop();
1267                 m = NULL;
1268         }
1269         delete m_minimap_mapblock;
1270 }
1271
1272 bool MapBlockMesh::animate(bool faraway, float time, int crack,
1273         u32 daynight_ratio)
1274 {
1275         if (!m_has_animation) {
1276                 m_animation_force_timer = 100000;
1277                 return false;
1278         }
1279
1280         m_animation_force_timer = myrand_range(5, 100);
1281
1282         // Cracks
1283         if (crack != m_last_crack) {
1284                 for (auto &crack_material : m_crack_materials) {
1285                         scene::IMeshBuffer *buf = m_mesh[crack_material.first.first]->
1286                                 getMeshBuffer(crack_material.first.second);
1287                         std::string basename = crack_material.second;
1288
1289                         // Create new texture name from original
1290                         std::ostringstream os;
1291                         os << basename << crack;
1292                         u32 new_texture_id = 0;
1293                         video::ITexture *new_texture =
1294                                         m_tsrc->getTextureForMesh(os.str(), &new_texture_id);
1295                         buf->getMaterial().setTexture(0, new_texture);
1296
1297                         // If the current material is also animated,
1298                         // update animation info
1299                         auto anim_iter = m_animation_tiles.find(crack_material.first);
1300                         if (anim_iter != m_animation_tiles.end()) {
1301                                 TileLayer &tile = anim_iter->second;
1302                                 tile.texture = new_texture;
1303                                 tile.texture_id = new_texture_id;
1304                                 // force animation update
1305                                 m_animation_frames[crack_material.first] = -1;
1306                         }
1307                 }
1308
1309                 m_last_crack = crack;
1310         }
1311
1312         // Texture animation
1313         for (auto &animation_tile : m_animation_tiles) {
1314                 const TileLayer &tile = animation_tile.second;
1315                 // Figure out current frame
1316                 int frameoffset = m_animation_frame_offsets[animation_tile.first];
1317                 int frame = (int)(time * 1000 / tile.animation_frame_length_ms
1318                                 + frameoffset) % tile.animation_frame_count;
1319                 // If frame doesn't change, skip
1320                 if (frame == m_animation_frames[animation_tile.first])
1321                         continue;
1322
1323                 m_animation_frames[animation_tile.first] = frame;
1324
1325                 scene::IMeshBuffer *buf = m_mesh[animation_tile.first.first]->
1326                         getMeshBuffer(animation_tile.first.second);
1327
1328                 const FrameSpec &animation_frame = (*tile.frames)[frame];
1329                 buf->getMaterial().setTexture(0, animation_frame.texture);
1330                 if (m_enable_shaders) {
1331                         if (animation_frame.normal_texture)
1332                                 buf->getMaterial().setTexture(1,
1333                                         animation_frame.normal_texture);
1334                         buf->getMaterial().setTexture(2, animation_frame.flags_texture);
1335                 }
1336         }
1337
1338         // Day-night transition
1339         if (!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio)) {
1340                 // Force reload mesh to VBO
1341                 if (m_enable_vbo)
1342                         for (scene::IMesh *m : m_mesh)
1343                                 m->setDirty();
1344                 video::SColorf day_color;
1345                 get_sunlight_color(&day_color, daynight_ratio);
1346
1347                 for (auto &daynight_diff : m_daynight_diffs) {
1348                         scene::IMeshBuffer *buf = m_mesh[daynight_diff.first.first]->
1349                                 getMeshBuffer(daynight_diff.first.second);
1350                         video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
1351                         for (const auto &j : daynight_diff.second)
1352                                 final_color_blend(&(vertices[j.first].Color), j.second,
1353                                                 day_color);
1354                 }
1355                 m_last_daynight_ratio = daynight_ratio;
1356         }
1357
1358         return true;
1359 }
1360
1361 void MapBlockMesh::updateCameraOffset(v3s16 camera_offset)
1362 {
1363         if (camera_offset != m_camera_offset) {
1364                 for (scene::IMesh *layer : m_mesh) {
1365                         translateMesh(layer,
1366                                 intToFloat(m_camera_offset - camera_offset, BS));
1367                         if (m_enable_vbo)
1368                                 layer->setDirty();
1369                 }
1370                 m_camera_offset = camera_offset;
1371         }
1372 }
1373
1374 /*
1375         MeshCollector
1376 */
1377
1378 void MeshCollector::append(const TileSpec &tile,
1379                 const video::S3DVertex *vertices, u32 numVertices,
1380                 const u16 *indices, u32 numIndices)
1381 {
1382         for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
1383                 const TileLayer *layer = &tile.layers[layernum];
1384                 if (layer->texture_id == 0)
1385                         continue;
1386                 append(*layer, vertices, numVertices, indices, numIndices,
1387                         layernum, tile.world_aligned);
1388         }
1389 }
1390
1391 void MeshCollector::append(const TileLayer &layer,
1392                 const video::S3DVertex *vertices, u32 numVertices,
1393                 const u16 *indices, u32 numIndices, u8 layernum,
1394                 bool use_scale)
1395 {
1396         if (numIndices > 65535) {
1397                 dstream << "FIXME: MeshCollector::append() called with numIndices="
1398                                 << numIndices << " (limit 65535)" << std::endl;
1399                 return;
1400         }
1401         std::vector<PreMeshBuffer> *buffers = &prebuffers[layernum];
1402
1403         PreMeshBuffer *p = NULL;
1404         for (PreMeshBuffer &pp : *buffers) {
1405                 if (pp.layer == layer && pp.indices.size() + numIndices <= 65535) {
1406                         p = &pp;
1407                         break;
1408                 }
1409         }
1410
1411         if (p == NULL) {
1412                 PreMeshBuffer pp;
1413                 pp.layer = layer;
1414                 buffers->push_back(pp);
1415                 p = &(*buffers)[buffers->size() - 1];
1416         }
1417
1418         f32 scale = 1.0;
1419         if (use_scale)
1420                 scale = 1.0 / layer.scale;
1421
1422         u32 vertex_count;
1423         if (m_use_tangent_vertices) {
1424                 vertex_count = p->tangent_vertices.size();
1425                 for (u32 i = 0; i < numVertices; i++) {
1426
1427                         video::S3DVertexTangents vert(vertices[i].Pos, vertices[i].Normal,
1428                                         vertices[i].Color, scale * vertices[i].TCoords);
1429                         p->tangent_vertices.push_back(vert);
1430                 }
1431         } else {
1432                 vertex_count = p->vertices.size();
1433                 for (u32 i = 0; i < numVertices; i++) {
1434                         video::S3DVertex vert(vertices[i].Pos, vertices[i].Normal,
1435                                         vertices[i].Color, scale * vertices[i].TCoords);
1436
1437                         p->vertices.push_back(vert);
1438                 }
1439         }
1440
1441         for (u32 i = 0; i < numIndices; i++) {
1442                 u32 j = indices[i] + vertex_count;
1443                 p->indices.push_back(j);
1444         }
1445 }
1446
1447 /*
1448         MeshCollector - for meshnodes and converted drawtypes.
1449 */
1450
1451 void MeshCollector::append(const TileSpec &tile,
1452                 const video::S3DVertex *vertices, u32 numVertices,
1453                 const u16 *indices, u32 numIndices,
1454                 v3f pos, video::SColor c, u8 light_source)
1455 {
1456         for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
1457                 const TileLayer *layer = &tile.layers[layernum];
1458                 if (layer->texture_id == 0)
1459                         continue;
1460                 append(*layer, vertices, numVertices, indices, numIndices, pos,
1461                                 c, light_source, layernum, tile.world_aligned);
1462         }
1463 }
1464
1465 void MeshCollector::append(const TileLayer &layer,
1466                 const video::S3DVertex *vertices, u32 numVertices,
1467                 const u16 *indices, u32 numIndices,
1468                 v3f pos, video::SColor c, u8 light_source, u8 layernum,
1469                 bool use_scale)
1470 {
1471         if (numIndices > 65535) {
1472                 dstream << "FIXME: MeshCollector::append() called with numIndices="
1473                                 << numIndices << " (limit 65535)" << std::endl;
1474                 return;
1475         }
1476         std::vector<PreMeshBuffer> *buffers = &prebuffers[layernum];
1477
1478         PreMeshBuffer *p = NULL;
1479         for (PreMeshBuffer &pp : *buffers) {
1480                 if (pp.layer == layer && pp.indices.size() + numIndices <= 65535) {
1481                         p = &pp;
1482                         break;
1483                 }
1484         }
1485
1486         if (p == NULL) {
1487                 PreMeshBuffer pp;
1488                 pp.layer = layer;
1489                 buffers->push_back(pp);
1490                 p = &(*buffers)[buffers->size() - 1];
1491         }
1492
1493         f32 scale = 1.0;
1494         if (use_scale)
1495                 scale = 1.0 / layer.scale;
1496
1497         video::SColor original_c = c;
1498         u32 vertex_count;
1499         if (m_use_tangent_vertices) {
1500                 vertex_count = p->tangent_vertices.size();
1501                 for (u32 i = 0; i < numVertices; i++) {
1502                         if (!light_source) {
1503                                 c = original_c;
1504                                 applyFacesShading(c, vertices[i].Normal);
1505                         }
1506                         video::S3DVertexTangents vert(vertices[i].Pos + pos,
1507                                         vertices[i].Normal, c, scale * vertices[i].TCoords);
1508                         p->tangent_vertices.push_back(vert);
1509                 }
1510         } else {
1511                 vertex_count = p->vertices.size();
1512                 for (u32 i = 0; i < numVertices; i++) {
1513                         if (!light_source) {
1514                                 c = original_c;
1515                                 applyFacesShading(c, vertices[i].Normal);
1516                         }
1517                         video::S3DVertex vert(vertices[i].Pos + pos, vertices[i].Normal, c,
1518                                 scale * vertices[i].TCoords);
1519                         p->vertices.push_back(vert);
1520                 }
1521         }
1522
1523         for (u32 i = 0; i < numIndices; i++) {
1524                 u32 j = indices[i] + vertex_count;
1525                 p->indices.push_back(j);
1526         }
1527 }
1528
1529 void MeshCollector::applyTileColors()
1530 {
1531         if (m_use_tangent_vertices)
1532                 for (auto &prebuffer : prebuffers) {
1533                         for (PreMeshBuffer &pmb : prebuffer) {
1534                                 video::SColor tc = pmb.layer.color;
1535                                 if (tc == video::SColor(0xFFFFFFFF))
1536                                         continue;
1537                                 for (video::S3DVertexTangents &tangent_vertex : pmb.tangent_vertices) {
1538                                         video::SColor *c = &tangent_vertex.Color;
1539                                         c->set(c->getAlpha(), c->getRed() * tc.getRed() / 255,
1540                                                 c->getGreen() * tc.getGreen() / 255,
1541                                                 c->getBlue() * tc.getBlue() / 255);
1542                                 }
1543                         }
1544                 }
1545         else
1546                 for (auto &prebuffer : prebuffers) {
1547                         for (PreMeshBuffer &pmb : prebuffer) {
1548                                 video::SColor tc = pmb.layer.color;
1549                                 if (tc == video::SColor(0xFFFFFFFF))
1550                                         continue;
1551                                 for (video::S3DVertex &vertex : pmb.vertices) {
1552                                         video::SColor *c = &vertex.Color;
1553                                         c->set(c->getAlpha(), c->getRed() * tc.getRed() / 255,
1554                                                 c->getGreen() * tc.getGreen() / 255,
1555                                                 c->getBlue() * tc.getBlue() / 255);
1556                                 }
1557                         }
1558                 }
1559 }
1560
1561 video::SColor encode_light(u16 light, u8 emissive_light)
1562 {
1563         // Get components
1564         u32 day = (light & 0xff);
1565         u32 night = (light >> 8);
1566         // Add emissive light
1567         night += emissive_light * 2.5f;
1568         if (night > 255)
1569                 night = 255;
1570         // Since we don't know if the day light is sunlight or
1571         // artificial light, assume it is artificial when the night
1572         // light bank is also lit.
1573         if (day < night)
1574                 day = 0;
1575         else
1576                 day = day - night;
1577         u32 sum = day + night;
1578         // Ratio of sunlight:
1579         u32 r;
1580         if (sum > 0)
1581                 r = day * 255 / sum;
1582         else
1583                 r = 0;
1584         // Average light:
1585         float b = (day + night) / 2;
1586         return video::SColor(r, b, b, b);
1587 }