Missing the code!

This commit is contained in:
Howard Stearns 2015-05-06 11:57:34 -07:00
parent e9c76da8d4
commit d2dbb2c116
2 changed files with 51 additions and 34 deletions

View file

@ -35,6 +35,10 @@ const QString SMART_DEFAULT_MATERIAL_NAME = "High Fidelity smart default materia
OBJTokenizer::OBJTokenizer(QIODevice* device) : _device(device), _pushedBackToken(-1) {
}
const QByteArray OBJTokenizer::getLineAsDatum() {
return _device->readLine().trimmed();
}
int OBJTokenizer::nextToken() {
if (_pushedBackToken != NO_PUSHBACKED_TOKEN) {
int token = _pushedBackToken;
@ -133,7 +137,7 @@ void setMeshPartDefaults(FBXMeshPart& meshPart, QString materialID) {
}
// OBJFace
bool OBJFace::add(const QByteArray& vertexIndex, const QByteArray& textureIndex, const QByteArray& normalIndex) {
bool OBJFace::add(const QByteArray& vertexIndex, const QByteArray& textureIndex, const QByteArray& normalIndex, const QVector<glm::vec3>& vertices) {
bool ok;
int index = vertexIndex.toInt(&ok);
if (!ok) {
@ -145,6 +149,9 @@ bool OBJFace::add(const QByteArray& vertexIndex, const QByteArray& textureIndex,
if (!ok) {
return false;
}
if (index < 0) { // Count backwards from the last one added.
index = vertices.count() + 1 + index;
}
textureUVIndices.append(index - 1);
}
if (!normalIndex.isEmpty()) {
@ -184,6 +191,14 @@ void OBJFace::addFrom(const OBJFace* face, int index) { // add using data from f
}
}
bool OBJReader::isValidTexture(const QByteArray &filename) {
QUrl candidateUrl = url->resolved(QUrl(filename));
QNetworkReply *netReply = request(candidateUrl, true);
bool isValid = netReply->isFinished() && (netReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200);
netReply->deleteLater();
return isValid;
}
void OBJReader::parseMaterialLibrary(QIODevice* device) {
OBJTokenizer tokenizer(device);
QString matName = SMART_DEFAULT_MATERIAL_NAME;
@ -221,16 +236,21 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) {
currentMaterial.diffuseColor = tokenizer.getVec3();
} else if (token == "Ks") {
currentMaterial.specularColor = tokenizer.getVec3();
} else if (token == "map_Kd") {
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
return;
} else if ((token == "map_Kd") || (token == "map_Ks")) {
QByteArray filename = QUrl(tokenizer.getLineAsDatum()).fileName().toUtf8();
if (filename.endsWith(".tga")) {
qCDebug(modelformat) << "OBJ Reader WARNING: currently ignoring tga texture " << filename << " in " << url;
break;
}
currentMaterial.diffuseTextureFilename = tokenizer.getDatum();
} else if (token == "map_Ks") {
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
return;
if (isValidTexture(filename)) {
if (token == "map_Kd") {
currentMaterial.diffuseTextureFilename = filename;
} else {
currentMaterial.specularTextureFilename = filename;
}
} else {
qCDebug(modelformat) << "OBJ Reader WARNING: " << url << " ignoring missing texture " << filename;
}
currentMaterial.diffuseTextureFilename = tokenizer.getDatum();
}
}
}
@ -302,7 +322,7 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi
break; // Some files use mtllib over and over again for the same libraryName
}
librariesSeen[libraryName] = true;
QUrl libraryUrl = url->resolved(QUrl(libraryName));
QUrl libraryUrl = url->resolved(QUrl(libraryName).fileName()); // Throw away any path part of libraryName, and merge against original url.
qCDebug(modelformat) << "OBJ Reader new library:" << libraryName << " at:" << libraryUrl;
QNetworkReply* netReply = request(libraryUrl, false);
if (netReply->isFinished() && (netReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200)) {
@ -345,9 +365,8 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi
QList<QByteArray> parts = token.split('/');
assert(parts.count() >= 1);
assert(parts.count() <= 3);
// FIXME: if we want to handle negative indices, it has to be done here.
const QByteArray noData {};
face.add(parts[0], (parts.count() > 1) ? parts[1] : noData, (parts.count() > 2) ? parts[2] : noData);
face.add(parts[0], (parts.count() > 1) ? parts[1] : noData, (parts.count() > 2) ? parts[2] : noData, vertices);
face.groupName = currentGroup;
face.materialName = currentMaterialName;
}
@ -428,14 +447,10 @@ FBXGeometry OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, Q
QByteArray base = basename.toUtf8(), textName = "";
for (int i = 0; i < extensions.count(); i++) {
QByteArray candidateString = base + extensions[i];
QUrl candidateUrl = url->resolved(QUrl(candidateString));
QNetworkReply *netReply = request(candidateUrl, true);
if (netReply->isFinished() && (netReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200)) {
if (isValidTexture(candidateString)) {
textName = candidateString;
netReply->deleteLater();
break;
}
netReply->deleteLater();
}
if (!textName.isEmpty()) {
preDefinedMaterial.diffuseTextureFilename = textName;
@ -447,24 +462,24 @@ FBXGeometry OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, Q
FaceGroup faceGroup = faceGroups[meshPartCount];
OBJFace leadFace = faceGroup[0]; // All the faces in the same group will have the same name and material.
QString groupMaterialName = leadFace.materialName;
if ((leadFace.textureUVIndices.count() > 0) && groupMaterialName.isEmpty()) {
if (groupMaterialName.isEmpty() && (leadFace.textureUVIndices.count() > 0)) {
qCDebug(modelformat) << "OBJ Reader WARNING: " << url << " needs a texture that isn't specified. Using default mechanism.";
groupMaterialName = SMART_DEFAULT_MATERIAL_NAME;
} else if (!groupMaterialName.isEmpty() && !materials.contains(groupMaterialName)) {
qCDebug(modelformat) << "OBJ Reader WARNING: " << url << " specifies a material " << groupMaterialName << " that is not defined. Using default mechanism.";
groupMaterialName = SMART_DEFAULT_MATERIAL_NAME;
}
if (!groupMaterialName.isEmpty()) {
if (!materials.contains(groupMaterialName)) {
qCDebug(modelformat) << "OBJ Reader:" << url << " references undefined material " << groupMaterialName << ".";
} else {
OBJMaterial* material = &materials[groupMaterialName];
// The code behind this is in transition. Some things are set directly in the FXBMeshPart...
meshPart.materialID = groupMaterialName;
meshPart.diffuseTexture.filename = material->diffuseTextureFilename;
meshPart.specularTexture.filename = material->specularTextureFilename;
// ... and some things are set in the underlying material.
meshPart._material->setDiffuse(material->diffuseColor);
meshPart._material->setSpecular(material->specularColor);
meshPart._material->setShininess(material->shininess);
meshPart._material->setOpacity(material->opacity);
}
if (!groupMaterialName.isEmpty()) {
OBJMaterial* material = &materials[groupMaterialName];
// The code behind this is in transition. Some things are set directly in the FXBMeshPart...
meshPart.materialID = groupMaterialName;
meshPart.diffuseTexture.filename = material->diffuseTextureFilename;
meshPart.specularTexture.filename = material->specularTextureFilename;
// ... and some things are set in the underlying material.
meshPart._material->setDiffuse(material->diffuseColor);
meshPart._material->setSpecular(material->specularColor);
meshPart._material->setShininess(material->shininess);
meshPart._material->setOpacity(material->opacity);
}
qCDebug(modelformat) << "OBJ Reader part:" << meshPartCount << "name:" << leadFace.groupName << "material:" << groupMaterialName << "diffuse:" << meshPart._material->getDiffuse() << "faces:" << faceGroup.count() << "triangle indices will start with:" << mesh.vertices.count();
foreach(OBJFace face, faceGroup) {

View file

@ -14,6 +14,7 @@ public:
int nextToken();
const QByteArray& getDatum() const { return _datum; }
bool isNextTokenFloat();
const QByteArray getLineAsDatum(); // some "filenames" have spaces in them
void skipLine() { _device->readLine(); }
void pushBackToken(int token) { _pushedBackToken = token; }
void ungetChar(char ch) { _device->ungetChar(ch); }
@ -37,7 +38,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 QByteArray& vertexIndex, const QByteArray& textureIndex, const QByteArray& normalIndex, const QVector<glm::vec3>& vertices);
// Return a set of one or more OBJFaces from this one, in which each is just a triangle.
// Even though FBXMeshPart can handle quads, it would be messy to try to keep track of mixed-size faces, so we treat everything as triangles.
QVector<OBJFace> triangulate();
@ -77,6 +78,7 @@ private:
QHash<QByteArray, bool> librariesSeen;
bool parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, float& scaleGuess);
void parseMaterialLibrary(QIODevice* device);
bool isValidTexture(const QByteArray &filename); // true if the file exists. TODO?: check content-type header and that it is a supported format.
};
// What are these utilities doing here? One is used by fbx loading code in VHACD Utils, and the other a general debugging utility.