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