]> git.lizzy.rs Git - minetest.git/blob - src/client/mapblock_mesh.cpp
Formspecs: Introduce formspec_version to mods
[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                 TileSpec &tile
799         )
800 {
801         VoxelManipulator &vmanip = data->m_vmanip;
802         const NodeDefManager *ndef = data->m_client->ndef();
803         v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
804
805         const MapNode &n0 = vmanip.getNodeRefUnsafe(blockpos_nodes + p);
806
807         // Don't even try to get n1 if n0 is already CONTENT_IGNORE
808         if (n0.getContent() == CONTENT_IGNORE) {
809                 makes_face = false;
810                 return;
811         }
812
813         const MapNode &n1 = vmanip.getNodeRefUnsafeCheckFlags(blockpos_nodes + p + face_dir);
814
815         if (n1.getContent() == CONTENT_IGNORE) {
816                 makes_face = false;
817                 return;
818         }
819
820         // This is hackish
821         bool equivalent = false;
822         u8 mf = face_contents(n0.getContent(), n1.getContent(),
823                         &equivalent, ndef);
824
825         if (mf == 0) {
826                 makes_face = false;
827                 return;
828         }
829
830         makes_face = true;
831
832         MapNode n = n0;
833
834         if (mf == 1) {
835                 p_corrected = p;
836                 face_dir_corrected = face_dir;
837         } else {
838                 n = n1;
839                 p_corrected = p + face_dir;
840                 face_dir_corrected = -face_dir;
841         }
842
843         getNodeTile(n, p_corrected, face_dir_corrected, data, tile);
844         const ContentFeatures &f = ndef->get(n);
845         tile.emissive_light = f.light_source;
846
847         // eg. water and glass
848         if (equivalent) {
849                 for (TileLayer &layer : tile.layers)
850                         layer.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
851         }
852
853         if (!data->m_smooth_lighting) {
854                 lights[0] = lights[1] = lights[2] = lights[3] =
855                                 getFaceLight(n0, n1, face_dir, ndef);
856         } else {
857                 v3s16 vertex_dirs[4];
858                 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
859
860                 v3s16 light_p = blockpos_nodes + p_corrected;
861                 for (u16 i = 0; i < 4; i++)
862                         lights[i] = getSmoothLightSolid(light_p, face_dir_corrected, vertex_dirs[i], data);
863         }
864 }
865
866 /*
867         startpos:
868         translate_dir: unit vector with only one of x, y or z
869         face_dir: unit vector with only one of x, y or z
870 */
871 static void updateFastFaceRow(
872                 MeshMakeData *data,
873                 const v3s16 &&startpos,
874                 v3s16 translate_dir,
875                 const v3f &&translate_dir_f,
876                 const v3s16 &&face_dir,
877                 std::vector<FastFace> &dest)
878 {
879         v3s16 p = startpos;
880
881         u16 continuous_tiles_count = 1;
882
883         bool makes_face = false;
884         v3s16 p_corrected;
885         v3s16 face_dir_corrected;
886         u16 lights[4] = {0, 0, 0, 0};
887         TileSpec tile;
888         getTileInfo(data, p, face_dir,
889                         makes_face, p_corrected, face_dir_corrected,
890                         lights, tile);
891
892         // Unroll this variable which has a significant build cost
893         TileSpec next_tile;
894         for (u16 j = 0; j < MAP_BLOCKSIZE; j++) {
895                 // If tiling can be done, this is set to false in the next step
896                 bool next_is_different = true;
897
898                 v3s16 p_next;
899
900                 bool next_makes_face = false;
901                 v3s16 next_p_corrected;
902                 v3s16 next_face_dir_corrected;
903                 u16 next_lights[4] = {0, 0, 0, 0};
904
905                 // If at last position, there is nothing to compare to and
906                 // the face must be drawn anyway
907                 if (j != MAP_BLOCKSIZE - 1) {
908                         p_next = p + translate_dir;
909
910                         getTileInfo(data, p_next, face_dir,
911                                         next_makes_face, next_p_corrected,
912                                         next_face_dir_corrected, next_lights,
913                                         next_tile);
914
915                         if (next_makes_face == makes_face
916                                         && next_p_corrected == p_corrected + translate_dir
917                                         && next_face_dir_corrected == face_dir_corrected
918                                         && memcmp(next_lights, lights, ARRLEN(lights) * sizeof(u16)) == 0
919                                         && next_tile.isTileable(tile)) {
920                                 next_is_different = false;
921                                 continuous_tiles_count++;
922                         }
923                 }
924                 if (next_is_different) {
925                         /*
926                                 Create a face if there should be one
927                         */
928                         if (makes_face) {
929                                 // Floating point conversion of the position vector
930                                 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
931                                 // Center point of face (kind of)
932                                 v3f sp = pf - ((f32)continuous_tiles_count * 0.5f - 0.5f)
933                                         * translate_dir_f;
934                                 v3f scale(1, 1, 1);
935
936                                 if (translate_dir.X != 0)
937                                         scale.X = continuous_tiles_count;
938                                 if (translate_dir.Y != 0)
939                                         scale.Y = continuous_tiles_count;
940                                 if (translate_dir.Z != 0)
941                                         scale.Z = continuous_tiles_count;
942
943                                 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
944                                                 pf, sp, face_dir_corrected, scale, dest);
945                                 g_profiler->avg("Meshgen: Tiles per face [#]", continuous_tiles_count);
946                         }
947
948                         continuous_tiles_count = 1;
949                 }
950
951                 makes_face = next_makes_face;
952                 p_corrected = next_p_corrected;
953                 face_dir_corrected = next_face_dir_corrected;
954                 std::memcpy(lights, next_lights, ARRLEN(lights) * sizeof(u16));
955                 if (next_is_different)
956                         tile = next_tile;
957                 p = p_next;
958         }
959 }
960
961 static void updateAllFastFaceRows(MeshMakeData *data,
962                 std::vector<FastFace> &dest)
963 {
964         /*
965                 Go through every y,z and get top(y+) faces in rows of x+
966         */
967         for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
968         for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
969                 updateFastFaceRow(data,
970                                 v3s16(0, y, z),
971                                 v3s16(1, 0, 0), //dir
972                                 v3f  (1, 0, 0),
973                                 v3s16(0, 1, 0), //face dir
974                                 dest);
975
976         /*
977                 Go through every x,y and get right(x+) faces in rows of z+
978         */
979         for (s16 x = 0; x < MAP_BLOCKSIZE; x++)
980         for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
981                 updateFastFaceRow(data,
982                                 v3s16(x, y, 0),
983                                 v3s16(0, 0, 1), //dir
984                                 v3f  (0, 0, 1),
985                                 v3s16(1, 0, 0), //face dir
986                                 dest);
987
988         /*
989                 Go through every y,z and get back(z+) faces in rows of x+
990         */
991         for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
992         for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
993                 updateFastFaceRow(data,
994                                 v3s16(0, y, z),
995                                 v3s16(1, 0, 0), //dir
996                                 v3f  (1, 0, 0),
997                                 v3s16(0, 0, 1), //face dir
998                                 dest);
999 }
1000
1001 static void applyTileColor(PreMeshBuffer &pmb)
1002 {
1003         video::SColor tc = pmb.layer.color;
1004         if (tc == video::SColor(0xFFFFFFFF))
1005                 return;
1006         for (video::S3DVertex &vertex : pmb.vertices) {
1007                 video::SColor *c = &vertex.Color;
1008                 c->set(c->getAlpha(),
1009                         c->getRed() * tc.getRed() / 255,
1010                         c->getGreen() * tc.getGreen() / 255,
1011                         c->getBlue() * tc.getBlue() / 255);
1012         }
1013 }
1014
1015 /*
1016         MapBlockMesh
1017 */
1018
1019 MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
1020         m_minimap_mapblock(NULL),
1021         m_tsrc(data->m_client->getTextureSource()),
1022         m_shdrsrc(data->m_client->getShaderSource()),
1023         m_animation_force_timer(0), // force initial animation
1024         m_last_crack(-1),
1025         m_last_daynight_ratio((u32) -1)
1026 {
1027         for (auto &m : m_mesh)
1028                 m = new scene::SMesh();
1029         m_enable_shaders = data->m_use_shaders;
1030         m_use_tangent_vertices = data->m_use_tangent_vertices;
1031         m_enable_vbo = g_settings->getBool("enable_vbo");
1032
1033         if (g_settings->getBool("enable_minimap")) {
1034                 m_minimap_mapblock = new MinimapMapblock;
1035                 m_minimap_mapblock->getMinimapNodes(
1036                         &data->m_vmanip, data->m_blockpos * MAP_BLOCKSIZE);
1037         }
1038
1039         // 4-21ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1040         // 24-155ms for MAP_BLOCKSIZE=32  (NOTE: probably outdated)
1041         //TimeTaker timer1("MapBlockMesh()");
1042
1043         std::vector<FastFace> fastfaces_new;
1044         fastfaces_new.reserve(512);
1045
1046         /*
1047                 We are including the faces of the trailing edges of the block.
1048                 This means that when something changes, the caller must
1049                 also update the meshes of the blocks at the leading edges.
1050
1051                 NOTE: This is the slowest part of this method.
1052         */
1053         {
1054                 // 4-23ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1055                 //TimeTaker timer2("updateAllFastFaceRows()");
1056                 updateAllFastFaceRows(data, fastfaces_new);
1057         }
1058         // End of slow part
1059
1060         /*
1061                 Convert FastFaces to MeshCollector
1062         */
1063
1064         MeshCollector collector;
1065
1066         {
1067                 // avg 0ms (100ms spikes when loading textures the first time)
1068                 // (NOTE: probably outdated)
1069                 //TimeTaker timer2("MeshCollector building");
1070
1071                 for (const FastFace &f : fastfaces_new) {
1072                         static const u16 indices[] = {0, 1, 2, 2, 3, 0};
1073                         static const u16 indices_alternate[] = {0, 1, 3, 2, 3, 1};
1074                         const u16 *indices_p =
1075                                 f.vertex_0_2_connected ? indices : indices_alternate;
1076                         collector.append(f.tile, f.vertices, 4, indices_p, 6);
1077                 }
1078         }
1079
1080         /*
1081                 Add special graphics:
1082                 - torches
1083                 - flowing water
1084                 - fences
1085                 - whatever
1086         */
1087
1088         {
1089                 MapblockMeshGenerator generator(data, &collector);
1090                 generator.generate();
1091         }
1092
1093         /*
1094                 Convert MeshCollector to SMesh
1095         */
1096
1097         for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
1098                 for(u32 i = 0; i < collector.prebuffers[layer].size(); i++)
1099                 {
1100                         PreMeshBuffer &p = collector.prebuffers[layer][i];
1101
1102                         applyTileColor(p);
1103
1104                         // Generate animation data
1105                         // - Cracks
1106                         if (p.layer.material_flags & MATERIAL_FLAG_CRACK) {
1107                                 // Find the texture name plus ^[crack:N:
1108                                 std::ostringstream os(std::ios::binary);
1109                                 os << m_tsrc->getTextureName(p.layer.texture_id) << "^[crack";
1110                                 if (p.layer.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1111                                         os << "o";  // use ^[cracko
1112                                 u8 tiles = p.layer.scale;
1113                                 if (tiles > 1)
1114                                         os << ":" << (u32)tiles;
1115                                 os << ":" << (u32)p.layer.animation_frame_count << ":";
1116                                 m_crack_materials.insert(std::make_pair(
1117                                                 std::pair<u8, u32>(layer, i), os.str()));
1118                                 // Replace tile texture with the cracked one
1119                                 p.layer.texture = m_tsrc->getTextureForMesh(
1120                                                 os.str() + "0",
1121                                                 &p.layer.texture_id);
1122                         }
1123                         // - Texture animation
1124                         if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
1125                                 // Add to MapBlockMesh in order to animate these tiles
1126                                 m_animation_tiles[std::pair<u8, u32>(layer, i)] = p.layer;
1127                                 m_animation_frames[std::pair<u8, u32>(layer, i)] = 0;
1128                                 if (g_settings->getBool(
1129                                                 "desynchronize_mapblock_texture_animation")) {
1130                                         // Get starting position from noise
1131                                         m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] =
1132                                                         100000 * (2.0 + noise3d(
1133                                                         data->m_blockpos.X, data->m_blockpos.Y,
1134                                                         data->m_blockpos.Z, 0));
1135                                 } else {
1136                                         // Play all synchronized
1137                                         m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] = 0;
1138                                 }
1139                                 // Replace tile texture with the first animation frame
1140                                 p.layer.texture = (*p.layer.frames)[0].texture;
1141                         }
1142
1143                         if (!m_enable_shaders) {
1144                                 // Extract colors for day-night animation
1145                                 // Dummy sunlight to handle non-sunlit areas
1146                                 video::SColorf sunlight;
1147                                 get_sunlight_color(&sunlight, 0);
1148                                 u32 vertex_count = p.vertices.size();
1149                                 for (u32 j = 0; j < vertex_count; j++) {
1150                                         video::SColor *vc = &p.vertices[j].Color;
1151                                         video::SColor copy = *vc;
1152                                         if (vc->getAlpha() == 0) // No sunlight - no need to animate
1153                                                 final_color_blend(vc, copy, sunlight); // Finalize color
1154                                         else // Record color to animate
1155                                                 m_daynight_diffs[std::pair<u8, u32>(layer, i)][j] = copy;
1156
1157                                         // The sunlight ratio has been stored,
1158                                         // delete alpha (for the final rendering).
1159                                         vc->setAlpha(255);
1160                                 }
1161                         }
1162
1163                         // Create material
1164                         video::SMaterial material;
1165                         material.setFlag(video::EMF_LIGHTING, false);
1166                         material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1167                         material.setFlag(video::EMF_BILINEAR_FILTER, false);
1168                         material.setFlag(video::EMF_FOG_ENABLE, true);
1169                         material.setTexture(0, p.layer.texture);
1170
1171                         if (m_enable_shaders) {
1172                                 material.MaterialType = m_shdrsrc->getShaderInfo(
1173                                                 p.layer.shader_id).material;
1174                                 p.layer.applyMaterialOptionsWithShaders(material);
1175                                 if (p.layer.normal_texture)
1176                                         material.setTexture(1, p.layer.normal_texture);
1177                                 material.setTexture(2, p.layer.flags_texture);
1178                         } else {
1179                                 p.layer.applyMaterialOptions(material);
1180                         }
1181
1182                         scene::SMesh *mesh = (scene::SMesh *)m_mesh[layer];
1183
1184                         // Create meshbuffer, add to mesh
1185                         if (m_use_tangent_vertices) {
1186                                 scene::SMeshBufferTangents *buf =
1187                                                 new scene::SMeshBufferTangents();
1188                                 buf->Material = material;
1189                                 buf->Vertices.reallocate(p.vertices.size());
1190                                 buf->Indices.reallocate(p.indices.size());
1191                                 for (const video::S3DVertex &v: p.vertices)
1192                                         buf->Vertices.push_back(video::S3DVertexTangents(v.Pos, v.Color, v.TCoords));
1193                                 for (u16 i: p.indices)
1194                                         buf->Indices.push_back(i);
1195                                 buf->recalculateBoundingBox();
1196                                 mesh->addMeshBuffer(buf);
1197                                 buf->drop();
1198                         } else {
1199                                 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1200                                 buf->Material = material;
1201                                 buf->append(&p.vertices[0], p.vertices.size(),
1202                                         &p.indices[0], p.indices.size());
1203                                 mesh->addMeshBuffer(buf);
1204                                 buf->drop();
1205                         }
1206                 }
1207
1208                 /*
1209                         Do some stuff to the mesh
1210                 */
1211                 m_camera_offset = camera_offset;
1212                 translateMesh(m_mesh[layer],
1213                         intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
1214
1215                 if (m_use_tangent_vertices) {
1216                         scene::IMeshManipulator* meshmanip =
1217                                 RenderingEngine::get_scene_manager()->getMeshManipulator();
1218                         meshmanip->recalculateTangents(m_mesh[layer], true, false, false);
1219                 }
1220
1221                 if (m_mesh[layer]) {
1222 #if 0
1223                         // Usually 1-700 faces and 1-7 materials
1224                         std::cout << "Updated MapBlock has " << fastfaces_new.size()
1225                                         << " faces and uses " << m_mesh[layer]->getMeshBufferCount()
1226                                         << " materials (meshbuffers)" << std::endl;
1227 #endif
1228
1229                         // Use VBO for mesh (this just would set this for ever buffer)
1230                         if (m_enable_vbo)
1231                                 m_mesh[layer]->setHardwareMappingHint(scene::EHM_STATIC);
1232                 }
1233         }
1234
1235         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1236
1237         // Check if animation is required for this mesh
1238         m_has_animation =
1239                 !m_crack_materials.empty() ||
1240                 !m_daynight_diffs.empty() ||
1241                 !m_animation_tiles.empty();
1242 }
1243
1244 MapBlockMesh::~MapBlockMesh()
1245 {
1246         for (scene::IMesh *m : m_mesh) {
1247                 if (m_enable_vbo && m)
1248                         for (u32 i = 0; i < m->getMeshBufferCount(); i++) {
1249                                 scene::IMeshBuffer *buf = m->getMeshBuffer(i);
1250                                 RenderingEngine::get_video_driver()->removeHardwareBuffer(buf);
1251                         }
1252                 m->drop();
1253                 m = NULL;
1254         }
1255         delete m_minimap_mapblock;
1256 }
1257
1258 bool MapBlockMesh::animate(bool faraway, float time, int crack,
1259         u32 daynight_ratio)
1260 {
1261         if (!m_has_animation) {
1262                 m_animation_force_timer = 100000;
1263                 return false;
1264         }
1265
1266         m_animation_force_timer = myrand_range(5, 100);
1267
1268         // Cracks
1269         if (crack != m_last_crack) {
1270                 for (auto &crack_material : m_crack_materials) {
1271                         scene::IMeshBuffer *buf = m_mesh[crack_material.first.first]->
1272                                 getMeshBuffer(crack_material.first.second);
1273                         std::string basename = crack_material.second;
1274
1275                         // Create new texture name from original
1276                         std::ostringstream os;
1277                         os << basename << crack;
1278                         u32 new_texture_id = 0;
1279                         video::ITexture *new_texture =
1280                                         m_tsrc->getTextureForMesh(os.str(), &new_texture_id);
1281                         buf->getMaterial().setTexture(0, new_texture);
1282
1283                         // If the current material is also animated,
1284                         // update animation info
1285                         auto anim_iter = m_animation_tiles.find(crack_material.first);
1286                         if (anim_iter != m_animation_tiles.end()) {
1287                                 TileLayer &tile = anim_iter->second;
1288                                 tile.texture = new_texture;
1289                                 tile.texture_id = new_texture_id;
1290                                 // force animation update
1291                                 m_animation_frames[crack_material.first] = -1;
1292                         }
1293                 }
1294
1295                 m_last_crack = crack;
1296         }
1297
1298         // Texture animation
1299         for (auto &animation_tile : m_animation_tiles) {
1300                 const TileLayer &tile = animation_tile.second;
1301                 // Figure out current frame
1302                 int frameoffset = m_animation_frame_offsets[animation_tile.first];
1303                 int frame = (int)(time * 1000 / tile.animation_frame_length_ms
1304                                 + frameoffset) % tile.animation_frame_count;
1305                 // If frame doesn't change, skip
1306                 if (frame == m_animation_frames[animation_tile.first])
1307                         continue;
1308
1309                 m_animation_frames[animation_tile.first] = frame;
1310
1311                 scene::IMeshBuffer *buf = m_mesh[animation_tile.first.first]->
1312                         getMeshBuffer(animation_tile.first.second);
1313
1314                 const FrameSpec &animation_frame = (*tile.frames)[frame];
1315                 buf->getMaterial().setTexture(0, animation_frame.texture);
1316                 if (m_enable_shaders) {
1317                         if (animation_frame.normal_texture)
1318                                 buf->getMaterial().setTexture(1,
1319                                         animation_frame.normal_texture);
1320                         buf->getMaterial().setTexture(2, animation_frame.flags_texture);
1321                 }
1322         }
1323
1324         // Day-night transition
1325         if (!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio)) {
1326                 // Force reload mesh to VBO
1327                 if (m_enable_vbo)
1328                         for (scene::IMesh *m : m_mesh)
1329                                 m->setDirty();
1330                 video::SColorf day_color;
1331                 get_sunlight_color(&day_color, daynight_ratio);
1332
1333                 for (auto &daynight_diff : m_daynight_diffs) {
1334                         scene::IMeshBuffer *buf = m_mesh[daynight_diff.first.first]->
1335                                 getMeshBuffer(daynight_diff.first.second);
1336                         video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
1337                         for (const auto &j : daynight_diff.second)
1338                                 final_color_blend(&(vertices[j.first].Color), j.second,
1339                                                 day_color);
1340                 }
1341                 m_last_daynight_ratio = daynight_ratio;
1342         }
1343
1344         return true;
1345 }
1346
1347 void MapBlockMesh::updateCameraOffset(v3s16 camera_offset)
1348 {
1349         if (camera_offset != m_camera_offset) {
1350                 for (scene::IMesh *layer : m_mesh) {
1351                         translateMesh(layer,
1352                                 intToFloat(m_camera_offset - camera_offset, BS));
1353                         if (m_enable_vbo)
1354                                 layer->setDirty();
1355                 }
1356                 m_camera_offset = camera_offset;
1357         }
1358 }
1359
1360 video::SColor encode_light(u16 light, u8 emissive_light)
1361 {
1362         // Get components
1363         u32 day = (light & 0xff);
1364         u32 night = (light >> 8);
1365         // Add emissive light
1366         night += emissive_light * 2.5f;
1367         if (night > 255)
1368                 night = 255;
1369         // Since we don't know if the day light is sunlight or
1370         // artificial light, assume it is artificial when the night
1371         // light bank is also lit.
1372         if (day < night)
1373                 day = 0;
1374         else
1375                 day = day - night;
1376         u32 sum = day + night;
1377         // Ratio of sunlight:
1378         u32 r;
1379         if (sum > 0)
1380                 r = day * 255 / sum;
1381         else
1382                 r = 0;
1383         // Average light:
1384         float b = (day + night) / 2;
1385         return video::SColor(r, b, b, b);
1386 }