]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapblock.h
before daynight mesh cache
[dragonfireclient.git] / src / mapblock.h
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 #ifndef MAPBLOCK_HEADER
21 #define MAPBLOCK_HEADER
22
23 #include <jmutex.h>
24 #include <jmutexautolock.h>
25 #include <exception>
26 #include "debug.h"
27 #include "common_irrlicht.h"
28 #include "mapnode.h"
29 #include "exceptions.h"
30 #include "serialization.h"
31 #include "constants.h"
32 #include "mapblockobject.h"
33 #include "voxel.h"
34
35 #define MAP_BLOCKSIZE 16
36
37 // Named by looking towards z+
38 enum{
39         FACE_BACK=0,
40         FACE_TOP,
41         FACE_RIGHT,
42         FACE_FRONT,
43         FACE_BOTTOM,
44         FACE_LEFT
45 };
46
47 struct FastFace
48 {
49         TileSpec tile;
50         video::S3DVertex vertices[4]; // Precalculated vertices
51 };
52
53 enum NodeModType
54 {
55         NODEMOD_NONE,
56         NODEMOD_CHANGECONTENT, //param is content id
57         NODEMOD_CRACK // param is crack progression
58 };
59
60 struct NodeMod
61 {
62         NodeMod()
63         {
64                 type = NODEMOD_NONE;
65         }
66         enum NodeModType type;
67         u16 param;
68 };
69
70 enum
71 {
72         NODECONTAINER_ID_MAPBLOCK,
73         NODECONTAINER_ID_MAPSECTOR,
74         NODECONTAINER_ID_MAP,
75         NODECONTAINER_ID_MAPBLOCKCACHE,
76         NODECONTAINER_ID_VOXELMANIPULATOR,
77 };
78
79 class NodeContainer
80 {
81 public:
82         virtual bool isValidPosition(v3s16 p) = 0;
83         virtual MapNode getNode(v3s16 p) = 0;
84         virtual void setNode(v3s16 p, MapNode & n) = 0;
85         virtual u16 nodeContainerId() const = 0;
86 };
87
88 class MapBlock : public NodeContainer
89 {
90 public:
91
92         /*
93                 This used by Server's block creation stuff for not sending
94                 blocks that are waiting a lighting update.
95
96                 If true, the block needs some work by the one who set this
97                 to true.
98
99                 While true, nobody else should touch the block.
100         */
101         //bool is_incomplete;
102         
103         scene::SMesh *mesh;
104         JMutex mesh_mutex;
105
106         MapBlock(NodeContainer *parent, v3s16 pos, bool dummy=false):
107                         m_parent(parent),
108                         m_pos(pos),
109                         changed(true),
110                         is_underground(false),
111                         m_mesh_expired(false),
112                         m_objects(this)
113                         //is_incomplete(false)
114         {
115                 data = NULL;
116                 if(dummy == false)
117                         reallocate();
118                 mesh_mutex.Init();
119                 mesh = NULL;
120         }
121
122         ~MapBlock()
123         {
124                 {
125                         JMutexAutoLock lock(mesh_mutex);
126                         
127                         if(mesh != NULL)
128                         {
129                                 mesh->drop();
130                                 mesh = NULL;
131                         }
132                 }
133
134                 if(data)
135                         delete[] data;
136         }
137         
138         virtual u16 nodeContainerId() const
139         {
140                 return NODECONTAINER_ID_MAPBLOCK;
141         }
142
143         NodeContainer * getParent()
144         {
145                 return m_parent;
146         }
147
148         bool isDummy()
149         {
150                 return (data == NULL);
151         }
152
153         void unDummify()
154         {
155                 assert(isDummy());
156                 reallocate();
157         }
158         
159         bool getChangedFlag()
160         {
161                 return changed;
162         }
163
164         void resetChangedFlag()
165         {
166                 changed = false;
167         }
168
169         void setChangedFlag()
170         {
171                 changed = true;
172         }
173
174         void setMeshExpired(bool expired)
175         {
176                 m_mesh_expired = expired;
177         }
178         
179         bool getMeshExpired()
180         {
181                 return m_mesh_expired;
182         }
183
184         v3s16 getPos()
185         {
186                 return m_pos;
187         }
188                 
189         v3s16 getPosRelative()
190         {
191                 return m_pos * MAP_BLOCKSIZE;
192         }
193                 
194         bool getIsUnderground()
195         {
196                 return is_underground;
197         }
198
199         void setIsUnderground(bool a_is_underground)
200         {
201                 is_underground = a_is_underground;
202                 setChangedFlag();
203         }
204
205         core::aabbox3d<s16> getBox()
206         {
207                 return core::aabbox3d<s16>(getPosRelative(),
208                                 getPosRelative()
209                                 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
210                                 - v3s16(1,1,1));
211         }
212         
213         void reallocate()
214         {
215                 if(data != NULL)
216                         delete[] data;
217                 u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
218                 data = new MapNode[l];
219                 for(u32 i=0; i<l; i++){
220                         data[i] = MapNode();
221                 }
222                 setChangedFlag();
223         }
224
225         bool isValidPosition(v3s16 p)
226         {
227                 if(data == NULL)
228                         return false;
229                 return (p.X >= 0 && p.X < MAP_BLOCKSIZE
230                                 && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
231                                 && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
232         }
233
234         /*
235                 Regular MapNode get-setters
236         */
237         
238         MapNode getNode(s16 x, s16 y, s16 z)
239         {
240                 if(data == NULL)
241                         throw InvalidPositionException();
242                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
243                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
244                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
245                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
246         }
247         
248         MapNode getNode(v3s16 p)
249         {
250                 return getNode(p.X, p.Y, p.Z);
251         }
252         
253         void setNode(s16 x, s16 y, s16 z, MapNode & n)
254         {
255                 if(data == NULL)
256                         throw InvalidPositionException();
257                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
258                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
259                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
260                 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
261                 setChangedFlag();
262         }
263         
264         void setNode(v3s16 p, MapNode & n)
265         {
266                 setNode(p.X, p.Y, p.Z, n);
267         }
268
269         /*
270                 Non-checking variants of the above
271         */
272
273         MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
274         {
275                 if(data == NULL)
276                         throw InvalidPositionException();
277                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
278         }
279         
280         MapNode getNodeNoCheck(v3s16 p)
281         {
282                 return getNodeNoCheck(p.X, p.Y, p.Z);
283         }
284         
285         void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
286         {
287                 if(data == NULL)
288                         throw InvalidPositionException();
289                 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
290                 setChangedFlag();
291         }
292         
293         void setNodeNoCheck(v3s16 p, MapNode & n)
294         {
295                 setNodeNoCheck(p.X, p.Y, p.Z, n);
296         }
297
298         /*
299                 These functions consult the parent container if the position
300                 is not valid on this MapBlock.
301         */
302         bool isValidPositionParent(v3s16 p);
303         MapNode getNodeParent(v3s16 p);
304         void setNodeParent(v3s16 p, MapNode & n);
305
306         void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
307         {
308                 for(u16 z=0; z<d; z++)
309                         for(u16 y=0; y<h; y++)
310                                 for(u16 x=0; x<w; x++)
311                                         setNode(x0+x, y0+y, z0+z, node);
312         }
313
314         static FastFace * makeFastFace(TileSpec tile, u8 light, v3f p,
315                         v3s16 dir, v3f scale, v3f posRelative_f);
316         
317         u8 getFaceLight(u32 daylight_factor, v3s16 p, v3s16 face_dir);
318         
319         TileSpec getNodeTile(v3s16 p, v3s16 face_dir);
320         u8 getNodeContent(v3s16 p);
321
322         /*
323                 startpos:
324                 translate_dir: unit vector with only one of x, y or z
325                 face_dir: unit vector with only one of x, y or z
326         */
327         void updateFastFaceRow(
328                         u32 daylight_factor,
329                         v3s16 startpos,
330                         u16 length,
331                         v3s16 translate_dir,
332                         v3s16 face_dir,
333                         core::list<FastFace*> &dest);
334
335         void updateMesh(u32 daylight_factor);
336
337         bool propagateSunlight(core::map<v3s16, bool> & light_sources);
338         
339         // Copies data to VoxelManipulator to getPosRelative()
340         void copyTo(VoxelManipulator &dst);
341
342         /*
343                 Object stuff
344         */
345         
346         void serializeObjects(std::ostream &os, u8 version)
347         {
348                 m_objects.serialize(os, version);
349         }
350         // If smgr!=NULL, new objects are added to the scene
351         void updateObjects(std::istream &is, u8 version,
352                         scene::ISceneManager *smgr)
353         {
354                 m_objects.update(is, version, smgr);
355
356                 setChangedFlag();
357         }
358         void clearObjects()
359         {
360                 m_objects.clear();
361
362                 setChangedFlag();
363         }
364         void addObject(MapBlockObject *object)
365                         throw(ContainerFullException, AlreadyExistsException)
366         {
367                 m_objects.add(object);
368
369                 setChangedFlag();
370         }
371         void removeObject(s16 id)
372         {
373                 m_objects.remove(id);
374
375                 setChangedFlag();
376         }
377         MapBlockObject * getObject(s16 id)
378         {
379                 return m_objects.get(id);
380         }
381         JMutexAutoLock * getObjectLock()
382         {
383                 return m_objects.getLock();
384         }
385         void stepObjects(float dtime, bool server)
386         {
387                 m_objects.step(dtime, server);
388
389                 setChangedFlag();
390         }
391
392         /*void wrapObject(MapBlockObject *object)
393         {
394                 m_objects.wrapObject(object);
395
396                 setChangedFlag();
397         }*/
398
399         // origin is relative to block
400         void getObjects(v3f origin, f32 max_d,
401                         core::array<DistanceSortedObject> &dest)
402         {
403                 m_objects.getObjects(origin, max_d, dest);
404         }
405
406         /*void getPseudoObjects(v3f origin, f32 max_d,
407                         core::array<DistanceSortedObject> &dest);*/
408
409         s32 getObjectCount()
410         {
411                 return m_objects.getCount();
412         }
413         
414         /*
415                 Methods for setting temporary modifications to nodes for
416                 drawing
417         */
418         void setTempMod(v3s16 p, NodeMod mod)
419         {
420                 m_temp_mods[p] = mod;
421         }
422         void clearTempMod(v3s16 p)
423         {
424                 if(m_temp_mods.find(p))
425                         m_temp_mods.remove(p);
426         }
427         void clearTempMods()
428         {
429                 m_temp_mods.clear();
430         }
431
432         /*
433                 Serialization
434         */
435         
436         // Doesn't write version by itself
437         void serialize(std::ostream &os, u8 version);
438
439         void deSerialize(std::istream &is, u8 version);
440
441 private:
442
443         /*
444                 Used only internally, because changes can't be tracked
445         */
446
447         MapNode & getNodeRef(s16 x, s16 y, s16 z)
448         {
449                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
450                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
451                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
452                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
453         }
454         MapNode & getNodeRef(v3s16 &p)
455         {
456                 return getNodeRef(p.X, p.Y, p.Z);
457         }
458
459         
460         NodeContainer *m_parent;
461         // Position in blocks on parent
462         v3s16 m_pos;
463         /*
464                 If NULL, block is a dummy block.
465                 Dummy blocks are used for caching not-found-on-disk blocks.
466         */
467         MapNode * data;
468         /*
469                 - On the client, this is used for checking whether to
470                   recalculate the face cache. (Is it anymore?)
471                 - On the server, this is used for telling whether the
472                   block has been changed from the one on disk.
473         */
474         bool changed;
475         /*
476                 Used for some initial lighting stuff.
477                 At least /has been/ used. 8)
478         */
479         bool is_underground;
480
481         bool m_mesh_expired;
482         
483         MapBlockObjectList m_objects;
484         
485         // Temporary modifications to nodes
486         // These are only used when drawing
487         core::map<v3s16, NodeMod> m_temp_mods;
488 };
489
490 inline bool blockpos_over_limit(v3s16 p)
491 {
492         return
493           (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
494         || p.X >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
495         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
496         || p.Y >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
497         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
498         || p.Z >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
499 }
500
501 /*
502         Returns the position of the block where the node is located
503 */
504 inline v3s16 getNodeBlockPos(v3s16 p)
505 {
506         return getContainerPos(p, MAP_BLOCKSIZE);
507 }
508
509 inline v2s16 getNodeSectorPos(v2s16 p)
510 {
511         return getContainerPos(p, MAP_BLOCKSIZE);
512 }
513
514 inline s16 getNodeBlockY(s16 y)
515 {
516         return getContainerPos(y, MAP_BLOCKSIZE);
517 }
518
519 #endif
520