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