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