]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapblock_mesh.cpp
f76033ea8a5bb16b8fab0ad27275a6b4fd8e32ef
[dragonfireclient.git] / src / mapblock_mesh.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "mapblock_mesh.h"
21 #include "light.h"
22 #include "mapblock.h"
23 #include "map.h"
24 #include "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         for(u16 j=0; j<MAP_BLOCKSIZE; j++)
859         {
860                 // If tiling can be done, this is set to false in the next step
861                 bool next_is_different = true;
862
863                 v3s16 p_next;
864
865                 bool next_makes_face = false;
866                 v3s16 next_p_corrected;
867                 v3s16 next_face_dir_corrected;
868                 u16 next_lights[4] = {0,0,0,0};
869                 TileSpec next_tile;
870
871                 // If at last position, there is nothing to compare to and
872                 // the face must be drawn anyway
873                 if(j != MAP_BLOCKSIZE - 1)
874                 {
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                         } else {
898                                 /*if(makes_face){
899                                         g_profiler->add("Meshgen: diff: next_makes_face != makes_face",
900                                                         next_makes_face != makes_face ? 1 : 0);
901                                         g_profiler->add("Meshgen: diff: n_p_corr != p_corr + t_dir",
902                                                         (next_p_corrected != p_corrected + translate_dir) ? 1 : 0);
903                                         g_profiler->add("Meshgen: diff: next_f_dir_corr != f_dir_corr",
904                                                         next_face_dir_corrected != face_dir_corrected ? 1 : 0);
905                                         g_profiler->add("Meshgen: diff: next_lights[] != lights[]",
906                                                         (next_lights[0] != lights[0] ||
907                                                         next_lights[0] != lights[0] ||
908                                                         next_lights[0] != lights[0] ||
909                                                         next_lights[0] != lights[0]) ? 1 : 0);
910                                         g_profiler->add("Meshgen: diff: !(next_tile == tile)",
911                                                         !(next_tile == tile) ? 1 : 0);
912                                 }*/
913                         }
914                         /*g_profiler->add("Meshgen: Total faces checked", 1);
915                         if(makes_face)
916                                 g_profiler->add("Meshgen: Total makes_face checked", 1);*/
917                 } else {
918                         /*if(makes_face)
919                                 g_profiler->add("Meshgen: diff: last position", 1);*/
920                 }
921
922                 if(next_is_different)
923                 {
924                         /*
925                                 Create a face if there should be one
926                         */
927                         if(makes_face)
928                         {
929                                 // Floating point conversion of the position vector
930                                 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
931                                 // Center point of face (kind of)
932                                 v3f sp = pf - ((f32)continuous_tiles_count / 2.0 - 0.5) * translate_dir_f;
933                                 v3f scale(1,1,1);
934
935                                 if(translate_dir.X != 0) {
936                                         scale.X = continuous_tiles_count;
937                                 }
938                                 if(translate_dir.Y != 0) {
939                                         scale.Y = continuous_tiles_count;
940                                 }
941                                 if(translate_dir.Z != 0) {
942                                         scale.Z = continuous_tiles_count;
943                                 }
944
945                                 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
946                                                 sp, face_dir_corrected, scale, dest);
947
948                                 g_profiler->avg("Meshgen: faces drawn by tiling", 0);
949                                 for(int i = 1; i < continuous_tiles_count; i++){
950                                         g_profiler->avg("Meshgen: faces drawn by tiling", 1);
951                                 }
952                         }
953
954                         continuous_tiles_count = 1;
955                 }
956
957                 makes_face = next_makes_face;
958                 p_corrected = next_p_corrected;
959                 face_dir_corrected = next_face_dir_corrected;
960                 lights[0] = next_lights[0];
961                 lights[1] = next_lights[1];
962                 lights[2] = next_lights[2];
963                 lights[3] = next_lights[3];
964                 tile = next_tile;
965                 p = p_next;
966         }
967 }
968
969 static void updateAllFastFaceRows(MeshMakeData *data,
970                 std::vector<FastFace> &dest)
971 {
972         /*
973                 Go through every y,z and get top(y+) faces in rows of x+
974         */
975         for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
976                 for(s16 z = 0; z < MAP_BLOCKSIZE; z++) {
977                         updateFastFaceRow(data,
978                                         v3s16(0,y,z),
979                                         v3s16(1,0,0), //dir
980                                         v3f  (1,0,0),
981                                         v3s16(0,1,0), //face dir
982                                         v3f  (0,1,0),
983                                         dest);
984                 }
985         }
986
987         /*
988                 Go through every x,y and get right(x+) faces in rows of z+
989         */
990         for(s16 x = 0; x < MAP_BLOCKSIZE; x++) {
991                 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
992                         updateFastFaceRow(data,
993                                         v3s16(x,y,0),
994                                         v3s16(0,0,1), //dir
995                                         v3f  (0,0,1),
996                                         v3s16(1,0,0), //face dir
997                                         v3f  (1,0,0),
998                                         dest);
999                 }
1000         }
1001
1002         /*
1003                 Go through every y,z and get back(z+) faces in rows of x+
1004         */
1005         for(s16 z = 0; z < MAP_BLOCKSIZE; z++) {
1006                 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
1007                         updateFastFaceRow(data,
1008                                         v3s16(0,y,z),
1009                                         v3s16(1,0,0), //dir
1010                                         v3f  (1,0,0),
1011                                         v3s16(0,0,1), //face dir
1012                                         v3f  (0,0,1),
1013                                         dest);
1014                 }
1015         }
1016 }
1017
1018 /*
1019         MapBlockMesh
1020 */
1021
1022 MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
1023         m_mesh(new scene::SMesh()),
1024         m_minimap_mapblock(NULL),
1025         m_client(data->m_client),
1026         m_driver(m_client->tsrc()->getDevice()->getVideoDriver()),
1027         m_tsrc(m_client->getTextureSource()),
1028         m_shdrsrc(m_client->getShaderSource()),
1029         m_animation_force_timer(0), // force initial animation
1030         m_last_crack(-1),
1031         m_crack_materials(),
1032         m_last_daynight_ratio((u32) -1),
1033         m_daynight_diffs()
1034 {
1035         m_enable_shaders = data->m_use_shaders;
1036         m_use_tangent_vertices = data->m_use_tangent_vertices;
1037         m_enable_vbo = g_settings->getBool("enable_vbo");
1038
1039         if (g_settings->getBool("enable_minimap")) {
1040                 m_minimap_mapblock = new MinimapMapblock;
1041                 m_minimap_mapblock->getMinimapNodes(
1042                         &data->m_vmanip, data->m_blockpos * MAP_BLOCKSIZE);
1043         }
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         fastfaces_new.reserve(512);
1051
1052         /*
1053                 We are including the faces of the trailing edges of the block.
1054                 This means that when something changes, the caller must
1055                 also update the meshes of the blocks at the leading edges.
1056
1057                 NOTE: This is the slowest part of this method.
1058         */
1059         {
1060                 // 4-23ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1061                 //TimeTaker timer2("updateAllFastFaceRows()");
1062                 updateAllFastFaceRows(data, fastfaces_new);
1063         }
1064         // End of slow part
1065
1066         /*
1067                 Convert FastFaces to MeshCollector
1068         */
1069
1070         MeshCollector collector(m_use_tangent_vertices);
1071
1072         {
1073                 // avg 0ms (100ms spikes when loading textures the first time)
1074                 // (NOTE: probably outdated)
1075                 //TimeTaker timer2("MeshCollector building");
1076
1077                 for (u32 i = 0; i < fastfaces_new.size(); i++) {
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 the
1090                                 brightness of vertices 1 and 3 differ less than
1091                                 the brightness of vertices 0 and 2.
1092                         */
1093                         if (fabs(f.vertices[0].Color.getLuminance()
1094                                         - f.vertices[2].Color.getLuminance())
1095                                         > fabs(f.vertices[1].Color.getLuminance()
1096                                         - f.vertices[3].Color.getLuminance()))
1097                                 indices_p = indices_alternate;
1098
1099                         collector.append(f.tile, f.vertices, 4, indices_p, 6);
1100                 }
1101         }
1102
1103         /*
1104                 Add special graphics:
1105                 - torches
1106                 - flowing water
1107                 - fences
1108                 - whatever
1109         */
1110
1111         {
1112                 MapblockMeshGenerator generator(data, &collector);
1113                 generator.generate();
1114         }
1115
1116         /*
1117                 Convert MeshCollector to SMesh
1118         */
1119
1120         for(u32 i = 0; i < collector.prebuffers.size(); i++)
1121         {
1122                 PreMeshBuffer &p = collector.prebuffers[i];
1123
1124                 // Generate animation data
1125                 // - Cracks
1126                 if(p.tile.material_flags & MATERIAL_FLAG_CRACK)
1127                 {
1128                         // Find the texture name plus ^[crack:N:
1129                         std::ostringstream os(std::ios::binary);
1130                         os<<m_tsrc->getTextureName(p.tile.texture_id)<<"^[crack";
1131                         if(p.tile.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1132                                 os<<"o";  // use ^[cracko
1133                         os<<":"<<(u32)p.tile.animation_frame_count<<":";
1134                         m_crack_materials.insert(std::make_pair(i, os.str()));
1135                         // Replace tile texture with the cracked one
1136                         p.tile.texture = m_tsrc->getTextureForMesh(
1137                                         os.str()+"0",
1138                                         &p.tile.texture_id);
1139                 }
1140                 // - Texture animation
1141                 if (p.tile.material_flags & MATERIAL_FLAG_ANIMATION) {
1142                         // Add to MapBlockMesh in order to animate these tiles
1143                         m_animation_tiles[i] = p.tile;
1144                         m_animation_frames[i] = 0;
1145                         if(g_settings->getBool("desynchronize_mapblock_texture_animation")){
1146                                 // Get starting position from noise
1147                                 m_animation_frame_offsets[i] = 100000 * (2.0 + noise3d(
1148                                                 data->m_blockpos.X, data->m_blockpos.Y,
1149                                                 data->m_blockpos.Z, 0));
1150                         } else {
1151                                 // Play all synchronized
1152                                 m_animation_frame_offsets[i] = 0;
1153                         }
1154                         // Replace tile texture with the first animation frame
1155                         FrameSpec animation_frame = p.tile.frames[0];
1156                         p.tile.texture = animation_frame.texture;
1157                 }
1158
1159                 if (!m_enable_shaders) {
1160                         // Extract colors for day-night animation
1161                         // Dummy sunlight to handle non-sunlit areas
1162                         video::SColorf sunlight;
1163                         get_sunlight_color(&sunlight, 0);
1164                         u32 vertex_count =
1165                                 m_use_tangent_vertices ?
1166                                         p.tangent_vertices.size() : p.vertices.size();
1167                         for (u32 j = 0; j < vertex_count; j++) {
1168                                 video::SColor *vc;
1169                                 if (m_use_tangent_vertices) {
1170                                         vc = &p.tangent_vertices[j].Color;
1171                                 } else {
1172                                         vc = &p.vertices[j].Color;
1173                                 }
1174                                 video::SColor copy(*vc);
1175                                 if (vc->getAlpha() == 0) // No sunlight - no need to animate
1176                                         final_color_blend(vc, copy, sunlight); // Finalize color
1177                                 else // Record color to animate
1178                                         m_daynight_diffs[i][j] = copy;
1179
1180                                 // The sunlight ratio has been stored,
1181                                 // delete alpha (for the final rendering).
1182                                 vc->setAlpha(255);
1183                         }
1184                 }
1185
1186                 // Create material
1187                 video::SMaterial material;
1188                 material.setFlag(video::EMF_LIGHTING, false);
1189                 material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1190                 material.setFlag(video::EMF_BILINEAR_FILTER, false);
1191                 material.setFlag(video::EMF_FOG_ENABLE, true);
1192                 material.setTexture(0, p.tile.texture);
1193
1194                 if (m_enable_shaders) {
1195                         material.MaterialType = m_shdrsrc->getShaderInfo(p.tile.shader_id).material;
1196                         p.tile.applyMaterialOptionsWithShaders(material);
1197                         if (p.tile.normal_texture) {
1198                                 material.setTexture(1, p.tile.normal_texture);
1199                         }
1200                         material.setTexture(2, p.tile.flags_texture);
1201                 } else {
1202                         p.tile.applyMaterialOptions(material);
1203                 }
1204
1205                 scene::SMesh *mesh = (scene::SMesh *)m_mesh;
1206
1207                 // Create meshbuffer, add to mesh
1208                 if (m_use_tangent_vertices) {
1209                         scene::SMeshBufferTangents *buf = new scene::SMeshBufferTangents();
1210                         // Set material
1211                         buf->Material = material;
1212                         // Add to mesh
1213                         mesh->addMeshBuffer(buf);
1214                         // Mesh grabbed it
1215                         buf->drop();
1216                         buf->append(&p.tangent_vertices[0], p.tangent_vertices.size(),
1217                                 &p.indices[0], p.indices.size());
1218                 } else {
1219                         scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1220                         // Set material
1221                         buf->Material = material;
1222                         // Add to mesh
1223                         mesh->addMeshBuffer(buf);
1224                         // Mesh grabbed it
1225                         buf->drop();
1226                         buf->append(&p.vertices[0], p.vertices.size(),
1227                                 &p.indices[0], p.indices.size());
1228                 }
1229         }
1230
1231         /*
1232                 Do some stuff to the mesh
1233         */
1234         m_camera_offset = camera_offset;
1235         translateMesh(m_mesh,
1236                 intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
1237
1238         if (m_use_tangent_vertices) {
1239                 scene::IMeshManipulator* meshmanip =
1240                         m_client->getSceneManager()->getMeshManipulator();
1241                 meshmanip->recalculateTangents(m_mesh, true, false, false);
1242         }
1243
1244         if (m_mesh)
1245         {
1246 #if 0
1247                 // Usually 1-700 faces and 1-7 materials
1248                 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
1249                                 <<"and uses "<<m_mesh->getMeshBufferCount()
1250                                 <<" materials (meshbuffers)"<<std::endl;
1251 #endif
1252
1253                 // Use VBO for mesh (this just would set this for ever buffer)
1254                 if (m_enable_vbo) {
1255                         m_mesh->setHardwareMappingHint(scene::EHM_STATIC);
1256                 }
1257         }
1258
1259         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1260
1261         // Check if animation is required for this mesh
1262         m_has_animation =
1263                 !m_crack_materials.empty() ||
1264                 !m_daynight_diffs.empty() ||
1265                 !m_animation_tiles.empty();
1266 }
1267
1268 MapBlockMesh::~MapBlockMesh()
1269 {
1270         if (m_enable_vbo && m_mesh) {
1271                 for (u32 i = 0; i < m_mesh->getMeshBufferCount(); i++) {
1272                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i);
1273                         m_driver->removeHardwareBuffer(buf);
1274                 }
1275         }
1276         m_mesh->drop();
1277         m_mesh = NULL;
1278         delete m_minimap_mapblock;
1279 }
1280
1281 bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_ratio)
1282 {
1283         if(!m_has_animation)
1284         {
1285                 m_animation_force_timer = 100000;
1286                 return false;
1287         }
1288
1289         m_animation_force_timer = myrand_range(5, 100);
1290
1291         // Cracks
1292         if(crack != m_last_crack)
1293         {
1294                 for (UNORDERED_MAP<u32, std::string>::iterator i = m_crack_materials.begin();
1295                                 i != m_crack_materials.end(); ++i) {
1296                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1297                         std::string basename = i->second;
1298
1299                         // Create new texture name from original
1300                         std::ostringstream os;
1301                         os<<basename<<crack;
1302                         u32 new_texture_id = 0;
1303                         video::ITexture *new_texture =
1304                                 m_tsrc->getTextureForMesh(os.str(), &new_texture_id);
1305                         buf->getMaterial().setTexture(0, new_texture);
1306
1307                         // If the current material is also animated,
1308                         // update animation info
1309                         UNORDERED_MAP<u32, TileSpec>::iterator anim_iter =
1310                                         m_animation_tiles.find(i->first);
1311                         if (anim_iter != m_animation_tiles.end()){
1312                                 TileSpec &tile = anim_iter->second;
1313                                 tile.texture = new_texture;
1314                                 tile.texture_id = new_texture_id;
1315                                 // force animation update
1316                                 m_animation_frames[i->first] = -1;
1317                         }
1318                 }
1319
1320                 m_last_crack = crack;
1321         }
1322
1323         // Texture animation
1324         for (UNORDERED_MAP<u32, TileSpec>::iterator i = m_animation_tiles.begin();
1325                         i != m_animation_tiles.end(); ++i) {
1326                 const TileSpec &tile = i->second;
1327                 // Figure out current frame
1328                 int frameoffset = m_animation_frame_offsets[i->first];
1329                 int frame = (int)(time * 1000 / tile.animation_frame_length_ms
1330                                 + frameoffset) % tile.animation_frame_count;
1331                 // If frame doesn't change, skip
1332                 if(frame == m_animation_frames[i->first])
1333                         continue;
1334
1335                 m_animation_frames[i->first] = frame;
1336
1337                 scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1338
1339                 FrameSpec animation_frame = tile.frames[frame];
1340                 buf->getMaterial().setTexture(0, animation_frame.texture);
1341                 if (m_enable_shaders) {
1342                         if (animation_frame.normal_texture) {
1343                                 buf->getMaterial().setTexture(1, animation_frame.normal_texture);
1344                         }
1345                         buf->getMaterial().setTexture(2, animation_frame.flags_texture);
1346                 }
1347         }
1348
1349         // Day-night transition
1350         if(!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio))
1351         {
1352                 // Force reload mesh to VBO
1353                 if (m_enable_vbo) {
1354                         m_mesh->setDirty();
1355                 }
1356                 video::SColorf day_color;
1357                 get_sunlight_color(&day_color, daynight_ratio);
1358                 for(std::map<u32, std::map<u32, video::SColor > >::iterator
1359                                 i = m_daynight_diffs.begin();
1360                                 i != m_daynight_diffs.end(); ++i)
1361                 {
1362                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1363                         video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
1364                         for(std::map<u32, video::SColor >::iterator
1365                                         j = i->second.begin();
1366                                         j != i->second.end(); ++j)
1367                         {
1368                                 final_color_blend(&(vertices[j->first].Color), j->second, day_color);
1369                         }
1370                 }
1371                 m_last_daynight_ratio = daynight_ratio;
1372         }
1373
1374         return true;
1375 }
1376
1377 void MapBlockMesh::updateCameraOffset(v3s16 camera_offset)
1378 {
1379         if (camera_offset != m_camera_offset) {
1380                 translateMesh(m_mesh, intToFloat(m_camera_offset-camera_offset, BS));
1381                 if (m_enable_vbo) {
1382                         m_mesh->setDirty();
1383                 }
1384                 m_camera_offset = camera_offset;
1385         }
1386 }
1387
1388 /*
1389         MeshCollector
1390 */
1391
1392 void MeshCollector::append(const TileSpec &tile,
1393                 const video::S3DVertex *vertices, u32 numVertices,
1394                 const u16 *indices, u32 numIndices)
1395 {
1396         if (numIndices > 65535) {
1397                 dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1398                 return;
1399         }
1400
1401         PreMeshBuffer *p = NULL;
1402         for (u32 i = 0; i < prebuffers.size(); i++) {
1403                 PreMeshBuffer &pp = prebuffers[i];
1404                 if (pp.tile != tile)
1405                         continue;
1406                 if (pp.indices.size() + numIndices > 65535)
1407                         continue;
1408
1409                 p = &pp;
1410                 break;
1411         }
1412
1413         if (p == NULL) {
1414                 PreMeshBuffer pp;
1415                 pp.tile = tile;
1416                 prebuffers.push_back(pp);
1417                 p = &prebuffers[prebuffers.size() - 1];
1418         }
1419
1420         u32 vertex_count;
1421         if (m_use_tangent_vertices) {
1422                 vertex_count = p->tangent_vertices.size();
1423                 for (u32 i = 0; i < numVertices; i++) {
1424                         video::S3DVertexTangents vert(vertices[i].Pos, vertices[i].Normal,
1425                                 vertices[i].Color, vertices[i].TCoords);
1426                         p->tangent_vertices.push_back(vert);
1427                 }
1428         } else {
1429                 vertex_count = p->vertices.size();
1430                 for (u32 i = 0; i < numVertices; i++) {
1431                         video::S3DVertex vert(vertices[i].Pos, vertices[i].Normal,
1432                                 vertices[i].Color, vertices[i].TCoords);
1433                         p->vertices.push_back(vert);
1434                 }
1435         }
1436
1437         for (u32 i = 0; i < numIndices; i++) {
1438                 u32 j = indices[i] + vertex_count;
1439                 p->indices.push_back(j);
1440         }
1441 }
1442
1443 /*
1444         MeshCollector - for meshnodes and converted drawtypes.
1445 */
1446
1447 void MeshCollector::append(const TileSpec &tile,
1448                 const video::S3DVertex *vertices, u32 numVertices,
1449                 const u16 *indices, u32 numIndices,
1450                 v3f pos, video::SColor c, u8 light_source)
1451 {
1452         if (numIndices > 65535) {
1453                 dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1454                 return;
1455         }
1456
1457         PreMeshBuffer *p = NULL;
1458         for (u32 i = 0; i < prebuffers.size(); i++) {
1459                 PreMeshBuffer &pp = prebuffers[i];
1460                 if(pp.tile != tile)
1461                         continue;
1462                 if(pp.indices.size() + numIndices > 65535)
1463                         continue;
1464
1465                 p = &pp;
1466                 break;
1467         }
1468
1469         if (p == NULL) {
1470                 PreMeshBuffer pp;
1471                 pp.tile = tile;
1472                 prebuffers.push_back(pp);
1473                 p = &prebuffers[prebuffers.size() - 1];
1474         }
1475
1476         video::SColor original_c = c;
1477         u32 vertex_count;
1478         if (m_use_tangent_vertices) {
1479                 vertex_count = p->tangent_vertices.size();
1480                 for (u32 i = 0; i < numVertices; i++) {
1481                         if (!light_source) {
1482                                 c = original_c;
1483                                 applyFacesShading(c, vertices[i].Normal);
1484                         }
1485                         video::S3DVertexTangents vert(vertices[i].Pos + pos,
1486                                 vertices[i].Normal, c, vertices[i].TCoords);
1487                         p->tangent_vertices.push_back(vert);
1488                 }
1489         } else {
1490                 vertex_count = p->vertices.size();
1491                 for (u32 i = 0; i < numVertices; i++) {
1492                         if (!light_source) {
1493                                 c = original_c;
1494                                 applyFacesShading(c, vertices[i].Normal);
1495                         }
1496                         video::S3DVertex vert(vertices[i].Pos + pos, vertices[i].Normal, c,
1497                                 vertices[i].TCoords);
1498                         p->vertices.push_back(vert);
1499                 }
1500         }
1501
1502         for (u32 i = 0; i < numIndices; i++) {
1503                 u32 j = indices[i] + vertex_count;
1504                 p->indices.push_back(j);
1505         }
1506 }
1507
1508 video::SColor encode_light_and_color(u16 light, const video::SColor &color,
1509         u8 emissive_light)
1510 {
1511         // Get components
1512         f32 day = (light & 0xff) / 255.0f;
1513         f32 night = (light >> 8) / 255.0f;
1514         // Add emissive light
1515         night += emissive_light * 0.01f;
1516         if (night > 255)
1517                 night = 255;
1518         // Since we don't know if the day light is sunlight or
1519         // artificial light, assume it is artificial when the night
1520         // light bank is also lit.
1521         if (day < night)
1522                 day = 0;
1523         else
1524                 day = day - night;
1525         f32 sum = day + night;
1526         // Ratio of sunlight:
1527         float r;
1528         if (sum > 0)
1529                 r = day / sum;
1530         else
1531                 r = 0;
1532         // Average light:
1533         float b = (day + night) / 2;
1534         return video::SColor(r * 255, b * color.getRed(), b * color.getGreen(),
1535                 b * color.getBlue());
1536 }