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