mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-11-04 09:15:29 +01:00 
			
		
		
		
	Add support for using arbitrary meshes as items
This commit is contained in:
		@@ -954,15 +954,43 @@ void GenericCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
 | 
			
		||||
			IItemDefManager *idef = m_gamedef->idef();
 | 
			
		||||
			ItemStack item(m_prop.textures[0], 1, 0, "", idef);
 | 
			
		||||
 | 
			
		||||
			m_wield_meshnode = new WieldMeshSceneNode(
 | 
			
		||||
					smgr->getRootSceneNode(), smgr, -1);
 | 
			
		||||
			m_wield_meshnode->setItem(item, m_gamedef);
 | 
			
		||||
			if (!item.getDefinition(idef).meshname.empty())
 | 
			
		||||
			{
 | 
			
		||||
				scene::IAnimatedMesh *mesh = m_gamedef->getMesh(item.getDefinition(idef).meshname);
 | 
			
		||||
				if(mesh)
 | 
			
		||||
				{
 | 
			
		||||
					m_animated_meshnode = smgr->addAnimatedMeshSceneNode(mesh, NULL);
 | 
			
		||||
 | 
			
		||||
			m_wield_meshnode->setScale(v3f(m_prop.visual_size.X/2,
 | 
			
		||||
					m_prop.visual_size.Y/2,
 | 
			
		||||
					m_prop.visual_size.X/2));
 | 
			
		||||
			u8 li = m_last_light;
 | 
			
		||||
			m_wield_meshnode->setColor(video::SColor(255,li,li,li));
 | 
			
		||||
					m_animated_meshnode->grab();
 | 
			
		||||
					mesh->drop(); // The scene node took hold of it
 | 
			
		||||
					m_animated_meshnode->animateJoints(); // Needed for some animations
 | 
			
		||||
					m_animated_meshnode->setScale(v3f(m_prop.visual_size.X,
 | 
			
		||||
							m_prop.visual_size.Y,
 | 
			
		||||
							m_prop.visual_size.X));
 | 
			
		||||
					u8 li = m_last_light;
 | 
			
		||||
					setMeshColor(m_animated_meshnode->getMesh(), video::SColor(255,li,li,li));
 | 
			
		||||
 | 
			
		||||
					bool backface_culling = m_prop.backface_culling;
 | 
			
		||||
					if (m_is_player)
 | 
			
		||||
						backface_culling = false;
 | 
			
		||||
 | 
			
		||||
					m_animated_meshnode->setMaterialFlag(video::EMF_LIGHTING, false);
 | 
			
		||||
					m_animated_meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
 | 
			
		||||
					m_animated_meshnode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
 | 
			
		||||
					m_animated_meshnode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
 | 
			
		||||
					m_animated_meshnode->setMaterialFlag(video::EMF_BACK_FACE_CULLING, backface_culling);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				m_wield_meshnode = new WieldMeshSceneNode(
 | 
			
		||||
						smgr->getRootSceneNode(), smgr, -1);
 | 
			
		||||
				m_wield_meshnode->setItem(item, m_gamedef);
 | 
			
		||||
				m_wield_meshnode->setScale(v3f(m_prop.visual_size.X/2,
 | 
			
		||||
						m_prop.visual_size.Y/2,
 | 
			
		||||
						m_prop.visual_size.X/2));
 | 
			
		||||
				u8 li = m_last_light;
 | 
			
		||||
				m_wield_meshnode->setColor(video::SColor(255,li,li,li));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		infostream<<"GenericCAO::addToScene(): \""<<m_prop.visual
 | 
			
		||||
@@ -1402,6 +1430,21 @@ void GenericCAO::updateTextures(const std::string &mod)
 | 
			
		||||
				m_animated_meshnode->getMaterial(i).SpecularColor = m_prop.colors[i];
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else if (m_prop.visual == "wielditem") {
 | 
			
		||||
			IItemDefManager *idef = m_gamedef->idef();
 | 
			
		||||
			ItemStack item(m_prop.textures[0], 1, 0, "", idef);
 | 
			
		||||
 | 
			
		||||
			if (!item.getDefinition(idef).meshname.empty()) {
 | 
			
		||||
 | 
			
		||||
				unsigned int materialcount = m_animated_meshnode->getMaterialCount();
 | 
			
		||||
 | 
			
		||||
				for (unsigned int i = 0; i < materialcount; i++) {
 | 
			
		||||
					m_animated_meshnode->getMaterial(i)
 | 
			
		||||
							.setTexture(0, tsrc->getTexture(item
 | 
			
		||||
									.getDefinition(idef).meshtexture));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if(m_meshnode)
 | 
			
		||||
	{
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										110
									
								
								src/itemdef.cpp
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								src/itemdef.cpp
									
									
									
									
									
								
							@@ -77,6 +77,8 @@ ItemDefinition& ItemDefinition::operator=(const ItemDefinition &def)
 | 
			
		||||
	sound_place = def.sound_place;
 | 
			
		||||
	sound_place_failed = def.sound_place_failed;
 | 
			
		||||
	range = def.range;
 | 
			
		||||
	meshname = def.meshname;
 | 
			
		||||
	meshtexture = def.meshtexture;
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -157,6 +159,10 @@ void ItemDefinition::serialize(std::ostream &os, u16 protocol_version) const
 | 
			
		||||
		os << serializeString(sound_place_failed.name);
 | 
			
		||||
		writeF1000(os, sound_place_failed.gain);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//TODO check for protocol version?
 | 
			
		||||
	os<<serializeString(meshname);
 | 
			
		||||
	os<<serializeString(meshtexture);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ItemDefinition::deSerialize(std::istream &is)
 | 
			
		||||
@@ -214,6 +220,10 @@ void ItemDefinition::deSerialize(std::istream &is)
 | 
			
		||||
		sound_place_failed.name = deSerializeString(is);
 | 
			
		||||
		sound_place_failed.gain = readF1000(is);
 | 
			
		||||
	} catch(SerializationError &e) {};
 | 
			
		||||
 | 
			
		||||
	//TODO check for protocol?
 | 
			
		||||
	meshname = deSerializeString(is);
 | 
			
		||||
	meshtexture = deSerializeString(is);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -341,7 +351,7 @@ CItemDefManager::ClientCached* CItemDefManager::createClientCachedDirect(const s
 | 
			
		||||
 | 
			
		||||
	// Create an inventory texture
 | 
			
		||||
	cc->inventory_texture = NULL;
 | 
			
		||||
	if (def.inventory_image != "")
 | 
			
		||||
	if (!def.inventory_image.empty())
 | 
			
		||||
		cc->inventory_texture = tsrc->getTexture(def.inventory_image);
 | 
			
		||||
 | 
			
		||||
	// Additional processing for nodes:
 | 
			
		||||
@@ -352,6 +362,10 @@ CItemDefManager::ClientCached* CItemDefManager::createClientCachedDirect(const s
 | 
			
		||||
	if (def.type == ITEM_NODE) {
 | 
			
		||||
		createNodeItemTexture(name, def, nodedef, cc, gamedef, tsrc);
 | 
			
		||||
	}
 | 
			
		||||
	else if (def.type == ITEM_CRAFT) {
 | 
			
		||||
		if ( !def.meshname.empty())
 | 
			
		||||
			createMeshItemTexture(name, def, nodedef, cc, gamedef, tsrc);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Put in cache
 | 
			
		||||
	m_clientcached.set(name, cc);
 | 
			
		||||
@@ -650,6 +664,100 @@ void CItemDefManager::createNodeItemTexture(const std::string& name,
 | 
			
		||||
	if (node_mesh)
 | 
			
		||||
		node_mesh->drop();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************************************************/
 | 
			
		||||
void CItemDefManager::renderMeshToTexture(const ItemDefinition& def, scene::IMesh* mesh,
 | 
			
		||||
		ClientCached* cc, ITextureSource* tsrc) const
 | 
			
		||||
{
 | 
			
		||||
	video::ITexture *itemimage = cc->inventory_texture;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 Draw node mesh into a render target texture
 | 
			
		||||
	 */
 | 
			
		||||
	TextureFromMeshParams params;
 | 
			
		||||
	params.mesh = 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.9, 0.9, 0.9);
 | 
			
		||||
	params.light_position.set(10, 100, -50);
 | 
			
		||||
	params.light_color.set(1.0, 0.5, 0.5, 0.5);
 | 
			
		||||
	params.light_radius = 1000;
 | 
			
		||||
	cc->inventory_texture = tsrc->generateTextureFromMesh(params);
 | 
			
		||||
 | 
			
		||||
	// render-to-target didn't work
 | 
			
		||||
	if (cc->inventory_texture == NULL) {
 | 
			
		||||
 | 
			
		||||
		cc->inventory_texture = itemimage;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************************************************/
 | 
			
		||||
void CItemDefManager::createMeshItemTexture(const std::string& name,
 | 
			
		||||
		const ItemDefinition& def, INodeDefManager* nodedef,
 | 
			
		||||
		ClientCached* cc, IGameDef* gamedef, ITextureSource* tsrc) const
 | 
			
		||||
{
 | 
			
		||||
	// Get node properties
 | 
			
		||||
	content_t id = nodedef->getId(name);
 | 
			
		||||
	const ContentFeatures& f = nodedef->get(id);
 | 
			
		||||
 | 
			
		||||
	if (def.meshname == "")
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	video::ITexture *texture = tsrc->getTexture(def.meshtexture);
 | 
			
		||||
 | 
			
		||||
	infostream<<"CItemDefManager::createMeshItemTexture(): mesh"<<std::endl;
 | 
			
		||||
 | 
			
		||||
	scene::IAnimatedMesh *mesh = gamedef->getMesh(def.meshname);
 | 
			
		||||
	if(mesh)
 | 
			
		||||
	{
 | 
			
		||||
 | 
			
		||||
		video::SColor c(255, 255, 255, 255);
 | 
			
		||||
		setMeshColor(mesh, c);
 | 
			
		||||
 | 
			
		||||
		rotateMeshXZby(mesh, 180);
 | 
			
		||||
 | 
			
		||||
		// scale and translate the mesh so it's a
 | 
			
		||||
		// unit cube centered on the origin
 | 
			
		||||
		scaleMesh(mesh, v3f(1.0 / BS, 1.0 / BS, 1.0 / BS));
 | 
			
		||||
 | 
			
		||||
		// Customize materials
 | 
			
		||||
		for (u32 i = 0; i < mesh->getMeshBufferCount(); ++i) {
 | 
			
		||||
 | 
			
		||||
			video::SMaterial &material = mesh->getMeshBuffer(i)->getMaterial();
 | 
			
		||||
			material.setTexture(0, texture);
 | 
			
		||||
			material.setFlag(video::EMF_BACK_FACE_CULLING, true);
 | 
			
		||||
			material.setFlag(video::EMF_BILINEAR_FILTER, false);
 | 
			
		||||
			material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 Draw node mesh into a render target texture
 | 
			
		||||
		 */
 | 
			
		||||
		renderMeshToTexture(def, mesh, cc, tsrc);
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 Use the ingot mesh as the wield mesh
 | 
			
		||||
		 */
 | 
			
		||||
 | 
			
		||||
		cc->wield_mesh = mesh;
 | 
			
		||||
		cc->wield_mesh->grab();
 | 
			
		||||
		// no way reference count can be smaller than 2 in this place!
 | 
			
		||||
		assert(cc->wield_mesh->getReferenceCount() >= 2);
 | 
			
		||||
 | 
			
		||||
		if (mesh)
 | 
			
		||||
			mesh->drop();
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
		errorstream<<"CItemDefManager::createMeshItemTexture(): Could not load mesh "<<def.meshname<<std::endl;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/******************************************************************************/
 | 
			
		||||
 
 | 
			
		||||
@@ -66,6 +66,8 @@ struct ItemDefinition
 | 
			
		||||
	std::string inventory_image; // Optional for nodes, mandatory for tools/craftitems
 | 
			
		||||
	std::string wield_image; // If empty, inventory_image or mesh (only nodes) is used
 | 
			
		||||
	v3f wield_scale;
 | 
			
		||||
	std::string meshname;    // name of internal mesh (or meshfile to use TBD)
 | 
			
		||||
	std::string meshtexture; // meshtexture
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
		Item stack and interaction properties
 | 
			
		||||
@@ -211,6 +213,13 @@ private:
 | 
			
		||||
			const ItemDefinition& def, INodeDefManager* nodedef,
 | 
			
		||||
			ClientCached* cc, IGameDef* gamedef, ITextureSource* tsrc) const;
 | 
			
		||||
 | 
			
		||||
	void createMeshItemTexture(const std::string& name,
 | 
			
		||||
			const ItemDefinition& def, INodeDefManager* nodedef,
 | 
			
		||||
			ClientCached* cc, IGameDef* gamedef, ITextureSource* tsrc) const;
 | 
			
		||||
 | 
			
		||||
	void renderMeshToTexture(const ItemDefinition& def, scene::IMesh* mesh,
 | 
			
		||||
			ClientCached* cc, ITextureSource* tsrc) const;
 | 
			
		||||
 | 
			
		||||
	ClientCached* createClientCachedDirect(const std::string &name,
 | 
			
		||||
			IGameDef *gamedef) const;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -58,6 +58,8 @@ ItemDefinition read_item_definition(lua_State* L,int index,
 | 
			
		||||
	getstringfield(L, index, "description", def.description);
 | 
			
		||||
	getstringfield(L, index, "inventory_image", def.inventory_image);
 | 
			
		||||
	getstringfield(L, index, "wield_image", def.wield_image);
 | 
			
		||||
	getstringfield(L, index, "mesh", def.meshname);
 | 
			
		||||
	getstringfield(L, index, "meshtexture", def.meshtexture);
 | 
			
		||||
 | 
			
		||||
	lua_getfield(L, index, "wield_scale");
 | 
			
		||||
	if(lua_istable(L, -1)){
 | 
			
		||||
 
 | 
			
		||||
@@ -386,6 +386,20 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, IGameDef *gamedef)
 | 
			
		||||
		}
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	else if (idef->getWieldMesh(def.name, gamedef) != 0) {
 | 
			
		||||
		irr::scene::IMesh * mesh = idef->getWieldMesh(def.name, gamedef);
 | 
			
		||||
		m_meshnode->setMesh(mesh);
 | 
			
		||||
		u32 material_count = m_meshnode->getMaterialCount();
 | 
			
		||||
		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);
 | 
			
		||||
			material.MaterialType = m_material_type;
 | 
			
		||||
			material.setTexture(0, tsrc->getTexture(def.meshtexture));
 | 
			
		||||
		}
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	else if (def.inventory_image != "") {
 | 
			
		||||
		setExtruded(def.inventory_image, def.wield_scale, tsrc, 1);
 | 
			
		||||
		return;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user