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