]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapnode.h
9d9aba8999acf5fbf7a43ebd1c462be40f81ebc4
[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 CONTENT_IGNORE 255
45 #define CONTENT_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 CONTENT_AIR 254
52
53 /*
54         Suggested materials:
55         GRAVEL
56           - Dynamics of gravel: if there is a drop of more than two
57             blocks on any side, it will drop in there. Is this doable?
58         
59         New naming scheme:
60         - Material = irrlicht's Material class
61         - Content = (u8) content of a node
62         - Tile = (u16) Material ID at some side of a node
63 */
64
65 enum Content
66 {
67         CONTENT_STONE=0,
68
69         CONTENT_GRASS,
70
71         CONTENT_WATER,
72
73         CONTENT_LIGHT,
74
75         CONTENT_TREE,
76         
77         CONTENT_LEAVES,
78
79         CONTENT_GRASS_FOOTSTEPS,
80         
81         CONTENT_MESE,
82
83         CONTENT_MUD,
84
85         CONTENT_OCEAN,
86         
87         // This is set to the number of the actual values in this enum
88         USEFUL_CONTENT_COUNT
89 };
90
91 /*
92         If true, the material allows light propagation and brightness is stored
93         in param.
94 */
95 inline bool light_propagates_content(u8 m)
96 {
97         return (m == CONTENT_AIR || m == CONTENT_LIGHT || m == CONTENT_WATER || m == CONTENT_OCEAN);
98 }
99
100 /*
101         If true, the material allows lossless sunlight propagation.
102 */
103 inline bool sunlight_propagates_content(u8 m)
104 {
105         return (m == CONTENT_AIR || m == CONTENT_LIGHT);
106 }
107
108 /*
109         On a node-node surface, the material of the node with higher solidness
110         is used for drawing.
111         0: Invisible
112         1: Transparent
113         2: Opaque
114 */
115 inline u8 content_solidness(u8 m)
116 {
117         if(m == CONTENT_AIR)
118                 return 0;
119         if(m == CONTENT_WATER || m == CONTENT_OCEAN)
120                 return 1;
121         return 2;
122 }
123
124 // Objects collide with walkable contents
125 inline bool content_walkable(u8 m)
126 {
127         return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_OCEAN && m != CONTENT_LIGHT);
128 }
129
130 // A liquid resists fast movement
131 inline bool content_liquid(u8 m)
132 {
133         return (m == CONTENT_WATER || m == CONTENT_OCEAN);
134 }
135
136 // Pointable contents can be pointed to in the map
137 inline bool content_pointable(u8 m)
138 {
139         return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_OCEAN);
140 }
141
142 inline bool content_diggable(u8 m)
143 {
144         return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_OCEAN);
145 }
146
147 inline bool content_buildable_to(u8 m)
148 {
149         return (m == CONTENT_AIR || m == CONTENT_WATER || m == CONTENT_OCEAN);
150 }
151
152 /*
153         TODO: Make a mapper class for mapping every side of a content
154               to some tile.
155         This dumbily maps all sides of content to the tile of the same id.
156 */
157 inline u8 content_tile(u8 c)
158 {
159         if(c == CONTENT_IGNORE || c == CONTENT_LIGHT)
160                 return CONTENT_AIR;
161         return c;
162 }
163
164 /*
165         Returns true for contents that form the base ground that
166         follows the main heightmap
167 */
168 inline bool is_ground_content(u8 m)
169 {
170         return(
171                 m == CONTENT_STONE ||
172                 m == CONTENT_GRASS ||
173                 m == CONTENT_GRASS_FOOTSTEPS ||
174                 m == CONTENT_MESE ||
175                 m == CONTENT_MUD
176         );
177 }
178
179 /*
180         Nodes make a face if contents differ and solidness differs.
181         Return value:
182                 0: No face
183                 1: Face uses m1's content
184                 2: Face uses m2's content
185 */
186 inline u8 face_contents(u8 m1, u8 m2)
187 {
188         if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
189                 return 0;
190         
191         bool contents_differ = (m1 != m2);
192         bool solidness_differs = (content_solidness(m1) != content_solidness(m2));
193         bool makes_face = contents_differ && solidness_differs;
194
195         if(makes_face == false)
196                 return 0;
197
198         if(content_solidness(m1) > content_solidness(m2))
199                 return 1;
200         else
201                 return 2;
202 }
203
204 inline bool liquid_replaces_content(u8 c)
205 {
206         return (c == CONTENT_AIR || c == CONTENT_LIGHT);
207 }
208
209 /*
210         When placing a node, drection info is added to it if this is true
211 */
212 inline bool content_directional(u8 c)
213 {
214         return (c == CONTENT_LIGHT);
215 }
216
217 /*
218         Packs directions like (1,0,0), (1,-1,0)
219 */
220 inline u8 packDir(v3s16 dir)
221 {
222         u8 b = 0;
223
224         if(dir.X > 0)
225                 b |= (1<<0);
226         else if(dir.X < 0)
227                 b |= (1<<1);
228
229         if(dir.Y > 0)
230                 b |= (1<<2);
231         else if(dir.Y < 0)
232                 b |= (1<<3);
233
234         if(dir.Z > 0)
235                 b |= (1<<4);
236         else if(dir.Z < 0)
237                 b |= (1<<5);
238         
239         return b;
240 }
241 inline v3s16 unpackDir(u8 b)
242 {
243         v3s16 d(0,0,0);
244
245         if(b & (1<<0))
246                 d.X = 1;
247         else if(b & (1<<1))
248                 d.X = -1;
249
250         if(b & (1<<2))
251                 d.Y = 1;
252         else if(b & (1<<3))
253                 d.Y = -1;
254
255         if(b & (1<<4))
256                 d.Z = 1;
257         else if(b & (1<<5))
258                 d.Z = -1;
259         
260         return d;
261 }
262
263 struct MapNode
264 {
265         // Content
266         u8 d;
267
268         /*
269                 Misc parameter. Initialized to 0.
270                 - For light_propagates() blocks, this is light intensity,
271                   stored logarithmically from 0 to LIGHT_MAX.
272                   Sunlight is LIGHT_SUN, which is LIGHT_MAX+1.
273         */
274         s8 param;
275         
276         union
277         {
278                 /*
279                         Pressure for liquids
280                 */
281                 u8 pressure;
282
283                 /*
284                         Direction for torches and other stuff.
285                         If possible, packed with packDir.
286                 */
287                 u8 dir;
288         };
289
290         MapNode(const MapNode & n)
291         {
292                 *this = n;
293         }
294         
295         MapNode(u8 data=CONTENT_AIR, u8 a_param=0, u8 a_pressure=0)
296         {
297                 d = data;
298                 param = a_param;
299                 pressure = a_pressure;
300         }
301
302         bool operator==(const MapNode &other)
303         {
304                 return (d == other.d
305                                 && param == other.param
306                                 && pressure == other.pressure);
307         }
308
309         bool light_propagates()
310         {
311                 return light_propagates_content(d);
312         }
313         
314         bool sunlight_propagates()
315         {
316                 return sunlight_propagates_content(d);
317         }
318         
319         u8 solidness()
320         {
321                 return content_solidness(d);
322         }
323
324         u8 light_source()
325         {
326                 /*
327                         Note that a block that isn't light_propagates() can be a light source.
328                 */
329                 if(d == CONTENT_LIGHT)
330                         return LIGHT_MAX;
331                 
332                 return 0;
333         }
334
335         u8 getLight()
336         {
337                 // Select the brightest of [light source, propagated light]
338                 u8 light = 0;
339                 if(light_propagates())
340                         light = param & 0x0f;
341                 if(light_source() > light)
342                         light = light_source();
343                 return light;
344         }
345
346         void setLight(u8 a_light)
347         {
348                 // If not transparent, can't set light
349                 if(light_propagates() == false)
350                         return;
351                 param = a_light;
352         }
353
354         /*
355                 These serialization functions are used when informing client
356                 of a single node add
357         */
358
359         static u32 serializedLength(u8 version)
360         {
361                 if(!ser_ver_supported(version))
362                         throw VersionMismatchException("ERROR: MapNode format not supported");
363                         
364                 if(version == 0)
365                         return 1;
366                 else if(version <= 9)
367                         return 2;
368                 else
369                         return 3;
370         }
371         void serialize(u8 *dest, u8 version)
372         {
373                 if(!ser_ver_supported(version))
374                         throw VersionMismatchException("ERROR: MapNode format not supported");
375                         
376                 if(version == 0)
377                 {
378                         dest[0] = d;
379                 }
380                 else if(version <= 9)
381                 {
382                         dest[0] = d;
383                         dest[1] = param;
384                 }
385                 else
386                 {
387                         dest[0] = d;
388                         dest[1] = param;
389                         dest[2] = pressure;
390                 }
391         }
392         void deSerialize(u8 *source, u8 version)
393         {
394                 if(!ser_ver_supported(version))
395                         throw VersionMismatchException("ERROR: MapNode format not supported");
396                         
397                 if(version == 0)
398                 {
399                         d = source[0];
400                 }
401                 else if(version == 1)
402                 {
403                         d = source[0];
404                         // This version doesn't support saved lighting
405                         if(light_propagates() || light_source() > 0)
406                                 param = 0;
407                         else
408                                 param = source[1];
409                 }
410                 else if(version <= 9)
411                 {
412                         d = source[0];
413                         param = source[1];
414                 }
415                 else
416                 {
417                         d = source[0];
418                         param = source[1];
419                         pressure = source[2];
420                 }
421         }
422 };
423
424 /*
425         Returns integer position of the node in given
426         floating point position.
427 */
428 inline v3s16 floatToInt(v3f p)
429 {
430         v3s16 p2(
431                 (p.X + (p.X>0 ? BS/2 : -BS/2))/BS,
432                 (p.Y + (p.Y>0 ? BS/2 : -BS/2))/BS,
433                 (p.Z + (p.Z>0 ? BS/2 : -BS/2))/BS);
434         return p2;
435 }
436
437 inline v3f intToFloat(v3s16 p)
438 {
439         v3f p2(
440                 p.X * BS,
441                 p.Y * BS,
442                 p.Z * BS
443         );
444         return p2;
445 }
446
447
448
449 #endif
450