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