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