]> git.lizzy.rs Git - minetest.git/blob - src/mapblock.cpp
+ papyrus
[minetest.git] / src / mapblock.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010 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 General Public License as published by
7 the Free Software Foundation; either version 2 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 General Public License for more details.
14
15 You should have received a copy of the GNU 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.h"
21 #include "map.h"
22 // For g_settings
23 #include "main.h"
24 #include "light.h"
25 #include <sstream>
26
27 #ifndef SERVER
28 void MeshMakeData::fill(u32 daynight_ratio, MapBlock *block)
29 {
30         m_daynight_ratio = daynight_ratio;
31         m_blockpos = block->getPos();
32
33         v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
34         
35         /*
36                 There is no harm not copying the TempMods of the neighbors
37                 because they are already copied to this block
38         */
39         m_temp_mods.clear();
40         block->copyTempMods(m_temp_mods);
41         
42         /*
43                 Copy data
44         */
45
46         // Allocate this block + neighbors
47         m_vmanip.clear();
48         m_vmanip.addArea(VoxelArea(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
49                         blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1)));
50
51         {
52                 //TimeTaker timer("copy central block data");
53                 // 0ms
54
55                 // Copy our data
56                 block->copyTo(m_vmanip);
57         }
58         {
59                 //TimeTaker timer("copy neighbor block data");
60                 // 0ms
61
62                 /*
63                         Copy neighbors. This is lightning fast.
64                         Copying only the borders would be *very* slow.
65                 */
66                 
67                 // Get map
68                 NodeContainer *parentcontainer = block->getParent();
69                 // This will only work if the parent is the map
70                 assert(parentcontainer->nodeContainerId() == NODECONTAINER_ID_MAP);
71                 // OK, we have the map!
72                 Map *map = (Map*)parentcontainer;
73
74                 for(u16 i=0; i<6; i++)
75                 {
76                         const v3s16 &dir = g_6dirs[i];
77                         v3s16 bp = m_blockpos + dir;
78                         MapBlock *b = map->getBlockNoCreateNoEx(bp);
79                         if(b)
80                                 b->copyTo(m_vmanip);
81                 }
82         }
83 }
84 #endif
85
86 /*
87         Parameters must consist of air and !air.
88         Order doesn't matter.
89
90         If either of the nodes doesn't exist, light is 0.
91         
92         parameters:
93                 daynight_ratio: 0...1000
94                 n: getNodeParent(p)
95                 n2: getNodeParent(p + face_dir)
96                 face_dir: axis oriented unit vector from p to p2
97         
98         returns encoded light value.
99 */
100 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
101                 v3s16 face_dir)
102 {
103         try{
104                 u8 light;
105                 u8 l1 = n.getLightBlend(daynight_ratio);
106                 u8 l2 = n2.getLightBlend(daynight_ratio);
107                 if(l1 > l2)
108                         light = l1;
109                 else
110                         light = l2;
111
112                 // Make some nice difference to different sides
113
114                 // This makes light come from a corner
115                 /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
116                         light = diminish_light(diminish_light(light));
117                 else if(face_dir.X == -1 || face_dir.Z == -1)
118                         light = diminish_light(light);*/
119                 
120                 // All neighboring faces have different shade (like in minecraft)
121                 if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
122                         light = diminish_light(diminish_light(light));
123                 else if(face_dir.Z == 1 || face_dir.Z == -1)
124                         light = diminish_light(light);
125
126                 return light;
127         }
128         catch(InvalidPositionException &e)
129         {
130                 return 0;
131         }
132 }
133
134 #ifndef SERVER
135
136 /*
137         vertex_dirs: v3s16[4]
138 */
139 void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
140 {
141         /*
142                 If looked from outside the node towards the face, the corners are:
143                 0: bottom-right
144                 1: bottom-left
145                 2: top-left
146                 3: top-right
147         */
148         if(dir == v3s16(0,0,1))
149         {
150                 // If looking towards z+, this is the face that is behind
151                 // the center point, facing towards z+.
152                 vertex_dirs[0] = v3s16(-1,-1, 1);
153                 vertex_dirs[1] = v3s16( 1,-1, 1);
154                 vertex_dirs[2] = v3s16( 1, 1, 1);
155                 vertex_dirs[3] = v3s16(-1, 1, 1);
156         }
157         else if(dir == v3s16(0,0,-1))
158         {
159                 // faces towards Z-
160                 vertex_dirs[0] = v3s16( 1,-1,-1);
161                 vertex_dirs[1] = v3s16(-1,-1,-1);
162                 vertex_dirs[2] = v3s16(-1, 1,-1);
163                 vertex_dirs[3] = v3s16( 1, 1,-1);
164         }
165         else if(dir == v3s16(1,0,0))
166         {
167                 // faces towards X+
168                 vertex_dirs[0] = v3s16( 1,-1, 1);
169                 vertex_dirs[1] = v3s16( 1,-1,-1);
170                 vertex_dirs[2] = v3s16( 1, 1,-1);
171                 vertex_dirs[3] = v3s16( 1, 1, 1);
172         }
173         else if(dir == v3s16(-1,0,0))
174         {
175                 // faces towards X-
176                 vertex_dirs[0] = v3s16(-1,-1,-1);
177                 vertex_dirs[1] = v3s16(-1,-1, 1);
178                 vertex_dirs[2] = v3s16(-1, 1, 1);
179                 vertex_dirs[3] = v3s16(-1, 1,-1);
180         }
181         else if(dir == v3s16(0,1,0))
182         {
183                 // faces towards Y+ (assume Z- as "down" in texture)
184                 vertex_dirs[0] = v3s16( 1, 1,-1);
185                 vertex_dirs[1] = v3s16(-1, 1,-1);
186                 vertex_dirs[2] = v3s16(-1, 1, 1);
187                 vertex_dirs[3] = v3s16( 1, 1, 1);
188         }
189         else if(dir == v3s16(0,-1,0))
190         {
191                 // faces towards Y- (assume Z+ as "down" in texture)
192                 vertex_dirs[0] = v3s16( 1,-1, 1);
193                 vertex_dirs[1] = v3s16(-1,-1, 1);
194                 vertex_dirs[2] = v3s16(-1,-1,-1);
195                 vertex_dirs[3] = v3s16( 1,-1,-1);
196         }
197 }
198
199 inline video::SColor lightColor(u8 alpha, u8 light)
200 {
201         return video::SColor(alpha,light,light,light);
202 }
203
204 void makeFastFace(TileSpec tile, u8 li0, u8 li1, u8 li2, u8 li3, v3f p,
205                 v3s16 dir, v3f scale, v3f posRelative_f,
206                 core::array<FastFace> &dest)
207 {
208         FastFace face;
209         
210         // Position is at the center of the cube.
211         v3f pos = p * BS;
212         posRelative_f *= BS;
213
214         v3f vertex_pos[4];
215         v3s16 vertex_dirs[4];
216         getNodeVertexDirs(dir, vertex_dirs);
217         for(u16 i=0; i<4; i++)
218         {
219                 vertex_pos[i] = v3f(
220                                 BS/2*vertex_dirs[i].X,
221                                 BS/2*vertex_dirs[i].Y,
222                                 BS/2*vertex_dirs[i].Z
223                 );
224         }
225
226         for(u16 i=0; i<4; i++)
227         {
228                 vertex_pos[i].X *= scale.X;
229                 vertex_pos[i].Y *= scale.Y;
230                 vertex_pos[i].Z *= scale.Z;
231                 vertex_pos[i] += pos + posRelative_f;
232         }
233
234         f32 abs_scale = 1.;
235         if     (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
236         else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
237         else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
238
239         v3f zerovector = v3f(0,0,0);
240         
241         u8 alpha = tile.alpha;
242         /*u8 alpha = 255;
243         if(tile.id == TILE_WATER)
244                 alpha = WATER_ALPHA;*/
245
246         float x0 = tile.texture.pos.X;
247         float y0 = tile.texture.pos.Y;
248         float w = tile.texture.size.X;
249         float h = tile.texture.size.Y;
250
251         /*video::SColor c = lightColor(alpha, li);
252
253         face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0), c,
254                         core::vector2d<f32>(x0+w*abs_scale, y0+h));
255         face.vertices[1] = video::S3DVertex(vertex_pos[1], v3f(0,1,0), c,
256                         core::vector2d<f32>(x0, y0+h));
257         face.vertices[2] = video::S3DVertex(vertex_pos[2], v3f(0,1,0), c,
258                         core::vector2d<f32>(x0, y0));
259         face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0), c,
260                         core::vector2d<f32>(x0+w*abs_scale, y0));*/
261
262         face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0),
263                         lightColor(alpha, li0),
264                         core::vector2d<f32>(x0+w*abs_scale, y0+h));
265         face.vertices[1] = video::S3DVertex(vertex_pos[1], v3f(0,1,0),
266                         lightColor(alpha, li1),
267                         core::vector2d<f32>(x0, y0+h));
268         face.vertices[2] = video::S3DVertex(vertex_pos[2], v3f(0,1,0),
269                         lightColor(alpha, li2),
270                         core::vector2d<f32>(x0, y0));
271         face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0),
272                         lightColor(alpha, li3),
273                         core::vector2d<f32>(x0+w*abs_scale, y0));
274
275         face.tile = tile;
276         //DEBUG
277         //f->tile = TILE_STONE;
278         
279         dest.push_back(face);
280 }
281         
282 /*
283         Gets node tile from any place relative to block.
284         Returns TILE_NODE if doesn't exist or should not be drawn.
285 */
286 TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
287                 NodeModMap &temp_mods)
288 {
289         TileSpec spec;
290         spec = mn.getTile(face_dir);
291         
292         /*
293                 Check temporary modifications on this node
294         */
295         /*core::map<v3s16, NodeMod>::Node *n;
296         n = m_temp_mods.find(p);
297         // If modified
298         if(n != NULL)
299         {
300                 struct NodeMod mod = n->getValue();*/
301         NodeMod mod;
302         if(temp_mods.get(p, &mod))
303         {
304                 if(mod.type == NODEMOD_CHANGECONTENT)
305                 {
306                         MapNode mn2(mod.param);
307                         spec = mn2.getTile(face_dir);
308                 }
309                 if(mod.type == NODEMOD_CRACK)
310                 {
311                         /*
312                                 Get texture id, translate it to name, append stuff to
313                                 name, get texture id
314                         */
315
316                         // Get original texture name
317                         u32 orig_id = spec.texture.id;
318                         std::string orig_name = g_texturesource->getTextureName(orig_id);
319
320                         // Create new texture name
321                         std::ostringstream os;
322                         os<<orig_name<<"^[crack"<<mod.param;
323
324                         // Get new texture
325                         u32 new_id = g_texturesource->getTextureId(os.str());
326                         
327                         /*dstream<<"MapBlock::getNodeTile(): Switching from "
328                                         <<orig_name<<" to "<<os.str()<<" ("
329                                         <<orig_id<<" to "<<new_id<<")"<<std::endl;*/
330                         
331                         spec.texture = g_texturesource->getTexture(new_id);
332                 }
333         }
334         
335         return spec;
336 }
337
338 u8 getNodeContent(v3s16 p, MapNode mn, NodeModMap &temp_mods)
339 {
340         /*
341                 Check temporary modifications on this node
342         */
343         /*core::map<v3s16, NodeMod>::Node *n;
344         n = m_temp_mods.find(p);
345         // If modified
346         if(n != NULL)
347         {
348                 struct NodeMod mod = n->getValue();*/
349         NodeMod mod;
350         if(temp_mods.get(p, &mod))
351         {
352                 if(mod.type == NODEMOD_CHANGECONTENT)
353                 {
354                         // Overrides content
355                         return mod.param;
356                 }
357                 if(mod.type == NODEMOD_CRACK)
358                 {
359                         /*
360                                 Content doesn't change.
361                                 
362                                 face_contents works just like it should, because
363                                 there should not be faces between differently cracked
364                                 nodes.
365
366                                 If a semi-transparent node is cracked in front an
367                                 another one, it really doesn't matter whether there
368                                 is a cracked face drawn in between or not.
369                         */
370                 }
371         }
372
373         return mn.d;
374 }
375
376 v3s16 dirs8[8] = {
377         v3s16(0,0,0),
378         v3s16(0,0,1),
379         v3s16(0,1,0),
380         v3s16(0,1,1),
381         v3s16(1,0,0),
382         v3s16(1,1,0),
383         v3s16(1,0,1),
384         v3s16(1,1,1),
385 };
386
387 // Calculate lighting at the XYZ- corner of p
388 u8 getSmoothLight(v3s16 p, VoxelManipulator &vmanip, u32 daynight_ratio)
389 {
390         u16 ambient_occlusion = 0;
391         u16 light = 0;
392         u16 light_count = 0;
393         for(u32 i=0; i<8; i++)
394         {
395                 MapNode n = vmanip.getNodeNoEx(p - dirs8[i]);
396                 if(content_features(n.d).param_type == CPT_LIGHT)
397                 {
398                         light += decode_light(n.getLightBlend(daynight_ratio));
399                         light_count++;
400                 }
401                 else
402                 {
403                         if(n.d != CONTENT_IGNORE)
404                                 ambient_occlusion++;
405                 }
406         }
407
408         if(light_count == 0)
409                 return 255;
410         
411         light /= light_count;
412
413         if(ambient_occlusion > 4)
414         {
415                 ambient_occlusion -= 4;
416                 light = (float)light / ((float)ambient_occlusion * 0.5 + 1.0);
417         }
418
419         return light;
420 }
421
422 // Calculate lighting at the given corner of p
423 u8 getSmoothLight(v3s16 p, v3s16 corner,
424                 VoxelManipulator &vmanip, u32 daynight_ratio)
425 {
426         if(corner.X == 1) p.X += 1;
427         else              assert(corner.X == -1);
428         if(corner.Y == 1) p.Y += 1;
429         else              assert(corner.Y == -1);
430         if(corner.Z == 1) p.Z += 1;
431         else              assert(corner.Z == -1);
432         
433         return getSmoothLight(p, vmanip, daynight_ratio);
434 }
435
436 void getTileInfo(
437                 // Input:
438                 v3s16 blockpos_nodes,
439                 v3s16 p,
440                 v3s16 face_dir,
441                 u32 daynight_ratio,
442                 VoxelManipulator &vmanip,
443                 NodeModMap &temp_mods,
444                 bool smooth_lighting,
445                 // Output:
446                 bool &makes_face,
447                 v3s16 &p_corrected,
448                 v3s16 &face_dir_corrected,
449                 u8 *lights,
450                 TileSpec &tile
451         )
452 {
453         MapNode n0 = vmanip.getNodeNoEx(blockpos_nodes + p);
454         MapNode n1 = vmanip.getNodeNoEx(blockpos_nodes + p + face_dir);
455         TileSpec tile0 = getNodeTile(n0, p, face_dir, temp_mods);
456         TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir, temp_mods);
457         
458         // This is hackish
459         u8 content0 = getNodeContent(p, n0, temp_mods);
460         u8 content1 = getNodeContent(p + face_dir, n1, temp_mods);
461         u8 mf = face_contents(content0, content1);
462
463         if(mf == 0)
464         {
465                 makes_face = false;
466                 return;
467         }
468
469         makes_face = true;
470         
471         if(mf == 1)
472         {
473                 tile = tile0;
474                 p_corrected = p;
475                 face_dir_corrected = face_dir;
476         }
477         else
478         {
479                 tile = tile1;
480                 p_corrected = p + face_dir;
481                 face_dir_corrected = -face_dir;
482         }
483         
484         if(smooth_lighting == false)
485         {
486                 lights[0] = lights[1] = lights[2] = lights[3] =
487                                 decode_light(getFaceLight(daynight_ratio, n0, n1, face_dir));
488         }
489         else
490         {
491                 v3s16 vertex_dirs[4];
492                 getNodeVertexDirs(face_dir_corrected, vertex_dirs);
493                 for(u16 i=0; i<4; i++)
494                 {
495                         lights[i] = getSmoothLight(blockpos_nodes + p_corrected,
496                                         vertex_dirs[i], vmanip, daynight_ratio);
497                 }
498         }
499         
500         return;
501 }
502
503 /*
504         startpos:
505         translate_dir: unit vector with only one of x, y or z
506         face_dir: unit vector with only one of x, y or z
507 */
508 void updateFastFaceRow(
509                 u32 daynight_ratio,
510                 v3f posRelative_f,
511                 v3s16 startpos,
512                 u16 length,
513                 v3s16 translate_dir,
514                 v3f translate_dir_f,
515                 v3s16 face_dir,
516                 v3f face_dir_f,
517                 core::array<FastFace> &dest,
518                 NodeModMap &temp_mods,
519                 VoxelManipulator &vmanip,
520                 v3s16 blockpos_nodes,
521                 bool smooth_lighting)
522 {
523         v3s16 p = startpos;
524         
525         u16 continuous_tiles_count = 0;
526         
527         bool makes_face;
528         v3s16 p_corrected;
529         v3s16 face_dir_corrected;
530         u8 lights[4];
531         TileSpec tile;
532         getTileInfo(blockpos_nodes, p, face_dir, daynight_ratio,
533                         vmanip, temp_mods, smooth_lighting,
534                         makes_face, p_corrected, face_dir_corrected, lights, tile);
535
536         for(u16 j=0; j<length; j++)
537         {
538                 // If tiling can be done, this is set to false in the next step
539                 bool next_is_different = true;
540                 
541                 v3s16 p_next;
542                 
543                 bool next_makes_face;
544                 v3s16 next_p_corrected;
545                 v3s16 next_face_dir_corrected;
546                 u8 next_lights[4];
547                 TileSpec next_tile;
548                 
549                 // If at last position, there is nothing to compare to and
550                 // the face must be drawn anyway
551                 if(j != length - 1)
552                 {
553                         p_next = p + translate_dir;
554                         
555                         getTileInfo(blockpos_nodes, p_next, face_dir, daynight_ratio,
556                                         vmanip, temp_mods, smooth_lighting,
557                                         next_makes_face, next_p_corrected,
558                                         next_face_dir_corrected, next_lights,
559                                         next_tile);
560                         
561                         if(next_makes_face == makes_face
562                                         && next_p_corrected == p_corrected
563                                         && next_face_dir_corrected == face_dir_corrected
564                                         && next_lights[0] == lights[0]
565                                         && next_lights[1] == lights[1]
566                                         && next_lights[2] == lights[2]
567                                         && next_lights[3] == lights[3]
568                                         && next_tile == tile)
569                         {
570                                 next_is_different = false;
571                         }
572                 }
573
574                 continuous_tiles_count++;
575                 
576                 // This is set to true if the texture doesn't allow more tiling
577                 bool end_of_texture = false;
578                 /*
579                         If there is no texture, it can be tiled infinitely.
580                         If tiled==0, it means the texture can be tiled infinitely.
581                         Otherwise check tiled agains continuous_tiles_count.
582                 */
583                 if(tile.texture.atlas != NULL && tile.texture.tiled != 0)
584                 {
585                         if(tile.texture.tiled <= continuous_tiles_count)
586                                 end_of_texture = true;
587                 }
588                 
589                 // Do this to disable tiling textures
590                 //end_of_texture = true; //DEBUG
591                 
592                 if(next_is_different || end_of_texture)
593                 {
594                         /*
595                                 Create a face if there should be one
596                         */
597                         if(makes_face)
598                         {
599                                 // Floating point conversion of the position vector
600                                 v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
601                                 // Center point of face (kind of)
602                                 v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
603                                 v3f scale(1,1,1);
604
605                                 if(translate_dir.X != 0)
606                                 {
607                                         scale.X = continuous_tiles_count;
608                                 }
609                                 if(translate_dir.Y != 0)
610                                 {
611                                         scale.Y = continuous_tiles_count;
612                                 }
613                                 if(translate_dir.Z != 0)
614                                 {
615                                         scale.Z = continuous_tiles_count;
616                                 }
617                                 
618                                 makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
619                                                 sp, face_dir_corrected, scale,
620                                                 posRelative_f, dest);
621                         }
622
623                         continuous_tiles_count = 0;
624                         
625                         makes_face = next_makes_face;
626                         p_corrected = next_p_corrected;
627                         face_dir_corrected = next_face_dir_corrected;
628                         lights[0] = next_lights[0];
629                         lights[1] = next_lights[1];
630                         lights[2] = next_lights[2];
631                         lights[3] = next_lights[3];
632                         tile = next_tile;
633                 }
634                 
635                 p = p_next;
636         }
637 }
638
639 /*
640         This is used because CMeshBuffer::append() is very slow
641 */
642 struct PreMeshBuffer
643 {
644         video::SMaterial material;
645         core::array<u16> indices;
646         core::array<video::S3DVertex> vertices;
647 };
648
649 class MeshCollector
650 {
651 public:
652         void append(
653                         video::SMaterial material,
654                         const video::S3DVertex* const vertices,
655                         u32 numVertices,
656                         const u16* const indices,
657                         u32 numIndices
658                 )
659         {
660                 PreMeshBuffer *p = NULL;
661                 for(u32 i=0; i<m_prebuffers.size(); i++)
662                 {
663                         PreMeshBuffer &pp = m_prebuffers[i];
664                         if(pp.material != material)
665                                 continue;
666
667                         p = &pp;
668                         break;
669                 }
670
671                 if(p == NULL)
672                 {
673                         PreMeshBuffer pp;
674                         pp.material = material;
675                         m_prebuffers.push_back(pp);
676                         p = &m_prebuffers[m_prebuffers.size()-1];
677                 }
678
679                 u32 vertex_count = p->vertices.size();
680                 for(u32 i=0; i<numIndices; i++)
681                 {
682                         u32 j = indices[i] + vertex_count;
683                         if(j > 65535)
684                         {
685                                 dstream<<"FIXME: Meshbuffer ran out of indices"<<std::endl;
686                                 // NOTE: Fix is to just add an another MeshBuffer
687                         }
688                         p->indices.push_back(j);
689                 }
690                 for(u32 i=0; i<numVertices; i++)
691                 {
692                         p->vertices.push_back(vertices[i]);
693                 }
694         }
695
696         void fillMesh(scene::SMesh *mesh)
697         {
698                 /*dstream<<"Filling mesh with "<<m_prebuffers.size()
699                                 <<" meshbuffers"<<std::endl;*/
700                 for(u32 i=0; i<m_prebuffers.size(); i++)
701                 {
702                         PreMeshBuffer &p = m_prebuffers[i];
703
704                         /*dstream<<"p.vertices.size()="<<p.vertices.size()
705                                         <<", p.indices.size()="<<p.indices.size()
706                                         <<std::endl;*/
707                         
708                         // Create meshbuffer
709                         
710                         // This is a "Standard MeshBuffer",
711                         // it's a typedeffed CMeshBuffer<video::S3DVertex>
712                         scene::SMeshBuffer *buf = new scene::SMeshBuffer();
713                         // Set material
714                         buf->Material = p.material;
715                         //((scene::SMeshBuffer*)buf)->Material = p.material;
716                         // Use VBO
717                         //buf->setHardwareMappingHint(scene::EHM_STATIC);
718                         // Add to mesh
719                         mesh->addMeshBuffer(buf);
720                         // Mesh grabbed it
721                         buf->drop();
722
723                         buf->append(p.vertices.pointer(), p.vertices.size(),
724                                         p.indices.pointer(), p.indices.size());
725                 }
726         }
727
728 private:
729         core::array<PreMeshBuffer> m_prebuffers;
730 };
731
732 void makeCuboid(video::SMaterial &material, MeshCollector *collector,
733         AtlasPointer* pa, video::SColor &c,
734         v3f &pos, f32 rx, f32 ry, f32 rz)
735 {
736         video::S3DVertex v[4] =
737         {
738                 video::S3DVertex(0,0,0, 0,0,0, c,
739                         pa->x0(), pa->y1()),
740                 video::S3DVertex(0,0,0, 0,0,0, c,
741                         pa->x1(), pa->y1()),
742                 video::S3DVertex(0,0,0, 0,0,0, c,
743                         pa->x1(), pa->y0()),
744                 video::S3DVertex(0,0,0, 0,0,0, c,
745                         pa->x0(), pa->y0())
746         };
747
748         for(int i=0;i<6;i++)
749         {
750                 switch(i)
751                 {
752                         case 0:
753                                 v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
754                                 v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
755                                 v[2].Pos.X= rx; v[2].Pos.Y= ry; v[2].Pos.Z= rz;
756                                 v[3].Pos.X= rx; v[3].Pos.Y= ry, v[3].Pos.Z=-rz;
757                                 break;
758                         case 1:
759                                 v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
760                                 v[1].Pos.X= rx; v[1].Pos.Y= ry; v[1].Pos.Z=-rz;
761                                 v[2].Pos.X= rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
762                                 v[3].Pos.X=-rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
763                                 break;
764                         case 2:
765                                 v[0].Pos.X= rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
766                                 v[1].Pos.X= rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
767                                 v[2].Pos.X= rx; v[2].Pos.Y=-ry; v[2].Pos.Z= rz;
768                                 v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
769                                 break;
770                         case 3:
771                                 v[0].Pos.X= rx; v[0].Pos.Y= ry; v[0].Pos.Z= rz;
772                                 v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
773                                 v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z= rz;
774                                 v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z= rz;
775                                 break;
776                         case 4:
777                                 v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z= rz;
778                                 v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z=-rz;
779                                 v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
780                                 v[3].Pos.X=-rx; v[3].Pos.Y=-ry, v[3].Pos.Z= rz;
781                                 break;
782                         case 5:
783                                 v[0].Pos.X= rx; v[0].Pos.Y=-ry; v[0].Pos.Z= rz;
784                                 v[1].Pos.X=-rx; v[1].Pos.Y=-ry; v[1].Pos.Z= rz;
785                                 v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
786                                 v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
787                                 break;
788                 }
789                 for(u16 i=0; i<4; i++)
790                         v[i].Pos += pos;
791                 u16 indices[] = {0,1,2,2,3,0};
792                 collector->append(material, v, 4, indices, 6);
793
794         }
795
796 }
797
798 scene::SMesh* makeMapBlockMesh(MeshMakeData *data)
799 {
800         // 4-21ms for MAP_BLOCKSIZE=16
801         // 24-155ms for MAP_BLOCKSIZE=32
802         //TimeTaker timer1("makeMapBlockMesh()");
803
804         core::array<FastFace> fastfaces_new;
805
806         v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE;
807         
808         // floating point conversion
809         v3f posRelative_f(blockpos_nodes.X, blockpos_nodes.Y, blockpos_nodes.Z);
810         
811         /*
812                 Some settings
813         */
814         bool new_style_water = g_settings.getBool("new_style_water");
815         bool new_style_leaves = g_settings.getBool("new_style_leaves");
816         bool smooth_lighting = g_settings.getBool("smooth_lighting");
817         
818         float node_water_level = 1.0;
819         if(new_style_water)
820                 node_water_level = 0.85;
821         
822         /*
823                 We are including the faces of the trailing edges of the block.
824                 This means that when something changes, the caller must
825                 also update the meshes of the blocks at the leading edges.
826
827                 NOTE: This is the slowest part of this method.
828         */
829         
830         {
831                 // 4-23ms for MAP_BLOCKSIZE=16
832                 //TimeTaker timer2("updateMesh() collect");
833
834                 /*
835                         Go through every y,z and get top(y+) faces in rows of x+
836                 */
837                 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
838                         for(s16 z=0; z<MAP_BLOCKSIZE; z++){
839                                 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
840                                                 v3s16(0,y,z), MAP_BLOCKSIZE,
841                                                 v3s16(1,0,0), //dir
842                                                 v3f  (1,0,0),
843                                                 v3s16(0,1,0), //face dir
844                                                 v3f  (0,1,0),
845                                                 fastfaces_new,
846                                                 data->m_temp_mods,
847                                                 data->m_vmanip,
848                                                 blockpos_nodes,
849                                                 smooth_lighting);
850                         }
851                 }
852                 /*
853                         Go through every x,y and get right(x+) faces in rows of z+
854                 */
855                 for(s16 x=0; x<MAP_BLOCKSIZE; x++){
856                         for(s16 y=0; y<MAP_BLOCKSIZE; y++){
857                                 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
858                                                 v3s16(x,y,0), MAP_BLOCKSIZE,
859                                                 v3s16(0,0,1),
860                                                 v3f  (0,0,1),
861                                                 v3s16(1,0,0),
862                                                 v3f  (1,0,0),
863                                                 fastfaces_new,
864                                                 data->m_temp_mods,
865                                                 data->m_vmanip,
866                                                 blockpos_nodes,
867                                                 smooth_lighting);
868                         }
869                 }
870                 /*
871                         Go through every y,z and get back(z+) faces in rows of x+
872                 */
873                 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
874                         for(s16 y=0; y<MAP_BLOCKSIZE; y++){
875                                 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
876                                                 v3s16(0,y,z), MAP_BLOCKSIZE,
877                                                 v3s16(1,0,0),
878                                                 v3f  (1,0,0),
879                                                 v3s16(0,0,1),
880                                                 v3f  (0,0,1),
881                                                 fastfaces_new,
882                                                 data->m_temp_mods,
883                                                 data->m_vmanip,
884                                                 blockpos_nodes,
885                                                 smooth_lighting);
886                         }
887                 }
888         }
889
890         // End of slow part
891
892         /*
893                 Convert FastFaces to SMesh
894         */
895
896         MeshCollector collector;
897
898         if(fastfaces_new.size() > 0)
899         {
900                 // avg 0ms (100ms spikes when loading textures the first time)
901                 //TimeTaker timer2("updateMesh() mesh building");
902
903                 video::SMaterial material;
904                 material.setFlag(video::EMF_LIGHTING, false);
905                 material.setFlag(video::EMF_BILINEAR_FILTER, false);
906                 material.setFlag(video::EMF_FOG_ENABLE, true);
907                 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
908                 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE);
909
910                 for(u32 i=0; i<fastfaces_new.size(); i++)
911                 {
912                         FastFace &f = fastfaces_new[i];
913
914                         const u16 indices[] = {0,1,2,2,3,0};
915                         const u16 indices_alternate[] = {0,1,3,2,3,1};
916                         
917                         video::ITexture *texture = f.tile.texture.atlas;
918                         if(texture == NULL)
919                                 continue;
920
921                         material.setTexture(0, texture);
922                         
923                         f.tile.applyMaterialOptions(material);
924
925                         const u16 *indices_p = indices;
926                         
927                         /*
928                                 Revert triangles for nicer looking gradient if vertices
929                                 1 and 3 have same color or 0 and 2 have different color.
930                         */
931                         if(f.vertices[0].Color != f.vertices[2].Color
932                                         || f.vertices[1].Color == f.vertices[3].Color)
933                                 indices_p = indices_alternate;
934                         
935                         collector.append(material, f.vertices, 4, indices_p, 6);
936                 }
937         }
938
939         /*
940                 Add special graphics:
941                 - torches
942                 - flowing water
943         */
944
945         // 0ms
946         //TimeTaker timer2("updateMesh() adding special stuff");
947
948         // Flowing water material
949         video::SMaterial material_water1;
950         material_water1.setFlag(video::EMF_LIGHTING, false);
951         material_water1.setFlag(video::EMF_BACK_FACE_CULLING, false);
952         material_water1.setFlag(video::EMF_BILINEAR_FILTER, false);
953         material_water1.setFlag(video::EMF_FOG_ENABLE, true);
954         material_water1.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
955         AtlasPointer pa_water1 = g_texturesource->getTexture(
956                         g_texturesource->getTextureId("water.png"));
957         material_water1.setTexture(0, pa_water1.atlas);
958
959         // New-style leaves material
960         video::SMaterial material_leaves1;
961         material_leaves1.setFlag(video::EMF_LIGHTING, false);
962         //material_leaves1.setFlag(video::EMF_BACK_FACE_CULLING, false);
963         material_leaves1.setFlag(video::EMF_BILINEAR_FILTER, false);
964         material_leaves1.setFlag(video::EMF_FOG_ENABLE, true);
965         material_leaves1.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
966         AtlasPointer pa_leaves1 = g_texturesource->getTexture(
967                         g_texturesource->getTextureId("leaves.png"));
968         material_leaves1.setTexture(0, pa_leaves1.atlas);
969
970         // Glass material
971         video::SMaterial material_glass;
972         material_glass.setFlag(video::EMF_LIGHTING, false);
973         material_glass.setFlag(video::EMF_BILINEAR_FILTER, false);
974         material_glass.setFlag(video::EMF_FOG_ENABLE, true);
975         material_glass.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
976         AtlasPointer pa_glass = g_texturesource->getTexture(
977                         g_texturesource->getTextureId("glass.png"));
978         material_glass.setTexture(0, pa_glass.atlas);
979
980         // Wood material
981         video::SMaterial material_wood;
982         material_wood.setFlag(video::EMF_LIGHTING, false);
983         material_wood.setFlag(video::EMF_BILINEAR_FILTER, false);
984         material_wood.setFlag(video::EMF_FOG_ENABLE, true);
985         material_wood.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
986         AtlasPointer pa_wood = g_texturesource->getTexture(
987                         g_texturesource->getTextureId("wood.png"));
988         material_wood.setTexture(0, pa_wood.atlas);
989
990         // Papyrus material
991         video::SMaterial material_papyrus;
992         material_papyrus.setFlag(video::EMF_LIGHTING, false);
993         material_papyrus.setFlag(video::EMF_BILINEAR_FILTER, false);
994         material_papyrus.setFlag(video::EMF_FOG_ENABLE, true);
995         material_papyrus.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
996         AtlasPointer pa_papyrus = g_texturesource->getTexture(
997                         g_texturesource->getTextureId("papyrus.png"));
998         material_papyrus.setTexture(0, pa_papyrus.atlas);
999
1000         for(s16 z=0; z<MAP_BLOCKSIZE; z++)
1001         for(s16 y=0; y<MAP_BLOCKSIZE; y++)
1002         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
1003         {
1004                 v3s16 p(x,y,z);
1005
1006                 MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes+p);
1007                 
1008                 /*
1009                         Add torches to mesh
1010                 */
1011                 if(n.d == CONTENT_TORCH)
1012                 {
1013                         video::SColor c(255,255,255,255);
1014
1015                         // Wall at X+ of node
1016                         video::S3DVertex vertices[4] =
1017                         {
1018                                 video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 0,1),
1019                                 video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, 1,1),
1020                                 video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
1021                                 video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
1022                         };
1023
1024                         v3s16 dir = unpackDir(n.dir);
1025
1026                         for(s32 i=0; i<4; i++)
1027                         {
1028                                 if(dir == v3s16(1,0,0))
1029                                         vertices[i].Pos.rotateXZBy(0);
1030                                 if(dir == v3s16(-1,0,0))
1031                                         vertices[i].Pos.rotateXZBy(180);
1032                                 if(dir == v3s16(0,0,1))
1033                                         vertices[i].Pos.rotateXZBy(90);
1034                                 if(dir == v3s16(0,0,-1))
1035                                         vertices[i].Pos.rotateXZBy(-90);
1036                                 if(dir == v3s16(0,-1,0))
1037                                         vertices[i].Pos.rotateXZBy(45);
1038                                 if(dir == v3s16(0,1,0))
1039                                         vertices[i].Pos.rotateXZBy(-45);
1040
1041                                 vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
1042                         }
1043
1044                         // Set material
1045                         video::SMaterial material;
1046                         material.setFlag(video::EMF_LIGHTING, false);
1047                         material.setFlag(video::EMF_BACK_FACE_CULLING, false);
1048                         material.setFlag(video::EMF_BILINEAR_FILTER, false);
1049                         //material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
1050                         material.MaterialType
1051                                         = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
1052
1053                         if(dir == v3s16(0,-1,0))
1054                                 material.setTexture(0,
1055                                                 g_texturesource->getTextureRaw("torch_on_floor.png"));
1056                         else if(dir == v3s16(0,1,0))
1057                                 material.setTexture(0,
1058                                                 g_texturesource->getTextureRaw("torch_on_ceiling.png"));
1059                         // For backwards compatibility
1060                         else if(dir == v3s16(0,0,0))
1061                                 material.setTexture(0,
1062                                                 g_texturesource->getTextureRaw("torch_on_floor.png"));
1063                         else
1064                                 material.setTexture(0, 
1065                                                 g_texturesource->getTextureRaw("torch.png"));
1066
1067                         u16 indices[] = {0,1,2,2,3,0};
1068                         // Add to mesh collector
1069                         collector.append(material, vertices, 4, indices, 6);
1070                 }
1071                 /*
1072                         Signs on walls
1073                 */
1074                 if(n.d == CONTENT_SIGN_WALL)
1075                 {
1076                         u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
1077                         video::SColor c(255,l,l,l);
1078                                 
1079                         float d = (float)BS/16;
1080                         // Wall at X+ of node
1081                         video::S3DVertex vertices[4] =
1082                         {
1083                                 video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c, 0,1),
1084                                 video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c, 1,1),
1085                                 video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c, 1,0),
1086                                 video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c, 0,0),
1087                         };
1088
1089                         v3s16 dir = unpackDir(n.dir);
1090
1091                         for(s32 i=0; i<4; i++)
1092                         {
1093                                 if(dir == v3s16(1,0,0))
1094                                         vertices[i].Pos.rotateXZBy(0);
1095                                 if(dir == v3s16(-1,0,0))
1096                                         vertices[i].Pos.rotateXZBy(180);
1097                                 if(dir == v3s16(0,0,1))
1098                                         vertices[i].Pos.rotateXZBy(90);
1099                                 if(dir == v3s16(0,0,-1))
1100                                         vertices[i].Pos.rotateXZBy(-90);
1101                                 if(dir == v3s16(0,-1,0))
1102                                         vertices[i].Pos.rotateXYBy(-90);
1103                                 if(dir == v3s16(0,1,0))
1104                                         vertices[i].Pos.rotateXYBy(90);
1105
1106                                 vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
1107                         }
1108
1109                         // Set material
1110                         video::SMaterial material;
1111                         material.setFlag(video::EMF_LIGHTING, false);
1112                         material.setFlag(video::EMF_BACK_FACE_CULLING, false);
1113                         material.setFlag(video::EMF_BILINEAR_FILTER, false);
1114                         material.setFlag(video::EMF_FOG_ENABLE, true);
1115                         //material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
1116                         material.MaterialType
1117                                         = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
1118
1119                         material.setTexture(0, 
1120                                         g_texturesource->getTextureRaw("sign_wall.png"));
1121
1122                         u16 indices[] = {0,1,2,2,3,0};
1123                         // Add to mesh collector
1124                         collector.append(material, vertices, 4, indices, 6);
1125                 }
1126                 /*
1127                         Add flowing water to mesh
1128                 */
1129                 else if(n.d == CONTENT_WATER)
1130                 {
1131                         bool top_is_water = false;
1132                         MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
1133                         if(ntop.d == CONTENT_WATER || ntop.d == CONTENT_WATERSOURCE)
1134                                 top_is_water = true;
1135                         
1136                         u8 l = 0;
1137                         // Use the light of the node on top if possible
1138                         if(content_features(ntop.d).param_type == CPT_LIGHT)
1139                                 l = decode_light(ntop.getLightBlend(data->m_daynight_ratio));
1140                         // Otherwise use the light of this node (the water)
1141                         else
1142                                 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
1143                         video::SColor c(WATER_ALPHA,l,l,l);
1144                         
1145                         // Neighbor water levels (key = relative position)
1146                         // Includes current node
1147                         core::map<v3s16, f32> neighbor_levels;
1148                         core::map<v3s16, u8> neighbor_contents;
1149                         core::map<v3s16, u8> neighbor_flags;
1150                         const u8 neighborflag_top_is_water = 0x01;
1151                         v3s16 neighbor_dirs[9] = {
1152                                 v3s16(0,0,0),
1153                                 v3s16(0,0,1),
1154                                 v3s16(0,0,-1),
1155                                 v3s16(1,0,0),
1156                                 v3s16(-1,0,0),
1157                                 v3s16(1,0,1),
1158                                 v3s16(-1,0,-1),
1159                                 v3s16(1,0,-1),
1160                                 v3s16(-1,0,1),
1161                         };
1162                         for(u32 i=0; i<9; i++)
1163                         {
1164                                 u8 content = CONTENT_AIR;
1165                                 float level = -0.5 * BS;
1166                                 u8 flags = 0;
1167                                 // Check neighbor
1168                                 v3s16 p2 = p + neighbor_dirs[i];
1169                                 MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
1170                                 if(n2.d != CONTENT_IGNORE)
1171                                 {
1172                                         content = n2.d;
1173
1174                                         if(n2.d == CONTENT_WATERSOURCE)
1175                                                 level = (-0.5+node_water_level) * BS;
1176                                         else if(n2.d == CONTENT_WATER)
1177                                                 level = (-0.5 + ((float)n2.param2 + 0.5) / 8.0
1178                                                                 * node_water_level) * BS;
1179
1180                                         // Check node above neighbor.
1181                                         // NOTE: This doesn't get executed if neighbor
1182                                         //       doesn't exist
1183                                         p2.Y += 1;
1184                                         n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
1185                                         if(n2.d == CONTENT_WATERSOURCE || n2.d == CONTENT_WATER)
1186                                                 flags |= neighborflag_top_is_water;
1187                                 }
1188                                 
1189                                 neighbor_levels.insert(neighbor_dirs[i], level);
1190                                 neighbor_contents.insert(neighbor_dirs[i], content);
1191                                 neighbor_flags.insert(neighbor_dirs[i], flags);
1192                         }
1193
1194                         //float water_level = (-0.5 + ((float)n.param2 + 0.5) / 8.0) * BS;
1195                         //float water_level = neighbor_levels[v3s16(0,0,0)];
1196
1197                         // Corner heights (average between four waters)
1198                         f32 corner_levels[4];
1199                         
1200                         v3s16 halfdirs[4] = {
1201                                 v3s16(0,0,0),
1202                                 v3s16(1,0,0),
1203                                 v3s16(1,0,1),
1204                                 v3s16(0,0,1),
1205                         };
1206                         for(u32 i=0; i<4; i++)
1207                         {
1208                                 v3s16 cornerdir = halfdirs[i];
1209                                 float cornerlevel = 0;
1210                                 u32 valid_count = 0;
1211                                 for(u32 j=0; j<4; j++)
1212                                 {
1213                                         v3s16 neighbordir = cornerdir - halfdirs[j];
1214                                         u8 content = neighbor_contents[neighbordir];
1215                                         // Special case for source nodes
1216                                         if(content == CONTENT_WATERSOURCE)
1217                                         {
1218                                                 cornerlevel = (-0.5+node_water_level)*BS;
1219                                                 valid_count = 1;
1220                                                 break;
1221                                         }
1222                                         else if(content == CONTENT_WATER)
1223                                         {
1224                                                 cornerlevel += neighbor_levels[neighbordir];
1225                                                 valid_count++;
1226                                         }
1227                                         else if(content == CONTENT_AIR)
1228                                         {
1229                                                 cornerlevel += -0.5*BS;
1230                                                 valid_count++;
1231                                         }
1232                                 }
1233                                 if(valid_count > 0)
1234                                         cornerlevel /= valid_count;
1235                                 corner_levels[i] = cornerlevel;
1236                         }
1237
1238                         /*
1239                                 Generate sides
1240                         */
1241
1242                         v3s16 side_dirs[4] = {
1243                                 v3s16(1,0,0),
1244                                 v3s16(-1,0,0),
1245                                 v3s16(0,0,1),
1246                                 v3s16(0,0,-1),
1247                         };
1248                         s16 side_corners[4][2] = {
1249                                 {1, 2},
1250                                 {3, 0},
1251                                 {2, 3},
1252                                 {0, 1},
1253                         };
1254                         for(u32 i=0; i<4; i++)
1255                         {
1256                                 v3s16 dir = side_dirs[i];
1257
1258                                 /*
1259                                         If our topside is water and neighbor's topside
1260                                         is water, don't draw side face
1261                                 */
1262                                 if(top_is_water &&
1263                                                 neighbor_flags[dir] & neighborflag_top_is_water)
1264                                         continue;
1265
1266                                 u8 neighbor_content = neighbor_contents[dir];
1267                                 
1268                                 // Don't draw face if neighbor is not air or water
1269                                 if(neighbor_content != CONTENT_AIR
1270                                                 && neighbor_content != CONTENT_WATER)
1271                                         continue;
1272                                 
1273                                 bool neighbor_is_water = (neighbor_content == CONTENT_WATER);
1274                                 
1275                                 // Don't draw any faces if neighbor is water and top is water
1276                                 if(neighbor_is_water == true && top_is_water == false)
1277                                         continue;
1278                                 
1279                                 video::S3DVertex vertices[4] =
1280                                 {
1281                                         /*video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
1282                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,1),
1283                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
1284                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
1285                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
1286                                                         pa_water1.x0(), pa_water1.y1()),
1287                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
1288                                                         pa_water1.x1(), pa_water1.y1()),
1289                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
1290                                                         pa_water1.x1(), pa_water1.y0()),
1291                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
1292                                                         pa_water1.x0(), pa_water1.y0()),
1293                                 };
1294                                 
1295                                 /*
1296                                         If our topside is water, set upper border of face
1297                                         at upper border of node
1298                                 */
1299                                 if(top_is_water)
1300                                 {
1301                                         vertices[2].Pos.Y = 0.5*BS;
1302                                         vertices[3].Pos.Y = 0.5*BS;
1303                                 }
1304                                 /*
1305                                         Otherwise upper position of face is corner levels
1306                                 */
1307                                 else
1308                                 {
1309                                         vertices[2].Pos.Y = corner_levels[side_corners[i][0]];
1310                                         vertices[3].Pos.Y = corner_levels[side_corners[i][1]];
1311                                 }
1312                                 
1313                                 /*
1314                                         If neighbor is water, lower border of face is corner
1315                                         water levels
1316                                 */
1317                                 if(neighbor_is_water)
1318                                 {
1319                                         vertices[0].Pos.Y = corner_levels[side_corners[i][1]];
1320                                         vertices[1].Pos.Y = corner_levels[side_corners[i][0]];
1321                                 }
1322                                 /*
1323                                         If neighbor is not water, lower border of face is
1324                                         lower border of node
1325                                 */
1326                                 else
1327                                 {
1328                                         vertices[0].Pos.Y = -0.5*BS;
1329                                         vertices[1].Pos.Y = -0.5*BS;
1330                                 }
1331                                 
1332                                 for(s32 j=0; j<4; j++)
1333                                 {
1334                                         if(dir == v3s16(0,0,1))
1335                                                 vertices[j].Pos.rotateXZBy(0);
1336                                         if(dir == v3s16(0,0,-1))
1337                                                 vertices[j].Pos.rotateXZBy(180);
1338                                         if(dir == v3s16(-1,0,0))
1339                                                 vertices[j].Pos.rotateXZBy(90);
1340                                         if(dir == v3s16(1,0,-0))
1341                                                 vertices[j].Pos.rotateXZBy(-90);
1342
1343                                         vertices[j].Pos += intToFloat(p + blockpos_nodes, BS);
1344                                 }
1345
1346                                 u16 indices[] = {0,1,2,2,3,0};
1347                                 // Add to mesh collector
1348                                 collector.append(material_water1, vertices, 4, indices, 6);
1349                         }
1350                         
1351                         /*
1352                                 Generate top side, if appropriate
1353                         */
1354                         
1355                         if(top_is_water == false)
1356                         {
1357                                 video::S3DVertex vertices[4] =
1358                                 {
1359                                         /*video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
1360                                         video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1),
1361                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
1362                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
1363                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
1364                                                         pa_water1.x0(), pa_water1.y1()),
1365                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
1366                                                         pa_water1.x1(), pa_water1.y1()),
1367                                         video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
1368                                                         pa_water1.x1(), pa_water1.y0()),
1369                                         video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
1370                                                         pa_water1.x0(), pa_water1.y0()),
1371                                 };
1372                                 
1373                                 // This fixes a strange bug
1374                                 s32 corner_resolve[4] = {3,2,1,0};
1375
1376                                 for(s32 i=0; i<4; i++)
1377                                 {
1378                                         //vertices[i].Pos.Y += water_level;
1379                                         //vertices[i].Pos.Y += neighbor_levels[v3s16(0,0,0)];
1380                                         s32 j = corner_resolve[i];
1381                                         vertices[i].Pos.Y += corner_levels[j];
1382                                         vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
1383                                 }
1384
1385                                 u16 indices[] = {0,1,2,2,3,0};
1386                                 // Add to mesh collector
1387                                 collector.append(material_water1, vertices, 4, indices, 6);
1388                         }
1389                 }
1390                 /*
1391                         Add water sources to mesh if using new style
1392                 */
1393                 else if(n.d == CONTENT_WATERSOURCE && new_style_water)
1394                 {
1395                         //bool top_is_water = false;
1396                         bool top_is_air = false;
1397                         MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
1398                         /*if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE)
1399                                 top_is_water = true;*/
1400                         if(n.d == CONTENT_AIR)
1401                                 top_is_air = true;
1402                         
1403                         /*if(top_is_water == true)
1404                                 continue;*/
1405                         if(top_is_air == false)
1406                                 continue;
1407
1408                         u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
1409                         video::SColor c(WATER_ALPHA,l,l,l);
1410                         
1411                         video::S3DVertex vertices[4] =
1412                         {
1413                                 /*video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
1414                                 video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1),
1415                                 video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
1416                                 video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
1417                                 video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
1418                                                 pa_water1.x0(), pa_water1.y1()),
1419                                 video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
1420                                                 pa_water1.x1(), pa_water1.y1()),
1421                                 video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
1422                                                 pa_water1.x1(), pa_water1.y0()),
1423                                 video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
1424                                                 pa_water1.x0(), pa_water1.y0()),
1425                         };
1426
1427                         for(s32 i=0; i<4; i++)
1428                         {
1429                                 vertices[i].Pos.Y += (-0.5+node_water_level)*BS;
1430                                 vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
1431                         }
1432
1433                         u16 indices[] = {0,1,2,2,3,0};
1434                         // Add to mesh collector
1435                         collector.append(material_water1, vertices, 4, indices, 6);
1436                 }
1437                 /*
1438                         Add leaves if using new style
1439                 */
1440                 else if(n.d == CONTENT_LEAVES && new_style_leaves)
1441                 {
1442                         /*u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));*/
1443                         u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
1444                         video::SColor c(255,l,l,l);
1445
1446                         for(u32 j=0; j<6; j++)
1447                         {
1448                                 video::S3DVertex vertices[4] =
1449                                 {
1450                                         /*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
1451                                         video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1),
1452                                         video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0),
1453                                         video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),*/
1454                                         video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
1455                                                 pa_leaves1.x0(), pa_leaves1.y1()),
1456                                         video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
1457                                                 pa_leaves1.x1(), pa_leaves1.y1()),
1458                                         video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
1459                                                 pa_leaves1.x1(), pa_leaves1.y0()),
1460                                         video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
1461                                                 pa_leaves1.x0(), pa_leaves1.y0()),
1462                                 };
1463
1464                                 if(j == 0)
1465                                 {
1466                                         for(u16 i=0; i<4; i++)
1467                                                 vertices[i].Pos.rotateXZBy(0);
1468                                 }
1469                                 else if(j == 1)
1470                                 {
1471                                         for(u16 i=0; i<4; i++)
1472                                                 vertices[i].Pos.rotateXZBy(180);
1473                                 }
1474                                 else if(j == 2)
1475                                 {
1476                                         for(u16 i=0; i<4; i++)
1477                                                 vertices[i].Pos.rotateXZBy(-90);
1478                                 }
1479                                 else if(j == 3)
1480                                 {
1481                                         for(u16 i=0; i<4; i++)
1482                                                 vertices[i].Pos.rotateXZBy(90);
1483                                 }
1484                                 else if(j == 4)
1485                                 {
1486                                         for(u16 i=0; i<4; i++)
1487                                                 vertices[i].Pos.rotateYZBy(-90);
1488                                 }
1489                                 else if(j == 5)
1490                                 {
1491                                         for(u16 i=0; i<4; i++)
1492                                                 vertices[i].Pos.rotateYZBy(90);
1493                                 }
1494
1495                                 for(u16 i=0; i<4; i++)
1496                                 {
1497                                         vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
1498                                 }
1499
1500                                 u16 indices[] = {0,1,2,2,3,0};
1501                                 // Add to mesh collector
1502                                 collector.append(material_leaves1, vertices, 4, indices, 6);
1503                         }
1504                 }
1505                 /*
1506                         Add glass
1507                 */
1508                 else if(n.d == CONTENT_GLASS)
1509                 {
1510                         u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
1511                         video::SColor c(255,l,l,l);
1512
1513                         for(u32 j=0; j<6; j++)
1514                         {
1515                                 video::S3DVertex vertices[4] =
1516                                 {
1517                                         video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
1518                                                 pa_glass.x0(), pa_glass.y1()),
1519                                         video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
1520                                                 pa_glass.x1(), pa_glass.y1()),
1521                                         video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
1522                                                 pa_glass.x1(), pa_glass.y0()),
1523                                         video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
1524                                                 pa_glass.x0(), pa_glass.y0()),
1525                                 };
1526
1527                                 if(j == 0)
1528                                 {
1529                                         for(u16 i=0; i<4; i++)
1530                                                 vertices[i].Pos.rotateXZBy(0);
1531                                 }
1532                                 else if(j == 1)
1533                                 {
1534                                         for(u16 i=0; i<4; i++)
1535                                                 vertices[i].Pos.rotateXZBy(180);
1536                                 }
1537                                 else if(j == 2)
1538                                 {
1539                                         for(u16 i=0; i<4; i++)
1540                                                 vertices[i].Pos.rotateXZBy(-90);
1541                                 }
1542                                 else if(j == 3)
1543                                 {
1544                                         for(u16 i=0; i<4; i++)
1545                                                 vertices[i].Pos.rotateXZBy(90);
1546                                 }
1547                                 else if(j == 4)
1548                                 {
1549                                         for(u16 i=0; i<4; i++)
1550                                                 vertices[i].Pos.rotateYZBy(-90);
1551                                 }
1552                                 else if(j == 5)
1553                                 {
1554                                         for(u16 i=0; i<4; i++)
1555                                                 vertices[i].Pos.rotateYZBy(90);
1556                                 }
1557
1558                                 for(u16 i=0; i<4; i++)
1559                                 {
1560                                         vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
1561                                 }
1562
1563                                 u16 indices[] = {0,1,2,2,3,0};
1564                                 // Add to mesh collector
1565                                 collector.append(material_glass, vertices, 4, indices, 6);
1566                         }
1567                 }
1568                 /*
1569                         Add fence
1570                 */
1571                 else if(n.d == CONTENT_FENCE)
1572                 {
1573                         u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
1574                         video::SColor c(255,l,l,l);
1575
1576                         const f32 post_rad=(f32)BS/(32.0/4.0);
1577                         const f32 bar_rad=(f32)BS/(32.0/2.0);
1578                         const f32 bar_len=(f32)(BS/2)-post_rad;
1579
1580                         // The post - always present
1581                         v3f pos = intToFloat(p+blockpos_nodes, BS);
1582                         makeCuboid(material_wood, &collector,
1583                                 &pa_wood, c, pos,
1584                                 post_rad,BS/2,post_rad);
1585
1586                         // Now a section of fence, +X, if there's a post there
1587                         v3s16 p2 = p;
1588                         p2.X++;
1589                         MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
1590                         if(n2.d == CONTENT_FENCE)
1591                         {
1592                                 pos = intToFloat(p+blockpos_nodes, BS);
1593                                 pos.X += BS/2;
1594                                 pos.Y += 3*bar_rad;
1595                                 makeCuboid(material_wood, &collector,
1596                                         &pa_wood, c, pos,
1597                                         bar_len,bar_rad,bar_rad);
1598
1599                                 pos.Y -= 6*bar_rad;
1600                                 makeCuboid(material_wood, &collector,
1601                                         &pa_wood, c, pos,
1602                                         bar_len,bar_rad,bar_rad);
1603                         }
1604
1605                         // Now a section of fence, +Z, if there's a post there
1606                         p2 = p;
1607                         p2.Z++;
1608                         n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
1609                         if(n2.d == CONTENT_FENCE)
1610                         {
1611                                 pos = intToFloat(p+blockpos_nodes, BS);
1612                                 pos.Z += BS/2;
1613                                 pos.Y += 3*bar_rad;
1614                                 makeCuboid(material_wood, &collector,
1615                                         &pa_wood, c, pos,
1616                                         bar_rad,bar_rad,bar_len);
1617                                 pos.Y -= 6*bar_rad;
1618                                 makeCuboid(material_wood, &collector,
1619                                         &pa_wood, c, pos,
1620                                         bar_rad,bar_rad,bar_len);
1621
1622                         }
1623
1624                 }
1625                 else if(n.d == CONTENT_PAPYRUS)
1626                 {
1627                         u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
1628                         video::SColor c(255,l,l,l);
1629
1630                         for(u32 j=0; j<4; j++)
1631                         {
1632                                 video::S3DVertex vertices[4] =
1633                                 {
1634                                         video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c,
1635                                                 pa_papyrus.x0(), pa_papyrus.y1()),
1636                                         video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c,
1637                                                 pa_papyrus.x1(), pa_papyrus.y1()),
1638                                         video::S3DVertex(BS/2,BS/2,0, 0,0,0, c,
1639                                                 pa_papyrus.x1(), pa_papyrus.y0()),
1640                                         video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c,
1641                                                 pa_papyrus.x0(), pa_papyrus.y0()),
1642                                 };
1643
1644                                 if(j == 0)
1645                                 {
1646                                         for(u16 i=0; i<4; i++)
1647                                                 vertices[i].Pos.rotateXZBy(45);
1648                                 }
1649                                 else if(j == 1)
1650                                 {
1651                                         for(u16 i=0; i<4; i++)
1652                                                 vertices[i].Pos.rotateXZBy(-45);
1653                                 }
1654                                 else if(j == 2)
1655                                 {
1656                                         for(u16 i=0; i<4; i++)
1657                                                 vertices[i].Pos.rotateXZBy(135);
1658                                 }
1659                                 else if(j == 3)
1660                                 {
1661                                         for(u16 i=0; i<4; i++)
1662                                                 vertices[i].Pos.rotateXZBy(-135);
1663                                 }
1664
1665                                 for(u16 i=0; i<4; i++)
1666                                 {
1667                                         vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
1668                                 }
1669
1670                                 u16 indices[] = {0,1,2,2,3,0};
1671                                 // Add to mesh collector
1672                                 collector.append(material_papyrus, vertices, 4, indices, 6);
1673                         }
1674                 }
1675
1676         }
1677
1678         /*
1679                 Add stuff from collector to mesh
1680         */
1681         
1682         scene::SMesh *mesh_new = NULL;
1683         mesh_new = new scene::SMesh();
1684         
1685         collector.fillMesh(mesh_new);
1686
1687         /*
1688                 Do some stuff to the mesh
1689         */
1690
1691         mesh_new->recalculateBoundingBox();
1692
1693         /*
1694                 Delete new mesh if it is empty
1695         */
1696
1697         if(mesh_new->getMeshBufferCount() == 0)
1698         {
1699                 mesh_new->drop();
1700                 mesh_new = NULL;
1701         }
1702
1703         if(mesh_new)
1704         {
1705 #if 0
1706                 // Usually 1-700 faces and 1-7 materials
1707                 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
1708                                 <<"and uses "<<mesh_new->getMeshBufferCount()
1709                                 <<" materials (meshbuffers)"<<std::endl;
1710 #endif
1711
1712                 // Use VBO for mesh (this just would set this for ever buffer)
1713                 // This will lead to infinite memory usage because or irrlicht.
1714                 //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
1715
1716                 /*
1717                         NOTE: If that is enabled, some kind of a queue to the main
1718                         thread should be made which would call irrlicht to delete
1719                         the hardware buffer and then delete the mesh
1720                 */
1721         }
1722
1723         return mesh_new;
1724         
1725         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1726 }
1727
1728 #endif // !SERVER
1729
1730 /*
1731         MapBlock
1732 */
1733
1734 MapBlock::MapBlock(NodeContainer *parent, v3s16 pos, bool dummy):
1735                 m_parent(parent),
1736                 m_pos(pos),
1737                 changed(true),
1738                 is_underground(false),
1739                 m_lighting_expired(true),
1740                 m_day_night_differs(false),
1741                 //m_not_fully_generated(false),
1742                 m_objects(this),
1743                 m_timestamp(BLOCK_TIMESTAMP_UNDEFINED)
1744 {
1745         data = NULL;
1746         if(dummy == false)
1747                 reallocate();
1748         
1749         //m_spawn_timer = -10000;
1750
1751 #ifndef SERVER
1752         m_mesh_expired = false;
1753         mesh_mutex.Init();
1754         mesh = NULL;
1755         m_temp_mods_mutex.Init();
1756 #endif
1757 }
1758
1759 MapBlock::~MapBlock()
1760 {
1761 #ifndef SERVER
1762         {
1763                 JMutexAutoLock lock(mesh_mutex);
1764                 
1765                 if(mesh)
1766                 {
1767                         mesh->drop();
1768                         mesh = NULL;
1769                 }
1770         }
1771 #endif
1772
1773         if(data)
1774                 delete[] data;
1775 }
1776
1777 bool MapBlock::isValidPositionParent(v3s16 p)
1778 {
1779         if(isValidPosition(p))
1780         {
1781                 return true;
1782         }
1783         else{
1784                 return m_parent->isValidPosition(getPosRelative() + p);
1785         }
1786 }
1787
1788 MapNode MapBlock::getNodeParent(v3s16 p)
1789 {
1790         if(isValidPosition(p) == false)
1791         {
1792                 return m_parent->getNode(getPosRelative() + p);
1793         }
1794         else
1795         {
1796                 if(data == NULL)
1797                         throw InvalidPositionException();
1798                 return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X];
1799         }
1800 }
1801
1802 void MapBlock::setNodeParent(v3s16 p, MapNode & n)
1803 {
1804         if(isValidPosition(p) == false)
1805         {
1806                 m_parent->setNode(getPosRelative() + p, n);
1807         }
1808         else
1809         {
1810                 if(data == NULL)
1811                         throw InvalidPositionException();
1812                 data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X] = n;
1813         }
1814 }
1815
1816 MapNode MapBlock::getNodeParentNoEx(v3s16 p)
1817 {
1818         if(isValidPosition(p) == false)
1819         {
1820                 try{
1821                         return m_parent->getNode(getPosRelative() + p);
1822                 }
1823                 catch(InvalidPositionException &e)
1824                 {
1825                         return MapNode(CONTENT_IGNORE);
1826                 }
1827         }
1828         else
1829         {
1830                 if(data == NULL)
1831                 {
1832                         return MapNode(CONTENT_IGNORE);
1833                 }
1834                 return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X];
1835         }
1836 }
1837
1838 #ifndef SERVER
1839
1840 #if 1
1841 void MapBlock::updateMesh(u32 daynight_ratio)
1842 {
1843 #if 0
1844         /*
1845                 DEBUG: If mesh has been generated, don't generate it again
1846         */
1847         {
1848                 JMutexAutoLock meshlock(mesh_mutex);
1849                 if(mesh != NULL)
1850                         return;
1851         }
1852 #endif
1853
1854         MeshMakeData data;
1855         data.fill(daynight_ratio, this);
1856         
1857         scene::SMesh *mesh_new = makeMapBlockMesh(&data);
1858         
1859         /*
1860                 Replace the mesh
1861         */
1862
1863         replaceMesh(mesh_new);
1864
1865 }
1866 #endif
1867
1868 void MapBlock::replaceMesh(scene::SMesh *mesh_new)
1869 {
1870         mesh_mutex.Lock();
1871
1872         //scene::SMesh *mesh_old = mesh[daynight_i];
1873         //mesh[daynight_i] = mesh_new;
1874
1875         scene::SMesh *mesh_old = mesh;
1876         mesh = mesh_new;
1877         setMeshExpired(false);
1878         
1879         if(mesh_old != NULL)
1880         {
1881                 // Remove hardware buffers of meshbuffers of mesh
1882                 // NOTE: No way, this runs in a different thread and everything
1883                 /*u32 c = mesh_old->getMeshBufferCount();
1884                 for(u32 i=0; i<c; i++)
1885                 {
1886                         IMeshBuffer *buf = mesh_old->getMeshBuffer(i);
1887                 }*/
1888                 
1889                 /*dstream<<"mesh_old->getReferenceCount()="
1890                                 <<mesh_old->getReferenceCount()<<std::endl;
1891                 u32 c = mesh_old->getMeshBufferCount();
1892                 for(u32 i=0; i<c; i++)
1893                 {
1894                         scene::IMeshBuffer *buf = mesh_old->getMeshBuffer(i);
1895                         dstream<<"buf->getReferenceCount()="
1896                                         <<buf->getReferenceCount()<<std::endl;
1897                 }*/
1898
1899                 // Drop the mesh
1900                 mesh_old->drop();
1901
1902                 //delete mesh_old;
1903         }
1904
1905         mesh_mutex.Unlock();
1906 }
1907         
1908 #endif // !SERVER
1909
1910 /*
1911         Propagates sunlight down through the block.
1912         Doesn't modify nodes that are not affected by sunlight.
1913         
1914         Returns false if sunlight at bottom block is invalid.
1915         Returns true if sunlight at bottom block is valid.
1916         Returns true if bottom block doesn't exist.
1917
1918         If there is a block above, continues from it.
1919         If there is no block above, assumes there is sunlight, unless
1920         is_underground is set or highest node is water.
1921
1922         All sunlighted nodes are added to light_sources.
1923
1924         If grow_grass==true, turns sunglighted mud into grass.
1925
1926         if remove_light==true, sets non-sunlighted nodes black.
1927
1928         if black_air_left!=NULL, it is set to true if non-sunlighted
1929         air is left in block.
1930 */
1931 bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources,
1932                 bool remove_light, bool *black_air_left,
1933                 bool grow_grass)
1934 {
1935         // Whether the sunlight at the top of the bottom block is valid
1936         bool block_below_is_valid = true;
1937         
1938         v3s16 pos_relative = getPosRelative();
1939         
1940         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
1941         {
1942                 for(s16 z=0; z<MAP_BLOCKSIZE; z++)
1943                 {
1944 #if 1
1945                         bool no_sunlight = false;
1946                         bool no_top_block = false;
1947                         // Check if node above block has sunlight
1948                         try{
1949                                 MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z));
1950                                 if(n.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
1951                                 {
1952                                         no_sunlight = true;
1953                                 }
1954                         }
1955                         catch(InvalidPositionException &e)
1956                         {
1957                                 no_top_block = true;
1958                                 
1959                                 // NOTE: This makes over-ground roofed places sunlighted
1960                                 // Assume sunlight, unless is_underground==true
1961                                 if(is_underground)
1962                                 {
1963                                         no_sunlight = true;
1964                                 }
1965                                 else
1966                                 {
1967                                         MapNode n = getNode(v3s16(x, MAP_BLOCKSIZE-1, z));
1968                                         if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE)
1969                                         {
1970                                                 no_sunlight = true;
1971                                         }
1972                                 }
1973                                 // NOTE: As of now, this just would make everything dark.
1974                                 // No sunlight here
1975                                 //no_sunlight = true;
1976                         }
1977 #endif
1978 #if 0 // Doesn't work; nothing gets light.
1979                         bool no_sunlight = true;
1980                         bool no_top_block = false;
1981                         // Check if node above block has sunlight
1982                         try{
1983                                 MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z));
1984                                 if(n.getLight(LIGHTBANK_DAY) == LIGHT_SUN)
1985                                 {
1986                                         no_sunlight = false;
1987                                 }
1988                         }
1989                         catch(InvalidPositionException &e)
1990                         {
1991                                 no_top_block = true;
1992                         }
1993 #endif
1994
1995                         /*std::cout<<"("<<x<<","<<z<<"): "
1996                                         <<"no_top_block="<<no_top_block
1997                                         <<", is_underground="<<is_underground
1998                                         <<", no_sunlight="<<no_sunlight
1999                                         <<std::endl;*/
2000                 
2001                         s16 y = MAP_BLOCKSIZE-1;
2002                         
2003                         // This makes difference to diminishing in water.
2004                         bool stopped_to_solid_object = false;
2005                         
2006                         u8 current_light = no_sunlight ? 0 : LIGHT_SUN;
2007
2008                         for(; y >= 0; y--)
2009                         {
2010                                 v3s16 pos(x, y, z);
2011                                 MapNode &n = getNodeRef(pos);
2012                                 
2013                                 if(current_light == 0)
2014                                 {
2015                                         // Do nothing
2016                                 }
2017                                 else if(current_light == LIGHT_SUN && n.sunlight_propagates())
2018                                 {
2019                                         // Do nothing: Sunlight is continued
2020                                 }
2021                                 else if(n.light_propagates() == false)
2022                                 {
2023                                         if(grow_grass)
2024                                         {
2025                                                 bool upper_is_air = false;
2026                                                 try
2027                                                 {
2028                                                         if(getNodeParent(pos+v3s16(0,1,0)).d == CONTENT_AIR)
2029                                                                 upper_is_air = true;
2030                                                 }
2031                                                 catch(InvalidPositionException &e)
2032                                                 {
2033                                                 }
2034                                                 // Turn mud into grass
2035                                                 if(upper_is_air && n.d == CONTENT_MUD
2036                                                                 && current_light == LIGHT_SUN)
2037                                                 {
2038                                                         n.d = CONTENT_GRASS;
2039                                                 }
2040                                         }
2041
2042                                         // A solid object is on the way.
2043                                         stopped_to_solid_object = true;
2044                                         
2045                                         // Light stops.
2046                                         current_light = 0;
2047                                 }
2048                                 else
2049                                 {
2050                                         // Diminish light
2051                                         current_light = diminish_light(current_light);
2052                                 }
2053
2054                                 u8 old_light = n.getLight(LIGHTBANK_DAY);
2055
2056                                 if(current_light > old_light || remove_light)
2057                                 {
2058                                         n.setLight(LIGHTBANK_DAY, current_light);
2059                                 }
2060                                 
2061                                 if(diminish_light(current_light) != 0)
2062                                 {
2063                                         light_sources.insert(pos_relative + pos, true);
2064                                 }
2065
2066                                 if(current_light == 0 && stopped_to_solid_object)
2067                                 {
2068                                         if(black_air_left)
2069                                         {
2070                                                 *black_air_left = true;
2071                                         }
2072                                 }
2073                         }
2074
2075                         // Whether or not the block below should see LIGHT_SUN
2076                         bool sunlight_should_go_down = (current_light == LIGHT_SUN);
2077
2078                         /*
2079                                 If the block below hasn't already been marked invalid:
2080
2081                                 Check if the node below the block has proper sunlight at top.
2082                                 If not, the block below is invalid.
2083                                 
2084                                 Ignore non-transparent nodes as they always have no light
2085                         */
2086                         try
2087                         {
2088                         if(block_below_is_valid)
2089                         {
2090                                 MapNode n = getNodeParent(v3s16(x, -1, z));
2091                                 if(n.light_propagates())
2092                                 {
2093                                         if(n.getLight(LIGHTBANK_DAY) == LIGHT_SUN
2094                                                         && sunlight_should_go_down == false)
2095                                                 block_below_is_valid = false;
2096                                         else if(n.getLight(LIGHTBANK_DAY) != LIGHT_SUN
2097                                                         && sunlight_should_go_down == true)
2098                                                 block_below_is_valid = false;
2099                                 }
2100                         }//if
2101                         }//try
2102                         catch(InvalidPositionException &e)
2103                         {
2104                                 /*std::cout<<"InvalidBlockException for bottom block node"
2105                                                 <<std::endl;*/
2106                                 // Just no block below, no need to panic.
2107                         }
2108                 }
2109         }
2110
2111         return block_below_is_valid;
2112 }
2113
2114
2115 void MapBlock::copyTo(VoxelManipulator &dst)
2116 {
2117         v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
2118         VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
2119         
2120         // Copy from data to VoxelManipulator
2121         dst.copyFrom(data, data_area, v3s16(0,0,0),
2122                         getPosRelative(), data_size);
2123 }
2124
2125 void MapBlock::copyFrom(VoxelManipulator &dst)
2126 {
2127         v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
2128         VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
2129         
2130         // Copy from VoxelManipulator to data
2131         dst.copyTo(data, data_area, v3s16(0,0,0),
2132                         getPosRelative(), data_size);
2133 }
2134
2135 void MapBlock::stepObjects(float dtime, bool server, u32 daynight_ratio)
2136 {
2137         /*
2138                 Step objects
2139         */
2140         m_objects.step(dtime, server, daynight_ratio);
2141
2142         setChangedFlag();
2143 }
2144
2145
2146 void MapBlock::updateDayNightDiff()
2147 {
2148         if(data == NULL)
2149         {
2150                 m_day_night_differs = false;
2151                 return;
2152         }
2153
2154         bool differs = false;
2155
2156         /*
2157                 Check if any lighting value differs
2158         */
2159         for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
2160         {
2161                 MapNode &n = data[i];
2162                 if(n.getLight(LIGHTBANK_DAY) != n.getLight(LIGHTBANK_NIGHT))
2163                 {
2164                         differs = true;
2165                         break;
2166                 }
2167         }
2168
2169         /*
2170                 If some lighting values differ, check if the whole thing is
2171                 just air. If it is, differ = false
2172         */
2173         if(differs)
2174         {
2175                 bool only_air = true;
2176                 for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
2177                 {
2178                         MapNode &n = data[i];
2179                         if(n.d != CONTENT_AIR)
2180                         {
2181                                 only_air = false;
2182                                 break;
2183                         }
2184                 }
2185                 if(only_air)
2186                         differs = false;
2187         }
2188
2189         // Set member variable
2190         m_day_night_differs = differs;
2191 }
2192
2193 s16 MapBlock::getGroundLevel(v2s16 p2d)
2194 {
2195         if(isDummy())
2196                 return -3;
2197         try
2198         {
2199                 s16 y = MAP_BLOCKSIZE-1;
2200                 for(; y>=0; y--)
2201                 {
2202                         //if(is_ground_content(getNodeRef(p2d.X, y, p2d.Y).d))
2203                         if(content_features(getNodeRef(p2d.X, y, p2d.Y).d).walkable)
2204                         {
2205                                 if(y == MAP_BLOCKSIZE-1)
2206                                         return -2;
2207                                 else
2208                                         return y;
2209                         }
2210                 }
2211                 return -1;
2212         }
2213         catch(InvalidPositionException &e)
2214         {
2215                 return -3;
2216         }
2217 }
2218
2219 /*
2220         Serialization
2221 */
2222
2223 void MapBlock::serialize(std::ostream &os, u8 version)
2224 {
2225         if(!ser_ver_supported(version))
2226                 throw VersionMismatchException("ERROR: MapBlock format not supported");
2227         
2228         if(data == NULL)
2229         {
2230                 throw SerializationError("ERROR: Not writing dummy block.");
2231         }
2232         
2233         // These have no compression
2234         if(version <= 3 || version == 5 || version == 6)
2235         {
2236                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
2237                 
2238                 u32 buflen = 1 + nodecount * MapNode::serializedLength(version);
2239                 SharedBuffer<u8> dest(buflen);
2240
2241                 dest[0] = is_underground;
2242                 for(u32 i=0; i<nodecount; i++)
2243                 {
2244                         u32 s = 1 + i * MapNode::serializedLength(version);
2245                         data[i].serialize(&dest[s], version);
2246                 }
2247                 
2248                 os.write((char*)*dest, dest.getSize());
2249         }
2250         else if(version <= 10)
2251         {
2252                 /*
2253                         With compression.
2254                         Compress the materials and the params separately.
2255                 */
2256                 
2257                 // First byte
2258                 os.write((char*)&is_underground, 1);
2259
2260                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
2261
2262                 // Get and compress materials
2263                 SharedBuffer<u8> materialdata(nodecount);
2264                 for(u32 i=0; i<nodecount; i++)
2265                 {
2266                         materialdata[i] = data[i].d;
2267                 }
2268                 compress(materialdata, os, version);
2269
2270                 // Get and compress lights
2271                 SharedBuffer<u8> lightdata(nodecount);
2272                 for(u32 i=0; i<nodecount; i++)
2273                 {
2274                         lightdata[i] = data[i].param;
2275                 }
2276                 compress(lightdata, os, version);
2277                 
2278                 if(version >= 10)
2279                 {
2280                         // Get and compress param2
2281                         SharedBuffer<u8> param2data(nodecount);
2282                         for(u32 i=0; i<nodecount; i++)
2283                         {
2284                                 param2data[i] = data[i].param2;
2285                         }
2286                         compress(param2data, os, version);
2287                 }
2288         }
2289         // All other versions (newest)
2290         else
2291         {
2292                 // First byte
2293                 u8 flags = 0;
2294                 if(is_underground)
2295                         flags |= 0x01;
2296                 if(m_day_night_differs)
2297                         flags |= 0x02;
2298                 if(m_lighting_expired)
2299                         flags |= 0x04;
2300                 os.write((char*)&flags, 1);
2301
2302                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
2303
2304                 /*
2305                         Get data
2306                 */
2307
2308                 SharedBuffer<u8> databuf(nodecount*3);
2309
2310                 // Get contents
2311                 for(u32 i=0; i<nodecount; i++)
2312                 {
2313                         databuf[i] = data[i].d;
2314                 }
2315
2316                 // Get params
2317                 for(u32 i=0; i<nodecount; i++)
2318                 {
2319                         databuf[i+nodecount] = data[i].param;
2320                 }
2321
2322                 // Get param2
2323                 for(u32 i=0; i<nodecount; i++)
2324                 {
2325                         databuf[i+nodecount*2] = data[i].param2;
2326                 }
2327
2328                 /*
2329                         Compress data to output stream
2330                 */
2331
2332                 compress(databuf, os, version);
2333                 
2334                 /*
2335                         NodeMetadata
2336                 */
2337                 if(version >= 14)
2338                 {
2339                         if(version <= 15)
2340                         {
2341                                 try{
2342                                         std::ostringstream oss(std::ios_base::binary);
2343                                         m_node_metadata.serialize(oss);
2344                                         os<<serializeString(oss.str());
2345                                 }
2346                                 // This will happen if the string is longer than 65535
2347                                 catch(SerializationError &e)
2348                                 {
2349                                         // Use an empty string
2350                                         os<<serializeString("");
2351                                 }
2352                         }
2353                         else
2354                         {
2355                                 std::ostringstream oss(std::ios_base::binary);
2356                                 m_node_metadata.serialize(oss);
2357                                 compressZlib(oss.str(), os);
2358                                 //os<<serializeLongString(oss.str());
2359                         }
2360                 }
2361         }
2362 }
2363
2364 void MapBlock::deSerialize(std::istream &is, u8 version)
2365 {
2366         if(!ser_ver_supported(version))
2367                 throw VersionMismatchException("ERROR: MapBlock format not supported");
2368
2369         // These have no lighting info
2370         if(version <= 1)
2371         {
2372                 setLightingExpired(true);
2373         }
2374
2375         // These have no compression
2376         if(version <= 3 || version == 5 || version == 6)
2377         {
2378                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
2379                 char tmp;
2380                 is.read(&tmp, 1);
2381                 if(is.gcount() != 1)
2382                         throw SerializationError
2383                                         ("MapBlock::deSerialize: no enough input data");
2384                 is_underground = tmp;
2385                 for(u32 i=0; i<nodecount; i++)
2386                 {
2387                         s32 len = MapNode::serializedLength(version);
2388                         SharedBuffer<u8> d(len);
2389                         is.read((char*)*d, len);
2390                         if(is.gcount() != len)
2391                                 throw SerializationError
2392                                                 ("MapBlock::deSerialize: no enough input data");
2393                         data[i].deSerialize(*d, version);
2394                 }
2395         }
2396         else if(version <= 10)
2397         {
2398                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
2399
2400                 u8 t8;
2401                 is.read((char*)&t8, 1);
2402                 is_underground = t8;
2403
2404                 {
2405                         // Uncompress and set material data
2406                         std::ostringstream os(std::ios_base::binary);
2407                         decompress(is, os, version);
2408                         std::string s = os.str();
2409                         if(s.size() != nodecount)
2410                                 throw SerializationError
2411                                                 ("MapBlock::deSerialize: invalid format");
2412                         for(u32 i=0; i<s.size(); i++)
2413                         {
2414                                 data[i].d = s[i];
2415                         }
2416                 }
2417                 {
2418                         // Uncompress and set param data
2419                         std::ostringstream os(std::ios_base::binary);
2420                         decompress(is, os, version);
2421                         std::string s = os.str();
2422                         if(s.size() != nodecount)
2423                                 throw SerializationError
2424                                                 ("MapBlock::deSerialize: invalid format");
2425                         for(u32 i=0; i<s.size(); i++)
2426                         {
2427                                 data[i].param = s[i];
2428                         }
2429                 }
2430         
2431                 if(version >= 10)
2432                 {
2433                         // Uncompress and set param2 data
2434                         std::ostringstream os(std::ios_base::binary);
2435                         decompress(is, os, version);
2436                         std::string s = os.str();
2437                         if(s.size() != nodecount)
2438                                 throw SerializationError
2439                                                 ("MapBlock::deSerialize: invalid format");
2440                         for(u32 i=0; i<s.size(); i++)
2441                         {
2442                                 data[i].param2 = s[i];
2443                         }
2444                 }
2445         }
2446         // All other versions (newest)
2447         else
2448         {
2449                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
2450
2451                 u8 flags;
2452                 is.read((char*)&flags, 1);
2453                 is_underground = (flags & 0x01) ? true : false;
2454                 m_day_night_differs = (flags & 0x02) ? true : false;
2455                 m_lighting_expired = (flags & 0x04) ? true : false;
2456
2457                 // Uncompress data
2458                 std::ostringstream os(std::ios_base::binary);
2459                 decompress(is, os, version);
2460                 std::string s = os.str();
2461                 if(s.size() != nodecount*3)
2462                         throw SerializationError
2463                                         ("MapBlock::deSerialize: invalid format");
2464
2465                 // Set contents
2466                 for(u32 i=0; i<nodecount; i++)
2467                 {
2468                         data[i].d = s[i];
2469                 }
2470                 // Set params
2471                 for(u32 i=0; i<nodecount; i++)
2472                 {
2473                         data[i].param = s[i+nodecount];
2474                 }
2475                 // Set param2
2476                 for(u32 i=0; i<nodecount; i++)
2477                 {
2478                         data[i].param2 = s[i+nodecount*2];
2479                 }
2480                 
2481                 /*
2482                         NodeMetadata
2483                 */
2484                 if(version >= 14)
2485                 {
2486                         // Ignore errors
2487                         try{
2488                                 if(version <= 15)
2489                                 {
2490                                         std::string data = deSerializeString(is);
2491                                         std::istringstream iss(data, std::ios_base::binary);
2492                                         m_node_metadata.deSerialize(iss);
2493                                 }
2494                                 else
2495                                 {
2496                                         //std::string data = deSerializeLongString(is);
2497                                         std::ostringstream oss(std::ios_base::binary);
2498                                         decompressZlib(is, oss);
2499                                         std::istringstream iss(oss.str(), std::ios_base::binary);
2500                                         m_node_metadata.deSerialize(iss);
2501                                 }
2502                         }
2503                         catch(SerializationError &e)
2504                         {
2505                                 dstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error"
2506                                                 <<" while deserializing node metadata"<<std::endl;
2507                         }
2508                 }
2509         }
2510         
2511         /*
2512                 Translate nodes as specified in the translate_to fields of
2513                 node features
2514
2515                 NOTE: This isn't really used. Should it be removed?
2516         */
2517         for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
2518         {
2519                 MapNode &n = data[i];
2520
2521                 MapNode *translate_to = content_features(n.d).translate_to;
2522                 if(translate_to)
2523                 {
2524                         dstream<<"MapBlock: WARNING: Translating node "<<n.d<<" to "
2525                                         <<translate_to->d<<std::endl;
2526                         n = *translate_to;
2527                 }
2528         }
2529 }
2530
2531 void MapBlock::serializeDiskExtra(std::ostream &os, u8 version)
2532 {
2533         // Versions up from 9 have block objects.
2534         if(version >= 9)
2535         {
2536                 serializeObjects(os, version);
2537         }
2538         
2539         // Versions up from 15 have static objects.
2540         if(version >= 15)
2541         {
2542                 m_static_objects.serialize(os);
2543         }
2544
2545         // Timestamp
2546         if(version >= 17)
2547         {
2548                 writeU32(os, getTimestamp());
2549         }
2550 }
2551
2552 void MapBlock::deSerializeDiskExtra(std::istream &is, u8 version)
2553 {
2554         /*
2555                 Versions up from 9 have block objects.
2556         */
2557         if(version >= 9)
2558         {
2559                 updateObjects(is, version, NULL, 0);
2560         }
2561
2562         /*
2563                 Versions up from 15 have static objects.
2564         */
2565         if(version >= 15)
2566         {
2567                 m_static_objects.deSerialize(is);
2568         }
2569                 
2570         // Timestamp
2571         if(version >= 17)
2572         {
2573                 setTimestamp(readU32(is));
2574         }
2575         else
2576         {
2577                 setTimestamp(BLOCK_TIMESTAMP_UNDEFINED);
2578         }
2579 }
2580
2581
2582 //END