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
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 TODO: Add 3: Both faces drawn with backface culling, remove equivalent
39 u8 face_contents(content_t m1, content_t m2, bool *equivalent,
40 INodeDefManager *nodemgr)
44 if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
47 bool contents_differ = (m1 != m2);
49 const ContentFeatures &f1 = nodemgr->get(m1);
50 const ContentFeatures &f2 = nodemgr->get(m2);
52 // Contents don't differ for different forms of same liquid
54 contents_differ = false;
59 bool solidness_differs = (c1 != c2);
60 bool makes_face = contents_differ && solidness_differs;
62 if(makes_face == false)
66 c1 = f1.visual_solidness;
68 c2 = f2.visual_solidness;
72 // If same solidness, liquid takes precense
85 v3s16 facedir_rotate(u8 facedir, v3s16 dir)
88 Face 2 (normally Z-) direction:
95 if(facedir==0) // Same
96 newdir = v3s16(dir.X, dir.Y, dir.Z);
97 else if(facedir == 1) // Face is taken from rotXZccv(-90)
98 newdir = v3s16(-dir.Z, dir.Y, dir.X);
99 else if(facedir == 2) // Face is taken from rotXZccv(180)
100 newdir = v3s16(-dir.X, dir.Y, -dir.Z);
101 else if(facedir == 3) // Face is taken from rotXZccv(90)
102 newdir = v3s16(dir.Z, dir.Y, -dir.X);
108 u8 packDir(v3s16 dir)
129 v3s16 unpackDir(u8 b)
155 void MapNode::setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr)
157 // If node doesn't contain light data, ignore this
158 if(nodemgr->get(*this).param_type != CPT_LIGHT)
160 if(bank == LIGHTBANK_DAY)
163 param1 |= a_light & 0x0f;
165 else if(bank == LIGHTBANK_NIGHT)
168 param1 |= (a_light & 0x0f)<<4;
174 u8 MapNode::getLight(enum LightBank bank, INodeDefManager *nodemgr) const
176 // Select the brightest of [light source, propagated light]
178 if(nodemgr->get(*this).param_type == CPT_LIGHT)
180 if(bank == LIGHTBANK_DAY)
181 light = param1 & 0x0f;
182 else if(bank == LIGHTBANK_NIGHT)
183 light = (param1>>4)&0x0f;
187 if(nodemgr->get(*this).light_source > light)
188 light = nodemgr->get(*this).light_source;
192 u8 MapNode::getLightBanksWithSource(INodeDefManager *nodemgr) const
194 // Select the brightest of [light source, propagated light]
197 if(nodemgr->get(*this).param_type == CPT_LIGHT)
199 lightday = param1 & 0x0f;
200 lightnight = (param1>>4)&0x0f;
202 if(nodemgr->get(*this).light_source > lightday)
203 lightday = nodemgr->get(*this).light_source;
204 if(nodemgr->get(*this).light_source > lightnight)
205 lightnight = nodemgr->get(*this).light_source;
206 return (lightday&0x0f) | ((lightnight<<4)&0xf0);
210 TileSpec MapNode::getTile(v3s16 dir, ITextureSource *tsrc,
211 INodeDefManager *nodemgr) const
213 if(nodemgr->get(*this).param_type == CPT_FACEDIR_SIMPLE)
214 dir = facedir_rotate(param1, dir);
220 if(dir == v3s16(0,0,0))
222 else if(dir == v3s16(0,1,0))
224 else if(dir == v3s16(0,-1,0))
226 else if(dir == v3s16(1,0,0))
228 else if(dir == v3s16(-1,0,0))
230 else if(dir == v3s16(0,0,1))
232 else if(dir == v3s16(0,0,-1))
237 spec = nodemgr->get(*this).tiles[0];
239 spec = nodemgr->get(*this).tiles[dir_i];
242 If it contains some mineral, change texture id
244 if(nodemgr->get(*this).param_type == CPT_MINERAL && tsrc)
246 u8 mineral = getMineral(nodemgr);
247 std::string mineral_texture_name = mineral_block_texture(mineral);
248 if(mineral_texture_name != "")
250 u32 orig_id = spec.texture.id;
251 std::string texture_name = tsrc->getTextureName(orig_id);
252 //texture_name += "^blit:";
254 texture_name += mineral_texture_name;
255 u32 new_id = tsrc->getTextureId(texture_name);
256 spec.texture = tsrc->getTexture(new_id);
264 u8 MapNode::getMineral(INodeDefManager *nodemgr) const
266 if(nodemgr->get(*this).param_type == CPT_MINERAL)
268 return param1 & 0x0f;
274 u32 MapNode::serializedLength(u8 version)
276 if(!ser_ver_supported(version))
277 throw VersionMismatchException("ERROR: MapNode format not supported");
281 else if(version <= 9)
286 void MapNode::serialize(u8 *dest, u8 version)
288 if(!ser_ver_supported(version))
289 throw VersionMismatchException("ERROR: MapNode format not supported");
291 // Translate to wanted version
292 MapNode n_foreign = mapnode_translate_from_internal(*this, version);
294 u8 actual_param0 = n_foreign.param0;
296 // Convert special values from new version to old
299 // In these versions, CONTENT_IGNORE and CONTENT_AIR
301 if(actual_param0 == CONTENT_IGNORE)
303 else if(actual_param0 == CONTENT_AIR)
309 dest[0] = actual_param0;
311 else if(version <= 9)
313 dest[0] = actual_param0;
314 dest[1] = n_foreign.param1;
318 dest[0] = actual_param0;
319 dest[1] = n_foreign.param1;
320 dest[2] = n_foreign.param2;
323 void MapNode::deSerialize(u8 *source, u8 version, INodeDefManager *nodemgr)
325 if(!ser_ver_supported(version))
326 throw VersionMismatchException("ERROR: MapNode format not supported");
332 else if(version == 1)
335 // This version doesn't support saved lighting
336 if(nodemgr->get(*this).light_propagates || nodemgr->get(*this).light_source > 0)
341 else if(version <= 9)
353 // Convert special values from old version to new
356 // In these versions, CONTENT_IGNORE and CONTENT_AIR
359 param0 = CONTENT_IGNORE;
360 else if(param0 == 254)
361 param0 = CONTENT_AIR;
363 // version 19 is fucked up with sometimes the old values and sometimes not
367 param0 = CONTENT_IGNORE;
368 else if(param0 == 254)
369 param0 = CONTENT_AIR;
372 // Translate to our known version
373 *this = mapnode_translate_to_internal(*this, version);
377 Gets lighting value at face of node
379 Parameters must consist of air and !air.
380 Order doesn't matter.
382 If either of the nodes doesn't exist, light is 0.
385 daynight_ratio: 0...1000
386 n: getNode(p) (uses only the lighting value)
387 n2: getNode(p + face_dir) (uses only the lighting value)
388 face_dir: axis oriented unit vector from p to p2
390 returns encoded light value.
392 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
393 v3s16 face_dir, INodeDefManager *nodemgr)
397 u8 l1 = n.getLightBlend(daynight_ratio, nodemgr);
398 u8 l2 = n2.getLightBlend(daynight_ratio, nodemgr);
404 // Make some nice difference to different sides
406 // This makes light come from a corner
407 /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
408 light = diminish_light(diminish_light(light));
409 else if(face_dir.X == -1 || face_dir.Z == -1)
410 light = diminish_light(light);*/
412 // All neighboring faces have different shade (like in minecraft)
413 if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
414 light = diminish_light(diminish_light(light));
415 else if(face_dir.Z == 1 || face_dir.Z == -1)
416 light = diminish_light(light);
420 catch(InvalidPositionException &e)