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