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