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 // Create directly from a nodename
159 // If name is unknown, sets CONTENT_IGNORE
160 MapNode::MapNode(INodeDefManager *ndef, const std::string &name,
161 u8 a_param1, u8 a_param2)
163 content_t id = CONTENT_IGNORE;
164 ndef->getId(name, id);
167 // Set content (param0 and (param2&0xf0)) after other params
168 // because this needs to override part of param2
172 void MapNode::setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr)
174 // If node doesn't contain light data, ignore this
175 if(nodemgr->get(*this).param_type != CPT_LIGHT)
177 if(bank == LIGHTBANK_DAY)
180 param1 |= a_light & 0x0f;
182 else if(bank == LIGHTBANK_NIGHT)
185 param1 |= (a_light & 0x0f)<<4;
191 u8 MapNode::getLight(enum LightBank bank, INodeDefManager *nodemgr) const
193 // Select the brightest of [light source, propagated light]
195 if(nodemgr->get(*this).param_type == CPT_LIGHT)
197 if(bank == LIGHTBANK_DAY)
198 light = param1 & 0x0f;
199 else if(bank == LIGHTBANK_NIGHT)
200 light = (param1>>4)&0x0f;
204 if(nodemgr->get(*this).light_source > light)
205 light = nodemgr->get(*this).light_source;
209 u8 MapNode::getLightBanksWithSource(INodeDefManager *nodemgr) const
211 // Select the brightest of [light source, propagated light]
214 if(nodemgr->get(*this).param_type == CPT_LIGHT)
216 lightday = param1 & 0x0f;
217 lightnight = (param1>>4)&0x0f;
219 if(nodemgr->get(*this).light_source > lightday)
220 lightday = nodemgr->get(*this).light_source;
221 if(nodemgr->get(*this).light_source > lightnight)
222 lightnight = nodemgr->get(*this).light_source;
223 return (lightday&0x0f) | ((lightnight<<4)&0xf0);
226 u8 MapNode::getMineral(INodeDefManager *nodemgr) const
228 if(nodemgr->get(*this).param_type == CPT_MINERAL)
230 return param1 & 0x0f;
236 u32 MapNode::serializedLength(u8 version)
238 if(!ser_ver_supported(version))
239 throw VersionMismatchException("ERROR: MapNode format not supported");
243 else if(version <= 9)
248 void MapNode::serialize(u8 *dest, u8 version)
250 if(!ser_ver_supported(version))
251 throw VersionMismatchException("ERROR: MapNode format not supported");
253 // Translate to wanted version
254 MapNode n_foreign = mapnode_translate_from_internal(*this, version);
256 u8 actual_param0 = n_foreign.param0;
258 // Convert special values from new version to old
261 // In these versions, CONTENT_IGNORE and CONTENT_AIR
263 if(actual_param0 == CONTENT_IGNORE)
265 else if(actual_param0 == CONTENT_AIR)
271 dest[0] = actual_param0;
273 else if(version <= 9)
275 dest[0] = actual_param0;
276 dest[1] = n_foreign.param1;
280 dest[0] = actual_param0;
281 dest[1] = n_foreign.param1;
282 dest[2] = n_foreign.param2;
285 void MapNode::deSerialize(u8 *source, u8 version)
287 if(!ser_ver_supported(version))
288 throw VersionMismatchException("ERROR: MapNode format not supported");
294 else if(version == 1)
298 else if(version <= 9)
310 // Convert special values from old version to new
313 // In these versions, CONTENT_IGNORE and CONTENT_AIR
316 param0 = CONTENT_IGNORE;
317 else if(param0 == 254)
318 param0 = CONTENT_AIR;
320 // version 19 is fucked up with sometimes the old values and sometimes not
324 param0 = CONTENT_IGNORE;
325 else if(param0 == 254)
326 param0 = CONTENT_AIR;
329 // Translate to our known version
330 *this = mapnode_translate_to_internal(*this, version);
334 Gets lighting value at face of node
336 Parameters must consist of air and !air.
337 Order doesn't matter.
339 If either of the nodes doesn't exist, light is 0.
342 daynight_ratio: 0...1000
343 n: getNode(p) (uses only the lighting value)
344 n2: getNode(p + face_dir) (uses only the lighting value)
345 face_dir: axis oriented unit vector from p to p2
347 returns encoded light value.
349 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
350 v3s16 face_dir, INodeDefManager *nodemgr)
354 u8 l1 = n.getLightBlend(daynight_ratio, nodemgr);
355 u8 l2 = n2.getLightBlend(daynight_ratio, nodemgr);
361 // Make some nice difference to different sides
363 // This makes light come from a corner
364 /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
365 light = diminish_light(diminish_light(light));
366 else if(face_dir.X == -1 || face_dir.Z == -1)
367 light = diminish_light(light);*/
369 // All neighboring faces have different shade (like in minecraft)
370 if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
371 light = diminish_light(diminish_light(light));
372 else if(face_dir.Z == 1 || face_dir.Z == -1)
373 light = diminish_light(light);
377 catch(InvalidPositionException &e)