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"
30 #include "content_mapnode.h"
31 #include "nodemetadata.h"
33 ContentFeatures::~ContentFeatures()
35 delete initial_metadata;
37 delete special_material;
43 void ContentFeatures::setTexture(u16 i, std::string name, u8 alpha)
45 used_texturenames[name] = true;
49 tiles[i].texture = g_texturesource->getTexture(name);
54 tiles[i].alpha = alpha;
55 tiles[i].material_type = MATERIAL_ALPHA_VERTEX;
58 if(inventory_texture == NULL)
59 setInventoryTexture(name);
62 void ContentFeatures::setInventoryTexture(std::string imgname)
64 if(g_texturesource == NULL)
67 imgname += "^[forcesingle";
69 inventory_texture = g_texturesource->getTextureRaw(imgname);
72 void ContentFeatures::setInventoryTextureCube(std::string top,
73 std::string left, std::string right)
75 if(g_texturesource == NULL)
78 str_replace_char(top, '^', '&');
79 str_replace_char(left, '^', '&');
80 str_replace_char(right, '^', '&');
82 std::string imgname_full;
83 imgname_full += "[inventorycube{";
88 imgname_full += right;
89 inventory_texture = g_texturesource->getTextureRaw(imgname_full);
93 struct ContentFeatures g_content_features[MAX_CONTENT+1];
95 ContentFeatures & content_features(content_t i)
97 return g_content_features[i];
99 ContentFeatures & content_features(MapNode &n)
101 return content_features(n.getContent());
105 See mapnode.h for description.
109 if(g_texturesource == NULL)
111 dstream<<"INFO: Initial run of init_mapnode with "
112 "g_texturesource=NULL. If this segfaults, "
113 "there is a bug with something not checking for "
114 "the NULL value."<<std::endl;
118 dstream<<"INFO: Full run of init_mapnode with "
119 "g_texturesource!=NULL"<<std::endl;
122 /*// Read some settings
123 bool new_style_water = g_settings.getBool("new_style_water");
124 bool new_style_leaves = g_settings.getBool("new_style_leaves");*/
127 Initialize content feature table
132 Set initial material type to same in all tiles, so that the
133 same material can be used in more stuff.
134 This is set according to the leaves because they are the only
135 differing material to which all materials can be changed to
136 get this optimization.
138 u8 initial_material_type = MATERIAL_ALPHA_SIMPLE;
139 /*if(new_style_leaves)
140 initial_material_type = MATERIAL_ALPHA_SIMPLE;
142 initial_material_type = MATERIAL_ALPHA_NONE;*/
143 for(u16 i=0; i<MAX_CONTENT+1; i++)
145 ContentFeatures *f = &g_content_features[i];
149 for(u16 j=0; j<6; j++)
150 f->tiles[j].material_type = initial_material_type;
155 Initially set every block to be shown as an unknown block.
156 Don't touch CONTENT_IGNORE or CONTENT_AIR.
158 for(u16 i=0; i<MAX_CONTENT+1; i++)
160 if(i == CONTENT_IGNORE || i == CONTENT_AIR)
162 ContentFeatures *f = &g_content_features[i];
163 f->setAllTextures("unknown_block.png");
164 f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
167 // Make CONTENT_IGNORE to not block the view when occlusion culling
168 content_features(CONTENT_IGNORE).solidness = 0;
171 Initialize mapnode content
173 content_mapnode_init();
177 v3s16 facedir_rotate(u8 facedir, v3s16 dir)
180 Face 2 (normally Z-) direction:
187 if(facedir==0) // Same
188 newdir = v3s16(dir.X, dir.Y, dir.Z);
189 else if(facedir == 1) // Face is taken from rotXZccv(-90)
190 newdir = v3s16(-dir.Z, dir.Y, dir.X);
191 else if(facedir == 2) // Face is taken from rotXZccv(180)
192 newdir = v3s16(-dir.X, dir.Y, -dir.Z);
193 else if(facedir == 3) // Face is taken from rotXZccv(90)
194 newdir = v3s16(dir.Z, dir.Y, -dir.X);
201 TileSpec MapNode::getTile(v3s16 dir)
203 if(content_features(*this).param_type == CPT_FACEDIR_SIMPLE)
204 dir = facedir_rotate(param1, dir);
210 if(dir == v3s16(0,0,0))
212 else if(dir == v3s16(0,1,0))
214 else if(dir == v3s16(0,-1,0))
216 else if(dir == v3s16(1,0,0))
218 else if(dir == v3s16(-1,0,0))
220 else if(dir == v3s16(0,0,1))
222 else if(dir == v3s16(0,0,-1))
227 spec = content_features(*this).tiles[0];
229 spec = content_features(*this).tiles[dir_i];
232 If it contains some mineral, change texture id
234 if(content_features(*this).param_type == CPT_MINERAL && g_texturesource)
236 u8 mineral = getMineral();
237 std::string mineral_texture_name = mineral_block_texture(mineral);
238 if(mineral_texture_name != "")
240 u32 orig_id = spec.texture.id;
241 std::string texture_name = g_texturesource->getTextureName(orig_id);
242 //texture_name += "^blit:";
244 texture_name += mineral_texture_name;
245 u32 new_id = g_texturesource->getTextureId(texture_name);
246 spec.texture = g_texturesource->getTexture(new_id);
254 u8 MapNode::getMineral()
256 if(content_features(*this).param_type == CPT_MINERAL)
258 return param1 & 0x0f;
264 u32 MapNode::serializedLength(u8 version)
266 if(!ser_ver_supported(version))
267 throw VersionMismatchException("ERROR: MapNode format not supported");
271 else if(version <= 9)
276 void MapNode::serialize(u8 *dest, u8 version)
278 if(!ser_ver_supported(version))
279 throw VersionMismatchException("ERROR: MapNode format not supported");
281 // Translate to wanted version
282 MapNode n_foreign = mapnode_translate_from_internal(*this, version);
284 u8 actual_param0 = n_foreign.param0;
286 // Convert special values from new version to old
289 // In these versions, CONTENT_IGNORE and CONTENT_AIR
291 if(actual_param0 == CONTENT_IGNORE)
293 else if(actual_param0 == CONTENT_AIR)
299 dest[0] = actual_param0;
301 else if(version <= 9)
303 dest[0] = actual_param0;
304 dest[1] = n_foreign.param1;
308 dest[0] = actual_param0;
309 dest[1] = n_foreign.param1;
310 dest[2] = n_foreign.param2;
313 void MapNode::deSerialize(u8 *source, u8 version)
315 if(!ser_ver_supported(version))
316 throw VersionMismatchException("ERROR: MapNode format not supported");
322 else if(version == 1)
325 // This version doesn't support saved lighting
326 if(light_propagates() || light_source() > 0)
331 else if(version <= 9)
343 // Convert special values from old version to new
346 // In these versions, CONTENT_IGNORE and CONTENT_AIR
349 param0 = CONTENT_IGNORE;
350 else if(param0 == 254)
351 param0 = CONTENT_AIR;
353 // version 19 is fucked up with sometimes the old values and sometimes not
357 param0 = CONTENT_IGNORE;
358 else if(param0 == 254)
359 param0 = CONTENT_AIR;
362 // Translate to our known version
363 *this = mapnode_translate_to_internal(*this, version);
367 Gets lighting value at face of node
369 Parameters must consist of air and !air.
370 Order doesn't matter.
372 If either of the nodes doesn't exist, light is 0.
375 daynight_ratio: 0...1000
377 n2: getNodeParent(p + face_dir)
378 face_dir: axis oriented unit vector from p to p2
380 returns encoded light value.
382 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
387 u8 l1 = n.getLightBlend(daynight_ratio);
388 u8 l2 = n2.getLightBlend(daynight_ratio);
394 // Make some nice difference to different sides
396 // This makes light come from a corner
397 /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
398 light = diminish_light(diminish_light(light));
399 else if(face_dir.X == -1 || face_dir.Z == -1)
400 light = diminish_light(light);*/
402 // All neighboring faces have different shade (like in minecraft)
403 if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
404 light = diminish_light(diminish_light(light));
405 else if(face_dir.Z == 1 || face_dir.Z == -1)
406 light = diminish_light(light);
410 catch(InvalidPositionException &e)