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