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