Ejemplo n.º 1
0
// spawn_tree(pos, treedef)
int ModApiEnvMod::l_spawn_tree(lua_State *L)
{
	GET_ENV_PTR;

	v3s16 p0 = read_v3s16(L, 1);

	treegen::TreeDef tree_def;
	std::string trunk,leaves,fruit;
	INodeDefManager *ndef = env->getGameDef()->ndef();

	if(lua_istable(L, 2))
	{
		getstringfield(L, 2, "axiom", tree_def.initial_axiom);
		getstringfield(L, 2, "rules_a", tree_def.rules_a);
		getstringfield(L, 2, "rules_b", tree_def.rules_b);
		getstringfield(L, 2, "rules_c", tree_def.rules_c);
		getstringfield(L, 2, "rules_d", tree_def.rules_d);
		getstringfield(L, 2, "trunk", trunk);
		tree_def.trunknode=ndef->getId(trunk);
		getstringfield(L, 2, "leaves", leaves);
		tree_def.leavesnode=ndef->getId(leaves);
		tree_def.leaves2_chance=0;
		getstringfield(L, 2, "leaves2", leaves);
		if (leaves !="")
		{
			tree_def.leaves2node=ndef->getId(leaves);
			getintfield(L, 2, "leaves2_chance", tree_def.leaves2_chance);
		}
		getintfield(L, 2, "angle", tree_def.angle);
		getintfield(L, 2, "iterations", tree_def.iterations);
		if (!getintfield(L, 2, "random_level", tree_def.iterations_random_level))
			tree_def.iterations_random_level = 0;
		getstringfield(L, 2, "trunk_type", tree_def.trunk_type);
		getboolfield(L, 2, "thin_branches", tree_def.thin_branches);
		tree_def.fruit_chance=0;
		getstringfield(L, 2, "fruit", fruit);
		if (fruit != "")
		{
			tree_def.fruitnode=ndef->getId(fruit);
			getintfield(L, 2, "fruit_chance",tree_def.fruit_chance);
		}
		tree_def.explicit_seed = getintfield(L, 2, "seed", tree_def.seed);
	}
	else
		return 0;

	treegen::error e;
	if ((e = treegen::spawn_ltree (env, p0, ndef, tree_def)) != treegen::SUCCESS) {
		if (e == treegen::UNBALANCED_BRACKETS) {
			luaL_error(L, "spawn_tree(): closing ']' has no matching opening bracket");
		} else {
			luaL_error(L, "spawn_tree(): unknown error");
		}
	}

	return 1;
}
Ejemplo n.º 2
0
void Mapgen_features::layers_init(EmergeManager *emerge, const Json::Value & paramsj) {
    const auto & layersj = paramsj["layers"];
    INodeDefManager *ndef = emerge->ndef;
    auto layer_default_thickness = paramsj.get("layer_default_thickness", 1).asInt();
    auto layer_thickness_multiplier = paramsj.get("layer_thickness_multiplier", 1).asInt();
    if (!layersj.empty())
        for (unsigned int i = 0; i < layersj.size(); ++i) {
            if (layersj[i].empty())
                continue;
            const auto & layerj = layersj[i];
            const auto & name = layerj["name"].asString();
            if (name.empty())
                continue;
            auto content = ndef->getId(name);
            if (content == CONTENT_IGNORE)
                continue;

            auto layer = layer_data{ content, MapNode(content, layerj["param1"].asInt(), layerj["param2"].asInt()) };
            layer.height_min = layerj.get("y_min", layerj.get("height_min", -MAX_MAP_GENERATION_LIMIT).asInt()).asInt();
            layer.height_max = layerj.get("y_max", layerj.get("height_max", +MAX_MAP_GENERATION_LIMIT).asInt()).asInt();
            layer.thickness  = layerj.get("thickness", layer_default_thickness).asInt() * layer_thickness_multiplier;

            //layer.name = name; //dev
            layers.emplace_back(layer);
        }
    if (layers.empty())
        infostream << "layers empty, using only default:stone mg_params="<<paramsj<<std::endl;
    else
        verbosestream << "layers size=" << layers.size() << std::endl;
}
Ejemplo n.º 3
0
// spawn_tree(pos, treedef)
int ModApiEnvMod::l_spawn_tree(lua_State *L)
{
	GET_ENV_PTR;

	v3s16 p0 = read_v3s16(L, 1);

	treegen::TreeDef tree_def;
	std::string trunk,leaves,fruit;
	INodeDefManager *ndef = env->getGameDef()->ndef();

	if(lua_istable(L, 2))
	{
		getstringfield(L, 2, "axiom", tree_def.initial_axiom);
		getstringfield(L, 2, "rules_a", tree_def.rules_a);
		getstringfield(L, 2, "rules_b", tree_def.rules_b);
		getstringfield(L, 2, "rules_c", tree_def.rules_c);
		getstringfield(L, 2, "rules_d", tree_def.rules_d);
		getstringfield(L, 2, "trunk", trunk);
		tree_def.trunknode=ndef->getId(trunk);
		getstringfield(L, 2, "leaves", leaves);
		tree_def.leavesnode=ndef->getId(leaves);
		tree_def.leaves2_chance=0;
		getstringfield(L, 2, "leaves2", leaves);
		if (leaves !="")
		{
			tree_def.leaves2node=ndef->getId(leaves);
			getintfield(L, 2, "leaves2_chance", tree_def.leaves2_chance);
		}
		getintfield(L, 2, "angle", tree_def.angle);
		getintfield(L, 2, "iterations", tree_def.iterations);
		getintfield(L, 2, "random_level", tree_def.iterations_random_level);
		getstringfield(L, 2, "trunk_type", tree_def.trunk_type);
		getboolfield(L, 2, "thin_branches", tree_def.thin_branches);
		tree_def.fruit_chance=0;
		getstringfield(L, 2, "fruit", fruit);
		if (fruit != "")
		{
			tree_def.fruitnode=ndef->getId(fruit);
			getintfield(L, 2, "fruit_chance",tree_def.fruit_chance);
		}
		getintfield(L, 2, "seed", tree_def.seed);
	}
	else
		return 0;
	treegen::spawn_ltree (env, p0, ndef, tree_def);
	return 1;
}
Ejemplo n.º 4
0
	virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n)
	{
		INodeDefManager *ndef = env->getGameDef()->ndef();
		ServerMap *map = &env->getServerMap();
		
		MapNode n_top = map->getNodeNoEx(p+v3s16(0,1,0));
		content_t c_snow = ndef->getId("snow");
		if(ndef->get(n_top).light_propagates &&
				!ndef->get(n_top).isLiquid() &&
				n_top.getLightBlend(env->getDayNightRatio(), ndef) >= 13)
		{
			if(c_snow != CONTENT_IGNORE && n_top.getContent() == c_snow)
				n.setContent(ndef->getId("dirt_with_snow"));
			else
				n.setContent(ndef->getId("mapgen_dirt_with_grass"));
			map->addNodeWithEvent(p, n);
		}
	}
Ejemplo n.º 5
0
// get_content_id(name)
int ModApiItemMod::l_get_content_id(lua_State *L)
{
	NO_MAP_LOCK_REQUIRED;
	std::string name = luaL_checkstring(L, 1);

	INodeDefManager *ndef = getServer(L)->getNodeDefManager();
	content_t c = ndef->getId(name);

	lua_pushinteger(L, c);
	return 1; /* number of results */
}
Ejemplo n.º 6
0
MapgenSinglenode::MapgenSinglenode(int mapgenid,
	MapgenParams *params, EmergeManager *emerge)
	: Mapgen(mapgenid, params, emerge)
{
	flags = params->flags;

	INodeDefManager *ndef = emerge->ndef;

	c_node = ndef->getId("mapgen_singlenode");
	if (c_node == CONTENT_IGNORE)
		c_node = CONTENT_AIR;
}
Ejemplo n.º 7
0
MapgenV7::MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge) {
	this->generating  = false;
	this->id     = mapgenid;
	this->emerge = emerge;
	this->bmgr   = emerge->biomemgr;

	this->seed        = (int)params->seed;
	this->water_level = params->water_level;
	this->flags       = params->flags;
	this->gennotify   = emerge->gennotify;

	this->csize   = v3s16(1, 1, 1) * params->chunksize * MAP_BLOCKSIZE;

	//// amount of elements to skip for the next index
	//// for noise/height/biome maps (not vmanip)
	this->ystride = csize.X;
	this->zstride = csize.X * csize.Y;

	this->biomemap  = new u8[csize.X * csize.Z];
	this->heightmap = new s16[csize.X * csize.Z];
	this->ridge_heightmap = new s16[csize.X * csize.Z];

	MapgenV7Params *sp = (MapgenV7Params *)params->sparams;
	this->spflags = sp->spflags;

	//// Terrain noise
	noise_terrain_base    = new Noise(&sp->np_terrain_base,    seed, csize.X, csize.Z);
	noise_terrain_alt     = new Noise(&sp->np_terrain_alt,     seed, csize.X, csize.Z);
	noise_terrain_persist = new Noise(&sp->np_terrain_persist, seed, csize.X, csize.Z);
	noise_height_select   = new Noise(&sp->np_height_select,   seed, csize.X, csize.Z);
	noise_filler_depth    = new Noise(&sp->np_filler_depth,    seed, csize.X, csize.Z);
	noise_mount_height    = new Noise(&sp->np_mount_height,    seed, csize.X, csize.Z);
	noise_ridge_uwater    = new Noise(&sp->np_ridge_uwater,    seed, csize.X, csize.Z);

	//// 3d terrain noise
	noise_mountain = new Noise(&sp->np_mountain, seed, csize.X, csize.Y, csize.Z);
	noise_ridge    = new Noise(&sp->np_ridge,    seed, csize.X, csize.Y, csize.Z);

	//// Biome noise
	noise_heat     = new Noise(bmgr->np_heat,     seed, csize.X, csize.Z);
	noise_humidity = new Noise(bmgr->np_humidity, seed, csize.X, csize.Z);

	//// Resolve nodes to be used
	INodeDefManager *ndef = emerge->ndef;

	c_stone           = ndef->getId("mapgen_stone");
	c_dirt            = ndef->getId("mapgen_dirt");
	c_dirt_with_grass = ndef->getId("mapgen_dirt_with_grass");
	c_sand            = ndef->getId("mapgen_sand");
	c_water_source    = ndef->getId("mapgen_water_source");
	c_lava_source     = ndef->getId("mapgen_lava_source");
	c_ice             = ndef->getId("default:ice");
	if (c_ice == CONTENT_IGNORE)
		c_ice = CONTENT_AIR;
}
Ejemplo n.º 8
0
	virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n)
	{
		INodeDefManager *ndef = env->getGameDef()->ndef();
		ServerMap *map = &env->getServerMap();
		
		MapNode n_top = map->getNodeNoEx(p+v3s16(0,1,0));
		if(!ndef->get(n_top).light_propagates ||
				ndef->get(n_top).isLiquid())
		{
			n.setContent(ndef->getId("dirt"));
			map->addNodeWithEvent(p, n);
		}
	}
Ejemplo n.º 9
0
// Correct ids in the block to match nodedef based on names.
// Unknown ones are added to nodedef.
// Will not update itself to match id-name pairs in nodedef.
void correctBlockNodeIds(const NameIdMapping *nimap, MapBlock *block,
		IGameDef *gamedef)
{
	INodeDefManager *nodedef = gamedef->ndef();
	// This means the block contains incorrect ids, and we contain
	// the information to convert those to names.
	// nodedef contains information to convert our names to globally
	// correct ids.
	std::set<content_t> unnamed_contents;
	std::set<std::string> unallocatable_contents;
	for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
	for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
	for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
	{
		v3s16 p(x0,y0,z0);
		MapNode n = block->getNode(p);
		content_t local_id = n.getContent();
		std::string name;
		bool found = nimap->getName(local_id, name);
		if(!found){
			unnamed_contents.insert(local_id);
			continue;
		}
		content_t global_id;
		found = nodedef->getId(name, global_id);
		if(!found){
			global_id = gamedef->allocateUnknownNodeId(name);
			if(global_id == CONTENT_IGNORE){
				unallocatable_contents.insert(name);
				continue;
			}
		}
		n.setContent(global_id);
		block->setNode(p, n);
	}
	for(std::set<content_t>::const_iterator
			i = unnamed_contents.begin();
			i != unnamed_contents.end(); i++){
		errorstream<<"correctBlockNodeIds(): IGNORING ERROR: "
				<<"Block contains id "<<(*i)
				<<" with no name mapping"<<std::endl;
	}
	for(std::set<std::string>::const_iterator
			i = unallocatable_contents.begin();
			i != unallocatable_contents.end(); i++){
		errorstream<<"correctBlockNodeIds(): IGNORING ERROR: "
				<<"Could not allocate global id for node name \""
				<<(*i)<<"\""<<std::endl;
	}
}
MapgenSinglenode::MapgenSinglenode(int mapgenid,
	MapgenParams *params, EmergeManager *emerge)
	: Mapgen(mapgenid, params, emerge)
{
	flags = params->flags;

	INodeDefManager *ndef = emerge->ndef;

	c_node = ndef->getId("mapgen_singlenode");
	if (c_node == CONTENT_IGNORE)
		c_node = CONTENT_AIR;

	MapNode n_node(c_node);
	set_light = (ndef->get(n_node).sunlight_propagates) ? LIGHT_SUN : 0x00;
}
Ejemplo n.º 11
0
static void correctBlockNodeIds(const NameIdMapping *nimap, MapNode *nodes,
		IGameDef *gamedef)
{
	INodeDefManager *nodedef = gamedef->ndef();
	// This means the block contains incorrect ids, and we contain
	// the information to convert those to names.
	// nodedef contains information to convert our names to globally
	// correct ids.
	std::set<content_t> unnamed_contents;
	std::set<std::string> unallocatable_contents;
	std::lock_guard<std::mutex> lock(correctBlockNodeIds_mutex);
	for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
	{
		content_t local_id = nodes[i].getContent();
		std::string name;
		bool found = nimap->getName(local_id, name);
		if(!found){
			unnamed_contents.insert(local_id);
			continue;
		}
		content_t global_id;
		found = nodedef->getId(name, global_id);
		if(!found){
			global_id = gamedef->allocateUnknownNodeId(name);
			if(global_id == CONTENT_IGNORE){
				unallocatable_contents.insert(name);
				continue;
			}
		}
		nodes[i].setContent(global_id);
	}
	for(std::set<content_t>::const_iterator
			i = unnamed_contents.begin();
			i != unnamed_contents.end(); i++){
		errorstream<<"correctBlockNodeIds(): IGNORING ERROR: "
				<<"Block contains id "<<(*i)
				<<" with no name mapping"<<std::endl;
	}
	for(std::set<std::string>::const_iterator
			i = unallocatable_contents.begin();
			i != unallocatable_contents.end(); i++){
		errorstream<<"correctBlockNodeIds(): IGNORING ERROR: "
				<<"Could not allocate global id for node name \""
				<<(*i)<<"\""<<std::endl;
	}
}
Ejemplo n.º 12
0
// get_node_def(nodename)
int ModApiClient::l_get_node_def(lua_State *L)
{
	IGameDef *gdef = getGameDef(L);
	assert(gdef);

	INodeDefManager *ndef = gdef->ndef();
	assert(ndef);

	if (!lua_isstring(L, 1))
		return 0;

	const std::string &name = lua_tostring(L, 1);
	const ContentFeatures &cf = ndef->get(ndef->getId(name));
	if (cf.name != name) // Unknown node. | name = <whatever>, cf.name = ignore
		return 0;

	push_content_features(L, cf);

	return 1;
}
Ejemplo n.º 13
0
	virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n,
			u32 active_object_count, u32 active_object_count_wider)
	{
		if(active_object_count_wider != 0)
			return;

		INodeDefManager *ndef = env->getGameDef()->ndef();
		ServerMap *map = &env->getServerMap();
		
		v3s16 p1 = p + v3s16(myrand_range(-2, 2),
				0, myrand_range(-2, 2));
		MapNode n1 = map->getNodeNoEx(p1);
		MapNode n1b = map->getNodeNoEx(p1+v3s16(0,-1,0));
		if(n1b.getContent() == ndef->getId("dirt_with_grass") &&
				n1.getContent() == CONTENT_AIR)
		{
			v3f pos = intToFloat(p1, BS);
			ServerActiveObject *obj = new RatSAO(env, pos);
			env->addActiveObject(obj);
		}
	}
Ejemplo n.º 14
0
u32 Map::transformLiquidsReal(Server *m_server, unsigned int max_cycle_ms) {

	INodeDefManager *nodemgr = m_gamedef->ndef();

	DSTACK(__FUNCTION_NAME);
	//TimeTaker timer("transformLiquidsReal()");
	u32 loopcount = 0;
	u32 initial_size = transforming_liquid_size();

	s32 regenerated = 0;

#if LIQUID_DEBUG
	bool debug = 1;
#endif

	u8 relax = g_settings->getS16("liquid_relax");
	bool fast_flood = g_settings->getS16("liquid_fast_flood");
	int water_level = g_settings->getS16("water_level");
	s16 liquid_pressure = m_server->m_emerge->params.liquid_pressure;
	//g_settings->getS16NoEx("liquid_pressure", liquid_pressure);

	// list of nodes that due to viscosity have not reached their max level height
	//std::unordered_map<v3POS, bool, v3POSHash, v3POSEqual> must_reflow, must_reflow_second, must_reflow_third;
	std::list<v3POS> must_reflow, must_reflow_second, must_reflow_third;
	// List of MapBlocks that will require a lighting update (due to lava)
	u16 loop_rand = myrand();

	u32 end_ms = porting::getTimeMs() + max_cycle_ms;

NEXT_LIQUID:
	;
	while (transforming_liquid_size() > 0) {
		// This should be done here so that it is done when continue is used
		if (loopcount >= initial_size * 2 || porting::getTimeMs() > end_ms)
			break;
		++loopcount;
		/*
			Get a queued transforming liquid node
		*/
		v3POS p0;
		{
			//JMutexAutoLock lock(m_transforming_liquid_mutex);
			p0 = transforming_liquid_pop();
		}
		s16 total_level = 0;
		//u16 level_max = 0;
		// surrounding flowing liquid nodes
		NodeNeighbor neighbors[7] = { { } };
		// current level of every block
		s8 liquid_levels[7] = { -1, -1, -1, -1, -1, -1, -1};
		// target levels
		s8 liquid_levels_want[7] = { -1, -1, -1, -1, -1, -1, -1};
		s8 can_liquid_same_level = 0;
		s8 can_liquid = 0;
		// warning! when MINETEST_PROTO enabled - CONTENT_IGNORE != 0
		content_t liquid_kind = CONTENT_IGNORE;
		content_t liquid_kind_flowing = CONTENT_IGNORE;
		content_t melt_kind = CONTENT_IGNORE;
		content_t melt_kind_flowing = CONTENT_IGNORE;
		//s8 viscosity = 0;
		/*
			Collect information about the environment, start from self
		 */
		for (u8 e = 0; e < 7; e++) {
			u8 i = liquid_explore_map[e];
			NodeNeighbor & nb = neighbors[i];
			nb.pos = p0 + liquid_flow_dirs[i];
			nb.node = getNodeNoEx(neighbors[i].pos);
			nb.content = nb.node.getContent();
			NeighborType nt = NEIGHBOR_SAME_LEVEL;
			switch (i) {
			case D_TOP:
				nt = NEIGHBOR_UPPER;
				break;
			case D_BOTTOM:
				nt = NEIGHBOR_LOWER;
				break;
			}
			nb.type = nt;
			nb.liquid = 0;
			nb.infinity = 0;
			nb.weight = 0;
			nb.drop = 0;

			if (!nb.node) {
				//if (i == D_SELF && (loopcount % 2) && initial_size < m_liquid_step_flow * 3)
				//	must_reflow_third[nb.pos] = 1;
				//	must_reflow_third.push_back(nb.pos);
				continue;
			}

			auto f = nodemgr->get(nb.content);
			switch (f.liquid_type) {
			case LIQUID_NONE:
				if (nb.content == CONTENT_AIR) {
					liquid_levels[i] = 0;
					nb.liquid = 1;
				}
				//TODO: if (nb.content == CONTENT_AIR || nodemgr->get(nb.node).buildable_to && !nodemgr->get(nb.node).walkable) { // need lua drop api for drop torches
				else if (	melt_kind_flowing != CONTENT_IGNORE &&
				            nb.content == melt_kind_flowing &&
				            nb.type != NEIGHBOR_UPPER &&
				            !(loopcount % 2)) {
					u8 melt_max_level = nb.node.getMaxLevel(nodemgr);
					u8 my_max_level = MapNode(liquid_kind_flowing).getMaxLevel(nodemgr);
					liquid_levels[i] = (float)my_max_level / melt_max_level * nb.node.getLevel(nodemgr);
					if (liquid_levels[i])
						nb.liquid = 1;
				} else if (	melt_kind != CONTENT_IGNORE &&
				            nb.content == melt_kind &&
				            nb.type != NEIGHBOR_UPPER &&
				            !(loopcount % 8)) {
					liquid_levels[i] = nodemgr->get(liquid_kind_flowing).getMaxLevel();
					if (liquid_levels[i])
						nb.liquid = 1;
				} else {
					int drop = ((ItemGroupList) f.groups)["drop_by_liquid"];
					if (drop && !(loopcount % drop) ) {
						liquid_levels[i] = 0;
						nb.liquid = 1;
						nb.drop = 1;
					}
				}

				// todo: for erosion add something here..
				break;
			case LIQUID_SOURCE:
				// if this node is not (yet) of a liquid type,
				// choose the first liquid type we encounter
				if (liquid_kind_flowing == CONTENT_IGNORE)
					liquid_kind_flowing = nodemgr->getId(
					                          f.liquid_alternative_flowing);
				if (liquid_kind == CONTENT_IGNORE)
					liquid_kind = nb.content;
				if (liquid_kind_flowing == CONTENT_IGNORE)
					liquid_kind_flowing = liquid_kind;
				if (melt_kind == CONTENT_IGNORE)
					melt_kind = nodemgr->getId(f.melt);
				if (melt_kind_flowing == CONTENT_IGNORE)
					melt_kind_flowing =
					    nodemgr->getId(
					        nodemgr->get(nodemgr->getId(f.melt)
					                    ).liquid_alternative_flowing);
				if (melt_kind_flowing == CONTENT_IGNORE)
					melt_kind_flowing = melt_kind;
				if (nb.content == liquid_kind) {
					if (nb.node.param2 & LIQUID_STABLE_MASK)
						continue;
					liquid_levels[i] = nb.node.getLevel(nodemgr); //LIQUID_LEVEL_SOURCE;
					nb.liquid = 1;
					nb.infinity = (nb.node.param2 & LIQUID_INFINITY_MASK);
				}
				break;
			case LIQUID_FLOWING:
				// if this node is not (yet) of a liquid type,
				// choose the first liquid type we encounter
				if (liquid_kind_flowing == CONTENT_IGNORE)
					liquid_kind_flowing = nb.content;
				if (liquid_kind == CONTENT_IGNORE)
					liquid_kind = nodemgr->getId(
					                  f.liquid_alternative_source);
				if (liquid_kind == CONTENT_IGNORE)
					liquid_kind = liquid_kind_flowing;
				if (melt_kind_flowing == CONTENT_IGNORE)
					melt_kind_flowing = nodemgr->getId(f.melt);
				if (melt_kind == CONTENT_IGNORE)
					melt_kind = nodemgr->getId(nodemgr->get(nodemgr->getId(
					        f.melt)).liquid_alternative_source);
				if (melt_kind == CONTENT_IGNORE)
					melt_kind = melt_kind_flowing;
				if (nb.content == liquid_kind_flowing) {
					if (nb.node.param2 & LIQUID_STABLE_MASK)
						continue;
					liquid_levels[i] = nb.node.getLevel(nodemgr);
					nb.liquid = 1;
					nb.infinity = (nb.node.param2 & LIQUID_INFINITY_MASK);
				}
				break;
			}

			// only self, top, bottom swap
			if (f.liquid_type && e <= 2) {
				try {
					nb.weight = ((ItemGroupList) f.groups)["weight"];
					if (e == 1 && neighbors[D_BOTTOM].weight && neighbors[D_SELF].weight > neighbors[D_BOTTOM].weight) {
						setNode(neighbors[D_SELF].pos, neighbors[D_BOTTOM].node);
						setNode(neighbors[D_BOTTOM].pos, neighbors[D_SELF].node);
						//must_reflow_second[neighbors[D_SELF].pos] = 1;
						//must_reflow_second[neighbors[D_BOTTOM].pos] = 1;
						must_reflow_second.push_back(neighbors[D_SELF].pos);
						must_reflow_second.push_back(neighbors[D_BOTTOM].pos);
#if LIQUID_DEBUG
						infostream << "Liquid swap1" << neighbors[D_SELF].pos << nodemgr->get(neighbors[D_SELF].node).name << neighbors[D_SELF].node << " w=" << neighbors[D_SELF].weight << " VS " << neighbors[D_BOTTOM].pos << nodemgr->get(neighbors[D_BOTTOM].node).name << neighbors[D_BOTTOM].node << " w=" << neighbors[D_BOTTOM].weight << std::endl;
#endif
						goto NEXT_LIQUID;
					}
					if (e == 2 && neighbors[D_SELF].weight && neighbors[D_TOP].weight > neighbors[D_SELF].weight) {
						setNode(neighbors[D_SELF].pos, neighbors[D_TOP].node);
						setNode(neighbors[D_TOP].pos, neighbors[D_SELF].node);
						//must_reflow_second[neighbors[D_SELF].pos] = 1;
						//must_reflow_second[neighbors[D_TOP].pos] = 1;
						must_reflow_second.push_back(neighbors[D_SELF].pos);
						must_reflow_second.push_back(neighbors[D_TOP].pos);
#if LIQUID_DEBUG
						infostream << "Liquid swap2" << neighbors[D_TOP].pos << nodemgr->get(neighbors[D_TOP].node).name << neighbors[D_TOP].node  << " w=" << neighbors[D_TOP].weight << " VS " << neighbors[D_SELF].pos << nodemgr->get(neighbors[D_SELF].node).name << neighbors[D_SELF].node << " w=" << neighbors[D_SELF].weight << std::endl;
#endif
						goto NEXT_LIQUID;
					}
				} catch(InvalidPositionException &e) {
					verbosestream << "transformLiquidsReal: weight: setNode() failed:" << nb.pos << ":" << e.what() << std::endl;
					//goto NEXT_LIQUID;
				}
			}

			if (nb.liquid) {
				liquid_levels_want[i] = 0;
				++can_liquid;
				if(nb.type == NEIGHBOR_SAME_LEVEL)
					++can_liquid_same_level;
			}
			if (liquid_levels[i] > 0)
				total_level += liquid_levels[i];

#if LIQUID_DEBUG
			infostream << "get node i=" << (int)i << " " << PP(nb.pos) << " c="
			           << nb.content << " p0=" << (int)nb.node.param0 << " p1="
			           << (int)nb.node.param1 << " p2=" << (int)nb.node.param2 << " lt="
			           << f.liquid_type
			           //<< " lk=" << liquid_kind << " lkf=" << liquid_kind_flowing
			           << " l=" << nb.liquid	<< " inf=" << nb.infinity << " nlevel=" << (int)liquid_levels[i]
			           << " totallevel=" << (int)total_level << " cansame="
			           << (int)can_liquid_same_level << " Lmax=" << (int)nodemgr->get(liquid_kind_flowing).getMaxLevel() << std::endl;
#endif
		}

		if (liquid_kind == CONTENT_IGNORE || !neighbors[D_SELF].liquid || total_level <= 0)
			continue;

		s16 level_max = nodemgr->get(liquid_kind_flowing).getMaxLevel();
		s16 level_max_compressed = nodemgr->get(liquid_kind_flowing).getMaxLevel(1);
		s16 pressure = liquid_pressure ? ((ItemGroupList) nodemgr->get(liquid_kind).groups)["pressure"] : 0;
		auto liquid_renewable = nodemgr->get(liquid_kind).liquid_renewable;
#if LIQUID_DEBUG
		s16 total_was = total_level; //debug
#endif
		//viscosity = nodemgr->get(liquid_kind).viscosity;

		s16 level_avg = total_level / can_liquid;
		if (!pressure && level_avg) {
			level_avg = level_max;
		}

#if LIQUID_DEBUG
		if (debug)
			infostream << " go: "
			           << nodemgr->get(liquid_kind).name
			           << " total_level=" << (int)total_level
			           //<<" total_was="<<(int)total_was
			           << " level_max=" << (int)level_max
			           << " level_max_compressed=" << (int)level_max_compressed
			           << " level_avg=" << (int)level_avg
			           << " pressure=" << (int)pressure
			           << " can_liquid=" << (int)can_liquid
			           << " can_liquid_same_level=" << (int)can_liquid_same_level
			           << std::endl;
		;
#endif

		// fill bottom block
		if (neighbors[D_BOTTOM].liquid) {
			liquid_levels_want[D_BOTTOM] = level_avg > level_max ? level_avg : total_level > level_max ? level_max : total_level;
			total_level -= liquid_levels_want[D_BOTTOM];
			//if (pressure && total_level && liquid_levels_want[D_BOTTOM] < level_max_compressed) {
			//	++liquid_levels_want[D_BOTTOM];
			//	--total_level;
			//}
		}

		//relax up
		u16 relax_want = level_max * can_liquid_same_level;
		if (	liquid_renewable &&
		        relax &&
		        ((p0.Y == water_level) || (fast_flood && p0.Y <= water_level)) &&
		        level_max > 1 &&
		        liquid_levels[D_TOP] == 0 &&
		        liquid_levels[D_BOTTOM] >= level_max &&
		        total_level >= relax_want - (can_liquid_same_level - relax) &&
		        total_level < relax_want &&
		        can_liquid_same_level >= relax + 1) {
			regenerated += relax_want - total_level;
#if LIQUID_DEBUG
			infostream << " relax_up: " << " total_level=" << (int)total_level << " to=> " << int(relax_want) << std::endl;
#endif
			total_level = relax_want;
		}

		// prevent lakes in air above unloaded blocks
		if (	liquid_levels[D_TOP] == 0 &&
		        p0.Y > water_level &&
		        level_max > 1 &&
		        !neighbors[D_BOTTOM].node &&
		        !(loopcount % 3)) {
			--total_level;
#if LIQUID_DEBUG
			infostream << " above unloaded fix: " << " total_level=" << (int)total_level << std::endl;
#endif
		}

		// calculate self level 5 blocks
		u16 want_level = level_avg > level_max ? level_avg :
		                 total_level >= level_max * can_liquid_same_level
		                 ? level_max
		                 : total_level / can_liquid_same_level;
		total_level -= want_level * can_liquid_same_level;

		/*
				if (pressure && total_level > 0 && neighbors[D_BOTTOM].liquid) { // bottom pressure +1
					++liquid_levels_want[D_BOTTOM];
					--total_level;
		#if LIQUID_DEBUG
					infostream << " bottom1 pressure+1: " << " bottom=" << (int)liquid_levels_want[D_BOTTOM] << " total_level=" << (int)total_level << std::endl;
		#endif
				}
		*/

		//relax down
		if (	liquid_renewable &&
		        relax &&
		        p0.Y >= water_level - 1  &&
		        p0.Y <= water_level + 1  &&
		        liquid_levels[D_TOP] == 0 &&
		        (total_level <= 1 || !(loopcount % 2)) &&
		        level_max > 1 &&
		        liquid_levels[D_BOTTOM] >= level_max &&
		        want_level <= 0 &&
		        total_level <= (can_liquid_same_level - relax) &&
		        can_liquid_same_level >= relax + 1) {
#if LIQUID_DEBUG
			infostream << " relax_down: " << " total_level WAS=" << (int)total_level << " to => 0" << std::endl;
#endif
			regenerated -= total_level;
			total_level = 0;
		}

		for (u16 ir = D_SELF; ir < D_TOP; ++ir) { // fill only same level
			u16 ii = liquid_random_map[(loopcount + loop_rand + 1) % 4][ir];
			if (!neighbors[ii].liquid)
				continue;
			liquid_levels_want[ii] = want_level;
			//if (viscosity > 1 && (liquid_levels_want[ii]-liquid_levels[ii]>8-viscosity))
			// randomly place rest of divide
			if (liquid_levels_want[ii] < level_max && total_level > 0) {
				if (level_max > LIQUID_LEVEL_SOURCE || loopcount % 3 || liquid_levels[ii] <= 0) {
					if (liquid_levels[ii] > liquid_levels_want[ii]) {
						++liquid_levels_want[ii];
						--total_level;
					}
				} else {
					++liquid_levels_want[ii];
					--total_level;
				}
			}
		}

		for (u16 ir = D_SELF; ir < D_TOP; ++ir) {
			if (total_level < 1)
				break;
			u16 ii = liquid_random_map[(loopcount + loop_rand + 2) % 4][ir];
			if (liquid_levels_want[ii] >= 0 &&
			        liquid_levels_want[ii] < level_max) {
				++liquid_levels_want[ii];
				--total_level;
			}
		}

		// fill top block if can
		if (neighbors[D_TOP].liquid && total_level > 0) {
			//infostream<<"compressing to top was="<<liquid_levels_want[D_TOP]<<" add="<<total_level<<std::endl;
			//liquid_levels_want[D_TOP] = total_level>level_max_compressed?level_max_compressed:total_level;
			liquid_levels_want[D_TOP] = total_level > level_max ? level_max : total_level;
			total_level -= liquid_levels_want[D_TOP];

			//if (liquid_levels_want[D_TOP] && total_level && pressure) {
			if (total_level > 0 && pressure) {

				/*
								if (total_level > 0 && neighbors[D_BOTTOM].liquid) { // bottom pressure +2
									++liquid_levels_want[D_BOTTOM];
									--total_level;
								}
				*/
				//compressing self level while can
				//for (u16 ir = D_SELF; ir < D_TOP; ++ir) {
				for (u16 ir = D_BOTTOM; ir <= D_TOP; ++ir) {
					if (total_level < 1)
						break;
					u16 ii = liquid_random_map[(loopcount + loop_rand + 3) % 4][ir];
					if (neighbors[ii].liquid &&
					        liquid_levels_want[ii] < level_max_compressed) {
						++liquid_levels_want[ii];
						--total_level;
					}
				}

				/*
								if (total_level > 0 && neighbors[D_BOTTOM].liquid) { // bottom pressure +2
									++liquid_levels_want[D_BOTTOM];
									--total_level;
				#if LIQUID_DEBUG
							infostream << " bottom2 pressure+1: " << " bottom=" << (int)liquid_levels_want[D_BOTTOM] << " total_level=" << (int)total_level << std::endl;
				#endif
								}
				*/
			}
		}

		if (pressure) {
			if (neighbors[D_BOTTOM].liquid &&
			        liquid_levels_want[D_BOTTOM] < level_max_compressed &&
			        liquid_levels_want[D_TOP] > 0
			   ) {
				//if (liquid_levels_want[D_BOTTOM] <= liquid_levels_want[D_TOP]) {
				--liquid_levels_want[D_TOP];
				++liquid_levels_want[D_BOTTOM];
#if LIQUID_DEBUG
				infostream << " bottom1 pressure+: " << " bot=" << (int)liquid_levels_want[D_BOTTOM] << " slf=" << (int)liquid_levels_want[D_SELF] << " top=" << (int)liquid_levels_want[D_TOP] << " total_level=" << (int)total_level << std::endl;
#endif
				//}
			} else if (
			    neighbors[D_BOTTOM].liquid &&
			    liquid_levels_want[D_BOTTOM] < level_max_compressed &&
			    liquid_levels_want[D_SELF] > level_max
			) {
				if (liquid_levels_want[D_BOTTOM] <= liquid_levels_want[D_SELF]) {
					--liquid_levels_want[D_SELF];
					++liquid_levels_want[D_BOTTOM];
#if LIQUID_DEBUG
					infostream << " bottom2 pressure+: " << " bot=" << (int)liquid_levels_want[D_BOTTOM] << " slf=" << (int)liquid_levels_want[D_SELF] << " top=" << (int)liquid_levels_want[D_TOP] << " total_level=" << (int)total_level << std::endl;
#endif
				}
			} else if (
			    neighbors[D_TOP].liquid &&
			    liquid_levels_want[D_SELF] < level_max_compressed &&
			    liquid_levels_want[D_TOP] > level_max
			) {
				if (liquid_levels_want[D_SELF] <= liquid_levels_want[D_TOP]) {
					--liquid_levels_want[D_TOP];
					++liquid_levels_want[D_SELF];
#if LIQUID_DEBUG
					infostream << " bottom3 pressure+: " << " bot=" << (int)liquid_levels_want[D_BOTTOM] << " slf=" << (int)liquid_levels_want[D_SELF] << " top=" << (int)liquid_levels_want[D_TOP] << " total_level=" << (int)total_level << std::endl;
#endif
				}
			}

			if (liquid_levels_want[D_TOP] > level_max && relax && total_level <= 0 && level_avg > level_max && liquid_levels_want[D_TOP] < level_avg) {
#if LIQUID_DEBUG
				infostream << " top pressure relax: " << " top=" << (int)liquid_levels_want[D_TOP] << " to=>" << level_avg << std::endl;
#endif

				//regenerated += level_avg - liquid_levels_want[D_TOP];
				//liquid_levels_want[D_TOP] = level_avg;
				regenerated += 1 ;
				liquid_levels_want[D_TOP] += 1;
			}
		}


#if LIQUID_DEBUG
		if (total_level > 0)
			infostream << " rest 1: "
			           << " wtop=" << (int)liquid_levels_want[D_TOP]
			           << " total_level=" << (int)total_level << std::endl;
#endif

		if (total_level > 0 && neighbors[D_TOP].liquid && liquid_levels_want[D_TOP] < level_max_compressed) {
			s16 add = (total_level > level_max_compressed - liquid_levels_want[D_TOP]) ? level_max_compressed - liquid_levels_want[D_TOP] : total_level;
			liquid_levels_want[D_TOP] += add;
			total_level -= add;
		}


		if (total_level > 0 && neighbors[D_SELF].liquid && liquid_levels_want[D_SELF] < level_max_compressed) { // very rare, compressed only
			s16 add = (total_level > level_max_compressed - liquid_levels_want[D_SELF]) ? level_max_compressed - liquid_levels_want[D_SELF] : total_level;
#if LIQUID_DEBUG
			if (total_level > 0)
				infostream << " rest 2: "
				           << " wself=" << (int)liquid_levels_want[D_SELF]
				           << " total_level=" << (int)total_level
				           << " add=" << (int)add
				           << std::endl;
#endif

			liquid_levels_want[D_SELF] += add;
			total_level -= add;
		}


#if LIQUID_DEBUG
		if (total_level > 0)
			infostream << " rest 3: "
			           << " total_level=" << (int)total_level << std::endl;
#endif

		for (u16 ii = 0; ii < 7; ii++) { // infinity and cave flood optimization
			if (neighbors[ii].infinity && liquid_levels_want[ii] < liquid_levels[ii]) {
#if LIQUID_DEBUG
				infostream << " infinity: was=" << (int)ii << " = "
				           << (int)liquid_levels_want[ii] << "  to=" << (int)liquid_levels[ii] << std::endl;
#endif

				regenerated += liquid_levels[ii] - liquid_levels_want[ii];
				liquid_levels_want[ii] = liquid_levels[ii];
			} else if ( liquid_levels_want[ii] >= 0	&&
			            liquid_levels_want[ii] < level_max &&
			            level_max > 1					&&
			            fast_flood					&&
			            p0.Y < water_level			&&
			            initial_size >= 1000			&&
			            ii != D_TOP					&&
			            want_level >= level_max / 4	&&
			            can_liquid_same_level >= 5	&&
			            liquid_levels[D_TOP] >= level_max) {
#if LIQUID_DEBUG
				infostream << " flood_fast: was=" << (int)ii << " = "
				           << (int)liquid_levels_want[ii] << "  to=" << (int)level_max << std::endl;
#endif
				regenerated += level_max - liquid_levels_want[ii];
				liquid_levels_want[ii] = level_max;
			}
		}

#if LIQUID_DEBUG
		if (total_level != 0) //|| flowed != volume)
			infostream << " AFTER err level=" << (int)total_level
			           //<< " flowed="<<flowed<< " volume=" << volume
			           << " max=" << (int)level_max
			           << " wantsame=" << (int)want_level << " top="
			           << (int)liquid_levels_want[D_TOP] << " topwas="
			           << (int)liquid_levels[D_TOP]
			           << " bot=" << (int)liquid_levels_want[D_BOTTOM]
			           << " botwas=" << (int)liquid_levels[D_BOTTOM]
			           << std::endl;

		s16 flowed = 0; // for debug
#endif

#if LIQUID_DEBUG
		if (debug) infostream << " dpress=" << " bot=" << (int)liquid_levels_want[D_BOTTOM] << " slf=" << (int)liquid_levels_want[D_SELF] << " top=" << (int)liquid_levels_want[D_TOP] << std::endl;
#endif

		for (u16 r = 0; r < 7; r++) {
			u16 i = liquid_random_map[(loopcount + loop_rand + 4) % 4][r];
			if (liquid_levels_want[i] < 0 || !neighbors[i].liquid)
				continue;

#if LIQUID_DEBUG
			if (debug) infostream << " set=" << i << " " << neighbors[i].pos << " want=" << (int)liquid_levels_want[i] << " was=" << (int) liquid_levels[i] << std::endl;
#endif

			/* disabled because brokes constant volume of lava
			u8 viscosity = nodemgr->get(liquid_kind).liquid_viscosity;
			if (viscosity > 1 && liquid_levels_want[i] != liquid_levels[i]) {
				// amount to gain, limited by viscosity
				// must be at least 1 in absolute value
				s8 level_inc = liquid_levels_want[i] - liquid_levels[i];
				if (level_inc < -viscosity || level_inc > viscosity)
					new_node_level = liquid_levels[i] + level_inc/viscosity;
				else if (level_inc < 0)
					new_node_level = liquid_levels[i] - 1;
				else if (level_inc > 0)
					new_node_level = liquid_levels[i] + 1;
			} else {
			*/

			// last level must flow down on stairs
			if (liquid_levels_want[i] != liquid_levels[i] &&
			        liquid_levels[D_TOP] <= 0 && (!neighbors[D_BOTTOM].liquid || level_max == 1) &&
			        liquid_levels_want[i] >= 1 && liquid_levels_want[i] <= 2) {
				for (u16 ir = D_SELF + 1; ir < D_TOP; ++ir) { // only same level
					u16 ii = liquid_random_map[(loopcount + loop_rand + 5) % 4][ir];
					if (neighbors[ii].liquid)
						must_reflow_second.push_back(neighbors[i].pos + liquid_flow_dirs[ii]);
					//must_reflow_second[neighbors[i].pos + liquid_flow_dirs[ii]] = 1;
				}
			}

#if LIQUID_DEBUG
			if (liquid_levels_want[i] > 0)
				flowed += liquid_levels_want[i];
#endif
			if (liquid_levels[i] == liquid_levels_want[i]) {
				continue;
			}

			if (neighbors[i].drop) {// && level_max > 1 && total_level >= level_max - 1
				m_server->getEnv().getScriptIface()->node_drop(neighbors[i].pos, 2);
			}

			neighbors[i].node.setContent(liquid_kind_flowing);
			neighbors[i].node.setLevel(nodemgr, liquid_levels_want[i], 1);

			try {
				setNode(neighbors[i].pos, neighbors[i].node);
			} catch(InvalidPositionException &e) {
				verbosestream << "transformLiquidsReal: setNode() failed:" << neighbors[i].pos << ":" << e.what() << std::endl;
			}

			// If node emits light, MapBlock requires lighting update
			// or if node removed
			v3POS blockpos = getNodeBlockPos(neighbors[i].pos);
			MapBlock *block = getBlockNoCreateNoEx(blockpos, true); // remove true if light bugs
			if(block != NULL) {
				//modified_blocks[blockpos] = block;
				if(!nodemgr->get(neighbors[i].node).light_propagates || nodemgr->get(neighbors[i].node).light_source) // better to update always
					lighting_modified_blocks.set_try(block->getPos(), block);
			}
			// fmtodo: make here random %2 or..
			if (total_level < level_max * can_liquid)
				must_reflow.push_back(neighbors[i].pos);

		}

#if LIQUID_DEBUG
		//if (total_was != flowed) {
		if (total_was > flowed) {
			infostream << " volume changed!  flowed=" << flowed << " total_was=" << total_was << " want_level=" << want_level;
			for (u16 rr = 0; rr <= 6; rr++) {
				infostream << "  i=" << rr << ",b" << (int)liquid_levels[rr] << ",a" << (int)liquid_levels_want[rr];
			}
			infostream << std::endl;
		}
#endif
		/* //for better relax  only same level
		if (changed)  for (u16 ii = D_SELF + 1; ii < D_TOP; ++ii) {
			if (!neighbors[ii].l) continue;
			must_reflow.push_back(p0 + dirs[ii]);
		}*/
		//g_profiler->graphAdd("liquids", 1);
	}

	u32 ret = loopcount >= initial_size ? 0 : transforming_liquid_size();
	if (ret || loopcount > m_liquid_step_flow)
		m_liquid_step_flow += (m_liquid_step_flow > loopcount ? -1 : 1) * (int)loopcount / 10;
	/*
	if (loopcount)
		infostream<<"Map::transformLiquidsReal(): loopcount="<<loopcount<<" initial_size="<<initial_size
		<<" avgflow="<<m_liquid_step_flow
		<<" reflow="<<must_reflow.size()
		<<" reflow_second="<<must_reflow_second.size()
		<<" reflow_third="<<must_reflow_third.size()
		<<" queue="<< transforming_liquid_size()
		<<" per="<< porting::getTimeMs() - (end_ms - max_cycle_ms)
		<<" ret="<<ret<<std::endl;
	*/

	{
		//TimeTaker timer13("transformLiquidsReal() reflow");
		//auto lock = m_transforming_liquid.lock_unique_rec();
		std::lock_guard<std::mutex> lock(m_transforming_liquid_mutex);

		//m_transforming_liquid.insert(must_reflow.begin(), must_reflow.end());
		for (const auto & p : must_reflow)
			m_transforming_liquid.push_back(p);
		must_reflow.clear();
		//m_transforming_liquid.insert(must_reflow_second.begin(), must_reflow_second.end());
		for (const auto & p : must_reflow_second)
			m_transforming_liquid.push_back(p);
		must_reflow_second.clear();
		//m_transforming_liquid.insert(must_reflow_third.begin(), must_reflow_third.end());
		for (const auto & p : must_reflow_third)
			m_transforming_liquid.push_back(p);
		must_reflow_third.clear();
	}

	g_profiler->add("Server: liquids real processed", loopcount);
	if (regenerated)
		g_profiler->add("Server: liquids regenerated", regenerated);
	if (loopcount < initial_size)
		g_profiler->add("Server: liquids queue", initial_size);

	return loopcount;
}
Ejemplo n.º 15
0
MapgenV5::MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge)
	: Mapgen(mapgenid, params, emerge)
	, Mapgen_features(mapgenid, params, emerge)
{
	this->m_emerge = emerge;
	this->bmgr     = emerge->biomemgr;

	// amount of elements to skip for the next index
	// for noise/height/biome maps (not vmanip)
	this->ystride = csize.X;
	this->zstride = csize.X * (csize.Y + 2);

	this->biomemap  = new u8[csize.X * csize.Z];
	this->heightmap = new s16[csize.X * csize.Z];
	this->heatmap   = NULL;
	this->humidmap  = NULL;

	MapgenV5Params *sp = (MapgenV5Params *)params->sparams;
	this->spflags      = sp->spflags;

	// Terrain noise
	noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);
	noise_factor       = new Noise(&sp->np_factor,       seed, csize.X, csize.Z);
	noise_height       = new Noise(&sp->np_height,       seed, csize.X, csize.Z);

	// 3D terrain noise
	noise_cave1  = new Noise(&sp->np_cave1,  seed, csize.X, csize.Y + 2, csize.Z);
	noise_cave2  = new Noise(&sp->np_cave2,  seed, csize.X, csize.Y + 2, csize.Z);
	noise_ground = new Noise(&sp->np_ground, seed, csize.X, csize.Y + 2, csize.Z);

	// Biome noise
	noise_heat           = new Noise(&params->np_biome_heat,           seed, csize.X, csize.Z);
	noise_humidity       = new Noise(&params->np_biome_humidity,       seed, csize.X, csize.Z);
	noise_heat_blend     = new Noise(&params->np_biome_heat_blend,     seed, csize.X, csize.Z);
	noise_humidity_blend = new Noise(&params->np_biome_humidity_blend, seed, csize.X, csize.Z);

	//// Resolve nodes to be used
	INodeDefManager *ndef = emerge->ndef;

	c_stone                = ndef->getId("mapgen_stone");
	c_water_source         = ndef->getId("mapgen_water_source");
	c_lava_source          = ndef->getId("mapgen_lava_source");
	c_desert_stone         = ndef->getId("mapgen_desert_stone");
	c_ice                  = ndef->getId("mapgen_ice");
	c_sandstone            = ndef->getId("mapgen_sandstone");

	c_cobble               = ndef->getId("mapgen_cobble");
	c_stair_cobble         = ndef->getId("mapgen_stair_cobble");
	c_mossycobble          = ndef->getId("mapgen_mossycobble");
	c_sandstonebrick       = ndef->getId("mapgen_sandstonebrick");
	c_stair_sandstonebrick = ndef->getId("mapgen_stair_sandstonebrick");

	if (c_ice == CONTENT_IGNORE)
		c_ice = CONTENT_AIR;
	if (c_mossycobble == CONTENT_IGNORE)
		c_mossycobble = c_cobble;
	if (c_stair_cobble == CONTENT_IGNORE)
		c_stair_cobble = c_cobble;

	//freeminer:
	y_offset = 1;
	float_islands = sp->float_islands;
	noise_float_islands1  = new Noise(&sp->np_float_islands1, seed, csize.X, csize.Y + y_offset * 2, csize.Z);
	noise_float_islands2  = new Noise(&sp->np_float_islands2, seed, csize.X, csize.Y + y_offset * 2, csize.Z);
	noise_float_islands3  = new Noise(&sp->np_float_islands3, seed, csize.X, csize.Z);

	noise_layers          = new Noise(&sp->np_layers,         seed, csize.X, csize.Y + y_offset * 2, csize.Z);
	layers_init(emerge, sp->paramsj);

	//noise_cave_indev      = new Noise(&sp->np_cave_indev,     seed, csize.X, csize.Y + y_offset * 2, csize.Z);
	//===

	if (c_sandstonebrick == CONTENT_IGNORE)
		c_sandstonebrick = c_sandstone;
	if (c_stair_sandstonebrick == CONTENT_IGNORE)
		c_stair_sandstonebrick = c_sandstone;
}
Ejemplo n.º 16
0
void MapBlock::serialize_pre22(std::ostream &os, u8 version, bool disk)
{
	u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;

	MapNode *tmp_data = new MapNode[nodecount];
	
	// Legacy data changes
	// This code has to change from post-22 to pre-22 format.
	INodeDefManager *nodedef = m_gamedef->ndef();
	for(u32 i=0; i<nodecount; i++)
	{
		const ContentFeatures &f = nodedef->get(tmp_data[i].getContent());
		// Mineral
		if(nodedef->getId("default:stone_with_coal") == tmp_data[i].getContent())
		{
			tmp_data[i].setContent(nodedef->getId("default:stone"));
			tmp_data[i].setParam1(1);  // MINERAL_COAL
		}
		else if(nodedef->getId("default:stone_with_iron") == tmp_data[i].getContent())
		{
			tmp_data[i].setContent(nodedef->getId("default:stone"));
			tmp_data[i].setParam1(2);  // MINERAL_IRON
		}
		// facedir_simple
		if(f.legacy_facedir_simple)
		{
			tmp_data[i].setParam1(tmp_data[i].getParam2());
			tmp_data[i].setParam2(0);
		}
		// wall_mounted
		if(f.legacy_wallmounted)
		{
			u8 wallmounted_new_to_old[8] = {0x04, 0x08, 0x01, 0x02, 0x10, 0x20, 0, 0};
			u8 dir_new_format = tmp_data[i].getParam2() & 7; // lowest 3 bits
			u8 dir_old_format = wallmounted_new_to_old[dir_new_format];
			tmp_data[i].setParam2(dir_old_format);
		}
	}

	// Serialize nodes
	u32 ser_length = MapNode::serializedLength(version);
	SharedBuffer<u8> databuf_nodelist(nodecount * ser_length);
	for(u32 i=0; i<nodecount; i++)
	{
		tmp_data[i].serialize(&databuf_nodelist[i*ser_length], version);
	}

	delete[] tmp_data;
		
	// These have no compression
	if(version <= 3 || version == 5 || version == 6)
	{
		writeU8(os, is_underground);
		os.write((char*)*databuf_nodelist, databuf_nodelist.getSize());
	}
	else if(version <= 10)
	{
		/*
			With compression.
			Compress the materials and the params separately.
		*/
		
		// First byte
		writeU8(os, is_underground);

		// Get and compress materials
		SharedBuffer<u8> materialdata(nodecount);
		for(u32 i=0; i<nodecount; i++)
		{
			materialdata[i] = databuf_nodelist[i*ser_length];
		}
		compress(materialdata, os, version);

		// Get and compress lights
		SharedBuffer<u8> lightdata(nodecount);
		for(u32 i=0; i<nodecount; i++)
		{
			lightdata[i] = databuf_nodelist[i*ser_length+1];
		}
		compress(lightdata, os, version);
		
		if(version >= 10)
		{
			// Get and compress param2
			SharedBuffer<u8> param2data(nodecount);
			for(u32 i=0; i<nodecount; i++)
			{
				param2data[i] = databuf_nodelist[i*ser_length+2];
			}
			compress(param2data, os, version);
		}
	}
	// All other versions (newest)
	else
	{
		// First byte
		u8 flags = 0;
		if(is_underground)
			flags |= 0x01;
		if(m_day_night_differs)
			flags |= 0x02;
		if(m_lighting_expired)
			flags |= 0x04;
		if(version >= 18)
		{
			if(m_generated == false)
				flags |= 0x08;
		}
		writeU8(os, flags);
		
		/*
			Get data
		*/

		// Create buffer with different parameters sorted
		SharedBuffer<u8> databuf(nodecount*3);
		for(u32 i=0; i<nodecount; i++)
		{
			databuf[i] = databuf_nodelist[i*ser_length];
			databuf[i+nodecount] = databuf_nodelist[i*ser_length+1];
			databuf[i+nodecount*2] = databuf_nodelist[i*ser_length+2];
		}

		/*
			Compress data to output stream
		*/

		compress(databuf, os, version);
		
		/*
			NodeMetadata
		*/
		if(version >= 14)
		{
			if(version <= 15)
			{
				try{
					std::ostringstream oss(std::ios_base::binary);
					m_node_metadata->serialize(oss);
					os<<serializeString(oss.str());
				}
				// This will happen if the string is longer than 65535
				catch(SerializationError &e)
				{
					// Use an empty string
					os<<serializeString("");
				}
			}
			else
			{
				std::ostringstream oss(std::ios_base::binary);
				m_node_metadata->serialize(oss);
				compressZlib(oss.str(), os);
				//os<<serializeLongString(oss.str());
			}
		}
	}


	if(disk)
	{
		// Versions up from 9 have block objects. (DEPRECATED)
		if(version >= 9)
		{
			// count=0
			writeU16(os, 0);
		}

		// Versions up from 15 have static objects.
		if(version >= 15)
		{
			m_static_objects.serialize(os);
		}

		// Timestamp
		if(version >= 17)
		{
			writeU32(os, getTimestamp());
		}

		// Scan and write node definition id mapping
		if(version >= 21)
		{
			NameIdMapping nimap;
			getBlockNodeIdMapping_pre22(&nimap, data, m_gamedef->ndef());
			nimap.serialize(os);
		}
	}
}
Ejemplo n.º 17
0
void MapBlock::deSerialize_pre22(std::istream &is, u8 version, bool disk)
{
	u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;

	// Initialize default flags
	is_underground = false;
	m_day_night_differs = false;
	m_lighting_expired = false;
	m_generated = true;

	// Make a temporary buffer
	u32 ser_length = MapNode::serializedLength(version);
	SharedBuffer<u8> databuf_nodelist(nodecount * ser_length);

	// These have no compression
	if(version <= 3 || version == 5 || version == 6)
	{
		char tmp;
		is.read(&tmp, 1);
		if(is.gcount() != 1)
			throw SerializationError
					("MapBlock::deSerialize: no enough input data");
		is_underground = tmp;
		is.read((char*)*databuf_nodelist, nodecount * ser_length);
		if(is.gcount() != nodecount * ser_length)
			throw SerializationError
					("MapBlock::deSerialize: no enough input data");
	}
	else if(version <= 10)
	{
		u8 t8;
		is.read((char*)&t8, 1);
		is_underground = t8;

		{
			// Uncompress and set material data
			std::ostringstream os(std::ios_base::binary);
			decompress(is, os, version);
			std::string s = os.str();
			if(s.size() != nodecount)
				throw SerializationError
						("MapBlock::deSerialize: invalid format");
			for(u32 i=0; i<s.size(); i++)
			{
				databuf_nodelist[i*ser_length] = s[i];
			}
		}
		{
			// Uncompress and set param data
			std::ostringstream os(std::ios_base::binary);
			decompress(is, os, version);
			std::string s = os.str();
			if(s.size() != nodecount)
				throw SerializationError
						("MapBlock::deSerialize: invalid format");
			for(u32 i=0; i<s.size(); i++)
			{
				databuf_nodelist[i*ser_length + 1] = s[i];
			}
		}
	
		if(version >= 10)
		{
			// Uncompress and set param2 data
			std::ostringstream os(std::ios_base::binary);
			decompress(is, os, version);
			std::string s = os.str();
			if(s.size() != nodecount)
				throw SerializationError
						("MapBlock::deSerialize: invalid format");
			for(u32 i=0; i<s.size(); i++)
			{
				databuf_nodelist[i*ser_length + 2] = s[i];
			}
		}
	}
	// All other versions (newest)
	else
	{
		u8 flags;
		is.read((char*)&flags, 1);
		is_underground = (flags & 0x01) ? true : false;
		m_day_night_differs = (flags & 0x02) ? true : false;
		m_lighting_expired = (flags & 0x04) ? true : false;
		if(version >= 18)
			m_generated = (flags & 0x08) ? false : true;

		// Uncompress data
		std::ostringstream os(std::ios_base::binary);
		decompress(is, os, version);
		std::string s = os.str();
		if(s.size() != nodecount*3)
			throw SerializationError
					("MapBlock::deSerialize: decompress resulted in size"
					" other than nodecount*3");

		// deserialize nodes from buffer
		for(u32 i=0; i<nodecount; i++)
		{
			databuf_nodelist[i*ser_length] = s[i];
			databuf_nodelist[i*ser_length + 1] = s[i+nodecount];
			databuf_nodelist[i*ser_length + 2] = s[i+nodecount*2];
		}
		
		/*
			NodeMetadata
		*/
		if(version >= 14)
		{
			// Ignore errors
			try{
				if(version <= 15)
				{
					std::string data = deSerializeString(is);
					std::istringstream iss(data, std::ios_base::binary);
					m_node_metadata->deSerialize(iss, m_gamedef);
				}
				else
				{
					//std::string data = deSerializeLongString(is);
					std::ostringstream oss(std::ios_base::binary);
					decompressZlib(is, oss);
					std::istringstream iss(oss.str(), std::ios_base::binary);
					m_node_metadata->deSerialize(iss, m_gamedef);
				}
			}
			catch(SerializationError &e)
			{
				errorstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error"
						<<" while deserializing node metadata"<<std::endl;
			}
		}
	}

	// Deserialize node data
	for(u32 i=0; i<nodecount; i++)
	{
		data[i].deSerialize(&databuf_nodelist[i*ser_length], version);
	}

	if(disk)
	{
		/*
			Versions up from 9 have block objects. (DEPRECATED)
		*/
		if(version >= 9){
			u16 count = readU16(is);
			// Not supported and length not known if count is not 0
			if(count != 0){
				errorstream<<"WARNING: MapBlock::deSerialize_pre22(): "
						<<"Ignoring stuff coming at and after MBOs"<<std::endl;
				return;
			}
		}

		/*
			Versions up from 15 have static objects.
		*/
		if(version >= 15)
			m_static_objects.deSerialize(is);

		// Timestamp
		if(version >= 17){
			setTimestamp(readU32(is));
			m_disk_timestamp = m_timestamp;
		} else {
			setTimestamp(BLOCK_TIMESTAMP_UNDEFINED);
		}

		// Dynamically re-set ids based on node names
		NameIdMapping nimap;
		// If supported, read node definition id mapping
		if(version >= 21){
			nimap.deSerialize(is);
		// Else set the legacy mapping
		} else {
			content_mapnode_get_name_id_mapping(&nimap);
		}
		correctBlockNodeIds(&nimap, data, m_gamedef);
	}


	// Legacy data changes
	// This code has to convert from pre-22 to post-22 format.
	INodeDefManager *nodedef = m_gamedef->ndef();
	for(u32 i=0; i<nodecount; i++)
	{
		const ContentFeatures &f = nodedef->get(data[i].getContent());
		// Mineral
		if(nodedef->getId("default:stone") == data[i].getContent()
				&& data[i].getParam1() == 1)
		{
			data[i].setContent(nodedef->getId("default:stone_with_coal"));
			data[i].setParam1(0);
		}
		else if(nodedef->getId("default:stone") == data[i].getContent()
				&& data[i].getParam1() == 2)
		{
			data[i].setContent(nodedef->getId("default:stone_with_iron"));
			data[i].setParam1(0);
		}
		// facedir_simple
		if(f.legacy_facedir_simple)
		{
			data[i].setParam2(data[i].getParam1());
			data[i].setParam1(0);
		}
		// wall_mounted
		if(f.legacy_wallmounted)
		{
			u8 wallmounted_new_to_old[8] = {0x04, 0x08, 0x01, 0x02, 0x10, 0x20, 0, 0};
			u8 dir_old_format = data[i].getParam2();
			u8 dir_new_format = 0;
			for(u8 j=0; j<8; j++)
			{
				if((dir_old_format & wallmounted_new_to_old[j]) != 0)
				{
					dir_new_format = j;
					break;
				}
			}
			data[i].setParam2(dir_new_format);
		}
	}

}
Ejemplo n.º 18
0
MapgenV6::MapgenV6(int mapgenid, MapgenParams *params, EmergeManager *emerge)
	: Mapgen(mapgenid, params, emerge)
{
	this->m_emerge = emerge;
	this->ystride = csize.X; //////fix this

	this->heightmap = new s16[csize.X * csize.Z];

	MapgenV6Params *sp = (MapgenV6Params *)params->sparams;
	this->spflags     = sp->spflags;
	this->freq_desert = sp->freq_desert;
	this->freq_beach  = sp->freq_beach;

	np_cave        = &sp->np_cave;
	np_humidity    = &sp->np_humidity;
	np_trees       = &sp->np_trees;
	np_apple_trees = &sp->np_apple_trees;

	//// Create noise objects
	noise_terrain_base   = new Noise(&sp->np_terrain_base,   seed, csize.X, csize.Y);
	noise_terrain_higher = new Noise(&sp->np_terrain_higher, seed, csize.X, csize.Y);
	noise_steepness      = new Noise(&sp->np_steepness,      seed, csize.X, csize.Y);
	noise_height_select  = new Noise(&sp->np_height_select,  seed, csize.X, csize.Y);
	noise_mud            = new Noise(&sp->np_mud,            seed, csize.X, csize.Y);
	noise_beach          = new Noise(&sp->np_beach,          seed, csize.X, csize.Y);
	noise_biome          = new Noise(&sp->np_biome,          seed,
			csize.X + 2 * MAP_BLOCKSIZE, csize.Y + 2 * MAP_BLOCKSIZE);
	noise_humidity       = new Noise(&sp->np_humidity,       seed,
			csize.X + 2 * MAP_BLOCKSIZE, csize.Y + 2 * MAP_BLOCKSIZE);

	//// Resolve nodes to be used
	INodeDefManager *ndef = emerge->ndef;

	c_stone           = ndef->getId("mapgen_stone");
	c_dirt            = ndef->getId("mapgen_dirt");
	c_dirt_with_grass = ndef->getId("mapgen_dirt_with_grass");
	c_sand            = ndef->getId("mapgen_sand");
	c_water_source    = ndef->getId("mapgen_water_source");
	c_lava_source     = ndef->getId("mapgen_lava_source");
	c_gravel          = ndef->getId("mapgen_gravel");
	c_desert_stone    = ndef->getId("mapgen_desert_stone");
	c_desert_sand     = ndef->getId("mapgen_desert_sand");
	c_dirt_with_snow  = ndef->getId("mapgen_dirt_with_snow");
	c_snow            = ndef->getId("mapgen_snow");
	c_snowblock       = ndef->getId("mapgen_snowblock");
	c_ice             = ndef->getId("mapgen_ice");
	c_clay            = ndef->getId("default:clay");

	c_cobble          = ndef->getId("mapgen_cobble");
	c_stair_cobble    = ndef->getId("mapgen_stair_cobble");
	c_mossycobble     = ndef->getId("mapgen_mossycobble");

	if (c_desert_sand == CONTENT_IGNORE)
		c_desert_sand = c_sand;
	if (c_desert_stone == CONTENT_IGNORE)
		c_desert_stone = c_stone;
	if (c_mossycobble == CONTENT_IGNORE)
		c_mossycobble = c_cobble;
	if (c_stair_cobble == CONTENT_IGNORE)
		c_stair_cobble = c_cobble;

	// freeminer:
	c_dirt_with_snow  = ndef->getId("mapgen_dirt_with_snow");
	c_ice             = ndef->getId("mapgen_ice");

	if (c_dirt_with_snow == CONTENT_IGNORE)
		c_dirt_with_snow = c_dirt_with_grass;
	if (c_snow == CONTENT_IGNORE)
		c_snow = CONTENT_AIR;
	if (c_snowblock == CONTENT_IGNORE)
		c_snowblock = c_dirt_with_grass;
	if (c_ice == CONTENT_IGNORE)
		c_ice = c_water_source;
}
Ejemplo n.º 19
0
	ClientCached* createClientCachedDirect(const std::string &name,
			IGameDef *gamedef) const
	{
		infostream<<"Lazily creating item texture and mesh for \""
				<<name<<"\""<<std::endl;

		// This is not thread-safe
		sanity_check(get_current_thread_id() == m_main_thread);

		// Skip if already in cache
		ClientCached *cc = NULL;
		m_clientcached.get(name, &cc);
		if(cc)
			return cc;

		ITextureSource *tsrc = gamedef->getTextureSource();
		INodeDefManager *nodedef = gamedef->getNodeDefManager();
		const ItemDefinition &def = get(name);

		// Create new ClientCached
		cc = new ClientCached();

		// Create an inventory texture
		cc->inventory_texture = NULL;
		if(def.inventory_image != "")
			cc->inventory_texture = tsrc->getTexture(def.inventory_image);

		// Additional processing for nodes:
		// - Create a wield mesh if WieldMeshSceneNode can't render
		//   the node on its own.
		// - If inventory_texture isn't set yet, create one using
		//   render-to-texture.
		if (def.type == ITEM_NODE) {
			// Get node properties
			content_t id = nodedef->getId(name);
			const ContentFeatures &f = nodedef->get(id);

			bool need_rtt_mesh = cc->inventory_texture == NULL;

			// Keep this in sync with WieldMeshSceneNode::setItem()
			bool need_wield_mesh =
				!(f.mesh_ptr[0] ||
				  f.drawtype == NDT_NORMAL ||
				  f.drawtype == NDT_ALLFACES ||
				  f.drawtype == NDT_AIRLIKE);

			scene::IMesh *node_mesh = NULL;

			if (need_rtt_mesh || need_wield_mesh) {
				u8 param1 = 0;
				if (f.param_type == CPT_LIGHT)
					param1 = 0xee;

				/*
					Make a mesh from the node
				*/
				MeshMakeData mesh_make_data(gamedef, false);
				u8 param2 = 0;
				if (f.param_type_2 == CPT2_WALLMOUNTED)
					param2 = 1;
				MapNode mesh_make_node(id, param1, param2);
				mesh_make_data.fillSingleNode(&mesh_make_node);
				MapBlockMesh mapblock_mesh(&mesh_make_data, v3s16(0, 0, 0));
				node_mesh = mapblock_mesh.getMesh();
				node_mesh->grab();
				video::SColor c(255, 255, 255, 255);
				setMeshColor(node_mesh, c);

				// scale and translate the mesh so it's a
				// unit cube centered on the origin
				scaleMesh(node_mesh, v3f(1.0/BS, 1.0/BS, 1.0/BS));
				translateMesh(node_mesh, v3f(-1.0, -1.0, -1.0));
			}

			/*
				Draw node mesh into a render target texture
			*/
			if (need_rtt_mesh) {
				TextureFromMeshParams params;
				params.mesh = node_mesh;
				params.dim.set(64, 64);
				params.rtt_texture_name = "INVENTORY_"
					+ def.name + "_RTT";
				params.delete_texture_on_shutdown = true;
				params.camera_position.set(0, 1.0, -1.5);
				params.camera_position.rotateXZBy(45);
				params.camera_lookat.set(0, 0, 0);
				// Set orthogonal projection
				params.camera_projection_matrix.buildProjectionMatrixOrthoLH(
						1.65, 1.65, 0, 100);
				params.ambient_light.set(1.0, 0.2, 0.2, 0.2);
				params.light_position.set(10, 100, -50);
				params.light_color.set(1.0, 0.5, 0.5, 0.5);
				params.light_radius = 1000;

#ifdef __ANDROID__
				params.camera_position.set(0, -1.0, -1.5);
				params.camera_position.rotateXZBy(45);
				params.light_position.set(10, -100, -50);
#endif
				cc->inventory_texture =
					tsrc->generateTextureFromMesh(params);

				// render-to-target didn't work
				if (cc->inventory_texture == NULL) {
					cc->inventory_texture =
						tsrc->getTexture(f.tiledef[0].name);
				}
			}

			/*
				Use the node mesh as the wield mesh
			*/
			if (need_wield_mesh) {
				cc->wield_mesh = node_mesh;
				cc->wield_mesh->grab();

				// no way reference count can be smaller than 2 in this place!
				assert(cc->wield_mesh->getReferenceCount() >= 2);
			}

			if (node_mesh)
				node_mesh->drop();
		}

		// Put in cache
		m_clientcached.set(name, cc);

		return cc;
	}
Ejemplo n.º 20
0
	virtual void updateTexturesAndMeshes(IGameDef *gamedef)
	{
#ifndef SERVER
		infostream<<"ItemDefManager::updateTexturesAndMeshes(): Updating "
				<<"textures and meshes in item definitions"<<std::endl;

		ITextureSource *tsrc = gamedef->getTextureSource();
		INodeDefManager *nodedef = gamedef->getNodeDefManager();
		IrrlichtDevice *device = tsrc->getDevice();
		video::IVideoDriver *driver = device->getVideoDriver();

		for(std::map<std::string, ItemDefinition*>::iterator
				i = m_item_definitions.begin();
				i != m_item_definitions.end(); i++)
		{
			ItemDefinition *def = i->second;

			bool need_node_mesh = false;

			// Create an inventory texture
			def->inventory_texture = NULL;
			if(def->inventory_image != "")
			{
				def->inventory_texture = tsrc->getTextureRaw(def->inventory_image);
			}
			else if(def->type == ITEM_NODE)
			{
				need_node_mesh = true;
			}

			// Create a wield mesh
			if(def->wield_mesh != NULL)
			{
				def->wield_mesh->drop();
				def->wield_mesh = NULL;
			}
			if(def->type == ITEM_NODE && def->wield_image == "")
			{
				need_node_mesh = true;
			}
			else if(def->wield_image != "" || def->inventory_image != "")
			{
				// Extrude the wield image into a mesh

				std::string imagename;
				if(def->wield_image != "")
					imagename = def->wield_image;
				else
					imagename = def->inventory_image;

				def->wield_mesh = createExtrudedMesh(
						tsrc->getTextureRaw(imagename),
						driver,
						def->wield_scale * v3f(40.0, 40.0, 4.0));
				if(def->wield_mesh == NULL)
				{
					infostream<<"ItemDefManager: WARNING: "
						<<"updateTexturesAndMeshes(): "
						<<"Unable to create extruded mesh for item "
						<<def->name<<std::endl;
				}
			}

			if(need_node_mesh)
			{
				/*
					Get node properties
				*/
				content_t id = nodedef->getId(def->name);
				const ContentFeatures &f = nodedef->get(id);

				u8 param1 = 0;
				if(f.param_type == CPT_LIGHT)
					param1 = 0xee;

				/*
				 	Make a mesh from the node
				*/
				MeshMakeData mesh_make_data(gamedef);
				MapNode mesh_make_node(id, param1, 0);
				mesh_make_data.fillSingleNode(&mesh_make_node);
				MapBlockMesh mapblock_mesh(&mesh_make_data);

				scene::IMesh *node_mesh = mapblock_mesh.getMesh();
				assert(node_mesh);
				setMeshColor(node_mesh, video::SColor(255, 255, 255, 255));

				/*
					Scale and translate the mesh so it's a unit cube
					centered on the origin
				*/
				scaleMesh(node_mesh, v3f(1.0/BS, 1.0/BS, 1.0/BS));
				translateMesh(node_mesh, v3f(-1.0, -1.0, -1.0));

				/*
					Draw node mesh into a render target texture
				*/
				if(def->inventory_texture == NULL)
				{
					core::dimension2d<u32> dim(64,64);
					std::string rtt_texture_name = "INVENTORY_"
						+ def->name + "_RTT";
					v3f camera_position(0, 1.0, -1.5);
					camera_position.rotateXZBy(45);
					v3f camera_lookat(0, 0, 0);
					core::CMatrix4<f32> camera_projection_matrix;
					// Set orthogonal projection
					camera_projection_matrix.buildProjectionMatrixOrthoLH(
							1.65, 1.65, 0, 100);

					video::SColorf ambient_light(0.2,0.2,0.2);
					v3f light_position(10, 100, -50);
					video::SColorf light_color(0.5,0.5,0.5);
					f32 light_radius = 1000;

					def->inventory_texture = generateTextureFromMesh(
						node_mesh, device, dim, rtt_texture_name,
						camera_position,
						camera_lookat,
						camera_projection_matrix,
						ambient_light,
						light_position,
						light_color,
						light_radius);

					// render-to-target didn't work
					if(def->inventory_texture == NULL)
					{
						def->inventory_texture =
							tsrc->getTextureRaw(f.tname_tiles[0]);
					}
				}

				/*
					Use the node mesh as the wield mesh
				*/
				if(def->wield_mesh == NULL)
				{
					// Scale to proper wield mesh proportions
					scaleMesh(node_mesh, v3f(30.0, 30.0, 30.0)
							* def->wield_scale);
					def->wield_mesh = node_mesh;
					def->wield_mesh->grab();
				}

				// falling outside of here deletes node_mesh
			}
		}
#endif
	}
Ejemplo n.º 21
0
void mapblock_mesh_generate_special(MeshMakeData *data,
		MeshCollector &collector, IGameDef *gamedef)
{
	INodeDefManager *nodedef = gamedef->ndef();

	// 0ms
	//TimeTaker timer("mapblock_mesh_generate_special()");

	/*
		Some settings
	*/
	bool new_style_water = g_settings->getBool("new_style_water");
	
	float node_liquid_level = 1.0;
	if(new_style_water)
		node_liquid_level = 0.85;
	
	v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE;

	/*// General ground material for special output
	// Texture is modified just before usage
	video::SMaterial material_general;
	material_general.setFlag(video::EMF_LIGHTING, false);
	material_general.setFlag(video::EMF_BILINEAR_FILTER, false);
	material_general.setFlag(video::EMF_FOG_ENABLE, true);
	material_general.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;*/

	for(s16 z=0; z<MAP_BLOCKSIZE; z++)
	for(s16 y=0; y<MAP_BLOCKSIZE; y++)
	for(s16 x=0; x<MAP_BLOCKSIZE; x++)
	{
		v3s16 p(x,y,z);

		MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes+p);
		const ContentFeatures &f = nodedef->get(n);

		// Only solidness=0 stuff is drawn here
		if(f.solidness != 0)
			continue;
		
		switch(f.drawtype){
		default:
			infostream<<"Got "<<f.drawtype<<std::endl;
			assert(0);
			break;
		case NDT_AIRLIKE:
			break;
		case NDT_LIQUID:
		{
			/*
				Add water sources to mesh if using new style
			*/
			assert(nodedef->get(n).special_materials[0]);
			//assert(nodedef->get(n).special_materials[1]);
			assert(nodedef->get(n).special_aps[0]);

			video::SMaterial &liquid_material =
					*nodedef->get(n).special_materials[0];
			/*video::SMaterial &liquid_material_bfculled =
					*nodedef->get(n).special_materials[1];*/
			AtlasPointer &pa_liquid1 =
					*nodedef->get(n).special_aps[0];

			bool top_is_air = false;
			MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
			if(n.getContent() == CONTENT_AIR)
				top_is_air = true;
			
			if(top_is_air == false)
				continue;

			u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio, nodedef));
			video::SColor c = MapBlock_LightColor(
					nodedef->get(n).alpha, l);
			
			video::S3DVertex vertices[4] =
			{
				video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
						pa_liquid1.x0(), pa_liquid1.y1()),
				video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
						pa_liquid1.x1(), pa_liquid1.y1()),
				video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
						pa_liquid1.x1(), pa_liquid1.y0()),
				video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
						pa_liquid1.x0(), pa_liquid1.y0()),
			};

			for(s32 i=0; i<4; i++)
			{
				vertices[i].Pos.Y += (-0.5+node_liquid_level)*BS;
				vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
			}

			u16 indices[] = {0,1,2,2,3,0};
			// Add to mesh collector
			collector.append(liquid_material, vertices, 4, indices, 6);
		break;}
		case NDT_FLOWINGLIQUID:
		{
			/*
				Add flowing liquid to mesh
			*/
			assert(nodedef->get(n).special_materials[0]);
			assert(nodedef->get(n).special_materials[1]);
			assert(nodedef->get(n).special_aps[0]);

			video::SMaterial &liquid_material =
					*nodedef->get(n).special_materials[0];
			video::SMaterial &liquid_material_bfculled =
					*nodedef->get(n).special_materials[1];
			AtlasPointer &pa_liquid1 =
					*nodedef->get(n).special_aps[0];

			bool top_is_same_liquid = false;
			MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
			content_t c_flowing = nodedef->getId(nodedef->get(n).liquid_alternative_flowing);
			content_t c_source = nodedef->getId(nodedef->get(n).liquid_alternative_source);
			if(ntop.getContent() == c_flowing || ntop.getContent() == c_source)
				top_is_same_liquid = true;
			
			u8 l = 0;
			// Use the light of the node on top if possible
			if(nodedef->get(ntop).param_type == CPT_LIGHT)
				l = decode_light(ntop.getLightBlend(data->m_daynight_ratio, nodedef));
			// Otherwise use the light of this node (the liquid)
			else
				l = decode_light(n.getLightBlend(data->m_daynight_ratio, nodedef));
			video::SColor c = MapBlock_LightColor(
					nodedef->get(n).alpha, l);
			
			// Neighbor liquid levels (key = relative position)
			// Includes current node
			core::map<v3s16, f32> neighbor_levels;
			core::map<v3s16, content_t> neighbor_contents;
			core::map<v3s16, u8> neighbor_flags;
			const u8 neighborflag_top_is_same_liquid = 0x01;
			v3s16 neighbor_dirs[9] = {
				v3s16(0,0,0),
				v3s16(0,0,1),
				v3s16(0,0,-1),
				v3s16(1,0,0),
				v3s16(-1,0,0),
				v3s16(1,0,1),
				v3s16(-1,0,-1),
				v3s16(1,0,-1),
				v3s16(-1,0,1),
			};
			for(u32 i=0; i<9; i++)
			{
				content_t content = CONTENT_AIR;
				float level = -0.5 * BS;
				u8 flags = 0;
				// Check neighbor
				v3s16 p2 = p + neighbor_dirs[i];
				MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
				if(n2.getContent() != CONTENT_IGNORE)
				{
					content = n2.getContent();

					if(n2.getContent() == c_source)
						level = (-0.5+node_liquid_level) * BS;
					else if(n2.getContent() == c_flowing)
						level = (-0.5 + ((float)(n2.param2&LIQUID_LEVEL_MASK)
								+ 0.5) / 8.0 * node_liquid_level) * BS;

					// Check node above neighbor.
					// NOTE: This doesn't get executed if neighbor
					//       doesn't exist
					p2.Y += 1;
					n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
					if(n2.getContent() == c_source ||
							n2.getContent() == c_flowing)
						flags |= neighborflag_top_is_same_liquid;
				}
				
				neighbor_levels.insert(neighbor_dirs[i], level);
				neighbor_contents.insert(neighbor_dirs[i], content);
				neighbor_flags.insert(neighbor_dirs[i], flags);
			}

			// Corner heights (average between four liquids)
			f32 corner_levels[4];
			
			v3s16 halfdirs[4] = {
				v3s16(0,0,0),
				v3s16(1,0,0),
				v3s16(1,0,1),
				v3s16(0,0,1),
			};
			for(u32 i=0; i<4; i++)
			{
				v3s16 cornerdir = halfdirs[i];
				float cornerlevel = 0;
				u32 valid_count = 0;
				u32 air_count = 0;
				for(u32 j=0; j<4; j++)
				{
					v3s16 neighbordir = cornerdir - halfdirs[j];
					content_t content = neighbor_contents[neighbordir];
					// If top is liquid, draw starting from top of node
					if(neighbor_flags[neighbordir] &
							neighborflag_top_is_same_liquid)
					{
						cornerlevel = 0.5*BS;
						valid_count = 1;
						break;
					}
					// Source is always the same height
					else if(content == c_source)
					{
						cornerlevel = (-0.5+node_liquid_level)*BS;
						valid_count = 1;
						break;
					}
					// Flowing liquid has level information
					else if(content == c_flowing)
					{
						cornerlevel += neighbor_levels[neighbordir];
						valid_count++;
					}
					else if(content == CONTENT_AIR)
					{
						air_count++;
					}
				}
				if(air_count >= 2)
					cornerlevel = -0.5*BS;
				else if(valid_count > 0)
					cornerlevel /= valid_count;
				corner_levels[i] = cornerlevel;
			}

			/*
				Generate sides
			*/

			v3s16 side_dirs[4] = {
				v3s16(1,0,0),
				v3s16(-1,0,0),
				v3s16(0,0,1),
				v3s16(0,0,-1),
			};
			s16 side_corners[4][2] = {
				{1, 2},
				{3, 0},
				{2, 3},
				{0, 1},
			};
			for(u32 i=0; i<4; i++)
			{
				v3s16 dir = side_dirs[i];

				/*
					If our topside is liquid and neighbor's topside
					is liquid, don't draw side face
				*/
				if(top_is_same_liquid &&
						neighbor_flags[dir] & neighborflag_top_is_same_liquid)
					continue;

				content_t neighbor_content = neighbor_contents[dir];
				const ContentFeatures &n_feat = nodedef->get(neighbor_content);
				
				// Don't draw face if neighbor is blocking the view
				if(n_feat.solidness == 2)
					continue;
				
				bool neighbor_is_same_liquid = (neighbor_content == c_source
						|| neighbor_content == c_flowing);
				
				// Don't draw any faces if neighbor same is liquid and top is
				// same liquid
				if(neighbor_is_same_liquid == true
						&& top_is_same_liquid == false)
					continue;

				// Use backface culled material if neighbor doesn't have a
				// solidness of 0
				video::SMaterial *current_material = &liquid_material;
				if(n_feat.solidness != 0 || n_feat.visual_solidness != 0)
					current_material = &liquid_material_bfculled;
				
				video::S3DVertex vertices[4] =
				{
					video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
							pa_liquid1.x0(), pa_liquid1.y1()),
					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
							pa_liquid1.x1(), pa_liquid1.y1()),
					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
							pa_liquid1.x1(), pa_liquid1.y0()),
					video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
							pa_liquid1.x0(), pa_liquid1.y0()),
				};
				
				/*
					If our topside is liquid, set upper border of face
					at upper border of node
				*/
				if(top_is_same_liquid)
				{
					vertices[2].Pos.Y = 0.5*BS;
					vertices[3].Pos.Y = 0.5*BS;
				}
				/*
					Otherwise upper position of face is corner levels
				*/
				else
				{
					vertices[2].Pos.Y = corner_levels[side_corners[i][0]];
					vertices[3].Pos.Y = corner_levels[side_corners[i][1]];
				}
				
				/*
					If neighbor is liquid, lower border of face is corner
					liquid levels
				*/
				if(neighbor_is_same_liquid)
				{
					vertices[0].Pos.Y = corner_levels[side_corners[i][1]];
					vertices[1].Pos.Y = corner_levels[side_corners[i][0]];
				}
				/*
					If neighbor is not liquid, lower border of face is
					lower border of node
				*/
				else
				{
					vertices[0].Pos.Y = -0.5*BS;
					vertices[1].Pos.Y = -0.5*BS;
				}
				
				for(s32 j=0; j<4; j++)
				{
					if(dir == v3s16(0,0,1))
						vertices[j].Pos.rotateXZBy(0);
					if(dir == v3s16(0,0,-1))
						vertices[j].Pos.rotateXZBy(180);
					if(dir == v3s16(-1,0,0))
						vertices[j].Pos.rotateXZBy(90);
					if(dir == v3s16(1,0,-0))
						vertices[j].Pos.rotateXZBy(-90);
						
					// Do this to not cause glitches when two liquids are
					// side-by-side
					/*if(neighbor_is_same_liquid == false){
						vertices[j].Pos.X *= 0.98;
						vertices[j].Pos.Z *= 0.98;
					}*/

					vertices[j].Pos += intToFloat(p + blockpos_nodes, BS);
				}

				u16 indices[] = {0,1,2,2,3,0};
				// Add to mesh collector
				collector.append(*current_material, vertices, 4, indices, 6);
			}
			
			/*
				Generate top side, if appropriate
			*/
			
			if(top_is_same_liquid == false)
			{
				video::S3DVertex vertices[4] =
				{
					video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
							pa_liquid1.x0(), pa_liquid1.y1()),
					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
							pa_liquid1.x1(), pa_liquid1.y1()),
					video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
							pa_liquid1.x1(), pa_liquid1.y0()),
					video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
							pa_liquid1.x0(), pa_liquid1.y0()),
				};
				
				// This fixes a strange bug
				s32 corner_resolve[4] = {3,2,1,0};

				for(s32 i=0; i<4; i++)
				{
					//vertices[i].Pos.Y += liquid_level;
					//vertices[i].Pos.Y += neighbor_levels[v3s16(0,0,0)];
					s32 j = corner_resolve[i];
					vertices[i].Pos.Y += corner_levels[j];
					vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
				}

				u16 indices[] = {0,1,2,2,3,0};
				// Add to mesh collector
				collector.append(liquid_material, vertices, 4, indices, 6);
			}
		break;}
		case NDT_GLASSLIKE:
		{
			video::SMaterial material_glass;
			material_glass.setFlag(video::EMF_LIGHTING, false);
			material_glass.setFlag(video::EMF_BILINEAR_FILTER, false);
			material_glass.setFlag(video::EMF_FOG_ENABLE, true);
			material_glass.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
			AtlasPointer pa_glass = f.tiles[0].texture;
			material_glass.setTexture(0, pa_glass.atlas);

			u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
			video::SColor c = MapBlock_LightColor(255, l);

			for(u32 j=0; j<6; j++)
			{
				// Check this neighbor
				v3s16 n2p = blockpos_nodes + p + g_6dirs[j];
				MapNode n2 = data->m_vmanip.getNodeNoEx(n2p);
				// Don't make face if neighbor is of same type
				if(n2.getContent() == n.getContent())
					continue;

				// The face at Z+
				video::S3DVertex vertices[4] =
				{
					video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
						pa_glass.x0(), pa_glass.y1()),
					video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
						pa_glass.x1(), pa_glass.y1()),
					video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
						pa_glass.x1(), pa_glass.y0()),
					video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
						pa_glass.x0(), pa_glass.y0()),
				};
				
				// Rotations in the g_6dirs format
				if(j == 0) // Z+
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(0);
				else if(j == 1) // Y+
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateYZBy(-90);
				else if(j == 2) // X+
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(-90);
				else if(j == 3) // Z-
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(180);
				else if(j == 4) // Y-
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateYZBy(90);
				else if(j == 5) // X-
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(90);

				for(u16 i=0; i<4; i++){
					vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
				}

				u16 indices[] = {0,1,2,2,3,0};
				// Add to mesh collector
				collector.append(material_glass, vertices, 4, indices, 6);
			}
		break;}
		case NDT_ALLFACES:
		{
			video::SMaterial material_leaves1;
			material_leaves1.setFlag(video::EMF_LIGHTING, false);
			material_leaves1.setFlag(video::EMF_BILINEAR_FILTER, false);
			material_leaves1.setFlag(video::EMF_FOG_ENABLE, true);
			material_leaves1.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
			AtlasPointer pa_leaves1 = f.tiles[0].texture;
			material_leaves1.setTexture(0, pa_leaves1.atlas);

			u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
			video::SColor c = MapBlock_LightColor(255, l);

			for(u32 j=0; j<6; j++)
			{
				video::S3DVertex vertices[4] =
				{
					video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
						pa_leaves1.x0(), pa_leaves1.y1()),
					video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
						pa_leaves1.x1(), pa_leaves1.y1()),
					video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
						pa_leaves1.x1(), pa_leaves1.y0()),
					video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
						pa_leaves1.x0(), pa_leaves1.y0()),
				};

				// Rotations in the g_6dirs format
				if(j == 0) // Z+
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(0);
				else if(j == 1) // Y+
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateYZBy(-90);
				else if(j == 2) // X+
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(-90);
				else if(j == 3) // Z-
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(180);
				else if(j == 4) // Y-
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateYZBy(90);
				else if(j == 5) // X-
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(90);

				for(u16 i=0; i<4; i++){
					vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
				}

				u16 indices[] = {0,1,2,2,3,0};
				// Add to mesh collector
				collector.append(material_leaves1, vertices, 4, indices, 6);
			}
		break;}
		case NDT_ALLFACES_OPTIONAL:
			// This is always pre-converted to something else
			assert(0);
			break;
		case NDT_TORCHLIKE:
		{
			v3s16 dir = unpackDir(n.param2);
			
			AtlasPointer ap(0);
			if(dir == v3s16(0,-1,0)){
				ap = f.tiles[0].texture; // floor
			} else if(dir == v3s16(0,1,0)){
				ap = f.tiles[1].texture; // ceiling
			// For backwards compatibility
			} else if(dir == v3s16(0,0,0)){
				ap = f.tiles[0].texture; // floor
			} else {
				ap = f.tiles[2].texture; // side
			}

			// Set material
			video::SMaterial material;
			material.setFlag(video::EMF_LIGHTING, false);
			material.setFlag(video::EMF_BACK_FACE_CULLING, false);
			material.setFlag(video::EMF_BILINEAR_FILTER, false);
			material.setFlag(video::EMF_FOG_ENABLE, true);
			//material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
			material.MaterialType
					= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
			material.setTexture(0, ap.atlas);

			video::SColor c(255,255,255,255);

			// Wall at X+ of node
			video::S3DVertex vertices[4] =
			{
				video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c,
						ap.x0(), ap.y1()),
				video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c,
						ap.x1(), ap.y1()),
				video::S3DVertex(BS/2,BS/2,0, 0,0,0, c,
						ap.x1(), ap.y0()),
				video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c,
						ap.x0(), ap.y0()),
			};

			for(s32 i=0; i<4; i++)
			{
				if(dir == v3s16(1,0,0))
					vertices[i].Pos.rotateXZBy(0);
				if(dir == v3s16(-1,0,0))
					vertices[i].Pos.rotateXZBy(180);
				if(dir == v3s16(0,0,1))
					vertices[i].Pos.rotateXZBy(90);
				if(dir == v3s16(0,0,-1))
					vertices[i].Pos.rotateXZBy(-90);
				if(dir == v3s16(0,-1,0))
					vertices[i].Pos.rotateXZBy(45);
				if(dir == v3s16(0,1,0))
					vertices[i].Pos.rotateXZBy(-45);

				vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
			}

			u16 indices[] = {0,1,2,2,3,0};
			// Add to mesh collector
			collector.append(material, vertices, 4, indices, 6);
		break;}
		case NDT_SIGNLIKE:
		{
			// Set material
			video::SMaterial material;
			material.setFlag(video::EMF_LIGHTING, false);
			material.setFlag(video::EMF_BACK_FACE_CULLING, false);
			material.setFlag(video::EMF_BILINEAR_FILTER, false);
			material.setFlag(video::EMF_FOG_ENABLE, true);
			material.MaterialType
					= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
			AtlasPointer ap = f.tiles[0].texture;
			material.setTexture(0, ap.atlas);

			u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio, nodedef));
			video::SColor c = MapBlock_LightColor(255, l);
				
			float d = (float)BS/16;
			// Wall at X+ of node
			video::S3DVertex vertices[4] =
			{
				video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c,
						ap.x0(), ap.y1()),
				video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c,
						ap.x1(), ap.y1()),
				video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c,
						ap.x1(), ap.y0()),
				video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c,
						ap.x0(), ap.y0()),
			};

			v3s16 dir = unpackDir(n.param2);

			for(s32 i=0; i<4; i++)
			{
				if(dir == v3s16(1,0,0))
					vertices[i].Pos.rotateXZBy(0);
				if(dir == v3s16(-1,0,0))
					vertices[i].Pos.rotateXZBy(180);
				if(dir == v3s16(0,0,1))
					vertices[i].Pos.rotateXZBy(90);
				if(dir == v3s16(0,0,-1))
					vertices[i].Pos.rotateXZBy(-90);
				if(dir == v3s16(0,-1,0))
					vertices[i].Pos.rotateXYBy(-90);
				if(dir == v3s16(0,1,0))
					vertices[i].Pos.rotateXYBy(90);

				vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
			}

			u16 indices[] = {0,1,2,2,3,0};
			// Add to mesh collector
			collector.append(material, vertices, 4, indices, 6);
		break;}
		case NDT_PLANTLIKE:
		{
			video::SMaterial material_papyrus;
			material_papyrus.setFlag(video::EMF_LIGHTING, false);
			material_papyrus.setFlag(video::EMF_BILINEAR_FILTER, false);
			material_papyrus.setFlag(video::EMF_FOG_ENABLE, true);
			material_papyrus.MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
			AtlasPointer pa_papyrus = f.tiles[0].texture;
			material_papyrus.setTexture(0, pa_papyrus.atlas);
			
			u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
			video::SColor c = MapBlock_LightColor(255, l);

			for(u32 j=0; j<4; j++)
			{
				video::S3DVertex vertices[4] =
				{
					video::S3DVertex(-BS/2*f.visual_scale,-BS/2,0, 0,0,0, c,
						pa_papyrus.x0(), pa_papyrus.y1()),
					video::S3DVertex( BS/2*f.visual_scale,-BS/2,0, 0,0,0, c,
						pa_papyrus.x1(), pa_papyrus.y1()),
					video::S3DVertex( BS/2*f.visual_scale,
						-BS/2 + f.visual_scale*BS,0, 0,0,0, c,
						pa_papyrus.x1(), pa_papyrus.y0()),
					video::S3DVertex(-BS/2*f.visual_scale,
						-BS/2 + f.visual_scale*BS,0, 0,0,0, c,
						pa_papyrus.x0(), pa_papyrus.y0()),
				};

				if(j == 0)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(45);
				}
				else if(j == 1)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(-45);
				}
				else if(j == 2)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(135);
				}
				else if(j == 3)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(-135);
				}

				for(u16 i=0; i<4; i++)
				{
					vertices[i].Pos *= f.visual_scale;
					vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
				}

				u16 indices[] = {0,1,2,2,3,0};
				// Add to mesh collector
				collector.append(material_papyrus, vertices, 4, indices, 6);
			}
		break;}
		case NDT_FENCELIKE:
		{
			video::SMaterial material_wood;
			material_wood.setFlag(video::EMF_LIGHTING, false);
			material_wood.setFlag(video::EMF_BILINEAR_FILTER, false);
			material_wood.setFlag(video::EMF_FOG_ENABLE, true);
			material_wood.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
			AtlasPointer pa_wood = f.tiles[0].texture;
			material_wood.setTexture(0, pa_wood.atlas);

			u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
			video::SColor c = MapBlock_LightColor(255, l);

			const f32 post_rad=(f32)BS/10;
			const f32 bar_rad=(f32)BS/20;
			const f32 bar_len=(f32)(BS/2)-post_rad;

			// The post - always present
			v3f pos = intToFloat(p+blockpos_nodes, BS);
			f32 postuv[24]={
					0.4,0.4,0.6,0.6,
					0.35,0,0.65,1,
					0.35,0,0.65,1,
					0.35,0,0.65,1,
					0.35,0,0.65,1,
					0.4,0.4,0.6,0.6};
			makeCuboid(material_wood, &collector,
				&pa_wood, c, pos,
				post_rad,BS/2,post_rad, postuv);

			// Now a section of fence, +X, if there's a post there
			v3s16 p2 = p;
			p2.X++;
			MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
			const ContentFeatures *f2 = &nodedef->get(n2);
			if(f2->drawtype == NDT_FENCELIKE)
			{
				pos = intToFloat(p+blockpos_nodes, BS);
				pos.X += BS/2;
				pos.Y += BS/4;
				f32 xrailuv[24]={
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6};
				makeCuboid(material_wood, &collector,
					&pa_wood, c, pos,
					bar_len,bar_rad,bar_rad, xrailuv);

				pos.Y -= BS/2;
				makeCuboid(material_wood, &collector,
					&pa_wood, c, pos,
					bar_len,bar_rad,bar_rad, xrailuv);
			}

			// Now a section of fence, +Z, if there's a post there
			p2 = p;
			p2.Z++;
			n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
			f2 = &nodedef->get(n2);
			if(f2->drawtype == NDT_FENCELIKE)
			{
				pos = intToFloat(p+blockpos_nodes, BS);
				pos.Z += BS/2;
				pos.Y += BS/4;
				f32 zrailuv[24]={
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6};
				makeCuboid(material_wood, &collector,
					&pa_wood, c, pos,
					bar_rad,bar_rad,bar_len, zrailuv);
				pos.Y -= BS/2;
				makeCuboid(material_wood, &collector,
					&pa_wood, c, pos,
					bar_rad,bar_rad,bar_len, zrailuv);

			}
		break;}
		case NDT_RAILLIKE:
		{
			bool is_rail_x [] = { false, false };  /* x-1, x+1 */
			bool is_rail_z [] = { false, false };  /* z-1, z+1 */

			MapNode n_minus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x-1,y,z));
			MapNode n_plus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x+1,y,z));
			MapNode n_minus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z-1));
			MapNode n_plus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z+1));
			
			content_t thiscontent = n.getContent();
			if(n_minus_x.getContent() == thiscontent)
				is_rail_x[0] = true;
			if(n_plus_x.getContent() == thiscontent)
				is_rail_x[1] = true;
			if(n_minus_z.getContent() == thiscontent)
				is_rail_z[0] = true;
			if(n_plus_z.getContent() == thiscontent)
				is_rail_z[1] = true;

			int adjacencies = is_rail_x[0] + is_rail_x[1] + is_rail_z[0] + is_rail_z[1];

			// Assign textures
			AtlasPointer ap = f.tiles[0].texture; // straight
			if(adjacencies < 2)
				ap = f.tiles[0].texture; // straight
			else if(adjacencies == 2)
			{
				if((is_rail_x[0] && is_rail_x[1]) || (is_rail_z[0] && is_rail_z[1]))
					ap = f.tiles[0].texture; // straight
				else
					ap = f.tiles[1].texture; // curved
			}
			else if(adjacencies == 3)
				ap = f.tiles[2].texture; // t-junction
			else if(adjacencies == 4)
				ap = f.tiles[3].texture; // crossing
			
			video::SMaterial material_rail;
			material_rail.setFlag(video::EMF_LIGHTING, false);
			material_rail.setFlag(video::EMF_BACK_FACE_CULLING, false);
			material_rail.setFlag(video::EMF_BILINEAR_FILTER, false);
			material_rail.setFlag(video::EMF_FOG_ENABLE, true);
			material_rail.MaterialType
					= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
			material_rail.setTexture(0, ap.atlas);

			u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio, nodedef));
			video::SColor c = MapBlock_LightColor(255, l);

			float d = (float)BS/16;
			video::S3DVertex vertices[4] =
			{
				video::S3DVertex(-BS/2,-BS/2+d,-BS/2, 0,0,0, c,
						ap.x0(), ap.y1()),
				video::S3DVertex(BS/2,-BS/2+d,-BS/2, 0,0,0, c,
						ap.x1(), ap.y1()),
				video::S3DVertex(BS/2,-BS/2+d,BS/2, 0,0,0, c,
						ap.x1(), ap.y0()),
				video::S3DVertex(-BS/2,-BS/2+d,BS/2, 0,0,0, c,
						ap.x0(), ap.y0()),
			};

			// Rotate textures
			int angle = 0;

			if(adjacencies == 1)
			{
				if(is_rail_x[0] || is_rail_x[1])
					angle = 90;
			}
			else if(adjacencies == 2)
			{
				if(is_rail_x[0] && is_rail_x[1])
					angle = 90;
				else if(is_rail_x[0] && is_rail_z[0])
					angle = 270;
				else if(is_rail_x[0] && is_rail_z[1])
					angle = 180;
				else if(is_rail_x[1] && is_rail_z[1])
					angle = 90;
			}
			else if(adjacencies == 3)
			{
				if(!is_rail_x[0])
					angle=0;
				if(!is_rail_x[1])
					angle=180;
				if(!is_rail_z[0])
					angle=90;
				if(!is_rail_z[1])
					angle=270;
			}

			if(angle != 0) {
				for(u16 i=0; i<4; i++)
					vertices[i].Pos.rotateXZBy(angle);
			}

			for(s32 i=0; i<4; i++)
			{
				vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
			}

			u16 indices[] = {0,1,2,2,3,0};
			collector.append(material_rail, vertices, 4, indices, 6);
		break;}
		}
	}
}
Ejemplo n.º 22
0
void WieldMeshSceneNode::setItem(const ItemStack &item, IGameDef *gamedef)
{
	ITextureSource *tsrc = gamedef->getTextureSource();
	IItemDefManager *idef = gamedef->getItemDefManager();
	//IShaderSource *shdrsrc = gamedef->getShaderSource();
	INodeDefManager *ndef = gamedef->getNodeDefManager();
	const ItemDefinition &def = item.getDefinition(idef);
	const ContentFeatures &f = ndef->get(def.name);
	content_t id = ndef->getId(def.name);

#if 0
//// TODO(RealBadAngel): Reactivate when shader is added for wield items
	if (m_enable_shaders) {
		u32 shader_id = shdrsrc->getShader("nodes_shader", TILE_MATERIAL_BASIC, NDT_NORMAL);
		m_material_type = shdrsrc->getShaderInfo(shader_id).material;
	}
#endif

	// If wield_image is defined, it overrides everything else
	if (def.wield_image != "") {
		setExtruded(def.wield_image, def.wield_scale, tsrc, 1);
		return;
	}
	// Handle nodes
	// See also CItemDefManager::createClientCached()
	else if (def.type == ITEM_NODE) {
		if (f.mesh_ptr[0]) {
			// e.g. mesh nodes and nodeboxes
			changeToMesh(f.mesh_ptr[0]);
			// mesh_ptr[0] is pre-scaled by BS * f->visual_scale
			m_meshnode->setScale(
					def.wield_scale * WIELD_SCALE_FACTOR
					/ (BS * f.visual_scale));
		} else if (f.drawtype == NDT_AIRLIKE) {
			changeToMesh(NULL);
		} else if (f.drawtype == NDT_PLANTLIKE) {
			setExtruded(tsrc->getTextureName(f.tiles[0].texture_id), def.wield_scale, tsrc, f.tiles[0].animation_frame_count);
		} else if (f.drawtype == NDT_NORMAL || f.drawtype == NDT_ALLFACES) {
			setCube(f.tiles, def.wield_scale, tsrc);
		} else {
			//// TODO: Change false in the following constructor args to
			//// appropriate value when shader is added for wield items (if applicable)
			MeshMakeData mesh_make_data(gamedef, false);
			MapNode mesh_make_node(id, 255, 0);
			mesh_make_data.fillSingleNode(&mesh_make_node);
			MapBlockMesh mapblock_mesh(&mesh_make_data, v3s16(0, 0, 0));
			changeToMesh(mapblock_mesh.getMesh());
			translateMesh(m_meshnode->getMesh(), v3f(-BS, -BS, -BS));
			m_meshnode->setScale(
					def.wield_scale * WIELD_SCALE_FACTOR
					/ (BS * f.visual_scale));
		}
		u32 material_count = m_meshnode->getMaterialCount();
		if (material_count > 6) {
			errorstream << "WieldMeshSceneNode::setItem: Invalid material "
				"count " << material_count << ", truncating to 6" << std::endl;
			material_count = 6;
		}
		for (u32 i = 0; i < material_count; ++i) {
			video::SMaterial &material = m_meshnode->getMaterial(i);
			material.setFlag(video::EMF_BACK_FACE_CULLING, true);
			material.setFlag(video::EMF_BILINEAR_FILTER, m_bilinear_filter);
			material.setFlag(video::EMF_TRILINEAR_FILTER, m_trilinear_filter);
			bool animated = (f.tiles[i].animation_frame_count > 1);
			if (animated) {
				FrameSpec animation_frame = f.tiles[i].frames[0];
				material.setTexture(0, animation_frame.texture);
			} else {
				material.setTexture(0, f.tiles[i].texture);
			}
			material.MaterialType = m_material_type;
#if 0
//// TODO(RealBadAngel): Reactivate when shader is added for wield items
			if (m_enable_shaders) {
				if (f.tiles[i].normal_texture) {
					if (animated) {
						FrameSpec animation_frame = f.tiles[i].frames[0];
						material.setTexture(1, animation_frame.normal_texture);
					} else {
						material.setTexture(1, f.tiles[i].normal_texture);
					}
					material.setTexture(2, tsrc->getTexture("enable_img.png"));
				} else {
					material.setTexture(2, tsrc->getTexture("disable_img.png"));
				}
			}
#endif
		}
		return;
	}
	else if (def.inventory_image != "") {
		setExtruded(def.inventory_image, def.wield_scale, tsrc, 1);
		return;
	}

	// no wield mesh found
	changeToMesh(NULL);
}
Ejemplo n.º 23
0
MapgenFractal::MapgenFractal(int mapgenid, MapgenParams *params, EmergeManager *emerge)
	: Mapgen(mapgenid, params, emerge)
{
	this->m_emerge = emerge;
	this->bmgr     = emerge->biomemgr;

	//// amount of elements to skip for the next index
	//// for noise/height/biome maps (not vmanip)
	this->ystride = csize.X;
	this->zstride = csize.X * (csize.Y + 2);

	this->biomemap  = new u8[csize.X * csize.Z];
	this->heightmap = new s16[csize.X * csize.Z];
	this->heatmap   = NULL;
	this->humidmap  = NULL;

	MapgenFractalParams *sp = (MapgenFractalParams *)params->sparams;
	this->spflags = sp->spflags;

	this->fractal    = sp->fractal;
	this->iterations = sp->iterations;
	this->scale      = sp->scale;
	this->offset     = sp->offset;
	this->slice_w    = sp->slice_w;

	this->julia_x = sp->julia_x;
	this->julia_y = sp->julia_y;
	this->julia_z = sp->julia_z;
	this->julia_w = sp->julia_w;

	this->formula = fractal / 2 + fractal % 2;
	this->julia   = fractal % 2 == 0;

	//// 2D terrain noise
	noise_seabed       = new Noise(&sp->np_seabed, seed, csize.X, csize.Z);
	noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);

	//// 3D terrain noise
	noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 2, csize.Z);
	noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 2, csize.Z);

	//// Biome noise
	noise_heat           = new Noise(&params->np_biome_heat,           seed, csize.X, csize.Z);
	noise_humidity       = new Noise(&params->np_biome_humidity,       seed, csize.X, csize.Z);
	noise_heat_blend     = new Noise(&params->np_biome_heat_blend,     seed, csize.X, csize.Z);
	noise_humidity_blend = new Noise(&params->np_biome_humidity_blend, seed, csize.X, csize.Z);

	//// Resolve nodes to be used
	INodeDefManager *ndef = emerge->ndef;

	c_stone                = ndef->getId("mapgen_stone");
	c_water_source         = ndef->getId("mapgen_water_source");
	c_lava_source          = ndef->getId("mapgen_lava_source");
	c_desert_stone         = ndef->getId("mapgen_desert_stone");
	c_ice                  = ndef->getId("mapgen_ice");
	c_sandstone            = ndef->getId("mapgen_sandstone");

	c_cobble               = ndef->getId("mapgen_cobble");
	c_stair_cobble         = ndef->getId("mapgen_stair_cobble");
	c_mossycobble          = ndef->getId("mapgen_mossycobble");
	c_sandstonebrick       = ndef->getId("mapgen_sandstonebrick");
	c_stair_sandstonebrick = ndef->getId("mapgen_stair_sandstonebrick");

	if (c_ice == CONTENT_IGNORE)
		c_ice = CONTENT_AIR;
	if (c_mossycobble == CONTENT_IGNORE)
		c_mossycobble = c_cobble;
	if (c_stair_cobble == CONTENT_IGNORE)
		c_stair_cobble = c_cobble;
	if (c_sandstonebrick == CONTENT_IGNORE)
		c_sandstonebrick = c_sandstone;
	if (c_stair_sandstonebrick == CONTENT_IGNORE)
		c_stair_sandstonebrick = c_sandstone;
}
Ejemplo n.º 24
0
void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client)
{
	ITextureSource *tsrc = client->getTextureSource();
	IItemDefManager *idef = client->getItemDefManager();
	IShaderSource *shdrsrc = client->getShaderSource();
	INodeDefManager *ndef = client->getNodeDefManager();
	const ItemDefinition &def = item.getDefinition(idef);
	const ContentFeatures &f = ndef->get(def.name);
	content_t id = ndef->getId(def.name);

	if (m_enable_shaders) {
		u32 shader_id = shdrsrc->getShader("wielded_shader", TILE_MATERIAL_BASIC, NDT_NORMAL);
		m_material_type = shdrsrc->getShaderInfo(shader_id).material;
	}
	m_colors.clear();

	// If wield_image is defined, it overrides everything else
	if (def.wield_image != "") {
		setExtruded(def.wield_image, def.wield_scale, tsrc, 1);
		return;
	}
	// Handle nodes
	// See also CItemDefManager::createClientCached()
	else if (def.type == ITEM_NODE) {
		if (f.mesh_ptr[0]) {
			// e.g. mesh nodes and nodeboxes
			changeToMesh(f.mesh_ptr[0]);
			// mesh_ptr[0] is pre-scaled by BS * f->visual_scale
			m_meshnode->setScale(
					def.wield_scale * WIELD_SCALE_FACTOR
					/ (BS * f.visual_scale));
		} else if (f.drawtype == NDT_AIRLIKE) {
			changeToMesh(NULL);
		} else if (f.drawtype == NDT_PLANTLIKE) {
			setExtruded(tsrc->getTextureName(f.tiles[0].texture_id), def.wield_scale, tsrc, f.tiles[0].animation_frame_count);
		} else if (f.drawtype == NDT_NORMAL || f.drawtype == NDT_ALLFACES) {
			setCube(f.tiles, def.wield_scale, tsrc);
		} else {
			MeshMakeData mesh_make_data(client, false);
			MapNode mesh_make_node(id, 255, 0);
			mesh_make_data.fillSingleNode(&mesh_make_node);
			MapBlockMesh mapblock_mesh(&mesh_make_data, v3s16(0, 0, 0));
			changeToMesh(mapblock_mesh.getMesh());
			translateMesh(m_meshnode->getMesh(), v3f(-BS, -BS, -BS));
			m_meshnode->setScale(
					def.wield_scale * WIELD_SCALE_FACTOR
					/ (BS * f.visual_scale));
		}
		u32 material_count = m_meshnode->getMaterialCount();
		if (material_count > 6) {
			errorstream << "WieldMeshSceneNode::setItem: Invalid material "
				"count " << material_count << ", truncating to 6" << std::endl;
			material_count = 6;
		}
		for (u32 i = 0; i < material_count; ++i) {
			const TileSpec *tile = &(f.tiles[i]);
			video::SMaterial &material = m_meshnode->getMaterial(i);
			material.setFlag(video::EMF_BACK_FACE_CULLING, true);
			material.setFlag(video::EMF_BILINEAR_FILTER, m_bilinear_filter);
			material.setFlag(video::EMF_TRILINEAR_FILTER, m_trilinear_filter);
			bool animated = (tile->animation_frame_count > 1);
			if (animated) {
				FrameSpec animation_frame = tile->frames[0];
				material.setTexture(0, animation_frame.texture);
			} else {
				material.setTexture(0, tile->texture);
			}
			m_colors.push_back(tile->color);
			material.MaterialType = m_material_type;
			if (m_enable_shaders) {
				if (tile->normal_texture) {
					if (animated) {
						FrameSpec animation_frame = tile->frames[0];
						material.setTexture(1, animation_frame.normal_texture);
					} else {
						material.setTexture(1, tile->normal_texture);
					}
				}
				material.setTexture(2, tile->flags_texture);
			}
		}
		return;
	}
	else if (def.inventory_image != "") {
		setExtruded(def.inventory_image, def.wield_scale, tsrc, 1);
		return;
	}

	// no wield mesh found
	changeToMesh(NULL);
}
Ejemplo n.º 25
0
    ClientCached* createClientCachedDirect(const std::string &name,
                                           IGameDef *gamedef) const
    {
        infostream<<"Lazily creating item texture and mesh for \""
                  <<name<<"\""<<std::endl;

        // This is not thread-safe
        assert(get_current_thread_id() == m_main_thread);

        // Skip if already in cache
        ClientCached *cc = NULL;
        m_clientcached.get(name, &cc);
        if(cc)
            return cc;

        ITextureSource *tsrc = gamedef->getTextureSource();
        INodeDefManager *nodedef = gamedef->getNodeDefManager();
        IrrlichtDevice *device = tsrc->getDevice();
        video::IVideoDriver *driver = device->getVideoDriver();
        const ItemDefinition *def = &get(name);

        // Create new ClientCached
        cc = new ClientCached();

        bool need_node_mesh = false;

        // Create an inventory texture
        cc->inventory_texture = NULL;
        if(def->inventory_image != "")
        {
            cc->inventory_texture = tsrc->getTextureRaw(def->inventory_image);
        }
        else if(def->type == ITEM_NODE)
        {
            need_node_mesh = true;
        }

        // Create a wield mesh
        assert(cc->wield_mesh == NULL);
        if(def->type == ITEM_NODE && def->wield_image == "")
        {
            need_node_mesh = true;
        }
        else if(def->wield_image != "" || def->inventory_image != "")
        {
            // Extrude the wield image into a mesh

            std::string imagename;
            if(def->wield_image != "")
                imagename = def->wield_image;
            else
                imagename = def->inventory_image;

            cc->wield_mesh = createExtrudedMesh(
                                 tsrc->getTextureRaw(imagename),
                                 driver,
                                 def->wield_scale * v3f(40.0, 40.0, 4.0));
            if(cc->wield_mesh == NULL)
            {
                infostream<<"ItemDefManager: WARNING: "
                          <<"updateTexturesAndMeshes(): "
                          <<"Unable to create extruded mesh for item "
                          <<def->name<<std::endl;
            }
        }

        if(need_node_mesh)
        {
            /*
            	Get node properties
            */
            content_t id = nodedef->getId(def->name);
            const ContentFeatures &f = nodedef->get(id);

            u8 param1 = 0;
            if(f.param_type == CPT_LIGHT)
                param1 = 0xee;

            /*
            	Make a mesh from the node
            */
            MeshMakeData mesh_make_data(gamedef);
            MapNode mesh_make_node(id, param1, 0);
            mesh_make_data.fillSingleNode(&mesh_make_node);
            MapBlockMesh mapblock_mesh(&mesh_make_data);

            scene::IMesh *node_mesh = mapblock_mesh.getMesh();
            assert(node_mesh);
            video::SColor c(255, 255, 255, 255);
            if(g_settings->getS32("enable_shaders") != 0)
                c = MapBlock_LightColor(255, 0xffff, decode_light(f.light_source));
            setMeshColor(node_mesh, c);

            /*
            	Scale and translate the mesh so it's a unit cube
            	centered on the origin
            */
            scaleMesh(node_mesh, v3f(1.0/BS, 1.0/BS, 1.0/BS));
            translateMesh(node_mesh, v3f(-1.0, -1.0, -1.0));

            /*
            	Draw node mesh into a render target texture
            */
            if(cc->inventory_texture == NULL)
            {
                core::dimension2d<u32> dim(64,64);
                std::string rtt_texture_name = "INVENTORY_"
                                               + def->name + "_RTT";
                v3f camera_position(0, 1.0, -1.5);
                camera_position.rotateXZBy(45);
                v3f camera_lookat(0, 0, 0);
                core::CMatrix4<f32> camera_projection_matrix;
                // Set orthogonal projection
                camera_projection_matrix.buildProjectionMatrixOrthoLH(
                    1.65, 1.65, 0, 100);

                video::SColorf ambient_light(0.2,0.2,0.2);
                v3f light_position(10, 100, -50);
                video::SColorf light_color(0.5,0.5,0.5);
                f32 light_radius = 1000;

                cc->inventory_texture = generateTextureFromMesh(
                                            node_mesh, device, dim, rtt_texture_name,
                                            camera_position,
                                            camera_lookat,
                                            camera_projection_matrix,
                                            ambient_light,
                                            light_position,
                                            light_color,
                                            light_radius);

                // render-to-target didn't work
                if(cc->inventory_texture == NULL)
                {
                    cc->inventory_texture =
                        tsrc->getTextureRaw(f.tiledef[0].name);
                }
            }
            else
            {
                if (m_driver == 0)
                    m_driver = driver;

                m_extruded_textures.push_back(cc->inventory_texture);
            }

            /*
            	Use the node mesh as the wield mesh
            */

            // Scale to proper wield mesh proportions
            scaleMesh(node_mesh, v3f(30.0, 30.0, 30.0)
                      * def->wield_scale);

            cc->wield_mesh = node_mesh;
            cc->wield_mesh->grab();

            //no way reference count can be smaller than 2 in this place!
            assert(cc->wield_mesh->getReferenceCount() >= 2);
        }

        // Put in cache
        m_clientcached.set(name, cc);

        return cc;
    }
Ejemplo n.º 26
0
scene::IMesh *getItemMesh(Client *client, const ItemStack &item)
{
	ITextureSource *tsrc = client->getTextureSource();
	IItemDefManager *idef = client->getItemDefManager();
	INodeDefManager *ndef = client->getNodeDefManager();
	const ItemDefinition &def = item.getDefinition(idef);
	const ContentFeatures &f = ndef->get(def.name);
	content_t id = ndef->getId(def.name);

	if (!g_extrusion_mesh_cache) {
		g_extrusion_mesh_cache = new ExtrusionMeshCache();
	} else {
		g_extrusion_mesh_cache->grab();
	}

	scene::IMesh *mesh;

	// If inventory_image is defined, it overrides everything else
	if (def.inventory_image != "") {
		mesh = getExtrudedMesh(tsrc, def.inventory_image);
		return mesh;
	} else if (def.type == ITEM_NODE) {
		if (f.mesh_ptr[0]) {
			mesh = cloneMesh(f.mesh_ptr[0]);
			scaleMesh(mesh, v3f(0.12, 0.12, 0.12));
			setMeshColor(mesh, video::SColor (255, 255, 255, 255));
		} else if (f.drawtype == NDT_PLANTLIKE) {
			mesh = getExtrudedMesh(tsrc,
				tsrc->getTextureName(f.tiles[0].texture_id));
		} else if (f.drawtype == NDT_NORMAL || f.drawtype == NDT_ALLFACES
			|| f.drawtype == NDT_LIQUID || f.drawtype == NDT_FLOWINGLIQUID) {
			mesh = cloneMesh(g_extrusion_mesh_cache->createCube());
			scaleMesh(mesh, v3f(1.2, 1.2, 1.2));
		} else {
			MeshMakeData mesh_make_data(client, false);
			MapNode mesh_make_node(id, 255, 0);
			mesh_make_data.fillSingleNode(&mesh_make_node);
			MapBlockMesh mapblock_mesh(&mesh_make_data, v3s16(0, 0, 0));
			mesh = cloneMesh(mapblock_mesh.getMesh());
			translateMesh(mesh, v3f(-BS, -BS, -BS));
			scaleMesh(mesh, v3f(0.12, 0.12, 0.12));

			u32 mc = mesh->getMeshBufferCount();
			for (u32 i = 0; i < mc; ++i) {
				video::SMaterial &material1 =
					mesh->getMeshBuffer(i)->getMaterial();
				video::SMaterial &material2 =
					mapblock_mesh.getMesh()->getMeshBuffer(i)->getMaterial();
				material1.setTexture(0, material2.getTexture(0));
				material1.setTexture(1, material2.getTexture(1));
				material1.setTexture(2, material2.getTexture(2));
				material1.setTexture(3, material2.getTexture(3));
				material1.MaterialType = material2.MaterialType;
			}
		}

		u32 mc = mesh->getMeshBufferCount();
		for (u32 i = 0; i < mc; ++i) {
			const TileSpec *tile = &(f.tiles[i]);
			scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
			colorizeMeshBuffer(buf, &tile->color);
			video::SMaterial &material = buf->getMaterial();
			material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
			material.setFlag(video::EMF_BILINEAR_FILTER, false);
			material.setFlag(video::EMF_TRILINEAR_FILTER, false);
			material.setFlag(video::EMF_BACK_FACE_CULLING, true);
			material.setFlag(video::EMF_LIGHTING, false);
			if (tile->animation_frame_count > 1) {
				FrameSpec animation_frame = tile->frames[0];
				material.setTexture(0, animation_frame.texture);
			} else {
				material.setTexture(0, tile->texture);
			}
		}

		rotateMeshXZby(mesh, -45);
		rotateMeshYZby(mesh, -30);
		return mesh;
	}
	return NULL;
}
Ejemplo n.º 27
0
MapgenV7::MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge)
	: Mapgen(mapgenid, params, emerge)
{
	this->m_emerge = emerge;
	this->bmgr     = emerge->biomemgr;

	//// amount of elements to skip for the next index
	//// for noise/height/biome maps (not vmanip)
	this->ystride = csize.X;
	this->zstride = csize.X * (csize.Y + 2);

	this->biomemap        = new u8[csize.X * csize.Z];
	this->heightmap       = new s16[csize.X * csize.Z];
	this->heatmap         = NULL;
	this->humidmap        = NULL;
	this->ridge_heightmap = new s16[csize.X * csize.Z];

	MapgenV7Params *sp = (MapgenV7Params *)params->sparams;
	this->spflags = sp->spflags;

	//// Terrain noise
	noise_terrain_base    = new Noise(&sp->np_terrain_base,    seed, csize.X, csize.Z);
	noise_terrain_alt     = new Noise(&sp->np_terrain_alt,     seed, csize.X, csize.Z);
	noise_terrain_persist = new Noise(&sp->np_terrain_persist, seed, csize.X, csize.Z);
	noise_height_select   = new Noise(&sp->np_height_select,   seed, csize.X, csize.Z);
	noise_filler_depth    = new Noise(&sp->np_filler_depth,    seed, csize.X, csize.Z);
	noise_mount_height    = new Noise(&sp->np_mount_height,    seed, csize.X, csize.Z);
	noise_ridge_uwater    = new Noise(&sp->np_ridge_uwater,    seed, csize.X, csize.Z);

	//// 3d terrain noise
	noise_mountain = new Noise(&sp->np_mountain, seed, csize.X, csize.Y + 2, csize.Z);
	noise_ridge    = new Noise(&sp->np_ridge,    seed, csize.X, csize.Y + 2, csize.Z);
	noise_cave1    = new Noise(&sp->np_cave1,    seed, csize.X, csize.Y + 2, csize.Z);
	noise_cave2    = new Noise(&sp->np_cave2,    seed, csize.X, csize.Y + 2, csize.Z);

	//// Biome noise
	noise_heat           = new Noise(&params->np_biome_heat,           seed, csize.X, csize.Z);
	noise_humidity       = new Noise(&params->np_biome_humidity,       seed, csize.X, csize.Z);
	noise_heat_blend     = new Noise(&params->np_biome_heat_blend,     seed, csize.X, csize.Z);
	noise_humidity_blend = new Noise(&params->np_biome_humidity_blend, seed, csize.X, csize.Z);

	//// Resolve nodes to be used
	INodeDefManager *ndef = emerge->ndef;

	c_stone                = ndef->getId("mapgen_stone");
	c_water_source         = ndef->getId("mapgen_water_source");
	c_lava_source          = ndef->getId("mapgen_lava_source");
	c_desert_stone         = ndef->getId("mapgen_desert_stone");
	c_ice                  = ndef->getId("mapgen_ice");
	c_sandstone            = ndef->getId("mapgen_sandstone");

	c_cobble               = ndef->getId("mapgen_cobble");
	c_stair_cobble         = ndef->getId("mapgen_stair_cobble");
	c_mossycobble          = ndef->getId("mapgen_mossycobble");
	c_sandstonebrick       = ndef->getId("mapgen_sandstonebrick");
	c_stair_sandstonebrick = ndef->getId("mapgen_stair_sandstonebrick");

	if (c_ice == CONTENT_IGNORE)
		c_ice = CONTENT_AIR;
	if (c_mossycobble == CONTENT_IGNORE)
		c_mossycobble = c_cobble;
	if (c_stair_cobble == CONTENT_IGNORE)
		c_stair_cobble = c_cobble;
	if (c_sandstonebrick == CONTENT_IGNORE)
		c_sandstonebrick = c_sandstone;
	if (c_stair_sandstonebrick == CONTENT_IGNORE)
		c_stair_sandstonebrick = c_sandstone;
}
Ejemplo n.º 28
0
MapgenFlat::MapgenFlat(int mapgenid, MapgenParams *params, EmergeManager *emerge)
	: Mapgen(mapgenid, params, emerge)
{
	this->m_emerge = emerge;
	this->bmgr     = emerge->biomemgr;

	//// amount of elements to skip for the next index
	//// for noise/height/biome maps (not vmanip)
	this->ystride = csize.X;
	this->zstride = csize.X * (csize.Y + 2);

	this->biomemap        = new u8[csize.X * csize.Z];
	this->heightmap       = new s16[csize.X * csize.Z];
	this->heatmap         = NULL;
	this->humidmap        = NULL;

	MapgenFlatParams *sp = (MapgenFlatParams *)params->sparams;
	this->spflags = sp->spflags;

	this->ground_level = sp->ground_level;
	this->large_cave_depth = sp->large_cave_depth;
	this->lake_threshold = sp->lake_threshold;
	this->lake_steepness = sp->lake_steepness;
	this->hill_threshold = sp->hill_threshold;
	this->hill_steepness = sp->hill_steepness;

	//// 2D noise
	noise_terrain      = new Noise(&sp->np_terrain,      seed, csize.X, csize.Z);
	noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);

	//// 3D noise
	noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 2, csize.Z);
	noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 2, csize.Z);

	//// Biome noise
	noise_heat           = new Noise(&params->np_biome_heat,           seed, csize.X, csize.Z);
	noise_humidity       = new Noise(&params->np_biome_humidity,       seed, csize.X, csize.Z);
	noise_heat_blend     = new Noise(&params->np_biome_heat_blend,     seed, csize.X, csize.Z);
	noise_humidity_blend = new Noise(&params->np_biome_humidity_blend, seed, csize.X, csize.Z);

	//// Resolve nodes to be used
	INodeDefManager *ndef = emerge->ndef;

	c_stone                = ndef->getId("mapgen_stone");
	c_water_source         = ndef->getId("mapgen_water_source");
	c_lava_source          = ndef->getId("mapgen_lava_source");
	c_desert_stone         = ndef->getId("mapgen_desert_stone");
	c_ice                  = ndef->getId("mapgen_ice");
	c_sandstone            = ndef->getId("mapgen_sandstone");

	c_cobble               = ndef->getId("mapgen_cobble");
	c_stair_cobble         = ndef->getId("mapgen_stair_cobble");
	c_mossycobble          = ndef->getId("mapgen_mossycobble");
	c_sandstonebrick       = ndef->getId("mapgen_sandstonebrick");
	c_stair_sandstonebrick = ndef->getId("mapgen_stair_sandstonebrick");

	if (c_ice == CONTENT_IGNORE)
		c_ice = CONTENT_AIR;
	if (c_mossycobble == CONTENT_IGNORE)
		c_mossycobble = c_cobble;
	if (c_stair_cobble == CONTENT_IGNORE)
		c_stair_cobble = c_cobble;
	if (c_sandstonebrick == CONTENT_IGNORE)
		c_sandstonebrick = c_sandstone;
	if (c_stair_sandstonebrick == CONTENT_IGNORE)
		c_stair_sandstonebrick = c_sandstone;
}
Ejemplo n.º 29
0
void mapblock_mesh_generate_special(MeshMakeData *data,
		MeshCollector &collector)
{
	INodeDefManager *nodedef = data->m_gamedef->ndef();

	// 0ms
	//TimeTaker timer("mapblock_mesh_generate_special()");

	/*
		Some settings
	*/
	bool new_style_water = g_settings->getBool("new_style_water");
	
	float node_liquid_level = 1.0;
	if(new_style_water)
		node_liquid_level = 0.85;
	
	v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE;

	for(s16 z=0; z<MAP_BLOCKSIZE; z++)
	for(s16 y=0; y<MAP_BLOCKSIZE; y++)
	for(s16 x=0; x<MAP_BLOCKSIZE; x++)
	{
		v3s16 p(x,y,z);

		MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes+p);
		const ContentFeatures &f = nodedef->get(n);

		// Only solidness=0 stuff is drawn here
		if(f.solidness != 0)
			continue;
		
		switch(f.drawtype){
		default:
			infostream<<"Got "<<f.drawtype<<std::endl;
			assert(0);
			break;
		case NDT_AIRLIKE:
			break;
		case NDT_LIQUID:
		{
			/*
				Add water sources to mesh if using new style
			*/
			TileSpec tile_liquid = f.special_tiles[0];
			AtlasPointer &pa_liquid = tile_liquid.texture;

			bool top_is_air = false;
			MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
			if(n.getContent() == CONTENT_AIR)
				top_is_air = true;
			
			if(top_is_air == false)
				continue;

			u16 l = getInteriorLight(n, 0, data);
			video::SColor c = MapBlock_LightColor(f.alpha, l);
			
			video::S3DVertex vertices[4] =
			{
				video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
						pa_liquid.x0(), pa_liquid.y1()),
				video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
						pa_liquid.x1(), pa_liquid.y1()),
				video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
						pa_liquid.x1(), pa_liquid.y0()),
				video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
						pa_liquid.x0(), pa_liquid.y0()),
			};

			v3f offset(p.X, p.Y + (-0.5+node_liquid_level)*BS, p.Z);
			for(s32 i=0; i<4; i++)
			{
				vertices[i].Pos += offset;
			}

			u16 indices[] = {0,1,2,2,3,0};
			// Add to mesh collector
			collector.append(tile_liquid, vertices, 4, indices, 6);
		break;}
		case NDT_FLOWINGLIQUID:
		{
			/*
				Add flowing liquid to mesh
			*/
			TileSpec tile_liquid = f.special_tiles[0];
			TileSpec tile_liquid_bfculled = f.special_tiles[1];
			AtlasPointer &pa_liquid = tile_liquid.texture;

			bool top_is_same_liquid = false;
			MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
			content_t c_flowing = nodedef->getId(f.liquid_alternative_flowing);
			content_t c_source = nodedef->getId(f.liquid_alternative_source);
			if(ntop.getContent() == c_flowing || ntop.getContent() == c_source)
				top_is_same_liquid = true;
			
			u16 l = 0;
			// If this liquid emits light and doesn't contain light, draw
			// it at what it emits, for an increased effect
			u8 light_source = nodedef->get(n).light_source;
			if(light_source != 0){
				//l = decode_light(undiminish_light(light_source));
				l = decode_light(light_source);
				l = l | (l<<8);
			}
			// Use the light of the node on top if possible
			else if(nodedef->get(ntop).param_type == CPT_LIGHT)
				l = getInteriorLight(ntop, 0, data);
			// Otherwise use the light of this node (the liquid)
			else
				l = getInteriorLight(n, 0, data);
			video::SColor c = MapBlock_LightColor(f.alpha, l);
			
			// Neighbor liquid levels (key = relative position)
			// Includes current node
			core::map<v3s16, f32> neighbor_levels;
			core::map<v3s16, content_t> neighbor_contents;
			core::map<v3s16, u8> neighbor_flags;
			const u8 neighborflag_top_is_same_liquid = 0x01;
			v3s16 neighbor_dirs[9] = {
				v3s16(0,0,0),
				v3s16(0,0,1),
				v3s16(0,0,-1),
				v3s16(1,0,0),
				v3s16(-1,0,0),
				v3s16(1,0,1),
				v3s16(-1,0,-1),
				v3s16(1,0,-1),
				v3s16(-1,0,1),
			};
			for(u32 i=0; i<9; i++)
			{
				content_t content = CONTENT_AIR;
				float level = -0.5 * BS;
				u8 flags = 0;
				// Check neighbor
				v3s16 p2 = p + neighbor_dirs[i];
				MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
				if(n2.getContent() != CONTENT_IGNORE)
				{
					content = n2.getContent();

					if(n2.getContent() == c_source)
						level = (-0.5+node_liquid_level) * BS;
					else if(n2.getContent() == c_flowing)
						level = (-0.5 + ((float)(n2.param2&LIQUID_LEVEL_MASK)
								+ 0.5) / 8.0 * node_liquid_level) * BS;

					// Check node above neighbor.
					// NOTE: This doesn't get executed if neighbor
					//       doesn't exist
					p2.Y += 1;
					n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
					if(n2.getContent() == c_source ||
							n2.getContent() == c_flowing)
						flags |= neighborflag_top_is_same_liquid;
				}
				
				neighbor_levels.insert(neighbor_dirs[i], level);
				neighbor_contents.insert(neighbor_dirs[i], content);
				neighbor_flags.insert(neighbor_dirs[i], flags);
			}

			// Corner heights (average between four liquids)
			f32 corner_levels[4];
			
			v3s16 halfdirs[4] = {
				v3s16(0,0,0),
				v3s16(1,0,0),
				v3s16(1,0,1),
				v3s16(0,0,1),
			};
			for(u32 i=0; i<4; i++)
			{
				v3s16 cornerdir = halfdirs[i];
				float cornerlevel = 0;
				u32 valid_count = 0;
				u32 air_count = 0;
				for(u32 j=0; j<4; j++)
				{
					v3s16 neighbordir = cornerdir - halfdirs[j];
					content_t content = neighbor_contents[neighbordir];
					// If top is liquid, draw starting from top of node
					if(neighbor_flags[neighbordir] &
							neighborflag_top_is_same_liquid)
					{
						cornerlevel = 0.5*BS;
						valid_count = 1;
						break;
					}
					// Source is always the same height
					else if(content == c_source)
					{
						cornerlevel = (-0.5+node_liquid_level)*BS;
						valid_count = 1;
						break;
					}
					// Flowing liquid has level information
					else if(content == c_flowing)
					{
						cornerlevel += neighbor_levels[neighbordir];
						valid_count++;
					}
					else if(content == CONTENT_AIR)
					{
						air_count++;
					}
				}
				if(air_count >= 2)
					cornerlevel = -0.5*BS;
				else if(valid_count > 0)
					cornerlevel /= valid_count;
				corner_levels[i] = cornerlevel;
			}

			/*
				Generate sides
			*/

			v3s16 side_dirs[4] = {
				v3s16(1,0,0),
				v3s16(-1,0,0),
				v3s16(0,0,1),
				v3s16(0,0,-1),
			};
			s16 side_corners[4][2] = {
				{1, 2},
				{3, 0},
				{2, 3},
				{0, 1},
			};
			for(u32 i=0; i<4; i++)
			{
				v3s16 dir = side_dirs[i];

				/*
					If our topside is liquid and neighbor's topside
					is liquid, don't draw side face
				*/
				if(top_is_same_liquid &&
						neighbor_flags[dir] & neighborflag_top_is_same_liquid)
					continue;

				content_t neighbor_content = neighbor_contents[dir];
				const ContentFeatures &n_feat = nodedef->get(neighbor_content);
				
				// Don't draw face if neighbor is blocking the view
				if(n_feat.solidness == 2)
					continue;
				
				bool neighbor_is_same_liquid = (neighbor_content == c_source
						|| neighbor_content == c_flowing);
				
				// Don't draw any faces if neighbor same is liquid and top is
				// same liquid
				if(neighbor_is_same_liquid == true
						&& top_is_same_liquid == false)
					continue;

				// Use backface culled material if neighbor doesn't have a
				// solidness of 0
				const TileSpec *current_tile = &tile_liquid;
				if(n_feat.solidness != 0 || n_feat.visual_solidness != 0)
					current_tile = &tile_liquid_bfculled;
				
				video::S3DVertex vertices[4] =
				{
					video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
							pa_liquid.x0(), pa_liquid.y1()),
					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
							pa_liquid.x1(), pa_liquid.y1()),
					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
							pa_liquid.x1(), pa_liquid.y0()),
					video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
							pa_liquid.x0(), pa_liquid.y0()),
				};
				
				/*
					If our topside is liquid, set upper border of face
					at upper border of node
				*/
				if(top_is_same_liquid)
				{
					vertices[2].Pos.Y = 0.5*BS;
					vertices[3].Pos.Y = 0.5*BS;
				}
				/*
					Otherwise upper position of face is corner levels
				*/
				else
				{
					vertices[2].Pos.Y = corner_levels[side_corners[i][0]];
					vertices[3].Pos.Y = corner_levels[side_corners[i][1]];
				}
				
				/*
					If neighbor is liquid, lower border of face is corner
					liquid levels
				*/
				if(neighbor_is_same_liquid)
				{
					vertices[0].Pos.Y = corner_levels[side_corners[i][1]];
					vertices[1].Pos.Y = corner_levels[side_corners[i][0]];
				}
				/*
					If neighbor is not liquid, lower border of face is
					lower border of node
				*/
				else
				{
					vertices[0].Pos.Y = -0.5*BS;
					vertices[1].Pos.Y = -0.5*BS;
				}
				
				for(s32 j=0; j<4; j++)
				{
					if(dir == v3s16(0,0,1))
						vertices[j].Pos.rotateXZBy(0);
					if(dir == v3s16(0,0,-1))
						vertices[j].Pos.rotateXZBy(180);
					if(dir == v3s16(-1,0,0))
						vertices[j].Pos.rotateXZBy(90);
					if(dir == v3s16(1,0,-0))
						vertices[j].Pos.rotateXZBy(-90);
						
					// Do this to not cause glitches when two liquids are
					// side-by-side
					/*if(neighbor_is_same_liquid == false){
						vertices[j].Pos.X *= 0.98;
						vertices[j].Pos.Z *= 0.98;
					}*/

					vertices[j].Pos += intToFloat(p, BS);
				}

				u16 indices[] = {0,1,2,2,3,0};
				// Add to mesh collector
				collector.append(*current_tile, vertices, 4, indices, 6);
			}
			
			/*
				Generate top side, if appropriate
			*/
			
			if(top_is_same_liquid == false)
			{
				video::S3DVertex vertices[4] =
				{
					video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
							pa_liquid.x0(), pa_liquid.y1()),
					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
							pa_liquid.x1(), pa_liquid.y1()),
					video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
							pa_liquid.x1(), pa_liquid.y0()),
					video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
							pa_liquid.x0(), pa_liquid.y0()),
				};
				
				// To get backface culling right, the vertices need to go
				// clockwise around the front of the face. And we happened to
				// calculate corner levels in exact reverse order.
				s32 corner_resolve[4] = {3,2,1,0};

				for(s32 i=0; i<4; i++)
				{
					//vertices[i].Pos.Y += liquid_level;
					//vertices[i].Pos.Y += neighbor_levels[v3s16(0,0,0)];
					s32 j = corner_resolve[i];
					vertices[i].Pos.Y += corner_levels[j];
					vertices[i].Pos += intToFloat(p, BS);
				}
				
				// Default downwards-flowing texture animation goes from 
				// -Z towards +Z, thus the direction is +Z.
				// Rotate texture to make animation go in flow direction
				// Positive if liquid moves towards +Z
				int dz = (corner_levels[side_corners[2][0]] +
						corner_levels[side_corners[2][1]] <
						corner_levels[side_corners[3][0]] +
						corner_levels[side_corners[3][1]]);
				// Positive if liquid moves towards +X
				int dx = (corner_levels[side_corners[0][0]] +
						corner_levels[side_corners[0][1]] <
						corner_levels[side_corners[1][0]] +
						corner_levels[side_corners[1][1]]);
				// -X
				if(-dx >= abs(dz))
				{
					v2f t = vertices[0].TCoords;
					vertices[0].TCoords = vertices[1].TCoords;
					vertices[1].TCoords = vertices[2].TCoords;
					vertices[2].TCoords = vertices[3].TCoords;
					vertices[3].TCoords = t;
				}
				// +X
				if(dx >= abs(dz))
				{
					v2f t = vertices[0].TCoords;
					vertices[0].TCoords = vertices[3].TCoords;
					vertices[3].TCoords = vertices[2].TCoords;
					vertices[2].TCoords = vertices[1].TCoords;
					vertices[1].TCoords = t;
				}
				// -Z
				if(-dz >= abs(dx))
				{
					v2f t = vertices[0].TCoords;
					vertices[0].TCoords = vertices[3].TCoords;
					vertices[3].TCoords = vertices[2].TCoords;
					vertices[2].TCoords = vertices[1].TCoords;
					vertices[1].TCoords = t;
					t = vertices[0].TCoords;
					vertices[0].TCoords = vertices[3].TCoords;
					vertices[3].TCoords = vertices[2].TCoords;
					vertices[2].TCoords = vertices[1].TCoords;
					vertices[1].TCoords = t;
				}

				u16 indices[] = {0,1,2,2,3,0};
				// Add to mesh collector
				collector.append(tile_liquid, vertices, 4, indices, 6);
			}
		break;}
		case NDT_GLASSLIKE:
		{
			TileSpec tile = getNodeTile(n, p, v3s16(0,0,0), data);
			AtlasPointer ap = tile.texture;

			u16 l = getInteriorLight(n, 1, data);
			video::SColor c = MapBlock_LightColor(255, l);

			for(u32 j=0; j<6; j++)
			{
				// Check this neighbor
				v3s16 n2p = blockpos_nodes + p + g_6dirs[j];
				MapNode n2 = data->m_vmanip.getNodeNoEx(n2p);
				// Don't make face if neighbor is of same type
				if(n2.getContent() == n.getContent())
					continue;

				// The face at Z+
				video::S3DVertex vertices[4] =
				{
					video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
						ap.x0(), ap.y1()),
					video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
						ap.x1(), ap.y1()),
					video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
						ap.x1(), ap.y0()),
					video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
						ap.x0(), ap.y0()),
				};
				
				// Rotations in the g_6dirs format
				if(j == 0) // Z+
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(0);
				else if(j == 1) // Y+
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateYZBy(-90);
				else if(j == 2) // X+
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(-90);
				else if(j == 3) // Z-
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(180);
				else if(j == 4) // Y-
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateYZBy(90);
				else if(j == 5) // X-
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(90);

				for(u16 i=0; i<4; i++){
					vertices[i].Pos += intToFloat(p, BS);
				}

				u16 indices[] = {0,1,2,2,3,0};
				// Add to mesh collector
				collector.append(tile, vertices, 4, indices, 6);
			}
		break;}
		case NDT_ALLFACES:
		{
			TileSpec tile_leaves = getNodeTile(n, p,
					v3s16(0,0,0), data);
			AtlasPointer pa_leaves = tile_leaves.texture;

			u16 l = getInteriorLight(n, 1, data);
			video::SColor c = MapBlock_LightColor(255, l);

			v3f pos = intToFloat(p, BS);
			aabb3f box(-BS/2,-BS/2,-BS/2,BS/2,BS/2,BS/2);
			box.MinEdge += pos;
			box.MaxEdge += pos;
			makeCuboid(&collector, box, &tile_leaves, 1, c, NULL);
		break;}
		case NDT_ALLFACES_OPTIONAL:
			// This is always pre-converted to something else
			assert(0);
			break;
		case NDT_TORCHLIKE:
		{
			v3s16 dir = n.getWallMountedDir(nodedef);
			
			u8 tileindex = 0;
			if(dir == v3s16(0,-1,0)){
				tileindex = 0; // floor
			} else if(dir == v3s16(0,1,0)){
				tileindex = 1; // ceiling
			// For backwards compatibility
			} else if(dir == v3s16(0,0,0)){
				tileindex = 0; // floor
			} else {
				tileindex = 2; // side
			}

			TileSpec tile = getNodeTileN(n, p, tileindex, data);
			tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
			tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;

			AtlasPointer ap = tile.texture;

			video::SColor c(255,255,255,255);

			// Wall at X+ of node
			video::S3DVertex vertices[4] =
			{
				video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c,
						ap.x0(), ap.y1()),
				video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c,
						ap.x1(), ap.y1()),
				video::S3DVertex(BS/2,BS/2,0, 0,0,0, c,
						ap.x1(), ap.y0()),
				video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c,
						ap.x0(), ap.y0()),
			};

			for(s32 i=0; i<4; i++)
			{
				if(dir == v3s16(1,0,0))
					vertices[i].Pos.rotateXZBy(0);
				if(dir == v3s16(-1,0,0))
					vertices[i].Pos.rotateXZBy(180);
				if(dir == v3s16(0,0,1))
					vertices[i].Pos.rotateXZBy(90);
				if(dir == v3s16(0,0,-1))
					vertices[i].Pos.rotateXZBy(-90);
				if(dir == v3s16(0,-1,0))
					vertices[i].Pos.rotateXZBy(45);
				if(dir == v3s16(0,1,0))
					vertices[i].Pos.rotateXZBy(-45);

				vertices[i].Pos += intToFloat(p, BS);
			}

			u16 indices[] = {0,1,2,2,3,0};
			// Add to mesh collector
			collector.append(tile, vertices, 4, indices, 6);
		break;}
		case NDT_SIGNLIKE:
		{
			TileSpec tile = getNodeTileN(n, p, 0, data);
			tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
			tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
			AtlasPointer ap = tile.texture;

			u16 l = getInteriorLight(n, 0, data);
			video::SColor c = MapBlock_LightColor(255, l);
				
			float d = (float)BS/16;
			// Wall at X+ of node
			video::S3DVertex vertices[4] =
			{
				video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c,
						ap.x0(), ap.y0()),
				video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c,
						ap.x1(), ap.y0()),
				video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c,
						ap.x1(), ap.y1()),
				video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c,
						ap.x0(), ap.y1()),
			};

			v3s16 dir = n.getWallMountedDir(nodedef);

			for(s32 i=0; i<4; i++)
			{
				if(dir == v3s16(1,0,0))
					vertices[i].Pos.rotateXZBy(0);
				if(dir == v3s16(-1,0,0))
					vertices[i].Pos.rotateXZBy(180);
				if(dir == v3s16(0,0,1))
					vertices[i].Pos.rotateXZBy(90);
				if(dir == v3s16(0,0,-1))
					vertices[i].Pos.rotateXZBy(-90);
				if(dir == v3s16(0,-1,0))
					vertices[i].Pos.rotateXYBy(-90);
				if(dir == v3s16(0,1,0))
					vertices[i].Pos.rotateXYBy(90);

				vertices[i].Pos += intToFloat(p, BS);
			}

			u16 indices[] = {0,1,2,2,3,0};
			// Add to mesh collector
			collector.append(tile, vertices, 4, indices, 6);
		break;}
		case NDT_PLANTLIKE:
		{
			TileSpec tile = getNodeTileN(n, p, 0, data);
			tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
			AtlasPointer ap = tile.texture;
			
			u16 l = getInteriorLight(n, 1, data);
			video::SColor c = MapBlock_LightColor(255, l);

			for(u32 j=0; j<4; j++)
			{
				video::S3DVertex vertices[4] =
				{
					video::S3DVertex(-BS/2*f.visual_scale,-BS/2,0, 0,0,0, c,
						ap.x0(), ap.y1()),
					video::S3DVertex( BS/2*f.visual_scale,-BS/2,0, 0,0,0, c,
						ap.x1(), ap.y1()),
					video::S3DVertex( BS/2*f.visual_scale,
						-BS/2 + f.visual_scale*BS,0, 0,0,0, c,
						ap.x1(), ap.y0()),
					video::S3DVertex(-BS/2*f.visual_scale,
						-BS/2 + f.visual_scale*BS,0, 0,0,0, c,
						ap.x0(), ap.y0()),
				};

				if(j == 0)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(45);
				}
				else if(j == 1)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(-45);
				}
				else if(j == 2)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(135);
				}
				else if(j == 3)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(-135);
				}

				for(u16 i=0; i<4; i++)
				{
					vertices[i].Pos *= f.visual_scale;
					vertices[i].Pos += intToFloat(p, BS);
				}

				u16 indices[] = {0,1,2,2,3,0};
				// Add to mesh collector
				collector.append(tile, vertices, 4, indices, 6);
			}
		break;}
		case NDT_FENCELIKE:
		{
			TileSpec tile = getNodeTile(n, p, v3s16(0,0,0), data);
			TileSpec tile_nocrack = tile;
			tile_nocrack.material_flags &= ~MATERIAL_FLAG_CRACK;
			
			// A hack to put wood the right way around in the posts
			ITextureSource *tsrc = data->m_gamedef->tsrc();
			TileSpec tile_rot = tile;
			tile_rot.texture = tsrc->getTexture(tsrc->getTextureName(
					tile.texture.id) + "^[transformR90");
					
			u16 l = getInteriorLight(n, 1, data);
			video::SColor c = MapBlock_LightColor(255, l);

			const f32 post_rad=(f32)BS/8;
			const f32 bar_rad=(f32)BS/16;
			const f32 bar_len=(f32)(BS/2)-post_rad;

			v3f pos = intToFloat(p, BS);

			// The post - always present
			aabb3f post(-post_rad,-BS/2,-post_rad,post_rad,BS/2,post_rad);
			post.MinEdge += pos;
			post.MaxEdge += pos;
			f32 postuv[24]={
					6/16.,6/16.,10/16.,10/16.,
					6/16.,6/16.,10/16.,10/16.,
					0/16.,0,4/16.,1,
					4/16.,0,8/16.,1,
					8/16.,0,12/16.,1,
					12/16.,0,16/16.,1};
			makeCuboid(&collector, post, &tile_rot, 1, c, postuv);

			// Now a section of fence, +X, if there's a post there
			v3s16 p2 = p;
			p2.X++;
			MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
			const ContentFeatures *f2 = &nodedef->get(n2);
			if(f2->drawtype == NDT_FENCELIKE)
			{
				aabb3f bar(-bar_len+BS/2,-bar_rad+BS/4,-bar_rad,
						bar_len+BS/2,bar_rad+BS/4,bar_rad);
				bar.MinEdge += pos;
				bar.MaxEdge += pos;
				f32 xrailuv[24]={
					0/16.,2/16.,16/16.,4/16.,
					0/16.,4/16.,16/16.,6/16.,
					6/16.,6/16.,8/16.,8/16.,
					10/16.,10/16.,12/16.,12/16.,
					0/16.,8/16.,16/16.,10/16.,
					0/16.,14/16.,16/16.,16/16.};
				makeCuboid(&collector, bar, &tile_nocrack, 1,
						c, xrailuv);
				bar.MinEdge.Y -= BS/2;
				bar.MaxEdge.Y -= BS/2;
				makeCuboid(&collector, bar, &tile_nocrack, 1,
						c, xrailuv);
			}

			// Now a section of fence, +Z, if there's a post there
			p2 = p;
			p2.Z++;
			n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
			f2 = &nodedef->get(n2);
			if(f2->drawtype == NDT_FENCELIKE)
			{
				aabb3f bar(-bar_rad,-bar_rad+BS/4,-bar_len+BS/2,
						bar_rad,bar_rad+BS/4,bar_len+BS/2);
				bar.MinEdge += pos;
				bar.MaxEdge += pos;
				f32 zrailuv[24]={
					3/16.,1/16.,5/16.,5/16., // cannot rotate; stretch
					4/16.,1/16.,6/16.,5/16., // for wood texture instead
					0/16.,9/16.,16/16.,11/16.,
					0/16.,6/16.,16/16.,8/16.,
					6/16.,6/16.,8/16.,8/16.,
					10/16.,10/16.,12/16.,12/16.};
				makeCuboid(&collector, bar, &tile_nocrack, 1,
						c, zrailuv);
				bar.MinEdge.Y -= BS/2;
				bar.MaxEdge.Y -= BS/2;
				makeCuboid(&collector, bar, &tile_nocrack, 1,
						c, zrailuv);
			}
		break;}
		case NDT_RAILLIKE:
		{
			bool is_rail_x [] = { false, false };  /* x-1, x+1 */
			bool is_rail_z [] = { false, false };  /* z-1, z+1 */

			bool is_rail_z_minus_y [] = { false, false };  /* z-1, z+1; y-1 */
			bool is_rail_x_minus_y [] = { false, false };  /* x-1, z+1; y-1 */
			bool is_rail_z_plus_y [] = { false, false };  /* z-1, z+1; y+1 */
			bool is_rail_x_plus_y [] = { false, false };  /* x-1, x+1; y+1 */

			MapNode n_minus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x-1,y,z));
			MapNode n_plus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x+1,y,z));
			MapNode n_minus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z-1));
			MapNode n_plus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z+1));
			MapNode n_plus_x_plus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x+1, y+1, z));
			MapNode n_plus_x_minus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x+1, y-1, z));
			MapNode n_minus_x_plus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x-1, y+1, z));
			MapNode n_minus_x_minus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x-1, y-1, z));
			MapNode n_plus_z_plus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x, y+1, z+1));
			MapNode n_minus_z_plus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x, y+1, z-1));
			MapNode n_plus_z_minus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x, y-1, z+1));
			MapNode n_minus_z_minus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x, y-1, z-1));
			
			content_t thiscontent = n.getContent();
			if(n_minus_x.getContent() == thiscontent)
				is_rail_x[0] = true;
			if (n_minus_x_minus_y.getContent() == thiscontent)
				is_rail_x_minus_y[0] = true;
			if(n_minus_x_plus_y.getContent() == thiscontent)
				is_rail_x_plus_y[0] = true;

			if(n_plus_x.getContent() == thiscontent)
				is_rail_x[1] = true;
			if (n_plus_x_minus_y.getContent() == thiscontent)
				is_rail_x_minus_y[1] = true;
			if(n_plus_x_plus_y.getContent() == thiscontent)
				is_rail_x_plus_y[1] = true;

			if(n_minus_z.getContent() == thiscontent)
				is_rail_z[0] = true;
			if (n_minus_z_minus_y.getContent() == thiscontent)
				is_rail_z_minus_y[0] = true;
			if(n_minus_z_plus_y.getContent() == thiscontent)
				is_rail_z_plus_y[0] = true;

			if(n_plus_z.getContent() == thiscontent)
				is_rail_z[1] = true;
			if (n_plus_z_minus_y.getContent() == thiscontent)
				is_rail_z_minus_y[1] = true;
			if(n_plus_z_plus_y.getContent() == thiscontent)
				is_rail_z_plus_y[1] = true;

			bool is_rail_x_all[] = {false, false};
			bool is_rail_z_all[] = {false, false};
			is_rail_x_all[0]=is_rail_x[0] || is_rail_x_minus_y[0] || is_rail_x_plus_y[0];
			is_rail_x_all[1]=is_rail_x[1] || is_rail_x_minus_y[1] || is_rail_x_plus_y[1];
			is_rail_z_all[0]=is_rail_z[0] || is_rail_z_minus_y[0] || is_rail_z_plus_y[0];
			is_rail_z_all[1]=is_rail_z[1] || is_rail_z_minus_y[1] || is_rail_z_plus_y[1];

			// reasonable default, flat straight unrotated rail
			bool is_straight = true;
			int adjacencies = 0;
			int angle = 0;
			u8 tileindex = 0;

			// check for sloped rail
			if (is_rail_x_plus_y[0] || is_rail_x_plus_y[1] || is_rail_z_plus_y[0] || is_rail_z_plus_y[1])
			{
				adjacencies = 5; //5 means sloped
				is_straight = true; // sloped is always straight
			}
			else
			{
				// is really straight, rails on both sides
				is_straight = (is_rail_x_all[0] && is_rail_x_all[1]) || (is_rail_z_all[0] && is_rail_z_all[1]);
				adjacencies = is_rail_x_all[0] + is_rail_x_all[1] + is_rail_z_all[0] + is_rail_z_all[1];
			}

			switch (adjacencies) {
			case 1:
				if(is_rail_x_all[0] || is_rail_x_all[1])
					angle = 90;
				break;
			case 2:
				if(!is_straight)
					tileindex = 1; // curved
				if(is_rail_x_all[0] && is_rail_x_all[1])
					angle = 90;
				if(is_rail_z_all[0] && is_rail_z_all[1]){
					if (n_minus_z_plus_y.getContent() == thiscontent) angle = 180;
				}
				else if(is_rail_x_all[0] && is_rail_z_all[0])
					angle = 270;
				else if(is_rail_x_all[0] && is_rail_z_all[1])
					angle = 180;
				else if(is_rail_x_all[1] && is_rail_z_all[1])
					angle = 90;
				break;
			case 3:
				// here is where the potential to 'switch' a junction is, but not implemented at present
				tileindex = 2; // t-junction
				if(!is_rail_x_all[1])
					angle=180;
				if(!is_rail_z_all[0])
					angle=90;
				if(!is_rail_z_all[1])
					angle=270;
				break;
			case 4:
				tileindex = 3; // crossing
				break;
			case 5: //sloped
				if(is_rail_z_plus_y[0])
					angle = 180;
				if(is_rail_x_plus_y[0])
					angle = 90;
				if(is_rail_x_plus_y[1])
					angle = -90;
				break;
			default:
				break;
			}

			TileSpec tile = getNodeTileN(n, p, tileindex, data);
			tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
			tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;

			AtlasPointer ap = tile.texture;
			
			u16 l = getInteriorLight(n, 0, data);
			video::SColor c = MapBlock_LightColor(255, l);

			float d = (float)BS/64;
			
			char g=-1;
			if (is_rail_x_plus_y[0] || is_rail_x_plus_y[1] || is_rail_z_plus_y[0] || is_rail_z_plus_y[1])
				g=1; //Object is at a slope

			video::S3DVertex vertices[4] =
			{
					video::S3DVertex(-BS/2,-BS/2+d,-BS/2, 0,0,0, c,
							ap.x0(), ap.y1()),
					video::S3DVertex(BS/2,-BS/2+d,-BS/2, 0,0,0, c,
							ap.x1(), ap.y1()),
					video::S3DVertex(BS/2,g*BS/2+d,BS/2, 0,0,0, c,
							ap.x1(), ap.y0()),
					video::S3DVertex(-BS/2,g*BS/2+d,BS/2, 0,0,0, c,
							ap.x0(), ap.y0()),
			};

			for(s32 i=0; i<4; i++)
			{
				if(angle != 0)
					vertices[i].Pos.rotateXZBy(angle);
				vertices[i].Pos += intToFloat(p, BS);
			}

			u16 indices[] = {0,1,2,2,3,0};
			collector.append(tile, vertices, 4, indices, 6);
		break;}
		case NDT_NODEBOX:
		{
			TileSpec tiles[6];
			for(int i = 0; i < 6; i++)
			{
				tiles[i] = getNodeTileN(n, p, i, data);
			}

			u16 l = getInteriorLight(n, 0, data);
			video::SColor c = MapBlock_LightColor(255, l);

			v3f pos = intToFloat(p, BS);

			std::vector<aabb3f> boxes = n.getNodeBoxes(nodedef);
			for(std::vector<aabb3f>::iterator
					i = boxes.begin();
					i != boxes.end(); i++)
			{
				aabb3f box = *i;
				box.MinEdge += pos;
				box.MaxEdge += pos;

				// Compute texture coords
				f32 tx1 = (i->MinEdge.X/BS)+0.5;
				f32 ty1 = (i->MinEdge.Y/BS)+0.5;
				f32 tz1 = (i->MinEdge.Z/BS)+0.5;
				f32 tx2 = (i->MaxEdge.X/BS)+0.5;
				f32 ty2 = (i->MaxEdge.Y/BS)+0.5;
				f32 tz2 = (i->MaxEdge.Z/BS)+0.5;
				f32 txc[24] = {
					// up
					tx1, 1-tz2, tx2, 1-tz1,
					// down
					tx1, tz1, tx2, tz2,
					// right
					tz1, 1-ty2, tz2, 1-ty1,
					// left
					1-tz2, 1-ty2, 1-tz1, 1-ty1,
					// back
					1-tx2, 1-ty2, 1-tx1, 1-ty1,
					// front
					tx1, 1-ty2, tx2, 1-ty1,
				};

				makeCuboid(&collector, box, tiles, 6, c, txc);
			}
		break;}
		}
	}
}
Ejemplo n.º 30
0
MapgenValleys::MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *emerge)
	: Mapgen(mapgenid, params, emerge)
{
	this->m_emerge = emerge;
	this->bmgr = emerge->biomemgr;

	//// amount of elements to skip for the next index
	//// for noise/height/biome maps (not vmanip)
	this->ystride = csize.X;
	this->zstride = csize.X * (csize.Y + 2);

	this->biomemap  = new u8[csize.X * csize.Z];
	this->heightmap = new s16[csize.X * csize.Z];
	this->heatmap   = NULL;
	this->humidmap  = NULL;

	this->map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT,
			g_settings->getU16("map_generation_limit"));

	MapgenValleysParams *sp = (MapgenValleysParams *)params->sparams;
	this->spflags = sp->spflags;

	this->humid_rivers       = (spflags & MG_VALLEYS_HUMID_RIVERS);
	this->use_altitude_chill = (spflags & MG_VALLEYS_ALT_CHILL);

	this->altitude_chill     = sp->altitude_chill;
	this->humidity_adjust    = params->np_biome_humidity.offset - 50.f;
	this->large_cave_depth   = sp->large_cave_depth;
	this->lava_features_lim  = rangelim(sp->lava_features, 0, 10);
	this->massive_cave_depth = sp->massive_cave_depth;
	this->river_depth_bed    = sp->river_depth + 1.f;
	this->river_size_factor  = sp->river_size / 100.f;
	this->water_features_lim = rangelim(sp->water_features, 0, 10);

	// a small chance of overflows if the settings are very high
	this->cave_water_max_height = water_level + MYMAX(0, water_features_lim - 6) * 50;
	this->lava_max_height       = water_level + MYMAX(0, lava_features_lim - 6) * 50;

	tcave_cache = new float[csize.Y + 2];

	//// 2D Terrain noise
	noise_filler_depth       = new Noise(&sp->np_filler_depth,       seed, csize.X, csize.Z);
	noise_inter_valley_slope = new Noise(&sp->np_inter_valley_slope, seed, csize.X, csize.Z);
	noise_rivers             = new Noise(&sp->np_rivers,             seed, csize.X, csize.Z);
	noise_terrain_height     = new Noise(&sp->np_terrain_height,     seed, csize.X, csize.Z);
	noise_valley_depth       = new Noise(&sp->np_valley_depth,       seed, csize.X, csize.Z);
	noise_valley_profile     = new Noise(&sp->np_valley_profile,     seed, csize.X, csize.Z);

	//// 3D Terrain noise
	noise_cave1             = new Noise(&sp->np_cave1,             seed, csize.X, csize.Y + 2, csize.Z);
	noise_cave2             = new Noise(&sp->np_cave2,             seed, csize.X, csize.Y + 2, csize.Z);
	noise_inter_valley_fill = new Noise(&sp->np_inter_valley_fill, seed, csize.X, csize.Y + 2, csize.Z);
	noise_massive_caves     = new Noise(&sp->np_massive_caves,     seed, csize.X, csize.Y + 2, csize.Z);

	//// Biome noise
	noise_heat_blend     = new Noise(&params->np_biome_heat_blend,     seed, csize.X, csize.Z);
	noise_heat           = new Noise(&params->np_biome_heat,           seed, csize.X, csize.Z);
	noise_humidity_blend = new Noise(&params->np_biome_humidity_blend, seed, csize.X, csize.Z);
	noise_humidity       = new Noise(&params->np_biome_humidity,       seed, csize.X, csize.Z);

	//// Resolve nodes to be used
	INodeDefManager *ndef = emerge->ndef;

	c_cobble               = ndef->getId("mapgen_cobble");
	c_desert_stone         = ndef->getId("mapgen_desert_stone");
	c_dirt                 = ndef->getId("mapgen_dirt");
	c_lava_source          = ndef->getId("mapgen_lava_source");
	c_mossycobble          = ndef->getId("mapgen_mossycobble");
	c_river_water_source   = ndef->getId("mapgen_river_water_source");
	c_sand                 = ndef->getId("mapgen_sand");
	c_sandstonebrick       = ndef->getId("mapgen_sandstonebrick");
	c_sandstone            = ndef->getId("mapgen_sandstone");
	c_stair_cobble         = ndef->getId("mapgen_stair_cobble");
	c_stair_sandstonebrick = ndef->getId("mapgen_stair_sandstonebrick");
	c_stone                = ndef->getId("mapgen_stone");
	c_water_source         = ndef->getId("mapgen_water_source");

	if (c_mossycobble == CONTENT_IGNORE)
		c_mossycobble = c_cobble;
	if (c_river_water_source == CONTENT_IGNORE)
		c_river_water_source = c_water_source;
	if (c_sand == CONTENT_IGNORE)
		c_sand = c_stone;
	if (c_sandstonebrick == CONTENT_IGNORE)
		c_sandstonebrick = c_sandstone;
	if (c_stair_cobble == CONTENT_IGNORE)
		c_stair_cobble = c_cobble;
	if (c_stair_sandstonebrick == CONTENT_IGNORE)
		c_stair_sandstonebrick = c_sandstone;
}