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