Implement a global shader parameter passing system and useful shaders
[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, 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),
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),
484                         core::vector2d<f32>(x0, y0+h));
485         face.vertices[2] = video::S3DVertex(vertex_pos[2], normal,
486                         MapBlock_LightColor(alpha, li2),
487                         core::vector2d<f32>(x0, y0));
488         face.vertices[3] = video::S3DVertex(vertex_pos[3], normal,
489                         MapBlock_LightColor(alpha, li3),
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         )
663 {
664         VoxelManipulator &vmanip = data->m_vmanip;
665         INodeDefManager *ndef = data->m_gamedef->ndef();
666         v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
667
668         MapNode n0 = vmanip.getNodeNoEx(blockpos_nodes + p);
669         MapNode n1 = vmanip.getNodeNoEx(blockpos_nodes + p + face_dir);
670         TileSpec tile0 = getNodeTile(n0, p, face_dir, data);
671         TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir, data);
672         
673         // This is hackish
674         bool equivalent = false;
675         u8 mf = face_contents(n0.getContent(), n1.getContent(),
676                         &equivalent, ndef);
677
678         if(mf == 0)
679         {
680                 makes_face = false;
681                 return;
682         }
683
684         makes_face = true;
685         
686         if(mf == 1)
687         {
688                 tile = tile0;
689                 p_corrected = p;
690                 face_dir_corrected = face_dir;
691         }
692         else
693         {
694                 tile = tile1;
695                 p_corrected = p + face_dir;
696                 face_dir_corrected = -face_dir;
697         }
698         
699         // eg. water and glass
700         if(equivalent)
701                 tile.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
702         
703         if(data->m_smooth_lighting == false)
704         {
705                 lights[0] = lights[1] = lights[2] = lights[3] =
706                                 getFaceLight(n0, n1, face_dir, data);
707         }
708         else
709         {
710                 v3s16 vertex_dirs[4];
711                 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
712                 for(u16 i=0; i<4; i++)
713                 {
714                         lights[i] = getSmoothLight(
715                                         blockpos_nodes + p_corrected,
716                                         vertex_dirs[i], data);
717                 }
718         }
719         
720         return;
721 }
722
723 /*
724         startpos:
725         translate_dir: unit vector with only one of x, y or z
726         face_dir: unit vector with only one of x, y or z
727 */
728 static void updateFastFaceRow(
729                 MeshMakeData *data,
730                 v3s16 startpos,
731                 v3s16 translate_dir,
732                 v3f translate_dir_f,
733                 v3s16 face_dir,
734                 v3f face_dir_f,
735                 core::array<FastFace> &dest)
736 {
737         v3s16 p = startpos;
738         
739         u16 continuous_tiles_count = 0;
740         
741         bool makes_face = false;
742         v3s16 p_corrected;
743         v3s16 face_dir_corrected;
744         u16 lights[4] = {0,0,0,0};
745         TileSpec tile;
746         getTileInfo(data, p, face_dir, 
747                         makes_face, p_corrected, face_dir_corrected,
748                         lights, tile);
749
750         for(u16 j=0; j<MAP_BLOCKSIZE; j++)
751         {
752                 // If tiling can be done, this is set to false in the next step
753                 bool next_is_different = true;
754                 
755                 v3s16 p_next;
756                 
757                 bool next_makes_face = false;
758                 v3s16 next_p_corrected;
759                 v3s16 next_face_dir_corrected;
760                 u16 next_lights[4] = {0,0,0,0};
761                 TileSpec next_tile;
762                 
763                 // If at last position, there is nothing to compare to and
764                 // the face must be drawn anyway
765                 if(j != MAP_BLOCKSIZE - 1)
766                 {
767                         p_next = p + translate_dir;
768                         
769                         getTileInfo(data, p_next, face_dir,
770                                         next_makes_face, next_p_corrected,
771                                         next_face_dir_corrected, next_lights,
772                                         next_tile);
773                         
774                         if(next_makes_face == makes_face
775                                         && next_p_corrected == p_corrected + translate_dir
776                                         && next_face_dir_corrected == face_dir_corrected
777                                         && next_lights[0] == lights[0]
778                                         && next_lights[1] == lights[1]
779                                         && next_lights[2] == lights[2]
780                                         && next_lights[3] == lights[3]
781                                         && next_tile == tile)
782                         {
783                                 next_is_different = false;
784                         }
785                         else{
786                                 /*if(makes_face){
787                                         g_profiler->add("Meshgen: diff: next_makes_face != makes_face",
788                                                         next_makes_face != makes_face ? 1 : 0);
789                                         g_profiler->add("Meshgen: diff: n_p_corr != p_corr + t_dir",
790                                                         (next_p_corrected != p_corrected + translate_dir) ? 1 : 0);
791                                         g_profiler->add("Meshgen: diff: next_f_dir_corr != f_dir_corr",
792                                                         next_face_dir_corrected != face_dir_corrected ? 1 : 0);
793                                         g_profiler->add("Meshgen: diff: next_lights[] != lights[]",
794                                                         (next_lights[0] != lights[0] ||
795                                                         next_lights[0] != lights[0] ||
796                                                         next_lights[0] != lights[0] ||
797                                                         next_lights[0] != lights[0]) ? 1 : 0);
798                                         g_profiler->add("Meshgen: diff: !(next_tile == tile)",
799                                                         !(next_tile == tile) ? 1 : 0);
800                                 }*/
801                         }
802                         /*g_profiler->add("Meshgen: Total faces checked", 1);
803                         if(makes_face)
804                                 g_profiler->add("Meshgen: Total makes_face checked", 1);*/
805                 } else {
806                         /*if(makes_face)
807                                 g_profiler->add("Meshgen: diff: last position", 1);*/
808                 }
809
810                 continuous_tiles_count++;
811                 
812                 // This is set to true if the texture doesn't allow more tiling
813                 bool end_of_texture = false;
814                 /*
815                         If there is no texture, it can be tiled infinitely.
816                         If tiled==0, it means the texture can be tiled infinitely.
817                         Otherwise check tiled agains continuous_tiles_count.
818                 */
819                 if(tile.texture.atlas != NULL && tile.texture.tiled != 0)
820                 {
821                         if(tile.texture.tiled <= continuous_tiles_count)
822                                 end_of_texture = true;
823                 }
824                 
825                 // Do this to disable tiling textures
826                 //end_of_texture = true; //DEBUG
827                 
828                 if(next_is_different || end_of_texture)
829                 {
830                         /*
831                                 Create a face if there should be one
832                         */
833                         if(makes_face)
834                         {
835                                 // Floating point conversion of the position vector
836                                 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
837                                 // Center point of face (kind of)
838                                 v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
839                                 if(continuous_tiles_count != 1)
840                                         sp += translate_dir_f;
841                                 v3f scale(1,1,1);
842
843                                 if(translate_dir.X != 0)
844                                 {
845                                         scale.X = continuous_tiles_count;
846                                 }
847                                 if(translate_dir.Y != 0)
848                                 {
849                                         scale.Y = continuous_tiles_count;
850                                 }
851                                 if(translate_dir.Z != 0)
852                                 {
853                                         scale.Z = continuous_tiles_count;
854                                 }
855                                 
856                                 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
857                                                 sp, face_dir_corrected, scale,
858                                                 dest);
859                                 
860                                 g_profiler->avg("Meshgen: faces drawn by tiling", 0);
861                                 for(int i=1; i<continuous_tiles_count; i++){
862                                         g_profiler->avg("Meshgen: faces drawn by tiling", 1);
863                                 }
864                         }
865
866                         continuous_tiles_count = 0;
867                         
868                         makes_face = next_makes_face;
869                         p_corrected = next_p_corrected;
870                         face_dir_corrected = next_face_dir_corrected;
871                         lights[0] = next_lights[0];
872                         lights[1] = next_lights[1];
873                         lights[2] = next_lights[2];
874                         lights[3] = next_lights[3];
875                         tile = next_tile;
876                 }
877                 
878                 p = p_next;
879         }
880 }
881
882 static void updateAllFastFaceRows(MeshMakeData *data,
883                 core::array<FastFace> &dest)
884 {
885         /*
886                 Go through every y,z and get top(y+) faces in rows of x+
887         */
888         for(s16 y=0; y<MAP_BLOCKSIZE; y++){
889                 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
890                         updateFastFaceRow(data,
891                                         v3s16(0,y,z),
892                                         v3s16(1,0,0), //dir
893                                         v3f  (1,0,0),
894                                         v3s16(0,1,0), //face dir
895                                         v3f  (0,1,0),
896                                         dest);
897                 }
898         }
899
900         /*
901                 Go through every x,y and get right(x+) faces in rows of z+
902         */
903         for(s16 x=0; x<MAP_BLOCKSIZE; x++){
904                 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
905                         updateFastFaceRow(data,
906                                         v3s16(x,y,0),
907                                         v3s16(0,0,1), //dir
908                                         v3f  (0,0,1),
909                                         v3s16(1,0,0), //face dir
910                                         v3f  (1,0,0),
911                                         dest);
912                 }
913         }
914
915         /*
916                 Go through every y,z and get back(z+) faces in rows of x+
917         */
918         for(s16 z=0; z<MAP_BLOCKSIZE; z++){
919                 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
920                         updateFastFaceRow(data,
921                                         v3s16(0,y,z),
922                                         v3s16(1,0,0), //dir
923                                         v3f  (1,0,0),
924                                         v3s16(0,0,1), //face dir
925                                         v3f  (0,0,1),
926                                         dest);
927                 }
928         }
929 }
930
931 /*
932         MapBlockMesh
933 */
934
935 MapBlockMesh::MapBlockMesh(MeshMakeData *data):
936         m_mesh(new scene::SMesh()),
937         m_gamedef(data->m_gamedef),
938         m_animation_force_timer(0), // force initial animation
939         m_last_crack(-1),
940         m_crack_materials(),
941         m_last_daynight_ratio((u32) -1),
942         m_daynight_diffs()
943 {
944         // 4-21ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
945         // 24-155ms for MAP_BLOCKSIZE=32  (NOTE: probably outdated)
946         //TimeTaker timer1("MapBlockMesh()");
947
948         core::array<FastFace> fastfaces_new;
949
950         /*
951                 We are including the faces of the trailing edges of the block.
952                 This means that when something changes, the caller must
953                 also update the meshes of the blocks at the leading edges.
954
955                 NOTE: This is the slowest part of this method.
956         */
957         {
958                 // 4-23ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
959                 //TimeTaker timer2("updateAllFastFaceRows()");
960                 updateAllFastFaceRows(data, fastfaces_new);
961         }
962         // End of slow part
963
964         /*
965                 Convert FastFaces to MeshCollector
966         */
967
968         MeshCollector collector;
969
970         {
971                 // avg 0ms (100ms spikes when loading textures the first time)
972                 // (NOTE: probably outdated)
973                 //TimeTaker timer2("MeshCollector building");
974
975                 for(u32 i=0; i<fastfaces_new.size(); i++)
976                 {
977                         FastFace &f = fastfaces_new[i];
978
979                         const u16 indices[] = {0,1,2,2,3,0};
980                         const u16 indices_alternate[] = {0,1,3,2,3,1};
981                         
982                         if(f.tile.texture.atlas == NULL)
983                                 continue;
984
985                         const u16 *indices_p = indices;
986                         
987                         /*
988                                 Revert triangles for nicer looking gradient if vertices
989                                 1 and 3 have same color or 0 and 2 have different color.
990                                 getRed() is the day color.
991                         */
992                         if(f.vertices[0].Color.getRed() != f.vertices[2].Color.getRed()
993                                         || f.vertices[1].Color.getRed() == f.vertices[3].Color.getRed())
994                                 indices_p = indices_alternate;
995                         
996                         collector.append(f.tile, f.vertices, 4, indices_p, 6);
997                 }
998         }
999
1000         /*
1001                 Add special graphics:
1002                 - torches
1003                 - flowing water
1004                 - fences
1005                 - whatever
1006         */
1007
1008         mapblock_mesh_generate_special(data, collector);
1009         
1010
1011         /*
1012                 Convert MeshCollector to SMesh
1013                 Also store animation info
1014         */
1015         bool enable_shaders = (g_settings->getS32("enable_shaders") > 0);
1016         video::E_MATERIAL_TYPE shadermat1 = m_gamedef->getShaderSource()->
1017                         getShader("test_shader_1").material;
1018         video::E_MATERIAL_TYPE shadermat2 = m_gamedef->getShaderSource()->
1019                         getShader("test_shader_2").material;
1020         for(u32 i = 0; i < collector.prebuffers.size(); i++)
1021         {
1022                 PreMeshBuffer &p = collector.prebuffers[i];
1023                 /*dstream<<"p.vertices.size()="<<p.vertices.size()
1024                                 <<", p.indices.size()="<<p.indices.size()
1025                                 <<std::endl;*/
1026
1027                 // Generate animation data
1028                 // - Cracks
1029                 if(p.tile.material_flags & MATERIAL_FLAG_CRACK)
1030                 {
1031                         ITextureSource *tsrc = data->m_gamedef->tsrc();
1032                         std::string crack_basename = tsrc->getTextureName(p.tile.texture.id);
1033                         if(p.tile.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1034                                 crack_basename += "^[cracko";
1035                         else
1036                                 crack_basename += "^[crack";
1037                         m_crack_materials.insert(std::make_pair(i, crack_basename));
1038                 }
1039                 // - Texture animation
1040                 if(p.tile.material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
1041                 {
1042                         ITextureSource *tsrc = data->m_gamedef->tsrc();
1043                         // Add to MapBlockMesh in order to animate these tiles
1044                         m_animation_tiles[i] = p.tile;
1045                         m_animation_frames[i] = 0;
1046                         if(g_settings->getBool("desynchronize_mapblock_texture_animation")){
1047                                 // Get starting position from noise
1048                                 m_animation_frame_offsets[i] = 100000 * (2.0 + noise3d(
1049                                                 data->m_blockpos.X, data->m_blockpos.Y,
1050                                                 data->m_blockpos.Z, 0));
1051                         } else {
1052                                 // Play all synchronized
1053                                 m_animation_frame_offsets[i] = 0;
1054                         }
1055                         // Replace tile texture with the first animation frame
1056                         std::ostringstream os(std::ios::binary);
1057                         os<<tsrc->getTextureName(p.tile.texture.id);
1058                         os<<"^[verticalframe:"<<(int)p.tile.animation_frame_count<<":0";
1059                         p.tile.texture = tsrc->getTexture(os.str());
1060                 }
1061                 // - Lighting
1062                 for(u32 j = 0; j < p.vertices.size(); j++)
1063                 {
1064                         video::SColor &vc = p.vertices[j].Color;
1065                         u8 day = vc.getRed();
1066                         u8 night = vc.getGreen();
1067                         finalColorBlend(vc, day, night, 1000);
1068                         if(day != night)
1069                                 m_daynight_diffs[i][j] = std::make_pair(day, night);
1070                 }
1071
1072
1073                 // Create material
1074                 video::SMaterial material;
1075                 material.setFlag(video::EMF_LIGHTING, false);
1076                 material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1077                 material.setFlag(video::EMF_BILINEAR_FILTER, false);
1078                 material.setFlag(video::EMF_FOG_ENABLE, true);
1079                 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
1080                 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE);
1081                 material.MaterialType
1082                                 = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
1083                 material.setTexture(0, p.tile.texture.atlas);
1084                 p.tile.applyMaterialOptions(material);
1085
1086                 if(enable_shaders){
1087                         if(material.MaterialType == video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF)
1088                                 material.MaterialType = shadermat1;
1089                         if(material.MaterialType == video::EMT_TRANSPARENT_VERTEX_ALPHA)
1090                                 material.MaterialType = shadermat2;
1091                 }
1092
1093                 // Create meshbuffer
1094
1095                 // This is a "Standard MeshBuffer",
1096                 // it's a typedeffed CMeshBuffer<video::S3DVertex>
1097                 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1098                 // Set material
1099                 buf->Material = material;
1100                 // Add to mesh
1101                 m_mesh->addMeshBuffer(buf);
1102                 // Mesh grabbed it
1103                 buf->drop();
1104                 buf->append(p.vertices.pointer(), p.vertices.size(),
1105                                 p.indices.pointer(), p.indices.size());
1106         }
1107
1108         /*
1109                 Do some stuff to the mesh
1110         */
1111
1112         translateMesh(m_mesh, intToFloat(data->m_blockpos * MAP_BLOCKSIZE, BS));
1113         m_mesh->recalculateBoundingBox(); // translateMesh already does this
1114
1115         if(m_mesh)
1116         {
1117 #if 0
1118                 // Usually 1-700 faces and 1-7 materials
1119                 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
1120                                 <<"and uses "<<m_mesh->getMeshBufferCount()
1121                                 <<" materials (meshbuffers)"<<std::endl;
1122 #endif
1123
1124                 // Use VBO for mesh (this just would set this for ever buffer)
1125                 // This will lead to infinite memory usage because or irrlicht.
1126                 //m_mesh->setHardwareMappingHint(scene::EHM_STATIC);
1127
1128                 /*
1129                         NOTE: If that is enabled, some kind of a queue to the main
1130                         thread should be made which would call irrlicht to delete
1131                         the hardware buffer and then delete the mesh
1132                 */
1133         }
1134         
1135         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1136
1137         // Check if animation is required for this mesh
1138         m_has_animation =
1139                 !m_crack_materials.empty() ||
1140                 !m_daynight_diffs.empty() ||
1141                 !m_animation_tiles.empty();
1142 }
1143
1144 MapBlockMesh::~MapBlockMesh()
1145 {
1146         m_mesh->drop();
1147         m_mesh = NULL;
1148 }
1149
1150 bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_ratio)
1151 {
1152         if(!m_has_animation)
1153         {
1154                 m_animation_force_timer = 100000;
1155                 return false;
1156         }
1157
1158         m_animation_force_timer = myrand_range(5, 100);
1159
1160         // Cracks
1161         if(crack != m_last_crack)
1162         {
1163                 for(std::map<u32, std::string>::iterator
1164                                 i = m_crack_materials.begin();
1165                                 i != m_crack_materials.end(); i++)
1166                 {
1167                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1168                         std::string basename = i->second;
1169
1170                         // Create new texture name from original
1171                         ITextureSource *tsrc = m_gamedef->getTextureSource();
1172                         std::ostringstream os;
1173                         os<<basename<<crack;
1174                         AtlasPointer ap = tsrc->getTexture(os.str());
1175                         buf->getMaterial().setTexture(0, ap.atlas);
1176                 }
1177
1178                 m_last_crack = crack;
1179         }
1180         
1181         // Texture animation
1182         for(std::map<u32, TileSpec>::iterator
1183                         i = m_animation_tiles.begin();
1184                         i != m_animation_tiles.end(); i++)
1185         {
1186                 const TileSpec &tile = i->second;
1187                 // Figure out current frame
1188                 int frameoffset = m_animation_frame_offsets[i->first];
1189                 int frame = (int)(time * 1000 / tile.animation_frame_length_ms
1190                                 + frameoffset) % tile.animation_frame_count;
1191                 // If frame doesn't change, skip
1192                 if(frame == m_animation_frames[i->first])
1193                         continue;
1194
1195                 m_animation_frames[i->first] = frame;
1196
1197                 scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1198                 ITextureSource *tsrc = m_gamedef->getTextureSource();
1199
1200                 // Create new texture name from original
1201                 std::ostringstream os(std::ios::binary);
1202                 os<<tsrc->getTextureName(tile.texture.id);
1203                 os<<"^[verticalframe:"<<(int)tile.animation_frame_count<<":"<<frame;
1204                 // Set the texture
1205                 AtlasPointer ap = tsrc->getTexture(os.str());
1206                 buf->getMaterial().setTexture(0, ap.atlas);
1207         }
1208
1209         // Day-night transition
1210         if(daynight_ratio != m_last_daynight_ratio)
1211         {
1212                 for(std::map<u32, std::map<u32, std::pair<u8, u8> > >::iterator
1213                                 i = m_daynight_diffs.begin();
1214                                 i != m_daynight_diffs.end(); i++)
1215                 {
1216                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1217                         video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
1218                         for(std::map<u32, std::pair<u8, u8 > >::iterator
1219                                         j = i->second.begin();
1220                                         j != i->second.end(); j++)
1221                         {
1222                                 u32 vertexIndex = j->first;
1223                                 u8 day = j->second.first;
1224                                 u8 night = j->second.second;
1225                                 finalColorBlend(vertices[vertexIndex].Color,
1226                                                 day, night, daynight_ratio);
1227                         }
1228                 }
1229                 m_last_daynight_ratio = daynight_ratio;
1230         }
1231
1232         return true;
1233 }
1234
1235 /*
1236         MeshCollector
1237 */
1238
1239 void MeshCollector::append(const TileSpec &tile,
1240                 const video::S3DVertex *vertices, u32 numVertices,
1241                 const u16 *indices, u32 numIndices)
1242 {
1243         PreMeshBuffer *p = NULL;
1244         for(u32 i=0; i<prebuffers.size(); i++)
1245         {
1246                 PreMeshBuffer &pp = prebuffers[i];
1247                 if(pp.tile != tile)
1248                         continue;
1249
1250                 p = &pp;
1251                 break;
1252         }
1253
1254         if(p == NULL)
1255         {
1256                 PreMeshBuffer pp;
1257                 pp.tile = tile;
1258                 prebuffers.push_back(pp);
1259                 p = &prebuffers[prebuffers.size()-1];
1260         }
1261
1262         u32 vertex_count = p->vertices.size();
1263         for(u32 i=0; i<numIndices; i++)
1264         {
1265                 u32 j = indices[i] + vertex_count;
1266                 if(j > 65535)
1267                 {
1268                         dstream<<"FIXME: Meshbuffer ran out of indices"<<std::endl;
1269                         // NOTE: Fix is to just add an another MeshBuffer
1270                 }
1271                 p->indices.push_back(j);
1272         }
1273         for(u32 i=0; i<numVertices; i++)
1274         {
1275                 p->vertices.push_back(vertices[i]);
1276         }
1277 }