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