4feeb9aef478bdb460e464d1d4f589fefb14cb8d
[oweals/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 // Create a cuboid.
733 //  material  - the material to use (for all 6 faces)
734 //  collector - the MeshCollector for the resulting polygons
735 //  pa        - texture atlas pointer for the material
736 //  c         - vertex colour - used for all
737 //  pos       - the position of the centre of the cuboid
738 //  rz,ry,rz  - the radius of the cuboid in each dimension
739 //  txc       - texture coordinates - this is a list of texture coordinates
740 //              for the opposite corners of each face - therefore, there
741 //              should be (2+2)*6=24 values in the list. Alternatively, pass
742 //              NULL to use the entire texture for each face. The order of
743 //              the faces in the list is top-backi-right-front-left-bottom
744 //              If you specified 0,0,1,1 for each face, that would be the
745 //              same as passing NULL.
746 void makeCuboid(video::SMaterial &material, MeshCollector *collector,
747         AtlasPointer* pa, video::SColor &c,
748         v3f &pos, f32 rx, f32 ry, f32 rz, f32* txc)
749 {
750         f32 tu0=pa->x0();
751         f32 tu1=pa->x1();
752         f32 tv0=pa->y0();
753         f32 tv1=pa->y1();
754         f32 txus=tu1-tu0;
755         f32 txvs=tv1-tv0;
756
757         video::S3DVertex v[4] =
758         {
759                 video::S3DVertex(0,0,0, 0,0,0, c, tu0, tv1),
760                 video::S3DVertex(0,0,0, 0,0,0, c, tu1, tv1),
761                 video::S3DVertex(0,0,0, 0,0,0, c, tu1, tv0),
762                 video::S3DVertex(0,0,0, 0,0,0, c, tu0, tv0)
763         };
764
765         for(int i=0;i<6;i++)
766         {
767                 switch(i)
768                 {
769                         case 0: // top
770                                 v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
771                                 v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
772                                 v[2].Pos.X= rx; v[2].Pos.Y= ry; v[2].Pos.Z= rz;
773                                 v[3].Pos.X= rx; v[3].Pos.Y= ry, v[3].Pos.Z=-rz;
774                                 break;
775                         case 1: // back
776                                 v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
777                                 v[1].Pos.X= rx; v[1].Pos.Y= ry; v[1].Pos.Z=-rz;
778                                 v[2].Pos.X= rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
779                                 v[3].Pos.X=-rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
780                                 break;
781                         case 2: //right
782                                 v[0].Pos.X= rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
783                                 v[1].Pos.X= rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
784                                 v[2].Pos.X= rx; v[2].Pos.Y=-ry; v[2].Pos.Z= rz;
785                                 v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
786                                 break;
787                         case 3: // front
788                                 v[0].Pos.X= rx; v[0].Pos.Y= ry; v[0].Pos.Z= rz;
789                                 v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
790                                 v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z= rz;
791                                 v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z= rz;
792                                 break;
793                         case 4: // left
794                                 v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z= rz;
795                                 v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z=-rz;
796                                 v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
797                                 v[3].Pos.X=-rx; v[3].Pos.Y=-ry, v[3].Pos.Z= rz;
798                                 break;
799                         case 5: // bottom
800                                 v[0].Pos.X= rx; v[0].Pos.Y=-ry; v[0].Pos.Z= rz;
801                                 v[1].Pos.X=-rx; v[1].Pos.Y=-ry; v[1].Pos.Z= rz;
802                                 v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
803                                 v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
804                                 break;
805                 }
806
807                 if(txc!=NULL)
808                 {
809                         v[0].TCoords.X=tu0+txus*txc[0]; v[0].TCoords.Y=tv0+txvs*txc[3];
810                         v[1].TCoords.X=tu0+txus*txc[2]; v[1].TCoords.Y=tv0+txvs*txc[3];
811                         v[2].TCoords.X=tu0+txus*txc[2]; v[2].TCoords.Y=tv0+txvs*txc[1];
812                         v[3].TCoords.X=tu0+txus*txc[0]; v[3].TCoords.Y=tv0+txvs*txc[1];
813                         txc+=4;
814                 }
815
816                 for(u16 i=0; i<4; i++)
817                         v[i].Pos += pos;
818                 u16 indices[] = {0,1,2,2,3,0};
819                 collector->append(material, v, 4, indices, 6);
820
821         }
822
823 }
824
825 scene::SMesh* makeMapBlockMesh(MeshMakeData *data)
826 {
827         // 4-21ms for MAP_BLOCKSIZE=16
828         // 24-155ms for MAP_BLOCKSIZE=32
829         //TimeTaker timer1("makeMapBlockMesh()");
830
831         core::array<FastFace> fastfaces_new;
832
833         v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE;
834         
835         // floating point conversion
836         v3f posRelative_f(blockpos_nodes.X, blockpos_nodes.Y, blockpos_nodes.Z);
837         
838         /*
839                 Some settings
840         */
841         bool new_style_water = g_settings.getBool("new_style_water");
842         bool new_style_leaves = g_settings.getBool("new_style_leaves");
843         bool smooth_lighting = g_settings.getBool("smooth_lighting");
844         
845         float node_water_level = 1.0;
846         if(new_style_water)
847                 node_water_level = 0.85;
848         
849         /*
850                 We are including the faces of the trailing edges of the block.
851                 This means that when something changes, the caller must
852                 also update the meshes of the blocks at the leading edges.
853
854                 NOTE: This is the slowest part of this method.
855         */
856         
857         {
858                 // 4-23ms for MAP_BLOCKSIZE=16
859                 //TimeTaker timer2("updateMesh() collect");
860
861                 /*
862                         Go through every y,z and get top(y+) faces in rows of x+
863                 */
864                 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
865                         for(s16 z=0; z<MAP_BLOCKSIZE; z++){
866                                 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
867                                                 v3s16(0,y,z), MAP_BLOCKSIZE,
868                                                 v3s16(1,0,0), //dir
869                                                 v3f  (1,0,0),
870                                                 v3s16(0,1,0), //face dir
871                                                 v3f  (0,1,0),
872                                                 fastfaces_new,
873                                                 data->m_temp_mods,
874                                                 data->m_vmanip,
875                                                 blockpos_nodes,
876                                                 smooth_lighting);
877                         }
878                 }
879                 /*
880                         Go through every x,y and get right(x+) faces in rows of z+
881                 */
882                 for(s16 x=0; x<MAP_BLOCKSIZE; x++){
883                         for(s16 y=0; y<MAP_BLOCKSIZE; y++){
884                                 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
885                                                 v3s16(x,y,0), MAP_BLOCKSIZE,
886                                                 v3s16(0,0,1),
887                                                 v3f  (0,0,1),
888                                                 v3s16(1,0,0),
889                                                 v3f  (1,0,0),
890                                                 fastfaces_new,
891                                                 data->m_temp_mods,
892                                                 data->m_vmanip,
893                                                 blockpos_nodes,
894                                                 smooth_lighting);
895                         }
896                 }
897                 /*
898                         Go through every y,z and get back(z+) faces in rows of x+
899                 */
900                 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
901                         for(s16 y=0; y<MAP_BLOCKSIZE; y++){
902                                 updateFastFaceRow(data->m_daynight_ratio, posRelative_f,
903                                                 v3s16(0,y,z), MAP_BLOCKSIZE,
904                                                 v3s16(1,0,0),
905                                                 v3f  (1,0,0),
906                                                 v3s16(0,0,1),
907                                                 v3f  (0,0,1),
908                                                 fastfaces_new,
909                                                 data->m_temp_mods,
910                                                 data->m_vmanip,
911                                                 blockpos_nodes,
912                                                 smooth_lighting);
913                         }
914                 }
915         }
916
917         // End of slow part
918
919         /*
920                 Convert FastFaces to SMesh
921         */
922
923         MeshCollector collector;
924
925         if(fastfaces_new.size() > 0)
926         {
927                 // avg 0ms (100ms spikes when loading textures the first time)
928                 //TimeTaker timer2("updateMesh() mesh building");
929
930                 video::SMaterial material;
931                 material.setFlag(video::EMF_LIGHTING, false);
932                 material.setFlag(video::EMF_BILINEAR_FILTER, false);
933                 material.setFlag(video::EMF_FOG_ENABLE, true);
934                 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
935                 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE);
936
937                 for(u32 i=0; i<fastfaces_new.size(); i++)
938                 {
939                         FastFace &f = fastfaces_new[i];
940
941                         const u16 indices[] = {0,1,2,2,3,0};
942                         const u16 indices_alternate[] = {0,1,3,2,3,1};
943                         
944                         video::ITexture *texture = f.tile.texture.atlas;
945                         if(texture == NULL)
946                                 continue;
947
948                         material.setTexture(0, texture);
949                         
950                         f.tile.applyMaterialOptions(material);
951
952                         const u16 *indices_p = indices;
953                         
954                         /*
955                                 Revert triangles for nicer looking gradient if vertices
956                                 1 and 3 have same color or 0 and 2 have different color.
957                         */
958                         if(f.vertices[0].Color != f.vertices[2].Color
959                                         || f.vertices[1].Color == f.vertices[3].Color)
960                                 indices_p = indices_alternate;
961                         
962                         collector.append(material, f.vertices, 4, indices_p, 6);
963                 }
964         }
965
966         /*
967                 Add special graphics:
968                 - torches
969                 - flowing water
970         */
971
972         // 0ms
973         //TimeTaker timer2("updateMesh() adding special stuff");
974
975         // Flowing water material
976         video::SMaterial material_water1;
977         material_water1.setFlag(video::EMF_LIGHTING, false);
978         material_water1.setFlag(video::EMF_BACK_FACE_CULLING, false);
979         material_water1.setFlag(video::EMF_BILINEAR_FILTER, false);
980         material_water1.setFlag(video::EMF_FOG_ENABLE, true);
981         material_water1.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
982         AtlasPointer pa_water1 = g_texturesource->getTexture(
983                         g_texturesource->getTextureId("water.png"));
984         material_water1.setTexture(0, pa_water1.atlas);
985
986         // New-style leaves material
987         video::SMaterial material_leaves1;
988         material_leaves1.setFlag(video::EMF_LIGHTING, false);
989         //material_leaves1.setFlag(video::EMF_BACK_FACE_CULLING, false);
990         material_leaves1.setFlag(video::EMF_BILINEAR_FILTER, false);
991         material_leaves1.setFlag(video::EMF_FOG_ENABLE, true);
992         material_leaves1.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
993         AtlasPointer pa_leaves1 = g_texturesource->getTexture(
994                         g_texturesource->getTextureId("leaves.png"));
995         material_leaves1.setTexture(0, pa_leaves1.atlas);
996
997         // Glass material
998         video::SMaterial material_glass;
999         material_glass.setFlag(video::EMF_LIGHTING, false);
1000         material_glass.setFlag(video::EMF_BILINEAR_FILTER, false);
1001         material_glass.setFlag(video::EMF_FOG_ENABLE, true);
1002         material_glass.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
1003         AtlasPointer pa_glass = g_texturesource->getTexture(
1004                         g_texturesource->getTextureId("glass.png"));
1005         material_glass.setTexture(0, pa_glass.atlas);
1006
1007         // Wood material
1008         video::SMaterial material_wood;
1009         material_wood.setFlag(video::EMF_LIGHTING, false);
1010         material_wood.setFlag(video::EMF_BILINEAR_FILTER, false);
1011         material_wood.setFlag(video::EMF_FOG_ENABLE, true);
1012         material_wood.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
1013         AtlasPointer pa_wood = g_texturesource->getTexture(
1014                         g_texturesource->getTextureId("wood.png"));
1015         material_wood.setTexture(0, pa_wood.atlas);
1016
1017         for(s16 z=0; z<MAP_BLOCKSIZE; z++)
1018         for(s16 y=0; y<MAP_BLOCKSIZE; y++)
1019         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
1020         {
1021                 v3s16 p(x,y,z);
1022
1023                 MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes+p);
1024                 
1025                 /*
1026                         Add torches to mesh
1027                 */
1028                 if(n.d == CONTENT_TORCH)
1029                 {
1030                         video::SColor c(255,255,255,255);
1031
1032                         // Wall at X+ of node
1033                         video::S3DVertex vertices[4] =
1034                         {
1035                                 video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 0,1),
1036                                 video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, 1,1),
1037                                 video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
1038                                 video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
1039                         };
1040
1041                         v3s16 dir = unpackDir(n.dir);
1042
1043                         for(s32 i=0; i<4; i++)
1044                         {
1045                                 if(dir == v3s16(1,0,0))
1046                                         vertices[i].Pos.rotateXZBy(0);
1047                                 if(dir == v3s16(-1,0,0))
1048                                         vertices[i].Pos.rotateXZBy(180);
1049                                 if(dir == v3s16(0,0,1))
1050                                         vertices[i].Pos.rotateXZBy(90);
1051                                 if(dir == v3s16(0,0,-1))
1052                                         vertices[i].Pos.rotateXZBy(-90);
1053                                 if(dir == v3s16(0,-1,0))
1054                                         vertices[i].Pos.rotateXZBy(45);
1055                                 if(dir == v3s16(0,1,0))
1056                                         vertices[i].Pos.rotateXZBy(-45);
1057
1058                                 vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
1059                         }
1060
1061                         // Set material
1062                         video::SMaterial material;
1063                         material.setFlag(video::EMF_LIGHTING, false);
1064                         material.setFlag(video::EMF_BACK_FACE_CULLING, false);
1065                         material.setFlag(video::EMF_BILINEAR_FILTER, false);
1066                         //material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
1067                         material.MaterialType
1068                                         = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
1069
1070                         if(dir == v3s16(0,-1,0))
1071                                 material.setTexture(0,
1072                                                 g_texturesource->getTextureRaw("torch_on_floor.png"));
1073                         else if(dir == v3s16(0,1,0))
1074                                 material.setTexture(0,
1075                                                 g_texturesource->getTextureRaw("torch_on_ceiling.png"));
1076                         // For backwards compatibility
1077                         else if(dir == v3s16(0,0,0))
1078                                 material.setTexture(0,
1079                                                 g_texturesource->getTextureRaw("torch_on_floor.png"));
1080                         else
1081                                 material.setTexture(0, 
1082                                                 g_texturesource->getTextureRaw("torch.png"));
1083
1084                         u16 indices[] = {0,1,2,2,3,0};
1085                         // Add to mesh collector
1086                         collector.append(material, vertices, 4, indices, 6);
1087                 }
1088                 /*
1089                         Signs on walls
1090                 */
1091                 if(n.d == CONTENT_SIGN_WALL)
1092                 {
1093                         u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
1094                         video::SColor c(255,l,l,l);
1095                                 
1096                         float d = (float)BS/16;
1097                         // Wall at X+ of node
1098                         video::S3DVertex vertices[4] =
1099                         {
1100                                 video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c, 0,1),
1101                                 video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c, 1,1),
1102                                 video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c, 1,0),
1103                                 video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c, 0,0),
1104                         };
1105
1106                         v3s16 dir = unpackDir(n.dir);
1107
1108                         for(s32 i=0; i<4; i++)
1109                         {
1110                                 if(dir == v3s16(1,0,0))
1111                                         vertices[i].Pos.rotateXZBy(0);
1112                                 if(dir == v3s16(-1,0,0))
1113                                         vertices[i].Pos.rotateXZBy(180);
1114                                 if(dir == v3s16(0,0,1))
1115                                         vertices[i].Pos.rotateXZBy(90);
1116                                 if(dir == v3s16(0,0,-1))
1117                                         vertices[i].Pos.rotateXZBy(-90);
1118                                 if(dir == v3s16(0,-1,0))
1119                                         vertices[i].Pos.rotateXYBy(-90);
1120                                 if(dir == v3s16(0,1,0))
1121                                         vertices[i].Pos.rotateXYBy(90);
1122
1123                                 vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
1124                         }
1125
1126                         // Set material
1127                         video::SMaterial material;
1128                         material.setFlag(video::EMF_LIGHTING, false);
1129                         material.setFlag(video::EMF_BACK_FACE_CULLING, false);
1130                         material.setFlag(video::EMF_BILINEAR_FILTER, false);
1131                         material.setFlag(video::EMF_FOG_ENABLE, true);
1132                         //material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
1133                         material.MaterialType
1134                                         = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
1135
1136                         material.setTexture(0, 
1137                                         g_texturesource->getTextureRaw("sign_wall.png"));
1138
1139                         u16 indices[] = {0,1,2,2,3,0};
1140                         // Add to mesh collector
1141                         collector.append(material, vertices, 4, indices, 6);
1142                 }
1143                 /*
1144                         Add flowing water to mesh
1145                 */
1146                 else if(n.d == CONTENT_WATER)
1147                 {
1148                         bool top_is_water = false;
1149                         MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
1150                         if(ntop.d == CONTENT_WATER || ntop.d == CONTENT_WATERSOURCE)
1151                                 top_is_water = true;
1152                         
1153                         u8 l = 0;
1154                         // Use the light of the node on top if possible
1155                         if(content_features(ntop.d).param_type == CPT_LIGHT)
1156                                 l = decode_light(ntop.getLightBlend(data->m_daynight_ratio));
1157                         // Otherwise use the light of this node (the water)
1158                         else
1159                                 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
1160                         video::SColor c(WATER_ALPHA,l,l,l);
1161                         
1162                         // Neighbor water levels (key = relative position)
1163                         // Includes current node
1164                         core::map<v3s16, f32> neighbor_levels;
1165                         core::map<v3s16, u8> neighbor_contents;
1166                         core::map<v3s16, u8> neighbor_flags;
1167                         const u8 neighborflag_top_is_water = 0x01;
1168                         v3s16 neighbor_dirs[9] = {
1169                                 v3s16(0,0,0),
1170                                 v3s16(0,0,1),
1171                                 v3s16(0,0,-1),
1172                                 v3s16(1,0,0),
1173                                 v3s16(-1,0,0),
1174                                 v3s16(1,0,1),
1175                                 v3s16(-1,0,-1),
1176                                 v3s16(1,0,-1),
1177                                 v3s16(-1,0,1),
1178                         };
1179                         for(u32 i=0; i<9; i++)
1180                         {
1181                                 u8 content = CONTENT_AIR;
1182                                 float level = -0.5 * BS;
1183                                 u8 flags = 0;
1184                                 // Check neighbor
1185                                 v3s16 p2 = p + neighbor_dirs[i];
1186                                 MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
1187                                 if(n2.d != CONTENT_IGNORE)
1188                                 {
1189                                         content = n2.d;
1190
1191                                         if(n2.d == CONTENT_WATERSOURCE)
1192                                                 level = (-0.5+node_water_level) * BS;
1193                                         else if(n2.d == CONTENT_WATER)
1194                                                 level = (-0.5 + ((float)n2.param2 + 0.5) / 8.0
1195                                                                 * node_water_level) * BS;
1196
1197                                         // Check node above neighbor.
1198                                         // NOTE: This doesn't get executed if neighbor
1199                                         //       doesn't exist
1200                                         p2.Y += 1;
1201                                         n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
1202                                         if(n2.d == CONTENT_WATERSOURCE || n2.d == CONTENT_WATER)
1203                                                 flags |= neighborflag_top_is_water;
1204                                 }
1205                                 
1206                                 neighbor_levels.insert(neighbor_dirs[i], level);
1207                                 neighbor_contents.insert(neighbor_dirs[i], content);
1208                                 neighbor_flags.insert(neighbor_dirs[i], flags);
1209                         }
1210
1211                         //float water_level = (-0.5 + ((float)n.param2 + 0.5) / 8.0) * BS;
1212                         //float water_level = neighbor_levels[v3s16(0,0,0)];
1213
1214                         // Corner heights (average between four waters)
1215                         f32 corner_levels[4];
1216                         
1217                         v3s16 halfdirs[4] = {
1218                                 v3s16(0,0,0),
1219                                 v3s16(1,0,0),
1220                                 v3s16(1,0,1),
1221                                 v3s16(0,0,1),
1222                         };
1223                         for(u32 i=0; i<4; i++)
1224                         {
1225                                 v3s16 cornerdir = halfdirs[i];
1226                                 float cornerlevel = 0;
1227                                 u32 valid_count = 0;
1228                                 for(u32 j=0; j<4; j++)
1229                                 {
1230                                         v3s16 neighbordir = cornerdir - halfdirs[j];
1231                                         u8 content = neighbor_contents[neighbordir];
1232                                         // Special case for source nodes
1233                                         if(content == CONTENT_WATERSOURCE)
1234                                         {
1235                                                 cornerlevel = (-0.5+node_water_level)*BS;
1236                                                 valid_count = 1;
1237                                                 break;
1238                                         }
1239                                         else if(content == CONTENT_WATER)
1240                                         {
1241                                                 cornerlevel += neighbor_levels[neighbordir];
1242                                                 valid_count++;
1243                                         }
1244                                         else if(content == CONTENT_AIR)
1245                                         {
1246                                                 cornerlevel += -0.5*BS;
1247                                                 valid_count++;
1248                                         }
1249                                 }
1250                                 if(valid_count > 0)
1251                                         cornerlevel /= valid_count;
1252                                 corner_levels[i] = cornerlevel;
1253                         }
1254
1255                         /*
1256                                 Generate sides
1257                         */
1258
1259                         v3s16 side_dirs[4] = {
1260                                 v3s16(1,0,0),
1261                                 v3s16(-1,0,0),
1262                                 v3s16(0,0,1),
1263                                 v3s16(0,0,-1),
1264                         };
1265                         s16 side_corners[4][2] = {
1266                                 {1, 2},
1267                                 {3, 0},
1268                                 {2, 3},
1269                                 {0, 1},
1270                         };
1271                         for(u32 i=0; i<4; i++)
1272                         {
1273                                 v3s16 dir = side_dirs[i];
1274
1275                                 /*
1276                                         If our topside is water and neighbor's topside
1277                                         is water, don't draw side face
1278                                 */
1279                                 if(top_is_water &&
1280                                                 neighbor_flags[dir] & neighborflag_top_is_water)
1281                                         continue;
1282
1283                                 u8 neighbor_content = neighbor_contents[dir];
1284                                 
1285                                 // Don't draw face if neighbor is not air or water
1286                                 if(neighbor_content != CONTENT_AIR
1287                                                 && neighbor_content != CONTENT_WATER)
1288                                         continue;
1289                                 
1290                                 bool neighbor_is_water = (neighbor_content == CONTENT_WATER);
1291                                 
1292                                 // Don't draw any faces if neighbor is water and top is water
1293                                 if(neighbor_is_water == true && top_is_water == false)
1294                                         continue;
1295                                 
1296                                 video::S3DVertex vertices[4] =
1297                                 {
1298                                         /*video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
1299                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,1),
1300                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
1301                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
1302                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
1303                                                         pa_water1.x0(), pa_water1.y1()),
1304                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
1305                                                         pa_water1.x1(), pa_water1.y1()),
1306                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
1307                                                         pa_water1.x1(), pa_water1.y0()),
1308                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
1309                                                         pa_water1.x0(), pa_water1.y0()),
1310                                 };
1311                                 
1312                                 /*
1313                                         If our topside is water, set upper border of face
1314                                         at upper border of node
1315                                 */
1316                                 if(top_is_water)
1317                                 {
1318                                         vertices[2].Pos.Y = 0.5*BS;
1319                                         vertices[3].Pos.Y = 0.5*BS;
1320                                 }
1321                                 /*
1322                                         Otherwise upper position of face is corner levels
1323                                 */
1324                                 else
1325                                 {
1326                                         vertices[2].Pos.Y = corner_levels[side_corners[i][0]];
1327                                         vertices[3].Pos.Y = corner_levels[side_corners[i][1]];
1328                                 }
1329                                 
1330                                 /*
1331                                         If neighbor is water, lower border of face is corner
1332                                         water levels
1333                                 */
1334                                 if(neighbor_is_water)
1335                                 {
1336                                         vertices[0].Pos.Y = corner_levels[side_corners[i][1]];
1337                                         vertices[1].Pos.Y = corner_levels[side_corners[i][0]];
1338                                 }
1339                                 /*
1340                                         If neighbor is not water, lower border of face is
1341                                         lower border of node
1342                                 */
1343                                 else
1344                                 {
1345                                         vertices[0].Pos.Y = -0.5*BS;
1346                                         vertices[1].Pos.Y = -0.5*BS;
1347                                 }
1348                                 
1349                                 for(s32 j=0; j<4; j++)
1350                                 {
1351                                         if(dir == v3s16(0,0,1))
1352                                                 vertices[j].Pos.rotateXZBy(0);
1353                                         if(dir == v3s16(0,0,-1))
1354                                                 vertices[j].Pos.rotateXZBy(180);
1355                                         if(dir == v3s16(-1,0,0))
1356                                                 vertices[j].Pos.rotateXZBy(90);
1357                                         if(dir == v3s16(1,0,-0))
1358                                                 vertices[j].Pos.rotateXZBy(-90);
1359
1360                                         vertices[j].Pos += intToFloat(p + blockpos_nodes, BS);
1361                                 }
1362
1363                                 u16 indices[] = {0,1,2,2,3,0};
1364                                 // Add to mesh collector
1365                                 collector.append(material_water1, vertices, 4, indices, 6);
1366                         }
1367                         
1368                         /*
1369                                 Generate top side, if appropriate
1370                         */
1371                         
1372                         if(top_is_water == false)
1373                         {
1374                                 video::S3DVertex vertices[4] =
1375                                 {
1376                                         /*video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
1377                                         video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1),
1378                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
1379                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
1380                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
1381                                                         pa_water1.x0(), pa_water1.y1()),
1382                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
1383                                                         pa_water1.x1(), pa_water1.y1()),
1384                                         video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
1385                                                         pa_water1.x1(), pa_water1.y0()),
1386                                         video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
1387                                                         pa_water1.x0(), pa_water1.y0()),
1388                                 };
1389                                 
1390                                 // This fixes a strange bug
1391                                 s32 corner_resolve[4] = {3,2,1,0};
1392
1393                                 for(s32 i=0; i<4; i++)
1394                                 {
1395                                         //vertices[i].Pos.Y += water_level;
1396                                         //vertices[i].Pos.Y += neighbor_levels[v3s16(0,0,0)];
1397                                         s32 j = corner_resolve[i];
1398                                         vertices[i].Pos.Y += corner_levels[j];
1399                                         vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
1400                                 }
1401
1402                                 u16 indices[] = {0,1,2,2,3,0};
1403                                 // Add to mesh collector
1404                                 collector.append(material_water1, vertices, 4, indices, 6);
1405                         }
1406                 }
1407                 /*
1408                         Add water sources to mesh if using new style
1409                 */
1410                 else if(n.d == CONTENT_WATERSOURCE && new_style_water)
1411                 {
1412                         //bool top_is_water = false;
1413                         bool top_is_air = false;
1414                         MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
1415                         /*if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE)
1416                                 top_is_water = true;*/
1417                         if(n.d == CONTENT_AIR)
1418                                 top_is_air = true;
1419                         
1420                         /*if(top_is_water == true)
1421                                 continue;*/
1422                         if(top_is_air == false)
1423                                 continue;
1424
1425                         u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
1426                         video::SColor c(WATER_ALPHA,l,l,l);
1427                         
1428                         video::S3DVertex vertices[4] =
1429                         {
1430                                 /*video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
1431                                 video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1),
1432                                 video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
1433                                 video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
1434                                 video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
1435                                                 pa_water1.x0(), pa_water1.y1()),
1436                                 video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
1437                                                 pa_water1.x1(), pa_water1.y1()),
1438                                 video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
1439                                                 pa_water1.x1(), pa_water1.y0()),
1440                                 video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
1441                                                 pa_water1.x0(), pa_water1.y0()),
1442                         };
1443
1444                         for(s32 i=0; i<4; i++)
1445                         {
1446                                 vertices[i].Pos.Y += (-0.5+node_water_level)*BS;
1447                                 vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
1448                         }
1449
1450                         u16 indices[] = {0,1,2,2,3,0};
1451                         // Add to mesh collector
1452                         collector.append(material_water1, vertices, 4, indices, 6);
1453                 }
1454                 /*
1455                         Add leaves if using new style
1456                 */
1457                 else if(n.d == CONTENT_LEAVES && new_style_leaves)
1458                 {
1459                         /*u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));*/
1460                         u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
1461                         video::SColor c(255,l,l,l);
1462
1463                         for(u32 j=0; j<6; j++)
1464                         {
1465                                 video::S3DVertex vertices[4] =
1466                                 {
1467                                         /*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
1468                                         video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1),
1469                                         video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0),
1470                                         video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),*/
1471                                         video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
1472                                                 pa_leaves1.x0(), pa_leaves1.y1()),
1473                                         video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
1474                                                 pa_leaves1.x1(), pa_leaves1.y1()),
1475                                         video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
1476                                                 pa_leaves1.x1(), pa_leaves1.y0()),
1477                                         video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
1478                                                 pa_leaves1.x0(), pa_leaves1.y0()),
1479                                 };
1480
1481                                 if(j == 0)
1482                                 {
1483                                         for(u16 i=0; i<4; i++)
1484                                                 vertices[i].Pos.rotateXZBy(0);
1485                                 }
1486                                 else if(j == 1)
1487                                 {
1488                                         for(u16 i=0; i<4; i++)
1489                                                 vertices[i].Pos.rotateXZBy(180);
1490                                 }
1491                                 else if(j == 2)
1492                                 {
1493                                         for(u16 i=0; i<4; i++)
1494                                                 vertices[i].Pos.rotateXZBy(-90);
1495                                 }
1496                                 else if(j == 3)
1497                                 {
1498                                         for(u16 i=0; i<4; i++)
1499                                                 vertices[i].Pos.rotateXZBy(90);
1500                                 }
1501                                 else if(j == 4)
1502                                 {
1503                                         for(u16 i=0; i<4; i++)
1504                                                 vertices[i].Pos.rotateYZBy(-90);
1505                                 }
1506                                 else if(j == 5)
1507                                 {
1508                                         for(u16 i=0; i<4; i++)
1509                                                 vertices[i].Pos.rotateYZBy(90);
1510                                 }
1511
1512                                 for(u16 i=0; i<4; i++)
1513                                 {
1514                                         vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
1515                                 }
1516
1517                                 u16 indices[] = {0,1,2,2,3,0};
1518                                 // Add to mesh collector
1519                                 collector.append(material_leaves1, vertices, 4, indices, 6);
1520                         }
1521                 }
1522                 /*
1523                         Add glass
1524                 */
1525                 else if(n.d == CONTENT_GLASS)
1526                 {
1527                         u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
1528                         video::SColor c(255,l,l,l);
1529
1530                         for(u32 j=0; j<6; j++)
1531                         {
1532                                 video::S3DVertex vertices[4] =
1533                                 {
1534                                         video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
1535                                                 pa_glass.x0(), pa_glass.y1()),
1536                                         video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
1537                                                 pa_glass.x1(), pa_glass.y1()),
1538                                         video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
1539                                                 pa_glass.x1(), pa_glass.y0()),
1540                                         video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
1541                                                 pa_glass.x0(), pa_glass.y0()),
1542                                 };
1543
1544                                 if(j == 0)
1545                                 {
1546                                         for(u16 i=0; i<4; i++)
1547                                                 vertices[i].Pos.rotateXZBy(0);
1548                                 }
1549                                 else if(j == 1)
1550                                 {
1551                                         for(u16 i=0; i<4; i++)
1552                                                 vertices[i].Pos.rotateXZBy(180);
1553                                 }
1554                                 else if(j == 2)
1555                                 {
1556                                         for(u16 i=0; i<4; i++)
1557                                                 vertices[i].Pos.rotateXZBy(-90);
1558                                 }
1559                                 else if(j == 3)
1560                                 {
1561                                         for(u16 i=0; i<4; i++)
1562                                                 vertices[i].Pos.rotateXZBy(90);
1563                                 }
1564                                 else if(j == 4)
1565                                 {
1566                                         for(u16 i=0; i<4; i++)
1567                                                 vertices[i].Pos.rotateYZBy(-90);
1568                                 }
1569                                 else if(j == 5)
1570                                 {
1571                                         for(u16 i=0; i<4; i++)
1572                                                 vertices[i].Pos.rotateYZBy(90);
1573                                 }
1574
1575                                 for(u16 i=0; i<4; i++)
1576                                 {
1577                                         vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
1578                                 }
1579
1580                                 u16 indices[] = {0,1,2,2,3,0};
1581                                 // Add to mesh collector
1582                                 collector.append(material_glass, vertices, 4, indices, 6);
1583                         }
1584                 }
1585                 /*
1586                         Add fence
1587                 */
1588                 else if(n.d == CONTENT_FENCE)
1589                 {
1590                         u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
1591                         video::SColor c(255,l,l,l);
1592
1593                         const f32 post_rad=(f32)BS/10;
1594                         const f32 bar_rad=(f32)BS/20;
1595                         const f32 bar_len=(f32)(BS/2)-post_rad;
1596
1597                         // The post - always present
1598                         v3f pos = intToFloat(p+blockpos_nodes, BS);
1599                         f32 postuv[24]={
1600                                         0,0,1,1,
1601                                         0,0,1,1,
1602                                         0,0,1,1,
1603                                         0,0,1,1,
1604                                         0,0,1,1,
1605                                         0,0,1,1};
1606                         makeCuboid(material_wood, &collector,
1607                                 &pa_wood, c, pos,
1608                                 post_rad,BS/2,post_rad, postuv);
1609
1610                         // Now a section of fence, +X, if there's a post there
1611                         v3s16 p2 = p;
1612                         p2.X++;
1613                         MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
1614                         if(n2.d == CONTENT_FENCE)
1615                         {
1616                                 pos = intToFloat(p+blockpos_nodes, BS);
1617                                 pos.X += BS/2;
1618                                 pos.Y += BS/4;
1619                                 makeCuboid(material_wood, &collector,
1620                                         &pa_wood, c, pos,
1621                                         bar_len,bar_rad,bar_rad, NULL);
1622
1623                                 pos.Y -= BS/2;
1624                                 makeCuboid(material_wood, &collector,
1625                                         &pa_wood, c, pos,
1626                                         bar_len,bar_rad,bar_rad, NULL);
1627                         }
1628
1629                         // Now a section of fence, +Z, if there's a post there
1630                         p2 = p;
1631                         p2.Z++;
1632                         n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
1633                         if(n2.d == CONTENT_FENCE)
1634                         {
1635                                 pos = intToFloat(p+blockpos_nodes, BS);
1636                                 pos.Z += BS/2;
1637                                 pos.Y += BS/4;
1638                                 makeCuboid(material_wood, &collector,
1639                                         &pa_wood, c, pos,
1640                                         bar_rad,bar_rad,bar_len, NULL);
1641                                 pos.Y -= BS/2;
1642                                 makeCuboid(material_wood, &collector,
1643                                         &pa_wood, c, pos,
1644                                         bar_rad,bar_rad,bar_len, NULL);
1645
1646                         }
1647
1648                 }
1649
1650
1651
1652         }
1653
1654         /*
1655                 Add stuff from collector to mesh
1656         */
1657         
1658         scene::SMesh *mesh_new = NULL;
1659         mesh_new = new scene::SMesh();
1660         
1661         collector.fillMesh(mesh_new);
1662
1663         /*
1664                 Do some stuff to the mesh
1665         */
1666
1667         mesh_new->recalculateBoundingBox();
1668
1669         /*
1670                 Delete new mesh if it is empty
1671         */
1672
1673         if(mesh_new->getMeshBufferCount() == 0)
1674         {
1675                 mesh_new->drop();
1676                 mesh_new = NULL;
1677         }
1678
1679         if(mesh_new)
1680         {
1681 #if 0
1682                 // Usually 1-700 faces and 1-7 materials
1683                 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
1684                                 <<"and uses "<<mesh_new->getMeshBufferCount()
1685                                 <<" materials (meshbuffers)"<<std::endl;
1686 #endif
1687
1688                 // Use VBO for mesh (this just would set this for ever buffer)
1689                 // This will lead to infinite memory usage because or irrlicht.
1690                 //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
1691
1692                 /*
1693                         NOTE: If that is enabled, some kind of a queue to the main
1694                         thread should be made which would call irrlicht to delete
1695                         the hardware buffer and then delete the mesh
1696                 */
1697         }
1698
1699         return mesh_new;
1700         
1701         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1702 }
1703
1704 #endif // !SERVER
1705
1706 /*
1707         MapBlock
1708 */
1709
1710 MapBlock::MapBlock(NodeContainer *parent, v3s16 pos, bool dummy):
1711                 m_parent(parent),
1712                 m_pos(pos),
1713                 changed(true),
1714                 is_underground(false),
1715                 m_lighting_expired(true),
1716                 m_day_night_differs(false),
1717                 //m_not_fully_generated(false),
1718                 m_objects(this),
1719                 m_timestamp(BLOCK_TIMESTAMP_UNDEFINED)
1720 {
1721         data = NULL;
1722         if(dummy == false)
1723                 reallocate();
1724         
1725         //m_spawn_timer = -10000;
1726
1727 #ifndef SERVER
1728         m_mesh_expired = false;
1729         mesh_mutex.Init();
1730         mesh = NULL;
1731         m_temp_mods_mutex.Init();
1732 #endif
1733 }
1734
1735 MapBlock::~MapBlock()
1736 {
1737 #ifndef SERVER
1738         {
1739                 JMutexAutoLock lock(mesh_mutex);
1740                 
1741                 if(mesh)
1742                 {
1743                         mesh->drop();
1744                         mesh = NULL;
1745                 }
1746         }
1747 #endif
1748
1749         if(data)
1750                 delete[] data;
1751 }
1752
1753 bool MapBlock::isValidPositionParent(v3s16 p)
1754 {
1755         if(isValidPosition(p))
1756         {
1757                 return true;
1758         }
1759         else{
1760                 return m_parent->isValidPosition(getPosRelative() + p);
1761         }
1762 }
1763
1764 MapNode MapBlock::getNodeParent(v3s16 p)
1765 {
1766         if(isValidPosition(p) == false)
1767         {
1768                 return m_parent->getNode(getPosRelative() + p);
1769         }
1770         else
1771         {
1772                 if(data == NULL)
1773                         throw InvalidPositionException();
1774                 return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X];
1775         }
1776 }
1777
1778 void MapBlock::setNodeParent(v3s16 p, MapNode & n)
1779 {
1780         if(isValidPosition(p) == false)
1781         {
1782                 m_parent->setNode(getPosRelative() + p, n);
1783         }
1784         else
1785         {
1786                 if(data == NULL)
1787                         throw InvalidPositionException();
1788                 data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X] = n;
1789         }
1790 }
1791
1792 MapNode MapBlock::getNodeParentNoEx(v3s16 p)
1793 {
1794         if(isValidPosition(p) == false)
1795         {
1796                 try{
1797                         return m_parent->getNode(getPosRelative() + p);
1798                 }
1799                 catch(InvalidPositionException &e)
1800                 {
1801                         return MapNode(CONTENT_IGNORE);
1802                 }
1803         }
1804         else
1805         {
1806                 if(data == NULL)
1807                 {
1808                         return MapNode(CONTENT_IGNORE);
1809                 }
1810                 return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X];
1811         }
1812 }
1813
1814 #ifndef SERVER
1815
1816 #if 1
1817 void MapBlock::updateMesh(u32 daynight_ratio)
1818 {
1819 #if 0
1820         /*
1821                 DEBUG: If mesh has been generated, don't generate it again
1822         */
1823         {
1824                 JMutexAutoLock meshlock(mesh_mutex);
1825                 if(mesh != NULL)
1826                         return;
1827         }
1828 #endif
1829
1830         MeshMakeData data;
1831         data.fill(daynight_ratio, this);
1832         
1833         scene::SMesh *mesh_new = makeMapBlockMesh(&data);
1834         
1835         /*
1836                 Replace the mesh
1837         */
1838
1839         replaceMesh(mesh_new);
1840
1841 }
1842 #endif
1843
1844 void MapBlock::replaceMesh(scene::SMesh *mesh_new)
1845 {
1846         mesh_mutex.Lock();
1847
1848         //scene::SMesh *mesh_old = mesh[daynight_i];
1849         //mesh[daynight_i] = mesh_new;
1850
1851         scene::SMesh *mesh_old = mesh;
1852         mesh = mesh_new;
1853         setMeshExpired(false);
1854         
1855         if(mesh_old != NULL)
1856         {
1857                 // Remove hardware buffers of meshbuffers of mesh
1858                 // NOTE: No way, this runs in a different thread and everything
1859                 /*u32 c = mesh_old->getMeshBufferCount();
1860                 for(u32 i=0; i<c; i++)
1861                 {
1862                         IMeshBuffer *buf = mesh_old->getMeshBuffer(i);
1863                 }*/
1864                 
1865                 /*dstream<<"mesh_old->getReferenceCount()="
1866                                 <<mesh_old->getReferenceCount()<<std::endl;
1867                 u32 c = mesh_old->getMeshBufferCount();
1868                 for(u32 i=0; i<c; i++)
1869                 {
1870                         scene::IMeshBuffer *buf = mesh_old->getMeshBuffer(i);
1871                         dstream<<"buf->getReferenceCount()="
1872                                         <<buf->getReferenceCount()<<std::endl;
1873                 }*/
1874
1875                 // Drop the mesh
1876                 mesh_old->drop();
1877
1878                 //delete mesh_old;
1879         }
1880
1881         mesh_mutex.Unlock();
1882 }
1883         
1884 #endif // !SERVER
1885
1886 /*
1887         Propagates sunlight down through the block.
1888         Doesn't modify nodes that are not affected by sunlight.
1889         
1890         Returns false if sunlight at bottom block is invalid.
1891         Returns true if sunlight at bottom block is valid.
1892         Returns true if bottom block doesn't exist.
1893
1894         If there is a block above, continues from it.
1895         If there is no block above, assumes there is sunlight, unless
1896         is_underground is set or highest node is water.
1897
1898         All sunlighted nodes are added to light_sources.
1899
1900         If grow_grass==true, turns sunglighted mud into grass.
1901
1902         if remove_light==true, sets non-sunlighted nodes black.
1903
1904         if black_air_left!=NULL, it is set to true if non-sunlighted
1905         air is left in block.
1906 */
1907 bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources,
1908                 bool remove_light, bool *black_air_left,
1909                 bool grow_grass)
1910 {
1911         // Whether the sunlight at the top of the bottom block is valid
1912         bool block_below_is_valid = true;
1913         
1914         v3s16 pos_relative = getPosRelative();
1915         
1916         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
1917         {
1918                 for(s16 z=0; z<MAP_BLOCKSIZE; z++)
1919                 {
1920 #if 1
1921                         bool no_sunlight = false;
1922                         bool no_top_block = false;
1923                         // Check if node above block has sunlight
1924                         try{
1925                                 MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z));
1926                                 if(n.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
1927                                 {
1928                                         no_sunlight = true;
1929                                 }
1930                         }
1931                         catch(InvalidPositionException &e)
1932                         {
1933                                 no_top_block = true;
1934                                 
1935                                 // NOTE: This makes over-ground roofed places sunlighted
1936                                 // Assume sunlight, unless is_underground==true
1937                                 if(is_underground)
1938                                 {
1939                                         no_sunlight = true;
1940                                 }
1941                                 else
1942                                 {
1943                                         MapNode n = getNode(v3s16(x, MAP_BLOCKSIZE-1, z));
1944                                         if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE)
1945                                         {
1946                                                 no_sunlight = true;
1947                                         }
1948                                 }
1949                                 // NOTE: As of now, this just would make everything dark.
1950                                 // No sunlight here
1951                                 //no_sunlight = true;
1952                         }
1953 #endif
1954 #if 0 // Doesn't work; nothing gets light.
1955                         bool no_sunlight = true;
1956                         bool no_top_block = false;
1957                         // Check if node above block has sunlight
1958                         try{
1959                                 MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z));
1960                                 if(n.getLight(LIGHTBANK_DAY) == LIGHT_SUN)
1961                                 {
1962                                         no_sunlight = false;
1963                                 }
1964                         }
1965                         catch(InvalidPositionException &e)
1966                         {
1967                                 no_top_block = true;
1968                         }
1969 #endif
1970
1971                         /*std::cout<<"("<<x<<","<<z<<"): "
1972                                         <<"no_top_block="<<no_top_block
1973                                         <<", is_underground="<<is_underground
1974                                         <<", no_sunlight="<<no_sunlight
1975                                         <<std::endl;*/
1976                 
1977                         s16 y = MAP_BLOCKSIZE-1;
1978                         
1979                         // This makes difference to diminishing in water.
1980                         bool stopped_to_solid_object = false;
1981                         
1982                         u8 current_light = no_sunlight ? 0 : LIGHT_SUN;
1983
1984                         for(; y >= 0; y--)
1985                         {
1986                                 v3s16 pos(x, y, z);
1987                                 MapNode &n = getNodeRef(pos);
1988                                 
1989                                 if(current_light == 0)
1990                                 {
1991                                         // Do nothing
1992                                 }
1993                                 else if(current_light == LIGHT_SUN && n.sunlight_propagates())
1994                                 {
1995                                         // Do nothing: Sunlight is continued
1996                                 }
1997                                 else if(n.light_propagates() == false)
1998                                 {
1999                                         if(grow_grass)
2000                                         {
2001                                                 bool upper_is_air = false;
2002                                                 try
2003                                                 {
2004                                                         if(getNodeParent(pos+v3s16(0,1,0)).d == CONTENT_AIR)
2005                                                                 upper_is_air = true;
2006                                                 }
2007                                                 catch(InvalidPositionException &e)
2008                                                 {
2009                                                 }
2010                                                 // Turn mud into grass
2011                                                 if(upper_is_air && n.d == CONTENT_MUD
2012                                                                 && current_light == LIGHT_SUN)
2013                                                 {
2014                                                         n.d = CONTENT_GRASS;
2015                                                 }
2016                                         }
2017
2018                                         // A solid object is on the way.
2019                                         stopped_to_solid_object = true;
2020                                         
2021                                         // Light stops.
2022                                         current_light = 0;
2023                                 }
2024                                 else
2025                                 {
2026                                         // Diminish light
2027                                         current_light = diminish_light(current_light);
2028                                 }
2029
2030                                 u8 old_light = n.getLight(LIGHTBANK_DAY);
2031
2032                                 if(current_light > old_light || remove_light)
2033                                 {
2034                                         n.setLight(LIGHTBANK_DAY, current_light);
2035                                 }
2036                                 
2037                                 if(diminish_light(current_light) != 0)
2038                                 {
2039                                         light_sources.insert(pos_relative + pos, true);
2040                                 }
2041
2042                                 if(current_light == 0 && stopped_to_solid_object)
2043                                 {
2044                                         if(black_air_left)
2045                                         {
2046                                                 *black_air_left = true;
2047                                         }
2048                                 }
2049                         }
2050
2051                         // Whether or not the block below should see LIGHT_SUN
2052                         bool sunlight_should_go_down = (current_light == LIGHT_SUN);
2053
2054                         /*
2055                                 If the block below hasn't already been marked invalid:
2056
2057                                 Check if the node below the block has proper sunlight at top.
2058                                 If not, the block below is invalid.
2059                                 
2060                                 Ignore non-transparent nodes as they always have no light
2061                         */
2062                         try
2063                         {
2064                         if(block_below_is_valid)
2065                         {
2066                                 MapNode n = getNodeParent(v3s16(x, -1, z));
2067                                 if(n.light_propagates())
2068                                 {
2069                                         if(n.getLight(LIGHTBANK_DAY) == LIGHT_SUN
2070                                                         && sunlight_should_go_down == false)
2071                                                 block_below_is_valid = false;
2072                                         else if(n.getLight(LIGHTBANK_DAY) != LIGHT_SUN
2073                                                         && sunlight_should_go_down == true)
2074                                                 block_below_is_valid = false;
2075                                 }
2076                         }//if
2077                         }//try
2078                         catch(InvalidPositionException &e)
2079                         {
2080                                 /*std::cout<<"InvalidBlockException for bottom block node"
2081                                                 <<std::endl;*/
2082                                 // Just no block below, no need to panic.
2083                         }
2084                 }
2085         }
2086
2087         return block_below_is_valid;
2088 }
2089
2090
2091 void MapBlock::copyTo(VoxelManipulator &dst)
2092 {
2093         v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
2094         VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
2095         
2096         // Copy from data to VoxelManipulator
2097         dst.copyFrom(data, data_area, v3s16(0,0,0),
2098                         getPosRelative(), data_size);
2099 }
2100
2101 void MapBlock::copyFrom(VoxelManipulator &dst)
2102 {
2103         v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
2104         VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
2105         
2106         // Copy from VoxelManipulator to data
2107         dst.copyTo(data, data_area, v3s16(0,0,0),
2108                         getPosRelative(), data_size);
2109 }
2110
2111 void MapBlock::stepObjects(float dtime, bool server, u32 daynight_ratio)
2112 {
2113         /*
2114                 Step objects
2115         */
2116         m_objects.step(dtime, server, daynight_ratio);
2117
2118         setChangedFlag();
2119 }
2120
2121
2122 void MapBlock::updateDayNightDiff()
2123 {
2124         if(data == NULL)
2125         {
2126                 m_day_night_differs = false;
2127                 return;
2128         }
2129
2130         bool differs = false;
2131
2132         /*
2133                 Check if any lighting value differs
2134         */
2135         for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
2136         {
2137                 MapNode &n = data[i];
2138                 if(n.getLight(LIGHTBANK_DAY) != n.getLight(LIGHTBANK_NIGHT))
2139                 {
2140                         differs = true;
2141                         break;
2142                 }
2143         }
2144
2145         /*
2146                 If some lighting values differ, check if the whole thing is
2147                 just air. If it is, differ = false
2148         */
2149         if(differs)
2150         {
2151                 bool only_air = true;
2152                 for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
2153                 {
2154                         MapNode &n = data[i];
2155                         if(n.d != CONTENT_AIR)
2156                         {
2157                                 only_air = false;
2158                                 break;
2159                         }
2160                 }
2161                 if(only_air)
2162                         differs = false;
2163         }
2164
2165         // Set member variable
2166         m_day_night_differs = differs;
2167 }
2168
2169 s16 MapBlock::getGroundLevel(v2s16 p2d)
2170 {
2171         if(isDummy())
2172                 return -3;
2173         try
2174         {
2175                 s16 y = MAP_BLOCKSIZE-1;
2176                 for(; y>=0; y--)
2177                 {
2178                         //if(is_ground_content(getNodeRef(p2d.X, y, p2d.Y).d))
2179                         if(content_features(getNodeRef(p2d.X, y, p2d.Y).d).walkable)
2180                         {
2181                                 if(y == MAP_BLOCKSIZE-1)
2182                                         return -2;
2183                                 else
2184                                         return y;
2185                         }
2186                 }
2187                 return -1;
2188         }
2189         catch(InvalidPositionException &e)
2190         {
2191                 return -3;
2192         }
2193 }
2194
2195 /*
2196         Serialization
2197 */
2198
2199 void MapBlock::serialize(std::ostream &os, u8 version)
2200 {
2201         if(!ser_ver_supported(version))
2202                 throw VersionMismatchException("ERROR: MapBlock format not supported");
2203         
2204         if(data == NULL)
2205         {
2206                 throw SerializationError("ERROR: Not writing dummy block.");
2207         }
2208         
2209         // These have no compression
2210         if(version <= 3 || version == 5 || version == 6)
2211         {
2212                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
2213                 
2214                 u32 buflen = 1 + nodecount * MapNode::serializedLength(version);
2215                 SharedBuffer<u8> dest(buflen);
2216
2217                 dest[0] = is_underground;
2218                 for(u32 i=0; i<nodecount; i++)
2219                 {
2220                         u32 s = 1 + i * MapNode::serializedLength(version);
2221                         data[i].serialize(&dest[s], version);
2222                 }
2223                 
2224                 os.write((char*)*dest, dest.getSize());
2225         }
2226         else if(version <= 10)
2227         {
2228                 /*
2229                         With compression.
2230                         Compress the materials and the params separately.
2231                 */
2232                 
2233                 // First byte
2234                 os.write((char*)&is_underground, 1);
2235
2236                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
2237
2238                 // Get and compress materials
2239                 SharedBuffer<u8> materialdata(nodecount);
2240                 for(u32 i=0; i<nodecount; i++)
2241                 {
2242                         materialdata[i] = data[i].d;
2243                 }
2244                 compress(materialdata, os, version);
2245
2246                 // Get and compress lights
2247                 SharedBuffer<u8> lightdata(nodecount);
2248                 for(u32 i=0; i<nodecount; i++)
2249                 {
2250                         lightdata[i] = data[i].param;
2251                 }
2252                 compress(lightdata, os, version);
2253                 
2254                 if(version >= 10)
2255                 {
2256                         // Get and compress param2
2257                         SharedBuffer<u8> param2data(nodecount);
2258                         for(u32 i=0; i<nodecount; i++)
2259                         {
2260                                 param2data[i] = data[i].param2;
2261                         }
2262                         compress(param2data, os, version);
2263                 }
2264         }
2265         // All other versions (newest)
2266         else
2267         {
2268                 // First byte
2269                 u8 flags = 0;
2270                 if(is_underground)
2271                         flags |= 0x01;
2272                 if(m_day_night_differs)
2273                         flags |= 0x02;
2274                 if(m_lighting_expired)
2275                         flags |= 0x04;
2276                 os.write((char*)&flags, 1);
2277
2278                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
2279
2280                 /*
2281                         Get data
2282                 */
2283
2284                 SharedBuffer<u8> databuf(nodecount*3);
2285
2286                 // Get contents
2287                 for(u32 i=0; i<nodecount; i++)
2288                 {
2289                         databuf[i] = data[i].d;
2290                 }
2291
2292                 // Get params
2293                 for(u32 i=0; i<nodecount; i++)
2294                 {
2295                         databuf[i+nodecount] = data[i].param;
2296                 }
2297
2298                 // Get param2
2299                 for(u32 i=0; i<nodecount; i++)
2300                 {
2301                         databuf[i+nodecount*2] = data[i].param2;
2302                 }
2303
2304                 /*
2305                         Compress data to output stream
2306                 */
2307
2308                 compress(databuf, os, version);
2309                 
2310                 /*
2311                         NodeMetadata
2312                 */
2313                 if(version >= 14)
2314                 {
2315                         if(version <= 15)
2316                         {
2317                                 try{
2318                                         std::ostringstream oss(std::ios_base::binary);
2319                                         m_node_metadata.serialize(oss);
2320                                         os<<serializeString(oss.str());
2321                                 }
2322                                 // This will happen if the string is longer than 65535
2323                                 catch(SerializationError &e)
2324                                 {
2325                                         // Use an empty string
2326                                         os<<serializeString("");
2327                                 }
2328                         }
2329                         else
2330                         {
2331                                 std::ostringstream oss(std::ios_base::binary);
2332                                 m_node_metadata.serialize(oss);
2333                                 compressZlib(oss.str(), os);
2334                                 //os<<serializeLongString(oss.str());
2335                         }
2336                 }
2337         }
2338 }
2339
2340 void MapBlock::deSerialize(std::istream &is, u8 version)
2341 {
2342         if(!ser_ver_supported(version))
2343                 throw VersionMismatchException("ERROR: MapBlock format not supported");
2344
2345         // These have no lighting info
2346         if(version <= 1)
2347         {
2348                 setLightingExpired(true);
2349         }
2350
2351         // These have no compression
2352         if(version <= 3 || version == 5 || version == 6)
2353         {
2354                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
2355                 char tmp;
2356                 is.read(&tmp, 1);
2357                 if(is.gcount() != 1)
2358                         throw SerializationError
2359                                         ("MapBlock::deSerialize: no enough input data");
2360                 is_underground = tmp;
2361                 for(u32 i=0; i<nodecount; i++)
2362                 {
2363                         s32 len = MapNode::serializedLength(version);
2364                         SharedBuffer<u8> d(len);
2365                         is.read((char*)*d, len);
2366                         if(is.gcount() != len)
2367                                 throw SerializationError
2368                                                 ("MapBlock::deSerialize: no enough input data");
2369                         data[i].deSerialize(*d, version);
2370                 }
2371         }
2372         else if(version <= 10)
2373         {
2374                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
2375
2376                 u8 t8;
2377                 is.read((char*)&t8, 1);
2378                 is_underground = t8;
2379
2380                 {
2381                         // Uncompress and set material data
2382                         std::ostringstream os(std::ios_base::binary);
2383                         decompress(is, os, version);
2384                         std::string s = os.str();
2385                         if(s.size() != nodecount)
2386                                 throw SerializationError
2387                                                 ("MapBlock::deSerialize: invalid format");
2388                         for(u32 i=0; i<s.size(); i++)
2389                         {
2390                                 data[i].d = s[i];
2391                         }
2392                 }
2393                 {
2394                         // Uncompress and set param data
2395                         std::ostringstream os(std::ios_base::binary);
2396                         decompress(is, os, version);
2397                         std::string s = os.str();
2398                         if(s.size() != nodecount)
2399                                 throw SerializationError
2400                                                 ("MapBlock::deSerialize: invalid format");
2401                         for(u32 i=0; i<s.size(); i++)
2402                         {
2403                                 data[i].param = s[i];
2404                         }
2405                 }
2406         
2407                 if(version >= 10)
2408                 {
2409                         // Uncompress and set param2 data
2410                         std::ostringstream os(std::ios_base::binary);
2411                         decompress(is, os, version);
2412                         std::string s = os.str();
2413                         if(s.size() != nodecount)
2414                                 throw SerializationError
2415                                                 ("MapBlock::deSerialize: invalid format");
2416                         for(u32 i=0; i<s.size(); i++)
2417                         {
2418                                 data[i].param2 = s[i];
2419                         }
2420                 }
2421         }
2422         // All other versions (newest)
2423         else
2424         {
2425                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
2426
2427                 u8 flags;
2428                 is.read((char*)&flags, 1);
2429                 is_underground = (flags & 0x01) ? true : false;
2430                 m_day_night_differs = (flags & 0x02) ? true : false;
2431                 m_lighting_expired = (flags & 0x04) ? true : false;
2432
2433                 // Uncompress 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*3)
2438                         throw SerializationError
2439                                         ("MapBlock::deSerialize: invalid format");
2440
2441                 // Set contents
2442                 for(u32 i=0; i<nodecount; i++)
2443                 {
2444                         data[i].d = s[i];
2445                 }
2446                 // Set params
2447                 for(u32 i=0; i<nodecount; i++)
2448                 {
2449                         data[i].param = s[i+nodecount];
2450                 }
2451                 // Set param2
2452                 for(u32 i=0; i<nodecount; i++)
2453                 {
2454                         data[i].param2 = s[i+nodecount*2];
2455                 }
2456                 
2457                 /*
2458                         NodeMetadata
2459                 */
2460                 if(version >= 14)
2461                 {
2462                         // Ignore errors
2463                         try{
2464                                 if(version <= 15)
2465                                 {
2466                                         std::string data = deSerializeString(is);
2467                                         std::istringstream iss(data, std::ios_base::binary);
2468                                         m_node_metadata.deSerialize(iss);
2469                                 }
2470                                 else
2471                                 {
2472                                         //std::string data = deSerializeLongString(is);
2473                                         std::ostringstream oss(std::ios_base::binary);
2474                                         decompressZlib(is, oss);
2475                                         std::istringstream iss(oss.str(), std::ios_base::binary);
2476                                         m_node_metadata.deSerialize(iss);
2477                                 }
2478                         }
2479                         catch(SerializationError &e)
2480                         {
2481                                 dstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error"
2482                                                 <<" while deserializing node metadata"<<std::endl;
2483                         }
2484                 }
2485         }
2486         
2487         /*
2488                 Translate nodes as specified in the translate_to fields of
2489                 node features
2490
2491                 NOTE: This isn't really used. Should it be removed?
2492         */
2493         for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
2494         {
2495                 MapNode &n = data[i];
2496
2497                 MapNode *translate_to = content_features(n.d).translate_to;
2498                 if(translate_to)
2499                 {
2500                         dstream<<"MapBlock: WARNING: Translating node "<<n.d<<" to "
2501                                         <<translate_to->d<<std::endl;
2502                         n = *translate_to;
2503                 }
2504         }
2505 }
2506
2507 void MapBlock::serializeDiskExtra(std::ostream &os, u8 version)
2508 {
2509         // Versions up from 9 have block objects.
2510         if(version >= 9)
2511         {
2512                 serializeObjects(os, version);
2513         }
2514         
2515         // Versions up from 15 have static objects.
2516         if(version >= 15)
2517         {
2518                 m_static_objects.serialize(os);
2519         }
2520
2521         // Timestamp
2522         if(version >= 17)
2523         {
2524                 writeU32(os, getTimestamp());
2525         }
2526 }
2527
2528 void MapBlock::deSerializeDiskExtra(std::istream &is, u8 version)
2529 {
2530         /*
2531                 Versions up from 9 have block objects.
2532         */
2533         if(version >= 9)
2534         {
2535                 updateObjects(is, version, NULL, 0);
2536         }
2537
2538         /*
2539                 Versions up from 15 have static objects.
2540         */
2541         if(version >= 15)
2542         {
2543                 m_static_objects.deSerialize(is);
2544         }
2545                 
2546         // Timestamp
2547         if(version >= 17)
2548         {
2549                 setTimestamp(readU32(is));
2550         }
2551         else
2552         {
2553                 setTimestamp(BLOCK_TIMESTAMP_UNDEFINED);
2554         }
2555 }
2556
2557
2558 //END