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