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