94c6ad90955de7b18a6096e908b6eea8091f54b1
[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 and g_irrlicht
23 #include "main.h"
24 #include "light.h"
25 #include <sstream>
26
27
28 /*
29         MapBlock
30 */
31
32 MapBlock::MapBlock(NodeContainer *parent, v3s16 pos, bool dummy):
33                 m_parent(parent),
34                 m_pos(pos),
35                 changed(true),
36                 is_underground(false),
37                 m_lighting_expired(true),
38                 m_day_night_differs(false),
39                 m_not_fully_generated(false),
40                 m_objects(this)
41 {
42         data = NULL;
43         if(dummy == false)
44                 reallocate();
45         
46         m_spawn_timer = -10000;
47
48 #ifndef SERVER
49         m_mesh_expired = false;
50         mesh_mutex.Init();
51         mesh = NULL;
52         m_temp_mods_mutex.Init();
53 #endif
54 }
55
56 MapBlock::~MapBlock()
57 {
58 #ifndef SERVER
59         {
60                 JMutexAutoLock lock(mesh_mutex);
61                 
62                 if(mesh)
63                 {
64                         mesh->drop();
65                         mesh = NULL;
66                 }
67         }
68 #endif
69
70         if(data)
71                 delete[] data;
72 }
73
74 bool MapBlock::isValidPositionParent(v3s16 p)
75 {
76         if(isValidPosition(p))
77         {
78                 return true;
79         }
80         else{
81                 return m_parent->isValidPosition(getPosRelative() + p);
82         }
83 }
84
85 MapNode MapBlock::getNodeParent(v3s16 p)
86 {
87         if(isValidPosition(p) == false)
88         {
89                 return m_parent->getNode(getPosRelative() + p);
90         }
91         else
92         {
93                 if(data == NULL)
94                         throw InvalidPositionException();
95                 return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X];
96         }
97 }
98
99 void MapBlock::setNodeParent(v3s16 p, MapNode & n)
100 {
101         if(isValidPosition(p) == false)
102         {
103                 m_parent->setNode(getPosRelative() + p, n);
104         }
105         else
106         {
107                 if(data == NULL)
108                         throw InvalidPositionException();
109                 data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X] = n;
110         }
111 }
112
113 MapNode MapBlock::getNodeParentNoEx(v3s16 p)
114 {
115         if(isValidPosition(p) == false)
116         {
117                 try{
118                         return m_parent->getNode(getPosRelative() + p);
119                 }
120                 catch(InvalidPositionException &e)
121                 {
122                         return MapNode(CONTENT_IGNORE);
123                 }
124         }
125         else
126         {
127                 if(data == NULL)
128                 {
129                         return MapNode(CONTENT_IGNORE);
130                 }
131                 return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X];
132         }
133 }
134
135 /*
136         Parameters must consist of air and !air.
137         Order doesn't matter.
138
139         If either of the nodes doesn't exist, light is 0.
140         
141         parameters:
142                 daynight_ratio: 0...1000
143                 n: getNodeParent(p)
144                 n2: getNodeParent(p + face_dir)
145                 face_dir: axis oriented unit vector from p to p2
146         
147         returns encoded light value.
148 */
149 u8 MapBlock::getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
150                 v3s16 face_dir)
151 {
152         try{
153                 u8 light;
154                 u8 l1 = n.getLightBlend(daynight_ratio);
155                 u8 l2 = n2.getLightBlend(daynight_ratio);
156                 if(l1 > l2)
157                         light = l1;
158                 else
159                         light = l2;
160
161                 // Make some nice difference to different sides
162
163                 // This makes light come from a corner
164                 /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
165                         light = diminish_light(diminish_light(light));
166                 else if(face_dir.X == -1 || face_dir.Z == -1)
167                         light = diminish_light(light);*/
168                 
169                 // All neighboring faces have different shade (like in minecraft)
170                 if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
171                         light = diminish_light(diminish_light(light));
172                 else if(face_dir.Z == 1 || face_dir.Z == -1)
173                         light = diminish_light(light);
174
175                 return light;
176         }
177         catch(InvalidPositionException &e)
178         {
179                 return 0;
180         }
181 }
182
183 #ifndef SERVER
184
185 void MapBlock::makeFastFace(TileSpec tile, u8 light, v3f p,
186                 v3s16 dir, v3f scale, v3f posRelative_f,
187                 core::array<FastFace> &dest)
188 {
189         FastFace face;
190         
191         // Position is at the center of the cube.
192         v3f pos = p * BS;
193         posRelative_f *= BS;
194
195         v3f vertex_pos[4];
196         // If looking towards z+, this is the face that is behind
197         // the center point, facing towards z+.
198         vertex_pos[0] = v3f(-BS/2,-BS/2,BS/2);
199         vertex_pos[1] = v3f( BS/2,-BS/2,BS/2);
200         vertex_pos[2] = v3f( BS/2, BS/2,BS/2);
201         vertex_pos[3] = v3f(-BS/2, BS/2,BS/2);
202         
203         if(dir == v3s16(0,0,1))
204         {
205                 for(u16 i=0; i<4; i++)
206                         vertex_pos[i].rotateXZBy(0);
207         }
208         else if(dir == v3s16(0,0,-1))
209         {
210                 for(u16 i=0; i<4; i++)
211                         vertex_pos[i].rotateXZBy(180);
212         }
213         else if(dir == v3s16(1,0,0))
214         {
215                 for(u16 i=0; i<4; i++)
216                         vertex_pos[i].rotateXZBy(-90);
217         }
218         else if(dir == v3s16(-1,0,0))
219         {
220                 for(u16 i=0; i<4; i++)
221                         vertex_pos[i].rotateXZBy(90);
222         }
223         else if(dir == v3s16(0,1,0))
224         {
225                 for(u16 i=0; i<4; i++)
226                         vertex_pos[i].rotateYZBy(-90);
227         }
228         else if(dir == v3s16(0,-1,0))
229         {
230                 for(u16 i=0; i<4; i++)
231                         vertex_pos[i].rotateYZBy(90);
232         }
233
234         for(u16 i=0; i<4; i++)
235         {
236                 vertex_pos[i].X *= scale.X;
237                 vertex_pos[i].Y *= scale.Y;
238                 vertex_pos[i].Z *= scale.Z;
239                 vertex_pos[i] += pos + posRelative_f;
240         }
241
242         f32 abs_scale = 1.;
243         if     (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
244         else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
245         else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
246
247         v3f zerovector = v3f(0,0,0);
248         
249         //u8 li = decode_light(light);
250         u8 li = light;
251         //u8 li = 255; //DEBUG
252
253         u8 alpha = tile.alpha;
254         /*u8 alpha = 255;
255         if(tile.id == TILE_WATER)
256                 alpha = WATER_ALPHA;*/
257
258         video::SColor c = video::SColor(alpha,li,li,li);
259
260         float x0 = tile.texture.pos.X;
261         float y0 = tile.texture.pos.Y;
262         float w = tile.texture.size.X;
263         float h = tile.texture.size.Y;
264
265         face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0), c,
266                         core::vector2d<f32>(x0+w*abs_scale, y0+h));
267         face.vertices[1] = video::S3DVertex(vertex_pos[1], v3f(0,1,0), c,
268                         core::vector2d<f32>(x0, y0+h));
269         face.vertices[2] = video::S3DVertex(vertex_pos[2], v3f(0,1,0), c,
270                         core::vector2d<f32>(x0, y0));
271         face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0), c,
272                         core::vector2d<f32>(x0+w*abs_scale, y0));
273
274         face.tile = tile;
275         //DEBUG
276         //f->tile = TILE_STONE;
277         
278         dest.push_back(face);
279         //return f;
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 MapBlock::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 MapBlock::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 /*
377         startpos:
378         translate_dir: unit vector with only one of x, y or z
379         face_dir: unit vector with only one of x, y or z
380 */
381 void MapBlock::updateFastFaceRow(
382                 u32 daynight_ratio,
383                 v3f posRelative_f,
384                 v3s16 startpos,
385                 u16 length,
386                 v3s16 translate_dir,
387                 v3f translate_dir_f,
388                 v3s16 face_dir,
389                 v3f face_dir_f,
390                 core::array<FastFace> &dest,
391                 NodeModMap &temp_mods)
392 {
393         v3s16 p = startpos;
394         
395         u16 continuous_tiles_count = 0;
396         
397         MapNode n0 = getNodeParentNoEx(p);
398         MapNode n1 = getNodeParentNoEx(p + face_dir);
399
400         u8 light = getFaceLight(daynight_ratio, n0, n1, face_dir);
401                 
402         TileSpec tile0 = getNodeTile(n0, p, face_dir, temp_mods);
403         TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir, temp_mods);
404
405         for(u16 j=0; j<length; j++)
406         {
407                 bool next_is_different = true;
408                 
409                 v3s16 p_next;
410                 MapNode n0_next;
411                 MapNode n1_next;
412                 TileSpec tile0_next;
413                 TileSpec tile1_next;
414                 u8 light_next = 0;
415                 
416                 // If at last position, there is nothing to compare to and
417                 // the face must be drawn anyway
418                 if(j != length - 1)
419                 {
420                         p_next = p + translate_dir;
421                         n0_next = getNodeParentNoEx(p_next);
422                         n1_next = getNodeParentNoEx(p_next + face_dir);
423                         tile0_next = getNodeTile(n0_next, p_next, face_dir, temp_mods);
424                         tile1_next = getNodeTile(n1_next,p_next+face_dir,-face_dir, temp_mods);
425                         light_next = getFaceLight(daynight_ratio, n0_next, n1_next, face_dir);
426
427                         if(tile0_next == tile0
428                                         && tile1_next == tile1
429                                         && light_next == light)
430                         {
431                                 next_is_different = false;
432                         }
433                 }
434
435                 continuous_tiles_count++;
436                 
437                 // This is set to true if the texture doesn't allow more tiling
438                 bool end_of_texture = false;
439                 /*
440                         If there is no texture, it can be tiled infinitely.
441                         If tiled==0, it means the texture can be tiled infinitely.
442                         Otherwise check tiled agains continuous_tiles_count.
443
444                         This check has to be made for both tiles, because this is
445                         a bit hackish and we know which one we're using only when
446                         the decision to make the faces is made.
447                 */
448                 if(tile0.texture.atlas != NULL && tile0.texture.tiled != 0)
449                 {
450                         if(tile0.texture.tiled <= continuous_tiles_count)
451                                 end_of_texture = true;
452                 }
453                 if(tile1.texture.atlas != NULL && tile1.texture.tiled != 0)
454                 {
455                         if(tile1.texture.tiled <= continuous_tiles_count)
456                                 end_of_texture = true;
457                 }
458                 
459                 //end_of_texture = true; //DEBUG
460                 
461                 if(next_is_different || end_of_texture)
462                 {
463                         /*
464                                 Create a face if there should be one
465                         */
466                         //u8 mf = face_contents(tile0, tile1);
467                         // This is hackish
468                         u8 content0 = getNodeContent(p, n0, temp_mods);
469                         u8 content1 = getNodeContent(p + face_dir, n1, temp_mods);
470                         u8 mf = face_contents(content0, content1);
471                         
472                         if(mf != 0)
473                         {
474                                 // Floating point conversion of the position vector
475                                 v3f pf(p.X, p.Y, p.Z);
476                                 // Center point of face (kind of)
477                                 v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
478                                 v3f scale(1,1,1);
479                                 if(translate_dir.X != 0){
480                                         scale.X = continuous_tiles_count;
481                                 }
482                                 if(translate_dir.Y != 0){
483                                         scale.Y = continuous_tiles_count;
484                                 }
485                                 if(translate_dir.Z != 0){
486                                         scale.Z = continuous_tiles_count;
487                                 }
488                                 
489                                 //FastFace *f;
490
491                                 // If node at sp (tile0) is more solid
492                                 if(mf == 1)
493                                 {
494                                         makeFastFace(tile0, decode_light(light),
495                                                         sp, face_dir, scale,
496                                                         posRelative_f, dest);
497                                 }
498                                 // If node at sp is less solid (mf == 2)
499                                 else
500                                 {
501                                         makeFastFace(tile1, decode_light(light),
502                                                         sp+face_dir_f, -face_dir, scale,
503                                                         posRelative_f, dest);
504                                 }
505                                 //dest.push_back(f);
506                         }
507
508                         continuous_tiles_count = 0;
509                         n0 = n0_next;
510                         n1 = n1_next;
511                         tile0 = tile0_next;
512                         tile1 = tile1_next;
513                         light = light_next;
514                 }
515                 
516                 p = p_next;
517         }
518 }
519
520 /*
521         This is used because CMeshBuffer::append() is very slow
522 */
523 struct PreMeshBuffer
524 {
525         video::SMaterial material;
526         core::array<u16> indices;
527         core::array<video::S3DVertex> vertices;
528 };
529
530 class MeshCollector
531 {
532 public:
533         void append(
534                         video::SMaterial material,
535                         const video::S3DVertex* const vertices,
536                         u32 numVertices,
537                         const u16* const indices,
538                         u32 numIndices
539                 )
540         {
541                 PreMeshBuffer *p = NULL;
542                 for(u32 i=0; i<m_prebuffers.size(); i++)
543                 {
544                         PreMeshBuffer &pp = m_prebuffers[i];
545                         if(pp.material != material)
546                                 continue;
547
548                         p = &pp;
549                         break;
550                 }
551
552                 if(p == NULL)
553                 {
554                         PreMeshBuffer pp;
555                         pp.material = material;
556                         m_prebuffers.push_back(pp);
557                         p = &m_prebuffers[m_prebuffers.size()-1];
558                 }
559
560                 u32 vertex_count = p->vertices.size();
561                 for(u32 i=0; i<numIndices; i++)
562                 {
563                         u32 j = indices[i] + vertex_count;
564                         if(j > 65535)
565                         {
566                                 dstream<<"FIXME: Meshbuffer ran out of indices"<<std::endl;
567                                 // NOTE: Fix is to just add an another MeshBuffer
568                         }
569                         p->indices.push_back(j);
570                 }
571                 for(u32 i=0; i<numVertices; i++)
572                 {
573                         p->vertices.push_back(vertices[i]);
574                 }
575         }
576
577         void fillMesh(scene::SMesh *mesh)
578         {
579                 /*dstream<<"Filling mesh with "<<m_prebuffers.size()
580                                 <<" meshbuffers"<<std::endl;*/
581                 for(u32 i=0; i<m_prebuffers.size(); i++)
582                 {
583                         PreMeshBuffer &p = m_prebuffers[i];
584
585                         /*dstream<<"p.vertices.size()="<<p.vertices.size()
586                                         <<", p.indices.size()="<<p.indices.size()
587                                         <<std::endl;*/
588                         
589                         // Create meshbuffer
590                         
591                         // This is a "Standard MeshBuffer",
592                         // it's a typedeffed CMeshBuffer<video::S3DVertex>
593                         scene::SMeshBuffer *buf = new scene::SMeshBuffer();
594                         // Set material
595                         buf->Material = p.material;
596                         //((scene::SMeshBuffer*)buf)->Material = p.material;
597                         // Use VBO
598                         //buf->setHardwareMappingHint(scene::EHM_STATIC);
599                         // Add to mesh
600                         mesh->addMeshBuffer(buf);
601                         // Mesh grabbed it
602                         buf->drop();
603
604                         buf->append(p.vertices.pointer(), p.vertices.size(),
605                                         p.indices.pointer(), p.indices.size());
606                 }
607         }
608
609 private:
610         core::array<PreMeshBuffer> m_prebuffers;
611 };
612
613 void MapBlock::updateMesh(u32 daynight_ratio)
614 {
615 #if 0
616         /*
617                 DEBUG: If mesh has been generated, don't generate it again
618         */
619         {
620                 JMutexAutoLock meshlock(mesh_mutex);
621                 if(mesh != NULL)
622                         return;
623         }
624 #endif
625         
626         // 4-21ms for MAP_BLOCKSIZE=16
627         // 24-155ms for MAP_BLOCKSIZE=32
628         //TimeTaker timer1("updateMesh()");
629
630         core::array<FastFace> fastfaces_new;
631         
632         v3f posRelative_f(getPosRelative().X, getPosRelative().Y,
633                         getPosRelative().Z); // floating point conversion
634         
635         /*
636                 Avoid interlocks by copying m_temp_mods
637         */
638         NodeModMap temp_mods;
639         {
640                 JMutexAutoLock lock(m_temp_mods_mutex);
641                 m_temp_mods.copy(temp_mods);
642         }
643         
644         /*
645                 Some settings
646         */
647         bool new_style_water = g_settings.getBool("new_style_water");
648         bool new_style_leaves = g_settings.getBool("new_style_leaves");
649         
650         float node_water_level = 1.0;
651         if(new_style_water)
652                 node_water_level = 0.85;
653         
654         /*
655                 We are including the faces of the trailing edges of the block.
656                 This means that when something changes, the caller must
657                 also update the meshes of the blocks at the leading edges.
658
659                 NOTE: This is the slowest part of this method.
660         */
661         
662         {
663                 // 4-23ms for MAP_BLOCKSIZE=16
664                 //TimeTaker timer2("updateMesh() collect");
665
666                 /*
667                         Go through every y,z and get top faces in rows of x+
668                 */
669                 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
670                         for(s16 z=0; z<MAP_BLOCKSIZE; z++){
671                                 updateFastFaceRow(daynight_ratio, posRelative_f,
672                                                 v3s16(0,y,z), MAP_BLOCKSIZE,
673                                                 v3s16(1,0,0), //dir
674                                                 v3f  (1,0,0),
675                                                 v3s16(0,1,0), //face dir
676                                                 v3f  (0,1,0),
677                                                 fastfaces_new,
678                                                 temp_mods);
679                         }
680                 }
681                 /*
682                         Go through every x,y and get right faces in rows of z+
683                 */
684                 for(s16 x=0; x<MAP_BLOCKSIZE; x++){
685                         for(s16 y=0; y<MAP_BLOCKSIZE; y++){
686                                 updateFastFaceRow(daynight_ratio, posRelative_f,
687                                                 v3s16(x,y,0), MAP_BLOCKSIZE,
688                                                 v3s16(0,0,1),
689                                                 v3f  (0,0,1),
690                                                 v3s16(1,0,0),
691                                                 v3f  (1,0,0),
692                                                 fastfaces_new,
693                                                 temp_mods);
694                         }
695                 }
696                 /*
697                         Go through every y,z and get back faces in rows of x+
698                 */
699                 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
700                         for(s16 y=0; y<MAP_BLOCKSIZE; y++){
701                                 updateFastFaceRow(daynight_ratio, posRelative_f,
702                                                 v3s16(0,y,z), MAP_BLOCKSIZE,
703                                                 v3s16(1,0,0),
704                                                 v3f  (1,0,0),
705                                                 v3s16(0,0,1),
706                                                 v3f  (0,0,1),
707                                                 fastfaces_new,
708                                                 temp_mods);
709                         }
710                 }
711         }
712
713         // End of slow part
714
715         /*
716                 Convert FastFaces to SMesh
717         */
718
719         MeshCollector collector;
720
721         if(fastfaces_new.size() > 0)
722         {
723                 // avg 0ms (100ms spikes when loading textures the first time)
724                 //TimeTaker timer2("updateMesh() mesh building");
725
726                 video::SMaterial material;
727                 material.setFlag(video::EMF_LIGHTING, false);
728                 material.setFlag(video::EMF_BILINEAR_FILTER, false);
729                 material.setFlag(video::EMF_FOG_ENABLE, true);
730                 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
731                 //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE);
732
733                 for(u32 i=0; i<fastfaces_new.size(); i++)
734                 {
735                         FastFace &f = fastfaces_new[i];
736
737                         const u16 indices[] = {0,1,2,2,3,0};
738                         
739                         //video::ITexture *texture = g_irrlicht->getTexture(f.tile.spec);
740                         video::ITexture *texture = f.tile.texture.atlas;
741                         if(texture == NULL)
742                                 continue;
743
744                         material.setTexture(0, texture);
745                         
746                         f.tile.applyMaterialOptions(material);
747                         
748                         collector.append(material, f.vertices, 4, indices, 6);
749                 }
750         }
751
752         /*
753                 Add special graphics:
754                 - torches
755                 - flowing water
756         */
757
758         // 0ms
759         //TimeTaker timer2("updateMesh() adding special stuff");
760
761         // Flowing water material
762         video::SMaterial material_water1;
763         material_water1.setFlag(video::EMF_LIGHTING, false);
764         //material_water1.setFlag(video::EMF_BACK_FACE_CULLING, false);
765         material_water1.setFlag(video::EMF_BILINEAR_FILTER, false);
766         material_water1.setFlag(video::EMF_FOG_ENABLE, true);
767         material_water1.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
768         //TODO
769         //material_water1.setTexture(0, g_irrlicht->getTexture("water.png"));
770         AtlasPointer pa_water1 = g_texturesource->getTexture(
771                         g_texturesource->getTextureId("water.png"));
772         material_water1.setTexture(0, pa_water1.atlas);
773
774         // New-style leaves material
775         video::SMaterial material_leaves1;
776         material_leaves1.setFlag(video::EMF_LIGHTING, false);
777         //material_leaves1.setFlag(video::EMF_BACK_FACE_CULLING, false);
778         material_leaves1.setFlag(video::EMF_BILINEAR_FILTER, false);
779         material_leaves1.setFlag(video::EMF_FOG_ENABLE, true);
780         material_leaves1.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
781         //TODO
782         //material_leaves1.setTexture(0, g_irrlicht->getTexture("leaves.png"));
783         AtlasPointer pa_leaves1 = g_texturesource->getTexture(
784                         g_texturesource->getTextureId("leaves.png"));
785         material_leaves1.setTexture(0, pa_leaves1.atlas);
786
787         for(s16 z=0; z<MAP_BLOCKSIZE; z++)
788         for(s16 y=0; y<MAP_BLOCKSIZE; y++)
789         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
790         {
791                 v3s16 p(x,y,z);
792
793                 MapNode &n = getNodeRef(x,y,z);
794                 
795                 /*
796                         Add torches to mesh
797                 */
798                 if(n.d == CONTENT_TORCH)
799                 {
800                         video::SColor c(255,255,255,255);
801
802                         video::S3DVertex vertices[4] =
803                         {
804                                 video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 0,1),
805                                 video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, 1,1),
806                                 video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
807                                 video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
808                         };
809
810                         v3s16 dir = unpackDir(n.dir);
811
812                         for(s32 i=0; i<4; i++)
813                         {
814                                 if(dir == v3s16(1,0,0))
815                                         vertices[i].Pos.rotateXZBy(0);
816                                 if(dir == v3s16(-1,0,0))
817                                         vertices[i].Pos.rotateXZBy(180);
818                                 if(dir == v3s16(0,0,1))
819                                         vertices[i].Pos.rotateXZBy(90);
820                                 if(dir == v3s16(0,0,-1))
821                                         vertices[i].Pos.rotateXZBy(-90);
822                                 if(dir == v3s16(0,-1,0))
823                                         vertices[i].Pos.rotateXZBy(45);
824                                 if(dir == v3s16(0,1,0))
825                                         vertices[i].Pos.rotateXZBy(-45);
826
827                                 vertices[i].Pos += intToFloat(p + getPosRelative(), BS);
828                         }
829
830                         // Set material
831                         video::SMaterial material;
832                         material.setFlag(video::EMF_LIGHTING, false);
833                         material.setFlag(video::EMF_BACK_FACE_CULLING, false);
834                         material.setFlag(video::EMF_BILINEAR_FILTER, false);
835                         //material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
836                         material.MaterialType
837                                         = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
838
839                         if(dir == v3s16(0,-1,0))
840                                 material.setTexture(0,
841                                                 g_texturesource->getTextureRaw("torch_on_floor.png"));
842                         else if(dir == v3s16(0,1,0))
843                                 material.setTexture(0,
844                                                 g_texturesource->getTextureRaw("torch_on_ceiling.png"));
845                         // For backwards compatibility
846                         else if(dir == v3s16(0,0,0))
847                                 material.setTexture(0,
848                                                 g_texturesource->getTextureRaw("torch_on_floor.png"));
849                         else
850                                 material.setTexture(0, 
851                                                 g_texturesource->getTextureRaw("torch.png"));
852
853                         u16 indices[] = {0,1,2,2,3,0};
854                         // Add to mesh collector
855                         collector.append(material, vertices, 4, indices, 6);
856                 }
857                 /*
858                         Add flowing water to mesh
859                 */
860                 else if(n.d == CONTENT_WATER)
861                 {
862                         bool top_is_water = false;
863                         try{
864                                 MapNode n = getNodeParent(v3s16(x,y+1,z));
865                                 if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE)
866                                         top_is_water = true;
867                         }catch(InvalidPositionException &e){}
868                         
869                         u8 l = decode_light(n.getLightBlend(daynight_ratio));
870                         video::SColor c(WATER_ALPHA,l,l,l);
871                         
872                         // Neighbor water levels (key = relative position)
873                         // Includes current node
874                         core::map<v3s16, f32> neighbor_levels;
875                         core::map<v3s16, u8> neighbor_contents;
876                         core::map<v3s16, u8> neighbor_flags;
877                         const u8 neighborflag_top_is_water = 0x01;
878                         v3s16 neighbor_dirs[9] = {
879                                 v3s16(0,0,0),
880                                 v3s16(0,0,1),
881                                 v3s16(0,0,-1),
882                                 v3s16(1,0,0),
883                                 v3s16(-1,0,0),
884                                 v3s16(1,0,1),
885                                 v3s16(-1,0,-1),
886                                 v3s16(1,0,-1),
887                                 v3s16(-1,0,1),
888                         };
889                         for(u32 i=0; i<9; i++)
890                         {
891                                 u8 content = CONTENT_AIR;
892                                 float level = -0.5 * BS;
893                                 u8 flags = 0;
894                                 try{
895                                         // Check neighbor
896                                         v3s16 p2 = p + neighbor_dirs[i];
897                                         MapNode n2 = getNodeParent(p2);
898
899                                         content = n2.d;
900
901                                         if(n2.d == CONTENT_WATERSOURCE)
902                                                 level = (-0.5+node_water_level) * BS;
903                                         else if(n2.d == CONTENT_WATER)
904                                                 level = (-0.5 + ((float)n2.param2 + 0.5) / 8.0
905                                                                 * node_water_level) * BS;
906
907                                         // Check node above neighbor.
908                                         // NOTE: This doesn't get executed if neighbor
909                                         //       doesn't exist
910                                         p2.Y += 1;
911                                         n2 = getNodeParent(p2);
912                                         if(n2.d == CONTENT_WATERSOURCE || n2.d == CONTENT_WATER)
913                                                 flags |= neighborflag_top_is_water;
914                                 }
915                                 catch(InvalidPositionException &e){}
916                                 
917                                 neighbor_levels.insert(neighbor_dirs[i], level);
918                                 neighbor_contents.insert(neighbor_dirs[i], content);
919                                 neighbor_flags.insert(neighbor_dirs[i], flags);
920                         }
921
922                         //float water_level = (-0.5 + ((float)n.param2 + 0.5) / 8.0) * BS;
923                         //float water_level = neighbor_levels[v3s16(0,0,0)];
924
925                         // Corner heights (average between four waters)
926                         f32 corner_levels[4];
927                         
928                         v3s16 halfdirs[4] = {
929                                 v3s16(0,0,0),
930                                 v3s16(1,0,0),
931                                 v3s16(1,0,1),
932                                 v3s16(0,0,1),
933                         };
934                         for(u32 i=0; i<4; i++)
935                         {
936                                 v3s16 cornerdir = halfdirs[i];
937                                 float cornerlevel = 0;
938                                 u32 valid_count = 0;
939                                 for(u32 j=0; j<4; j++)
940                                 {
941                                         v3s16 neighbordir = cornerdir - halfdirs[j];
942                                         u8 content = neighbor_contents[neighbordir];
943                                         // Special case for source nodes
944                                         if(content == CONTENT_WATERSOURCE)
945                                         {
946                                                 cornerlevel = (-0.5+node_water_level)*BS;
947                                                 valid_count = 1;
948                                                 break;
949                                         }
950                                         else if(content == CONTENT_WATER)
951                                         {
952                                                 cornerlevel += neighbor_levels[neighbordir];
953                                                 valid_count++;
954                                         }
955                                         else if(content == CONTENT_AIR)
956                                         {
957                                                 cornerlevel += -0.5*BS;
958                                                 valid_count++;
959                                         }
960                                 }
961                                 if(valid_count > 0)
962                                         cornerlevel /= valid_count;
963                                 corner_levels[i] = cornerlevel;
964                         }
965
966                         /*
967                                 Generate sides
968                         */
969
970                         v3s16 side_dirs[4] = {
971                                 v3s16(1,0,0),
972                                 v3s16(-1,0,0),
973                                 v3s16(0,0,1),
974                                 v3s16(0,0,-1),
975                         };
976                         s16 side_corners[4][2] = {
977                                 {1, 2},
978                                 {3, 0},
979                                 {2, 3},
980                                 {0, 1},
981                         };
982                         for(u32 i=0; i<4; i++)
983                         {
984                                 v3s16 dir = side_dirs[i];
985
986                                 /*
987                                         If our topside is water and neighbor's topside
988                                         is water, don't draw side face
989                                 */
990                                 if(top_is_water &&
991                                                 neighbor_flags[dir] & neighborflag_top_is_water)
992                                         continue;
993
994                                 u8 neighbor_content = neighbor_contents[dir];
995                                 
996                                 // Don't draw face if neighbor is not air or water
997                                 if(neighbor_content != CONTENT_AIR
998                                                 && neighbor_content != CONTENT_WATER)
999                                         continue;
1000                                 
1001                                 bool neighbor_is_water = (neighbor_content == CONTENT_WATER);
1002                                 
1003                                 // Don't draw any faces if neighbor is water and top is water
1004                                 if(neighbor_is_water == true && top_is_water == false)
1005                                         continue;
1006                                 
1007                                 video::S3DVertex vertices[4] =
1008                                 {
1009                                         /*video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
1010                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,1),
1011                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
1012                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
1013                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
1014                                                         pa_water1.x0(), pa_water1.y1()),
1015                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
1016                                                         pa_water1.x1(), pa_water1.y1()),
1017                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
1018                                                         pa_water1.x1(), pa_water1.y0()),
1019                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
1020                                                         pa_water1.x0(), pa_water1.y0()),
1021                                 };
1022                                 
1023                                 /*
1024                                         If our topside is water, set upper border of face
1025                                         at upper border of node
1026                                 */
1027                                 if(top_is_water)
1028                                 {
1029                                         vertices[2].Pos.Y = 0.5*BS;
1030                                         vertices[3].Pos.Y = 0.5*BS;
1031                                 }
1032                                 /*
1033                                         Otherwise upper position of face is corner levels
1034                                 */
1035                                 else
1036                                 {
1037                                         vertices[2].Pos.Y = corner_levels[side_corners[i][0]];
1038                                         vertices[3].Pos.Y = corner_levels[side_corners[i][1]];
1039                                 }
1040                                 
1041                                 /*
1042                                         If neighbor is water, lower border of face is corner
1043                                         water levels
1044                                 */
1045                                 if(neighbor_is_water)
1046                                 {
1047                                         vertices[0].Pos.Y = corner_levels[side_corners[i][1]];
1048                                         vertices[1].Pos.Y = corner_levels[side_corners[i][0]];
1049                                 }
1050                                 /*
1051                                         If neighbor is not water, lower border of face is
1052                                         lower border of node
1053                                 */
1054                                 else
1055                                 {
1056                                         vertices[0].Pos.Y = -0.5*BS;
1057                                         vertices[1].Pos.Y = -0.5*BS;
1058                                 }
1059                                 
1060                                 for(s32 j=0; j<4; j++)
1061                                 {
1062                                         if(dir == v3s16(0,0,1))
1063                                                 vertices[j].Pos.rotateXZBy(0);
1064                                         if(dir == v3s16(0,0,-1))
1065                                                 vertices[j].Pos.rotateXZBy(180);
1066                                         if(dir == v3s16(-1,0,0))
1067                                                 vertices[j].Pos.rotateXZBy(90);
1068                                         if(dir == v3s16(1,0,-0))
1069                                                 vertices[j].Pos.rotateXZBy(-90);
1070
1071                                         vertices[j].Pos += intToFloat(p + getPosRelative(), BS);
1072                                 }
1073
1074                                 u16 indices[] = {0,1,2,2,3,0};
1075                                 // Add to mesh collector
1076                                 collector.append(material_water1, vertices, 4, indices, 6);
1077                         }
1078                         
1079                         /*
1080                                 Generate top side, if appropriate
1081                         */
1082                         
1083                         if(top_is_water == false)
1084                         {
1085                                 video::S3DVertex vertices[4] =
1086                                 {
1087                                         /*video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
1088                                         video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1),
1089                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
1090                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
1091                                         video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
1092                                                         pa_water1.x0(), pa_water1.y1()),
1093                                         video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
1094                                                         pa_water1.x1(), pa_water1.y1()),
1095                                         video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
1096                                                         pa_water1.x1(), pa_water1.y0()),
1097                                         video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
1098                                                         pa_water1.x0(), pa_water1.y0()),
1099                                 };
1100                                 
1101                                 // This fixes a strange bug
1102                                 s32 corner_resolve[4] = {3,2,1,0};
1103
1104                                 for(s32 i=0; i<4; i++)
1105                                 {
1106                                         //vertices[i].Pos.Y += water_level;
1107                                         //vertices[i].Pos.Y += neighbor_levels[v3s16(0,0,0)];
1108                                         s32 j = corner_resolve[i];
1109                                         vertices[i].Pos.Y += corner_levels[j];
1110                                         vertices[i].Pos += intToFloat(p + getPosRelative(), BS);
1111                                 }
1112
1113                                 u16 indices[] = {0,1,2,2,3,0};
1114                                 // Add to mesh collector
1115                                 collector.append(material_water1, vertices, 4, indices, 6);
1116                         }
1117                 }
1118                 /*
1119                         Add water sources to mesh if using new style
1120                 */
1121                 else if(n.d == CONTENT_WATERSOURCE && new_style_water)
1122                 {
1123                         //bool top_is_water = false;
1124                         bool top_is_air = false;
1125                         try{
1126                                 MapNode n = getNodeParent(v3s16(x,y+1,z));
1127                                 /*if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE)
1128                                         top_is_water = true;*/
1129                                 if(n.d == CONTENT_AIR)
1130                                         top_is_air = true;
1131                         }catch(InvalidPositionException &e){}
1132                         
1133                         /*if(top_is_water == true)
1134                                 continue;*/
1135                         if(top_is_air == false)
1136                                 continue;
1137
1138                         u8 l = decode_light(n.getLightBlend(daynight_ratio));
1139                         video::SColor c(WATER_ALPHA,l,l,l);
1140                         
1141                         video::S3DVertex vertices[4] =
1142                         {
1143                                 /*video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
1144                                 video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1),
1145                                 video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
1146                                 video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/
1147                                 video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
1148                                                 pa_water1.x0(), pa_water1.y1()),
1149                                 video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
1150                                                 pa_water1.x1(), pa_water1.y1()),
1151                                 video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
1152                                                 pa_water1.x1(), pa_water1.y0()),
1153                                 video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
1154                                                 pa_water1.x0(), pa_water1.y0()),
1155                         };
1156
1157                         for(s32 i=0; i<4; i++)
1158                         {
1159                                 vertices[i].Pos.Y += (-0.5+node_water_level)*BS;
1160                                 vertices[i].Pos += intToFloat(p + getPosRelative(), BS);
1161                         }
1162
1163                         u16 indices[] = {0,1,2,2,3,0};
1164                         // Add to mesh collector
1165                         collector.append(material_water1, vertices, 4, indices, 6);
1166                 }
1167                 /*
1168                         Add leaves if using new style
1169                 */
1170                 else if(n.d == CONTENT_LEAVES && new_style_leaves)
1171                 {
1172                         /*u8 l = decode_light(n.getLightBlend(daynight_ratio));*/
1173                         u8 l = decode_light(undiminish_light(n.getLightBlend(daynight_ratio)));
1174                         video::SColor c(255,l,l,l);
1175
1176                         for(u32 j=0; j<6; j++)
1177                         {
1178                                 video::S3DVertex vertices[4] =
1179                                 {
1180                                         /*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
1181                                         video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1),
1182                                         video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0),
1183                                         video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),*/
1184                                         video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
1185                                                 pa_leaves1.x0(), pa_leaves1.y1()),
1186                                         video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
1187                                                 pa_leaves1.x1(), pa_leaves1.y1()),
1188                                         video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
1189                                                 pa_leaves1.x1(), pa_leaves1.y0()),
1190                                         video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
1191                                                 pa_leaves1.x0(), pa_leaves1.y0()),
1192                                 };
1193
1194                                 if(j == 0)
1195                                 {
1196                                         for(u16 i=0; i<4; i++)
1197                                                 vertices[i].Pos.rotateXZBy(0);
1198                                 }
1199                                 else if(j == 1)
1200                                 {
1201                                         for(u16 i=0; i<4; i++)
1202                                                 vertices[i].Pos.rotateXZBy(180);
1203                                 }
1204                                 else if(j == 2)
1205                                 {
1206                                         for(u16 i=0; i<4; i++)
1207                                                 vertices[i].Pos.rotateXZBy(-90);
1208                                 }
1209                                 else if(j == 3)
1210                                 {
1211                                         for(u16 i=0; i<4; i++)
1212                                                 vertices[i].Pos.rotateXZBy(90);
1213                                 }
1214                                 else if(j == 4)
1215                                 {
1216                                         for(u16 i=0; i<4; i++)
1217                                                 vertices[i].Pos.rotateYZBy(-90);
1218                                 }
1219                                 else if(j == 5)
1220                                 {
1221                                         for(u16 i=0; i<4; i++)
1222                                                 vertices[i].Pos.rotateYZBy(90);
1223                                 }
1224
1225                                 for(u16 i=0; i<4; i++)
1226                                 {
1227                                         vertices[i].Pos += intToFloat(p + getPosRelative(), BS);
1228                                 }
1229
1230                                 u16 indices[] = {0,1,2,2,3,0};
1231                                 // Add to mesh collector
1232                                 collector.append(material_leaves1, vertices, 4, indices, 6);
1233                         }
1234                 }
1235         }
1236
1237         /*
1238                 Add stuff from collector to mesh
1239         */
1240         
1241         scene::SMesh *mesh_new = NULL;
1242         mesh_new = new scene::SMesh();
1243         
1244         collector.fillMesh(mesh_new);
1245
1246         /*
1247                 Do some stuff to the mesh
1248         */
1249
1250         mesh_new->recalculateBoundingBox();
1251
1252         /*
1253                 Delete new mesh if it is empty
1254         */
1255
1256         if(mesh_new->getMeshBufferCount() == 0)
1257         {
1258                 mesh_new->drop();
1259                 mesh_new = NULL;
1260         }
1261
1262         if(mesh_new)
1263         {
1264 #if 0
1265                 // Usually 1-700 faces and 1-7 materials
1266                 std::cout<<"Updated MapBlock has "<<fastfaces_new.size()<<" faces "
1267                                 <<"and uses "<<mesh_new->getMeshBufferCount()
1268                                 <<" materials (meshbuffers)"<<std::endl;
1269 #endif
1270
1271                 // Use VBO for mesh (this just would set this for ever buffer)
1272                 // This will lead to infinite memory usage because or irrlicht.
1273                 //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
1274
1275                 /*
1276                         NOTE: If that is enabled, some kind of a queue to the main
1277                         thread should be made which would call irrlicht to delete
1278                         the hardware buffer and then delete the mesh
1279                 */
1280         }
1281         
1282         /*
1283                 Replace the mesh
1284         */
1285
1286         mesh_mutex.Lock();
1287
1288         //scene::SMesh *mesh_old = mesh[daynight_i];
1289         //mesh[daynight_i] = mesh_new;
1290
1291         scene::SMesh *mesh_old = mesh;
1292         mesh = mesh_new;
1293         setMeshExpired(false);
1294         
1295         if(mesh_old != NULL)
1296         {
1297                 // Remove hardware buffers of meshbuffers of mesh
1298                 // NOTE: No way, this runs in a different thread and everything
1299                 /*u32 c = mesh_old->getMeshBufferCount();
1300                 for(u32 i=0; i<c; i++)
1301                 {
1302                         IMeshBuffer *buf = mesh_old->getMeshBuffer(i);
1303                 }*/
1304                 
1305                 /*dstream<<"mesh_old->getReferenceCount()="
1306                                 <<mesh_old->getReferenceCount()<<std::endl;
1307                 u32 c = mesh_old->getMeshBufferCount();
1308                 for(u32 i=0; i<c; i++)
1309                 {
1310                         scene::IMeshBuffer *buf = mesh_old->getMeshBuffer(i);
1311                         dstream<<"buf->getReferenceCount()="
1312                                         <<buf->getReferenceCount()<<std::endl;
1313                 }*/
1314
1315                 // Drop the mesh
1316                 mesh_old->drop();
1317
1318                 //delete mesh_old;
1319         }
1320
1321         mesh_mutex.Unlock();
1322         
1323         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
1324 }
1325
1326 /*void MapBlock::updateMeshes(s32 first_i)
1327 {
1328         assert(first_i >= 0 && first_i <= DAYNIGHT_CACHE_COUNT);
1329         updateMesh(first_i);
1330         for(s32 i=0; i<DAYNIGHT_CACHE_COUNT; i++)
1331         {
1332                 if(i == first_i)
1333                         continue;
1334                 updateMesh(i);
1335         }
1336 }*/
1337
1338 #endif // !SERVER
1339
1340 /*
1341         Propagates sunlight down through the block.
1342         Doesn't modify nodes that are not affected by sunlight.
1343         
1344         Returns false if sunlight at bottom block is invalid
1345         Returns true if bottom block doesn't exist.
1346
1347         If there is a block above, continues from it.
1348         If there is no block above, assumes there is sunlight, unless
1349         is_underground is set or highest node is water.
1350
1351         At the moment, all sunlighted nodes are added to light_sources.
1352         - SUGG: This could be optimized
1353
1354         Turns sunglighted mud into grass.
1355
1356         if remove_light==true, sets non-sunlighted nodes black.
1357
1358         if black_air_left!=NULL, it is set to true if non-sunlighted
1359         air is left in block.
1360 */
1361 bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources,
1362                 bool remove_light, bool *black_air_left,
1363                 bool grow_grass)
1364 {
1365         // Whether the sunlight at the top of the bottom block is valid
1366         bool block_below_is_valid = true;
1367         
1368         v3s16 pos_relative = getPosRelative();
1369         
1370         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
1371         {
1372                 for(s16 z=0; z<MAP_BLOCKSIZE; z++)
1373                 {
1374 #if 1
1375                         bool no_sunlight = false;
1376                         bool no_top_block = false;
1377                         // Check if node above block has sunlight
1378                         try{
1379                                 MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z));
1380                                 if(n.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
1381                                 {
1382                                         no_sunlight = true;
1383                                 }
1384                         }
1385                         catch(InvalidPositionException &e)
1386                         {
1387                                 no_top_block = true;
1388                                 
1389                                 // NOTE: This makes over-ground roofed places sunlighted
1390                                 // Assume sunlight, unless is_underground==true
1391                                 if(is_underground)
1392                                 {
1393                                         no_sunlight = true;
1394                                 }
1395                                 else
1396                                 {
1397                                         MapNode n = getNode(v3s16(x, MAP_BLOCKSIZE-1, z));
1398                                         if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE)
1399                                         {
1400                                                 no_sunlight = true;
1401                                         }
1402                                 }
1403                                 // NOTE: As of now, this just would make everything dark.
1404                                 // No sunlight here
1405                                 //no_sunlight = true;
1406                         }
1407 #endif
1408 #if 0 // Doesn't work; nothing gets light.
1409                         bool no_sunlight = true;
1410                         bool no_top_block = false;
1411                         // Check if node above block has sunlight
1412                         try{
1413                                 MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z));
1414                                 if(n.getLight(LIGHTBANK_DAY) == LIGHT_SUN)
1415                                 {
1416                                         no_sunlight = false;
1417                                 }
1418                         }
1419                         catch(InvalidPositionException &e)
1420                         {
1421                                 no_top_block = true;
1422                         }
1423 #endif
1424
1425                         /*std::cout<<"("<<x<<","<<z<<"): "
1426                                         <<"no_top_block="<<no_top_block
1427                                         <<", is_underground="<<is_underground
1428                                         <<", no_sunlight="<<no_sunlight
1429                                         <<std::endl;*/
1430                 
1431                         s16 y = MAP_BLOCKSIZE-1;
1432                         
1433                         // This makes difference to diminishing in water.
1434                         bool stopped_to_solid_object = false;
1435                         
1436                         u8 current_light = no_sunlight ? 0 : LIGHT_SUN;
1437
1438                         for(; y >= 0; y--)
1439                         {
1440                                 v3s16 pos(x, y, z);
1441                                 MapNode &n = getNodeRef(pos);
1442                                 
1443                                 if(current_light == 0)
1444                                 {
1445                                         // Do nothing
1446                                 }
1447                                 else if(current_light == LIGHT_SUN && n.sunlight_propagates())
1448                                 {
1449                                         // Do nothing: Sunlight is continued
1450                                 }
1451                                 else if(n.light_propagates() == false)
1452                                 {
1453                                         if(grow_grass)
1454                                         {
1455                                                 bool upper_is_air = false;
1456                                                 try
1457                                                 {
1458                                                         if(getNodeParent(pos+v3s16(0,1,0)).d == CONTENT_AIR)
1459                                                                 upper_is_air = true;
1460                                                 }
1461                                                 catch(InvalidPositionException &e)
1462                                                 {
1463                                                 }
1464                                                 // Turn mud into grass
1465                                                 if(upper_is_air && n.d == CONTENT_MUD
1466                                                                 && current_light == LIGHT_SUN)
1467                                                 {
1468                                                         n.d = CONTENT_GRASS;
1469                                                 }
1470                                         }
1471
1472                                         // A solid object is on the way.
1473                                         stopped_to_solid_object = true;
1474                                         
1475                                         // Light stops.
1476                                         current_light = 0;
1477                                 }
1478                                 else
1479                                 {
1480                                         // Diminish light
1481                                         current_light = diminish_light(current_light);
1482                                 }
1483
1484                                 u8 old_light = n.getLight(LIGHTBANK_DAY);
1485
1486                                 if(current_light > old_light || remove_light)
1487                                 {
1488                                         n.setLight(LIGHTBANK_DAY, current_light);
1489                                 }
1490                                 
1491                                 if(diminish_light(current_light) != 0)
1492                                 {
1493                                         light_sources.insert(pos_relative + pos, true);
1494                                 }
1495
1496                                 if(current_light == 0 && stopped_to_solid_object)
1497                                 {
1498                                         if(black_air_left)
1499                                         {
1500                                                 *black_air_left = true;
1501                                         }
1502                                 }
1503                         }
1504
1505                         // Whether or not the block below should see LIGHT_SUN
1506                         bool sunlight_should_go_down = (current_light == LIGHT_SUN);
1507
1508                         /*
1509                                 If the block below hasn't already been marked invalid:
1510
1511                                 Check if the node below the block has proper sunlight at top.
1512                                 If not, the block below is invalid.
1513                                 
1514                                 Ignore non-transparent nodes as they always have no light
1515                         */
1516                         try
1517                         {
1518                         if(block_below_is_valid)
1519                         {
1520                                 MapNode n = getNodeParent(v3s16(x, -1, z));
1521                                 if(n.light_propagates())
1522                                 {
1523                                         if(n.getLight(LIGHTBANK_DAY) == LIGHT_SUN
1524                                                         && sunlight_should_go_down == false)
1525                                                 block_below_is_valid = false;
1526                                         else if(n.getLight(LIGHTBANK_DAY) != LIGHT_SUN
1527                                                         && sunlight_should_go_down == true)
1528                                                 block_below_is_valid = false;
1529                                 }
1530                         }//if
1531                         }//try
1532                         catch(InvalidPositionException &e)
1533                         {
1534                                 /*std::cout<<"InvalidBlockException for bottom block node"
1535                                                 <<std::endl;*/
1536                                 // Just no block below, no need to panic.
1537                         }
1538                 }
1539         }
1540
1541         return block_below_is_valid;
1542 }
1543
1544 void MapBlock::copyTo(VoxelManipulator &dst)
1545 {
1546         v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
1547         VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
1548         
1549         // Copy from data to VoxelManipulator
1550         dst.copyFrom(data, data_area, v3s16(0,0,0),
1551                         getPosRelative(), data_size);
1552 }
1553
1554 void MapBlock::copyFrom(VoxelManipulator &dst)
1555 {
1556         v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
1557         VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
1558         
1559         // Copy from VoxelManipulator to data
1560         dst.copyTo(data, data_area, v3s16(0,0,0),
1561                         getPosRelative(), data_size);
1562 }
1563
1564 void MapBlock::stepObjects(float dtime, bool server, u32 daynight_ratio)
1565 {
1566         /*
1567                 Step objects
1568         */
1569         m_objects.step(dtime, server, daynight_ratio);
1570         
1571         /*
1572                 Spawn some objects at random.
1573
1574                 Use dayNightDiffed() to approximate being near ground level
1575         */
1576         if(m_spawn_timer < -999)
1577         {
1578                 m_spawn_timer = 60;
1579         }
1580         if(dayNightDiffed() == true && getObjectCount() == 0)
1581         {
1582                 m_spawn_timer -= dtime;
1583                 if(m_spawn_timer <= 0.0)
1584                 {
1585                         m_spawn_timer += myrand() % 300;
1586                         
1587                         v2s16 p2d(
1588                                 (myrand()%(MAP_BLOCKSIZE-1))+0,
1589                                 (myrand()%(MAP_BLOCKSIZE-1))+0
1590                         );
1591
1592                         s16 y = getGroundLevel(p2d);
1593                         
1594                         if(y >= 0)
1595                         {
1596                                 v3s16 p(p2d.X, y+1, p2d.Y);
1597
1598                                 if(getNode(p).d == CONTENT_AIR
1599                                                 && getNode(p).getLightBlend(daynight_ratio) <= 11)
1600                                 {
1601                                         RatObject *obj = new RatObject(NULL, -1, intToFloat(p, BS));
1602                                         addObject(obj);
1603                                 }
1604                         }
1605                 }
1606         }
1607
1608         setChangedFlag();
1609 }
1610
1611
1612 void MapBlock::updateDayNightDiff()
1613 {
1614         if(data == NULL)
1615         {
1616                 m_day_night_differs = false;
1617                 return;
1618         }
1619
1620         bool differs = false;
1621
1622         /*
1623                 Check if any lighting value differs
1624         */
1625         for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
1626         {
1627                 MapNode &n = data[i];
1628                 if(n.getLight(LIGHTBANK_DAY) != n.getLight(LIGHTBANK_NIGHT))
1629                 {
1630                         differs = true;
1631                         break;
1632                 }
1633         }
1634
1635         /*
1636                 If some lighting values differ, check if the whole thing is
1637                 just air. If it is, differ = false
1638         */
1639         if(differs)
1640         {
1641                 bool only_air = true;
1642                 for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
1643                 {
1644                         MapNode &n = data[i];
1645                         if(n.d != CONTENT_AIR)
1646                         {
1647                                 only_air = false;
1648                                 break;
1649                         }
1650                 }
1651                 if(only_air)
1652                         differs = false;
1653         }
1654
1655         // Set member variable
1656         m_day_night_differs = differs;
1657 }
1658
1659 s16 MapBlock::getGroundLevel(v2s16 p2d)
1660 {
1661         if(isDummy())
1662                 return -3;
1663         try
1664         {
1665                 s16 y = MAP_BLOCKSIZE-1;
1666                 for(; y>=0; y--)
1667                 {
1668                         //if(is_ground_content(getNodeRef(p2d.X, y, p2d.Y).d))
1669                         if(content_features(getNodeRef(p2d.X, y, p2d.Y).d).walkable)
1670                         {
1671                                 if(y == MAP_BLOCKSIZE-1)
1672                                         return -2;
1673                                 else
1674                                         return y;
1675                         }
1676                 }
1677                 return -1;
1678         }
1679         catch(InvalidPositionException &e)
1680         {
1681                 return -3;
1682         }
1683 }
1684
1685 /*
1686         Serialization
1687 */
1688
1689 void MapBlock::serialize(std::ostream &os, u8 version)
1690 {
1691         if(!ser_ver_supported(version))
1692                 throw VersionMismatchException("ERROR: MapBlock format not supported");
1693         
1694         if(data == NULL)
1695         {
1696                 throw SerializationError("ERROR: Not writing dummy block.");
1697         }
1698         
1699         // These have no compression
1700         if(version <= 3 || version == 5 || version == 6)
1701         {
1702                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1703                 
1704                 u32 buflen = 1 + nodecount * MapNode::serializedLength(version);
1705                 SharedBuffer<u8> dest(buflen);
1706
1707                 dest[0] = is_underground;
1708                 for(u32 i=0; i<nodecount; i++)
1709                 {
1710                         u32 s = 1 + i * MapNode::serializedLength(version);
1711                         data[i].serialize(&dest[s], version);
1712                 }
1713                 
1714                 os.write((char*)*dest, dest.getSize());
1715         }
1716         else if(version <= 10)
1717         {
1718                 /*
1719                         With compression.
1720                         Compress the materials and the params separately.
1721                 */
1722                 
1723                 // First byte
1724                 os.write((char*)&is_underground, 1);
1725
1726                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1727
1728                 // Get and compress materials
1729                 SharedBuffer<u8> materialdata(nodecount);
1730                 for(u32 i=0; i<nodecount; i++)
1731                 {
1732                         materialdata[i] = data[i].d;
1733                 }
1734                 compress(materialdata, os, version);
1735
1736                 // Get and compress lights
1737                 SharedBuffer<u8> lightdata(nodecount);
1738                 for(u32 i=0; i<nodecount; i++)
1739                 {
1740                         lightdata[i] = data[i].param;
1741                 }
1742                 compress(lightdata, os, version);
1743                 
1744                 if(version >= 10)
1745                 {
1746                         // Get and compress param2
1747                         SharedBuffer<u8> param2data(nodecount);
1748                         for(u32 i=0; i<nodecount; i++)
1749                         {
1750                                 param2data[i] = data[i].param2;
1751                         }
1752                         compress(param2data, os, version);
1753                 }
1754         }
1755         // All other versions (newest)
1756         else
1757         {
1758                 // First byte
1759                 u8 flags = 0;
1760                 if(is_underground)
1761                         flags |= 0x01;
1762                 if(m_day_night_differs)
1763                         flags |= 0x02;
1764                 if(m_lighting_expired)
1765                         flags |= 0x04;
1766                 if(m_not_fully_generated)
1767                         flags |= 0x08;
1768                 os.write((char*)&flags, 1);
1769
1770                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1771
1772                 /*
1773                         Get data
1774                 */
1775
1776                 SharedBuffer<u8> databuf(nodecount*3);
1777
1778                 // Get contents
1779                 for(u32 i=0; i<nodecount; i++)
1780                 {
1781                         databuf[i] = data[i].d;
1782                 }
1783
1784                 // Get params
1785                 for(u32 i=0; i<nodecount; i++)
1786                 {
1787                         databuf[i+nodecount] = data[i].param;
1788                 }
1789
1790                 // Get param2
1791                 for(u32 i=0; i<nodecount; i++)
1792                 {
1793                         databuf[i+nodecount*2] = data[i].param2;
1794                 }
1795
1796                 /*
1797                         Compress data to output stream
1798                 */
1799
1800                 compress(databuf, os, version);
1801         }
1802 }
1803
1804 void MapBlock::deSerialize(std::istream &is, u8 version)
1805 {
1806         if(!ser_ver_supported(version))
1807                 throw VersionMismatchException("ERROR: MapBlock format not supported");
1808
1809         // These have no compression
1810         if(version <= 3 || version == 5 || version == 6)
1811         {
1812                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1813                 char tmp;
1814                 is.read(&tmp, 1);
1815                 if(is.gcount() != 1)
1816                         throw SerializationError
1817                                         ("MapBlock::deSerialize: no enough input data");
1818                 is_underground = tmp;
1819                 for(u32 i=0; i<nodecount; i++)
1820                 {
1821                         s32 len = MapNode::serializedLength(version);
1822                         SharedBuffer<u8> d(len);
1823                         is.read((char*)*d, len);
1824                         if(is.gcount() != len)
1825                                 throw SerializationError
1826                                                 ("MapBlock::deSerialize: no enough input data");
1827                         data[i].deSerialize(*d, version);
1828                 }
1829         }
1830         else if(version <= 10)
1831         {
1832                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1833
1834                 u8 t8;
1835                 is.read((char*)&t8, 1);
1836                 is_underground = t8;
1837
1838                 {
1839                         // Uncompress and set material data
1840                         std::ostringstream os(std::ios_base::binary);
1841                         decompress(is, os, version);
1842                         std::string s = os.str();
1843                         if(s.size() != nodecount)
1844                                 throw SerializationError
1845                                                 ("MapBlock::deSerialize: invalid format");
1846                         for(u32 i=0; i<s.size(); i++)
1847                         {
1848                                 data[i].d = s[i];
1849                         }
1850                 }
1851                 {
1852                         // Uncompress and set param data
1853                         std::ostringstream os(std::ios_base::binary);
1854                         decompress(is, os, version);
1855                         std::string s = os.str();
1856                         if(s.size() != nodecount)
1857                                 throw SerializationError
1858                                                 ("MapBlock::deSerialize: invalid format");
1859                         for(u32 i=0; i<s.size(); i++)
1860                         {
1861                                 data[i].param = s[i];
1862                         }
1863                 }
1864         
1865                 if(version >= 10)
1866                 {
1867                         // Uncompress and set param2 data
1868                         std::ostringstream os(std::ios_base::binary);
1869                         decompress(is, os, version);
1870                         std::string s = os.str();
1871                         if(s.size() != nodecount)
1872                                 throw SerializationError
1873                                                 ("MapBlock::deSerialize: invalid format");
1874                         for(u32 i=0; i<s.size(); i++)
1875                         {
1876                                 data[i].param2 = s[i];
1877                         }
1878                 }
1879         }
1880         // All other versions (newest)
1881         else
1882         {
1883                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1884
1885                 u8 flags;
1886                 is.read((char*)&flags, 1);
1887                 is_underground = (flags & 0x01) ? true : false;
1888                 m_day_night_differs = (flags & 0x02) ? true : false;
1889                 m_lighting_expired = (flags & 0x04) ? true : false;
1890                 m_not_fully_generated = (flags & 0x08) ? true : false;
1891
1892                 // Uncompress data
1893                 std::ostringstream os(std::ios_base::binary);
1894                 decompress(is, os, version);
1895                 std::string s = os.str();
1896                 if(s.size() != nodecount*3)
1897                         throw SerializationError
1898                                         ("MapBlock::deSerialize: invalid format");
1899
1900                 // Set contents
1901                 for(u32 i=0; i<nodecount; i++)
1902                 {
1903                         data[i].d = s[i];
1904                 }
1905                 // Set params
1906                 for(u32 i=0; i<nodecount; i++)
1907                 {
1908                         data[i].param = s[i+nodecount];
1909                 }
1910                 // Set param2
1911                 for(u32 i=0; i<nodecount; i++)
1912                 {
1913                         data[i].param2 = s[i+nodecount*2];
1914                 }
1915         }
1916         
1917         /*
1918                 Translate nodes as specified in the translate_to fields of
1919                 node features
1920         */
1921         for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
1922         {
1923                 MapNode &n = data[i];
1924
1925                 MapNode *translate_to = content_features(n.d).translate_to;
1926                 if(translate_to)
1927                 {
1928                         dstream<<"MapBlock: WARNING: Translating node "<<n.d<<" to "
1929                                         <<translate_to->d<<std::endl;
1930                         n = *translate_to;
1931                 }
1932         }
1933 }
1934
1935
1936 //END