Browse Source

Some work on the GLTF importer

Panagiotis Christopoulos Charitos 6 years ago
parent
commit
126c1d8971

+ 7 - 5
src/anki/gr/RenderGraph.cpp

@@ -1400,7 +1400,7 @@ StringAuto RenderGraph::bufferUsageToStr(StackAllocator<U8>& alloc, BufferUsageB
 Error RenderGraph::dumpDependencyDotFile(
 	const RenderGraphDescription& descr, const BakeContext& ctx, CString path) const
 {
-	static const Array<const char*, 6> COLORS = {{"red", "green", "blue", "magenta", "yellow", "cyan"}};
+	static const Array<const char*, 5> COLORS = {{"red", "green", "blue", "magenta", "cyan"}};
 	auto alloc = ctx.m_alloc;
 	StringListAuto slist(alloc);
 
@@ -1424,7 +1424,7 @@ Error RenderGraph::dumpDependencyDotFile(
 
 			slist.pushBackSprintf("\t\"%s\"[color=%s,style=%s,shape=box];\n",
 				passName.cstr(),
-				COLORS[batchIdx % 6],
+				COLORS[batchIdx % COLORS.getSize()],
 				(descr.m_passes[passIdx]->m_type == RenderPassDescriptionBase::Type::GRAPHICS) ? "bold" : "dashed");
 
 			for(U32 depIdx : ctx.m_passes[passIdx].m_dependsOn)
@@ -1444,7 +1444,8 @@ Error RenderGraph::dumpDependencyDotFile(
 	slist.pushBackSprintf("subgraph cluster_0 {\n");
 	for(U rtIdx = 0; rtIdx < descr.m_renderTargets.getSize(); ++rtIdx)
 	{
-		slist.pushBackSprintf("\t\"%s\"[color=%s];\n", &descr.m_renderTargets[rtIdx].m_name[0], COLORS[rtIdx % 6]);
+		slist.pushBackSprintf(
+			"\t\"%s\"[color=%s];\n", &descr.m_renderTargets[rtIdx].m_name[0], COLORS[rtIdx % COLORS.getSize()]);
 	}
 	slist.pushBackSprintf("}\n");
 #	endif
@@ -1490,7 +1491,7 @@ Error RenderGraph::dumpDependencyDotFile(
 
 			slist.pushBackSprintf("\t\"%s\"[color=%s,style=bold,shape=box,label=< %s >];\n",
 				barrierName.cstr(),
-				COLORS[batchIdx % 6],
+				COLORS[batchIdx % COLORS.getSize()],
 				barrierLabel.cstr());
 			slist.pushBackSprintf("\t\"%s\"->\"%s\";\n", prevBubble.cstr(), barrierName.cstr());
 
@@ -1502,7 +1503,8 @@ Error RenderGraph::dumpDependencyDotFile(
 			const RenderPassDescriptionBase& pass = *descr.m_passes[passIdx];
 			StringAuto passName(alloc);
 			passName.sprintf("%s pass", pass.m_name.cstr());
-			slist.pushBackSprintf("\t\"%s\"[color=%s,style=bold];\n", passName.cstr(), COLORS[batchIdx % 6]);
+			slist.pushBackSprintf(
+				"\t\"%s\"[color=%s,style=bold];\n", passName.cstr(), COLORS[batchIdx % COLORS.getSize()]);
 			slist.pushBackSprintf("\t\"%s\"->\"%s\";\n", prevBubble.cstr(), passName.cstr());
 
 			prevBubble = passName;

+ 2 - 1
tools/CMakeLists.txt

@@ -1,2 +1,3 @@
 add_subdirectory(scene)
-add_subdirectory(gltf_exporter)
+add_subdirectory(gltf_exporter)
+add_subdirectory(gltf_importer)

+ 3 - 3
tools/gltf_importer/CMakeLists.txt

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

+ 4 - 1
tools/gltf_importer/CgltfImpl.cpp

@@ -1,4 +1,7 @@
 // Copyright (C) 2009-2019, Panagiotis Christopoulos Charitos and contributors.
 // All rights reserved.
 // Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
+// http://www.anki3d.org/LICENSE
+
+#define CGLTF_IMPLEMENTATION
+#include <cgltf/cgltf.h>

+ 43 - 0
tools/gltf_importer/Importer.cpp

@@ -8,4 +8,47 @@
 namespace anki
 {
 
+Importer::~Importer()
+{
+	if(m_gltf)
+	{
+		cgltf_free(m_gltf);
+		m_gltf = nullptr;
+	}
+}
+
+Error Importer::load(CString inputFname, CString outDir)
+{
+	m_inputFname.create(inputFname);
+	m_outDir.create(outDir);
+
+	cgltf_options options = {};
+	cgltf_result res = cgltf_parse_file(&options, inputFname.cstr(), &m_gltf);
+	if(res != cgltf_result_success)
+	{
+		ANKI_LOGE("Failed to open the GLTF file. Code: %d", res);
+		return Error::FUNCTION_FAILED;
+	}
+
+	res = cgltf_load_buffers(&options, m_gltf, inputFname.cstr());
+	if(res != cgltf_result_success)
+	{
+		ANKI_LOGE("Failed to load GLTF data. Code: %d", res);
+		return Error::FUNCTION_FAILED;
+	}
+
+	return Error::NONE;
+}
+
+Error Importer::writeAll()
+{
+	// Export meshes
+	for(U i = 0; i < m_gltf->meshes_count; ++i)
+	{
+		ANKI_CHECK(writeMesh(m_gltf->meshes[i]));
+	}
+
+	return Error::NONE;
+}
+
 } // end namespace anki

+ 23 - 1
tools/gltf_importer/Importer.h

@@ -6,13 +6,35 @@
 #pragma once
 
 #include <src/anki/AnKi.h>
-#include <tinygltf/tiny_gltf.h>
+#include <cgltf/cgltf.h>
 
 namespace anki
 {
 
+/// Import GLTF and spit AnKi scenes.
 class Importer
 {
+public:
+	~Importer();
+
+	Error load(CString inputFname, CString outDir);
+
+	Error writeAll();
+
+private:
+	HeapAllocator<U8> m_alloc{allocAligned, nullptr};
+
+	StringAuto m_inputFname = {m_alloc};
+	StringAuto m_outDir = {m_alloc};
+
+	cgltf_data* m_gltf = nullptr;
+
+	ANKI_USE_RESULT Error writeMesh(const cgltf_mesh& mesh);
 };
 
+#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__)
+
 } // end namespace anki

+ 87 - 0
tools/gltf_importer/ImporterMesh.cpp

@@ -0,0 +1,87 @@
+// Copyright (C) 2009-2019, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include "Importer.h"
+
+namespace anki
+{
+
+template<typename T>
+static Error appendAttribute(const cgltf_attribute& attrib, DynamicArrayAuto<T>& out)
+{
+	ANKI_ASSERT(attrib.data);
+	if(attrib.data->type == cgltf_type_vec3 && attrib.data->component_type == cgltf_component_type_r_32f)
+	{
+		const U8* base = static_cast<const U8*>(attrib.data->buffer_view->buffer->data) + attrib.data->offset
+						 + attrib.data->buffer_view->offset;
+
+		const PtrSize stride = (attrib.data->stride == 0) ? sizeof(Vec3) : attrib.data->stride == 0;
+
+		const U count = attrib.data->count;
+		if(count == 0)
+		{
+			ANKI_GLTF_LOGE("Zero vertex count");
+			return Error::USER_DATA;
+		}
+
+		for(U i = 0; i < count; ++i)
+		{
+			const U8* ptr = base + stride * i;
+			T val;
+			memcpy(&val, ptr, sizeof(T)); // Memcpy because it might not be aligned
+			out.emplaceBack(val);
+		}
+	}
+	else
+	{
+		ANKI_ASSERT(!"TODO");
+	}
+
+	return Error::NONE;
+}
+
+Error Importer::writeMesh(const cgltf_mesh& mesh)
+{
+	StringAuto fname(m_alloc);
+	fname.sprintf("%s%s.ankimesh", m_outDir.cstr(), mesh.name);
+	ANKI_GLTF_LOGI("Exporting %s", fname.cstr());
+
+	DynamicArrayAuto<Vec3> positions(m_alloc);
+	DynamicArrayAuto<Vec3> normals(m_alloc);
+	DynamicArrayAuto<Vec4> tangents(m_alloc);
+	DynamicArrayAuto<Vec2> uvs(m_alloc);
+
+	// Iterate primitives
+	for(const cgltf_primitive* primitive = mesh.primitives; primitive < mesh.primitives + mesh.primitives_count;
+		++primitive)
+	{
+		if(primitive->type != cgltf_primitive_type_triangles)
+		{
+			ANKI_GLTF_LOGE("Expecting triangles got %d", primitive->type);
+			return Error::USER_DATA;
+		}
+
+		ANKI_ASSERT(primitive->indices);
+		if(primitive->indices->count == 0 || (primitive->indices->count % 3) != 0)
+		{
+			ANKI_GLTF_LOGE("Incorect index count: %d", primitive->indices->count);
+			return Error::USER_DATA;
+		}
+
+		for(const cgltf_attribute* attrib = primitive->attributes;
+			attrib < primitive->attributes + primitive->attributes_count;
+			++attrib)
+		{
+			if(attrib->type == cgltf_attribute_type_position)
+			{
+				appendAttribute(*attrib, positions);
+			}
+		}
+	}
+
+	return Error::NONE;
+}
+
+} // end namespace anki

+ 106 - 1
tools/gltf_importer/Main.cpp

@@ -3,9 +3,114 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#include "Exporter.h"
+#include "Importer.h"
+
+using namespace anki;
+
+static const char* USAGE = R"(Usage: %s in_file out_dir [options]
+Options:
+-rpath <string>     : Replace all absolute paths of assets with that path
+-texrpath <string>  : Same as rpath but for textures
+)";
+
+class CmdLineArgs
+{
+public:
+	HeapAllocator<U8> m_alloc{allocAligned, nullptr};
+	StringAuto m_inputFname = {m_alloc};
+	StringAuto m_outDir = {m_alloc};
+	StringAuto m_rpath = {m_alloc};
+	StringAuto m_texRpath = {m_alloc};
+};
+
+static Error parseCommandLineArgs(int argc, char** argv, CmdLineArgs& info)
+{
+	Bool rpathFound = false;
+	Bool texrpathFound = false;
+
+	// Parse config
+	if(argc < 3)
+	{
+		return Error::USER_DATA;
+	}
+
+	info.m_inputFname.create(argv[1]);
+	info.m_outDir.sprintf("%s/", argv[2]);
+
+	for(I i = 3; i < argc; i++)
+	{
+		if(strcmp(argv[i], "-texrpath") == 0)
+		{
+			texrpathFound = true;
+			++i;
+
+			if(i < argc)
+			{
+				if(std::strlen(argv[i]) > 0)
+				{
+					info.m_texRpath.sprintf("%s/", argv[i]);
+				}
+			}
+			else
+			{
+				return Error::USER_DATA;
+			}
+		}
+		else if(strcmp(argv[i], "-rpath") == 0)
+		{
+			rpathFound = true;
+			++i;
+
+			if(i < argc)
+			{
+				if(std::strlen(argv[i]) > 0)
+				{
+					info.m_rpath.sprintf("%s/", argv[i]);
+				}
+			}
+			else
+			{
+				return Error::USER_DATA;
+			}
+		}
+		else
+		{
+			return Error::USER_DATA;
+		}
+	}
+
+	if(!rpathFound)
+	{
+		info.m_rpath = info.m_outDir;
+	}
+
+	if(!texrpathFound)
+	{
+		info.m_texRpath = info.m_outDir;
+	}
+
+	return Error::NONE;
+}
 
 int main(int argc, char** argv)
 {
+	CmdLineArgs info;
+	if(parseCommandLineArgs(argc, argv, info))
+	{
+		ANKI_GLTF_LOGE(USAGE, argv[0]);
+		return 1;
+	}
+
+	Importer importer;
+	if(importer.load(info.m_inputFname.toCString(), info.m_outDir.toCString()))
+	{
+		return 1;
+	}
+
+	if(importer.writeAll())
+	{
+		return 1;
+	}
+
 	return 0;
 }