Browse Source

Move the GLTF importer to libanki

Panagiotis Christopoulos Charitos 6 years ago
parent
commit
68d4bc1259

+ 3 - 2
CMakeLists.txt

@@ -409,10 +409,11 @@ if(SDL)
 endif()
 
 set(THIRD_PARTY_LIBS ${THIRD_PARTY_LIBS} BulletSoftBody BulletDynamics BulletCollision LinearMath
-	ankispirvcross ankitinyxml2 ankilua ankiz glslang SPIRV OGLCompiler OSDependent ankitinyexpr ankiimgui)
+	ankispirvcross ankitinyxml2 ankilua ankimeshoptimizer ankiz glslang SPIRV OGLCompiler OSDependent ankitinyexpr
+	ankiimgui)
 
 # Add anki sub libraries
-set(ANKI_SUB_DIRS core script renderer scene ui input physics resource misc gr collision math util)
+set(ANKI_SUB_DIRS importer core script renderer scene ui input physics resource misc gr collision math util)
 foreach(TMP ${ANKI_SUB_DIRS})
 	add_subdirectory(src/anki/${TMP})
 endforeach()

+ 1 - 1
samples/sponza/assets/arch.001.ankimtl

@@ -21,7 +21,7 @@
 		<input shaderInput="diffTex" value="assets/sponza_arch_diff.ankitex"/>
 		<input shaderInput="specColor" value="0.040000 0.040000 0.040000"/>
 		<input shaderInput="roughnessTex" value="assets/sponza_arch_spec.ankitex"/>
-		<input shaderInput="metallic" value="0.000000" />
+		<input shaderInput="metallic" value="0.000000"/>
 		<input shaderInput="normalTex" value="assets/sponza_arch_ddn.ankitex"/>
 		<input shaderInput="emission" value="0.000000 0.000000 0.000000"/>
 		<input shaderInput="subsurface" value="0.000000"/>

+ 1 - 1
samples/sponza/assets/arch.ankimtl

@@ -21,7 +21,7 @@
 		<input shaderInput="diffTex" value="assets/sponza_arch_diff_tga.ankitex"/>
 		<input shaderInput="specColor" value="0.040000 0.040000 0.040000"/>
 		<input shaderInput="roughnessTex" value="assets/sponza_arch_spec_tga.ankitex"/>
-		<input shaderInput="metallic" value="0.000000" />
+		<input shaderInput="metallic" value="0.000000"/>
 		<input shaderInput="normalTex" value="assets/sponza_arch_ddn_tga.ankitex"/>
 		<input shaderInput="emission" value="0.000000 0.000000 0.000000"/>
 		<input shaderInput="subsurface" value="0.000000"/>

+ 1 - 1
samples/sponza/assets/bricks.ankimtl

@@ -21,7 +21,7 @@
 		<input shaderInput="diffTex" value="assets/sponza_bricks_a_diff_tga.ankitex"/>
 		<input shaderInput="specColor" value="0.040000 0.040000 0.040000"/>
 		<input shaderInput="roughnessTex" value="assets/sponza_arch_spec_tga.ankitex"/>
-		<input shaderInput="metallic" value="0.000000" />
+		<input shaderInput="metallic" value="0.000000"/>
 		<input shaderInput="normalTex" value="assets/sponza_bricks_a_ddn_tga.ankitex"/>
 		<input shaderInput="emission" value="0.000000 0.000000 0.000000"/>
 		<input shaderInput="subsurface" value="0.000000"/>

+ 1 - 1
samples/sponza/assets/ceiling.ankimtl

@@ -21,7 +21,7 @@
 		<input shaderInput="diffTex" value="assets/sponza_ceiling_a_diff_tga.ankitex"/>
 		<input shaderInput="specColor" value="0.040000 0.040000 0.040000"/>
 		<input shaderInput="roughnessTex" value="assets/Sponza_Ceiling_roughness_tga.ankitex"/>
-		<input shaderInput="metallic" value="0.000000" />
+		<input shaderInput="metallic" value="0.000000"/>
 		
 		<input shaderInput="emission" value="0.000000 0.000000 0.000000"/>
 		<input shaderInput="subsurface" value="0.000000"/>

+ 2 - 2
samples/sponza/assets/chain.ankimtl

@@ -20,8 +20,8 @@
 
 		<input shaderInput="diffTex" value="assets/chain_texture_tga.ankitex"/>
 		<input shaderInput="specColor" value="0.040000 0.040000 0.040000"/>
-		<input shaderInput="roughness" value="0.500000" />
-		<input shaderInput="metallic" value="0.000000" />
+		<input shaderInput="roughness" value="0.500000"/>
+		<input shaderInput="metallic" value="0.000000"/>
 		
 		<input shaderInput="emission" value="0.000000 0.000000 0.000000"/>
 		<input shaderInput="subsurface" value="0.000000"/>

+ 1 - 1
samples/sponza/assets/column_a.ankimtl

@@ -21,7 +21,7 @@
 		<input shaderInput="diffTex" value="assets/sponza_column_a_diff_tga.ankitex"/>
 		<input shaderInput="specColor" value="0.040000 0.040000 0.040000"/>
 		<input shaderInput="roughnessTex" value="assets/sponza_column_a_spec_tga.ankitex"/>
-		<input shaderInput="metallic" value="0.000000" />
+		<input shaderInput="metallic" value="0.000000"/>
 		<input shaderInput="normalTex" value="assets/sponza_column_a_ddn_tga.ankitex"/>
 		<input shaderInput="emission" value="0.000000 0.000000 0.000000"/>
 		<input shaderInput="subsurface" value="0.000000"/>

+ 1 - 1
samples/sponza/assets/column_b.ankimtl

@@ -21,7 +21,7 @@
 		<input shaderInput="diffTex" value="assets/sponza_column_b_diff_tga.ankitex"/>
 		<input shaderInput="specColor" value="0.040000 0.040000 0.040000"/>
 		<input shaderInput="roughnessTex" value="assets/Sponza_Column_b_roughness_tga.ankitex"/>
-		<input shaderInput="metallic" value="0.000000" />
+		<input shaderInput="metallic" value="0.000000"/>
 		<input shaderInput="normalTex" value="assets/sponza_column_b_ddn_tga.ankitex"/>
 		<input shaderInput="emission" value="0.000000 0.000000 0.000000"/>
 		<input shaderInput="subsurface" value="0.000000"/>

+ 1 - 1
samples/sponza/assets/column_c.ankimtl

@@ -21,7 +21,7 @@
 		<input shaderInput="diffTex" value="assets/sponza_column_c_diff_tga.ankitex"/>
 		<input shaderInput="specColor" value="0.040000 0.040000 0.040000"/>
 		<input shaderInput="roughnessTex" value="assets/Sponza_Column_c_roughness_tga.ankitex"/>
-		<input shaderInput="metallic" value="0.000000" />
+		<input shaderInput="metallic" value="0.000000"/>
 		<input shaderInput="normalTex" value="assets/sponza_column_c_ddn_tga.ankitex"/>
 		<input shaderInput="emission" value="0.000000 0.000000 0.000000"/>
 		<input shaderInput="subsurface" value="0.000000"/>

+ 1 - 1
samples/sponza/assets/fabric_f.ankimtl

@@ -21,7 +21,7 @@
 		<input shaderInput="diffTex" value="assets/sponza_curtain_green_diff_tga.ankitex"/>
 		<input shaderInput="specColor" value="0.040000 0.040000 0.040000"/>
 		<input shaderInput="roughnessTex" value="assets/Sponza_Curtain_roughness_tga_001.ankitex"/>
-		<input shaderInput="metallic" value="0.000000" />
+		<input shaderInput="metallic" value="0.000000"/>
 		<input shaderInput="normalTex" value="assets/Sponza_Curtain_Red_normal_tga_001.ankitex"/>
 		<input shaderInput="emission" value="0.000000 0.000000 0.000000"/>
 		<input shaderInput="subsurface" value="0.250000"/>

+ 1 - 1
samples/sponza/assets/flagpole.ankimtl

@@ -21,7 +21,7 @@
 		<input shaderInput="diffTex" value="assets/sponza_flagpole_diff.ankitex"/>
 		<input shaderInput="specColor" value="0.040000 0.040000 0.040000"/>
 		<input shaderInput="roughnessTex" value="assets/Sponza_FlagPole_roughness.ankitex"/>
-		<input shaderInput="metallic" value="0.000000" />
+		<input shaderInput="metallic" value="0.000000"/>
 		<input shaderInput="normalTex" value="assets/Sponza_FlagPole_normal.ankitex"/>
 		<input shaderInput="emission" value="0.000000 0.000000 0.000000"/>
 		<input shaderInput="subsurface" value="0.000000"/>

+ 1 - 1
samples/sponza/assets/floor.ankimtl

@@ -21,7 +21,7 @@
 		<input shaderInput="diffTex" value="assets/sponza_floor_a_diff.ankitex"/>
 		<input shaderInput="specColor" value="0.040000 0.040000 0.040000"/>
 		<input shaderInput="roughnessTex" value="assets/Sponza_Floor_roughness.ankitex"/>
-		<input shaderInput="metallic" value="0.000000" />
+		<input shaderInput="metallic" value="0.000000"/>
 		<input shaderInput="normalTex" value="assets/Sponza_Floor_normal.ankitex"/>
 		<input shaderInput="emission" value="0.000000 0.000000 0.000000"/>
 		<input shaderInput="subsurface" value="0.000000"/>

+ 1 - 1
samples/sponza/assets/leaf.ankimtl

@@ -21,7 +21,7 @@
 		<input shaderInput="diffTex" value="assets/sponza_thorn_diff.ankitex"/>
 		<input shaderInput="specColor" value="0.040000 0.040000 0.040000"/>
 		<input shaderInput="roughnessTex" value="assets/Sponza_Thorn_roughness.ankitex"/>
-		<input shaderInput="metallic" value="0.000000" />
+		<input shaderInput="metallic" value="0.000000"/>
 		<input shaderInput="normalTex" value="assets/sponza_thorn_ddn.ankitex"/>
 		<input shaderInput="emission" value="0.000000 0.000000 0.000000"/>
 		<input shaderInput="subsurface" value="0.100000"/>

+ 1 - 1
samples/sponza/assets/lion.ankimtl

@@ -21,7 +21,7 @@
 		<input shaderInput="diffTex" value="assets/lion.ankitex"/>
 		<input shaderInput="specColor" value="0.040000 0.040000 0.040000"/>
 		<input shaderInput="roughnessTex" value="assets/Lion_Roughness.ankitex"/>
-		<input shaderInput="metallic" value="0.000000" />
+		<input shaderInput="metallic" value="0.000000"/>
 		<input shaderInput="normalTex" value="assets/lion_ddn.ankitex"/>
 		<input shaderInput="emission" value="0.000000 0.000000 0.000000"/>
 		<input shaderInput="subsurface" value="0.000000"/>

+ 1 - 1
samples/sponza/assets/lion_stand.ankimtl

@@ -21,7 +21,7 @@
 		<input shaderInput="diffTex" value="assets/background.ankitex"/>
 		<input shaderInput="specColor" value="0.040000 0.040000 0.040000"/>
 		<input shaderInput="roughnessTex" value="assets/Background_Roughness.ankitex"/>
-		<input shaderInput="metallic" value="0.000000" />
+		<input shaderInput="metallic" value="0.000000"/>
 		<input shaderInput="normalTex" value="assets/background_ddn.ankitex"/>
 		<input shaderInput="emission" value="0.000000 0.000000 0.000000"/>
 		<input shaderInput="subsurface" value="0.000000"/>

+ 1 - 1
samples/sponza/assets/roof.ankimtl

@@ -21,7 +21,7 @@
 		<input shaderInput="diffTex" value="assets/sponza_roof_diff.ankitex"/>
 		<input shaderInput="specColor" value="0.040000 0.040000 0.040000"/>
 		<input shaderInput="roughnessTex" value="assets/Sponza_Roof_roughness.ankitex"/>
-		<input shaderInput="metallic" value="0.000000" />
+		<input shaderInput="metallic" value="0.000000"/>
 		<input shaderInput="normalTex" value="assets/Sponza_Roof_normal.ankitex"/>
 		<input shaderInput="emission" value="0.000000 0.000000 0.000000"/>
 		<input shaderInput="subsurface" value="0.000000"/>

+ 2 - 2
samples/sponza/assets/sky.ankimtl

@@ -20,8 +20,8 @@
 
 		<input shaderInput="diffColor" value="0.352369 0.517735 0.800000"/>
 		<input shaderInput="specColor" value="0.040000 0.040000 0.040000"/>
-		<input shaderInput="roughness" value="0.500000" />
-		<input shaderInput="metallic" value="0.000000" />
+		<input shaderInput="roughness" value="0.500000"/>
+		<input shaderInput="metallic" value="0.000000"/>
 		
 		<input shaderInput="emission" value="10.000000 10.000000 10.000000"/>
 		<input shaderInput="subsurface" value="0.000000"/>

+ 1 - 1
samples/sponza/assets/vase.ankimtl

@@ -21,7 +21,7 @@
 		<input shaderInput="diffTex" value="assets/vase_dif.ankitex"/>
 		<input shaderInput="specColor" value="0.040000 0.040000 0.040000"/>
 		<input shaderInput="roughnessTex" value="assets/Vase_roughness.ankitex"/>
-		<input shaderInput="metallic" value="0.000000" />
+		<input shaderInput="metallic" value="0.000000"/>
 		<input shaderInput="normalTex" value="assets/vase_ddn.ankitex"/>
 		<input shaderInput="emission" value="0.000000 0.000000 0.000000"/>
 		<input shaderInput="subsurface" value="0.000000"/>

+ 1 - 1
samples/sponza/assets/vase_fl.ankimtl

@@ -21,7 +21,7 @@
 		<input shaderInput="diffTex" value="assets/vase_plant_tga.ankitex"/>
 		<input shaderInput="specColor" value="0.040000 0.040000 0.040000"/>
 		<input shaderInput="roughnessTex" value="assets/VaseRound_roughness.ankitex"/>
-		<input shaderInput="metallic" value="0.000000" />
+		<input shaderInput="metallic" value="0.000000"/>
 		<input shaderInput="normalTex" value="assets/VasePlant_normal.ankitex"/>
 		<input shaderInput="emission" value="0.000000 0.000000 0.000000"/>
 		<input shaderInput="subsurface" value="0.250000"/>

+ 1 - 1
samples/sponza/assets/vase_hanging.ankimtl

@@ -21,7 +21,7 @@
 		<input shaderInput="diffTex" value="assets/vase_hanging_tga.ankitex"/>
 		<input shaderInput="specColor" value="0.040000 0.040000 0.040000"/>
 		<input shaderInput="roughnessTex" value="assets/VaseHanging_roughness_tga.ankitex"/>
-		<input shaderInput="metallic" value="0.000000" />
+		<input shaderInput="metallic" value="0.000000"/>
 		<input shaderInput="normalTex" value="assets/VaseHanging_normal_tga.ankitex"/>
 		<input shaderInput="emission" value="0.000000 0.000000 0.000000"/>
 		<input shaderInput="subsurface" value="0.000000"/>

+ 1 - 1
samples/sponza/assets/vase_round.ankimtl

@@ -21,7 +21,7 @@
 		<input shaderInput="diffTex" value="assets/vase_round_tga.ankitex"/>
 		<input shaderInput="specColor" value="0.040000 0.040000 0.040000"/>
 		<input shaderInput="roughnessTex" value="assets/VaseRound_roughness.ankitex"/>
-		<input shaderInput="metallic" value="0.000000" />
+		<input shaderInput="metallic" value="0.000000"/>
 		<input shaderInput="normalTex" value="assets/VaseRound_normal.ankitex"/>
 		<input shaderInput="emission" value="0.000000 0.000000 0.000000"/>
 		<input shaderInput="subsurface" value="0.000000"/>

+ 1 - 0
src/anki/AnKi.h

@@ -16,3 +16,4 @@
 #include <anki/Physics.h>
 #include <anki/Gr.h>
 #include <anki/Core.h>
+#include <anki/Importer.h>

+ 2 - 0
src/anki/Config.h.cmake

@@ -156,6 +156,7 @@
 #	define ANKI_HOT __attribute__ ((hot))
 #	define ANKI_UNREACHABLE() __builtin_unreachable()
 #	define ANKI_PREFETCH_MEMORY(addr) __builtin_prefetch(addr)
+#	define ANKI_CHECK_FORMAT(fmtArgIdx, firstArgIdx) __attribute__ ((format (printf, fmtArgIdx + 1, firstArgIdx + 1)))
 #else
 #	define ANKI_LIKELY(x) ((x) == 1)
 #	define ANKI_UNLIKELY(x) ((x) == 1)
@@ -168,6 +169,7 @@
 #	define ANKI_HOT
 #	define ANKI_UNREACHABLE() __assume(false)
 #	define ANKI_PREFETCH_MEMORY(addr) (void)(addr)
+#	define ANKI_CHECK_FORMAT(fmtArgIdx, firstArgIdx)
 #endif
 
 // Pack structs

+ 10 - 0
src/anki/Importer.h

@@ -0,0 +1,10 @@
+// Copyright (C) 2009-2019, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <anki/importer/GltfImporter.h>
+
+/// @defgroup importer Importers

+ 2 - 0
src/anki/importer/CMakeLists.txt

@@ -0,0 +1,2 @@
+file(GLOB SOURCES *.cpp)
+addAnkiSourceFiles(${SOURCES})

+ 25 - 21
tools/gltf_importer/Importer.cpp → src/anki/importer/GltfImporter.cpp

@@ -3,7 +3,10 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#include "Importer.h"
+#include <anki/importer/GltfImporter.h>
+#include <anki/util/System.h>
+#include <anki/util/ThreadHive.h>
+#include <anki/util/StringList.h>
 
 #if ANKI_COMPILER_GCC_COMPATIBLE
 #	pragma GCC diagnostic push
@@ -133,14 +136,15 @@ static ANKI_USE_RESULT Error getNodeTransform(const cgltf_node& node, Transform&
 	return Error::NONE;
 }
 
-const char* Importer::XML_HEADER = R"(<?xml version="1.0" encoding="UTF-8" ?>)";
+const char* GltfImporter::XML_HEADER = R"(<?xml version="1.0" encoding="UTF-8" ?>)";
 
-Importer::Importer()
+GltfImporter::GltfImporter(GenericMemoryPoolAllocator<U8> alloc)
+	: m_alloc(alloc)
 {
 	m_hive = m_alloc.newInstance<ThreadHive>(getCpuCoresCount(), m_alloc, true);
 }
 
-Importer::~Importer()
+GltfImporter::~GltfImporter()
 {
 	if(m_gltf)
 	{
@@ -151,7 +155,7 @@ Importer::~Importer()
 	m_alloc.deleteInstance(m_hive);
 }
 
-Error Importer::init(CString inputFname, CString outDir, CString rpath, CString texrpath, Bool optimizeMeshes)
+Error GltfImporter::init(CString inputFname, CString outDir, CString rpath, CString texrpath, Bool optimizeMeshes)
 {
 	m_inputFname.create(inputFname);
 	m_outDir.create(outDir);
@@ -177,7 +181,7 @@ Error Importer::init(CString inputFname, CString outDir, CString rpath, CString
 	return Error::NONE;
 }
 
-Error Importer::writeAll()
+Error GltfImporter::writeAll()
 {
 	populateNodePtrToIdx();
 
@@ -214,7 +218,7 @@ Error Importer::writeAll()
 	return err;
 }
 
-Error Importer::getExtras(const cgltf_extras& extras, HashMapAuto<CString, StringAuto>& out)
+Error GltfImporter::getExtras(const cgltf_extras& extras, HashMapAuto<CString, StringAuto>& out)
 {
 	cgltf_size extrasSize;
 	cgltf_copy_extras_json(m_gltf, &extras, nullptr, &extrasSize);
@@ -285,7 +289,7 @@ Error Importer::getExtras(const cgltf_extras& extras, HashMapAuto<CString, Strin
 	return Error::NONE;
 }
 
-void Importer::populateNodePtrToIdxInternal(const cgltf_node& node, U32& idx)
+void GltfImporter::populateNodePtrToIdxInternal(const cgltf_node& node, U32& idx)
 {
 	m_nodePtrToIdx.emplace(&node, idx++);
 
@@ -295,7 +299,7 @@ void Importer::populateNodePtrToIdxInternal(const cgltf_node& node, U32& idx)
 	}
 }
 
-void Importer::populateNodePtrToIdx()
+void GltfImporter::populateNodePtrToIdx()
 {
 	U32 idx = 0;
 
@@ -308,7 +312,7 @@ void Importer::populateNodePtrToIdx()
 	}
 }
 
-StringAuto Importer::getNodeName(const cgltf_node& node)
+StringAuto GltfImporter::getNodeName(const cgltf_node& node)
 {
 	StringAuto out{m_alloc};
 
@@ -326,7 +330,7 @@ StringAuto Importer::getNodeName(const cgltf_node& node)
 	return out;
 }
 
-Error Importer::parseArrayOfNumbers(CString str, DynamicArrayAuto<F64>& out, const U* expectedArraySize)
+Error GltfImporter::parseArrayOfNumbers(CString str, DynamicArrayAuto<F64>& out, const U* expectedArraySize)
 {
 	StringListAuto list(m_alloc);
 	list.splitString(str, ' ');
@@ -357,7 +361,7 @@ Error Importer::parseArrayOfNumbers(CString str, DynamicArrayAuto<F64>& out, con
 	return Error::NONE;
 }
 
-Error Importer::visitNode(
+Error GltfImporter::visitNode(
 	const cgltf_node& node, const Transform& parentTrf, const HashMapAuto<CString, StringAuto>& parentExtras)
 {
 	// Check error from a thread
@@ -579,7 +583,7 @@ Error Importer::visitNode(
 			// Async because it's slow
 			struct Ctx
 			{
-				Importer* m_importer;
+				GltfImporter* m_importer;
 				cgltf_mesh* m_mesh;
 				cgltf_material* m_mtl;
 				cgltf_skin* m_skin;
@@ -669,7 +673,7 @@ Error Importer::visitNode(
 	return Error::NONE;
 }
 
-Error Importer::writeTransform(const Transform& trf)
+Error GltfImporter::writeTransform(const Transform& trf)
 {
 	ANKI_CHECK(m_sceneFile.writeText("trf = Transform.new()\n"));
 	ANKI_CHECK(m_sceneFile.writeText(
@@ -690,7 +694,7 @@ Error Importer::writeTransform(const Transform& trf)
 	return Error::NONE;
 }
 
-Error Importer::writeModel(const cgltf_mesh& mesh, CString skinName)
+Error GltfImporter::writeModel(const cgltf_mesh& mesh, CString skinName)
 {
 	StringAuto modelFname(m_alloc);
 	modelFname.sprintf("%s%s_%s.ankimdl", m_outDir.cstr(), mesh.name, mesh.primitives[0].material->name);
@@ -746,7 +750,7 @@ Error Importer::writeModel(const cgltf_mesh& mesh, CString skinName)
 	return Error::NONE;
 }
 
-Error Importer::writeAnimation(const cgltf_animation& anim)
+Error GltfImporter::writeAnimation(const cgltf_animation& anim)
 {
 	StringAuto fname(m_alloc);
 	fname.sprintf("%s%s.ankianim", m_outDir.cstr(), anim.name);
@@ -896,7 +900,7 @@ Error Importer::writeAnimation(const cgltf_animation& anim)
 	return Error::NONE;
 }
 
-Error Importer::writeSkeleton(const cgltf_skin& skin)
+Error GltfImporter::writeSkeleton(const cgltf_skin& skin)
 {
 	StringAuto fname(m_alloc);
 	fname.sprintf("%s%s.ankiskel", m_outDir.cstr(), skin.name);
@@ -957,7 +961,7 @@ Error Importer::writeSkeleton(const cgltf_skin& skin)
 	return Error::NONE;
 }
 
-Error Importer::writeCollisionMesh(const cgltf_mesh& mesh)
+Error GltfImporter::writeCollisionMesh(const cgltf_mesh& mesh)
 {
 	StringAuto fname(m_alloc);
 	fname.sprintf("%s%s.ankicl", m_outDir.cstr(), mesh.name);
@@ -977,7 +981,7 @@ Error Importer::writeCollisionMesh(const cgltf_mesh& mesh)
 	return Error::NONE;
 }
 
-Error Importer::writeLight(const cgltf_node& node, const HashMapAuto<CString, StringAuto>& parentExtras)
+Error GltfImporter::writeLight(const cgltf_node& node, const HashMapAuto<CString, StringAuto>& parentExtras)
 {
 	const cgltf_light& light = *node.light;
 	StringAuto nodeName = getNodeName(node);
@@ -1103,7 +1107,7 @@ Error Importer::writeLight(const cgltf_node& node, const HashMapAuto<CString, St
 	return Error::NONE;
 }
 
-Error Importer::writeCamera(const cgltf_node& node, const HashMapAuto<CString, StringAuto>& parentExtras)
+Error GltfImporter::writeCamera(const cgltf_node& node, const HashMapAuto<CString, StringAuto>& parentExtras)
 {
 	if(node.camera->type != cgltf_camera_type_perspective)
 	{
@@ -1127,7 +1131,7 @@ Error Importer::writeCamera(const cgltf_node& node, const HashMapAuto<CString, S
 	return Error::NONE;
 }
 
-Error Importer::writeModelNode(const cgltf_node& node, const HashMapAuto<CString, StringAuto>& parentExtras)
+Error GltfImporter::writeModelNode(const cgltf_node& node, const HashMapAuto<CString, StringAuto>& parentExtras)
 {
 	ANKI_GLTF_LOGI("Importing model node %s", getNodeName(node).cstr());
 

+ 13 - 6
tools/gltf_importer/Importer.h → src/anki/importer/GltfImporter.h

@@ -5,24 +5,30 @@
 
 #pragma once
 
-#include <src/anki/AnKi.h>
+#include <anki/util/String.h>
+#include <anki/util/File.h>
+#include <anki/util/HashMap.h>
+#include <anki/Math.h>
 #include <cgltf/cgltf.h>
 
 namespace anki
 {
 
+/// @addtogroup importer
+/// @{
+
 #define ANKI_GLTF_LOGI(...) ANKI_LOG("GLTF", NORMAL, __VA_ARGS__)
 #define ANKI_GLTF_LOGE(...) ANKI_LOG("GLTF", ERROR, __VA_ARGS__)
 #define ANKI_GLTF_LOGW(...) ANKI_LOG("GLTF", WARNING, __VA_ARGS__)
 #define ANKI_GLTF_LOGF(...) ANKI_LOG("GLTF", FATAL, __VA_ARGS__)
 
 /// Import GLTF and spit AnKi scenes.
-class Importer
+class GltfImporter
 {
 public:
-	Importer();
+	GltfImporter(GenericMemoryPoolAllocator<U8> alloc);
 
-	~Importer();
+	~GltfImporter();
 
 	ANKI_USE_RESULT Error init(
 		CString inputFname, CString outDir, CString rpath, CString texrpath, Bool optimizeMeshes);
@@ -42,7 +48,7 @@ private:
 	// Data
 	static const char* XML_HEADER;
 
-	HeapAllocator<U8> m_alloc{allocAligned, nullptr};
+	GenericMemoryPoolAllocator<U8> m_alloc;
 
 	StringAuto m_inputFname = {m_alloc};
 	StringAuto m_outDir = {m_alloc};
@@ -96,9 +102,10 @@ private:
 	ANKI_USE_RESULT Error writeCamera(const cgltf_node& node, const HashMapAuto<CString, StringAuto>& parentExtras);
 	ANKI_USE_RESULT Error writeModelNode(const cgltf_node& node, const HashMapAuto<CString, StringAuto>& parentExtras);
 };
+/// @}
 
 template<typename T, typename TFunc>
-void Importer::visitAccessor(const cgltf_accessor& accessor, TFunc func)
+void GltfImporter::visitAccessor(const cgltf_accessor& accessor, TFunc func)
 {
 	const U8* base =
 		static_cast<const U8*>(accessor.buffer_view->buffer->data) + accessor.offset + accessor.buffer_view->offset;

+ 73 - 104
tools/gltf_importer/ImporterMaterial.cpp → src/anki/importer/GltfImporterMaterial.cpp

@@ -3,20 +3,8 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#include "Importer.h"
-
-#define STB_IMAGE_IMPLEMENTATION
-#define STBI_ASSERT(x) ANKI_ASSERT(x)
-#if ANKI_COMPILER_GCC_COMPATIBLE
-#	pragma GCC diagnostic push
-#	pragma GCC diagnostic ignored "-Wfloat-conversion"
-#	pragma GCC diagnostic ignored "-Wconversion"
-#	pragma GCC diagnostic ignored "-Wtype-limits"
-#endif
-#include <stb/stb_image.h>
-#if ANKI_COMPILER_GCC_COMPATIBLE
-#	pragma GCC diagnostic pop
-#endif
+#include <anki/importer/GltfImporter.h>
+#include <anki/resource/ImageLoader.h>
 
 namespace anki
 {
@@ -52,24 +40,6 @@ const char* MATERIAL_TEMPLATE = R"(<!-- This file is auto generated by ImporterM
 </material>
 )";
 
-static std::string replaceAllString(const std::string& str, const std::string& from, const std::string& to)
-{
-	if(from.empty())
-	{
-		return str;
-	}
-
-	std::string out = str;
-	size_t start_pos = 0;
-	while((start_pos = out.find(from, start_pos)) != std::string::npos)
-	{
-		out.replace(start_pos, from.length(), to);
-		start_pos += to.length();
-	}
-
-	return out;
-}
-
 static CString getTextureUri(const cgltf_texture_view& view)
 {
 	ANKI_ASSERT(view.texture);
@@ -79,22 +49,22 @@ static CString getTextureUri(const cgltf_texture_view& view)
 }
 
 /// Read the texture and find out if
-static Error identifyMetallicRoughnessTexture(CString fname, F32& constantMetalines, F32& constantRoughness)
+static Error identifyMetallicRoughnessTexture(
+	CString fname, F32& constantMetalines, F32& constantRoughness, GenericMemoryPoolAllocator<U8>& alloc)
 {
-	int width, height, comp;
-	U8Vec4* data = reinterpret_cast<U8Vec4*>(stbi_load(fname.cstr(), &width, &height, &comp, 4));
-	if(!data)
-	{
-		ANKI_GLTF_LOGE("Failed to read: %s", fname.cstr());
-		return Error::FUNCTION_FAILED;
-	}
+	ImageLoader iloader(alloc);
+	ANKI_CHECK(iloader.load(fname));
+	ANKI_ASSERT(iloader.getColorFormat() == ImageLoaderColorFormat::RGBA8);
+	ANKI_ASSERT(iloader.getCompression() == ImageLoaderDataCompression::RAW);
+
+	const U8Vec4* data = reinterpret_cast<const U8Vec4*>(&iloader.getSurface(0, 0, 0).m_data[0]);
 
 	const F32 epsilon = 1.0f / 255.0f;
-	for(int y = 0; y < height; ++y)
+	for(U32 y = 0; y < iloader.getWidth(); ++y)
 	{
-		for(int x = 0; x < width; ++x)
+		for(U32 x = 0; x < iloader.getHeight(); ++x)
 		{
-			const U8Vec4& pixel = *(data + y * width + x);
+			const U8Vec4& pixel = *(data + y * iloader.getWidth() + x);
 			const F32 m = F32(pixel.z()) / 255.0f;
 			const F32 r = F32(pixel.y()) / 255.0f;
 
@@ -119,12 +89,10 @@ static Error identifyMetallicRoughnessTexture(CString fname, F32& constantMetali
 		}
 	}
 
-	stbi_image_free(data);
-
 	return Error::NONE;
 }
 
-Error Importer::writeMaterial(const cgltf_material& mtl)
+Error GltfImporter::writeMaterial(const cgltf_material& mtl)
 {
 	StringAuto fname(m_alloc);
 	fname.sprintf("%s%s.ankimtl", m_outDir.cstr(), mtl.name);
@@ -139,7 +107,10 @@ Error Importer::writeMaterial(const cgltf_material& mtl)
 	HashMapAuto<CString, StringAuto> extras(m_alloc);
 	ANKI_CHECK(getExtras(mtl.extras, extras));
 
-	std::string xml = XML_HEADER + std::string("\n") + MATERIAL_TEMPLATE;
+	StringAuto xml(m_alloc);
+	xml.append(XML_HEADER);
+	xml.append("\n");
+	xml.append(MATERIAL_TEMPLATE);
 
 	// Diffuse
 	if(mtl.pbr_metallic_roughness.base_color_texture.texture)
@@ -147,20 +118,19 @@ Error Importer::writeMaterial(const cgltf_material& mtl)
 		StringAuto uri(m_alloc);
 		uri.sprintf("%s%s", m_texrpath.cstr(), getTextureUri(mtl.pbr_metallic_roughness.base_color_texture).cstr());
 
-		xml = replaceAllString(
-			xml, "%diff%", "<input shaderInput=\"diffTex\" value=\"" + std::string(uri.cstr()) + "\"/>");
-		xml = replaceAllString(xml, "%diffTexMutator%", "1");
+		xml.replaceAll(
+			"%diff%", StringAuto{m_alloc}.sprintf("<input shaderInput=\"diffTex\" value=\"%s\"/>", uri.cstr()));
+		xml.replaceAll("%diffTexMutator%", "1");
 	}
 	else
 	{
 		const F32* diffCol = &mtl.pbr_metallic_roughness.base_color_factor[0];
 
-		xml = replaceAllString(xml,
-			"%diff%",
-			"<input shaderInput=\"diffColor\" value=\"" + std::to_string(diffCol[0]) + " " + std::to_string(diffCol[1])
-				+ " " + std::to_string(diffCol[2]) + "\"/>");
+		xml.replaceAll("%diff%",
+			StringAuto{m_alloc}.sprintf(
+				"<input shaderInput=\"diffColor\" value=\"%f %f %f\"/>", diffCol[0], diffCol[1], diffCol[2]));
 
-		xml = replaceAllString(xml, "%diffTexMutator%", "0");
+		xml.replaceAll("%diffTexMutator%", "0");
 	}
 
 	// Specular color (freshnel)
@@ -189,11 +159,11 @@ Error Importer::writeMaterial(const cgltf_material& mtl)
 			specular = Vec3(0.04f);
 		}
 
-		xml = replaceAllString(xml,
-			"%spec%",
-			"<input shaderInput=\"specColor\" value=\"" + std::to_string(specular.x()) + " "
-				+ std::to_string(specular.y()) + " " + std::to_string(specular.z()) + "\"/>");
-		xml = replaceAllString(xml, "%specTexMutator%", "0");
+		xml.replaceAll("%spec%",
+			StringAuto{m_alloc}.sprintf(
+				"<input shaderInput=\"specColor\" value=\"%f %f %f\"/>", specular.x(), specular.y(), specular.z()));
+
+		xml.replaceAll("%specTexMutator%", "0");
 	}
 
 	// Identify metallic/roughness texture
@@ -202,7 +172,7 @@ Error Importer::writeMaterial(const cgltf_material& mtl)
 	{
 		const CString fname = getTextureUri(mtl.pbr_metallic_roughness.metallic_roughness_texture);
 
-		ANKI_CHECK(identifyMetallicRoughnessTexture(fname, constantMetaliness, constantRoughness));
+		ANKI_CHECK(identifyMetallicRoughnessTexture(fname, constantMetaliness, constantRoughness, m_alloc));
 	}
 
 	// Roughness
@@ -212,10 +182,10 @@ Error Importer::writeMaterial(const cgltf_material& mtl)
 		uri.sprintf(
 			"%s%s", m_texrpath.cstr(), getTextureUri(mtl.pbr_metallic_roughness.metallic_roughness_texture).cstr());
 
-		xml = replaceAllString(
-			xml, "%roughness%", "<input shaderInput=\"roughnessTex\" value=\"" + std::string(uri.cstr()) + "\"/>");
+		xml.replaceAll("%roughness%",
+			StringAuto{m_alloc}.sprintf("<input shaderInput=\"roughnessTex\" value=\"%s\"/>", uri.cstr()));
 
-		xml = replaceAllString(xml, "%roughnessTexMutator%", "1");
+		xml.replaceAll("%roughnessTexMutator%", "1");
 	}
 	else
 	{
@@ -223,10 +193,10 @@ Error Importer::writeMaterial(const cgltf_material& mtl)
 								  ? constantRoughness * mtl.pbr_metallic_roughness.roughness_factor
 								  : mtl.pbr_metallic_roughness.roughness_factor;
 
-		xml = replaceAllString(
-			xml, "%roughness%", "<input shaderInput=\"roughness\" value=\"" + std::to_string(roughness) + "\" />");
+		xml.replaceAll(
+			"%roughness%", StringAuto{m_alloc}.sprintf("<input shaderInput=\"roughness\" value=\"%f\"/>", roughness));
 
-		xml = replaceAllString(xml, "%roughnessTexMutator%", "0");
+		xml.replaceAll("%roughnessTexMutator%", "0");
 	}
 
 	// Metallic
@@ -236,10 +206,10 @@ Error Importer::writeMaterial(const cgltf_material& mtl)
 		uri.sprintf(
 			"%s%s", m_texrpath.cstr(), getTextureUri(mtl.pbr_metallic_roughness.metallic_roughness_texture).cstr());
 
-		xml = replaceAllString(
-			xml, "%metallic%", "<input shaderInput=\"metallicTex\" value=\"" + std::string(uri.cstr()) + "\"/>");
+		xml.replaceAll(
+			"%metallic%", StringAuto{m_alloc}.sprintf("<input shaderInput=\"metallicTex\" value=\"%s\"/>", uri.cstr()));
 
-		xml = replaceAllString(xml, "%metalTexMutator%", "1");
+		xml.replaceAll("%metalTexMutator%", "1");
 	}
 	else
 	{
@@ -247,10 +217,10 @@ Error Importer::writeMaterial(const cgltf_material& mtl)
 								  ? constantMetaliness * mtl.pbr_metallic_roughness.metallic_factor
 								  : mtl.pbr_metallic_roughness.metallic_factor;
 
-		xml = replaceAllString(
-			xml, "%metallic%", "<input shaderInput=\"metallic\" value=\"" + std::to_string(metalines) + "\" />");
+		xml.replaceAll(
+			"%metallic%", StringAuto{m_alloc}.sprintf("<input shaderInput=\"metallic\" value=\"%f\"/>", metalines));
 
-		xml = replaceAllString(xml, "%metalTexMutator%", "0");
+		xml.replaceAll("%metalTexMutator%", "0");
 	}
 
 	// Normal texture
@@ -259,15 +229,15 @@ Error Importer::writeMaterial(const cgltf_material& mtl)
 		StringAuto uri(m_alloc);
 		uri.sprintf("%s%s", m_texrpath.cstr(), getTextureUri(mtl.normal_texture).cstr());
 
-		xml = replaceAllString(
-			xml, "%normal%", "<input shaderInput=\"normalTex\" value=\"" + std::string(uri.cstr()) + "\"/>");
+		xml.replaceAll(
+			"%normal%", StringAuto{m_alloc}.sprintf("<input shaderInput=\"normalTex\" value=\"%s\"/>", uri.cstr()));
 
-		xml = replaceAllString(xml, "%normalTexMutator%", "1");
+		xml.replaceAll("%normalTexMutator%", "1");
 	}
 	else
 	{
-		xml = replaceAllString(xml, "%normal%", "");
-		xml = replaceAllString(xml, "%normalTexMutator%", "0");
+		xml.replaceAll("%normal%", "");
+		xml.replaceAll("%normalTexMutator%", "0");
 	}
 
 	// Emissive texture
@@ -276,21 +246,22 @@ Error Importer::writeMaterial(const cgltf_material& mtl)
 		StringAuto uri(m_alloc);
 		uri.sprintf("%s%s", m_texrpath.cstr(), getTextureUri(mtl.emissive_texture).cstr());
 
-		xml = replaceAllString(
-			xml, "%emission%", "<input shaderInput=\"emissiveTex\" value=\"" + std::string(uri.cstr()) + "\"/>");
+		xml.replaceAll(
+			"%emission%", StringAuto{m_alloc}.sprintf("<input shaderInput=\"emissiveTex\" value=\"%s\"/>", uri.cstr()));
 
-		xml = replaceAllString(xml, "%emissiveTexMutator%", "1");
+		xml.replaceAll("%emissiveTexMutator%", "1");
 	}
 	else
 	{
 		const F32* emissionCol = &mtl.emissive_factor[0];
 
-		xml = replaceAllString(xml,
-			"%emission%",
-			"<input shaderInput=\"emission\" value=\"" + std::to_string(emissionCol[0]) + " "
-				+ std::to_string(emissionCol[1]) + " " + std::to_string(emissionCol[2]) + "\"/>");
+		xml.replaceAll("%emission%",
+			StringAuto{m_alloc}.sprintf("<input shaderInput=\"emission\" value=\"%f %f %f\"/>",
+				emissionCol[0],
+				emissionCol[1],
+				emissionCol[2]));
 
-		xml = replaceAllString(xml, "%emissiveTexMutator%", "0");
+		xml.replaceAll("%emissiveTexMutator%", "0");
 	}
 
 	// Subsurface
@@ -306,8 +277,8 @@ Error Importer::writeMaterial(const cgltf_material& mtl)
 			subsurface = 0.0f;
 		}
 
-		xml = replaceAllString(
-			xml, "%subsurface%", "<input shaderInput=\"subsurface\" value=\"" + std::to_string(subsurface) + "\"/>");
+		xml.replaceAll("%subsurface%",
+			StringAuto{m_alloc}.sprintf("<input shaderInput=\"subsurface\" value=\"%f\"/>", subsurface));
 	}
 
 	// Height texture
@@ -317,34 +288,32 @@ Error Importer::writeMaterial(const cgltf_material& mtl)
 		StringAuto uri(m_alloc);
 		uri.sprintf("%s%s", m_texrpath.cstr(), it->cstr());
 
-		xml = replaceAllString(xml,
-			"%height%",
-			"<input shaderInput=\"heightTex\" value=\"" + std::string(uri.cstr())
-				+ "\"/>\n"
-				  "\t\t<input shaderInput=\"heightMapScale\" value=\"0.05\"/>");
+		xml.replaceAll("%height%",
+			StringAuto{m_alloc}.sprintf("<input shaderInput=\"heightTex\" value=\"%s\" \"/>\n"
+										"\t\t<input shaderInput=\"heightMapScale\" value=\"0.05\"/>",
+				uri.cstr()));
 
-		xml = replaceAllString(
-			xml, "%parallaxInput%", "<input shaderInput=\"modelViewMat\" builtin=\"MODEL_VIEW_MATRIX\"/>");
+		xml.replaceAll("%parallaxInput%", "<input shaderInput=\"modelViewMat\" builtin=\"MODEL_VIEW_MATRIX\"/>");
 
-		xml = replaceAllString(xml, "%parallaxMutator%", "1");
+		xml.replaceAll("%parallaxMutator%", "1");
 	}
 	else
 	{
-		xml = replaceAllString(xml, "%height%", "");
-		xml = replaceAllString(xml, "%parallaxInput%", "");
-		xml = replaceAllString(xml, "%parallaxMutator%", "0");
+		xml.replaceAll("%height%", "");
+		xml.replaceAll("%parallaxInput%", "");
+		xml.replaceAll("%parallaxMutator%", "0");
 	}
 
 	// Replace texture extensions with .anki
-	xml = replaceAllString(xml, ".tga", ".ankitex");
-	xml = replaceAllString(xml, ".png", ".ankitex");
-	xml = replaceAllString(xml, ".jpg", ".ankitex");
-	xml = replaceAllString(xml, ".jpeg", ".ankitex");
+	xml.replaceAll(".tga", ".ankitex");
+	xml.replaceAll(".png", ".ankitex");
+	xml.replaceAll(".jpg", ".ankitex");
+	xml.replaceAll(".jpeg", ".ankitex");
 
 	// Write file
 	File file;
 	ANKI_CHECK(file.open(fname.toCString(), FileOpenFlag::WRITE));
-	ANKI_CHECK(file.writeText("%s", xml.c_str()));
+	ANKI_CHECK(file.writeText("%s", xml.cstr()));
 
 	return Error::NONE;
 }

+ 8 - 4
tools/gltf_importer/ImporterMesh.cpp → src/anki/importer/GltfImporterMesh.cpp

@@ -3,7 +3,11 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#include "Importer.h"
+#include <anki/importer/GltfImporter.h>
+#include <anki/util/StringList.h>
+#include <anki/collision/Plane.h>
+#include <anki/collision/Functions.h>
+#include <anki/resource/MeshLoader.h>
 #include <meshoptimizer/meshoptimizer.h>
 
 namespace anki
@@ -117,7 +121,7 @@ public:
 	U32 m_firstIdx = MAX_U32;
 	U32 m_idxCount = MAX_U32;
 
-	SubMesh(HeapAllocator<U8>& alloc)
+	SubMesh(GenericMemoryPoolAllocator<U8>& alloc)
 		: m_verts(alloc)
 		, m_indices(alloc)
 	{
@@ -131,7 +135,7 @@ struct WeightVertex
 };
 
 /// Optimize a submesh using meshoptimizer.
-static void optimizeSubmesh(SubMesh& submesh, HeapAllocator<U8> alloc)
+static void optimizeSubmesh(SubMesh& submesh, GenericMemoryPoolAllocator<U8> alloc)
 {
 	const PtrSize vertSize = sizeof(submesh.m_verts[0]);
 
@@ -209,7 +213,7 @@ static void optimizeSubmesh(SubMesh& submesh, HeapAllocator<U8> alloc)
 	}
 }
 
-Error Importer::writeMesh(const cgltf_mesh& mesh)
+Error GltfImporter::writeMesh(const cgltf_mesh& mesh)
 {
 	StringAuto fname(m_alloc);
 	fname.sprintf("%s%s.ankimesh", m_outDir.cstr(), mesh.name);

+ 86 - 3
src/anki/resource/ImageLoader.cpp

@@ -8,6 +8,19 @@
 #include <anki/util/Filesystem.h>
 #include <anki/util/Array.h>
 
+#define STB_IMAGE_IMPLEMENTATION
+#define STBI_ASSERT(x) ANKI_ASSERT(x)
+#if ANKI_COMPILER_GCC_COMPATIBLE
+#	pragma GCC diagnostic push
+#	pragma GCC diagnostic ignored "-Wfloat-conversion"
+#	pragma GCC diagnostic ignored "-Wconversion"
+#	pragma GCC diagnostic ignored "-Wtype-limits"
+#endif
+#include <stb/stb_image.h>
+#if ANKI_COMPILER_GCC_COMPATIBLE
+#	pragma GCC diagnostic pop
+#endif
+
 namespace anki
 {
 
@@ -141,7 +154,14 @@ class ImageLoader::FileInterface
 {
 public:
 	virtual ANKI_USE_RESULT Error read(void* buff, PtrSize size) = 0;
+
 	virtual ANKI_USE_RESULT Error seek(PtrSize offset, FileSeekOrigin origin) = 0;
+
+	virtual PtrSize getSize() const
+	{
+		ANKI_ASSERT(!"Not Implemented");
+		return MAX_PTR_SIZE;
+	}
 };
 
 class ImageLoader::RsrcFile : public FileInterface
@@ -174,6 +194,11 @@ public:
 	{
 		return m_file.seek(offset, origin);
 	}
+
+	PtrSize getSize() const final
+	{
+		return m_file.getSize();
+	}
 };
 
 Error ImageLoader::loadUncompressedTga(
@@ -578,18 +603,62 @@ Error ImageLoader::loadAnkiTexture(FileInterface& file,
 	return Error::NONE;
 }
 
+Error ImageLoader::loadStb(
+	FileInterface& fs, U32& width, U32& height, DynamicArray<U8>& data, GenericMemoryPoolAllocator<U8>& alloc)
+{
+	// Read the file
+	DynamicArrayAuto<U8> fileData = {alloc};
+	const PtrSize fileSize = fs.getSize();
+	fileData.create(fileSize);
+	ANKI_CHECK(fs.read(&fileData[0], fileSize));
+
+	// Use STB to read the image
+	int stbw, stbh, comp;
+	U8* stbdata = reinterpret_cast<U8*>(stbi_load_from_memory(&fileData[0], I32(fileSize), &stbw, &stbh, &comp, 4));
+	if(!stbdata)
+	{
+		ANKI_RESOURCE_LOGE("STB failed to read image");
+		return Error::FUNCTION_FAILED;
+	}
+
+	// Store it
+	width = U32(stbw);
+	height = U32(stbh);
+	data.create(alloc, width * height * 4);
+	memcpy(&data[0], stbdata, data.getSize());
+
+	// Cleanup
+	stbi_image_free(stbdata);
+
+	return Error::NONE;
+}
+
 Error ImageLoader::load(ResourceFilePtr rfile, const CString& filename, U32 maxTextureSize)
 {
 	RsrcFile file;
 	file.m_rfile = rfile;
-	return loadInternal(file, filename, maxTextureSize);
+
+	const Error err = loadInternal(file, filename, maxTextureSize);
+	if(err)
+	{
+		ANKI_RESOURCE_LOGE("Failed to read image: %s", filename.cstr());
+	}
+
+	return err;
 }
 
 Error ImageLoader::load(const CString& filename, U32 maxTextureSize)
 {
 	SystemFile file;
 	ANKI_CHECK(file.m_file.open(filename, FileOpenFlag::READ | FileOpenFlag::BINARY));
-	return loadInternal(file, filename, maxTextureSize);
+
+	const Error err = loadInternal(file, filename, maxTextureSize);
+	if(err)
+	{
+		ANKI_RESOURCE_LOGE("Failed to read image: %s", filename.cstr());
+	}
+
+	return err;
 }
 
 Error ImageLoader::loadInternal(FileInterface& file, const CString& filename, U32 maxTextureSize)
@@ -605,7 +674,6 @@ Error ImageLoader::loadInternal(FileInterface& file, const CString& filename, U3
 	}
 
 	// load from this extension
-	U32 bpp = 0;
 	m_textureType = ImageLoaderTextureType::_2D;
 	m_compression = ImageLoaderDataCompression::RAW;
 
@@ -616,6 +684,7 @@ Error ImageLoader::loadInternal(FileInterface& file, const CString& filename, U3
 		m_mipCount = 1;
 		m_depth = 1;
 		m_layerCount = 1;
+		U32 bpp = 0;
 		ANKI_CHECK(loadTga(file, m_surfaces[0].m_width, m_surfaces[0].m_height, bpp, m_surfaces[0].m_data, m_alloc));
 
 		m_width = m_surfaces[0].m_width;
@@ -656,6 +725,20 @@ Error ImageLoader::loadInternal(FileInterface& file, const CString& filename, U3
 			m_textureType,
 			m_colorFormat));
 	}
+	else if(ext == "png")
+	{
+		m_surfaces.create(m_alloc, 1);
+
+		m_mipCount = 1;
+		m_depth = 1;
+		m_layerCount = 1;
+		m_colorFormat = ImageLoaderColorFormat::RGBA8;
+
+		ANKI_CHECK(loadStb(file, m_surfaces[0].m_width, m_surfaces[0].m_height, m_surfaces[0].m_data, m_alloc));
+
+		m_width = m_surfaces[0].m_width;
+		m_height = m_surfaces[0].m_height;
+	}
 	else
 	{
 		ANKI_RESOURCE_LOGE("Unsupported extension: %s", &ext[0]);

+ 3 - 0
src/anki/resource/ImageLoader.h

@@ -180,6 +180,9 @@ private:
 		DynamicArray<U8>& data,
 		GenericMemoryPoolAllocator<U8>& alloc);
 
+	static ANKI_USE_RESULT Error loadStb(
+		FileInterface& fs, U32& width, U32& height, DynamicArray<U8>& data, GenericMemoryPoolAllocator<U8>& alloc);
+
 	static ANKI_USE_RESULT Error loadAnkiTexture(FileInterface& file,
 		U32 maxTextureSize,
 		ImageLoaderDataCompression& preferredCompression,

+ 1 - 1
tools/gltf_importer/CMakeLists.txt

@@ -3,5 +3,5 @@ include_directories("../../src")
 file(GLOB_RECURSE SOURCES *.cpp)
 
 add_executable(gltf_importer ${SOURCES})
-target_link_libraries(gltf_importer anki ankimeshoptimizer)
+target_link_libraries(gltf_importer anki)
 installExecutable(gltf_importer)

+ 4 - 3
tools/gltf_importer/Main.cpp

@@ -3,7 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#include "Importer.h"
+#include <anki/importer/GltfImporter.h>
 
 using namespace anki;
 
@@ -126,7 +126,8 @@ int main(int argc, char** argv)
 		return 1;
 	}
 
-	Importer importer;
+	HeapAllocator<U8> alloc{allocAligned, nullptr};
+	GltfImporter importer{alloc};
 	if(importer.init(info.m_inputFname.toCString(),
 		   info.m_outDir.toCString(),
 		   info.m_rpath.toCString(),
@@ -142,4 +143,4 @@ int main(int argc, char** argv)
 	}
 
 	return 0;
-}
+}