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