diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt
index dd85299902d9459a383002e12facde7132a3316d..1ca5f16dc048330eb4eaae4325bcf01861d4b2b8 100644
--- a/builtin/settingtypes.txt
+++ b/builtin/settingtypes.txt
@@ -508,6 +508,9 @@ directional_colored_fog (Colored fog) bool true
 #    set to the nearest valid value.
 ambient_occlusion_gamma (Ambient occlusion gamma) float 2.2 0.25 4.0
 
+#    Enables animation of inventory items.
+inventory_items_animations (Inventory items animations) bool false
+
 [**Menus]
 
 #    Use a cloud animation for the main menu background.
diff --git a/minetest.conf.example b/minetest.conf.example
index d8f91e7cb670dd9089c52d3f183d2fad6ce08a6f..198b9323848e7313f1d6bf7b76571ba43be92657 100644
--- a/minetest.conf.example
+++ b/minetest.conf.example
@@ -588,6 +588,9 @@
 #    type: float min: 0.25 max: 4
 # ambient_occlusion_gamma = 2.2
 
+#    Enable animation of inventory items.
+# inventory_items_animations = false
+
 ### Menus
 
 #    Use a cloud animation for the main menu background.
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index 42eddb8ceb7c4b998a1c44108acbc981fc095804..669987d0031471611b4f95a7ef934b8baacd1004 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -138,6 +138,7 @@ void set_default_settings(Settings *settings)
 	settings->setDefault("console_alpha", "200");
 	settings->setDefault("selectionbox_color", "(0,0,0)");
 	settings->setDefault("enable_node_highlighting", "false");
+	settings->setDefault("inventory_items_animations", "false");
 	settings->setDefault("crosshair_color", "(255,255,255)");
 	settings->setDefault("crosshair_alpha", "255");
 	settings->setDefault("hud_scaling", "1.0");
diff --git a/src/guiFormSpecMenu.cpp b/src/guiFormSpecMenu.cpp
index 3cef5079ec9c2049a3bed9d6af2d6677ba3299a6..4784d73145a4daba18114d1e41b26c60a0c6b1ac 100644
--- a/src/guiFormSpecMenu.cpp
+++ b/src/guiFormSpecMenu.cpp
@@ -572,7 +572,7 @@ void GUIFormSpecMenu::parseItemImage(parserData* data,std::string element)
 
 		if(!data->explicit_size)
 			warningstream<<"invalid use of item_image without a size[] element"<<std::endl;
-		m_itemimages.push_back(ImageDrawSpec(name, pos, geom));
+		m_itemimages.push_back(ImageDrawSpec("", name, pos, geom));
 		return;
 	}
 	errorstream<< "Invalid ItemImage element(" << parts.size() << "): '" << element << "'"  << std::endl;
@@ -1483,7 +1483,6 @@ void GUIFormSpecMenu::parseItemImageButton(parserData* data,std::string element)
 		IItemDefManager *idef = m_gamedef->idef();
 		ItemStack item;
 		item.deSerialize(item_name, idef);
-		video::ITexture *texture = idef->getInventoryTexture(item.getDefinition(idef).name, m_gamedef);
 
 		m_tooltips[name] =
 			TooltipSpec(item.getDefinition(idef).description,
@@ -1505,13 +1504,17 @@ void GUIFormSpecMenu::parseItemImageButton(parserData* data,std::string element)
 		}
 
 		e->setUseAlphaChannel(true);
-		e->setImage(guiScalingImageButton(Environment->getVideoDriver(), texture, geom.X, geom.Y));
-		e->setPressedImage(guiScalingImageButton(Environment->getVideoDriver(), texture, geom.X, geom.Y));
+		e->setImage(guiScalingImageButton(Environment->getVideoDriver(), NULL, geom.X, geom.Y));
+		e->setPressedImage(guiScalingImageButton(Environment->getVideoDriver(), NULL, geom.X, geom.Y));
 		e->setScaleImage(true);
 		spec.ftype = f_Button;
 		rect+=data->basepos-padding;
 		spec.rect=rect;
 		m_fields.push_back(spec);
+		pos = padding + AbsoluteRect.UpperLeftCorner;
+		pos.X += stof(v_pos[0]) * (float) spacing.X;
+		pos.Y += stof(v_pos[1]) * (float) spacing.Y;
+		m_itemimages.push_back(ImageDrawSpec("", item_name, pos, geom));
 		return;
 	}
 	errorstream<< "Invalid ItemImagebutton element(" << parts.size() << "): '" << element << "'"  << std::endl;
@@ -2151,7 +2154,8 @@ GUIFormSpecMenu::ItemSpec GUIFormSpecMenu::getItemAtPos(v2s32 p) const
 	return ItemSpec(InventoryLocation(), "", -1);
 }
 
-void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase)
+void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase,
+		bool &item_hovered)
 {
 	video::IVideoDriver* driver = Environment->getVideoDriver();
 
@@ -2193,12 +2197,13 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase)
 			&& m_selected_item->i == item_i;
 		bool hovering = rect.isPointInside(m_pointer);
 
-		if(phase == 0)
-		{
-			if(hovering)
+		if (phase == 0) {
+			if (hovering) {
+				item_hovered = true;
 				driver->draw2DRectangle(m_slotbg_h, rect, &AbsoluteClippingRect);
-			else
+			} else {
 				driver->draw2DRectangle(m_slotbg_n, rect, &AbsoluteClippingRect);
+			}
 		}
 
 		//Draw inv slot borders
@@ -2232,7 +2237,8 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase)
 			if(!item.empty())
 			{
 				drawItemStack(driver, m_font, item,
-						rect, &AbsoluteClippingRect, m_gamedef);
+					rect, &AbsoluteClippingRect, m_gamedef,
+					selected, hovering, false);
 			}
 
 			// Draw tooltip
@@ -2273,11 +2279,15 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase)
 
 void GUIFormSpecMenu::drawSelectedItem()
 {
-	if(!m_selected_item)
-		return;
-
 	video::IVideoDriver* driver = Environment->getVideoDriver();
 
+	if (!m_selected_item) {
+		drawItemStack(driver, m_font, ItemStack(),
+			core::rect<s32>(v2s32(0, 0), v2s32(0, 0)),
+			NULL, m_gamedef, false, false, true);
+		return;
+	}
+
 	Inventory *inv = m_invmgr->getInventory(m_selected_item->inventoryloc);
 	sanity_check(inv);
 	InventoryList *list = inv->getList(m_selected_item->listname);
@@ -2287,7 +2297,7 @@ void GUIFormSpecMenu::drawSelectedItem()
 
 	core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
 	core::rect<s32> rect = imgrect + (m_pointer - imgrect.getCenter());
-	drawItemStack(driver, m_font, stack, rect, NULL, m_gamedef);
+	drawItemStack(driver, m_font, stack, rect, NULL, m_gamedef, false, false, true);
 }
 
 void GUIFormSpecMenu::drawMenu()
@@ -2369,6 +2379,12 @@ void GUIFormSpecMenu::drawMenu()
 
 		driver->draw2DRectangle(todraw, rect, 0);
 	}
+
+	/*
+		Call base class
+	*/
+	gui::IGUIElement::draw();
+
 	/*
 		Draw images
 	*/
@@ -2413,18 +2429,12 @@ void GUIFormSpecMenu::drawMenu()
 		const ImageDrawSpec &spec = m_itemimages[i];
 		IItemDefManager *idef = m_gamedef->idef();
 		ItemStack item;
-		item.deSerialize(spec.name, idef);
-		video::ITexture *texture = idef->getInventoryTexture(item.getDefinition(idef).name, m_gamedef);
-		// Image size on screen
+		item.deSerialize(spec.item_name, idef);
 		core::rect<s32> imgrect(0, 0, spec.geom.X, spec.geom.Y);
-		// Image rectangle on screen
+		// Viewport rectangle on screen
 		core::rect<s32> rect = imgrect + spec.pos;
-		const video::SColor color(255,255,255,255);
-		const video::SColor colors[] = {color,color,color,color};
-		draw2DImageFilterScaled(driver, texture, rect,
-			core::rect<s32>(core::position2d<s32>(0,0),
-					core::dimension2di(texture->getOriginalSize())),
-			NULL/*&AbsoluteClippingRect*/, colors, true);
+		drawItemStack(driver, m_font, item, rect, &AbsoluteClippingRect,
+				m_gamedef, false, false, false);
 	}
 
 	/*
@@ -2432,17 +2442,18 @@ void GUIFormSpecMenu::drawMenu()
 		Phase 0: Item slot rectangles
 		Phase 1: Item images; prepare tooltip
 	*/
-	int start_phase=0;
-	for(int phase=start_phase; phase<=1; phase++)
-	for(u32 i=0; i<m_inventorylists.size(); i++)
-	{
-		drawList(m_inventorylists[i], phase);
+	bool item_hovered = false;
+	int start_phase = 0;
+	for (int phase = start_phase; phase <= 1; phase++) {
+		for (u32 i = 0; i < m_inventorylists.size(); i++) {
+			drawList(m_inventorylists[i], phase, item_hovered);
+		}
+	}
+	if (!item_hovered) {
+		drawItemStack(driver, m_font, ItemStack(),
+			core::rect<s32>(v2s32(0, 0), v2s32(0, 0)),
+			NULL, m_gamedef, false, true, false);
 	}
-
-	/*
-		Call base class
-	*/
-	gui::IGUIElement::draw();
 
 /* TODO find way to show tooltips on touchscreen */
 #ifndef HAVE_TOUCHSCREENGUI
diff --git a/src/guiFormSpecMenu.h b/src/guiFormSpecMenu.h
index 2ba47f7ff5bac5c60648465886cfd4daec20f959..9b892f19273d2cd110cb5ac7660aa0fdd00a3a28 100644
--- a/src/guiFormSpecMenu.h
+++ b/src/guiFormSpecMenu.h
@@ -143,21 +143,32 @@ class GUIFormSpecMenu : public GUIModalMenu
 		{
 		}
 		ImageDrawSpec(const std::string &a_name,
-				v2s32 a_pos, v2s32 a_geom):
+				const std::string &a_item_name,
+				const v2s32 &a_pos, const v2s32 &a_geom):
 			name(a_name),
+			item_name (a_item_name),
 			pos(a_pos),
 			geom(a_geom)
 		{
 			scale = true;
 		}
 		ImageDrawSpec(const std::string &a_name,
-				v2s32 a_pos):
+				const v2s32 &a_pos, const v2s32 &a_geom):
+			name(a_name),
+			pos(a_pos),
+			geom(a_geom)
+		{
+			scale = true;
+		}
+		ImageDrawSpec(const std::string &a_name,
+				const v2s32 &a_pos):
 			name(a_name),
 			pos(a_pos)
 		{
 			scale = false;
 		}
 		std::string name;
+		std::string item_name;
 		v2s32 pos;
 		v2s32 geom;
 		bool scale;
@@ -282,7 +293,7 @@ class GUIFormSpecMenu : public GUIModalMenu
 	void regenerateGui(v2u32 screensize);
 
 	ItemSpec getItemAtPos(v2s32 p) const;
-	void drawList(const ListDrawSpec &s, int phase);
+	void drawList(const ListDrawSpec &s, int phase,	bool &item_hovered);
 	void drawSelectedItem();
 	void drawMenu();
 	void updateSelectedItem();
@@ -334,6 +345,8 @@ class GUIFormSpecMenu : public GUIModalMenu
 	std::vector<std::pair<FieldSpec,gui::IGUIScrollBar*> > m_scrollbars;
 
 	ItemSpec *m_selected_item;
+	f32 m_timer1;
+	f32 m_timer2;
 	u32 m_selected_amount;
 	bool m_selected_dragging;
 
@@ -373,6 +386,7 @@ class GUIFormSpecMenu : public GUIModalMenu
 	TextDest         *m_text_dst;
 	unsigned int      m_formspec_version;
 	std::string       m_focused_element;
+	bool              m_selection_active;
 
 	typedef struct {
 		bool explicit_size;
diff --git a/src/hud.cpp b/src/hud.cpp
index d1313089ae8dd95ce74ef5f6852ed6d984857831..2d22f963c02482890b6222e6e5a05e0c8be07fcb 100644
--- a/src/hud.cpp
+++ b/src/hud.cpp
@@ -82,8 +82,9 @@ Hud::Hud(video::IVideoDriver *driver, scene::ISceneManager* smgr,
 	use_hotbar_selected_image = false;
 }
 
-void Hud::drawItem(const ItemStack &item, const core::rect<s32>& rect, bool selected) {
-
+void Hud::drawItem(const ItemStack &item, const core::rect<s32>& rect,
+		bool selected)
+{
 	if (selected) {
 			/* draw hihlighting around selected item */
 			if (use_hotbar_selected_image) {
@@ -154,7 +155,8 @@ void Hud::drawItem(const ItemStack &item, const core::rect<s32>& rect, bool sele
 		video::SColor bgcolor2(128, 0, 0, 0);
 		if (!use_hotbar_image)
 			driver->draw2DRectangle(bgcolor2, rect, NULL);
-		drawItemStack(driver, g_fontengine->getFont(), item, rect, NULL, gamedef);
+		drawItemStack(driver, g_fontengine->getFont(), item, rect, NULL,
+			gamedef, selected, false, false);
 	}
 
 //NOTE: selectitem = 0 -> no selected; selectitem 1-based
@@ -489,23 +491,90 @@ void drawItemStack(video::IVideoDriver *driver,
 		const ItemStack &item,
 		const core::rect<s32> &rect,
 		const core::rect<s32> *clip,
-		IGameDef *gamedef)
+		IGameDef *gamedef,
+		bool selected,
+		bool hovered,
+		bool dragged)
 {
-	if(item.empty())
+	static s32 hovered_time;
+	static s32 selected_time;
+	static s32 dragged_time;
+	static scene::IMesh *hovered_mesh;
+	static scene::IMesh *selected_mesh;
+	static scene::IMesh *dragged_mesh;
+	bool enable_animations =
+		g_settings->getBool("inventory_items_animations");
+
+	if (item.empty()) {
+		if (selected) {
+			selected_mesh = NULL;
+		} else if (hovered) {
+			hovered_mesh = NULL;
+		} else if (dragged) {
+			dragged_mesh = NULL;
+		}
 		return;
+	}
 
 	const ItemDefinition &def = item.getDefinition(gamedef->idef());
-	video::ITexture *texture = gamedef->idef()->getInventoryTexture(def.name, gamedef);
+	scene::IMesh* mesh = gamedef->idef()->getWieldMesh(def.name, gamedef);
+
+	if (mesh) {
+		driver->clearZBuffer();
+		s32 delta = 0;
+		if (selected) {
+			if (mesh != selected_mesh) {
+				selected_mesh = mesh;
+				selected_time = getTimeMs();
+			} else {
+				delta = porting::getDeltaMs(selected_time, getTimeMs()) % 100000;
+			}
+		} else if (hovered) {
+			if (mesh != hovered_mesh) {
+				hovered_mesh = mesh;
+				hovered_time = getTimeMs();
+			} else {
+				delta = porting::getDeltaMs(hovered_time, getTimeMs()) % 100000;
+			}
+		} else if (dragged) {
+			if (mesh != dragged_mesh) {
+				dragged_mesh = mesh;
+				dragged_time = getTimeMs();
+			} else {
+				delta = porting::getDeltaMs(dragged_time, getTimeMs()) % 100000;
+			}
+		}
+		core::rect<s32> oldViewPort = driver->getViewPort();
+		core::matrix4 oldProjMat = driver->getTransform(video::ETS_PROJECTION);
+		core::matrix4 oldViewMat = driver->getTransform(video::ETS_VIEW);
+		core::matrix4 ProjMatrix;
+		ProjMatrix.buildProjectionMatrixOrthoLH(2, 2, -1, 100);
+		driver->setTransform(video::ETS_PROJECTION, ProjMatrix);
+		driver->setTransform(video::ETS_VIEW, ProjMatrix);
+		core::matrix4 matrix;
+		matrix.makeIdentity();
+
+		if (enable_animations) {
+			float timer_f = (float)delta / 5000.0;
+			matrix.setRotationDegrees(core::vector3df(0, 360 * timer_f, 0));
+		}
 
-	// Draw the inventory texture
-	if(texture != NULL)
-	{
-		const video::SColor color(255,255,255,255);
-		const video::SColor colors[] = {color,color,color,color};
-		draw2DImageFilterScaled(driver, texture, rect,
-			core::rect<s32>(core::position2d<s32>(0,0),
-			core::dimension2di(texture->getOriginalSize())),
-			clip, colors, true);
+		driver->setTransform(video::ETS_WORLD, matrix);
+		driver->setViewPort(rect);
+
+		u32 mc = mesh->getMeshBufferCount();
+		for (u32 j = 0; j < mc; ++j) {
+			scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
+			video::SMaterial &material = buf->getMaterial();
+			material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
+			material.Lighting = false;
+			driver->setMaterial(material);
+			driver->drawMeshBuffer(buf);
+		}
+
+		driver->setTransform(video::ETS_VIEW, oldViewMat);
+		driver->setTransform(video::ETS_PROJECTION, oldProjMat);
+		driver->setViewPort(oldViewPort);
 	}
 
 	if(def.type == ITEM_TOOL && item.wear != 0)
diff --git a/src/hud.h b/src/hud.h
index 65453aec1ae7288cbdd127226bf1f0bc57bfd758..88e7181d6f67079152b7573e1d89daf1415dac1a 100644
--- a/src/hud.h
+++ b/src/hud.h
@@ -137,7 +137,8 @@ class Hud {
 	void drawItems(v2s32 upperleftpos, s32 itemcount, s32 offset,
 		InventoryList *mainlist, u16 selectitem, u16 direction);
 
-	void drawItem(const ItemStack &item, const core::rect<s32>& rect, bool selected);
+	void drawItem(const ItemStack &item, const core::rect<s32>& rect,
+		bool selected);
 
 	v2u32 m_screensize;
 	v2s32 m_displaycenter;
@@ -151,8 +152,10 @@ void drawItemStack(video::IVideoDriver *driver,
 		const ItemStack &item,
 		const core::rect<s32> &rect,
 		const core::rect<s32> *clip,
-		IGameDef *gamedef);
-
+		IGameDef *gamedef,
+		bool selected,
+		bool hovered,
+		bool dragged);
 
 #endif
 
diff --git a/src/itemdef.cpp b/src/itemdef.cpp
index 60a7dc64e33316f109eb3c20b81f6fb953792cea..a618ad631b078666a682ec39d944b129b2096884 100644
--- a/src/itemdef.cpp
+++ b/src/itemdef.cpp
@@ -332,7 +332,6 @@ class CItemDefManager: public IWritableItemDefManager
 			return cc;
 
 		ITextureSource *tsrc = gamedef->getTextureSource();
-		INodeDefManager *nodedef = gamedef->getNodeDefManager();
 		const ItemDefinition &def = get(name);
 
 		// Create new ClientCached
@@ -343,103 +342,11 @@ class CItemDefManager: public IWritableItemDefManager
 		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();
+		ItemStack item = ItemStack();
+		item.name = def.name;
 
-				// no way reference count can be smaller than 2 in this place!
-				assert(cc->wield_mesh->getReferenceCount() >= 2);
-			}
-
-			if (node_mesh)
-				node_mesh->drop();
-		}
+		scene::IMesh *mesh = getItemMesh(gamedef, item);
+		cc->wield_mesh = mesh;
 
 		// Put in cache
 		m_clientcached.set(name, cc);
diff --git a/src/wieldmesh.cpp b/src/wieldmesh.cpp
index a022754a6864da4fce61ad64285043caa00723f7..3e2483b5ee5c7b54b3a0075dfdf00dc7759f8170 100644
--- a/src/wieldmesh.cpp
+++ b/src/wieldmesh.cpp
@@ -114,9 +114,7 @@ static scene::IMesh *createExtrusionMesh(int resolution_x, int resolution_y)
 	mesh->addMeshBuffer(buf);
 	buf->drop();
 	scaleMesh(mesh, scale);  // also recalculates bounding box
-	scene::IMesh *newmesh = createForsythOptimizedMesh(mesh);
-	mesh->drop();
-	return newmesh;
+	return mesh;
 }
 
 /*
@@ -436,3 +434,116 @@ void WieldMeshSceneNode::changeToMesh(scene::IMesh *mesh)
 	m_meshnode->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, m_lighting);
 	m_meshnode->setVisible(true);
 }
+
+scene::IMesh *getItemMesh(IGameDef *gamedef, const ItemStack &item)
+{
+	ITextureSource *tsrc = gamedef->getTextureSource();
+	IItemDefManager *idef = gamedef->getItemDefManager();
+	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 (!g_extrusion_mesh_cache) {
+		g_extrusion_mesh_cache = new ExtrusionMeshCache();
+	} else {
+		g_extrusion_mesh_cache->grab();
+	}
+
+	scene::IMesh *mesh;
+
+	// If wield_image is defined, it overrides everything else
+	if (def.wield_image != "") {
+		mesh = getExtrudedMesh(tsrc, def.wield_image);
+		return mesh;
+	} 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));
+			return mesh;
+		} 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(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));
+			mesh = cloneMesh(mapblock_mesh.getMesh());
+			translateMesh(mesh, v3f(-BS, -BS, -BS));
+			scaleMesh(mesh, v3f(0.12, 0.12, 0.12));
+			rotateMeshXZby(mesh, -45);
+			rotateMeshYZby(mesh, -30);
+
+			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;
+			}
+			return mesh;
+		}
+
+		shadeMeshFaces(mesh);
+		rotateMeshXZby(mesh, -45);
+		rotateMeshYZby(mesh, -30);
+
+		u32 mc = mesh->getMeshBufferCount();
+		for (u32 i = 0; i < mc; ++i) {
+			video::SMaterial &material = mesh->getMeshBuffer(i)->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 (f.tiles[i].animation_frame_count > 1) {
+				FrameSpec animation_frame = f.tiles[i].frames[0];
+				material.setTexture(0, animation_frame.texture);
+			} else {
+				material.setTexture(0, f.tiles[i].texture);
+			}
+		}
+		return mesh;
+	}
+	return NULL;
+}
+
+scene::IMesh * getExtrudedMesh(ITextureSource *tsrc,
+		const std::string &imagename)
+{
+	video::ITexture *texture = tsrc->getTextureForMesh(imagename);
+	if (!texture) {
+		return NULL;
+	}
+
+	core::dimension2d<u32> dim = texture->getSize();
+	scene::IMesh *mesh = cloneMesh(g_extrusion_mesh_cache->create(dim));
+
+	// Customize material
+	video::SMaterial &material = mesh->getMeshBuffer(0)->getMaterial();
+	material.setTexture(0, tsrc->getTexture(imagename));
+	material.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
+	material.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
+	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);
+	material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+	scaleMesh(mesh, v3f(2.0, 2.0, 2.0));
+
+	return mesh;
+}
diff --git a/src/wieldmesh.h b/src/wieldmesh.h
index 3f4f4fc042a5e5c46a5c41f02cee8de0a7e4ab94..c29c06f956a2f674435e2de6ae8edf2aa1594179 100644
--- a/src/wieldmesh.h
+++ b/src/wieldmesh.h
@@ -77,4 +77,8 @@ class WieldMeshSceneNode: public scene::ISceneNode
 	core::aabbox3d<f32> m_bounding_box;
 };
 
+scene::IMesh *getItemMesh(IGameDef *gamedef, const ItemStack &item);
+
+scene::IMesh *getExtrudedMesh(ITextureSource *tsrc,
+		const std::string &imagename);
 #endif