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
31 Nodes make a face if contents differ and solidness differs.
34 1: Face uses m1's content
35 2: Face uses m2's content
36 equivalent: Whether the blocks share the same face (eg. water and glass)
38 TODO: Add 3: Both faces drawn with backface culling, remove equivalent
40 u8 face_contents(content_t m1, content_t m2, bool *equivalent,
41 INodeDefManager *nodemgr)
45 if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
48 bool contents_differ = (m1 != m2);
50 const ContentFeatures &f1 = nodemgr->get(m1);
51 const ContentFeatures &f2 = nodemgr->get(m2);
53 // Contents don't differ for different forms of same liquid
55 contents_differ = false;
60 bool solidness_differs = (c1 != c2);
61 bool makes_face = contents_differ && solidness_differs;
63 if(makes_face == false)
67 c1 = f1.visual_solidness;
69 c2 = f2.visual_solidness;
73 // If same solidness, liquid takes precense
87 v3s16 facedir_rotate(u8 facedir, v3s16 dir)
90 Face 2 (normally Z-) direction:
97 if(facedir==0) // Same
98 newdir = v3s16(dir.X, dir.Y, dir.Z);
99 else if(facedir == 1) // Face is taken from rotXZccv(-90)
100 newdir = v3s16(-dir.Z, dir.Y, dir.X);
101 else if(facedir == 2) // Face is taken from rotXZccv(180)
102 newdir = v3s16(-dir.X, dir.Y, -dir.Z);
103 else if(facedir == 3) // Face is taken from rotXZccv(90)
104 newdir = v3s16(dir.Z, dir.Y, -dir.X);
110 u8 packDir(v3s16 dir)
131 v3s16 unpackDir(u8 b)
157 void MapNode::setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr)
159 // If node doesn't contain light data, ignore this
160 if(nodemgr->get(*this).param_type != CPT_LIGHT)
162 if(bank == LIGHTBANK_DAY)
165 param1 |= a_light & 0x0f;
167 else if(bank == LIGHTBANK_NIGHT)
170 param1 |= (a_light & 0x0f)<<4;
176 u8 MapNode::getLight(enum LightBank bank, INodeDefManager *nodemgr) const
178 // Select the brightest of [light source, propagated light]
180 if(nodemgr->get(*this).param_type == CPT_LIGHT)
182 if(bank == LIGHTBANK_DAY)
183 light = param1 & 0x0f;
184 else if(bank == LIGHTBANK_NIGHT)
185 light = (param1>>4)&0x0f;
189 if(nodemgr->get(*this).light_source > light)
190 light = nodemgr->get(*this).light_source;
194 u8 MapNode::getLightBanksWithSource(INodeDefManager *nodemgr) const
196 // Select the brightest of [light source, propagated light]
199 if(nodemgr->get(*this).param_type == CPT_LIGHT)
201 lightday = param1 & 0x0f;
202 lightnight = (param1>>4)&0x0f;
204 if(nodemgr->get(*this).light_source > lightday)
205 lightday = nodemgr->get(*this).light_source;
206 if(nodemgr->get(*this).light_source > lightnight)
207 lightnight = nodemgr->get(*this).light_source;
208 return (lightday&0x0f) | ((lightnight<<4)&0xf0);
212 TileSpec MapNode::getTile(v3s16 dir, ITextureSource *tsrc,
213 INodeDefManager *nodemgr) const
215 if(nodemgr->get(*this).param_type == CPT_FACEDIR_SIMPLE)
216 dir = facedir_rotate(param1, dir);
222 if(dir == v3s16(0,0,0))
224 else if(dir == v3s16(0,1,0))
226 else if(dir == v3s16(0,-1,0))
228 else if(dir == v3s16(1,0,0))
230 else if(dir == v3s16(-1,0,0))
232 else if(dir == v3s16(0,0,1))
234 else if(dir == v3s16(0,0,-1))
239 spec = nodemgr->get(*this).tiles[0];
241 spec = nodemgr->get(*this).tiles[dir_i];
244 If it contains some mineral, change texture id
246 if(nodemgr->get(*this).param_type == CPT_MINERAL && tsrc)
248 u8 mineral = getMineral(nodemgr);
249 std::string mineral_texture_name = mineral_block_texture(mineral);
250 if(mineral_texture_name != "")
252 u32 orig_id = spec.texture.id;
253 std::string texture_name = tsrc->getTextureName(orig_id);
254 //texture_name += "^blit:";
256 texture_name += mineral_texture_name;
257 u32 new_id = tsrc->getTextureId(texture_name);
258 spec.texture = tsrc->getTexture(new_id);
266 u8 MapNode::getMineral(INodeDefManager *nodemgr) const
268 if(nodemgr->get(*this).param_type == CPT_MINERAL)
270 return param1 & 0x0f;
276 u32 MapNode::serializedLength(u8 version)
278 if(!ser_ver_supported(version))
279 throw VersionMismatchException("ERROR: MapNode format not supported");
283 else if(version <= 9)
288 void MapNode::serialize(u8 *dest, u8 version)
290 if(!ser_ver_supported(version))
291 throw VersionMismatchException("ERROR: MapNode format not supported");
293 // Translate to wanted version
294 MapNode n_foreign = mapnode_translate_from_internal(*this, version);
296 u8 actual_param0 = n_foreign.param0;
298 // Convert special values from new version to old
301 // In these versions, CONTENT_IGNORE and CONTENT_AIR
303 if(actual_param0 == CONTENT_IGNORE)
305 else if(actual_param0 == CONTENT_AIR)
311 dest[0] = actual_param0;
313 else if(version <= 9)
315 dest[0] = actual_param0;
316 dest[1] = n_foreign.param1;
320 dest[0] = actual_param0;
321 dest[1] = n_foreign.param1;
322 dest[2] = n_foreign.param2;
325 void MapNode::deSerialize(u8 *source, u8 version, INodeDefManager *nodemgr)
327 if(!ser_ver_supported(version))
328 throw VersionMismatchException("ERROR: MapNode format not supported");
334 else if(version == 1)
337 // This version doesn't support saved lighting
338 if(nodemgr->get(*this).light_propagates || nodemgr->get(*this).light_source > 0)
343 else if(version <= 9)
355 // Convert special values from old version to new
358 // In these versions, CONTENT_IGNORE and CONTENT_AIR
361 param0 = CONTENT_IGNORE;
362 else if(param0 == 254)
363 param0 = CONTENT_AIR;
365 // version 19 is fucked up with sometimes the old values and sometimes not
369 param0 = CONTENT_IGNORE;
370 else if(param0 == 254)
371 param0 = CONTENT_AIR;
374 // Translate to our known version
375 *this = mapnode_translate_to_internal(*this, version);
379 Gets lighting value at face of node
381 Parameters must consist of air and !air.
382 Order doesn't matter.
384 If either of the nodes doesn't exist, light is 0.
387 daynight_ratio: 0...1000
388 n: getNode(p) (uses only the lighting value)
389 n2: getNode(p + face_dir) (uses only the lighting value)
390 face_dir: axis oriented unit vector from p to p2
392 returns encoded light value.
394 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
395 v3s16 face_dir, INodeDefManager *nodemgr)
399 u8 l1 = n.getLightBlend(daynight_ratio, nodemgr);
400 u8 l2 = n2.getLightBlend(daynight_ratio, nodemgr);
406 // Make some nice difference to different sides
408 // This makes light come from a corner
409 /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
410 light = diminish_light(diminish_light(light));
411 else if(face_dir.X == -1 || face_dir.Z == -1)
412 light = diminish_light(light);*/
414 // All neighboring faces have different shade (like in minecraft)
415 if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
416 light = diminish_light(diminish_light(light));
417 else if(face_dir.Z == 1 || face_dir.Z == -1)
418 light = diminish_light(light);
422 catch(InvalidPositionException &e)