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