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