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