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