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