From f900a81e7ad282dbad5c7fcfd1be58f081a04826 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Wed, 14 Nov 2018 15:33:40 -0800 Subject: [PATCH] Add ModelLoader --- .../src/model-networking/ModelLoader.cpp | 52 +++++++++++ .../src/model-networking/ModelLoader.h | 87 +++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 libraries/model-networking/src/model-networking/ModelLoader.cpp create mode 100644 libraries/model-networking/src/model-networking/ModelLoader.h diff --git a/libraries/model-networking/src/model-networking/ModelLoader.cpp b/libraries/model-networking/src/model-networking/ModelLoader.cpp new file mode 100644 index 0000000000..3eb1bec9f0 --- /dev/null +++ b/libraries/model-networking/src/model-networking/ModelLoader.cpp @@ -0,0 +1,52 @@ +// +// ModelLoader.cpp +// libraries/model-networking/src/model-networking +// +// Created by Sabrina Shanman on 2018/11/14. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ModelLoader.h" + +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); + } + } + } + + // 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(); +} diff --git a/libraries/model-networking/src/model-networking/ModelLoader.h b/libraries/model-networking/src/model-networking/ModelLoader.h new file mode 100644 index 0000000000..1a8901e8da --- /dev/null +++ b/libraries/model-networking/src/model-networking/ModelLoader.h @@ -0,0 +1,87 @@ +// +// ModelLoader.h +// libraries/model-networking/src/model-networking +// +// Created by Sabrina Shanman on 2018/11/13. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ModelLoader_h +#define hifi_ModelLoader_h + +#include +#include +#include + +#include +#include + +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 extensions; + std::vector webMediaTypes; + std::vector fileSignatures; + }; + + // T is a subclass of hfm::Serializer + template + void addSupportedFormat(const MIMEType& mimeType) { + supportedFormats.push_back(SupportedFormat(mimeType, SupportedFormat::getLoader())); + } + + // 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; + + class SupportedFormat { + public: + SupportedFormat(const MIMEType& mimeType, const Loader& loader) : + mimeType(mimeType), + loader(loader) { + } + + MIMEType mimeType; + Loader loader; + + template + static Loader getLoader() { + assert(dynamic_cast(&T())); + + return [](const hifi::ByteArray& bytes, const hifi::VariantHash& mapping, const hifi::URL& url) -> hfm::Model::Pointer { + return T().read(bytes, mapping, url); + }; + } + }; + + std::vector supportedFormats; +}; + +#endif // hifi_ModelLoader_h