]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapblock.h
disable tiling of textures only if smooth lighting is used
[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 #include "nodemetadata.h"
35 #include "staticobject.h"
36
37
38 // Named by looking towards z+
39 enum{
40         FACE_BACK=0,
41         FACE_TOP,
42         FACE_RIGHT,
43         FACE_FRONT,
44         FACE_BOTTOM,
45         FACE_LEFT
46 };
47
48 struct FastFace
49 {
50         TileSpec tile;
51         video::S3DVertex vertices[4]; // Precalculated vertices
52 };
53
54 enum NodeModType
55 {
56         NODEMOD_NONE,
57         NODEMOD_CHANGECONTENT, //param is content id
58         NODEMOD_CRACK // param is crack progression
59 };
60
61 struct NodeMod
62 {
63         NodeMod(enum NodeModType a_type=NODEMOD_NONE, u16 a_param=0)
64         {
65                 type = a_type;
66                 param = a_param;
67         }
68         bool operator==(const NodeMod &other)
69         {
70                 return (type == other.type && param == other.param);
71         }
72         enum NodeModType type;
73         u16 param;
74 };
75
76 class NodeModMap
77 {
78 public:
79         /*
80                 returns true if the mod was different last time
81         */
82         bool set(v3s16 p, const NodeMod &mod)
83         {
84                 // See if old is different, cancel if it is not different.
85                 core::map<v3s16, NodeMod>::Node *n = m_mods.find(p);
86                 if(n)
87                 {
88                         NodeMod old = n->getValue();
89                         if(old == mod)
90                                 return false;
91
92                         n->setValue(mod);
93                 }
94                 else
95                 {
96                         m_mods.insert(p, mod);
97                 }
98                 
99                 return true;
100         }
101         // Returns true if there was one
102         bool get(v3s16 p, NodeMod *mod)
103         {
104                 core::map<v3s16, NodeMod>::Node *n;
105                 n = m_mods.find(p);
106                 if(n == NULL)
107                         return false;
108                 if(mod)
109                         *mod = n->getValue();
110                 return true;
111         }
112         bool clear(v3s16 p)
113         {
114                 if(m_mods.find(p))
115                 {
116                         m_mods.remove(p);
117                         return true;
118                 }
119                 return false;
120         }
121         bool clear()
122         {
123                 if(m_mods.size() == 0)
124                         return false;
125                 m_mods.clear();
126                 return true;
127         }
128         void copy(NodeModMap &dest)
129         {
130                 dest.m_mods.clear();
131
132                 for(core::map<v3s16, NodeMod>::Iterator
133                                 i = m_mods.getIterator();
134                                 i.atEnd() == false; i++)
135                 {
136                         dest.m_mods.insert(i.getNode()->getKey(), i.getNode()->getValue());
137                 }
138         }
139
140 private:
141         core::map<v3s16, NodeMod> m_mods;
142 };
143
144 enum
145 {
146         NODECONTAINER_ID_MAPBLOCK,
147         NODECONTAINER_ID_MAPSECTOR,
148         NODECONTAINER_ID_MAP,
149         NODECONTAINER_ID_MAPBLOCKCACHE,
150         NODECONTAINER_ID_VOXELMANIPULATOR,
151 };
152
153 class NodeContainer
154 {
155 public:
156         virtual bool isValidPosition(v3s16 p) = 0;
157         virtual MapNode getNode(v3s16 p) = 0;
158         virtual void setNode(v3s16 p, MapNode & n) = 0;
159         virtual u16 nodeContainerId() const = 0;
160
161         MapNode getNodeNoEx(v3s16 p)
162         {
163                 try{
164                         return getNode(p);
165                 }
166                 catch(InvalidPositionException &e){
167                         return MapNode(CONTENT_IGNORE);
168                 }
169         }
170 };
171
172 /*
173         Mesh making stuff
174 */
175
176 class MapBlock;
177
178 #ifndef SERVER
179
180 struct MeshMakeData
181 {
182         u32 m_daynight_ratio;
183         NodeModMap m_temp_mods;
184         VoxelManipulator m_vmanip;
185         v3s16 m_blockpos;
186         
187         /*
188                 Copy central data directly from block, and other data from
189                 parent of block.
190         */
191         void fill(u32 daynight_ratio, MapBlock *block);
192 };
193
194 scene::SMesh* makeMapBlockMesh(MeshMakeData *data);
195
196 #endif
197
198 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
199                 v3s16 face_dir);
200
201 /*
202         MapBlock itself
203 */
204
205 class MapBlock : public NodeContainer
206 {
207 public:
208         MapBlock(NodeContainer *parent, v3s16 pos, bool dummy=false);
209         ~MapBlock();
210         
211         virtual u16 nodeContainerId() const
212         {
213                 return NODECONTAINER_ID_MAPBLOCK;
214         }
215         
216         NodeContainer * getParent()
217         {
218                 return m_parent;
219         }
220
221         void reallocate()
222         {
223                 if(data != NULL)
224                         delete[] data;
225                 u32 l = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
226                 data = new MapNode[l];
227                 for(u32 i=0; i<l; i++){
228                         data[i] = MapNode();
229                 }
230                 setChangedFlag();
231         }
232
233         /*
234                 Flags
235         */
236
237         bool isDummy()
238         {
239                 return (data == NULL);
240         }
241         void unDummify()
242         {
243                 assert(isDummy());
244                 reallocate();
245         }
246         
247         bool getChangedFlag()
248         {
249                 return changed;
250         }
251         void resetChangedFlag()
252         {
253                 changed = false;
254         }
255         void setChangedFlag()
256         {
257                 changed = true;
258         }
259
260         bool getIsUnderground()
261         {
262                 return is_underground;
263         }
264
265         void setIsUnderground(bool a_is_underground)
266         {
267                 is_underground = a_is_underground;
268                 setChangedFlag();
269         }
270
271 #ifndef SERVER
272         void setMeshExpired(bool expired)
273         {
274                 m_mesh_expired = expired;
275         }
276         
277         bool getMeshExpired()
278         {
279                 return m_mesh_expired;
280         }
281 #endif
282
283         void setLightingExpired(bool expired)
284         {
285                 m_lighting_expired = expired;
286                 setChangedFlag();
287         }
288         bool getLightingExpired()
289         {
290                 return m_lighting_expired;
291         }
292
293         /*bool isFullyGenerated()
294         {
295                 return !m_not_fully_generated;
296         }
297         void setFullyGenerated(bool b)
298         {
299                 setChangedFlag();
300                 m_not_fully_generated = !b;
301         }*/
302
303         bool isValid()
304         {
305                 if(m_lighting_expired)
306                         return false;
307                 if(data == NULL)
308                         return false;
309                 return true;
310         }
311
312         /*
313                 Position stuff
314         */
315
316         v3s16 getPos()
317         {
318                 return m_pos;
319         }
320                 
321         v3s16 getPosRelative()
322         {
323                 return m_pos * MAP_BLOCKSIZE;
324         }
325                 
326         core::aabbox3d<s16> getBox()
327         {
328                 return core::aabbox3d<s16>(getPosRelative(),
329                                 getPosRelative()
330                                 + v3s16(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE)
331                                 - v3s16(1,1,1));
332         }
333
334         /*
335                 Regular MapNode get-setters
336         */
337         
338         bool isValidPosition(v3s16 p)
339         {
340                 if(data == NULL)
341                         return false;
342                 return (p.X >= 0 && p.X < MAP_BLOCKSIZE
343                                 && p.Y >= 0 && p.Y < MAP_BLOCKSIZE
344                                 && p.Z >= 0 && p.Z < MAP_BLOCKSIZE);
345         }
346
347         MapNode getNode(s16 x, s16 y, s16 z)
348         {
349                 if(data == NULL)
350                         throw InvalidPositionException();
351                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
352                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
353                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
354                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
355         }
356         
357         MapNode getNode(v3s16 p)
358         {
359                 return getNode(p.X, p.Y, p.Z);
360         }
361         
362         void setNode(s16 x, s16 y, s16 z, MapNode & n)
363         {
364                 if(data == NULL)
365                         throw InvalidPositionException();
366                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
367                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
368                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
369                 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
370                 setChangedFlag();
371         }
372         
373         void setNode(v3s16 p, MapNode & n)
374         {
375                 setNode(p.X, p.Y, p.Z, n);
376         }
377
378         /*
379                 Non-checking variants of the above
380         */
381
382         MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
383         {
384                 if(data == NULL)
385                         throw InvalidPositionException();
386                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
387         }
388         
389         MapNode getNodeNoCheck(v3s16 p)
390         {
391                 return getNodeNoCheck(p.X, p.Y, p.Z);
392         }
393         
394         void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
395         {
396                 if(data == NULL)
397                         throw InvalidPositionException();
398                 data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
399                 setChangedFlag();
400         }
401         
402         void setNodeNoCheck(v3s16 p, MapNode & n)
403         {
404                 setNodeNoCheck(p.X, p.Y, p.Z, n);
405         }
406
407         /*
408                 These functions consult the parent container if the position
409                 is not valid on this MapBlock.
410         */
411         bool isValidPositionParent(v3s16 p);
412         MapNode getNodeParent(v3s16 p);
413         void setNodeParent(v3s16 p, MapNode & n);
414         MapNode getNodeParentNoEx(v3s16 p);
415
416         void drawbox(s16 x0, s16 y0, s16 z0, s16 w, s16 h, s16 d, MapNode node)
417         {
418                 for(u16 z=0; z<d; z++)
419                         for(u16 y=0; y<h; y++)
420                                 for(u16 x=0; x<w; x++)
421                                         setNode(x0+x, y0+y, z0+z, node);
422         }
423
424         /*
425                 Graphics-related methods
426         */
427         
428         /*// A quick version with nodes passed as parameters
429         u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
430                         v3s16 face_dir);*/
431         /*// A more convenient version
432         u8 getFaceLight(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
433         {
434                 return getFaceLight(daynight_ratio,
435                                 getNodeParentNoEx(p),
436                                 getNodeParentNoEx(p + face_dir),
437                                 face_dir);
438         }*/
439         u8 getFaceLight2(u32 daynight_ratio, v3s16 p, v3s16 face_dir)
440         {
441                 return getFaceLight(daynight_ratio,
442                                 getNodeParentNoEx(p),
443                                 getNodeParentNoEx(p + face_dir),
444                                 face_dir);
445         }
446         
447 #ifndef SERVER
448         // light = 0...255
449         /*static void makeFastFace(TileSpec tile, u8 light, v3f p,
450                         v3s16 dir, v3f scale, v3f posRelative_f,
451                         core::array<FastFace> &dest);*/
452         
453         /*TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
454                         NodeModMap &temp_mods);*/
455         /*u8 getNodeContent(v3s16 p, MapNode mn,
456                         NodeModMap &temp_mods);*/
457
458         /*
459                 Generates the FastFaces of a node row. This has a
460                 ridiculous amount of parameters because that way they
461                 can be precalculated by the caller.
462
463                 translate_dir: unit vector with only one of x, y or z
464                 face_dir: unit vector with only one of x, y or z
465         */
466         /*void updateFastFaceRow(
467                         u32 daynight_ratio,
468                         v3f posRelative_f,
469                         v3s16 startpos,
470                         u16 length,
471                         v3s16 translate_dir,
472                         v3f translate_dir_f,
473                         v3s16 face_dir,
474                         v3f face_dir_f,
475                         core::array<FastFace> &dest,
476                         NodeModMap &temp_mods);*/
477         
478         /*
479                 Thread-safely updates the whole mesh of the mapblock.
480         */
481 #if 1
482         void updateMesh(u32 daynight_ratio);
483 #endif
484
485         void replaceMesh(scene::SMesh *mesh_new);
486         
487 #endif // !SERVER
488         
489         // See comments in mapblock.cpp
490         bool propagateSunlight(core::map<v3s16, bool> & light_sources,
491                         bool remove_light=false, bool *black_air_left=NULL,
492                         bool grow_grass=false);
493         
494         // Copies data to VoxelManipulator to getPosRelative()
495         void copyTo(VoxelManipulator &dst);
496         // Copies data from VoxelManipulator getPosRelative()
497         void copyFrom(VoxelManipulator &dst);
498
499         /*
500                 MapBlockObject stuff
501         */
502         
503         void serializeObjects(std::ostream &os, u8 version)
504         {
505                 m_objects.serialize(os, version);
506         }
507         // If smgr!=NULL, new objects are added to the scene
508         void updateObjects(std::istream &is, u8 version,
509                         scene::ISceneManager *smgr, u32 daynight_ratio)
510         {
511                 m_objects.update(is, version, smgr, daynight_ratio);
512
513                 setChangedFlag();
514         }
515         void clearObjects()
516         {
517                 m_objects.clear();
518
519                 setChangedFlag();
520         }
521         void addObject(MapBlockObject *object)
522                         throw(ContainerFullException, AlreadyExistsException)
523         {
524                 m_objects.add(object);
525
526                 setChangedFlag();
527         }
528         void removeObject(s16 id)
529         {
530                 m_objects.remove(id);
531
532                 setChangedFlag();
533         }
534         MapBlockObject * getObject(s16 id)
535         {
536                 return m_objects.get(id);
537         }
538         JMutexAutoLock * getObjectLock()
539         {
540                 return m_objects.getLock();
541         }
542
543         /*
544                 Moves objects, deletes objects and spawns new objects
545         */
546         void stepObjects(float dtime, bool server, u32 daynight_ratio);
547
548         /*void wrapObject(MapBlockObject *object)
549         {
550                 m_objects.wrapObject(object);
551
552                 setChangedFlag();
553         }*/
554
555         // origin is relative to block
556         void getObjects(v3f origin, f32 max_d,
557                         core::array<DistanceSortedObject> &dest)
558         {
559                 m_objects.getObjects(origin, max_d, dest);
560         }
561
562         s32 getObjectCount()
563         {
564                 return m_objects.getCount();
565         }
566
567 #ifndef SERVER
568         /*
569                 Methods for setting temporary modifications to nodes for
570                 drawing
571
572                 returns true if the mod was different last time
573         */
574         bool setTempMod(v3s16 p, const NodeMod &mod)
575         {
576                 /*dstream<<"setTempMod called on block"
577                                 <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
578                                 <<", mod.type="<<mod.type
579                                 <<", mod.param="<<mod.param
580                                 <<std::endl;*/
581                 JMutexAutoLock lock(m_temp_mods_mutex);
582
583                 return m_temp_mods.set(p, mod);
584         }
585         // Returns true if there was one
586         bool getTempMod(v3s16 p, NodeMod *mod)
587         {
588                 JMutexAutoLock lock(m_temp_mods_mutex);
589
590                 return m_temp_mods.get(p, mod);
591         }
592         bool clearTempMod(v3s16 p)
593         {
594                 JMutexAutoLock lock(m_temp_mods_mutex);
595
596                 return m_temp_mods.clear(p);
597         }
598         bool clearTempMods()
599         {
600                 JMutexAutoLock lock(m_temp_mods_mutex);
601                 
602                 return m_temp_mods.clear();
603         }
604         void copyTempMods(NodeModMap &dst)
605         {
606                 JMutexAutoLock lock(m_temp_mods_mutex);
607                 m_temp_mods.copy(dst);
608         }
609 #endif
610
611         /*
612                 Update day-night lighting difference flag.
613                 
614                 Sets m_day_night_differs to appropriate value.
615                 
616                 These methods don't care about neighboring blocks.
617                 It means that to know if a block really doesn't need a mesh
618                 update between day and night, the neighboring blocks have
619                 to be taken into account. Use Map::dayNightDiffed().
620         */
621         void updateDayNightDiff();
622
623         bool dayNightDiffed()
624         {
625                 return m_day_night_differs;
626         }
627
628         /*
629                 Miscellaneous stuff
630         */
631         
632         /*
633                 Tries to measure ground level.
634                 Return value:
635                         -1 = only air
636                         -2 = only ground
637                         -3 = random fail
638                         0...MAP_BLOCKSIZE-1 = ground level
639         */
640         s16 getGroundLevel(v2s16 p2d);
641
642         /*
643                 Serialization
644         */
645         
646         // Doesn't write version by itself
647         void serialize(std::ostream &os, u8 version);
648
649         void deSerialize(std::istream &is, u8 version);
650
651 private:
652         /*
653                 Private methods
654         */
655
656         /*
657                 Used only internally, because changes can't be tracked
658         */
659
660         MapNode & getNodeRef(s16 x, s16 y, s16 z)
661         {
662                 if(data == NULL)
663                         throw InvalidPositionException();
664                 if(x < 0 || x >= MAP_BLOCKSIZE) throw InvalidPositionException();
665                 if(y < 0 || y >= MAP_BLOCKSIZE) throw InvalidPositionException();
666                 if(z < 0 || z >= MAP_BLOCKSIZE) throw InvalidPositionException();
667                 return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
668         }
669         MapNode & getNodeRef(v3s16 &p)
670         {
671                 return getNodeRef(p.X, p.Y, p.Z);
672         }
673
674 public:
675         /*
676                 Public member variables
677         */
678
679 #ifndef SERVER
680         scene::SMesh *mesh;
681         JMutex mesh_mutex;
682 #endif
683         
684         NodeMetadataList m_node_metadata;
685         StaticObjectList m_static_objects;
686         
687 private:
688         /*
689                 Private member variables
690         */
691
692         // NOTE: Lots of things rely on this being the Map
693         NodeContainer *m_parent;
694         // Position in blocks on parent
695         v3s16 m_pos;
696         
697         /*
698                 If NULL, block is a dummy block.
699                 Dummy blocks are used for caching not-found-on-disk blocks.
700         */
701         MapNode * data;
702
703         /*
704                 - On the server, this is used for telling whether the
705                   block has been changed from the one on disk.
706                 - On the client, this is used for nothing.
707         */
708         bool changed;
709
710         /*
711                 When propagating sunlight and the above block doesn't exist,
712                 sunlight is assumed if this is false.
713
714                 In practice this is set to true if the block is completely
715                 undeground with nothing visible above the ground except
716                 caves.
717         */
718         bool is_underground;
719
720         /*
721                 Set to true if changes has been made that make the old lighting
722                 values wrong but the lighting hasn't been actually updated.
723
724                 If this is false, lighting is exactly right.
725                 If this is true, lighting might be wrong or right.
726         */
727         bool m_lighting_expired;
728         
729         // Whether day and night lighting differs
730         bool m_day_night_differs;
731         
732         // TODO: Remove this
733         MapBlockObjectList m_objects;
734
735         // Object spawning stuff
736         //float m_spawn_timer;
737
738 #ifndef SERVER // Only on client
739         /*
740                 Set to true if the mesh has been ordered to be updated
741                 sometime in the background.
742                 In practice this is set when the day/night lighting switches.
743         */
744         bool m_mesh_expired;
745         
746         // Temporary modifications to nodes
747         // These are only used when drawing
748         NodeModMap m_temp_mods;
749         JMutex m_temp_mods_mutex;
750 #endif
751 };
752
753 inline bool blockpos_over_limit(v3s16 p)
754 {
755         return
756           (p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
757         || p.X >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
758         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
759         || p.Y >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
760         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
761         || p.Z >  MAP_GENERATION_LIMIT / MAP_BLOCKSIZE);
762 }
763
764 /*
765         Returns the position of the block where the node is located
766 */
767 inline v3s16 getNodeBlockPos(v3s16 p)
768 {
769         return getContainerPos(p, MAP_BLOCKSIZE);
770 }
771
772 inline v2s16 getNodeSectorPos(v2s16 p)
773 {
774         return getContainerPos(p, MAP_BLOCKSIZE);
775 }
776
777 inline s16 getNodeBlockY(s16 y)
778 {
779         return getContainerPos(y, MAP_BLOCKSIZE);
780 }
781
782 #endif
783