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