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