diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7be8582cdc..d90c82e6ca 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -208,6 +209,9 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _window->setMenuBar(Menu::getInstance()); _networkAccessManager = new QNetworkAccessManager(this); + QNetworkDiskCache* cache = new QNetworkDiskCache(_networkAccessManager); + cache->setCacheDirectory("interfaceCache"); + _networkAccessManager->setCache(cache); QRect available = desktop()->availableGeometry(); _window->resize(available.size()); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 57a754cae1..1d50416b73 100755 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -699,6 +699,10 @@ void Avatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) { SKIN_COLOR[1] - _bodyBall[b].touchForce * 0.2f, SKIN_COLOR[2] - _bodyBall[b].touchForce * 0.1f); + if (b == BODY_BALL_NECK_BASE && _head.getBlendFace().isActive()) { + continue; // don't render the neck if we have a face model + } + if ((b != BODY_BALL_HEAD_TOP ) && (b != BODY_BALL_HEAD_BASE )) { glPushMatrix(); diff --git a/interface/src/avatar/BlendFace.cpp b/interface/src/avatar/BlendFace.cpp index 15e70bef82..4bd0c0d7da 100644 --- a/interface/src/avatar/BlendFace.cpp +++ b/interface/src/avatar/BlendFace.cpp @@ -118,7 +118,9 @@ void BlendFace::setModelURL(const QUrl& url) { if (!url.isValid()) { return; } - _modelReply = Application::getInstance()->getNetworkAccessManager()->get(QNetworkRequest(url)); + QNetworkRequest request(url); + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); + _modelReply = Application::getInstance()->getNetworkAccessManager()->get(request); connect(_modelReply, SIGNAL(downloadProgress(qint64,qint64)), SLOT(handleModelDownloadProgress(qint64,qint64))); connect(_modelReply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(handleModelReplyError())); } @@ -163,7 +165,7 @@ void BlendFace::setRig(const fsMsgRig& rig) { } void BlendFace::handleModelDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { - if (bytesReceived < bytesTotal) { + if (bytesReceived < bytesTotal && !_modelReply->isFinished()) { return; } diff --git a/interface/src/avatar/BlendFace.h b/interface/src/avatar/BlendFace.h index 937d696edf..5e98650e12 100644 --- a/interface/src/avatar/BlendFace.h +++ b/interface/src/avatar/BlendFace.h @@ -30,6 +30,8 @@ public: BlendFace(Head* owningHead); ~BlendFace(); + bool isActive() const { return _iboID != 0; } + bool render(float alpha); Q_INVOKABLE void setModelURL(const QUrl& url); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 342a9945ef..16718948f0 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -567,6 +567,10 @@ void MyAvatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) { alpha); } + if (b == BODY_BALL_NECK_BASE && _head.getBlendFace().isActive()) { + continue; // don't render the neck if we have a face model + } + if ((b != BODY_BALL_HEAD_TOP ) && (b != BODY_BALL_HEAD_BASE )) { glPushMatrix(); diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 8398ba2513..b23f7fee35 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -272,7 +272,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) { if (object.properties.at(2) == "Mesh") { FBXGeometry mesh; - QVector vertices; + QVector normals; QVector polygonIndices; foreach (const FBXNode& data, object.children) { if (data.name == "Vertices") { @@ -284,12 +284,19 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) { } else if (data.name == "LayerElementNormal") { foreach (const FBXNode& subdata, data.children) { if (subdata.name == "Normals") { - mesh.normals = createVec3Vector( - subdata.properties.at(0).value >()); + normals = createVec3Vector(subdata.properties.at(0).value >()); } } } } + + // the (base) normals correspond to the polygon indices, for some reason + mesh.normals.resize(mesh.vertices.size()); + for (int i = 0, n = polygonIndices.size(); i < n; i++) { + int index = polygonIndices.at(i); + mesh.normals[index < 0 ? (-index - 1) : index] = normals[i]; + } + // convert the polygons to quads and triangles for (const int* beginIndex = polygonIndices.constData(), *end = beginIndex + polygonIndices.size(); beginIndex != end; ) {