Browse Source

Introducing resource filesystem

Panagiotis Christopoulos Charitos 10 years ago
parent
commit
9d67550208
42 changed files with 271 additions and 406 deletions
  1. 1 1
      include/anki/resource/Animation.h
  2. 1 1
      include/anki/resource/CollisionResource.h
  3. 4 3
      include/anki/resource/Common.h
  4. 3 3
      include/anki/resource/DummyRsrc.h
  5. 0 29
      include/anki/resource/Extension.h
  6. 13 9
      include/anki/resource/ImageLoader.h
  7. 6 4
      include/anki/resource/Material.h
  8. 7 5
      include/anki/resource/Mesh.h
  9. 14 13
      include/anki/resource/MeshLoader.h
  10. 9 7
      include/anki/resource/Model.h
  11. 4 5
      include/anki/resource/ParticleEmitterResource.h
  12. 5 7
      include/anki/resource/ProgramPrePreprocessor.h
  13. 2 1
      include/anki/resource/ResourceFilesystem.h
  14. 0 9
      include/anki/resource/ResourceManager.h
  15. 9 2
      include/anki/resource/ResourceObject.h
  16. 1 1
      include/anki/resource/ResourcePointer.h
  17. 2 8
      include/anki/resource/ResourcePointer.inl.h
  18. 3 5
      include/anki/resource/Script.h
  19. 6 6
      include/anki/resource/ShaderResource.h
  20. 5 3
      include/anki/resource/SkelAnim.h
  21. 7 6
      include/anki/resource/Skeleton.h
  22. 3 8
      include/anki/resource/TextureResource.h
  23. 1 0
      src/core/App.cpp
  24. 2 2
      src/resource/Animation.cpp
  25. 6 9
      src/resource/CollisionResource.cpp
  26. 0 43
      src/resource/Extension.cpp
  27. 50 59
      src/resource/ImageLoader.cpp
  28. 4 4
      src/resource/Material.cpp
  29. 3 3
      src/resource/Mesh.cpp
  30. 28 42
      src/resource/MeshLoader.cpp
  31. 2 2
      src/resource/Model.cpp
  32. 2 2
      src/resource/ParticleEmitterResource.cpp
  33. 12 14
      src/resource/ProgramPrePreprocessor.cpp
  34. 1 1
      src/resource/ResourceFilesystem.cpp
  35. 0 34
      src/resource/ResourceManager.cpp
  36. 16 1
      src/resource/ResourceObject.cpp
  37. 4 4
      src/resource/Script.cpp
  38. 14 14
      src/resource/ShaderResource.cpp
  39. 3 3
      src/resource/Skeleton.cpp
  40. 10 22
      src/resource/TextureResource.cpp
  41. 7 11
      src/scene/Sector.cpp
  42. 1 0
      testapp/Main.cpp

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

@@ -74,7 +74,7 @@ public:
 
 	~Animation();
 
-	ANKI_USE_RESULT Error load(const CString& filename);
+	ANKI_USE_RESULT Error load(const ResourceFilename& filename);
 
 	/// Get a vector of all animation channels
 	const DArray<AnimationChannel>& getChannels() const

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

@@ -32,7 +32,7 @@ public:
 	~CollisionResource()
 	{}
 
-	ANKI_USE_RESULT Error load(const CString& filename);
+	ANKI_USE_RESULT Error load(const ResourceFilename& filename);
 
 	PhysicsCollisionShapePtr getShape() const
 	{

+ 4 - 3
include/anki/resource/Common.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_COMMON_H
-#define ANKI_RESOURCE_COMMON_H
+#pragma once
 
 #include "anki/util/Allocator.h"
 #include "anki/util/DArray.h"
@@ -47,8 +46,10 @@ using ResourceAllocator = HeapAllocator<T>;
 
 template<typename T>
 using TempResourceAllocator = StackAllocator<T>;
+
+/// An alias that denotes a ResourceFilesystem path.
+using ResourceFilename = CString;
 /// @}
 
 } // end namespace anki
 
-#endif

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

@@ -19,7 +19,7 @@ class DummyRsrc: public ResourceObject
 {
 public:
 	DummyRsrc(ResourceManager* manager)
-	:	ResourceObject(manager)
+		: ResourceObject(manager)
 	{}
 
 	~DummyRsrc()
@@ -30,10 +30,10 @@ public:
 		}
 	}
 
-	ANKI_USE_RESULT Error load(const CString& filename)
+	ANKI_USE_RESULT Error load(const ResourceFilename& filename)
 	{
 		Error err = ErrorCode::NONE;
-		if(filename.find("error") == CString::NPOS)
+		if(filename.find("error") == ResourceFilename::NPOS)
 		{
 			m_memory = getAllocator().allocate(128);
 			void* tempMem = getTempAllocator().allocate(128);

+ 0 - 29
include/anki/resource/Extension.h

@@ -1,29 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#ifndef ANKI_RESOURCE_EXTENSION_H
-#define ANKI_RESOURCE_EXTENSION_H
-
-namespace anki {
-
-/// Extension resource
-class Extension
-{
-public:
-	Extension();
-	~Extension();
-	void load(const char* filename);
-	/*template<typename Type>
-	int FooBar(Type* ptr) { DEBUG_ERR(foobarPtr==NULL);
-		return (*foobarPtr)(reinterpret_cast<Type*>(ptr)); }*/
-
-private:
-	void* libHandle = nullptr;
-	int(*foobarPtr)(void*) = nullptr;
-};
-
-} // end namespace
-
-#endif

+ 13 - 9
include/anki/resource/ImageLoader.h

@@ -3,10 +3,10 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_IMAGE_LOADER_H
-#define ANKI_RESOURCE_IMAGE_LOADER_H
+#pragma once
 
 #include "anki/resource/Common.h"
+#include "anki/resource/ResourceFilesystem.h"
 #include "anki/util/Functions.h"
 #include "anki/util/Enum.h"
 
@@ -57,7 +57,7 @@ public:
 	};
 
 	ImageLoader(GenericMemoryPoolAllocator<U8> alloc)
-	:	m_alloc(alloc)
+		: m_alloc(alloc)
 	{}
 
 	~ImageLoader()
@@ -102,15 +102,20 @@ public:
 		return m_alloc;
 	}
 
-	/// Load an image file
-	/// @param[in] filename The file to load
-	/// @param[in] maxTextureSize Only load mipmaps less or equal to that. Used
-	///                           with AnKi textures
+	/// Load an image file.
 	ANKI_USE_RESULT Error load(
-		const CString& filename, U32 maxTextureSize = MAX_U32);
+		ResourceFilePtr file,
+		const CString& filename,
+		U32 maxTextureSize = MAX_U32);
+
+	Atomic<I32>& getRefcount()
+	{
+		return m_refcount;
+	}
 
 private:
 	GenericMemoryPoolAllocator<U8> m_alloc;
+	Atomic<I32> m_refcount = {0};
 	/// [mip][depthFace]
 	DArray<Surface> m_surfaces;
 	U8 m_mipLevels = 0;
@@ -124,4 +129,3 @@ private:
 
 } // end namespace anki
 
-#endif

+ 6 - 4
include/anki/resource/Material.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_MATERIAL_H
-#define ANKI_RESOURCE_MATERIAL_H
+#pragma once
 
 #include "anki/resource/ResourceObject.h"
 #include "anki/resource/ResourcePointer.h"
@@ -28,6 +27,9 @@ class MaterialVariableTemplate;
 
 class MaterialVariable;
 
+/// @addtogroup resource
+/// @{
+
 /// Material variable base. Its a visitable
 typedef VisitableCommonBase<
 	MaterialVariable,
@@ -354,7 +356,7 @@ public:
 		const RenderingKey& key, PipelinePtr& out);
 
 	/// Load a material file
-	ANKI_USE_RESULT Error load(const CString& filename);
+	ANKI_USE_RESULT Error load(const ResourceFilename& filename);
 
 	/// For sorting
 	Bool operator<(const Material& b) const
@@ -392,7 +394,7 @@ private:
 	U countShaders(ShaderType type) const;
 	U getShaderIndex(const RenderingKey key, ShaderType type) const;
 };
+/// @}
 
 } // end namespace anki
 
-#endif

+ 7 - 5
include/anki/resource/Mesh.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_MESH_H
-#define ANKI_RESOURCE_MESH_H
+#pragma once
 
 #include "anki/resource/ResourceObject.h"
 #include "anki/Math.h"
@@ -15,6 +14,9 @@ namespace anki {
 
 class MeshLoader;
 
+/// @addtogroup resource
+/// @{
+
 /// Vertex attributes. This should match the shaders
 enum class VertexAttribute: U8
 {
@@ -36,7 +38,7 @@ class Mesh: public ResourceObject
 public:
 	/// Default constructor
 	Mesh(ResourceManager* manager)
-	:	ResourceObject(manager)
+		: ResourceObject(manager)
 	{}
 
 	~Mesh();
@@ -96,7 +98,7 @@ public:
 	Bool isCompatible(const Mesh& other) const;
 
 	/// Load from a .mesh file
-	ANKI_USE_RESULT Error load(const CString& filename);
+	ANKI_USE_RESULT Error load(const ResourceFilename& filename);
 
 protected:
 	/// Per sub mesh data
@@ -137,7 +139,7 @@ public:
 	/// Load from a .mmesh file
 	ANKI_USE_RESULT Error load(const CString& filename);
 };
+/// @}
 
 } // end namespace anki
 
-#endif

+ 14 - 13
include/anki/resource/MeshLoader.h

@@ -3,14 +3,16 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_MESH_LOADER_H
-#define ANKI_RESOURCE_MESH_LOADER_H
+#pragma once
 
 #include "anki/resource/Common.h"
 #include "anki/Math.h"
 
 namespace anki {
 
+/// @addtogroup resource
+/// @{
+
 /// Mesh data. This class loads the mesh file and the Mesh class loads it to
 /// the GPU.
 class MeshLoader
@@ -76,7 +78,7 @@ public:
 
 		U32 m_totalIndicesCount;
 		U32 m_totalVerticesCount;
-		/// Number of UV sets. Eg one for normal diffuse and another for 
+		/// Number of UV sets. Eg one for normal diffuse and another for
 		/// lightmaps.
 		U32 m_uvsChannelCount;
 		U32 m_subMeshCount;
@@ -92,11 +94,13 @@ public:
 		U32 m_indicesCount = 0;
 	};
 
+	MeshLoader(ResourceManager* manager)
+		: m_manager(manager)
+	{}
+
 	~MeshLoader();
 
-	ANKI_USE_RESULT Error load(
-		GenericMemoryPoolAllocator<U8> alloc,
-		const CString& filename);
+	ANKI_USE_RESULT Error load(const ResourceFilename& filename);
 
 	const Header& getHeader() const
 	{
@@ -137,7 +141,7 @@ public:
 	Bool hasBoneInfo() const
 	{
 		ANKI_ASSERT(isLoaded());
-		return 
+		return
 			m_header.m_boneWeightsFormat.m_components != ComponentFormat::NONE;
 	}
 
@@ -145,7 +149,7 @@ private:
 	template<typename T>
 	using MDArray = DArray<T>;
 
-	GenericPoolAllocator<U8, BaseMemoryPool> m_alloc;
+	ResourceManager* m_manager;
 	Header m_header;
 
 	MDArray<U8> m_verts;
@@ -158,15 +162,12 @@ private:
 		return m_verts.getSize() > 0;
 	}
 
-	ANKI_USE_RESULT Error loadInternal(const CString& filename);
-
 	static ANKI_USE_RESULT Error checkFormat(
-		const Format& fmt, 
+		const Format& fmt,
 		const CString& attrib,
 		Bool cannotBeEmpty);
 };
+/// @}
 
 } // end namespace anki
 
-#endif
-

+ 9 - 7
include/anki/resource/Model.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_MODEL_H
-#define ANKI_RESOURCE_MODEL_H
+#pragma once
 
 #include "anki/resource/ResourceObject.h"
 #include "anki/Gr.h"
@@ -20,13 +19,16 @@ namespace anki {
 // Forward
 class PhysicsCollisionShape;
 
+/// @addtogroup resource
+/// @{
+
 /// Model patch interface class. Its very important class and it binds the
 /// material with the mesh
 class ModelPatchBase
 {
 public:
 	ModelPatchBase(ResourceAllocator<U8> alloc)
-	:	m_alloc(alloc)
+		: m_alloc(alloc)
 	{}
 
 	virtual ~ModelPatchBase();
@@ -111,7 +113,7 @@ public:
 
 	/// Accepts a number of mesh filenames, one for each LOD
 	ModelPatch(ResourceAllocator<U8> alloc)
-	:	ModelPatchBase(alloc)
+		: ModelPatchBase(alloc)
 	{}
 
 	~ModelPatch()
@@ -165,7 +167,7 @@ class Model: public ResourceObject
 {
 public:
 	Model(ResourceManager* manager)
-	:	ResourceObject(manager)
+		: ResourceObject(manager)
 	{}
 
 	~Model();
@@ -180,7 +182,7 @@ public:
 		return m_visibilityShape;
 	}
 
-	ANKI_USE_RESULT Error load(const CString& filename);
+	ANKI_USE_RESULT Error load(const ResourceFilename& filename);
 
 private:
 	DArray<ModelPatchBase*> m_modelPatches;
@@ -188,7 +190,7 @@ private:
 	SkeletonResourcePtr m_skeleton;
 	DArray<AnimationResourcePtr> m_animations;
 };
+/// @}
 
 } // end namespace anki
 
-#endif

+ 4 - 5
include/anki/resource/ParticleEmitterResource.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_PARTICLE_EMITTER_RSRC_H
-#define ANKI_RESOURCE_PARTICLE_EMITTER_RSRC_H
+#pragma once
 
 #include "anki/resource/ResourceObject.h"
 #include "anki/resource/ResourcePointer.h"
@@ -98,7 +97,7 @@ class ParticleEmitterResource: public ResourceObject,
 {
 public:
 	ParticleEmitterResource(ResourceManager* manager)
-	:	ResourceObject(manager)
+		: ResourceObject(manager)
 	{}
 
 	~ParticleEmitterResource();
@@ -112,13 +111,14 @@ public:
 	{
 		return *m_material;
 	}
+
 	Material& getMaterial()
 	{
 		return *m_material;
 	}
 
 	/// Load it
-	ANKI_USE_RESULT Error load(const CString& filename);
+	ANKI_USE_RESULT Error load(const ResourceFilename& filename);
 
 private:
 	MaterialResourcePtr m_material;
@@ -129,4 +129,3 @@ private:
 
 } // end namespace anki
 
-#endif

+ 5 - 7
include/anki/resource/ProgramPrePreprocessor.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_PROGRAM_PRE_PREPROCESSOR_H
-#define ANKI_RESOURCE_PROGRAM_PRE_PREPROCESSOR_H
+#pragma once
 
 #include "anki/resource/ResourceManager.h"
 #include "anki/util/StdTypes.h"
@@ -30,8 +29,8 @@ public:
 	/// It loads a file and parses it
 	/// @param[in] filename The file to load
 	ProgramPrePreprocessor(ResourceManager* manager)
-	:	m_alloc(manager->getTempAllocator()),
-		m_manager(manager)
+		: m_alloc(manager->getTempAllocator())
+		, m_manager(manager)
 	{}
 
 	~ProgramPrePreprocessor()
@@ -44,7 +43,7 @@ public:
 	/// the output
 	///
 	/// @param filename The file to parse
-	ANKI_USE_RESULT Error parseFile(const CString& filename);
+	ANKI_USE_RESULT Error parseFile(const ResourceFilename& filename);
 
 	const String& getShaderSource() const
 	{
@@ -80,7 +79,7 @@ protected:
 	/// @param depth The #line in GLSL does not support filename so an
 	///              depth it being used. It also tracks the includance depth
 	ANKI_USE_RESULT Error parseFileForPragmas(
-		CString filename, U32 depth);
+		ResourceFilename filename, U32 depth);
 
 	/// Parse the type
 	ANKI_USE_RESULT Error parseType(const String& line, Bool& found);
@@ -90,4 +89,3 @@ protected:
 
 } // end namespace anki
 
-#endif

+ 2 - 1
include/anki/resource/ResourceFilesystem.h

@@ -5,6 +5,7 @@
 
 #pragma once
 
+#include "anki/resource/Common.h"
 #include "anki/util/String.h"
 #include "anki/util/StringList.h"
 #include "anki/util/File.h"
@@ -86,7 +87,7 @@ public:
 
 	/// Search the path list to find the file. Then open the file for reading.
 	ANKI_USE_RESULT Error openFile(
-		const CString& filename,
+		const ResourceFilename& filename,
 		ResourceFilePtr& file);
 
 private:

+ 0 - 9
include/anki/resource/ResourceManager.h

@@ -126,11 +126,6 @@ public:
 
 	ANKI_USE_RESULT Error create(Initializer& init);
 
-	const String& getDataDirectory() const
-	{
-		return m_dataDir;
-	}
-
 	U32 getMaxTextureSize() const
 	{
 		return m_maxTextureSize;
@@ -141,10 +136,6 @@ public:
 		return m_textureAnisotropy;
 	}
 
-	void fixResourceFilename(
-		const CString& filename,
-		StringAuto& out) const;
-
 	/// @privatesection
 	/// @{
 	ResourceAllocator<U8>& getAllocator()

+ 9 - 2
include/anki/resource/ResourceObject.h

@@ -13,6 +13,9 @@
 
 namespace anki {
 
+// Forward
+class XmlDocument;
+
 /// @addtogroup resource
 /// @{
 
@@ -60,12 +63,16 @@ public:
 	}
 
 	ANKI_USE_RESULT Error openFile(
-		const CString& filename,
+		const ResourceFilename& filename,
 		ResourceFilePtr& file);
 
 	ANKI_USE_RESULT Error openFileReadAllText(
-		const CString& filename,
+		const ResourceFilename& filename,
 		StringAuto& file);
+
+	ANKI_USE_RESULT Error openFileParseXml(
+		const ResourceFilename& filename,
+		XmlDocument& xml);
 	/// @}
 
 private:

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

@@ -57,7 +57,7 @@ public:
 
 	/// Load the resource using the resource manager
 	ANKI_USE_RESULT Error load(
-		const CString& filename, ResourceManager* resources);
+		const ResourceFilename& filename, ResourceManager* resources);
 
 	template<typename... TArgs>
 	ANKI_USE_RESULT Error loadToCache(

+ 2 - 8
include/anki/resource/ResourcePointer.inl.h

@@ -35,20 +35,14 @@ Error ResourcePointer<T>::load(
 		// Populate the ptr. Use a block ton cleanup temp_pool allocations
 		auto& pool = resources->getTempAllocator().getMemoryPool();
 
-		// WARNING: Keep the brackets to force deallocation of newFname before
-		// reseting the mempool
 		{
-			StringAuto newFname(resources->getTempAllocator());
-
-			resources->fixResourceFilename(filename, newFname);
-
 			U allocsCountBefore = pool.getAllocationsCount();
 			(void)allocsCountBefore;
 
-			err = ptr->load(newFname.toCString());
+			err = ptr->load(filename);
 			if(err)
 			{
-				ANKI_LOGE("Failed to load resource: %s", &newFname[0]);
+				ANKI_LOGE("Failed to load resource: %s", &filename[0]);
 				alloc.deleteInstance(ptr);
 				return err;
 			}

+ 3 - 5
include/anki/resource/Script.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_SCRIPT_H
-#define ANKI_RESOURCE_SCRIPT_H
+#pragma once
 
 #include "anki/resource/ResourceObject.h"
 
@@ -18,12 +17,12 @@ class Script: public ResourceObject
 {
 public:
 	Script(ResourceManager* manager)
-	:	ResourceObject(manager)
+		: ResourceObject(manager)
 	{}
 
 	~Script();
 
-	ANKI_USE_RESULT Error load(const CString& filename);
+	ANKI_USE_RESULT Error load(const ResourceFilename& filename);
 
 	CString getSource() const
 	{
@@ -37,4 +36,3 @@ private:
 
 } // end namespace
 
-#endif

+ 6 - 6
include/anki/resource/ShaderResource.h

@@ -20,7 +20,7 @@ class ShaderResource: public ResourceObject
 {
 public:
 	ShaderResource(ResourceManager* manager)
-	:	ResourceObject(manager)
+		: ResourceObject(manager)
 	{}
 
 	~ShaderResource()
@@ -32,11 +32,11 @@ public:
 	}
 
 	/// Resource load
-	ANKI_USE_RESULT Error load(const CString& filename);
+	ANKI_USE_RESULT Error load(const ResourceFilename& filename);
 
 	/// Load and add extra code on top of the file
 	ANKI_USE_RESULT Error load(
-		const CString& filename, const CString& extraSrc);
+		const CString& ResourceFilename, const CString& extraSrc);
 
 	/// Used by @ref Material and @ref Renderer to create custom shaders in
 	/// the cache
@@ -45,10 +45,10 @@ public:
 	///        of the shader prog
 	/// @param filenamePrefix Add that at the base filename for additional
 	///        ways to identify the file in the cache
-	/// @param out The file pathname of the new shader prog. Its
-	///            $HOME/.anki/cache/ + filenamePrefix + hash + .glsl
+	/// @param out The file pathname of the new shader prog. It's
+	///            filenamePrefix + hash + .glsl
 	static ANKI_USE_RESULT Error createToCache(
-		const CString& filename,
+		const ResourceFilename& filename,
 		const CString& preAppendedSrcCode,
 		const CString& filenamePrefix,
 		ResourceManager& manager,

+ 5 - 3
include/anki/resource/SkelAnim.h

@@ -3,14 +3,16 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_SKEL_ANIM_H
-#define ANKI_RESOURCE_SKEL_ANIM_H
+#pragma once
 
 #include "anki/Math.h"
 #include "anki/util/Vector.h"
 
 namespace anki {
 
+/// @addtogroup resource
+/// @{
+
 /// Bone pose
 struct BonePose
 {
@@ -117,7 +119,7 @@ private:
 	U32 framesNum;
 	Vector<BoneAnim> boneAnims;
 };
+/// @}
 
 } // end namespace
 
-#endif

+ 7 - 6
include/anki/resource/Skeleton.h

@@ -3,14 +3,16 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_SKELETON_H
-#define ANKI_RESOURCE_SKELETON_H
+#pragma once
 
 #include "anki/resource/ResourceObject.h"
 #include "anki/Math.h"
 
 namespace anki {
 
+/// @addtogroup resource
+/// @{
+
 /// Skeleton bone
 struct Bone
 {
@@ -66,13 +68,13 @@ class Skeleton: public ResourceObject
 {
 public:
 	Skeleton(ResourceManager* manager)
-	:	ResourceObject(manager)
+		: ResourceObject(manager)
 	{}
 
 	~Skeleton();
 
 	/// Load file
-	ANKI_USE_RESULT Error load(const CString& filename);
+	ANKI_USE_RESULT Error load(const ResourceFilename& filename);
 
 	const DArray<Bone>& getBones() const
 	{
@@ -82,8 +84,7 @@ public:
 private:
 	DArray<Bone> m_bones;
 };
+/// @}
 
 } // end namespace anki
 
-
-#endif

+ 3 - 8
include/anki/resource/TextureResource.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#ifndef ANKI_RESOURCE_TEXTURE_RESOURCE_H
-#define ANKI_RESOURCE_TEXTURE_RESOURCE_H
+#pragma once
 
 #include "anki/resource/ResourceObject.h"
 #include "anki/resource/ResourcePointer.h"
@@ -12,9 +11,6 @@
 
 namespace anki {
 
-// Forward
-class Image;
-
 /// @addtogroup resource
 /// @{
 
@@ -26,13 +22,13 @@ class TextureResource: public ResourceObject
 {
 public:
 	TextureResource(ResourceManager* manager)
-	:	ResourceObject(manager)
+		: ResourceObject(manager)
 	{}
 
 	~TextureResource();
 
 	/// Load a texture
-	ANKI_USE_RESULT Error load(const CString& filename);
+	ANKI_USE_RESULT Error load(const ResourceFilename& filename);
 
 	/// Get the GL texture
 	const TexturePtr& getGlTexture() const
@@ -69,4 +65,3 @@ private:
 
 } // end namespace anki
 
-#endif

+ 1 - 0
src/core/App.cpp

@@ -228,6 +228,7 @@ Error App::createInternal(const ConfigSet& config_,
 	ResourceManager::Initializer rinit;
 	rinit.m_gr = m_gr;
 	rinit.m_physics = m_physics;
+	rinit.m_resourceFs = m_resourceFs;
 	rinit.m_config = &config;
 	rinit.m_cacheDir = m_cacheDir.toCString();
 	rinit.m_allocCallback = m_allocCb;

+ 2 - 2
src/resource/Animation.cpp

@@ -20,7 +20,7 @@ Animation::~Animation()
 }
 
 //==============================================================================
-Error Animation::load(const CString& filename)
+Error Animation::load(const ResourceFilename& filename)
 {
 	XmlElement el;
 	I64 tmp;
@@ -31,7 +31,7 @@ Error Animation::load(const CString& filename)
 
 	// Document
 	XmlDocument doc;
-	ANKI_CHECK(doc.loadFile(filename, getTempAllocator()));
+	ANKI_CHECK(openFileParseXml(filename, doc));
 	XmlElement rootel;
 	ANKI_CHECK(doc.getChildElement("animation", rootel));
 

+ 6 - 9
src/resource/CollisionResource.cpp

@@ -12,11 +12,11 @@
 namespace anki {
 
 //==============================================================================
-Error CollisionResource::load(const CString& filename)
+Error CollisionResource::load(const ResourceFilename& filename)
 {
 	XmlElement el;
 	XmlDocument doc;
-	ANKI_CHECK(doc.loadFile(filename, getTempAllocator()));
+	ANKI_CHECK(openFileParseXml(filename, doc));
 
 	XmlElement collEl;
 	ANKI_CHECK(doc.getChildElement("collisionShape", collEl));
@@ -45,14 +45,11 @@ Error CollisionResource::load(const CString& filename)
 	}
 	else if(type == "staticMesh")
 	{
-		CString filename;
-		ANKI_CHECK(valEl.getText(filename));
+		CString meshfname;
+		ANKI_CHECK(valEl.getText(meshfname));
 
-		StringAuto fixedFilename(getTempAllocator());
-		getManager().fixResourceFilename(filename, fixedFilename);
-
-		MeshLoader loader;
-		ANKI_CHECK(loader.load(getTempAllocator(), fixedFilename.toCString()));
+		MeshLoader loader(&getManager());
+		ANKI_CHECK(loader.load(meshfname));
 
 		m_physicsShape = physics.newInstance<PhysicsTriangleSoup>(
 			csInit,

+ 0 - 43
src/resource/Extension.cpp

@@ -1,43 +0,0 @@
-// Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include "anki/resource/Extension.h"
-//#include <dlfcn.h>
-
-namespace anki {
-
-//==============================================================================
-// load                                                                        =
-//==============================================================================
-void Extension::load(const char* /*filename*/)
-{
-	/*// load libary
-	libHandle = dlopen(filename, RTLD_LAZY);
-	if(libHandle == NULL)
-	{
-		throw ANKI_EXCEPTION("File \"" + filename + "\": " + dlerror());
-	}
-	
-	// get FooBar
-	foobarPtr = (int(*)(void*))(dlsym(libHandle, "FooBar"));
-	if(foobarPtr == NULL)
-	{
-		throw ANKI_EXCEPTION("File \"" + filename +
-			"\": \"FooBar\" entry symbol not found: " + dlerror());
-	}*/
-}
-
-//==============================================================================
-// Destructor                                                                  =
-//==============================================================================
-Extension::~Extension()
-{
-	/*//DEBUG_ERR(libHandle==NULL || foobarPtr==NULL);
-	dlclose(libHandle);
-	libHandle = NULL;
-	foobarPtr = NULL;*/
-}
-
-} // end namespace

+ 50 - 59
src/resource/ImageLoader.cpp

@@ -5,7 +5,6 @@
 
 #include "anki/resource/ImageLoader.h"
 #include "anki/util/Logger.h"
-#include "anki/util/File.h"
 #include "anki/util/Filesystem.h"
 #include "anki/util/Assert.h"
 #include "anki/util/Array.h"
@@ -22,13 +21,13 @@ static U8 tgaHeaderCompressed[12] = {0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
 //==============================================================================
 static ANKI_USE_RESULT Error loadUncompressedTga(
-	File& fs, U32& width, U32& height, U32& bpp, DArray<U8>& data,
+	ResourceFilePtr fs, U32& width, U32& height, U32& bpp, DArray<U8>& data,
 	GenericMemoryPoolAllocator<U8>& alloc)
 {
 	Array<U8, 6> header6;
 
 	// read the info from header
-	ANKI_CHECK(fs.read((char*)&header6[0], sizeof(header6)));
+	ANKI_CHECK(fs->read((char*)&header6[0], sizeof(header6)));
 
 	width  = header6[1] * 256 + header6[0];
 	height = header6[3] * 256 + header6[2];
@@ -45,7 +44,7 @@ static ANKI_USE_RESULT Error loadUncompressedTga(
 	I imageSize = bytesPerPxl * width * height;
 	data.create(alloc, imageSize);
 
-	ANKI_CHECK(fs.read(reinterpret_cast<char*>(&data[0]), imageSize));
+	ANKI_CHECK(fs->read(reinterpret_cast<char*>(&data[0]), imageSize));
 
 	// swap red with blue
 	for(I i = 0; i < imageSize; i += bytesPerPxl)
@@ -60,11 +59,11 @@ static ANKI_USE_RESULT Error loadUncompressedTga(
 
 //==============================================================================
 static ANKI_USE_RESULT Error loadCompressedTga(
-	File& fs, U32& width, U32& height, U32& bpp, DArray<U8>& data,
+	ResourceFilePtr fs, U32& width, U32& height, U32& bpp, DArray<U8>& data,
 	GenericMemoryPoolAllocator<U8>& alloc)
 {
 	Array<U8, 6> header6;
-	ANKI_CHECK(fs.read(reinterpret_cast<char*>(&header6[0]), sizeof(header6)));
+	ANKI_CHECK(fs->read(reinterpret_cast<char*>(&header6[0]), sizeof(header6)));
 
 	width  = header6[1] * 256 + header6[0];
 	height = header6[3] * 256 + header6[2];
@@ -89,14 +88,14 @@ static ANKI_USE_RESULT Error loadCompressedTga(
 	{
 		U8 chunkheader = 0;
 
-		ANKI_CHECK(fs.read((char*)&chunkheader, sizeof(U8)));
+		ANKI_CHECK(fs->read((char*)&chunkheader, sizeof(U8)));
 
 		if(chunkheader < 128)
 		{
 			chunkheader++;
 			for(int counter = 0; counter < chunkheader; counter++)
 			{
-				ANKI_CHECK(fs.read((char*)&colorbuffer[0], bytesPerPxl));
+				ANKI_CHECK(fs->read((char*)&colorbuffer[0], bytesPerPxl));
 
 				data[currentbyte] = colorbuffer[2];
 				data[currentbyte + 1] = colorbuffer[1];
@@ -120,7 +119,7 @@ static ANKI_USE_RESULT Error loadCompressedTga(
 		else
 		{
 			chunkheader -= 127;
-			ANKI_CHECK(fs.read((char*)&colorbuffer[0], bytesPerPxl));
+			ANKI_CHECK(fs->read((char*)&colorbuffer[0], bytesPerPxl));
 
 			for(int counter = 0; counter < chunkheader; counter++)
 			{
@@ -150,20 +149,15 @@ static ANKI_USE_RESULT Error loadCompressedTga(
 }
 
 //==============================================================================
-static ANKI_USE_RESULT Error loadTga(const CString& filename, 
+static ANKI_USE_RESULT Error loadTga(ResourceFilePtr fs,
 	U32& width, U32& height, U32& bpp, DArray<U8>& data,
 	GenericMemoryPoolAllocator<U8>& alloc)
 {
-	File fs;
 	char myTgaHeader[12];
 
-	ANKI_CHECK(fs.open(filename, 
-		File::OpenFlag::READ | File::OpenFlag::BINARY));
+	ANKI_CHECK(fs->read(&myTgaHeader[0], sizeof(myTgaHeader)));
 
-	ANKI_CHECK(fs.read(&myTgaHeader[0], sizeof(myTgaHeader)));
-
-	if(std::memcmp(
-		tgaHeaderUncompressed, &myTgaHeader[0], sizeof(myTgaHeader)) == 0)
+	if(memcmp(tgaHeaderUncompressed, &myTgaHeader[0], sizeof(myTgaHeader)) == 0)
 	{
 		ANKI_CHECK(loadUncompressedTga(fs, width, height, bpp, data, alloc));
 	}
@@ -207,12 +201,12 @@ public:
 	U8 m_padding[88];
 };
 
-static_assert(sizeof(AnkiTextureHeader) == 128, 
+static_assert(sizeof(AnkiTextureHeader) == 128,
 	"Check sizeof AnkiTextureHeader");
 
 //==============================================================================
 /// Get the size in bytes of a single surface
-static PtrSize calcSurfaceSize(const U width, const U height, 
+static PtrSize calcSurfaceSize(const U width, const U height,
 	const ImageLoader::DataCompression comp, const ImageLoader::ColorFormat cf)
 {
 	PtrSize out = 0;
@@ -225,7 +219,7 @@ static PtrSize calcSurfaceSize(const U width, const U height,
 		out = width * height * ((cf == ImageLoader::ColorFormat::RGB8) ? 3 : 4);
 		break;
 	case ImageLoader::DataCompression::S3TC:
-		out = (width / 4) * (height / 4) 
+		out = (width / 4) * (height / 4)
 			* ((cf == ImageLoader::ColorFormat::RGB8) ? 8 : 16); // block size
 		break;
 	case ImageLoader::DataCompression::ETC:
@@ -242,7 +236,7 @@ static PtrSize calcSurfaceSize(const U width, const U height,
 
 //==============================================================================
 /// Calculate the size of a compressed or uncomressed color data
-static PtrSize calcSizeOfSegment(const AnkiTextureHeader& header, 
+static PtrSize calcSizeOfSegment(const AnkiTextureHeader& header,
 	ImageLoader::DataCompression comp)
 {
 	PtrSize out = 0;
@@ -272,7 +266,7 @@ static PtrSize calcSizeOfSegment(const AnkiTextureHeader& header,
 
 	while(mips-- != 0)
 	{
-		out += calcSurfaceSize(width, height, comp, header.m_colorFormat) 
+		out += calcSurfaceSize(width, height, comp, header.m_colorFormat)
 			* layers;
 
 		width /= 2;
@@ -284,26 +278,21 @@ static PtrSize calcSizeOfSegment(const AnkiTextureHeader& header,
 
 //==============================================================================
 static ANKI_USE_RESULT Error loadAnkiTexture(
-	const CString& filename, 
+	ResourceFilePtr file,
 	U32 maxTextureSize,
 	ImageLoader::DataCompression& preferredCompression,
 	DArray<ImageLoader::Surface>& surfaces,
 	GenericMemoryPoolAllocator<U8>& alloc,
-	U8& depth, 
-	U8& mipLevels, 
+	U8& depth,
+	U8& mipLevels,
 	ImageLoader::TextureType& textureType,
 	ImageLoader::ColorFormat& colorFormat)
 {
-	File file;
-	ANKI_CHECK(file.open(filename, 
-		File::OpenFlag::READ | File::OpenFlag::BINARY 
-		| File::OpenFlag::LITTLE_ENDIAN));
-
 	//
 	// Read and check the header
 	//
 	AnkiTextureHeader header;
-	ANKI_CHECK(file.read(&header, sizeof(AnkiTextureHeader)));
+	ANKI_CHECK(file->read(&header, sizeof(AnkiTextureHeader)));
 
 	if(std::memcmp(&header.m_magic[0], "ANKITEX1", 8) != 0)
 	{
@@ -311,11 +300,11 @@ static ANKI_USE_RESULT Error loadAnkiTexture(
 		return ErrorCode::USER_DATA;
 	}
 
-	if(header.m_width == 0 
-		|| !isPowerOfTwo(header.m_width) 
+	if(header.m_width == 0
+		|| !isPowerOfTwo(header.m_width)
 		|| header.m_width > 4096
-		|| header.m_height == 0 
-		|| !isPowerOfTwo(header.m_height) 
+		|| header.m_height == 0
+		|| !isPowerOfTwo(header.m_height)
 		|| header.m_height > 4096)
 	{
 		ANKI_LOGE("Incorrect width/height value");
@@ -328,21 +317,21 @@ static ANKI_USE_RESULT Error loadAnkiTexture(
 		return ErrorCode::USER_DATA;
 	}
 
-	if(header.m_type < ImageLoader::TextureType::_2D 
+	if(header.m_type < ImageLoader::TextureType::_2D
 		|| header.m_type > ImageLoader::TextureType::_2D_ARRAY)
 	{
 		ANKI_LOGE("Incorrect header: texture type");
 		return ErrorCode::USER_DATA;
 	}
 
-	if(header.m_colorFormat < ImageLoader::ColorFormat::RGB8 
+	if(header.m_colorFormat < ImageLoader::ColorFormat::RGB8
 		|| header.m_colorFormat > ImageLoader::ColorFormat::RGBA8)
 	{
 		ANKI_LOGE("Incorrect header: color format");
 		return ErrorCode::USER_DATA;
 	}
 
-	if((header.m_compressionFormats & preferredCompression) 
+	if((header.m_compressionFormats & preferredCompression)
 		== ImageLoader::DataCompression::NONE)
 	{
 		ANKI_LOGI("File does not contain the requested compression");
@@ -350,7 +339,7 @@ static ANKI_USE_RESULT Error loadAnkiTexture(
 		// Fallback
 		preferredCompression = ImageLoader::DataCompression::RAW;
 
-		if((header.m_compressionFormats & preferredCompression) 
+		if((header.m_compressionFormats & preferredCompression)
 			== ImageLoader::DataCompression::NONE)
 		{
 			ANKI_LOGI("File does not contain raw compression");
@@ -424,9 +413,9 @@ static ANKI_USE_RESULT Error loadAnkiTexture(
 			!= ImageLoader::DataCompression::NONE)
 		{
 			// If raw compression is present then skip it
-			ANKI_CHECK(file.seek(
-				calcSizeOfSegment(header, ImageLoader::DataCompression::RAW), 
-				File::SeekOrigin::CURRENT));
+			ANKI_CHECK(file->seek(
+				calcSizeOfSegment(header, ImageLoader::DataCompression::RAW),
+				ResourceFile::SeekOrigin::CURRENT));
 		}
 	}
 	else if(preferredCompression == ImageLoader::DataCompression::ETC)
@@ -435,18 +424,18 @@ static ANKI_USE_RESULT Error loadAnkiTexture(
 			!= ImageLoader::DataCompression::NONE)
 		{
 			// If raw compression is present then skip it
-			ANKI_CHECK(file.seek(
-				calcSizeOfSegment(header, ImageLoader::DataCompression::RAW), 
-				File::SeekOrigin::CURRENT));
+			ANKI_CHECK(file->seek(
+				calcSizeOfSegment(header, ImageLoader::DataCompression::RAW),
+				ResourceFile::SeekOrigin::CURRENT));
 		}
 
 		if((header.m_compressionFormats & ImageLoader::DataCompression::S3TC)
 			!= ImageLoader::DataCompression::NONE)
 		{
 			// If s3tc compression is present then skip it
-			ANKI_CHECK(file.seek(
-				calcSizeOfSegment(header, ImageLoader::DataCompression::S3TC), 
-				File::SeekOrigin::CURRENT));
+			ANKI_CHECK(file->seek(
+				calcSizeOfSegment(header, ImageLoader::DataCompression::S3TC),
+				ResourceFile::SeekOrigin::CURRENT));
 		}
 	}
 
@@ -454,7 +443,7 @@ static ANKI_USE_RESULT Error loadAnkiTexture(
 	// It's time to read
 	//
 
-	// Allocate the surfaces 
+	// Allocate the surfaces
 	surfaces.create(alloc, mipLevels * depth);
 
 	// Read all surfaces
@@ -466,7 +455,7 @@ static ANKI_USE_RESULT Error loadAnkiTexture(
 		for(U d = 0; d < depth; d++)
 		{
 			U dataSize = calcSurfaceSize(
-				mipWidth, mipHeight, preferredCompression, 
+				mipWidth, mipHeight, preferredCompression,
 				header.m_colorFormat);
 
 			// Check if this mipmap can be skipped because of size
@@ -478,11 +467,12 @@ static ANKI_USE_RESULT Error loadAnkiTexture(
 
 				surf.m_data.create(alloc, dataSize);
 
-				ANKI_CHECK(file.read(&surf.m_data[0], dataSize));
+				ANKI_CHECK(file->read(&surf.m_data[0], dataSize));
 			}
 			else
 			{
-				ANKI_CHECK(file.seek(dataSize, File::SeekOrigin::CURRENT));
+				ANKI_CHECK(
+					file->seek(dataSize, ResourceFile::SeekOrigin::CURRENT));
 			}
 		}
 
@@ -498,12 +488,13 @@ static ANKI_USE_RESULT Error loadAnkiTexture(
 //==============================================================================
 
 //==============================================================================
-Error ImageLoader::load(const CString& filename, U32 maxTextureSize)
+Error ImageLoader::load(ResourceFilePtr file, const CString& filename,
+	U32 maxTextureSize)
 {
 	// get the extension
 	StringAuto ext(m_alloc);
 	getFileExtension(filename, m_alloc, ext);
-	
+
 	if(ext.isEmpty())
 	{
 		ANKI_LOGE("Failed to get filename extension");
@@ -518,10 +509,10 @@ Error ImageLoader::load(const CString& filename, U32 maxTextureSize)
 	if(ext == "tga")
 	{
 		m_surfaces.create(m_alloc, 1);
-		
+
 		m_mipLevels = 1;
 		m_depth = 1;
-		ANKI_CHECK(loadTga(filename, m_surfaces[0].m_width, 
+		ANKI_CHECK(loadTga(file, m_surfaces[0].m_width,
 			m_surfaces[0].m_height, bpp, m_surfaces[0].m_data, m_alloc));
 
 		if(bpp == 32)
@@ -547,8 +538,8 @@ Error ImageLoader::load(const CString& filename, U32 maxTextureSize)
 		m_compression = ImageLoader::DataCompression::ETC;
 #endif
 
-		ANKI_CHECK(loadAnkiTexture(filename, maxTextureSize, 
-			m_compression, m_surfaces, m_alloc, m_depth, 
+		ANKI_CHECK(loadAnkiTexture(file, maxTextureSize,
+			m_compression, m_surfaces, m_alloc, m_depth,
 			m_mipLevels, m_textureType, m_colorFormat));
 
 	}
@@ -586,7 +577,7 @@ const ImageLoader::Surface& ImageLoader::getSurface(U mipLevel, U layer) const
 
 	// [mip][depthFace]
 	U index = mipLevel * layers + layer;
-	
+
 	ANKI_ASSERT(index < m_surfaces.getSize());
 
 	return m_surfaces[index];

+ 4 - 4
src/resource/Material.cpp

@@ -155,8 +155,8 @@ Error MaterialVariableTemplate<T>::_newInstance(
 
 //==============================================================================
 Material::Material(ResourceManager* manager)
-:	ResourceObject(manager),
-	m_varDict(10, Dictionary<MaterialVariable*>::hasher(),
+	: ResourceObject(manager)
+	, m_varDict(10, Dictionary<MaterialVariable*>::hasher(),
 		Dictionary<MaterialVariable*>::key_equal(), getAllocator())
 {}
 
@@ -347,10 +347,10 @@ Error Material::getProgramPipeline(
 }
 
 //==============================================================================
-Error Material::load(const CString& filename)
+Error Material::load(const ResourceFilename& filename)
 {
 	XmlDocument doc;
-	ANKI_CHECK(doc.loadFile(filename, getTempAllocator()));
+	ANKI_CHECK(openFileParseXml(filename, doc));
 
 	XmlElement el;
 	ANKI_CHECK(doc.getChildElement("material", el));

+ 3 - 3
src/resource/Mesh.cpp

@@ -29,12 +29,12 @@ Bool Mesh::isCompatible(const Mesh& other) const
 }
 
 //==============================================================================
-Error Mesh::load(const CString& filename)
+Error Mesh::load(const ResourceFilename& filename)
 {
 	Error err = ErrorCode::NONE;
 
-	MeshLoader loader;
-	ANKI_CHECK(loader.load(getTempAllocator(), filename));
+	MeshLoader loader(&getManager());
+	ANKI_CHECK(loader.load(filename));
 
 	const MeshLoader::Header& header = loader.getHeader();
 	m_indicesCount = header.m_totalIndicesCount;

+ 28 - 42
src/resource/MeshLoader.cpp

@@ -4,46 +4,32 @@
 // http://www.anki3d.org/LICENSE
 
 #include "anki/resource/MeshLoader.h"
-#include "anki/util/File.h"
+#include "anki/resource/ResourceManager.h"
+#include "anki/resource/ResourceFilesystem.h"
 
 namespace anki {
 
 //==============================================================================
 MeshLoader::~MeshLoader()
 {
+	auto alloc = m_manager->getTempAllocator();
+
 	// WARNING: Watch the order of deallocation. Reverse of the deallocation to
 	// have successful cleanups
-	m_verts.destroy(m_alloc);
-	m_indices.destroy(m_alloc);
-	m_subMeshes.destroy(m_alloc);
-}
-
-//==============================================================================
-Error MeshLoader::load(
-	GenericMemoryPoolAllocator<U8> alloc,
-	const CString& filename)
-{
-	m_alloc = alloc;
-	
-	Error err = loadInternal(filename);
-	if(err)
-	{
-		ANKI_LOGE("Failed to load mesh %s", &filename[0]);
-	}
-
-	return err;
+	m_verts.destroy(alloc);
+	m_indices.destroy(alloc);
+	m_subMeshes.destroy(alloc);
 }
 
 //==============================================================================
-Error MeshLoader::loadInternal(const CString& filename)
+Error MeshLoader::load(const ResourceFilename& filename)
 {
-	File file;
-	ANKI_CHECK(file.open(filename, 
-		File::OpenFlag::READ | File::OpenFlag::BINARY 
-		| File::OpenFlag::LITTLE_ENDIAN));
+	auto alloc = m_manager->getTempAllocator();
 
 	// Load header
-	ANKI_CHECK(file.read(&m_header, sizeof(m_header)));
+	ResourceFilePtr file;
+	ANKI_CHECK(m_manager->getFilesystem().openFile(filename, file));
+	ANKI_CHECK(file->read(&m_header, sizeof(m_header)));
 
 	//
 	// Check header
@@ -114,9 +100,9 @@ Error MeshLoader::loadInternal(const CString& filename)
 		hasBoneInfo = true;
 
 		// Bone weights
-		if(m_header.m_boneWeightsFormat.m_components 
+		if(m_header.m_boneWeightsFormat.m_components
 			!= ComponentFormat::R8G8B8A8
-			|| m_header.m_boneWeightsFormat.m_transform 
+			|| m_header.m_boneWeightsFormat.m_transform
 			!= FormatTransform::UNORM)
 		{
 			ANKI_LOGE("Incorrect/unsupported UVs format");
@@ -124,9 +110,9 @@ Error MeshLoader::loadInternal(const CString& filename)
 		}
 
 		// Bone indices
-		if(m_header.m_boneIndicesFormat.m_components 
+		if(m_header.m_boneIndicesFormat.m_components
 			!= ComponentFormat::R16G16B16A16
-			|| m_header.m_boneIndicesFormat.m_transform 
+			|| m_header.m_boneIndicesFormat.m_transform
 			!= FormatTransform::UINT)
 		{
 			ANKI_LOGE("Incorrect/unsupported UVs format");
@@ -138,9 +124,9 @@ Error MeshLoader::loadInternal(const CString& filename)
 		// No bone info
 
 		// Bone weights
-		if(m_header.m_boneWeightsFormat.m_components 
+		if(m_header.m_boneWeightsFormat.m_components
 			!= ComponentFormat::NONE
-			|| m_header.m_boneWeightsFormat.m_transform 
+			|| m_header.m_boneWeightsFormat.m_transform
 			!= FormatTransform::NONE)
 		{
 			ANKI_LOGE("Incorrect/unsupported UVs format");
@@ -148,9 +134,9 @@ Error MeshLoader::loadInternal(const CString& filename)
 		}
 
 		// Bone indices
-		if(m_header.m_boneIndicesFormat.m_components 
+		if(m_header.m_boneIndicesFormat.m_components
 			!= ComponentFormat::NONE
-			|| m_header.m_boneIndicesFormat.m_transform 
+			|| m_header.m_boneIndicesFormat.m_transform
 			!= FormatTransform::NONE)
 		{
 			ANKI_LOGE("Incorrect/unsupported UVs format");
@@ -192,8 +178,8 @@ Error MeshLoader::loadInternal(const CString& filename)
 	//
 	// Read submesh info
 	//
-	m_subMeshes.create(m_alloc, m_header.m_subMeshCount);
-	ANKI_CHECK(file.read(&m_subMeshes[0], m_subMeshes.getSizeInBytes()));
+	m_subMeshes.create(alloc, m_header.m_subMeshCount);
+	ANKI_CHECK(file->read(&m_subMeshes[0], m_subMeshes.getSizeInBytes()));
 
 	// Checks
 	U idxSum = 0;
@@ -219,28 +205,28 @@ Error MeshLoader::loadInternal(const CString& filename)
 	//
 	// Read indices
 	//
-	m_indices.create(m_alloc, m_header.m_totalIndicesCount * sizeof(U16));
-	ANKI_CHECK(file.read(&m_indices[0], m_indices.getSizeInBytes()));
+	m_indices.create(alloc, m_header.m_totalIndicesCount * sizeof(U16));
+	ANKI_CHECK(file->read(&m_indices[0], m_indices.getSizeInBytes()));
 
 	//
 	// Read vertices
 	//
-	m_vertSize = 
+	m_vertSize =
 		3 * sizeof(F32) // pos
 		+ 1 * sizeof(U32) // norm
 		+ 1 * sizeof(U32) // tang
 		+ 2 * sizeof(U16) // uvs
 		+ ((hasBoneInfo) ? (4 * sizeof(U8) + 4 * sizeof(U16)) : 0);
 
-	m_verts.create(m_alloc, m_header.m_totalVerticesCount * m_vertSize);
-	ANKI_CHECK(file.read(&m_verts[0], m_verts.getSizeInBytes()));
+	m_verts.create(alloc, m_header.m_totalVerticesCount * m_vertSize);
+	ANKI_CHECK(file->read(&m_verts[0], m_verts.getSizeInBytes()));
 
 	return ErrorCode::NONE;
 }
 
 //==============================================================================
 Error MeshLoader::checkFormat(
-	const Format& fmt, 
+	const Format& fmt,
 	const CString& attrib,
 	Bool cannotBeEmpty)
 {

+ 2 - 2
src/resource/Model.cpp

@@ -259,7 +259,7 @@ Model::~Model()
 }
 
 //==============================================================================
-Error Model::load(const CString& filename)
+Error Model::load(const ResourceFilename& filename)
 {
 	auto alloc = getAllocator();
 
@@ -267,7 +267,7 @@ Error Model::load(const CString& filename)
 	//
 	XmlElement el;
 	XmlDocument doc;
-	ANKI_CHECK(doc.loadFile(filename, getTempAllocator()));
+	ANKI_CHECK(openFileParseXml(filename, doc));
 
 	XmlElement rootEl;
 	ANKI_CHECK(doc.getChildElement("model", rootEl));

+ 2 - 2
src/resource/ParticleEmitterResource.cpp

@@ -113,12 +113,12 @@ ParticleEmitterResource::~ParticleEmitterResource()
 {}
 
 //==============================================================================
-Error ParticleEmitterResource::load(const CString& filename)
+Error ParticleEmitterResource::load(const ResourceFilename& filename)
 {
 	U32 tmp;
 
 	XmlDocument doc;
-	ANKI_CHECK(doc.loadFile(filename, getTempAllocator()));
+	ANKI_CHECK(openFileParseXml(filename, doc));
 	XmlElement rel; // Root element
 	ANKI_CHECK(doc.getChildElement("particleEmitter", rel));
 

+ 12 - 14
src/resource/ProgramPrePreprocessor.cpp

@@ -5,6 +5,7 @@
 
 #include "anki/resource/ProgramPrePreprocessor.h"
 #include "anki/resource/ResourceManager.h"
+#include "anki/resource/ResourceFilesystem.h"
 #include "anki/util/Functions.h"
 #include "anki/util/File.h"
 #include "anki/util/Array.h"
@@ -17,7 +18,7 @@ namespace anki {
 // Keep the strings in that order so that the start pragmas will match to the
 // ShaderType enums
 static Array<const char*, 7> commands = {{
-	"#pragma anki type vert", 
+	"#pragma anki type vert",
 	"#pragma anki type tesc",
 	"#pragma anki type tese",
 	"#pragma anki type geom",
@@ -40,7 +41,7 @@ void ProgramPrePreprocessor::printSourceLines() const
 }
 
 //==============================================================================
-Error ProgramPrePreprocessor::parseFile(const CString& filename)
+Error ProgramPrePreprocessor::parseFile(const ResourceFilename& filename)
 {
 	// Parse files recursively
 	Error err = parseFileForPragmas(filename, 0);
@@ -49,13 +50,13 @@ Error ProgramPrePreprocessor::parseFile(const CString& filename)
 	{
 		m_sourceLines.join(m_alloc, "\n", m_shaderSource);
 	}
-	
+
 	return err;
 }
 
 //==============================================================================
 Error ProgramPrePreprocessor::parseFileForPragmas(
-	CString filename, U32 depth)
+	ResourceFilename filename, U32 depth)
 {
 	// first check the depth
 	if(depth > MAX_DEPTH)
@@ -69,9 +70,9 @@ Error ProgramPrePreprocessor::parseFileForPragmas(
 	StringAuto txt(m_alloc);
 	StringListAuto lines(m_alloc);
 
-	File file;
-	ANKI_CHECK(file.open(filename, File::OpenFlag::READ));
-	ANKI_CHECK(file.readAllText(TempResourceAllocator<char>(m_alloc), txt));
+	ResourceFilePtr file;
+	ANKI_CHECK(m_manager->getFilesystem().openFile(filename, file));
+	ANKI_CHECK(file->readAllText(TempResourceAllocator<char>(m_alloc), txt));
 	lines.splitString(txt.toCString(), '\n');
 	if(lines.getSize() < 1)
 	{
@@ -100,18 +101,15 @@ Error ProgramPrePreprocessor::parseFileForPragmas(
 				if(line.getLength() >= std::strlen(commands[6]) + 2)
 				{
 					StringAuto filen(m_alloc);
-					
+
 					filen.create(
-						line.begin() + std::strlen(commands[6]), 
+						line.begin() + std::strlen(commands[6]),
 						line.end() - 1);
 
 					StringAuto filenFixed(m_alloc);
 
-					m_manager->fixResourceFilename(
-						filen.toCString(), filenFixed);
-
-					ANKI_CHECK(parseFileForPragmas(
-						filenFixed.toCString(), depth + 1));
+					ANKI_CHECK(
+						parseFileForPragmas(filen.toCString(), depth + 1));
 
 					malformed = false; // All OK
 				}

+ 1 - 1
src/resource/ResourceFilesystem.cpp

@@ -319,7 +319,7 @@ Error ResourceFilesystem::addNewPath(const CString& path)
 
 //==============================================================================
 Error ResourceFilesystem::openFile(
-	const CString& filename, ResourceFilePtr& filePtr)
+	const ResourceFilename& filename, ResourceFilePtr& filePtr)
 {
 	ResourceFile* rfile = nullptr;
 	Error err = ErrorCode::NONE;

+ 0 - 34
src/resource/ResourceManager.cpp

@@ -27,7 +27,6 @@ ResourceManager::ResourceManager()
 ResourceManager::~ResourceManager()
 {
 	m_cacheDir.destroy(m_alloc);
-	m_dataDir.destroy(m_alloc);
 	m_alloc.deleteInstance(m_asyncLoader);
 }
 
@@ -48,23 +47,6 @@ Error ResourceManager::create(Initializer& init)
 
 	m_cacheDir.create(m_alloc, init.m_cacheDir);
 
-	// Init the data path
-	//
-	if(getenv("ANKI_DATA_PATH"))
-	{
-		m_dataDir.sprintf(m_alloc, "%s/", getenv("ANKI_DATA_PATH"));
-		ANKI_LOGI("Data path: %s", &m_dataDir[0]);
-	}
-	else
-	{
-		// Assume working directory
-#if ANKI_OS == ANKI_OS_ANDROID
-		m_dataDir.create(m_alloc, "$");
-#else
-		m_dataDir.create(m_alloc, "./");
-#endif
-	}
-
 	// Init some constants
 	//
 	m_maxTextureSize = init.m_config->getNumber("maxTextureSize");
@@ -97,20 +79,4 @@ Error ResourceManager::create(Initializer& init)
 	return err;
 }
 
-//==============================================================================
-void ResourceManager::fixResourceFilename(
-	const CString& filename,
-	StringAuto& out) const
-{
-	// If the filename is in cache then dont append the data path
-	if(filename.find(m_cacheDir.toCString()) != String::NPOS)
-	{
-		out.create(filename);
-	}
-	else
-	{
-		out.sprintf("%s%s", &m_dataDir[0], &filename[0]);
-	}
-}
-
 } // end namespace anki

+ 16 - 1
src/resource/ResourceObject.cpp

@@ -5,6 +5,7 @@
 
 #include "anki/resource/ResourceObject.h"
 #include "anki/resource/ResourceManager.h"
+#include "anki/misc/Xml.h"
 
 namespace anki {
 
@@ -34,7 +35,8 @@ Error ResourceObject::openFile(const CString& filename, ResourceFilePtr& file)
 
 //==============================================================================
 Error ResourceObject::openFileReadAllText(
-	const CString& filename, StringAuto& text)
+	const CString& filename,
+	StringAuto& text)
 {
 	// Load file
 	ResourceFilePtr file;
@@ -47,4 +49,17 @@ Error ResourceObject::openFileReadAllText(
 	return ErrorCode::NONE;
 }
 
+//==============================================================================
+Error ResourceObject::openFileParseXml(
+	const CString& filename,
+	XmlDocument& xml)
+{
+	StringAuto txt(getTempAllocator());
+	ANKI_CHECK(openFileReadAllText(filename, txt));
+
+	ANKI_CHECK(xml.parse(txt.toCString(), getTempAllocator()));
+
+	return ErrorCode::NONE;
+}
+
 } // end namespace anki

+ 4 - 4
src/resource/Script.cpp

@@ -15,12 +15,12 @@ Script::~Script()
 }
 
 //==============================================================================
-Error Script::load(const CString& filename)
+Error Script::load(const ResourceFilename& filename)
 {
-	File file;
+	ResourceFilePtr file;
+	ANKI_CHECK(openFile(filename, file));
 
-	ANKI_CHECK(file.open(filename, File::OpenFlag::READ));
-	ANKI_CHECK(file.readAllText(getAllocator(), m_source));
+	ANKI_CHECK(file->readAllText(getAllocator(), m_source));
 
 	return ErrorCode::NONE;
 }

+ 14 - 14
src/resource/ShaderResource.cpp

@@ -15,13 +15,14 @@
 namespace anki {
 
 //==============================================================================
-Error ShaderResource::load(const CString& filename)
+Error ShaderResource::load(const ResourceFilename& filename)
 {
 	return load(filename, " ");
 }
 
 //==============================================================================
-Error ShaderResource::load(const CString& filename, const CString& extraSrc)
+Error ShaderResource::load(const ResourceFilename& filename,
+	const CString& extraSrc)
 {
 	auto alloc = getTempAllocator();
 
@@ -53,7 +54,7 @@ Error ShaderResource::load(const CString& filename, const CString& extraSrc)
 
 //==============================================================================
 Error ShaderResource::createToCache(
-	const CString& filename, const CString& preAppendedSrcCode,
+	const ResourceFilename& filename, const CString& preAppendedSrcCode,
 	const CString& filenamePrefix, ResourceManager& manager,
 	StringAuto& out)
 {
@@ -61,6 +62,7 @@ Error ShaderResource::createToCache(
 
 	if(preAppendedSrcCode.getLength() < 1)
 	{
+		// Early exit, nothing to mutate
 		out.create(filename);
 		return ErrorCode::NONE;
 	}
@@ -76,30 +78,29 @@ Error ShaderResource::createToCache(
 	StringAuto suffix(alloc);
 	suffix.toString(h);
 
+	// Create out
+	out = std::move(StringAuto(alloc));
+	out.sprintf("%s%s.glsl", &filenamePrefix[0], &suffix[0]);
+
 	// Compose cached filename
 	StringAuto newFilename(alloc);
 
 	newFilename.sprintf(
-		"%s/%s%s.glsl",
+		"%s/%s",
 		&manager._getCacheDirectory()[0],
-		&filenamePrefix[0],
-		&suffix[0]);
+		&out[0]);
 
 	if(fileExists(newFilename.toCString()))
 	{
-		out = std::move(newFilename);
 		return ErrorCode::NONE;
 	}
 
 	// Read file and append code
 	StringAuto src(alloc);
 
-	StringAuto fixedFname(alloc);
-	manager.fixResourceFilename(filename, fixedFname);
-
-	File file;
-	ANKI_CHECK(file.open(fixedFname.toCString(), File::OpenFlag::READ));
-	ANKI_CHECK(file.readAllText(TempResourceAllocator<char>(alloc), src));
+	ResourceFilePtr file;
+	ANKI_CHECK(manager.getFilesystem().openFile(filename, file));
+	ANKI_CHECK(file->readAllText(alloc, src));
 
 	StringAuto srcfull(alloc);
 	srcfull.sprintf("%s%s", &preAppendedSrcCode[0], &src[0]);
@@ -109,7 +110,6 @@ Error ShaderResource::createToCache(
 	ANKI_CHECK(f.open(newFilename.toCString(), File::OpenFlag::WRITE));
 	ANKI_CHECK(f.writeText("%s\n", &srcfull[0]));
 
-	out = std::move(newFilename);
 	return ErrorCode::NONE;
 }
 

+ 3 - 3
src/resource/Skeleton.cpp

@@ -21,10 +21,10 @@ Skeleton::~Skeleton()
 }
 
 //==============================================================================
-Error Skeleton::load(const CString& filename)
+Error Skeleton::load(const ResourceFilename& filename)
 {
 	XmlDocument doc;
-	ANKI_CHECK(doc.loadFile(filename, getTempAllocator()));
+	ANKI_CHECK(openFileParseXml(filename, doc));
 
 	XmlElement rootEl;
 	ANKI_CHECK(doc.getChildElement("skeleton", rootEl));
@@ -59,7 +59,7 @@ Error Skeleton::load(const CString& filename)
 		ANKI_CHECK(boneEl.getChildElement("transform", trfEl));
 		ANKI_CHECK(trfEl.getMat4(bone.m_transform));
 
-		// Advance 
+		// Advance
 		ANKI_CHECK(boneEl.getNextSiblingElement("bone", boneEl));
 	} while(boneEl);
 

+ 10 - 22
src/resource/TextureResource.cpp

@@ -9,21 +9,12 @@
 
 namespace anki {
 
-//==============================================================================
-static Error deleteImageCallback(void* data)
-{
-	ImageLoader* image = reinterpret_cast<ImageLoader*>(data);
-	auto alloc = image->getAllocator();
-	alloc.deleteInstance(image);
-	return ErrorCode::NONE;
-}
-
 //==============================================================================
 TextureResource::~TextureResource()
 {}
 
 //==============================================================================
-Error TextureResource::load(const CString& filename)
+Error TextureResource::load(const ResourceFilename& filename)
 {
 	GrManager& gr = getManager().getGrManager();
 	CommandBufferPtr cmdb;
@@ -35,14 +26,13 @@ Error TextureResource::load(const CString& filename)
 	U layers = 0;
 
 	// Load image
-	ImageLoader* img = getAllocator().newInstance<ImageLoader>(getAllocator());
+	UniquePtr<ImageLoader> img;
+	img.reset(getAllocator().newInstance<ImageLoader>(getAllocator()));
 
-	Error err = img->load(filename, getManager().getMaxTextureSize());
-	if(err)
-	{
-		getAllocator().deleteInstance(img);
-		return err;
-	}
+	ResourceFilePtr file;
+	ANKI_CHECK(openFile(filename, file));
+
+	ANKI_CHECK(img->load(file, filename, getManager().getMaxTextureSize()));
 
 	// width + height
 	const auto& tmpSurf = img->getSurface(0, 0);
@@ -162,15 +152,13 @@ Error TextureResource::load(const CString& filename)
 	// Add the GL job to create the texture
 	m_tex.create(cmdb, init);
 
-	// Add cleanup job
-	cmdb.pushBackUserCommand(deleteImageCallback, img);
-
 	// Finaly enque the GL job chain
-	cmdb.flush();
+	// TODO Make asynchronous
+	cmdb.finish();
 
 	m_size = UVec3(init.m_width, init.m_height, init.m_depth);
 
-	return err;
+	return ErrorCode::NONE;
 }
 
 } // end namespace anki

+ 7 - 11
src/scene/Sector.cpp

@@ -36,7 +36,7 @@ PortalSectorBase::~PortalSectorBase()
 }
 
 //==============================================================================
-Error PortalSectorBase::create(const CString& name, const CString& modelFname)
+Error PortalSectorBase::create(const CString& name, const CString& meshFname)
 {
 	ANKI_CHECK(SceneNode::create(name));
 
@@ -49,12 +49,8 @@ Error PortalSectorBase::create(const CString& name, const CString& modelFname)
 	addComponent(comp, true);
 
 	// Load mesh
-	StringAuto newFname(getFrameAllocator());
-	getSceneGraph()._getResourceManager().fixResourceFilename(
-		modelFname, newFname);
-
-	MeshLoader loader;
-	ANKI_CHECK(loader.load(getFrameAllocator(), newFname.toCString()));
+	MeshLoader loader(&getSceneGraph()._getResourceManager());
+	ANKI_CHECK(loader.load(meshFname));
 
 	// Convert Vec3 positions to Vec4
 	const MeshLoader::Header& header = loader.getHeader();
@@ -141,9 +137,9 @@ Portal::~Portal()
 }
 
 //==============================================================================
-Error Portal::create(const CString& name, const CString& modelFname)
+Error Portal::create(const CString& name, const CString& meshFname)
 {
-	ANKI_CHECK(Base::create(name, modelFname));
+	ANKI_CHECK(Base::create(name, meshFname));
 	getSectorGroup().m_portals.pushBack(getSceneAllocator(), this);
 	return ErrorCode::NONE;
 }
@@ -267,9 +263,9 @@ Sector::~Sector()
 }
 
 //==============================================================================
-Error Sector::create(const CString& name, const CString& modelFname)
+Error Sector::create(const CString& name, const CString& meshFname)
 {
-	ANKI_CHECK(PortalSectorBase::create(name, modelFname));
+	ANKI_CHECK(PortalSectorBase::create(name, meshFname));
 	getSectorGroup().m_sectors.pushBack(getSceneAllocator(), this);
 	return ErrorCode::NONE;
 }

+ 1 - 0
testapp/Main.cpp

@@ -509,6 +509,7 @@ Error initSubsystems(int argc, char* argv[])
 	//config.set("maxTextureSize", 256);
 	config.set("fullscreenDesktopResolution", false);
 	config.set("debugContext", false);
+	config.set("dataPaths", ".:assets");
 
 	app = new App;
 	err = app->create(config, allocAligned, nullptr);