diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp
index 47a81ba1fe..fb4b65726a 100644
--- a/assignment-client/src/avatars/AvatarMixerSlave.cpp
+++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp
@@ -214,7 +214,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
uint64_t getTimestamp() const override {
return _lastEncodeTime;
}
- const AvatarSharedPointer& getAvatar() const { return _avatar; }
+ AvatarSharedPointer getAvatar() const { return _avatar; }
private:
AvatarSharedPointer _avatar;
@@ -326,7 +326,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
int remainingAvatars = (int)sortedAvatars.size();
while (!sortedAvatars.empty()) {
- const auto& avatarData = sortedAvatars.top().getAvatar();
+ const auto avatarData = sortedAvatars.top().getAvatar();
sortedAvatars.pop();
remainingAvatars--;
diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml
index 6b7432b8b2..4de09c1bf3 100644
--- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml
+++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml
@@ -33,6 +33,7 @@ Rectangle {
property string itemName;
property string itemId;
property string itemHref;
+ property string itemAuthor;
property double balanceAfterPurchase;
property bool alreadyOwned: false;
property int itemPrice: -1;
@@ -81,12 +82,12 @@ Rectangle {
if (result.status !== 'success') {
failureErrorText.text = result.message;
root.activeView = "checkoutFailure";
- UserActivityLogger.commercePurchaseFailure(root.itemId, root.itemPrice, !root.alreadyOwned, result.message);
+ UserActivityLogger.commercePurchaseFailure(root.itemId, root.itemAuthor, root.itemPrice, !root.alreadyOwned, result.message);
} else {
root.itemHref = result.data.download_url;
root.isWearable = result.data.categories.indexOf("Wearables") > -1;
root.activeView = "checkoutSuccess";
- UserActivityLogger.commercePurchaseSuccess(root.itemId, root.itemPrice, !root.alreadyOwned);
+ UserActivityLogger.commercePurchaseSuccess(root.itemId, root.itemAuthor, root.itemPrice, !root.alreadyOwned);
}
}
@@ -410,7 +411,8 @@ Rectangle {
Rectangle {
id: buyTextContainer;
visible: buyText.text !== "";
- anchors.top: parent.top;
+ anchors.top: cancelPurchaseButton.bottom;
+ anchors.topMargin: 16;
anchors.left: parent.left;
anchors.right: parent.right;
height: buyText.height + 30;
@@ -465,8 +467,8 @@ Rectangle {
enabled: (root.balanceAfterPurchase >= 0 && purchasesReceived && balanceReceived) || !itemIsJson;
color: hifi.buttons.blue;
colorScheme: hifi.colorSchemes.light;
- anchors.top: buyTextContainer.visible ? buyTextContainer.bottom : checkoutActionButtonsContainer.top;
- anchors.topMargin: buyTextContainer.visible ? 12 : 16;
+ anchors.top: checkoutActionButtonsContainer.top;
+ anchors.topMargin: 16;
height: 40;
anchors.left: parent.left;
anchors.right: parent.right;
@@ -879,6 +881,7 @@ Rectangle {
root.itemPrice = message.params.itemPrice;
itemHref = message.params.itemHref;
referrer = message.params.referrer;
+ itemAuthor = message.params.itemAuthor;
setBuyText();
break;
default:
@@ -926,11 +929,11 @@ Rectangle {
buyText.text = "";
}
} else {
- buyText.text = "This free item will not be added to your Purchases. Non-entities can't yet be purchased for HFC.";
- buyTextContainer.color = "#FFD6AD";
- buyTextContainer.border.color = "#FAC07D";
- buyGlyph.text = hifi.glyphs.alert;
- buyGlyph.size = 46;
+ buyText.text = 'This type of item cannot currently be certified, so it will not show up in "My Purchases". You can access it again for free from the Marketplace.';
+ buyTextContainer.color = hifi.colors.white;
+ buyTextContainer.border.color = hifi.colors.white;
+ buyGlyph.text = "";
+ buyGlyph.size = 0;
}
}
diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp
index 8a294182bd..93caef555f 100644
--- a/interface/src/avatar/AvatarManager.cpp
+++ b/interface/src/avatar/AvatarManager.cpp
@@ -150,7 +150,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
glm::vec3 getPosition() const override { return _avatar->getWorldPosition(); }
float getRadius() const override { return std::static_pointer_cast(_avatar)->getBoundingRadius(); }
uint64_t getTimestamp() const override { return std::static_pointer_cast(_avatar)->getLastRenderUpdateTime(); }
- const AvatarSharedPointer& getAvatar() const { return _avatar; }
+ AvatarSharedPointer getAvatar() const { return _avatar; }
private:
AvatarSharedPointer _avatar;
};
@@ -185,7 +185,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
render::Transaction transaction;
while (!sortedAvatars.empty()) {
const SortableAvatar& sortData = sortedAvatars.top();
- const auto& avatar = std::static_pointer_cast(sortData.getAvatar());
+ const auto avatar = std::static_pointer_cast(sortData.getAvatar());
bool ignoring = DependencyManager::get()->isPersonalMutingNode(avatar->getID());
if (ignoring) {
@@ -239,7 +239,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
sortedAvatars.pop();
while (inView && !sortedAvatars.empty()) {
const SortableAvatar& newSortData = sortedAvatars.top();
- const auto& newAvatar = std::static_pointer_cast(newSortData.getAvatar());
+ const auto newAvatar = std::static_pointer_cast(newSortData.getAvatar());
inView = newSortData.getPriority() > OUT_OF_VIEW_THRESHOLD;
if (inView && newAvatar->hasNewJointData()) {
numAVatarsNotUpdated++;
diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp
index 3257a634c7..d7d36dabf6 100644
--- a/interface/src/commerce/Ledger.cpp
+++ b/interface/src/commerce/Ledger.cpp
@@ -61,7 +61,7 @@ void Ledger::send(const QString& endpoint, const QString& success, const QString
void Ledger::signedSend(const QString& propertyName, const QByteArray& text, const QString& key, const QString& endpoint, const QString& success, const QString& fail, const bool controlled_failure) {
auto wallet = DependencyManager::get();
- QString signature = key.isEmpty() ? "" : wallet->signWithKey(text, key);
+ QString signature = wallet->signWithKey(text, key);
QJsonObject request;
request[propertyName] = QString(text);
if (!controlled_failure) {
diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp
index 00941d6c50..c3c91e82a8 100644
--- a/interface/src/commerce/Wallet.cpp
+++ b/interface/src/commerce/Wallet.cpp
@@ -548,13 +548,16 @@ QStringList Wallet::listPublicKeys() {
// the horror of code pages and so on (changing the bytes) by just returning a base64
// encoded string representing the signature (suitable for http, etc...)
QString Wallet::signWithKey(const QByteArray& text, const QString& key) {
- qCInfo(commerce) << "Signing text" << text << "with key" << key;
EC_KEY* ecPrivateKey = NULL;
+
+ auto keyFilePathString = keyFilePath().toStdString();
if ((ecPrivateKey = readPrivateKey(keyFilePath().toStdString().c_str()))) {
unsigned char* sig = new unsigned char[ECDSA_size(ecPrivateKey)];
unsigned int signatureBytes = 0;
+ qCInfo(commerce) << "Hashing and signing plaintext" << text << "with key at address" << ecPrivateKey;
+
QByteArray hashedPlaintext = QCryptographicHash::hash(text, QCryptographicHash::Sha256);
@@ -747,12 +750,10 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer pack
}
EC_KEY_free(ec);
- QByteArray ba = sig.toLocal8Bit();
- const char *sigChar = ba.data();
QByteArray textByteArray;
if (status > -1) {
- textByteArray = QByteArray(sigChar, (int) strlen(sigChar));
+ textByteArray = sig.toUtf8();
}
textByteArraySize = textByteArray.size();
int certIDSize = certID.size();
diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp
index ba8bf8cbef..67fa94f7e5 100644
--- a/interface/src/ui/overlays/ModelOverlay.cpp
+++ b/interface/src/ui/overlays/ModelOverlay.cpp
@@ -24,7 +24,6 @@ ModelOverlay::ModelOverlay()
: _model(std::make_shared(nullptr, this)),
_modelTextures(QVariantMap())
{
- _model->init();
_model->setLoadingPriority(_loadPriority);
_isLoaded = false;
}
@@ -38,7 +37,6 @@ ModelOverlay::ModelOverlay(const ModelOverlay* modelOverlay) :
_scaleToFit(modelOverlay->_scaleToFit),
_loadPriority(modelOverlay->_loadPriority)
{
- _model->init();
_model->setLoadingPriority(_loadPriority);
if (_url.isValid()) {
_updateModel = true;
diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
index bb7f141cd9..c532e7659f 100644
--- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
+++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
@@ -138,7 +138,6 @@ Avatar::~Avatar() {
void Avatar::init() {
getHead()->init();
- _skeletonModel->init();
_initialized = true;
}
diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp
index 8c3b56d89e..bf711b94c2 100644
--- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp
+++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp
@@ -349,7 +349,7 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene
float getRadius() const override { return 0.5f * _renderer->getEntity()->getQueryAACube().getScale(); }
uint64_t getTimestamp() const override { return _renderer->getUpdateTime(); }
- const EntityRendererPointer& getRenderer() const { return _renderer; }
+ EntityRendererPointer getRenderer() const { return _renderer; }
private:
EntityRendererPointer _renderer;
};
@@ -382,7 +382,7 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene
std::unordered_map::iterator itr;
size_t numSorted = sortedRenderables.size();
while (!sortedRenderables.empty() && usecTimestampNow() < expiry) {
- const EntityRendererPointer& renderable = sortedRenderables.top().getRenderer();
+ const auto renderable = sortedRenderables.top().getRenderer();
renderable->updateInScene(scene, transaction);
_renderablesToUpdate.erase(renderable->getEntity()->getID());
sortedRenderables.pop();
diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
index bc99522d0f..e40e9a2f0c 100644
--- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp
@@ -1209,7 +1209,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate);
connect(entity.get(), &RenderableModelEntityItem::requestCollisionGeometryUpdate, this, &ModelEntityRenderer::flagForCollisionGeometryUpdate);
model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity));
- model->init();
entity->setModel(model);
withWriteLock([&] { _model = model; });
}
diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp
index fbf85fa8c2..21764dff7f 100644
--- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp
@@ -303,6 +303,7 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) {
batch.setInputBuffer(0, _verticesBuffer, 0, sizeof(Vertex));
#ifndef POLYLINE_ENTITY_USE_FADE_EFFECT
+ // glColor4f must be called after setInputFormat if it must be taken into account
if (_isFading) {
batch._glColor4f(1.0f, 1.0f, 1.0f, Interpolate::calculateFadeRatio(_fadeStartTime));
} else {
diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
index 3524709395..b00ad0259e 100644
--- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
@@ -137,11 +137,10 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
});
if (proceduralRender) {
- batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a);
if (render::ShapeKey(args->_globalShapeKey).isWireframe()) {
- geometryCache->renderWireShape(batch, geometryShape);
+ geometryCache->renderWireShape(batch, geometryShape, outColor);
} else {
- geometryCache->renderShape(batch, geometryShape);
+ geometryCache->renderShape(batch, geometryShape, outColor);
}
} else {
// FIXME, support instanced multi-shape rendering using multidraw indirect
diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp
index 16e2c4c789..fb4c50cfc2 100644
--- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp
@@ -190,7 +190,6 @@ void WebEntityRenderer::doRender(RenderArgs* args) {
});
batch.setResourceTexture(0, _texture);
float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
- batch._glColor4f(1.0f, 1.0f, 1.0f, fadeRatio);
DependencyManager::get()->bindWebBrowserProgram(batch, fadeRatio < OPAQUE_ALPHA_THRESHOLD);
DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, texMin, texMax, glm::vec4(1.0f, 1.0f, 1.0f, fadeRatio), _geometryId);
diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp
index 678ddfcea5..13ebd9ef9f 100644
--- a/libraries/entities/src/EntityItemProperties.cpp
+++ b/libraries/entities/src/EntityItemProperties.cpp
@@ -2530,7 +2530,8 @@ bool EntityItemProperties::verifySignature(const QString& publicKey, const QByte
return false;
}
- const unsigned char* key = reinterpret_cast(publicKey.toUtf8().constData());
+ auto keyByteArray = publicKey.toUtf8();
+ auto key = keyByteArray.constData();
int keyLength = publicKey.length();
BIO *bio = BIO_new_mem_buf((void*)key, keyLength);
@@ -2548,19 +2549,23 @@ bool EntityItemProperties::verifySignature(const QString& publicKey, const QByte
// ECSDA verification prototype: note that type is currently ignored
// int ECDSA_verify(int type, const unsigned char *dgst, int dgstlen,
// const unsigned char *sig, int siglen, EC_KEY *eckey);
- bool answer = ECDSA_verify(0,
+ int answer = ECDSA_verify(0,
digest,
digestLength,
signature,
signatureLength,
ec);
long error = ERR_get_error();
- if (error != 0) {
- const char* error_str = ERR_error_string(error, NULL);
- qCWarning(entities) << "ERROR while verifying signature! EC error:" << error_str
+ if (error != 0 || answer == -1) {
+ qCWarning(entities) << "ERROR while verifying signature!"
<< "\nKey:" << publicKey << "\nutf8 Key Length:" << keyLength
<< "\nDigest:" << digest << "\nDigest Length:" << digestLength
<< "\nSignature:" << signature << "\nSignature Length:" << signatureLength;
+ while (error != 0) {
+ const char* error_str = ERR_error_string(error, NULL);
+ qCWarning(entities) << "EC error:" << error_str;
+ error = ERR_get_error();
+ }
}
EC_KEY_free(ec);
if (bio) {
@@ -2569,7 +2574,7 @@ bool EntityItemProperties::verifySignature(const QString& publicKey, const QByte
if (evp_key) {
EVP_PKEY_free(evp_key);
}
- return answer;
+ return (answer == 1);
} else {
if (bio) {
BIO_free(bio);
diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp
index b5765bb44b..8f780355db 100644
--- a/libraries/entities/src/EntityTree.cpp
+++ b/libraries/entities/src/EntityTree.cpp
@@ -1189,13 +1189,15 @@ bool EntityTree::verifyNonce(const QString& certID, const QString& nonce, Entity
key = sent.second;
}
- QString annotatedKey = "-----BEGIN PUBLIC KEY-----\n" + key.insert(64, "\n") + "\n-----END PUBLIC KEY-----";
- bool verificationSuccess = EntityItemProperties::verifySignature(annotatedKey.toUtf8(), actualNonce.toUtf8(), nonce.toUtf8());
+ QString annotatedKey = "-----BEGIN PUBLIC KEY-----\n" + key.insert(64, "\n") + "\n-----END PUBLIC KEY-----\n";
+ QByteArray hashedActualNonce = QCryptographicHash::hash(QByteArray(actualNonce.toUtf8()), QCryptographicHash::Sha256);
+ bool verificationSuccess = EntityItemProperties::verifySignature(annotatedKey.toUtf8(), hashedActualNonce, QByteArray::fromBase64(nonce.toUtf8()));
if (verificationSuccess) {
qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "succeeded.";
} else {
- qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed for nonce" << actualNonce << "key" << key << "signature" << nonce;
+ qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed. Actual nonce:" << actualNonce <<
+ "\nHashed actual nonce (digest):" << hashedActualNonce << "\nSent nonce (signature)" << nonce << "\nKey" << key;
}
return verificationSuccess;
diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp
index f93d430152..2192f5f45b 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp
+++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp
@@ -605,6 +605,10 @@ void GLBackend::do_glColor4f(const Batch& batch, size_t paramOffset) {
if (_input._colorAttribute != newColor) {
_input._colorAttribute = newColor;
glVertexAttrib4fv(gpu::Stream::COLOR, &_input._colorAttribute.r);
+ // Color has been changed and is not white. To prevent colors from bleeding
+ // between different objects, we need to set the _hadColorAttribute flag
+ // as if a previous render call had potential colors
+ _input._hadColorAttribute = (newColor != glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));
}
(void)CHECK_GL_ERROR();
}
diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h
index 1908db614d..5558d3ada1 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h
+++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h
@@ -253,6 +253,7 @@ protected:
struct InputStageState {
bool _invalidFormat { true };
+ bool _hadColorAttribute{ true };
Stream::FormatPointer _format;
std::string _formatKey;
diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp
index e8ebcbe05c..42bd56e6e4 100644
--- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp
+++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp
@@ -62,6 +62,8 @@ void GL41Backend::updateInput() {
// now we need to bind the buffers and assign the attrib pointers
if (_input._format) {
+ bool hasColorAttribute{ false };
+
const Buffers& buffers = _input._buffers;
const Offsets& offsets = _input._bufferOffsets;
const Offsets& strides = _input._bufferStrides;
@@ -98,6 +100,8 @@ void GL41Backend::updateInput() {
uintptr_t pointer = (uintptr_t)(attrib._offset + offsets[bufferNum]);
GLboolean isNormalized = attrib._element.isNormalized();
+ hasColorAttribute = hasColorAttribute || (slot == Stream::COLOR);
+
for (size_t locNum = 0; locNum < locationCount; ++locNum) {
if (attrib._element.isInteger()) {
glVertexAttribIPointer(slot + (GLuint)locNum, count, type, stride,
@@ -117,6 +121,15 @@ void GL41Backend::updateInput() {
}
}
}
+
+ if (_input._hadColorAttribute && !hasColorAttribute) {
+ // The previous input stage had a color attribute but this one doesn't so reset
+ // color to pure white.
+ const auto white = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
+ glVertexAttrib4fv(Stream::COLOR, &white.r);
+ _input._colorAttribute = white;
+ }
+ _input._hadColorAttribute = hasColorAttribute;
}
// everything format related should be in sync now
_input._invalidFormat = false;
diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp
index ece62e15f1..4a43fc988c 100644
--- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp
+++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp
@@ -32,6 +32,8 @@ void GL45Backend::updateInput() {
// Assign the vertex format required
if (_input._format) {
+ bool hasColorAttribute{ false };
+
_input._attribBindingBuffers.reset();
const Stream::Format::AttributeMap& attributes = _input._format->getAttributes();
@@ -54,6 +56,9 @@ void GL45Backend::updateInput() {
GLboolean isNormalized = attrib._element.isNormalized();
GLenum perLocationSize = attrib._element.getLocationSize();
+
+ hasColorAttribute = hasColorAttribute || (slot == Stream::COLOR);
+
for (GLuint locNum = 0; locNum < locationCount; ++locNum) {
GLuint attriNum = (GLuint)(slot + locNum);
newActivation.set(attriNum);
@@ -84,6 +89,15 @@ void GL45Backend::updateInput() {
glVertexBindingDivisor(bufferChannelNum, frequency);
#endif
}
+
+ if (_input._hadColorAttribute && !hasColorAttribute) {
+ // The previous input stage had a color attribute but this one doesn't so reset
+ // color to pure white.
+ const auto white = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
+ glVertexAttrib4fv(Stream::COLOR, &white.r);
+ _input._colorAttribute = white;
+ }
+ _input._hadColorAttribute = hasColorAttribute;
}
// Manage Activation what was and what is expected now
diff --git a/libraries/networking/src/SentPacketHistory.cpp b/libraries/networking/src/SentPacketHistory.cpp
index fbb7eff41a..3bd6d4cf03 100644
--- a/libraries/networking/src/SentPacketHistory.cpp
+++ b/libraries/networking/src/SentPacketHistory.cpp
@@ -24,8 +24,7 @@ SentPacketHistory::SentPacketHistory(int size)
}
-void SentPacketHistory::packetSent(uint16_t sequenceNumber, const NLPacket& packet) {
-
+void SentPacketHistory::untrackedPacketSent(uint16_t sequenceNumber) {
// check if given seq number has the expected value. if not, something's wrong with
// the code calling this function
uint16_t expectedSequenceNumber = _newestSequenceNumber + (uint16_t)1;
@@ -34,6 +33,10 @@ void SentPacketHistory::packetSent(uint16_t sequenceNumber, const NLPacket& pack
<< "Expected:" << expectedSequenceNumber << "Actual:" << sequenceNumber;
}
_newestSequenceNumber = sequenceNumber;
+}
+
+void SentPacketHistory::packetSent(uint16_t sequenceNumber, const NLPacket& packet) {
+ untrackedPacketSent(sequenceNumber);
QWriteLocker locker(&_packetsLock);
_sentPackets.insert(NLPacket::createCopy(packet));
diff --git a/libraries/networking/src/SentPacketHistory.h b/libraries/networking/src/SentPacketHistory.h
index 72150658e3..dc92d38b25 100644
--- a/libraries/networking/src/SentPacketHistory.h
+++ b/libraries/networking/src/SentPacketHistory.h
@@ -27,6 +27,8 @@ class SentPacketHistory {
public:
SentPacketHistory(int size = MAX_REASONABLE_SEQUENCE_GAP);
+ void untrackedPacketSent(uint16_t sequenceNumber);
+
void packetSent(uint16_t sequenceNumber, const NLPacket& packet);
const NLPacket* getPacket(uint16_t sequenceNumber) const;
diff --git a/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp b/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp
index aec6df4f14..c63170de75 100644
--- a/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp
+++ b/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp
@@ -89,17 +89,19 @@ void UserActivityLoggerScriptingInterface::doLogAction(QString action, QJsonObje
Q_ARG(QJsonObject, details));
}
-void UserActivityLoggerScriptingInterface::commercePurchaseSuccess(QString marketplaceID, int cost, bool firstPurchaseOfThisItem) {
+void UserActivityLoggerScriptingInterface::commercePurchaseSuccess(QString marketplaceID, QString contentCreator, int cost, bool firstPurchaseOfThisItem) {
QJsonObject payload;
payload["marketplaceID"] = marketplaceID;
+ payload["contentCreator"] = contentCreator;
payload["cost"] = cost;
payload["firstPurchaseOfThisItem"] = firstPurchaseOfThisItem;
doLogAction("commercePurchaseSuccess", payload);
}
-void UserActivityLoggerScriptingInterface::commercePurchaseFailure(QString marketplaceID, int cost, bool firstPurchaseOfThisItem, QString errorDetails) {
+void UserActivityLoggerScriptingInterface::commercePurchaseFailure(QString marketplaceID, QString contentCreator, int cost, bool firstPurchaseOfThisItem, QString errorDetails) {
QJsonObject payload;
payload["marketplaceID"] = marketplaceID;
+ payload["contentCreator"] = contentCreator;
payload["cost"] = cost;
payload["firstPurchaseOfThisItem"] = firstPurchaseOfThisItem;
payload["errorDetails"] = errorDetails;
diff --git a/libraries/networking/src/UserActivityLoggerScriptingInterface.h b/libraries/networking/src/UserActivityLoggerScriptingInterface.h
index 0e08b050d7..71d411056d 100644
--- a/libraries/networking/src/UserActivityLoggerScriptingInterface.h
+++ b/libraries/networking/src/UserActivityLoggerScriptingInterface.h
@@ -33,8 +33,8 @@ public:
Q_INVOKABLE void bubbleToggled(bool newValue);
Q_INVOKABLE void bubbleActivated();
Q_INVOKABLE void logAction(QString action, QVariantMap details = QVariantMap{});
- Q_INVOKABLE void commercePurchaseSuccess(QString marketplaceID, int cost, bool firstPurchaseOfThisItem);
- Q_INVOKABLE void commercePurchaseFailure(QString marketplaceID, int cost, bool firstPurchaseOfThisItem, QString errorDetails);
+ Q_INVOKABLE void commercePurchaseSuccess(QString marketplaceID, QString contentCreator, int cost, bool firstPurchaseOfThisItem);
+ Q_INVOKABLE void commercePurchaseFailure(QString marketplaceID, QString contentCreator, int cost, bool firstPurchaseOfThisItem, QString errorDetails);
Q_INVOKABLE void commerceEntityRezzed(QString marketplaceID, QString source, QString type);
Q_INVOKABLE void commerceWalletSetupStarted(int timestamp, QString setupAttemptID, int setupFlowVersion, QString referrer, QString currentDomain);
Q_INVOKABLE void commerceWalletSetupProgress(int timestamp, QString setupAttemptID, int secondsElapsed, int currentStepNumber, QString currentStepName);
diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp
index 2f57523f79..77ed589e0b 100644
--- a/libraries/networking/src/udt/Connection.cpp
+++ b/libraries/networking/src/udt/Connection.cpp
@@ -191,6 +191,8 @@ void Connection::queueReceivedMessagePacket(std::unique_ptr packet) {
pendingMessage.enqueuePacket(std::move(packet));
+ bool processedLastOrOnly = false;
+
while (pendingMessage.hasAvailablePackets()) {
auto packet = pendingMessage.removeNextPacket();
@@ -201,9 +203,13 @@ void Connection::queueReceivedMessagePacket(std::unique_ptr packet) {
// if this was the last or only packet, then we can remove the pending message from our hash
if (packetPosition == Packet::PacketPosition::LAST ||
packetPosition == Packet::PacketPosition::ONLY) {
- _pendingReceivedMessages.erase(messageNumber);
+ processedLastOrOnly = true;
}
}
+
+ if (processedLastOrOnly) {
+ _pendingReceivedMessages.erase(messageNumber);
+ }
}
void Connection::sync() {
diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp
index 62354da11a..0a75e8c31b 100644
--- a/libraries/networking/src/udt/PacketHeaders.cpp
+++ b/libraries/networking/src/udt/PacketHeaders.cpp
@@ -30,7 +30,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketType::EntityEdit:
case PacketType::EntityData:
case PacketType::EntityPhysics:
- return static_cast(EntityVersion::StaticCertJsonVersionOne);
+ return static_cast(EntityVersion::OwnershipChallengeFix);
case PacketType::EntityQuery:
return static_cast(EntityQueryPacketVersion::ConnectionIdentifier);
diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h
index 618ac2de0c..85f321a198 100644
--- a/libraries/networking/src/udt/PacketHeaders.h
+++ b/libraries/networking/src/udt/PacketHeaders.h
@@ -197,10 +197,11 @@ uint qHash(const PacketType& key, uint seed);
QDebug operator<<(QDebug debug, const PacketType& type);
enum class EntityVersion : PacketVersion {
- StrokeColorProperty = 77,
+ StrokeColorProperty = 0,
HasDynamicOwnershipTests,
HazeEffect,
- StaticCertJsonVersionOne
+ StaticCertJsonVersionOne,
+ OwnershipChallengeFix,
};
enum class EntityScriptCallMethodVersion : PacketVersion {
diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp
index 9cb383df41..7e46831faa 100644
--- a/libraries/octree/src/OctreeEditPacketSender.cpp
+++ b/libraries/octree/src/OctreeEditPacketSender.cpp
@@ -291,6 +291,9 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, QByteArray&
// release the new packet
releaseQueuedPacketList(nodeUUID, std::move(newPacket));
+ // tell the sent packet history that we used a sequence number for an untracked packet
+ auto& sentPacketHistory = _sentPacketHistories[nodeUUID];
+ sentPacketHistory.untrackedPacketSent(sequence);
} else {
std::unique_ptr& bufferedPacket = _pendingEditPackets[nodeUUID].first; //only a NLPacket for now
diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp
index 3bb2aa2ef9..396cd13508 100644
--- a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp
+++ b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp
@@ -40,17 +40,7 @@ void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform
void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const {
// Still relying on the raw data from the model
- bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE);
- if (useCauterizedMesh) {
- ModelPointer model = _model.lock();
- if (model) {
- CauterizedModel* skeleton = static_cast(model.get());
- useCauterizedMesh = useCauterizedMesh && skeleton->getEnableCauterization();
- } else {
- useCauterizedMesh = false;
- }
- }
-
+ bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) && _enableCauterization;
if (useCauterizedMesh) {
if (_cauterizedClusterBuffer) {
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, _cauterizedClusterBuffer);
diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.h b/libraries/render-utils/src/CauterizedMeshPartPayload.h
index 1c98f5abf3..44eddc6e31 100644
--- a/libraries/render-utils/src/CauterizedMeshPartPayload.h
+++ b/libraries/render-utils/src/CauterizedMeshPartPayload.h
@@ -21,9 +21,12 @@ public:
void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override;
+ void setEnableCauterization(bool enableCauterization) { _enableCauterization = enableCauterization; }
+
private:
gpu::BufferPointer _cauterizedClusterBuffer;
Transform _cauterizedTransform;
+ bool _enableCauterization { false };
};
#endif // hifi_CauterizedMeshPartPayload_h
diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp
index c437a8c556..dbb82ab638 100644
--- a/libraries/render-utils/src/CauterizedModel.cpp
+++ b/libraries/render-utils/src/CauterizedModel.cpp
@@ -178,6 +178,12 @@ void CauterizedModel::updateRenderItems() {
modelTransform.setTranslation(self->getTranslation());
modelTransform.setRotation(self->getRotation());
+ bool isWireframe = self->isWireframe();
+ bool isVisible = self->isVisible();
+ bool isLayeredInFront = self->isLayeredInFront();
+ bool isLayeredInHUD = self->isLayeredInHUD();
+ bool enableCauterization = self->getEnableCauterization();
+
render::Transaction transaction;
for (int i = 0; i < (int)self->_modelMeshRenderItemIDs.size(); i++) {
@@ -186,7 +192,10 @@ void CauterizedModel::updateRenderItems() {
auto clusterMatrices(self->getMeshState(meshIndex).clusterMatrices);
auto clusterMatricesCauterized(self->getCauterizeMeshState(meshIndex).clusterMatrices);
- transaction.updateItem(itemID, [modelTransform, clusterMatrices, clusterMatricesCauterized](CauterizedMeshPartPayload& data) {
+ bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
+
+ transaction.updateItem(itemID, [modelTransform, clusterMatrices, clusterMatricesCauterized, invalidatePayloadShapeKey,
+ isWireframe, isVisible, isLayeredInFront, isLayeredInHUD, enableCauterization](CauterizedMeshPartPayload& data) {
data.updateClusterBuffer(clusterMatrices, clusterMatricesCauterized);
Transform renderTransform = modelTransform;
@@ -200,6 +209,11 @@ void CauterizedModel::updateRenderItems() {
renderTransform = modelTransform.worldTransform(Transform(clusterMatricesCauterized[0]));
}
data.updateTransformForCauterizedMesh(renderTransform);
+
+ data.setEnableCauterization(enableCauterization);
+ data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
+ data.setLayer(isLayeredInFront, isLayeredInHUD);
+ data.setShapeKey(invalidatePayloadShapeKey, isWireframe);
});
}
diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp
index 76c354bdf8..2616d08600 100644
--- a/libraries/render-utils/src/GeometryCache.cpp
+++ b/libraries/render-utils/src/GeometryCache.cpp
@@ -760,6 +760,20 @@ void GeometryCache::renderWireShape(gpu::Batch& batch, Shape shape) {
_shapes[shape].drawWire(batch);
}
+void GeometryCache::renderShape(gpu::Batch& batch, Shape shape, const glm::vec4& color) {
+ batch.setInputFormat(getSolidStreamFormat());
+ // Color must be set after input format
+ batch._glColor4f(color.r, color.g, color.b, color.a);
+ _shapes[shape].draw(batch);
+}
+
+void GeometryCache::renderWireShape(gpu::Batch& batch, Shape shape, const glm::vec4& color) {
+ batch.setInputFormat(getSolidStreamFormat());
+ // Color must be set after input format
+ batch._glColor4f(color.r, color.g, color.b, color.a);
+ _shapes[shape].drawWire(batch);
+}
+
void setupBatchInstance(gpu::Batch& batch, gpu::BufferPointer colorBuffer) {
gpu::BufferView colorView(colorBuffer, COLOR_ELEMENT);
batch.setInputBuffer(gpu::Stream::COLOR, colorView);
@@ -811,6 +825,14 @@ void GeometryCache::renderWireCube(gpu::Batch& batch) {
renderWireShape(batch, Cube);
}
+void GeometryCache::renderCube(gpu::Batch& batch, const glm::vec4& color) {
+ renderShape(batch, Cube, color);
+}
+
+void GeometryCache::renderWireCube(gpu::Batch& batch, const glm::vec4& color) {
+ renderWireShape(batch, Cube, color);
+}
+
void GeometryCache::renderSphere(gpu::Batch& batch) {
renderShape(batch, Sphere);
}
@@ -819,6 +841,14 @@ void GeometryCache::renderWireSphere(gpu::Batch& batch) {
renderWireShape(batch, Sphere);
}
+void GeometryCache::renderSphere(gpu::Batch& batch, const glm::vec4& color) {
+ renderShape(batch, Sphere, color);
+}
+
+void GeometryCache::renderWireSphere(gpu::Batch& batch, const glm::vec4& color) {
+ renderWireShape(batch, Sphere, color);
+}
+
void GeometryCache::renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner,
int majorRows, int majorCols, float majorEdge,
int minorRows, int minorCols, float minorEdge,
diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h
index cd8c43f1df..0585cc9e55 100644
--- a/libraries/render-utils/src/GeometryCache.h
+++ b/libraries/render-utils/src/GeometryCache.h
@@ -251,14 +251,20 @@ public:
// Dynamic geometry
void renderShape(gpu::Batch& batch, Shape shape);
void renderWireShape(gpu::Batch& batch, Shape shape);
+ void renderShape(gpu::Batch& batch, Shape shape, const glm::vec4& color);
+ void renderWireShape(gpu::Batch& batch, Shape shape, const glm::vec4& color);
size_t getShapeTriangleCount(Shape shape);
void renderCube(gpu::Batch& batch);
void renderWireCube(gpu::Batch& batch);
+ void renderCube(gpu::Batch& batch, const glm::vec4& color);
+ void renderWireCube(gpu::Batch& batch, const glm::vec4& color);
size_t getCubeTriangleCount();
void renderSphere(gpu::Batch& batch);
void renderWireSphere(gpu::Batch& batch);
+ void renderSphere(gpu::Batch& batch, const glm::vec4& color);
+ void renderWireSphere(gpu::Batch& batch, const glm::vec4& color);
size_t getSphereTriangleCount();
void renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner,
diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp
index 1ea3e1a705..2a59c7d3c5 100644
--- a/libraries/render-utils/src/MeshPartPayload.cpp
+++ b/libraries/render-utils/src/MeshPartPayload.cpp
@@ -122,11 +122,6 @@ void MeshPartPayload::bindMesh(gpu::Batch& batch) {
batch.setInputFormat((_drawMesh->getVertexFormat()));
batch.setInputStream(0, _drawMesh->getVertexStream());
-
- // TODO: Get rid of that extra call
- if (!_hasColorAttrib) {
- batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
- }
}
void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, bool enableTextures) const {
@@ -325,7 +320,7 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in
_shapeID(shapeIndex) {
assert(model && model->isLoaded());
- _model = model;
+ _blendedVertexBuffer = model->_blendedVertexBuffers[_meshIndex];
auto& modelMesh = model->getGeometry()->getMeshes().at(_meshIndex);
const Model::MeshState& state = model->getMeshState(_meshIndex);
@@ -339,13 +334,10 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in
}
updateTransformForSkinnedMesh(renderTransform, transform);
- initCache();
+ initCache(model);
}
-void ModelMeshPartPayload::initCache() {
- ModelPointer model = _model.lock();
- assert(model && model->isLoaded());
-
+void ModelMeshPartPayload::initCache(const ModelPointer& model) {
if (_drawMesh) {
auto vertexFormat = _drawMesh->getVertexFormat();
_hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR);
@@ -355,6 +347,7 @@ void ModelMeshPartPayload::initCache() {
const FBXMesh& mesh = geometry.meshes.at(_meshIndex);
_isBlendShaped = !mesh.blendshapes.isEmpty();
+ _hasTangents = !mesh.tangents.isEmpty();
}
auto networkMaterial = model->getGeometry()->getShapeMaterial(_shapeID);
@@ -388,94 +381,70 @@ void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& render
_worldBound.transform(boundTransform);
}
-ItemKey ModelMeshPartPayload::getKey() const {
+void ModelMeshPartPayload::setKey(bool isVisible, bool isLayered) {
ItemKey::Builder builder;
builder.withTypeShape();
- ModelPointer model = _model.lock();
- if (model) {
- if (!model->isVisible()) {
- builder.withInvisible();
- }
+ if (!isVisible) {
+ builder.withInvisible();
+ }
- if (model->isLayeredInFront() || model->isLayeredInHUD()) {
- builder.withLayered();
- }
+ if (isLayered) {
+ builder.withLayered();
+ }
- if (_isBlendShaped || _isSkinned) {
- builder.withDeformed();
- }
+ if (_isBlendShaped || _isSkinned) {
+ builder.withDeformed();
+ }
- if (_drawMaterial) {
- auto matKey = _drawMaterial->getKey();
- if (matKey.isTranslucent()) {
- builder.withTransparent();
- }
+ if (_drawMaterial) {
+ auto matKey = _drawMaterial->getKey();
+ if (matKey.isTranslucent()) {
+ builder.withTransparent();
}
}
- return builder.build();
+
+ _itemKey = builder.build();
+}
+
+ItemKey ModelMeshPartPayload::getKey() const {
+ return _itemKey;
+}
+
+void ModelMeshPartPayload::setLayer(bool isLayeredInFront, bool isLayeredInHUD) {
+ if (isLayeredInFront) {
+ _layer = Item::LAYER_3D_FRONT;
+ } else if (isLayeredInHUD) {
+ _layer = Item::LAYER_3D_HUD;
+ } else {
+ _layer = Item::LAYER_3D;
+ }
}
int ModelMeshPartPayload::getLayer() const {
- ModelPointer model = _model.lock();
- if (model) {
- if (model->isLayeredInFront()) {
- return Item::LAYER_3D_FRONT;
- } else if (model->isLayeredInHUD()) {
- return Item::LAYER_3D_HUD;
- }
- }
- return Item::LAYER_3D;
+ return _layer;
}
-ShapeKey ModelMeshPartPayload::getShapeKey() const {
- // guard against partially loaded meshes
- ModelPointer model = _model.lock();
- if (!model || !model->isLoaded() || !model->getGeometry()) {
- return ShapeKey::Builder::invalid();
+void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe) {
+ if (invalidateShapeKey) {
+ _shapeKey = ShapeKey::Builder::invalid();
+ return;
}
- const FBXGeometry& geometry = model->getFBXGeometry();
- const auto& networkMeshes = model->getGeometry()->getMeshes();
-
- // guard against partially loaded meshes
- if (_meshIndex >= (int)networkMeshes.size() || _meshIndex >= (int)geometry.meshes.size() || _meshIndex >= (int)model->_meshStates.size()) {
- return ShapeKey::Builder::invalid();
- }
-
- const FBXMesh& mesh = geometry.meshes.at(_meshIndex);
-
- // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown
- // to false to rebuild out mesh groups.
- if (_meshIndex < 0 || _meshIndex >= (int)networkMeshes.size() || _meshIndex > geometry.meshes.size()) {
- model->_needsFixupInScene = true; // trigger remove/add cycle
- model->invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid
- return ShapeKey::Builder::invalid();
- }
-
-
- int vertexCount = mesh.vertices.size();
- if (vertexCount == 0) {
- // sanity check
- return ShapeKey::Builder::invalid(); // FIXME
- }
-
-
model::MaterialKey drawMaterialKey;
if (_drawMaterial) {
drawMaterialKey = _drawMaterial->getKey();
}
bool isTranslucent = drawMaterialKey.isTranslucent();
- bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty();
+ bool hasTangents = drawMaterialKey.isNormalMap() && _hasTangents;
bool hasSpecular = drawMaterialKey.isMetallicMap();
bool hasLightmap = drawMaterialKey.isLightmapMap();
bool isUnlit = drawMaterialKey.isUnlit();
bool isSkinned = _isSkinned;
- bool wireframe = model->isWireframe();
- if (wireframe) {
+ if (isWireframe) {
isTranslucent = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
}
@@ -500,10 +469,14 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const {
if (isSkinned) {
builder.withSkinned();
}
- if (wireframe) {
+ if (isWireframe) {
builder.withWireframe();
}
- return builder.build();
+ _shapeKey = builder.build();
+}
+
+ShapeKey ModelMeshPartPayload::getShapeKey() const {
+ return _shapeKey;
}
void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) {
@@ -515,10 +488,9 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) {
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
batch.setInputFormat((_drawMesh->getVertexFormat()));
- ModelPointer model = _model.lock();
- if (model) {
- batch.setInputBuffer(0, model->_blendedVertexBuffers[_meshIndex], 0, sizeof(glm::vec3));
- batch.setInputBuffer(1, model->_blendedVertexBuffers[_meshIndex], _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3));
+ if (_blendedVertexBuffer) {
+ batch.setInputBuffer(0, _blendedVertexBuffer, 0, sizeof(glm::vec3));
+ batch.setInputBuffer(1, _blendedVertexBuffer, _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3));
batch.setInputStream(2, _drawMesh->getVertexStream().makeRangedStream(2));
} else {
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
@@ -526,11 +498,6 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) {
batch.setInputStream(0, _drawMesh->getVertexStream());
}
}
-
- // TODO: Get rid of that extra call
- if (!_hasColorAttrib) {
- batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
- }
}
void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const {
@@ -544,31 +511,9 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline:
void ModelMeshPartPayload::render(RenderArgs* args) {
PerformanceTimer perfTimer("ModelMeshPartPayload::render");
- ModelPointer model = _model.lock();
- if (!model || !model->isAddedToScene() || !model->isVisible()) {
- return; // bail asap
- }
-
- if (_state == WAITING_TO_START) {
- if (model->isLoaded()) {
- _state = STARTED;
- model->setRenderItemsNeedUpdate();
- } else {
- return;
- }
- }
-
- if (_materialNeedsUpdate && model->getGeometry()->areTexturesLoaded()) {
- model->setRenderItemsNeedUpdate();
- _materialNeedsUpdate = false;
- }
-
if (!args) {
return;
}
- if (!getShapeKey().isValid()) {
- return;
- }
gpu::Batch& batch = *(args->_batch);
auto locations = args->_shapePipeline->locations;
diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h
index 971c6fe90b..fb55883101 100644
--- a/libraries/render-utils/src/MeshPartPayload.h
+++ b/libraries/render-utils/src/MeshPartPayload.h
@@ -96,32 +96,32 @@ public:
render::ShapeKey getShapeKey() const override; // shape interface
void render(RenderArgs* args) override;
+ void setKey(bool isVisible, bool isLayered);
+ void setLayer(bool isLayeredInFront, bool isLayeredInHUD);
+ void setShapeKey(bool invalidateShapeKey, bool isWireframe);
+
// ModelMeshPartPayload functions to perform render
void bindMesh(gpu::Batch& batch) override;
void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override;
- void initCache();
-
void computeAdjustedLocalBound(const std::vector& clusterMatrices);
gpu::BufferPointer _clusterBuffer;
- ModelWeakPointer _model;
int _meshIndex;
int _shapeID;
bool _isSkinned{ false };
bool _isBlendShaped { false };
- bool _materialNeedsUpdate { true };
+ bool _hasTangents { false };
private:
+ void initCache(const ModelPointer& model);
- enum State : uint8_t {
- WAITING_TO_START = 0,
- STARTED = 1,
- };
-
- mutable State _state { WAITING_TO_START } ;
+ gpu::BufferPointer _blendedVertexBuffer;
+ render::ItemKey _itemKey { render::ItemKey::Builder::opaqueShape().build() };
+ render::ShapeKey _shapeKey { render::ShapeKey::Builder::invalid() };
+ int _layer { render::Item::LAYER_3D };
};
namespace render {
diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp
index c4bc435691..7717ceda6f 100644
--- a/libraries/render-utils/src/Model.cpp
+++ b/libraries/render-utils/src/Model.cpp
@@ -210,6 +210,24 @@ int Model::getRenderInfoTextureCount() {
return _renderInfoTextureCount;
}
+bool Model::shouldInvalidatePayloadShapeKey(int meshIndex) {
+ if (!getGeometry()) {
+ return true;
+ }
+
+ const FBXGeometry& geometry = getFBXGeometry();
+ const auto& networkMeshes = getGeometry()->getMeshes();
+ // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown
+ // to false to rebuild out mesh groups.
+ if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)geometry.meshes.size() || meshIndex >= (int)_meshStates.size()) {
+ _needsFixupInScene = true; // trigger remove/add cycle
+ invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid
+ return true;
+ }
+
+ return false;
+}
+
void Model::updateRenderItems() {
if (!_addedToScene) {
return;
@@ -237,6 +255,11 @@ void Model::updateRenderItems() {
Transform modelTransform = self->getTransform();
modelTransform.setScale(glm::vec3(1.0f));
+ bool isWireframe = self->isWireframe();
+ bool isVisible = self->isVisible();
+ bool isLayeredInFront = self->isLayeredInFront();
+ bool isLayeredInHUD = self->isLayeredInHUD();
+
render::Transaction transaction;
for (int i = 0; i < (int) self->_modelMeshRenderItemIDs.size(); i++) {
@@ -244,13 +267,20 @@ void Model::updateRenderItems() {
auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex;
auto clusterMatrices(self->getMeshState(meshIndex).clusterMatrices);
- transaction.updateItem(itemID, [modelTransform, clusterMatrices](ModelMeshPartPayload& data) {
+ bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
+
+ transaction.updateItem(itemID, [modelTransform, clusterMatrices, invalidatePayloadShapeKey,
+ isWireframe, isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
data.updateClusterBuffer(clusterMatrices);
Transform renderTransform = modelTransform;
if (clusterMatrices.size() == 1) {
renderTransform = modelTransform.worldTransform(Transform(clusterMatrices[0]));
}
data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
+
+ data.setKey(isVisible, isLayeredInFront || isLayeredInHUD);
+ data.setLayer(isLayeredInFront, isLayeredInHUD);
+ data.setShapeKey(invalidatePayloadShapeKey, isWireframe);
});
}
@@ -272,16 +302,6 @@ void Model::setRenderItemsNeedUpdate() {
emit requestRenderUpdate();
}
-void Model::initJointTransforms() {
- if (isLoaded()) {
- glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset);
- _rig.setModelOffset(modelOffset);
- }
-}
-
-void Model::init() {
-}
-
void Model::reset() {
if (isLoaded()) {
const FBXGeometry& geometry = getFBXGeometry();
diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h
index 7568a17342..50ccb22131 100644
--- a/libraries/render-utils/src/Model.h
+++ b/libraries/render-utils/src/Model.h
@@ -122,7 +122,6 @@ public:
void setIsWireframe(bool isWireframe) { _isWireframe = isWireframe; }
bool isWireframe() const { return _isWireframe; }
- void init();
void reset();
void setSnapModelToRegistrationPoint(bool snapModelToRegistrationPoint, const glm::vec3& registrationPoint);
@@ -346,11 +345,7 @@ protected:
// hook for derived classes to be notified when setUrl invalidates the current model.
virtual void onInvalidate() {};
-
-protected:
-
virtual void deleteGeometry();
- void initJointTransforms();
QVector _blendshapeCoefficients;
@@ -419,6 +414,8 @@ protected:
bool _isLayeredInFront { false };
bool _isLayeredInHUD { false };
+ bool shouldInvalidatePayloadShapeKey(int meshIndex);
+
private:
float _loadingPriority { 0.0f };
diff --git a/libraries/shared/src/PrioritySortUtil.h b/libraries/shared/src/PrioritySortUtil.h
index dc6a877bb9..279fa42ea4 100644
--- a/libraries/shared/src/PrioritySortUtil.h
+++ b/libraries/shared/src/PrioritySortUtil.h
@@ -28,7 +28,7 @@
glm::vec3 getPosition() const override { return _thing->getPosition(); }
float getRadius() const override { return 0.5f * _thing->getBoundingRadius(); }
uint64_t getTimestamp() const override { return _thing->getLastTime(); }
- const Thing& getThing() const { return _thing; }
+ Thing getThing() const { return _thing; }
private:
Thing _thing;
};
@@ -43,6 +43,13 @@
(3) Loop over your priority queue and do timeboxed work:
+ NOTE: Be careful using references to members of instances of T from std::priority_queue.
+ Under the hood std::priority_queue may re-use instances of T.
+ For example, after a pop() or a push() the top T may have the same memory address
+ as the top T before the pop() or push() (but point to a swapped instance of T).
+ This causes a reference to member variable of T to point to a different value
+ when operations taken on std::priority_queue shuffle around the instances of T.
+
uint64_t cutoffTime = usecTimestampNow() + TIME_BUDGET;
while (!sortedThings.empty()) {
const Thing& thing = sortedThings.top();
diff --git a/scripts/system/html/js/marketplacesInject.js b/scripts/system/html/js/marketplacesInject.js
index 698dd93f29..2b016884f1 100644
--- a/scripts/system/html/js/marketplacesInject.js
+++ b/scripts/system/html/js/marketplacesInject.js
@@ -250,7 +250,8 @@
itemName: name,
itemPrice: price ? parseInt(price, 10) : 0,
itemHref: href,
- referrer: referrer
+ referrer: referrer,
+ itemAuthor: author
}));
}
diff --git a/tests/gpu-test/src/TestShapes.cpp b/tests/gpu-test/src/TestShapes.cpp
index 253d89cf61..67a348c002 100644
--- a/tests/gpu-test/src/TestShapes.cpp
+++ b/tests/gpu-test/src/TestShapes.cpp
@@ -29,19 +29,18 @@ void TestShapes::renderTest(size_t testId, RenderArgs* args) {
float seconds = secTimestampNow() - startSecs;
seconds /= 4.0f;
batch.setModelTransform(Transform());
- batch._glColor4f(0.8f, 0.25f, 0.25f, 1.0f);
+ const auto color = glm::vec4(0.8f, 0.25f, 0.25f, 1.0f);
bool wire = (seconds - floorf(seconds) > 0.5f);
int shapeIndex = ((int)seconds) % TYPE_COUNT;
if (wire) {
- geometryCache->renderWireShape(batch, SHAPE[shapeIndex]);
+ geometryCache->renderWireShape(batch, SHAPE[shapeIndex], color);
} else {
- geometryCache->renderShape(batch, SHAPE[shapeIndex]);
+ geometryCache->renderShape(batch, SHAPE[shapeIndex], color);
}
batch.setModelTransform(Transform().setScale(1.01f));
- batch._glColor4f(1, 1, 1, 1);
- geometryCache->renderWireCube(batch);
+ geometryCache->renderWireCube(batch, glm::vec4(1,1,1,1));
}