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