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