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