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