]> git.lizzy.rs Git - minetest.git/blob - src/mapblock_mesh.cpp
Drop luaentity_common.h which is not included anywhere
[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 "profiler.h"
25 #include "nodedef.h"
26 #include "gamedef.h"
27 #include "mesh.h"
28 #include "minimap.h"
29 #include "content_mapblock.h"
30 #include "noise.h"
31 #include "shader.h"
32 #include "settings.h"
33 #include "util/directiontables.h"
34 #include <IMeshManipulator.h>
35
36 static void applyFacesShading(video::SColor& color, float factor)
37 {
38         color.setRed(core::clamp(core::round32(color.getRed()*factor), 0, 255));
39         color.setGreen(core::clamp(core::round32(color.getGreen()*factor), 0, 255));
40 }
41
42 /*
43         MeshMakeData
44 */
45
46 MeshMakeData::MeshMakeData(IGameDef *gamedef, bool use_shaders):
47         m_vmanip(),
48         m_blockpos(-1337,-1337,-1337),
49         m_crack_pos_relative(-1337, -1337, -1337),
50         m_smooth_lighting(false),
51         m_show_hud(false),
52         m_gamedef(gamedef),
53         m_use_shaders(use_shaders)
54 {}
55
56 void MeshMakeData::fill(MapBlock *block)
57 {
58         m_blockpos = block->getPos();
59
60         v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
61
62         /*
63                 Copy data
64         */
65
66         // Allocate this block + neighbors
67         m_vmanip.clear();
68         VoxelArea voxel_area(blockpos_nodes - v3s16(1,1,1) * MAP_BLOCKSIZE,
69                         blockpos_nodes + v3s16(1,1,1) * MAP_BLOCKSIZE*2-v3s16(1,1,1));
70         m_vmanip.addArea(voxel_area);
71
72         {
73                 //TimeTaker timer("copy central block data");
74                 // 0ms
75
76                 // Copy our data
77                 block->copyTo(m_vmanip);
78         }
79         {
80                 //TimeTaker timer("copy neighbor block data");
81                 // 0ms
82
83                 /*
84                         Copy neighbors. This is lightning fast.
85                         Copying only the borders would be *very* slow.
86                 */
87
88                 // Get map
89                 Map *map = block->getParent();
90
91                 for(u16 i=0; i<26; i++)
92                 {
93                         const v3s16 &dir = g_26dirs[i];
94                         v3s16 bp = m_blockpos + dir;
95                         MapBlock *b = map->getBlockNoCreateNoEx(bp);
96                         if(b)
97                                 b->copyTo(m_vmanip);
98                 }
99         }
100 }
101
102 void MeshMakeData::fillSingleNode(MapNode *node)
103 {
104         m_blockpos = v3s16(0,0,0);
105
106         v3s16 blockpos_nodes = v3s16(0,0,0);
107         VoxelArea area(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
108                         blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1));
109         s32 volume = area.getVolume();
110         s32 our_node_index = area.index(1,1,1);
111
112         // Allocate this block + neighbors
113         m_vmanip.clear();
114         m_vmanip.addArea(area);
115
116         // Fill in data
117         MapNode *data = new MapNode[volume];
118         for(s32 i = 0; i < volume; i++)
119         {
120                 if(i == our_node_index)
121                 {
122                         data[i] = *node;
123                 }
124                 else
125                 {
126                         data[i] = MapNode(CONTENT_AIR, LIGHT_MAX, 0);
127                 }
128         }
129         m_vmanip.copyFrom(data, area, area.MinEdge, area.MinEdge, area.getExtent());
130         delete[] data;
131 }
132
133 void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
134 {
135         if(crack_level >= 0)
136                 m_crack_pos_relative = crack_pos - m_blockpos*MAP_BLOCKSIZE;
137 }
138
139 void MeshMakeData::setSmoothLighting(bool smooth_lighting)
140 {
141         m_smooth_lighting = smooth_lighting;
142 }
143
144 /*
145         Light and vertex color functions
146 */
147
148 /*
149         Calculate non-smooth lighting at interior of node.
150         Single light bank.
151 */
152 static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
153                 INodeDefManager *ndef)
154 {
155         u8 light = n.getLight(bank, ndef);
156
157         while(increment > 0)
158         {
159                 light = undiminish_light(light);
160                 --increment;
161         }
162         while(increment < 0)
163         {
164                 light = diminish_light(light);
165                 ++increment;
166         }
167
168         return decode_light(light);
169 }
170
171 /*
172         Calculate non-smooth lighting at interior of node.
173         Both light banks.
174 */
175 u16 getInteriorLight(MapNode n, s32 increment, INodeDefManager *ndef)
176 {
177         u16 day = getInteriorLight(LIGHTBANK_DAY, n, increment, ndef);
178         u16 night = getInteriorLight(LIGHTBANK_NIGHT, n, increment, ndef);
179         return day | (night << 8);
180 }
181
182 /*
183         Calculate non-smooth lighting at face of node.
184         Single light bank.
185 */
186 static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
187                 v3s16 face_dir, INodeDefManager *ndef)
188 {
189         u8 light;
190         u8 l1 = n.getLight(bank, ndef);
191         u8 l2 = n2.getLight(bank, ndef);
192         if(l1 > l2)
193                 light = l1;
194         else
195                 light = l2;
196
197         // Boost light level for light sources
198         u8 light_source = MYMAX(ndef->get(n).light_source,
199                         ndef->get(n2).light_source);
200         if(light_source > light)
201                 light = light_source;
202
203         return decode_light(light);
204 }
205
206 /*
207         Calculate non-smooth lighting at face of node.
208         Both light banks.
209 */
210 u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef)
211 {
212         u16 day = getFaceLight(LIGHTBANK_DAY, n, n2, face_dir, ndef);
213         u16 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, face_dir, ndef);
214         return day | (night << 8);
215 }
216
217 /*
218         Calculate smooth lighting at the XYZ- corner of p.
219         Both light banks
220 */
221 static u16 getSmoothLightCombined(v3s16 p, MeshMakeData *data)
222 {
223         static const v3s16 dirs8[8] = {
224                 v3s16(0,0,0),
225                 v3s16(0,0,1),
226                 v3s16(0,1,0),
227                 v3s16(0,1,1),
228                 v3s16(1,0,0),
229                 v3s16(1,1,0),
230                 v3s16(1,0,1),
231                 v3s16(1,1,1),
232         };
233
234         INodeDefManager *ndef = data->m_gamedef->ndef();
235
236         u16 ambient_occlusion = 0;
237         u16 light_count = 0;
238         u8 light_source_max = 0;
239         u16 light_day = 0;
240         u16 light_night = 0;
241
242         for (u32 i = 0; i < 8; i++)
243         {
244                 const MapNode &n = data->m_vmanip.getNodeRefUnsafeCheckFlags(p - dirs8[i]);
245
246                 // if it's CONTENT_IGNORE we can't do any light calculations
247                 if (n.getContent() == CONTENT_IGNORE) {
248                         continue;
249                 }
250
251                 const ContentFeatures &f = ndef->get(n);
252                 if (f.light_source > light_source_max)
253                         light_source_max = f.light_source;
254                 // Check f.solidness because fast-style leaves look better this way
255                 if (f.param_type == CPT_LIGHT && f.solidness != 2) {
256                         light_day += decode_light(n.getLightNoChecks(LIGHTBANK_DAY, &f));
257                         light_night += decode_light(n.getLightNoChecks(LIGHTBANK_NIGHT, &f));
258                         light_count++;
259                 } else {
260                         ambient_occlusion++;
261                 }
262         }
263
264         if(light_count == 0)
265                 return 0xffff;
266
267         light_day /= light_count;
268         light_night /= light_count;
269
270         // Boost brightness around light sources
271         bool skip_ambient_occlusion_day = false;
272         if(decode_light(light_source_max) >= light_day) {
273                 light_day = decode_light(light_source_max);
274                 skip_ambient_occlusion_day = true;
275         }
276
277         bool skip_ambient_occlusion_night = false;
278         if(decode_light(light_source_max) >= light_night) {
279                 light_night = decode_light(light_source_max);
280                 skip_ambient_occlusion_night = true;
281         }
282
283         if (ambient_occlusion > 4)
284         {
285                 static const float ao_gamma = rangelim(
286                         g_settings->getFloat("ambient_occlusion_gamma"), 0.25, 4.0);
287
288                 // Table of gamma space multiply factors.
289                 static const float light_amount[3] = {
290                         powf(0.75, 1.0 / ao_gamma),
291                         powf(0.5,  1.0 / ao_gamma),
292                         powf(0.25, 1.0 / ao_gamma)
293                 };
294
295                 //calculate table index for gamma space multiplier
296                 ambient_occlusion -= 5;
297
298                 if (!skip_ambient_occlusion_day)
299                         light_day = rangelim(core::round32(light_day*light_amount[ambient_occlusion]), 0, 255);
300                 if (!skip_ambient_occlusion_night)
301                         light_night = rangelim(core::round32(light_night*light_amount[ambient_occlusion]), 0, 255);
302         }
303
304         return light_day | (light_night << 8);
305 }
306
307 /*
308         Calculate smooth lighting at the given corner of p.
309         Both light banks.
310 */
311 u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data)
312 {
313         if(corner.X == 1) p.X += 1;
314         // else corner.X == -1
315         if(corner.Y == 1) p.Y += 1;
316         // else corner.Y == -1
317         if(corner.Z == 1) p.Z += 1;
318         // else corner.Z == -1
319
320         return getSmoothLightCombined(p, data);
321 }
322
323 /*
324         Converts from day + night color values (0..255)
325         and a given daynight_ratio to the final SColor shown on screen.
326 */
327 void finalColorBlend(video::SColor& result,
328                 u8 day, u8 night, u32 daynight_ratio)
329 {
330         s32 rg = (day * daynight_ratio + night * (1000-daynight_ratio)) / 1000;
331         s32 b = rg;
332
333         // Moonlight is blue
334         b += (day - night) / 13;
335         rg -= (day - night) / 23;
336
337         // Emphase blue a bit in darker places
338         // Each entry of this array represents a range of 8 blue levels
339         static const u8 emphase_blue_when_dark[32] = {
340                 1, 4, 6, 6, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0,
341                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
342         };
343         b += emphase_blue_when_dark[irr::core::clamp(b, 0, 255) / 8];
344         b = irr::core::clamp(b, 0, 255);
345
346         // Artificial light is yellow-ish
347         static const u8 emphase_yellow_when_artificial[16] = {
348                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 10, 15, 15, 15
349         };
350         rg += emphase_yellow_when_artificial[night/16];
351         rg = irr::core::clamp(rg, 0, 255);
352
353         result.setRed(rg);
354         result.setGreen(rg);
355         result.setBlue(b);
356 }
357
358 /*
359         Mesh generation helpers
360 */
361
362 /*
363         vertex_dirs: v3s16[4]
364 */
365 static void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
366 {
367         /*
368                 If looked from outside the node towards the face, the corners are:
369                 0: bottom-right
370                 1: bottom-left
371                 2: top-left
372                 3: top-right
373         */
374         if(dir == v3s16(0,0,1))
375         {
376                 // If looking towards z+, this is the face that is behind
377                 // the center point, facing towards z+.
378                 vertex_dirs[0] = v3s16(-1,-1, 1);
379                 vertex_dirs[1] = v3s16( 1,-1, 1);
380                 vertex_dirs[2] = v3s16( 1, 1, 1);
381                 vertex_dirs[3] = v3s16(-1, 1, 1);
382         }
383         else if(dir == v3s16(0,0,-1))
384         {
385                 // faces towards Z-
386                 vertex_dirs[0] = v3s16( 1,-1,-1);
387                 vertex_dirs[1] = v3s16(-1,-1,-1);
388                 vertex_dirs[2] = v3s16(-1, 1,-1);
389                 vertex_dirs[3] = v3s16( 1, 1,-1);
390         }
391         else if(dir == v3s16(1,0,0))
392         {
393                 // faces towards X+
394                 vertex_dirs[0] = v3s16( 1,-1, 1);
395                 vertex_dirs[1] = v3s16( 1,-1,-1);
396                 vertex_dirs[2] = v3s16( 1, 1,-1);
397                 vertex_dirs[3] = v3s16( 1, 1, 1);
398         }
399         else if(dir == v3s16(-1,0,0))
400         {
401                 // faces towards X-
402                 vertex_dirs[0] = v3s16(-1,-1,-1);
403                 vertex_dirs[1] = v3s16(-1,-1, 1);
404                 vertex_dirs[2] = v3s16(-1, 1, 1);
405                 vertex_dirs[3] = v3s16(-1, 1,-1);
406         }
407         else if(dir == v3s16(0,1,0))
408         {
409                 // faces towards Y+ (assume Z- as "down" in texture)
410                 vertex_dirs[0] = v3s16( 1, 1,-1);
411                 vertex_dirs[1] = v3s16(-1, 1,-1);
412                 vertex_dirs[2] = v3s16(-1, 1, 1);
413                 vertex_dirs[3] = v3s16( 1, 1, 1);
414         }
415         else if(dir == v3s16(0,-1,0))
416         {
417                 // faces towards Y- (assume Z+ as "down" in texture)
418                 vertex_dirs[0] = v3s16( 1,-1, 1);
419                 vertex_dirs[1] = v3s16(-1,-1, 1);
420                 vertex_dirs[2] = v3s16(-1,-1,-1);
421                 vertex_dirs[3] = v3s16( 1,-1,-1);
422         }
423 }
424
425 struct FastFace
426 {
427         TileSpec tile;
428         video::S3DVertex vertices[4]; // Precalculated vertices
429 };
430
431 static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
432                 v3f p, v3s16 dir, v3f scale, u8 light_source, std::vector<FastFace> &dest)
433 {
434         // Position is at the center of the cube.
435         v3f pos = p * BS;
436
437         float x0 = 0.0;
438         float y0 = 0.0;
439         float w = 1.0;
440         float h = 1.0;
441
442         v3f vertex_pos[4];
443         v3s16 vertex_dirs[4];
444         getNodeVertexDirs(dir, vertex_dirs);
445
446         v3s16 t;
447         u16 t1;
448         switch (tile.rotation)
449         {
450         case 0:
451                 break;
452         case 1: //R90
453                 t = vertex_dirs[0];
454                 vertex_dirs[0] = vertex_dirs[3];
455                 vertex_dirs[3] = vertex_dirs[2];
456                 vertex_dirs[2] = vertex_dirs[1];
457                 vertex_dirs[1] = t;
458                 t1=li0;
459                 li0=li3;
460                 li3=li2;
461                 li2=li1;
462                 li1=t1;
463                 break;
464         case 2: //R180
465                 t = vertex_dirs[0];
466                 vertex_dirs[0] = vertex_dirs[2];
467                 vertex_dirs[2] = t;
468                 t = vertex_dirs[1];
469                 vertex_dirs[1] = vertex_dirs[3];
470                 vertex_dirs[3] = t;
471                 t1  = li0;
472                 li0 = li2;
473                 li2 = t1;
474                 t1  = li1;
475                 li1 = li3;
476                 li3 = t1;
477                 break;
478         case 3: //R270
479                 t = vertex_dirs[0];
480                 vertex_dirs[0] = vertex_dirs[1];
481                 vertex_dirs[1] = vertex_dirs[2];
482                 vertex_dirs[2] = vertex_dirs[3];
483                 vertex_dirs[3] = t;
484                 t1  = li0;
485                 li0 = li1;
486                 li1 = li2;
487                 li2 = li3;
488                 li3 = t1;
489                 break;
490         case 4: //FXR90
491                 t = vertex_dirs[0];
492                 vertex_dirs[0] = vertex_dirs[3];
493                 vertex_dirs[3] = vertex_dirs[2];
494                 vertex_dirs[2] = vertex_dirs[1];
495                 vertex_dirs[1] = t;
496                 t1  = li0;
497                 li0 = li3;
498                 li3 = li2;
499                 li2 = li1;
500                 li1 = t1;
501                 y0 += h;
502                 h *= -1;
503                 break;
504         case 5: //FXR270
505                 t = vertex_dirs[0];
506                 vertex_dirs[0] = vertex_dirs[1];
507                 vertex_dirs[1] = vertex_dirs[2];
508                 vertex_dirs[2] = vertex_dirs[3];
509                 vertex_dirs[3] = t;
510                 t1  = li0;
511                 li0 = li1;
512                 li1 = li2;
513                 li2 = li3;
514                 li3 = t1;
515                 y0 += h;
516                 h *= -1;
517                 break;
518         case 6: //FYR90
519                 t = vertex_dirs[0];
520                 vertex_dirs[0] = vertex_dirs[3];
521                 vertex_dirs[3] = vertex_dirs[2];
522                 vertex_dirs[2] = vertex_dirs[1];
523                 vertex_dirs[1] = t;
524                 t1  = li0;
525                 li0 = li3;
526                 li3 = li2;
527                 li2 = li1;
528                 li1 = t1;
529                 x0 += w;
530                 w *= -1;
531                 break;
532         case 7: //FYR270
533                 t = vertex_dirs[0];
534                 vertex_dirs[0] = vertex_dirs[1];
535                 vertex_dirs[1] = vertex_dirs[2];
536                 vertex_dirs[2] = vertex_dirs[3];
537                 vertex_dirs[3] = t;
538                 t1  = li0;
539                 li0 = li1;
540                 li1 = li2;
541                 li2 = li3;
542                 li3 = t1;
543                 x0 += w;
544                 w *= -1;
545                 break;
546         case 8: //FX
547                 y0 += h;
548                 h *= -1;
549                 break;
550         case 9: //FY
551                 x0 += w;
552                 w *= -1;
553                 break;
554         default:
555                 break;
556         }
557
558         for(u16 i=0; i<4; i++)
559         {
560                 vertex_pos[i] = v3f(
561                                 BS/2*vertex_dirs[i].X,
562                                 BS/2*vertex_dirs[i].Y,
563                                 BS/2*vertex_dirs[i].Z
564                 );
565         }
566
567         for(u16 i=0; i<4; i++)
568         {
569                 vertex_pos[i].X *= scale.X;
570                 vertex_pos[i].Y *= scale.Y;
571                 vertex_pos[i].Z *= scale.Z;
572                 vertex_pos[i] += pos;
573         }
574
575         f32 abs_scale = 1.0;
576         if     (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
577         else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
578         else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
579
580         v3f normal(dir.X, dir.Y, dir.Z);
581
582         u8 alpha = tile.alpha;
583
584         dest.push_back(FastFace());
585
586         FastFace& face = *dest.rbegin();
587
588         face.vertices[0] = video::S3DVertex(vertex_pos[0], normal,
589                         MapBlock_LightColor(alpha, li0, light_source),
590                         core::vector2d<f32>(x0+w*abs_scale, y0+h));
591         face.vertices[1] = video::S3DVertex(vertex_pos[1], normal,
592                         MapBlock_LightColor(alpha, li1, light_source),
593                         core::vector2d<f32>(x0, y0+h));
594         face.vertices[2] = video::S3DVertex(vertex_pos[2], normal,
595                         MapBlock_LightColor(alpha, li2, light_source),
596                         core::vector2d<f32>(x0, y0));
597         face.vertices[3] = video::S3DVertex(vertex_pos[3], normal,
598                         MapBlock_LightColor(alpha, li3, light_source),
599                         core::vector2d<f32>(x0+w*abs_scale, y0));
600
601         face.tile = tile;
602 }
603
604 /*
605         Nodes make a face if contents differ and solidness differs.
606         Return value:
607                 0: No face
608                 1: Face uses m1's content
609                 2: Face uses m2's content
610         equivalent: Whether the blocks share the same face (eg. water and glass)
611
612         TODO: Add 3: Both faces drawn with backface culling, remove equivalent
613 */
614 static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
615                 INodeDefManager *ndef)
616 {
617         *equivalent = false;
618
619         if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
620                 return 0;
621
622         bool contents_differ = (m1 != m2);
623
624         const ContentFeatures &f1 = ndef->get(m1);
625         const ContentFeatures &f2 = ndef->get(m2);
626
627         // Contents don't differ for different forms of same liquid
628         if(f1.sameLiquid(f2))
629                 contents_differ = false;
630
631         u8 c1 = f1.solidness;
632         u8 c2 = f2.solidness;
633
634         bool solidness_differs = (c1 != c2);
635         bool makes_face = contents_differ && solidness_differs;
636
637         if(makes_face == false)
638                 return 0;
639
640         if(c1 == 0)
641                 c1 = f1.visual_solidness;
642         if(c2 == 0)
643                 c2 = f2.visual_solidness;
644
645         if(c1 == c2){
646                 *equivalent = true;
647                 // If same solidness, liquid takes precense
648                 if(f1.isLiquid())
649                         return 1;
650                 if(f2.isLiquid())
651                         return 2;
652         }
653
654         if(c1 > c2)
655                 return 1;
656         else
657                 return 2;
658 }
659
660 /*
661         Gets nth node tile (0 <= n <= 5).
662 */
663 TileSpec getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data)
664 {
665         INodeDefManager *ndef = data->m_gamedef->ndef();
666         TileSpec spec = ndef->get(mn).tiles[tileindex];
667         // Apply temporary crack
668         if (p == data->m_crack_pos_relative)
669                 spec.material_flags |= MATERIAL_FLAG_CRACK;
670         return spec;
671 }
672
673 /*
674         Gets node tile given a face direction.
675 */
676 TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data)
677 {
678         INodeDefManager *ndef = data->m_gamedef->ndef();
679
680         // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
681         // (0,0,1), (0,0,-1) or (0,0,0)
682         assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z <= 1);
683
684         // Convert direction to single integer for table lookup
685         //  0 = (0,0,0)
686         //  1 = (1,0,0)
687         //  2 = (0,1,0)
688         //  3 = (0,0,1)
689         //  4 = invalid, treat as (0,0,0)
690         //  5 = (0,0,-1)
691         //  6 = (0,-1,0)
692         //  7 = (-1,0,0)
693         u8 dir_i = ((dir.X + 2 * dir.Y + 3 * dir.Z) & 7)*2;
694
695         // Get rotation for things like chests
696         u8 facedir = mn.getFaceDir(ndef);
697
698         static const u16 dir_to_tile[24 * 16] =
699         {
700                 // 0     +X    +Y    +Z           -Z    -Y    -X   ->   value=tile,rotation
701                    0,0,  2,0 , 0,0 , 4,0 ,  0,0,  5,0 , 1,0 , 3,0 ,  // rotate around y+ 0 - 3
702                    0,0,  4,0 , 0,3 , 3,0 ,  0,0,  2,0 , 1,1 , 5,0 ,
703                    0,0,  3,0 , 0,2 , 5,0 ,  0,0,  4,0 , 1,2 , 2,0 ,
704                    0,0,  5,0 , 0,1 , 2,0 ,  0,0,  3,0 , 1,3 , 4,0 ,
705
706                    0,0,  2,3 , 5,0 , 0,2 ,  0,0,  1,0 , 4,2 , 3,1 ,  // rotate around z+ 4 - 7
707                    0,0,  4,3 , 2,0 , 0,1 ,  0,0,  1,1 , 3,2 , 5,1 ,
708                    0,0,  3,3 , 4,0 , 0,0 ,  0,0,  1,2 , 5,2 , 2,1 ,
709                    0,0,  5,3 , 3,0 , 0,3 ,  0,0,  1,3 , 2,2 , 4,1 ,
710
711                    0,0,  2,1 , 4,2 , 1,2 ,  0,0,  0,0 , 5,0 , 3,3 ,  // rotate around z- 8 - 11
712                    0,0,  4,1 , 3,2 , 1,3 ,  0,0,  0,3 , 2,0 , 5,3 ,
713                    0,0,  3,1 , 5,2 , 1,0 ,  0,0,  0,2 , 4,0 , 2,3 ,
714                    0,0,  5,1 , 2,2 , 1,1 ,  0,0,  0,1 , 3,0 , 4,3 ,
715
716                    0,0,  0,3 , 3,3 , 4,1 ,  0,0,  5,3 , 2,3 , 1,3 ,  // rotate around x+ 12 - 15
717                    0,0,  0,2 , 5,3 , 3,1 ,  0,0,  2,3 , 4,3 , 1,0 ,
718                    0,0,  0,1 , 2,3 , 5,1 ,  0,0,  4,3 , 3,3 , 1,1 ,
719                    0,0,  0,0 , 4,3 , 2,1 ,  0,0,  3,3 , 5,3 , 1,2 ,
720
721                    0,0,  1,1 , 2,1 , 4,3 ,  0,0,  5,1 , 3,1 , 0,1 ,  // rotate around x- 16 - 19
722                    0,0,  1,2 , 4,1 , 3,3 ,  0,0,  2,1 , 5,1 , 0,0 ,
723                    0,0,  1,3 , 3,1 , 5,3 ,  0,0,  4,1 , 2,1 , 0,3 ,
724                    0,0,  1,0 , 5,1 , 2,3 ,  0,0,  3,1 , 4,1 , 0,2 ,
725
726                    0,0,  3,2 , 1,2 , 4,2 ,  0,0,  5,2 , 0,2 , 2,2 ,  // rotate around y- 20 - 23
727                    0,0,  5,2 , 1,3 , 3,2 ,  0,0,  2,2 , 0,1 , 4,2 ,
728                    0,0,  2,2 , 1,0 , 5,2 ,  0,0,  4,2 , 0,0 , 3,2 ,
729                    0,0,  4,2 , 1,1 , 2,2 ,  0,0,  3,2 , 0,3 , 5,2
730
731         };
732         u16 tile_index=facedir*16 + dir_i;
733         TileSpec spec = getNodeTileN(mn, p, dir_to_tile[tile_index], data);
734         spec.rotation=dir_to_tile[tile_index + 1];
735         spec.texture = data->m_gamedef->tsrc()->getTexture(spec.texture_id);
736         return spec;
737 }
738
739 static void getTileInfo(
740                 // Input:
741                 MeshMakeData *data,
742                 const v3s16 &p,
743                 const v3s16 &face_dir,
744                 // Output:
745                 bool &makes_face,
746                 v3s16 &p_corrected,
747                 v3s16 &face_dir_corrected,
748                 u16 *lights,
749                 TileSpec &tile,
750                 u8 &light_source
751         )
752 {
753         VoxelManipulator &vmanip = data->m_vmanip;
754         INodeDefManager *ndef = data->m_gamedef->ndef();
755         v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
756
757         MapNode &n0 = vmanip.getNodeRefUnsafe(blockpos_nodes + p);
758
759         // Don't even try to get n1 if n0 is already CONTENT_IGNORE
760         if (n0.getContent() == CONTENT_IGNORE) {
761                 makes_face = false;
762                 return;
763         }
764
765         const MapNode &n1 = vmanip.getNodeRefUnsafeCheckFlags(blockpos_nodes + p + face_dir);
766
767         if (n1.getContent() == CONTENT_IGNORE) {
768                 makes_face = false;
769                 return;
770         }
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_minimap_mapblock(NULL),
1025         m_gamedef(data->m_gamedef),
1026         m_tsrc(m_gamedef->getTextureSource()),
1027         m_shdrsrc(m_gamedef->getShaderSource()),
1028         m_animation_force_timer(0), // force initial animation
1029         m_last_crack(-1),
1030         m_crack_materials(),
1031         m_last_daynight_ratio((u32) -1),
1032         m_daynight_diffs()
1033 {
1034         m_enable_shaders = data->m_use_shaders;
1035
1036         if (g_settings->getBool("enable_minimap")) {
1037                 m_minimap_mapblock = new MinimapMapblock;
1038                 m_minimap_mapblock->getMinimapNodes(
1039                         &data->m_vmanip, data->m_blockpos * MAP_BLOCKSIZE);
1040         }
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         /*
1110                 Convert MeshCollector to SMesh
1111         */
1112
1113         for(u32 i = 0; i < collector.prebuffers.size(); i++)
1114         {
1115                 PreMeshBuffer &p = collector.prebuffers[i];
1116
1117                 // Generate animation data
1118                 // - Cracks
1119                 if(p.tile.material_flags & MATERIAL_FLAG_CRACK)
1120                 {
1121                         // Find the texture name plus ^[crack:N:
1122                         std::ostringstream os(std::ios::binary);
1123                         os<<m_tsrc->getTextureName(p.tile.texture_id)<<"^[crack";
1124                         if(p.tile.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1125                                 os<<"o";  // use ^[cracko
1126                         os<<":"<<(u32)p.tile.animation_frame_count<<":";
1127                         m_crack_materials.insert(std::make_pair(i, os.str()));
1128                         // Replace tile texture with the cracked one
1129                         p.tile.texture = m_tsrc->getTextureForMesh(
1130                                         os.str()+"0",
1131                                         &p.tile.texture_id);
1132                 }
1133                 // - Texture animation
1134                 if(p.tile.material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
1135                 {
1136                         // Add to MapBlockMesh in order to animate these tiles
1137                         m_animation_tiles[i] = p.tile;
1138                         m_animation_frames[i] = 0;
1139                         if(g_settings->getBool("desynchronize_mapblock_texture_animation")){
1140                                 // Get starting position from noise
1141                                 m_animation_frame_offsets[i] = 100000 * (2.0 + noise3d(
1142                                                 data->m_blockpos.X, data->m_blockpos.Y,
1143                                                 data->m_blockpos.Z, 0));
1144                         } else {
1145                                 // Play all synchronized
1146                                 m_animation_frame_offsets[i] = 0;
1147                         }
1148                         // Replace tile texture with the first animation frame
1149                         FrameSpec animation_frame = p.tile.frames[0];
1150                         p.tile.texture = animation_frame.texture;
1151                 }
1152
1153                 for(u32 j = 0; j < p.vertices.size(); j++)
1154                 {
1155                         video::S3DVertex *vertex = &p.vertices[j];
1156                         // Note applyFacesShading second parameter is precalculated sqrt
1157                         // value for speed improvement
1158                         // Skip it for lightsources and top faces.
1159                         video::SColor &vc = vertex->Color;
1160                         if (!vc.getBlue()) {
1161                                 if (vertex->Normal.Y < -0.5) {
1162                                         applyFacesShading (vc, 0.447213);
1163                                 } else if (vertex->Normal.X > 0.5) {
1164                                         applyFacesShading (vc, 0.670820);
1165                                 } else if (vertex->Normal.X < -0.5) {
1166                                         applyFacesShading (vc, 0.670820);
1167                                 } else if (vertex->Normal.Z > 0.5) {
1168                                         applyFacesShading (vc, 0.836660);
1169                                 } else if (vertex->Normal.Z < -0.5) {
1170                                         applyFacesShading (vc, 0.836660);
1171                                 }
1172                         }
1173                         if(!m_enable_shaders)
1174                         {
1175                                 // - Classic lighting (shaders handle this by themselves)
1176                                 // Set initial real color and store for later updates
1177                                 u8 day = vc.getRed();
1178                                 u8 night = vc.getGreen();
1179                                 finalColorBlend(vc, day, night, 1000);
1180                                 if(day != night)
1181                                         m_daynight_diffs[i][j] = std::make_pair(day, night);
1182                         }
1183                 }
1184
1185                 // Create material
1186                 video::SMaterial material;
1187                 material.setFlag(video::EMF_LIGHTING, false);
1188                 material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1189                 material.setFlag(video::EMF_BILINEAR_FILTER, false);
1190                 material.setFlag(video::EMF_FOG_ENABLE, true);
1191                 material.setTexture(0, p.tile.texture);
1192
1193                 if (m_enable_shaders) {
1194                         material.MaterialType = m_shdrsrc->getShaderInfo(p.tile.shader_id).material;
1195                         p.tile.applyMaterialOptionsWithShaders(material);
1196                         if (p.tile.normal_texture) {
1197                                 material.setTexture(1, p.tile.normal_texture);
1198                         }
1199                         material.setTexture(2, p.tile.flags_texture);
1200                 } else {
1201                         p.tile.applyMaterialOptions(material);
1202                 }
1203
1204         // Create meshbuffer
1205         scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1206         // Set material
1207         buf->Material = material;
1208         // Add to mesh
1209         scene::SMesh *mesh = (scene::SMesh *)m_mesh;
1210         mesh->addMeshBuffer(buf);
1211         // Mesh grabbed it
1212         buf->drop();
1213         buf->append(&p.vertices[0], p.vertices.size(),
1214                 &p.indices[0], p.indices.size());
1215 }
1216         m_camera_offset = camera_offset;
1217
1218         /*
1219                 Do some stuff to the mesh
1220         */
1221
1222         translateMesh(m_mesh, intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
1223
1224         if (m_enable_shaders) {
1225                 scene::IMeshManipulator* meshmanip = m_gamedef->getSceneManager()->getMeshManipulator();
1226                 scene::IMesh* tangentMesh = meshmanip->createMeshWithTangents(m_mesh);
1227                 m_mesh->drop();
1228                 m_mesh = tangentMesh;
1229         }
1230
1231         if(m_mesh)
1232         {
1233 #if 0
1234                 // Usually 1-700 faces and 1-7 materials
1235                 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
1236                                 <<"and uses "<<m_mesh->getMeshBufferCount()
1237                                 <<" materials (meshbuffers)"<<std::endl;
1238 #endif
1239
1240                 // Use VBO for mesh (this just would set this for ever buffer)
1241                 // This will lead to infinite memory usage because or irrlicht.
1242                 //m_mesh->setHardwareMappingHint(scene::EHM_STATIC);
1243
1244                 /*
1245                         NOTE: If that is enabled, some kind of a queue to the main
1246                         thread should be made which would call irrlicht to delete
1247                         the hardware buffer and then delete the mesh
1248                 */
1249         }
1250
1251         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1252
1253         // Check if animation is required for this mesh
1254         m_has_animation =
1255                 !m_crack_materials.empty() ||
1256                 !m_daynight_diffs.empty() ||
1257                 !m_animation_tiles.empty();
1258 }
1259
1260 MapBlockMesh::~MapBlockMesh()
1261 {
1262         m_mesh->drop();
1263         m_mesh = NULL;
1264         delete m_minimap_mapblock;
1265 }
1266
1267 bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_ratio)
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                         std::ostringstream os;
1289                         os<<basename<<crack;
1290                         u32 new_texture_id = 0;
1291                         video::ITexture *new_texture =
1292                                 m_tsrc->getTextureForMesh(os.str(), &new_texture_id);
1293                         buf->getMaterial().setTexture(0, new_texture);
1294
1295                         // If the current material is also animated,
1296                         // update animation info
1297                         std::map<u32, TileSpec>::iterator anim_iter =
1298                                 m_animation_tiles.find(i->first);
1299                         if(anim_iter != m_animation_tiles.end()){
1300                                 TileSpec &tile = anim_iter->second;
1301                                 tile.texture = new_texture;
1302                                 tile.texture_id = new_texture_id;
1303                                 // force animation update
1304                                 m_animation_frames[i->first] = -1;
1305                         }
1306                 }
1307
1308                 m_last_crack = crack;
1309         }
1310
1311         // Texture animation
1312         for(std::map<u32, TileSpec>::iterator
1313                         i = m_animation_tiles.begin();
1314                         i != m_animation_tiles.end(); ++i)
1315         {
1316                 const TileSpec &tile = i->second;
1317                 // Figure out current frame
1318                 int frameoffset = m_animation_frame_offsets[i->first];
1319                 int frame = (int)(time * 1000 / tile.animation_frame_length_ms
1320                                 + frameoffset) % tile.animation_frame_count;
1321                 // If frame doesn't change, skip
1322                 if(frame == m_animation_frames[i->first])
1323                         continue;
1324
1325                 m_animation_frames[i->first] = frame;
1326
1327                 scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1328
1329                 FrameSpec animation_frame = tile.frames[frame];
1330                 buf->getMaterial().setTexture(0, animation_frame.texture);
1331                 if (m_enable_shaders) {
1332                         if (animation_frame.normal_texture) {
1333                                 buf->getMaterial().setTexture(1, animation_frame.normal_texture);
1334                         }
1335                         buf->getMaterial().setTexture(2, animation_frame.flags_texture);
1336                 }
1337         }
1338
1339         // Day-night transition
1340         if(!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio))
1341         {
1342                 for(std::map<u32, std::map<u32, std::pair<u8, u8> > >::iterator
1343                                 i = m_daynight_diffs.begin();
1344                                 i != m_daynight_diffs.end(); ++i)
1345                 {
1346                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1347                         video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
1348                         for(std::map<u32, std::pair<u8, u8 > >::iterator
1349                                         j = i->second.begin();
1350                                         j != i->second.end(); ++j)
1351                         {
1352                                 u8 day = j->second.first;
1353                                 u8 night = j->second.second;
1354                                 finalColorBlend(vertices[j->first].Color, day, night, daynight_ratio);
1355                         }
1356                 }
1357                 m_last_daynight_ratio = daynight_ratio;
1358         }
1359
1360         return true;
1361 }
1362
1363 void MapBlockMesh::updateCameraOffset(v3s16 camera_offset)
1364 {
1365         if (camera_offset != m_camera_offset) {
1366                 translateMesh(m_mesh, intToFloat(m_camera_offset-camera_offset, BS));
1367                 m_camera_offset = camera_offset;
1368         }
1369 }
1370
1371 /*
1372         MeshCollector
1373 */
1374
1375 void MeshCollector::append(const TileSpec &tile,
1376                 const video::S3DVertex *vertices, u32 numVertices,
1377                 const u16 *indices, u32 numIndices)
1378 {
1379         if (numIndices > 65535) {
1380                 dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1381                 return;
1382         }
1383
1384         PreMeshBuffer *p = NULL;
1385         for (u32 i = 0; i < prebuffers.size(); i++) {
1386                 PreMeshBuffer &pp = prebuffers[i];
1387                 if (pp.tile != tile)
1388                         continue;
1389                 if (pp.indices.size() + numIndices > 65535)
1390                         continue;
1391
1392                 p = &pp;
1393                 break;
1394         }
1395
1396         if (p == NULL) {
1397                 PreMeshBuffer pp;
1398                 pp.tile = tile;
1399                 prebuffers.push_back(pp);
1400                 p = &prebuffers[prebuffers.size() - 1];
1401         }
1402
1403         u32 vertex_count = p->vertices.size();
1404         for (u32 i = 0; i < numIndices; i++)    {
1405                 u32 j = indices[i] + vertex_count;
1406                 p->indices.push_back(j);
1407         }
1408
1409         for (u32 i = 0; i < numVertices; i++) {
1410                 video::S3DVertex vert(vertices[i].Pos, vertices[i].Normal,
1411                         vertices[i].Color, vertices[i].TCoords);
1412                 p->vertices.push_back(vert);
1413         }
1414 }
1415
1416 /*
1417         MeshCollector - for meshnodes and converted drawtypes.
1418 */
1419
1420 void MeshCollector::append(const TileSpec &tile,
1421                 const video::S3DVertex *vertices, u32 numVertices,
1422                 const u16 *indices, u32 numIndices,
1423                 v3f pos, video::SColor c)
1424 {
1425         if (numIndices > 65535) {
1426                 dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1427                 return;
1428         }
1429
1430         PreMeshBuffer *p = NULL;
1431         for (u32 i = 0; i < prebuffers.size(); i++) {
1432                 PreMeshBuffer &pp = prebuffers[i];
1433                 if(pp.tile != tile)
1434                         continue;
1435                 if(pp.indices.size() + numIndices > 65535)
1436                         continue;
1437
1438                 p = &pp;
1439                 break;
1440         }
1441
1442         if (p == NULL) {
1443                 PreMeshBuffer pp;
1444                 pp.tile = tile;
1445                 prebuffers.push_back(pp);
1446                 p = &prebuffers[prebuffers.size() - 1];
1447         }
1448
1449         u32 vertex_count = p->vertices.size();
1450         for (u32 i = 0; i < numIndices; i++) {
1451                 u32 j = indices[i] + vertex_count;
1452                 p->indices.push_back(j);
1453         }
1454
1455         for (u32 i = 0; i < numVertices; i++) {
1456                 video::S3DVertex vert(vertices[i].Pos + pos, vertices[i].Normal,
1457                         c, vertices[i].TCoords);
1458                 p->vertices.push_back(vert);
1459         }
1460 }