eee9177f371cb7109ebce2b9a240606d31586c4c
[oweals/minetest.git] / src / voxel.h
1 #ifndef VOXEL_HEADER
2 #define VOXEL_HEADER
3
4 #include "common_irrlicht.h"
5 #include "mapblock.h"
6 #include <iostream>
7
8 /*
9         TODO: A fast voxel manipulator class
10
11         Not thread-safe.
12 */
13
14 /*
15         This class resembles aabbox3d<s16> a lot, but has inclusive
16         edges for saner handling of integer sizes
17 */
18 class VoxelArea
19 {
20 public:
21         // Starts as zero sized
22         VoxelArea():
23                 MinEdge(1,1,1),
24                 MaxEdge(0,0,0)
25         {
26         }
27         VoxelArea(v3s16 min_edge, v3s16 max_edge):
28                 MinEdge(min_edge),
29                 MaxEdge(max_edge)
30         {
31         }
32         VoxelArea(v3s16 p):
33                 MinEdge(p),
34                 MaxEdge(p)
35         {
36         }
37         void addArea(VoxelArea &a)
38         {
39                 if(a.MinEdge.X < MinEdge.X) MinEdge.X = a.MinEdge.X;
40                 if(a.MinEdge.Y < MinEdge.Y) MinEdge.Y = a.MinEdge.Y;
41                 if(a.MinEdge.Z < MinEdge.Z) MinEdge.Z = a.MinEdge.Z;
42                 if(a.MaxEdge.X > MaxEdge.X) MaxEdge.X = a.MaxEdge.X;
43                 if(a.MaxEdge.Y > MaxEdge.Y) MaxEdge.Y = a.MaxEdge.Y;
44                 if(a.MaxEdge.Z > MaxEdge.Z) MaxEdge.Z = a.MaxEdge.Z;
45         }
46         void addPoint(v3s16 p)
47         {
48                 if(p.X < MinEdge.X) MinEdge.X = p.X;
49                 if(p.Y < MinEdge.Y) MinEdge.Y = p.Y;
50                 if(p.Z < MinEdge.Z) MinEdge.Z = p.Z;
51                 if(p.X > MaxEdge.X) MaxEdge.X = p.X;
52                 if(p.Y > MaxEdge.Y) MaxEdge.Y = p.Y;
53                 if(p.Z > MaxEdge.Z) MaxEdge.Z = p.Z;
54         }
55         v3s16 getExtent()
56         {
57                 return MaxEdge - MinEdge + v3s16(1,1,1);
58         }
59         s32 getVolume()
60         {
61                 v3s16 e = getExtent();
62                 return (s32)e.X * (s32)e.Y * (s32)e.Z;
63         }
64         bool isInside(v3s16 p)
65         {
66                 return(
67                         p.X >= MinEdge.X && p.X <= MaxEdge.X &&
68                         p.Y >= MinEdge.Y && p.Y <= MaxEdge.Y &&
69                         p.Z >= MinEdge.Z && p.Z <= MaxEdge.Z
70                 );
71         }
72         bool operator==(const VoxelArea &other)
73         {
74                 return (MinEdge == other.MinEdge
75                                 && MaxEdge == other.MaxEdge);
76         }
77         
78         /*
79                 Translates position from virtual coordinates to array index
80         */
81         s32 index(s16 x, s16 y, s16 z)
82         {
83                 v3s16 em = getExtent();
84                 v3s16 off = MinEdge;
85                 s32 i = (s32)(z-off.Z)*em.Y*em.X + (y-off.Y)*em.X + (x-off.X);
86                 //dstream<<" i("<<x<<","<<y<<","<<z<<")="<<i<<" ";
87                 return i;
88         }
89         s32 index(v3s16 p)
90         {
91                 return index(p.X, p.Y, p.Z);
92         }
93
94         void print(std::ostream &o)
95         {
96                 o<<"("<<MinEdge.X
97                  <<","<<MinEdge.Y
98                  <<","<<MinEdge.Z
99                  <<")("<<MaxEdge.X
100                  <<","<<MaxEdge.Y
101                  <<","<<MaxEdge.Z
102                  <<")";
103         }
104
105         // Edges are inclusive
106         v3s16 MinEdge;
107         v3s16 MaxEdge;
108 };
109
110 class VoxelManipulator : public NodeContainer
111 {
112 public:
113         VoxelManipulator();
114         ~VoxelManipulator();
115         
116         /*
117                 Virtuals from NodeContainer
118         */
119         virtual u16 nodeContainerId() const
120         {
121                 return NODECONTAINER_ID_VOXELMANIPULATOR;
122         }
123         bool isValidPosition(v3s16 p)
124         {
125                 return m_area.isInside(p);
126         }
127         // These are a bit slow and shouldn't be used internally
128         MapNode getNode(v3s16 p)
129         {
130                 if(isValidPosition(p) == false)
131                         emerge(VoxelArea(p));
132
133                 MapNode &n = m_data[m_area.index(p)];
134
135                 //TODO: Is this the right behaviour?
136                 if(n.d == MATERIAL_IGNORE)
137                         throw InvalidPositionException
138                         ("Not returning MATERIAL_IGNORE in VoxelManipulator");
139
140                 return n;
141         }
142         void setNode(v3s16 p, MapNode & n)
143         {
144                 if(isValidPosition(p) == false)
145                         emerge(VoxelArea(p));
146                 m_data[m_area.index(p)] = n;
147         }
148         
149         MapNode & operator[](v3s16 p)
150         {
151                 //dstream<<"operator[] p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;
152                 if(isValidPosition(p) == false)
153                         emerge(VoxelArea(p));
154                 return m_data[m_area.index(p)];
155         }
156
157         /*
158                 Manipulation of bigger chunks
159         */
160         
161         void print(std::ostream &o);
162         
163         void addArea(VoxelArea area);
164
165         void interpolate(VoxelArea area);
166
167         /*void blitFromNodeContainer
168                         (v3s16 p_from, v3s16 p_to, v3s16 size, NodeContainer *c);
169         
170         void blitToNodeContainer
171                         (v3s16 p_from, v3s16 p_to, v3s16 size, NodeContainer *c);*/
172
173         /*
174                 Virtual functions
175         */
176         
177         /*
178                 Get the contents of the requested area from somewhere.
179
180                 If not found from source, add as MATERIAL_IGNORE.
181         */
182         virtual void emerge(VoxelArea a)
183         {
184                 //dstream<<"emerge p=("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;
185                 addArea(a);
186         }
187
188         /*
189                 Member variables
190         */
191
192         /*
193                 The area that is stored in m_data.
194                 addInternalBox should not be used if getExtent() == v3s16(0,0,0)
195                 MaxEdge is 1 higher than maximum allowed position
196         */
197         VoxelArea m_area;
198         /*
199                 NULL if data size is 0
200                 Data is stored as [z*h*w + y*h + x]
201                 Special data values:
202                         MATERIAL_IGNORE: Unspecified node
203         */
204         MapNode *m_data;
205 private:
206 };
207
208 class Map;
209
210 class MapVoxelManipulator : public VoxelManipulator
211 {
212 public:
213         MapVoxelManipulator(Map *map);
214
215         virtual void emerge(VoxelArea a);
216
217         void blitBack(core::map<v3s16, MapBlock*> & modified_blocks);
218
219 private:
220         Map *m_map;
221 };
222
223 #endif
224