History

ResourceCache, NetworkGeometry and Model refactoring and optimizations.

* Removed validation logic from Resource class, Qt does this internally and is more standards compliant. This should result in more accurate caching and faster resource fetching when cache is stale and validation fails. * Added loaded and failed slots to Resource class, so it does not have to be polled. * NetworkGeometry now uses multiple Resource objects to download the fst/mapping file and the fbx/obj models. * NetworkGeometry is no longer a subclass of Resource * NetworkGeometry now has signals for success and failure, you no longer have to poll it to determine when loading is complete (except for textures *sigh*) Some functionality was removed * NetworkGeometry no longer has a fallback * NetworkGeometry no longer loads LODs or has lod logic. * The number of FBXGeometry copies is greatly reduced. * Model::setURL no supports fallback URL, delayLoad or retainCurrent option. This can result in a pop when switching avatars, and there's no longer a default if avatar loading fails.

Anthony J. Thibault committed 11 years ago

Commit 1b3d7fa1 parent f2fd7db20 files · +664 −815Browse files

Showing the changes to libraries/render-utils/src/GeometryCache.cpp (1 of 20 files). Show all

Unified · Split

libraries/render-utils/src/GeometryCache.cpp+305−469
@@ -14,7 +14,6 @@ · 13 unmodified lines
1414 #include <cmath>
1515
1616 #include <QNetworkReply>
17−#include <QRunnable>
1817 #include <QThreadPool>
1918
2019 #include <FSTReader.h>
@@ -50,6 +49,13 @@ GeometryCache::~GeometryCache() { · 29 unmodified lines
5049 #endif //def WANT_DEBUG
5150 }
5251
52+QSharedPointer<Resource> GeometryCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
53+ bool delayLoad, const void* extra) {
54+ // NetworkGeometry is no longer a subclass of Resource, but requires this method because, it is pure virtual.
55+ assert(false);
56+ return QSharedPointer<Resource>();
57+}
58+
5359 const int NUM_VERTICES_PER_TRIANGLE = 3;
5460 const int NUM_TRIANGLES_PER_QUAD = 2;
5561 const int NUM_VERTICES_PER_TRIANGULATED_QUAD = NUM_VERTICES_PER_TRIANGLE * NUM_TRIANGLES_PER_QUAD;
@@ -1643,19 +1649,6 @@ void GeometryCache::renderLine(gpu::Batch& batch, const glm::vec2& p1, const glm · 1587 unmodified lines
16431649 batch.draw(gpu::LINES, 2, 0);
16441650 }
16451651
1646−
1647−QSharedPointer<NetworkGeometry> GeometryCache::getGeometry(const QUrl& url, const QUrl& fallback, bool delayLoad) {
1648− return getResource(url, fallback, delayLoad, NULL).staticCast<NetworkGeometry>();
1649−}
1650−
1651−QSharedPointer<Resource> GeometryCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
1652− bool delayLoad, const void* extra) {
1653− QSharedPointer<NetworkGeometry> geometry(new NetworkGeometry(url, fallback.staticCast<NetworkGeometry>(), delayLoad),
1654− &Resource::allReferencesCleared);
1655− geometry->setLODParent(geometry);
1656− return geometry.staticCast<Resource>();
1657−}
1658−
16591652 void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) {
16601653 if (!_standardDrawPipeline) {
16611654 auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)));
@@ -1685,232 +1678,136 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { · 23 unmodified lines
16851678 }
16861679 }
16871680
1688−const float NetworkGeometry::NO_HYSTERESIS = -1.0f;
1689−
1690−NetworkGeometry::NetworkGeometry(const QUrl& url, const QSharedPointer<NetworkGeometry>& fallback, bool delayLoad,
1691− const QVariantHash& mapping, const QUrl& textureBase) :
1692− Resource(url, delayLoad),
1693− _mapping(mapping),
1694− _textureBase(textureBase.isValid() ? textureBase : url),
1695− _fallback(fallback)
1696−{
1697−
1698− if (url.isEmpty()) {
1699− // make the minimal amount of dummy geometry to satisfy Model
1700− FBXJoint joint = { false, QVector<int>(), -1, 0.0f, 0.0f, glm::vec3(), glm::mat4(), glm::quat(), glm::quat(),
1701− glm::quat(), glm::mat4(), glm::mat4(), glm::vec3(), glm::vec3(), glm::quat(), glm::quat(),
1702− glm::mat4(), QString(""), false};
1703− _geometry.joints.append(joint);
1704− _geometry.leftEyeJointIndex = -1;
1705− _geometry.rightEyeJointIndex = -1;
1706− _geometry.neckJointIndex = -1;
1707− _geometry.rootJointIndex = -1;
1708− _geometry.leanJointIndex = -1;
1709− _geometry.headJointIndex = -1;
1710− _geometry.leftHandJointIndex = -1;
1711− _geometry.rightHandJointIndex = -1;
1712− }
1713−
1714− connect(this, &Resource::loaded, this, &NetworkGeometry::replaceTexturesWithPendingChanges);
1681+GeometryReader::GeometryReader(const QUrl& url, QNetworkReply* reply, const QVariantHash& mapping) :
1682+ _url(url),
1683+ _reply(reply),
1684+ _mapping(mapping) {
17151685 }
17161686
1717−bool NetworkGeometry::isLoadedWithTextures() const {
1718− if (!isLoaded()) {
1719− return false;
1720− }
1721− if (!_isLoadedWithTextures) {
1722− foreach (const NetworkMesh& mesh, _meshes) {
1723− foreach (const NetworkMeshPart& part, mesh.parts) {
1724− if ((part.diffuseTexture && !part.diffuseTexture->isLoaded()) ||
1725− (part.normalTexture && !part.normalTexture->isLoaded()) ||
1726− (part.specularTexture && !part.specularTexture->isLoaded()) ||
1727− (part.emissiveTexture && !part.emissiveTexture->isLoaded())) {
1728− return false;
1729− }
1730− }
1687+void GeometryReader::run() {
1688+ try {
1689+ if (!_reply) {
1690+ throw QString("Reply is NULL ?!");
17311691 }
1732− _isLoadedWithTextures = true;
1733− }
1734− return true;
1735−}
1692+ QString urlname = _url.path().toLower();
1693+ bool urlValid = true;
1694+ urlValid &= !urlname.isEmpty();
1695+ urlValid &= !_url.path().isEmpty();
1696+ urlValid &= _url.path().toLower().endsWith(".fbx") || _url.path().toLower().endsWith(".obj");
17361697
1737−QSharedPointer<NetworkGeometry> NetworkGeometry::getLODOrFallback(float distance, float& hysteresis, bool delayLoad) const {
1738− if (_lodParent.data() != this) {
1739− return _lodParent.data()->getLODOrFallback(distance, hysteresis, delayLoad);
1740− }
1741− if (_failedToLoad && _fallback) {
1742− return _fallback;
1743− }
1744− QSharedPointer<NetworkGeometry> lod = _lodParent;
1745− float lodDistance = 0.0f;
1746− QMap<float, QSharedPointer<NetworkGeometry> >::const_iterator it = _lods.upperBound(distance);
1747− if (it != _lods.constBegin()) {
1748− it = it - 1;
1749− lod = it.value();
1750− lodDistance = it.key();
1751− }
1752− if (hysteresis != NO_HYSTERESIS && hysteresis != lodDistance) {
1753− // if we previously selected a different distance, make sure we've moved far enough to justify switching
1754− const float HYSTERESIS_PROPORTION = 0.1f;
1755− if (glm::abs(distance - qMax(hysteresis, lodDistance)) / fabsf(hysteresis - lodDistance) < HYSTERESIS_PROPORTION) {
1756− lod = _lodParent;
1757− lodDistance = 0.0f;
1758− it = _lods.upperBound(hysteresis);
1759− if (it != _lods.constBegin()) {
1760− it = it - 1;
1761− lod = it.value();
1762− lodDistance = it.key();
1698+ if (urlValid) {
1699+ // Let's read the binaries from the network
1700+ FBXGeometry* fbxgeo = nullptr;
1701+ if (_url.path().toLower().endsWith(".fbx")) {
1702+ const bool grabLightmaps = true;
1703+ const float lightmapLevel = 1.0f;
1704+ fbxgeo = readFBX(_reply, _mapping, _url.path(), grabLightmaps, lightmapLevel);
1705+ } else if (_url.path().toLower().endsWith(".obj")) {
1706+ fbxgeo = OBJReader().readOBJ(_reply, _mapping, &_url);
1707+ } else {
1708+ QString errorStr("usupported format");
1709+ emit onError(NetworkGeometry::ModelParseError, errorStr);
17631710 }
1711+ emit onSuccess(fbxgeo);
1712+ } else {
1713+ throw QString("url is invalid");
17641714 }
1715+
1716+ } catch (const QString& error) {
1717+ qCDebug(renderutils) << "Error reading " << _url << ": " << error;
1718+ emit onError(NetworkGeometry::ModelParseError, error);
17651719 }
1766− if (lod && lod->isLoaded()) {
1767− hysteresis = lodDistance;
1768− return lod;
1769− }
1770− // if the ideal LOD isn't loaded, we need to make sure it's started to load, and possibly return the closest loaded one
1771− if (!delayLoad) {
1772− lod->ensureLoading();
1773− }
1774− float closestDistance = FLT_MAX;
1775− if (isLoaded()) {
1776− lod = _lodParent;
1777− closestDistance = distance;
1778− }
1779− for (it = _lods.constBegin(); it != _lods.constEnd(); it++) {
1780− float distanceToLOD = glm::abs(distance - it.key());
1781− if (it.value()->isLoaded() && distanceToLOD < closestDistance) {
1782− lod = it.value();
1783− closestDistance = distanceToLOD;
1784− }
1785− }
1786− hysteresis = NO_HYSTERESIS;
1787− return lod;
1720+ _reply->deleteLater();
17881721 }
17891722
1790−uint qHash(const QWeakPointer<Animation>& animation, uint seed = 0) {
1791− return qHash(animation.data(), seed);
1723+NetworkGeometry::NetworkGeometry(const QUrl& url, bool delayLoad, const QVariantHash& mapping, const QUrl& textureBaseUrl) :
1724+ _url(url),
1725+ _mapping(mapping),
1726+ _textureBaseUrl(textureBaseUrl) {
1727+
1728+ if (delayLoad) {
1729+ _state = DelayState;
1730+ } else {
1731+ attemptRequestInternal();
1732+ }
17921733 }
17931734
1794−QVector<int> NetworkGeometry::getJointMappings(const AnimationPointer& animation) {
1795− QVector<int> mappings = _jointMappings.value(animation);
1796− if (mappings.isEmpty() && isLoaded() && animation && animation->isLoaded()) {
1797− const FBXGeometry& animationGeometry = animation->getGeometry();
1798− for (int i = 0; i < animationGeometry.joints.size(); i++) {
1799− mappings.append(_geometry.jointIndices.value(animationGeometry.joints.at(i).name) - 1);
1800− }
1801− _jointMappings.insert(animation, mappings);
1735+NetworkGeometry::~NetworkGeometry() {
1736+ if (_resource) {
1737+ _resource->deleteLater();
18021738 }
1803− return mappings;
18041739 }
18051740
1806−void NetworkGeometry::setLoadPriority(const QPointer<QObject>& owner, float priority) {
1807− Resource::setLoadPriority(owner, priority);
1808−
1809− for (int i = 0; i < _meshes.size(); i++) {
1810− NetworkMesh& mesh = _meshes[i];
1811− for (int j = 0; j < mesh.parts.size(); j++) {
1812− NetworkMeshPart& part = mesh.parts[j];
1813− if (part.diffuseTexture) {
1814− part.diffuseTexture->setLoadPriority(owner, priority);
1815− }
1816− if (part.normalTexture) {
1817− part.normalTexture->setLoadPriority(owner, priority);
1818− }
1819− if (part.specularTexture) {
1820− part.specularTexture->setLoadPriority(owner, priority);
1821− }
1822− if (part.emissiveTexture) {
1823− part.emissiveTexture->setLoadPriority(owner, priority);
1824− }
1825− }
1741+void NetworkGeometry::attemptRequest() {
1742+ if (_state == DelayState) {
1743+ attemptRequestInternal();
18261744 }
18271745 }
18281746
1829−void NetworkGeometry::setLoadPriorities(const QHash<QPointer<QObject>, float>& priorities) {
1830− Resource::setLoadPriorities(priorities);
1831−
1832− for (int i = 0; i < _meshes.size(); i++) {
1833− NetworkMesh& mesh = _meshes[i];
1834− for (int j = 0; j < mesh.parts.size(); j++) {
1835− NetworkMeshPart& part = mesh.parts[j];
1836− if (part.diffuseTexture) {
1837− part.diffuseTexture->setLoadPriorities(priorities);
1838− }
1839− if (part.normalTexture) {
1840− part.normalTexture->setLoadPriorities(priorities);
1841− }
1842− if (part.specularTexture) {
1843− part.specularTexture->setLoadPriorities(priorities);
1844− }
1845− if (part.emissiveTexture) {
1846− part.emissiveTexture->setLoadPriorities(priorities);
1847− }
1848− }
1747+void NetworkGeometry::attemptRequestInternal() {
1748+ if (_url.path().toLower().endsWith(".fst")) {
1749+ requestMapping(_url);
1750+ } else {
1751+ requestModel(_url);
18491752 }
18501753 }
18511754
1852−void NetworkGeometry::clearLoadPriority(const QPointer<QObject>& owner) {
1853− Resource::clearLoadPriority(owner);
1854−
1855− for (int i = 0; i < _meshes.size(); i++) {
1856− NetworkMesh& mesh = _meshes[i];
1857− for (int j = 0; j < mesh.parts.size(); j++) {
1858− NetworkMeshPart& part = mesh.parts[j];
1859− if (part.diffuseTexture) {
1860− part.diffuseTexture->clearLoadPriority(owner);
1861− }
1862− if (part.normalTexture) {
1863− part.normalTexture->clearLoadPriority(owner);
1864− }
1865− if (part.specularTexture) {
1866− part.specularTexture->clearLoadPriority(owner);
1867− }
1868− if (part.emissiveTexture) {
1869− part.emissiveTexture->clearLoadPriority(owner);
1755+bool NetworkGeometry::isLoaded() const {
1756+ return _state == SuccessState;
1757+}
1758+
1759+bool NetworkGeometry::isLoadedWithTextures() const {
1760+ if (!isLoaded()) {
1761+ return false;
1762+ }
1763+ if (!_isLoadedWithTextures) {
1764+ for (auto&& mesh : _meshes) {
1765+ for (auto && part : mesh->_parts) {
1766+ if ((part->diffuseTexture && !part->diffuseTexture->isLoaded()) ||
1767+ (part->normalTexture && !part->normalTexture->isLoaded()) ||
1768+ (part->specularTexture && !part->specularTexture->isLoaded()) ||
1769+ (part->emissiveTexture && !part->emissiveTexture->isLoaded())) {
1770+ return false;
1771+ }
18701772 }
18711773 }
1774+ _isLoadedWithTextures = true;
18721775 }
1776+ return true;
18731777 }
18741778
18751779 void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& url) {
18761780 if (_meshes.size() > 0) {
18771781 auto textureCache = DependencyManager::get<TextureCache>();
1878− for (int i = 0; i < _meshes.size(); i++) {
1879− NetworkMesh& mesh = _meshes[i];
1880− for (int j = 0; j < mesh.parts.size(); j++) {
1881− NetworkMeshPart& part = mesh.parts[j];
1882−
1782+ for (size_t i = 0; i < _meshes.size(); i++) {
1783+ NetworkMesh& mesh = *(_meshes[i].get());
1784+ for (size_t j = 0; j < mesh._parts.size(); j++) {
1785+ NetworkMeshPart& part = *(mesh._parts[j].get());
18831786 QSharedPointer<NetworkTexture> matchingTexture = QSharedPointer<NetworkTexture>();
18841787 if (part.diffuseTextureName == name) {
1885− part.diffuseTexture = textureCache->getTexture(url, DEFAULT_TEXTURE, _geometry.meshes[i].isEye);
1886− part.diffuseTexture->setLoadPriorities(_loadPriorities);
1788+ part.diffuseTexture = textureCache->getTexture(url, DEFAULT_TEXTURE, _geometry->meshes[i].isEye);
18871789 } else if (part.normalTextureName == name) {
18881790 part.normalTexture = textureCache->getTexture(url);
1889− part.normalTexture->setLoadPriorities(_loadPriorities);
18901791 } else if (part.specularTextureName == name) {
18911792 part.specularTexture = textureCache->getTexture(url);
1892− part.specularTexture->setLoadPriorities(_loadPriorities);
18931793 } else if (part.emissiveTextureName == name) {
18941794 part.emissiveTexture = textureCache->getTexture(url);
1895− part.emissiveTexture->setLoadPriorities(_loadPriorities);
18961795 }
18971796 }
18981797 }
18991798 } else {
1900− qCDebug(renderutils) << "Adding a name url pair to pending" << name << url;
1901− // we don't have meshes downloaded yet, so hold this texture as pending
1902− _pendingTextureChanges.insert(name, url);
1799+ qCWarning(renderutils) << "Ignoring setTextureWirthNameToURL() geometry not ready." << name << url;
19031800 }
19041801 _isLoadedWithTextures = false;
19051802 }
19061803
19071804 QStringList NetworkGeometry::getTextureNames() const {
19081805 QStringList result;
1909− for (int i = 0; i < _meshes.size(); i++) {
1910− const NetworkMesh& mesh = _meshes[i];
1911− for (int j = 0; j < mesh.parts.size(); j++) {
1912− const NetworkMeshPart& part = mesh.parts[j];
1913−
1806+ for (size_t i = 0; i < _meshes.size(); i++) {
1807+ const NetworkMesh& mesh = *(_meshes[i].get());
1808+ for (size_t j = 0; j < mesh._parts.size(); j++) {
1809+ const NetworkMeshPart& part = *(mesh._parts[j].get());
1810+
19141811 if (!part.diffuseTextureName.isEmpty() && part.diffuseTexture) {
19151812 QString textureURL = part.diffuseTexture->getURL().toString();
19161813 result << part.diffuseTextureName + ":" + textureURL;
@@ -1935,320 +1832,259 @@ QStringList NetworkGeometry::getTextureNames() const { · 18 unmodified lines
19351832 return result;
19361833 }
19371834
1938−void NetworkGeometry::replaceTexturesWithPendingChanges() {
1939− QHash<QString, QUrl>::Iterator it = _pendingTextureChanges.begin();
1940−
1941− while (it != _pendingTextureChanges.end()) {
1942− setTextureWithNameToURL(it.key(), it.value());
1943− it = _pendingTextureChanges.erase(it);
1835+void NetworkGeometry::requestMapping(const QUrl& url) {
1836+ _state = RequestMappingState;
1837+ if (_resource) {
1838+ _resource->deleteLater();
19441839 }
1840+ _resource = new Resource(url, false);
1841+ connect(_resource, SIGNAL(loaded(QNetworkReply&)), SLOT(mappingRequestDone(QNetworkReply&)));
1842+ connect(_resource, SIGNAL(failed(QNetworkReply::NetworkError)), SLOT(mappingRequestError(QNetworkReply::NetworkError)));
19451843 }
19461844
1947−/// Reads geometry in a worker thread.
1948−class GeometryReader : public QRunnable {
1949−public:
1950−
1951− GeometryReader(const QWeakPointer<Resource>& geometry, const QUrl& url,
1952− QNetworkReply* reply, const QVariantHash& mapping);
1953−
1954− virtual void run();
1955−
1956−private:
1957−
1958− QWeakPointer<Resource> _geometry;
1959− QUrl _url;
1960− QNetworkReply* _reply;
1961− QVariantHash _mapping;
1962−};
1963−
1964−GeometryReader::GeometryReader(const QWeakPointer<Resource>& geometry, const QUrl& url,
1965− QNetworkReply* reply, const QVariantHash& mapping) :
1966− _geometry(geometry),
1967− _url(url),
1968− _reply(reply),
1969− _mapping(mapping) {
1845+void NetworkGeometry::requestModel(const QUrl& url) {
1846+ _state = RequestModelState;
1847+ if (_resource) {
1848+ _resource->deleteLater();
1849+ }
1850+ _resource = new Resource(url, false);
1851+ connect(_resource, SIGNAL(loaded(QNetworkReply&)), SLOT(modelRequestDone(QNetworkReply&)));
1852+ connect(_resource, SIGNAL(failed(QNetworkReply::NetworkError)), SLOT(modelRequestError(QNetworkReply::NetworkError)));
19701853 }
19711854
1972−void GeometryReader::run() {
1973− QSharedPointer<Resource> geometry = _geometry.toStrongRef();
1974− if (geometry.isNull()) {
1975− _reply->deleteLater();
1976− return;
1977− }
1978− try {
1979− if (!_reply) {
1980− throw QString("Reply is NULL ?!");
1981− }
1982− QString urlname = _url.path().toLower();
1983− bool urlValid = true;
1984− urlValid &= !urlname.isEmpty();
1985− urlValid &= !_url.path().isEmpty();
1986− urlValid &= _url.path().toLower().endsWith(".fbx")
1987− || _url.path().toLower().endsWith(".obj")
1988− || _url.path().toLower().endsWith(".svo");
1855+void NetworkGeometry::mappingRequestDone(QNetworkReply& reply) {
1856+ assert(_state == RequestMappingState);
19891857
1990− if (urlValid) {
1991− // Let's read the binaries from the network
1992− FBXGeometry fbxgeo;
1993− if (_url.path().toLower().endsWith(".fbx")) {
1994− bool grabLightmaps = true;
1995− float lightmapLevel = 1.0f;
1996− // HACK: For monday 12/01/2014 we need to kill lighmaps loading in starchamber...
1997− if (_url.path().toLower().endsWith("loungev4_11-18.fbx")) {
1998− grabLightmaps = false;
1999− } else if (_url.path().toLower().endsWith("apt8_reboot.fbx")) {
2000− lightmapLevel = 4.0f;
2001− } else if (_url.path().toLower().endsWith("palaceoforinthilian4.fbx")) {
2002− lightmapLevel = 3.5f;
2003− }
2004− fbxgeo = readFBX(_reply, _mapping, _url.path(), grabLightmaps, lightmapLevel);
2005− } else if (_url.path().toLower().endsWith(".obj")) {
2006− fbxgeo = OBJReader().readOBJ(_reply, _mapping, &_url);
1858+ // parse the mapping file
1859+ _mapping = FSTReader::readMapping(reply.readAll());
1860+
1861+ QUrl replyUrl = reply.url();
1862+ QString modelUrlStr = _mapping.value("filename").toString();
1863+ if (modelUrlStr.isNull()) {
1864+ qCDebug(renderutils) << "Mapping file " << _url << "has no \"filename\" entry";
1865+ emit onFailure(*this, MissingFilenameInMapping);
1866+ } else {
1867+ // read _textureBase from mapping file, if present
1868+ QString texdir = _mapping.value("texdir").toString();
1869+ if (!texdir.isNull()) {
1870+ if (!texdir.endsWith('/')) {
1871+ texdir += '/';
20071872 }
2008− QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&, fbxgeo));
2009− } else {
2010− throw QString("url is invalid");
1873+ _textureBaseUrl = replyUrl.resolved(texdir);
20111874 }
20121875
2013− } catch (const QString& error) {
2014− qCDebug(renderutils) << "Error reading " << _url << ": " << error;
2015− QMetaObject::invokeMethod(geometry.data(), "finishedLoading", Q_ARG(bool, false));
1876+ QUrl modelUrl = replyUrl.resolved(modelUrlStr);
1877+ requestModel(modelUrl);
20161878 }
2017− _reply->deleteLater();
20181879 }
20191880
2020−void NetworkGeometry::init() {
2021− _mapping = QVariantHash();
2022− _geometry = FBXGeometry();
2023− _meshes.clear();
2024− _lods.clear();
2025− _pendingTextureChanges.clear();
2026− _request.setUrl(_url);
2027− Resource::init();
1881+void NetworkGeometry::mappingRequestError(QNetworkReply::NetworkError error) {
1882+ assert(_state == RequestMappingState);
1883+ _state = ErrorState;
1884+ emit onFailure(*this, MappingRequestError);
20281885 }
20291886
2030−void NetworkGeometry::downloadFinished(QNetworkReply* reply) {
2031− QUrl url = reply->url();
2032− if (url.path().toLower().endsWith(".fst")) {
2033− // it's a mapping file; parse it and get the mesh filename
2034− _mapping = FSTReader::readMapping(reply->readAll());
2035− reply->deleteLater();
2036− QString filename = _mapping.value("filename").toString();
2037− if (filename.isNull()) {
2038− qCDebug(renderutils) << "Mapping file " << url << " has no filename.";
2039− finishedLoading(false);
2040−
2041− } else {
2042− QString texdir = _mapping.value("texdir").toString();
2043− if (!texdir.isNull()) {
2044− if (!texdir.endsWith('/')) {
2045− texdir += '/';
2046− }
2047− _textureBase = url.resolved(texdir);
2048− }
2049− QVariantHash lods = _mapping.value("lod").toHash();
2050− for (QVariantHash::const_iterator it = lods.begin(); it != lods.end(); it++) {
2051− auto geometry = QSharedPointer<NetworkGeometry>::create(url.resolved(it.key()),
2052− QSharedPointer<NetworkGeometry>(), true, _mapping, _textureBase);
2053− geometry->setSelf(geometry.staticCast<Resource>());
2054− geometry->setLODParent(_lodParent);
2055− _lods.insert(it.value().toFloat(), geometry);
2056− }
2057− _request.setUrl(url.resolved(filename));
2058−
2059− // make the request immediately only if we have no LODs to switch between
2060− _startedLoading = false;
2061− if (_lods.isEmpty()) {
2062− attemptRequest();
2063− }
2064− }
2065− return;
2066− }
2067−
2068− // send the reader off to the thread pool
2069− QThreadPool::globalInstance()->start(new GeometryReader(_self, url, reply, _mapping));
2070−}
1887+void NetworkGeometry::modelRequestDone(QNetworkReply& reply) {
1888+ assert(_state == RequestModelState);
20711889
2072−void NetworkGeometry::reinsert() {
2073− Resource::reinsert();
2074−
2075− _lodParent = qWeakPointerCast<NetworkGeometry, Resource>(_self);
2076− foreach (const QSharedPointer<NetworkGeometry>& lod, _lods) {
2077− lod->setLODParent(_lodParent);
2078− }
1890+ _state = ParsingModelState;
1891+
1892+ // asynchronously parse the model file.
1893+ GeometryReader* geometryReader = new GeometryReader(reply.url(), &reply, _mapping);
1894+ connect(geometryReader, SIGNAL(onSuccess(FBXGeometry*)), SLOT(modelParseSuccess(FBXGeometry*)));
1895+ connect(geometryReader, SIGNAL(onError(int, QString)), SLOT(modelParseError(int, QString)));
1896+
1897+ QThreadPool::globalInstance()->start(geometryReader);
20791898 }
20801899
2081−void NetworkGeometry::setGeometry(const FBXGeometry& geometry) {
2082− _geometry = geometry;
1900+void NetworkGeometry::modelRequestError(QNetworkReply::NetworkError error) {
1901+ assert(_state == RequestModelState);
1902+ _state = ErrorState;
1903+ emit onFailure(*this, ModelRequestError);
1904+}
20831905
1906+static NetworkMesh* buildNetworkMesh(const FBXMesh& mesh, const QUrl& textureBaseUrl) {
20841907 auto textureCache = DependencyManager::get<TextureCache>();
2085−
2086− foreach (const FBXMesh& mesh, _geometry.meshes) {
2087− NetworkMesh networkMesh;
2088−
2089− int totalIndices = 0;
2090− bool checkForTexcoordLightmap = false;
2091− foreach (const FBXMeshPart& part, mesh.parts) {
2092− NetworkMeshPart networkPart;
2093− if (!part.diffuseTexture.filename.isEmpty()) {
2094− networkPart.diffuseTexture = textureCache->getTexture(
2095− _textureBase.resolved(QUrl(part.diffuseTexture.filename)), DEFAULT_TEXTURE,
2096− mesh.isEye, part.diffuseTexture.content);
2097− networkPart.diffuseTextureName = part.diffuseTexture.name;
2098− networkPart.diffuseTexture->setLoadPriorities(_loadPriorities);
2099− }
2100− if (!part.normalTexture.filename.isEmpty()) {
2101− networkPart.normalTexture = textureCache->getTexture(
2102− _textureBase.resolved(QUrl(part.normalTexture.filename)), NORMAL_TEXTURE,
2103− false, part.normalTexture.content);
2104− networkPart.normalTextureName = part.normalTexture.name;
2105− networkPart.normalTexture->setLoadPriorities(_loadPriorities);
2106− }
2107− if (!part.specularTexture.filename.isEmpty()) {
2108− networkPart.specularTexture = textureCache->getTexture(
2109− _textureBase.resolved(QUrl(part.specularTexture.filename)), SPECULAR_TEXTURE,
2110− false, part.specularTexture.content);
2111− networkPart.specularTextureName = part.specularTexture.name;
2112− networkPart.specularTexture->setLoadPriorities(_loadPriorities);
2113− }
2114− if (!part.emissiveTexture.filename.isEmpty()) {
2115− networkPart.emissiveTexture = textureCache->getTexture(
2116− _textureBase.resolved(QUrl(part.emissiveTexture.filename)), EMISSIVE_TEXTURE,
2117− false, part.emissiveTexture.content);
2118− networkPart.emissiveTextureName = part.emissiveTexture.name;
2119− networkPart.emissiveTexture->setLoadPriorities(_loadPriorities);
2120− checkForTexcoordLightmap = true;
2121− }
2122− networkMesh.parts.append(networkPart);
2123−
2124− totalIndices += (part.quadIndices.size() + part.triangleIndices.size());
1908+ NetworkMesh* networkMesh = new NetworkMesh();
1909+
1910+ int totalIndices = 0;
1911+ bool checkForTexcoordLightmap = false;
1912+
1913+ // process network parts
1914+ foreach (const FBXMeshPart& part, mesh.parts) {
1915+ NetworkMeshPart* networkPart = new NetworkMeshPart();
1916+
1917+ if (!part.diffuseTexture.filename.isEmpty()) {
1918+ networkPart->diffuseTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(part.diffuseTexture.filename)), DEFAULT_TEXTURE,
1919+ mesh.isEye, part.diffuseTexture.content);
1920+ networkPart->diffuseTextureName = part.diffuseTexture.name;
21251921 }
1922+ if (!part.normalTexture.filename.isEmpty()) {
1923+ networkPart->normalTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(part.normalTexture.filename)), NORMAL_TEXTURE,
1924+ false, part.normalTexture.content);
1925+ networkPart->normalTextureName = part.normalTexture.name;
1926+ }
1927+ if (!part.specularTexture.filename.isEmpty()) {
1928+ networkPart->specularTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(part.specularTexture.filename)), SPECULAR_TEXTURE,
1929+ false, part.specularTexture.content);
1930+ networkPart->specularTextureName = part.specularTexture.name;
1931+ }
1932+ if (!part.emissiveTexture.filename.isEmpty()) {
1933+ networkPart->emissiveTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(part.emissiveTexture.filename)), EMISSIVE_TEXTURE,
1934+ false, part.emissiveTexture.content);
1935+ networkPart->emissiveTextureName = part.emissiveTexture.name;
1936+ checkForTexcoordLightmap = true;
1937+ }
1938+ networkMesh->_parts.emplace_back(networkPart);
1939+ totalIndices += (part.quadIndices.size() + part.triangleIndices.size());
1940+ }
1941+
1942+ // initialize index buffer
1943+ {
1944+ networkMesh->_indexBuffer = std::make_shared<gpu::Buffer>();
1945+ networkMesh->_indexBuffer->resize(totalIndices * sizeof(int));
1946+ int offset = 0;
1947+ foreach(const FBXMeshPart& part, mesh.parts) {
1948+ networkMesh->_indexBuffer->setSubData(offset, part.quadIndices.size() * sizeof(int),
1949+ (gpu::Byte*) part.quadIndices.constData());
1950+ offset += part.quadIndices.size() * sizeof(int);
1951+ networkMesh->_indexBuffer->setSubData(offset, part.triangleIndices.size() * sizeof(int),
1952+ (gpu::Byte*) part.triangleIndices.constData());
1953+ offset += part.triangleIndices.size() * sizeof(int);
1954+ }
1955+ }
21261956
2127− {
2128− networkMesh._indexBuffer = std::make_shared<gpu::Buffer>();
2129− networkMesh._indexBuffer->resize(totalIndices * sizeof(int));
2130− int offset = 0;
2131− foreach(const FBXMeshPart& part, mesh.parts) {
2132− networkMesh._indexBuffer->setSubData(offset, part.quadIndices.size() * sizeof(int),
2133− (gpu::Byte*) part.quadIndices.constData());
2134− offset += part.quadIndices.size() * sizeof(int);
2135− networkMesh._indexBuffer->setSubData(offset, part.triangleIndices.size() * sizeof(int),
2136− (gpu::Byte*) part.triangleIndices.constData());
2137− offset += part.triangleIndices.size() * sizeof(int);
1957+ // initialize vertex buffer
1958+ {
1959+ networkMesh->_vertexBuffer = std::make_shared<gpu::Buffer>();
1960+ // if we don't need to do any blending, the positions/normals can be static
1961+ if (mesh.blendshapes.isEmpty()) {
1962+ int normalsOffset = mesh.vertices.size() * sizeof(glm::vec3);
1963+ int tangentsOffset = normalsOffset + mesh.normals.size() * sizeof(glm::vec3);
1964+ int colorsOffset = tangentsOffset + mesh.tangents.size() * sizeof(glm::vec3);
1965+ int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
1966+ int texCoords1Offset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
1967+ int clusterIndicesOffset = texCoords1Offset + mesh.texCoords1.size() * sizeof(glm::vec2);
1968+ int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4);
1969+
1970+ networkMesh->_vertexBuffer->resize(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4));
1971+
1972+ networkMesh->_vertexBuffer->setSubData(0, mesh.vertices.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.vertices.constData());
1973+ networkMesh->_vertexBuffer->setSubData(normalsOffset, mesh.normals.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.normals.constData());
1974+ networkMesh->_vertexBuffer->setSubData(tangentsOffset,
1975+ mesh.tangents.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.tangents.constData());
1976+ networkMesh->_vertexBuffer->setSubData(colorsOffset, mesh.colors.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.colors.constData());
1977+ networkMesh->_vertexBuffer->setSubData(texCoordsOffset,
1978+ mesh.texCoords.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords.constData());
1979+ networkMesh->_vertexBuffer->setSubData(texCoords1Offset,
1980+ mesh.texCoords1.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords1.constData());
1981+ networkMesh->_vertexBuffer->setSubData(clusterIndicesOffset,
1982+ mesh.clusterIndices.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterIndices.constData());
1983+ networkMesh->_vertexBuffer->setSubData(clusterWeightsOffset,
1984+ mesh.clusterWeights.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterWeights.constData());
1985+
1986+ // otherwise, at least the cluster indices/weights can be static
1987+ networkMesh->_vertexStream = std::make_shared<gpu::BufferStream>();
1988+ networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, 0, sizeof(glm::vec3));
1989+ if (mesh.normals.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, normalsOffset, sizeof(glm::vec3));
1990+ if (mesh.tangents.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, tangentsOffset, sizeof(glm::vec3));
1991+ if (mesh.colors.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, colorsOffset, sizeof(glm::vec3));
1992+ if (mesh.texCoords.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, texCoordsOffset, sizeof(glm::vec2));
1993+ if (mesh.texCoords1.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, texCoords1Offset, sizeof(glm::vec2));
1994+ if (mesh.clusterIndices.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterIndicesOffset, sizeof(glm::vec4));
1995+ if (mesh.clusterWeights.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterWeightsOffset, sizeof(glm::vec4));
1996+
1997+ int channelNum = 0;
1998+ networkMesh->_vertexFormat = std::make_shared<gpu::Stream::Format>();
1999+ networkMesh->_vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
2000+ if (mesh.normals.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
2001+ if (mesh.tangents.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
2002+ if (mesh.colors.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB));
2003+ if (mesh.texCoords.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
2004+ if (mesh.texCoords1.size()) {
2005+ networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD1, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
2006+ } else if (checkForTexcoordLightmap && mesh.texCoords.size()) {
2007+ // need lightmap texcoord UV but doesn't have uv#1 so just reuse the same channel
2008+ networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD1, channelNum - 1, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
21382009 }
2010+ if (mesh.clusterIndices.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
2011+ if (mesh.clusterWeights.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
21392012 }
2013+ else {
2014+ int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3);
2015+ int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
2016+ int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
2017+ int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4);
2018+
2019+ networkMesh->_vertexBuffer->resize(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4));
2020+ networkMesh->_vertexBuffer->setSubData(0, mesh.tangents.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.tangents.constData());
2021+ networkMesh->_vertexBuffer->setSubData(colorsOffset, mesh.colors.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.colors.constData());
2022+ networkMesh->_vertexBuffer->setSubData(texCoordsOffset,
2023+ mesh.texCoords.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords.constData());
2024+ networkMesh->_vertexBuffer->setSubData(clusterIndicesOffset,
2025+ mesh.clusterIndices.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterIndices.constData());
2026+ networkMesh->_vertexBuffer->setSubData(clusterWeightsOffset,
2027+ mesh.clusterWeights.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterWeights.constData());
2028+
2029+ networkMesh->_vertexStream = std::make_shared<gpu::BufferStream>();
2030+ if (mesh.tangents.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, 0, sizeof(glm::vec3));
2031+ if (mesh.colors.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, colorsOffset, sizeof(glm::vec3));
2032+ if (mesh.texCoords.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, texCoordsOffset, sizeof(glm::vec2));
2033+ if (mesh.clusterIndices.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterIndicesOffset, sizeof(glm::vec4));
2034+ if (mesh.clusterWeights.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterWeightsOffset, sizeof(glm::vec4));
2035+
2036+ int channelNum = 0;
2037+ networkMesh->_vertexFormat = std::make_shared<gpu::Stream::Format>();
2038+ networkMesh->_vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
2039+ if (mesh.normals.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
2040+ if (mesh.tangents.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
2041+ if (mesh.colors.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB));
2042+ if (mesh.texCoords.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
2043+ if (mesh.clusterIndices.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
2044+ if (mesh.clusterWeights.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
2045+ }
2046+ }
21402047
2141− {
2142− networkMesh._vertexBuffer = std::make_shared<gpu::Buffer>();
2143− // if we don't need to do any blending, the positions/normals can be static
2144− if (mesh.blendshapes.isEmpty()) {
2145− int normalsOffset = mesh.vertices.size() * sizeof(glm::vec3);
2146− int tangentsOffset = normalsOffset + mesh.normals.size() * sizeof(glm::vec3);
2147− int colorsOffset = tangentsOffset + mesh.tangents.size() * sizeof(glm::vec3);
2148− int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
2149− int texCoords1Offset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
2150− int clusterIndicesOffset = texCoords1Offset + mesh.texCoords1.size() * sizeof(glm::vec2);
2151− int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4);
2152−
2153− networkMesh._vertexBuffer->resize(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4));
2154−
2155− networkMesh._vertexBuffer->setSubData(0, mesh.vertices.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.vertices.constData());
2156− networkMesh._vertexBuffer->setSubData(normalsOffset, mesh.normals.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.normals.constData());
2157− networkMesh._vertexBuffer->setSubData(tangentsOffset,
2158− mesh.tangents.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.tangents.constData());
2159− networkMesh._vertexBuffer->setSubData(colorsOffset, mesh.colors.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.colors.constData());
2160− networkMesh._vertexBuffer->setSubData(texCoordsOffset,
2161− mesh.texCoords.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords.constData());
2162− networkMesh._vertexBuffer->setSubData(texCoords1Offset,
2163− mesh.texCoords1.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords1.constData());
2164− networkMesh._vertexBuffer->setSubData(clusterIndicesOffset,
2165− mesh.clusterIndices.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterIndices.constData());
2166− networkMesh._vertexBuffer->setSubData(clusterWeightsOffset,
2167− mesh.clusterWeights.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterWeights.constData());
2168−
2169− // otherwise, at least the cluster indices/weights can be static
2170− networkMesh._vertexStream = std::make_shared<gpu::BufferStream>();
2171− networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, 0, sizeof(glm::vec3));
2172− if (mesh.normals.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, normalsOffset, sizeof(glm::vec3));
2173− if (mesh.tangents.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, tangentsOffset, sizeof(glm::vec3));
2174− if (mesh.colors.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, colorsOffset, sizeof(glm::vec3));
2175− if (mesh.texCoords.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, texCoordsOffset, sizeof(glm::vec2));
2176− if (mesh.texCoords1.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, texCoords1Offset, sizeof(glm::vec2));
2177− if (mesh.clusterIndices.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, clusterIndicesOffset, sizeof(glm::vec4));
2178− if (mesh.clusterWeights.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, clusterWeightsOffset, sizeof(glm::vec4));
2179−
2180− int channelNum = 0;
2181− networkMesh._vertexFormat = std::make_shared<gpu::Stream::Format>();
2182− networkMesh._vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
2183− if (mesh.normals.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
2184− if (mesh.tangents.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
2185− if (mesh.colors.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB));
2186− if (mesh.texCoords.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
2187− if (mesh.texCoords1.size()) {
2188− networkMesh._vertexFormat->setAttribute(gpu::Stream::TEXCOORD1, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
2189− } else if (checkForTexcoordLightmap && mesh.texCoords.size()) {
2190− // need lightmap texcoord UV but doesn't have uv#1 so just reuse the same channel
2191− networkMesh._vertexFormat->setAttribute(gpu::Stream::TEXCOORD1, channelNum - 1, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
2192− }
2193− if (mesh.clusterIndices.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
2194− if (mesh.clusterWeights.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
2195− }
2196− else {
2197− int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3);
2198− int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
2199− int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
2200− int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4);
2201−
2202− networkMesh._vertexBuffer->resize(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4));
2203− networkMesh._vertexBuffer->setSubData(0, mesh.tangents.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.tangents.constData());
2204− networkMesh._vertexBuffer->setSubData(colorsOffset, mesh.colors.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.colors.constData());
2205− networkMesh._vertexBuffer->setSubData(texCoordsOffset,
2206− mesh.texCoords.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords.constData());
2207− networkMesh._vertexBuffer->setSubData(clusterIndicesOffset,
2208− mesh.clusterIndices.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterIndices.constData());
2209− networkMesh._vertexBuffer->setSubData(clusterWeightsOffset,
2210− mesh.clusterWeights.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterWeights.constData());
2211−
2212− networkMesh._vertexStream = std::make_shared<gpu::BufferStream>();
2213− if (mesh.tangents.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, 0, sizeof(glm::vec3));
2214− if (mesh.colors.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, colorsOffset, sizeof(glm::vec3));
2215− if (mesh.texCoords.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, texCoordsOffset, sizeof(glm::vec2));
2216− if (mesh.clusterIndices.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, clusterIndicesOffset, sizeof(glm::vec4));
2217− if (mesh.clusterWeights.size()) networkMesh._vertexStream->addBuffer(networkMesh._vertexBuffer, clusterWeightsOffset, sizeof(glm::vec4));
2218−
2219− int channelNum = 0;
2220− networkMesh._vertexFormat = std::make_shared<gpu::Stream::Format>();
2221− networkMesh._vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
2222− if (mesh.normals.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
2223− if (mesh.tangents.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
2224− if (mesh.colors.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB));
2225− if (mesh.texCoords.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
2226− if (mesh.clusterIndices.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
2227− if (mesh.clusterWeights.size()) networkMesh._vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
2048+ return networkMesh;
2049+}
22282050
2229− }
2230− }
2051+void NetworkGeometry::modelParseSuccess(FBXGeometry* geometry) {
2052+ // assume owner ship of geometry pointer
2053+ _geometry.reset(geometry);
22312054
2232− _meshes.append(networkMesh);
2055+ foreach(const FBXMesh& mesh, _geometry->meshes) {
2056+ _meshes.emplace_back(buildNetworkMesh(mesh, _textureBaseUrl));
22332057 }
2234−
2235− finishedLoading(true);
2058+
2059+ _state = SuccessState;
2060+ emit onSuccess(*this, *_geometry.get());
2061+
2062+ delete _resource;
2063+ _resource = nullptr;
2064+}
2065+
2066+void NetworkGeometry::modelParseError(int error, QString str) {
2067+ _state = ErrorState;
2068+ emit onFailure(*this, (NetworkGeometry::Error)error);
2069+
2070+ delete _resource;
2071+ _resource = nullptr;
22362072 }
22372073
22382074 bool NetworkMeshPart::isTranslucent() const {
22392075 return diffuseTexture && diffuseTexture->isTranslucent();
22402076 }
22412077
2242−
22432078 bool NetworkMesh::isPartTranslucent(const FBXMesh& fbxMesh, int partIndex) const {
22442079 assert(partIndex >= 0);
2245− assert(partIndex < parts.size());
2246− return (parts.at(partIndex).isTranslucent() || fbxMesh.parts.at(partIndex).opacity != 1.0f);
2080+ assert((size_t)partIndex < _parts.size());
2081+ return (_parts.at(partIndex)->isTranslucent() || fbxMesh.parts.at(partIndex).opacity != 1.0f);
22472082 }
22482083
22492084 int NetworkMesh::getTranslucentPartCount(const FBXMesh& fbxMesh) const {
22502085 int count = 0;
2251− for (int i = 0; i < parts.size(); i++) {
2086+
2087+ for (size_t i = 0; i < _parts.size(); i++) {
22522088 if (isPartTranslucent(fbxMesh, i)) {
22532089 count++;
22542090 }