Simplify ModelLoader to utilize new model format registry

This commit is contained in:
sabrina-shanman 2018-11-30 16:14:14 -08:00
parent 243a1d6598
commit 39d1a2be6f
2 changed files with 6 additions and 123 deletions

View file

@ -11,64 +11,14 @@
#include "ModelLoader.h"
#include "FBXSerializer.h"
#include "OBJSerializer.h"
#include "GLTFSerializer.h"
#include <DependencyManager.h>
#include "ModelFormatRegistry.h"
ModelLoader::ModelLoader() {
// Add supported model formats
MIMEType fbxMIMEType("fbx");
fbxMIMEType.extensions.push_back("fbx");
fbxMIMEType.fileSignatures.emplace_back("Kaydara FBX Binary \x00", 0);
addSupportedFormat<FBXSerializer>(fbxMIMEType);
MIMEType objMIMEType("obj");
objMIMEType.extensions.push_back("obj");
addSupportedFormat<OBJSerializer>(objMIMEType);
MIMEType gltfMIMEType("gltf");
gltfMIMEType.extensions.push_back("gltf");
gltfMIMEType.webMediaTypes.push_back("model/gltf+json");
addSupportedFormat<GLTFSerializer>(gltfMIMEType);
}
hfm::Model::Pointer ModelLoader::load(const hifi::ByteArray& data, const hifi::VariantHash& mapping, const hifi::URL& url, const std::string& webMediaType) const {
// Check file contents
for (auto& supportedFormat : supportedFormats) {
for (auto& fileSignature : supportedFormat.mimeType.fileSignatures) {
auto testBytes = data.mid(fileSignature.byteOffset, (int)fileSignature.bytes.size()).toStdString();
if (testBytes == fileSignature.bytes) {
return supportedFormat.loader(data, mapping, url);
}
}
auto factory = DependencyManager::get<ModelFormatRegistry>()->getFactoryForMIMEType(data, mapping, url, webMediaType);
if (!factory) {
return hfm::Model::Pointer();
}
// Check file extension
std::string urlString = url.path().toStdString();
std::size_t extensionSeparator = urlString.rfind('.');
if (extensionSeparator != std::string::npos) {
std::string detectedExtension = urlString.substr(extensionSeparator + 1);
for (auto& supportedFormat : supportedFormats) {
for (auto& extension : supportedFormat.mimeType.extensions) {
if (extension == detectedExtension) {
return supportedFormat.loader(data, mapping, url);
}
}
}
}
// Check web media type
if (webMediaType != "") {
for (auto& supportedFormat : supportedFormats) {
for (auto& candidateWebMediaType : supportedFormat.mimeType.webMediaTypes) {
if (candidateWebMediaType == webMediaType) {
return supportedFormat.loader(data, mapping, url);
}
}
}
}
// Supported file type not found. Abort loading.
return hfm::Model::Pointer();
return factory->get()->read(data, mapping, url);
}

View file

@ -12,82 +12,15 @@
#ifndef hifi_ModelLoader_h
#define hifi_ModelLoader_h
#include <vector>
#include <string>
#include <functional>
#include <shared/HifiTypes.h>
#include <hfm/HFM.h>
#include <hfm/HFMSerializer.h>
class ModelLoader {
public:
// A short sequence of bytes, typically at the beginning of the file, which identifies the file format
class FileSignature {
public:
FileSignature(const std::string& bytes, int byteOffset) :
bytes(bytes),
byteOffset(byteOffset) {
}
std::string bytes;
int byteOffset;
};
// A named file extension with a list of known ways to positively identify the file type
class MIMEType {
public:
MIMEType(const std::string& name) :
name(name) {
}
std::string name;
std::vector<std::string> extensions;
std::vector<std::string> webMediaTypes;
std::vector<FileSignature> fileSignatures;
};
ModelLoader();
// T is a subclass of hfm::Serializer
template <typename T>
void addSupportedFormat(const MIMEType& mimeType) {
supportedFormats.push_back(SupportedFormat(mimeType, SupportedFormat::getLoader<T>()));
}
// Given the currently stored list of supported file formats, determine how to load a model from the given parameters.
// If successful, return an owned reference to the newly loaded model.
// If failed, return an empty reference.
hfm::Model::Pointer load(const hifi::ByteArray& data, const hifi::VariantHash& mapping, const hifi::URL& url, const std::string& webMediaType) const;
protected:
using Loader = std::function<hfm::Model::Pointer(const hifi::ByteArray&, const hifi::VariantHash&, const hifi::URL&)>;
class SupportedFormat {
public:
SupportedFormat(const MIMEType& mimeType, const Loader& loader) :
mimeType(mimeType),
loader(loader) {
}
MIMEType mimeType;
Loader loader;
template <typename T>
static Loader getLoader() {
assert([](){
T t;
return dynamic_cast<hfm::Serializer*>(&t) != nullptr;
}());
return [](const hifi::ByteArray& bytes, const hifi::VariantHash& mapping, const hifi::URL& url) -> hfm::Model::Pointer {
return T().read(bytes, mapping, url);
};
}
};
std::vector<SupportedFormat> supportedFormats;
};
#endif // hifi_ModelLoader_h