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