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