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