Convert serializers and FBX.h to use HifiTypes.h

This commit is contained in:
sabrina-shanman 2019-02-25 12:04:26 -08:00
parent 8ff212ac95
commit 2af17015d3
10 changed files with 177 additions and 179 deletions

View file

@ -13,16 +13,17 @@
#define hifi_FBX_h_
#include <QMetaType>
#include <QVarLengthArray>
#include <QVariant>
#include <QVector>
#include <glm/glm.hpp>
#include <shared/HifiTypes.h>
// See comment in FBXSerializer::parseFBX().
static const int FBX_HEADER_BYTES_BEFORE_VERSION = 23;
static const QByteArray FBX_BINARY_PROLOG("Kaydara FBX Binary ");
static const QByteArray FBX_BINARY_PROLOG2("\0\x1a\0", 3);
static const hifi::ByteArray FBX_BINARY_PROLOG("Kaydara FBX Binary ");
static const hifi::ByteArray FBX_BINARY_PROLOG2("\0\x1a\0", 3);
static const quint32 FBX_VERSION_2015 = 7400;
static const quint32 FBX_VERSION_2016 = 7500;
@ -36,7 +37,7 @@ using FBXNodeList = QList<FBXNode>;
/// A node within an FBX document.
class FBXNode {
public:
QByteArray name;
hifi::ByteArray name;
QVariantList properties;
FBXNodeList children;
};

View file

@ -179,7 +179,7 @@ public:
void printNode(const FBXNode& node, int indentLevel) {
int indentLength = 2;
QByteArray spaces(indentLevel * indentLength, ' ');
hifi::ByteArray spaces(indentLevel * indentLength, ' ');
QDebug nodeDebug = qDebug(modelformat);
nodeDebug.nospace() << spaces.data() << node.name.data() << ": ";
@ -309,7 +309,7 @@ public:
};
bool checkMaterialsHaveTextures(const QHash<QString, HFMMaterial>& materials,
const QHash<QString, QByteArray>& textureFilenames, const QMultiMap<QString, QString>& _connectionChildMap) {
const QHash<QString, hifi::ByteArray>& textureFilenames, const QMultiMap<QString, QString>& _connectionChildMap) {
foreach (const QString& materialID, materials.keys()) {
foreach (const QString& childID, _connectionChildMap.values(materialID)) {
if (textureFilenames.contains(childID)) {
@ -376,7 +376,7 @@ HFMLight extractLight(const FBXNode& object) {
return light;
}
QByteArray fileOnUrl(const QByteArray& filepath, const QString& url) {
hifi::ByteArray fileOnUrl(const hifi::ByteArray& filepath, const QString& url) {
// in order to match the behaviour when loading models from remote URLs
// we assume that all external textures are right beside the loaded model
// ignoring any relative paths or absolute paths inside of models
@ -384,7 +384,7 @@ QByteArray fileOnUrl(const QByteArray& filepath, const QString& url) {
return filepath.mid(filepath.lastIndexOf('/') + 1);
}
HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QString& url) {
HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const QString& url) {
const FBXNode& node = _rootNode;
QMap<QString, ExtractedMesh> meshes;
QHash<QString, QString> modelIDsToNames;
@ -407,11 +407,11 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
std::map<QString, HFMLight> lights;
QVariantHash blendshapeMappings = mapping.value("bs").toHash();
hifi::VariantHash blendshapeMappings = mapping.value("bs").toHash();
QMultiHash<QByteArray, WeightedIndex> blendshapeIndices;
QMultiHash<hifi::ByteArray, WeightedIndex> blendshapeIndices;
for (int i = 0;; i++) {
QByteArray blendshapeName = FACESHIFT_BLENDSHAPES[i];
hifi::ByteArray blendshapeName = FACESHIFT_BLENDSHAPES[i];
if (blendshapeName.isEmpty()) {
break;
}
@ -454,7 +454,7 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
}
} else if (subobject.name == "Properties70") {
foreach (const FBXNode& subsubobject, subobject.children) {
static const QVariant APPLICATION_NAME = QVariant(QByteArray("Original|ApplicationName"));
static const QVariant APPLICATION_NAME = QVariant(hifi::ByteArray("Original|ApplicationName"));
if (subsubobject.name == "P" && subsubobject.properties.size() >= 5 &&
subsubobject.properties.at(0) == APPLICATION_NAME) {
hfmModel.applicationName = subsubobject.properties.at(4).toString();
@ -471,8 +471,8 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
int index = 4;
foreach (const FBXNode& subobject, object.children) {
if (subobject.name == propertyName) {
static const QVariant UNIT_SCALE_FACTOR = QByteArray("UnitScaleFactor");
static const QVariant AMBIENT_COLOR = QByteArray("AmbientColor");
static const QVariant UNIT_SCALE_FACTOR = hifi::ByteArray("UnitScaleFactor");
static const QVariant AMBIENT_COLOR = hifi::ByteArray("AmbientColor");
const auto& subpropName = subobject.properties.at(0);
if (subpropName == UNIT_SCALE_FACTOR) {
unitScaleFactor = subobject.properties.at(index).toFloat();
@ -528,7 +528,7 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
QVector<ExtractedBlendshape> blendshapes;
foreach (const FBXNode& subobject, object.children) {
bool properties = false;
QByteArray propertyName;
hifi::ByteArray propertyName;
int index;
if (subobject.name == "Properties60") {
properties = true;
@ -541,27 +541,27 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
index = 4;
}
if (properties) {
static const QVariant ROTATION_ORDER = QByteArray("RotationOrder");
static const QVariant GEOMETRIC_TRANSLATION = QByteArray("GeometricTranslation");
static const QVariant GEOMETRIC_ROTATION = QByteArray("GeometricRotation");
static const QVariant GEOMETRIC_SCALING = QByteArray("GeometricScaling");
static const QVariant LCL_TRANSLATION = QByteArray("Lcl Translation");
static const QVariant LCL_ROTATION = QByteArray("Lcl Rotation");
static const QVariant LCL_SCALING = QByteArray("Lcl Scaling");
static const QVariant ROTATION_MAX = QByteArray("RotationMax");
static const QVariant ROTATION_MAX_X = QByteArray("RotationMaxX");
static const QVariant ROTATION_MAX_Y = QByteArray("RotationMaxY");
static const QVariant ROTATION_MAX_Z = QByteArray("RotationMaxZ");
static const QVariant ROTATION_MIN = QByteArray("RotationMin");
static const QVariant ROTATION_MIN_X = QByteArray("RotationMinX");
static const QVariant ROTATION_MIN_Y = QByteArray("RotationMinY");
static const QVariant ROTATION_MIN_Z = QByteArray("RotationMinZ");
static const QVariant ROTATION_OFFSET = QByteArray("RotationOffset");
static const QVariant ROTATION_PIVOT = QByteArray("RotationPivot");
static const QVariant SCALING_OFFSET = QByteArray("ScalingOffset");
static const QVariant SCALING_PIVOT = QByteArray("ScalingPivot");
static const QVariant PRE_ROTATION = QByteArray("PreRotation");
static const QVariant POST_ROTATION = QByteArray("PostRotation");
static const QVariant ROTATION_ORDER = hifi::ByteArray("RotationOrder");
static const QVariant GEOMETRIC_TRANSLATION = hifi::ByteArray("GeometricTranslation");
static const QVariant GEOMETRIC_ROTATION = hifi::ByteArray("GeometricRotation");
static const QVariant GEOMETRIC_SCALING = hifi::ByteArray("GeometricScaling");
static const QVariant LCL_TRANSLATION = hifi::ByteArray("Lcl Translation");
static const QVariant LCL_ROTATION = hifi::ByteArray("Lcl Rotation");
static const QVariant LCL_SCALING = hifi::ByteArray("Lcl Scaling");
static const QVariant ROTATION_MAX = hifi::ByteArray("RotationMax");
static const QVariant ROTATION_MAX_X = hifi::ByteArray("RotationMaxX");
static const QVariant ROTATION_MAX_Y = hifi::ByteArray("RotationMaxY");
static const QVariant ROTATION_MAX_Z = hifi::ByteArray("RotationMaxZ");
static const QVariant ROTATION_MIN = hifi::ByteArray("RotationMin");
static const QVariant ROTATION_MIN_X = hifi::ByteArray("RotationMinX");
static const QVariant ROTATION_MIN_Y = hifi::ByteArray("RotationMinY");
static const QVariant ROTATION_MIN_Z = hifi::ByteArray("RotationMinZ");
static const QVariant ROTATION_OFFSET = hifi::ByteArray("RotationOffset");
static const QVariant ROTATION_PIVOT = hifi::ByteArray("RotationPivot");
static const QVariant SCALING_OFFSET = hifi::ByteArray("ScalingOffset");
static const QVariant SCALING_PIVOT = hifi::ByteArray("ScalingPivot");
static const QVariant PRE_ROTATION = hifi::ByteArray("PreRotation");
static const QVariant POST_ROTATION = hifi::ByteArray("PostRotation");
foreach(const FBXNode& property, subobject.children) {
const auto& childProperty = property.properties.at(0);
if (property.name == propertyName) {
@ -701,8 +701,8 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
const int MODEL_UV_SCALING_MIN_SIZE = 2;
const int CROPPING_MIN_SIZE = 4;
if (subobject.name == "RelativeFilename" && subobject.properties.length() >= RELATIVE_FILENAME_MIN_SIZE) {
QByteArray filename = subobject.properties.at(0).toByteArray();
QByteArray filepath = filename.replace('\\', '/');
hifi::ByteArray filename = subobject.properties.at(0).toByteArray();
hifi::ByteArray filepath = filename.replace('\\', '/');
filename = fileOnUrl(filepath, url);
_textureFilepaths.insert(getID(object.properties), filepath);
_textureFilenames.insert(getID(object.properties), filename);
@ -731,17 +731,17 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
subobject.properties.at(2).value<int>(),
subobject.properties.at(3).value<int>()));
} else if (subobject.name == "Properties70") {
QByteArray propertyName;
hifi::ByteArray propertyName;
int index;
propertyName = "P";
index = 4;
foreach (const FBXNode& property, subobject.children) {
static const QVariant UV_SET = QByteArray("UVSet");
static const QVariant CURRENT_TEXTURE_BLEND_MODE = QByteArray("CurrentTextureBlendMode");
static const QVariant USE_MATERIAL = QByteArray("UseMaterial");
static const QVariant TRANSLATION = QByteArray("Translation");
static const QVariant ROTATION = QByteArray("Rotation");
static const QVariant SCALING = QByteArray("Scaling");
static const QVariant UV_SET = hifi::ByteArray("UVSet");
static const QVariant CURRENT_TEXTURE_BLEND_MODE = hifi::ByteArray("CurrentTextureBlendMode");
static const QVariant USE_MATERIAL = hifi::ByteArray("UseMaterial");
static const QVariant TRANSLATION = hifi::ByteArray("Translation");
static const QVariant ROTATION = hifi::ByteArray("Rotation");
static const QVariant SCALING = hifi::ByteArray("Scaling");
if (property.name == propertyName) {
QString v = property.properties.at(0).toString();
if (property.properties.at(0) == UV_SET) {
@ -795,8 +795,8 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
_textureParams.insert(getID(object.properties), tex);
}
} else if (object.name == "Video") {
QByteArray filepath;
QByteArray content;
hifi::ByteArray filepath;
hifi::ByteArray content;
foreach (const FBXNode& subobject, object.children) {
if (subobject.name == "RelativeFilename") {
filepath = subobject.properties.at(0).toByteArray();
@ -816,7 +816,7 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
foreach (const FBXNode& subobject, object.children) {
bool properties = false;
QByteArray propertyName;
hifi::ByteArray propertyName;
int index;
if (subobject.name == "Properties60") {
properties = true;
@ -833,31 +833,31 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
if (properties) {
std::vector<std::string> unknowns;
static const QVariant DIFFUSE_COLOR = QByteArray("DiffuseColor");
static const QVariant DIFFUSE_FACTOR = QByteArray("DiffuseFactor");
static const QVariant DIFFUSE = QByteArray("Diffuse");
static const QVariant SPECULAR_COLOR = QByteArray("SpecularColor");
static const QVariant SPECULAR_FACTOR = QByteArray("SpecularFactor");
static const QVariant SPECULAR = QByteArray("Specular");
static const QVariant EMISSIVE_COLOR = QByteArray("EmissiveColor");
static const QVariant EMISSIVE_FACTOR = QByteArray("EmissiveFactor");
static const QVariant EMISSIVE = QByteArray("Emissive");
static const QVariant AMBIENT_FACTOR = QByteArray("AmbientFactor");
static const QVariant SHININESS = QByteArray("Shininess");
static const QVariant OPACITY = QByteArray("Opacity");
static const QVariant MAYA_USE_NORMAL_MAP = QByteArray("Maya|use_normal_map");
static const QVariant MAYA_BASE_COLOR = QByteArray("Maya|base_color");
static const QVariant MAYA_USE_COLOR_MAP = QByteArray("Maya|use_color_map");
static const QVariant MAYA_ROUGHNESS = QByteArray("Maya|roughness");
static const QVariant MAYA_USE_ROUGHNESS_MAP = QByteArray("Maya|use_roughness_map");
static const QVariant MAYA_METALLIC = QByteArray("Maya|metallic");
static const QVariant MAYA_USE_METALLIC_MAP = QByteArray("Maya|use_metallic_map");
static const QVariant MAYA_EMISSIVE = QByteArray("Maya|emissive");
static const QVariant MAYA_EMISSIVE_INTENSITY = QByteArray("Maya|emissive_intensity");
static const QVariant MAYA_USE_EMISSIVE_MAP = QByteArray("Maya|use_emissive_map");
static const QVariant MAYA_USE_AO_MAP = QByteArray("Maya|use_ao_map");
static const QVariant MAYA_UV_SCALE = QByteArray("Maya|uv_scale");
static const QVariant MAYA_UV_OFFSET = QByteArray("Maya|uv_offset");
static const QVariant DIFFUSE_COLOR = hifi::ByteArray("DiffuseColor");
static const QVariant DIFFUSE_FACTOR = hifi::ByteArray("DiffuseFactor");
static const QVariant DIFFUSE = hifi::ByteArray("Diffuse");
static const QVariant SPECULAR_COLOR = hifi::ByteArray("SpecularColor");
static const QVariant SPECULAR_FACTOR = hifi::ByteArray("SpecularFactor");
static const QVariant SPECULAR = hifi::ByteArray("Specular");
static const QVariant EMISSIVE_COLOR = hifi::ByteArray("EmissiveColor");
static const QVariant EMISSIVE_FACTOR = hifi::ByteArray("EmissiveFactor");
static const QVariant EMISSIVE = hifi::ByteArray("Emissive");
static const QVariant AMBIENT_FACTOR = hifi::ByteArray("AmbientFactor");
static const QVariant SHININESS = hifi::ByteArray("Shininess");
static const QVariant OPACITY = hifi::ByteArray("Opacity");
static const QVariant MAYA_USE_NORMAL_MAP = hifi::ByteArray("Maya|use_normal_map");
static const QVariant MAYA_BASE_COLOR = hifi::ByteArray("Maya|base_color");
static const QVariant MAYA_USE_COLOR_MAP = hifi::ByteArray("Maya|use_color_map");
static const QVariant MAYA_ROUGHNESS = hifi::ByteArray("Maya|roughness");
static const QVariant MAYA_USE_ROUGHNESS_MAP = hifi::ByteArray("Maya|use_roughness_map");
static const QVariant MAYA_METALLIC = hifi::ByteArray("Maya|metallic");
static const QVariant MAYA_USE_METALLIC_MAP = hifi::ByteArray("Maya|use_metallic_map");
static const QVariant MAYA_EMISSIVE = hifi::ByteArray("Maya|emissive");
static const QVariant MAYA_EMISSIVE_INTENSITY = hifi::ByteArray("Maya|emissive_intensity");
static const QVariant MAYA_USE_EMISSIVE_MAP = hifi::ByteArray("Maya|use_emissive_map");
static const QVariant MAYA_USE_AO_MAP = hifi::ByteArray("Maya|use_ao_map");
static const QVariant MAYA_UV_SCALE = hifi::ByteArray("Maya|uv_scale");
static const QVariant MAYA_UV_OFFSET = hifi::ByteArray("Maya|uv_offset");
static const int MAYA_UV_OFFSET_PROPERTY_LENGTH = 6;
static const int MAYA_UV_SCALE_PROPERTY_LENGTH = 6;
@ -1034,7 +1034,7 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
clusters.insert(getID(object.properties), cluster);
} else if (object.properties.last() == "BlendShapeChannel") {
QByteArray name = object.properties.at(1).toByteArray();
hifi::ByteArray name = object.properties.at(1).toByteArray();
name = name.left(name.indexOf('\0'));
if (!blendshapeIndices.contains(name)) {
@ -1071,8 +1071,8 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
#endif
}
} else if (child.name == "Connections") {
static const QVariant OO = QByteArray("OO");
static const QVariant OP = QByteArray("OP");
static const QVariant OO = hifi::ByteArray("OO");
static const QVariant OP = hifi::ByteArray("OP");
foreach (const FBXNode& connection, child.children) {
if (connection.name == "C" || connection.name == "Connect") {
if (connection.properties.at(0) == OO) {
@ -1091,7 +1091,7 @@ HFMModel* FBXSerializer::extractHFMModel(const QVariantHash& mapping, const QStr
}
} else if (connection.properties.at(0) == OP) {
int counter = 0;
QByteArray type = connection.properties.at(3).toByteArray().toLower();
hifi::ByteArray type = connection.properties.at(3).toByteArray().toLower();
if (type.contains("DiffuseFactor")) {
diffuseFactorTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
} else if ((type.contains("diffuse") && !type.contains("tex_global_diffuse"))) {
@ -1678,8 +1678,8 @@ std::unique_ptr<hfm::Serializer::Factory> FBXSerializer::getFactory() const {
return std::make_unique<hfm::Serializer::SimpleFactory<FBXSerializer>>();
}
HFMModel::Pointer FBXSerializer::read(const QByteArray& data, const QVariantHash& mapping, const QUrl& url) {
QBuffer buffer(const_cast<QByteArray*>(&data));
HFMModel::Pointer FBXSerializer::read(const hifi::ByteArray& data, const hifi::VariantHash& mapping, const hifi::URL& url) {
QBuffer buffer(const_cast<hifi::ByteArray*>(&data));
buffer.open(QIODevice::ReadOnly);
_rootNode = parseFBX(&buffer);

View file

@ -15,9 +15,6 @@
#include <QtGlobal>
#include <QMetaType>
#include <QSet>
#include <QUrl>
#include <QVarLengthArray>
#include <QVariant>
#include <QVector>
#include <glm/glm.hpp>
@ -25,6 +22,7 @@
#include <Extents.h>
#include <Transform.h>
#include <shared/HifiTypes.h>
#include "FBX.h"
#include <hfm/HFMSerializer.h>
@ -114,12 +112,12 @@ public:
HFMModel* _hfmModel;
/// Reads HFMModel from the supplied model and mapping data.
/// \exception QString if an error occurs in parsing
HFMModel::Pointer read(const QByteArray& data, const QVariantHash& mapping, const QUrl& url = QUrl()) override;
HFMModel::Pointer read(const hifi::ByteArray& data, const hifi::VariantHash& mapping, const hifi::URL& url = hifi::URL()) override;
FBXNode _rootNode;
static FBXNode parseFBX(QIODevice* device);
HFMModel* extractHFMModel(const QVariantHash& mapping, const QString& url);
HFMModel* extractHFMModel(const hifi::VariantHash& mapping, const QString& url);
static ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex, bool deduplicate = true);
QHash<QString, ExtractedMesh> meshes;
@ -128,11 +126,11 @@ public:
QHash<QString, QString> _textureNames;
// Hashes the original RelativeFilename of textures
QHash<QString, QByteArray> _textureFilepaths;
QHash<QString, hifi::ByteArray> _textureFilepaths;
// Hashes the place to look for textures, in case they are not inlined
QHash<QString, QByteArray> _textureFilenames;
QHash<QString, hifi::ByteArray> _textureFilenames;
// Hashes texture content by filepath, in case they are inlined
QHash<QByteArray, QByteArray> _textureContent;
QHash<hifi::ByteArray, hifi::ByteArray> _textureContent;
QHash<QString, TextureParam> _textureParams;

View file

@ -15,7 +15,6 @@
#include <memory>
#include <QBuffer>
#include <QDataStream>
#include <QIODevice>
#include <QStringList>
#include <QTextStream>
@ -29,7 +28,7 @@
HFMTexture FBXSerializer::getTexture(const QString& textureID, const QString& materialID) {
HFMTexture texture;
const QByteArray& filepath = _textureFilepaths.value(textureID);
const hifi::ByteArray& filepath = _textureFilepaths.value(textureID);
texture.content = _textureContent.value(filepath);
if (texture.content.isEmpty()) { // the content is not inlined

View file

@ -190,8 +190,8 @@ ExtractedMesh FBXSerializer::extractMesh(const FBXNode& object, unsigned int& me
bool isMaterialPerPolygon = false;
static const QVariant BY_VERTICE = QByteArray("ByVertice");
static const QVariant INDEX_TO_DIRECT = QByteArray("IndexToDirect");
static const QVariant BY_VERTICE = hifi::ByteArray("ByVertice");
static const QVariant INDEX_TO_DIRECT = hifi::ByteArray("IndexToDirect");
bool isDracoMesh = false;
@ -321,7 +321,7 @@ ExtractedMesh FBXSerializer::extractMesh(const FBXNode& object, unsigned int& me
}
}
} else if (child.name == "LayerElementMaterial") {
static const QVariant BY_POLYGON = QByteArray("ByPolygon");
static const QVariant BY_POLYGON = hifi::ByteArray("ByPolygon");
foreach (const FBXNode& subdata, child.children) {
if (subdata.name == "Materials") {
materials = getIntVector(subdata);
@ -348,7 +348,7 @@ ExtractedMesh FBXSerializer::extractMesh(const FBXNode& object, unsigned int& me
// load the draco mesh from the FBX and create a draco::Mesh
draco::Decoder decoder;
draco::DecoderBuffer decodedBuffer;
QByteArray dracoArray = child.properties.at(0).value<QByteArray>();
hifi::ByteArray dracoArray = child.properties.at(0).value<hifi::ByteArray>();
decodedBuffer.Init(dracoArray.data(), dracoArray.size());
std::unique_ptr<draco::Mesh> dracoMesh(new draco::Mesh());

View file

@ -48,10 +48,10 @@ QVariant readBinaryArray(QDataStream& in, int& position) {
QVector<T> values;
if ((int)QSysInfo::ByteOrder == (int)in.byteOrder()) {
values.resize(arrayLength);
QByteArray arrayData;
hifi::ByteArray arrayData;
if (encoding == FBX_PROPERTY_COMPRESSED_FLAG) {
// preface encoded data with uncompressed length
QByteArray compressed(sizeof(quint32) + compressedLength, 0);
hifi::ByteArray compressed(sizeof(quint32) + compressedLength, 0);
*((quint32*)compressed.data()) = qToBigEndian<quint32>(arrayLength * sizeof(T));
in.readRawData(compressed.data() + sizeof(quint32), compressedLength);
position += compressedLength;
@ -73,11 +73,11 @@ QVariant readBinaryArray(QDataStream& in, int& position) {
values.reserve(arrayLength);
if (encoding == FBX_PROPERTY_COMPRESSED_FLAG) {
// preface encoded data with uncompressed length
QByteArray compressed(sizeof(quint32) + compressedLength, 0);
hifi::ByteArray compressed(sizeof(quint32) + compressedLength, 0);
*((quint32*)compressed.data()) = qToBigEndian<quint32>(arrayLength * sizeof(T));
in.readRawData(compressed.data() + sizeof(quint32), compressedLength);
position += compressedLength;
QByteArray uncompressed = qUncompress(compressed);
hifi::ByteArray uncompressed = qUncompress(compressed);
if (uncompressed.isEmpty()) { // answers empty byte array if corrupt
throw QString("corrupt fbx file");
}
@ -234,7 +234,7 @@ public:
};
int nextToken();
const QByteArray& getDatum() const { return _datum; }
const hifi::ByteArray& getDatum() const { return _datum; }
void pushBackToken(int token) { _pushedBackToken = token; }
void ungetChar(char ch) { _device->ungetChar(ch); }
@ -242,7 +242,7 @@ public:
private:
QIODevice* _device;
QByteArray _datum;
hifi::ByteArray _datum;
int _pushedBackToken;
};
@ -325,7 +325,7 @@ FBXNode parseTextFBXNode(Tokenizer& tokenizer) {
expectingDatum = true;
} else if (token == Tokenizer::DATUM_TOKEN && expectingDatum) {
QByteArray datum = tokenizer.getDatum();
hifi::ByteArray datum = tokenizer.getDatum();
if ((token = tokenizer.nextToken()) == ':') {
tokenizer.ungetChar(':');
tokenizer.pushBackToken(Tokenizer::DATUM_TOKEN);

View file

@ -125,18 +125,18 @@ bool GLTFSerializer::getObjectArrayVal(const QJsonObject& object, const QString&
return _defined;
}
QByteArray GLTFSerializer::setGLBChunks(const QByteArray& data) {
hifi::ByteArray GLTFSerializer::setGLBChunks(const hifi::ByteArray& data) {
int byte = 4;
int jsonStart = data.indexOf("JSON", Qt::CaseSensitive);
int binStart = data.indexOf("BIN", Qt::CaseSensitive);
int jsonLength, binLength;
QByteArray jsonLengthChunk, binLengthChunk;
hifi::ByteArray jsonLengthChunk, binLengthChunk;
jsonLengthChunk = data.mid(jsonStart - byte, byte);
QDataStream tempJsonLen(jsonLengthChunk);
tempJsonLen.setByteOrder(QDataStream::LittleEndian);
tempJsonLen >> jsonLength;
QByteArray jsonChunk = data.mid(jsonStart + byte, jsonLength);
hifi::ByteArray jsonChunk = data.mid(jsonStart + byte, jsonLength);
if (binStart != -1) {
binLengthChunk = data.mid(binStart - byte, byte);
@ -567,10 +567,10 @@ bool GLTFSerializer::addTexture(const QJsonObject& object) {
return true;
}
bool GLTFSerializer::parseGLTF(const QByteArray& data) {
bool GLTFSerializer::parseGLTF(const hifi::ByteArray& data) {
PROFILE_RANGE_EX(resource_parse, __FUNCTION__, 0xffff0000, nullptr);
QByteArray jsonChunk = data;
hifi::ByteArray jsonChunk = data;
if (_url.toString().endsWith("glb") && data.indexOf("glTF") == 0 && data.contains("JSON")) {
jsonChunk = setGLBChunks(data);
@ -734,7 +734,7 @@ glm::mat4 GLTFSerializer::getModelTransform(const GLTFNode& node) {
return tmat;
}
bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const QUrl& url) {
bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::URL& url) {
//Build dependencies
QVector<QVector<int>> nodeDependencies(_file.nodes.size());
@ -993,15 +993,15 @@ std::unique_ptr<hfm::Serializer::Factory> GLTFSerializer::getFactory() const {
return std::make_unique<hfm::Serializer::SimpleFactory<GLTFSerializer>>();
}
HFMModel::Pointer GLTFSerializer::read(const QByteArray& data, const QVariantHash& mapping, const QUrl& url) {
HFMModel::Pointer GLTFSerializer::read(const hifi::ByteArray& data, const hifi::VariantHash& mapping, const hifi::URL& url) {
_url = url;
// Normalize url for local files
QUrl normalizeUrl = DependencyManager::get<ResourceManager>()->normalizeURL(_url);
hifi::URL normalizeUrl = DependencyManager::get<ResourceManager>()->normalizeURL(_url);
if (normalizeUrl.scheme().isEmpty() || (normalizeUrl.scheme() == "file")) {
QString localFileName = PathUtils::expandToLocalDataAbsolutePath(normalizeUrl).toLocalFile();
_url = QUrl(QFileInfo(localFileName).absoluteFilePath());
_url = hifi::URL(QFileInfo(localFileName).absoluteFilePath());
}
if (parseGLTF(data)) {
@ -1019,15 +1019,15 @@ HFMModel::Pointer GLTFSerializer::read(const QByteArray& data, const QVariantHas
return nullptr;
}
bool GLTFSerializer::readBinary(const QString& url, QByteArray& outdata) {
bool GLTFSerializer::readBinary(const QString& url, hifi::ByteArray& outdata) {
bool success;
if (url.contains("data:application/octet-stream;base64,")) {
outdata = requestEmbeddedData(url);
success = !outdata.isEmpty();
} else {
QUrl binaryUrl = _url.resolved(url);
std::tie<bool, QByteArray>(success, outdata) = requestData(binaryUrl);
hifi::URL binaryUrl = _url.resolved(url);
std::tie<bool, hifi::ByteArray>(success, outdata) = requestData(binaryUrl);
}
return success;
@ -1037,16 +1037,16 @@ bool GLTFSerializer::doesResourceExist(const QString& url) {
if (_url.isEmpty()) {
return false;
}
QUrl candidateUrl = _url.resolved(url);
hifi::URL candidateUrl = _url.resolved(url);
return DependencyManager::get<ResourceManager>()->resourceExists(candidateUrl);
}
std::tuple<bool, QByteArray> GLTFSerializer::requestData(QUrl& url) {
std::tuple<bool, hifi::ByteArray> GLTFSerializer::requestData(hifi::URL& url) {
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(
nullptr, url, true, -1, "GLTFSerializer::requestData");
if (!request) {
return std::make_tuple(false, QByteArray());
return std::make_tuple(false, hifi::ByteArray());
}
QEventLoop loop;
@ -1057,17 +1057,17 @@ std::tuple<bool, QByteArray> GLTFSerializer::requestData(QUrl& url) {
if (request->getResult() == ResourceRequest::Success) {
return std::make_tuple(true, request->getData());
} else {
return std::make_tuple(false, QByteArray());
return std::make_tuple(false, hifi::ByteArray());
}
}
QByteArray GLTFSerializer::requestEmbeddedData(const QString& url) {
hifi::ByteArray GLTFSerializer::requestEmbeddedData(const QString& url) {
QString binaryUrl = url.split(",")[1];
return binaryUrl.isEmpty() ? QByteArray() : QByteArray::fromBase64(binaryUrl.toUtf8());
return binaryUrl.isEmpty() ? hifi::ByteArray() : QByteArray::fromBase64(binaryUrl.toUtf8());
}
QNetworkReply* GLTFSerializer::request(QUrl& url, bool isTest) {
QNetworkReply* GLTFSerializer::request(hifi::URL& url, bool isTest) {
if (!qApp) {
return nullptr;
}
@ -1098,8 +1098,8 @@ HFMTexture GLTFSerializer::getHFMTexture(const GLTFTexture& texture) {
if (texture.defined["source"]) {
QString url = _file.images[texture.source].uri;
QString fname = QUrl(url).fileName();
QUrl textureUrl = _url.resolved(url);
QString fname = hifi::URL(url).fileName();
hifi::URL textureUrl = _url.resolved(url);
qCDebug(modelformat) << "fname: " << fname;
fbxtex.name = fname;
fbxtex.filename = textureUrl.toEncoded();
@ -1187,7 +1187,7 @@ void GLTFSerializer::setHFMMaterial(HFMMaterial& fbxmat, const GLTFMaterial& mat
}
template<typename T, typename L>
bool GLTFSerializer::readArray(const QByteArray& bin, int byteOffset, int count,
bool GLTFSerializer::readArray(const hifi::ByteArray& bin, int byteOffset, int count,
QVector<L>& outarray, int accessorType) {
QDataStream blobstream(bin);
@ -1244,7 +1244,7 @@ bool GLTFSerializer::readArray(const QByteArray& bin, int byteOffset, int count,
return true;
}
template<typename T>
bool GLTFSerializer::addArrayOfType(const QByteArray& bin, int byteOffset, int count,
bool GLTFSerializer::addArrayOfType(const hifi::ByteArray& bin, int byteOffset, int count,
QVector<T>& outarray, int accessorType, int componentType) {
switch (componentType) {

View file

@ -214,7 +214,7 @@ struct GLTFBufferView {
struct GLTFBuffer {
int byteLength; //required
QString uri;
QByteArray blob;
hifi::ByteArray blob;
QMap<QString, bool> defined;
void dump() {
if (defined["byteLength"]) {
@ -705,16 +705,16 @@ public:
MediaType getMediaType() const override;
std::unique_ptr<hfm::Serializer::Factory> getFactory() const override;
HFMModel::Pointer read(const QByteArray& data, const QVariantHash& mapping, const QUrl& url = QUrl()) override;
HFMModel::Pointer read(const hifi::ByteArray& data, const hifi::VariantHash& mapping, const hifi::URL& url = hifi::URL()) override;
private:
GLTFFile _file;
QUrl _url;
QByteArray _glbBinary;
hifi::URL _url;
hifi::ByteArray _glbBinary;
glm::mat4 getModelTransform(const GLTFNode& node);
bool buildGeometry(HFMModel& hfmModel, const QUrl& url);
bool parseGLTF(const QByteArray& data);
bool buildGeometry(HFMModel& hfmModel, const hifi::URL& url);
bool parseGLTF(const hifi::ByteArray& data);
bool getStringVal(const QJsonObject& object, const QString& fieldname,
QString& value, QMap<QString, bool>& defined);
@ -733,7 +733,7 @@ private:
bool getObjectArrayVal(const QJsonObject& object, const QString& fieldname,
QJsonArray& objects, QMap<QString, bool>& defined);
QByteArray setGLBChunks(const QByteArray& data);
hifi::ByteArray setGLBChunks(const hifi::ByteArray& data);
int getMaterialAlphaMode(const QString& type);
int getAccessorType(const QString& type);
@ -760,24 +760,24 @@ private:
bool addSkin(const QJsonObject& object);
bool addTexture(const QJsonObject& object);
bool readBinary(const QString& url, QByteArray& outdata);
bool readBinary(const QString& url, hifi::ByteArray& outdata);
template<typename T, typename L>
bool readArray(const QByteArray& bin, int byteOffset, int count,
bool readArray(const hifi::ByteArray& bin, int byteOffset, int count,
QVector<L>& outarray, int accessorType);
template<typename T>
bool addArrayOfType(const QByteArray& bin, int byteOffset, int count,
bool addArrayOfType(const hifi::ByteArray& bin, int byteOffset, int count,
QVector<T>& outarray, int accessorType, int componentType);
void retriangulate(const QVector<int>& in_indices, const QVector<glm::vec3>& in_vertices,
const QVector<glm::vec3>& in_normals, QVector<int>& out_indices,
QVector<glm::vec3>& out_vertices, QVector<glm::vec3>& out_normals);
std::tuple<bool, QByteArray> requestData(QUrl& url);
QByteArray requestEmbeddedData(const QString& url);
std::tuple<bool, hifi::ByteArray> requestData(hifi::URL& url);
hifi::ByteArray requestEmbeddedData(const QString& url);
QNetworkReply* request(QUrl& url, bool isTest);
QNetworkReply* request(hifi::URL& url, bool isTest);
bool doesResourceExist(const QString& url);

View file

@ -54,7 +54,7 @@ T& checked_at(QVector<T>& vector, int i) {
OBJTokenizer::OBJTokenizer(QIODevice* device) : _device(device), _pushedBackToken(-1) {
}
const QByteArray OBJTokenizer::getLineAsDatum() {
const hifi::ByteArray OBJTokenizer::getLineAsDatum() {
return _device->readLine().trimmed();
}
@ -117,7 +117,7 @@ bool OBJTokenizer::isNextTokenFloat() {
if (nextToken() != OBJTokenizer::DATUM_TOKEN) {
return false;
}
QByteArray token = getDatum();
hifi::ByteArray token = getDatum();
pushBackToken(OBJTokenizer::DATUM_TOKEN);
bool ok;
token.toFloat(&ok);
@ -182,7 +182,7 @@ void setMeshPartDefaults(HFMMeshPart& meshPart, QString materialID) {
// OBJFace
// NOTE (trent, 7/20/17): The vertexColors vector being passed-in isn't necessary here, but I'm just
// pairing it with the vertices vector for consistency.
bool OBJFace::add(const QByteArray& vertexIndex, const QByteArray& textureIndex, const QByteArray& normalIndex, const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& vertexColors) {
bool OBJFace::add(const hifi::ByteArray& vertexIndex, const hifi::ByteArray& textureIndex, const hifi::ByteArray& normalIndex, const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& vertexColors) {
bool ok;
int index = vertexIndex.toInt(&ok);
if (!ok) {
@ -238,11 +238,11 @@ void OBJFace::addFrom(const OBJFace* face, int index) { // add using data from f
}
}
bool OBJSerializer::isValidTexture(const QByteArray &filename) {
bool OBJSerializer::isValidTexture(const hifi::ByteArray &filename) {
if (_url.isEmpty()) {
return false;
}
QUrl candidateUrl = _url.resolved(QUrl(filename));
hifi::URL candidateUrl = _url.resolved(hifi::URL(filename));
return DependencyManager::get<ResourceManager>()->resourceExists(candidateUrl);
}
@ -278,7 +278,7 @@ void OBJSerializer::parseMaterialLibrary(QIODevice* device) {
#endif
return;
}
QByteArray token = tokenizer.getDatum();
hifi::ByteArray token = tokenizer.getDatum();
if (token == "newmtl") {
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
return;
@ -328,8 +328,8 @@ void OBJSerializer::parseMaterialLibrary(QIODevice* device) {
} else if (token == "Ks") {
currentMaterial.specularColor = tokenizer.getVec3();
} else if ((token == "map_Kd") || (token == "map_Ke") || (token == "map_Ks") || (token == "map_bump") || (token == "bump") || (token == "map_d")) {
const QByteArray textureLine = tokenizer.getLineAsDatum();
QByteArray filename;
const hifi::ByteArray textureLine = tokenizer.getLineAsDatum();
hifi::ByteArray filename;
OBJMaterialTextureOptions textureOptions;
parseTextureLine(textureLine, filename, textureOptions);
if (filename.endsWith(".tga")) {
@ -354,7 +354,7 @@ void OBJSerializer::parseMaterialLibrary(QIODevice* device) {
}
}
void OBJSerializer::parseTextureLine(const QByteArray& textureLine, QByteArray& filename, OBJMaterialTextureOptions& textureOptions) {
void OBJSerializer::parseTextureLine(const hifi::ByteArray& textureLine, hifi::ByteArray& filename, OBJMaterialTextureOptions& textureOptions) {
// Texture options reference http://paulbourke.net/dataformats/mtl/
// and https://wikivisually.com/wiki/Material_Template_Library
@ -442,12 +442,12 @@ void OBJSerializer::parseTextureLine(const QByteArray& textureLine, QByteArray&
}
}
std::tuple<bool, QByteArray> requestData(QUrl& url) {
std::tuple<bool, hifi::ByteArray> requestData(hifi::URL& url) {
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(
nullptr, url, true, -1, "(OBJSerializer) requestData");
if (!request) {
return std::make_tuple(false, QByteArray());
return std::make_tuple(false, hifi::ByteArray());
}
QEventLoop loop;
@ -458,12 +458,12 @@ std::tuple<bool, QByteArray> requestData(QUrl& url) {
if (request->getResult() == ResourceRequest::Success) {
return std::make_tuple(true, request->getData());
} else {
return std::make_tuple(false, QByteArray());
return std::make_tuple(false, hifi::ByteArray());
}
}
QNetworkReply* request(QUrl& url, bool isTest) {
QNetworkReply* request(hifi::URL& url, bool isTest) {
if (!qApp) {
return nullptr;
}
@ -488,7 +488,7 @@ QNetworkReply* request(QUrl& url, bool isTest) {
}
bool OBJSerializer::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, HFMModel& hfmModel,
bool OBJSerializer::parseOBJGroup(OBJTokenizer& tokenizer, const hifi::VariantHash& mapping, HFMModel& hfmModel,
float& scaleGuess, bool combineParts) {
FaceGroup faces;
HFMMesh& mesh = hfmModel.meshes[0];
@ -522,7 +522,7 @@ bool OBJSerializer::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& m
result = false;
break;
}
QByteArray token = tokenizer.getDatum();
hifi::ByteArray token = tokenizer.getDatum();
//qCDebug(modelformat) << token;
// we don't support separate objects in the same file, so treat "o" the same as "g".
if (token == "g" || token == "o") {
@ -535,7 +535,7 @@ bool OBJSerializer::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& m
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
break;
}
QByteArray groupName = tokenizer.getDatum();
hifi::ByteArray groupName = tokenizer.getDatum();
currentGroup = groupName;
if (!combineParts) {
currentMaterialName = QString("part-") + QString::number(_partCounter++);
@ -544,7 +544,7 @@ bool OBJSerializer::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& m
if (tokenizer.nextToken(true) != OBJTokenizer::DATUM_TOKEN) {
break;
}
QByteArray libraryName = tokenizer.getDatum();
hifi::ByteArray libraryName = tokenizer.getDatum();
librariesSeen[libraryName] = true;
// We'll read it later only if we actually need it.
} else if (token == "usemtl") {
@ -598,14 +598,14 @@ bool OBJSerializer::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& m
// vertex-index
// vertex-index/texture-index
// vertex-index/texture-index/surface-normal-index
QByteArray token = tokenizer.getDatum();
hifi::ByteArray token = tokenizer.getDatum();
auto firstChar = token[0];
// Tokenizer treats line endings as whitespace. Non-digit and non-negative sign indicates done;
if (!isdigit(firstChar) && firstChar != '-') {
tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN);
break;
}
QList<QByteArray> parts = token.split('/');
QList<hifi::ByteArray> parts = token.split('/');
assert(parts.count() >= 1);
assert(parts.count() <= 3);
// If indices are negative relative indices then adjust them to absolute indices based on current vector sizes
@ -626,7 +626,7 @@ bool OBJSerializer::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& m
}
}
}
const QByteArray noData {};
const hifi::ByteArray noData {};
face.add(parts[0], (parts.count() > 1) ? parts[1] : noData, (parts.count() > 2) ? parts[2] : noData,
vertices, vertexColors);
face.groupName = currentGroup;
@ -661,9 +661,9 @@ std::unique_ptr<hfm::Serializer::Factory> OBJSerializer::getFactory() const {
return std::make_unique<hfm::Serializer::SimpleFactory<OBJSerializer>>();
}
HFMModel::Pointer OBJSerializer::read(const QByteArray& data, const QVariantHash& mapping, const QUrl& url) {
HFMModel::Pointer OBJSerializer::read(const hifi::ByteArray& data, const hifi::VariantHash& mapping, const hifi::URL& url) {
PROFILE_RANGE_EX(resource_parse, __FUNCTION__, 0xffff0000, nullptr);
QBuffer buffer { const_cast<QByteArray*>(&data) };
QBuffer buffer { const_cast<hifi::ByteArray*>(&data) };
buffer.open(QIODevice::ReadOnly);
auto hfmModelPtr = std::make_shared<HFMModel>();
@ -849,11 +849,11 @@ HFMModel::Pointer OBJSerializer::read(const QByteArray& data, const QVariantHash
int extIndex = filename.lastIndexOf('.'); // by construction, this does not fail
QString basename = filename.remove(extIndex + 1, sizeof("obj"));
preDefinedMaterial.diffuseColor = glm::vec3(1.0f);
QVector<QByteArray> extensions = { "jpg", "jpeg", "png", "tga" };
QByteArray base = basename.toUtf8(), textName = "";
QVector<hifi::ByteArray> extensions = { "jpg", "jpeg", "png", "tga" };
hifi::ByteArray base = basename.toUtf8(), textName = "";
qCDebug(modelformat) << "OBJSerializer looking for default texture";
for (int i = 0; i < extensions.count(); i++) {
QByteArray candidateString = base + extensions[i];
hifi::ByteArray candidateString = base + extensions[i];
if (isValidTexture(candidateString)) {
textName = candidateString;
break;
@ -871,11 +871,11 @@ HFMModel::Pointer OBJSerializer::read(const QByteArray& data, const QVariantHash
if (needsMaterialLibrary) {
foreach (QString libraryName, librariesSeen.keys()) {
// Throw away any path part of libraryName, and merge against original url.
QUrl libraryUrl = _url.resolved(QUrl(libraryName).fileName());
hifi::URL libraryUrl = _url.resolved(hifi::URL(libraryName).fileName());
qCDebug(modelformat) << "OBJSerializer material library" << libraryName;
bool success;
QByteArray data;
std::tie<bool, QByteArray>(success, data) = requestData(libraryUrl);
hifi::ByteArray data;
std::tie<bool, hifi::ByteArray>(success, data) = requestData(libraryUrl);
if (success) {
QBuffer buffer { &data };
buffer.open(QIODevice::ReadOnly);

View file

@ -25,9 +25,9 @@ public:
COMMENT_TOKEN = 0x101
};
int nextToken(bool allowSpaceChar = false);
const QByteArray& getDatum() const { return _datum; }
const hifi::ByteArray& getDatum() const { return _datum; }
bool isNextTokenFloat();
const QByteArray getLineAsDatum(); // some "filenames" have spaces in them
const hifi::ByteArray getLineAsDatum(); // some "filenames" have spaces in them
void skipLine() { _device->readLine(); }
void pushBackToken(int token) { _pushedBackToken = token; }
void ungetChar(char ch) { _device->ungetChar(ch); }
@ -39,7 +39,7 @@ public:
private:
QIODevice* _device;
QByteArray _datum;
hifi::ByteArray _datum;
int _pushedBackToken;
QString _comment;
};
@ -52,7 +52,7 @@ public:
QString groupName; // We don't make use of hierarchical structure, but it can be preserved for debugging and future use.
QString materialName;
// Add one more set of vertex data. Answers true if successful
bool add(const QByteArray& vertexIndex, const QByteArray& textureIndex, const QByteArray& normalIndex,
bool add(const hifi::ByteArray& vertexIndex, const hifi::ByteArray& textureIndex, const hifi::ByteArray& normalIndex,
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& vertexColors);
// Return a set of one or more OBJFaces from this one, in which each is just a triangle.
// Even though HFMMeshPart can handle quads, it would be messy to try to keep track of mixed-size faces, so we treat everything as triangles.
@ -75,11 +75,11 @@ public:
glm::vec3 diffuseColor;
glm::vec3 specularColor;
glm::vec3 emissiveColor;
QByteArray diffuseTextureFilename;
QByteArray specularTextureFilename;
QByteArray emissiveTextureFilename;
QByteArray bumpTextureFilename;
QByteArray opacityTextureFilename;
hifi::ByteArray diffuseTextureFilename;
hifi::ByteArray specularTextureFilename;
hifi::ByteArray emissiveTextureFilename;
hifi::ByteArray bumpTextureFilename;
hifi::ByteArray opacityTextureFilename;
OBJMaterialTextureOptions bumpTextureOptions;
int illuminationModel;
@ -103,17 +103,17 @@ public:
QString currentMaterialName;
QHash<QString, OBJMaterial> materials;
HFMModel::Pointer read(const QByteArray& data, const QVariantHash& mapping, const QUrl& url = QUrl()) override;
HFMModel::Pointer read(const hifi::ByteArray& data, const hifi::VariantHash& mapping, const hifi::URL& url = hifi::URL()) override;
private:
QUrl _url;
hifi::URL _url;
QHash<QByteArray, bool> librariesSeen;
bool parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, HFMModel& hfmModel,
QHash<hifi::ByteArray, bool> librariesSeen;
bool parseOBJGroup(OBJTokenizer& tokenizer, const hifi::VariantHash& mapping, HFMModel& hfmModel,
float& scaleGuess, bool combineParts);
void parseMaterialLibrary(QIODevice* device);
void parseTextureLine(const QByteArray& textureLine, QByteArray& filename, OBJMaterialTextureOptions& textureOptions);
bool isValidTexture(const QByteArray &filename); // true if the file exists. TODO?: check content-type header and that it is a supported format.
void parseTextureLine(const hifi::ByteArray& textureLine, hifi::ByteArray& filename, OBJMaterialTextureOptions& textureOptions);
bool isValidTexture(const hifi::ByteArray &filename); // true if the file exists. TODO?: check content-type header and that it is a supported format.
int _partCounter { 0 };
};