]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapnode.h
old water removed, some fixes here and there
[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 #define MATERIALS_COUNT 256
32
33 /*
34         Ignored node.
35
36         Anything that stores MapNodes doesn't have to preserve parameters
37         associated with this material.
38         
39         Doesn't create faces with anything and is considered being
40         out-of-map in the game map.
41 */
42 #define CONTENT_IGNORE 255
43 #define CONTENT_IGNORE_DEFAULT_PARAM 0
44
45 /*
46         The common material through which the player can walk and which
47         is transparent to light
48 */
49 #define CONTENT_AIR 254
50
51 /*
52         Suggested materials:
53         - Gravel
54         - Sand
55         
56         New naming scheme:
57         - Material = irrlicht's Material class
58         - Content = (u8) content of a node
59         - Tile = (u16) Material ID at some side of a node
60 */
61
62 #define CONTENT_STONE 0
63 #define CONTENT_GRASS 1
64 #define CONTENT_WATER 2
65 #define CONTENT_TORCH 3
66 #define CONTENT_TREE 4
67 #define CONTENT_LEAVES 5
68 #define CONTENT_GRASS_FOOTSTEPS 6
69 #define CONTENT_MESE 7
70 #define CONTENT_MUD 8
71 #define CONTENT_WATERSOURCE 9
72 #define CONTENT_CLOUD 10
73 #define CONTENT_COALSTONE 11
74 #define CONTENT_WOOD 12
75         
76 #define USEFUL_CONTENT_COUNT 13
77
78 extern u16 g_content_tiles[USEFUL_CONTENT_COUNT][6];
79 extern const char * g_content_inventory_texture_paths[USEFUL_CONTENT_COUNT];
80 // Initializes g_content_inventory_texture_paths
81 void init_content_inventory_texture_paths();
82
83 /*
84         If true, the material allows light propagation and brightness is stored
85         in param.
86 */
87 inline bool light_propagates_content(u8 m)
88 {
89         return (m == CONTENT_AIR || m == CONTENT_TORCH || m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
90 }
91
92 /*
93         If true, the material allows lossless sunlight propagation.
94         NOTE: It doesn't seem to go through torches regardlessly of this
95 */
96 inline bool sunlight_propagates_content(u8 m)
97 {
98         return (m == CONTENT_AIR || m == CONTENT_TORCH);
99 }
100
101 /*
102         On a node-node surface, the material of the node with higher solidness
103         is used for drawing.
104         0: Invisible
105         1: Transparent
106         2: Opaque
107 */
108 inline u8 content_solidness(u8 m)
109 {
110         // As of now, every pseudo node like torches are added to this
111         if(m == CONTENT_AIR || m == CONTENT_TORCH)
112                 return 0;
113         if(m == CONTENT_WATER || m == CONTENT_WATERSOURCE)
114                 return 1;
115         return 2;
116 }
117
118 // Objects collide with walkable contents
119 inline bool content_walkable(u8 m)
120 {
121         return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE && m != CONTENT_TORCH);
122 }
123
124 // A liquid resists fast movement
125 inline bool content_liquid(u8 m)
126 {
127         return (m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
128 }
129
130 // Pointable contents can be pointed to in the map
131 inline bool content_pointable(u8 m)
132 {
133         return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE);
134 }
135
136 inline bool content_diggable(u8 m)
137 {
138         return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE);
139 }
140
141 inline bool content_buildable_to(u8 m)
142 {
143         return (m == CONTENT_AIR || m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
144 }
145
146 /*
147         Returns true for contents that form the base ground that
148         follows the main heightmap
149 */
150 inline bool is_ground_content(u8 m)
151 {
152         return (
153                 m != CONTENT_IGNORE
154                 && m != CONTENT_AIR
155                 && m != CONTENT_WATER
156                 && m != CONTENT_TORCH
157                 && m != CONTENT_TREE
158                 && m != CONTENT_LEAVES
159                 && m != CONTENT_WATERSOURCE
160                 && m != CONTENT_CLOUD
161         );
162 }
163
164 inline bool is_mineral(u8 c)
165 {
166         return(c == CONTENT_MESE
167                 || c == CONTENT_COALSTONE);
168 }
169
170 inline bool liquid_replaces_content(u8 c)
171 {
172         return (c == CONTENT_AIR || c == CONTENT_TORCH);
173 }
174
175 /*
176         When placing a node, drection info is added to it if this is true
177 */
178 inline bool content_directional(u8 c)
179 {
180         return (c == CONTENT_TORCH);
181 }
182
183 /*
184         Nodes make a face if contents differ and solidness differs.
185         Return value:
186                 0: No face
187                 1: Face uses m1's content
188                 2: Face uses m2's content
189 */
190 inline u8 face_contents(u8 m1, u8 m2)
191 {
192         if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
193                 return 0;
194         
195         bool contents_differ = (m1 != m2);
196         bool solidness_differs = (content_solidness(m1) != content_solidness(m2));
197         bool makes_face = contents_differ && solidness_differs;
198
199         if(makes_face == false)
200                 return 0;
201
202         if(content_solidness(m1) > content_solidness(m2))
203                 return 1;
204         else
205                 return 2;
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 enum LightBank
283 {
284         LIGHTBANK_DAY,
285         LIGHTBANK_NIGHT
286 };
287
288 #if 0
289 #define DIR_PX 1 //X+
290 #define DIR_NX 2 //X-
291 #define DIR_PZ 4 //Z+
292 #define DIR_NZ 8 //Z-
293 #define DIR_PY 16 //Y+
294 #define DIR_NY 32 //Y-
295
296 inline void decode_dirs(u8 b, core::list<v3s16> &dirs)
297 {
298         if(b & DIR_PX)
299                 dirs.push_back(v3s16(1,0,0));
300         if(b & DIR_NX)
301                 dirs.push_back(v3s16(-1,0,0));
302         if(b & DIR_PZ)
303                 dirs.push_back(v3s16(0,0,1));
304         if(b & DIR_NZ)
305                 dirs.push_back(v3s16(0,0,-1));
306         if(b & DIR_PY)
307                 dirs.push_back(v3s16(0,1,0));
308         if(b & DIR_NY)
309                 dirs.push_back(v3s16(0,-1,0));
310 }
311
312 inline u8 encode_dirs(core::list<v3s16> &dirs)
313 {
314         u8 b = 0;
315         for(core::list<v3s16>::Iterator
316                         i = dirs.begin();
317                         i != dirs.end(); i++)
318         {
319                 if(*i == v3s16(1,0,0))
320                         b += DIR_PX;
321                 else if(*i == v3s16(-1,0,0))
322                         b += DIR_NX;
323                 else if(*i == v3s16(0,0,1))
324                         b += DIR_PZ;
325                 else if(*i == v3s16(0,0,-1))
326                         b += DIR_NZ;
327                 else if(*i == v3s16(0,1,0))
328                         b += DIR_PY;
329                 else if(*i == v3s16(0,-1,0))
330                         b += DIR_NY;
331         }
332         return b;
333 }
334 #endif
335
336 struct MapNode
337 {
338         // Content
339         u8 d;
340
341         /*
342                 Misc parameter. Initialized to 0.
343                 - For light_propagates() blocks, this is light intensity,
344                   stored logarithmically from 0 to LIGHT_MAX.
345                   Sunlight is LIGHT_SUN, which is LIGHT_MAX+1.
346                 - Contains 2 values, day- and night lighting. Each takes 4 bits.
347         */
348         s8 param;
349         
350         union
351         {
352                 /*
353                         Pressure for liquids
354                 */
355                 u8 pressure;
356
357                 /*
358                         Direction for torches and other stuff.
359                         Format is freeform. e.g. packDir or encode_dirs can be used.
360                 */
361                 u8 dir;
362         };
363
364         MapNode(const MapNode & n)
365         {
366                 *this = n;
367         }
368         
369         MapNode(u8 data=CONTENT_AIR, u8 a_param=0, u8 a_pressure=0)
370         {
371                 d = data;
372                 param = a_param;
373                 pressure = a_pressure;
374         }
375
376         bool operator==(const MapNode &other)
377         {
378                 return (d == other.d
379                                 && param == other.param
380                                 && pressure == other.pressure);
381         }
382
383         bool light_propagates()
384         {
385                 return light_propagates_content(d);
386         }
387         
388         bool sunlight_propagates()
389         {
390                 return sunlight_propagates_content(d);
391         }
392         
393         u8 solidness()
394         {
395                 return content_solidness(d);
396         }
397
398         u8 light_source()
399         {
400                 /*
401                         Note that a block that isn't light_propagates() can be a light source.
402                 */
403                 if(d == CONTENT_TORCH)
404                         return LIGHT_MAX;
405                 
406                 return 0;
407         }
408
409         u8 getLightBanksWithSource()
410         {
411                 // Select the brightest of [light source, propagated light]
412                 u8 lightday = 0;
413                 u8 lightnight = 0;
414                 if(light_propagates())
415                 {
416                         lightday = param & 0x0f;
417                         lightnight = (param>>4)&0x0f;
418                 }
419                 if(light_source() > lightday)
420                         lightday = light_source();
421                 if(light_source() > lightnight)
422                         lightnight = light_source();
423                 return (lightday&0x0f) | ((lightnight<<4)&0xf0);
424         }
425
426         void setLightBanks(u8 a_light)
427         {
428                 param = a_light;
429         }
430
431         u8 getLight(enum LightBank bank)
432         {
433                 // Select the brightest of [light source, propagated light]
434                 u8 light = 0;
435                 if(light_propagates())
436                 {
437                         if(bank == LIGHTBANK_DAY)
438                                 light = param & 0x0f;
439                         else if(bank == LIGHTBANK_NIGHT)
440                                 light = (param>>4)&0x0f;
441                         else
442                                 assert(0);
443                 }
444                 if(light_source() > light)
445                         light = light_source();
446                 return light;
447         }
448         
449         // 0 <= daylight_factor <= 1000
450         // 0 <= return value <= LIGHT_SUN
451         u8 getLightBlend(u32 daylight_factor)
452         {
453                 u8 l = ((daylight_factor * getLight(LIGHTBANK_DAY)
454                         + (1000-daylight_factor) * getLight(LIGHTBANK_NIGHT))
455                         )/1000;
456                 u8 max = LIGHT_MAX;
457                 if(getLight(LIGHTBANK_DAY) == LIGHT_SUN)
458                         max = LIGHT_SUN;
459                 if(l > max)
460                         l = max;
461                 return l;
462         }
463         /*// 0 <= daylight_factor <= 1000
464         // 0 <= return value <= 255
465         u8 getLightBlend(u32 daylight_factor)
466         {
467                 u8 daylight = decode_light(getLight(LIGHTBANK_DAY));
468                 u8 nightlight = decode_light(getLight(LIGHTBANK_NIGHT));
469                 u8 mix = ((daylight_factor * daylight
470                         + (1000-daylight_factor) * nightlight)
471                         )/1000;
472                 return mix;
473         }*/
474
475         void setLight(enum LightBank bank, u8 a_light)
476         {
477                 // If not transparent, can't set light
478                 if(light_propagates() == false)
479                         return;
480                 if(bank == LIGHTBANK_DAY)
481                 {
482                         param &= 0xf0;
483                         param |= a_light & 0x0f;
484                 }
485                 else if(bank == LIGHTBANK_NIGHT)
486                 {
487                         param &= 0x0f;
488                         param |= (a_light & 0x0f)<<4;
489                 }
490                 else
491                         assert(0);
492         }
493
494         u16 getTile(v3s16 dir)
495         {
496                 return content_tile(d, dir);
497         }
498
499         /*
500                 These serialization functions are used when informing client
501                 of a single node add
502         */
503
504         static u32 serializedLength(u8 version)
505         {
506                 if(!ser_ver_supported(version))
507                         throw VersionMismatchException("ERROR: MapNode format not supported");
508                         
509                 if(version == 0)
510                         return 1;
511                 else if(version <= 9)
512                         return 2;
513                 else
514                         return 3;
515         }
516         void serialize(u8 *dest, u8 version)
517         {
518                 if(!ser_ver_supported(version))
519                         throw VersionMismatchException("ERROR: MapNode format not supported");
520                         
521                 if(version == 0)
522                 {
523                         dest[0] = d;
524                 }
525                 else if(version <= 9)
526                 {
527                         dest[0] = d;
528                         dest[1] = param;
529                 }
530                 else
531                 {
532                         dest[0] = d;
533                         dest[1] = param;
534                         dest[2] = pressure;
535                 }
536         }
537         void deSerialize(u8 *source, u8 version)
538         {
539                 if(!ser_ver_supported(version))
540                         throw VersionMismatchException("ERROR: MapNode format not supported");
541                         
542                 if(version == 0)
543                 {
544                         d = source[0];
545                 }
546                 else if(version == 1)
547                 {
548                         d = source[0];
549                         // This version doesn't support saved lighting
550                         if(light_propagates() || light_source() > 0)
551                                 param = 0;
552                         else
553                                 param = source[1];
554                 }
555                 else if(version <= 9)
556                 {
557                         d = source[0];
558                         param = source[1];
559                 }
560                 else
561                 {
562                         d = source[0];
563                         param = source[1];
564                         pressure = source[2];
565                 }
566         }
567 };
568
569 /*
570         Returns integer position of the node in given
571         floating point position.
572 */
573 inline v3s16 floatToInt(v3f p)
574 {
575         v3s16 p2(
576                 (p.X + (p.X>0 ? BS/2 : -BS/2))/BS,
577                 (p.Y + (p.Y>0 ? BS/2 : -BS/2))/BS,
578                 (p.Z + (p.Z>0 ? BS/2 : -BS/2))/BS);
579         return p2;
580 }
581
582 inline v3f intToFloat(v3s16 p)
583 {
584         v3f p2(
585                 p.X * BS,
586                 p.Y * BS,
587                 p.Z * BS
588         );
589         return p2;
590 }
591
592
593
594 #endif
595