]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapblock_mesh.cpp
Fix MinGW build
[dragonfireclient.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         if (facedir > 23)
715                 facedir = 0;
716         static const u16 dir_to_tile[24 * 16] =
717         {
718                 // 0     +X    +Y    +Z           -Z    -Y    -X   ->   value=tile,rotation  
719                    0,0,  2,0 , 0,0 , 4,0 ,  0,0,  5,0 , 1,0 , 3,0 ,  // rotate around y+ 0 - 3
720                    0,0,  4,0 , 0,3 , 3,0 ,  0,0,  2,0 , 1,1 , 5,0 ,
721                    0,0,  3,0 , 0,2 , 5,0 ,  0,0,  4,0 , 1,2 , 2,0 ,
722                    0,0,  5,0 , 0,1 , 2,0 ,  0,0,  3,0 , 1,3 , 4,0 ,
723
724                    0,0,  2,3 , 5,0 , 0,2 ,  0,0,  1,0 , 4,2 , 3,1 ,  // rotate around z+ 4 - 7
725                    0,0,  4,3 , 2,0 , 0,3 ,  0,0,  1,1 , 3,2 , 5,1 ,
726                    0,0,  3,3 , 4,0 , 0,0 ,  0,0,  1,2 , 5,2 , 2,1 ,
727                    0,0,  5,3 , 3,0 , 0,1 ,  0,0,  1,3 , 2,2 , 4,1 ,
728
729                    0,0,  2,1 , 4,2 , 1,2 ,  0,0,  0,0 , 5,0 , 3,3 ,  // rotate around z- 8 - 11
730                    0,0,  4,1 , 3,2 , 1,3 ,  0,0,  0,3 , 2,0 , 5,3 ,
731                    0,0,  3,1 , 5,2 , 1,0 ,  0,0,  0,2 , 4,0 , 2,3 ,
732                    0,0,  5,1 , 2,2 , 1,1 ,  0,0,  0,1 , 3,0 , 4,3 ,
733
734                    0,0,  0,3 , 3,3 , 4,1 ,  0,0,  5,3 , 2,3 , 1,3 ,  // rotate around x+ 12 - 15
735                    0,0,  0,2 , 5,3 , 3,1 ,  0,0,  2,3 , 4,3 , 1,0 ,
736                    0,0,  0,1 , 2,3 , 5,1 ,  0,0,  4,3 , 3,3 , 1,1 ,
737                    0,0,  0,0 , 4,3 , 2,1 ,  0,0,  3,3 , 5,3 , 1,2 ,
738
739                    0,0,  1,1 , 2,1 , 4,3 ,  0,0,  5,1 , 3,1 , 0,1 ,  // rotate around x- 16 - 19  
740                    0,0,  1,2 , 4,1 , 3,3 ,  0,0,  2,1 , 5,1 , 0,0 ,
741                    0,0,  1,3 , 3,1 , 5,3 ,  0,0,  4,1 , 2,1 , 0,3 ,  
742                    0,0,  1,0 , 5,1 , 2,3 ,  0,0,  3,1 , 4,1 , 0,2 ,  
743
744                    0,0,  3,2 , 1,2 , 4,2 ,  0,0,  5,2 , 0,2 , 2,2 ,  // rotate around y- 20 - 23
745                    0,0,  5,2 , 1,3 , 3,2 ,  0,0,  2,2 , 0,1 , 4,2 ,  
746                    0,0,  2,2 , 1,0 , 5,2 ,  0,0,  4,2 , 0,0 , 3,2 ,  
747                    0,0,  4,2 , 1,1 , 2,2 ,  0,0,  3,2 , 0,3 , 5,2   
748
749         };
750         u16 tile_index=facedir*16 + dir_i;
751         TileSpec spec = getNodeTileN(mn, p, dir_to_tile[tile_index], data);
752         spec.rotation=dir_to_tile[tile_index + 1];
753         spec.texture = data->m_gamedef->tsrc()->getTexture(spec.texture_id);
754         return spec;
755 }
756
757 static void getTileInfo(
758                 // Input:
759                 MeshMakeData *data,
760                 v3s16 p,
761                 v3s16 face_dir,
762                 // Output:
763                 bool &makes_face,
764                 v3s16 &p_corrected,
765                 v3s16 &face_dir_corrected,
766                 u16 *lights,
767                 TileSpec &tile,
768                 u8 &light_source
769         )
770 {
771         VoxelManipulator &vmanip = data->m_vmanip;
772         INodeDefManager *ndef = data->m_gamedef->ndef();
773         v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
774
775         MapNode n0 = vmanip.getNodeNoEx(blockpos_nodes + p);
776         MapNode n1 = vmanip.getNodeNoEx(blockpos_nodes + p + face_dir);
777         TileSpec tile0 = getNodeTile(n0, p, face_dir, data);
778         TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir, data);
779         
780         // This is hackish
781         bool equivalent = false;
782         u8 mf = face_contents(n0.getContent(), n1.getContent(),
783                         &equivalent, ndef);
784
785         if(mf == 0)
786         {
787                 makes_face = false;
788                 return;
789         }
790
791         makes_face = true;
792         
793         if(mf == 1)
794         {
795                 tile = tile0;
796                 p_corrected = p;
797                 face_dir_corrected = face_dir;
798                 light_source = ndef->get(n0).light_source;
799         }
800         else
801         {
802                 tile = tile1;
803                 p_corrected = p + face_dir;
804                 face_dir_corrected = -face_dir;
805                 light_source = ndef->get(n1).light_source;
806         }
807         
808         // eg. water and glass
809         if(equivalent)
810                 tile.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
811
812         if(data->m_smooth_lighting == false)
813         {
814                 lights[0] = lights[1] = lights[2] = lights[3] =
815                                 getFaceLight(n0, n1, face_dir, data);
816         }
817         else
818         {
819                 v3s16 vertex_dirs[4];
820                 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
821                 for(u16 i=0; i<4; i++)
822                 {
823                         lights[i] = getSmoothLight(
824                                         blockpos_nodes + p_corrected,
825                                         vertex_dirs[i], data);
826                 }
827         }
828         
829         return;
830 }
831
832 /*
833         startpos:
834         translate_dir: unit vector with only one of x, y or z
835         face_dir: unit vector with only one of x, y or z
836 */
837 static void updateFastFaceRow(
838                 MeshMakeData *data,
839                 v3s16 startpos,
840                 v3s16 translate_dir,
841                 v3f translate_dir_f,
842                 v3s16 face_dir,
843                 v3f face_dir_f,
844                 std::vector<FastFace> &dest)
845 {
846         v3s16 p = startpos;
847         
848         u16 continuous_tiles_count = 0;
849         
850         bool makes_face = false;
851         v3s16 p_corrected;
852         v3s16 face_dir_corrected;
853         u16 lights[4] = {0,0,0,0};
854         TileSpec tile;
855         u8 light_source = 0;
856         getTileInfo(data, p, face_dir, 
857                         makes_face, p_corrected, face_dir_corrected,
858                         lights, tile, light_source);
859
860         for(u16 j=0; j<MAP_BLOCKSIZE; j++)
861         {
862                 // If tiling can be done, this is set to false in the next step
863                 bool next_is_different = true;
864                 
865                 v3s16 p_next;
866                 
867                 bool next_makes_face = false;
868                 v3s16 next_p_corrected;
869                 v3s16 next_face_dir_corrected;
870                 u16 next_lights[4] = {0,0,0,0};
871                 TileSpec next_tile;
872                 u8 next_light_source = 0;
873                 
874                 // If at last position, there is nothing to compare to and
875                 // the face must be drawn anyway
876                 if(j != MAP_BLOCKSIZE - 1)
877                 {
878                         p_next = p + translate_dir;
879                         
880                         getTileInfo(data, p_next, face_dir,
881                                         next_makes_face, next_p_corrected,
882                                         next_face_dir_corrected, next_lights,
883                                         next_tile, next_light_source);
884                         
885                         if(next_makes_face == makes_face
886                                         && next_p_corrected == p_corrected + translate_dir
887                                         && next_face_dir_corrected == face_dir_corrected
888                                         && next_lights[0] == lights[0]
889                                         && next_lights[1] == lights[1]
890                                         && next_lights[2] == lights[2]
891                                         && next_lights[3] == lights[3]
892                                         && next_tile == tile
893                                         && tile.rotation == 0
894                                         && next_light_source == light_source)
895                         {
896                                 next_is_different = false;
897                         }
898                         else{
899                                 /*if(makes_face){
900                                         g_profiler->add("Meshgen: diff: next_makes_face != makes_face",
901                                                         next_makes_face != makes_face ? 1 : 0);
902                                         g_profiler->add("Meshgen: diff: n_p_corr != p_corr + t_dir",
903                                                         (next_p_corrected != p_corrected + translate_dir) ? 1 : 0);
904                                         g_profiler->add("Meshgen: diff: next_f_dir_corr != f_dir_corr",
905                                                         next_face_dir_corrected != face_dir_corrected ? 1 : 0);
906                                         g_profiler->add("Meshgen: diff: next_lights[] != lights[]",
907                                                         (next_lights[0] != lights[0] ||
908                                                         next_lights[0] != lights[0] ||
909                                                         next_lights[0] != lights[0] ||
910                                                         next_lights[0] != lights[0]) ? 1 : 0);
911                                         g_profiler->add("Meshgen: diff: !(next_tile == tile)",
912                                                         !(next_tile == tile) ? 1 : 0);
913                                 }*/
914                         }
915                         /*g_profiler->add("Meshgen: Total faces checked", 1);
916                         if(makes_face)
917                                 g_profiler->add("Meshgen: Total makes_face checked", 1);*/
918                 } else {
919                         /*if(makes_face)
920                                 g_profiler->add("Meshgen: diff: last position", 1);*/
921                 }
922
923                 continuous_tiles_count++;
924                 
925                 if(next_is_different)
926                 {
927                         /*
928                                 Create a face if there should be one
929                         */
930                         if(makes_face)
931                         {
932                                 // Floating point conversion of the position vector
933                                 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
934                                 // Center point of face (kind of)
935                                 v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
936                                 if(continuous_tiles_count != 1)
937                                         sp += translate_dir_f;
938                                 v3f scale(1,1,1);
939
940                                 if(translate_dir.X != 0)
941                                 {
942                                         scale.X = continuous_tiles_count;
943                                 }
944                                 if(translate_dir.Y != 0)
945                                 {
946                                         scale.Y = continuous_tiles_count;
947                                 }
948                                 if(translate_dir.Z != 0)
949                                 {
950                                         scale.Z = continuous_tiles_count;
951                                 }
952                                 
953                                 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
954                                                 sp, face_dir_corrected, scale, light_source,
955                                                 dest);
956                                 
957                                 g_profiler->avg("Meshgen: faces drawn by tiling", 0);
958                                 for(int i=1; i<continuous_tiles_count; i++){
959                                         g_profiler->avg("Meshgen: faces drawn by tiling", 1);
960                                 }
961                         }
962
963                         continuous_tiles_count = 0;
964                         
965                         makes_face = next_makes_face;
966                         p_corrected = next_p_corrected;
967                         face_dir_corrected = next_face_dir_corrected;
968                         lights[0] = next_lights[0];
969                         lights[1] = next_lights[1];
970                         lights[2] = next_lights[2];
971                         lights[3] = next_lights[3];
972                         tile = next_tile;
973                         light_source = next_light_source;
974                 }
975                 
976                 p = p_next;
977         }
978 }
979
980 static void updateAllFastFaceRows(MeshMakeData *data,
981                 std::vector<FastFace> &dest)
982 {
983         /*
984                 Go through every y,z and get top(y+) faces in rows of x+
985         */
986         for(s16 y=0; y<MAP_BLOCKSIZE; y++){
987                 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
988                         updateFastFaceRow(data,
989                                         v3s16(0,y,z),
990                                         v3s16(1,0,0), //dir
991                                         v3f  (1,0,0),
992                                         v3s16(0,1,0), //face dir
993                                         v3f  (0,1,0),
994                                         dest);
995                 }
996         }
997
998         /*
999                 Go through every x,y and get right(x+) faces in rows of z+
1000         */
1001         for(s16 x=0; x<MAP_BLOCKSIZE; x++){
1002                 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
1003                         updateFastFaceRow(data,
1004                                         v3s16(x,y,0),
1005                                         v3s16(0,0,1), //dir
1006                                         v3f  (0,0,1),
1007                                         v3s16(1,0,0), //face dir
1008                                         v3f  (1,0,0),
1009                                         dest);
1010                 }
1011         }
1012
1013         /*
1014                 Go through every y,z and get back(z+) faces in rows of x+
1015         */
1016         for(s16 z=0; z<MAP_BLOCKSIZE; z++){
1017                 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
1018                         updateFastFaceRow(data,
1019                                         v3s16(0,y,z),
1020                                         v3s16(1,0,0), //dir
1021                                         v3f  (1,0,0),
1022                                         v3s16(0,0,1), //face dir
1023                                         v3f  (0,0,1),
1024                                         dest);
1025                 }
1026         }
1027 }
1028
1029 /*
1030         MapBlockMesh
1031 */
1032
1033 MapBlockMesh::MapBlockMesh(MeshMakeData *data):
1034         m_mesh(new scene::SMesh()),
1035         m_gamedef(data->m_gamedef),
1036         m_animation_force_timer(0), // force initial animation
1037         m_last_crack(-1),
1038         m_crack_materials(),
1039         m_last_daynight_ratio((u32) -1),
1040         m_daynight_diffs()
1041 {
1042         // 4-21ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1043         // 24-155ms for MAP_BLOCKSIZE=32  (NOTE: probably outdated)
1044         //TimeTaker timer1("MapBlockMesh()");
1045
1046         std::vector<FastFace> fastfaces_new;
1047
1048         /*
1049                 We are including the faces of the trailing edges of the block.
1050                 This means that when something changes, the caller must
1051                 also update the meshes of the blocks at the leading edges.
1052
1053                 NOTE: This is the slowest part of this method.
1054         */
1055         {
1056                 // 4-23ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1057                 //TimeTaker timer2("updateAllFastFaceRows()");
1058                 updateAllFastFaceRows(data, fastfaces_new);
1059         }
1060         // End of slow part
1061
1062         /*
1063                 Convert FastFaces to MeshCollector
1064         */
1065
1066         MeshCollector collector;
1067
1068         {
1069                 // avg 0ms (100ms spikes when loading textures the first time)
1070                 // (NOTE: probably outdated)
1071                 //TimeTaker timer2("MeshCollector building");
1072
1073                 for(u32 i=0; i<fastfaces_new.size(); i++)
1074                 {
1075                         FastFace &f = fastfaces_new[i];
1076
1077                         const u16 indices[] = {0,1,2,2,3,0};
1078                         const u16 indices_alternate[] = {0,1,3,2,3,1};
1079                         
1080                         if(f.tile.texture == NULL)
1081                                 continue;
1082
1083                         const u16 *indices_p = indices;
1084                         
1085                         /*
1086                                 Revert triangles for nicer looking gradient if vertices
1087                                 1 and 3 have same color or 0 and 2 have different color.
1088                                 getRed() is the day color.
1089                         */
1090                         if(f.vertices[0].Color.getRed() != f.vertices[2].Color.getRed()
1091                                         || f.vertices[1].Color.getRed() == f.vertices[3].Color.getRed())
1092                                 indices_p = indices_alternate;
1093                         
1094                         collector.append(f.tile, f.vertices, 4, indices_p, 6);
1095                 }
1096         }
1097
1098         /*
1099                 Add special graphics:
1100                 - torches
1101                 - flowing water
1102                 - fences
1103                 - whatever
1104         */
1105
1106         mapblock_mesh_generate_special(data, collector);
1107         
1108
1109         /*
1110                 Convert MeshCollector to SMesh
1111         */
1112         bool enable_shaders     = g_settings->getBool("enable_shaders");
1113         bool enable_bumpmapping = g_settings->getBool("enable_bumpmapping");
1114
1115         video::E_MATERIAL_TYPE  shadermat1, shadermat2, shadermat3, bumpmaps1, bumpmaps2;
1116         shadermat1 = shadermat2 = shadermat3 = bumpmaps1 = bumpmaps2 = video::EMT_SOLID;
1117
1118         if (enable_shaders) {
1119                 IShaderSource *shdrsrc = m_gamedef->getShaderSource();
1120                 shadermat1 = shdrsrc->getShader("test_shader_1").material;
1121                 shadermat2 = shdrsrc->getShader("test_shader_2").material;
1122                 shadermat3 = shdrsrc->getShader("test_shader_3").material;
1123                 if (enable_bumpmapping) {
1124                         bumpmaps1 = shdrsrc->getShader("bumpmaps_solids").material;
1125                         bumpmaps2 = shdrsrc->getShader("bumpmaps_liquids").material;
1126                 }
1127         }
1128
1129         for(u32 i = 0; i < collector.prebuffers.size(); i++)
1130         {
1131                 PreMeshBuffer &p = collector.prebuffers[i];
1132                 /*dstream<<"p.vertices.size()="<<p.vertices.size()
1133                                 <<", p.indices.size()="<<p.indices.size()
1134                                 <<std::endl;*/
1135
1136                 // Generate animation data
1137                 // - Cracks
1138                 if(p.tile.material_flags & MATERIAL_FLAG_CRACK)
1139                 {
1140                         ITextureSource *tsrc = data->m_gamedef->tsrc();
1141                         // Find the texture name plus ^[crack:N:
1142                         std::ostringstream os(std::ios::binary);
1143                         os<<tsrc->getTextureName(p.tile.texture_id)<<"^[crack";
1144                         if(p.tile.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1145                                 os<<"o";  // use ^[cracko
1146                         os<<":"<<(u32)p.tile.animation_frame_count<<":";
1147                         m_crack_materials.insert(std::make_pair(i, os.str()));
1148                         // Replace tile texture with the cracked one
1149                         p.tile.texture = tsrc->getTexture(
1150                                         os.str()+"0",
1151                                         &p.tile.texture_id);
1152                 }
1153                 // - Texture animation
1154                 if(p.tile.material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
1155                 {
1156                         ITextureSource *tsrc = data->m_gamedef->tsrc();
1157                         // Add to MapBlockMesh in order to animate these tiles
1158                         m_animation_tiles[i] = p.tile;
1159                         m_animation_frames[i] = 0;
1160                         if(g_settings->getBool("desynchronize_mapblock_texture_animation")){
1161                                 // Get starting position from noise
1162                                 m_animation_frame_offsets[i] = 100000 * (2.0 + noise3d(
1163                                                 data->m_blockpos.X, data->m_blockpos.Y,
1164                                                 data->m_blockpos.Z, 0));
1165                         } else {
1166                                 // Play all synchronized
1167                                 m_animation_frame_offsets[i] = 0;
1168                         }
1169                         // Replace tile texture with the first animation frame
1170                         std::ostringstream os(std::ios::binary);
1171                         os<<tsrc->getTextureName(p.tile.texture_id);
1172                         os<<"^[verticalframe:"<<(int)p.tile.animation_frame_count<<":0";
1173                         p.tile.texture = tsrc->getTexture(
1174                                         os.str(),
1175                                         &p.tile.texture_id);
1176                 }
1177                 // - Classic lighting (shaders handle this by themselves)
1178                 if(!enable_shaders)
1179                 {
1180                         for(u32 j = 0; j < p.vertices.size(); j++)
1181                         {
1182                                 video::SColor &vc = p.vertices[j].Color;
1183                                 // Set initial real color and store for later updates
1184                                 u8 day = vc.getRed();
1185                                 u8 night = vc.getGreen();
1186                                 finalColorBlend(vc, day, night, 1000);
1187                                 if(day != night)
1188                                         m_daynight_diffs[i][j] = std::make_pair(day, night);
1189                                 // Brighten topside (no shaders)
1190                                 if(p.vertices[j].Normal.Y > 0.5)
1191                                 {
1192                                         vc.setRed  (srgb_linear_multiply(vc.getRed(),   1.3, 255.0));
1193                                         vc.setGreen(srgb_linear_multiply(vc.getGreen(), 1.3, 255.0));
1194                                         vc.setBlue (srgb_linear_multiply(vc.getBlue(),  1.3, 255.0));
1195                                 }
1196                         }
1197                 }
1198
1199                 // Create material
1200                 video::SMaterial material;
1201                 material.setFlag(video::EMF_LIGHTING, false);
1202                 material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1203                 material.setFlag(video::EMF_BILINEAR_FILTER, false);
1204                 material.setFlag(video::EMF_FOG_ENABLE, true);
1205                 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
1206                 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE);
1207                 material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
1208                 material.setTexture(0, p.tile.texture);
1209         
1210                 if (enable_shaders) {
1211                         video::E_MATERIAL_TYPE smat1 = shadermat1;
1212                         video::E_MATERIAL_TYPE smat2 = shadermat2;
1213                         video::E_MATERIAL_TYPE smat3 = shadermat3;
1214                         
1215                         if (enable_bumpmapping) {
1216                                 ITextureSource *tsrc = data->m_gamedef->tsrc();
1217                                 std::string fname_base = tsrc->getTextureName(p.tile.texture_id);
1218
1219                                 std::string normal_ext = "_normal.png";
1220                                 size_t pos = fname_base.find(".");
1221                                 std::string fname_normal = fname_base.substr(0, pos) + normal_ext;
1222                                 
1223                                 if (tsrc->isKnownSourceImage(fname_normal)) {
1224                                         // look for image extension and replace it 
1225                                         size_t i = 0;
1226                                         while ((i = fname_base.find(".", i)) != std::string::npos) {
1227                                                 fname_base.replace(i, 4, normal_ext);
1228                                                 i += normal_ext.length();
1229                                         }
1230                                         
1231                                         material.setTexture(1, tsrc->getTexture(fname_base));
1232                                         
1233                                         smat1 = bumpmaps1;
1234                                         smat2 = bumpmaps2;
1235                                 }
1236                         }
1237                         
1238                         p.tile.applyMaterialOptionsWithShaders(material, smat1, smat2, smat3);
1239                 } else {
1240                         p.tile.applyMaterialOptions(material);
1241                 }
1242
1243                 // Create meshbuffer
1244
1245                 // This is a "Standard MeshBuffer",
1246                 // it's a typedeffed CMeshBuffer<video::S3DVertex>
1247                 scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1248                 // Set material
1249                 buf->Material = material;
1250                 // Add to mesh
1251                 m_mesh->addMeshBuffer(buf);
1252                 // Mesh grabbed it
1253                 buf->drop();
1254                 buf->append(&p.vertices[0], p.vertices.size(),
1255                                 &p.indices[0], p.indices.size());
1256         }
1257
1258         /*
1259                 Do some stuff to the mesh
1260         */
1261
1262         translateMesh(m_mesh, intToFloat(data->m_blockpos * MAP_BLOCKSIZE, BS));
1263
1264         if(m_mesh)
1265         {
1266 #if 0
1267                 // Usually 1-700 faces and 1-7 materials
1268                 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
1269                                 <<"and uses "<<m_mesh->getMeshBufferCount()
1270                                 <<" materials (meshbuffers)"<<std::endl;
1271 #endif
1272
1273                 // Use VBO for mesh (this just would set this for ever buffer)
1274                 // This will lead to infinite memory usage because or irrlicht.
1275                 //m_mesh->setHardwareMappingHint(scene::EHM_STATIC);
1276
1277                 /*
1278                         NOTE: If that is enabled, some kind of a queue to the main
1279                         thread should be made which would call irrlicht to delete
1280                         the hardware buffer and then delete the mesh
1281                 */
1282         }
1283         
1284         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1285
1286         // Check if animation is required for this mesh
1287         m_has_animation =
1288                 !m_crack_materials.empty() ||
1289                 !m_daynight_diffs.empty() ||
1290                 !m_animation_tiles.empty();
1291 }
1292
1293 MapBlockMesh::~MapBlockMesh()
1294 {
1295         m_mesh->drop();
1296         m_mesh = NULL;
1297 }
1298
1299 bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_ratio)
1300 {
1301         bool enable_shaders = g_settings->getBool("enable_shaders");
1302         bool enable_bumpmapping = g_settings->getBool("enable_bumpmapping");
1303         
1304         if(!m_has_animation)
1305         {
1306                 m_animation_force_timer = 100000;
1307                 return false;
1308         }
1309
1310         m_animation_force_timer = myrand_range(5, 100);
1311
1312         // Cracks
1313         if(crack != m_last_crack)
1314         {
1315                 for(std::map<u32, std::string>::iterator
1316                                 i = m_crack_materials.begin();
1317                                 i != m_crack_materials.end(); i++)
1318                 {
1319                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1320                         std::string basename = i->second;
1321
1322                         // Create new texture name from original
1323                         ITextureSource *tsrc = m_gamedef->getTextureSource();
1324                         std::ostringstream os;
1325                         os<<basename<<crack;
1326                         u32 new_texture_id = 0;
1327                         video::ITexture *new_texture =
1328                                 tsrc->getTexture(os.str(), &new_texture_id);
1329                         buf->getMaterial().setTexture(0, new_texture);
1330
1331                         // If the current material is also animated,
1332                         // update animation info
1333                         std::map<u32, TileSpec>::iterator anim_iter =
1334                                 m_animation_tiles.find(i->first);
1335                         if(anim_iter != m_animation_tiles.end()){
1336                                 TileSpec &tile = anim_iter->second;
1337                                 tile.texture = new_texture;
1338                                 tile.texture_id = new_texture_id;
1339                                 // force animation update
1340                                 m_animation_frames[i->first] = -1;
1341                         }
1342                 }
1343
1344                 m_last_crack = crack;
1345         }
1346         
1347         // Texture animation
1348         for(std::map<u32, TileSpec>::iterator
1349                         i = m_animation_tiles.begin();
1350                         i != m_animation_tiles.end(); i++)
1351         {
1352                 const TileSpec &tile = i->second;
1353                 // Figure out current frame
1354                 int frameoffset = m_animation_frame_offsets[i->first];
1355                 int frame = (int)(time * 1000 / tile.animation_frame_length_ms
1356                                 + frameoffset) % tile.animation_frame_count;
1357                 // If frame doesn't change, skip
1358                 if(frame == m_animation_frames[i->first])
1359                         continue;
1360
1361                 m_animation_frames[i->first] = frame;
1362
1363                 scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1364                 ITextureSource *tsrc = m_gamedef->getTextureSource();
1365
1366                 // Create new texture name from original
1367                 std::ostringstream os(std::ios::binary);
1368                 os<<tsrc->getTextureName(tile.texture_id);
1369                 os<<"^[verticalframe:"<<(int)tile.animation_frame_count<<":"<<frame;
1370                 // Set the texture
1371                 buf->getMaterial().setTexture(0, tsrc->getTexture(os.str()));
1372                 if (enable_shaders && enable_bumpmapping)
1373                         {
1374                                 std::string basename,normal;
1375                                 basename = tsrc->getTextureName(tile.texture_id);
1376                                 unsigned pos;
1377                                 pos = basename.find(".");
1378                                 normal = basename.substr (0, pos);
1379                                 normal += "_normal.png";
1380                                 os.str("");
1381                                 os<<normal<<"^[verticalframe:"<<(int)tile.animation_frame_count<<":"<<frame;
1382                                 if (tsrc->isKnownSourceImage(normal))
1383                                         buf->getMaterial().setTexture(1, tsrc->getTexture(os.str()));
1384                         }
1385         }
1386
1387         // Day-night transition
1388         if(daynight_ratio != m_last_daynight_ratio)
1389         {
1390                 for(std::map<u32, std::map<u32, std::pair<u8, u8> > >::iterator
1391                                 i = m_daynight_diffs.begin();
1392                                 i != m_daynight_diffs.end(); i++)
1393                 {
1394                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1395                         video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
1396                         for(std::map<u32, std::pair<u8, u8 > >::iterator
1397                                         j = i->second.begin();
1398                                         j != i->second.end(); j++)
1399                         {
1400                                 u32 vertexIndex = j->first;
1401                                 u8 day = j->second.first;
1402                                 u8 night = j->second.second;
1403                                 finalColorBlend(vertices[vertexIndex].Color,
1404                                                 day, night, daynight_ratio);
1405                                 // Brighten topside (no shaders)
1406                                 if(vertices[vertexIndex].Normal.Y > 0.5)
1407                                 {
1408                                         video::SColor &vc = vertices[vertexIndex].Color;
1409                                         vc.setRed  (srgb_linear_multiply(vc.getRed(),   1.3, 255.0));
1410                                         vc.setGreen(srgb_linear_multiply(vc.getGreen(), 1.3, 255.0));
1411                                         vc.setBlue (srgb_linear_multiply(vc.getBlue(),  1.3, 255.0));
1412                                 }
1413                         }
1414                 }
1415                 m_last_daynight_ratio = daynight_ratio;
1416         }
1417
1418         return true;
1419 }
1420
1421 /*
1422         MeshCollector
1423 */
1424
1425 void MeshCollector::append(const TileSpec &tile,
1426                 const video::S3DVertex *vertices, u32 numVertices,
1427                 const u16 *indices, u32 numIndices)
1428 {
1429         if(numIndices > 65535)
1430         {
1431                 dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1432                 return;
1433         }
1434
1435         PreMeshBuffer *p = NULL;
1436         for(u32 i=0; i<prebuffers.size(); i++)
1437         {
1438                 PreMeshBuffer &pp = prebuffers[i];
1439                 if(pp.tile != tile)
1440                         continue;
1441                 if(pp.indices.size() + numIndices > 65535)
1442                         continue;
1443
1444                 p = &pp;
1445                 break;
1446         }
1447
1448         if(p == NULL)
1449         {
1450                 PreMeshBuffer pp;
1451                 pp.tile = tile;
1452                 prebuffers.push_back(pp);
1453                 p = &prebuffers[prebuffers.size()-1];
1454         }
1455
1456         u32 vertex_count = p->vertices.size();
1457         for(u32 i=0; i<numIndices; i++)
1458         {
1459                 u32 j = indices[i] + vertex_count;
1460                 p->indices.push_back(j);
1461         }
1462         for(u32 i=0; i<numVertices; i++)
1463         {
1464                 p->vertices.push_back(vertices[i]);
1465         }
1466 }