Browse Source

Refactoring

Panagiotis Christopoulos Charitos 11 years ago
parent
commit
8fbb3c18b7

+ 2 - 2
include/anki/core/App.h

@@ -50,12 +50,12 @@ public:
 		m_timerTick = x;
 	}
 
-	const String& getSettingsPath() const
+	const String& getSettingsDirectory() const
 	{
 		return m_settingsPath;
 	}
 
-	const String& getCachePath() const
+	const String& getCacheDirectory() const
 	{
 		return m_cachePath;
 	}

+ 4 - 4
include/anki/gl/GlCommon.h

@@ -116,9 +116,9 @@ public:
 		return m_type;
 	}
 
-	const char* getName() const
+	CString getName() const
 	{
-		return &m_name[0];
+		return CString(&m_name[0]);
 	}
 
 	GLenum getDataType() const
@@ -241,9 +241,9 @@ public:
 		return m_size;
 	}
 
-	const char* getName() const
+	CString getName() const
 	{
-		return &m_name[0];
+		return CString(&m_name[0]);
 	}
 
 	U32 getBinding() const

+ 2 - 2
include/anki/gl/GlDevice.h

@@ -25,7 +25,7 @@ public:
 		GlCallback swapBuffersCallback, void* swapBuffersCbData,
 		Bool registerDebugMessages,
 		AllocAlignedCallback alloc, void* allocUserData,
-		const char* cacheDir);
+		const CString& cacheDir);
 
 	~GlDevice()
 	{
@@ -58,7 +58,7 @@ public:
 		return *m_queue;
 	}
 
-	const char* _getCacheDirectory() const
+	CString _getCacheDirectory() const
 	{
 		ANKI_ASSERT(m_cacheDir != nullptr);
 		return m_cacheDir;

+ 11 - 11
include/anki/gl/GlProgram.h

@@ -27,7 +27,7 @@ public:
 
 	template<typename T>
 	using ProgramDictionary = 
-		Dictionary<T, GlGlobalHeapAllocator<std::pair<const char*, T>>>;
+		Dictionary<T, GlGlobalHeapAllocator<std::pair<CString, T>>>;
 
 	GlProgramData(const GlGlobalHeapAllocator<U8>& alloc)
 	:	m_variables(alloc), 
@@ -87,9 +87,9 @@ public:
 	/// @param alloc The allocator to be used for internally
 	GlProgram(
 		GLenum shaderType, 
-		const char* source, 
+		const CString& source, 
 		const GlGlobalHeapAllocator<U8>& alloc, 
-		const char* cacheDir)
+		const CString& cacheDir)
 	:	m_data(nullptr)
 	{
 		create(shaderType, source, alloc, cacheDir);
@@ -122,20 +122,20 @@ public:
 		return m_data->m_blocks;
 	}
 
-	const GlProgramVariable& findVariable(const char* name) const;
-	const GlProgramBlock& findBlock(const char* name) const;
+	const GlProgramVariable& findVariable(const CString& name) const;
+	const GlProgramBlock& findBlock(const CString& name) const;
 
-	const GlProgramVariable* tryFindVariable(const char* name) const;
-	const GlProgramBlock* tryFindBlock(const char* name) const;
+	const GlProgramVariable* tryFindVariable(const CString& name) const;
+	const GlProgramBlock* tryFindBlock(const CString& name) const;
 
 private:
 	GLenum m_type;
 	GlProgramData* m_data;
 
-	void create(GLenum type, const char* source, 
-		const GlGlobalHeapAllocator<U8>& alloc, const char* cacheDir);
-	void createInternal(GLenum type, const char* source, 
-		const GlGlobalHeapAllocator<U8>& alloc, const char* cacheDir);
+	void create(GLenum type, const CString& source, 
+		const GlGlobalHeapAllocator<U8>& alloc, const CString& cacheDir);
+	void createInternal(GLenum type, const CString& source, 
+		const GlGlobalHeapAllocator<U8>& alloc, const CString& cacheDir);
 	void destroy();
 
 	/// Query the program for blocks

+ 4 - 4
include/anki/gl/GlProgramHandle.h

@@ -48,13 +48,13 @@ public:
 
 	const ProgramVector<GlProgramBlock>& getBlocks() const;
 
-	const GlProgramVariable& findVariable(const char* name) const;
+	const GlProgramVariable& findVariable(const CString& name) const;
 
-	const GlProgramBlock& findBlock(const char* name) const;
+	const GlProgramBlock& findBlock(const CString& name) const;
 
-	const GlProgramVariable* tryFindVariable(const char* name) const;
+	const GlProgramVariable* tryFindVariable(const CString& name) const;
 
-	const GlProgramBlock* tryFindBlock(const char* name) const;
+	const GlProgramBlock* tryFindBlock(const CString& name) const;
 	/// @}
 };
 

+ 9 - 1
include/anki/misc/Xml.h

@@ -48,7 +48,15 @@ public:
 	CString getText() const
 	{
 		check();
-		return CString(m_el->GetText());
+
+		if(m_el->GetText())
+		{
+			return CString(m_el->GetText());
+		}
+		else
+		{
+			return CString();
+		}
 	}
 
 	/// Return the text inside as an int

+ 2 - 5
include/anki/resource/Common.h

@@ -41,18 +41,15 @@ class ResourceInitializer
 public:
 	ResourceAllocator<U8>& m_alloc;
 	TempResourceAllocator<U8>& m_tempAlloc;
-	GlDevice& m_gl;
-	ResourceManager& m_resourceManager;
+	ResourceManager& m_resources;
 
 	ResourceInitializer(
 		ResourceAllocator<U8>& alloc, 
 		TempResourceAllocator<U8>& tempAlloc,
-		GlDevice& gl,
 		ResourceManager& resourceManager)
 	:	m_alloc(alloc),
 		m_tempAlloc(tempAlloc),
-		m_gl(gl),
-		m_resourceManager(resourceManager)
+		m_resources(resourceManager)
 	{}
 };
 

+ 11 - 8
include/anki/resource/Material.h

@@ -6,14 +6,13 @@
 #ifndef ANKI_RESOURCE_MATERIAL_H
 #define ANKI_RESOURCE_MATERIAL_H
 
-#include "anki/resource/Resource.h"
+#include "anki/resource/ResourceManager.h"
 #include "anki/resource/ProgramResource.h"
 #include "anki/resource/RenderingKey.h"
 #include "anki/Math.h"
 #include "anki/util/Visitor.h"
 #include "anki/util/Dictionary.h"
 #include "anki/util/NonCopyable.h"
-#include <memory>
 
 namespace anki {
 
@@ -84,7 +83,7 @@ public:
 	}
 
 	/// Get the name of all the shader program variables
-	const char* getName() const;
+	CString getName() const;
 
 	/// If false then it should be buildin
 	virtual Bool hasValues() const = 0;
@@ -333,14 +332,14 @@ public:
 	GlProgramPipelineHandle getProgramPipeline(const RenderingKey& key);
 
 	/// Get by name
-	const MaterialVariable* findVariableByName(const char* name) const
+	const MaterialVariable* findVariableByName(const CString& name) const
 	{
 		auto it = m_varDict.find(name);
 		return (it == m_varDict.end()) ? nullptr : it->second;
 	}
 
 	/// Load a material file
-	void load(const char* filename);
+	void load(const CString& filename, ResourceInitializer& init);
 
 	/// For sorting
 	Bool operator<(const Material& b) const
@@ -349,6 +348,9 @@ public:
 	}
 
 private:
+	/// Keep it to have access to some stuff at runtime
+	ResourceManager* m_resources = nullptr; 
+		
 	ResourceVector<MaterialVariable*> m_vars;
 	Dictionary<MaterialVariable*> m_varDict;
 
@@ -358,16 +360,17 @@ private:
 	U32 m_shaderBlockSize;
 
 	/// Used for sorting
-	PtrSize m_hash;
+	U64 m_hash;
 
 	/// Get a program resource
 	ProgramResourcePointer& getProgram(const RenderingKey key, U32 shaderId);
 
 	/// Parse what is within the @code <material></material> @endcode
-	void parseMaterialTag(const XmlElement& el);
+	void parseMaterialTag(const XmlElement& el, ResourceInitializer& rinit);
 
 	/// Create a unique shader source in chache. If already exists do nothing
-	std::string createProgramSourceToChache(const std::string& source);
+	TempResourceString createProgramSourceToChache(
+		const TempResourceString& source);
 
 	/// Read all shader programs and pupulate the @a vars and @a nameToVar
 	/// containers

+ 3 - 3
include/anki/resource/MaterialProgramCreator.h

@@ -25,8 +25,8 @@ class XmlElement;
 class MaterialProgramCreator
 {
 public:
-	using MPString = BasicString<char, TempResourceAllocator<char>>; 
-	using MPStringList = BasicStringList<char, TempResourceAllocator<char>>; 
+	using MPString = TempResourceString; 
+	using MPStringList = BasicStringList<TempResourceAllocator<char>>; 
 
 	class Input
 	{
@@ -60,7 +60,7 @@ public:
 	MPString getProgramSource(U shaderType) const
 	{
 		ANKI_ASSERT(m_source[shaderType].size() > 0);
-		return m_source[shaderType].join("\n");
+		return m_source[shaderType].join(CString("\n"));
 	}
 
 	const TempResourceVector<Input>& getInputVariables() const

+ 1 - 1
include/anki/resource/ParticleEmitterResource.h

@@ -110,7 +110,7 @@ public:
 	}
 
 	/// Load it
-	void load(const char* filename);
+	void load(const CString& filename, );
 
 private:
 	MaterialResourcePointer m_material;

+ 1 - 1
include/anki/resource/ProgramPrePreprocessor.h

@@ -58,7 +58,7 @@ public:
 
 	/// @name Accessors
 	/// @{
-	const PPPString& getShaderSource()
+	const PPPString& getShaderSource() const
 	{
 		ANKI_ASSERT(!m_shaderSource.isEmpty());
 		return m_shaderSource;

+ 0 - 1
include/anki/resource/Resource.h

@@ -8,7 +8,6 @@
 
 #include "anki/resource/ResourceManager.h"
 #include "anki/resource/ResourcePointer.h"
-#include "anki/util/Singleton.h"
 
 namespace anki {
 

+ 7 - 1
include/anki/resource/ResourceManager.h

@@ -17,6 +17,7 @@ namespace anki {
 // Forward
 class ConfigSet;
 class App;
+class GlDevice;
 
 class Animation;
 class Material;
@@ -98,7 +99,7 @@ private:
 		
 		for(it = m_ptrs.begin(); it != m_ptrs.end(); ++it)
 		{
-			if(std::strcmp(it->getResourceName(), filename) == 0)
+			if(it->getResourceName() == filename)
 			{
 				break;
 			}
@@ -156,6 +157,11 @@ public:
 		return *m_app;
 	}
 
+	GlDevice& _getGlDevice();
+
+	/// For materials
+	CString _getShaderPostProcessorString() const;
+
 	template<typename T>
 	Bool _findLoadedResource(const CString& filename, 
 		ResourcePointer<T, ResourceManager>& ptr)

+ 7 - 7
include/anki/resource/ResourcePointer.h

@@ -7,7 +7,7 @@
 #define ANKI_RESOURCE_RESOURCE_POINTER_H
 
 #include "anki/util/Assert.h"
-#include <atomic>
+#include "anki/util/Atomic.h"
 #include <cstring>
 
 namespace anki {
@@ -45,9 +45,9 @@ public:
 	}
 
 	/// Construct and load
-	ResourcePointer(const CString& filename)
+	ResourcePointer(const CString& filename, TResourceManager* resources)
 	{
-		load(filename);
+		load(filename, resources);
 	}
 
 	~ResourcePointer()
@@ -91,7 +91,7 @@ public:
 		return &m_cb->m_resource;
 	}
 
-	const char* getResourceName() const
+	CString getResourceName() const
 	{
 		ANKI_ASSERT(m_cb != nullptr);
 		return &m_cb->m_uuid[0];
@@ -100,7 +100,7 @@ public:
 	U32 getReferenceCount() const
 	{
 		ANKI_ASSERT(m_cb != nullptr);
-		return &m_cb->m_refcount.load();
+		return m_cb->m_refcount.load();
 	}
 	
 	/// Copy
@@ -126,7 +126,7 @@ public:
 	}
 
 	/// Load the resource using the resource manager
-	void load(const char* filename, TResourceManager* resources);
+	void load(const CString& filename, TResourceManager* resources);
 
 	Bool isLoaded() const
 	{
@@ -139,7 +139,7 @@ private:
 	{
 	public:
 		Type m_resource;
-		std::atomic<U32> m_refcount = {1};
+		AtomicU32 m_refcount = {1};
 		TResourceManager* m_resources = nullptr;
 		char m_uuid[1]; ///< This is part of the UUID
 	};

+ 12 - 7
include/anki/resource/ResourcePointer.inl.h

@@ -10,10 +10,9 @@ namespace anki {
 //==============================================================================
 template<typename T, typename TResourceManager>
 void ResourcePointer<T, TResourceManager>::load(
-	const char* filename, TResourceManager* resources)
+	const CString& filename, TResourceManager* resources)
 {
 	ANKI_ASSERT(m_cb == nullptr);
-	ANKI_ASSERT(filename != nullptr);
 	ANKI_ASSERT(resources != nullptr);
 
 	ResourcePointer other;
@@ -22,16 +21,22 @@ void ResourcePointer<T, TResourceManager>::load(
 	if(!found)
 	{
 		// Allocate m_cb
-		U len = std::strlen(filename);
+		U len = filename.getLength();
 		PtrSize alignment = alignof(ControlBlock);
-		m_cb = resources->_getAllocator().allocate(
-			sizeof(ControlBlock) + len, &alignment);
+		m_cb = reinterpret_cast<ControlBlock*>(
+			resources->_getAllocator().allocate(
+			sizeof(ControlBlock) + len, &alignment));
 		resources->_getAllocator().construct(m_cb);
 
 		// Populate the m_cb
 		try
 		{
-			m_cb->m_resource.load(filename);
+			ResourceInitializer init(
+				resources->_getAllocator(),
+				resources->_getTempAllocator(),
+				*resources);
+
+			m_cb->m_resource.load(filename, init);
 		}
 		catch(const std::exception& e)
 		{
@@ -39,7 +44,7 @@ void ResourcePointer<T, TResourceManager>::load(
 		}
 
 		m_cb->m_resources = resources;
-		std::memcpy(&m_cb->m_uuid[0], filename, len + 1);
+		std::memcpy(&m_cb->m_uuid[0], &filename[0], len + 1);
 
 		// Register resource
 		resources->_registerResource(*this);

+ 2 - 2
include/anki/resource/TextureResource.h

@@ -25,7 +25,7 @@ class TextureResource
 {
 public:
 	/// Load a texture
-	void load(const char* filename, ResourceInitializer& init);
+	void load(const CString& filename, ResourceInitializer& init);
 
 	/// Get the GL texture
 	const GlTextureHandle& getGlTexture() const
@@ -43,7 +43,7 @@ private:
 	GlTextureHandle m_tex;
 
 	/// Load a texture
-	void loadInternal(const char* filename, ResourceInitializer& init);
+	void loadInternal(const CString& filename, ResourceInitializer& init);
 };
 /// @}
 

+ 4 - 0
include/anki/util/Atomic.h

@@ -9,6 +9,8 @@
 #include "anki/util/StdTypes.h"
 #include <atomic>
 
+namespace anki {
+
 /// @addtogroup util_other
 /// @{
 
@@ -22,5 +24,7 @@ using AtomicU64 = std::atomic<U64>;
 
 /// @}
 
+} // end namespace anki
+
 #endif
 

+ 2 - 2
include/anki/util/Dictionary.h

@@ -46,14 +46,14 @@ public:
 /// Its template struct because C++ does not offer template typedefs
 template<
 	typename T, 
-	template <typename> class TAlloc = HeapAllocator>
+	typename TAlloc = HeapAllocator<std::pair<CString, T>>>
 using Dictionary = 
 	std::unordered_map<
 		CString,
 		T,
 		DictionaryHasher,
 		DictionaryEqual,
-		TAlloc<std::pair<CString, T>>>;
+		TAlloc>;
 
 /// @}
 

+ 1 - 1
include/anki/util/File.h

@@ -112,7 +112,7 @@ public:
 	void write(void* buff, PtrSize size);
 
 	/// Write formated text
-	void writeText(const CString& format, ...);
+	void writeText(CString format, ...);
 
 	/// Set the position indicator to a new position
 	/// @param offset Number of bytes to offset from origin

+ 24 - 0
include/anki/util/Hash.h

@@ -0,0 +1,24 @@
+// Copyright (C) 2014, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include "anki/util/StdTypes.h"
+
+namespace anki {
+
+/// @addtogroup util_other
+/// @{
+
+/// Computes a hash of a buffer.
+/// This function implements the MurmurHash2 algorithm by Austin Appleby.
+/// @param[in] buffer The buffer to hash.
+/// @param bufferSize The size of the buffer.
+/// @param seed A unique seed.
+/// @return The hash.
+U64 computeHash(const void* buffer, U32 bufferSize, U64 seed = 123);
+
+/// @}
+
+} // end namespace anki
+

+ 104 - 19
include/anki/util/String.h

@@ -60,9 +60,17 @@ ANKI_DEPLOY_TO_STRING(F64, "%f")
 /// A wrapper on top of C strings. Used mainly for safety.
 class CString
 {
+	template<typename TAlloc>
+	friend class BasicString; // For the secret constructor
+
+	// For the secret constructor
+	friend CString operator"" _cstr(const char*, unsigned long); 
+
 public:
 	using Char = char;
 
+	static const PtrSize NPOS = MAX_PTR_SIZE;
+
 	CString() noexcept = default;
 
 	CString(const Char* ptr) noexcept
@@ -88,6 +96,12 @@ public:
 		return *this;
 	}
 
+	/// Return true if the string is initialized.
+	operator Bool() const noexcept
+	{
+		return !isEmpty();
+	}
+
 	/// Return char at the specified position.
 	const Char& operator[](U pos) const noexcept
 	{
@@ -108,6 +122,12 @@ public:
 		return &m_ptr[getLength()];
 	}
 
+	/// Return true if the string is not initialized.
+	Bool isEmpty() const noexcept
+	{
+		return m_ptr == nullptr;
+	}
+
 	/// Add with a BasicString.
 	template<typename TAlloc>
 	BasicString<TAlloc> operator+(const BasicString<TAlloc>& str) const;
@@ -166,6 +186,14 @@ public:
 		return m_length;
 	}
 
+	PtrSize find(const CString& cstr, PtrSize position = 0) const noexcept
+	{
+		checkInit();
+		ANKI_ASSERT(position < getLength());
+		const Char* out = std::strstr(m_ptr, &cstr[0]);
+		return (out == nullptr) ? NPOS : (out - m_ptr);
+	}
+
 	/// Convert to F64.
 	F64 toF64() const
 	{
@@ -198,13 +226,27 @@ private:
 	const Char* m_ptr = nullptr;
 	mutable U16 m_length = 0;
 
+	/// Constructor for friends
+	CString(const Char* ptr, U16 length) noexcept
+	:	m_ptr(ptr),
+		m_length(length)
+	{
+		checkInit();
+		ANKI_ASSERT(std::strlen(ptr) == length);
+	}
+
 	void checkInit() const noexcept
 	{
 		ANKI_ASSERT(m_ptr != nullptr);
-		ANKI_ASSERT(m_ptr[0] != '\0' && "Empty strings are not allowed");
 	}
 };
 
+/// User defined string literal for CStrings.
+CString operator"" _cstr(const char* str, unsigned long length)
+{
+	return CString(str, length);
+}
+
 /// The base class for strings.
 template<typename TAlloc>
 class BasicString
@@ -222,14 +264,12 @@ public:
 	BasicString() noexcept
 	{}
 
-	template<typename TTAlloc>
-	BasicString(TTAlloc& alloc) noexcept
+	BasicString(Allocator alloc) noexcept
 	:	m_data(alloc)
 	{}
 
 	/// Initialize using a const string.
-	template<typename TTAlloc>
-	BasicString(const CStringType& cstr, TTAlloc& alloc)
+	BasicString(const CStringType& cstr, Allocator alloc)
 	:	m_data(alloc)
 	{
 		auto size = cstr.getLength() + 1;
@@ -238,8 +278,7 @@ public:
 	}
 
 	/// Initialize using a range. Copies the range of [first, last)
-	template<typename TTAlloc>
-	BasicString(ConstIterator first, ConstIterator last, TTAlloc& alloc)
+	BasicString(ConstIterator first, ConstIterator last, Allocator alloc)
 	:	m_data(alloc)
 	{
 		ANKI_ASSERT(first != 0 && last != 0);
@@ -450,17 +489,55 @@ public:
 		return (size != 0) ? (size - 1) : 0;
 	}
 
+	/// Return the allocator
+	Allocator getAllocator() const noexcept
+	{
+		return m_data.get_allocator();
+	}
+
 	/// Return the CString.
 	CStringType toCString() const noexcept
 	{
 		checkInit();
-		return CStringType(&m_data[0]);
+		return CStringType(&m_data[0], getLength());
 	}
 
-	/// Return the allocator
-	Allocator getAllocator() const noexcept
+	Self& sprintf(CString fmt, ...)
 	{
-		return m_data.get_allocator();
+		Array<Char, 512> buffer;
+		va_list args;
+		Char* out = &buffer[0];
+
+		va_start(args, fmt);
+		I len = std::vsnprintf(&buffer[0], sizeof(buffer), &fmt[0], args);
+		va_end(args);
+
+		if(len < 0)
+		{
+			throw ANKI_EXCEPTION("vsnprintf() failed");
+		}
+		else if(static_cast<PtrSize>(len) >= sizeof(buffer))
+		{
+			I size = len + 1;
+			out = reinterpret_cast<Char*>(getAllocator().allocate(size));
+
+			va_start(args, fmt);
+			len = std::vsnprintf(out, size, &fmt[0], args);
+			(void)len;
+			va_end(args);
+
+			ANKI_ASSERT(len < size);
+		}
+
+		*this = out;
+
+		// Delete the allocated memory
+		if(out != &buffer[0])
+		{
+			getAllocator().deallocate(out, 0);
+		}
+
+		return *this;
 	}
 
 	/// Clears the contents of the string and makes it empty.
@@ -516,9 +593,7 @@ public:
 	PtrSize find(const CStringType& cstr, PtrSize position = 0) const noexcept
 	{
 		checkInit();
-		ANKI_ASSERT(position < m_data.size() - 1);
-		const Char* out = std::strstr(&m_data[position], cstr.get());
-		return (out == nullptr) ? NPOS : (out - &m_data[0]);
+		return toString().find(cstr, position);
 	}
 
 	/// Find a substring of this string.
@@ -538,8 +613,8 @@ public:
 	/// @param number The number to convert.
 	/// @param[in,out] alloc The allocator to allocate the returned string.
 	/// @return The string that presents the number.
-	template<typename TNumber>
-	Self toString(TNumber number, Allocator& alloc)
+	template<typename TNumber, typename TTAlloc>
+	static Self toString(TNumber number, TTAlloc alloc)
 	{
 		Array<Char, 512> buff;
 		I ret = std::snprintf(
@@ -550,7 +625,8 @@ public:
 			throw ANKI_EXCEPTION("To small intermediate buffer");
 		}
 
-		return Self(alloc, CStringType(&buff[0]));
+		using YAlloc = typename TTAlloc::template rebind<Char>::other;
+		return BasicString<YAlloc>(&buff[0], alloc);
 	}
 
 	/// Convert to F64.
@@ -590,7 +666,7 @@ private:
 		std::memcpy(&m_data[size - 1], str, sizeof(Char) * strSize);
 	}
 
-	Self add(const Char* str, PtrSize strSize)
+	Self add(const Char* str, PtrSize strSize) const
 	{
 		checkInit();
 
@@ -613,10 +689,19 @@ inline BasicString<TAlloc> CString::operator+(
 	BasicString<TAlloc> out(str.getAllocator());
 
 	auto thisLength = getLength();
-	out.resize(thisLength + str.getLength() + 1);
+	out.resize(thisLength + str.getLength());
 
 	std::memcpy(&out[0], &m_ptr[0], thisLength);
 	std::memcpy(&out[thisLength], &str[0], str.getLength() + 1);
+
+	return out;
+}
+
+template<typename TAlloc>
+inline BasicString<TAlloc> operator+(
+	const CString& left, const BasicString<TAlloc>& right)
+{
+	return left.operator+(right);
 }
 
 /// A common string type that uses heap allocator.

+ 3 - 3
src/gl/GlDevice.cpp

@@ -15,14 +15,14 @@ GlDevice::GlDevice(
 	GlCallback swapBuffersCallback, void* swapBuffersCbData,
 	Bool registerDebugMessages,
 	AllocAlignedCallback alloc, void* allocUserData,
-	const char* cacheDir)
+	const CString& cacheDir)
 {
 	m_alloc = HeapAllocator<U8>(HeapMemoryPool(alloc, allocUserData));
 
 	// Allocate cache dir
-	I len = std::strlen(cacheDir);
+	auto len = cacheDir.getLength();
 	m_cacheDir = reinterpret_cast<char*>(m_alloc.allocate(len + 1));
-	std::memcpy(m_cacheDir, cacheDir, len + 1);
+	std::memcpy(m_cacheDir, &cacheDir[0], len + 1);
 
 	// Start the server
 	m_queue = m_alloc.newInstance<GlQueue>(

+ 35 - 30
src/gl/GlProgram.cpp

@@ -290,8 +290,8 @@ GlProgram& GlProgram::operator=(GlProgram&& b)
 }
 
 //==============================================================================
-void GlProgram::create(GLenum type, const char* source, 
-	const GlGlobalHeapAllocator<U8>& alloc, const char* cacheDir)
+void GlProgram::create(GLenum type, const CString& source, 
+	const GlGlobalHeapAllocator<U8>& alloc, const CString& cacheDir)
 {
 	try
 	{
@@ -305,8 +305,8 @@ void GlProgram::create(GLenum type, const char* source,
 }
 
 //==============================================================================
-void GlProgram::createInternal(GLenum type, const char* source, 
-	const GlGlobalHeapAllocator<U8>& alloc_, const char* cacheDir)
+void GlProgram::createInternal(GLenum type, const CString& source, 
+	const GlGlobalHeapAllocator<U8>& alloc_, const CString& cacheDir)
 {
 	ANKI_ASSERT(source);
 	ANKI_ASSERT(!isCreated() && m_data == nullptr);
@@ -325,13 +325,11 @@ void GlProgram::createInternal(GLenum type, const char* source,
 		version = major * 100 + minor * 10;
 	}
 
-	String fullSrc;
+	String fullSrc(alloc);
 #if ANKI_GL == ANKI_GL_DESKTOP
-	fullSrc = "#version " + std::to_string(version) + " core\n" 
-		+ String(source);
+	fullSrc.sprintf("#version %d core\n%s\n", version, &source[0]); 
 #else
-	fullSrc = "#version " + std::to_string(version) + " es\n"
-		+ String(source);
+	fullSrc.sprintf("#version %d es\n%s\n", version, &source[0]);
 #endif
 
 	// 2) Gen name, create, compile and link
@@ -378,7 +376,7 @@ void GlProgram::createInternal(GLenum type, const char* source,
 			<< std::setfill('0') << std::setw(4) << (U32)m_glName << ext;
 
 		File file(fname.str().c_str(), File::OpenFlag::WRITE);
-		file.writeText("%s", fullSrc.c_str());
+		file.writeText("%s", &fullSrc[0]);
 	}
 #endif
 	
@@ -389,7 +387,7 @@ void GlProgram::createInternal(GLenum type, const char* source,
 	{
 		GLint infoLen = 0;
 		GLint charsWritten = 0;
-		String infoLog;
+		String infoLog(alloc);
 
 		static const char* padding = 
 			"======================================="
@@ -400,23 +398,25 @@ void GlProgram::createInternal(GLenum type, const char* source,
 		infoLog.resize(infoLen + 1);
 		glGetProgramInfoLog(m_glName, infoLen, &charsWritten, &infoLog[0]);
 		
-		std::stringstream err;
-		err << "Shader compile failed (type:" << std::hex << m_type
-			<< std::dec << "):\n" << padding << "\n" << &infoLog[0]
-			<< "\n" << padding << "\nSource:\n" << padding << "\n";
+		String err(alloc);
+		err.sprintf("Shader compile failed (type %x):\n%s\n%s\n%s\n",
+			m_type, padding, &infoLog[0], padding);
 
 		// Prettyfy source
-		StringList lines = StringList::splitString(fullSrc.c_str(), '\n', true);
-		int lineno = 0;
+		StringList lines(
+			StringList::splitString(fullSrc.toCString(), '\n', alloc));
+		I lineno = 0;
 		for(const String& line : lines)
 		{
-			err << std::setw(4) << std::setfill('0') << ++lineno << ": "
-				<< line << "\n";
+			String tmp(alloc);
+			tmp.sprintf("%4d: %s\n", ++lineno, &line[0]);
+
+			err += tmp;
 		}
 
-		err << padding;
+		err += padding;
 
-		throw ANKI_EXCEPTION("%s", err.str().c_str());
+		throw ANKI_EXCEPTION("%s", &err[0]);
 	}
 
 	// 3) Populate with vars and blocks
@@ -459,14 +459,14 @@ void GlProgram::createInternal(GLenum type, const char* source,
 			}
 
 			// Recalc length after trimming
-			len = strlen(&name[0]);
+			len = std::strlen(&name[0]);
 
 			namesLen += (U)len + 1;
 			++count[i];
 		}
 	}
 
-	m_data->m_names = (char*)alloc.allocate(namesLen);
+	m_data->m_names = reinterpret_cast<char*>(alloc.allocate(namesLen));
 	char* namesPtr = m_data->m_names;
 
 	// Populate the blocks
@@ -495,7 +495,12 @@ void GlProgram::createInternal(GLenum type, const char* source,
 		// Sanity checks
 
 		// Iterate all samples and make sure they have set the unit explicitly
-		std::unordered_map<U, U> unitToCount;
+		std::unordered_map<
+			U, 
+			U, 
+			std::hash<U>,
+			std::equal_to<U>,
+			HeapAllocator<std::pair<U, U>>> unitToCount;
 		for(const GlProgramVariable& var : m_data->m_variables)
 		{
 			if(isSampler(var.m_dataType))
@@ -745,7 +750,7 @@ void GlProgram::initBlocksOfType(
 }
 
 //==============================================================================
-const GlProgramVariable* GlProgram::tryFindVariable(const char* name) const
+const GlProgramVariable* GlProgram::tryFindVariable(const CString& name) const
 {
 	ANKI_ASSERT(isCreated() && m_data);
 	auto it = m_data->m_variablesDict.find(name);
@@ -753,19 +758,19 @@ const GlProgramVariable* GlProgram::tryFindVariable(const char* name) const
 }
 
 //==============================================================================
-const GlProgramVariable& GlProgram::findVariable(const char* name) const
+const GlProgramVariable& GlProgram::findVariable(const CString& name) const
 {
 	ANKI_ASSERT(isCreated() && m_data);
 	const GlProgramVariable* var = tryFindVariable(name);
 	if(var == nullptr)
 	{
-		throw ANKI_EXCEPTION("Variable not found: %s", name);
+		throw ANKI_EXCEPTION("Variable not found: %s", &name[0]);
 	}
 	return *var;
 }
 
 //==============================================================================
-const GlProgramBlock* GlProgram::tryFindBlock(const char* name) const
+const GlProgramBlock* GlProgram::tryFindBlock(const CString& name) const
 {
 	ANKI_ASSERT(isCreated() && m_data);
 	auto it = m_data->m_blocksDict.find(name);
@@ -773,13 +778,13 @@ const GlProgramBlock* GlProgram::tryFindBlock(const char* name) const
 }
 
 //==============================================================================
-const GlProgramBlock& GlProgram::findBlock(const char* name) const
+const GlProgramBlock& GlProgram::findBlock(const CString& name) const
 {
 	ANKI_ASSERT(isCreated() && m_data);
 	const GlProgramBlock* var = tryFindBlock(name);
 	if(var == nullptr)
 	{
-		throw ANKI_EXCEPTION("Buffer not found: %s", name);
+		throw ANKI_EXCEPTION("Buffer not found: %s", &name[0]);
 	}
 	return *var;
 }

+ 7 - 5
src/gl/GlProgramHandle.cpp

@@ -29,7 +29,8 @@ public:
 
 	void operator()(GlCommandBuffer* commands)
 	{
-		GlProgram p(m_type, (const char*)m_source.getBaseAddress(), 
+		GlProgram p(m_type, 
+			reinterpret_cast<const char*>(m_source.getBaseAddress()),
 			commands->getQueue().getDevice()._getAllocator(),
 			commands->getQueue().getDevice()._getCacheDirectory());
 		m_prog._get() = std::move(p);
@@ -89,14 +90,15 @@ const GlProgramData::ProgramVector<GlProgramBlock>&
 }
 
 //==============================================================================
-const GlProgramVariable& GlProgramHandle::findVariable(const char* name) const
+const GlProgramVariable& GlProgramHandle::findVariable(
+	const CString& name) const
 {
 	serializeOnGetter();
 	return _get().findVariable(name);
 }
 
 //==============================================================================
-const GlProgramBlock& GlProgramHandle::findBlock(const char* name) const
+const GlProgramBlock& GlProgramHandle::findBlock(const CString& name) const
 {
 	serializeOnGetter();
 	return _get().findBlock(name);
@@ -104,14 +106,14 @@ const GlProgramBlock& GlProgramHandle::findBlock(const char* name) const
 
 //==============================================================================
 const GlProgramVariable* 
-	GlProgramHandle::tryFindVariable(const char* name) const
+	GlProgramHandle::tryFindVariable(const CString& name) const
 {
 	serializeOnGetter();
 	return _get().tryFindVariable(name);
 }
 
 //==============================================================================
-const GlProgramBlock* GlProgramHandle::tryFindBlock(const char* name) const
+const GlProgramBlock* GlProgramHandle::tryFindBlock(const CString& name) const
 {
 	serializeOnGetter();
 	return _get().tryFindBlock(name);

+ 1 - 1
src/gl/GlProgramPipeline.cpp

@@ -56,7 +56,7 @@ GlProgramPipeline::GlProgramPipeline(
 
 		infoLogTxt = "Ppline error log follows:\n" + infoLogTxt;
 
-		throw ANKI_EXCEPTION("%s", infoLogTxt.c_str());
+		throw ANKI_EXCEPTION("%s", &infoLogTxt[0]);
 	}
 
 	glBindProgramPipeline(0);

+ 1 - 1
src/gl/GlQueue.cpp

@@ -39,7 +39,7 @@ void GlQueue::flushCommandBuffer(GlCommandBufferHandle& commands)
 	{
 		LockGuard<Mutex> lock(m_mtx);
 
-		if(m_error.size() > 0)
+		if(!m_error.isEmpty())
 		{
 			throw ANKI_EXCEPTION("GL rendering thread failed with error:\n%s",
 				&m_error[0]);

+ 3 - 5
src/gl/GlState.cpp

@@ -87,15 +87,13 @@ void GlState::init()
 	m_version = major * 100 + minor * 10;
 
 	// Vendor
-	String glstr = (const char*)glGetString(GL_VENDOR);
-	glstr += (const char*)glGetString(GL_RENDERER);
-	std::transform(glstr.begin(), glstr.end(), glstr.begin(), ::tolower);
+	CString glstr = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
 
-	if(glstr.find("arm") != String::npos)
+	if(glstr.find("ARM") != CString::NPOS)
 	{
 		m_gpu = GlGpu::ARM;
 	}
-	else if(glstr.find("nvidia") != String::npos)
+	else if(glstr.find("NVIDIA") != CString::NPOS)
 	{
 		m_gpu = GlGpu::NVIDIA;
 	}

+ 87 - 60
src/resource/Material.cpp

@@ -9,10 +9,11 @@
 #include "anki/core/Logger.h"
 #include "anki/resource/ProgramResource.h"
 #include "anki/resource/TextureResource.h"
+#include "anki/util/Hash.h"
 #include "anki/util/File.h"
+#include "anki/util/Filesystem.h"
 #include "anki/misc/Xml.h"
-#include "anki/renderer/MainRenderer.h"
-#include <functional>
+#include <functional> // TODO
 #include <algorithm>
 #include <sstream>
 
@@ -26,9 +27,10 @@ namespace anki {
 /// Create an numeric material variable
 template<typename T>
 static MaterialVariable* newMaterialVariable(
-	const GlProgramVariable& glvar, const MaterialProgramCreator::Input& in)
+	const GlProgramVariable& glvar, const MaterialProgramCreator::Input& in,
+	ResourceAllocator<U8>& alloc, TempResourceAllocator<U8>& talloc)
 {
-	MaterialVariable* out;
+	MaterialVariable* out = nullptr;
 
 	if(in.m_value.size() > 0)
 	{
@@ -39,31 +41,33 @@ static MaterialVariable* newMaterialVariable(
 		if(in.m_value.size() != floatsNeeded)
 		{
 			throw ANKI_EXCEPTION("Incorrect number of values. Variable %s",
-				glvar.getName());
+				&glvar.getName()[0]);
 		}
 
-		Vector<F32> floatvec;
+		TempResourceVector<F32> floatvec(talloc);
 		floatvec.resize(floatsNeeded);
 		for(U i = 0; i < floatsNeeded; ++i)
 		{
-			floatvec[i] = std::stof(in.m_value[i]);
+			floatvec[i] = in.m_value[i].toF64();
 		}
 
-		out = new MaterialVariableTemplate<T>(
+		out = alloc.newInstance<MaterialVariableTemplate<T>>(
 			&glvar, 
 			in.m_instanced,
 			(T*)&floatvec[0],
-			glvar.getArraySize());
+			glvar.getArraySize(),
+			alloc);
 	}
 	else
 	{
 		// Buildin
 
-		out = new MaterialVariableTemplate<T>(
+		out = alloc.newInstance<MaterialVariableTemplate<T>>(
 			&glvar, 
 			in.m_instanced,
 			nullptr,
-			0);
+			0,
+			alloc);
 	}
 
 	return out;
@@ -71,11 +75,12 @@ static MaterialVariable* newMaterialVariable(
 
 //==============================================================================
 /// Given a string that defines blending return the GLenum
-static GLenum blendToEnum(const char* str)
+static GLenum blendToEnum(const CString& str)
 {
 // Dont make idiotic mistakes
 #define TXT_AND_ENUM(x) \
-	if(strcmp(str, #x) == 0) { \
+	if(str == #x) \
+	{ \
 		return x; \
 	}
 
@@ -105,7 +110,7 @@ MaterialVariable::~MaterialVariable()
 {}
 
 //==============================================================================
-const char* MaterialVariable::getName() const
+CString MaterialVariable::getName() const
 {
 	return m_progVar->getName();
 }
@@ -127,9 +132,11 @@ Material::Material()
 //==============================================================================
 Material::~Material()
 {
+	auto alloc = m_vars.get_allocator();
+
 	for(auto it : m_vars)
 	{
-		delete it;
+		alloc.deleteInstance(it);
 	}
 }
 
@@ -240,26 +247,39 @@ GlProgramPipelineHandle Material::getProgramPipeline(
 
 		progs[progCount++] = getProgram(key, 4)->getGlProgram();
 
-		GlDevice& gl = GlDeviceSingleton::get();
-		GlCommandBufferHandle jobs(&gl);
+		GlDevice& gl = m_resources->_getGlDevice();
+		GlCommandBufferHandle cmdBuff(&gl);
 
 		ppline = GlProgramPipelineHandle(
-			jobs, &progs[0], &progs[0] + progCount);
+			cmdBuff, &progs[0], &progs[0] + progCount);
 
-		jobs.flush();
+		cmdBuff.flush();
 	}
 
 	return ppline;
 }
 
 //==============================================================================
-void Material::load(const char* filename)
+void Material::load(const CString& filename, ResourceInitializer& init)
 {
 	try
 	{
+		m_vars = std::move(ResourceVector<MaterialVariable*>(init.m_alloc));
+
+		Dictionary<MaterialVariable*> dict(10, 
+			Dictionary<MaterialVariable*>::hasher(),
+			Dictionary<MaterialVariable*>::key_equal(),
+			init.m_alloc);
+		m_varDict = std::move(dict);
+
+		m_progs = 
+			std::move(ResourceVector<ProgramResourcePointer>(init.m_alloc));
+		m_pplines = 
+			std::move(ResourceVector<GlProgramPipelineHandle>(init.m_alloc));
+
 		XmlDocument doc;
-		doc.loadFile(filename);
-		parseMaterialTag(doc.getChildElement("material"));
+		doc.loadFile(filename, init.m_tempAlloc);
+		parseMaterialTag(doc.getChildElement("material"), init);
 	}
 	catch(std::exception& e)
 	{
@@ -268,7 +288,8 @@ void Material::load(const char* filename)
 }
 
 //==============================================================================
-void Material::parseMaterialTag(const XmlElement& materialEl)
+void Material::parseMaterialTag(const XmlElement& materialEl,
+	ResourceInitializer& rinit)
 {
 	// levelsOfDetail
 	//
@@ -335,7 +356,8 @@ void Material::parseMaterialTag(const XmlElement& materialEl)
 	// shaderProgram
 	//
 	MaterialProgramCreator mspc(
-		materialEl.getChildElement("programs"));
+		materialEl.getChildElement("programs"),
+		rinit.m_tempAlloc);
 
 	m_tessellation = mspc.hasTessellation();
 	U tessCount = m_tessellation ? 2 : 1;
@@ -372,29 +394,21 @@ void Material::parseMaterialTag(const XmlElement& materialEl)
 			{
 				for(U tess = 0; tess < tessCount; ++tess)
 				{
-					std::stringstream src;
-
-					src << "#define LOD " << level << "\n";
-					src << "#define PASS " << pid << "\n";
-					src << "#define TESSELLATION " << tess << "\n";
+					TempResourceString src(rinit.m_tempAlloc);
 
-#if 0
-					src << MainRendererSingleton::get().
-						getShaderPostProcessorString() << "\n"
-						<< mspc.getProgramSource(shader) << std::endl;
-#endif
-					ANKI_ASSERT(0 && "TODO");
+					src.sprintf("#define LOD %u\n#define PASS %u\n"
+						"#define TESSELLATION %u\n%s\n", level, pid, tess,
+						&rinit.m_resources._getShaderPostProcessorString()[0]);
 
-					std::string filename =
-						createProgramSourceToChache(src.str().c_str());
+					TempResourceString filename =
+						createProgramSourceToChache(src);
 
 					RenderingKey key((Pass)pid, level, tess);
 					ProgramResourcePointer& progr = getProgram(key, shader);
-					progr.load(filename.c_str());
+					progr.load(filename.toCString(), &rinit.m_resources);
 
 					// Update the hash
-					std::hash<std::string> stringHasher;
-					m_hash ^= stringHasher(src.str());
+					m_hash ^= computeHash(&src[0], src.getLength());
 				}
 			}
 		}
@@ -409,23 +423,26 @@ void Material::parseMaterialTag(const XmlElement& materialEl)
 }
 
 //==============================================================================
-std::string Material::createProgramSourceToChache(const std::string& source)
+TempResourceString Material::createProgramSourceToChache(
+	const TempResourceString& source)
 {
 	// Create the hash
-	std::hash<std::string> stringHasher;
-	PtrSize h = stringHasher(source);
-	std::string prefix = std::to_string(h);
+	U64 h = computeHash(&source[0], source.getLength());
+	TempResourceString prefix = 
+		TempResourceString::toString(h, source.getAllocator());
 
 	// Create path
-	std::string newfPathName =
-		AppSingleton::get().getCachePath() + "/mtl_" + prefix + ".glsl";
+	TempResourceString newfPathName(source.getAllocator());
+	newfPathName.sprintf("%s/mtl_%s.glsl", 
+		&m_resources->_getApp().getCacheDirectory()[0],
+		&prefix[0]);
 
 	// If file not exists write it
-	if(!File::fileExists(newfPathName.c_str()))
+	if(!fileExists(newfPathName.toCString()))
 	{
 		// If not create it
-		File f(newfPathName.c_str(), File::OpenFlag::WRITE);
-		f.writeText("%s\n", source.c_str());
+		File f(newfPathName.toCString(), File::OpenFlag::WRITE);
+		f.writeText("%s\n", &source[0]);
 	}
 
 	return newfPathName;
@@ -449,7 +466,7 @@ void Material::populateVariables(const MaterialProgramCreator& mspc)
 		{
 			const GlProgramHandle& prog = progr->getGlProgram();
 
-			glvar = prog.tryFindVariable(in.m_name.c_str());
+			glvar = prog.tryFindVariable(in.m_name.toCString());
 			if(glvar)
 			{
 				break;
@@ -460,7 +477,7 @@ void Material::populateVariables(const MaterialProgramCreator& mspc)
 		if(glvar == nullptr)
 		{
 			throw ANKI_EXCEPTION("Variable not found in "
-				"at least one program: %s", in.m_name.c_str());
+				"at least one program: %s", &in.m_name[0]);
 		}
 
 		switch(glvar->getDataType())
@@ -473,36 +490,46 @@ void Material::populateVariables(const MaterialProgramCreator& mspc)
 				
 				if(in.m_value.size() > 0)
 				{
-					tp = TextureResourcePointer(in.m_value[0].c_str());
+					tp = TextureResourcePointer(
+						in.m_value[0].toCString(),
+						m_resources);
 				}
 
-				mtlvar = new MaterialVariableTemplate<TextureResourcePointer>(
-					glvar, false, &tp, 1);
+				auto alloc = m_resources->_getAllocator();
+				mtlvar = alloc.newInstance<
+					MaterialVariableTemplate<TextureResourcePointer>>(
+					glvar, false, &tp, 1, alloc);
 			}
 			break;
 		// F32
 		case GL_FLOAT:
-			mtlvar = newMaterialVariable<F32>(*glvar, in);
+			mtlvar = newMaterialVariable<F32>(*glvar, in,
+				m_resources->_getAllocator(), m_resources->_getTempAllocator());
 			break;
 		// vec2
 		case GL_FLOAT_VEC2:
-			mtlvar = newMaterialVariable<Vec2>(*glvar, in);
+			mtlvar = newMaterialVariable<Vec2>(*glvar, in,
+				m_resources->_getAllocator(), m_resources->_getTempAllocator());
 			break;
 		// vec3
 		case GL_FLOAT_VEC3:
-			mtlvar = newMaterialVariable<Vec3>(*glvar, in);
+			mtlvar = newMaterialVariable<Vec3>(*glvar, in,
+				m_resources->_getAllocator(), m_resources->_getTempAllocator());
 			break;
 		// vec4
 		case GL_FLOAT_VEC4:
-			mtlvar = newMaterialVariable<Vec4>(*glvar, in);
+			mtlvar = newMaterialVariable<Vec4>(*glvar, in,
+				m_resources->_getAllocator(), m_resources->_getTempAllocator());
 			break;
 		// mat3
 		case GL_FLOAT_MAT3:
-			mtlvar = newMaterialVariable<Mat3>(*glvar, in);
+			mtlvar = newMaterialVariable<Mat3>(*glvar, in,
+				m_resources->_getAllocator(), m_resources->_getTempAllocator());
 			break;
 		// mat4
 		case GL_FLOAT_MAT4:
-			mtlvar = newMaterialVariable<Mat4>(*glvar, in);
+			mtlvar = newMaterialVariable<Mat4>(*glvar, in,
+				m_resources->_getAllocator(), m_resources->_getTempAllocator());
 			break;
 		// default is error
 		default:

+ 31 - 33
src/resource/MaterialProgramCreator.cpp

@@ -36,36 +36,36 @@ public:
 //==============================================================================
 /// Given a string return info about the shader
 static void getShaderInfo(
-	const char* str, 
+	const CString& str, 
 	GLenum& type, 
 	GLbitfield& bit,
 	U& idx)
 {
-	if(std::strcmp(str, "vert") == 0)
+	if(str == "vert"_cstr)
 	{
 		type = GL_VERTEX_SHADER;
 		bit = GL_VERTEX_SHADER_BIT;
 		idx = 0;
 	}
-	else if(std::strcmp(str, "tesc") == 0)
+	else if(str == "tesc"_cstr)
 	{
 		type = GL_TESS_CONTROL_SHADER;
 		bit = GL_TESS_CONTROL_SHADER_BIT;
 		idx = 1;
 	}
-	else if(std::strcmp(str, "tese") == 0)
+	else if(str == "tese"_cstr)
 	{
 		type = GL_TESS_EVALUATION_SHADER;
 		bit = GL_TESS_EVALUATION_SHADER_BIT;
 		idx = 2;
 	}
-	else if(std::strcmp(str, "geom") == 0)
+	else if(str == "geom"_cstr)
 	{
 		type = GL_GEOMETRY_SHADER;
 		bit = GL_GEOMETRY_SHADER_BIT;
 		idx = 3;
 	}
-	else if(std::strcmp(str, "frag") == 0)
+	else if(str == "frag"_cstr)
 	{
 		type = GL_GEOMETRY_SHADER;
 		bit = GL_GEOMETRY_SHADER_BIT;
@@ -73,7 +73,7 @@ static void getShaderInfo(
 	}
 	else
 	{
-		throw ANKI_EXCEPTION("Incorrect type %s", str);
+		throw ANKI_EXCEPTION("Incorrect type %s", &str[0]);
 	}
 }
 
@@ -101,12 +101,12 @@ void MaterialProgramCreator::parseProgramsTag(const XmlElement& el)
 	//
 	// First gather all the inputs
 	//
-	XmlElement programEl = el.getChildElement("program");
+	XmlElement programEl = el.getChildElement("program"_cstr);
 	do
 	{
 		parseInputsTag(programEl);
 
-		programEl = programEl.getNextSiblingElement("program");
+		programEl = programEl.getNextSiblingElement("program"_cstr);
 	} while(programEl);
 
 	// Sort them by name to decrease the change of creating unique shaders
@@ -115,12 +115,12 @@ void MaterialProgramCreator::parseProgramsTag(const XmlElement& el)
 	//
 	// Then parse the includes, operations and other parts of the program
 	//
-	programEl = el.getChildElement("program");
+	programEl = el.getChildElement("program"_cstr);
 	do
 	{
 		parseProgramTag(programEl);
 
-		programEl = programEl.getNextSiblingElement("program");
+		programEl = programEl.getNextSiblingElement("program"_cstr);
 	} while(programEl);
 
 	//
@@ -133,7 +133,7 @@ void MaterialProgramCreator::parseProgramsTag(const XmlElement& el)
 		if(in.m_shaderDefinedMask != in.m_shaderReferencedMask)
 		{
 			throw ANKI_EXCEPTION("Variable not referenced or not defined %s", 
-				in.m_name.c_str());
+				&in.m_name[0]);
 		}
 	}
 }
@@ -143,7 +143,7 @@ void MaterialProgramCreator::parseProgramTag(
 	const XmlElement& programEl)
 {
 	// <type>
-	const char* type = programEl.getChildElement("type").getText();
+	CString type = programEl.getChildElement("type"_cstr).getText();
 	GLbitfield glshaderbit;
 	GLenum glshader;
 	U shaderidx;
@@ -151,7 +151,7 @@ void MaterialProgramCreator::parseProgramTag(
 
 	m_source[shaderidx] = MPStringList(m_alloc);
 	auto& lines = m_source[shaderidx];
-	lines.push_back(ANKI_STRL("#pragma anki type ") + type);
+	lines.push_back(ANKI_STRL("#pragma anki type "_cstr) + type);
 
 	if(glshader == GL_TESS_CONTROL_SHADER 
 		|| glshader == GL_TESS_EVALUATION_SHADER)
@@ -160,16 +160,16 @@ void MaterialProgramCreator::parseProgramTag(
 	}
 
 	// <includes></includes>
-	XmlElement includesEl = programEl.getChildElement("includes");
-	XmlElement includeEl = includesEl.getChildElement("include");
+	XmlElement includesEl = programEl.getChildElement("includes"_cstr);
+	XmlElement includeEl = includesEl.getChildElement("include"_cstr);
 
 	do
 	{
 		MPString fname(includeEl.getText(), m_alloc);
 		lines.push_back(
-			ANKI_STRL("#pragma anki include \"") + fname + "\"");
+			ANKI_STRL("#pragma anki include \""_cstr) + fname + "\""_cstr);
 
-		includeEl = includeEl.getNextSiblingElement("include");
+		includeEl = includeEl.getNextSiblingElement("include"_cstr);
 	} while(includeEl);
 
 	// Inputs
@@ -180,12 +180,12 @@ void MaterialProgramCreator::parseProgramTag(
 	{
 		// TODO Make block SSB when driver bug is fixed
 		lines.push_back(ANKI_STRL(
-			"\nlayout(binding = 0, std140) uniform bDefaultBlock\n{"));
+			"\nlayout(binding = 0, std140) uniform bDefaultBlock\n{"_cstr));
 
 		lines.insert(
 			lines.end(), m_uniformBlock.begin(), m_uniformBlock.end());
 
-		lines.push_back("};");
+		lines.push_back(ANKI_STRL("};"));
 	}
 
 	// Other variables
@@ -298,7 +298,7 @@ void MaterialProgramCreator::parseInputsTag(const XmlElement& programEl)
 			if(!same)
 			{
 				throw ANKI_EXCEPTION("Variable defined differently between "
-					"shaders: %s", inpvar.m_name.c_str());
+					"shaders: %s", &inpvar.m_name[0]);
 			}
 
 			duplicateInp->m_shaderDefinedMask |= glshaderbit;
@@ -314,15 +314,14 @@ void MaterialProgramCreator::parseInputsTag(const XmlElement& programEl)
 				
 			if(inpvar.m_arraySize > 1)
 			{
-				MPString tmp(m_alloc);
-				toString(inpvar.m_arraySize, tmp);
+				MPString tmp(MPString::toString(inpvar.m_arraySize, m_alloc));
 				inpvar.m_line += "[" + tmp + "U]";
 			}
 
 			if(inpvar.m_instanced)
 			{
-				MPString tmp(m_alloc);
-				toString(ANKI_GL_MAX_INSTANCES, tmp);
+				MPString tmp(
+					MPString::toString(ANKI_GL_MAX_INSTANCES, m_alloc));
 				inpvar.m_line += "[" +  tmp + "U]";
 			}
 
@@ -331,8 +330,8 @@ void MaterialProgramCreator::parseInputsTag(const XmlElement& programEl)
 			// Can put it block
 			if(inpvar.m_type == "sampler2D" || inpvar.m_type == "samplerCube")
 			{
-				MPString tmp(m_alloc);
-				toString(m_texBinding++, tmp);
+				MPString tmp(
+					MPString::toString(m_texBinding++, m_alloc));
 
 				inpvar.m_line = ANKI_STRL("layout(binding = ") 
 					+ tmp + ") uniform " + inpvar.m_line;
@@ -395,8 +394,7 @@ void MaterialProgramCreator::parseOperationTag(
 	MPString operationOut(m_alloc);
 	if(retType != "void")
 	{
-		MPString tmp(m_alloc);
-		toString(id, tmp);
+		MPString tmp(MPString::toString(id, m_alloc));
 		operationOut = ANKI_STRL(OUT) + tmp;
 	}
 	
@@ -432,9 +430,9 @@ void MaterialProgramCreator::parseOperationTag(
 
 			// The argument should be an input variable or an outXX
 			if(!(input != nullptr 
-				|| strncmp(arg.c_str(), OUT, sizeof(OUT) - 1) == 0))
+				|| std::strncmp(&arg[0], OUT, sizeof(OUT) - 1) == 0))
 			{
-				throw ANKI_EXCEPTION("Incorrect argument: %s", arg.c_str());
+				throw ANKI_EXCEPTION("Incorrect argument: %s", &arg[0]);
 			}
 
 			// Add to a list and do something special if instanced
@@ -476,7 +474,7 @@ void MaterialProgramCreator::parseOperationTag(
 			}
 			else
 			{
-				argsList.push_back(argEl.getText());
+				argsList.push_back(MPString(argEl.getText(), m_alloc));
 			}
 
 			// Advance
@@ -506,7 +504,7 @@ void MaterialProgramCreator::parseOperationTag(
 	}
 	else
 	{
-		lines += '\t';
+		lines += "\t";
 	}
 	
 	// write the blah = func(args...)

+ 20 - 22
src/resource/ProgramResource.cpp

@@ -8,15 +8,16 @@
 #include "anki/resource/ResourceManager.h"
 #include "anki/core/App.h" // To get cache dir
 #include "anki/util/File.h"
+#include "anki/util/Filesystem.h"
+#include "anki/util/Hash.h"
 #include "anki/util/Exception.h"
-#include <cstring>
 
 namespace anki {
 
 //==============================================================================
 void ProgramResource::load(const CString& filename, ResourceInitializer& init)
 {
-	load(filename, "", init.m_resourceManager);
+	load(filename, " ", init.m_resourceManager);
 }
 
 //==============================================================================
@@ -24,13 +25,13 @@ void ProgramResource::load(const CString& filename, const CString& extraSrc,
 	ResourceManager& manager)
 {
 	ProgramPrePreprocessor pars(filename, &manager);
-	TempResourceString source = extraSrc + pars.getShaderSource();
+	TempResourceString source(extraSrc + pars.getShaderSource());
 
-	GlDevice& gl = GlDeviceSingleton::get();
+	GlDevice& gl = manager._getGlDevice();
 	GlCommandBufferHandle jobs(&gl);
-	GlClientBufferHandle glsource(jobs, source.length() + 1, nullptr);
+	GlClientBufferHandle glsource(jobs, source.getLength() + 1, nullptr);
 
-	strcpy((char*)glsource.getBaseAddress(), &source[0]);
+	std::strcpy(reinterpret_cast<char*>(glsource.getBaseAddress()), &source[0]);
 
 	m_prog = GlProgramHandle(jobs, 
 		computeGlShaderType((U)pars.getShaderType()), glsource);
@@ -40,43 +41,40 @@ void ProgramResource::load(const CString& filename, const CString& extraSrc,
 
 //==============================================================================
 String ProgramResource::createSourceToCache(
-	const char* filename, const char* preAppendedSrcCode, 
-	const char* filenamePrefix, App& app)
+	const CString& filename, const CString& preAppendedSrcCode, 
+	const CString& filenamePrefix, ResourceManager& manager)
 {
-	ANKI_ASSERT(filename && preAppendedSrcCode && filenamePrefix);
+	auto& alloc = manager._getAllocator();
 
-	auto& alloc = app.getAllocator();
-
-	if(std::strlen(preAppendedSrcCode) < 1)
+	if(preAppendedSrcCode == "")
 	{
 		return String(filename, alloc);
 	}
 
 	// Create suffix
-	std::hash<String> stringHasher;
-	PtrSize h = stringHasher(String(filename, alloc) + preAppendedSrcCode);
+	String unique(String(filename, alloc) + preAppendedSrcCode);
+	U64 h = computeHash(&unique[0], unique.getLength());
 
-	String suffix(alloc);
-	toString(h, suffix);
+	String suffix(String::toString(h, alloc));
 
 	// Compose cached filename
-	String newFilename(app.getCachePath()
-		+ "/" + filenamePrefix + suffix + ".glsl";
+	String newFilename(manager._getApp().getCachePath()
+		+ CString("/") + filenamePrefix + suffix + CString(".glsl"));
 
-	if(File::fileExists(newFilename.c_str()))
+	if(fileExists(newFilename.toCString()))
 	{
 		return newFilename;
 	}
 
 	// Read file and append code
 	String src(alloc);
-	File(ResourceManagerSingleton::get().fixResourcePath(filename).c_str(), 
+	File(manager.fixResourceFilename(filename).toCString(), 
 		File::OpenFlag::READ).readAllText(src);
 	src = preAppendedSrcCode + src;
 
 	// Write cached file
-	File f(newFilename.c_str(), File::OpenFlag::WRITE);
-	f.writeText("%s\n", src.c_str());
+	File f(newFilename.toCString(), File::OpenFlag::WRITE);
+	f.writeText("%s\n", &src[0]);
 
 	return newFilename;
 }

+ 5 - 5
src/resource/TextureResource.cpp

@@ -25,7 +25,7 @@ static void deleteImageCallback(void* data)
 }
 
 //==============================================================================
-void TextureResource::load(const char* filename, ResourceInitializer& init)
+void TextureResource::load(const CString& filename, ResourceInitializer& init)
 {
 	try
 	{
@@ -38,10 +38,10 @@ void TextureResource::load(const char* filename, ResourceInitializer& init)
 }
 
 //==============================================================================
-void TextureResource::loadInternal(const char* filename, 
+void TextureResource::loadInternal(const CString& filename, 
 	ResourceInitializer& rinit)
 {
-	GlDevice& gl = rinit.m_gl;
+	GlDevice& gl = rinit.m_resources._getGlDevice();
 	GlCommandBufferHandle jobs(&gl); // Always first to avoid assertions (
 	                                 // because of the check of the allocator)
 
@@ -52,7 +52,7 @@ void TextureResource::loadInternal(const char* filename,
 	// Load image
 	Image* imgPtr = rinit.m_alloc.newInstance<Image>(rinit.m_alloc);
 	Image& img = *imgPtr;
-	img.load(filename, rinit.m_resourceManager.getMaxTextureSize());
+	img.load(filename, rinit.m_resources.getMaxTextureSize());
 	
 	// width + height
 	init.m_width = img.getSurface(0, 0).m_width;
@@ -173,7 +173,7 @@ void TextureResource::loadInternal(const char* filename,
 	init.m_repeat = true;
 
 	// anisotropyLevel
-	init.m_anisotropyLevel = rinit.m_resourceManager.getTextureAnisotropy();
+	init.m_anisotropyLevel = rinit.m_resource.getTextureAnisotropy();
 
 	// genMipmaps
 	if(init.m_mipmapsCount == 1 || driverShouldGenMipmaps)

+ 1 - 1
src/util/CMakeLists.txt

@@ -1,4 +1,4 @@
-set(ANKI_UTIL_SOURCES Assert.cpp Exception.cpp Functions.cpp File.cpp Memory.cpp System.cpp HighRezTimer.cpp Thread.cpp)
+set(ANKI_UTIL_SOURCES Assert.cpp Exception.cpp Functions.cpp File.cpp Memory.cpp System.cpp HighRezTimer.cpp Thread.cpp Hash.cpp)
 
 if(LINUX OR ANDROID OR MACOS)
 	set(ANKI_UTIL_SOURCES ${ANKI_UTIL_SOURCES} HighRezTimerPosix.cpp FilesystemPosix.cpp ThreadPosix.cpp)

+ 1 - 1
src/util/File.cpp

@@ -420,7 +420,7 @@ void File::write(void* buff, PtrSize size)
 }
 
 //==============================================================================
-void File::writeText(const CString& format, ...)
+void File::writeText(CString format, ...)
 {
 	ANKI_ASSERT(m_file);
 	ANKI_ASSERT(m_flags != OpenFlag::NONE);

+ 62 - 0
src/util/Hash.cpp

@@ -0,0 +1,62 @@
+// Copyright (C) 2014, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include "anki/util/Hash.h"
+
+namespace anki {
+
+//==============================================================================
+U64 computeHash(const void* buffer, U32 bufferSize, U64 seed)
+{
+	const U64 m = 0xc6a4a7935bd1e995;
+	const U64 r = 47;
+
+	U64 h = seed ^ (bufferSize * m);
+
+	const U64* data = reinterpret_cast<const U64*>(buffer);
+	const U64* end = data + (bufferSize / sizeof(U64));
+
+	while(data != end)
+	{
+		U64 k = *data++;
+
+		k *= m; 
+		k ^= k >> r; 
+		k *= m; 
+		
+		h ^= k;
+		h *= m;
+	}
+
+	const U8* data2 = reinterpret_cast<const U8*>(data);
+
+	switch(bufferSize & (sizeof(U64) - 1))
+	{
+	case 7: 
+		h ^= static_cast<U64>(data2[6]) << 48;
+	case 6: 
+		h ^= static_cast<U64>(data2[5]) << 40;
+	case 5: 
+		h ^= static_cast<U64>(data2[4]) << 32;
+	case 4: 
+		h ^= static_cast<U64>(data2[3]) << 24;
+	case 3: 
+		h ^= static_cast<U64>(data2[2]) << 16;
+	case 2: 
+		h ^= static_cast<U64>(data2[1]) << 8;
+	case 1: 
+		h ^= static_cast<U64>(data2[0]);
+		h *= m;
+	};
+ 
+	h ^= h >> r;
+	h *= m;
+	h ^= h >> r;
+
+	return h;
+}
+
+} // end namespace anki
+