/* Minetest-c55 Copyright (C) 2010 celeron55, Perttu Ahola This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 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 General Public License for more details. You should have received a copy of the GNU 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 "common_irrlicht.h" #include "mapnode.h" #include "tile.h" #include "porting.h" #include #include "mineral.h" // For g_settings #include "main.h" #include "content_mapnode.h" #include "nodemetadata.h" ContentFeatures::~ContentFeatures() { if(initial_metadata) delete initial_metadata; } void ContentFeatures::setTexture(u16 i, std::string name, u8 alpha) { if(g_texturesource) { tiles[i].texture = g_texturesource->getTexture(name); } if(alpha != 255) { tiles[i].alpha = alpha; tiles[i].material_type = MATERIAL_ALPHA_VERTEX; } if(inventory_texture == NULL) setInventoryTexture(name); } void ContentFeatures::setInventoryTexture(std::string imgname) { if(g_texturesource == NULL) return; imgname += "^[forcesingle"; inventory_texture = g_texturesource->getTextureRaw(imgname); } void ContentFeatures::setInventoryTextureCube(std::string top, std::string left, std::string right) { if(g_texturesource == NULL) return; str_replace_char(top, '^', '&'); str_replace_char(left, '^', '&'); str_replace_char(right, '^', '&'); std::string imgname_full; imgname_full += "[inventorycube{"; imgname_full += top; imgname_full += "{"; imgname_full += left; imgname_full += "{"; imgname_full += right; inventory_texture = g_texturesource->getTextureRaw(imgname_full); } struct ContentFeatures g_content_features[MAX_CONTENT+1]; ContentFeatures & content_features(content_t i) { return g_content_features[i]; } ContentFeatures & content_features(MapNode &n) { return content_features(n.getContent()); } /* See mapnode.h for description. */ void init_mapnode() { if(g_texturesource == NULL) { dstream<<"INFO: Initial run of init_mapnode with " "g_texturesource=NULL. If this segfaults, " "there is a bug with something not checking for " "the NULL value."<reset(); for(u16 j=0; j<6; j++) f->tiles[j].material_type = initial_material_type; } /* Initially set every block to be shown as an unknown block. Don't touch CONTENT_IGNORE or CONTENT_AIR. */ for(u16 i=0; isetAllTextures("unknown_block.png"); f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1"; } /* Initialize mapnode content */ content_mapnode_init(); } v3s16 facedir_rotate(u8 facedir, v3s16 dir) { /* Face 2 (normally Z-) direction: facedir=0: Z- facedir=1: X- facedir=2: Z+ facedir=3: X+ */ v3s16 newdir; if(facedir==0) // Same newdir = v3s16(dir.X, dir.Y, dir.Z); else if(facedir == 1) // Face is taken from rotXZccv(-90) newdir = v3s16(-dir.Z, dir.Y, dir.X); else if(facedir == 2) // Face is taken from rotXZccv(180) newdir = v3s16(-dir.X, dir.Y, -dir.Z); else if(facedir == 3) // Face is taken from rotXZccv(90) newdir = v3s16(dir.Z, dir.Y, -dir.X); else newdir = dir; return newdir; } TileSpec MapNode::getTile(v3s16 dir) { if(content_features(*this).param_type == CPT_FACEDIR_SIMPLE) dir = facedir_rotate(param1, dir); TileSpec spec; s32 dir_i = -1; if(dir == v3s16(0,0,0)) dir_i = -1; else if(dir == v3s16(0,1,0)) dir_i = 0; else if(dir == v3s16(0,-1,0)) dir_i = 1; else if(dir == v3s16(1,0,0)) dir_i = 2; else if(dir == v3s16(-1,0,0)) dir_i = 3; else if(dir == v3s16(0,0,1)) dir_i = 4; else if(dir == v3s16(0,0,-1)) dir_i = 5; if(dir_i == -1) // Non-directional spec = content_features(*this).tiles[0]; else spec = content_features(*this).tiles[dir_i]; /* If it contains some mineral, change texture id */ if(content_features(*this).param_type == CPT_MINERAL && g_texturesource) { u8 mineral = getMineral(); std::string mineral_texture_name = mineral_block_texture(mineral); if(mineral_texture_name != "") { u32 orig_id = spec.texture.id; std::string texture_name = g_texturesource->getTextureName(orig_id); //texture_name += "^blit:"; texture_name += "^"; texture_name += mineral_texture_name; u32 new_id = g_texturesource->getTextureId(texture_name); spec.texture = g_texturesource->getTexture(new_id); } } return spec; } u8 MapNode::getMineral() { if(content_features(*this).param_type == CPT_MINERAL) { return param1 & 0x0f; } return MINERAL_NONE; } u32 MapNode::serializedLength(u8 version) { if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapNode format not supported"); if(version == 0) return 1; else if(version <= 9) return 2; else return 3; } void MapNode::serialize(u8 *dest, u8 version) { if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapNode format not supported"); // Translate to wanted version MapNode n_foreign = mapnode_translate_from_internal(*this, version); u8 actual_param0 = n_foreign.param0; // Convert special values from new version to old if(version <= 18) { // In these versions, CONTENT_IGNORE and CONTENT_AIR // are 255 and 254 if(actual_param0 == CONTENT_IGNORE) actual_param0 = 255; else if(actual_param0 == CONTENT_AIR) actual_param0 = 254; } if(version == 0) { dest[0] = actual_param0; } else if(version <= 9) { dest[0] = actual_param0; dest[1] = n_foreign.param1; } else { dest[0] = actual_param0; dest[1] = n_foreign.param1; dest[2] = n_foreign.param2; } } void MapNode::deSerialize(u8 *source, u8 version) { if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapNode format not supported"); if(version == 0) { param0 = source[0]; } else if(version == 1) { param0 = source[0]; // This version doesn't support saved lighting if(light_propagates() || light_source() > 0) param1 = 0; else param1 = source[1]; } else if(version <= 9) { param0 = source[0]; param1 = source[1]; } else { param0 = source[0]; param1 = source[1]; param2 = source[2]; } // Convert special values from old version to new if(version <= 18) { // In these versions, CONTENT_IGNORE and CONTENT_AIR // are 255 and 254 if(param0 == 255) param0 = CONTENT_IGNORE; else if(param0 == 254) param0 = CONTENT_AIR; } // version 19 is fucked up with sometimes the old values and sometimes not if(version == 19) { 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); } /* Gets lighting value at face of node Parameters must consist of air and !air. Order doesn't matter. If either of the nodes doesn't exist, light is 0. parameters: daynight_ratio: 0...1000 n: getNodeParent(p) n2: getNodeParent(p + face_dir) face_dir: axis oriented unit vector from p to p2 returns encoded light value. */ u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2, v3s16 face_dir) { try{ u8 light; u8 l1 = n.getLightBlend(daynight_ratio); u8 l2 = n2.getLightBlend(daynight_ratio); if(l1 > l2) light = l1; else light = l2; // Make some nice difference to different sides // This makes light come from a corner /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1) light = diminish_light(diminish_light(light)); else if(face_dir.X == -1 || face_dir.Z == -1) light = diminish_light(light);*/ // All neighboring faces have different shade (like in minecraft) if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1) light = diminish_light(diminish_light(light)); else if(face_dir.Z == 1 || face_dir.Z == -1) light = diminish_light(light); return light; } catch(InvalidPositionException &e) { return 0; } }