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