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();
178 Nodes make a face if contents differ and solidness differs.
181 1: Face uses m1's content
182 2: Face uses m2's content
183 equivalent: Whether the blocks share the same face (eg. water and glass)
185 u8 face_contents(content_t m1, content_t m2, bool *equivalent)
189 if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
192 bool contents_differ = (m1 != m2);
194 // Contents don't differ for different forms of same liquid
195 if(content_liquid(m1) && content_liquid(m2)
196 && make_liquid_flowing(m1) == make_liquid_flowing(m2))
197 contents_differ = false;
199 u8 c1 = content_solidness(m1);
200 u8 c2 = content_solidness(m2);
202 bool solidness_differs = (c1 != c2);
203 bool makes_face = contents_differ && solidness_differs;
205 if(makes_face == false)
209 c1 = content_features(m1).visual_solidness;
211 c2 = content_features(m2).visual_solidness;
215 // If same solidness, liquid takes precense
216 if(content_features(m1).liquid_type != LIQUID_NONE)
218 if(content_features(m2).liquid_type != LIQUID_NONE)
228 v3s16 facedir_rotate(u8 facedir, v3s16 dir)
231 Face 2 (normally Z-) direction:
238 if(facedir==0) // Same
239 newdir = v3s16(dir.X, dir.Y, dir.Z);
240 else if(facedir == 1) // Face is taken from rotXZccv(-90)
241 newdir = v3s16(-dir.Z, dir.Y, dir.X);
242 else if(facedir == 2) // Face is taken from rotXZccv(180)
243 newdir = v3s16(-dir.X, dir.Y, -dir.Z);
244 else if(facedir == 3) // Face is taken from rotXZccv(90)
245 newdir = v3s16(dir.Z, dir.Y, -dir.X);
252 TileSpec MapNode::getTile(v3s16 dir)
254 if(content_features(*this).param_type == CPT_FACEDIR_SIMPLE)
255 dir = facedir_rotate(param1, dir);
261 if(dir == v3s16(0,0,0))
263 else if(dir == v3s16(0,1,0))
265 else if(dir == v3s16(0,-1,0))
267 else if(dir == v3s16(1,0,0))
269 else if(dir == v3s16(-1,0,0))
271 else if(dir == v3s16(0,0,1))
273 else if(dir == v3s16(0,0,-1))
278 spec = content_features(*this).tiles[0];
280 spec = content_features(*this).tiles[dir_i];
283 If it contains some mineral, change texture id
285 if(content_features(*this).param_type == CPT_MINERAL && g_texturesource)
287 u8 mineral = getMineral();
288 std::string mineral_texture_name = mineral_block_texture(mineral);
289 if(mineral_texture_name != "")
291 u32 orig_id = spec.texture.id;
292 std::string texture_name = g_texturesource->getTextureName(orig_id);
293 //texture_name += "^blit:";
295 texture_name += mineral_texture_name;
296 u32 new_id = g_texturesource->getTextureId(texture_name);
297 spec.texture = g_texturesource->getTexture(new_id);
305 u8 MapNode::getMineral()
307 if(content_features(*this).param_type == CPT_MINERAL)
309 return param1 & 0x0f;
315 u32 MapNode::serializedLength(u8 version)
317 if(!ser_ver_supported(version))
318 throw VersionMismatchException("ERROR: MapNode format not supported");
322 else if(version <= 9)
327 void MapNode::serialize(u8 *dest, u8 version)
329 if(!ser_ver_supported(version))
330 throw VersionMismatchException("ERROR: MapNode format not supported");
332 // Translate to wanted version
333 MapNode n_foreign = mapnode_translate_from_internal(*this, version);
335 u8 actual_param0 = n_foreign.param0;
337 // Convert special values from new version to old
340 // In these versions, CONTENT_IGNORE and CONTENT_AIR
342 if(actual_param0 == CONTENT_IGNORE)
344 else if(actual_param0 == CONTENT_AIR)
350 dest[0] = actual_param0;
352 else if(version <= 9)
354 dest[0] = actual_param0;
355 dest[1] = n_foreign.param1;
359 dest[0] = actual_param0;
360 dest[1] = n_foreign.param1;
361 dest[2] = n_foreign.param2;
364 void MapNode::deSerialize(u8 *source, u8 version)
366 if(!ser_ver_supported(version))
367 throw VersionMismatchException("ERROR: MapNode format not supported");
373 else if(version == 1)
376 // This version doesn't support saved lighting
377 if(light_propagates() || light_source() > 0)
382 else if(version <= 9)
394 // Convert special values from old version to new
397 // In these versions, CONTENT_IGNORE and CONTENT_AIR
400 param0 = CONTENT_IGNORE;
401 else if(param0 == 254)
402 param0 = CONTENT_AIR;
404 // version 19 is fucked up with sometimes the old values and sometimes not
408 param0 = CONTENT_IGNORE;
409 else if(param0 == 254)
410 param0 = CONTENT_AIR;
413 // Translate to our known version
414 *this = mapnode_translate_to_internal(*this, version);
418 Gets lighting value at face of node
420 Parameters must consist of air and !air.
421 Order doesn't matter.
423 If either of the nodes doesn't exist, light is 0.
426 daynight_ratio: 0...1000
428 n2: getNodeParent(p + face_dir)
429 face_dir: axis oriented unit vector from p to p2
431 returns encoded light value.
433 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
438 u8 l1 = n.getLightBlend(daynight_ratio);
439 u8 l2 = n2.getLightBlend(daynight_ratio);
445 // Make some nice difference to different sides
447 // This makes light come from a corner
448 /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
449 light = diminish_light(diminish_light(light));
450 else if(face_dir.X == -1 || face_dir.Z == -1)
451 light = diminish_light(light);*/
453 // All neighboring faces have different shade (like in minecraft)
454 if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
455 light = diminish_light(diminish_light(light));
456 else if(face_dir.Z == 1 || face_dir.Z == -1)
457 light = diminish_light(light);
461 catch(InvalidPositionException &e)