Exemple #1
0
bool ObjLoader::load(::QIODevice *ioDev, const QString &subMesh)
{
    Q_CHECK_PTR(ioDev);
    if (!ioDev->isOpen()) {
        qCWarning(Render::Io) << "iodevice" << ioDev << "not open for reading";
        return false;
    }

    int faceCount = 0;

    // Parse faces taking into account each vertex in a face can index different indices
    // for the positions, normals and texture coords;
    // Generate unique vertices (in OpenGL parlance) and output to m_points, m_texCoords,
    // m_normals and calculate mapping from faces to unique indices
    QVector<QVector3D> positions;
    QVector<QVector3D> normals;
    QVector<QVector2D> texCoords;
    QHash<FaceIndices, unsigned int> faceIndexMap;
    QVector<FaceIndices> faceIndexVector;

    bool skipping = false;
    int positionsOffset = 0;
    int normalsOffset = 0;
    int texCoordsOffset = 0;

    QRegExp subMeshMatch(subMesh);
    if (!subMeshMatch.isValid())
        subMeshMatch.setPattern(QString(QStringLiteral("^(%1)$")).arg(subMesh));
    Q_ASSERT(subMeshMatch.isValid());

    QTextStream stream(ioDev);
    while (!stream.atEnd()) {
        QString line = stream.readLine();
        line = line.simplified();

        if (line.length() > 0 && line.at(0) != QChar::fromLatin1('#')) {
            const QVector<QStringRef> tokens = line.splitRef(QChar::fromLatin1(' '));

            if (tokens.first() == QStringLiteral("v")) {
                if (tokens.size() < 4) {
                    qCWarning(Render::Io) << "Unsupported number of components in vertex";
                } else {
                    if (!skipping) {
                        float x = tokens.at(1).toFloat();
                        float y = tokens.at(2).toFloat();
                        float z = tokens.at(3).toFloat();
                        positions.append(QVector3D( x, y, z ));
                    } else {
                        positionsOffset++;
                    }
                }
            } else if (tokens.first() == QStringLiteral("vt") && m_loadTextureCoords) {
                if (tokens.size() < 3) {
                    qCWarning(Render::Io) << "Unsupported number of components in texture coordinate";
                } else {
                    if (!skipping) {
                        // Process texture coordinate
                        float s = tokens.at(1).toFloat();
                        float t = tokens.at(2).toFloat();
                        //FlipUVs
                        t = 1.0f - t;
                        texCoords.append(QVector2D( s, t ));
                    } else {
                        texCoordsOffset++;
                    }
                }
            } else if (tokens.first() == QStringLiteral("vn")) {
                if (tokens.size() < 4) {
                    qCWarning(Render::Io) << "Unsupported number of components in vertex normal";
                } else {
                    if (!skipping) {
                        float x = tokens.at(1).toFloat();
                        float y = tokens.at(2).toFloat();
                        float z = tokens.at(3).toFloat();
                        normals.append(QVector3D( x, y, z ));
                    } else {
                        normalsOffset++;
                    }
                }
            } else if (!skipping && tokens.first() == QStringLiteral("f")) {
                // Process face
                ++faceCount;

                int faceVertices = tokens.size() - 1;

                QVector<FaceIndices> face;
                face.reserve(faceVertices);

                for (int i = 0; i < faceVertices; i++) {
                    FaceIndices faceIndices;
                    const QVector<QStringRef> indices = tokens.at(i + 1).split(QChar::fromLatin1('/'));
                    switch (indices.size()) {
                    case 3:
                        faceIndices.normalIndex = indices.at(2).toInt() - 1 - normalsOffset;  // fall through
                    case 2:
                        faceIndices.texCoordIndex = indices.at(1).toInt() - 1 - texCoordsOffset; // fall through
                    case 1:
                        faceIndices.positionIndex = indices.at(0).toInt() - 1 - positionsOffset;
                        break;
                    default:
                        qCWarning(Render::Io) << "Unsupported number of indices in face element";
                    }

                    face.append(faceIndices);
                }

                // If number of edges in face is greater than 3,
                // decompose into triangles as a triangle fan.
                FaceIndices v0 = face[0];
                FaceIndices v1 = face[1];
                FaceIndices v2 = face[2];

                // First face
                addFaceVertex(v0, faceIndexVector, faceIndexMap);
                addFaceVertex(v1, faceIndexVector, faceIndexMap);
                addFaceVertex(v2, faceIndexVector, faceIndexMap);

                for ( int i = 3; i < face.size(); ++i ) {
                    v1 = v2;
                    v2 = face[i];
                    addFaceVertex(v0, faceIndexVector, faceIndexMap);
                    addFaceVertex(v1, faceIndexVector, faceIndexMap);
                    addFaceVertex(v2, faceIndexVector, faceIndexMap);
                }

                // end of face
            } else if (tokens.first() == QStringLiteral("o")) {
                if (tokens.size() < 2) {
                    qCWarning(Render::Io) << "Missing submesh name";
                } else {
                    if (!subMesh.isEmpty() ) {
                        QString objName = tokens.at(1).toString();
                        skipping = subMeshMatch.indexIn(objName) < 0;
                    }
                }
            }
        } // end of input line
    } // while (!stream.atEnd())

    updateIndices(positions, normals, texCoords, faceIndexMap, faceIndexVector);

    if (m_normals.isEmpty())
        generateAveragedNormals(m_points, m_normals, m_indices);

    if (m_generateTangents && !m_texCoords.isEmpty())
        generateTangents(m_points, m_normals, m_indices, m_texCoords, m_tangents);

    if (m_centerMesh)
        center(m_points);

    qCDebug(Render::Io) << "Loaded mesh:";
    qCDebug(Render::Io) << " " << m_points.size() << "points";
    qCDebug(Render::Io) << " " << faceCount << "faces";
    qCDebug(Render::Io) << " " << m_indices.size() / 3 << "triangles.";
    qCDebug(Render::Io) << " " << m_normals.size() << "normals";
    qCDebug(Render::Io) << " " << m_tangents.size() << "tangents ";
    qCDebug(Render::Io) << " " << m_texCoords.size() << "texture coordinates.";

    return true;
}
Exemple #2
0
Mesh::Mesh(Object *parent, const char *fileName, Game::Surface *texture, int _flags):
    Object(parent),
    vertexCount(0),
    faceCount(0),
    currentFace(0),
    currentVertex(0),
    vertex(0),
    transformedVertex(0),
    face(0),
    flags(_flags)
{
    transformation.makeIdentity();
    TagFile file(fileName);
    int i;

    beginMesh();

    while(1)
        switch(file.readTag())
        {
        case 0: // list of vertices
        {
            vertexCount = file.getDataSize() / sizeof(SerializedVertex);
            SerializedVertex *v = new SerializedVertex[vertexCount];

            vertex = new Vertex[vertexCount];
            transformedVertex = new Vertex[vertexCount];

            file.readData((unsigned char*)v, sizeof(SerializedVertex)*vertexCount);

            for(i=0; i<vertexCount; i++)
            {
                setTexCoord(v[i].u, v[i].v);
                //                  addVertex(Vector(v[i].x >> 1, v[i].y >> 1, v[i].z >> 1));
                addVertex(Vector(v[i].x, v[i].y, v[i].z));
            }

            delete[] v;
        }
        break;
        case 1: // list of faces
        {
            faceCount = file.getDataSize() / sizeof(SerializedTriangle);
            SerializedTriangle *t = new SerializedTriangle[faceCount];

            face = new Face[faceCount];

            file.readData((unsigned char*)t, sizeof(SerializedTriangle)*faceCount);

            for(i=0; i<faceCount; i++)
            {
                beginFace(3);
                setTexture(texture);
                addFaceVertex(t[i].a);
                addFaceVertex(t[i].b);
                addFaceVertex(t[i].c);
                endFace();
            }

            delete[] t;
        }
        break;
        default:
            endMesh();
            return;
        }
}