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