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