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