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