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