Plugins: Add Assimp plugin (WIP)
Currently load only static meshes Former-commit-id: 61dee8f53a423d6d170bd3bfe72e71daa63e8c5b
This commit is contained in:
parent
019c1f4a36
commit
34b7260d54
|
|
@ -243,12 +243,17 @@ function NazaraBuild:Execute()
|
||||||
|
|
||||||
-- Tools
|
-- Tools
|
||||||
for k, toolTable in ipairs(self.OrderedTools) do
|
for k, toolTable in ipairs(self.OrderedTools) do
|
||||||
project("Nazara" .. toolTable.Name)
|
local prefix = "Nazara"
|
||||||
|
if (toolTable.Kind == "plugin") then
|
||||||
|
prefix = "Plugin"
|
||||||
|
end
|
||||||
|
|
||||||
|
project(prefix .. toolTable.Name)
|
||||||
|
|
||||||
location(_ACTION .. "/tools")
|
location(_ACTION .. "/tools")
|
||||||
targetdir(toolTable.Directory)
|
targetdir(toolTable.Directory)
|
||||||
|
|
||||||
if (toolTable.Kind == "library") then
|
if (toolTable.Kind == "plugin" or toolTable.Kind == "library") then
|
||||||
kind("SharedLib")
|
kind("SharedLib")
|
||||||
elseif (toolTable.Kind == "consoleapp") then
|
elseif (toolTable.Kind == "consoleapp") then
|
||||||
debugdir(toolTable.Directory)
|
debugdir(toolTable.Directory)
|
||||||
|
|
@ -257,7 +262,7 @@ function NazaraBuild:Execute()
|
||||||
debugdir(toolTable.Directory)
|
debugdir(toolTable.Directory)
|
||||||
kind("WindowedApp")
|
kind("WindowedApp")
|
||||||
else
|
else
|
||||||
assert(false, "wut")
|
assert(false, "Invalid tool Kind")
|
||||||
end
|
end
|
||||||
|
|
||||||
includedirs({
|
includedirs({
|
||||||
|
|
@ -280,6 +285,8 @@ function NazaraBuild:Execute()
|
||||||
libdirs("../lib/" .. makeLibDir .. "/x86")
|
libdirs("../lib/" .. makeLibDir .. "/x86")
|
||||||
if (toolTable.Kind == "library") then
|
if (toolTable.Kind == "library") then
|
||||||
targetdir("../lib/" .. makeLibDir .. "/x86")
|
targetdir("../lib/" .. makeLibDir .. "/x86")
|
||||||
|
elseif (toolTable.Kind == "plugin") then
|
||||||
|
targetdir("../plugins/" .. toolTable.Name .. "/lib/" .. makeLibDir .. "/x32")
|
||||||
end
|
end
|
||||||
|
|
||||||
configuration({"codeblocks or codelite or gmake", "x64"})
|
configuration({"codeblocks or codelite or gmake", "x64"})
|
||||||
|
|
@ -287,6 +294,8 @@ function NazaraBuild:Execute()
|
||||||
libdirs("../lib/" .. makeLibDir .. "/x64")
|
libdirs("../lib/" .. makeLibDir .. "/x64")
|
||||||
if (toolTable.Kind == "library") then
|
if (toolTable.Kind == "library") then
|
||||||
targetdir("../lib/" .. makeLibDir .. "/x64")
|
targetdir("../lib/" .. makeLibDir .. "/x64")
|
||||||
|
elseif (toolTable.Kind == "plugin") then
|
||||||
|
targetdir("../plugins/" .. toolTable.Name .. "/lib/" .. makeLibDir .. "/x64")
|
||||||
end
|
end
|
||||||
|
|
||||||
configuration({"vs*", "x32"})
|
configuration({"vs*", "x32"})
|
||||||
|
|
@ -294,6 +303,8 @@ function NazaraBuild:Execute()
|
||||||
libdirs("../lib/msvc/x86")
|
libdirs("../lib/msvc/x86")
|
||||||
if (toolTable.Kind == "library") then
|
if (toolTable.Kind == "library") then
|
||||||
targetdir("../lib/msvc/x86")
|
targetdir("../lib/msvc/x86")
|
||||||
|
elseif (toolTable.Kind == "plugin") then
|
||||||
|
targetdir("../plugins/" .. toolTable.Name .. "/lib/msvc/x86")
|
||||||
end
|
end
|
||||||
|
|
||||||
configuration({"vs*", "x64"})
|
configuration({"vs*", "x64"})
|
||||||
|
|
@ -301,6 +312,8 @@ function NazaraBuild:Execute()
|
||||||
libdirs("../lib/msvc/x64")
|
libdirs("../lib/msvc/x64")
|
||||||
if (toolTable.Kind == "library") then
|
if (toolTable.Kind == "library") then
|
||||||
targetdir("../lib/msvc/x64")
|
targetdir("../lib/msvc/x64")
|
||||||
|
elseif (toolTable.Kind == "plugin") then
|
||||||
|
targetdir("../plugins/" .. toolTable.Name .. "/lib/msvc/x64")
|
||||||
end
|
end
|
||||||
|
|
||||||
configuration({"xcode3 or xcode4", "x32"})
|
configuration({"xcode3 or xcode4", "x32"})
|
||||||
|
|
@ -308,6 +321,8 @@ function NazaraBuild:Execute()
|
||||||
libdirs("../lib/xcode/x86")
|
libdirs("../lib/xcode/x86")
|
||||||
if (toolTable.Kind == "library") then
|
if (toolTable.Kind == "library") then
|
||||||
targetdir("../lib/xcode/x86")
|
targetdir("../lib/xcode/x86")
|
||||||
|
elseif (toolTable.Kind == "plugin") then
|
||||||
|
targetdir("../plugins/" .. toolTable.Name .. "/lib/xcode/x86")
|
||||||
end
|
end
|
||||||
|
|
||||||
configuration({"xcode3 or xcode4", "x64"})
|
configuration({"xcode3 or xcode4", "x64"})
|
||||||
|
|
@ -315,9 +330,11 @@ function NazaraBuild:Execute()
|
||||||
libdirs("../lib/xcode/x64")
|
libdirs("../lib/xcode/x64")
|
||||||
if (toolTable.Kind == "library") then
|
if (toolTable.Kind == "library") then
|
||||||
targetdir("../lib/xcode/x64")
|
targetdir("../lib/xcode/x64")
|
||||||
|
elseif (toolTable.Kind == "plugin") then
|
||||||
|
targetdir("../plugins/" .. toolTable.Name .. "/lib/xcode/x64")
|
||||||
end
|
end
|
||||||
|
|
||||||
if (toolTable.Kind == "library") then
|
if (toolTable.Kind == "library" or toolTable.Kind == "plugin") then
|
||||||
configuration("*Static")
|
configuration("*Static")
|
||||||
kind("StaticLib")
|
kind("StaticLib")
|
||||||
|
|
||||||
|
|
@ -719,7 +736,7 @@ function NazaraBuild:RegisterTool(toolTable)
|
||||||
end
|
end
|
||||||
|
|
||||||
local lowerCaseKind = toolTable.Kind:lower()
|
local lowerCaseKind = toolTable.Kind:lower()
|
||||||
if (lowerCaseKind == "library" or lowerCaseKind == "consoleapp" or lowerCaseKind == "windowapp") then
|
if (lowerCaseKind == "library" or lowerCaseKind == "plugin" or lowerCaseKind == "consoleapp" or lowerCaseKind == "windowapp") then
|
||||||
toolTable.Kind = lowerCaseKind
|
toolTable.Kind = lowerCaseKind
|
||||||
else
|
else
|
||||||
return false, "Invalid tool type"
|
return false, "Invalid tool type"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
TOOL.Name = "Assimp"
|
||||||
|
|
||||||
|
TOOL.Directory = "../SDK/lib"
|
||||||
|
TOOL.Kind = "Plugin"
|
||||||
|
|
||||||
|
TOOL.Includes = {
|
||||||
|
"../include",
|
||||||
|
"../plugins/Assimp"
|
||||||
|
}
|
||||||
|
|
||||||
|
TOOL.Files = {
|
||||||
|
"../plugins/Assimp/**.hpp",
|
||||||
|
"../plugins/Assimp/**.inl",
|
||||||
|
"../plugins/Assimp/**.cpp"
|
||||||
|
}
|
||||||
|
|
||||||
|
TOOL.Libraries = {
|
||||||
|
"NazaraCore",
|
||||||
|
"NazaraUtility",
|
||||||
|
"assimp"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,140 @@
|
||||||
|
// Copyright (C) 2016 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Assimp Plugin"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Plugin.cpp
|
||||||
|
|
||||||
|
#include <CustomStream.hpp>
|
||||||
|
#include <Nazara/Core/Error.hpp>
|
||||||
|
#include <Nazara/Core/ErrorFlags.hpp>
|
||||||
|
#include <Nazara/Core/File.hpp>
|
||||||
|
#include <Nazara/Core/String.hpp>
|
||||||
|
#include <Nazara/Utility/Mesh.hpp>
|
||||||
|
#include <assimp/cfileio.h>
|
||||||
|
#include <assimp/cimport.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
using namespace Nz;
|
||||||
|
|
||||||
|
void StreamFlush(aiFile* file)
|
||||||
|
{
|
||||||
|
Stream* stream = reinterpret_cast<Stream*>(file->UserData);
|
||||||
|
stream->Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t StreamRead(aiFile* file, char* buffer, size_t size, size_t count)
|
||||||
|
{
|
||||||
|
Stream* stream = reinterpret_cast<Stream*>(file->UserData);
|
||||||
|
return stream->Read(buffer, size * count);
|
||||||
|
}
|
||||||
|
|
||||||
|
aiReturn StreamSeek(aiFile* file, size_t offset, aiOrigin origin)
|
||||||
|
{
|
||||||
|
Stream* stream = reinterpret_cast<Stream*>(file->UserData);
|
||||||
|
switch (origin)
|
||||||
|
{
|
||||||
|
case aiOrigin_CUR:
|
||||||
|
return (stream->SetCursorPos(stream->GetCursorPos() + offset)) ? aiReturn_SUCCESS : aiReturn_FAILURE;
|
||||||
|
|
||||||
|
case aiOrigin_END:
|
||||||
|
return (stream->SetCursorPos(stream->GetSize() - offset)) ? aiReturn_SUCCESS : aiReturn_FAILURE;
|
||||||
|
|
||||||
|
case aiOrigin_SET:
|
||||||
|
return (stream->SetCursorPos(offset)) ? aiReturn_SUCCESS : aiReturn_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
NazaraWarning("Unhandled aiOrigin enum (value: 0x" + String(origin, 16) + ')');
|
||||||
|
return aiReturn_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t StreamSize(aiFile* file)
|
||||||
|
{
|
||||||
|
Stream* stream = reinterpret_cast<Stream*>(file->UserData);
|
||||||
|
return static_cast<std::size_t>(stream->GetSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t StreamTell(aiFile* file)
|
||||||
|
{
|
||||||
|
Stream* stream = reinterpret_cast<Stream*>(file->UserData);
|
||||||
|
return static_cast<std::size_t>(stream->GetCursorPos());
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t StreamWrite(aiFile* file, const char* buffer, size_t size, size_t count)
|
||||||
|
{
|
||||||
|
Stream* stream = reinterpret_cast<Stream*>(file->UserData);
|
||||||
|
return stream->Write(buffer, size * count);
|
||||||
|
}
|
||||||
|
|
||||||
|
aiFile* StreamOpener(aiFileIO* fileIO, const char* filePath, const char* openMode)
|
||||||
|
{
|
||||||
|
FileIOUserdata* fileIOUserdata = reinterpret_cast<FileIOUserdata*>(fileIO->UserData);
|
||||||
|
|
||||||
|
bool isOriginalStream = (std::strcmp(filePath, fileIOUserdata->originalFilePath) == 0);
|
||||||
|
if (!isOriginalStream && strstr(filePath, StreamPath) != 0)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
aiUserData stream;
|
||||||
|
if (isOriginalStream)
|
||||||
|
stream = reinterpret_cast<aiUserData>(fileIOUserdata->originalStream);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ErrorFlags errFlags(ErrorFlag_ThrowExceptionDisabled, true);
|
||||||
|
|
||||||
|
///TODO: Move to File::DecodeOpenMode
|
||||||
|
UInt32 openModeEnum = 0;
|
||||||
|
|
||||||
|
if (std::strchr(openMode, 'r'))
|
||||||
|
{
|
||||||
|
openModeEnum |= OpenMode_ReadOnly;
|
||||||
|
if (std::strchr(openMode, '+'))
|
||||||
|
openModeEnum |= OpenMode_ReadWrite | OpenMode_MustExit;
|
||||||
|
}
|
||||||
|
else if (std::strchr(openMode, 'w'))
|
||||||
|
{
|
||||||
|
openModeEnum |= OpenMode_WriteOnly | OpenMode_Truncate;
|
||||||
|
if (std::strchr(openMode, '+'))
|
||||||
|
openModeEnum |= OpenMode_ReadOnly;
|
||||||
|
}
|
||||||
|
else if (std::strchr(openMode, 'a'))
|
||||||
|
{
|
||||||
|
openModeEnum |= OpenMode_WriteOnly | OpenMode_Append;
|
||||||
|
if (std::strchr(openMode, '+'))
|
||||||
|
openModeEnum |= OpenMode_ReadOnly;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NazaraError(String("Unhandled/Invalid openmode: ") + openMode + String(" for file ") + filePath);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!std::strchr(openMode, 'b'))
|
||||||
|
openModeEnum |= OpenMode_Text;
|
||||||
|
|
||||||
|
std::unique_ptr<File> file = std::make_unique<File>();
|
||||||
|
if (!file->Open(filePath, openModeEnum))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
stream = reinterpret_cast<char*>(file.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<aiFile> file = std::make_unique<aiFile>();
|
||||||
|
file->FileSizeProc = StreamSize;
|
||||||
|
file->FlushProc = StreamFlush;
|
||||||
|
file->ReadProc = StreamRead;
|
||||||
|
file->SeekProc = StreamSeek;
|
||||||
|
file->TellProc = StreamTell;
|
||||||
|
file->WriteProc = StreamWrite;
|
||||||
|
file->UserData = stream;
|
||||||
|
|
||||||
|
return file.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamCloser(aiFileIO* fileIO, aiFile* file)
|
||||||
|
{
|
||||||
|
FileIOUserdata* fileIOUserdata = reinterpret_cast<FileIOUserdata*>(fileIO->UserData);
|
||||||
|
Stream* fileUserdata = reinterpret_cast<Stream*>(file->UserData);
|
||||||
|
|
||||||
|
if (fileUserdata != fileIOUserdata->originalStream)
|
||||||
|
delete reinterpret_cast<File*>(file->UserData);
|
||||||
|
|
||||||
|
delete file;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright (C) 2016 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Assimp Plugin"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Plugin.cpp
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_ASSIMP_CUSTOM_STREAM_HPP
|
||||||
|
#define NAZARA_ASSIMP_CUSTOM_STREAM_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Core/Stream.hpp>
|
||||||
|
#include <assimp/cfileio.h>
|
||||||
|
|
||||||
|
constexpr const char StreamPath[] = "<Nazara:Stream>";
|
||||||
|
|
||||||
|
void StreamFlush(aiFile* file);
|
||||||
|
size_t StreamRead(aiFile* file, char* buffer, size_t size, size_t count);
|
||||||
|
aiReturn StreamSeek(aiFile* file, size_t offset, aiOrigin origin);
|
||||||
|
size_t StreamSize(aiFile* file);
|
||||||
|
size_t StreamTell(aiFile* file);
|
||||||
|
size_t StreamWrite(aiFile* file, const char* buffer, size_t size, size_t count);
|
||||||
|
|
||||||
|
struct FileIOUserdata
|
||||||
|
{
|
||||||
|
Nz::Stream* originalStream;
|
||||||
|
const char* originalFilePath;
|
||||||
|
};
|
||||||
|
|
||||||
|
aiFile* StreamOpener(aiFileIO* fileIO, const char* filePath, const char* openMode);
|
||||||
|
void StreamCloser(aiFileIO* fileIO, aiFile* file);
|
||||||
|
|
||||||
|
#endif // NAZARA_ASSIMP_CUSTOM_STREAM_HPP
|
||||||
|
|
@ -0,0 +1,250 @@
|
||||||
|
/*
|
||||||
|
Nazara Engine - Assimp Plugin
|
||||||
|
|
||||||
|
Copyright (C) 2015 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <CustomStream.hpp>
|
||||||
|
#include <Nazara/Core/String.hpp>
|
||||||
|
#include <Nazara/Utility/Mesh.hpp>
|
||||||
|
#include <Nazara/Utility/IndexIterator.hpp>
|
||||||
|
#include <Nazara/Utility/IndexMapper.hpp>
|
||||||
|
#include <Nazara/Utility/StaticMesh.hpp>
|
||||||
|
#include <assimp/cfileio.h>
|
||||||
|
#include <assimp/cimport.h>
|
||||||
|
#include <assimp/config.h>
|
||||||
|
#include <assimp/mesh.h>
|
||||||
|
#include <assimp/postprocess.h>
|
||||||
|
#include <assimp/scene.h>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
using namespace Nz;
|
||||||
|
|
||||||
|
void ProcessJoints(aiNode* node, Skeleton* skeleton, const std::set<Nz::String>& joints)
|
||||||
|
{
|
||||||
|
Nz::String jointName(node->mName.data, node->mName.length);
|
||||||
|
if (joints.count(jointName))
|
||||||
|
{
|
||||||
|
Joint* joint = skeleton->GetJoint(jointName);
|
||||||
|
if (joint)
|
||||||
|
{
|
||||||
|
if (node->mParent)
|
||||||
|
joint->SetParent(skeleton->GetJoint(node->mParent->mName.C_Str()));
|
||||||
|
|
||||||
|
Matrix4f transformMatrix(node->mTransformation.a1, node->mTransformation.a2, node->mTransformation.a3, node->mTransformation.a4,
|
||||||
|
node->mTransformation.b1, node->mTransformation.b2, node->mTransformation.b3, node->mTransformation.b4,
|
||||||
|
node->mTransformation.c1, node->mTransformation.c2, node->mTransformation.c3, node->mTransformation.c4,
|
||||||
|
node->mTransformation.d1, node->mTransformation.d2, node->mTransformation.d3, node->mTransformation.d4);
|
||||||
|
|
||||||
|
transformMatrix.InverseAffine();
|
||||||
|
|
||||||
|
joint->SetInverseBindMatrix(transformMatrix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < node->mNumChildren; ++i)
|
||||||
|
ProcessJoints(node->mChildren[i], skeleton, joints);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSupported(const String& extension)
|
||||||
|
{
|
||||||
|
String dotExt = '.' + extension;
|
||||||
|
return (aiIsExtensionSupported(dotExt.GetConstBuffer()) == AI_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ternary Check(Stream& stream, const MeshParams& parameters)
|
||||||
|
{
|
||||||
|
bool skip;
|
||||||
|
if (parameters.custom.GetBooleanParameter("SkipAssimpLoader", &skip) && skip)
|
||||||
|
return Ternary_False;
|
||||||
|
|
||||||
|
return Ternary_Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters)
|
||||||
|
{
|
||||||
|
Nz::String streamPath = stream.GetPath();
|
||||||
|
|
||||||
|
FileIOUserdata userdata;
|
||||||
|
userdata.originalFilePath = (!streamPath.IsEmpty()) ? streamPath.GetConstBuffer() : StreamPath;
|
||||||
|
userdata.originalStream = &stream;
|
||||||
|
|
||||||
|
aiFileIO fileIO;
|
||||||
|
fileIO.CloseProc = StreamCloser;
|
||||||
|
fileIO.OpenProc = StreamOpener;
|
||||||
|
fileIO.UserData = reinterpret_cast<char*>(&userdata);
|
||||||
|
|
||||||
|
unsigned int postProcess = aiProcess_CalcTangentSpace | aiProcess_JoinIdenticalVertices
|
||||||
|
| aiProcess_MakeLeftHanded | aiProcess_Triangulate
|
||||||
|
| aiProcess_RemoveComponent | aiProcess_GenSmoothNormals
|
||||||
|
| aiProcess_SplitLargeMeshes | aiProcess_LimitBoneWeights
|
||||||
|
| aiProcess_ImproveCacheLocality | aiProcess_RemoveRedundantMaterials
|
||||||
|
| aiProcess_FixInfacingNormals | aiProcess_SortByPType
|
||||||
|
| aiProcess_FindInvalidData | aiProcess_GenUVCoords
|
||||||
|
| aiProcess_TransformUVCoords | aiProcess_OptimizeMeshes
|
||||||
|
| aiProcess_OptimizeGraph | aiProcess_FlipWindingOrder
|
||||||
|
| aiProcess_Debone;
|
||||||
|
|
||||||
|
if (!parameters.flipUVs)
|
||||||
|
postProcess |= aiProcess_FlipUVs;
|
||||||
|
|
||||||
|
if (parameters.optimizeIndexBuffers)
|
||||||
|
postProcess |= aiProcess_ImproveCacheLocality;
|
||||||
|
|
||||||
|
float smoothingAngle = 80.f;
|
||||||
|
parameters.custom.GetFloatParameter("AssimpLoader_SmoothingAngle", &smoothingAngle);
|
||||||
|
|
||||||
|
int triangleLimit = 1'000'000;
|
||||||
|
parameters.custom.GetIntegerParameter("AssimpLoader_TriangleLimit", &triangleLimit);
|
||||||
|
|
||||||
|
int vertexLimit = 1'000'000;
|
||||||
|
parameters.custom.GetIntegerParameter("AssimpLoader_VertexLimit", &vertexLimit);
|
||||||
|
|
||||||
|
aiPropertyStore* properties = aiCreatePropertyStore();
|
||||||
|
aiSetImportPropertyFloat(properties, AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE, smoothingAngle);
|
||||||
|
aiSetImportPropertyInteger(properties, AI_CONFIG_PP_LBW_MAX_WEIGHTS, 4);
|
||||||
|
aiSetImportPropertyInteger(properties, AI_CONFIG_PP_SBP_REMOVE, ~aiPrimitiveType_TRIANGLE); //< We only want triangles
|
||||||
|
aiSetImportPropertyInteger(properties, AI_CONFIG_PP_SLM_TRIANGLE_LIMIT, triangleLimit);
|
||||||
|
aiSetImportPropertyInteger(properties, AI_CONFIG_PP_SLM_VERTEX_LIMIT, vertexLimit);
|
||||||
|
aiSetImportPropertyInteger(properties, AI_CONFIG_PP_RVC_FLAGS, aiComponent_COLORS);
|
||||||
|
|
||||||
|
const aiScene* scene = aiImportFileExWithProperties(userdata.originalFilePath, postProcess, &fileIO, properties);
|
||||||
|
aiReleasePropertyStore(properties);
|
||||||
|
|
||||||
|
std::set<Nz::String> joints;
|
||||||
|
|
||||||
|
bool animatedMesh = false;
|
||||||
|
if (parameters.animated)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < scene->mNumMeshes; ++i)
|
||||||
|
{
|
||||||
|
aiMesh* mesh = scene->mMeshes[i];
|
||||||
|
if (mesh->HasBones()) // Inline functions can be safely called
|
||||||
|
{
|
||||||
|
animatedMesh = true;
|
||||||
|
for (unsigned int j = 0; j < mesh->mNumBones; ++j)
|
||||||
|
joints.insert(mesh->mBones[j]->mName.C_Str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (animatedMesh)
|
||||||
|
{
|
||||||
|
mesh->CreateSkeletal(joints.size());
|
||||||
|
|
||||||
|
Skeleton* skeleton = mesh->GetSkeleton();
|
||||||
|
|
||||||
|
// First, assign names
|
||||||
|
unsigned int jointIndex = 0;
|
||||||
|
for (const Nz::String& jointName : joints)
|
||||||
|
skeleton->GetJoint(jointIndex++)->SetName(jointName);
|
||||||
|
|
||||||
|
ProcessJoints(scene->mRootNode, skeleton, joints);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mesh->CreateStatic();
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < scene->mNumMeshes; ++i)
|
||||||
|
{
|
||||||
|
aiMesh* iMesh = scene->mMeshes[i];
|
||||||
|
if (!iMesh->HasBones()) // Don't process skeletal meshs
|
||||||
|
{
|
||||||
|
unsigned int indexCount = iMesh->mNumFaces * 3;
|
||||||
|
unsigned int vertexCount = iMesh->mNumVertices;
|
||||||
|
|
||||||
|
// Index buffer
|
||||||
|
bool largeIndices = (vertexCount > std::numeric_limits<UInt16>::max());
|
||||||
|
|
||||||
|
IndexBufferRef indexBuffer = IndexBuffer::New(largeIndices, indexCount, parameters.storage);
|
||||||
|
|
||||||
|
IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite);
|
||||||
|
IndexIterator index = indexMapper.begin();
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j < iMesh->mNumFaces; ++j)
|
||||||
|
{
|
||||||
|
aiFace& face = iMesh->mFaces[j];
|
||||||
|
if (face.mNumIndices != 3)
|
||||||
|
NazaraWarning("Assimp plugin: This face is not a triangle!");
|
||||||
|
|
||||||
|
*index++ = face.mIndices[0];
|
||||||
|
*index++ = face.mIndices[1];
|
||||||
|
*index++ = face.mIndices[2];
|
||||||
|
}
|
||||||
|
indexMapper.Unmap();
|
||||||
|
|
||||||
|
// Vertex buffer
|
||||||
|
VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent), vertexCount, parameters.storage);
|
||||||
|
BufferMapper<VertexBuffer> vertexMapper(vertexBuffer, BufferAccess_WriteOnly);
|
||||||
|
|
||||||
|
MeshVertex* vertex = static_cast<MeshVertex*>(vertexMapper.GetPointer());
|
||||||
|
for (unsigned int j = 0; j < vertexCount; ++j)
|
||||||
|
{
|
||||||
|
aiVector3D position = iMesh->mVertices[j];
|
||||||
|
aiVector3D normal = iMesh->mNormals[j];
|
||||||
|
aiVector3D tangent = iMesh->mTangents[j];
|
||||||
|
aiVector3D uv = iMesh->mTextureCoords[0][j];
|
||||||
|
|
||||||
|
vertex->position = parameters.scale * Vector3f(position.x, position.y, position.z);
|
||||||
|
vertex->normal.Set(normal.x, normal.y, normal.z);
|
||||||
|
vertex->tangent.Set(tangent.x, tangent.y, tangent.z);
|
||||||
|
vertex->uv.Set(uv.x, uv.y);
|
||||||
|
vertex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
vertexMapper.Unmap();
|
||||||
|
|
||||||
|
// Submesh
|
||||||
|
StaticMeshRef subMesh = StaticMesh::New(mesh);
|
||||||
|
subMesh->Create(vertexBuffer);
|
||||||
|
|
||||||
|
subMesh->SetIndexBuffer(indexBuffer);
|
||||||
|
subMesh->GenerateAABB();
|
||||||
|
subMesh->SetMaterialIndex(iMesh->mMaterialIndex);
|
||||||
|
|
||||||
|
mesh->AddSubMesh(subMesh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameters.center)
|
||||||
|
mesh->Recenter();
|
||||||
|
}
|
||||||
|
|
||||||
|
aiReleaseImport(scene);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
NAZARA_EXPORT int PluginLoad()
|
||||||
|
{
|
||||||
|
Nz::MeshLoader::RegisterLoader(IsSupported, Check, Load);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
NAZARA_EXPORT void PluginUnload()
|
||||||
|
{
|
||||||
|
Nz::MeshLoader::UnregisterLoader(IsSupported, Check, Load);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue