Initial files
[oweals/minetest.git] / src / mapnode.h
1 /*
2 (c) 2010 Perttu Ahola <celeron55@gmail.com>
3 */
4
5 #ifndef MAPNODE_HEADER
6 #define MAPNODE_HEADER
7
8 #include <iostream>
9 #include "common_irrlicht.h"
10 #include "light.h"
11 #include "utility.h"
12 #include "exceptions.h"
13 #include "serialization.h"
14
15 // Size of node in rendering units
16 #define BS 10
17
18 #define MATERIALS_COUNT 256
19
20 // This is completely ignored. It doesn't create faces with anything.
21 #define MATERIAL_IGNORE 255
22 // This is the common material through which the player can walk
23 // and which is transparent to light
24 #define MATERIAL_AIR 254
25
26 /*
27         Materials-todo:
28
29         GRAVEL
30           - Dynamics of gravel: if there is a drop of more than two
31             blocks on any side, it will drop in there. Is this doable?
32 */
33
34 enum Material
35 {
36         MATERIAL_STONE=0,
37
38         MATERIAL_GRASS,
39
40         /*
41                 For water, the param is water pressure. 0...127.
42                 TODO: No, at least the lowest nibble is used for lighting.
43                 
44                 - Water will be a bit like light, but with different flow
45                   behavior.
46                 - Water blocks will fall down if there is empty space below.
47                 - If there is water below, the pressure of the block below is
48                   the pressure of the current block + 1, or higher.
49                 - If there is any pressure in a horizontally neighboring
50                   block, a water block will try to move away from it.
51                 - If there is >=2 of pressure in a block below, water will
52                   try to move upwards.
53                 - NOTE: To keep large operations fast, we have to keep a
54                         cache of the water-air-surfaces, just like with light
55         */
56         MATERIAL_WATER,
57
58         MATERIAL_LIGHT,
59
60         MATERIAL_TREE,
61         MATERIAL_LEAVES,
62
63         MATERIAL_GRASS_FOOTSTEPS,
64         
65         MATERIAL_MESE,
66         
67         // This is set to the number of the actual values in this enum
68         USEFUL_MATERIAL_COUNT
69 };
70
71 /*
72         If true, the material allows light propagation and brightness is stored
73         in param.
74 */
75 inline bool light_propagates_material(u8 m)
76 {
77         return (m == MATERIAL_AIR || m == MATERIAL_LIGHT || m == MATERIAL_WATER);
78 }
79
80 /*
81         If true, the material allows lossless sunlight propagation.
82 */
83 inline bool sunlight_propagates_material(u8 m)
84 {
85         return (m == MATERIAL_AIR);
86 }
87
88 /*
89         On a node-node surface, the material of the node with higher solidness
90         is used for drawing.
91         0: Invisible
92         1: Transparent
93         2: Opaque
94 */
95 inline u8 material_solidness(u8 m)
96 {
97         if(m == MATERIAL_AIR)
98                 return 0;
99         if(m == MATERIAL_WATER)
100                 return 1;
101         return 2;
102 }
103
104 /*
105         Nodes make a face if materials differ and solidness differs.
106         Return value:
107                 0: No face
108                 1: Face uses m1's material
109                 2: Face uses m2's material
110 */
111 inline u8 face_materials(u8 m1, u8 m2)
112 {
113         if(m1 == MATERIAL_IGNORE || m2 == MATERIAL_IGNORE)
114                 return 0;
115         
116         bool materials_differ = (m1 != m2);
117         bool solidness_differs = (material_solidness(m1) != material_solidness(m2));
118         bool makes_face = materials_differ && solidness_differs;
119
120         if(makes_face == false)
121                 return 0;
122
123         if(material_solidness(m1) > material_solidness(m2))
124                 return 1;
125         else
126                 return 2;
127 }
128
129 struct MapNode
130 {
131         //TODO: block type to differ from material
132         //      (e.g. grass edges or something)
133         // block type
134         u8 d;
135
136         // Removed because light is now stored in param for air
137         // f32 light;
138
139         /*
140                 Misc parameter. Initialized to 0.
141                 - For light_propagates() blocks, this is light intensity,
142                   stored logarithmically from 0 to LIGHT_MAX.
143                   Sunlight is LIGHT_SUN, which is LIGHT_MAX+1.
144         */
145         s8 param;
146
147         MapNode(const MapNode & n)
148         {
149                 *this = n;
150         }
151         
152         MapNode(u8 data=MATERIAL_AIR, u8 a_param=0)
153         {
154                 d = data;
155                 param = a_param;
156         }
157
158         bool light_propagates()
159         {
160                 return light_propagates_material(d);
161         }
162         
163         bool sunlight_propagates()
164         {
165                 return sunlight_propagates_material(d);
166         }
167         
168         u8 solidness()
169         {
170                 return material_solidness(d);
171         }
172
173         u8 light_source()
174         {
175                 /*
176                         Note that a block that isn't light_propagates() can be a light source.
177                 */
178                 if(d == MATERIAL_LIGHT)
179                         return LIGHT_MAX;
180                 
181                 return 0;
182         }
183
184         u8 getLight()
185         {
186                 // Select the brightest of [light_source, transparent_light]
187                 u8 light = 0;
188                 if(light_propagates())
189                         light = param & 0x0f;
190                 if(light_source() > light)
191                         light = light_source();
192                 return light;
193         }
194
195         void setLight(u8 a_light)
196         {
197                 // If not transparent, can't set light
198                 if(light_propagates() == false)
199                         return;
200                 param = a_light;
201         }
202
203         static u32 serializedLength(u8 version)
204         {
205                 if(!ser_ver_supported(version))
206                         throw VersionMismatchException("ERROR: MapNode format not supported");
207                         
208                 if(version == 0)
209                         return 1;
210                 else
211                         return 2;
212         }
213         void serialize(u8 *dest, u8 version)
214         {
215                 if(!ser_ver_supported(version))
216                         throw VersionMismatchException("ERROR: MapNode format not supported");
217                         
218                 if(version == 0)
219                 {
220                         dest[0] = d;
221                 }
222                 else
223                 {
224                         dest[0] = d;
225                         dest[1] = param;
226                 }
227         }
228         void deSerialize(u8 *source, u8 version)
229         {
230                 if(!ser_ver_supported(version))
231                         throw VersionMismatchException("ERROR: MapNode format not supported");
232                         
233                 if(version == 0)
234                 {
235                         d = source[0];
236                 }
237                 else if(version == 1)
238                 {
239                         d = source[0];
240                         // This version doesn't support saved lighting
241                         if(light_propagates() || light_source() > 0)
242                                 param = 0;
243                         else
244                                 param = source[1];
245                 }
246                 else
247                 {
248                         d = source[0];
249                         param = source[1];
250                 }
251         }
252 };
253
254 /*
255         Returns integer position of the node in given
256         floating point position.
257 */
258 inline v3s16 floatToInt(v3f p)
259 {
260         v3s16 p2(
261                 (p.X + (p.X>0 ? BS/2 : -BS/2))/BS,
262                 (p.Y + (p.Y>0 ? BS/2 : -BS/2))/BS,
263                 (p.Z + (p.Z>0 ? BS/2 : -BS/2))/BS);
264         return p2;
265 }
266
267 inline v3f intToFloat(v3s16 p)
268 {
269         v3f p2(
270                 p.X * BS,
271                 p.Y * BS,
272                 p.Z * BS
273         );
274         return p2;
275 }
276
277
278
279 #endif
280