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