/* Minetest Copyright (C) 2013 celeron55, Perttu Ahola This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "irrlichttypes_extrabloated.h" #include "mapnode.h" #include "porting.h" #include "nodedef.h" #include "content_mapnode.h" // For mapnode_translate_*_internal #include "serialization.h" // For ser_ver_supported #include "util/serialize.h" #include "log.h" #include "util/numeric.h" #include #include static const Rotation wallmounted_to_rot[] = { ROTATE_0, ROTATE_180, ROTATE_90, ROTATE_270 }; static const u8 rot_to_wallmounted[] = { 2, 4, 3, 5 }; /* MapNode */ // Create directly from a nodename // If name is unknown, sets CONTENT_IGNORE MapNode::MapNode(INodeDefManager *ndef, const std::string &name, u8 a_param1, u8 a_param2) { content_t id = CONTENT_IGNORE; ndef->getId(name, id); param0 = id; param1 = a_param1; param2 = a_param2; } void MapNode::setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr) { // If node doesn't contain light data, ignore this if(nodemgr->get(*this).param_type != CPT_LIGHT) return; if(bank == LIGHTBANK_DAY) { param1 &= 0xf0; param1 |= a_light & 0x0f; } else if(bank == LIGHTBANK_NIGHT) { param1 &= 0x0f; param1 |= (a_light & 0x0f)<<4; } else assert("Invalid light bank" == NULL); } bool MapNode::isLightDayNightEq(INodeDefManager *nodemgr) const { const ContentFeatures &f = nodemgr->get(*this); bool isEqual; if (f.param_type == CPT_LIGHT) { u8 day = MYMAX(f.light_source, param1 & 0x0f); u8 night = MYMAX(f.light_source, (param1 >> 4) & 0x0f); isEqual = day == night; } else { isEqual = true; } return isEqual; } u8 MapNode::getLight(enum LightBank bank, INodeDefManager *nodemgr) const { // Select the brightest of [light source, propagated light] const ContentFeatures &f = nodemgr->get(*this); u8 light; if(f.param_type == CPT_LIGHT) light = bank == LIGHTBANK_DAY ? param1 & 0x0f : (param1 >> 4) & 0x0f; else light = 0; return MYMAX(f.light_source, light); } u8 MapNode::getLightNoChecks(enum LightBank bank, const ContentFeatures *f) const { return MYMAX(f->light_source, bank == LIGHTBANK_DAY ? param1 & 0x0f : (param1 >> 4) & 0x0f); } bool MapNode::getLightBanks(u8 &lightday, u8 &lightnight, INodeDefManager *nodemgr) const { // Select the brightest of [light source, propagated light] const ContentFeatures &f = nodemgr->get(*this); if(f.param_type == CPT_LIGHT) { lightday = param1 & 0x0f; lightnight = (param1>>4)&0x0f; } else { lightday = 0; lightnight = 0; } if(f.light_source > lightday) lightday = f.light_source; if(f.light_source > lightnight) lightnight = f.light_source; return f.param_type == CPT_LIGHT || f.light_source != 0; } u8 MapNode::getFaceDir(INodeDefManager *nodemgr) const { const ContentFeatures &f = nodemgr->get(*this); if(f.param_type_2 == CPT2_FACEDIR) return (getParam2() & 0x1F) % 24; return 0; } u8 MapNode::getWallMounted(INodeDefManager *nodemgr) const { const ContentFeatures &f = nodemgr->get(*this); if(f.param_type_2 == CPT2_WALLMOUNTED) return getParam2() & 0x07; return 0; } v3s16 MapNode::getWallMountedDir(INodeDefManager *nodemgr) const { switch(getWallMounted(nodemgr)) { case 0: default: return v3s16(0,1,0); case 1: return v3s16(0,-1,0); case 2: return v3s16(1,0,0); case 3: return v3s16(-1,0,0); case 4: return v3s16(0,0,1); case 5: return v3s16(0,0,-1); } } void MapNode::rotateAlongYAxis(INodeDefManager *nodemgr, Rotation rot) { ContentParamType2 cpt2 = nodemgr->get(*this).param_type_2; if (cpt2 == CPT2_FACEDIR) { static const u8 rotate_facedir[24 * 4] = { // Table value = rotated facedir // Columns: 0, 90, 180, 270 degrees rotation around vertical axis // Rotation is anticlockwise as seen from above (+Y) 0, 1, 2, 3, // Initial facedir 0 to 3 1, 2, 3, 0, 2, 3, 0, 1, 3, 0, 1, 2, 4, 13, 10, 19, // 4 to 7 5, 14, 11, 16, 6, 15, 8, 17, 7, 12, 9, 18, 8, 17, 6, 15, // 8 to 11 9, 18, 7, 12, 10, 19, 4, 13, 11, 16, 5, 14, 12, 9, 18, 7, // 12 to 15 13, 10, 19, 4, 14, 11, 16, 5, 15, 8, 17, 6, 16, 5, 14, 11, // 16 to 19 17, 6, 15, 8, 18, 7, 12, 9, 19, 4, 13, 10, 20, 23, 22, 21, // 20 to 23 21, 20, 23, 22, 22, 21, 20, 23, 23, 22, 21, 20 }; u8 facedir = (param2 & 31) % 24; u8 index = facedir * 4 + rot; param2 &= ~31; param2 |= rotate_facedir[index]; } else if (cpt2 == CPT2_WALLMOUNTED) { u8 wmountface = (param2 & 7); if (wmountface <= 1) return; Rotation oldrot = wallmounted_to_rot[wmountface - 2]; param2 &= ~7; param2 |= rot_to_wallmounted[(oldrot - rot) & 3]; } } static std::vector transformNodeBox(const MapNode &n, const NodeBox &nodebox, INodeDefManager *nodemgr) { std::vector boxes; if(nodebox.type == NODEBOX_FIXED || nodebox.type == NODEBOX_LEVELED) { const std::vector &fixed = nodebox.fixed; int facedir = n.getFaceDir(nodemgr); u8 axisdir = facedir>>2; facedir&=0x03; for(std::vector::const_iterator i = fixed.begin(); i != fixed.end(); ++i) { aabb3f box = *i; if (nodebox.type == NODEBOX_LEVELED) { box.MaxEdge.Y = -BS/2 + BS*((float)1/LEVELED_MAX) * n.getLevel(nodemgr); } switch (axisdir) { case 0: if(facedir == 1) { box.MinEdge.rotateXZBy(-90); box.MaxEdge.rotateXZBy(-90); } else if(facedir == 2) { box.MinEdge.rotateXZBy(180); box.MaxEdge.rotateXZBy(180); } else if(facedir == 3) { box.MinEdge.rotateXZBy(90); box.MaxEdge.rotateXZBy(90); } break; case 1: // z+ box.MinEdge.rotateYZBy(90); box.MaxEdge.rotateYZBy(90); if(facedir == 1) { box.MinEdge.rotateXYBy(90); box.MaxEdge.rotateXYBy(90); } else if(facedir == 2) { box.MinEdge.rotateXYBy(180); box.MaxEdge.rotateXYBy(180); } else if(facedir == 3) { box.MinEdge.rotateXYBy(-90); box.MaxEdge.rotateXYBy(-90); } break; case 2: //z- box.MinEdge.rotateYZBy(-90); box.MaxEdge.rotateYZBy(-90); if(facedir == 1) { box.MinEdge.rotateXYBy(-90); box.MaxEdge.rotateXYBy(-90); } else if(facedir == 2) { box.MinEdge.rotateXYBy(180); box.MaxEdge.rotateXYBy(180); } else if(facedir == 3) { box.MinEdge.rotateXYBy(90); box.MaxEdge.rotateXYBy(90); } break; case 3: //x+ box.MinEdge.rotateXYBy(-90); box.MaxEdge.rotateXYBy(-90); if(facedir == 1) { box.MinEdge.rotateYZBy(90); box.MaxEdge.rotateYZBy(90); } else if(facedir == 2) { box.MinEdge.rotateYZBy(180); box.MaxEdge.rotateYZBy(180); } else if(facedir == 3) { box.MinEdge.rotateYZBy(-90); box.MaxEdge.rotateYZBy(-90); } break; case 4: //x- box.MinEdge.rotateXYBy(90); box.MaxEdge.rotateXYBy(90); if(facedir == 1) { box.MinEdge.rotateYZBy(-90); box.MaxEdge.rotateYZBy(-90); } else if(facedir == 2) { box.MinEdge.rotateYZBy(180); box.MaxEdge.rotateYZBy(180); } else if(facedir == 3) { box.MinEdge.rotateYZBy(90); box.MaxEdge.rotateYZBy/* Minetest Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once #include "voxel.h" #include "mapnode.h" #include "util/container.h" class Map; class ServerMap; class MapBlock; class MMVManip; namespace voxalgo { /*! * Updates the lighting on the map. * The result will be correct only if * no nodes were changed except the given ones. * Before calling this procedure make sure that all new nodes on * the map have zero light level! * * \param oldnodes contains the MapNodes that were replaced by the new * MapNodes and their positions * \param modified_blocks output, contains all map blocks that * the function modified */ void update_lighting_nodes( Map *map, const std::vector<std::pair<v3s16, MapNode>> &oldnodes, std::map<v3s16, MapBlock*> &modified_blocks); /*! * Updates borders of the given mapblock. * Only updates if the block was marked with incomplete * lighting and the neighbor is also loaded. * * \param block the block to update * \param modified_blocks output, contains all map blocks that * the function modified */ void update_block_border_lighting(Map *map, MapBlock *block, std::map<v3s16, MapBlock*> &modified_blocks); /*! * Copies back nodes from a voxel manipulator * to the map and updates lighting. * For server use only. * * \param modified_blocks output, contains all map blocks that * the function modified */ void blit_back_with_light(ServerMap *map, MMVManip *vm, std::map<v3s16, MapBlock*> *modified_blocks); /*! * Corrects the light in a map block. * For server use only. * * \param block the block to update */ void repair_block_light(ServerMap *map, MapBlock *block, std::map<v3s16, MapBlock*> *modified_blocks); /*! * This class iterates trough voxels that intersect with * a line. The collision detection does not see nodeboxes, * every voxel is a cube and is returned. * This iterator steps to all nodes exactly once. */ struct VoxelLineIterator { public: //! Starting position of the line in world coordinates. v3f m_start_position; //! Direction and length of the line in world coordinates. v3f m_line_vector; /*! * Each component stores the next smallest positive number, by * which multiplying the line's vector gives a vector that ends * on the intersection of two nodes. */ v3f m_next_intersection_multi { 10000.0f, 10000.0f, 10000.0f }; /*! * Each component stores the smallest positive number, by which * m_next_intersection_multi's components can be increased. */ v3f m_intersection_multi_inc { 10000.0f, 10000.0f, 10000.0f }; /*! * Direction of the line. Each component can be -1 or 1 (if a { for(u32 i=0; i 0x7f){ param0 <<= 4; param0 |= (param2&0xf0)>>4; param2 &= 0x0f; } } // Convert special values from old version to new if(version <= 19) { // In these versions, CONTENT_IGNORE and CONTENT_AIR // are 255 and 254 // Version 19 is fucked up with sometimes the old values and sometimes not if(param0 == 255) param0 = CONTENT_IGNORE; else if(param0 == 254) param0 = CONTENT_AIR; } // Translate to our known version *this = mapnode_translate_to_internal(*this, version); }