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