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