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
14#include <cmath>14#include <cmath>
15 15
16#include <QNetworkReply>16#include <QNetworkReply>
17#include <QRunnable>
18#include <QThreadPool>17#include <QThreadPool>
19 18
20#include <FSTReader.h>19#include <FSTReader.h>
@@ -50,6 +49,13 @@ GeometryCache::~GeometryCache() { · 29 unmodified lines
50 #endif //def WANT_DEBUG49 #endif //def WANT_DEBUG
51}50}
52 51
52QSharedPointer<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
53const int NUM_VERTICES_PER_TRIANGLE = 3;59const int NUM_VERTICES_PER_TRIANGLE = 3;
54const int NUM_TRIANGLES_PER_QUAD = 2;60const int NUM_TRIANGLES_PER_QUAD = 2;
55const int NUM_VERTICES_PER_TRIANGULATED_QUAD = NUM_VERTICES_PER_TRIANGLE * NUM_TRIANGLES_PER_QUAD;61const 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
1643 batch.draw(gpu::LINES, 2, 0);1649 batch.draw(gpu::LINES, 2, 0);
1644}1650}
1645 1651
1646
1647QSharedPointer<NetworkGeometry> GeometryCache::getGeometry(const QUrl& url, const QUrl& fallback, bool delayLoad) {
1648 return getResource(url, fallback, delayLoad, NULL).staticCast<NetworkGeometry>();
1649}
1650
1651QSharedPointer<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
1659void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) {1652void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) {
1660 if (!_standardDrawPipeline) {1653 if (!_standardDrawPipeline) {
1661 auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)));1654 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
1685 }1678 }
1686}1679}
1687 1680
1688const float NetworkGeometry::NO_HYSTERESIS = -1.0f;1681GeometryReader::GeometryReader(const QUrl& url, QNetworkReply* reply, const QVariantHash& mapping) :
1689 1682 _url(url),
1690NetworkGeometry::NetworkGeometry(const QUrl& url, const QSharedPointer<NetworkGeometry>& fallback, bool delayLoad,1683 _reply(reply),
1691 const QVariantHash& mapping, const QUrl& textureBase) :1684 _mapping(mapping) {
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);
1715}1685}
1716 1686
1717bool NetworkGeometry::isLoadedWithTextures() const {1687void GeometryReader::run() {
1718 if (!isLoaded()) {1688 try {
1719 return false;1689 if (!_reply) {
1720 }1690 throw QString("Reply is NULL ?!");
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 }
1731 }1691 }
1732 _isLoadedWithTextures = true;1692 QString urlname = _url.path().toLower();
1733 }1693 bool urlValid = true;
1734 return true;1694 urlValid &= !urlname.isEmpty();
1735}1695 urlValid &= !_url.path().isEmpty();
1696 urlValid &= _url.path().toLower().endsWith(".fbx") || _url.path().toLower().endsWith(".obj");
1736 1697
1737QSharedPointer<NetworkGeometry> NetworkGeometry::getLODOrFallback(float distance, float& hysteresis, bool delayLoad) const {1698 if (urlValid) {
1738 if (_lodParent.data() != this) {1699 // Let's read the binaries from the network
1739 return _lodParent.data()->getLODOrFallback(distance, hysteresis, delayLoad);1700 FBXGeometry* fbxgeo = nullptr;
1740 }1701 if (_url.path().toLower().endsWith(".fbx")) {
1741 if (_failedToLoad && _fallback) {1702 const bool grabLightmaps = true;
1742 return _fallback;1703 const float lightmapLevel = 1.0f;
1743 }1704 fbxgeo = readFBX(_reply, _mapping, _url.path(), grabLightmaps, lightmapLevel);
1744 QSharedPointer<NetworkGeometry> lod = _lodParent;1705 } else if (_url.path().toLower().endsWith(".obj")) {
1745 float lodDistance = 0.0f;1706 fbxgeo = OBJReader().readOBJ(_reply, _mapping, &_url);
1746 QMap<float, QSharedPointer<NetworkGeometry> >::const_iterator it = _lods.upperBound(distance);1707 } else {
1747 if (it != _lods.constBegin()) {1708 QString errorStr("usupported format");
1748 it = it - 1;1709 emit onError(NetworkGeometry::ModelParseError, errorStr);
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();
1763 }1710 }
1711 emit onSuccess(fbxgeo);
1712 } else {
1713 throw QString("url is invalid");
1764 }1714 }
1715
1716 } catch (const QString& error) {
1717 qCDebug(renderutils) << "Error reading " << _url << ": " << error;
1718 emit onError(NetworkGeometry::ModelParseError, error);
1765 }1719 }
1766 if (lod && lod->isLoaded()) {1720 _reply->deleteLater();
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;
1788}1721}
1789 1722
1790uint qHash(const QWeakPointer<Animation>& animation, uint seed = 0) {1723NetworkGeometry::NetworkGeometry(const QUrl& url, bool delayLoad, const QVariantHash& mapping, const QUrl& textureBaseUrl) :
1791 return qHash(animation.data(), seed);1724 _url(url),
1725 _mapping(mapping),
1726 _textureBaseUrl(textureBaseUrl) {
1727
1728 if (delayLoad) {
1729 _state = DelayState;
1730 } else {
1731 attemptRequestInternal();
1732 }
1792}1733}
1793 1734
1794QVector<int> NetworkGeometry::getJointMappings(const AnimationPointer& animation) {1735NetworkGeometry::~NetworkGeometry() {
1795 QVector<int> mappings = _jointMappings.value(animation);1736 if (_resource) {
1796 if (mappings.isEmpty() && isLoaded() && animation && animation->isLoaded()) {1737 _resource->deleteLater();
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);
1802 }1738 }
1803 return mappings;
1804}1739}
1805 1740
1806void NetworkGeometry::setLoadPriority(const QPointer<QObject>& owner, float priority) {1741void NetworkGeometry::attemptRequest() {
1807 Resource::setLoadPriority(owner, priority);1742 if (_state == DelayState) {
1808 1743 attemptRequestInternal();
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 }
1826 }1744 }
1827}1745}
1828 1746
1829void NetworkGeometry::setLoadPriorities(const QHash<QPointer<QObject>, float>& priorities) {1747void NetworkGeometry::attemptRequestInternal() {
1830 Resource::setLoadPriorities(priorities);1748 if (_url.path().toLower().endsWith(".fst")) {
1831 1749 requestMapping(_url);
1832 for (int i = 0; i < _meshes.size(); i++) {1750 } else {
1833 NetworkMesh& mesh = _meshes[i];1751 requestModel(_url);
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 }
1849 }1752 }
1850}1753}
1851 1754
1852void NetworkGeometry::clearLoadPriority(const QPointer<QObject>& owner) {1755bool NetworkGeometry::isLoaded() const {
1853 Resource::clearLoadPriority(owner);1756 return _state == SuccessState;
1854 1757}
1855 for (int i = 0; i < _meshes.size(); i++) {1758
1856 NetworkMesh& mesh = _meshes[i];1759bool NetworkGeometry::isLoadedWithTextures() const {
1857 for (int j = 0; j < mesh.parts.size(); j++) {1760 if (!isLoaded()) {
1858 NetworkMeshPart& part = mesh.parts[j];1761 return false;
1859 if (part.diffuseTexture) {1762 }
1860 part.diffuseTexture->clearLoadPriority(owner);1763 if (!_isLoadedWithTextures) {
1861 }1764 for (auto&& mesh : _meshes) {
1862 if (part.normalTexture) {1765 for (auto && part : mesh->_parts) {
1863 part.normalTexture->clearLoadPriority(owner);1766 if ((part->diffuseTexture && !part->diffuseTexture->isLoaded()) ||
1864 }1767 (part->normalTexture && !part->normalTexture->isLoaded()) ||
1865 if (part.specularTexture) {1768 (part->specularTexture && !part->specularTexture->isLoaded()) ||
1866 part.specularTexture->clearLoadPriority(owner);1769 (part->emissiveTexture && !part->emissiveTexture->isLoaded())) {
1867 }1770 return false;
1868 if (part.emissiveTexture) {1771 }
1869 part.emissiveTexture->clearLoadPriority(owner);
1870 }1772 }
1871 }1773 }
1774 _isLoadedWithTextures = true;
1872 }1775 }
1776 return true;
1873}1777}
1874 1778
1875void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& url) {1779void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& url) {
1876 if (_meshes.size() > 0) {1780 if (_meshes.size() > 0) {
1877 auto textureCache = DependencyManager::get<TextureCache>();1781 auto textureCache = DependencyManager::get<TextureCache>();
1878 for (int i = 0; i < _meshes.size(); i++) {1782 for (size_t i = 0; i < _meshes.size(); i++) {
1879 NetworkMesh& mesh = _meshes[i];1783 NetworkMesh& mesh = *(_meshes[i].get());
1880 for (int j = 0; j < mesh.parts.size(); j++) {1784 for (size_t j = 0; j < mesh._parts.size(); j++) {
1881 NetworkMeshPart& part = mesh.parts[j];1785 NetworkMeshPart& part = *(mesh._parts[j].get());
1882
1883 QSharedPointer<NetworkTexture> matchingTexture = QSharedPointer<NetworkTexture>();1786 QSharedPointer<NetworkTexture> matchingTexture = QSharedPointer<NetworkTexture>();
1884 if (part.diffuseTextureName == name) {1787 if (part.diffuseTextureName == name) {
1885 part.diffuseTexture = textureCache->getTexture(url, DEFAULT_TEXTURE, _geometry.meshes[i].isEye);1788 part.diffuseTexture = textureCache->getTexture(url, DEFAULT_TEXTURE, _geometry->meshes[i].isEye);
1886 part.diffuseTexture->setLoadPriorities(_loadPriorities);
1887 } else if (part.normalTextureName == name) {1789 } else if (part.normalTextureName == name) {
1888 part.normalTexture = textureCache->getTexture(url);1790 part.normalTexture = textureCache->getTexture(url);
1889 part.normalTexture->setLoadPriorities(_loadPriorities);
1890 } else if (part.specularTextureName == name) {1791 } else if (part.specularTextureName == name) {
1891 part.specularTexture = textureCache->getTexture(url);1792 part.specularTexture = textureCache->getTexture(url);
1892 part.specularTexture->setLoadPriorities(_loadPriorities);
1893 } else if (part.emissiveTextureName == name) {1793 } else if (part.emissiveTextureName == name) {
1894 part.emissiveTexture = textureCache->getTexture(url);1794 part.emissiveTexture = textureCache->getTexture(url);
1895 part.emissiveTexture->setLoadPriorities(_loadPriorities);
1896 }1795 }
1897 }1796 }
1898 }1797 }
1899 } else {1798 } else {
1900 qCDebug(renderutils) << "Adding a name url pair to pending" << name << url;1799 qCWarning(renderutils) << "Ignoring setTextureWirthNameToURL() geometry not ready." << name << url;
1901 // we don't have meshes downloaded yet, so hold this texture as pending
1902 _pendingTextureChanges.insert(name, url);
1903 }1800 }
1904 _isLoadedWithTextures = false;1801 _isLoadedWithTextures = false;
1905}1802}
1906 1803
1907QStringList NetworkGeometry::getTextureNames() const {1804QStringList NetworkGeometry::getTextureNames() const {
1908 QStringList result;1805 QStringList result;
1909 for (int i = 0; i < _meshes.size(); i++) {1806 for (size_t i = 0; i < _meshes.size(); i++) {
1910 const NetworkMesh& mesh = _meshes[i];1807 const NetworkMesh& mesh = *(_meshes[i].get());
1911 for (int j = 0; j < mesh.parts.size(); j++) {1808 for (size_t j = 0; j < mesh._parts.size(); j++) {
1912 const NetworkMeshPart& part = mesh.parts[j];1809 const NetworkMeshPart& part = *(mesh._parts[j].get());
1913 1810
1914 if (!part.diffuseTextureName.isEmpty() && part.diffuseTexture) {1811 if (!part.diffuseTextureName.isEmpty() && part.diffuseTexture) {
1915 QString textureURL = part.diffuseTexture->getURL().toString();1812 QString textureURL = part.diffuseTexture->getURL().toString();
1916 result << part.diffuseTextureName + ":" + textureURL;1813 result << part.diffuseTextureName + ":" + textureURL;
@@ -1935,320 +1832,259 @@ QStringList NetworkGeometry::getTextureNames() const { · 18 unmodified lines
1935 return result;1832 return result;
1936}1833}
1937 1834
1938void NetworkGeometry::replaceTexturesWithPendingChanges() {1835void NetworkGeometry::requestMapping(const QUrl& url) {
1939 QHash<QString, QUrl>::Iterator it = _pendingTextureChanges.begin();1836 _state = RequestMappingState;
1940 1837 if (_resource) {
1941 while (it != _pendingTextureChanges.end()) {1838 _resource->deleteLater();
1942 setTextureWithNameToURL(it.key(), it.value());
1943 it = _pendingTextureChanges.erase(it);
1944 }1839 }
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)));
1945}1843}
1946 1844
1947/// Reads geometry in a worker thread.1845void NetworkGeometry::requestModel(const QUrl& url) {
1948class GeometryReader : public QRunnable {1846 _state = RequestModelState;
1949public:1847 if (_resource) {
1950 1848 _resource->deleteLater();
1951 GeometryReader(const QWeakPointer<Resource>& geometry, const QUrl& url,1849 }
1952 QNetworkReply* reply, const QVariantHash& mapping);1850 _resource = new Resource(url, false);
1953 1851 connect(_resource, SIGNAL(loaded(QNetworkReply&)), SLOT(modelRequestDone(QNetworkReply&)));
1954 virtual void run();1852 connect(_resource, SIGNAL(failed(QNetworkReply::NetworkError)), SLOT(modelRequestError(QNetworkReply::NetworkError)));
1955
1956private:
1957
1958 QWeakPointer<Resource> _geometry;
1959 QUrl _url;
1960 QNetworkReply* _reply;
1961 QVariantHash _mapping;
1962};
1963
1964GeometryReader::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) {
1970}1853}
1971 1854
1972void GeometryReader::run() {1855void NetworkGeometry::mappingRequestDone(QNetworkReply& reply) {
1973 QSharedPointer<Resource> geometry = _geometry.toStrongRef();1856 assert(_state == RequestMappingState);
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");
1989 1857
1990 if (urlValid) {1858 // parse the mapping file
1991 // Let's read the binaries from the network1859 _mapping = FSTReader::readMapping(reply.readAll());
1992 FBXGeometry fbxgeo;1860
1993 if (_url.path().toLower().endsWith(".fbx")) {1861 QUrl replyUrl = reply.url();
1994 bool grabLightmaps = true;1862 QString modelUrlStr = _mapping.value("filename").toString();
1995 float lightmapLevel = 1.0f;1863 if (modelUrlStr.isNull()) {
1996 // HACK: For monday 12/01/2014 we need to kill lighmaps loading in starchamber...1864 qCDebug(renderutils) << "Mapping file " << _url << "has no \"filename\" entry";
1997 if (_url.path().toLower().endsWith("loungev4_11-18.fbx")) {1865 emit onFailure(*this, MissingFilenameInMapping);
1998 grabLightmaps = false;1866 } else {
1999 } else if (_url.path().toLower().endsWith("apt8_reboot.fbx")) {1867 // read _textureBase from mapping file, if present
2000 lightmapLevel = 4.0f;1868 QString texdir = _mapping.value("texdir").toString();
2001 } else if (_url.path().toLower().endsWith("palaceoforinthilian4.fbx")) {1869 if (!texdir.isNull()) {
2002 lightmapLevel = 3.5f;1870 if (!texdir.endsWith('/')) {
2003 }1871 texdir += '/';
2004 fbxgeo = readFBX(_reply, _mapping, _url.path(), grabLightmaps, lightmapLevel);
2005 } else if (_url.path().toLower().endsWith(".obj")) {
2006 fbxgeo = OBJReader().readOBJ(_reply, _mapping, &_url);
2007 }1872 }
2008 QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&, fbxgeo));1873 _textureBaseUrl = replyUrl.resolved(texdir);
2009 } else {
2010 throw QString("url is invalid");
2011 }1874 }
2012 1875
2013 } catch (const QString& error) {1876 QUrl modelUrl = replyUrl.resolved(modelUrlStr);
2014 qCDebug(renderutils) << "Error reading " << _url << ": " << error;1877 requestModel(modelUrl);
2015 QMetaObject::invokeMethod(geometry.data(), "finishedLoading", Q_ARG(bool, false));
2016 }1878 }
2017 _reply->deleteLater();
2018}1879}
2019 1880
2020void NetworkGeometry::init() {1881void NetworkGeometry::mappingRequestError(QNetworkReply::NetworkError error) {
2021 _mapping = QVariantHash();1882 assert(_state == RequestMappingState);
2022 _geometry = FBXGeometry();1883 _state = ErrorState;
2023 _meshes.clear();1884 emit onFailure(*this, MappingRequestError);
2024 _lods.clear();
2025 _pendingTextureChanges.clear();
2026 _request.setUrl(_url);
2027 Resource::init();
2028}1885}
2029 1886
2030void NetworkGeometry::downloadFinished(QNetworkReply* reply) {1887void NetworkGeometry::modelRequestDone(QNetworkReply& reply) {
2031 QUrl url = reply->url();1888 assert(_state == RequestModelState);
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}
2071 1889
2072void NetworkGeometry::reinsert() {1890 _state = ParsingModelState;
2073 Resource::reinsert();1891
2074 1892 // asynchronously parse the model file.
2075 _lodParent = qWeakPointerCast<NetworkGeometry, Resource>(_self);1893 GeometryReader* geometryReader = new GeometryReader(reply.url(), &reply, _mapping);
2076 foreach (const QSharedPointer<NetworkGeometry>& lod, _lods) {1894 connect(geometryReader, SIGNAL(onSuccess(FBXGeometry*)), SLOT(modelParseSuccess(FBXGeometry*)));
2077 lod->setLODParent(_lodParent);1895 connect(geometryReader, SIGNAL(onError(int, QString)), SLOT(modelParseError(int, QString)));
2078 }1896
1897 QThreadPool::globalInstance()->start(geometryReader);
2079}1898}
2080 1899
2081void NetworkGeometry::setGeometry(const FBXGeometry& geometry) {1900void NetworkGeometry::modelRequestError(QNetworkReply::NetworkError error) {
2082 _geometry = geometry;1901 assert(_state == RequestModelState);
1902 _state = ErrorState;
1903 emit onFailure(*this, ModelRequestError);
1904}
2083 1905
1906static NetworkMesh* buildNetworkMesh(const FBXMesh& mesh, const QUrl& textureBaseUrl) {
2084 auto textureCache = DependencyManager::get<TextureCache>();1907 auto textureCache = DependencyManager::get<TextureCache>();
2085 1908 NetworkMesh* networkMesh = new NetworkMesh();
2086 foreach (const FBXMesh& mesh, _geometry.meshes) {1909
2087 NetworkMesh networkMesh;1910 int totalIndices = 0;
2088 1911 bool checkForTexcoordLightmap = false;
2089 int totalIndices = 0;1912
2090 bool checkForTexcoordLightmap = false;1913 // process network parts
2091 foreach (const FBXMeshPart& part, mesh.parts) {1914 foreach (const FBXMeshPart& part, mesh.parts) {
2092 NetworkMeshPart networkPart;1915 NetworkMeshPart* networkPart = new NetworkMeshPart();
2093 if (!part.diffuseTexture.filename.isEmpty()) {1916
2094 networkPart.diffuseTexture = textureCache->getTexture(1917 if (!part.diffuseTexture.filename.isEmpty()) {
2095 _textureBase.resolved(QUrl(part.diffuseTexture.filename)), DEFAULT_TEXTURE,1918 networkPart->diffuseTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(part.diffuseTexture.filename)), DEFAULT_TEXTURE,
2096 mesh.isEye, part.diffuseTexture.content);1919 mesh.isEye, part.diffuseTexture.content);
2097 networkPart.diffuseTextureName = part.diffuseTexture.name;1920 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());
2125 }1921 }
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 }
2126 1956
2127 {1957 // initialize vertex buffer
2128 networkMesh._indexBuffer = std::make_shared<gpu::Buffer>();1958 {
2129 networkMesh._indexBuffer->resize(totalIndices * sizeof(int));1959 networkMesh->_vertexBuffer = std::make_shared<gpu::Buffer>();
2130 int offset = 0;1960 // if we don't need to do any blending, the positions/normals can be static
2131 foreach(const FBXMeshPart& part, mesh.parts) {1961 if (mesh.blendshapes.isEmpty()) {
2132 networkMesh._indexBuffer->setSubData(offset, part.quadIndices.size() * sizeof(int),1962 int normalsOffset = mesh.vertices.size() * sizeof(glm::vec3);
2133 (gpu::Byte*) part.quadIndices.constData());1963 int tangentsOffset = normalsOffset + mesh.normals.size() * sizeof(glm::vec3);
2134 offset += part.quadIndices.size() * sizeof(int);1964 int colorsOffset = tangentsOffset + mesh.tangents.size() * sizeof(glm::vec3);
2135 networkMesh._indexBuffer->setSubData(offset, part.triangleIndices.size() * sizeof(int),1965 int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
2136 (gpu::Byte*) part.triangleIndices.constData());1966 int texCoords1Offset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
2137 offset += part.triangleIndices.size() * sizeof(int);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));
2138 }2009 }
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));
2139 }2012 }
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 }
2140 2047
2141 {2048 return networkMesh;
2142 networkMesh._vertexBuffer = std::make_shared<gpu::Buffer>();2049}
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));
2228 2050
2229 }2051void NetworkGeometry::modelParseSuccess(FBXGeometry* geometry) {
2230 }2052 // assume owner ship of geometry pointer
2053 _geometry.reset(geometry);
2231 2054
2232 _meshes.append(networkMesh);2055 foreach(const FBXMesh& mesh, _geometry->meshes) {
2056 _meshes.emplace_back(buildNetworkMesh(mesh, _textureBaseUrl));
2233 }2057 }
2234 2058
2235 finishedLoading(true);2059 _state = SuccessState;
2060 emit onSuccess(*this, *_geometry.get());
2061
2062 delete _resource;
2063 _resource = nullptr;
2064}
2065
2066void NetworkGeometry::modelParseError(int error, QString str) {
2067 _state = ErrorState;
2068 emit onFailure(*this, (NetworkGeometry::Error)error);
2069
2070 delete _resource;
2071 _resource = nullptr;
2236}2072}
2237 2073
2238bool NetworkMeshPart::isTranslucent() const {2074bool NetworkMeshPart::isTranslucent() const {
2239 return diffuseTexture && diffuseTexture->isTranslucent();2075 return diffuseTexture && diffuseTexture->isTranslucent();
2240}2076}
2241 2077
2242
2243bool NetworkMesh::isPartTranslucent(const FBXMesh& fbxMesh, int partIndex) const {2078bool NetworkMesh::isPartTranslucent(const FBXMesh& fbxMesh, int partIndex) const {
2244 assert(partIndex >= 0);2079 assert(partIndex >= 0);
2245 assert(partIndex < parts.size());2080 assert((size_t)partIndex < _parts.size());
2246 return (parts.at(partIndex).isTranslucent() || fbxMesh.parts.at(partIndex).opacity != 1.0f);2081 return (_parts.at(partIndex)->isTranslucent() || fbxMesh.parts.at(partIndex).opacity != 1.0f);
2247}2082}
2248 2083
2249int NetworkMesh::getTranslucentPartCount(const FBXMesh& fbxMesh) const {2084int NetworkMesh::getTranslucentPartCount(const FBXMesh& fbxMesh) const {
2250 int count = 0;2085 int count = 0;
2251 for (int i = 0; i < parts.size(); i++) {2086
2087 for (size_t i = 0; i < _parts.size(); i++) {
2252 if (isPartTranslucent(fbxMesh, i)) {2088 if (isPartTranslucent(fbxMesh, i)) {
2253 count++;2089 count++;
2254 }2090 }