Move ContentFeatures to mapnode_contentfeatures.{h,cpp} and clean stuff
[oweals/minetest.git] / src / mapblock_mesh.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 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 General Public License as published by
7 the Free Software Foundation; either version 2 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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "mapblock_mesh.h"
21 #include "light.h"
22 #include "mapblock.h"
23 #include "map.h"
24 #include "main.h" // For g_settings and g_texturesource
25 #include "content_mapblock.h"
26 #include "settings.h"
27 #include "profiler.h"
28 #include "mapnode_contentfeatures.h"
29
30 void MeshMakeData::fill(u32 daynight_ratio, MapBlock *block)
31 {
32         m_daynight_ratio = daynight_ratio;
33         m_blockpos = block->getPos();
34
35         v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
36         
37         /*
38                 There is no harm not copying the TempMods of the neighbors
39                 because they are already copied to this block
40         */
41         m_temp_mods.clear();
42         block->copyTempMods(m_temp_mods);
43         
44         /*
45                 Copy data
46         */
47
48         // Allocate this block + neighbors
49         m_vmanip.clear();
50         m_vmanip.addArea(VoxelArea(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
51                         blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1)));
52
53         {
54                 //TimeTaker timer("copy central block data");
55                 // 0ms
56
57                 // Copy our data
58                 block->copyTo(m_vmanip);
59         }
60         {
61                 //TimeTaker timer("copy neighbor block data");
62                 // 0ms
63
64                 /*
65                         Copy neighbors. This is lightning fast.
66                         Copying only the borders would be *very* slow.
67                 */
68                 
69                 // Get map
70                 Map *map = block->getParent();
71
72                 for(u16 i=0; i<6; i++)
73                 {
74                         const v3s16 &dir = g_6dirs[i];
75                         v3s16 bp = m_blockpos + dir;
76                         MapBlock *b = map->getBlockNoCreateNoEx(bp);
77                         if(b)
78                                 b->copyTo(m_vmanip);
79                 }
80         }
81 }
82
83 /*
84         vertex_dirs: v3s16[4]
85 */
86 void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
87 {
88         /*
89                 If looked from outside the node towards the face, the corners are:
90                 0: bottom-right
91                 1: bottom-left
92                 2: top-left
93                 3: top-right
94         */
95         if(dir == v3s16(0,0,1))
96         {
97                 // If looking towards z+, this is the face that is behind
98                 // the center point, facing towards z+.
99                 vertex_dirs[0] = v3s16(-1,-1, 1);
100                 vertex_dirs[1] = v3s16( 1,-1, 1);
101                 vertex_dirs[2] = v3s16( 1, 1, 1);
102                 vertex_dirs[3] = v3s16(-1, 1, 1);
103         }
104         else if(dir == v3s16(0,0,-1))
105         {
106                 // faces towards Z-
107                 vertex_dirs[0] = v3s16( 1,-1,-1);
108                 vertex_dirs[1] = v3s16(-1,-1,-1);
109                 vertex_dirs[2] = v3s16(-1, 1,-1);
110                 vertex_dirs[3] = v3s16( 1, 1,-1);
111         }
112         else if(dir == v3s16(1,0,0))
113         {
114                 // faces towards X+
115                 vertex_dirs[0] = v3s16( 1,-1, 1);
116                 vertex_dirs[1] = v3s16( 1,-1,-1);
117                 vertex_dirs[2] = v3s16( 1, 1,-1);
118                 vertex_dirs[3] = v3s16( 1, 1, 1);
119         }
120         else if(dir == v3s16(-1,0,0))
121         {
122                 // faces towards X-
123                 vertex_dirs[0] = v3s16(-1,-1,-1);
124                 vertex_dirs[1] = v3s16(-1,-1, 1);
125                 vertex_dirs[2] = v3s16(-1, 1, 1);
126                 vertex_dirs[3] = v3s16(-1, 1,-1);
127         }
128         else if(dir == v3s16(0,1,0))
129         {
130                 // faces towards Y+ (assume Z- as "down" in texture)
131                 vertex_dirs[0] = v3s16( 1, 1,-1);
132                 vertex_dirs[1] = v3s16(-1, 1,-1);
133                 vertex_dirs[2] = v3s16(-1, 1, 1);
134                 vertex_dirs[3] = v3s16( 1, 1, 1);
135         }
136         else if(dir == v3s16(0,-1,0))
137         {
138                 // faces towards Y- (assume Z+ as "down" in texture)
139                 vertex_dirs[0] = v3s16( 1,-1, 1);
140                 vertex_dirs[1] = v3s16(-1,-1, 1);
141                 vertex_dirs[2] = v3s16(-1,-1,-1);
142                 vertex_dirs[3] = v3s16( 1,-1,-1);
143         }
144 }
145
146 video::SColor MapBlock_LightColor(u8 alpha, u8 light)
147 {
148 #if 0
149         return video::SColor(alpha,light,light,light);
150 #endif
151         //return video::SColor(alpha,light,light,MYMAX(0, (s16)light-25)+25);
152         /*return video::SColor(alpha,light,light,MYMAX(0,
153                         pow((float)light/255.0, 0.8)*255.0));*/
154 #if 1
155         // Emphase blue a bit in darker places
156         float lim = 80;
157         float power = 0.8;
158         if(light > lim)
159                 return video::SColor(alpha,light,light,light);
160         else
161                 return video::SColor(alpha,light,light,MYMAX(0,
162                                 pow((float)light/lim, power)*lim));
163 #endif
164 }
165
166 struct FastFace
167 {
168         TileSpec tile;
169         video::S3DVertex vertices[4]; // Precalculated vertices
170 };
171
172 void makeFastFace(TileSpec tile, u8 li0, u8 li1, u8 li2, u8 li3, v3f p,
173                 v3s16 dir, v3f scale, v3f posRelative_f,
174                 core::array<FastFace> &dest)
175 {
176         FastFace face;
177         
178         // Position is at the center of the cube.
179         v3f pos = p * BS;
180         posRelative_f *= BS;
181
182         v3f vertex_pos[4];
183         v3s16 vertex_dirs[4];
184         getNodeVertexDirs(dir, vertex_dirs);
185         for(u16 i=0; i<4; i++)
186         {
187                 vertex_pos[i] = v3f(
188                                 BS/2*vertex_dirs[i].X,
189                                 BS/2*vertex_dirs[i].Y,
190                                 BS/2*vertex_dirs[i].Z
191                 );
192         }
193
194         for(u16 i=0; i<4; i++)
195         {
196                 vertex_pos[i].X *= scale.X;
197                 vertex_pos[i].Y *= scale.Y;
198                 vertex_pos[i].Z *= scale.Z;
199                 vertex_pos[i] += pos + posRelative_f;
200         }
201
202         f32 abs_scale = 1.;
203         if     (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
204         else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
205         else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
206
207         v3f zerovector = v3f(0,0,0);
208         
209         u8 alpha = tile.alpha;
210         /*u8 alpha = 255;
211         if(tile.id == TILE_WATER)
212                 alpha = WATER_ALPHA;*/
213
214         float x0 = tile.texture.pos.X;
215         float y0 = tile.texture.pos.Y;
216         float w = tile.texture.size.X;
217         float h = tile.texture.size.Y;
218
219         /*video::SColor c = MapBlock_LightColor(alpha, li);
220
221         face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0), c,
222                         core::vector2d<f32>(x0+w*abs_scale, y0+h));
223         face.vertices[1] = video::S3DVertex(vertex_pos[1], v3f(0,1,0), c,
224                         core::vector2d<f32>(x0, y0+h));
225         face.vertices[2] = video::S3DVertex(vertex_pos[2], v3f(0,1,0), c,
226                         core::vector2d<f32>(x0, y0));
227         face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0), c,
228                         core::vector2d<f32>(x0+w*abs_scale, y0));*/
229
230         face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0),
231                         MapBlock_LightColor(alpha, li0),
232                         core::vector2d<f32>(x0+w*abs_scale, y0+h));
233         face.vertices[1] = video::S3DVertex(vertex_pos[1], v3f(0,1,0),
234                         MapBlock_LightColor(alpha, li1),
235                         core::vector2d<f32>(x0, y0+h));
236         face.vertices[2] = video::S3DVertex(vertex_pos[2], v3f(0,1,0),
237                         MapBlock_LightColor(alpha, li2),
238                         core::vector2d<f32>(x0, y0));
239         face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0),
240                         MapBlock_LightColor(alpha, li3),
241                         core::vector2d<f32>(x0+w*abs_scale, y0));
242
243         face.tile = tile;
244         //DEBUG
245         //f->tile = TILE_STONE;
246         
247         dest.push_back(face);
248 }
249         
250 /*
251         Gets node tile from any place relative to block.
252         Returns TILE_NODE if doesn't exist or should not be drawn.
253 */
254 TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
255                 NodeModMap &temp_mods)
256 {
257         TileSpec spec;
258         spec = mn.getTile(face_dir);
259         
260         /*
261                 Check temporary modifications on this node
262         */
263         /*core::map<v3s16, NodeMod>::Node *n;
264         n = m_temp_mods.find(p);
265         // If modified
266         if(n != NULL)
267         {
268                 struct NodeMod mod = n->getValue();*/
269         NodeMod mod;
270         if(temp_mods.get(p, &mod))
271         {
272                 if(mod.type == NODEMOD_CHANGECONTENT)
273                 {
274                         MapNode mn2(mod.param);
275                         spec = mn2.getTile(face_dir);
276                 }
277                 if(mod.type == NODEMOD_CRACK)
278                 {
279                         /*
280                                 Get texture id, translate it to name, append stuff to
281                                 name, get texture id
282                         */
283
284                         // Get original texture name
285                         u32 orig_id = spec.texture.id;
286                         std::string orig_name = g_texturesource->getTextureName(orig_id);
287
288                         // Create new texture name
289                         std::ostringstream os;
290                         os<<orig_name<<"^[crack"<<mod.param;
291
292                         // Get new texture
293                         u32 new_id = g_texturesource->getTextureId(os.str());
294                         
295                         /*dstream<<"MapBlock::getNodeTile(): Switching from "
296                                         <<orig_name<<" to "<<os.str()<<" ("
297                                         <<orig_id<<" to "<<new_id<<")"<<std::endl;*/
298                         
299                         spec.texture = g_texturesource->getTexture(new_id);
300                 }
301         }
302         
303         return spec;
304 }
305
306 content_t getNodeContent(v3s16 p, MapNode mn, NodeModMap &temp_mods)
307 {
308         /*
309                 Check temporary modifications on this node
310         */
311         /*core::map<v3s16, NodeMod>::Node *n;
312         n = m_temp_mods.find(p);
313         // If modified
314         if(n != NULL)
315         {
316                 struct NodeMod mod = n->getValue();*/
317         NodeMod mod;
318         if(temp_mods.get(p, &mod))
319         {
320                 if(mod.type == NODEMOD_CHANGECONTENT)
321                 {
322                         // Overrides content
323                         return mod.param;
324                 }
325                 if(mod.type == NODEMOD_CRACK)
326                 {
327                         /*
328                                 Content doesn't change.
329                                 
330                                 face_contents works just like it should, because
331                                 there should not be faces between differently cracked
332                                 nodes.
333
334                                 If a semi-transparent node is cracked in front an
335                                 another one, it really doesn't matter whether there
336                                 is a cracked face drawn in between or not.
337                         */
338                 }
339         }
340
341         return mn.getContent();
342 }
343
344 v3s16 dirs8[8] = {
345         v3s16(0,0,0),
346         v3s16(0,0,1),
347         v3s16(0,1,0),
348         v3s16(0,1,1),
349         v3s16(1,0,0),
350         v3s16(1,1,0),
351         v3s16(1,0,1),
352         v3s16(1,1,1),
353 };
354
355 // Calculate lighting at the XYZ- corner of p
356 u8 getSmoothLight(v3s16 p, VoxelManipulator &vmanip, u32 daynight_ratio)
357 {
358         u16 ambient_occlusion = 0;
359         u16 light = 0;
360         u16 light_count = 0;
361         for(u32 i=0; i<8; i++)
362         {
363                 MapNode n = vmanip.getNodeNoEx(p - dirs8[i]);
364                 if(content_features(n).param_type == CPT_LIGHT
365                                 // Fast-style leaves look better this way
366                                 && content_features(n).solidness != 2)
367                 {
368                         light += decode_light(n.getLightBlend(daynight_ratio));
369                         light_count++;
370                 }
371                 else
372                 {
373                         if(n.getContent() != CONTENT_IGNORE)
374                                 ambient_occlusion++;
375                 }
376         }
377
378         if(light_count == 0)
379                 return 255;
380         
381         light /= light_count;
382
383         if(ambient_occlusion > 4)
384         {
385                 ambient_occlusion -= 4;
386                 light = (float)light / ((float)ambient_occlusion * 0.5 + 1.0);
387         }
388
389         return light;
390 }
391
392 // Calculate lighting at the given corner of p
393 u8 getSmoothLight(v3s16 p, v3s16 corner,
394                 VoxelManipulator &vmanip, u32 daynight_ratio)
395 {
396         if(corner.X == 1) p.X += 1;
397         else              assert(corner.X == -1);
398         if(corner.Y == 1) p.Y += 1;
399         else              assert(corner.Y == -1);
400         if(corner.Z == 1) p.Z += 1;
401         else              assert(corner.Z == -1);
402         
403         return getSmoothLight(p, vmanip, daynight_ratio);
404 }
405
406 void getTileInfo(
407                 // Input:
408                 v3s16 blockpos_nodes,
409                 v3s16 p,
410                 v3s16 face_dir,
411                 u32 daynight_ratio,
412                 VoxelManipulator &vmanip,
413                 NodeModMap &temp_mods,
414                 bool smooth_lighting,
415                 // Output:
416                 bool &makes_face,
417                 v3s16 &p_corrected,
418                 v3s16 &face_dir_corrected,
419                 u8 *lights,
420                 TileSpec &tile
421         )
422 {
423         MapNode n0 = vmanip.getNodeNoEx(blockpos_nodes + p);
424         MapNode n1 = vmanip.getNodeNoEx(blockpos_nodes + p + face_dir);
425         TileSpec tile0 = getNodeTile(n0, p, face_dir, temp_mods);
426         TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir, temp_mods);
427         
428         // This is hackish
429         content_t content0 = getNodeContent(p, n0, temp_mods);
430         content_t content1 = getNodeContent(p + face_dir, n1, temp_mods);
431         bool equivalent = false;
432         u8 mf = face_contents(content0, content1, &equivalent);
433
434         if(mf == 0)
435         {
436                 makes_face = false;
437                 return;
438         }
439
440         makes_face = true;
441         
442         if(mf == 1)
443         {
444                 tile = tile0;
445                 p_corrected = p;
446                 face_dir_corrected = face_dir;
447         }
448         else
449         {
450                 tile = tile1;
451                 p_corrected = p + face_dir;
452                 face_dir_corrected = -face_dir;
453         }
454         
455         // eg. water and glass
456         if(equivalent)
457                 tile.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
458         
459         if(smooth_lighting == false)
460         {
461                 lights[0] = lights[1] = lights[2] = lights[3] =
462                                 decode_light(getFaceLight(daynight_ratio, n0, n1, face_dir));
463         }
464         else
465         {
466                 v3s16 vertex_dirs[4];
467                 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
468                 for(u16 i=0; i<4; i++)
469                 {
470                         lights[i] = getSmoothLight(blockpos_nodes + p_corrected,
471                                         vertex_dirs[i], vmanip, daynight_ratio);
472                 }
473         }
474         
475         return;
476 }
477
478 /*
479         startpos:
480         translate_dir: unit vector with only one of x, y or z
481         face_dir: unit vector with only one of x, y or z
482 */
483 void updateFastFaceRow(
484                 u32 daynight_ratio,
485                 v3f posRelative_f,
486                 v3s16 startpos,
487                 u16 length,
488                 v3s16 translate_dir,
489                 v3f translate_dir_f,
490                 v3s16 face_dir,
491                 v3f face_dir_f,
492                 core::array<FastFace> &dest,
493                 NodeModMap &temp_mods,
494                 VoxelManipulator &vmanip,
495                 v3s16 blockpos_nodes,
496                 bool smooth_lighting)
497 {
498         v3s16 p = startpos;
499         
500         u16 continuous_tiles_count = 0;
501         
502         bool makes_face = false;
503         v3s16 p_corrected;
504         v3s16 face_dir_corrected;
505         u8 lights[4] = {0,0,0,0};
506         TileSpec tile;
507         getTileInfo(blockpos_nodes, p, face_dir, daynight_ratio,
508                         vmanip, temp_mods, smooth_lighting,
509                         makes_face, p_corrected, face_dir_corrected, lights, tile);
510
511         for(u16 j=0; j<length; j++)
512         {
513                 // If tiling can be done, this is set to false in the next step
514                 bool next_is_different = true;
515                 
516                 v3s16 p_next;
517                 
518                 bool next_makes_face = false;
519                 v3s16 next_p_corrected;
520                 v3s16 next_face_dir_corrected;
521                 u8 next_lights[4] = {0,0,0,0};
522                 TileSpec next_tile;
523                 
524                 // If at last position, there is nothing to compare to and
525                 // the face must be drawn anyway
526                 if(j != length - 1)
527                 {
528                         p_next = p + translate_dir;
529                         
530                         getTileInfo(blockpos_nodes, p_next, face_dir, daynight_ratio,
531                                         vmanip, temp_mods, smooth_lighting,
532                                         next_makes_face, next_p_corrected,
533                                         next_face_dir_corrected, next_lights,
534                                         next_tile);
535                         
536                         if(next_makes_face == makes_face
537                                         && next_p_corrected == p_corrected + translate_dir
538                                         && next_face_dir_corrected == face_dir_corrected
539                                         && next_lights[0] == lights[0]
540                                         && next_lights[1] == lights[1]
541                                         && next_lights[2] == lights[2]
542                                         && next_lights[3] == lights[3]
543                                         && next_tile == tile)
544                         {
545                                 next_is_different = false;
546                         }
547                         else{
548                                 /*if(makes_face){
549                                         g_profiler->add("Meshgen: diff: next_makes_face != makes_face",
550                                                         next_makes_face != makes_face ? 1 : 0);
551                                         g_profiler->add("Meshgen: diff: n_p_corr != p_corr + t_dir",
552                                                         (next_p_corrected != p_corrected + translate_dir) ? 1 : 0);
553                                         g_profiler->add("Meshgen: diff: next_f_dir_corr != f_dir_corr",
554                                                         next_face_dir_corrected != face_dir_corrected ? 1 : 0);
555                                         g_profiler->add("Meshgen: diff: next_lights[] != lights[]",
556                                                         (next_lights[0] != lights[0] ||
557                                                         next_lights[0] != lights[0] ||
558                                                         next_lights[0] != lights[0] ||
559                                                         next_lights[0] != lights[0]) ? 1 : 0);
560                                         g_profiler->add("Meshgen: diff: !(next_tile == tile)",
561                                                         !(next_tile == tile) ? 1 : 0);
562                                 }*/
563                         }
564                         /*g_profiler->add("Meshgen: Total faces checked", 1);
565                         if(makes_face)
566                                 g_profiler->add("Meshgen: Total makes_face checked", 1);*/
567                 } else {
568                         /*if(makes_face)
569                                 g_profiler->add("Meshgen: diff: last position", 1);*/
570                 }
571
572                 continuous_tiles_count++;
573                 
574                 // This is set to true if the texture doesn't allow more tiling
575                 bool end_of_texture = false;
576                 /*
577                         If there is no texture, it can be tiled infinitely.
578                         If tiled==0, it means the texture can be tiled infinitely.
579                         Otherwise check tiled agains continuous_tiles_count.
580                 */
581                 if(tile.texture.atlas != NULL && tile.texture.tiled != 0)
582                 {
583                         if(tile.texture.tiled <= continuous_tiles_count)
584                                 end_of_texture = true;
585                 }
586                 
587                 // Do this to disable tiling textures
588                 //end_of_texture = true; //DEBUG
589                 
590                 if(next_is_different || end_of_texture)
591                 {
592                         /*
593                                 Create a face if there should be one
594                         */
595                         if(makes_face)
596                         {
597                                 // Floating point conversion of the position vector
598                                 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
599                                 // Center point of face (kind of)
600                                 v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
601                                 if(continuous_tiles_count != 1)
602                                         sp += translate_dir_f;
603                                 v3f scale(1,1,1);
604
605                                 if(translate_dir.X != 0)
606                                 {
607                                         scale.X = continuous_tiles_count;
608                                 }
609                                 if(translate_dir.Y != 0)
610                                 {
611                                         scale.Y = continuous_tiles_count;
612                                 }
613                                 if(translate_dir.Z != 0)
614                                 {
615                                         scale.Z = continuous_tiles_count;
616                                 }
617                                 
618                                 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
619                                                 sp, face_dir_corrected, scale,
620                                                 posRelative_f, dest);
621                                 
622                                 g_profiler->avg("Meshgen: faces drawn by tiling", 0);
623                                 for(int i=1; i<continuous_tiles_count; i++){
624                                         g_profiler->avg("Meshgen: faces drawn by tiling", 1);
625                                 }
626                         }
627
628                         continuous_tiles_count = 0;
629                         
630                         makes_face = next_makes_face;
631                         p_corrected = next_p_corrected;
632                         face_dir_corrected = next_face_dir_corrected;
633                         lights[0] = next_lights[0];
634                         lights[1] = next_lights[1];
635                         lights[2] = next_lights[2];
636                         lights[3] = next_lights[3];
637                         tile = next_tile;
638                 }
639                 
640                 p = p_next;
641         }
642 }
643
644 scene::SMesh* makeMapBlockMesh(MeshMakeData *data)
645 {
646         // 4-21ms for MAP_BLOCKSIZE=16
647         // 24-155ms for MAP_BLOCKSIZE=32
648         //TimeTaker timer1("makeMapBlockMesh()");
649
650         core::array<FastFace> fastfaces_new;
651
652         v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE;
653         
654         // floating point conversion
655         v3f posRelative_f(blockpos_nodes.X, blockpos_nodes.Y, blockpos_nodes.Z);
656         
657         /*
658                 Some settings
659         */
660         //bool new_style_water = g_settings->getBool("new_style_water");
661         //bool new_style_leaves = g_settings->getBool("new_style_leaves");
662         bool smooth_lighting = g_settings->getBool("smooth_lighting");
663         
664         /*
665                 We are including the faces of the trailing edges of the block.
666                 This means that when something changes, the caller must
667                 also update the meshes of the blocks at the leading edges.
668
669                 NOTE: This is the slowest part of this method.
670         */
671         
672         {
673                 // 4-23ms for MAP_BLOCKSIZE=16
674                 //TimeTaker timer2("updateMesh() collect");
675
676                 /*
677                         Go through every y,z and get top(y+) faces in rows of x+
678                 */
679                 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
680                         for(s16 z=0; z<MAP_BLOCKSIZE; z++){
681                                 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
682                                                 v3s16(0,y,z), MAP_BLOCKSIZE,
683                                                 v3s16(1,0,0), //dir
684                                                 v3f  (1,0,0),
685                                                 v3s16(0,1,0), //face dir
686                                                 v3f  (0,1,0),
687                                                 fastfaces_new,
688                                                 data->m_temp_mods,
689                                                 data->m_vmanip,
690                                                 blockpos_nodes,
691                                                 smooth_lighting);
692                         }
693                 }
694                 /*
695                         Go through every x,y and get right(x+) faces in rows of z+
696                 */
697                 for(s16 x=0; x<MAP_BLOCKSIZE; x++){
698                         for(s16 y=0; y<MAP_BLOCKSIZE; y++){
699                                 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
700                                                 v3s16(x,y,0), MAP_BLOCKSIZE,
701                                                 v3s16(0,0,1),
702                                                 v3f  (0,0,1),
703                                                 v3s16(1,0,0),
704                                                 v3f  (1,0,0),
705                                                 fastfaces_new,
706                                                 data->m_temp_mods,
707                                                 data->m_vmanip,
708                                                 blockpos_nodes,
709                                                 smooth_lighting);
710                         }
711                 }
712                 /*
713                         Go through every y,z and get back(z+) faces in rows of x+
714                 */
715                 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
716                         for(s16 y=0; y<MAP_BLOCKSIZE; y++){
717                                 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
718                                                 v3s16(0,y,z), MAP_BLOCKSIZE,
719                                                 v3s16(1,0,0),
720                                                 v3f  (1,0,0),
721                                                 v3s16(0,0,1),
722                                                 v3f  (0,0,1),
723                                                 fastfaces_new,
724                                                 data->m_temp_mods,
725                                                 data->m_vmanip,
726                                                 blockpos_nodes,
727                                                 smooth_lighting);
728                         }
729                 }
730         }
731
732         // End of slow part
733
734         /*
735                 Convert FastFaces to SMesh
736         */
737
738         MeshCollector collector;
739
740         if(fastfaces_new.size() > 0)
741         {
742                 // avg 0ms (100ms spikes when loading textures the first time)
743                 //TimeTaker timer2("updateMesh() mesh building");
744
745                 video::SMaterial material;
746                 material.setFlag(video::EMF_LIGHTING, false);
747                 material.setFlag(video::EMF_BACK_FACE_CULLING, true);
748                 material.setFlag(video::EMF_BILINEAR_FILTER, false);
749                 material.setFlag(video::EMF_FOG_ENABLE, true);
750                 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
751                 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE);
752                 material.MaterialType
753                                 = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
754
755                 for(u32 i=0; i<fastfaces_new.size(); i++)
756                 {
757                         FastFace &f = fastfaces_new[i];
758
759                         const u16 indices[] = {0,1,2,2,3,0};
760                         const u16 indices_alternate[] = {0,1,3,2,3,1};
761                         
762                         video::ITexture *texture = f.tile.texture.atlas;
763                         if(texture == NULL)
764                                 continue;
765
766                         material.setTexture(0, texture);
767                         
768                         f.tile.applyMaterialOptions(material);
769
770                         const u16 *indices_p = indices;
771                         
772                         /*
773                                 Revert triangles for nicer looking gradient if vertices
774                                 1 and 3 have same color or 0 and 2 have different color.
775                         */
776                         if(f.vertices[0].Color != f.vertices[2].Color
777                                         || f.vertices[1].Color == f.vertices[3].Color)
778                                 indices_p = indices_alternate;
779                         
780                         collector.append(material, f.vertices, 4, indices_p, 6);
781                 }
782         }
783
784         /*
785                 Add special graphics:
786                 - torches
787                 - flowing water
788                 - fences
789                 - whatever
790         */
791
792         mapblock_mesh_generate_special(data, collector);
793         
794         /*
795                 Add stuff from collector to mesh
796         */
797         
798         scene::SMesh *mesh_new = NULL;
799         mesh_new = new scene::SMesh();
800         
801         collector.fillMesh(mesh_new);
802
803         /*
804                 Do some stuff to the mesh
805         */
806
807         mesh_new->recalculateBoundingBox();
808
809         /*
810                 Delete new mesh if it is empty
811         */
812
813         if(mesh_new->getMeshBufferCount() == 0)
814         {
815                 mesh_new->drop();
816                 mesh_new = NULL;
817         }
818
819         if(mesh_new)
820         {
821 #if 0
822                 // Usually 1-700 faces and 1-7 materials
823                 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
824                                 <<"and uses "<<mesh_new->getMeshBufferCount()
825                                 <<" materials (meshbuffers)"<<std::endl;
826 #endif
827
828                 // Use VBO for mesh (this just would set this for ever buffer)
829                 // This will lead to infinite memory usage because or irrlicht.
830                 //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
831
832                 /*
833                         NOTE: If that is enabled, some kind of a queue to the main
834                         thread should be made which would call irrlicht to delete
835                         the hardware buffer and then delete the mesh
836                 */
837         }
838
839         return mesh_new;
840         
841         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
842 }
843