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