Fix i18n of some strings.
[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         spec.texture = data->m_gamedef->tsrc()->getTexture(spec.texture.id);
721         return spec;
722 }
723
724 static void getTileInfo(
725                 // Input:
726                 MeshMakeData *data,
727                 v3s16 p,
728                 v3s16 face_dir,
729                 // Output:
730                 bool &makes_face,
731                 v3s16 &p_corrected,
732                 v3s16 &face_dir_corrected,
733                 u16 *lights,
734                 TileSpec &tile,
735                 u8 &light_source
736         )
737 {
738         VoxelManipulator &vmanip = data->m_vmanip;
739         INodeDefManager *ndef = data->m_gamedef->ndef();
740         v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
741
742         MapNode n0 = vmanip.getNodeNoEx(blockpos_nodes + p);
743         MapNode n1 = vmanip.getNodeNoEx(blockpos_nodes + p + face_dir);
744         TileSpec tile0 = getNodeTile(n0, p, face_dir, data);
745         TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir, data);
746         
747         // This is hackish
748         bool equivalent = false;
749         u8 mf = face_contents(n0.getContent(), n1.getContent(),
750                         &equivalent, ndef);
751
752         if(mf == 0)
753         {
754                 makes_face = false;
755                 return;
756         }
757
758         makes_face = true;
759         
760         if(mf == 1)
761         {
762                 tile = tile0;
763                 p_corrected = p;
764                 face_dir_corrected = face_dir;
765                 light_source = ndef->get(n0).light_source;
766         }
767         else
768         {
769                 tile = tile1;
770                 p_corrected = p + face_dir;
771                 face_dir_corrected = -face_dir;
772                 light_source = ndef->get(n1).light_source;
773         }
774         
775         // eg. water and glass
776         if(equivalent)
777                 tile.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
778
779         if(data->m_smooth_lighting == false)
780         {
781                 lights[0] = lights[1] = lights[2] = lights[3] =
782                                 getFaceLight(n0, n1, face_dir, data);
783         }
784         else
785         {
786                 v3s16 vertex_dirs[4];
787                 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
788                 for(u16 i=0; i<4; i++)
789                 {
790                         lights[i] = getSmoothLight(
791                                         blockpos_nodes + p_corrected,
792                                         vertex_dirs[i], data);
793                 }
794         }
795         
796         return;
797 }
798
799 /*
800         startpos:
801         translate_dir: unit vector with only one of x, y or z
802         face_dir: unit vector with only one of x, y or z
803 */
804 static void updateFastFaceRow(
805                 MeshMakeData *data,
806                 v3s16 startpos,
807                 v3s16 translate_dir,
808                 v3f translate_dir_f,
809                 v3s16 face_dir,
810                 v3f face_dir_f,
811                 std::vector<FastFace> &dest)
812 {
813         v3s16 p = startpos;
814         
815         u16 continuous_tiles_count = 0;
816         
817         bool makes_face = false;
818         v3s16 p_corrected;
819         v3s16 face_dir_corrected;
820         u16 lights[4] = {0,0,0,0};
821         TileSpec tile;
822         u8 light_source = 0;
823         getTileInfo(data, p, face_dir, 
824                         makes_face, p_corrected, face_dir_corrected,
825                         lights, tile, light_source);
826
827         for(u16 j=0; j<MAP_BLOCKSIZE; j++)
828         {
829                 // If tiling can be done, this is set to false in the next step
830                 bool next_is_different = true;
831                 
832                 v3s16 p_next;
833                 
834                 bool next_makes_face = false;
835                 v3s16 next_p_corrected;
836                 v3s16 next_face_dir_corrected;
837                 u16 next_lights[4] = {0,0,0,0};
838                 TileSpec next_tile;
839                 u8 next_light_source = 0;
840                 
841                 // If at last position, there is nothing to compare to and
842                 // the face must be drawn anyway
843                 if(j != MAP_BLOCKSIZE - 1)
844                 {
845                         p_next = p + translate_dir;
846                         
847                         getTileInfo(data, p_next, face_dir,
848                                         next_makes_face, next_p_corrected,
849                                         next_face_dir_corrected, next_lights,
850                                         next_tile, next_light_source);
851                         
852                         if(next_makes_face == makes_face
853                                         && next_p_corrected == p_corrected + translate_dir
854                                         && next_face_dir_corrected == face_dir_corrected
855                                         && next_lights[0] == lights[0]
856                                         && next_lights[1] == lights[1]
857                                         && next_lights[2] == lights[2]
858                                         && next_lights[3] == lights[3]
859                                         && next_tile == tile
860                                         && tile.rotation == 0
861                                         && next_light_source == light_source)
862                         {
863                                 next_is_different = false;
864                         }
865                         else{
866                                 /*if(makes_face){
867                                         g_profiler->add("Meshgen: diff: next_makes_face != makes_face",
868                                                         next_makes_face != makes_face ? 1 : 0);
869                                         g_profiler->add("Meshgen: diff: n_p_corr != p_corr + t_dir",
870                                                         (next_p_corrected != p_corrected + translate_dir) ? 1 : 0);
871                                         g_profiler->add("Meshgen: diff: next_f_dir_corr != f_dir_corr",
872                                                         next_face_dir_corrected != face_dir_corrected ? 1 : 0);
873                                         g_profiler->add("Meshgen: diff: next_lights[] != lights[]",
874                                                         (next_lights[0] != lights[0] ||
875                                                         next_lights[0] != lights[0] ||
876                                                         next_lights[0] != lights[0] ||
877                                                         next_lights[0] != lights[0]) ? 1 : 0);
878                                         g_profiler->add("Meshgen: diff: !(next_tile == tile)",
879                                                         !(next_tile == tile) ? 1 : 0);
880                                 }*/
881                         }
882                         /*g_profiler->add("Meshgen: Total faces checked", 1);
883                         if(makes_face)
884                                 g_profiler->add("Meshgen: Total makes_face checked", 1);*/
885                 } else {
886                         /*if(makes_face)
887                                 g_profiler->add("Meshgen: diff: last position", 1);*/
888                 }
889
890                 continuous_tiles_count++;
891                 
892                 // This is set to true if the texture doesn't allow more tiling
893                 bool end_of_texture = false;
894                 /*
895                         If there is no texture, it can be tiled infinitely.
896                         If tiled==0, it means the texture can be tiled infinitely.
897                         Otherwise check tiled agains continuous_tiles_count.
898                 */
899                 if(tile.texture.atlas != NULL && tile.texture.tiled != 0)
900                 {
901                         if(tile.texture.tiled <= continuous_tiles_count)
902                                 end_of_texture = true;
903                 }
904                 
905                 // Do this to disable tiling textures
906                 //end_of_texture = true; //DEBUG
907                 
908                 if(next_is_different || end_of_texture)
909                 {
910                         /*
911                                 Create a face if there should be one
912                         */
913                         if(makes_face)
914                         {
915                                 // Floating point conversion of the position vector
916                                 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
917                                 // Center point of face (kind of)
918                                 v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
919                                 if(continuous_tiles_count != 1)
920                                         sp += translate_dir_f;
921                                 v3f scale(1,1,1);
922
923                                 if(translate_dir.X != 0)
924                                 {
925                                         scale.X = continuous_tiles_count;
926                                 }
927                                 if(translate_dir.Y != 0)
928                                 {
929                                         scale.Y = continuous_tiles_count;
930                                 }
931                                 if(translate_dir.Z != 0)
932                                 {
933                                         scale.Z = continuous_tiles_count;
934                                 }
935                                 
936                                 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
937                                                 sp, face_dir_corrected, scale, light_source,
938                                                 dest);
939                                 
940                                 g_profiler->avg("Meshgen: faces drawn by tiling", 0);
941                                 for(int i=1; i<continuous_tiles_count; i++){
942                                         g_profiler->avg("Meshgen: faces drawn by tiling", 1);
943                                 }
944                         }
945
946                         continuous_tiles_count = 0;
947                         
948                         makes_face = next_makes_face;
949                         p_corrected = next_p_corrected;
950                         face_dir_corrected = next_face_dir_corrected;
951                         lights[0] = next_lights[0];
952                         lights[1] = next_lights[1];
953                         lights[2] = next_lights[2];
954                         lights[3] = next_lights[3];
955                         tile = next_tile;
956                         light_source = next_light_source;
957                 }
958                 
959                 p = p_next;
960         }
961 }
962
963 static void updateAllFastFaceRows(MeshMakeData *data,
964                 std::vector<FastFace> &dest)
965 {
966         /*
967                 Go through every y,z and get top(y+) faces in rows of x+
968         */
969         for(s16 y=0; y<MAP_BLOCKSIZE; y++){
970                 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
971                         updateFastFaceRow(data,
972                                         v3s16(0,y,z),
973                                         v3s16(1,0,0), //dir
974                                         v3f  (1,0,0),
975                                         v3s16(0,1,0), //face dir
976                                         v3f  (0,1,0),
977                                         dest);
978                 }
979         }
980
981         /*
982                 Go through every x,y and get right(x+) faces in rows of z+
983         */
984         for(s16 x=0; x<MAP_BLOCKSIZE; x++){
985                 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
986                         updateFastFaceRow(data,
987                                         v3s16(x,y,0),
988                                         v3s16(0,0,1), //dir
989                                         v3f  (0,0,1),
990                                         v3s16(1,0,0), //face dir
991                                         v3f  (1,0,0),
992                                         dest);
993                 }
994         }
995
996         /*
997                 Go through every y,z and get back(z+) faces in rows of x+
998         */
999         for(s16 z=0; z<MAP_BLOCKSIZE; z++){
1000                 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
1001                         updateFastFaceRow(data,
1002                                         v3s16(0,y,z),
1003                                         v3s16(1,0,0), //dir
1004                                         v3f  (1,0,0),
1005                                         v3s16(0,0,1), //face dir
1006                                         v3f  (0,0,1),
1007                                         dest);
1008                 }
1009         }
1010 }
1011
1012 /*
1013         MapBlockMesh
1014 */
1015
1016 MapBlockMesh::MapBlockMesh(MeshMakeData *data):
1017         m_mesh(new scene::SMesh()),
1018         m_gamedef(data->m_gamedef),
1019         m_animation_force_timer(0), // force initial animation
1020         m_last_crack(-1),
1021         m_crack_materials(),
1022         m_last_daynight_ratio((u32) -1),
1023         m_daynight_diffs()
1024 {
1025         // 4-21ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1026         // 24-155ms for MAP_BLOCKSIZE=32  (NOTE: probably outdated)
1027         //TimeTaker timer1("MapBlockMesh()");
1028
1029         std::vector<FastFace> fastfaces_new;
1030
1031         /*
1032                 We are including the faces of the trailing edges of the block.
1033                 This means that when something changes, the caller must
1034                 also update the meshes of the blocks at the leading edges.
1035
1036                 NOTE: This is the slowest part of this method.
1037         */
1038         {
1039                 // 4-23ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1040                 //TimeTaker timer2("updateAllFastFaceRows()");
1041                 updateAllFastFaceRows(data, fastfaces_new);
1042         }
1043         // End of slow part
1044
1045         /*
1046                 Convert FastFaces to MeshCollector
1047         */
1048
1049         MeshCollector collector;
1050
1051         {
1052                 // avg 0ms (100ms spikes when loading textures the first time)
1053                 // (NOTE: probably outdated)
1054                 //TimeTaker timer2("MeshCollector building");
1055
1056                 for(u32 i=0; i<fastfaces_new.size(); i++)
1057                 {
1058                         FastFace &f = fastfaces_new[i];
1059
1060                         const u16 indices[] = {0,1,2,2,3,0};
1061                         const u16 indices_alternate[] = {0,1,3,2,3,1};
1062                         
1063                         if(f.tile.texture.atlas == NULL)
1064                                 continue;
1065
1066                         const u16 *indices_p = indices;
1067                         
1068                         /*
1069                                 Revert triangles for nicer looking gradient if vertices
1070                                 1 and 3 have same color or 0 and 2 have different color.
1071                                 getRed() is the day color.
1072                         */
1073                         if(f.vertices[0].Color.getRed() != f.vertices[2].Color.getRed()
1074                                         || f.vertices[1].Color.getRed() == f.vertices[3].Color.getRed())
1075                                 indices_p = indices_alternate;
1076                         
1077                         collector.append(f.tile, f.vertices, 4, indices_p, 6);
1078                 }
1079         }
1080
1081         /*
1082                 Add special graphics:
1083                 - torches
1084                 - flowing water
1085                 - fences
1086                 - whatever
1087         */
1088
1089         mapblock_mesh_generate_special(data, collector);
1090         
1091
1092         /*
1093                 Convert MeshCollector to SMesh
1094                 Also store animation info
1095         */
1096         bool enable_shaders = (g_settings->getS32("enable_shaders") > 0);
1097         video::E_MATERIAL_TYPE shadermat1 = m_gamedef->getShaderSource()->
1098                         getShader("test_shader_1").material;
1099         video::E_MATERIAL_TYPE shadermat2 = m_gamedef->getShaderSource()->
1100                         getShader("test_shader_2").material;
1101         video::E_MATERIAL_TYPE shadermat3 = m_gamedef->getShaderSource()->
1102                         getShader("test_shader_3").material;
1103         for(u32 i = 0; i < collector.prebuffers.size(); i++)
1104         {
1105                 PreMeshBuffer &p = collector.prebuffers[i];
1106                 /*dstream<<"p.vertices.size()="<<p.vertices.size()
1107                                 <<", p.indices.size()="<<p.indices.size()
1108                                 <<std::endl;*/
1109
1110                 // Generate animation data
1111                 // - Cracks
1112                 if(p.tile.material_flags & MATERIAL_FLAG_CRACK)
1113                 {
1114                         ITextureSource *tsrc = data->m_gamedef->tsrc();
1115                         std::string crack_basename = tsrc->getTextureName(p.tile.texture.id);
1116                         if(p.tile.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1117                                 crack_basename += "^[cracko";
1118                         else
1119                                 crack_basename += "^[crack";
1120                         m_crack_materials.insert(std::make_pair(i, crack_basename));
1121                 }
1122                 // - Texture animation
1123                 if(p.tile.material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
1124                 {
1125                         ITextureSource *tsrc = data->m_gamedef->tsrc();
1126                         // Add to MapBlockMesh in order to animate these tiles
1127                         m_animation_tiles[i] = p.tile;
1128                         m_animation_frames[i] = 0;
1129                         if(g_settings->getBool("desynchronize_mapblock_texture_animation")){
1130                                 // Get starting position from noise
1131                                 m_animation_frame_offsets[i] = 100000 * (2.0 + noise3d(
1132                                                 data->m_blockpos.X, data->m_blockpos.Y,
1133                                                 data->m_blockpos.Z, 0));
1134                         } else {
1135                                 // Play all synchronized
1136                                 m_animation_frame_offsets[i] = 0;
1137                         }
1138                         // Replace tile texture with the first animation frame
1139                         std::ostringstream os(std::ios::binary);
1140                         os<<tsrc->getTextureName(p.tile.texture.id);
1141                         os<<"^[verticalframe:"<<(int)p.tile.animation_frame_count<<":0";
1142                         p.tile.texture = tsrc->getTexture(os.str());
1143                 }
1144                 // - Classic lighting (shaders handle this by themselves)
1145                 if(!enable_shaders)
1146                 {
1147                         for(u32 j = 0; j < p.vertices.size(); j++)
1148                         {
1149                                 video::SColor &vc = p.vertices[j].Color;
1150                                 // Set initial real color and store for later updates
1151                                 u8 day = vc.getRed();
1152                                 u8 night = vc.getGreen();
1153                                 finalColorBlend(vc, day, night, 1000);
1154                                 if(day != night)
1155                                         m_daynight_diffs[i][j] = std::make_pair(day, night);
1156                                 // Brighten topside (no shaders)
1157                                 if(p.vertices[j].Normal.Y > 0.5)
1158                                 {
1159                                         vc.setRed  (srgb_linear_multiply(vc.getRed(),   1.3, 255.0));
1160                                         vc.setGreen(srgb_linear_multiply(vc.getGreen(), 1.3, 255.0));
1161                                         vc.setBlue (srgb_linear_multiply(vc.getBlue(),  1.3, 255.0));
1162                                 }
1163                         }
1164                 }
1165
1166                 // Create material
1167                 video::SMaterial material;
1168                 material.setFlag(video::EMF_LIGHTING, false);
1169                 material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1170                 material.setFlag(video::EMF_BILINEAR_FILTER, false);
1171                 material.setFlag(video::EMF_FOG_ENABLE, true);
1172                 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
1173                 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE);
1174                 material.MaterialType
1175                                 = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
1176                 material.setTexture(0, p.tile.texture.atlas);
1177                 if(enable_shaders)
1178                         p.tile.applyMaterialOptionsWithShaders(material, shadermat1, shadermat2, shadermat3);
1179                 else
1180                         p.tile.applyMaterialOptions(material);
1181
1182                 // Create meshbuffer
1183
1184                 // This is a "Standard MeshBuffer",
1185                 // it's a typedeffed CMeshBuffer<video::S3DVertex>
1186                 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1187                 // Set material
1188                 buf->Material = material;
1189                 // Add to mesh
1190                 m_mesh->addMeshBuffer(buf);
1191                 // Mesh grabbed it
1192                 buf->drop();
1193                 buf->append(&p.vertices[0], p.vertices.size(),
1194                                 &p.indices[0], p.indices.size());
1195         }
1196
1197         /*
1198                 Do some stuff to the mesh
1199         */
1200
1201         translateMesh(m_mesh, intToFloat(data->m_blockpos * MAP_BLOCKSIZE, BS));
1202
1203         if(m_mesh)
1204         {
1205 #if 0
1206                 // Usually 1-700 faces and 1-7 materials
1207                 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
1208                                 <<"and uses "<<m_mesh->getMeshBufferCount()
1209                                 <<" materials (meshbuffers)"<<std::endl;
1210 #endif
1211
1212                 // Use VBO for mesh (this just would set this for ever buffer)
1213                 // This will lead to infinite memory usage because or irrlicht.
1214                 //m_mesh->setHardwareMappingHint(scene::EHM_STATIC);
1215
1216                 /*
1217                         NOTE: If that is enabled, some kind of a queue to the main
1218                         thread should be made which would call irrlicht to delete
1219                         the hardware buffer and then delete the mesh
1220                 */
1221         }
1222         
1223         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1224
1225         // Check if animation is required for this mesh
1226         m_has_animation =
1227                 !m_crack_materials.empty() ||
1228                 !m_daynight_diffs.empty() ||
1229                 !m_animation_tiles.empty();
1230 }
1231
1232 MapBlockMesh::~MapBlockMesh()
1233 {
1234         m_mesh->drop();
1235         m_mesh = NULL;
1236 }
1237
1238 bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_ratio)
1239 {
1240         if(!m_has_animation)
1241         {
1242                 m_animation_force_timer = 100000;
1243                 return false;
1244         }
1245
1246         m_animation_force_timer = myrand_range(5, 100);
1247
1248         // Cracks
1249         if(crack != m_last_crack)
1250         {
1251                 for(std::map<u32, std::string>::iterator
1252                                 i = m_crack_materials.begin();
1253                                 i != m_crack_materials.end(); i++)
1254                 {
1255                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1256                         std::string basename = i->second;
1257
1258                         // Create new texture name from original
1259                         ITextureSource *tsrc = m_gamedef->getTextureSource();
1260                         std::ostringstream os;
1261                         os<<basename<<crack;
1262                         AtlasPointer ap = tsrc->getTexture(os.str());
1263                         buf->getMaterial().setTexture(0, ap.atlas);
1264                 }
1265
1266                 m_last_crack = crack;
1267         }
1268         
1269         // Texture animation
1270         for(std::map<u32, TileSpec>::iterator
1271                         i = m_animation_tiles.begin();
1272                         i != m_animation_tiles.end(); i++)
1273         {
1274                 const TileSpec &tile = i->second;
1275                 // Figure out current frame
1276                 int frameoffset = m_animation_frame_offsets[i->first];
1277                 int frame = (int)(time * 1000 / tile.animation_frame_length_ms
1278                                 + frameoffset) % tile.animation_frame_count;
1279                 // If frame doesn't change, skip
1280                 if(frame == m_animation_frames[i->first])
1281                         continue;
1282
1283                 m_animation_frames[i->first] = frame;
1284
1285                 scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1286                 ITextureSource *tsrc = m_gamedef->getTextureSource();
1287
1288                 // Create new texture name from original
1289                 std::ostringstream os(std::ios::binary);
1290                 os<<tsrc->getTextureName(tile.texture.id);
1291                 os<<"^[verticalframe:"<<(int)tile.animation_frame_count<<":"<<frame;
1292                 // Set the texture
1293                 AtlasPointer ap = tsrc->getTexture(os.str());
1294                 buf->getMaterial().setTexture(0, ap.atlas);
1295         }
1296
1297         // Day-night transition
1298         if(daynight_ratio != m_last_daynight_ratio)
1299         {
1300                 for(std::map<u32, std::map<u32, std::pair<u8, u8> > >::iterator
1301                                 i = m_daynight_diffs.begin();
1302                                 i != m_daynight_diffs.end(); i++)
1303                 {
1304                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1305                         video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
1306                         for(std::map<u32, std::pair<u8, u8 > >::iterator
1307                                         j = i->second.begin();
1308                                         j != i->second.end(); j++)
1309                         {
1310                                 u32 vertexIndex = j->first;
1311                                 u8 day = j->second.first;
1312                                 u8 night = j->second.second;
1313                                 finalColorBlend(vertices[vertexIndex].Color,
1314                                                 day, night, daynight_ratio);
1315                                 // Brighten topside (no shaders)
1316                                 if(vertices[vertexIndex].Normal.Y > 0.5)
1317                                 {
1318                                         video::SColor &vc = vertices[vertexIndex].Color;
1319                                         vc.setRed  (srgb_linear_multiply(vc.getRed(),   1.3, 255.0));
1320                                         vc.setGreen(srgb_linear_multiply(vc.getGreen(), 1.3, 255.0));
1321                                         vc.setBlue (srgb_linear_multiply(vc.getBlue(),  1.3, 255.0));
1322                                 }
1323                         }
1324                 }
1325                 m_last_daynight_ratio = daynight_ratio;
1326         }
1327
1328         return true;
1329 }
1330
1331 /*
1332         MeshCollector
1333 */
1334
1335 void MeshCollector::append(const TileSpec &tile,
1336                 const video::S3DVertex *vertices, u32 numVertices,
1337                 const u16 *indices, u32 numIndices)
1338 {
1339         if(numIndices > 65535)
1340         {
1341                 dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1342                 return;
1343         }
1344
1345         PreMeshBuffer *p = NULL;
1346         for(u32 i=0; i<prebuffers.size(); i++)
1347         {
1348                 PreMeshBuffer &pp = prebuffers[i];
1349                 if(pp.tile != tile)
1350                         continue;
1351                 if(pp.indices.size() + numIndices > 65535)
1352                         continue;
1353
1354                 p = &pp;
1355                 break;
1356         }
1357
1358         if(p == NULL)
1359         {
1360                 PreMeshBuffer pp;
1361                 pp.tile = tile;
1362                 prebuffers.push_back(pp);
1363                 p = &prebuffers[prebuffers.size()-1];
1364         }
1365
1366         u32 vertex_count = p->vertices.size();
1367         for(u32 i=0; i<numIndices; i++)
1368         {
1369                 u32 j = indices[i] + vertex_count;
1370                 p->indices.push_back(j);
1371         }
1372         for(u32 i=0; i<numVertices; i++)
1373         {
1374                 p->vertices.push_back(vertices[i]);
1375         }
1376 }