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