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