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