3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
20 #include "common_irrlicht.h"
25 #include "main.h" // For g_settings
27 #include "content_mapnode.h" // For mapnode_translate_*_internal
28 #include "serialization.h" // For ser_ver_supported
32 Nodes make a face if contents differ and solidness differs.
35 1: Face uses m1's content
36 2: Face uses m2's content
37 equivalent: Whether the blocks share the same face (eg. water and glass)
39 TODO: Add 3: Both faces drawn with backface culling, remove equivalent
41 u8 face_contents(content_t m1, content_t m2, bool *equivalent,
42 INodeDefManager *nodemgr)
46 if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
49 bool contents_differ = (m1 != m2);
51 const ContentFeatures &f1 = nodemgr->get(m1);
52 const ContentFeatures &f2 = nodemgr->get(m2);
54 // Contents don't differ for different forms of same liquid
56 contents_differ = false;
61 bool solidness_differs = (c1 != c2);
62 bool makes_face = contents_differ && solidness_differs;
64 if(makes_face == false)
68 c1 = f1.visual_solidness;
70 c2 = f2.visual_solidness;
74 // If same solidness, liquid takes precense
88 v3s16 facedir_rotate(u8 facedir, v3s16 dir)
91 Face 2 (normally Z-) direction:
98 if(facedir==0) // Same
99 newdir = v3s16(dir.X, dir.Y, dir.Z);
100 else if(facedir == 1) // Face is taken from rotXZccv(-90)
101 newdir = v3s16(-dir.Z, dir.Y, dir.X);
102 else if(facedir == 2) // Face is taken from rotXZccv(180)
103 newdir = v3s16(-dir.X, dir.Y, -dir.Z);
104 else if(facedir == 3) // Face is taken from rotXZccv(90)
105 newdir = v3s16(dir.Z, dir.Y, -dir.X);
111 u8 packDir(v3s16 dir)
132 v3s16 unpackDir(u8 b)
158 void MapNode::setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr)
160 // If node doesn't contain light data, ignore this
161 if(nodemgr->get(*this).param_type != CPT_LIGHT)
163 if(bank == LIGHTBANK_DAY)
166 param1 |= a_light & 0x0f;
168 else if(bank == LIGHTBANK_NIGHT)
171 param1 |= (a_light & 0x0f)<<4;
177 u8 MapNode::getLight(enum LightBank bank, INodeDefManager *nodemgr) const
179 // Select the brightest of [light source, propagated light]
181 if(nodemgr->get(*this).param_type == CPT_LIGHT)
183 if(bank == LIGHTBANK_DAY)
184 light = param1 & 0x0f;
185 else if(bank == LIGHTBANK_NIGHT)
186 light = (param1>>4)&0x0f;
190 if(nodemgr->get(*this).light_source > light)
191 light = nodemgr->get(*this).light_source;
195 u8 MapNode::getLightBanksWithSource(INodeDefManager *nodemgr) const
197 // Select the brightest of [light source, propagated light]
200 if(nodemgr->get(*this).param_type == CPT_LIGHT)
202 lightday = param1 & 0x0f;
203 lightnight = (param1>>4)&0x0f;
205 if(nodemgr->get(*this).light_source > lightday)
206 lightday = nodemgr->get(*this).light_source;
207 if(nodemgr->get(*this).light_source > lightnight)
208 lightnight = nodemgr->get(*this).light_source;
209 return (lightday&0x0f) | ((lightnight<<4)&0xf0);
212 u8 MapNode::getMineral(INodeDefManager *nodemgr) const
214 if(nodemgr->get(*this).param_type == CPT_MINERAL)
216 return param1 & 0x0f;
222 u32 MapNode::serializedLength(u8 version)
224 if(!ser_ver_supported(version))
225 throw VersionMismatchException("ERROR: MapNode format not supported");
229 else if(version <= 9)
234 void MapNode::serialize(u8 *dest, u8 version)
236 if(!ser_ver_supported(version))
237 throw VersionMismatchException("ERROR: MapNode format not supported");
239 // Translate to wanted version
240 MapNode n_foreign = mapnode_translate_from_internal(*this, version);
242 u8 actual_param0 = n_foreign.param0;
244 // Convert special values from new version to old
247 // In these versions, CONTENT_IGNORE and CONTENT_AIR
249 if(actual_param0 == CONTENT_IGNORE)
251 else if(actual_param0 == CONTENT_AIR)
257 dest[0] = actual_param0;
259 else if(version <= 9)
261 dest[0] = actual_param0;
262 dest[1] = n_foreign.param1;
266 dest[0] = actual_param0;
267 dest[1] = n_foreign.param1;
268 dest[2] = n_foreign.param2;
271 void MapNode::deSerialize(u8 *source, u8 version)
273 if(!ser_ver_supported(version))
274 throw VersionMismatchException("ERROR: MapNode format not supported");
280 else if(version == 1)
284 else if(version <= 9)
296 // Convert special values from old version to new
299 // In these versions, CONTENT_IGNORE and CONTENT_AIR
302 param0 = CONTENT_IGNORE;
303 else if(param0 == 254)
304 param0 = CONTENT_AIR;
306 // version 19 is fucked up with sometimes the old values and sometimes not
310 param0 = CONTENT_IGNORE;
311 else if(param0 == 254)
312 param0 = CONTENT_AIR;
315 // Translate to our known version
316 *this = mapnode_translate_to_internal(*this, version);
320 Gets lighting value at face of node
322 Parameters must consist of air and !air.
323 Order doesn't matter.
325 If either of the nodes doesn't exist, light is 0.
328 daynight_ratio: 0...1000
329 n: getNode(p) (uses only the lighting value)
330 n2: getNode(p + face_dir) (uses only the lighting value)
331 face_dir: axis oriented unit vector from p to p2
333 returns encoded light value.
335 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
336 v3s16 face_dir, INodeDefManager *nodemgr)
340 u8 l1 = n.getLightBlend(daynight_ratio, nodemgr);
341 u8 l2 = n2.getLightBlend(daynight_ratio, nodemgr);
347 // Make some nice difference to different sides
349 // This makes light come from a corner
350 /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
351 light = diminish_light(diminish_light(light));
352 else if(face_dir.X == -1 || face_dir.Z == -1)
353 light = diminish_light(light);*/
355 // All neighboring faces have different shade (like in minecraft)
356 if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
357 light = diminish_light(diminish_light(light));
358 else if(face_dir.Z == 1 || face_dir.Z == -1)
359 light = diminish_light(light);
363 catch(InvalidPositionException &e)