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