mirror of
https://github.com/lubosz/overte.git
synced 2025-04-08 10:43:56 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into scale-wearables-with-avatar-3
This commit is contained in:
commit
96197e66bb
33 changed files with 243 additions and 189 deletions
|
@ -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 <b>will not</b> be added to your <b>Purchases</b>. 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 = '<i>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.</i>';
|
||||
buyTextContainer.color = hifi.colors.white;
|
||||
buyTextContainer.border.color = hifi.colors.white;
|
||||
buyGlyph.text = "";
|
||||
buyGlyph.size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Wallet>();
|
||||
QString signature = key.isEmpty() ? "" : wallet->signWithKey(text, key);
|
||||
QString signature = wallet->signWithKey(text, key);
|
||||
QJsonObject request;
|
||||
request[propertyName] = QString(text);
|
||||
if (!controlled_failure) {
|
||||
|
|
|
@ -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<ReceivedMessage> 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();
|
||||
|
|
|
@ -24,7 +24,6 @@ ModelOverlay::ModelOverlay()
|
|||
: _model(std::make_shared<Model>(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;
|
||||
|
|
|
@ -138,7 +138,6 @@ Avatar::~Avatar() {
|
|||
|
||||
void Avatar::init() {
|
||||
getHead()->init();
|
||||
_skeletonModel->init();
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -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; });
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<GeometryCache>()->bindWebBrowserProgram(batch, fadeRatio < OPAQUE_ALPHA_THRESHOLD);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, texMin, texMax, glm::vec4(1.0f, 1.0f, 1.0f, fadeRatio), _geometryId);
|
||||
|
|
|
@ -2551,7 +2551,8 @@ bool EntityItemProperties::verifySignature(const QString& publicKey, const QByte
|
|||
return false;
|
||||
}
|
||||
|
||||
const unsigned char* key = reinterpret_cast<const unsigned char*>(publicKey.toUtf8().constData());
|
||||
auto keyByteArray = publicKey.toUtf8();
|
||||
auto key = keyByteArray.constData();
|
||||
int keyLength = publicKey.length();
|
||||
|
||||
BIO *bio = BIO_new_mem_buf((void*)key, keyLength);
|
||||
|
@ -2569,19 +2570,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) {
|
||||
|
@ -2590,7 +2595,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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -253,6 +253,7 @@ protected:
|
|||
|
||||
struct InputStageState {
|
||||
bool _invalidFormat { true };
|
||||
bool _hadColorAttribute{ true };
|
||||
Stream::FormatPointer _format;
|
||||
std::string _formatKey;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -30,7 +30,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
|||
case PacketType::EntityEdit:
|
||||
case PacketType::EntityData:
|
||||
case PacketType::EntityPhysics:
|
||||
return static_cast<PacketVersion>(EntityVersion::StaticCertJsonVersionOne);
|
||||
return static_cast<PacketVersion>(EntityVersion::OwnershipChallengeFix);
|
||||
|
||||
case PacketType::EntityQuery:
|
||||
return static_cast<PacketVersion>(EntityQueryPacketVersion::ConnectionIdentifier);
|
||||
|
|
|
@ -200,7 +200,8 @@ enum class EntityVersion : PacketVersion {
|
|||
StrokeColorProperty = 77,
|
||||
HasDynamicOwnershipTests,
|
||||
HazeEffect,
|
||||
StaticCertJsonVersionOne
|
||||
StaticCertJsonVersionOne,
|
||||
OwnershipChallengeFix,
|
||||
};
|
||||
|
||||
enum class EntityScriptCallMethodVersion : PacketVersion {
|
||||
|
|
|
@ -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<NLPacket>& bufferedPacket = _pendingEditPackets[nodeUUID].first; //only a NLPacket for now
|
||||
|
|
|
@ -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<CauterizedModel*>(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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<CauterizedMeshPartPayload>(itemID, [modelTransform, clusterMatrices, clusterMatricesCauterized](CauterizedMeshPartPayload& data) {
|
||||
bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
|
||||
|
||||
transaction.updateItem<CauterizedMeshPartPayload>(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);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<glm::mat4>& 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 {
|
||||
|
|
|
@ -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<ModelMeshPartPayload>(itemID, [modelTransform, clusterMatrices](ModelMeshPartPayload& data) {
|
||||
bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
|
||||
|
||||
transaction.updateItem<ModelMeshPartPayload>(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();
|
||||
|
|
|
@ -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<float> _blendshapeCoefficients;
|
||||
|
||||
|
@ -419,6 +414,8 @@ protected:
|
|||
bool _isLayeredInFront { false };
|
||||
bool _isLayeredInHUD { false };
|
||||
|
||||
bool shouldInvalidatePayloadShapeKey(int meshIndex);
|
||||
|
||||
private:
|
||||
float _loadingPriority { 0.0f };
|
||||
|
||||
|
|
|
@ -250,7 +250,8 @@
|
|||
itemName: name,
|
||||
itemPrice: price ? parseInt(price, 10) : 0,
|
||||
itemHref: href,
|
||||
referrer: referrer
|
||||
referrer: referrer,
|
||||
itemAuthor: author
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue