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
26 #include "mapnode_contentfeatures.h"
27 #include "content_mapnode.h" // For mapnode_translate_*_internal
30 Nodes make a face if contents differ and solidness differs.
33 1: Face uses m1's content
34 2: Face uses m2's content
35 equivalent: Whether the blocks share the same face (eg. water and glass)
37 u8 face_contents(content_t m1, content_t m2, bool *equivalent)
41 if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
44 bool contents_differ = (m1 != m2);
46 // Contents don't differ for different forms of same liquid
47 if(content_liquid(m1) && content_liquid(m2)
48 && make_liquid_flowing(m1) == make_liquid_flowing(m2))
49 contents_differ = false;
51 u8 c1 = content_solidness(m1);
52 u8 c2 = content_solidness(m2);
54 bool solidness_differs = (c1 != c2);
55 bool makes_face = contents_differ && solidness_differs;
57 if(makes_face == false)
61 c1 = content_features(m1).visual_solidness;
63 c2 = content_features(m2).visual_solidness;
67 // If same solidness, liquid takes precense
68 if(content_features(m1).liquid_type != LIQUID_NONE)
70 if(content_features(m2).liquid_type != LIQUID_NONE)
80 v3s16 facedir_rotate(u8 facedir, v3s16 dir)
83 Face 2 (normally Z-) direction:
90 if(facedir==0) // Same
91 newdir = v3s16(dir.X, dir.Y, dir.Z);
92 else if(facedir == 1) // Face is taken from rotXZccv(-90)
93 newdir = v3s16(-dir.Z, dir.Y, dir.X);
94 else if(facedir == 2) // Face is taken from rotXZccv(180)
95 newdir = v3s16(-dir.X, dir.Y, -dir.Z);
96 else if(facedir == 3) // Face is taken from rotXZccv(90)
97 newdir = v3s16(dir.Z, dir.Y, -dir.X);
103 u8 packDir(v3s16 dir)
124 v3s16 unpackDir(u8 b)
150 // These four are DEPRECATED.
151 bool MapNode::light_propagates()
153 return light_propagates_content(getContent());
155 bool MapNode::sunlight_propagates()
157 return sunlight_propagates_content(getContent());
159 u8 MapNode::solidness()
161 return content_solidness(getContent());
163 u8 MapNode::light_source()
165 return content_features(*this).light_source;
168 void MapNode::setLight(enum LightBank bank, u8 a_light)
170 // If node doesn't contain light data, ignore this
171 if(content_features(*this).param_type != CPT_LIGHT)
173 if(bank == LIGHTBANK_DAY)
176 param1 |= a_light & 0x0f;
178 else if(bank == LIGHTBANK_NIGHT)
181 param1 |= (a_light & 0x0f)<<4;
187 u8 MapNode::getLight(enum LightBank bank)
189 // Select the brightest of [light source, propagated light]
191 if(content_features(*this).param_type == CPT_LIGHT)
193 if(bank == LIGHTBANK_DAY)
194 light = param1 & 0x0f;
195 else if(bank == LIGHTBANK_NIGHT)
196 light = (param1>>4)&0x0f;
200 if(light_source() > light)
201 light = light_source();
205 u8 MapNode::getLightBanksWithSource()
207 // Select the brightest of [light source, propagated light]
210 if(content_features(*this).param_type == CPT_LIGHT)
212 lightday = param1 & 0x0f;
213 lightnight = (param1>>4)&0x0f;
215 if(light_source() > lightday)
216 lightday = light_source();
217 if(light_source() > lightnight)
218 lightnight = light_source();
219 return (lightday&0x0f) | ((lightnight<<4)&0xf0);
223 TileSpec MapNode::getTile(v3s16 dir)
225 if(content_features(*this).param_type == CPT_FACEDIR_SIMPLE)
226 dir = facedir_rotate(param1, dir);
232 if(dir == v3s16(0,0,0))
234 else if(dir == v3s16(0,1,0))
236 else if(dir == v3s16(0,-1,0))
238 else if(dir == v3s16(1,0,0))
240 else if(dir == v3s16(-1,0,0))
242 else if(dir == v3s16(0,0,1))
244 else if(dir == v3s16(0,0,-1))
249 spec = content_features(*this).tiles[0];
251 spec = content_features(*this).tiles[dir_i];
254 If it contains some mineral, change texture id
256 if(content_features(*this).param_type == CPT_MINERAL && g_texturesource)
258 u8 mineral = getMineral();
259 std::string mineral_texture_name = mineral_block_texture(mineral);
260 if(mineral_texture_name != "")
262 u32 orig_id = spec.texture.id;
263 std::string texture_name = g_texturesource->getTextureName(orig_id);
264 //texture_name += "^blit:";
266 texture_name += mineral_texture_name;
267 u32 new_id = g_texturesource->getTextureId(texture_name);
268 spec.texture = g_texturesource->getTexture(new_id);
276 u8 MapNode::getMineral()
278 if(content_features(*this).param_type == CPT_MINERAL)
280 return param1 & 0x0f;
286 u32 MapNode::serializedLength(u8 version)
288 if(!ser_ver_supported(version))
289 throw VersionMismatchException("ERROR: MapNode format not supported");
293 else if(version <= 9)
298 void MapNode::serialize(u8 *dest, u8 version)
300 if(!ser_ver_supported(version))
301 throw VersionMismatchException("ERROR: MapNode format not supported");
303 // Translate to wanted version
304 MapNode n_foreign = mapnode_translate_from_internal(*this, version);
306 u8 actual_param0 = n_foreign.param0;
308 // Convert special values from new version to old
311 // In these versions, CONTENT_IGNORE and CONTENT_AIR
313 if(actual_param0 == CONTENT_IGNORE)
315 else if(actual_param0 == CONTENT_AIR)
321 dest[0] = actual_param0;
323 else if(version <= 9)
325 dest[0] = actual_param0;
326 dest[1] = n_foreign.param1;
330 dest[0] = actual_param0;
331 dest[1] = n_foreign.param1;
332 dest[2] = n_foreign.param2;
335 void MapNode::deSerialize(u8 *source, u8 version)
337 if(!ser_ver_supported(version))
338 throw VersionMismatchException("ERROR: MapNode format not supported");
344 else if(version == 1)
347 // This version doesn't support saved lighting
348 if(light_propagates() || light_source() > 0)
353 else if(version <= 9)
365 // Convert special values from old version to new
368 // In these versions, CONTENT_IGNORE and CONTENT_AIR
371 param0 = CONTENT_IGNORE;
372 else if(param0 == 254)
373 param0 = CONTENT_AIR;
375 // version 19 is fucked up with sometimes the old values and sometimes not
379 param0 = CONTENT_IGNORE;
380 else if(param0 == 254)
381 param0 = CONTENT_AIR;
384 // Translate to our known version
385 *this = mapnode_translate_to_internal(*this, version);
389 Gets lighting value at face of node
391 Parameters must consist of air and !air.
392 Order doesn't matter.
394 If either of the nodes doesn't exist, light is 0.
397 daynight_ratio: 0...1000
398 n: getNode(p) (uses only the lighting value)
399 n2: getNode(p + face_dir) (uses only the lighting value)
400 face_dir: axis oriented unit vector from p to p2
402 returns encoded light value.
404 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
409 u8 l1 = n.getLightBlend(daynight_ratio);
410 u8 l2 = n2.getLightBlend(daynight_ratio);
416 // Make some nice difference to different sides
418 // This makes light come from a corner
419 /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
420 light = diminish_light(diminish_light(light));
421 else if(face_dir.X == -1 || face_dir.Z == -1)
422 light = diminish_light(light);*/
424 // All neighboring faces have different shade (like in minecraft)
425 if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
426 light = diminish_light(diminish_light(light));
427 else if(face_dir.Z == 1 || face_dir.Z == -1)
428 light = diminish_light(light);
432 catch(InvalidPositionException &e)