fcbb80fd123f025011907cfcde6d376277ec4f83
[oweals/minetest.git] / src / mapnode.h
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 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 #include "iirrlichtwrapper.h"
31
32 /*
33         Initializes all kind of stuff in here.
34         Many things depend on this.
35
36         irrlicht: Used for getting texture ids.
37 */
38 void init_mapnode(IIrrlichtWrapper *irrlicht);
39
40 // Initializes g_content_inventory_texture_paths
41 void init_content_inventory_texture_paths();
42
43
44 // NOTE: This is not used appropriately everywhere.
45 #define MATERIALS_COUNT 256
46
47 /*
48         Ignored node.
49
50         Anything that stores MapNodes doesn't have to preserve parameters
51         associated with this material.
52         
53         Doesn't create faces with anything and is considered being
54         out-of-map in the game map.
55 */
56 #define CONTENT_IGNORE 255
57 #define CONTENT_IGNORE_DEFAULT_PARAM 0
58
59 /*
60         The common material through which the player can walk and which
61         is transparent to light
62 */
63 #define CONTENT_AIR 254
64
65 /*
66         Suggested materials:
67         - Gravel
68         - Sand
69         
70         New naming scheme:
71         - Material = irrlicht's Material class
72         - Content = (u8) content of a node
73         - Tile = (u16) Material ID at some side of a node
74 */
75
76 #define CONTENT_STONE 0
77 #define CONTENT_GRASS 1
78 #define CONTENT_WATER 2
79 #define CONTENT_TORCH 3
80 #define CONTENT_TREE 4
81 #define CONTENT_LEAVES 5
82 #define CONTENT_GRASS_FOOTSTEPS 6
83 #define CONTENT_MESE 7
84 #define CONTENT_MUD 8
85 #define CONTENT_WATERSOURCE 9
86 // Pretty much useless, clouds won't be drawn this way
87 #define CONTENT_CLOUD 10
88 #define CONTENT_COALSTONE 11
89 #define CONTENT_WOOD 12
90 #define CONTENT_SAND 13
91
92 /*
93         This is used by all kinds of things to allocate memory for all
94         contents except CONTENT_AIR and CONTENT_IGNORE
95 */
96 #define USEFUL_CONTENT_COUNT 14
97
98 /*
99         Content feature list
100 */
101
102 enum ContentParamType
103 {
104         CPT_NONE,
105         CPT_LIGHT,
106         CPT_MINERAL
107 };
108
109 enum LiquidType
110 {
111         LIQUID_NONE,
112         LIQUID_FLOWING,
113         LIQUID_SOURCE
114 };
115
116 class MapNode;
117
118 struct ContentFeatures
119 {
120         // If non-NULL, content is translated to this when deserialized
121         MapNode *translate_to;
122
123         // Type of MapNode::param
124         ContentParamType param_type;
125
126         /*
127                 0: up
128                 1: down
129                 2: right
130                 3: left
131                 4: back
132                 5: front
133         */
134         TileSpec tiles[6];
135
136         //std::string inventory_image_path;
137         TextureSpec inventory_texture;
138
139         bool is_ground_content; //TODO: Remove, use walkable instead
140         bool light_propagates;
141         bool sunlight_propagates;
142         u8 solidness; // Used when choosing which face is drawn
143         bool walkable;
144         bool pointable;
145         bool diggable;
146         bool buildable_to;
147         enum LiquidType liquid_type;
148         bool wall_mounted; // If true, param2 is set to direction when placed
149
150         //TODO: Move more properties here
151
152         ContentFeatures()
153         {
154                 translate_to = NULL;
155                 param_type = CPT_NONE;
156                 is_ground_content = false;
157                 light_propagates = false;
158                 sunlight_propagates = false;
159                 solidness = 2;
160                 walkable = true;
161                 pointable = true;
162                 diggable = true;
163                 buildable_to = false;
164                 liquid_type = LIQUID_NONE;
165                 wall_mounted = false;
166         }
167
168         ~ContentFeatures();
169         
170         void setAllTextures(const TextureSpec &spec, u8 alpha=255)
171         {
172                 for(u16 i=0; i<6; i++)
173                 {
174                         tiles[i].spec = spec;
175                         tiles[i].alpha = alpha;
176                 }
177                 
178                 // Set this too so it can be left as is most times
179                 /*if(inventory_image_path == "")
180                         inventory_image_path = porting::getDataPath(imgname.c_str());*/
181
182                 if(inventory_texture.empty())
183                         inventory_texture = spec;
184         }
185         void setTexture(u16 i, const TextureSpec &spec, u8 alpha=255)
186         {
187                 tiles[i].spec = spec;
188                 tiles[i].alpha = alpha;
189         }
190
191         void setInventoryTexture(const TextureSpec &spec)
192         {
193                 inventory_texture = spec;
194         }
195
196         /*void setInventoryImage(std::string imgname)
197         {
198                 inventory_image_path = porting::getDataPath(imgname.c_str());
199         }*/
200 };
201
202 /*
203         Call this to access the ContentFeature list
204 */
205 ContentFeatures & content_features(u8 i);
206
207 /*
208         If true, the material allows light propagation and brightness is stored
209         in param.
210         NOTE: Don't use, use "content_features(m).whatever" instead
211 */
212 inline bool light_propagates_content(u8 m)
213 {
214         return content_features(m).light_propagates;
215         //return (m == CONTENT_AIR || m == CONTENT_TORCH || m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
216 }
217
218 /*
219         If true, the material allows lossless sunlight propagation.
220         NOTE: It doesn't seem to go through torches regardlessly of this
221         NOTE: Don't use, use "content_features(m).whatever" instead
222 */
223 inline bool sunlight_propagates_content(u8 m)
224 {
225         return content_features(m).sunlight_propagates;
226         //return (m == CONTENT_AIR || m == CONTENT_TORCH);
227 }
228
229 /*
230         On a node-node surface, the material of the node with higher solidness
231         is used for drawing.
232         0: Invisible
233         1: Transparent
234         2: Opaque
235         NOTE: Don't use, use "content_features(m).whatever" instead
236 */
237 inline u8 content_solidness(u8 m)
238 {
239         return content_features(m).solidness;
240         /*// As of now, every pseudo node like torches are added to this
241         if(m == CONTENT_AIR || m == CONTENT_TORCH || m == CONTENT_WATER)
242                 return 0;
243         if(m == CONTENT_WATER || m == CONTENT_WATERSOURCE)
244                 return 1;
245         return 2;*/
246 }
247
248 // Objects collide with walkable contents
249 // NOTE: Don't use, use "content_features(m).whatever" instead
250 inline bool content_walkable(u8 m)
251 {
252         return content_features(m).walkable;
253         //return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE && m != CONTENT_TORCH);
254 }
255
256 // NOTE: Don't use, use "content_features(m).whatever" instead
257 inline bool content_liquid(u8 m)
258 {
259         return content_features(m).liquid_type != LIQUID_NONE;
260         //return (m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
261 }
262
263 // NOTE: Don't use, use "content_features(m).whatever" instead
264 inline bool content_flowing_liquid(u8 m)
265 {
266         return content_features(m).liquid_type == LIQUID_FLOWING;
267         //return (m == CONTENT_WATER);
268 }
269
270 // NOTE: Don't use, use "content_features(m).whatever" instead
271 inline bool content_liquid_source(u8 m)
272 {
273         return content_features(m).liquid_type == LIQUID_SOURCE;
274         //return (m == CONTENT_WATERSOURCE);
275 }
276
277 // CONTENT_WATER || CONTENT_WATERSOURCE -> CONTENT_WATER
278 // CONTENT_LAVA || CONTENT_LAVASOURCE -> CONTENT_LAVA
279 inline u8 make_liquid_flowing(u8 m)
280 {
281         if(m == CONTENT_WATER || m == CONTENT_WATERSOURCE)
282                 return CONTENT_WATER;
283         assert(0);
284 }
285
286 // Pointable contents can be pointed to in the map
287 // NOTE: Don't use, use "content_features(m).whatever" instead
288 inline bool content_pointable(u8 m)
289 {
290         return content_features(m).pointable;
291         //return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE);
292 }
293
294 // NOTE: Don't use, use "content_features(m).whatever" instead
295 inline bool content_diggable(u8 m)
296 {
297         return content_features(m).diggable;
298         //return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE);
299 }
300
301 // NOTE: Don't use, use "content_features(m).whatever" instead
302 inline bool content_buildable_to(u8 m)
303 {
304         return content_features(m).buildable_to;
305         //return (m == CONTENT_AIR || m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
306 }
307
308 /*
309         Returns true for contents that form the base ground that
310         follows the main heightmap
311 */
312 /*inline bool is_ground_content(u8 m)
313 {
314         return content_features(m).is_ground_content;
315 }*/
316
317 /*
318         Nodes make a face if contents differ and solidness differs.
319         Return value:
320                 0: No face
321                 1: Face uses m1's content
322                 2: Face uses m2's content
323 */
324 inline u8 face_contents(u8 m1, u8 m2)
325 {
326         if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
327                 return 0;
328         
329         bool contents_differ = (m1 != m2);
330         
331         // Contents don't differ for different forms of same liquid
332         if(content_liquid(m1) && content_liquid(m2)
333                         && make_liquid_flowing(m1) == make_liquid_flowing(m2))
334                 contents_differ = false;
335         
336         bool solidness_differs = (content_solidness(m1) != content_solidness(m2));
337         bool makes_face = contents_differ && solidness_differs;
338
339         if(makes_face == false)
340                 return 0;
341
342         if(content_solidness(m1) > content_solidness(m2))
343                 return 1;
344         else
345                 return 2;
346 }
347
348 /*
349         Packs directions like (1,0,0), (1,-1,0)
350 */
351 inline u8 packDir(v3s16 dir)
352 {
353         u8 b = 0;
354
355         if(dir.X > 0)
356                 b |= (1<<0);
357         else if(dir.X < 0)
358                 b |= (1<<1);
359
360         if(dir.Y > 0)
361                 b |= (1<<2);
362         else if(dir.Y < 0)
363                 b |= (1<<3);
364
365         if(dir.Z > 0)
366                 b |= (1<<4);
367         else if(dir.Z < 0)
368                 b |= (1<<5);
369         
370         return b;
371 }
372 inline v3s16 unpackDir(u8 b)
373 {
374         v3s16 d(0,0,0);
375
376         if(b & (1<<0))
377                 d.X = 1;
378         else if(b & (1<<1))
379                 d.X = -1;
380
381         if(b & (1<<2))
382                 d.Y = 1;
383         else if(b & (1<<3))
384                 d.Y = -1;
385
386         if(b & (1<<4))
387                 d.Z = 1;
388         else if(b & (1<<5))
389                 d.Z = -1;
390         
391         return d;
392 }
393
394 enum LightBank
395 {
396         LIGHTBANK_DAY,
397         LIGHTBANK_NIGHT
398 };
399
400 /*
401         This is the stuff what the whole world consists of.
402 */
403
404 struct MapNode
405 {
406         // Content
407         u8 d;
408
409         /*
410                 Misc parameter. Initialized to 0.
411                 - For light_propagates() blocks, this is light intensity,
412                   stored logarithmically from 0 to LIGHT_MAX.
413                   Sunlight is LIGHT_SUN, which is LIGHT_MAX+1.
414                 - Contains 2 values, day- and night lighting. Each takes 4 bits.
415         */
416         s8 param;
417         
418         union
419         {
420                 u8 param2;
421
422                 /*
423                         Direction for torches and other stuff.
424                         Format is freeform. e.g. packDir or encode_dirs can be used.
425                 */
426                 u8 dir;
427         };
428
429         MapNode(const MapNode & n)
430         {
431                 *this = n;
432         }
433         
434         MapNode(u8 data=CONTENT_AIR, u8 a_param=0, u8 a_param2=0)
435         {
436                 d = data;
437                 param = a_param;
438                 param2 = a_param2;
439         }
440
441         /*MapNode & operator=(const MapNode &other)
442         {
443                 d = other.d;
444                 param = other.param;
445                 param2 = other.param2;
446                 return *this;
447         }*/
448
449         bool operator==(const MapNode &other)
450         {
451                 return (d == other.d
452                                 && param == other.param
453                                 && param2 == other.param2);
454         }
455
456         bool light_propagates()
457         {
458                 return light_propagates_content(d);
459         }
460         
461         bool sunlight_propagates()
462         {
463                 return sunlight_propagates_content(d);
464         }
465         
466         u8 solidness()
467         {
468                 return content_solidness(d);
469         }
470
471         u8 light_source()
472         {
473                 /*
474                         Note that a block that isn't light_propagates() can be a light source.
475                 */
476                 if(d == CONTENT_TORCH)
477                         return LIGHT_MAX;
478                 
479                 return 0;
480         }
481
482         u8 getLightBanksWithSource()
483         {
484                 // Select the brightest of [light source, propagated light]
485                 u8 lightday = 0;
486                 u8 lightnight = 0;
487                 if(light_propagates())
488                 {
489                         lightday = param & 0x0f;
490                         lightnight = (param>>4)&0x0f;
491                 }
492                 if(light_source() > lightday)
493                         lightday = light_source();
494                 if(light_source() > lightnight)
495                         lightnight = light_source();
496                 return (lightday&0x0f) | ((lightnight<<4)&0xf0);
497         }
498
499         void setLightBanks(u8 a_light)
500         {
501                 param = a_light;
502         }
503
504         u8 getLight(enum LightBank bank)
505         {
506                 // Select the brightest of [light source, propagated light]
507                 u8 light = 0;
508                 if(light_propagates())
509                 {
510                         if(bank == LIGHTBANK_DAY)
511                                 light = param & 0x0f;
512                         else if(bank == LIGHTBANK_NIGHT)
513                                 light = (param>>4)&0x0f;
514                         else
515                                 assert(0);
516                 }
517                 if(light_source() > light)
518                         light = light_source();
519                 return light;
520         }
521         
522         // 0 <= daylight_factor <= 1000
523         // 0 <= return value <= LIGHT_SUN
524         u8 getLightBlend(u32 daylight_factor)
525         {
526                 u8 l = ((daylight_factor * getLight(LIGHTBANK_DAY)
527                         + (1000-daylight_factor) * getLight(LIGHTBANK_NIGHT))
528                         )/1000;
529                 u8 max = LIGHT_MAX;
530                 if(getLight(LIGHTBANK_DAY) == LIGHT_SUN)
531                         max = LIGHT_SUN;
532                 if(l > max)
533                         l = max;
534                 return l;
535         }
536         /*// 0 <= daylight_factor <= 1000
537         // 0 <= return value <= 255
538         u8 getLightBlend(u32 daylight_factor)
539         {
540                 u8 daylight = decode_light(getLight(LIGHTBANK_DAY));
541                 u8 nightlight = decode_light(getLight(LIGHTBANK_NIGHT));
542                 u8 mix = ((daylight_factor * daylight
543                         + (1000-daylight_factor) * nightlight)
544                         )/1000;
545                 return mix;
546         }*/
547
548         void setLight(enum LightBank bank, u8 a_light)
549         {
550                 // If not transparent, can't set light
551                 if(light_propagates() == false)
552                         return;
553                 if(bank == LIGHTBANK_DAY)
554                 {
555                         param &= 0xf0;
556                         param |= a_light & 0x0f;
557                 }
558                 else if(bank == LIGHTBANK_NIGHT)
559                 {
560                         param &= 0x0f;
561                         param |= (a_light & 0x0f)<<4;
562                 }
563                 else
564                         assert(0);
565         }
566         
567         // In mapnode.cpp
568         TileSpec getTile(v3s16 dir);
569
570         u8 getMineral();
571
572         /*
573                 These serialization functions are used when informing client
574                 of a single node add
575         */
576
577         static u32 serializedLength(u8 version)
578         {
579                 if(!ser_ver_supported(version))
580                         throw VersionMismatchException("ERROR: MapNode format not supported");
581                         
582                 if(version == 0)
583                         return 1;
584                 else if(version <= 9)
585                         return 2;
586                 else
587                         return 3;
588         }
589         void serialize(u8 *dest, u8 version)
590         {
591                 if(!ser_ver_supported(version))
592                         throw VersionMismatchException("ERROR: MapNode format not supported");
593                         
594                 if(version == 0)
595                 {
596                         dest[0] = d;
597                 }
598                 else if(version <= 9)
599                 {
600                         dest[0] = d;
601                         dest[1] = param;
602                 }
603                 else
604                 {
605                         dest[0] = d;
606                         dest[1] = param;
607                         dest[2] = param2;
608                 }
609         }
610         void deSerialize(u8 *source, u8 version)
611         {
612                 if(!ser_ver_supported(version))
613                         throw VersionMismatchException("ERROR: MapNode format not supported");
614                         
615                 if(version == 0)
616                 {
617                         d = source[0];
618                 }
619                 else if(version == 1)
620                 {
621                         d = source[0];
622                         // This version doesn't support saved lighting
623                         if(light_propagates() || light_source() > 0)
624                                 param = 0;
625                         else
626                                 param = source[1];
627                 }
628                 else if(version <= 9)
629                 {
630                         d = source[0];
631                         param = source[1];
632                 }
633                 else
634                 {
635                         d = source[0];
636                         param = source[1];
637                         param2 = source[2];
638                 }
639
640                 // Translate deprecated stuff
641                 // NOTE: This doesn't get used because MapBlock handles node
642                 // parameters directly
643                 MapNode *translate_to = content_features(d).translate_to;
644                 if(translate_to)
645                 {
646                         dstream<<"MapNode: WARNING: Translating "<<d<<" to "
647                                         <<translate_to->d<<std::endl;
648                         *this = *translate_to;
649                 }
650         }
651 };
652
653 /*
654         Returns integer position of the node in given
655         floating point position.
656 */
657 inline v3s16 floatToInt(v3f p)
658 {
659         v3s16 p2(
660                 (p.X + (p.X>0 ? BS/2 : -BS/2))/BS,
661                 (p.Y + (p.Y>0 ? BS/2 : -BS/2))/BS,
662                 (p.Z + (p.Z>0 ? BS/2 : -BS/2))/BS);
663         return p2;
664 }
665
666 /*
667         The same thing backwards
668 */
669 inline v3f intToFloat(v3s16 p)
670 {
671         v3f p2(
672                 p.X * BS,
673                 p.Y * BS,
674                 p.Z * BS
675         );
676         return p2;
677 }
678
679
680
681 #endif
682