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