]> git.lizzy.rs Git - minetest.git/blob - src/mapblock_mesh.cpp
Set acceleration only once in falling node
[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 = 0;
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                         }
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                 continuous_tiles_count++;
919
920                 if(next_is_different)
921                 {
922                         /*
923                                 Create a face if there should be one
924                         */
925                         if(makes_face)
926                         {
927                                 // Floating point conversion of the position vector
928                                 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
929                                 // Center point of face (kind of)
930                                 v3f sp = pf - ((f32)continuous_tiles_count / 2.0 - 0.5) * translate_dir_f;
931                                 if(continuous_tiles_count != 1)
932                                         sp += 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, light_source,
947                                                 dest);
948
949                                 g_profiler->avg("Meshgen: faces drawn by tiling", 0);
950                                 for(int i = 1; i < continuous_tiles_count; i++){
951                                         g_profiler->avg("Meshgen: faces drawn by tiling", 1);
952                                 }
953                         }
954
955                         continuous_tiles_count = 0;
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                         light_source = next_light_source;
966                 }
967
968                 p = p_next;
969         }
970 }
971
972 static void updateAllFastFaceRows(MeshMakeData *data,
973                 std::vector<FastFace> &dest)
974 {
975         /*
976                 Go through every y,z and get top(y+) faces in rows of x+
977         */
978         for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
979                 for(s16 z = 0; z < MAP_BLOCKSIZE; z++) {
980                         updateFastFaceRow(data,
981                                         v3s16(0,y,z),
982                                         v3s16(1,0,0), //dir
983                                         v3f  (1,0,0),
984                                         v3s16(0,1,0), //face dir
985                                         v3f  (0,1,0),
986                                         dest);
987                 }
988         }
989
990         /*
991                 Go through every x,y and get right(x+) faces in rows of z+
992         */
993         for(s16 x = 0; x < MAP_BLOCKSIZE; x++) {
994                 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
995                         updateFastFaceRow(data,
996                                         v3s16(x,y,0),
997                                         v3s16(0,0,1), //dir
998                                         v3f  (0,0,1),
999                                         v3s16(1,0,0), //face dir
1000                                         v3f  (1,0,0),
1001                                         dest);
1002                 }
1003         }
1004
1005         /*
1006                 Go through every y,z and get back(z+) faces in rows of x+
1007         */
1008         for(s16 z = 0; z < MAP_BLOCKSIZE; z++) {
1009                 for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
1010                         updateFastFaceRow(data,
1011                                         v3s16(0,y,z),
1012                                         v3s16(1,0,0), //dir
1013                                         v3f  (1,0,0),
1014                                         v3s16(0,0,1), //face dir
1015                                         v3f  (0,0,1),
1016                                         dest);
1017                 }
1018         }
1019 }
1020
1021 /*
1022         MapBlockMesh
1023 */
1024
1025 MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
1026         m_mesh(new scene::SMesh()),
1027         m_minimap_mapblock(NULL),
1028         m_gamedef(data->m_gamedef),
1029         m_driver(m_gamedef->tsrc()->getDevice()->getVideoDriver()),
1030         m_tsrc(m_gamedef->getTextureSource()),
1031         m_shdrsrc(m_gamedef->getShaderSource()),
1032         m_animation_force_timer(0), // force initial animation
1033         m_last_crack(-1),
1034         m_crack_materials(),
1035         m_last_daynight_ratio((u32) -1),
1036         m_daynight_diffs()
1037 {
1038         m_enable_shaders = data->m_use_shaders;
1039         m_use_tangent_vertices = data->m_use_tangent_vertices;
1040         m_enable_vbo = g_settings->getBool("enable_vbo");
1041         
1042         if (g_settings->getBool("enable_minimap")) {
1043                 m_minimap_mapblock = new MinimapMapblock;
1044                 m_minimap_mapblock->getMinimapNodes(
1045                         &data->m_vmanip, data->m_blockpos * MAP_BLOCKSIZE);
1046         }
1047
1048         // 4-21ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1049         // 24-155ms for MAP_BLOCKSIZE=32  (NOTE: probably outdated)
1050         //TimeTaker timer1("MapBlockMesh()");
1051
1052         std::vector<FastFace> fastfaces_new;
1053         fastfaces_new.reserve(512);
1054
1055         /*
1056                 We are including the faces of the trailing edges of the block.
1057                 This means that when something changes, the caller must
1058                 also update the meshes of the blocks at the leading edges.
1059
1060                 NOTE: This is the slowest part of this method.
1061         */
1062         {
1063                 // 4-23ms for MAP_BLOCKSIZE=16  (NOTE: probably outdated)
1064                 //TimeTaker timer2("updateAllFastFaceRows()");
1065                 updateAllFastFaceRows(data, fastfaces_new);
1066         }
1067         // End of slow part
1068
1069         /*
1070                 Convert FastFaces to MeshCollector
1071         */
1072
1073         MeshCollector collector(m_use_tangent_vertices);
1074
1075         {
1076                 // avg 0ms (100ms spikes when loading textures the first time)
1077                 // (NOTE: probably outdated)
1078                 //TimeTaker timer2("MeshCollector building");
1079
1080                 for (u32 i = 0; i < fastfaces_new.size(); i++) {
1081                         FastFace &f = fastfaces_new[i];
1082
1083                         const u16 indices[] = {0,1,2,2,3,0};
1084                         const u16 indices_alternate[] = {0,1,3,2,3,1};
1085
1086                         if(f.tile.texture == NULL)
1087                                 continue;
1088
1089                         const u16 *indices_p = indices;
1090
1091                         /*
1092                                 Revert triangles for nicer looking gradient if vertices
1093                                 1 and 3 have same color or 0 and 2 have different color.
1094                                 getRed() is the day color.
1095                         */
1096                         if(f.vertices[0].Color.getRed() != f.vertices[2].Color.getRed()
1097                                         || f.vertices[1].Color.getRed() == f.vertices[3].Color.getRed())
1098                                 indices_p = indices_alternate;
1099
1100                         collector.append(f.tile, f.vertices, 4, indices_p, 6);
1101                 }
1102         }
1103
1104         /*
1105                 Add special graphics:
1106                 - torches
1107                 - flowing water
1108                 - fences
1109                 - whatever
1110         */
1111
1112         mapblock_mesh_generate_special(data, collector);
1113
1114         /*
1115                 Convert MeshCollector to SMesh
1116         */
1117
1118         for(u32 i = 0; i < collector.prebuffers.size(); i++)
1119         {
1120                 PreMeshBuffer &p = collector.prebuffers[i];
1121
1122                 // Generate animation data
1123                 // - Cracks
1124                 if(p.tile.material_flags & MATERIAL_FLAG_CRACK)
1125                 {
1126                         // Find the texture name plus ^[crack:N:
1127                         std::ostringstream os(std::ios::binary);
1128                         os<<m_tsrc->getTextureName(p.tile.texture_id)<<"^[crack";
1129                         if(p.tile.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
1130                                 os<<"o";  // use ^[cracko
1131                         os<<":"<<(u32)p.tile.animation_frame_count<<":";
1132                         m_crack_materials.insert(std::make_pair(i, os.str()));
1133                         // Replace tile texture with the cracked one
1134                         p.tile.texture = m_tsrc->getTextureForMesh(
1135                                         os.str()+"0",
1136                                         &p.tile.texture_id);
1137                 }
1138                 // - Texture animation
1139                 if(p.tile.material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
1140                 {
1141                         // Add to MapBlockMesh in order to animate these tiles
1142                         m_animation_tiles[i] = p.tile;
1143                         m_animation_frames[i] = 0;
1144                         if(g_settings->getBool("desynchronize_mapblock_texture_animation")){
1145                                 // Get starting position from noise
1146                                 m_animation_frame_offsets[i] = 100000 * (2.0 + noise3d(
1147                                                 data->m_blockpos.X, data->m_blockpos.Y,
1148                                                 data->m_blockpos.Z, 0));
1149                         } else {
1150                                 // Play all synchronized
1151                                 m_animation_frame_offsets[i] = 0;
1152                         }
1153                         // Replace tile texture with the first animation frame
1154                         FrameSpec animation_frame = p.tile.frames[0];
1155                         p.tile.texture = animation_frame.texture;
1156                 }
1157
1158                 u32 vertex_count = m_use_tangent_vertices ?
1159                         p.tangent_vertices.size() : p.vertices.size();
1160                 for (u32 j = 0; j < vertex_count; j++) {
1161                         v3f *Normal;
1162                         video::SColor *vc;
1163                         if (m_use_tangent_vertices) {
1164                                 vc = &p.tangent_vertices[j].Color;
1165                                 Normal = &p.tangent_vertices[j].Normal;
1166                         } else {
1167                                 vc = &p.vertices[j].Color;
1168                                 Normal = &p.vertices[j].Normal;
1169                         }
1170                         // Note applyFacesShading second parameter is precalculated sqrt
1171                         // value for speed improvement
1172                         // Skip it for lightsources and top faces.
1173                         if (!vc->getBlue()) {
1174                                 if (Normal->Y < -0.5) {
1175                                         applyFacesShading(*vc, 0.447213);
1176                                 } else if (Normal->X > 0.5) {
1177                                         applyFacesShading(*vc, 0.670820);
1178                                 } else if (Normal->X < -0.5) {
1179                                         applyFacesShading(*vc, 0.670820);
1180                                 } else if (Normal->Z > 0.5) {
1181                                         applyFacesShading(*vc, 0.836660);
1182                                 } else if (Normal->Z < -0.5) {
1183                                         applyFacesShading(*vc, 0.836660);
1184                                 }
1185                         }
1186                         if (!m_enable_shaders) {
1187                                 // - Classic lighting (shaders handle this by themselves)
1188                                 // Set initial real color and store for later updates
1189                                 u8 day = vc->getRed();
1190                                 u8 night = vc->getGreen();
1191                                 finalColorBlend(*vc, day, night, 1000);
1192                                 if (day != night) {
1193                                         m_daynight_diffs[i][j] = std::make_pair(day, night);
1194                                 }
1195                         }
1196                 }
1197
1198                 // Create material
1199                 video::SMaterial material;
1200                 material.setFlag(video::EMF_LIGHTING, false);
1201                 material.setFlag(video::EMF_BACK_FACE_CULLING, true);
1202                 material.setFlag(video::EMF_BILINEAR_FILTER, false);
1203                 material.setFlag(video::EMF_FOG_ENABLE, true);
1204                 material.setTexture(0, p.tile.texture);
1205
1206                 if (m_enable_shaders) {
1207                         material.MaterialType = m_shdrsrc->getShaderInfo(p.tile.shader_id).material;
1208                         p.tile.applyMaterialOptionsWithShaders(material);
1209                         if (p.tile.normal_texture) {
1210                                 material.setTexture(1, p.tile.normal_texture);
1211                         }
1212                         material.setTexture(2, p.tile.flags_texture);
1213                 } else {
1214                         p.tile.applyMaterialOptions(material);
1215                 }
1216
1217                 scene::SMesh *mesh = (scene::SMesh *)m_mesh;
1218
1219                 // Create meshbuffer, add to mesh
1220                 if (m_use_tangent_vertices) {
1221                         scene::SMeshBufferTangents *buf = new scene::SMeshBufferTangents();
1222                         // Set material
1223                         buf->Material = material;
1224                         // Add to mesh
1225                         mesh->addMeshBuffer(buf);
1226                         // Mesh grabbed it
1227                         buf->drop();
1228                         buf->append(&p.tangent_vertices[0], p.tangent_vertices.size(),
1229                                 &p.indices[0], p.indices.size());
1230                 } else {
1231                         scene::SMeshBuffer *buf = new scene::SMeshBuffer();
1232                         // Set material
1233                         buf->Material = material;
1234                         // Add to mesh
1235                         mesh->addMeshBuffer(buf);
1236                         // Mesh grabbed it
1237                         buf->drop();
1238                         buf->append(&p.vertices[0], p.vertices.size(),
1239                                 &p.indices[0], p.indices.size());
1240                 }
1241         }
1242
1243         /*
1244                 Do some stuff to the mesh
1245         */
1246         m_camera_offset = camera_offset;
1247         translateMesh(m_mesh,
1248                 intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
1249
1250         if (m_use_tangent_vertices) {
1251                 scene::IMeshManipulator* meshmanip =
1252                         m_gamedef->getSceneManager()->getMeshManipulator();
1253                 meshmanip->recalculateTangents(m_mesh, true, false, false);
1254         }
1255
1256         if (m_mesh)
1257         {
1258 #if 0
1259                 // Usually 1-700 faces and 1-7 materials
1260                 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
1261                                 <<"and uses "<<m_mesh->getMeshBufferCount()
1262                                 <<" materials (meshbuffers)"<<std::endl;
1263 #endif
1264
1265                 // Use VBO for mesh (this just would set this for ever buffer)
1266                 if (m_enable_vbo) {
1267                         m_mesh->setHardwareMappingHint(scene::EHM_STATIC);
1268                 }
1269         }
1270
1271         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1272
1273         // Check if animation is required for this mesh
1274         m_has_animation =
1275                 !m_crack_materials.empty() ||
1276                 !m_daynight_diffs.empty() ||
1277                 !m_animation_tiles.empty();
1278 }
1279
1280 MapBlockMesh::~MapBlockMesh()
1281 {
1282         if (m_enable_vbo && m_mesh) {
1283                 for (u32 i = 0; i < m_mesh->getMeshBufferCount(); i++) {
1284                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i);
1285                         m_driver->removeHardwareBuffer(buf);
1286                 }
1287         }
1288         m_mesh->drop();
1289         m_mesh = NULL;
1290         delete m_minimap_mapblock;
1291 }
1292
1293 bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_ratio)
1294 {
1295         if(!m_has_animation)
1296         {
1297                 m_animation_force_timer = 100000;
1298                 return false;
1299         }
1300
1301         m_animation_force_timer = myrand_range(5, 100);
1302
1303         // Cracks
1304         if(crack != m_last_crack)
1305         {
1306                 for(std::map<u32, std::string>::iterator
1307                                 i = m_crack_materials.begin();
1308                                 i != m_crack_materials.end(); ++i)
1309                 {
1310                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1311                         std::string basename = i->second;
1312
1313                         // Create new texture name from original
1314                         std::ostringstream os;
1315                         os<<basename<<crack;
1316                         u32 new_texture_id = 0;
1317                         video::ITexture *new_texture =
1318                                 m_tsrc->getTextureForMesh(os.str(), &new_texture_id);
1319                         buf->getMaterial().setTexture(0, new_texture);
1320
1321                         // If the current material is also animated,
1322                         // update animation info
1323                         std::map<u32, TileSpec>::iterator anim_iter =
1324                                 m_animation_tiles.find(i->first);
1325                         if(anim_iter != m_animation_tiles.end()){
1326                                 TileSpec &tile = anim_iter->second;
1327                                 tile.texture = new_texture;
1328                                 tile.texture_id = new_texture_id;
1329                                 // force animation update
1330                                 m_animation_frames[i->first] = -1;
1331                         }
1332                 }
1333
1334                 m_last_crack = crack;
1335         }
1336
1337         // Texture animation
1338         for(std::map<u32, TileSpec>::iterator
1339                         i = m_animation_tiles.begin();
1340                         i != m_animation_tiles.end(); ++i)
1341         {
1342                 const TileSpec &tile = i->second;
1343                 // Figure out current frame
1344                 int frameoffset = m_animation_frame_offsets[i->first];
1345                 int frame = (int)(time * 1000 / tile.animation_frame_length_ms
1346                                 + frameoffset) % tile.animation_frame_count;
1347                 // If frame doesn't change, skip
1348                 if(frame == m_animation_frames[i->first])
1349                         continue;
1350
1351                 m_animation_frames[i->first] = frame;
1352
1353                 scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1354
1355                 FrameSpec animation_frame = tile.frames[frame];
1356                 buf->getMaterial().setTexture(0, animation_frame.texture);
1357                 if (m_enable_shaders) {
1358                         if (animation_frame.normal_texture) {
1359                                 buf->getMaterial().setTexture(1, animation_frame.normal_texture);
1360                         }
1361                         buf->getMaterial().setTexture(2, animation_frame.flags_texture);
1362                 }
1363         }
1364
1365         // Day-night transition
1366         if(!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio))
1367         {
1368                 // Force reload mesh to VBO
1369                 if (m_enable_vbo) {
1370                         m_mesh->setDirty();
1371                 }
1372                 for(std::map<u32, std::map<u32, std::pair<u8, u8> > >::iterator
1373                                 i = m_daynight_diffs.begin();
1374                                 i != m_daynight_diffs.end(); ++i)
1375                 {
1376                         scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
1377                         video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
1378                         for(std::map<u32, std::pair<u8, u8 > >::iterator
1379                                         j = i->second.begin();
1380                                         j != i->second.end(); ++j)
1381                         {
1382                                 u8 day = j->second.first;
1383                                 u8 night = j->second.second;
1384                                 finalColorBlend(vertices[j->first].Color, day, night, daynight_ratio);
1385                         }
1386                 }
1387                 m_last_daynight_ratio = daynight_ratio;
1388         }
1389
1390         return true;
1391 }
1392
1393 void MapBlockMesh::updateCameraOffset(v3s16 camera_offset)
1394 {
1395         if (camera_offset != m_camera_offset) {
1396                 translateMesh(m_mesh, intToFloat(m_camera_offset-camera_offset, BS));
1397                 if (m_enable_vbo) {
1398                         m_mesh->setDirty();
1399                 }
1400                 m_camera_offset = camera_offset;
1401         }
1402 }
1403
1404 /*
1405         MeshCollector
1406 */
1407
1408 void MeshCollector::append(const TileSpec &tile,
1409                 const video::S3DVertex *vertices, u32 numVertices,
1410                 const u16 *indices, u32 numIndices)
1411 {
1412         if (numIndices > 65535) {
1413                 dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1414                 return;
1415         }
1416
1417         PreMeshBuffer *p = NULL;
1418         for (u32 i = 0; i < prebuffers.size(); i++) {
1419                 PreMeshBuffer &pp = prebuffers[i];
1420                 if (pp.tile != tile)
1421                         continue;
1422                 if (pp.indices.size() + numIndices > 65535)
1423                         continue;
1424
1425                 p = &pp;
1426                 break;
1427         }
1428
1429         if (p == NULL) {
1430                 PreMeshBuffer pp;
1431                 pp.tile = tile;
1432                 prebuffers.push_back(pp);
1433                 p = &prebuffers[prebuffers.size() - 1];
1434         }
1435
1436         u32 vertex_count;
1437         if (m_use_tangent_vertices) {
1438                 vertex_count = p->tangent_vertices.size();
1439                 for (u32 i = 0; i < numVertices; i++) {
1440                         video::S3DVertexTangents vert(vertices[i].Pos, vertices[i].Normal,
1441                                 vertices[i].Color, vertices[i].TCoords);
1442                         p->tangent_vertices.push_back(vert);
1443                 }
1444         } else {
1445                 vertex_count = p->vertices.size();
1446                 for (u32 i = 0; i < numVertices; i++) {
1447                         video::S3DVertex vert(vertices[i].Pos, vertices[i].Normal,
1448                                 vertices[i].Color, vertices[i].TCoords);
1449                         p->vertices.push_back(vert);
1450                 }
1451         } 
1452
1453         for (u32 i = 0; i < numIndices; i++) {
1454                 u32 j = indices[i] + vertex_count;
1455                 p->indices.push_back(j);
1456         }
1457 }
1458
1459 /*
1460         MeshCollector - for meshnodes and converted drawtypes.
1461 */
1462
1463 void MeshCollector::append(const TileSpec &tile,
1464                 const video::S3DVertex *vertices, u32 numVertices,
1465                 const u16 *indices, u32 numIndices,
1466                 v3f pos, video::SColor c)
1467 {
1468         if (numIndices > 65535) {
1469                 dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
1470                 return;
1471         }
1472
1473         PreMeshBuffer *p = NULL;
1474         for (u32 i = 0; i < prebuffers.size(); i++) {
1475                 PreMeshBuffer &pp = prebuffers[i];
1476                 if(pp.tile != tile)
1477                         continue;
1478                 if(pp.indices.size() + numIndices > 65535)
1479                         continue;
1480
1481                 p = &pp;
1482                 break;
1483         }
1484
1485         if (p == NULL) {
1486                 PreMeshBuffer pp;
1487                 pp.tile = tile;
1488                 prebuffers.push_back(pp);
1489                 p = &prebuffers[prebuffers.size() - 1];
1490         }
1491
1492         u32 vertex_count;
1493         if (m_use_tangent_vertices) {
1494                 vertex_count = p->tangent_vertices.size();
1495                 for (u32 i = 0; i < numVertices; i++) {
1496                         video::S3DVertexTangents vert(vertices[i].Pos + pos,
1497                                 vertices[i].Normal, c, vertices[i].TCoords);
1498                         p->tangent_vertices.push_back(vert);
1499                 }
1500         } else {
1501                 vertex_count = p->vertices.size();
1502                 for (u32 i = 0; i < numVertices; i++) {
1503                         video::S3DVertex vert(vertices[i].Pos + pos,
1504                                 vertices[i].Normal, c, vertices[i].TCoords);
1505                         p->vertices.push_back(vert);
1506                 }
1507         } 
1508
1509         for (u32 i = 0; i < numIndices; i++) {
1510                 u32 j = indices[i] + vertex_count;
1511                 p->indices.push_back(j);
1512         }
1513 }