]> git.lizzy.rs Git - dragonfireclient.git/blob - src/client/mapblock_mesh.cpp
add LUA_FCT
[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 && ! g_settings->getBool("fullbright");
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         bool obstructed[4] = { true, true, true, true };
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 // This table is moved outside getNodeVertexDirs to avoid the compiler using
379 // a mutex to initialize this table at runtime right in the hot path.
380 // For details search the internet for "cxa_guard_acquire".
381 static const v3s16 vertex_dirs_table[] = {
382         // ( 1, 0, 0)
383         v3s16( 1,-1, 1), v3s16( 1,-1,-1),
384         v3s16( 1, 1,-1), v3s16( 1, 1, 1),
385         // ( 0, 1, 0)
386         v3s16( 1, 1,-1), v3s16(-1, 1,-1),
387         v3s16(-1, 1, 1), v3s16( 1, 1, 1),
388         // ( 0, 0, 1)
389         v3s16(-1,-1, 1), v3s16( 1,-1, 1),
390         v3s16( 1, 1, 1), v3s16(-1, 1, 1),
391         // invalid
392         v3s16(), v3s16(), v3s16(), v3s16(),
393         // ( 0, 0,-1)
394         v3s16( 1,-1,-1), v3s16(-1,-1,-1),
395         v3s16(-1, 1,-1), v3s16( 1, 1,-1),
396         // ( 0,-1, 0)
397         v3s16( 1,-1, 1), v3s16(-1,-1, 1),
398         v3s16(-1,-1,-1), v3s16( 1,-1,-1),
399         // (-1, 0, 0)
400         v3s16(-1,-1,-1), v3s16(-1,-1, 1),
401         v3s16(-1, 1, 1), v3s16(-1, 1,-1)
402 };
403
404 /*
405         vertex_dirs: v3s16[4]
406 */
407 static void getNodeVertexDirs(const v3s16 &dir, v3s16 *vertex_dirs)
408 {
409         /*
410                 If looked from outside the node towards the face, the corners are:
411                 0: bottom-right
412                 1: bottom-left
413                 2: top-left
414                 3: top-right
415         */
416
417         // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
418         // (0,0,1), (0,0,-1)
419         assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z == 1);
420
421         // Convert direction to single integer for table lookup
422         u8 idx = (dir.X + 2 * dir.Y + 3 * dir.Z) & 7;
423         idx = (idx - 1) * 4;
424
425         memcpy(vertex_dirs, &vertex_dirs_table[idx], 4 * sizeof(v3s16));
426 }
427
428 static void getNodeTextureCoords(v3f base, const v3f &scale, const v3s16 &dir, float *u, float *v)
429 {
430         if (dir.X > 0 || dir.Y > 0 || dir.Z < 0)
431                 base -= scale;
432         if (dir == v3s16(0,0,1)) {
433                 *u = -base.X - 1;
434                 *v = -base.Y - 1;
435         } else if (dir == v3s16(0,0,-1)) {
436                 *u = base.X + 1;
437                 *v = -base.Y - 2;
438         } else if (dir == v3s16(1,0,0)) {
439                 *u = base.Z + 1;
440                 *v = -base.Y - 2;
441         } else if (dir == v3s16(-1,0,0)) {
442                 *u = -base.Z - 1;
443                 *v = -base.Y - 1;
444         } else if (dir == v3s16(0,1,0)) {
445                 *u = base.X + 1;
446                 *v = -base.Z - 2;
447         } else if (dir == v3s16(0,-1,0)) {
448                 *u = base.X;
449                 *v = base.Z;
450         }
451 }
452
453 struct FastFace
454 {
455         TileSpec tile;
456         video::S3DVertex vertices[4]; // Precalculated vertices
457         /*!
458          * The face is divided into two triangles. If this is true,
459          * vertices 0 and 2 are connected, othervise vertices 1 and 3
460          * are connected.
461          */
462         bool vertex_0_2_connected;
463 };
464
465 static void makeFastFace(const TileSpec &tile, u16 li0, u16 li1, u16 li2, u16 li3,
466         const v3f &tp, const v3f &p, const v3s16 &dir, const v3f &scale, std::vector<FastFace> &dest)
467 {
468         // Position is at the center of the cube.
469         v3f pos = p * BS;
470
471         float x0 = 0.0f;
472         float y0 = 0.0f;
473         float w = 1.0f;
474         float h = 1.0f;
475
476         v3f vertex_pos[4];
477         v3s16 vertex_dirs[4];
478         getNodeVertexDirs(dir, vertex_dirs);
479         if (tile.world_aligned)
480                 getNodeTextureCoords(tp, scale, dir, &x0, &y0);
481
482         v3s16 t;
483         u16 t1;
484         switch (tile.rotation) {
485         case 0:
486                 break;
487         case 1: //R90
488                 t = vertex_dirs[0];
489                 vertex_dirs[0] = vertex_dirs[3];
490                 vertex_dirs[3] = vertex_dirs[2];
491                 vertex_dirs[2] = vertex_dirs[1];
492                 vertex_dirs[1] = t;
493                 t1  = li0;
494                 li0 = li3;
495                 li3 = li2;
496                 li2 = li1;
497                 li1 = t1;
498                 break;
499         case 2: //R180
500                 t = vertex_dirs[0];
501                 vertex_dirs[0] = vertex_dirs[2];
502                 vertex_dirs[2] = t;
503                 t = vertex_dirs[1];
504                 vertex_dirs[1] = vertex_dirs[3];
505                 vertex_dirs[3] = t;
506                 t1  = li0;
507                 li0 = li2;
508                 li2 = t1;
509                 t1  = li1;
510                 li1 = li3;
511                 li3 = t1;
512                 break;
513         case 3: //R270
514                 t = vertex_dirs[0];
515                 vertex_dirs[0] = vertex_dirs[1];
516                 vertex_dirs[1] = vertex_dirs[2];
517                 vertex_dirs[2] = vertex_dirs[3];
518                 vertex_dirs[3] = t;
519                 t1  = li0;
520                 li0 = li1;
521                 li1 = li2;
522                 li2 = li3;
523                 li3 = t1;
524                 break;
525         case 4: //FXR90
526                 t = vertex_dirs[0];
527                 vertex_dirs[0] = vertex_dirs[3];
528                 vertex_dirs[3] = vertex_dirs[2];
529                 vertex_dirs[2] = vertex_dirs[1];
530                 vertex_dirs[1] = t;
531                 t1  = li0;
532                 li0 = li3;
533                 li3 = li2;
534                 li2 = li1;
535                 li1 = t1;
536                 y0 += h;
537                 h *= -1;
538                 break;
539         case 5: //FXR270
540                 t = vertex_dirs[0];
541                 vertex_dirs[0] = vertex_dirs[1];
542                 vertex_dirs[1] = vertex_dirs[2];
543                 vertex_dirs[2] = vertex_dirs[3];
544                 vertex_dirs[3] = t;
545                 t1  = li0;
546                 li0 = li1;
547                 li1 = li2;
548                 li2 = li3;
549                 li3 = t1;
550                 y0 += h;
551                 h *= -1;
552                 break;
553         case 6: //FYR90
554                 t = vertex_dirs[0];
555                 vertex_dirs[0] = vertex_dirs[3];
556                 vertex_dirs[3] = vertex_dirs[2];
557                 vertex_dirs[2] = vertex_dirs[1];
558                 vertex_dirs[1] = t;
559                 t1  = li0;
560                 li0 = li3;
561                 li3 = li2;
562                 li2 = li1;
563                 li1 = t1;
564                 x0 += w;
565                 w *= -1;
566                 break;
567         case 7: //FYR270
568                 t = vertex_dirs[0];
569                 vertex_dirs[0] = vertex_dirs[1];
570                 vertex_dirs[1] = vertex_dirs[2];
571                 vertex_dirs[2] = vertex_dirs[3];
572                 vertex_dirs[3] = t;
573                 t1  = li0;
574                 li0 = li1;
575                 li1 = li2;
576                 li2 = li3;
577                 li3 = t1;
578                 x0 += w;
579                 w *= -1;
580                 break;
581         case 8: //FX
582                 y0 += h;
583                 h *= -1;
584                 break;
585         case 9: //FY
586                 x0 += w;
587                 w *= -1;
588                 break;
589         default:
590                 break;
591         }
592
593         for (u16 i = 0; i < 4; i++) {
594                 vertex_pos[i] = v3f(
595                                 BS / 2 * vertex_dirs[i].X,
596                                 BS / 2 * vertex_dirs[i].Y,
597                                 BS / 2 * vertex_dirs[i].Z
598                 );
599         }
600
601         for (v3f &vpos : vertex_pos) {
602                 vpos.X *= scale.X;
603                 vpos.Y *= scale.Y;
604                 vpos.Z *= scale.Z;
605                 vpos += pos;
606         }
607
608         f32 abs_scale = 1.0f;
609         if      (scale.X < 0.999f || scale.X > 1.001f) abs_scale = scale.X;
610         else if (scale.Y < 0.999f || scale.Y > 1.001f) abs_scale = scale.Y;
611         else if (scale.Z < 0.999f || scale.Z > 1.001f) abs_scale = scale.Z;
612
613         v3f normal(dir.X, dir.Y, dir.Z);
614
615         u16 li[4] = { li0, li1, li2, li3 };
616         u16 day[4];
617         u16 night[4];
618
619         for (u8 i = 0; i < 4; i++) {
620                 day[i] = li[i] >> 8;
621                 night[i] = li[i] & 0xFF;
622         }
623
624         bool vertex_0_2_connected = abs(day[0] - day[2]) + abs(night[0] - night[2])
625                         < abs(day[1] - day[3]) + abs(night[1] - night[3]);
626
627         v2f32 f[4] = {
628                 core::vector2d<f32>(x0 + w * abs_scale, y0 + h),
629                 core::vector2d<f32>(x0, y0 + h),
630                 core::vector2d<f32>(x0, y0),
631                 core::vector2d<f32>(x0 + w * abs_scale, y0) };
632
633         // equivalent to dest.push_back(FastFace()) but faster
634         dest.emplace_back();
635         FastFace& face = *dest.rbegin();
636
637         for (u8 i = 0; i < 4; i++) {
638                 video::SColor c = encode_light(li[i], tile.emissive_light);
639                 if (!tile.emissive_light)
640                         applyFacesShading(c, normal);
641
642                 face.vertices[i] = video::S3DVertex(vertex_pos[i], normal, c, f[i]);
643         }
644
645         /*
646                 Revert triangles for nicer looking gradient if the
647                 brightness of vertices 1 and 3 differ less than
648                 the brightness of vertices 0 and 2.
649                 */
650         face.vertex_0_2_connected = vertex_0_2_connected;
651         face.tile = tile;
652 }
653
654 /*
655         Nodes make a face if contents differ and solidness differs.
656         Return value:
657                 0: No face
658                 1: Face uses m1's content
659                 2: Face uses m2's content
660         equivalent: Whether the blocks share the same face (eg. water and glass)
661
662         TODO: Add 3: Both faces drawn with backface culling, remove equivalent
663 */
664 static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
665         const NodeDefManager *ndef)
666 {
667         *equivalent = false;
668
669         if (m1 == m2 || m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
670                 return 0;
671
672         const ContentFeatures &f1 = ndef->get(m1);
673         const ContentFeatures &f2 = ndef->get(m2);
674
675         // Contents don't differ for different forms of same liquid
676         if (f1.sameLiquid(f2))
677                 return 0;
678
679         u8 c1 = f1.solidness;
680         u8 c2 = f2.solidness;
681
682
683         if (c1 == c2)
684                 return 0;
685
686         if (c1 == 0)
687                 c1 = f1.visual_solidness;
688         else if (c2 == 0)
689                 c2 = f2.visual_solidness;
690
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 std::set<content_t> splitToContentT(std::string str, const NodeDefManager *ndef)
792 {
793         str += "\n";
794         std::set<content_t> dat;
795         std::string buf;
796         for (char c : str) {
797                 if (c == ',' || c == '\n') {
798                         if (! buf.empty()) {
799                                 dat.insert(ndef->getId(buf));
800                         }
801                         buf.clear();
802                 } else if (c != ' ') {
803                         buf += c;
804                 }
805         }
806         return dat;
807 }
808
809 static void getTileInfo(
810                 // Input:
811                 MeshMakeData *data,
812                 const v3s16 &p,
813                 const v3s16 &face_dir,
814                 // Output:
815                 bool &makes_face,
816                 v3s16 &p_corrected,
817                 v3s16 &face_dir_corrected,
818                 u16 *lights,
819                 u8 &waving,
820                 TileSpec &tile,
821                 bool xray,
822                 std::set<content_t> xraySet
823         )
824 {
825         VoxelManipulator &vmanip = data->m_vmanip;
826         const NodeDefManager *ndef = data->m_client->ndef();
827         v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
828         
829         const MapNode &n0 = vmanip.getNodeRefUnsafe(blockpos_nodes + p);
830
831         content_t c0 = n0.getContent();
832         if (xray && xraySet.find(c0) != xraySet.end())
833                 c0 = CONTENT_AIR;
834
835         // Don't even try to get n1 if n0 is already CONTENT_IGNORE
836         if (c0 == CONTENT_IGNORE) {
837                 makes_face = false;
838                 return;
839         }
840
841         const MapNode &n1 = vmanip.getNodeRefUnsafeCheckFlags(blockpos_nodes + p + face_dir);
842
843         content_t c1 = n1.getContent();
844         if (xray && xraySet.find(c1) != xraySet.end())
845                 c1 = CONTENT_AIR;
846
847         if (c1 == CONTENT_IGNORE) {
848                 makes_face = false;
849                 return;
850         }
851
852         // This is hackish
853         bool equivalent = false;
854         u8 mf = face_contents(c0, c1,
855                         &equivalent, ndef);
856
857         if (mf == 0) {
858                 makes_face = false;
859                 return;
860         }
861
862         makes_face = true;
863
864         MapNode n = n0;
865
866         if (mf == 1) {
867                 p_corrected = p;
868                 face_dir_corrected = face_dir;
869         } else {
870                 n = n1;
871                 p_corrected = p + face_dir;
872                 face_dir_corrected = -face_dir;
873         }
874
875         getNodeTile(n, p_corrected, face_dir_corrected, data, tile);
876         const ContentFeatures &f = ndef->get(n);
877         waving = f.waving;
878         tile.emissive_light = f.light_source;
879
880         // eg. water and glass
881         if (equivalent) {
882                 for (TileLayer &layer : tile.layers)
883                         layer.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
884         }
885
886         if (!data->m_smooth_lighting) {
887                 lights[0] = lights[1] = lights[2] = lights[3] =
888                                 getFaceLight(n0, n1, face_dir, ndef);
889         } else {
890                 v3s16 vertex_dirs[4];
891                 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
892
893                 v3s16 light_p = blockpos_nodes + p_corrected;
894                 for (u16 i = 0; i < 4; i++)
895                         lights[i] = getSmoothLightSolid(light_p, face_dir_corrected, vertex_dirs[i], data);
896         }
897 }
898
899 /*
900         startpos:
901         translate_dir: unit vector with only one of x, y or z
902         face_dir: unit vector with only one of x, y or z
903 */
904 static void updateFastFaceRow(
905                 MeshMakeData *data,
906                 const v3s16 &&startpos,
907                 v3s16 translate_dir,
908                 const v3f &&translate_dir_f,
909                 const v3s16 &&face_dir,
910                 std::vector<FastFace> &dest,
911                 bool xray,
912                 std::set<content_t> xraySet)
913 {
914         static thread_local const bool waving_liquids =
915                 g_settings->getBool("enable_shaders") &&
916                 g_settings->getBool("enable_waving_water");
917
918         v3s16 p = startpos;
919
920         u16 continuous_tiles_count = 1;
921
922         bool makes_face = false;
923         v3s16 p_corrected;
924         v3s16 face_dir_corrected;
925         u16 lights[4] = {0, 0, 0, 0};
926         u8 waving = 0;
927         TileSpec tile;
928
929         // Get info of first tile
930         getTileInfo(data, p, face_dir,
931                         makes_face, p_corrected, face_dir_corrected,
932                         lights, waving, tile, xray, xraySet);
933
934         // Unroll this variable which has a significant build cost
935         TileSpec next_tile;
936         for (u16 j = 0; j < MAP_BLOCKSIZE; j++) {
937                 // If tiling can be done, this is set to false in the next step
938                 bool next_is_different = true;
939
940                 bool next_makes_face = false;
941                 v3s16 next_p_corrected;
942                 v3s16 next_face_dir_corrected;
943                 u16 next_lights[4] = {0, 0, 0, 0};
944
945                 // If at last position, there is nothing to compare to and
946                 // the face must be drawn anyway
947                 if (j != MAP_BLOCKSIZE - 1) {
948                         p += translate_dir;
949
950                         getTileInfo(data, p, face_dir,
951                                         next_makes_face, next_p_corrected,
952                                         next_face_dir_corrected, next_lights,
953                                         waving,
954                                         next_tile,
955                                         xray,
956                                         xraySet);
957
958                         if (next_makes_face == makes_face
959                                         && next_p_corrected == p_corrected + translate_dir
960                                         && next_face_dir_corrected == face_dir_corrected
961                                         && memcmp(next_lights, lights, sizeof(lights)) == 0
962                                         // Don't apply fast faces to waving water.
963                                         && (waving != 3 || !waving_liquids)
964                                         && next_tile.isTileable(tile)) {
965                                 next_is_different = false;
966                                 continuous_tiles_count++;
967                         }
968                 }
969                 if (next_is_different) {
970                         /*
971                                 Create a face if there should be one
972                         */
973                         if (makes_face) {
974                                 // Floating point conversion of the position vector
975                                 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
976                                 // Center point of face (kind of)
977                                 v3f sp = pf - ((f32)continuous_tiles_count * 0.5f - 0.5f)
978                                         * translate_dir_f;
979                                 v3f scale(1, 1, 1);
980
981                                 if (translate_dir.X != 0)
982                                         scale.X = continuous_tiles_count;
983                                 if (translate_dir.Y != 0)
984                                         scale.Y = continuous_tiles_count;
985                                 if (translate_dir.Z != 0)
986                                         scale.Z = continuous_tiles_count;
987
988                                 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
989                                                 pf, sp, face_dir_corrected, scale, dest);
990                                 g_profiler->avg("Meshgen: Tiles per face [#]", continuous_tiles_count);
991                         }
992
993                         continuous_tiles_count = 1;
994                 }
995
996                 makes_face = next_makes_face;
997                 p_corrected = next_p_corrected;
998                 face_dir_corrected = next_face_dir_corrected;
999                 memcpy(lights, next_lights, sizeof(lights));
1000                 if (next_is_different)
1001                         tile = std::move(next_tile); // faster than copy
1002         }
1003 }
1004
1005 static void updateAllFastFaceRows(MeshMakeData *data,
1006                 std::vector<FastFace> &dest, bool xray, std::set<content_t> xraySet)
1007 {
1008         /*
1009                 Go through every y,z and get top(y+) faces in rows of x+
1010         */
1011         for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
1012         for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
1013                 updateFastFaceRow(data,
1014                                 v3s16(0, y, z),
1015                                 v3s16(1, 0, 0), //dir
1016                                 v3f  (1, 0, 0),
1017                                 v3s16(0, 1, 0), //face dir
1018                                 dest,
1019                                 xray,
1020                                 xraySet);
1021
1022         /*
1023                 Go through every x,y and get right(x+) faces in rows of z+
1024         */
1025         for (s16 x = 0; x < MAP_BLOCKSIZE; x++)
1026         for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
1027                 updateFastFaceRow(data,
1028                                 v3s16(x, y, 0),
1029                                 v3s16(0, 0, 1), //dir
1030                                 v3f  (0, 0, 1),
1031                                 v3s16(1, 0, 0), //face dir
1032                                 dest,
1033                                 xray,
1034                                 xraySet);
1035
1036         /*
1037                 Go through every y,z and get back(z+) faces in rows of x+
1038         */
1039         for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
1040         for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
1041                 updateFastFaceRow(data,
1042                                 v3s16(0, y, z),
1043                                 v3s16(1, 0, 0), //dir
1044                                 v3f  (1, 0, 0),
1045                                 v3s16(0, 0, 1), //face dir
1046                                 dest,
1047                                 xray,
1048                                 xraySet);
1049 }
1050
1051 static void applyTileColor(PreMeshBuffer &pmb)
1052 {
1053         video::SColor tc = pmb.layer.color;
1054         if (tc == video::SColor(0xFFFFFFFF))
1055                 return;
1056         for (video::S3DVertex &vertex : pmb.vertices) {
1057                 video::SColor *c = &vertex.Color;
1058                 c->set(c->getAlpha(),
1059                         c->getRed() * tc.getRed() / 255,
1060                         c->getGreen() * tc.getGreen() / 255,
1061                         c->getBlue() * tc.getBlue() / 255);
1062         }
1063 }
1064
1065 /*
1066         MapBlockMesh
1067 */
1068
1069 MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
1070         m_minimap_mapblock(NULL),
1071         m_tsrc(data->m_client->getTextureSource()),
1072         m_shdrsrc(data->m_client->getShaderSource()),
1073         m_animation_force_timer(0), // force initial animation
1074         m_last_crack(-1),
1075         m_last_daynight_ratio((u32) -1)
1076 {
1077         for (auto &m : m_mesh)
1078                 m = new scene::SMesh();
1079         m_enable_shaders = data->m_use_shaders;
1080         m_use_tangent_vertices = data->m_use_tangent_vertices;
1081         m_enable_vbo = g_settings->getBool("enable_vbo");
1082
1083         if (g_settings->getBool("enable_minimap")) {
1084                 m_minimap_mapblock = new MinimapMapblock;
1085                 m_minimap_mapblock->getMinimapNodes(
1086                         &data->m_vmanip, data->m_blockpos * MAP_BLOCKSIZE);
1087         }
1088
1089         // 4-21ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1090         // 24-155ms for MAP_BLOCKSIZE=32  (NOTE: probably outdated)
1091         //TimeTaker timer1("MapBlockMesh()");
1092
1093         std::vector<FastFace> fastfaces_new;
1094         fastfaces_new.reserve(512);
1095         /*
1096                 X-Ray
1097         */
1098         bool xray = g_settings->getBool("xray");
1099         std::set<content_t> xraySet;
1100         if (xray)
1101                 xraySet = splitToContentT(g_settings->get("xray_nodes"), data->m_client->ndef());
1102         
1103         /*
1104                 We are including the faces of the trailing edges of the block.
1105                 This means that when something changes, the caller must
1106                 also update the meshes of the blocks at the leading edges.
1107
1108                 NOTE: This is the slowest part of this method.
1109         */      
1110         {
1111                 // 4-23ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1112                 //TimeTaker timer2("updateAllFastFaceRows()");
1113                 updateAllFastFaceRows(data, fastfaces_new, xray, xraySet);
1114         }
1115         // End of slow part
1116
1117         /*
1118                 Convert FastFaces to MeshCollector
1119         */
1120
1121         MeshCollector collector;
1122
1123         {
1124                 // avg 0ms (100ms spikes when loading textures the first time)
1125                 // (NOTE: probably outdated)
1126                 //TimeTaker timer2("MeshCollector building");
1127
1128                 for (const FastFace &f : fastfaces_new) {
1129                         static const u16 indices[] = {0, 1, 2, 2, 3, 0};
1130                         static const u16 indices_alternate[] = {0, 1, 3, 2, 3, 1};
1131                         const u16 *indices_p =
1132                                 f.vertex_0_2_connected ? indices : indices_alternate;
1133                         collector.append(f.tile, f.vertices, 4, indices_p, 6);
1134                 }
1135         }
1136
1137         /*
1138                 Add special graphics:
1139                 - torches
1140                 - flowing water
1141                 - fences
1142                 - whatever
1143         */
1144
1145         {
1146                 MapblockMeshGenerator generator(data, &collector);
1147                 generator.generate();
1148         }
1149
1150         /*
1151                 Convert MeshCollector to SMesh
1152         */
1153
1154         for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
1155                 for(u32 i = 0; i < collector.prebuffers[layer].size(); i++)
1156                 {
1157                         PreMeshBuffer &p = collector.prebuffers[layer][i];
1158
1159                         applyTileColor(p);
1160
1161                         // Generate animation data
1162                         // - Cracks
1163                         if (p.layer.material_flags & MATERIAL_FLAG_CRACK) {
1164                                 // Find the texture name plus ^[crack:N:
1165                                 std::ostringstream os(std::ios::binary);
1166                                 os << m_tsrc->getTextureName(p.layer.texture_id) << "^[crack";
1167                                 if (p.layer.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1168                                         os << "o";  // use ^[cracko
1169                                 u8 tiles = p.layer.scale;
1170                                 if (tiles > 1)
1171                                         os << ":" << (u32)tiles;
1172                                 os << ":" << (u32)p.layer.animation_frame_count << ":";
1173                                 m_crack_materials.insert(std::make_pair(
1174                                                 std::pair<u8, u32>(layer, i), os.str()));
1175                                 // Replace tile texture with the cracked one
1176                                 p.layer.texture = m_tsrc->getTextureForMesh(
1177                                                 os.str() + "0",
1178                                                 &p.layer.texture_id);
1179                         }
1180                         // - Texture animation
1181                         if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
1182                                 // Add to MapBlockMesh in order to animate these tiles
1183                                 m_animation_tiles[std::pair<u8, u32>(layer, i)] = p.layer;
1184                                 m_animation_frames[std::pair<u8, u32>(layer, i)] = 0;
1185                                 if (g_settings->getBool(
1186                                                 "desynchronize_mapblock_texture_animation")) {
1187                                         // Get starting position from noise
1188                                         m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] =
1189                                                         100000 * (2.0 + noise3d(
1190                                                         data->m_blockpos.X, data->m_blockpos.Y,
1191                                                         data->m_blockpos.Z, 0));
1192                                 } else {
1193                                         // Play all synchronized
1194                                         m_animation_frame_offsets[std::pair<u8, u32>(layer, i)] = 0;
1195                                 }
1196                                 // Replace tile texture with the first animation frame
1197                                 p.layer.texture = (*p.layer.frames)[0].texture;
1198                         }
1199
1200                         if (!m_enable_shaders) {
1201                                 // Extract colors for day-night animation
1202                                 // Dummy sunlight to handle non-sunlit areas
1203                                 video::SColorf sunlight;
1204                                 get_sunlight_color(&sunlight, 0);
1205                                 u32 vertex_count = p.vertices.size();
1206                                 for (u32 j = 0; j < vertex_count; j++) {
1207                                         video::SColor *vc = &p.vertices[j].Color;
1208                                         video::SColor copy = *vc;
1209                                         if (vc->getAlpha() == 0) // No sunlight - no need to animate
1210                                                 final_color_blend(vc, copy, sunlight); // Finalize color
1211                                         else // Record color to animate
1212                                                 m_daynight_diffs[std::pair<u8, u32>(layer, i)][j] = copy;
1213
1214                                         // The sunlight ratio has been stored,
1215                                         // delete alpha (for the final rendering).
1216                                         vc->setAlpha(255);
1217                                 }
1218                         }
1219
1220                         // Create material
1221                         video::SMaterial material;
1222                         material.setFlag(video::EMF_LIGHTING, false);
1223                         material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1224                         material.setFlag(video::EMF_BILINEAR_FILTER, false);
1225                         material.setFlag(video::EMF_FOG_ENABLE, true);
1226                         material.setTexture(0, p.layer.texture);
1227
1228                         if (m_enable_shaders) {
1229                                 material.MaterialType = m_shdrsrc->getShaderInfo(
1230                                                 p.layer.shader_id).material;
1231                                 p.layer.applyMaterialOptionsWithShaders(material);
1232                                 if (p.layer.normal_texture)
1233                                         material.setTexture(1, p.layer.normal_texture);
1234                                 material.setTexture(2, p.layer.flags_texture);
1235                         } else {
1236                                 p.layer.applyMaterialOptions(material);
1237                         }
1238
1239                         scene::SMesh *mesh = (scene::SMesh *)m_mesh[layer];
1240
1241                         // Create meshbuffer, add to mesh
1242                         if (m_use_tangent_vertices) {
1243                                 scene::SMeshBufferTangents *buf =
1244                                                 new scene::SMeshBufferTangents();
1245                                 buf->Material = material;
1246                                 buf->Vertices.reallocate(p.vertices.size());
1247                                 buf->Indices.reallocate(p.indices.size());
1248                                 for (const video::S3DVertex &v: p.vertices)
1249                                         buf->Vertices.push_back(video::S3DVertexTangents(v.Pos, v.Color, v.TCoords));
1250                                 for (u16 i: p.indices)
1251                                         buf->Indices.push_back(i);
1252                                 buf->recalculateBoundingBox();
1253                                 mesh->addMeshBuffer(buf);
1254                                 buf->drop();
1255                         } else {
1256                                 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1257                                 buf->Material = material;
1258                                 buf->append(&p.vertices[0], p.vertices.size(),
1259                                         &p.indices[0], p.indices.size());
1260                                 mesh->addMeshBuffer(buf);
1261                                 buf->drop();
1262                         }
1263                 }
1264
1265                 /*
1266                         Do some stuff to the mesh
1267                 */
1268                 m_camera_offset = camera_offset;
1269                 translateMesh(m_mesh[layer],
1270                         intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
1271
1272                 if (m_use_tangent_vertices) {
1273                         scene::IMeshManipulator* meshmanip =
1274                                 RenderingEngine::get_scene_manager()->getMeshManipulator();
1275                         meshmanip->recalculateTangents(m_mesh[layer], true, false, false);
1276                 }
1277
1278                 if (m_mesh[layer]) {
1279 #if 0
1280                         // Usually 1-700 faces and 1-7 materials
1281                         std::cout << "Updated MapBlock has " << fastfaces_new.size()
1282                                         << " faces and uses " << m_mesh[layer]->getMeshBufferCount()
1283                                         << " materials (meshbuffers)" << std::endl;
1284 #endif
1285
1286                         // Use VBO for mesh (this just would set this for ever buffer)
1287                         if (m_enable_vbo)
1288                                 m_mesh[layer]->setHardwareMappingHint(scene::EHM_STATIC);
1289                 }
1290         }
1291
1292         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1293
1294         // Check if animation is required for this mesh
1295         m_has_animation =
1296                 !m_crack_materials.empty() ||
1297                 !m_daynight_diffs.empty() ||
1298                 !m_animation_tiles.empty();
1299 }
1300
1301 MapBlockMesh::~MapBlockMesh()
1302 {
1303         for (scene::IMesh *m : m_mesh) {
1304                 if (m_enable_vbo && m)
1305                         for (u32 i = 0; i < m->getMeshBufferCount(); i++) {
1306                                 scene::IMeshBuffer *buf = m->getMeshBuffer(i);
1307                                 RenderingEngine::get_video_driver()->removeHardwareBuffer(buf);
1308                         }
1309                 m->drop();
1310                 m = NULL;
1311         }
1312         delete m_minimap_mapblock;
1313 }
1314
1315 bool MapBlockMesh::animate(bool faraway, float time, int crack,
1316         u32 daynight_ratio)
1317 {
1318         if (!m_has_animation) {
1319                 m_animation_force_timer = 100000;
1320                 return false;
1321         }
1322
1323         m_animation_force_timer = myrand_range(5, 100);
1324
1325         // Cracks
1326         if (crack != m_last_crack) {
1327                 for (auto &crack_material : m_crack_materials) {
1328                         scene::IMeshBuffer *buf = m_mesh[crack_material.first.first]->
1329                                 getMeshBuffer(crack_material.first.second);
1330                         std::string basename = crack_material.second;
1331
1332                         // Create new texture name from original
1333                         std::ostringstream os;
1334                         os << basename << crack;
1335                         u32 new_texture_id = 0;
1336                         video::ITexture *new_texture =
1337                                         m_tsrc->getTextureForMesh(os.str(), &new_texture_id);
1338                         buf->getMaterial().setTexture(0, new_texture);
1339
1340                         // If the current material is also animated,
1341                         // update animation info
1342                         auto anim_iter = m_animation_tiles.find(crack_material.first);
1343                         if (anim_iter != m_animation_tiles.end()) {
1344                                 TileLayer &tile = anim_iter->second;
1345                                 tile.texture = new_texture;
1346                                 tile.texture_id = new_texture_id;
1347                                 // force animation update
1348                                 m_animation_frames[crack_material.first] = -1;
1349                         }
1350                 }
1351
1352                 m_last_crack = crack;
1353         }
1354
1355         // Texture animation
1356         for (auto &animation_tile : m_animation_tiles) {
1357                 const TileLayer &tile = animation_tile.second;
1358                 // Figure out current frame
1359                 int frameoffset = m_animation_frame_offsets[animation_tile.first];
1360                 int frame = (int)(time * 1000 / tile.animation_frame_length_ms
1361                                 + frameoffset) % tile.animation_frame_count;
1362                 // If frame doesn't change, skip
1363                 if (frame == m_animation_frames[animation_tile.first])
1364                         continue;
1365
1366                 m_animation_frames[animation_tile.first] = frame;
1367
1368                 scene::IMeshBuffer *buf = m_mesh[animation_tile.first.first]->
1369                         getMeshBuffer(animation_tile.first.second);
1370
1371                 const FrameSpec &animation_frame = (*tile.frames)[frame];
1372                 buf->getMaterial().setTexture(0, animation_frame.texture);
1373                 if (m_enable_shaders) {
1374                         if (animation_frame.normal_texture)
1375                                 buf->getMaterial().setTexture(1,
1376                                         animation_frame.normal_texture);
1377                         buf->getMaterial().setTexture(2, animation_frame.flags_texture);
1378                 }
1379         }
1380
1381         // Day-night transition
1382         if (!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio)) {
1383                 // Force reload mesh to VBO
1384                 if (m_enable_vbo)
1385                         for (scene::IMesh *m : m_mesh)
1386                                 m->setDirty();
1387                 video::SColorf day_color;
1388                 get_sunlight_color(&day_color, daynight_ratio);
1389
1390                 for (auto &daynight_diff : m_daynight_diffs) {
1391                         scene::IMeshBuffer *buf = m_mesh[daynight_diff.first.first]->
1392                                 getMeshBuffer(daynight_diff.first.second);
1393                         video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
1394                         for (const auto &j : daynight_diff.second)
1395                                 final_color_blend(&(vertices[j.first].Color), j.second,
1396                                                 day_color);
1397                 }
1398                 m_last_daynight_ratio = daynight_ratio;
1399         }
1400
1401         return true;
1402 }
1403
1404 void MapBlockMesh::updateCameraOffset(v3s16 camera_offset)
1405 {
1406         if (camera_offset != m_camera_offset) {
1407                 for (scene::IMesh *layer : m_mesh) {
1408                         translateMesh(layer,
1409                                 intToFloat(m_camera_offset - camera_offset, BS));
1410                         if (m_enable_vbo)
1411                                 layer->setDirty();
1412                 }
1413                 m_camera_offset = camera_offset;
1414         }
1415 }
1416
1417 video::SColor encode_light(u16 light, u8 emissive_light)
1418 {
1419         // Get components
1420         u32 day = (light & 0xff);
1421         u32 night = (light >> 8);
1422         // Add emissive light
1423         night += emissive_light * 2.5f;
1424         if (night > 255)
1425                 night = 255;
1426         // Since we don't know if the day light is sunlight or
1427         // artificial light, assume it is artificial when the night
1428         // light bank is also lit.
1429         if (day < night)
1430                 day = 0;
1431         else
1432                 day = day - night;
1433         u32 sum = day + night;
1434         // Ratio of sunlight:
1435         u32 r;
1436         if (sum > 0)
1437                 r = day * 255 / sum;
1438         else
1439                 r = 0;
1440         // Average light:
1441         float b = (day + night) / 2;
1442         return video::SColor(r, b, b, b);
1443 }