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