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