]> git.lizzy.rs Git - minetest.git/blob - src/mapblock_mesh.cpp
b3a1a73d731661f8f16bf05064455ab95378e722
[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                 MapNode n = data->m_vmanip.getNodeNoEx(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         FastFace face;
442
443         // Position is at the center of the cube.
444         v3f pos = p * BS;
445
446         float x0 = 0.0;
447         float y0 = 0.0;
448         float w = 1.0;
449         float h = 1.0;
450
451         v3f vertex_pos[4];
452         v3s16 vertex_dirs[4];
453         getNodeVertexDirs(dir, vertex_dirs);
454
455         v3s16 t;
456         u16 t1;
457         switch (tile.rotation)
458         {
459         case 0:
460                 break;
461         case 1: //R90
462                 t = vertex_dirs[0];
463                 vertex_dirs[0] = vertex_dirs[3];
464                 vertex_dirs[3] = vertex_dirs[2];
465                 vertex_dirs[2] = vertex_dirs[1];
466                 vertex_dirs[1] = t;
467                 t1=li0;
468                 li0=li3;
469                 li3=li2;
470                 li2=li1;
471                 li1=t1;
472                 break;
473         case 2: //R180
474                 t = vertex_dirs[0];
475                 vertex_dirs[0] = vertex_dirs[2];
476                 vertex_dirs[2] = t;
477                 t = vertex_dirs[1];
478                 vertex_dirs[1] = vertex_dirs[3];
479                 vertex_dirs[3] = t;
480                 t1  = li0;
481                 li0 = li2;
482                 li2 = t1;
483                 t1  = li1;
484                 li1 = li3;
485                 li3 = t1;
486                 break;
487         case 3: //R270
488                 t = vertex_dirs[0];
489                 vertex_dirs[0] = vertex_dirs[1];
490                 vertex_dirs[1] = vertex_dirs[2];
491                 vertex_dirs[2] = vertex_dirs[3];
492                 vertex_dirs[3] = t;
493                 t1  = li0;
494                 li0 = li1;
495                 li1 = li2;
496                 li2 = li3;
497                 li3 = t1;
498                 break;
499         case 4: //FXR90
500                 t = vertex_dirs[0];
501                 vertex_dirs[0] = vertex_dirs[3];
502                 vertex_dirs[3] = vertex_dirs[2];
503                 vertex_dirs[2] = vertex_dirs[1];
504                 vertex_dirs[1] = t;
505                 t1  = li0;
506                 li0 = li3;
507                 li3 = li2;
508                 li2 = li1;
509                 li1 = t1;
510                 y0 += h;
511                 h *= -1;
512                 break;
513         case 5: //FXR270
514                 t = vertex_dirs[0];
515                 vertex_dirs[0] = vertex_dirs[1];
516                 vertex_dirs[1] = vertex_dirs[2];
517                 vertex_dirs[2] = vertex_dirs[3];
518                 vertex_dirs[3] = t;
519                 t1  = li0;
520                 li0 = li1;
521                 li1 = li2;
522                 li2 = li3;
523                 li3 = t1;
524                 y0 += h;
525                 h *= -1;
526                 break;
527         case 6: //FYR90
528                 t = vertex_dirs[0];
529                 vertex_dirs[0] = vertex_dirs[3];
530                 vertex_dirs[3] = vertex_dirs[2];
531                 vertex_dirs[2] = vertex_dirs[1];
532                 vertex_dirs[1] = t;
533                 t1  = li0;
534                 li0 = li3;
535                 li3 = li2;
536                 li2 = li1;
537                 li1 = t1;
538                 x0 += w;
539                 w *= -1;
540                 break;
541         case 7: //FYR270
542                 t = vertex_dirs[0];
543                 vertex_dirs[0] = vertex_dirs[1];
544                 vertex_dirs[1] = vertex_dirs[2];
545                 vertex_dirs[2] = vertex_dirs[3];
546                 vertex_dirs[3] = t;
547                 t1  = li0;
548                 li0 = li1;
549                 li1 = li2;
550                 li2 = li3;
551                 li3 = t1;
552                 x0 += w;
553                 w *= -1;
554                 break;
555         case 8: //FX
556                 y0 += h;
557                 h *= -1;
558                 break;
559         case 9: //FY
560                 x0 += w;
561                 w *= -1;
562                 break;
563         default:
564                 break;
565         }
566
567         for(u16 i=0; i<4; i++)
568         {
569                 vertex_pos[i] = v3f(
570                                 BS/2*vertex_dirs[i].X,
571                                 BS/2*vertex_dirs[i].Y,
572                                 BS/2*vertex_dirs[i].Z
573                 );
574         }
575
576         for(u16 i=0; i<4; i++)
577         {
578                 vertex_pos[i].X *= scale.X;
579                 vertex_pos[i].Y *= scale.Y;
580                 vertex_pos[i].Z *= scale.Z;
581                 vertex_pos[i] += pos;
582         }
583
584         f32 abs_scale = 1.0;
585         if     (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
586         else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
587         else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
588
589         v3f normal(dir.X, dir.Y, dir.Z);
590
591         u8 alpha = tile.alpha;
592
593         face.vertices[0] = video::S3DVertex(vertex_pos[0], normal,
594                         MapBlock_LightColor(alpha, li0, light_source),
595                         core::vector2d<f32>(x0+w*abs_scale, y0+h));
596         face.vertices[1] = video::S3DVertex(vertex_pos[1], normal,
597                         MapBlock_LightColor(alpha, li1, light_source),
598                         core::vector2d<f32>(x0, y0+h));
599         face.vertices[2] = video::S3DVertex(vertex_pos[2], normal,
600                         MapBlock_LightColor(alpha, li2, light_source),
601                         core::vector2d<f32>(x0, y0));
602         face.vertices[3] = video::S3DVertex(vertex_pos[3], normal,
603                         MapBlock_LightColor(alpha, li3, light_source),
604                         core::vector2d<f32>(x0+w*abs_scale, y0));
605
606         face.tile = tile;
607         dest.push_back(face);
608 }
609
610 /*
611         Nodes make a face if contents differ and solidness differs.
612         Return value:
613                 0: No face
614                 1: Face uses m1's content
615                 2: Face uses m2's content
616         equivalent: Whether the blocks share the same face (eg. water and glass)
617
618         TODO: Add 3: Both faces drawn with backface culling, remove equivalent
619 */
620 static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
621                 INodeDefManager *ndef)
622 {
623         *equivalent = false;
624
625         if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
626                 return 0;
627
628         bool contents_differ = (m1 != m2);
629
630         const ContentFeatures &f1 = ndef->get(m1);
631         const ContentFeatures &f2 = ndef->get(m2);
632
633         // Contents don't differ for different forms of same liquid
634         if(f1.sameLiquid(f2))
635                 contents_differ = false;
636
637         u8 c1 = f1.solidness;
638         u8 c2 = f2.solidness;
639
640         bool solidness_differs = (c1 != c2);
641         bool makes_face = contents_differ && solidness_differs;
642
643         if(makes_face == false)
644                 return 0;
645
646         if(c1 == 0)
647                 c1 = f1.visual_solidness;
648         if(c2 == 0)
649                 c2 = f2.visual_solidness;
650
651         if(c1 == c2){
652                 *equivalent = true;
653                 // If same solidness, liquid takes precense
654                 if(f1.isLiquid())
655                         return 1;
656                 if(f2.isLiquid())
657                         return 2;
658         }
659
660         if(c1 > c2)
661                 return 1;
662         else
663                 return 2;
664 }
665
666 /*
667         Gets nth node tile (0 <= n <= 5).
668 */
669 TileSpec getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data)
670 {
671         INodeDefManager *ndef = data->m_gamedef->ndef();
672         TileSpec spec = ndef->get(mn).tiles[tileindex];
673         // Apply temporary crack
674         if (p == data->m_crack_pos_relative)
675                 spec.material_flags |= MATERIAL_FLAG_CRACK;
676         return spec;
677 }
678
679 /*
680         Gets node tile given a face direction.
681 */
682 TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data)
683 {
684         INodeDefManager *ndef = data->m_gamedef->ndef();
685
686         // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
687         // (0,0,1), (0,0,-1) or (0,0,0)
688         assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z <= 1);
689
690         // Convert direction to single integer for table lookup
691         //  0 = (0,0,0)
692         //  1 = (1,0,0)
693         //  2 = (0,1,0)
694         //  3 = (0,0,1)
695         //  4 = invalid, treat as (0,0,0)
696         //  5 = (0,0,-1)
697         //  6 = (0,-1,0)
698         //  7 = (-1,0,0)
699         u8 dir_i = ((dir.X + 2 * dir.Y + 3 * dir.Z) & 7)*2;
700
701         // Get rotation for things like chests
702         u8 facedir = mn.getFaceDir(ndef);
703
704         static const u16 dir_to_tile[24 * 16] =
705         {
706                 // 0     +X    +Y    +Z           -Z    -Y    -X   ->   value=tile,rotation
707                    0,0,  2,0 , 0,0 , 4,0 ,  0,0,  5,0 , 1,0 , 3,0 ,  // rotate around y+ 0 - 3
708                    0,0,  4,0 , 0,3 , 3,0 ,  0,0,  2,0 , 1,1 , 5,0 ,
709                    0,0,  3,0 , 0,2 , 5,0 ,  0,0,  4,0 , 1,2 , 2,0 ,
710                    0,0,  5,0 , 0,1 , 2,0 ,  0,0,  3,0 , 1,3 , 4,0 ,
711
712                    0,0,  2,3 , 5,0 , 0,2 ,  0,0,  1,0 , 4,2 , 3,1 ,  // rotate around z+ 4 - 7
713                    0,0,  4,3 , 2,0 , 0,1 ,  0,0,  1,1 , 3,2 , 5,1 ,
714                    0,0,  3,3 , 4,0 , 0,0 ,  0,0,  1,2 , 5,2 , 2,1 ,
715                    0,0,  5,3 , 3,0 , 0,3 ,  0,0,  1,3 , 2,2 , 4,1 ,
716
717                    0,0,  2,1 , 4,2 , 1,2 ,  0,0,  0,0 , 5,0 , 3,3 ,  // rotate around z- 8 - 11
718                    0,0,  4,1 , 3,2 , 1,3 ,  0,0,  0,3 , 2,0 , 5,3 ,
719                    0,0,  3,1 , 5,2 , 1,0 ,  0,0,  0,2 , 4,0 , 2,3 ,
720                    0,0,  5,1 , 2,2 , 1,1 ,  0,0,  0,1 , 3,0 , 4,3 ,
721
722                    0,0,  0,3 , 3,3 , 4,1 ,  0,0,  5,3 , 2,3 , 1,3 ,  // rotate around x+ 12 - 15
723                    0,0,  0,2 , 5,3 , 3,1 ,  0,0,  2,3 , 4,3 , 1,0 ,
724                    0,0,  0,1 , 2,3 , 5,1 ,  0,0,  4,3 , 3,3 , 1,1 ,
725                    0,0,  0,0 , 4,3 , 2,1 ,  0,0,  3,3 , 5,3 , 1,2 ,
726
727                    0,0,  1,1 , 2,1 , 4,3 ,  0,0,  5,1 , 3,1 , 0,1 ,  // rotate around x- 16 - 19
728                    0,0,  1,2 , 4,1 , 3,3 ,  0,0,  2,1 , 5,1 , 0,0 ,
729                    0,0,  1,3 , 3,1 , 5,3 ,  0,0,  4,1 , 2,1 , 0,3 ,
730                    0,0,  1,0 , 5,1 , 2,3 ,  0,0,  3,1 , 4,1 , 0,2 ,
731
732                    0,0,  3,2 , 1,2 , 4,2 ,  0,0,  5,2 , 0,2 , 2,2 ,  // rotate around y- 20 - 23
733                    0,0,  5,2 , 1,3 , 3,2 ,  0,0,  2,2 , 0,1 , 4,2 ,
734                    0,0,  2,2 , 1,0 , 5,2 ,  0,0,  4,2 , 0,0 , 3,2 ,
735                    0,0,  4,2 , 1,1 , 2,2 ,  0,0,  3,2 , 0,3 , 5,2
736
737         };
738         u16 tile_index=facedir*16 + dir_i;
739         TileSpec spec = getNodeTileN(mn, p, dir_to_tile[tile_index], data);
740         spec.rotation=dir_to_tile[tile_index + 1];
741         spec.texture = data->m_gamedef->tsrc()->getTexture(spec.texture_id);
742         return spec;
743 }
744
745 static void getTileInfo(
746                 // Input:
747                 MeshMakeData *data,
748                 v3s16 p,
749                 v3s16 face_dir,
750                 // Output:
751                 bool &makes_face,
752                 v3s16 &p_corrected,
753                 v3s16 &face_dir_corrected,
754                 u16 *lights,
755                 TileSpec &tile,
756                 u8 &light_source
757         )
758 {
759         VoxelManipulator &vmanip = data->m_vmanip;
760         INodeDefManager *ndef = data->m_gamedef->ndef();
761         v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
762
763         MapNode n0 = vmanip.getNodeNoEx(blockpos_nodes + p);
764
765         // Don't even try to get n1 if n0 is already CONTENT_IGNORE
766         if (n0.getContent() == CONTENT_IGNORE ) {
767                 makes_face = false;
768                 return;
769         }
770         MapNode n1 = vmanip.getNodeNoEx(blockpos_nodes + p + face_dir);
771
772         // This is hackish
773         bool equivalent = false;
774         u8 mf = face_contents(n0.getContent(), n1.getContent(),
775                         &equivalent, ndef);
776
777         if(mf == 0)
778         {
779                 makes_face = false;
780                 return;
781         }
782
783         makes_face = true;
784
785         if(mf == 1)
786         {
787                 tile = getNodeTile(n0, p, face_dir, data);
788                 p_corrected = p;
789                 face_dir_corrected = face_dir;
790                 light_source = ndef->get(n0).light_source;
791         }
792         else
793         {
794                 tile = getNodeTile(n1, p + face_dir, -face_dir, data);
795                 p_corrected = p + face_dir;
796                 face_dir_corrected = -face_dir;
797                 light_source = ndef->get(n1).light_source;
798         }
799
800         // eg. water and glass
801         if(equivalent)
802                 tile.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
803
804         if(data->m_smooth_lighting == false)
805         {
806                 lights[0] = lights[1] = lights[2] = lights[3] =
807                                 getFaceLight(n0, n1, face_dir, ndef);
808         }
809         else
810         {
811                 v3s16 vertex_dirs[4];
812                 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
813                 for(u16 i=0; i<4; i++)
814                 {
815                         lights[i] = getSmoothLight(
816                                         blockpos_nodes + p_corrected,
817                                         vertex_dirs[i], data);
818                 }
819         }
820
821         return;
822 }
823
824 /*
825         startpos:
826         translate_dir: unit vector with only one of x, y or z
827         face_dir: unit vector with only one of x, y or z
828 */
829 static void updateFastFaceRow(
830                 MeshMakeData *data,
831                 v3s16 startpos,
832                 v3s16 translate_dir,
833                 v3f translate_dir_f,
834                 v3s16 face_dir,
835                 v3f face_dir_f,
836                 std::vector<FastFace> &dest)
837 {
838         v3s16 p = startpos;
839
840         u16 continuous_tiles_count = 0;
841
842         bool makes_face = false;
843         v3s16 p_corrected;
844         v3s16 face_dir_corrected;
845         u16 lights[4] = {0,0,0,0};
846         TileSpec tile;
847         u8 light_source = 0;
848         getTileInfo(data, p, face_dir,
849                         makes_face, p_corrected, face_dir_corrected,
850                         lights, tile, light_source);
851
852         for(u16 j=0; j<MAP_BLOCKSIZE; j++)
853         {
854                 // If tiling can be done, this is set to false in the next step
855                 bool next_is_different = true;
856
857                 v3s16 p_next;
858
859                 bool next_makes_face = false;
860                 v3s16 next_p_corrected;
861                 v3s16 next_face_dir_corrected;
862                 u16 next_lights[4] = {0,0,0,0};
863                 TileSpec next_tile;
864                 u8 next_light_source = 0;
865
866                 // If at last position, there is nothing to compare to and
867                 // the face must be drawn anyway
868                 if(j != MAP_BLOCKSIZE - 1)
869                 {
870                         p_next = p + translate_dir;
871
872                         getTileInfo(data, p_next, face_dir,
873                                         next_makes_face, next_p_corrected,
874                                         next_face_dir_corrected, next_lights,
875                                         next_tile, next_light_source);
876
877                         if(next_makes_face == makes_face
878                                         && next_p_corrected == p_corrected + translate_dir
879                                         && next_face_dir_corrected == face_dir_corrected
880                                         && next_lights[0] == lights[0]
881                                         && next_lights[1] == lights[1]
882                                         && next_lights[2] == lights[2]
883                                         && next_lights[3] == lights[3]
884                                         && next_tile == tile
885                                         && tile.rotation == 0
886                                         && next_light_source == light_source)
887                         {
888                                 next_is_different = false;
889                         }
890                         else{
891                                 /*if(makes_face){
892                                         g_profiler->add("Meshgen: diff: next_makes_face != makes_face",
893                                                         next_makes_face != makes_face ? 1 : 0);
894                                         g_profiler->add("Meshgen: diff: n_p_corr != p_corr + t_dir",
895                                                         (next_p_corrected != p_corrected + translate_dir) ? 1 : 0);
896                                         g_profiler->add("Meshgen: diff: next_f_dir_corr != f_dir_corr",
897                                                         next_face_dir_corrected != face_dir_corrected ? 1 : 0);
898                                         g_profiler->add("Meshgen: diff: next_lights[] != lights[]",
899                                                         (next_lights[0] != lights[0] ||
900                                                         next_lights[0] != lights[0] ||
901                                                         next_lights[0] != lights[0] ||
902                                                         next_lights[0] != lights[0]) ? 1 : 0);
903                                         g_profiler->add("Meshgen: diff: !(next_tile == tile)",
904                                                         !(next_tile == tile) ? 1 : 0);
905                                 }*/
906                         }
907                         /*g_profiler->add("Meshgen: Total faces checked", 1);
908                         if(makes_face)
909                                 g_profiler->add("Meshgen: Total makes_face checked", 1);*/
910                 } else {
911                         /*if(makes_face)
912                                 g_profiler->add("Meshgen: diff: last position", 1);*/
913                 }
914
915                 continuous_tiles_count++;
916
917                 if(next_is_different)
918                 {
919                         /*
920                                 Create a face if there should be one
921                         */
922                         if(makes_face)
923                         {
924                                 // Floating point conversion of the position vector
925                                 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
926                                 // Center point of face (kind of)
927                                 v3f sp = pf - ((f32)continuous_tiles_count / 2.0 - 0.5) * translate_dir_f;
928                                 if(continuous_tiles_count != 1)
929                                         sp += translate_dir_f;
930                                 v3f scale(1,1,1);
931
932                                 if(translate_dir.X != 0) {
933                                         scale.X = continuous_tiles_count;
934                                 }
935                                 if(translate_dir.Y != 0) {
936                                         scale.Y = continuous_tiles_count;
937                                 }
938                                 if(translate_dir.Z != 0) {
939                                         scale.Z = continuous_tiles_count;
940                                 }
941
942                                 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
943                                                 sp, face_dir_corrected, scale, light_source,
944                                                 dest);
945
946                                 g_profiler->avg("Meshgen: faces drawn by tiling", 0);
947                                 for(int i = 1; i < continuous_tiles_count; i++){
948                                         g_profiler->avg("Meshgen: faces drawn by tiling", 1);
949                                 }
950                         }
951
952                         continuous_tiles_count = 0;
953
954                         makes_face = next_makes_face;
955                         p_corrected = next_p_corrected;
956                         face_dir_corrected = next_face_dir_corrected;
957                         lights[0] = next_lights[0];
958                         lights[1] = next_lights[1];
959                         lights[2] = next_lights[2];
960                         lights[3] = next_lights[3];
961                         tile = next_tile;
962                         light_source = next_light_source;
963                 }
964
965                 p = p_next;
966         }
967 }
968
969 static void updateAllFastFaceRows(MeshMakeData *data,
970                 std::vector<FastFace> &dest)
971 {
972         /*
973                 Go through every y,z and get top(y+) faces in rows of x+
974         */
975         for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
976                 for(s16 z = 0; z < MAP_BLOCKSIZE; z++) {
977                         updateFastFaceRow(data,
978                                         v3s16(0,y,z),
979                                         v3s16(1,0,0), //dir
980                                         v3f  (1,0,0),
981                                         v3s16(0,1,0), //face dir
982                                         v3f  (0,1,0),
983                                         dest);
984                 }
985         }
986
987         /*
988                 Go through every x,y and get right(x+) faces in rows of z+
989         */
990         for(s16 x = 0; x < MAP_BLOCKSIZE; x++) {
991                 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
992                         updateFastFaceRow(data,
993                                         v3s16(x,y,0),
994                                         v3s16(0,0,1), //dir
995                                         v3f  (0,0,1),
996                                         v3s16(1,0,0), //face dir
997                                         v3f  (1,0,0),
998                                         dest);
999                 }
1000         }
1001
1002         /*
1003                 Go through every y,z and get back(z+) faces in rows of x+
1004         */
1005         for(s16 z = 0; z < MAP_BLOCKSIZE; z++) {
1006                 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
1007                         updateFastFaceRow(data,
1008                                         v3s16(0,y,z),
1009                                         v3s16(1,0,0), //dir
1010                                         v3f  (1,0,0),
1011                                         v3s16(0,0,1), //face dir
1012                                         v3f  (0,0,1),
1013                                         dest);
1014                 }
1015         }
1016 }
1017
1018 /*
1019         MapBlockMesh
1020 */
1021
1022 MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
1023         m_mesh(new scene::SMesh()),
1024         m_gamedef(data->m_gamedef),
1025         m_animation_force_timer(0), // force initial animation
1026         m_last_crack(-1),
1027         m_crack_materials(),
1028         m_highlighted_materials(),
1029         m_last_daynight_ratio((u32) -1),
1030         m_daynight_diffs()
1031 {
1032         m_enable_shaders = data->m_use_shaders;
1033         m_enable_highlighting = g_settings->getBool("enable_node_highlighting");
1034
1035         // 4-21ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1036         // 24-155ms for MAP_BLOCKSIZE=32  (NOTE: probably outdated)
1037         //TimeTaker timer1("MapBlockMesh()");
1038
1039         std::vector<FastFace> fastfaces_new;
1040
1041         /*
1042                 We are including the faces of the trailing edges of the block.
1043                 This means that when something changes, the caller must
1044                 also update the meshes of the blocks at the leading edges.
1045
1046                 NOTE: This is the slowest part of this method.
1047         */
1048         {
1049                 // 4-23ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1050                 //TimeTaker timer2("updateAllFastFaceRows()");
1051                 updateAllFastFaceRows(data, fastfaces_new);
1052         }
1053         // End of slow part
1054
1055         /*
1056                 Convert FastFaces to MeshCollector
1057         */
1058
1059         MeshCollector collector;
1060
1061         {
1062                 // avg 0ms (100ms spikes when loading textures the first time)
1063                 // (NOTE: probably outdated)
1064                 //TimeTaker timer2("MeshCollector building");
1065
1066                 for(u32 i=0; i<fastfaces_new.size(); i++)
1067                 {
1068                         FastFace &f = fastfaces_new[i];
1069
1070                         const u16 indices[] = {0,1,2,2,3,0};
1071                         const u16 indices_alternate[] = {0,1,3,2,3,1};
1072
1073                         if(f.tile.texture == NULL)
1074                                 continue;
1075
1076                         const u16 *indices_p = indices;
1077
1078                         /*
1079                                 Revert triangles for nicer looking gradient if vertices
1080                                 1 and 3 have same color or 0 and 2 have different color.
1081                                 getRed() is the day color.
1082                         */
1083                         if(f.vertices[0].Color.getRed() != f.vertices[2].Color.getRed()
1084                                         || f.vertices[1].Color.getRed() == f.vertices[3].Color.getRed())
1085                                 indices_p = indices_alternate;
1086
1087                         collector.append(f.tile, f.vertices, 4, indices_p, 6);
1088                 }
1089         }
1090
1091         /*
1092                 Add special graphics:
1093                 - torches
1094                 - flowing water
1095                 - fences
1096                 - whatever
1097         */
1098
1099         mapblock_mesh_generate_special(data, collector);
1100
1101         m_highlight_mesh_color = data->m_highlight_mesh_color;
1102
1103         /*
1104                 Convert MeshCollector to SMesh
1105         */
1106         ITextureSource *tsrc = m_gamedef->tsrc();
1107         IShaderSource *shdrsrc = m_gamedef->getShaderSource();
1108
1109         for(u32 i = 0; i < collector.prebuffers.size(); i++)
1110         {
1111                 PreMeshBuffer &p = collector.prebuffers[i];
1112
1113                 // Generate animation data
1114                 // - Cracks
1115                 if(p.tile.material_flags & MATERIAL_FLAG_CRACK)
1116                 {
1117                         // Find the texture name plus ^[crack:N:
1118                         std::ostringstream os(std::ios::binary);
1119                         os<<tsrc->getTextureName(p.tile.texture_id)<<"^[crack";
1120                         if(p.tile.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1121                                 os<<"o";  // use ^[cracko
1122                         os<<":"<<(u32)p.tile.animation_frame_count<<":";
1123                         m_crack_materials.insert(std::make_pair(i, os.str()));
1124                         // Replace tile texture with the cracked one
1125                         p.tile.texture = tsrc->getTexture(
1126                                         os.str()+"0",
1127                                         &p.tile.texture_id);
1128                 }
1129                 // - Texture animation
1130                 if(p.tile.material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
1131                 {
1132                         // Add to MapBlockMesh in order to animate these tiles
1133                         m_animation_tiles[i] = p.tile;
1134                         m_animation_frames[i] = 0;
1135                         if(g_settings->getBool("desynchronize_mapblock_texture_animation")){
1136                                 // Get starting position from noise
1137                                 m_animation_frame_offsets[i] = 100000 * (2.0 + noise3d(
1138                                                 data->m_blockpos.X, data->m_blockpos.Y,
1139                                                 data->m_blockpos.Z, 0));
1140                         } else {
1141                                 // Play all synchronized
1142                                 m_animation_frame_offsets[i] = 0;
1143                         }
1144                         // Replace tile texture with the first animation frame
1145                         FrameSpec animation_frame = p.tile.frames[0];
1146                         p.tile.texture = animation_frame.texture;
1147                 }
1148
1149                 if(m_enable_highlighting && p.tile.material_flags & MATERIAL_FLAG_HIGHLIGHTED)
1150                         m_highlighted_materials.push_back(i);   
1151
1152                 for(u32 j = 0; j < p.vertices.size(); j++)
1153                 {
1154                         // Note applyFacesShading second parameter is precalculated sqrt
1155                         // value for speed improvement
1156                         // Skip it for lightsources and top faces.
1157                         video::SColor &vc = p.vertices[j].Color;
1158                         if (!vc.getBlue()) {
1159                                 if (p.vertices[j].Normal.Y < -0.5) {
1160                                         applyFacesShading (vc, 0.447213);
1161                                 } else if (p.vertices[j].Normal.X > 0.5) {
1162                                         applyFacesShading (vc, 0.670820);
1163                                 } else if (p.vertices[j].Normal.X < -0.5) {
1164                                         applyFacesShading (vc, 0.670820);
1165                                 } else if (p.vertices[j].Normal.Z > 0.5) {
1166                                         applyFacesShading (vc, 0.836660);
1167                                 } else if (p.vertices[j].Normal.Z < -0.5) {
1168                                         applyFacesShading (vc, 0.836660);
1169                                 }
1170                         }
1171                         if(!m_enable_shaders)
1172                         {
1173                                 // - Classic lighting (shaders handle this by themselves)
1174                                 // Set initial real color and store for later updates
1175                                 u8 day = vc.getRed();
1176                                 u8 night = vc.getGreen();
1177                                 finalColorBlend(vc, day, night, 1000);
1178                                 if(day != night)
1179                                         m_daynight_diffs[i][j] = std::make_pair(day, night);
1180                         }
1181                 }
1182
1183                 // Create material
1184                 video::SMaterial material;
1185                 material.setFlag(video::EMF_LIGHTING, false);
1186                 material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1187                 material.setFlag(video::EMF_BILINEAR_FILTER, false);
1188                 material.setFlag(video::EMF_FOG_ENABLE, true);
1189                 material.setTexture(0, p.tile.texture);
1190
1191                 if (p.tile.material_flags & MATERIAL_FLAG_HIGHLIGHTED) {
1192                         material.MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
1193                 } else {
1194                         if (m_enable_shaders) {
1195                                 material.MaterialType = shdrsrc->getShaderInfo(p.tile.shader_id).material;
1196                                 p.tile.applyMaterialOptionsWithShaders(material);
1197                                 if (p.tile.normal_texture) {
1198                                         material.setTexture(1, p.tile.normal_texture);
1199                                         material.setTexture(2, tsrc->getTexture("enable_img.png"));
1200                                 } else {
1201                                         material.setTexture(2, tsrc->getTexture("disable_img.png"));
1202                                 }
1203                         } else {
1204                                 p.tile.applyMaterialOptions(material);
1205                         }
1206                 }
1207
1208                 // Create meshbuffer
1209                 // This is a "Standard MeshBuffer",
1210                 // it's a typedeffed CMeshBuffer<video::S3DVertex>
1211                 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1212                 // Set material
1213                 buf->Material = material;
1214                 // Add to mesh
1215                 m_mesh->addMeshBuffer(buf);
1216                 // Mesh grabbed it
1217                 buf->drop();
1218                 buf->append(&p.vertices[0], p.vertices.size(),
1219                                 &p.indices[0], p.indices.size());
1220         }
1221
1222         m_camera_offset = camera_offset;
1223
1224         /*
1225                 Do some stuff to the mesh
1226         */
1227
1228         translateMesh(m_mesh, intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
1229
1230         if(m_mesh)
1231         {
1232 #if 0
1233                 // Usually 1-700 faces and 1-7 materials
1234                 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
1235                                 <<"and uses "<<m_mesh->getMeshBufferCount()
1236                                 <<" materials (meshbuffers)"<<std::endl;
1237 #endif
1238
1239                 // Use VBO for mesh (this just would set this for ever buffer)
1240                 // This will lead to infinite memory usage because or irrlicht.
1241                 //m_mesh->setHardwareMappingHint(scene::EHM_STATIC);
1242
1243                 /*
1244                         NOTE: If that is enabled, some kind of a queue to the main
1245                         thread should be made which would call irrlicht to delete
1246                         the hardware buffer and then delete the mesh
1247                 */
1248         }
1249
1250         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1251
1252         // Check if animation is required for this mesh
1253         m_has_animation =
1254                 !m_crack_materials.empty() ||
1255                 !m_daynight_diffs.empty() ||
1256                 !m_animation_tiles.empty() ||
1257                 !m_highlighted_materials.empty();
1258 }
1259
1260 MapBlockMesh::~MapBlockMesh()
1261 {
1262         m_mesh->drop();
1263         m_mesh = NULL;
1264 }
1265
1266 bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_ratio)
1267 {
1268
1269         if(!m_has_animation)
1270         {
1271                 m_animation_force_timer = 100000;
1272                 return false;
1273         }
1274
1275         m_animation_force_timer = myrand_range(5, 100);
1276
1277         // Cracks
1278         if(crack != m_last_crack)
1279         {
1280                 for(std::map<u32, std::string>::iterator
1281                                 i = m_crack_materials.begin();
1282                                 i != m_crack_materials.end(); i++)
1283                 {
1284                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1285                         std::string basename = i->second;
1286
1287                         // Create new texture name from original
1288                         ITextureSource *tsrc = m_gamedef->getTextureSource();
1289                         std::ostringstream os;
1290                         os<<basename<<crack;
1291                         u32 new_texture_id = 0;
1292                         video::ITexture *new_texture =
1293                                 tsrc->getTexture(os.str(), &new_texture_id);
1294                         buf->getMaterial().setTexture(0, new_texture);
1295
1296                         // If the current material is also animated,
1297                         // update animation info
1298                         std::map<u32, TileSpec>::iterator anim_iter =
1299                                 m_animation_tiles.find(i->first);
1300                         if(anim_iter != m_animation_tiles.end()){
1301                                 TileSpec &tile = anim_iter->second;
1302                                 tile.texture = new_texture;
1303                                 tile.texture_id = new_texture_id;
1304                                 // force animation update
1305                                 m_animation_frames[i->first] = -1;
1306                         }
1307                 }
1308
1309                 m_last_crack = crack;
1310         }
1311
1312         // Texture animation
1313         for(std::map<u32, TileSpec>::iterator
1314                         i = m_animation_tiles.begin();
1315                         i != m_animation_tiles.end(); i++)
1316         {
1317                 const TileSpec &tile = i->second;
1318                 // Figure out current frame
1319                 int frameoffset = m_animation_frame_offsets[i->first];
1320                 int frame = (int)(time * 1000 / tile.animation_frame_length_ms
1321                                 + frameoffset) % tile.animation_frame_count;
1322                 // If frame doesn't change, skip
1323                 if(frame == m_animation_frames[i->first])
1324                         continue;
1325
1326                 m_animation_frames[i->first] = frame;
1327
1328                 scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1329                 ITextureSource *tsrc = m_gamedef->getTextureSource();
1330
1331                 FrameSpec animation_frame = tile.frames[frame];
1332                 buf->getMaterial().setTexture(0, animation_frame.texture);
1333                 if (m_enable_shaders) {
1334                         if (animation_frame.normal_texture) {
1335                                 buf->getMaterial().setTexture(1, animation_frame.normal_texture);
1336                                 buf->getMaterial().setTexture(2, tsrc->getTexture("enable_img.png"));
1337                         } else {
1338                                 buf->getMaterial().setTexture(2, tsrc->getTexture("disable_img.png"));
1339                         }
1340                 }
1341         }
1342
1343         // Day-night transition
1344         if(!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio))
1345         {
1346                 for(std::map<u32, std::map<u32, std::pair<u8, u8> > >::iterator
1347                                 i = m_daynight_diffs.begin();
1348                                 i != m_daynight_diffs.end(); i++)
1349                 {
1350                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1351                         video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
1352                         for(std::map<u32, std::pair<u8, u8 > >::iterator
1353                                         j = i->second.begin();
1354                                         j != i->second.end(); j++)
1355                         {
1356                                 u32 vertexIndex = j->first;
1357                                 u8 day = j->second.first;
1358                                 u8 night = j->second.second;
1359                                 finalColorBlend(vertices[vertexIndex].Color,
1360                                                 day, night, daynight_ratio);
1361                         }
1362                 }
1363                 m_last_daynight_ratio = daynight_ratio;
1364         }
1365
1366         // Node highlighting
1367         if (m_enable_highlighting) {
1368                 u8 day = m_highlight_mesh_color.getRed();
1369                 u8 night = m_highlight_mesh_color.getGreen();   
1370                 video::SColor hc;
1371                 finalColorBlend(hc, day, night, daynight_ratio);
1372                 float sin_r = 0.07 * sin(1.5 * time);
1373                 float sin_g = 0.07 * sin(1.5 * time + irr::core::PI * 0.5);
1374                 float sin_b = 0.07 * sin(1.5 * time + irr::core::PI);
1375                 hc.setRed(core::clamp(core::round32(hc.getRed() * (0.8 + sin_r)), 0, 255));
1376                 hc.setGreen(core::clamp(core::round32(hc.getGreen() * (0.8 + sin_g)), 0, 255));
1377                 hc.setBlue(core::clamp(core::round32(hc.getBlue() * (0.8 + sin_b)), 0, 255));
1378
1379                 for(std::list<u32>::iterator
1380                         i = m_highlighted_materials.begin();
1381                         i != m_highlighted_materials.end(); i++)
1382                 {
1383                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(*i);
1384                         video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
1385                         for (u32 j = 0; j < buf->getVertexCount() ;j++)
1386                                 vertices[j].Color = hc;
1387                 }
1388         }
1389
1390         return true;
1391 }
1392
1393 void MapBlockMesh::updateCameraOffset(v3s16 camera_offset)
1394 {
1395         if (camera_offset != m_camera_offset) {
1396                 translateMesh(m_mesh, intToFloat(m_camera_offset-camera_offset, BS));
1397                 m_camera_offset = camera_offset;
1398         }
1399 }
1400
1401 /*
1402         MeshCollector
1403 */
1404
1405 void MeshCollector::append(const TileSpec &tile,
1406                 const video::S3DVertex *vertices, u32 numVertices,
1407                 const u16 *indices, u32 numIndices)
1408 {
1409         if(numIndices > 65535)
1410         {
1411                 dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1412                 return;
1413         }
1414
1415         PreMeshBuffer *p = NULL;
1416         for(u32 i=0; i<prebuffers.size(); i++)
1417         {
1418                 PreMeshBuffer &pp = prebuffers[i];
1419                 if(pp.tile != tile)
1420                         continue;
1421                 if(pp.indices.size() + numIndices > 65535)
1422                         continue;
1423
1424                 p = &pp;
1425                 break;
1426         }
1427
1428         if(p == NULL)
1429         {
1430                 PreMeshBuffer pp;
1431                 pp.tile = tile;
1432                 prebuffers.push_back(pp);
1433                 p = &prebuffers[prebuffers.size()-1];
1434         }
1435
1436         u32 vertex_count = p->vertices.size();
1437         for(u32 i=0; i<numIndices; i++)
1438         {
1439                 u32 j = indices[i] + vertex_count;
1440                 p->indices.push_back(j);
1441         }
1442         for(u32 i=0; i<numVertices; i++)
1443         {
1444                 p->vertices.push_back(vertices[i]);
1445         }
1446 }
1447
1448 /*
1449         MeshCollector - for meshnodes and converted drawtypes.
1450 */
1451
1452 void MeshCollector::append(const TileSpec &tile,
1453                 const video::S3DVertex *vertices, u32 numVertices,
1454                 const u16 *indices, u32 numIndices,
1455                 v3f pos, video::SColor c)
1456 {
1457         if(numIndices > 65535)
1458         {
1459                 dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1460                 return;
1461         }
1462
1463         PreMeshBuffer *p = NULL;
1464         for(u32 i=0; i<prebuffers.size(); i++)
1465         {
1466                 PreMeshBuffer &pp = prebuffers[i];
1467                 if(pp.tile != tile)
1468                         continue;
1469                 if(pp.indices.size() + numIndices > 65535)
1470                         continue;
1471
1472                 p = &pp;
1473                 break;
1474         }
1475
1476         if(p == NULL)
1477         {
1478                 PreMeshBuffer pp;
1479                 pp.tile = tile;
1480                 prebuffers.push_back(pp);
1481                 p = &prebuffers[prebuffers.size()-1];
1482         }
1483
1484         u32 vertex_count = p->vertices.size();
1485         for(u32 i=0; i<numIndices; i++)
1486         {
1487                 u32 j = indices[i] + vertex_count;
1488                 p->indices.push_back(j);
1489         }
1490         for(u32 i=0; i<numVertices; i++)
1491         {
1492                 video::S3DVertex vert = vertices[i];
1493                 vert.Pos += pos;
1494                 vert.Color = c;         
1495                 p->vertices.push_back(vert);
1496         }
1497 }