mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 06:58:56 +02:00
Merge pull request #5441 from sethalves/fix-vhacd
if OBJ data isn't from a url, don't dereference null QUrl pointers
This commit is contained in:
commit
6433a48fdb
2 changed files with 46 additions and 33 deletions
|
@ -195,7 +195,10 @@ void OBJFace::addFrom(const OBJFace* face, int index) { // add using data from f
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OBJReader::isValidTexture(const QByteArray &filename) {
|
bool OBJReader::isValidTexture(const QByteArray &filename) {
|
||||||
QUrl candidateUrl = url->resolved(QUrl(filename));
|
if (!_url) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QUrl candidateUrl = _url->resolved(QUrl(filename));
|
||||||
QNetworkReply *netReply = request(candidateUrl, true);
|
QNetworkReply *netReply = request(candidateUrl, true);
|
||||||
bool isValid = netReply->isFinished() && (netReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200);
|
bool isValid = netReply->isFinished() && (netReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200);
|
||||||
netReply->deleteLater();
|
netReply->deleteLater();
|
||||||
|
@ -242,7 +245,7 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) {
|
||||||
} else if ((token == "map_Kd") || (token == "map_Ks")) {
|
} else if ((token == "map_Kd") || (token == "map_Ks")) {
|
||||||
QByteArray filename = QUrl(tokenizer.getLineAsDatum()).fileName().toUtf8();
|
QByteArray filename = QUrl(tokenizer.getLineAsDatum()).fileName().toUtf8();
|
||||||
if (filename.endsWith(".tga")) {
|
if (filename.endsWith(".tga")) {
|
||||||
qCDebug(modelformat) << "OBJ Reader WARNING: currently ignoring tga texture " << filename << " in " << url;
|
qCDebug(modelformat) << "OBJ Reader WARNING: currently ignoring tga texture " << filename << " in " << _url;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (isValidTexture(filename)) {
|
if (isValidTexture(filename)) {
|
||||||
|
@ -252,7 +255,7 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) {
|
||||||
currentMaterial.specularTextureFilename = filename;
|
currentMaterial.specularTextureFilename = filename;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qCDebug(modelformat) << "OBJ Reader WARNING: " << url << " ignoring missing texture " << filename;
|
qCDebug(modelformat) << "OBJ Reader WARNING: " << _url << " ignoring missing texture " << filename;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -316,7 +319,7 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi
|
||||||
QByteArray groupName = tokenizer.getDatum();
|
QByteArray groupName = tokenizer.getDatum();
|
||||||
currentGroup = groupName;
|
currentGroup = groupName;
|
||||||
//qCDebug(modelformat) << "new group:" << groupName;
|
//qCDebug(modelformat) << "new group:" << groupName;
|
||||||
} else if (token == "mtllib") {
|
} else if (token == "mtllib" && _url) {
|
||||||
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
|
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -325,13 +328,15 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi
|
||||||
break; // Some files use mtllib over and over again for the same libraryName
|
break; // Some files use mtllib over and over again for the same libraryName
|
||||||
}
|
}
|
||||||
librariesSeen[libraryName] = true;
|
librariesSeen[libraryName] = true;
|
||||||
QUrl libraryUrl = url->resolved(QUrl(libraryName).fileName()); // Throw away any path part of libraryName, and merge against original url.
|
// Throw away any path part of libraryName, and merge against original url.
|
||||||
|
QUrl libraryUrl = _url->resolved(QUrl(libraryName).fileName());
|
||||||
qCDebug(modelformat) << "OBJ Reader new library:" << libraryName << " at:" << libraryUrl;
|
qCDebug(modelformat) << "OBJ Reader new library:" << libraryName << " at:" << libraryUrl;
|
||||||
QNetworkReply* netReply = request(libraryUrl, false);
|
QNetworkReply* netReply = request(libraryUrl, false);
|
||||||
if (netReply->isFinished() && (netReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200)) {
|
if (netReply->isFinished() && (netReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200)) {
|
||||||
parseMaterialLibrary(netReply);
|
parseMaterialLibrary(netReply);
|
||||||
} else {
|
} else {
|
||||||
qCDebug(modelformat) << "OBJ Reader " << libraryName << " did not answer. Got " << netReply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
|
qCDebug(modelformat) << "OBJ Reader " << libraryName << " did not answer. Got "
|
||||||
|
<< netReply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
|
||||||
}
|
}
|
||||||
netReply->deleteLater();
|
netReply->deleteLater();
|
||||||
} else if (token == "usemtl") {
|
} else if (token == "usemtl") {
|
||||||
|
@ -406,10 +411,10 @@ FBXGeometry OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, Q
|
||||||
OBJTokenizer tokenizer(device);
|
OBJTokenizer tokenizer(device);
|
||||||
float scaleGuess = 1.0f;
|
float scaleGuess = 1.0f;
|
||||||
|
|
||||||
this->url = url;
|
_url = url;
|
||||||
geometry.meshExtents.reset();
|
geometry.meshExtents.reset();
|
||||||
geometry.meshes.append(FBXMesh());
|
geometry.meshes.append(FBXMesh());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// call parseOBJGroup as long as it's returning true. Each successful call will
|
// call parseOBJGroup as long as it's returning true. Each successful call will
|
||||||
// add a new meshPart to the geometry's single mesh.
|
// add a new meshPart to the geometry's single mesh.
|
||||||
|
@ -417,7 +422,7 @@ FBXGeometry OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, Q
|
||||||
|
|
||||||
FBXMesh& mesh = geometry.meshes[0];
|
FBXMesh& mesh = geometry.meshes[0];
|
||||||
mesh.meshIndex = 0;
|
mesh.meshIndex = 0;
|
||||||
|
|
||||||
geometry.joints.resize(1);
|
geometry.joints.resize(1);
|
||||||
geometry.joints[0].isFree = false;
|
geometry.joints[0].isFree = false;
|
||||||
geometry.joints[0].parentIndex = -1;
|
geometry.joints[0].parentIndex = -1;
|
||||||
|
@ -440,37 +445,44 @@ FBXGeometry OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, Q
|
||||||
0, 0, 1, 0,
|
0, 0, 1, 0,
|
||||||
0, 0, 0, 1);
|
0, 0, 0, 1);
|
||||||
mesh.clusters.append(cluster);
|
mesh.clusters.append(cluster);
|
||||||
|
|
||||||
// Some .obj files use the convention that a group with uv coordinates that doesn't define a material, should use a texture with the same basename as the .obj file.
|
// Some .obj files use the convention that a group with uv coordinates that doesn't define a material, should use
|
||||||
QString filename = url->fileName();
|
// a texture with the same basename as the .obj file.
|
||||||
int extIndex = filename.lastIndexOf('.'); // by construction, this does not fail
|
if (url) {
|
||||||
QString basename = filename.remove(extIndex + 1, sizeof("obj"));
|
QString filename = url->fileName();
|
||||||
OBJMaterial& preDefinedMaterial = materials[SMART_DEFAULT_MATERIAL_NAME];
|
int extIndex = filename.lastIndexOf('.'); // by construction, this does not fail
|
||||||
preDefinedMaterial.diffuseColor = glm::vec3(1.0f);
|
QString basename = filename.remove(extIndex + 1, sizeof("obj"));
|
||||||
QVector<QByteArray> extensions = {"jpg", "jpeg", "png", "tga"};
|
OBJMaterial& preDefinedMaterial = materials[SMART_DEFAULT_MATERIAL_NAME];
|
||||||
QByteArray base = basename.toUtf8(), textName = "";
|
preDefinedMaterial.diffuseColor = glm::vec3(1.0f);
|
||||||
for (int i = 0; i < extensions.count(); i++) {
|
QVector<QByteArray> extensions = {"jpg", "jpeg", "png", "tga"};
|
||||||
QByteArray candidateString = base + extensions[i];
|
QByteArray base = basename.toUtf8(), textName = "";
|
||||||
if (isValidTexture(candidateString)) {
|
for (int i = 0; i < extensions.count(); i++) {
|
||||||
textName = candidateString;
|
QByteArray candidateString = base + extensions[i];
|
||||||
break;
|
if (isValidTexture(candidateString)) {
|
||||||
|
textName = candidateString;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!textName.isEmpty()) {
|
||||||
|
preDefinedMaterial.diffuseTextureFilename = textName;
|
||||||
|
}
|
||||||
|
materials[SMART_DEFAULT_MATERIAL_NAME] = preDefinedMaterial;
|
||||||
}
|
}
|
||||||
if (!textName.isEmpty()) {
|
|
||||||
preDefinedMaterial.diffuseTextureFilename = textName;
|
|
||||||
}
|
|
||||||
materials[SMART_DEFAULT_MATERIAL_NAME] = preDefinedMaterial;
|
|
||||||
|
|
||||||
for (int i = 0, meshPartCount = 0; i < mesh.parts.count(); i++, meshPartCount++) {
|
for (int i = 0, meshPartCount = 0; i < mesh.parts.count(); i++, meshPartCount++) {
|
||||||
FBXMeshPart& meshPart = mesh.parts[i];
|
FBXMeshPart& meshPart = mesh.parts[i];
|
||||||
FaceGroup faceGroup = faceGroups[meshPartCount];
|
FaceGroup faceGroup = faceGroups[meshPartCount];
|
||||||
OBJFace leadFace = faceGroup[0]; // All the faces in the same group will have the same name and material.
|
OBJFace leadFace = faceGroup[0]; // All the faces in the same group will have the same name and material.
|
||||||
QString groupMaterialName = leadFace.materialName;
|
QString groupMaterialName = leadFace.materialName;
|
||||||
if (groupMaterialName.isEmpty() && (leadFace.textureUVIndices.count() > 0)) {
|
if (groupMaterialName.isEmpty() && (leadFace.textureUVIndices.count() > 0)) {
|
||||||
qCDebug(modelformat) << "OBJ Reader WARNING: " << url << " needs a texture that isn't specified. Using default mechanism.";
|
qCDebug(modelformat) << "OBJ Reader WARNING: " << url
|
||||||
|
<< " needs a texture that isn't specified. Using default mechanism.";
|
||||||
groupMaterialName = SMART_DEFAULT_MATERIAL_NAME;
|
groupMaterialName = SMART_DEFAULT_MATERIAL_NAME;
|
||||||
} else if (!groupMaterialName.isEmpty() && !materials.contains(groupMaterialName)) {
|
} else if (!groupMaterialName.isEmpty() && !materials.contains(groupMaterialName)) {
|
||||||
qCDebug(modelformat) << "OBJ Reader WARNING: " << url << " specifies a material " << groupMaterialName << " that is not defined. Using default mechanism.";
|
qCDebug(modelformat) << "OBJ Reader WARNING: " << url
|
||||||
|
<< " specifies a material " << groupMaterialName
|
||||||
|
<< " that is not defined. Using default mechanism.";
|
||||||
groupMaterialName = SMART_DEFAULT_MATERIAL_NAME;
|
groupMaterialName = SMART_DEFAULT_MATERIAL_NAME;
|
||||||
}
|
}
|
||||||
if (!groupMaterialName.isEmpty()) {
|
if (!groupMaterialName.isEmpty()) {
|
||||||
|
|
|
@ -69,12 +69,13 @@ public:
|
||||||
QVector<FaceGroup> faceGroups;
|
QVector<FaceGroup> faceGroups;
|
||||||
QString currentMaterialName;
|
QString currentMaterialName;
|
||||||
QHash<QString, OBJMaterial> materials;
|
QHash<QString, OBJMaterial> materials;
|
||||||
QUrl* url;
|
|
||||||
|
|
||||||
QNetworkReply* request(QUrl& url, bool isTest);
|
QNetworkReply* request(QUrl& url, bool isTest);
|
||||||
FBXGeometry readOBJ(const QByteArray& model, const QVariantHash& mapping);
|
FBXGeometry readOBJ(const QByteArray& model, const QVariantHash& mapping);
|
||||||
FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping, QUrl* url);
|
FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping, QUrl* url);
|
||||||
private:
|
private:
|
||||||
|
QUrl* _url = nullptr;
|
||||||
|
|
||||||
QHash<QByteArray, bool> librariesSeen;
|
QHash<QByteArray, bool> librariesSeen;
|
||||||
bool parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, float& scaleGuess);
|
bool parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, float& scaleGuess);
|
||||||
void parseMaterialLibrary(QIODevice* device);
|
void parseMaterialLibrary(QIODevice* device);
|
||||||
|
@ -83,4 +84,4 @@ private:
|
||||||
|
|
||||||
// What are these utilities doing here? One is used by fbx loading code in VHACD Utils, and the other a general debugging utility.
|
// What are these utilities doing here? One is used by fbx loading code in VHACD Utils, and the other a general debugging utility.
|
||||||
void setMeshPartDefaults(FBXMeshPart& meshPart, QString materialID);
|
void setMeshPartDefaults(FBXMeshPart& meshPart, QString materialID);
|
||||||
void fbxDebugDump(const FBXGeometry& fbxgeo);
|
void fbxDebugDump(const FBXGeometry& fbxgeo);
|
||||||
|
|
Loading…
Reference in a new issue