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