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