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