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