Performance fixes.
[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.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                 //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
697         static const u16 dir_to_tile[24 * 16] =
698         {
699                 // 0     +X    +Y    +Z           -Z    -Y    -X   ->   value=tile,rotation
700                    0,0,  2,0 , 0,0 , 4,0 ,  0,0,  5,0 , 1,0 , 3,0 ,  // rotate around y+ 0 - 3
701                    0,0,  4,0 , 0,3 , 3,0 ,  0,0,  2,0 , 1,1 , 5,0 ,
702                    0,0,  3,0 , 0,2 , 5,0 ,  0,0,  4,0 , 1,2 , 2,0 ,
703                    0,0,  5,0 , 0,1 , 2,0 ,  0,0,  3,0 , 1,3 , 4,0 ,
704
705                    0,0,  2,3 , 5,0 , 0,2 ,  0,0,  1,0 , 4,2 , 3,1 ,  // rotate around z+ 4 - 7
706                    0,0,  4,3 , 2,0 , 0,1 ,  0,0,  1,1 , 3,2 , 5,1 ,
707                    0,0,  3,3 , 4,0 , 0,0 ,  0,0,  1,2 , 5,2 , 2,1 ,
708                    0,0,  5,3 , 3,0 , 0,3 ,  0,0,  1,3 , 2,2 , 4,1 ,
709
710                    0,0,  2,1 , 4,2 , 1,2 ,  0,0,  0,0 , 5,0 , 3,3 ,  // rotate around z- 8 - 11
711                    0,0,  4,1 , 3,2 , 1,3 ,  0,0,  0,3 , 2,0 , 5,3 ,
712                    0,0,  3,1 , 5,2 , 1,0 ,  0,0,  0,2 , 4,0 , 2,3 ,
713                    0,0,  5,1 , 2,2 , 1,1 ,  0,0,  0,1 , 3,0 , 4,3 ,
714
715                    0,0,  0,3 , 3,3 , 4,1 ,  0,0,  5,3 , 2,3 , 1,3 ,  // rotate around x+ 12 - 15
716                    0,0,  0,2 , 5,3 , 3,1 ,  0,0,  2,3 , 4,3 , 1,0 ,
717                    0,0,  0,1 , 2,3 , 5,1 ,  0,0,  4,3 , 3,3 , 1,1 ,
718                    0,0,  0,0 , 4,3 , 2,1 ,  0,0,  3,3 , 5,3 , 1,2 ,
719
720                    0,0,  1,1 , 2,1 , 4,3 ,  0,0,  5,1 , 3,1 , 0,1 ,  // rotate around x- 16 - 19
721                    0,0,  1,2 , 4,1 , 3,3 ,  0,0,  2,1 , 5,1 , 0,0 ,
722                    0,0,  1,3 , 3,1 , 5,3 ,  0,0,  4,1 , 2,1 , 0,3 ,
723                    0,0,  1,0 , 5,1 , 2,3 ,  0,0,  3,1 , 4,1 , 0,2 ,
724
725                    0,0,  3,2 , 1,2 , 4,2 ,  0,0,  5,2 , 0,2 , 2,2 ,  // rotate around y- 20 - 23
726                    0,0,  5,2 , 1,3 , 3,2 ,  0,0,  2,2 , 0,1 , 4,2 ,
727                    0,0,  2,2 , 1,0 , 5,2 ,  0,0,  4,2 , 0,0 , 3,2 ,
728                    0,0,  4,2 , 1,1 , 2,2 ,  0,0,  3,2 , 0,3 , 5,2
729
730         };
731         u16 tile_index=facedir*16 + dir_i;
732         TileSpec spec = getNodeTileN(mn, p, dir_to_tile[tile_index], data);
733         spec.rotation=dir_to_tile[tile_index + 1];
734         spec.texture = data->m_gamedef->tsrc()->getTexture(spec.texture_id);
735         return spec;
736 }
737
738 static void getTileInfo(
739                 // Input:
740                 MeshMakeData *data,
741                 v3s16 p,
742                 v3s16 face_dir,
743                 // Output:
744                 bool &makes_face,
745                 v3s16 &p_corrected,
746                 v3s16 &face_dir_corrected,
747                 u16 *lights,
748                 TileSpec &tile,
749                 u8 &light_source
750         )
751 {
752         VoxelManipulator &vmanip = data->m_vmanip;
753         INodeDefManager *ndef = data->m_gamedef->ndef();
754         v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
755
756         MapNode n0 = vmanip.getNodeNoEx(blockpos_nodes + p);
757
758         // Don't even try to get n1 if n0 is already CONTENT_IGNORE
759         if (n0.getContent() == CONTENT_IGNORE ) {
760                 makes_face = false;
761                 return;
762         }
763         MapNode n1 = vmanip.getNodeNoEx(blockpos_nodes + p + face_dir);
764
765         // This is hackish
766         bool equivalent = false;
767         u8 mf = face_contents(n0.getContent(), n1.getContent(),
768                         &equivalent, ndef);
769
770         if(mf == 0)
771         {
772                 makes_face = false;
773                 return;
774         }
775
776         makes_face = true;
777
778         if(mf == 1)
779         {
780                 tile = getNodeTile(n0, p, face_dir, data);
781                 p_corrected = p;
782                 face_dir_corrected = face_dir;
783                 light_source = ndef->get(n0).light_source;
784         }
785         else
786         {
787                 tile = getNodeTile(n1, p + face_dir, -face_dir, data);
788                 p_corrected = p + face_dir;
789                 face_dir_corrected = -face_dir;
790                 light_source = ndef->get(n1).light_source;
791         }
792
793         // eg. water and glass
794         if(equivalent)
795                 tile.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
796
797         if(data->m_smooth_lighting == false)
798         {
799                 lights[0] = lights[1] = lights[2] = lights[3] =
800                                 getFaceLight(n0, n1, face_dir, ndef);
801         }
802         else
803         {
804                 v3s16 vertex_dirs[4];
805                 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
806                 for(u16 i=0; i<4; i++)
807                 {
808                         lights[i] = getSmoothLight(
809                                         blockpos_nodes + p_corrected,
810                                         vertex_dirs[i], data);
811                 }
812         }
813
814         return;
815 }
816
817 /*
818         startpos:
819         translate_dir: unit vector with only one of x, y or z
820         face_dir: unit vector with only one of x, y or z
821 */
822 static void updateFastFaceRow(
823                 MeshMakeData *data,
824                 v3s16 startpos,
825                 v3s16 translate_dir,
826                 v3f translate_dir_f,
827                 v3s16 face_dir,
828                 v3f face_dir_f,
829                 std::vector<FastFace> &dest)
830 {
831         v3s16 p = startpos;
832
833         u16 continuous_tiles_count = 0;
834
835         bool makes_face = false;
836         v3s16 p_corrected;
837         v3s16 face_dir_corrected;
838         u16 lights[4] = {0,0,0,0};
839         TileSpec tile;
840         u8 light_source = 0;
841         getTileInfo(data, p, face_dir,
842                         makes_face, p_corrected, face_dir_corrected,
843                         lights, tile, light_source);
844
845         for(u16 j=0; j<MAP_BLOCKSIZE; j++)
846         {
847                 // If tiling can be done, this is set to false in the next step
848                 bool next_is_different = true;
849
850                 v3s16 p_next;
851
852                 bool next_makes_face = false;
853                 v3s16 next_p_corrected;
854                 v3s16 next_face_dir_corrected;
855                 u16 next_lights[4] = {0,0,0,0};
856                 TileSpec next_tile;
857                 u8 next_light_source = 0;
858
859                 // If at last position, there is nothing to compare to and
860                 // the face must be drawn anyway
861                 if(j != MAP_BLOCKSIZE - 1)
862                 {
863                         p_next = p + translate_dir;
864
865                         getTileInfo(data, p_next, face_dir,
866                                         next_makes_face, next_p_corrected,
867                                         next_face_dir_corrected, next_lights,
868                                         next_tile, next_light_source);
869
870                         if(next_makes_face == makes_face
871                                         && next_p_corrected == p_corrected + translate_dir
872                                         && next_face_dir_corrected == face_dir_corrected
873                                         && next_lights[0] == lights[0]
874                                         && next_lights[1] == lights[1]
875                                         && next_lights[2] == lights[2]
876                                         && next_lights[3] == lights[3]
877                                         && next_tile == tile
878                                         && tile.rotation == 0
879                                         && next_light_source == light_source)
880                         {
881                                 next_is_different = false;
882                         }
883                         else{
884                                 /*if(makes_face){
885                                         g_profiler->add("Meshgen: diff: next_makes_face != makes_face",
886                                                         next_makes_face != makes_face ? 1 : 0);
887                                         g_profiler->add("Meshgen: diff: n_p_corr != p_corr + t_dir",
888                                                         (next_p_corrected != p_corrected + translate_dir) ? 1 : 0);
889                                         g_profiler->add("Meshgen: diff: next_f_dir_corr != f_dir_corr",
890                                                         next_face_dir_corrected != face_dir_corrected ? 1 : 0);
891                                         g_profiler->add("Meshgen: diff: next_lights[] != lights[]",
892                                                         (next_lights[0] != lights[0] ||
893                                                         next_lights[0] != lights[0] ||
894                                                         next_lights[0] != lights[0] ||
895                                                         next_lights[0] != lights[0]) ? 1 : 0);
896                                         g_profiler->add("Meshgen: diff: !(next_tile == tile)",
897                                                         !(next_tile == tile) ? 1 : 0);
898                                 }*/
899                         }
900                         /*g_profiler->add("Meshgen: Total faces checked", 1);
901                         if(makes_face)
902                                 g_profiler->add("Meshgen: Total makes_face checked", 1);*/
903                 } else {
904                         /*if(makes_face)
905                                 g_profiler->add("Meshgen: diff: last position", 1);*/
906                 }
907
908                 continuous_tiles_count++;
909
910                 if(next_is_different)
911                 {
912                         /*
913                                 Create a face if there should be one
914                         */
915                         if(makes_face)
916                         {
917                                 // Floating point conversion of the position vector
918                                 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
919                                 // Center point of face (kind of)
920                                 v3f sp = pf - ((f32)continuous_tiles_count / 2.0 - 0.5) * translate_dir_f;
921                                 if(continuous_tiles_count != 1)
922                                         sp += translate_dir_f;
923                                 v3f scale(1,1,1);
924
925                                 if(translate_dir.X != 0) {
926                                         scale.X = continuous_tiles_count;
927                                 }
928                                 if(translate_dir.Y != 0) {
929                                         scale.Y = continuous_tiles_count;
930                                 }
931                                 if(translate_dir.Z != 0) {
932                                         scale.Z = continuous_tiles_count;
933                                 }
934
935                                 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
936                                                 sp, face_dir_corrected, scale, light_source,
937                                                 dest);
938
939                                 g_profiler->avg("Meshgen: faces drawn by tiling", 0);
940                                 for(int i = 1; i < continuous_tiles_count; i++){
941                                         g_profiler->avg("Meshgen: faces drawn by tiling", 1);
942                                 }
943                         }
944
945                         continuous_tiles_count = 0;
946
947                         makes_face = next_makes_face;
948                         p_corrected = next_p_corrected;
949                         face_dir_corrected = next_face_dir_corrected;
950                         lights[0] = next_lights[0];
951                         lights[1] = next_lights[1];
952                         lights[2] = next_lights[2];
953                         lights[3] = next_lights[3];
954                         tile = next_tile;
955                         light_source = next_light_source;
956                 }
957
958                 p = p_next;
959         }
960 }
961
962 static void updateAllFastFaceRows(MeshMakeData *data,
963                 std::vector<FastFace> &dest)
964 {
965         /*
966                 Go through every y,z and get top(y+) faces in rows of x+
967         */
968         for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
969                 for(s16 z = 0; z < MAP_BLOCKSIZE; z++) {
970                         updateFastFaceRow(data,
971                                         v3s16(0,y,z),
972                                         v3s16(1,0,0), //dir
973                                         v3f  (1,0,0),
974                                         v3s16(0,1,0), //face dir
975                                         v3f  (0,1,0),
976                                         dest);
977                 }
978         }
979
980         /*
981                 Go through every x,y and get right(x+) faces in rows of z+
982         */
983         for(s16 x = 0; x < MAP_BLOCKSIZE; x++) {
984                 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
985                         updateFastFaceRow(data,
986                                         v3s16(x,y,0),
987                                         v3s16(0,0,1), //dir
988                                         v3f  (0,0,1),
989                                         v3s16(1,0,0), //face dir
990                                         v3f  (1,0,0),
991                                         dest);
992                 }
993         }
994
995         /*
996                 Go through every y,z and get back(z+) faces in rows of x+
997         */
998         for(s16 z = 0; z < MAP_BLOCKSIZE; z++) {
999                 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
1000                         updateFastFaceRow(data,
1001                                         v3s16(0,y,z),
1002                                         v3s16(1,0,0), //dir
1003                                         v3f  (1,0,0),
1004                                         v3s16(0,0,1), //face dir
1005                                         v3f  (0,0,1),
1006                                         dest);
1007                 }
1008         }
1009 }
1010
1011 /*
1012         MapBlockMesh
1013 */
1014
1015 MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
1016         m_mesh(new scene::SMesh()),
1017         m_gamedef(data->m_gamedef),
1018         m_animation_force_timer(0), // force initial animation
1019         m_last_crack(-1),
1020         m_crack_materials(),
1021         m_highlighted_materials(),
1022         m_last_daynight_ratio((u32) -1),
1023         m_daynight_diffs()
1024 {
1025         m_enable_shaders = g_settings->getBool("enable_shaders");
1026         m_enable_highlighting = g_settings->getBool("enable_node_highlighting");
1027
1028         // 4-21ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1029         // 24-155ms for MAP_BLOCKSIZE=32  (NOTE: probably outdated)
1030         //TimeTaker timer1("MapBlockMesh()");
1031
1032         std::vector<FastFace> fastfaces_new;
1033
1034         /*
1035                 We are including the faces of the trailing edges of the block.
1036                 This means that when something changes, the caller must
1037                 also update the meshes of the blocks at the leading edges.
1038
1039                 NOTE: This is the slowest part of this method.
1040         */
1041         {
1042                 // 4-23ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1043                 //TimeTaker timer2("updateAllFastFaceRows()");
1044                 updateAllFastFaceRows(data, fastfaces_new);
1045         }
1046         // End of slow part
1047
1048         /*
1049                 Convert FastFaces to MeshCollector
1050         */
1051
1052         MeshCollector collector;
1053
1054         {
1055                 // avg 0ms (100ms spikes when loading textures the first time)
1056                 // (NOTE: probably outdated)
1057                 //TimeTaker timer2("MeshCollector building");
1058
1059                 for(u32 i=0; i<fastfaces_new.size(); i++)
1060                 {
1061                         FastFace &f = fastfaces_new[i];
1062
1063                         const u16 indices[] = {0,1,2,2,3,0};
1064                         const u16 indices_alternate[] = {0,1,3,2,3,1};
1065
1066                         if(f.tile.texture == NULL)
1067                                 continue;
1068
1069                         const u16 *indices_p = indices;
1070
1071                         /*
1072                                 Revert triangles for nicer looking gradient if vertices
1073                                 1 and 3 have same color or 0 and 2 have different color.
1074                                 getRed() is the day color.
1075                         */
1076                         if(f.vertices[0].Color.getRed() != f.vertices[2].Color.getRed()
1077                                         || f.vertices[1].Color.getRed() == f.vertices[3].Color.getRed())
1078                                 indices_p = indices_alternate;
1079
1080                         collector.append(f.tile, f.vertices, 4, indices_p, 6);
1081                 }
1082         }
1083
1084         /*
1085                 Add special graphics:
1086                 - torches
1087                 - flowing water
1088                 - fences
1089                 - whatever
1090         */
1091
1092         mapblock_mesh_generate_special(data, collector);
1093
1094         m_highlight_mesh_color = data->m_highlight_mesh_color;
1095
1096         /*
1097                 Convert MeshCollector to SMesh
1098         */
1099         ITextureSource *tsrc = m_gamedef->tsrc();
1100         IShaderSource *shdrsrc = m_gamedef->getShaderSource();
1101
1102         for(u32 i = 0; i < collector.prebuffers.size(); i++)
1103         {
1104                 PreMeshBuffer &p = collector.prebuffers[i];
1105
1106                 // Generate animation data
1107                 // - Cracks
1108                 if(p.tile.material_flags & MATERIAL_FLAG_CRACK)
1109                 {
1110                         // Find the texture name plus ^[crack:N:
1111                         std::ostringstream os(std::ios::binary);
1112                         os<<tsrc->getTextureName(p.tile.texture_id)<<"^[crack";
1113                         if(p.tile.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1114                                 os<<"o";  // use ^[cracko
1115                         os<<":"<<(u32)p.tile.animation_frame_count<<":";
1116                         m_crack_materials.insert(std::make_pair(i, os.str()));
1117                         // Replace tile texture with the cracked one
1118                         p.tile.texture = tsrc->getTexture(
1119                                         os.str()+"0",
1120                                         &p.tile.texture_id);
1121                 }
1122                 // - Texture animation
1123                 if(p.tile.material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
1124                 {
1125                         // Add to MapBlockMesh in order to animate these tiles
1126                         m_animation_tiles[i] = p.tile;
1127                         m_animation_frames[i] = 0;
1128                         if(g_settings->getBool("desynchronize_mapblock_texture_animation")){
1129                                 // Get starting position from noise
1130                                 m_animation_frame_offsets[i] = 100000 * (2.0 + noise3d(
1131                                                 data->m_blockpos.X, data->m_blockpos.Y,
1132                                                 data->m_blockpos.Z, 0));
1133                         } else {
1134                                 // Play all synchronized
1135                                 m_animation_frame_offsets[i] = 0;
1136                         }
1137                         // Replace tile texture with the first animation frame
1138                         FrameSpec animation_frame = p.tile.frames[0];
1139                         p.tile.texture = animation_frame.texture;
1140                 }
1141
1142                 if(m_enable_highlighting && p.tile.material_flags & MATERIAL_FLAG_HIGHLIGHTED)
1143                         m_highlighted_materials.push_back(i);   
1144
1145                 for(u32 j = 0; j < p.vertices.size(); j++)
1146                 {
1147                         // Note applyFacesShading second parameter is precalculated sqrt
1148                         // value for speed improvement
1149                         // Skip it for lightsources and top faces.
1150                         video::SColor &vc = p.vertices[j].Color;
1151                         if (!vc.getBlue()) {
1152                                 if (p.vertices[j].Normal.Y < -0.5) {
1153                                         applyFacesShading (vc, 0.447213);
1154                                 } else if (p.vertices[j].Normal.X > 0.5) {
1155                                         applyFacesShading (vc, 0.670820);
1156                                 } else if (p.vertices[j].Normal.X < -0.5) {
1157                                         applyFacesShading (vc, 0.670820);
1158                                 } else if (p.vertices[j].Normal.Z > 0.5) {
1159                                         applyFacesShading (vc, 0.836660);
1160                                 } else if (p.vertices[j].Normal.Z < -0.5) {
1161                                         applyFacesShading (vc, 0.836660);
1162                                 }
1163                         }
1164                         if(!m_enable_shaders)
1165                         {
1166                                 // - Classic lighting (shaders handle this by themselves)
1167                                 // Set initial real color and store for later updates
1168                                 u8 day = vc.getRed();
1169                                 u8 night = vc.getGreen();
1170                                 finalColorBlend(vc, day, night, 1000);
1171                                 if(day != night)
1172                                         m_daynight_diffs[i][j] = std::make_pair(day, night);
1173                         }
1174                 }
1175
1176                 // Create material
1177                 video::SMaterial material;
1178                 material.setFlag(video::EMF_LIGHTING, false);
1179                 material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1180                 material.setFlag(video::EMF_BILINEAR_FILTER, false);
1181                 material.setFlag(video::EMF_FOG_ENABLE, true);
1182                 material.setTexture(0, p.tile.texture);
1183
1184                 if (p.tile.material_flags & MATERIAL_FLAG_HIGHLIGHTED) {
1185                         material.MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
1186                 } else {
1187                         if (m_enable_shaders) {
1188                                 material.MaterialType = shdrsrc->getShaderInfo(p.tile.shader_id).material;
1189                                 p.tile.applyMaterialOptionsWithShaders(material);
1190                                 if (p.tile.normal_texture) {
1191                                         material.setTexture(1, p.tile.normal_texture);
1192                                         material.setTexture(2, tsrc->getTexture("enable_img.png"));
1193                                 } else {
1194                                         material.setTexture(2, tsrc->getTexture("disable_img.png"));
1195                                 }
1196                         } else {
1197                                 p.tile.applyMaterialOptions(material);
1198                         }
1199                 }
1200
1201                 // Create meshbuffer
1202                 // This is a "Standard MeshBuffer",
1203                 // it's a typedeffed CMeshBuffer<video::S3DVertex>
1204                 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1205                 // Set material
1206                 buf->Material = material;
1207                 // Add to mesh
1208                 m_mesh->addMeshBuffer(buf);
1209                 // Mesh grabbed it
1210                 buf->drop();
1211                 buf->append(&p.vertices[0], p.vertices.size(),
1212                                 &p.indices[0], p.indices.size());
1213         }
1214
1215         m_camera_offset = camera_offset;
1216
1217         /*
1218                 Do some stuff to the mesh
1219         */
1220
1221         translateMesh(m_mesh, intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
1222
1223         if(m_mesh)
1224         {
1225 #if 0
1226                 // Usually 1-700 faces and 1-7 materials
1227                 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
1228                                 <<"and uses "<<m_mesh->getMeshBufferCount()
1229                                 <<" materials (meshbuffers)"<<std::endl;
1230 #endif
1231
1232                 // Use VBO for mesh (this just would set this for ever buffer)
1233                 // This will lead to infinite memory usage because or irrlicht.
1234                 //m_mesh->setHardwareMappingHint(scene::EHM_STATIC);
1235
1236                 /*
1237                         NOTE: If that is enabled, some kind of a queue to the main
1238                         thread should be made which would call irrlicht to delete
1239                         the hardware buffer and then delete the mesh
1240                 */
1241         }
1242
1243         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1244
1245         // Check if animation is required for this mesh
1246         m_has_animation =
1247                 !m_crack_materials.empty() ||
1248                 !m_daynight_diffs.empty() ||
1249                 !m_animation_tiles.empty() ||
1250                 !m_highlighted_materials.empty();
1251 }
1252
1253 MapBlockMesh::~MapBlockMesh()
1254 {
1255         m_mesh->drop();
1256         m_mesh = NULL;
1257 }
1258
1259 bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_ratio)
1260 {
1261
1262         if(!m_has_animation)
1263         {
1264                 m_animation_force_timer = 100000;
1265                 return false;
1266         }
1267
1268         m_animation_force_timer = myrand_range(5, 100);
1269
1270         // Cracks
1271         if(crack != m_last_crack)
1272         {
1273                 for(std::map<u32, std::string>::iterator
1274                                 i = m_crack_materials.begin();
1275                                 i != m_crack_materials.end(); i++)
1276                 {
1277                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1278                         std::string basename = i->second;
1279
1280                         // Create new texture name from original
1281                         ITextureSource *tsrc = m_gamedef->getTextureSource();
1282                         std::ostringstream os;
1283                         os<<basename<<crack;
1284                         u32 new_texture_id = 0;
1285                         video::ITexture *new_texture =
1286                                 tsrc->getTexture(os.str(), &new_texture_id);
1287                         buf->getMaterial().setTexture(0, new_texture);
1288
1289                         // If the current material is also animated,
1290                         // update animation info
1291                         std::map<u32, TileSpec>::iterator anim_iter =
1292                                 m_animation_tiles.find(i->first);
1293                         if(anim_iter != m_animation_tiles.end()){
1294                                 TileSpec &tile = anim_iter->second;
1295                                 tile.texture = new_texture;
1296                                 tile.texture_id = new_texture_id;
1297                                 // force animation update
1298                                 m_animation_frames[i->first] = -1;
1299                         }
1300                 }
1301
1302                 m_last_crack = crack;
1303         }
1304
1305         // Texture animation
1306         for(std::map<u32, TileSpec>::iterator
1307                         i = m_animation_tiles.begin();
1308                         i != m_animation_tiles.end(); i++)
1309         {
1310                 const TileSpec &tile = i->second;
1311                 // Figure out current frame
1312                 int frameoffset = m_animation_frame_offsets[i->first];
1313                 int frame = (int)(time * 1000 / tile.animation_frame_length_ms
1314                                 + frameoffset) % tile.animation_frame_count;
1315                 // If frame doesn't change, skip
1316                 if(frame == m_animation_frames[i->first])
1317                         continue;
1318
1319                 m_animation_frames[i->first] = frame;
1320
1321                 scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1322                 ITextureSource *tsrc = m_gamedef->getTextureSource();
1323
1324                 FrameSpec animation_frame = tile.frames[frame];
1325                 buf->getMaterial().setTexture(0, animation_frame.texture);
1326                 if (m_enable_shaders) {
1327                         if (animation_frame.normal_texture) {
1328                                 buf->getMaterial().setTexture(1, animation_frame.normal_texture);
1329                                 buf->getMaterial().setTexture(2, tsrc->getTexture("enable_img.png"));
1330                         } else {
1331                                 buf->getMaterial().setTexture(2, tsrc->getTexture("disable_img.png"));
1332                         }
1333                 }
1334         }
1335
1336         // Day-night transition
1337         if(!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio))
1338         {
1339                 for(std::map<u32, std::map<u32, std::pair<u8, u8> > >::iterator
1340                                 i = m_daynight_diffs.begin();
1341                                 i != m_daynight_diffs.end(); i++)
1342                 {
1343                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1344                         video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
1345                         for(std::map<u32, std::pair<u8, u8 > >::iterator
1346                                         j = i->second.begin();
1347                                         j != i->second.end(); j++)
1348                         {
1349                                 u32 vertexIndex = j->first;
1350                                 u8 day = j->second.first;
1351                                 u8 night = j->second.second;
1352                                 finalColorBlend(vertices[vertexIndex].Color,
1353                                                 day, night, daynight_ratio);
1354                         }
1355                 }
1356                 m_last_daynight_ratio = daynight_ratio;
1357         }
1358
1359         // Node highlighting
1360         if (m_enable_highlighting) {
1361                 u8 day = m_highlight_mesh_color.getRed();
1362                 u8 night = m_highlight_mesh_color.getGreen();   
1363                 video::SColor hc;
1364                 finalColorBlend(hc, day, night, daynight_ratio);
1365                 float sin_r = 0.07 * sin(1.5 * time);
1366                 float sin_g = 0.07 * sin(1.5 * time + irr::core::PI * 0.5);
1367                 float sin_b = 0.07 * sin(1.5 * time + irr::core::PI);
1368                 hc.setRed(core::clamp(core::round32(hc.getRed() * (0.8 + sin_r)), 0, 255));
1369                 hc.setGreen(core::clamp(core::round32(hc.getGreen() * (0.8 + sin_g)), 0, 255));
1370                 hc.setBlue(core::clamp(core::round32(hc.getBlue() * (0.8 + sin_b)), 0, 255));
1371
1372                 for(std::list<u32>::iterator
1373                         i = m_highlighted_materials.begin();
1374                         i != m_highlighted_materials.end(); i++)
1375                 {
1376                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(*i);
1377                         video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
1378                         for (u32 j = 0; j < buf->getVertexCount() ;j++)
1379                                 vertices[j].Color = hc;
1380                 }
1381         }
1382
1383         return true;
1384 }
1385
1386 void MapBlockMesh::updateCameraOffset(v3s16 camera_offset)
1387 {
1388         if (camera_offset != m_camera_offset) {
1389                 translateMesh(m_mesh, intToFloat(m_camera_offset-camera_offset, BS));
1390                 m_camera_offset = camera_offset;
1391         }
1392 }
1393
1394 /*
1395         MeshCollector
1396 */
1397
1398 void MeshCollector::append(const TileSpec &tile,
1399                 const video::S3DVertex *vertices, u32 numVertices,
1400                 const u16 *indices, u32 numIndices)
1401 {
1402         if(numIndices > 65535)
1403         {
1404                 dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1405                 return;
1406         }
1407
1408         PreMeshBuffer *p = NULL;
1409         for(u32 i=0; i<prebuffers.size(); i++)
1410         {
1411                 PreMeshBuffer &pp = prebuffers[i];
1412                 if(pp.tile != tile)
1413                         continue;
1414                 if(pp.indices.size() + numIndices > 65535)
1415                         continue;
1416
1417                 p = &pp;
1418                 break;
1419         }
1420
1421         if(p == NULL)
1422         {
1423                 PreMeshBuffer pp;
1424                 pp.tile = tile;
1425                 prebuffers.push_back(pp);
1426                 p = &prebuffers[prebuffers.size()-1];
1427         }
1428
1429         u32 vertex_count = p->vertices.size();
1430         for(u32 i=0; i<numIndices; i++)
1431         {
1432                 u32 j = indices[i] + vertex_count;
1433                 p->indices.push_back(j);
1434         }
1435         for(u32 i=0; i<numVertices; i++)
1436         {
1437                 p->vertices.push_back(vertices[i]);
1438         }
1439 }
1440
1441 /*
1442         MeshCollector - for meshnodes and converted drawtypes.
1443 */
1444
1445 void MeshCollector::append(const TileSpec &tile,
1446                 const video::S3DVertex *vertices, u32 numVertices,
1447                 const u16 *indices, u32 numIndices,
1448                 v3f pos, video::SColor c)
1449 {
1450         if(numIndices > 65535)
1451         {
1452                 dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1453                 return;
1454         }
1455
1456         PreMeshBuffer *p = NULL;
1457         for(u32 i=0; i<prebuffers.size(); i++)
1458         {
1459                 PreMeshBuffer &pp = prebuffers[i];
1460                 if(pp.tile != tile)
1461                         continue;
1462                 if(pp.indices.size() + numIndices > 65535)
1463                         continue;
1464
1465                 p = &pp;
1466                 break;
1467         }
1468
1469         if(p == NULL)
1470         {
1471                 PreMeshBuffer pp;
1472                 pp.tile = tile;
1473                 prebuffers.push_back(pp);
1474                 p = &prebuffers[prebuffers.size()-1];
1475         }
1476
1477         u32 vertex_count = p->vertices.size();
1478         for(u32 i=0; i<numIndices; i++)
1479         {
1480                 u32 j = indices[i] + vertex_count;
1481                 p->indices.push_back(j);
1482         }
1483         for(u32 i=0; i<numVertices; i++)
1484         {
1485                 video::S3DVertex vert = vertices[i];
1486                 vert.Pos += pos;
1487                 vert.Color = c;         
1488                 p->vertices.push_back(vert);
1489         }
1490 }