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