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