From 969fbb189d16d87d26ceab29795644588fb90a32 Mon Sep 17 00:00:00 2001
From: Perttu Ahola <celeron55@gmail.com>
Date: Sat, 21 May 2011 11:07:03 +0300
Subject: [PATCH] All textures are are now searched first from the directory
 specified by the texture_path setting.

---
 src/clientobject.cpp   |   9 +--
 src/game.cpp           |  38 ++++++------
 src/main.cpp           |   6 +-
 src/mapblockobject.cpp |   6 +-
 src/mapblockobject.h   |   4 +-
 src/mineral.cpp        |   2 -
 src/mineral.h          |   3 +-
 src/player.cpp         |   4 +-
 src/texture.h          | 134 -----------------------------------------
 src/tile.cpp           |  62 +++++++++++++++----
 src/tile.h             |  18 +++++-
 src/utility.h          |  12 ++--
 12 files changed, 108 insertions(+), 190 deletions(-)
 delete mode 100644 src/texture.h

diff --git a/src/clientobject.cpp b/src/clientobject.cpp
index 9e4bf757c..402535ffc 100644
--- a/src/clientobject.cpp
+++ b/src/clientobject.cpp
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "constants.h"
 #include "utility.h"
 #include "environment.h"
+#include "tile.h"
 
 /*
 	ClientActiveObject
@@ -114,7 +115,7 @@ void TestCAO::addToScene(scene::ISceneManager *smgr)
 	buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
 	buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
 	buf->getMaterial().setTexture
-			(0, driver->getTexture(porting::getDataPath("rat.png").c_str()));
+			(0, driver->getTexture(getTexturePath("rat.png").c_str()));
 	buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
 	buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
 	buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
@@ -237,7 +238,7 @@ void ItemCAO::addToScene(scene::ISceneManager *smgr)
 	//buf->getMaterial().setTexture(0, NULL);
 	// Initialize with the stick texture
 	buf->getMaterial().setTexture
-			(0, driver->getTexture(porting::getDataPath("stick.png").c_str()));
+			(0, driver->getTexture(getTexturePath("stick.png").c_str()));
 	buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
 	buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
 	buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
@@ -443,7 +444,7 @@ void RatCAO::addToScene(scene::ISceneManager *smgr)
 	buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
 	//buf->getMaterial().setTexture(0, NULL);
 	buf->getMaterial().setTexture
-			(0, driver->getTexture(porting::getDataPath("rat.png").c_str()));
+			(0, driver->getTexture(getTexturePath("rat.png").c_str()));
 	buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
 	buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
 	buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
@@ -604,7 +605,7 @@ void Oerkki1CAO::addToScene(scene::ISceneManager *smgr)
 	buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
 	//buf->getMaterial().setTexture(0, NULL);
 	buf->getMaterial().setTexture
-			(0, driver->getTexture(porting::getDataPath("oerkki1.png").c_str()));
+			(0, driver->getTexture(getTexturePath("oerkki1.png").c_str()));
 	buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
 	buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
 	buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
diff --git a/src/game.cpp b/src/game.cpp
index 69e673fa4..b1a804ae3 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -345,7 +345,7 @@ void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
 	*/
 	{
 		video::ITexture *heart_texture =
-				driver->getTexture(porting::getDataPath("heart.png").c_str());
+				driver->getTexture(getTexturePath("heart.png").c_str());
 		v2s32 p = pos + v2s32(0, -20);
 		for(s32 i=0; i<halfheartcount/2; i++)
 		{
@@ -597,32 +597,32 @@ void update_skybox(video::IVideoDriver* driver,
 	if(brightness >= 0.5)
 	{
 		skybox = smgr->addSkyBoxSceneNode(
-			driver->getTexture(porting::getDataPath("skybox2.png").c_str()),
-			driver->getTexture(porting::getDataPath("skybox3.png").c_str()),
-			driver->getTexture(porting::getDataPath("skybox1.png").c_str()),
-			driver->getTexture(porting::getDataPath("skybox1.png").c_str()),
-			driver->getTexture(porting::getDataPath("skybox1.png").c_str()),
-			driver->getTexture(porting::getDataPath("skybox1.png").c_str()));
+			driver->getTexture(getTexturePath("skybox2.png").c_str()),
+			driver->getTexture(getTexturePath("skybox3.png").c_str()),
+			driver->getTexture(getTexturePath("skybox1.png").c_str()),
+			driver->getTexture(getTexturePath("skybox1.png").c_str()),
+			driver->getTexture(getTexturePath("skybox1.png").c_str()),
+			driver->getTexture(getTexturePath("skybox1.png").c_str()));
 	}
 	else if(brightness >= 0.2)
 	{
 		skybox = smgr->addSkyBoxSceneNode(
-			driver->getTexture(porting::getDataPath("skybox2_dawn.png").c_str()),
-			driver->getTexture(porting::getDataPath("skybox3_dawn.png").c_str()),
-			driver->getTexture(porting::getDataPath("skybox1_dawn.png").c_str()),
-			driver->getTexture(porting::getDataPath("skybox1_dawn.png").c_str()),
-			driver->getTexture(porting::getDataPath("skybox1_dawn.png").c_str()),
-			driver->getTexture(porting::getDataPath("skybox1_dawn.png").c_str()));
+			driver->getTexture(getTexturePath("skybox2_dawn.png").c_str()),
+			driver->getTexture(getTexturePath("skybox3_dawn.png").c_str()),
+			driver->getTexture(getTexturePath("skybox1_dawn.png").c_str()),
+			driver->getTexture(getTexturePath("skybox1_dawn.png").c_str()),
+			driver->getTexture(getTexturePath("skybox1_dawn.png").c_str()),
+			driver->getTexture(getTexturePath("skybox1_dawn.png").c_str()));
 	}
 	else
 	{
 		skybox = smgr->addSkyBoxSceneNode(
-			driver->getTexture(porting::getDataPath("skybox2_night.png").c_str()),
-			driver->getTexture(porting::getDataPath("skybox3_night.png").c_str()),
-			driver->getTexture(porting::getDataPath("skybox1_night.png").c_str()),
-			driver->getTexture(porting::getDataPath("skybox1_night.png").c_str()),
-			driver->getTexture(porting::getDataPath("skybox1_night.png").c_str()),
-			driver->getTexture(porting::getDataPath("skybox1_night.png").c_str()));
+			driver->getTexture(getTexturePath("skybox2_night.png").c_str()),
+			driver->getTexture(getTexturePath("skybox3_night.png").c_str()),
+			driver->getTexture(getTexturePath("skybox1_night.png").c_str()),
+			driver->getTexture(getTexturePath("skybox1_night.png").c_str()),
+			driver->getTexture(getTexturePath("skybox1_night.png").c_str()),
+			driver->getTexture(getTexturePath("skybox1_night.png").c_str()));
 	}
 }
 
diff --git a/src/main.cpp b/src/main.cpp
index 184643b9f..7b33bdb84 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -913,7 +913,7 @@ void drawMenuBackground(video::IVideoDriver* driver)
 	core::dimension2d<u32> screensize = driver->getScreenSize();
 		
 	video::ITexture *bgtexture =
-			driver->getTexture(porting::getDataPath("mud.png").c_str());
+			driver->getTexture(getTexturePath("mud.png").c_str());
 	if(bgtexture)
 	{
 		s32 texturesize = 128;
@@ -933,7 +933,7 @@ void drawMenuBackground(video::IVideoDriver* driver)
 	}
 	
 	video::ITexture *logotexture =
-			driver->getTexture(porting::getDataPath("menulogo.png").c_str());
+			driver->getTexture(getTexturePath("menulogo.png").c_str());
 	if(logotexture)
 	{
 		v2s32 logosize(logotexture->getOriginalSize().Width,
@@ -1288,7 +1288,7 @@ int main(int argc, char *argv[])
 
 	guienv = device->getGUIEnvironment();
 	gui::IGUISkin* skin = guienv->getSkin();
-	gui::IGUIFont* font = guienv->getFont(porting::getDataPath("fontlucida.png").c_str());
+	gui::IGUIFont* font = guienv->getFont(getTexturePath("fontlucida.png").c_str());
 	if(font)
 		skin->setFont(font);
 	else
diff --git a/src/mapblockobject.cpp b/src/mapblockobject.cpp
index d05eee808..009163a18 100644
--- a/src/mapblockobject.cpp
+++ b/src/mapblockobject.cpp
@@ -283,7 +283,7 @@ void RatObject::addToScene(scene::ISceneManager *smgr)
 	buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
 	buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
 	buf->getMaterial().setTexture
-			(0, driver->getTexture(porting::getDataPath("rat.png").c_str()));
+			(0, driver->getTexture(getTexturePath("rat.png").c_str()));
 	buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
 	buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
 	buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
@@ -413,7 +413,7 @@ void PlayerObject::addToScene(scene::ISceneManager *smgr)
 	// Set material
 	buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
 	//buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
-	buf->getMaterial().setTexture(0, driver->getTexture(porting::getDataPath("player.png").c_str()));
+	buf->getMaterial().setTexture(0, driver->getTexture(getTexturePath("player.png").c_str()));
 	buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
 	buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
 	//buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
@@ -437,7 +437,7 @@ void PlayerObject::addToScene(scene::ISceneManager *smgr)
 	// Set material
 	buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
 	//buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
-	buf->getMaterial().setTexture(0, driver->getTexture(porting::getDataPath("player_back.png").c_str()));
+	buf->getMaterial().setTexture(0, driver->getTexture(getTexturePath("player_back.png").c_str()));
 	buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
 	buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
 	buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
diff --git a/src/mapblockobject.h b/src/mapblockobject.h
index db8006fd9..804494715 100644
--- a/src/mapblockobject.h
+++ b/src/mapblockobject.h
@@ -432,7 +432,7 @@ class SignObject : public MapBlockObject
 		buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
 		//buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
 		buf->getMaterial().setTexture
-				(0, driver->getTexture(porting::getDataPath("sign.png").c_str()));
+				(0, driver->getTexture(getTexturePath("sign.png").c_str()));
 		buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
 		buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
 		buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
@@ -456,7 +456,7 @@ class SignObject : public MapBlockObject
 		buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
 		//buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
 		buf->getMaterial().setTexture
-				(0, driver->getTexture(porting::getDataPath("sign_back.png").c_str()));
+				(0, driver->getTexture(getTexturePath("sign_back.png").c_str()));
 		buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
 		buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
 		buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
diff --git a/src/mineral.cpp b/src/mineral.cpp
index e61c25c1e..038251fa3 100644
--- a/src/mineral.cpp
+++ b/src/mineral.cpp
@@ -27,7 +27,6 @@ const char *mineral_filenames[MINERAL_COUNT] =
 	"mineral_iron.png"
 };
 
-//textureid_t mineral_textures[MINERAL_COUNT] = {0};
 std::string mineral_textures[MINERAL_COUNT];
 
 void init_mineral()
@@ -40,7 +39,6 @@ void init_mineral()
 	}
 }
 
-//textureid_t mineral_block_texture(u8 mineral)
 std::string mineral_block_texture(u8 mineral)
 {
 	if(mineral >= MINERAL_COUNT)
diff --git a/src/mineral.h b/src/mineral.h
index fcc1bd123..970ff1f78 100644
--- a/src/mineral.h
+++ b/src/mineral.h
@@ -21,7 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define MINERAL_HEADER
 
 #include "inventory.h"
-#include "texture.h"
+#include "tile.h"
 
 /*
 	Minerals
@@ -39,7 +39,6 @@ void init_mineral();
 
 #define MINERAL_COUNT 3
 
-//textureid_t mineral_block_texture(u8 mineral);
 std::string mineral_block_texture(u8 mineral);
 
 inline CraftItem * getDiggedMineralItem(u8 mineral)
diff --git a/src/player.cpp b/src/player.cpp
index 539244709..12f18de75 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -261,7 +261,7 @@ RemotePlayer::RemotePlayer(
 		// Set material
 		buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
 		//buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
-		buf->getMaterial().setTexture(0, driver->getTexture(porting::getDataPath("player.png").c_str()));
+		buf->getMaterial().setTexture(0, driver->getTexture(getTexturePath("player.png").c_str()));
 		buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
 		buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
 		//buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
@@ -285,7 +285,7 @@ RemotePlayer::RemotePlayer(
 		// Set material
 		buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
 		//buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
-		buf->getMaterial().setTexture(0, driver->getTexture(porting::getDataPath("player_back.png").c_str()));
+		buf->getMaterial().setTexture(0, driver->getTexture(getTexturePath("player_back.png").c_str()));
 		buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
 		buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
 		buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
diff --git a/src/texture.h b/src/texture.h
deleted file mode 100644
index d8310789d..000000000
--- a/src/texture.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
-Minetest-c55
-Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program; if not, write to the Free Software Foundation, Inc.,
-51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-
-#ifndef TEXTURE_HEADER
-#define TEXTURE_HEADER
-
-// This file now contains all that was here
-#include "tile.h"
-
-// TODO: Remove this
-typedef u16 textureid_t;
-
-#if 0
-
-#include "common_irrlicht.h"
-//#include "utility.h"
-#include "debug.h"
-
-/*
-	All textures are given a "texture id".
-	0 = nothing (a NULL pointer texture)
-*/
-typedef u16 textureid_t;
-
-/*
-	Every texture in the game can be specified by this.
-	
-	It exists instead of specification strings because arbitary
-	texture combinations for map nodes are handled using this,
-	and strings are too slow for that purpose.
-
-	Plain texture pointers are not used because they don't contain
-	content information by themselves. A texture can be completely
-	reconstructed by just looking at this, while this also is a
-	fast unique key to containers.
-*/
-
-#define TEXTURE_SPEC_TEXTURE_COUNT 4
-
-struct TextureSpec
-{
-	TextureSpec()
-	{
-		clear();
-	}
-
-	TextureSpec(textureid_t id0)
-	{
-		clear();
-		tids[0] = id0;
-	}
-
-	TextureSpec(textureid_t id0, textureid_t id1)
-	{
-		clear();
-		tids[0] = id0;
-		tids[1] = id1;
-	}
-
-	void clear()
-	{
-		for(u32 i=0; i<TEXTURE_SPEC_TEXTURE_COUNT; i++)
-		{
-			tids[i] = 0;
-		}
-	}
-
-	bool empty() const
-	{
-		for(u32 i=0; i<TEXTURE_SPEC_TEXTURE_COUNT; i++)
-		{
-			if(tids[i] != 0)
-				return false;
-		}
-		return true;
-	}
-
-	void addTid(textureid_t tid)
-	{
-		for(u32 i=0; i<TEXTURE_SPEC_TEXTURE_COUNT; i++)
-		{
-			if(tids[i] == 0)
-			{
-				tids[i] = tid;
-				return;
-			}
-		}
-		// Too many textures
-		assert(0);
-	}
-
-	bool operator==(const TextureSpec &other) const
-	{
-		for(u32 i=0; i<TEXTURE_SPEC_TEXTURE_COUNT; i++)
-		{
-			if(tids[i] != other.tids[i])
-				return false;
-		}
-		return true;
-	}
-
-	bool operator<(const TextureSpec &other) const
-	{
-		for(u32 i=0; i<TEXTURE_SPEC_TEXTURE_COUNT; i++)
-		{
-			if(tids[i] >= other.tids[i])
-				return false;
-		}
-		return true;
-	}
-
-	// Ids of textures. They are blit on each other.
-	textureid_t tids[TEXTURE_SPEC_TEXTURE_COUNT];
-};
-
-#endif
-
-#endif
diff --git a/src/tile.cpp b/src/tile.cpp
index 5b89c6932..dabc1dcf3 100644
--- a/src/tile.cpp
+++ b/src/tile.cpp
@@ -1,6 +1,6 @@
 /*
 Minetest-c55
-Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -21,6 +21,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "debug.h"
 #include "main.h" // for g_settings
 #include "filesys.h"
+#include "utility.h"
+
+/*
+	A cache from texture name to texture path
+*/
+MutexedMap<std::string, std::string> g_texturename_to_path_cache;
 
 /*
 	Replaces the filename extension.
@@ -30,7 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 		-> image = "a/image.jpg"
 	Returns true on success.
 */
-inline bool replace_ext(std::string &path, const char *ext)
+static bool replace_ext(std::string &path, const char *ext)
 {
 	if(ext == NULL)
 		return false;
@@ -61,7 +67,7 @@ inline bool replace_ext(std::string &path, const char *ext)
 
 	If failed, return "".
 */
-inline std::string getImagePath(std::string path)
+static std::string getImagePath(std::string path)
 {
 	// A NULL-ended list of possible image extensions
 	const char *extensions[] = {
@@ -86,25 +92,55 @@ inline std::string getImagePath(std::string path)
 /*
 	Gets the path to a texture by first checking if the texture exists
 	in texture_path and if not, using the data path.
+
+	Checks all supported extensions by replacing the original extension.
+
+	If not found, returns "".
+
+	Utilizes a thread-safe cache.
 */
-inline std::string getTexturePath(std::string filename)
+std::string getTexturePath(const std::string &filename)
 {
+	std::string fullpath = "";
+	/*
+		Check from cache
+	*/
+	bool incache = g_texturename_to_path_cache.get(filename, &fullpath);
+	if(incache)
+		return fullpath;
+	
+	/*
+		Check from texture_path
+	*/
 	std::string texture_path = g_settings.get("texture_path");
 	if(texture_path != "")
 	{
-		std::string fullpath = texture_path + '/' + filename;
-		// Check all filename extensions
-		fullpath = getImagePath(fullpath);
-		// If found, return it
-		if(fullpath != "")
-			return fullpath;
+		std::string testpath = texture_path + '/' + filename;
+		// Check all filename extensions. Returns "" if not found.
+		fullpath = getImagePath(testpath);
 	}
-	std::string fullpath = porting::getDataPath(filename.c_str());
-	// Check all filename extensions
-	fullpath = getImagePath(fullpath);
+	
+	/*
+		Check from default data directory
+	*/
+	if(fullpath == "")
+	{
+		std::string testpath = porting::getDataPath(filename.c_str());
+		// Check all filename extensions. Returns "" if not found.
+		fullpath = getImagePath(testpath);
+	}
+	
+	// Add to cache (also an empty result is cached)
+	g_texturename_to_path_cache.set(filename, fullpath);
+	
+	// Finally return it
 	return fullpath;
 }
 
+/*
+	TextureSource
+*/
+
 TextureSource::TextureSource(IrrlichtDevice *device):
 		m_device(device),
 		m_main_atlas_image(NULL),
diff --git a/src/tile.h b/src/tile.h
index f06285960..216d76508 100644
--- a/src/tile.h
+++ b/src/tile.h
@@ -1,6 +1,6 @@
 /*
 Minetest-c55
-Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -25,6 +25,22 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "utility.h"
 #include <string>
 
+/*
+	tile.{h,cpp}: Texture handling stuff.
+*/
+
+/*
+	Gets the path to a texture by first checking if the texture exists
+	in texture_path and if not, using the data path.
+
+	Checks all supported extensions by replacing the original extension.
+
+	If not found, returns "".
+
+	Utilizes a thread-safe cache.
+*/
+std::string getTexturePath(const std::string &filename);
+
 /*
 	Specifies a texture in an atlas.
 
diff --git a/src/utility.h b/src/utility.h
index 84838c0c7..cc8891a07 100644
--- a/src/utility.h
+++ b/src/utility.h
@@ -1766,12 +1766,12 @@ class UniqueQueue
 	core::list<Value> m_list;
 };
 
-#if 0
+#if 1
 template<typename Key, typename Value>
-class MutexedCache
+class MutexedMap
 {
 public:
-	MutexedCache()
+	MutexedMap()
 	{
 		m_mutex.Init();
 		assert(m_mutex.IsInitialized());
@@ -1793,8 +1793,10 @@ class MutexedCache
 
 		if(n == NULL)
 			return false;
-
-		*result = n->getValue();
+		
+		if(result != NULL)
+			*result = n->getValue();
+			
 		return true;
 	}
 
-- 
GitLab