]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapnode.h
0d65f30a48cc209993010241446199a040f147e5
[dragonfireclient.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         TODO: These should be named to "content" or something like that
61 */
62
63 enum Material
64 {
65         MATERIAL_STONE=0,
66
67         MATERIAL_GRASS,
68
69         MATERIAL_WATER,
70
71         MATERIAL_LIGHT,
72
73         MATERIAL_TREE,
74         
75         MATERIAL_LEAVES,
76
77         MATERIAL_GRASS_FOOTSTEPS,
78         
79         MATERIAL_MESE,
80
81         MATERIAL_MUD,
82
83         MATERIAL_OCEAN,
84         
85         // This is set to the number of the actual values in this enum
86         USEFUL_MATERIAL_COUNT
87 };
88
89 /*
90         If true, the material allows light propagation and brightness is stored
91         in param.
92 */
93 inline bool light_propagates_material(u8 m)
94 {
95         return (m == MATERIAL_AIR || m == MATERIAL_LIGHT || m == MATERIAL_WATER || m == MATERIAL_OCEAN);
96 }
97
98 /*
99         If true, the material allows lossless sunlight propagation.
100 */
101 inline bool sunlight_propagates_material(u8 m)
102 {
103         return (m == MATERIAL_AIR);
104 }
105
106 /*
107         On a node-node surface, the material of the node with higher solidness
108         is used for drawing.
109         0: Invisible
110         1: Transparent
111         2: Opaque
112 */
113 inline u8 material_solidness(u8 m)
114 {
115         if(m == MATERIAL_AIR)
116                 return 0;
117         if(m == MATERIAL_WATER || m == MATERIAL_OCEAN)
118                 return 1;
119         return 2;
120 }
121
122 // Objects collide with walkable materials
123 inline bool material_walkable(u8 m)
124 {
125         return (m != MATERIAL_AIR && m != MATERIAL_WATER && m != MATERIAL_OCEAN && m != MATERIAL_LIGHT);
126 }
127
128 // A liquid resists fast movement
129 inline bool material_liquid(u8 m)
130 {
131         return (m == MATERIAL_WATER || m == MATERIAL_OCEAN);
132 }
133
134 // Pointable materials can be pointed to in the map
135 inline bool material_pointable(u8 m)
136 {
137         return (m != MATERIAL_AIR && m != MATERIAL_WATER && m != MATERIAL_OCEAN);
138 }
139
140 inline bool material_diggable(u8 m)
141 {
142         return (m != MATERIAL_AIR && m != MATERIAL_WATER && m != MATERIAL_OCEAN);
143 }
144
145 inline bool material_buildable_to(u8 m)
146 {
147         return (m == MATERIAL_AIR || m == MATERIAL_WATER || m == MATERIAL_OCEAN);
148 }
149
150 /*
151         As of now, input is a "material" and the output is a "material"
152 */
153 inline u8 content_cube_material(u8 c)
154 {
155         if(c == MATERIAL_IGNORE || c == MATERIAL_LIGHT)
156                 return MATERIAL_AIR;
157         return c;
158 }
159
160 /*
161         Returns true for materials that form the base ground that
162         follows the main heightmap
163 */
164 inline bool is_ground_material(u8 m)
165 {
166         return(
167                 m == MATERIAL_STONE ||
168                 m == MATERIAL_GRASS ||
169                 m == MATERIAL_GRASS_FOOTSTEPS ||
170                 m == MATERIAL_MESE ||
171                 m == MATERIAL_MUD
172         );
173 }
174
175 /*
176         Nodes make a face if materials differ and solidness differs.
177         Return value:
178                 0: No face
179                 1: Face uses m1's material
180                 2: Face uses m2's material
181 */
182 inline u8 face_materials(u8 m1, u8 m2)
183 {
184         if(m1 == MATERIAL_IGNORE || m2 == MATERIAL_IGNORE)
185                 return 0;
186         
187         bool materials_differ = (m1 != m2);
188         bool solidness_differs = (material_solidness(m1) != material_solidness(m2));
189         bool makes_face = materials_differ && solidness_differs;
190
191         if(makes_face == false)
192                 return 0;
193
194         if(material_solidness(m1) > material_solidness(m2))
195                 return 1;
196         else
197                 return 2;
198 }
199
200 struct MapNode
201 {
202         //TODO: block type to differ from material
203         //      (e.g. grass edges or something)
204         // block type
205         u8 d;
206
207         /*
208                 Misc parameter. Initialized to 0.
209                 - For light_propagates() blocks, this is light intensity,
210                   stored logarithmically from 0 to LIGHT_MAX.
211                   Sunlight is LIGHT_SUN, which is LIGHT_MAX+1.
212         */
213         s8 param;
214
215         u8 pressure;
216
217         MapNode(const MapNode & n)
218         {
219                 *this = n;
220         }
221         
222         MapNode(u8 data=MATERIAL_AIR, u8 a_param=0, u8 a_pressure=0)
223         {
224                 d = data;
225                 param = a_param;
226                 pressure = a_pressure;
227         }
228
229         bool operator==(const MapNode &other)
230         {
231                 return (d == other.d
232                                 && param == other.param
233                                 && pressure == other.pressure);
234         }
235
236         bool light_propagates()
237         {
238                 return light_propagates_material(d);
239         }
240         
241         bool sunlight_propagates()
242         {
243                 return sunlight_propagates_material(d);
244         }
245         
246         u8 solidness()
247         {
248                 return material_solidness(d);
249         }
250
251         u8 light_source()
252         {
253                 /*
254                         Note that a block that isn't light_propagates() can be a light source.
255                 */
256                 if(d == MATERIAL_LIGHT)
257                         return LIGHT_MAX;
258                 
259                 return 0;
260         }
261
262         u8 getLight()
263         {
264                 // Select the brightest of [light_source, transparent_light]
265                 u8 light = 0;
266                 if(light_propagates())
267                         light = param & 0x0f;
268                 if(light_source() > light)
269                         light = light_source();
270                 return light;
271         }
272
273         void setLight(u8 a_light)
274         {
275                 // If not transparent, can't set light
276                 if(light_propagates() == false)
277                         return;
278                 param = a_light;
279         }
280
281         /*
282                 These serialization functions are used when informing client
283                 of a single node add
284         */
285
286         static u32 serializedLength(u8 version)
287         {
288                 if(!ser_ver_supported(version))
289                         throw VersionMismatchException("ERROR: MapNode format not supported");
290                         
291                 if(version == 0)
292                         return 1;
293                 else if(version <= 9)
294                         return 2;
295                 else
296                         return 3;
297         }
298         void serialize(u8 *dest, u8 version)
299         {
300                 if(!ser_ver_supported(version))
301                         throw VersionMismatchException("ERROR: MapNode format not supported");
302                         
303                 if(version == 0)
304                 {
305                         dest[0] = d;
306                 }
307                 else if(version <= 9)
308                 {
309                         dest[0] = d;
310                         dest[1] = param;
311                 }
312                 else
313                 {
314                         dest[0] = d;
315                         dest[1] = param;
316                         dest[2] = pressure;
317                 }
318         }
319         void deSerialize(u8 *source, u8 version)
320         {
321                 if(!ser_ver_supported(version))
322                         throw VersionMismatchException("ERROR: MapNode format not supported");
323                         
324                 if(version == 0)
325                 {
326                         d = source[0];
327                 }
328                 else if(version == 1)
329                 {
330                         d = source[0];
331                         // This version doesn't support saved lighting
332                         if(light_propagates() || light_source() > 0)
333                                 param = 0;
334                         else
335                                 param = source[1];
336                 }
337                 else if(version <= 9)
338                 {
339                         d = source[0];
340                         param = source[1];
341                 }
342                 else
343                 {
344                         d = source[0];
345                         param = source[1];
346                         pressure = source[2];
347                 }
348         }
349 };
350
351 /*
352         Returns integer position of the node in given
353         floating point position.
354 */
355 inline v3s16 floatToInt(v3f p)
356 {
357         v3s16 p2(
358                 (p.X + (p.X>0 ? BS/2 : -BS/2))/BS,
359                 (p.Y + (p.Y>0 ? BS/2 : -BS/2))/BS,
360                 (p.Z + (p.Z>0 ? BS/2 : -BS/2))/BS);
361         return p2;
362 }
363
364 inline v3f intToFloat(v3s16 p)
365 {
366         v3f p2(
367                 p.X * BS,
368                 p.Y * BS,
369                 p.Z * BS
370         );
371         return p2;
372 }
373
374
375
376 #endif
377