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