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