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