]> git.lizzy.rs Git - minetest.git/blob - src/mapnode.h
some work-in-progress water stuff
[minetest.git] / src / mapnode.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 MAPNODE_HEADER
21 #define MAPNODE_HEADER
22
23 #include <iostream>
24 #include "common_irrlicht.h"
25 #include "light.h"
26 #include "utility.h"
27 #include "exceptions.h"
28 #include "serialization.h"
29
30 // Size of node in rendering units
31 #define BS 10
32
33 #define MATERIALS_COUNT 256
34
35 /*
36         Ignored node.
37
38         Anything that stores MapNodes doesn't have to preserve parameters
39         associated with this material.
40         
41         Doesn't create faces with anything and is considered being
42         out-of-map in the game map.
43 */
44 #define MATERIAL_IGNORE 255
45 #define MATERIAL_IGNORE_DEFAULT_PARAM 0
46
47 /*
48         The common material through which the player can walk and which
49         is transparent to light
50 */
51 #define MATERIAL_AIR 254
52
53 /*
54         Materials-todo:
55
56         GRAVEL
57           - Dynamics of gravel: if there is a drop of more than two
58             blocks on any side, it will drop in there. Is this doable?
59 */
60
61 enum Material
62 {
63         MATERIAL_STONE=0,
64
65         MATERIAL_GRASS,
66
67         MATERIAL_WATER,
68
69         MATERIAL_LIGHT,
70
71         MATERIAL_TREE,
72         
73         MATERIAL_LEAVES,
74
75         MATERIAL_GRASS_FOOTSTEPS,
76         
77         MATERIAL_MESE,
78
79         MATERIAL_MUD,
80         
81         // This is set to the number of the actual values in this enum
82         USEFUL_MATERIAL_COUNT
83 };
84
85 /*
86         If true, the material allows light propagation and brightness is stored
87         in param.
88 */
89 inline bool light_propagates_material(u8 m)
90 {
91         return (m == MATERIAL_AIR || m == MATERIAL_LIGHT || m == MATERIAL_WATER);
92 }
93
94 /*
95         If true, the material allows lossless sunlight propagation.
96 */
97 inline bool sunlight_propagates_material(u8 m)
98 {
99         return (m == MATERIAL_AIR);
100 }
101
102 /*
103         On a node-node surface, the material of the node with higher solidness
104         is used for drawing.
105         0: Invisible
106         1: Transparent
107         2: Opaque
108 */
109 inline u8 material_solidness(u8 m)
110 {
111         if(m == MATERIAL_AIR)
112                 return 0;
113         if(m == MATERIAL_WATER)
114                 return 1;
115         return 2;
116 }
117
118 // Objects collide with walkable materials
119 inline bool material_walkable(u8 m)
120 {
121         return (m != MATERIAL_AIR && m != MATERIAL_WATER);
122 }
123
124 // A liquid resists fast movement
125 inline bool material_liquid(u8 m)
126 {
127         return (m == MATERIAL_WATER);
128 }
129
130 // Pointable materials can be pointed to in the map
131 inline bool material_pointable(u8 m)
132 {
133         return (m != MATERIAL_AIR && m != MATERIAL_WATER);
134 }
135
136 inline bool material_diggable(u8 m)
137 {
138         return (m != MATERIAL_AIR && m != MATERIAL_WATER);
139 }
140
141 inline bool material_buildable_to(u8 m)
142 {
143         return (m == MATERIAL_AIR || m == MATERIAL_WATER);
144 }
145
146 /*
147         Nodes make a face if materials differ and solidness differs.
148         Return value:
149                 0: No face
150                 1: Face uses m1's material
151                 2: Face uses m2's material
152 */
153 inline u8 face_materials(u8 m1, u8 m2)
154 {
155         if(m1 == MATERIAL_IGNORE || m2 == MATERIAL_IGNORE)
156                 return 0;
157         
158         bool materials_differ = (m1 != m2);
159         bool solidness_differs = (material_solidness(m1) != material_solidness(m2));
160         bool makes_face = materials_differ && solidness_differs;
161
162         if(makes_face == false)
163                 return 0;
164
165         if(material_solidness(m1) > material_solidness(m2))
166                 return 1;
167         else
168                 return 2;
169 }
170
171 /*
172         Returns true for materials that form the base ground that
173         follows the main heightmap
174 */
175 inline bool is_ground_material(u8 m)
176 {
177         return(
178                 m == MATERIAL_STONE ||
179                 m == MATERIAL_GRASS ||
180                 m == MATERIAL_GRASS_FOOTSTEPS ||
181                 m == MATERIAL_MESE ||
182                 m == MATERIAL_MUD
183         );
184 }
185
186 struct MapNode
187 {
188         //TODO: block type to differ from material
189         //      (e.g. grass edges or something)
190         // block type
191         u8 d;
192
193         /*
194                 Misc parameter. Initialized to 0.
195                 - For light_propagates() blocks, this is light intensity,
196                   stored logarithmically from 0 to LIGHT_MAX.
197                   Sunlight is LIGHT_SUN, which is LIGHT_MAX+1.
198         */
199         s8 param;
200
201         u8 pressure;
202
203         MapNode(const MapNode & n)
204         {
205                 *this = n;
206         }
207         
208         MapNode(u8 data=MATERIAL_AIR, u8 a_param=0)
209         {
210                 d = data;
211                 param = a_param;
212         }
213
214         bool operator==(const MapNode &other)
215         {
216                 return (d == other.d && param == other.param);
217         }
218
219         bool light_propagates()
220         {
221                 return light_propagates_material(d);
222         }
223         
224         bool sunlight_propagates()
225         {
226                 return sunlight_propagates_material(d);
227         }
228         
229         u8 solidness()
230         {
231                 return material_solidness(d);
232         }
233
234         u8 light_source()
235         {
236                 /*
237                         Note that a block that isn't light_propagates() can be a light source.
238                 */
239                 if(d == MATERIAL_LIGHT)
240                         return LIGHT_MAX;
241                 
242                 return 0;
243         }
244
245         u8 getLight()
246         {
247                 // Select the brightest of [light_source, transparent_light]
248                 u8 light = 0;
249                 if(light_propagates())
250                         light = param & 0x0f;
251                 if(light_source() > light)
252                         light = light_source();
253                 return light;
254         }
255
256         void setLight(u8 a_light)
257         {
258                 // If not transparent, can't set light
259                 if(light_propagates() == false)
260                         return;
261                 param = a_light;
262         }
263
264         static u32 serializedLength(u8 version)
265         {
266                 if(!ser_ver_supported(version))
267                         throw VersionMismatchException("ERROR: MapNode format not supported");
268                         
269                 if(version == 0)
270                         return 1;
271                 else
272                         return 2;
273         }
274         void serialize(u8 *dest, u8 version)
275         {
276                 if(!ser_ver_supported(version))
277                         throw VersionMismatchException("ERROR: MapNode format not supported");
278                         
279                 if(version == 0)
280                 {
281                         dest[0] = d;
282                 }
283                 else
284                 {
285                         dest[0] = d;
286                         dest[1] = param;
287                 }
288         }
289         void deSerialize(u8 *source, u8 version)
290         {
291                 if(!ser_ver_supported(version))
292                         throw VersionMismatchException("ERROR: MapNode format not supported");
293                         
294                 if(version == 0)
295                 {
296                         d = source[0];
297                 }
298                 else if(version == 1)
299                 {
300                         d = source[0];
301                         // This version doesn't support saved lighting
302                         if(light_propagates() || light_source() > 0)
303                                 param = 0;
304                         else
305                                 param = source[1];
306                 }
307                 else
308                 {
309                         d = source[0];
310                         param = source[1];
311                 }
312         }
313 };
314
315 /*
316         Returns integer position of the node in given
317         floating point position.
318 */
319 inline v3s16 floatToInt(v3f p)
320 {
321         v3s16 p2(
322                 (p.X + (p.X>0 ? BS/2 : -BS/2))/BS,
323                 (p.Y + (p.Y>0 ? BS/2 : -BS/2))/BS,
324                 (p.Z + (p.Z>0 ? BS/2 : -BS/2))/BS);
325         return p2;
326 }
327
328 inline v3f intToFloat(v3s16 p)
329 {
330         v3f p2(
331                 p.X * BS,
332                 p.Y * BS,
333                 p.Z * BS
334         );
335         return p2;
336 }
337
338
339
340 #endif
341