1098 lines · 45.8 KB · C++
RawDownload
    buffer.release();} QSharedPointer<NetworkGeometry> GeometryCache::getGeometry(const QUrl& url, const QUrl& fallback, bool delayLoad) {    return getResource(url, fallback, delayLoad).staticCast<NetworkGeometry>();} void GeometryCache::noteRequiresBlend(Model* model) {    if (_pendingBlenders < QThread::idealThreadCount()) {        if (model->maybeStartBlender()) {            _pendingBlenders++;        }        return;    }    if (!_modelsRequiringBlends.contains(model)) {        _modelsRequiringBlends.append(model);    }} void GeometryCache::setBlendedVertices(const QPointer<Model>& model, int blendNumber,        const QWeakPointer<NetworkGeometry>& geometry, const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals) {    if (!model.isNull()) {        model->setBlendedVertices(blendNumber, geometry, vertices, normals);    }    _pendingBlenders--;    while (!_modelsRequiringBlends.isEmpty()) {        Model* nextModel = _modelsRequiringBlends.takeFirst();        if (nextModel && nextModel->maybeStartBlender()) {            _pendingBlenders++;            return;        }    }} QSharedPointer<Resource> GeometryCache::createResource(const QUrl& url,        const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) {    QSharedPointer<NetworkGeometry> geometry(new NetworkGeometry(url, fallback.staticCast<NetworkGeometry>(), delayLoad),        &Resource::allReferencesCleared);    geometry->setLODParent(geometry);    return geometry.staticCast<Resource>();} const float NetworkGeometry::NO_HYSTERESIS = -1.0f; NetworkGeometry::NetworkGeometry(const QUrl& url, const QSharedPointer<NetworkGeometry>& fallback, bool delayLoad,        const QVariantHash& mapping, const QUrl& textureBase) :    Resource(url, delayLoad),    _mapping(mapping),    _textureBase(textureBase.isValid() ? textureBase : url),    _fallback(fallback){        if (url.isEmpty()) {        // make the minimal amount of dummy geometry to satisfy Model        FBXJoint joint = { false, QVector<int>(), -1 };        _geometry.joints.append(joint);        _geometry.leftEyeJointIndex = -1;        _geometry.rightEyeJointIndex = -1;        _geometry.neckJointIndex = -1;        _geometry.rootJointIndex = -1;        _geometry.leanJointIndex = -1;        _geometry.headJointIndex = -1;        _geometry.leftHandJointIndex = -1;        _geometry.rightHandJointIndex = -1;    }            connect(this, &Resource::loaded, this, &NetworkGeometry::replaceTexturesWithPendingChanges);} bool NetworkGeometry::isLoadedWithTextures() const {    if (!isLoaded()) {        return false;    }    foreach (const NetworkMesh& mesh, _meshes) {        foreach (const NetworkMeshPart& part, mesh.parts) {            if ((part.diffuseTexture && !part.diffuseTexture->isLoaded()) ||                    (part.normalTexture && !part.normalTexture->isLoaded()) ||                    (part.specularTexture && !part.specularTexture->isLoaded()) ||                    (part.emissiveTexture && !part.emissiveTexture->isLoaded())) {                return false;            }        }    }    return true;} QSharedPointer<NetworkGeometry> NetworkGeometry::getLODOrFallback(float distance, float& hysteresis, bool delayLoad) const {    if (_lodParent.data() != this) {        return _lodParent.data()->getLODOrFallback(distance, hysteresis, delayLoad);    }    if (_failedToLoad && _fallback) {        return _fallback;    }    QSharedPointer<NetworkGeometry> lod = _lodParent;    float lodDistance = 0.0f;    QMap<float, QSharedPointer<NetworkGeometry> >::const_iterator it = _lods.upperBound(distance);    if (it != _lods.constBegin()) {        it = it - 1;        lod = it.value();        lodDistance = it.key();    }    if (hysteresis != NO_HYSTERESIS && hysteresis != lodDistance) {        // if we previously selected a different distance, make sure we've moved far enough to justify switching        const float HYSTERESIS_PROPORTION = 0.1f;        if (glm::abs(distance - qMax(hysteresis, lodDistance)) / fabsf(hysteresis - lodDistance) < HYSTERESIS_PROPORTION) {            lod = _lodParent;            lodDistance = 0.0f;            it = _lods.upperBound(hysteresis);            if (it != _lods.constBegin()) {                it = it - 1;                lod = it.value();                lodDistance = it.key();            }        }    }    if (lod->isLoaded()) {        hysteresis = lodDistance;        return lod;    }    // if the ideal LOD isn't loaded, we need to make sure it's started to load, and possibly return the closest loaded one    if (!delayLoad) {        lod->ensureLoading();    }    float closestDistance = FLT_MAX;    if (isLoaded()) {        lod = _lodParent;        closestDistance = distance;    }    for (it = _lods.constBegin(); it != _lods.constEnd(); it++) {        float distanceToLOD = glm::abs(distance - it.key());        if (it.value()->isLoaded() && distanceToLOD < closestDistance) {            lod = it.value();            closestDistance = distanceToLOD;        }        }    hysteresis = NO_HYSTERESIS;    return lod;} uint qHash(const QWeakPointer<Animation>& animation, uint seed = 0) {    return qHash(animation.data(), seed);} QVector<int> NetworkGeometry::getJointMappings(const AnimationPointer& animation) {    QVector<int> mappings = _jointMappings.value(animation);    if (mappings.isEmpty() && isLoaded() && animation && animation->isLoaded()) {        const FBXGeometry& animationGeometry = animation->getGeometry();        for (int i = 0; i < animationGeometry.joints.size(); i++) {             mappings.append(_geometry.jointIndices.value(animationGeometry.joints.at(i).name) - 1);        }        _jointMappings.insert(animation, mappings);    }    return mappings;} void NetworkGeometry::setLoadPriority(const QPointer<QObject>& owner, float priority) {    Resource::setLoadPriority(owner, priority);        for (int i = 0; i < _meshes.size(); i++) {        NetworkMesh& mesh = _meshes[i];        for (int j = 0; j < mesh.parts.size(); j++) {            NetworkMeshPart& part = mesh.parts[j];            if (part.diffuseTexture) {                part.diffuseTexture->setLoadPriority(owner, priority);            }            if (part.normalTexture) {                part.normalTexture->setLoadPriority(owner, priority);            }            if (part.specularTexture) {                part.specularTexture->setLoadPriority(owner, priority);            }            if (part.emissiveTexture) {                part.emissiveTexture->setLoadPriority(owner, priority);            }        }    }} void NetworkGeometry::setLoadPriorities(const QHash<QPointer<QObject>, float>& priorities) {    Resource::setLoadPriorities(priorities);        for (int i = 0; i < _meshes.size(); i++) {        NetworkMesh& mesh = _meshes[i];        for (int j = 0; j < mesh.parts.size(); j++) {            NetworkMeshPart& part = mesh.parts[j];            if (part.diffuseTexture) {                part.diffuseTexture->setLoadPriorities(priorities);            }            if (part.normalTexture) {                part.normalTexture->setLoadPriorities(priorities);            }            if (part.specularTexture) {                part.specularTexture->setLoadPriorities(priorities);            }            if (part.emissiveTexture) {                part.emissiveTexture->setLoadPriorities(priorities);            }        }    }} void NetworkGeometry::clearLoadPriority(const QPointer<QObject>& owner) {    Resource::clearLoadPriority(owner);        for (int i = 0; i < _meshes.size(); i++) {        NetworkMesh& mesh = _meshes[i];        for (int j = 0; j < mesh.parts.size(); j++) {            NetworkMeshPart& part = mesh.parts[j];            if (part.diffuseTexture) {                part.diffuseTexture->clearLoadPriority(owner);            }            if (part.normalTexture) {                part.normalTexture->clearLoadPriority(owner);            }            if (part.specularTexture) {                part.specularTexture->clearLoadPriority(owner);            }            if (part.emissiveTexture) {                part.emissiveTexture->clearLoadPriority(owner);            }        }    }} void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& url) {    if (_meshes.size() > 0) {        for (int i = 0; i < _meshes.size(); i++) {            NetworkMesh& mesh = _meshes[i];            for (int j = 0; j < mesh.parts.size(); j++) {                NetworkMeshPart& part = mesh.parts[j];                                QSharedPointer<NetworkTexture> matchingTexture = QSharedPointer<NetworkTexture>();                if (part.diffuseTextureName == name) {                    part.diffuseTexture =                    Application::getInstance()->getTextureCache()->getTexture(url, DEFAULT_TEXTURE,                                                                              _geometry.meshes[i].isEye, QByteArray());                    part.diffuseTexture->setLoadPriorities(_loadPriorities);                } else if (part.normalTextureName == name) {                    part.normalTexture = Application::getInstance()->getTextureCache()->getTexture(url, DEFAULT_TEXTURE,                                                                                                   false, QByteArray());                    part.normalTexture->setLoadPriorities(_loadPriorities);                } else if (part.specularTextureName == name) {                    part.specularTexture = Application::getInstance()->getTextureCache()->getTexture(url, DEFAULT_TEXTURE,                                                                                                     false, QByteArray());                    part.specularTexture->setLoadPriorities(_loadPriorities);                } else if (part.emissiveTextureName == name) {                    part.emissiveTexture = Application::getInstance()->getTextureCache()->getTexture(url, DEFAULT_TEXTURE,                                                                                                     false, QByteArray());                    part.emissiveTexture->setLoadPriorities(_loadPriorities);                }            }        }    } else {        qDebug() << "Adding a name url pair to pending" << name << url;        // we don't have meshes downloaded yet, so hold this texture as pending        _pendingTextureChanges.insert(name, url);    }} QStringList NetworkGeometry::getTextureNames() const {    QStringList result;    for (int i = 0; i < _meshes.size(); i++) {        const NetworkMesh& mesh = _meshes[i];        for (int j = 0; j < mesh.parts.size(); j++) {            const NetworkMeshPart& part = mesh.parts[j];                        if (!part.diffuseTextureName.isEmpty()) {                QString textureURL = part.diffuseTexture->getURL().toString();                result << part.diffuseTextureName + ":" + textureURL;            }             if (!part.normalTextureName.isEmpty()) {                QString textureURL = part.normalTexture->getURL().toString();                result << part.normalTextureName + ":" + textureURL;            }             if (!part.specularTextureName.isEmpty()) {                QString textureURL = part.specularTexture->getURL().toString();                result << part.specularTextureName + ":" + textureURL;            }             if (!part.emissiveTextureName.isEmpty()) {                QString textureURL = part.emissiveTexture->getURL().toString();                result << part.emissiveTextureName + ":" + textureURL;            }        }    }    return result;} void NetworkGeometry::replaceTexturesWithPendingChanges() {    QHash<QString, QUrl>::Iterator it = _pendingTextureChanges.begin();        while (it != _pendingTextureChanges.end()) {        setTextureWithNameToURL(it.key(), it.value());        it = _pendingTextureChanges.erase(it);    }} /// Reads geometry in a worker thread.class GeometryReader : public QRunnable {public:     GeometryReader(const QWeakPointer<Resource>& geometry, const QUrl& url,        QNetworkReply* reply, const QVariantHash& mapping);     virtual void run(); private:         QWeakPointer<Resource> _geometry;    QUrl _url;    QNetworkReply* _reply;    QVariantHash _mapping;}; GeometryReader::GeometryReader(const QWeakPointer<Resource>& geometry, const QUrl& url,        QNetworkReply* reply, const QVariantHash& mapping) :    _geometry(geometry),    _url(url),    _reply(reply),    _mapping(mapping) {} void GeometryReader::run() {    QSharedPointer<Resource> geometry = _geometry.toStrongRef();    if (geometry.isNull()) {        _reply->deleteLater();        return;    }    try {        if (!_reply) {            throw QString("Reply is NULL ?!");        }        std::string urlname = _url.path().toLower().toStdString();        bool urlValid = true;        urlValid &= !urlname.empty();        urlValid &= !_url.path().isEmpty();        urlValid &= _url.path().toLower().endsWith(".fbx")                    || _url.path().toLower().endsWith(".svo");         if (urlValid) {            // Let's read the binaries from the network            QByteArray fileBinary = _reply->readAll();            if (fileBinary.isEmpty() || fileBinary.isNull()) {                throw QString("Read File binary is empty?!");            }             FBXGeometry fbxgeo;            if (_url.path().toLower().endsWith(".svo")) {                fbxgeo = readSVO(fileBinary);            } else if (_url.path().toLower().endsWith(".fbx")) {                bool grabLightmaps = true;                float lightmapLevel = 1.0f;                // HACK: For monday 12/01/2014 we need to kill lighmaps loading in starchamber...                if (_url.path().toLower().endsWith("loungev4_11-18.fbx")) {                    grabLightmaps = false;                } else if (_url.path().toLower().endsWith("apt8_reboot.fbx")) {                    lightmapLevel = 4.0f;                } else if (_url.path().toLower().endsWith("palaceoforinthilian4.fbx")) {                    lightmapLevel = 3.5f;                }                fbxgeo = readFBX(fileBinary, _mapping, grabLightmaps, lightmapLevel);            }            QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&, fbxgeo));        } else {            throw QString("url is invalid");        }     } catch (const QString& error) {        qDebug() << "Error reading " << _url << ": " << error;        QMetaObject::invokeMethod(geometry.data(), "finishedLoading", Q_ARG(bool, false));    }    _reply->deleteLater();} void NetworkGeometry::init() {    _mapping = QVariantHash();    _geometry = FBXGeometry();    _meshes.clear();    _lods.clear();    _pendingTextureChanges.clear();    _request.setUrl(_url);    Resource::init();} void NetworkGeometry::downloadFinished(QNetworkReply* reply) {    QUrl url = reply->url();    if (url.path().toLower().endsWith(".fst")) {        // it's a mapping file; parse it and get the mesh filename        _mapping = readMapping(reply->readAll());        reply->deleteLater();        QString filename = _mapping.value("filename").toString();        if (filename.isNull()) {            qDebug() << "Mapping file " << url << " has no filename.";            finishedLoading(false);                    } else {            QString texdir = _mapping.value("texdir").toString();            if (!texdir.isNull()) {                if (!texdir.endsWith('/')) {                    texdir += '/';                }                _textureBase = url.resolved(texdir);            }            QVariantHash lods = _mapping.value("lod").toHash();            for (QVariantHash::const_iterator it = lods.begin(); it != lods.end(); it++) {                QSharedPointer<NetworkGeometry> geometry(new NetworkGeometry(url.resolved(it.key()),                    QSharedPointer<NetworkGeometry>(), true, _mapping, _textureBase));                    geometry->setSelf(geometry.staticCast<Resource>());                geometry->setLODParent(_lodParent);                _lods.insert(it.value().toFloat(), geometry);            }                 _request.setUrl(url.resolved(filename));                        // make the request immediately only if we have no LODs to switch between            _startedLoading = false;            if (_lods.isEmpty()) {                attemptRequest();            }        }        return;    }        // send the reader off to the thread pool    QThreadPool::globalInstance()->start(new GeometryReader(_self, url, reply, _mapping));} void NetworkGeometry::reinsert() {    Resource::reinsert();        _lodParent = qWeakPointerCast<NetworkGeometry, Resource>(_self);    foreach (const QSharedPointer<NetworkGeometry>& lod, _lods) {        lod->setLODParent(_lodParent);    }} void NetworkGeometry::setGeometry(const FBXGeometry& geometry) {    _geometry = geometry;        foreach (const FBXMesh& mesh, _geometry.meshes) {        NetworkMesh networkMesh;                int totalIndices = 0;        foreach (const FBXMeshPart& part, mesh.parts) {            NetworkMeshPart networkPart;            if (!part.diffuseTexture.filename.isEmpty()) {                networkPart.diffuseTexture = Application::getInstance()->getTextureCache()->getTexture(                    _textureBase.resolved(QUrl(part.diffuseTexture.filename)), DEFAULT_TEXTURE,                    mesh.isEye, part.diffuseTexture.content);                networkPart.diffuseTextureName = part.diffuseTexture.name;                networkPart.diffuseTexture->setLoadPriorities(_loadPriorities);            }            if (!part.normalTexture.filename.isEmpty()) {                networkPart.normalTexture = Application::getInstance()->getTextureCache()->getTexture(                    _textureBase.resolved(QUrl(part.normalTexture.filename)), NORMAL_TEXTURE,                    false, part.normalTexture.content);                networkPart.normalTextureName = part.normalTexture.name;                networkPart.normalTexture->setLoadPriorities(_loadPriorities);            }            if (!part.specularTexture.filename.isEmpty()) {                networkPart.specularTexture = Application::getInstance()->getTextureCache()->getTexture(                    _textureBase.resolved(QUrl(part.specularTexture.filename)), SPECULAR_TEXTURE,                    false, part.specularTexture.content);                networkPart.specularTextureName = part.specularTexture.name;                networkPart.specularTexture->setLoadPriorities(_loadPriorities);            }            if (!part.emissiveTexture.filename.isEmpty()) {                networkPart.emissiveTexture = Application::getInstance()->getTextureCache()->getTexture(                    _textureBase.resolved(QUrl(part.emissiveTexture.filename)), EMISSIVE_TEXTURE,                    false, part.emissiveTexture.content);                networkPart.emissiveTextureName = part.emissiveTexture.name;                networkPart.emissiveTexture->setLoadPriorities(_loadPriorities);            }            networkMesh.parts.append(networkPart);                                    totalIndices += (part.quadIndices.size() + part.triangleIndices.size());        }         {            networkMesh._indexBuffer = gpu::BufferPointer(new gpu::Buffer());            networkMesh._indexBuffer->resize(totalIndices * sizeof(int));            int offset = 0;            foreach(const FBXMeshPart& part, mesh.parts) {                networkMesh._indexBuffer->setSubData(offset, part.quadIndices.size() * sizeof(int),                    (gpu::Resource::Byte*) part.quadIndices.constData());                offset += part.quadIndices.size() * sizeof(int);                networkMesh._indexBuffer->setSubData(offset, part.triangleIndices.size() * sizeof(int),                    (gpu::Resource::Byte*) part.triangleIndices.constData());                offset += part.triangleIndices.size() * sizeof(int);            }        }         {            networkMesh._vertexBuffer = gpu::BufferPointer(new gpu::Buffer());            // if we don't need to do any blending, the positions/normals can be static            if (mesh.blendshapes.isEmpty()) {                int normalsOffset = mesh.vertices.size() * sizeof(glm::vec3);                int tangentsOffset = normalsOffset + mesh.normals.size() * sizeof(glm::vec3);                int colorsOffset = tangentsOffset + mesh.tangents.size() * sizeof(glm::vec3);

Lines 501–1000 of 1098. Previous lines