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