diff --git a/interface/resources/meshes/defaultAvatar_body.fbx b/interface/resources/meshes/defaultAvatar/body.fbx similarity index 100% rename from interface/resources/meshes/defaultAvatar_body.fbx rename to interface/resources/meshes/defaultAvatar/body.fbx diff --git a/interface/resources/meshes/body.jpg b/interface/resources/meshes/defaultAvatar/body.jpg similarity index 100% rename from interface/resources/meshes/body.jpg rename to interface/resources/meshes/defaultAvatar/body.jpg diff --git a/interface/resources/meshes/defaultAvatar_head.fbx b/interface/resources/meshes/defaultAvatar/head.fbx similarity index 100% rename from interface/resources/meshes/defaultAvatar_head.fbx rename to interface/resources/meshes/defaultAvatar/head.fbx diff --git a/interface/resources/meshes/tail.jpg b/interface/resources/meshes/defaultAvatar/tail.jpg similarity index 100% rename from interface/resources/meshes/tail.jpg rename to interface/resources/meshes/defaultAvatar/tail.jpg diff --git a/interface/resources/meshes/visor.png b/interface/resources/meshes/defaultAvatar/visor.png similarity index 100% rename from interface/resources/meshes/visor.png rename to interface/resources/meshes/defaultAvatar/visor.png diff --git a/interface/resources/meshes/defaultAvatar_body.fst b/interface/resources/meshes/defaultAvatar_body.fst index 3e8fa3ef45..5874c206db 100644 --- a/interface/resources/meshes/defaultAvatar_body.fst +++ b/interface/resources/meshes/defaultAvatar_body.fst @@ -1,3 +1,5 @@ +filename=defaultAvatar/body.fbx +texdir=defaultAvatar scale=130 joint = jointRoot = jointRoot joint = jointLean = jointSpine diff --git a/interface/resources/meshes/defaultAvatar_head.fst b/interface/resources/meshes/defaultAvatar_head.fst index 1352652efc..34cf44f0e4 100644 --- a/interface/resources/meshes/defaultAvatar_head.fst +++ b/interface/resources/meshes/defaultAvatar_head.fst @@ -1,7 +1,7 @@ # faceshift target mapping file name= defaultAvatar_head -filename=../../../Avatars/Jelly/jellyrob_blue.fbx -texdir=../../../Avatars/Jelly +filename=defaultAvatar/head.fbx +texdir=defaultAvatar scale=80 rx=0 ry=0 diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 761ed59db9..c56830de9f 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -345,13 +345,13 @@ bool Avatar::findSphereCollisionWithSkeleton(const glm::vec3& sphereCenter, floa void Avatar::setFaceModelURL(const QUrl &faceModelURL) { AvatarData::setFaceModelURL(faceModelURL); - const QUrl DEFAULT_FACE_MODEL_URL = QUrl::fromLocalFile("resources/meshes/defaultAvatar_head.fbx"); + const QUrl DEFAULT_FACE_MODEL_URL = QUrl::fromLocalFile("resources/meshes/defaultAvatar_head.fst"); _head.getFaceModel().setURL(_faceModelURL, DEFAULT_FACE_MODEL_URL); } void Avatar::setSkeletonModelURL(const QUrl &skeletonModelURL) { AvatarData::setSkeletonModelURL(skeletonModelURL); - const QUrl DEFAULT_SKELETON_MODEL_URL = QUrl::fromLocalFile("resources/meshes/defaultAvatar_body.fbx"); + const QUrl DEFAULT_SKELETON_MODEL_URL = QUrl::fromLocalFile("resources/meshes/defaultAvatar_body.fst"); _skeletonModel.setURL(_skeletonModelURL, DEFAULT_SKELETON_MODEL_URL); } diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index b4e7c4abc5..a0d5f03ae9 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -1568,14 +1568,16 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) return geometry; } -FBXGeometry readFBX(const QByteArray& model, const QByteArray& mapping) { - QBuffer modelBuffer(const_cast<QByteArray*>(&model)); - modelBuffer.open(QIODevice::ReadOnly); +QVariantHash readMapping(const QByteArray& data) { + QBuffer buffer(const_cast<QByteArray*>(&data)); + buffer.open(QIODevice::ReadOnly); + return parseMapping(&buffer); +} - QBuffer mappingBuffer(const_cast<QByteArray*>(&mapping)); - mappingBuffer.open(QIODevice::ReadOnly); - - return extractFBXGeometry(parseFBX(&modelBuffer), parseMapping(&mappingBuffer)); +FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping) { + QBuffer buffer(const_cast<QByteArray*>(&model)); + buffer.open(QIODevice::ReadOnly); + return extractFBXGeometry(parseFBX(&buffer), mapping); } bool addMeshVoxelsOperation(OctreeElement* element, void* extraData) { diff --git a/interface/src/renderer/FBXReader.h b/interface/src/renderer/FBXReader.h index d700439460..5e2b77035f 100644 --- a/interface/src/renderer/FBXReader.h +++ b/interface/src/renderer/FBXReader.h @@ -163,9 +163,12 @@ public: QVector<FBXAttachment> attachments; }; +/// Reads an FST mapping from the supplied data. +QVariantHash readMapping(const QByteArray& data); + /// Reads FBX geometry from the supplied model and mapping data. /// \exception QString if an error occurs in parsing -FBXGeometry readFBX(const QByteArray& model, const QByteArray& mapping); +FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping); /// Reads SVO geometry from the supplied model data. FBXGeometry readSVO(const QByteArray& model); diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index 3526fa5050..dfe6949438 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -7,11 +7,7 @@ #include <cmath> -// include this before QOpenGLBuffer, which includes an earlier version of OpenGL -#include "InterfaceConfig.h" - #include <QNetworkReply> -#include <QOpenGLBuffer> #include <QTimer> #include "Application.h" @@ -304,40 +300,23 @@ QSharedPointer<NetworkGeometry> GeometryCache::getGeometry(const QUrl& url, cons } NetworkGeometry::NetworkGeometry(const QUrl& url, const QSharedPointer<NetworkGeometry>& fallback) : - _modelRequest(url), - _modelReply(NULL), - _mappingReply(NULL), + _request(url), + _reply(NULL), + _textureBase(url), _fallback(fallback), - _attempts(0) -{ + _attempts(0) { + if (!url.isValid()) { return; } - _modelRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); - makeModelRequest(); - - QUrl mappingURL = url; - QString path = url.path(); - mappingURL.setPath(path.left(path.lastIndexOf('.')) + ".fst"); - QNetworkRequest mappingRequest(mappingURL); - mappingRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); - _mappingReply = Application::getInstance()->getNetworkAccessManager()->get(mappingRequest); - - connect(_mappingReply, SIGNAL(downloadProgress(qint64,qint64)), SLOT(maybeReadModelWithMapping())); - connect(_mappingReply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(handleMappingReplyError())); + _request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); + makeRequest(); } NetworkGeometry::~NetworkGeometry() { - if (_modelReply != NULL) { - delete _modelReply; + if (_reply != NULL) { + delete _reply; } - if (_mappingReply != NULL) { - delete _mappingReply; - } - foreach (const NetworkMesh& mesh, _meshes) { - glDeleteBuffers(1, &mesh.indexBufferID); - glDeleteBuffers(1, &mesh.vertexBufferID); - } } glm::vec4 NetworkGeometry::computeAverageColor() const { @@ -364,20 +343,155 @@ glm::vec4 NetworkGeometry::computeAverageColor() const { return (totalTriangles == 0) ? glm::vec4(1.0f, 1.0f, 1.0f, 1.0f) : totalColor / totalTriangles; } -void NetworkGeometry::makeModelRequest() { - _modelReply = Application::getInstance()->getNetworkAccessManager()->get(_modelRequest); +void NetworkGeometry::makeRequest() { + _reply = Application::getInstance()->getNetworkAccessManager()->get(_request); - connect(_modelReply, SIGNAL(downloadProgress(qint64,qint64)), SLOT(maybeReadModelWithMapping())); - connect(_modelReply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(handleModelReplyError())); + connect(_reply, SIGNAL(downloadProgress(qint64,qint64)), SLOT(handleDownloadProgress(qint64,qint64))); + connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(handleReplyError())); } -void NetworkGeometry::handleModelReplyError() { - QDebug debug = qDebug() << _modelReply->errorString(); +void NetworkGeometry::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { + if (!_reply->isFinished()) { + return; + } - QNetworkReply::NetworkError error = _modelReply->error(); - _modelReply->disconnect(this); - _modelReply->deleteLater(); - _modelReply = NULL; + QUrl url = _reply->url(); + QByteArray data = _reply->readAll(); + _reply->disconnect(this); + _reply->deleteLater(); + _reply = NULL; + + if (url.path().toLower().endsWith(".fst")) { + // it's a mapping file; parse it and get the mesh filename + _mapping = readMapping(data); + QString filename = _mapping.value("filename").toString(); + if (filename.isNull()) { + qDebug() << "Mapping file " << url << " has no filename."; + maybeLoadFallback(); + } else { + QString texdir = _mapping.value("texdir").toString(); + if (!texdir.isNull()) { + if (!texdir.endsWith('/')) { + texdir += '/'; + } + _textureBase = url.resolved(texdir); + } + _request.setUrl(url.resolved(filename)); + makeRequest(); + } + return; + } + + try { + _geometry = url.path().toLower().endsWith(".svo") ? readSVO(data) : readFBX(data, _mapping); + + } catch (const QString& error) { + qDebug() << "Error reading " << url << ": " << error; + maybeLoadFallback(); + return; + } + + foreach (const FBXMesh& mesh, _geometry.meshes) { + NetworkMesh networkMesh = { QOpenGLBuffer(QOpenGLBuffer::IndexBuffer), QOpenGLBuffer(QOpenGLBuffer::VertexBuffer) }; + + int totalIndices = 0; + foreach (const FBXMeshPart& part, mesh.parts) { + NetworkMeshPart networkPart; + if (!part.diffuseFilename.isEmpty()) { + networkPart.diffuseTexture = Application::getInstance()->getTextureCache()->getTexture( + _textureBase.resolved(QUrl(part.diffuseFilename)), false, mesh.isEye); + } + if (!part.normalFilename.isEmpty()) { + networkPart.normalTexture = Application::getInstance()->getTextureCache()->getTexture( + _textureBase.resolved(QUrl(part.normalFilename)), true); + } + networkMesh.parts.append(networkPart); + + totalIndices += (part.quadIndices.size() + part.triangleIndices.size()); + } + + networkMesh.indexBuffer.create(); + networkMesh.indexBuffer.bind(); + networkMesh.indexBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw); + networkMesh.indexBuffer.allocate(totalIndices * sizeof(int)); + int offset = 0; + foreach (const FBXMeshPart& part, mesh.parts) { + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, part.quadIndices.size() * sizeof(int), + part.quadIndices.constData()); + offset += part.quadIndices.size() * sizeof(int); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, part.triangleIndices.size() * sizeof(int), + part.triangleIndices.constData()); + offset += part.triangleIndices.size() * sizeof(int); + } + networkMesh.indexBuffer.release(); + + networkMesh.vertexBuffer.create(); + networkMesh.vertexBuffer.bind(); + networkMesh.vertexBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw); + + // if we don't need to do any blending or springing, then the positions/normals can be static + if (mesh.blendshapes.isEmpty() && mesh.springiness == 0.0f) { + int normalsOffset = mesh.vertices.size() * sizeof(glm::vec3); + int tangentsOffset = normalsOffset + mesh.normals.size() * sizeof(glm::vec3); + int colorsOffset = tangentsOffset + mesh.tangents.size() * sizeof(glm::vec3); + int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3); + int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2); + int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4); + + networkMesh.vertexBuffer.allocate(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4)); + networkMesh.vertexBuffer.write(0, mesh.vertices.constData(), mesh.vertices.size() * sizeof(glm::vec3)); + networkMesh.vertexBuffer.write(normalsOffset, mesh.normals.constData(), mesh.normals.size() * sizeof(glm::vec3)); + networkMesh.vertexBuffer.write(tangentsOffset, mesh.tangents.constData(), + mesh.tangents.size() * sizeof(glm::vec3)); + networkMesh.vertexBuffer.write(colorsOffset, mesh.colors.constData(), mesh.colors.size() * sizeof(glm::vec3)); + networkMesh.vertexBuffer.write(texCoordsOffset, mesh.texCoords.constData(), + mesh.texCoords.size() * sizeof(glm::vec2)); + networkMesh.vertexBuffer.write(clusterIndicesOffset, mesh.clusterIndices.constData(), + mesh.clusterIndices.size() * sizeof(glm::vec4)); + networkMesh.vertexBuffer.write(clusterWeightsOffset, mesh.clusterWeights.constData(), + mesh.clusterWeights.size() * sizeof(glm::vec4)); + + // if there's no springiness, then the cluster indices/weights can be static + } else if (mesh.springiness == 0.0f) { + int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3); + int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3); + int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2); + int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4); + networkMesh.vertexBuffer.allocate(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4)); + networkMesh.vertexBuffer.write(0, mesh.tangents.constData(), mesh.tangents.size() * sizeof(glm::vec3)); + networkMesh.vertexBuffer.write(colorsOffset, mesh.colors.constData(), mesh.colors.size() * sizeof(glm::vec3)); + networkMesh.vertexBuffer.write(texCoordsOffset, mesh.texCoords.constData(), + mesh.texCoords.size() * sizeof(glm::vec2)); + networkMesh.vertexBuffer.write(clusterIndicesOffset, mesh.clusterIndices.constData(), + mesh.clusterIndices.size() * sizeof(glm::vec4)); + networkMesh.vertexBuffer.write(clusterWeightsOffset, mesh.clusterWeights.constData(), + mesh.clusterWeights.size() * sizeof(glm::vec4)); + + } else { + int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3); + int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3); + networkMesh.vertexBuffer.allocate(texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2)); + networkMesh.vertexBuffer.write(0, mesh.tangents.constData(), mesh.tangents.size() * sizeof(glm::vec3)); + networkMesh.vertexBuffer.write(colorsOffset, mesh.colors.constData(), mesh.colors.size() * sizeof(glm::vec3)); + networkMesh.vertexBuffer.write(texCoordsOffset, mesh.texCoords.constData(), + mesh.texCoords.size() * sizeof(glm::vec2)); + } + + networkMesh.vertexBuffer.release(); + + _meshes.append(networkMesh); + } + + emit loaded(); +} + +void NetworkGeometry::handleReplyError() { + QDebug debug = qDebug() << _reply->errorString(); + + QNetworkReply::NetworkError error = _reply->error(); + _reply->disconnect(this); + _reply->deleteLater(); + _reply = NULL; // retry for certain types of failures switch (error) { @@ -394,7 +508,7 @@ void NetworkGeometry::handleModelReplyError() { const int MAX_ATTEMPTS = 8; const int BASE_DELAY_MS = 1000; if (++_attempts < MAX_ATTEMPTS) { - QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, SLOT(makeModelRequest())); + QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, SLOT(makeRequest())); debug << " -- retrying..."; return; } @@ -407,135 +521,6 @@ void NetworkGeometry::handleModelReplyError() { } -void NetworkGeometry::handleMappingReplyError() { - _mappingReply->disconnect(this); - _mappingReply->deleteLater(); - _mappingReply = NULL; - - maybeReadModelWithMapping(); -} - -void NetworkGeometry::maybeReadModelWithMapping() { - if (_modelReply == NULL || !_modelReply->isFinished() || (_mappingReply != NULL && !_mappingReply->isFinished())) { - return; - } - - QUrl url = _modelReply->url(); - QByteArray model = _modelReply->readAll(); - _modelReply->disconnect(this); - _modelReply->deleteLater(); - _modelReply = NULL; - - QByteArray mapping; - if (_mappingReply != NULL) { - mapping = _mappingReply->readAll(); - _mappingReply->disconnect(this); - _mappingReply->deleteLater(); - _mappingReply = NULL; - } - - try { - _geometry = url.path().toLower().endsWith(".svo") ? readSVO(model) : readFBX(model, mapping); - - } catch (const QString& error) { - qDebug() << "Error reading " << url << ": " << error; - maybeLoadFallback(); - return; - } - - foreach (const FBXMesh& mesh, _geometry.meshes) { - NetworkMesh networkMesh; - - int totalIndices = 0; - foreach (const FBXMeshPart& part, mesh.parts) { - NetworkMeshPart networkPart; - QString basePath = url.path(); - basePath = basePath.left(basePath.lastIndexOf('/') + 1); - if (!part.diffuseFilename.isEmpty()) { - url.setPath(basePath + part.diffuseFilename); - networkPart.diffuseTexture = Application::getInstance()->getTextureCache()->getTexture(url, false, mesh.isEye); - } - if (!part.normalFilename.isEmpty()) { - url.setPath(basePath + part.normalFilename); - networkPart.normalTexture = Application::getInstance()->getTextureCache()->getTexture(url, true); - } - networkMesh.parts.append(networkPart); - - totalIndices += (part.quadIndices.size() + part.triangleIndices.size()); - } - - glGenBuffers(1, &networkMesh.indexBufferID); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, networkMesh.indexBufferID); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, totalIndices * sizeof(int), NULL, GL_STATIC_DRAW); - int offset = 0; - foreach (const FBXMeshPart& part, mesh.parts) { - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, part.quadIndices.size() * sizeof(int), - part.quadIndices.constData()); - offset += part.quadIndices.size() * sizeof(int); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, part.triangleIndices.size() * sizeof(int), - part.triangleIndices.constData()); - offset += part.triangleIndices.size() * sizeof(int); - } - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - glGenBuffers(1, &networkMesh.vertexBufferID); - glBindBuffer(GL_ARRAY_BUFFER, networkMesh.vertexBufferID); - - // if we don't need to do any blending or springing, then the positions/normals can be static - if (mesh.blendshapes.isEmpty() && mesh.springiness == 0.0f) { - int normalsOffset = mesh.vertices.size() * sizeof(glm::vec3); - int tangentsOffset = normalsOffset + mesh.normals.size() * sizeof(glm::vec3); - int colorsOffset = tangentsOffset + mesh.tangents.size() * sizeof(glm::vec3); - int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3); - int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2); - int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4); - glBufferData(GL_ARRAY_BUFFER, clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4), - NULL, GL_STATIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, mesh.vertices.size() * sizeof(glm::vec3), mesh.vertices.constData()); - glBufferSubData(GL_ARRAY_BUFFER, normalsOffset, mesh.normals.size() * sizeof(glm::vec3), mesh.normals.constData()); - glBufferSubData(GL_ARRAY_BUFFER, tangentsOffset, mesh.tangents.size() * sizeof(glm::vec3), mesh.tangents.constData()); - glBufferSubData(GL_ARRAY_BUFFER, colorsOffset, mesh.colors.size() * sizeof(glm::vec3), mesh.colors.constData()); - glBufferSubData(GL_ARRAY_BUFFER, texCoordsOffset, mesh.texCoords.size() * sizeof(glm::vec2), - mesh.texCoords.constData()); - glBufferSubData(GL_ARRAY_BUFFER, clusterIndicesOffset, mesh.clusterIndices.size() * sizeof(glm::vec4), - mesh.clusterIndices.constData()); - glBufferSubData(GL_ARRAY_BUFFER, clusterWeightsOffset, mesh.clusterWeights.size() * sizeof(glm::vec4), - mesh.clusterWeights.constData()); - - // if there's no springiness, then the cluster indices/weights can be static - } else if (mesh.springiness == 0.0f) { - int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3); - int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3); - int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2); - int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4); - glBufferData(GL_ARRAY_BUFFER, clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4), - NULL, GL_STATIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, mesh.tangents.size() * sizeof(glm::vec3), mesh.tangents.constData()); - glBufferSubData(GL_ARRAY_BUFFER, colorsOffset, mesh.colors.size() * sizeof(glm::vec3), mesh.colors.constData()); - glBufferSubData(GL_ARRAY_BUFFER, texCoordsOffset, mesh.texCoords.size() * sizeof(glm::vec2), mesh.texCoords.constData()); - glBufferSubData(GL_ARRAY_BUFFER, clusterIndicesOffset, mesh.clusterIndices.size() * sizeof(glm::vec4), - mesh.clusterIndices.constData()); - glBufferSubData(GL_ARRAY_BUFFER, clusterWeightsOffset, mesh.clusterWeights.size() * sizeof(glm::vec4), - mesh.clusterWeights.constData()); - - } else { - int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3); - int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3); - glBufferData(GL_ARRAY_BUFFER, texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2), NULL, GL_STATIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, mesh.tangents.size() * sizeof(glm::vec3), mesh.tangents.constData()); - glBufferSubData(GL_ARRAY_BUFFER, colorsOffset, mesh.colors.size() * sizeof(glm::vec3), mesh.colors.constData()); - glBufferSubData(GL_ARRAY_BUFFER, texCoordsOffset, mesh.texCoords.size() * sizeof(glm::vec2), - mesh.texCoords.constData()); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - - _meshes.append(networkMesh); - } - - emit loaded(); -} - void NetworkGeometry::loadFallback() { _geometry = _fallback->_geometry; _meshes = _fallback->_meshes; diff --git a/interface/src/renderer/GeometryCache.h b/interface/src/renderer/GeometryCache.h index 618796e907..0587831721 100644 --- a/interface/src/renderer/GeometryCache.h +++ b/interface/src/renderer/GeometryCache.h @@ -9,17 +9,19 @@ #ifndef __interface__GeometryCache__ #define __interface__GeometryCache__ +// include this before QOpenGLBuffer, which includes an earlier version of OpenGL +#include "InterfaceConfig.h" + #include <QHash> #include <QNetworkRequest> #include <QObject> +#include <QOpenGLBuffer> #include <QSharedPointer> #include <QWeakPointer> #include "FBXReader.h" -#include "InterfaceConfig.h" class QNetworkReply; -class QOpenGLBuffer; class NetworkGeometry; class NetworkMesh; @@ -76,19 +78,19 @@ signals: private slots: - void makeModelRequest(); - void handleModelReplyError(); - void handleMappingReplyError(); - void maybeReadModelWithMapping(); + void makeRequest(); + void handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); + void handleReplyError(); void loadFallback(); private: void maybeLoadFallback(); - QNetworkRequest _modelRequest; - QNetworkReply* _modelReply; - QNetworkReply* _mappingReply; + QNetworkRequest _request; + QNetworkReply* _reply; + QVariantHash _mapping; + QUrl _textureBase; QSharedPointer<NetworkGeometry> _fallback; int _attempts; @@ -110,8 +112,8 @@ public: class NetworkMesh { public: - GLuint indexBufferID; - GLuint vertexBufferID; + QOpenGLBuffer indexBuffer; + QOpenGLBuffer vertexBuffer; QVector<NetworkMeshPart> parts; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index b14ed1036d..095429f201 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -768,13 +768,13 @@ void Model::renderMeshes(float alpha, bool translucent) { (networkMesh.getTranslucentPartCount() == networkMesh.parts.size())) { continue; } - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, networkMesh.indexBufferID); - + const_cast<QOpenGLBuffer&>(networkMesh.indexBuffer).bind(); + const FBXMesh& mesh = geometry.meshes.at(i); int vertexCount = mesh.vertices.size(); - glBindBuffer(GL_ARRAY_BUFFER, networkMesh.vertexBufferID); - + const_cast<QOpenGLBuffer&>(networkMesh.vertexBuffer).bind(); + ProgramObject* program = &_program; ProgramObject* skinProgram = &_skinProgram; SkinLocations* skinLocations = &_skinLocations;