]> git.lizzy.rs Git - minetest.git/blob - src/mapnode.h
before daynight mesh cache
[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 enum LightBank
284 {
285         LIGHTBANK_DAY,
286         LIGHTBANK_NIGHT
287 };
288
289 struct MapNode
290 {
291         // Content
292         u8 d;
293
294         /*
295                 Misc parameter. Initialized to 0.
296                 - For light_propagates() blocks, this is light intensity,
297                   stored logarithmically from 0 to LIGHT_MAX.
298                   Sunlight is LIGHT_SUN, which is LIGHT_MAX+1.
299         */
300         s8 param;
301         
302         union
303         {
304                 /*
305                         Pressure for liquids
306                 */
307                 u8 pressure;
308
309                 /*
310                         Direction for torches and other stuff.
311                         If possible, packed with packDir.
312                 */
313                 u8 dir;
314         };
315
316         MapNode(const MapNode & n)
317         {
318                 *this = n;
319         }
320         
321         MapNode(u8 data=CONTENT_AIR, u8 a_param=0, u8 a_pressure=0)
322         {
323                 d = data;
324                 param = a_param;
325                 pressure = a_pressure;
326         }
327
328         bool operator==(const MapNode &other)
329         {
330                 return (d == other.d
331                                 && param == other.param
332                                 && pressure == other.pressure);
333         }
334
335         bool light_propagates()
336         {
337                 return light_propagates_content(d);
338         }
339         
340         bool sunlight_propagates()
341         {
342                 return sunlight_propagates_content(d);
343         }
344         
345         u8 solidness()
346         {
347                 return content_solidness(d);
348         }
349
350         u8 light_source()
351         {
352                 /*
353                         Note that a block that isn't light_propagates() can be a light source.
354                 */
355                 if(d == CONTENT_TORCH)
356                         return LIGHT_MAX;
357                 
358                 return 0;
359         }
360
361         u8 getLightBanksWithSource()
362         {
363                 // Select the brightest of [light source, propagated light]
364                 u8 lightday = 0;
365                 u8 lightnight = 0;
366                 if(light_propagates())
367                 {
368                         lightday = param & 0x0f;
369                         lightnight = (param>>4)&0x0f;
370                 }
371                 if(light_source() > lightday)
372                         lightday = light_source();
373                 if(light_source() > lightnight)
374                         lightnight = light_source();
375                 return (lightday&0x0f) | ((lightnight<<4)&0xf0);
376         }
377
378         void setLightBanks(u8 a_light)
379         {
380                 param = a_light;
381         }
382
383         u8 getLight(enum LightBank bank)
384         {
385                 // Select the brightest of [light source, propagated light]
386                 u8 light = 0;
387                 if(light_propagates())
388                 {
389                         if(bank == LIGHTBANK_DAY)
390                                 light = param & 0x0f;
391                         else if(bank == LIGHTBANK_NIGHT)
392                                 light = (param>>4)&0x0f;
393                         else
394                                 assert(0);
395                 }
396                 if(light_source() > light)
397                         light = light_source();
398                 return light;
399         }
400         
401         // 0 <= daylight_factor <= 1000
402         u8 getLightBlend(u32 daylight_factor)
403         {
404                 u8 l = ((daylight_factor * getLight(LIGHTBANK_DAY)
405                         + (1000-daylight_factor) * getLight(LIGHTBANK_NIGHT))
406                         )/1000;
407                 u8 max = LIGHT_MAX;
408                 if(getLight(LIGHTBANK_DAY) == LIGHT_SUN)
409                         max = LIGHT_SUN;
410                 if(l > max)
411                         l = max;
412                 return l;
413         }
414
415         void setLight(enum LightBank bank, u8 a_light)
416         {
417                 // If not transparent, can't set light
418                 if(light_propagates() == false)
419                         return;
420                 if(bank == LIGHTBANK_DAY)
421                 {
422                         param &= 0xf0;
423                         param |= a_light & 0x0f;
424                 }
425                 else if(bank == LIGHTBANK_NIGHT)
426                 {
427                         param &= 0x0f;
428                         param |= (a_light & 0x0f)<<4;
429                 }
430                 else
431                         assert(0);
432         }
433
434         u16 getTile(v3s16 dir)
435         {
436                 return content_tile(d, dir);
437         }
438
439         /*
440                 These serialization functions are used when informing client
441                 of a single node add
442         */
443
444         static u32 serializedLength(u8 version)
445         {
446                 if(!ser_ver_supported(version))
447                         throw VersionMismatchException("ERROR: MapNode format not supported");
448                         
449                 if(version == 0)
450                         return 1;
451                 else if(version <= 9)
452                         return 2;
453                 else
454                         return 3;
455         }
456         void serialize(u8 *dest, u8 version)
457         {
458                 if(!ser_ver_supported(version))
459                         throw VersionMismatchException("ERROR: MapNode format not supported");
460                         
461                 if(version == 0)
462                 {
463                         dest[0] = d;
464                 }
465                 else if(version <= 9)
466                 {
467                         dest[0] = d;
468                         dest[1] = param;
469                 }
470                 else
471                 {
472                         dest[0] = d;
473                         dest[1] = param;
474                         dest[2] = pressure;
475                 }
476         }
477         void deSerialize(u8 *source, u8 version)
478         {
479                 if(!ser_ver_supported(version))
480                         throw VersionMismatchException("ERROR: MapNode format not supported");
481                         
482                 if(version == 0)
483                 {
484                         d = source[0];
485                 }
486                 else if(version == 1)
487                 {
488                         d = source[0];
489                         // This version doesn't support saved lighting
490                         if(light_propagates() || light_source() > 0)
491                                 param = 0;
492                         else
493                                 param = source[1];
494                 }
495                 else if(version <= 9)
496                 {
497                         d = source[0];
498                         param = source[1];
499                 }
500                 else
501                 {
502                         d = source[0];
503                         param = source[1];
504                         pressure = source[2];
505                 }
506         }
507 };
508
509 /*
510         Returns integer position of the node in given
511         floating point position.
512 */
513 inline v3s16 floatToInt(v3f p)
514 {
515         v3s16 p2(
516                 (p.X + (p.X>0 ? BS/2 : -BS/2))/BS,
517                 (p.Y + (p.Y>0 ? BS/2 : -BS/2))/BS,
518                 (p.Z + (p.Z>0 ? BS/2 : -BS/2))/BS);
519         return p2;
520 }
521
522 inline v3f intToFloat(v3s16 p)
523 {
524         v3f p2(
525                 p.X * BS,
526                 p.Y * BS,
527                 p.Z * BS
528         );
529         return p2;
530 }
531
532
533
534 #endif
535