]> git.lizzy.rs Git - minetest.git/blob - src/mapblock.cpp
added dedicated server build without irrlicht
[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_materials
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 #ifndef SERVER
45         m_mesh_expired = false;
46         mesh_mutex.Init();
47         mesh = NULL;
48 #endif
49 }
50
51 MapBlock::~MapBlock()
52 {
53 #ifndef SERVER
54         {
55                 JMutexAutoLock lock(mesh_mutex);
56                 
57                 if(mesh)
58                 {
59                         mesh->drop();
60                         mesh = NULL;
61                 }
62         }
63 #endif
64
65         if(data)
66                 delete[] data;
67 }
68
69 bool MapBlock::isValidPositionParent(v3s16 p)
70 {
71         if(isValidPosition(p))
72         {
73                 return true;
74         }
75         else{
76                 return m_parent->isValidPosition(getPosRelative() + p);
77         }
78 }
79
80 MapNode MapBlock::getNodeParent(v3s16 p)
81 {
82         if(isValidPosition(p) == false)
83         {
84                 return m_parent->getNode(getPosRelative() + p);
85         }
86         else
87         {
88                 if(data == NULL)
89                         throw InvalidPositionException();
90                 return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X];
91         }
92 }
93
94 void MapBlock::setNodeParent(v3s16 p, MapNode & n)
95 {
96         if(isValidPosition(p) == false)
97         {
98                 m_parent->setNode(getPosRelative() + p, n);
99         }
100         else
101         {
102                 if(data == NULL)
103                         throw InvalidPositionException();
104                 data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X] = n;
105         }
106 }
107
108 MapNode MapBlock::getNodeParentNoEx(v3s16 p)
109 {
110         if(isValidPosition(p) == false)
111         {
112                 try{
113                         return m_parent->getNode(getPosRelative() + p);
114                 }
115                 catch(InvalidPositionException &e)
116                 {
117                         return MapNode(CONTENT_IGNORE);
118                 }
119         }
120         else
121         {
122                 if(data == NULL)
123                 {
124                         return MapNode(CONTENT_IGNORE);
125                 }
126                 return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X];
127         }
128 }
129
130 /*
131         Parameters must consist of air and !air.
132         Order doesn't matter.
133
134         If either of the nodes doesn't exist, light is 0.
135         
136         parameters:
137                 daynight_ratio: 0...1000
138                 n: getNodeParent(p)
139                 n2: getNodeParent(p + face_dir)
140                 face_dir: axis oriented unit vector from p to p2
141 */
142 u8 MapBlock::getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
143                 v3s16 face_dir)
144 {
145         try{
146                 u8 light;
147                 u8 l1 = n.getLightBlend(daynight_ratio);
148                 u8 l2 = n2.getLightBlend(daynight_ratio);
149                 if(l1 > l2)
150                         light = l1;
151                 else
152                         light = l2;
153
154                 // Make some nice difference to different sides
155
156                 /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
157                         light = diminish_light(diminish_light(light));
158                 else if(face_dir.X == -1 || face_dir.Z == -1)
159                         light = diminish_light(light);*/
160
161                 if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
162                         light = diminish_light(diminish_light(light));
163                 else if(face_dir.Z == 1 || face_dir.Z == -1)
164                         light = diminish_light(light);
165
166                 return light;
167         }
168         catch(InvalidPositionException &e)
169         {
170                 return 0;
171         }
172 }
173
174 #ifndef SERVER
175
176 void MapBlock::makeFastFace(TileSpec tile, u8 light, v3f p,
177                 v3s16 dir, v3f scale, v3f posRelative_f,
178                 core::array<FastFace> &dest)
179 {
180         FastFace face;
181         
182         // Position is at the center of the cube.
183         v3f pos = p * BS;
184         posRelative_f *= BS;
185
186         v3f vertex_pos[4];
187         // If looking towards z+, this is the face that is behind
188         // the center point, facing towards z+.
189         vertex_pos[0] = v3f( BS/2,-BS/2,BS/2);
190         vertex_pos[1] = v3f(-BS/2,-BS/2,BS/2);
191         vertex_pos[2] = v3f(-BS/2, BS/2,BS/2);
192         vertex_pos[3] = v3f( BS/2, BS/2,BS/2);
193         
194         if(dir == v3s16(0,0,1))
195         {
196                 for(u16 i=0; i<4; i++)
197                         vertex_pos[i].rotateXZBy(0);
198         }
199         else if(dir == v3s16(0,0,-1))
200         {
201                 for(u16 i=0; i<4; i++)
202                         vertex_pos[i].rotateXZBy(180);
203         }
204         else if(dir == v3s16(1,0,0))
205         {
206                 for(u16 i=0; i<4; i++)
207                         vertex_pos[i].rotateXZBy(-90);
208         }
209         else if(dir == v3s16(-1,0,0))
210         {
211                 for(u16 i=0; i<4; i++)
212                         vertex_pos[i].rotateXZBy(90);
213         }
214         else if(dir == v3s16(0,1,0))
215         {
216                 for(u16 i=0; i<4; i++)
217                         vertex_pos[i].rotateYZBy(-90);
218         }
219         else if(dir == v3s16(0,-1,0))
220         {
221                 for(u16 i=0; i<4; i++)
222                         vertex_pos[i].rotateYZBy(90);
223         }
224
225         for(u16 i=0; i<4; i++)
226         {
227                 vertex_pos[i].X *= scale.X;
228                 vertex_pos[i].Y *= scale.Y;
229                 vertex_pos[i].Z *= scale.Z;
230                 vertex_pos[i] += pos + posRelative_f;
231         }
232
233         f32 abs_scale = 1.;
234         if     (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
235         else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
236         else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
237
238         v3f zerovector = v3f(0,0,0);
239         
240         u8 li = decode_light(light);
241         //u8 li = 150;
242
243         u8 alpha = 255;
244
245         if(tile.id == TILE_WATER)
246         {
247                 alpha = 128;
248         }
249
250         video::SColor c = video::SColor(alpha,li,li,li);
251
252         face.vertices[0] = video::S3DVertex(vertex_pos[0], zerovector, c,
253                         core::vector2d<f32>(0,1));
254         face.vertices[1] = video::S3DVertex(vertex_pos[1], zerovector, c,
255                         core::vector2d<f32>(abs_scale,1));
256         face.vertices[2] = video::S3DVertex(vertex_pos[2], zerovector, c,
257                         core::vector2d<f32>(abs_scale,0));
258         face.vertices[3] = video::S3DVertex(vertex_pos[3], zerovector, c,
259                         core::vector2d<f32>(0,0));
260
261         face.tile = tile;
262         //DEBUG
263         //f->tile = TILE_STONE;
264         
265         dest.push_back(face);
266         //return f;
267 }
268         
269 /*
270         Gets node tile from any place relative to block.
271         Returns TILE_NODE if doesn't exist or should not be drawn.
272 */
273 TileSpec MapBlock::getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir)
274 {
275         TileSpec spec;
276
277         /*//DEBUG
278         {
279                 spec.id = TILE_STONE;
280                 return spec;
281         }*/
282
283         spec.feature = TILEFEAT_NONE;
284         //spec.id = TILE_STONE;
285         spec.id = mn.getTile(face_dir);
286
287         /*
288                 Check temporary modifications on this node
289         */
290         core::map<v3s16, NodeMod>::Node *n;
291         n = m_temp_mods.find(p);
292
293         // If modified
294         if(n != NULL)
295         {
296                 struct NodeMod mod = n->getValue();
297                 if(mod.type == NODEMOD_CHANGECONTENT)
298                 {
299                         spec.id = content_tile(mod.param, face_dir);
300                 }
301                 if(mod.type == NODEMOD_CRACK)
302                 {
303                 }
304         }
305         
306         return spec;
307 }
308
309 u8 MapBlock::getNodeContent(v3s16 p, MapNode mn)
310 {
311         /*
312                 Check temporary modifications on this node
313         */
314         core::map<v3s16, NodeMod>::Node *n;
315         n = m_temp_mods.find(p);
316
317         // If modified
318         if(n != NULL)
319         {
320                 struct NodeMod mod = n->getValue();
321                 if(mod.type == NODEMOD_CHANGECONTENT)
322                 {
323                         // Overrides content
324                         return mod.param;
325                 }
326                 if(mod.type == NODEMOD_CRACK)
327                 {
328                         /*
329                                 Content doesn't change.
330                                 
331                                 face_contents works just like it should, because
332                                 there should not be faces between differently cracked
333                                 nodes.
334
335                                 If a semi-transparent node is cracked in front an
336                                 another one, it really doesn't matter whether there
337                                 is a cracked face drawn in between or not.
338                         */
339                 }
340         }
341
342         return mn.d;
343 }
344
345 /*
346         startpos:
347         translate_dir: unit vector with only one of x, y or z
348         face_dir: unit vector with only one of x, y or z
349 */
350 void MapBlock::updateFastFaceRow(
351                 u32 daynight_ratio,
352                 v3f posRelative_f,
353                 v3s16 startpos,
354                 u16 length,
355                 v3s16 translate_dir,
356                 v3f translate_dir_f,
357                 v3s16 face_dir,
358                 v3f face_dir_f,
359                 core::array<FastFace> &dest)
360 {
361         v3s16 p = startpos;
362         
363         u16 continuous_tiles_count = 0;
364         
365         MapNode n0 = getNodeParentNoEx(p);
366         MapNode n1 = getNodeParentNoEx(p + face_dir);
367
368         u8 light = getFaceLight(daynight_ratio, n0, n1, face_dir);
369                 
370         TileSpec tile0 = getNodeTile(n0, p, face_dir);
371         TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir);
372
373         for(u16 j=0; j<length; j++)
374         {
375                 bool next_is_different = true;
376                 
377                 v3s16 p_next;
378                 MapNode n0_next;
379                 MapNode n1_next;
380                 TileSpec tile0_next;
381                 TileSpec tile1_next;
382                 u8 light_next = 0;
383
384                 if(j != length - 1)
385                 {
386                         p_next = p + translate_dir;
387                         n0_next = getNodeParentNoEx(p_next);
388                         n1_next = getNodeParentNoEx(p_next + face_dir);
389                         tile0_next = getNodeTile(n0_next, p_next, face_dir);
390                         tile1_next = getNodeTile(n1_next, p_next + face_dir, -face_dir);
391                         light_next = getFaceLight(daynight_ratio, n0_next, n1_next, face_dir);
392
393                         if(tile0_next == tile0
394                                         && tile1_next == tile1
395                                         && light_next == light)
396                         {
397                                 next_is_different = false;
398                         }
399                 }
400
401                 continuous_tiles_count++;
402                 
403                 if(next_is_different)
404                 {
405                         /*
406                                 Create a face if there should be one
407                         */
408                         //u8 mf = face_contents(tile0, tile1);
409                         // This is hackish
410                         u8 content0 = getNodeContent(p, n0);
411                         u8 content1 = getNodeContent(p + face_dir, n1);
412                         u8 mf = face_contents(content0, content1);
413                         
414                         if(mf != 0)
415                         {
416                                 // Floating point conversion of the position vector
417                                 v3f pf(p.X, p.Y, p.Z);
418                                 // Center point of face (kind of)
419                                 v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
420                                 v3f scale(1,1,1);
421                                 if(translate_dir.X != 0){
422                                         scale.X = continuous_tiles_count;
423                                 }
424                                 if(translate_dir.Y != 0){
425                                         scale.Y = continuous_tiles_count;
426                                 }
427                                 if(translate_dir.Z != 0){
428                                         scale.Z = continuous_tiles_count;
429                                 }
430                                 
431                                 //FastFace *f;
432
433                                 // If node at sp (tile0) is more solid
434                                 if(mf == 1)
435                                 {
436                                         makeFastFace(tile0, light,
437                                                         sp, face_dir, scale,
438                                                         posRelative_f, dest);
439                                 }
440                                 // If node at sp is less solid (mf == 2)
441                                 else
442                                 {
443                                         makeFastFace(tile1, light,
444                                                         sp+face_dir_f, -face_dir, scale,
445                                                         posRelative_f, dest);
446                                 }
447                                 //dest.push_back(f);
448                         }
449
450                         continuous_tiles_count = 0;
451                         n0 = n0_next;
452                         n1 = n1_next;
453                         tile0 = tile0_next;
454                         tile1 = tile1_next;
455                         light = light_next;
456                 }
457                 
458                 p = p_next;
459         }
460 }
461
462 /*
463         This is used because CMeshBuffer::append() is very slow
464 */
465 struct PreMeshBuffer
466 {
467         video::SMaterial material;
468         core::array<u16> indices;
469         core::array<video::S3DVertex> vertices;
470 };
471
472 class MeshCollector
473 {
474 public:
475         void append(
476                         video::SMaterial material,
477                         const video::S3DVertex* const vertices,
478                         u32 numVertices,
479                         const u16* const indices,
480                         u32 numIndices
481                 )
482         {
483                 PreMeshBuffer *p = NULL;
484                 for(u32 i=0; i<m_prebuffers.size(); i++)
485                 {
486                         PreMeshBuffer &pp = m_prebuffers[i];
487                         if(pp.material != material)
488                                 continue;
489
490                         p = &pp;
491                         break;
492                 }
493
494                 if(p == NULL)
495                 {
496                         PreMeshBuffer pp;
497                         pp.material = material;
498                         m_prebuffers.push_back(pp);
499                         p = &m_prebuffers[m_prebuffers.size()-1];
500                 }
501
502                 u32 vertex_count = p->vertices.size();
503                 for(u32 i=0; i<numIndices; i++)
504                 {
505                         u32 j = indices[i] + vertex_count;
506                         if(j > 65535)
507                         {
508                                 dstream<<"FIXME: Meshbuffer ran out of indices"<<std::endl;
509                                 // NOTE: Fix is to just add an another MeshBuffer
510                         }
511                         p->indices.push_back(j);
512                 }
513                 for(u32 i=0; i<numVertices; i++)
514                 {
515                         p->vertices.push_back(vertices[i]);
516                 }
517         }
518
519         void fillMesh(scene::SMesh *mesh)
520         {
521                 /*dstream<<"Filling mesh with "<<m_prebuffers.size()
522                                 <<" meshbuffers"<<std::endl;*/
523                 for(u32 i=0; i<m_prebuffers.size(); i++)
524                 {
525                         PreMeshBuffer &p = m_prebuffers[i];
526
527                         /*dstream<<"p.vertices.size()="<<p.vertices.size()
528                                         <<", p.indices.size()="<<p.indices.size()
529                                         <<std::endl;*/
530                         
531                         // Create meshbuffer
532                         
533                         // This is a "Standard MeshBuffer",
534                         // it's a typedeffed CMeshBuffer<video::S3DVertex>
535                         scene::SMeshBuffer *buf = new scene::SMeshBuffer();
536                         // Set material
537                         buf->Material = p.material;
538                         //((scene::SMeshBuffer*)buf)->Material = p.material;
539                         // Use VBO
540                         //buf->setHardwareMappingHint(scene::EHM_STATIC);
541                         // Add to mesh
542                         mesh->addMeshBuffer(buf);
543                         // Mesh grabbed it
544                         buf->drop();
545
546                         buf->append(p.vertices.pointer(), p.vertices.size(),
547                                         p.indices.pointer(), p.indices.size());
548                 }
549         }
550
551 private:
552         core::array<PreMeshBuffer> m_prebuffers;
553 };
554
555 void MapBlock::updateMesh(u32 daynight_ratio)
556 {
557 #if 0
558         /*
559                 DEBUG: If mesh has been generated, don't generate it again
560         */
561         {
562                 JMutexAutoLock meshlock(mesh_mutex);
563                 if(mesh != NULL)
564                         return;
565         }
566 #endif
567         
568         // 4-21ms
569         //TimeTaker timer1("updateMesh()", g_device);
570
571         core::array<FastFace> fastfaces_new;
572         
573         v3f posRelative_f(getPosRelative().X, getPosRelative().Y,
574                         getPosRelative().Z); // floating point conversion
575         
576         /*
577                 We are including the faces of the trailing edges of the block.
578                 This means that when something changes, the caller must
579                 also update the meshes of the blocks at the leading edges.
580
581                 NOTE: This is the slowest part of this method.
582         */
583
584         /*
585                 Go through every y,z and get top faces in rows of x+
586         */
587         for(s16 y=0; y<MAP_BLOCKSIZE; y++){
588                 for(s16 z=0; z<MAP_BLOCKSIZE; z++){
589                         updateFastFaceRow(daynight_ratio, posRelative_f,
590                                         v3s16(0,y,z), MAP_BLOCKSIZE,
591                                         v3s16(1,0,0), //dir
592                                         v3f  (1,0,0),
593                                         v3s16(0,1,0), //face dir
594                                         v3f  (0,1,0),
595                                         fastfaces_new);
596                 }
597         }
598         /*
599                 Go through every x,y and get right faces in rows of z+
600         */
601         for(s16 x=0; x<MAP_BLOCKSIZE; x++){
602                 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
603                         updateFastFaceRow(daynight_ratio, posRelative_f,
604                                         v3s16(x,y,0), MAP_BLOCKSIZE,
605                                         v3s16(0,0,1),
606                                         v3f  (0,0,1),
607                                         v3s16(1,0,0),
608                                         v3f  (1,0,0),
609                                         fastfaces_new);
610                 }
611         }
612         /*
613                 Go through every y,z and get back faces in rows of x+
614         */
615         for(s16 z=0; z<MAP_BLOCKSIZE; z++){
616                 for(s16 y=0; y<MAP_BLOCKSIZE; y++){
617                         updateFastFaceRow(daynight_ratio, posRelative_f,
618                                         v3s16(0,y,z), MAP_BLOCKSIZE,
619                                         v3s16(1,0,0),
620                                         v3f  (1,0,0),
621                                         v3s16(0,0,1),
622                                         v3f  (0,0,1),
623                                         fastfaces_new);
624                 }
625         }
626
627         // End of slow part
628
629         /*
630                 Convert FastFaces to SMesh
631         */
632
633         scene::SMesh *mesh_new = NULL;
634         
635         mesh_new = new scene::SMesh();
636         
637         if(fastfaces_new.size() > 0)
638         {
639                 MeshCollector collector;
640
641                 for(u32 i=0; i<fastfaces_new.size(); i++)
642                 {
643                         FastFace &f = fastfaces_new[i];
644
645                         const u16 indices[] = {0,1,2,2,3,0};
646                         
647                         if(f.tile.feature == TILEFEAT_NONE)
648                         {
649                                 collector.append(g_tile_materials[f.tile.id], f.vertices, 4,
650                                                 indices, 6);
651                         }
652                         else
653                         {
654                                 // Not implemented
655                                 assert(0);
656                         }
657                 }
658
659                 collector.fillMesh(mesh_new);
660
661                 // Use VBO for mesh (this just would set this for ever buffer)
662                 //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
663                 
664                 /*std::cout<<"MapBlock has "<<fastfaces_new->getSize()<<" faces "
665                                 <<"and uses "<<mesh_new->getMeshBufferCount()
666                                 <<" materials (meshbuffers)"<<std::endl;*/
667         }
668
669         /*
670                 Clear temporary FastFaces
671         */
672
673         /*core::list<FastFace*>::Iterator i;
674         i = fastfaces_new->begin();
675         for(; i != fastfaces_new->end(); i++)
676         {
677                 delete *i;
678         }
679         fastfaces_new->clear();
680         delete fastfaces_new;*/
681
682         /*
683                 Add special graphics:
684                 - torches
685                 
686                 TODO: Optimize by using same meshbuffer for same textures
687         */
688
689         /*scene::ISceneManager *smgr = NULL;
690         video::IVideoDriver* driver = NULL;
691         if(g_device)
692         {
693                 smgr = g_device->getSceneManager();
694                 driver = smgr->getVideoDriver();
695         }*/
696                         
697         for(s16 z=0; z<MAP_BLOCKSIZE; z++)
698         for(s16 y=0; y<MAP_BLOCKSIZE; y++)
699         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
700         {
701                 v3s16 p(x,y,z);
702
703                 MapNode &n = getNodeRef(x,y,z);
704                 
705                 if(n.d == CONTENT_TORCH)
706                 {
707                         //scene::IMeshBuffer *buf = new scene::SMeshBuffer();
708                         scene::SMeshBuffer *buf = new scene::SMeshBuffer();
709                         video::SColor c(255,255,255,255);
710
711                         video::S3DVertex vertices[4] =
712                         {
713                                 video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 0,1),
714                                 video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, 1,1),
715                                 video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
716                                 video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
717                         };
718
719                         v3s16 dir = unpackDir(n.dir);
720
721                         for(s32 i=0; i<4; i++)
722                         {
723                                 if(dir == v3s16(1,0,0))
724                                         vertices[i].Pos.rotateXZBy(0);
725                                 if(dir == v3s16(-1,0,0))
726                                         vertices[i].Pos.rotateXZBy(180);
727                                 if(dir == v3s16(0,0,1))
728                                         vertices[i].Pos.rotateXZBy(90);
729                                 if(dir == v3s16(0,0,-1))
730                                         vertices[i].Pos.rotateXZBy(-90);
731                                 if(dir == v3s16(0,-1,0))
732                                         vertices[i].Pos.rotateXZBy(45);
733                                 if(dir == v3s16(0,1,0))
734                                         vertices[i].Pos.rotateXZBy(-45);
735
736                                 vertices[i].Pos += intToFloat(p + getPosRelative());
737                         }
738
739                         u16 indices[] = {0,1,2,2,3,0};
740                         buf->append(vertices, 4, indices, 6);
741
742                         // Set material
743                         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
744                         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
745                         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
746                         //buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
747                         buf->getMaterial().MaterialType
748                                         = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
749                         if(dir == v3s16(0,-1,0))
750                                 buf->getMaterial().setTexture(0,
751                                                 g_texturecache.get("torch_on_floor"));
752                         else if(dir == v3s16(0,1,0))
753                                 buf->getMaterial().setTexture(0,
754                                                 g_texturecache.get("torch_on_ceiling"));
755                         // For backwards compatibility
756                         else if(dir == v3s16(0,0,0))
757                                 buf->getMaterial().setTexture(0,
758                                                 g_texturecache.get("torch_on_floor"));
759                         else
760                                 buf->getMaterial().setTexture(0, g_texturecache.get("torch"));
761
762                         // Add to mesh
763                         mesh_new->addMeshBuffer(buf);
764                         buf->drop();
765                 }
766         }
767         
768         /*
769                 Do some stuff to the mesh
770         */
771
772         mesh_new->recalculateBoundingBox();
773
774         /*
775                 Delete new mesh if it is empty
776         */
777
778         if(mesh_new->getMeshBufferCount() == 0)
779         {
780                 mesh_new->drop();
781                 mesh_new = NULL;
782         }
783
784         /*
785                 Replace the mesh
786         */
787
788         mesh_mutex.Lock();
789
790         //scene::SMesh *mesh_old = mesh[daynight_i];
791         //mesh[daynight_i] = mesh_new;
792
793         scene::SMesh *mesh_old = mesh;
794         mesh = mesh_new;
795         setMeshExpired(false);
796         
797         if(mesh_old != NULL)
798         {
799                 // Remove hardware buffers of meshbuffers of mesh
800                 // NOTE: No way, this runs in a different thread and everything
801                 /*u32 c = mesh_old->getMeshBufferCount();
802                 for(u32 i=0; i<c; i++)
803                 {
804                         IMeshBuffer *buf = mesh_old->getMeshBuffer(i);
805                 }*/
806                 
807                 /*dstream<<"mesh_old->getReferenceCount()="
808                                 <<mesh_old->getReferenceCount()<<std::endl;
809                 u32 c = mesh_old->getMeshBufferCount();
810                 for(u32 i=0; i<c; i++)
811                 {
812                         scene::IMeshBuffer *buf = mesh_old->getMeshBuffer(i);
813                         dstream<<"buf->getReferenceCount()="
814                                         <<buf->getReferenceCount()<<std::endl;
815                 }*/
816
817                 // Drop the mesh
818                 mesh_old->drop();
819
820                 //delete mesh_old;
821         }
822
823         mesh_mutex.Unlock();
824         
825         //std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
826 }
827
828 /*void MapBlock::updateMeshes(s32 first_i)
829 {
830         assert(first_i >= 0 && first_i <= DAYNIGHT_CACHE_COUNT);
831         updateMesh(first_i);
832         for(s32 i=0; i<DAYNIGHT_CACHE_COUNT; i++)
833         {
834                 if(i == first_i)
835                         continue;
836                 updateMesh(i);
837         }
838 }*/
839
840 #endif // !SERVER
841
842 /*
843         Propagates sunlight down through the block.
844         Doesn't modify nodes that are not affected by sunlight.
845         
846         Returns false if sunlight at bottom block is invalid
847         Returns true if bottom block doesn't exist.
848
849         If there is a block above, continues from it.
850         If there is no block above, assumes there is sunlight, unless
851         is_underground is set.
852
853         At the moment, all sunlighted nodes are added to light_sources.
854         TODO: This could be optimized.
855 */
856 bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources)
857 {
858         // Whether the sunlight at the top of the bottom block is valid
859         bool block_below_is_valid = true;
860         
861         v3s16 pos_relative = getPosRelative();
862         
863         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
864         {
865                 for(s16 z=0; z<MAP_BLOCKSIZE; z++)
866                 {
867                         bool no_sunlight = false;
868                         bool no_top_block = false;
869                         // Check if node above block has sunlight
870                         try{
871                                 MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z));
872                                 if(n.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
873                                 {
874                                         /*if(is_underground)
875                                         {
876                                                 no_sunlight = true;
877                                         }*/
878                                         no_sunlight = true;
879                                 }
880                         }
881                         catch(InvalidPositionException &e)
882                         {
883                                 no_top_block = true;
884                                 
885                                 // TODO: This makes over-ground roofed places sunlighted
886                                 // Assume sunlight, unless is_underground==true
887                                 if(is_underground)
888                                 {
889                                         no_sunlight = true;
890                                 }
891                                 
892                                 // TODO: There has to be some way to allow this behaviour
893                                 // As of now, it just makes everything dark.
894                                 // No sunlight here
895                                 //no_sunlight = true;
896                         }
897
898                         /*std::cout<<"("<<x<<","<<z<<"): "
899                                         <<"no_top_block="<<no_top_block
900                                         <<", is_underground="<<is_underground
901                                         <<", no_sunlight="<<no_sunlight
902                                         <<std::endl;*/
903                 
904                         s16 y = MAP_BLOCKSIZE-1;
905                         
906                         if(no_sunlight == false)
907                         {
908                                 // Continue spreading sunlight downwards through transparent
909                                 // nodes
910                                 for(; y >= 0; y--)
911                                 {
912                                         v3s16 pos(x, y, z);
913                                         
914                                         MapNode &n = getNodeRef(pos);
915
916                                         if(n.sunlight_propagates())
917                                         {
918                                                 n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
919
920                                                 light_sources.insert(pos_relative + pos, true);
921                                         }
922                                         else{
923                                                 break;
924                                         }
925                                 }
926                         }
927
928                         bool sunlight_should_go_down = (y==-1);
929
930                         // Fill rest with black (only transparent ones)
931                         for(; y >= 0; y--){
932                                 v3s16 pos(x, y, z);
933                                 
934                                 MapNode &n = getNodeRef(pos);
935
936                                 if(n.light_propagates())
937                                 {
938                                         n.setLight(LIGHTBANK_DAY, 0);
939                                 }
940                                 else{
941                                         break;
942                                 }
943                         }
944
945                         /*
946                                 If the block below hasn't already been marked invalid:
947
948                                 Check if the node below the block has proper sunlight at top.
949                                 If not, the block below is invalid.
950                                 
951                                 Ignore non-transparent nodes as they always have no light
952                         */
953                         try
954                         {
955                         if(block_below_is_valid)
956                         {
957                                 MapNode n = getNodeParent(v3s16(x, -1, z));
958                                 if(n.light_propagates())
959                                 {
960                                         if(n.getLight(LIGHTBANK_DAY) == LIGHT_SUN
961                                                         && sunlight_should_go_down == false)
962                                                 block_below_is_valid = false;
963                                         else if(n.getLight(LIGHTBANK_DAY) != LIGHT_SUN
964                                                         && sunlight_should_go_down == true)
965                                                 block_below_is_valid = false;
966                                 }
967                         }//if
968                         }//try
969                         catch(InvalidPositionException &e)
970                         {
971                                 /*std::cout<<"InvalidBlockException for bottom block node"
972                                                 <<std::endl;*/
973                                 // Just no block below, no need to panic.
974                         }
975                 }
976         }
977
978         return block_below_is_valid;
979 }
980
981 void MapBlock::copyTo(VoxelManipulator &dst)
982 {
983         v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
984         VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
985         
986         dst.copyFrom(data, data_area, v3s16(0,0,0),
987                         getPosRelative(), data_size);
988 }
989
990 /*void getPseudoObjects(v3f origin, f32 max_d,
991                 core::array<DistanceSortedObject> &dest)
992 {
993 }*/
994
995
996 void MapBlock::updateDayNightDiff()
997 {
998         if(data == NULL)
999         {
1000                 m_day_night_differs = false;
1001                 return;
1002         }
1003
1004         bool differs = false;
1005
1006         /*
1007                 Check if any lighting value differs
1008         */
1009         for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
1010         {
1011                 MapNode &n = data[i];
1012                 if(n.getLight(LIGHTBANK_DAY) != n.getLight(LIGHTBANK_NIGHT))
1013                 {
1014                         differs = true;
1015                         break;
1016                 }
1017         }
1018
1019         /*
1020                 If some lighting values differ, check if the whole thing is
1021                 just air. If it is, differ = false
1022         */
1023         if(differs)
1024         {
1025                 bool only_air = true;
1026                 for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
1027                 {
1028                         MapNode &n = data[i];
1029                         if(n.d != CONTENT_AIR)
1030                         {
1031                                 only_air = false;
1032                                 break;
1033                         }
1034                 }
1035                 if(only_air)
1036                         differs = false;
1037         }
1038
1039         // Set member variable
1040         m_day_night_differs = differs;
1041 }
1042
1043 /*
1044         Serialization
1045 */
1046
1047 void MapBlock::serialize(std::ostream &os, u8 version)
1048 {
1049         if(!ser_ver_supported(version))
1050                 throw VersionMismatchException("ERROR: MapBlock format not supported");
1051         
1052         if(data == NULL)
1053         {
1054                 throw SerializationError("ERROR: Not writing dummy block.");
1055         }
1056         
1057         // These have no compression
1058         if(version <= 3 || version == 5 || version == 6)
1059         {
1060                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1061                 
1062                 u32 buflen = 1 + nodecount * MapNode::serializedLength(version);
1063                 SharedBuffer<u8> dest(buflen);
1064
1065                 dest[0] = is_underground;
1066                 for(u32 i=0; i<nodecount; i++)
1067                 {
1068                         u32 s = 1 + i * MapNode::serializedLength(version);
1069                         data[i].serialize(&dest[s], version);
1070                 }
1071                 
1072                 os.write((char*)*dest, dest.getSize());
1073         }
1074         else if(version <= 10)
1075         {
1076                 /*
1077                         With compression.
1078                         Compress the materials and the params separately.
1079                 */
1080                 
1081                 // First byte
1082                 os.write((char*)&is_underground, 1);
1083
1084                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1085
1086                 // Get and compress materials
1087                 SharedBuffer<u8> materialdata(nodecount);
1088                 for(u32 i=0; i<nodecount; i++)
1089                 {
1090                         materialdata[i] = data[i].d;
1091                 }
1092                 compress(materialdata, os, version);
1093
1094                 // Get and compress lights
1095                 SharedBuffer<u8> lightdata(nodecount);
1096                 for(u32 i=0; i<nodecount; i++)
1097                 {
1098                         lightdata[i] = data[i].param;
1099                 }
1100                 compress(lightdata, os, version);
1101                 
1102                 if(version >= 10)
1103                 {
1104                         // Get and compress pressure
1105                         SharedBuffer<u8> pressuredata(nodecount);
1106                         for(u32 i=0; i<nodecount; i++)
1107                         {
1108                                 pressuredata[i] = data[i].pressure;
1109                         }
1110                         compress(pressuredata, os, version);
1111                 }
1112         }
1113         // All other versions (newest)
1114         else
1115         {
1116                 // First byte
1117                 u8 flags = 0;
1118                 if(is_underground)
1119                         flags |= 1;
1120                 if(m_day_night_differs)
1121                         flags |= 2;
1122                 os.write((char*)&flags, 1);
1123
1124                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1125
1126                 /*
1127                         Get data
1128                 */
1129
1130                 SharedBuffer<u8> databuf(nodecount*3);
1131
1132                 // Get contents
1133                 for(u32 i=0; i<nodecount; i++)
1134                 {
1135                         databuf[i] = data[i].d;
1136                 }
1137
1138                 // Get params
1139                 for(u32 i=0; i<nodecount; i++)
1140                 {
1141                         databuf[i+nodecount] = data[i].param;
1142                 }
1143
1144                 // Get pressure
1145                 for(u32 i=0; i<nodecount; i++)
1146                 {
1147                         databuf[i+nodecount*2] = data[i].pressure;
1148                 }
1149
1150                 /*
1151                         Compress data to output stream
1152                 */
1153
1154                 compress(databuf, os, version);
1155         }
1156 }
1157
1158 void MapBlock::deSerialize(std::istream &is, u8 version)
1159 {
1160         if(!ser_ver_supported(version))
1161                 throw VersionMismatchException("ERROR: MapBlock format not supported");
1162
1163         // These have no compression
1164         if(version <= 3 || version == 5 || version == 6)
1165         {
1166                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1167                 char tmp;
1168                 is.read(&tmp, 1);
1169                 if(is.gcount() != 1)
1170                         throw SerializationError
1171                                         ("MapBlock::deSerialize: no enough input data");
1172                 is_underground = tmp;
1173                 for(u32 i=0; i<nodecount; i++)
1174                 {
1175                         s32 len = MapNode::serializedLength(version);
1176                         SharedBuffer<u8> d(len);
1177                         is.read((char*)*d, len);
1178                         if(is.gcount() != len)
1179                                 throw SerializationError
1180                                                 ("MapBlock::deSerialize: no enough input data");
1181                         data[i].deSerialize(*d, version);
1182                 }
1183         }
1184         else if(version <= 10)
1185         {
1186                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1187
1188                 u8 t8;
1189                 is.read((char*)&t8, 1);
1190                 is_underground = t8;
1191
1192                 {
1193                         // Uncompress and set material data
1194                         std::ostringstream os(std::ios_base::binary);
1195                         decompress(is, os, version);
1196                         std::string s = os.str();
1197                         if(s.size() != nodecount)
1198                                 throw SerializationError
1199                                                 ("MapBlock::deSerialize: invalid format");
1200                         for(u32 i=0; i<s.size(); i++)
1201                         {
1202                                 data[i].d = s[i];
1203                         }
1204                 }
1205                 {
1206                         // Uncompress and set param data
1207                         std::ostringstream os(std::ios_base::binary);
1208                         decompress(is, os, version);
1209                         std::string s = os.str();
1210                         if(s.size() != nodecount)
1211                                 throw SerializationError
1212                                                 ("MapBlock::deSerialize: invalid format");
1213                         for(u32 i=0; i<s.size(); i++)
1214                         {
1215                                 data[i].param = s[i];
1216                         }
1217                 }
1218         
1219                 if(version >= 10)
1220                 {
1221                         // Uncompress and set pressure data
1222                         std::ostringstream os(std::ios_base::binary);
1223                         decompress(is, os, version);
1224                         std::string s = os.str();
1225                         if(s.size() != nodecount)
1226                                 throw SerializationError
1227                                                 ("MapBlock::deSerialize: invalid format");
1228                         for(u32 i=0; i<s.size(); i++)
1229                         {
1230                                 data[i].pressure = s[i];
1231                         }
1232                 }
1233         }
1234         // All other versions (newest)
1235         else
1236         {
1237                 u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1238
1239                 u8 flags;
1240                 is.read((char*)&flags, 1);
1241                 is_underground = (flags & 1) ? true : false;
1242                 m_day_night_differs = (flags & 2) ? true : false;
1243
1244                 // Uncompress data
1245                 std::ostringstream os(std::ios_base::binary);
1246                 decompress(is, os, version);
1247                 std::string s = os.str();
1248                 if(s.size() != nodecount*3)
1249                         throw SerializationError
1250                                         ("MapBlock::deSerialize: invalid format");
1251
1252                 // Set contents
1253                 for(u32 i=0; i<nodecount; i++)
1254                 {
1255                         data[i].d = s[i];
1256                 }
1257                 // Set params
1258                 for(u32 i=0; i<nodecount; i++)
1259                 {
1260                         data[i].param = s[i+nodecount];
1261                 }
1262                 // Set pressure
1263                 for(u32 i=0; i<nodecount; i++)
1264                 {
1265                         data[i].pressure = s[i+nodecount*2];
1266                 }
1267         }
1268 }
1269
1270
1271 //END