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