]> git.lizzy.rs Git - minetest.git/blob - src/mapblock_mesh.cpp
Disable word wrap in vertical texts in main menu
[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_profiler
25 #include "profiler.h"
26 #include "nodedef.h"
27 #include "gamedef.h"
28 #include "mesh.h"
29 #include "content_mapblock.h"
30
31 /*
32         MeshMakeData
33 */
34
35 MeshMakeData::MeshMakeData(IGameDef *gamedef):
36         m_vmanip(),
37         m_blockpos(-1337,-1337,-1337),
38         m_crack_pos_relative(-1337, -1337, -1337),
39         m_smooth_lighting(false),
40         m_gamedef(gamedef)
41 {}
42
43 void MeshMakeData::fill(MapBlock *block)
44 {
45         m_blockpos = block->getPos();
46
47         v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
48         
49         /*
50                 Copy data
51         */
52
53         // Allocate this block + neighbors
54         m_vmanip.clear();
55         m_vmanip.addArea(VoxelArea(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
56                         blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1)));
57
58         {
59                 //TimeTaker timer("copy central block data");
60                 // 0ms
61
62                 // Copy our data
63                 block->copyTo(m_vmanip);
64         }
65         {
66                 //TimeTaker timer("copy neighbor block data");
67                 // 0ms
68
69                 /*
70                         Copy neighbors. This is lightning fast.
71                         Copying only the borders would be *very* slow.
72                 */
73                 
74                 // Get map
75                 Map *map = block->getParent();
76
77                 for(u16 i=0; i<6; i++)
78                 {
79                         const v3s16 &dir = g_6dirs[i];
80                         v3s16 bp = m_blockpos + dir;
81                         MapBlock *b = map->getBlockNoCreateNoEx(bp);
82                         if(b)
83                                 b->copyTo(m_vmanip);
84                 }
85         }
86 }
87
88 void MeshMakeData::fillSingleNode(MapNode *node)
89 {
90         m_blockpos = v3s16(0,0,0);
91         
92         v3s16 blockpos_nodes = v3s16(0,0,0);
93         VoxelArea area(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
94                         blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1));
95         s32 volume = area.getVolume();
96         s32 our_node_index = area.index(1,1,1);
97
98         // Allocate this block + neighbors
99         m_vmanip.clear();
100         m_vmanip.addArea(area);
101
102         // Fill in data
103         MapNode *data = new MapNode[volume];
104         for(s32 i = 0; i < volume; i++)
105         {
106                 if(i == our_node_index)
107                 {
108                         data[i] = *node;
109                 }
110                 else
111                 {
112                         data[i] = MapNode(CONTENT_AIR, LIGHT_MAX, 0);
113                 }
114         }
115         m_vmanip.copyFrom(data, area, area.MinEdge, area.MinEdge, area.getExtent());
116         delete[] data;
117 }
118
119 void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
120 {
121         if(crack_level >= 0)
122                 m_crack_pos_relative = crack_pos - m_blockpos*MAP_BLOCKSIZE;
123 }
124
125 void MeshMakeData::setSmoothLighting(bool smooth_lighting)
126 {
127         m_smooth_lighting = smooth_lighting;
128 }
129
130 /*
131         Light and vertex color functions
132 */
133
134 /*
135         Calculate non-smooth lighting at interior of node.
136         Single light bank.
137 */
138 static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
139                 MeshMakeData *data)
140 {
141         INodeDefManager *ndef = data->m_gamedef->ndef();
142         u8 light = n.getLight(bank, ndef);
143
144         while(increment > 0)
145         {
146                 light = undiminish_light(light);
147                 --increment;
148         }
149         while(increment < 0)
150         {
151                 light = diminish_light(light);
152                 ++increment;
153         }
154
155         return decode_light(light);
156 }
157
158 /*
159         Calculate non-smooth lighting at interior of node.
160         Both light banks.
161 */
162 u16 getInteriorLight(MapNode n, s32 increment, MeshMakeData *data)
163 {
164         u16 day = getInteriorLight(LIGHTBANK_DAY, n, increment, data);
165         u16 night = getInteriorLight(LIGHTBANK_NIGHT, n, increment, data);
166         return day | (night << 8);
167 }
168
169 /*
170         Calculate non-smooth lighting at face of node.
171         Single light bank.
172 */
173 static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
174                 v3s16 face_dir, MeshMakeData *data)
175 {
176         INodeDefManager *ndef = data->m_gamedef->ndef();
177
178         u8 light;
179         u8 l1 = n.getLight(bank, ndef);
180         u8 l2 = n2.getLight(bank, ndef);
181         if(l1 > l2)
182                 light = l1;
183         else
184                 light = l2;
185
186         // Make some nice difference to different sides
187
188         // This makes light come from a corner
189         /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
190                 light = diminish_light(diminish_light(light));
191         else if(face_dir.X == -1 || face_dir.Z == -1)
192                 light = diminish_light(light);*/
193
194         // All neighboring faces have different shade (like in minecraft)
195         if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
196                 light = diminish_light(diminish_light(light));
197         else if(face_dir.Z == 1 || face_dir.Z == -1)
198                 light = diminish_light(light);
199
200         return decode_light(light);
201 }
202
203 /*
204         Calculate non-smooth lighting at face of node.
205         Both light banks.
206 */
207 u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, MeshMakeData *data)
208 {
209         u16 day = getFaceLight(LIGHTBANK_DAY, n, n2, face_dir, data);
210         u16 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, face_dir, data);
211         return day | (night << 8);
212 }
213
214 /*
215         Calculate smooth lighting at the XYZ- corner of p.
216         Single light bank.
217 */
218 static u8 getSmoothLight(enum LightBank bank, v3s16 p, MeshMakeData *data)
219 {
220         static v3s16 dirs8[8] = {
221                 v3s16(0,0,0),
222                 v3s16(0,0,1),
223                 v3s16(0,1,0),
224                 v3s16(0,1,1),
225                 v3s16(1,0,0),
226                 v3s16(1,1,0),
227                 v3s16(1,0,1),
228                 v3s16(1,1,1),
229         };
230
231         INodeDefManager *ndef = data->m_gamedef->ndef();
232
233         u16 ambient_occlusion = 0;
234         u16 light = 0;
235         u16 light_count = 0;
236         for(u32 i=0; i<8; i++)
237         {
238                 MapNode n = data->m_vmanip.getNodeNoEx(p - dirs8[i]);
239                 const ContentFeatures &f = ndef->get(n);
240                 // Check f.solidness because fast-style leaves look
241                 // better this way
242                 if(f.param_type == CPT_LIGHT && f.solidness != 2)
243                 {
244                         light += decode_light(n.getLight(bank, ndef));
245                         light_count++;
246                 }
247                 else if(n.getContent() != CONTENT_IGNORE)
248                 {
249                         ambient_occlusion++;
250                 }
251         }
252
253         if(light_count == 0)
254                 return 255;
255         
256         light /= light_count;
257
258         if(ambient_occlusion > 4)
259         {
260                 ambient_occlusion -= 4;
261                 light = (float)light / ((float)ambient_occlusion * 0.5 + 1.0);
262         }
263
264         return light;
265 }
266
267 /*
268         Calculate smooth lighting at the XYZ- corner of p.
269         Both light banks.
270 */
271 static u16 getSmoothLight(v3s16 p, MeshMakeData *data)
272 {
273         u16 day = getSmoothLight(LIGHTBANK_DAY, p, data);
274         u16 night = getSmoothLight(LIGHTBANK_NIGHT, p, data);
275         return day | (night << 8);
276 }
277
278 /*
279         Calculate smooth lighting at the given corner of p.
280         Both light banks.
281 */
282 u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data)
283 {
284         if(corner.X == 1) p.X += 1;
285         else              assert(corner.X == -1);
286         if(corner.Y == 1) p.Y += 1;
287         else              assert(corner.Y == -1);
288         if(corner.Z == 1) p.Z += 1;
289         else              assert(corner.Z == -1);
290         
291         return getSmoothLight(p, data);
292 }
293
294 /*
295         Converts from day + night color values (0..255)
296         and a given daynight_ratio to the final SColor shown on screen.
297 */
298 static void finalColorBlend(video::SColor& result,
299                 u8 day, u8 night, u32 daynight_ratio)
300 {
301         s32 rg = (day * daynight_ratio + night * (1000-daynight_ratio)) / 1000;
302         s32 b = rg;
303
304         // Moonlight is blue
305         b += (day - night) / 13;
306         rg -= (day - night) / 23;
307
308         // Emphase blue a bit in darker places
309         // Each entry of this array represents a range of 8 blue levels
310         static u8 emphase_blue_when_dark[32] = {
311                 1, 4, 6, 6, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0,
312                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
313         };
314         if(b < 0)
315                 b = 0;
316         if(b > 255)
317                 b = 255;
318         b += emphase_blue_when_dark[b / 8];
319
320         // Artificial light is yellow-ish
321         static u8 emphase_yellow_when_artificial[16] = {
322                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 10, 15, 15, 15
323         };
324         rg += emphase_yellow_when_artificial[night/16];
325         if(rg < 0)
326                 rg = 0;
327         if(rg > 255)
328                 rg = 255;
329
330         result.setRed(rg);
331         result.setGreen(rg);
332         result.setBlue(b);
333 }
334
335 /*
336         Mesh generation helpers
337 */
338
339 /*
340         vertex_dirs: v3s16[4]
341 */
342 static void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
343 {
344         /*
345                 If looked from outside the node towards the face, the corners are:
346                 0: bottom-right
347                 1: bottom-left
348                 2: top-left
349                 3: top-right
350         */
351         if(dir == v3s16(0,0,1))
352         {
353                 // If looking towards z+, this is the face that is behind
354                 // the center point, facing towards z+.
355                 vertex_dirs[0] = v3s16(-1,-1, 1);
356                 vertex_dirs[1] = v3s16( 1,-1, 1);
357                 vertex_dirs[2] = v3s16( 1, 1, 1);
358                 vertex_dirs[3] = v3s16(-1, 1, 1);
359         }
360         else if(dir == v3s16(0,0,-1))
361         {
362                 // faces towards Z-
363                 vertex_dirs[0] = v3s16( 1,-1,-1);
364                 vertex_dirs[1] = v3s16(-1,-1,-1);
365                 vertex_dirs[2] = v3s16(-1, 1,-1);
366                 vertex_dirs[3] = v3s16( 1, 1,-1);
367         }
368         else if(dir == v3s16(1,0,0))
369         {
370                 // faces towards X+
371                 vertex_dirs[0] = v3s16( 1,-1, 1);
372                 vertex_dirs[1] = v3s16( 1,-1,-1);
373                 vertex_dirs[2] = v3s16( 1, 1,-1);
374                 vertex_dirs[3] = v3s16( 1, 1, 1);
375         }
376         else if(dir == v3s16(-1,0,0))
377         {
378                 // faces towards X-
379                 vertex_dirs[0] = v3s16(-1,-1,-1);
380                 vertex_dirs[1] = v3s16(-1,-1, 1);
381                 vertex_dirs[2] = v3s16(-1, 1, 1);
382                 vertex_dirs[3] = v3s16(-1, 1,-1);
383         }
384         else if(dir == v3s16(0,1,0))
385         {
386                 // faces towards Y+ (assume Z- as "down" in texture)
387                 vertex_dirs[0] = v3s16( 1, 1,-1);
388                 vertex_dirs[1] = v3s16(-1, 1,-1);
389                 vertex_dirs[2] = v3s16(-1, 1, 1);
390                 vertex_dirs[3] = v3s16( 1, 1, 1);
391         }
392         else if(dir == v3s16(0,-1,0))
393         {
394                 // faces towards Y- (assume Z+ as "down" in texture)
395                 vertex_dirs[0] = v3s16( 1,-1, 1);
396                 vertex_dirs[1] = v3s16(-1,-1, 1);
397                 vertex_dirs[2] = v3s16(-1,-1,-1);
398                 vertex_dirs[3] = v3s16( 1,-1,-1);
399         }
400 }
401
402 struct FastFace
403 {
404         TileSpec tile;
405         video::S3DVertex vertices[4]; // Precalculated vertices
406 };
407
408 static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
409                 v3f p, v3s16 dir, v3f scale, core::array<FastFace> &dest)
410 {
411         FastFace face;
412         
413         // Position is at the center of the cube.
414         v3f pos = p * BS;
415
416         v3f vertex_pos[4];
417         v3s16 vertex_dirs[4];
418         getNodeVertexDirs(dir, vertex_dirs);
419         for(u16 i=0; i<4; i++)
420         {
421                 vertex_pos[i] = v3f(
422                                 BS/2*vertex_dirs[i].X,
423                                 BS/2*vertex_dirs[i].Y,
424                                 BS/2*vertex_dirs[i].Z
425                 );
426         }
427
428         for(u16 i=0; i<4; i++)
429         {
430                 vertex_pos[i].X *= scale.X;
431                 vertex_pos[i].Y *= scale.Y;
432                 vertex_pos[i].Z *= scale.Z;
433                 vertex_pos[i] += pos;
434         }
435
436         f32 abs_scale = 1.;
437         if     (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
438         else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
439         else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
440
441         v3f normal(dir.X, dir.Y, dir.Z);
442
443         u8 alpha = tile.alpha;
444
445         float x0 = tile.texture.pos.X;
446         float y0 = tile.texture.pos.Y;
447         float w = tile.texture.size.X;
448         float h = tile.texture.size.Y;
449
450         face.vertices[0] = video::S3DVertex(vertex_pos[0], normal,
451                         MapBlock_LightColor(alpha, li0),
452                         core::vector2d<f32>(x0+w*abs_scale, y0+h));
453         face.vertices[1] = video::S3DVertex(vertex_pos[1], normal,
454                         MapBlock_LightColor(alpha, li1),
455                         core::vector2d<f32>(x0, y0+h));
456         face.vertices[2] = video::S3DVertex(vertex_pos[2], normal,
457                         MapBlock_LightColor(alpha, li2),
458                         core::vector2d<f32>(x0, y0));
459         face.vertices[3] = video::S3DVertex(vertex_pos[3], normal,
460                         MapBlock_LightColor(alpha, li3),
461                         core::vector2d<f32>(x0+w*abs_scale, y0));
462
463         face.tile = tile;
464         
465         dest.push_back(face);
466 }
467
468 /*
469         Nodes make a face if contents differ and solidness differs.
470         Return value:
471                 0: No face
472                 1: Face uses m1's content
473                 2: Face uses m2's content
474         equivalent: Whether the blocks share the same face (eg. water and glass)
475
476         TODO: Add 3: Both faces drawn with backface culling, remove equivalent
477 */
478 static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
479                 INodeDefManager *ndef)
480 {
481         *equivalent = false;
482
483         if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
484                 return 0;
485         
486         bool contents_differ = (m1 != m2);
487         
488         const ContentFeatures &f1 = ndef->get(m1);
489         const ContentFeatures &f2 = ndef->get(m2);
490
491         // Contents don't differ for different forms of same liquid
492         if(f1.sameLiquid(f2))
493                 contents_differ = false;
494         
495         u8 c1 = f1.solidness;
496         u8 c2 = f2.solidness;
497
498         bool solidness_differs = (c1 != c2);
499         bool makes_face = contents_differ && solidness_differs;
500
501         if(makes_face == false)
502                 return 0;
503         
504         if(c1 == 0)
505                 c1 = f1.visual_solidness;
506         if(c2 == 0)
507                 c2 = f2.visual_solidness;
508         
509         if(c1 == c2){
510                 *equivalent = true;
511                 // If same solidness, liquid takes precense
512                 if(f1.isLiquid())
513                         return 1;
514                 if(f2.isLiquid())
515                         return 2;
516         }
517         
518         if(c1 > c2)
519                 return 1;
520         else
521                 return 2;
522 }
523
524 /*
525         Gets nth node tile (0 <= n <= 5).
526 */
527 TileSpec getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data)
528 {
529         INodeDefManager *ndef = data->m_gamedef->ndef();
530         TileSpec spec = ndef->get(mn).tiles[tileindex];
531         // Apply temporary crack
532         if(p == data->m_crack_pos_relative)
533         {
534                 spec.material_flags |= MATERIAL_FLAG_CRACK;
535                 spec.texture = data->m_gamedef->tsrc()->getTextureRawAP(spec.texture);
536         }
537         return spec;
538 }
539
540 /*
541         Gets node tile given a face direction.
542 */
543 TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data)
544 {
545         INodeDefManager *ndef = data->m_gamedef->ndef();
546
547         // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
548         // (0,0,1), (0,0,-1) or (0,0,0)
549         assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z <= 1);
550
551         // Convert direction to single integer for table lookup
552         //  0 = (0,0,0)
553         //  1 = (1,0,0)
554         //  2 = (0,1,0)
555         //  3 = (0,0,1)
556         //  4 = invalid, treat as (0,0,0)
557         //  5 = (0,0,-1)
558         //  6 = (0,-1,0)
559         //  7 = (-1,0,0)
560         u8 dir_i = (dir.X + 2 * dir.Y + 3 * dir.Z) & 7;
561
562         // Get rotation for things like chests
563         u8 facedir = mn.getFaceDir(ndef);
564         assert(facedir <= 3);
565         
566         static const u8 dir_to_tile[4 * 8] =
567         {
568                 // 0  +X  +Y  +Z   0  -Z  -Y  -X
569                    0,  2,  0,  4,  0,  5,  1,  3,  // facedir = 0
570                    0,  4,  0,  3,  0,  2,  1,  5,  // facedir = 1
571                    0,  3,  0,  5,  0,  4,  1,  2,  // facedir = 2
572                    0,  5,  0,  2,  0,  3,  1,  4,  // facedir = 3
573         };
574         u8 tileindex = dir_to_tile[facedir*8 + dir_i];
575         return getNodeTileN(mn, p, tileindex, data);
576 }
577
578 static void getTileInfo(
579                 // Input:
580                 MeshMakeData *data,
581                 v3s16 p,
582                 v3s16 face_dir,
583                 // Output:
584                 bool &makes_face,
585                 v3s16 &p_corrected,
586                 v3s16 &face_dir_corrected,
587                 u16 *lights,
588                 TileSpec &tile
589         )
590 {
591         VoxelManipulator &vmanip = data->m_vmanip;
592         INodeDefManager *ndef = data->m_gamedef->ndef();
593         v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
594
595         MapNode n0 = vmanip.getNodeNoEx(blockpos_nodes + p);
596         MapNode n1 = vmanip.getNodeNoEx(blockpos_nodes + p + face_dir);
597         TileSpec tile0 = getNodeTile(n0, p, face_dir, data);
598         TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir, data);
599         
600         // This is hackish
601         bool equivalent = false;
602         u8 mf = face_contents(n0.getContent(), n1.getContent(),
603                         &equivalent, ndef);
604
605         if(mf == 0)
606         {
607                 makes_face = false;
608                 return;
609         }
610
611         makes_face = true;
612         
613         if(mf == 1)
614         {
615                 tile = tile0;
616                 p_corrected = p;
617                 face_dir_corrected = face_dir;
618         }
619         else
620         {
621                 tile = tile1;
622                 p_corrected = p + face_dir;
623                 face_dir_corrected = -face_dir;
624         }
625         
626         // eg. water and glass
627         if(equivalent)
628                 tile.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
629         
630         if(data->m_smooth_lighting == false)
631         {
632                 lights[0] = lights[1] = lights[2] = lights[3] =
633                                 getFaceLight(n0, n1, face_dir, data);
634         }
635         else
636         {
637                 v3s16 vertex_dirs[4];
638                 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
639                 for(u16 i=0; i<4; i++)
640                 {
641                         lights[i] = getSmoothLight(
642                                         blockpos_nodes + p_corrected,
643                                         vertex_dirs[i], data);
644                 }
645         }
646         
647         return;
648 }
649
650 /*
651         startpos:
652         translate_dir: unit vector with only one of x, y or z
653         face_dir: unit vector with only one of x, y or z
654 */
655 static void updateFastFaceRow(
656                 MeshMakeData *data,
657                 v3s16 startpos,
658                 v3s16 translate_dir,
659                 v3f translate_dir_f,
660                 v3s16 face_dir,
661                 v3f face_dir_f,
662                 core::array<FastFace> &dest)
663 {
664         v3s16 p = startpos;
665         
666         u16 continuous_tiles_count = 0;
667         
668         bool makes_face = false;
669         v3s16 p_corrected;
670         v3s16 face_dir_corrected;
671         u16 lights[4] = {0,0,0,0};
672         TileSpec tile;
673         getTileInfo(data, p, face_dir, 
674                         makes_face, p_corrected, face_dir_corrected,
675                         lights, tile);
676
677         for(u16 j=0; j<MAP_BLOCKSIZE; j++)
678         {
679                 // If tiling can be done, this is set to false in the next step
680                 bool next_is_different = true;
681                 
682                 v3s16 p_next;
683                 
684                 bool next_makes_face = false;
685                 v3s16 next_p_corrected;
686                 v3s16 next_face_dir_corrected;
687                 u16 next_lights[4] = {0,0,0,0};
688                 TileSpec next_tile;
689                 
690                 // If at last position, there is nothing to compare to and
691                 // the face must be drawn anyway
692                 if(j != MAP_BLOCKSIZE - 1)
693                 {
694                         p_next = p + translate_dir;
695                         
696                         getTileInfo(data, p_next, face_dir,
697                                         next_makes_face, next_p_corrected,
698                                         next_face_dir_corrected, next_lights,
699                                         next_tile);
700                         
701                         if(next_makes_face == makes_face
702                                         && next_p_corrected == p_corrected + translate_dir
703                                         && next_face_dir_corrected == face_dir_corrected
704                                         && next_lights[0] == lights[0]
705                                         && next_lights[1] == lights[1]
706                                         && next_lights[2] == lights[2]
707                                         && next_lights[3] == lights[3]
708                                         && next_tile == tile)
709                         {
710                                 next_is_different = false;
711                         }
712                         else{
713                                 /*if(makes_face){
714                                         g_profiler->add("Meshgen: diff: next_makes_face != makes_face",
715                                                         next_makes_face != makes_face ? 1 : 0);
716                                         g_profiler->add("Meshgen: diff: n_p_corr != p_corr + t_dir",
717                                                         (next_p_corrected != p_corrected + translate_dir) ? 1 : 0);
718                                         g_profiler->add("Meshgen: diff: next_f_dir_corr != f_dir_corr",
719                                                         next_face_dir_corrected != face_dir_corrected ? 1 : 0);
720                                         g_profiler->add("Meshgen: diff: next_lights[] != lights[]",
721                                                         (next_lights[0] != lights[0] ||
722                                                         next_lights[0] != lights[0] ||
723                                                         next_lights[0] != lights[0] ||
724                                                         next_lights[0] != lights[0]) ? 1 : 0);
725                                         g_profiler->add("Meshgen: diff: !(next_tile == tile)",
726                                                         !(next_tile == tile) ? 1 : 0);
727                                 }*/
728                         }
729                         /*g_profiler->add("Meshgen: Total faces checked", 1);
730                         if(makes_face)
731                                 g_profiler->add("Meshgen: Total makes_face checked", 1);*/
732                 } else {
733                         /*if(makes_face)
734                                 g_profiler->add("Meshgen: diff: last position", 1);*/
735                 }
736
737                 continuous_tiles_count++;
738                 
739                 // This is set to true if the texture doesn't allow more tiling
740                 bool end_of_texture = false;
741                 /*
742                         If there is no texture, it can be tiled infinitely.
743                         If tiled==0, it means the texture can be tiled infinitely.
744                         Otherwise check tiled agains continuous_tiles_count.
745                 */
746                 if(tile.texture.atlas != NULL && tile.texture.tiled != 0)
747                 {
748                         if(tile.texture.tiled <= continuous_tiles_count)
749                                 end_of_texture = true;
750                 }
751                 
752                 // Do this to disable tiling textures
753                 //end_of_texture = true; //DEBUG
754                 
755                 if(next_is_different || end_of_texture)
756                 {
757                         /*
758                                 Create a face if there should be one
759                         */
760                         if(makes_face)
761                         {
762                                 // Floating point conversion of the position vector
763                                 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
764                                 // Center point of face (kind of)
765                                 v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
766                                 if(continuous_tiles_count != 1)
767                                         sp += translate_dir_f;
768                                 v3f scale(1,1,1);
769
770                                 if(translate_dir.X != 0)
771                                 {
772                                         scale.X = continuous_tiles_count;
773                                 }
774                                 if(translate_dir.Y != 0)
775                                 {
776                                         scale.Y = continuous_tiles_count;
777                                 }
778                                 if(translate_dir.Z != 0)
779                                 {
780                                         scale.Z = continuous_tiles_count;
781                                 }
782                                 
783                                 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
784                                                 sp, face_dir_corrected, scale,
785                                                 dest);
786                                 
787                                 g_profiler->avg("Meshgen: faces drawn by tiling", 0);
788                                 for(int i=1; i<continuous_tiles_count; i++){
789                                         g_profiler->avg("Meshgen: faces drawn by tiling", 1);
790                                 }
791                         }
792
793                         continuous_tiles_count = 0;
794                         
795                         makes_face = next_makes_face;
796                         p_corrected = next_p_corrected;
797                         face_dir_corrected = next_face_dir_corrected;
798                         lights[0] = next_lights[0];
799                         lights[1] = next_lights[1];
800                         lights[2] = next_lights[2];
801                         lights[3] = next_lights[3];
802                         tile = next_tile;
803                 }
804                 
805                 p = p_next;
806         }
807 }
808
809 static void updateAllFastFaceRows(MeshMakeData *data,
810                 core::array<FastFace> &dest)
811 {
812         /*
813                 Go through every y,z and get top(y+) faces in rows of x+
814         */
815         for(s16 y=0; y<MAP_BLOCKSIZE; y++){
816                 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
817                         updateFastFaceRow(data,
818                                         v3s16(0,y,z),
819                                         v3s16(1,0,0), //dir
820                                         v3f  (1,0,0),
821                                         v3s16(0,1,0), //face dir
822                                         v3f  (0,1,0),
823                                         dest);
824                 }
825         }
826
827         /*
828                 Go through every x,y and get right(x+) faces in rows of z+
829         */
830         for(s16 x=0; x<MAP_BLOCKSIZE; x++){
831                 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
832                         updateFastFaceRow(data,
833                                         v3s16(x,y,0),
834                                         v3s16(0,0,1), //dir
835                                         v3f  (0,0,1),
836                                         v3s16(1,0,0), //face dir
837                                         v3f  (1,0,0),
838                                         dest);
839                 }
840         }
841
842         /*
843                 Go through every y,z and get back(z+) faces in rows of x+
844         */
845         for(s16 z=0; z<MAP_BLOCKSIZE; z++){
846                 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
847                         updateFastFaceRow(data,
848                                         v3s16(0,y,z),
849                                         v3s16(1,0,0), //dir
850                                         v3f  (1,0,0),
851                                         v3s16(0,0,1), //face dir
852                                         v3f  (0,0,1),
853                                         dest);
854                 }
855         }
856 }
857
858 /*
859         MapBlockMesh
860 */
861
862 MapBlockMesh::MapBlockMesh(MeshMakeData *data):
863         m_mesh(new scene::SMesh()),
864         m_gamedef(data->m_gamedef),
865         m_animation_force_timer(0), // force initial animation
866         m_last_crack(-1),
867         m_crack_materials(),
868         m_last_daynight_ratio((u32) -1),
869         m_daynight_diffs()
870 {
871         // 4-21ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
872         // 24-155ms for MAP_BLOCKSIZE=32  (NOTE: probably outdated)
873         //TimeTaker timer1("MapBlockMesh()");
874
875         core::array<FastFace> fastfaces_new;
876
877         /*
878                 We are including the faces of the trailing edges of the block.
879                 This means that when something changes, the caller must
880                 also update the meshes of the blocks at the leading edges.
881
882                 NOTE: This is the slowest part of this method.
883         */
884         {
885                 // 4-23ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
886                 //TimeTaker timer2("updateAllFastFaceRows()");
887                 updateAllFastFaceRows(data, fastfaces_new);
888         }
889         // End of slow part
890
891         /*
892                 Convert FastFaces to MeshCollector
893         */
894
895         MeshCollector collector;
896
897         {
898                 // avg 0ms (100ms spikes when loading textures the first time)
899                 // (NOTE: probably outdated)
900                 //TimeTaker timer2("MeshCollector building");
901
902                 for(u32 i=0; i<fastfaces_new.size(); i++)
903                 {
904                         FastFace &f = fastfaces_new[i];
905
906                         const u16 indices[] = {0,1,2,2,3,0};
907                         const u16 indices_alternate[] = {0,1,3,2,3,1};
908                         
909                         if(f.tile.texture.atlas == NULL)
910                                 continue;
911
912                         const u16 *indices_p = indices;
913                         
914                         /*
915                                 Revert triangles for nicer looking gradient if vertices
916                                 1 and 3 have same color or 0 and 2 have different color.
917                                 getRed() is the day color.
918                         */
919                         if(f.vertices[0].Color.getRed() != f.vertices[2].Color.getRed()
920                                         || f.vertices[1].Color.getRed() == f.vertices[3].Color.getRed())
921                                 indices_p = indices_alternate;
922                         
923                         collector.append(f.tile, f.vertices, 4, indices_p, 6);
924                 }
925         }
926
927         /*
928                 Add special graphics:
929                 - torches
930                 - flowing water
931                 - fences
932                 - whatever
933         */
934
935         mapblock_mesh_generate_special(data, collector);
936         
937
938         /*
939                 Convert MeshCollector to SMesh
940                 Also store animation info
941         */
942         for(u32 i = 0; i < collector.prebuffers.size(); i++)
943         {
944                 PreMeshBuffer &p = collector.prebuffers[i];
945                 /*dstream<<"p.vertices.size()="<<p.vertices.size()
946                                 <<", p.indices.size()="<<p.indices.size()
947                                 <<std::endl;*/
948
949                 // Generate animation data
950                 // - Cracks
951                 if(p.tile.material_flags & MATERIAL_FLAG_CRACK)
952                 {
953                         ITextureSource *tsrc = data->m_gamedef->tsrc();
954                         std::string crack_basename = tsrc->getTextureName(p.tile.texture.id);
955                         if(p.tile.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
956                                 crack_basename += "^[cracko";
957                         else
958                                 crack_basename += "^[crack";
959                         m_crack_materials.insert(std::make_pair(i, crack_basename));
960                 }
961                 // - Lighting
962                 for(u32 j = 0; j < p.vertices.size(); j++)
963                 {
964                         video::SColor &vc = p.vertices[j].Color;
965                         u8 day = vc.getRed();
966                         u8 night = vc.getGreen();
967                         finalColorBlend(vc, day, night, 1000);
968                         if(day != night)
969                                 m_daynight_diffs[i][j] = std::make_pair(day, night);
970                 }
971
972
973                 // Create material
974                 video::SMaterial material;
975                 material.setFlag(video::EMF_LIGHTING, false);
976                 material.setFlag(video::EMF_BACK_FACE_CULLING, true);
977                 material.setFlag(video::EMF_BILINEAR_FILTER, false);
978                 material.setFlag(video::EMF_FOG_ENABLE, true);
979                 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
980                 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE);
981                 material.MaterialType
982                                 = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
983                 material.setTexture(0, p.tile.texture.atlas);
984                 p.tile.applyMaterialOptions(material);
985
986                 // Create meshbuffer
987
988                 // This is a "Standard MeshBuffer",
989                 // it's a typedeffed CMeshBuffer<video::S3DVertex>
990                 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
991                 // Set material
992                 buf->Material = material;
993                 // Add to mesh
994                 m_mesh->addMeshBuffer(buf);
995                 // Mesh grabbed it
996                 buf->drop();
997                 buf->append(p.vertices.pointer(), p.vertices.size(),
998                                 p.indices.pointer(), p.indices.size());
999         }
1000
1001         /*
1002                 Do some stuff to the mesh
1003         */
1004
1005         translateMesh(m_mesh, intToFloat(data->m_blockpos * MAP_BLOCKSIZE, BS));
1006         m_mesh->recalculateBoundingBox(); // translateMesh already does this
1007
1008         if(m_mesh)
1009         {
1010 #if 0
1011                 // Usually 1-700 faces and 1-7 materials
1012                 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
1013                                 <<"and uses "<<m_mesh->getMeshBufferCount()
1014                                 <<" materials (meshbuffers)"<<std::endl;
1015 #endif
1016
1017                 // Use VBO for mesh (this just would set this for ever buffer)
1018                 // This will lead to infinite memory usage because or irrlicht.
1019                 //m_mesh->setHardwareMappingHint(scene::EHM_STATIC);
1020
1021                 /*
1022                         NOTE: If that is enabled, some kind of a queue to the main
1023                         thread should be made which would call irrlicht to delete
1024                         the hardware buffer and then delete the mesh
1025                 */
1026         }
1027         
1028         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1029
1030         // Check if animation is required for this mesh
1031         m_has_animation =
1032                 !m_crack_materials.empty() ||
1033                 !m_daynight_diffs.empty();
1034 }
1035
1036 MapBlockMesh::~MapBlockMesh()
1037 {
1038         m_mesh->drop();
1039         m_mesh = NULL;
1040 }
1041
1042 bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_ratio)
1043 {
1044         if(!m_has_animation)
1045         {
1046                 m_animation_force_timer = 100000;
1047                 return false;
1048         }
1049
1050         m_animation_force_timer = myrand_range(5, 100);
1051
1052         // Cracks
1053         if(crack != m_last_crack)
1054         {
1055                 for(std::map<u32, std::string>::iterator
1056                                 i = m_crack_materials.begin();
1057                                 i != m_crack_materials.end(); i++)
1058                 {
1059                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1060                         std::string basename = i->second;
1061
1062                         // Create new texture name from original
1063                         ITextureSource *tsrc = m_gamedef->getTextureSource();
1064                         std::ostringstream os;
1065                         os<<basename<<crack;
1066                         AtlasPointer ap = tsrc->getTexture(os.str());
1067                         buf->getMaterial().setTexture(0, ap.atlas);
1068                 }
1069
1070                 m_last_crack = crack;
1071         }
1072
1073         // Day-night transition
1074         if(daynight_ratio != m_last_daynight_ratio)
1075         {
1076                 for(std::map<u32, std::map<u32, std::pair<u8, u8> > >::iterator
1077                                 i = m_daynight_diffs.begin();
1078                                 i != m_daynight_diffs.end(); i++)
1079                 {
1080                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1081                         video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
1082                         for(std::map<u32, std::pair<u8, u8 > >::iterator
1083                                         j = i->second.begin();
1084                                         j != i->second.end(); j++)
1085                         {
1086                                 u32 vertexIndex = j->first;
1087                                 u8 day = j->second.first;
1088                                 u8 night = j->second.second;
1089                                 finalColorBlend(vertices[vertexIndex].Color,
1090                                                 day, night, daynight_ratio);
1091                         }
1092                 }
1093                 m_last_daynight_ratio = daynight_ratio;
1094         }
1095
1096         return true;
1097 }
1098
1099 /*
1100         MeshCollector
1101 */
1102
1103 void MeshCollector::append(const TileSpec &tile,
1104                 const video::S3DVertex *vertices, u32 numVertices,
1105                 const u16 *indices, u32 numIndices)
1106 {
1107         PreMeshBuffer *p = NULL;
1108         for(u32 i=0; i<prebuffers.size(); i++)
1109         {
1110                 PreMeshBuffer &pp = prebuffers[i];
1111                 if(pp.tile != tile)
1112                         continue;
1113
1114                 p = &pp;
1115                 break;
1116         }
1117
1118         if(p == NULL)
1119         {
1120                 PreMeshBuffer pp;
1121                 pp.tile = tile;
1122                 prebuffers.push_back(pp);
1123                 p = &prebuffers[prebuffers.size()-1];
1124         }
1125
1126         u32 vertex_count = p->vertices.size();
1127         for(u32 i=0; i<numIndices; i++)
1128         {
1129                 u32 j = indices[i] + vertex_count;
1130                 if(j > 65535)
1131                 {
1132                         dstream<<"FIXME: Meshbuffer ran out of indices"<<std::endl;
1133                         // NOTE: Fix is to just add an another MeshBuffer
1134                 }
1135                 p->indices.push_back(j);
1136         }
1137         for(u32 i=0; i<numVertices; i++)
1138         {
1139                 p->vertices.push_back(vertices[i]);
1140         }
1141 }