From 1e89debc4e85ceccce3f72582bc422b904098e95 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 16 Mar 2018 13:38:45 -0700 Subject: [PATCH 1/5] model behaves correctly if missing material --- libraries/render-utils/src/MeshPartPayload.cpp | 14 ++++++++------ libraries/render-utils/src/MeshPartPayload.h | 9 ++++++--- libraries/render-utils/src/Model.cpp | 3 ++- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 2637d24d67..a03a531ec9 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -47,6 +47,8 @@ template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderAr } } +const graphics::MaterialPointer MeshPartPayload::DEFAULT_MATERIAL = std::make_shared(); + MeshPartPayload::MeshPartPayload(const std::shared_ptr& mesh, int partIndex, graphics::MaterialPointer material) { updateMeshPart(mesh, partIndex); addMaterial(graphics::MaterialLayer(material, 0)); @@ -95,7 +97,7 @@ void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits, builder.withSubMetaCulled(); } - if (_drawMaterials.top().material) { + if (topMaterialExists()) { auto matKey = _drawMaterials.top().material->getKey(); if (matKey.isTranslucent()) { builder.withTransparent(); @@ -115,7 +117,7 @@ Item::Bound MeshPartPayload::getBound() const { ShapeKey MeshPartPayload::getShapeKey() const { graphics::MaterialKey drawMaterialKey; - if (_drawMaterials.top().material) { + if (topMaterialExists()) { drawMaterialKey = _drawMaterials.top().material->getKey(); } @@ -170,7 +172,7 @@ void MeshPartPayload::render(RenderArgs* args) { bindMesh(batch); // apply material properties - RenderPipelines::bindMaterial(_drawMaterials.top().material, batch, args->_enableTexturing); + RenderPipelines::bindMaterial(!_drawMaterials.empty() ? _drawMaterials.top().material : DEFAULT_MATERIAL, batch, args->_enableTexturing); args->_details._materialSwitches++; // Draw! @@ -350,7 +352,7 @@ void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tag builder.withDeformed(); } - if (_drawMaterials.top().material) { + if (topMaterialExists()) { auto matKey = _drawMaterials.top().material->getKey(); if (matKey.isTranslucent()) { builder.withTransparent(); @@ -381,7 +383,7 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe } graphics::MaterialKey drawMaterialKey; - if (_drawMaterials.top().material) { + if (topMaterialExists()) { drawMaterialKey = _drawMaterials.top().material->getKey(); } @@ -467,7 +469,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) { bindMesh(batch); // apply material properties - RenderPipelines::bindMaterial(_drawMaterials.top().material, batch, args->_enableTexturing); + RenderPipelines::bindMaterial(!_drawMaterials.empty() ? _drawMaterials.top().material : DEFAULT_MATERIAL, batch, args->_enableTexturing); args->_details._materialSwitches++; // Draw! diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 3ad222d90c..7440f55e7e 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -65,15 +65,18 @@ public: graphics::Mesh::Part _drawPart; size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; } - size_t getMaterialTextureSize() { return _drawMaterials.top().material ? _drawMaterials.top().material->getTextureSize() : 0; } - int getMaterialTextureCount() { return _drawMaterials.top().material ? _drawMaterials.top().material->getTextureCount() : 0; } - bool hasTextureInfo() const { return _drawMaterials.top().material ? _drawMaterials.top().material->hasTextureInfo() : false; } + size_t getMaterialTextureSize() { return topMaterialExists() ? _drawMaterials.top().material->getTextureSize() : 0; } + int getMaterialTextureCount() { return topMaterialExists() ? _drawMaterials.top().material->getTextureCount() : 0; } + bool hasTextureInfo() const { return topMaterialExists() ? _drawMaterials.top().material->hasTextureInfo() : false; } void addMaterial(graphics::MaterialLayer material); void removeMaterial(graphics::MaterialPointer material); protected: + static const graphics::MaterialPointer DEFAULT_MATERIAL; render::ItemKey _itemKey{ render::ItemKey::Builder::opaqueShape().build() }; + + bool topMaterialExists() const { return !_drawMaterials.empty() && _drawMaterials.top().material; } }; namespace render { diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 12d6659849..5784101f63 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1573,7 +1573,8 @@ void Model::createVisibleRenderItemSet() { int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { _modelMeshRenderItems << std::make_shared(shared_from_this(), i, partIndex, shapeID, transform, offset); - _modelMeshMaterialNames.push_back(getGeometry()->getShapeMaterial(shapeID)->getName()); + auto material = getGeometry()->getShapeMaterial(shapeID); + _modelMeshMaterialNames.push_back(material ? material->getName() : ""); _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i }); shapeID++; } From 3a98cf284fa98d6adffd02f2f66711c6ce0521f8 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 16 Mar 2018 14:18:42 -0700 Subject: [PATCH 2/5] Fix DS not handling lowercase header keys --- domain-server/src/DomainServer.cpp | 10 +++++----- libraries/embedded-webserver/src/HTTPConnection.cpp | 8 ++++---- libraries/embedded-webserver/src/HTTPConnection.h | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index a048b113da..f5ed0f6899 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -2209,7 +2209,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url const QString ASSIGNMENT_INSTANCES_HEADER = "ASSIGNMENT-INSTANCES"; const QString ASSIGNMENT_POOL_HEADER = "ASSIGNMENT-POOL"; - QByteArray assignmentInstancesValue = connection->requestHeaders().value(ASSIGNMENT_INSTANCES_HEADER.toLocal8Bit()); + QByteArray assignmentInstancesValue = connection->requestHeader(ASSIGNMENT_INSTANCES_HEADER.toLocal8Bit()); int numInstances = 1; @@ -2221,7 +2221,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url } QString assignmentPool = emptyPool; - QByteArray assignmentPoolValue = connection->requestHeaders().value(ASSIGNMENT_POOL_HEADER.toLocal8Bit()); + QByteArray assignmentPoolValue = connection->requestHeader(ASSIGNMENT_POOL_HEADER.toLocal8Bit()); if (!assignmentPoolValue.isEmpty()) { // specific pool requested, set that on the created assignment @@ -2619,7 +2619,7 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl if (!_oauthProviderURL.isEmpty() && (adminUsersVariant.isValid() || adminRolesVariant.isValid())) { - QString cookieString = connection->requestHeaders().value(HTTP_COOKIE_HEADER_KEY); + QString cookieString = connection->requestHeader(HTTP_COOKIE_HEADER_KEY); const QString COOKIE_UUID_REGEX_STRING = HIFI_SESSION_COOKIE_KEY + "=([\\d\\w-]+)($|;)"; QRegExp cookieUUIDRegex(COOKIE_UUID_REGEX_STRING); @@ -2664,7 +2664,7 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl static const QByteArray REQUESTED_WITH_HEADER = "X-Requested-With"; static const QString XML_REQUESTED_WITH = "XMLHttpRequest"; - if (connection->requestHeaders().value(REQUESTED_WITH_HEADER) == XML_REQUESTED_WITH) { + if (connection->requestHeader(REQUESTED_WITH_HEADER) == XML_REQUESTED_WITH) { // unauthorized XHR requests get a 401 and not a 302, since there isn't an XHR // path to OAuth authorize connection->respond(HTTPConnection::StatusCode401, UNAUTHENTICATED_BODY); @@ -2695,7 +2695,7 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl const QByteArray BASIC_AUTH_HEADER_KEY = "Authorization"; // check if a username and password have been provided with the request - QString basicAuthString = connection->requestHeaders().value(BASIC_AUTH_HEADER_KEY); + QString basicAuthString = connection->requestHeader(BASIC_AUTH_HEADER_KEY); if (!basicAuthString.isEmpty()) { QStringList splitAuthString = basicAuthString.split(' '); diff --git a/libraries/embedded-webserver/src/HTTPConnection.cpp b/libraries/embedded-webserver/src/HTTPConnection.cpp index 00879e1380..845822cdf7 100644 --- a/libraries/embedded-webserver/src/HTTPConnection.cpp +++ b/libraries/embedded-webserver/src/HTTPConnection.cpp @@ -55,7 +55,7 @@ HTTPConnection::~HTTPConnection() { QHash HTTPConnection::parseUrlEncodedForm() { // make sure we have the correct MIME type - QList elements = _requestHeaders.value("Content-Type").split(';'); + QList elements = requestHeader("Content-Type").split(';'); QString contentType = elements.at(0).trimmed(); if (contentType != "application/x-www-form-urlencoded") { @@ -75,7 +75,7 @@ QHash HTTPConnection::parseUrlEncodedForm() { QList HTTPConnection::parseFormData() const { // make sure we have the correct MIME type - QList elements = _requestHeaders.value("Content-Type").split(';'); + QList elements = requestHeader("Content-Type").split(';'); QString contentType = elements.at(0).trimmed(); @@ -251,7 +251,7 @@ void HTTPConnection::readHeaders() { if (trimmed.isEmpty()) { _socket->disconnect(this, SLOT(readHeaders())); - QByteArray clength = _requestHeaders.value("Content-Length"); + QByteArray clength = _requestHeaders.value("content-length"); if (clength.isEmpty()) { _parentManager->handleHTTPRequest(this, _requestUrl); @@ -275,7 +275,7 @@ void HTTPConnection::readHeaders() { respond("400 Bad Request", "The header was malformed."); return; } - _lastRequestHeader = trimmed.left(idx); + _lastRequestHeader = trimmed.left(idx).toLower(); QByteArray& value = _requestHeaders[_lastRequestHeader]; if (!value.isEmpty()) { value.append(", "); diff --git a/libraries/embedded-webserver/src/HTTPConnection.h b/libraries/embedded-webserver/src/HTTPConnection.h index 60408d4325..e4d23e3c90 100644 --- a/libraries/embedded-webserver/src/HTTPConnection.h +++ b/libraries/embedded-webserver/src/HTTPConnection.h @@ -72,8 +72,8 @@ public: /// Returns a reference to the request URL. const QUrl& requestUrl () const { return _requestUrl; } - /// Returns a reference to the request headers. - const Headers& requestHeaders () const { return _requestHeaders; } + /// Returns a copy of the request header value. If it does not exist, it will return a default constructed QByteArray. + QByteArray requestHeader(const QString& key) const { return _requestHeaders.value(key.toLower().toLocal8Bit()); } /// Returns a reference to the request content. const QByteArray& requestContent () const { return _requestContent; } From debea3791de4d9aa6ac22b329c705e1bcc365063 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 16 Mar 2018 14:22:46 -0700 Subject: [PATCH 3/5] Fix DS content backups not loading on IE IE does not support Object.assign --- domain-server/resources/web/js/shared.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/resources/web/js/shared.js b/domain-server/resources/web/js/shared.js index 84bba4de56..1647da045f 100644 --- a/domain-server/resources/web/js/shared.js +++ b/domain-server/resources/web/js/shared.js @@ -2,7 +2,7 @@ if (typeof Settings === "undefined") { Settings = {}; } -Object.assign(Settings, { +$.extend(Settings, { DEPRECATED_CLASS: 'deprecated-setting', TRIGGER_CHANGE_CLASS: 'trigger-change', DATA_ROW_CLASS: 'value-row', From fdca6e083253d88db1c09c3c45c31671bfbb6035 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 16 Mar 2018 15:21:36 -0700 Subject: [PATCH 4/5] Update direct _requestHeaders access to be consistent with other reads --- libraries/embedded-webserver/src/HTTPConnection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/embedded-webserver/src/HTTPConnection.cpp b/libraries/embedded-webserver/src/HTTPConnection.cpp index 845822cdf7..280b44cec0 100644 --- a/libraries/embedded-webserver/src/HTTPConnection.cpp +++ b/libraries/embedded-webserver/src/HTTPConnection.cpp @@ -251,7 +251,7 @@ void HTTPConnection::readHeaders() { if (trimmed.isEmpty()) { _socket->disconnect(this, SLOT(readHeaders())); - QByteArray clength = _requestHeaders.value("content-length"); + QByteArray clength = requestHeader("Content-Length"); if (clength.isEmpty()) { _parentManager->handleHTTPRequest(this, _requestUrl); From 3f2a49d2435815cbe7c9fe7faa18bdc71604a4b0 Mon Sep 17 00:00:00 2001 From: David Back Date: Fri, 16 Mar 2018 16:57:54 -0700 Subject: [PATCH 5/5] fix list of tablet IDs ray cast checks in edit.js --- scripts/system/edit.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 0e1718ac45..1f442c09b0 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -776,9 +776,12 @@ function findClickedEntity(event) { } var pickRay = Camera.computePickRay(event.x, event.y); - var overlayResult = Overlays.findRayIntersection(pickRay, true, getMainTabletIDs()); - if (overlayResult.intersects) { - return null; + var tabletIDs = getMainTabletIDs(); + if (tabletIDs.length > 0) { + var overlayResult = Overlays.findRayIntersection(pickRay, true, tabletIDs); + if (overlayResult.intersects) { + return null; + } } var entityResult = Entities.findRayIntersection(pickRay, true); // want precision picking @@ -967,8 +970,13 @@ function mouseReleaseEvent(event) { function wasTabletClicked(event) { var rayPick = Camera.computePickRay(event.x, event.y); - var result = Overlays.findRayIntersection(rayPick, true, getMainTabletIDs()); - return result.intersects; + var tabletIDs = getMainTabletIDs(); + if (tabletIDs.length === 0) { + return false; + } else { + var result = Overlays.findRayIntersection(rayPick, true, getMainTabletIDs()); + return result.intersects; + } } function mouseClickEvent(event) {