Merge branch 'master' of github.com:highfidelity/hifi into 20778-pullFolderFromAndroid

This commit is contained in:
NissimHadar 2019-01-24 08:55:30 -08:00
commit e87d5abbd7
22 changed files with 181 additions and 97 deletions

View file

@ -919,6 +919,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
DependencyManager::set<Wallet>();
DependencyManager::set<WalletScriptingInterface>();
DependencyManager::set<TTSScriptingInterface>();
DependencyManager::set<QmlCommerce>();
DependencyManager::set<FadeEffect>();
DependencyManager::set<ResourceRequestObserver>();
@ -1200,6 +1201,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
connect(&domainHandler, SIGNAL(connectedToDomain(QUrl)), SLOT(updateWindowTitle()));
connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle()));
connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, [this]() {
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
if (tabletScriptingInterface) {
tabletScriptingInterface->setQmlTabletRoot(SYSTEM_TABLET, nullptr);
}
getOverlays().deleteOverlay(getTabletScreenID());
getOverlays().deleteOverlay(getTabletHomeButtonID());
getOverlays().deleteOverlay(getTabletFrameID());
@ -2598,6 +2603,7 @@ void Application::cleanupBeforeQuit() {
DependencyManager::destroy<ContextOverlayInterface>(); // Must be destroyed before TabletScriptingInterface
// stop QML
DependencyManager::destroy<QmlCommerce>();
DependencyManager::destroy<TabletScriptingInterface>();
DependencyManager::destroy<ToolbarScriptingInterface>();
DependencyManager::destroy<OffscreenUi>();
@ -2886,7 +2892,7 @@ void Application::initializeUi() {
Tooltip::registerType();
UpdateDialog::registerType();
QmlContextCallback commerceCallback = [](QQmlContext* context) {
context->setContextProperty("Commerce", new QmlCommerce());
context->setContextProperty("Commerce", DependencyManager::get<QmlCommerce>().data());
};
OffscreenQmlSurface::addWhitelistContextHandler({
QUrl{ "hifi/commerce/checkout/Checkout.qml" },
@ -2911,6 +2917,7 @@ void Application::initializeUi() {
QUrl{ "hifi/dialogs/security/SecurityImageChange.qml" },
QUrl{ "hifi/dialogs/security/SecurityImageModel.qml" },
QUrl{ "hifi/dialogs/security/SecurityImageSelection.qml" },
QUrl{ "hifi/tablet/TabletMenu.qml" },
}, commerceCallback);
QmlContextCallback ttsCallback = [](QQmlContext* context) {
context->setContextProperty("TextToSpeech", DependencyManager::get<TTSScriptingInterface>().data());
@ -8014,8 +8021,7 @@ void Application::openUrl(const QUrl& url) const {
if (url.scheme() == URL_SCHEME_HIFI) {
DependencyManager::get<AddressManager>()->handleLookupString(url.toString());
} else if (url.scheme() == URL_SCHEME_HIFIAPP) {
QmlCommerce commerce;
commerce.openSystemApp(url.path());
DependencyManager::get<QmlCommerce>()->openSystemApp(url.path());
} else {
// address manager did not handle - ask QDesktopServices to handle
QDesktopServices::openUrl(url);

View file

@ -767,7 +767,7 @@ void MyAvatar::simulate(float deltaTime, bool inView) {
auto headBoneSet = _skeletonModel->getCauterizeBoneSet();
forEachChild([&](SpatiallyNestablePointer object) {
bool isChildOfHead = headBoneSet.find(object->getParentJointIndex()) != headBoneSet.end();
if (isChildOfHead) {
if (isChildOfHead && !object->hasGrabs()) {
// Cauterize or display children of head per head drawing state.
updateChildCauterization(object, !_prevShouldDrawHead);
object->forEachDescendant([&](SpatiallyNestablePointer descendant) {
@ -817,7 +817,9 @@ void MyAvatar::simulate(float deltaTime, bool inView) {
// and all of its joints, now update our attachements.
Avatar::simulateAttachments(deltaTime);
relayJointDataToChildren();
updateGrabs();
if (updateGrabs()) {
_cauterizationNeedsUpdate = true;
}
if (!_skeletonModel->hasSkeleton()) {
// All the simulation that can be done has been done
@ -873,9 +875,13 @@ void MyAvatar::simulate(float deltaTime, bool inView) {
collisionlessAllowed = zone->getGhostingAllowed();
}
EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender();
bool force = false;
bool iShouldTellServer = true;
forEachDescendant([&](SpatiallyNestablePointer object) {
// we need to update attached queryAACubes in our own local tree so point-select always works
// however we don't want to flood the update pipeline with AvatarEntity updates, so we assume
// others have all info required to properly update queryAACube of AvatarEntities on their end
EntityItemPointer entity = std::dynamic_pointer_cast<EntityItem>(object);
bool iShouldTellServer = !(entity && entity->isAvatarEntity());
const bool force = false;
entityTree->updateEntityQueryAACube(object, packetSender, force, iShouldTellServer);
});
});

View file

@ -22,7 +22,9 @@
#include <ui/TabletScriptingInterface.h>
#include "scripting/HMDScriptingInterface.h"
QmlCommerce::QmlCommerce() {
QmlCommerce::QmlCommerce() :
_appsPath(PathUtils::getAppDataPath() + "Apps/")
{
auto ledger = DependencyManager::get<Ledger>();
auto wallet = DependencyManager::get<Wallet>();
connect(ledger.data(), &Ledger::buyResult, this, &QmlCommerce::buyResult);
@ -44,22 +46,18 @@ QmlCommerce::QmlCommerce() {
auto accountManager = DependencyManager::get<AccountManager>();
connect(accountManager.data(), &AccountManager::usernameChanged, this, [&]() { setPassphrase(""); });
_appsPath = PathUtils::getAppDataPath() + "Apps/";
}
void QmlCommerce::openSystemApp(const QString& appName) {
static QMap<QString, QString> systemApps {
static const QMap<QString, QString> systemApps {
{"GOTO", "hifi/tablet/TabletAddressDialog.qml"},
{"PEOPLE", "hifi/Pal.qml"},
{"WALLET", "hifi/commerce/wallet/Wallet.qml"},
{"MARKET", "/marketplace.html"}
};
static QMap<QString, QString> systemInject{
static const QMap<QString, QString> systemInject{
{"MARKET", "/scripts/system/html/js/marketplacesInject.js"}
};

View file

@ -19,7 +19,9 @@
#include <QPixmap>
class QmlCommerce : public QObject {
#include <DependencyManager.h>
class QmlCommerce : public QObject, public Dependency {
Q_OBJECT
public:
@ -98,7 +100,7 @@ protected:
Q_INVOKABLE void updateItem(const QString& certificateId);
private:
QString _appsPath;
const QString _appsPath;
};
#endif // hifi_QmlCommerce_h

View file

@ -134,13 +134,6 @@ void Web3DOverlay::destroyWebSurface() {
QQuickItem* rootItem = _webSurface->getRootItem();
if (rootItem && rootItem->objectName() == "tabletRoot") {
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
if (tabletScriptingInterface) {
tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", nullptr);
}
}
// Fix for crash in QtWebEngineCore when rapidly switching domains
// Call stop on the QWebEngineView before destroying OffscreenQMLSurface.
if (rootItem) {

View file

@ -1984,11 +1984,10 @@ void Rig::copyJointsIntoJointData(QVector<JointData>& jointDataVec) const {
data.rotation = !_sendNetworkNode ? _internalPoseSet._absolutePoses[i].rot() : _networkPoseSet._absolutePoses[i].rot();
data.rotationIsDefaultPose = isEqual(data.rotation, defaultAbsRot);
// translations are in relative frame but scaled so that they are in meters,
// instead of model units.
// translations are in relative frame.
glm::vec3 defaultRelTrans = _animSkeleton->getRelativeDefaultPose(i).trans();
glm::vec3 currentRelTrans = _sendNetworkNode ? _networkPoseSet._relativePoses[i].trans() : _internalPoseSet._relativePoses[i].trans();
data.translation = geometryToRigScale * currentRelTrans;
data.translation = currentRelTrans;
data.translationIsDefaultPose = isEqual(currentRelTrans, defaultRelTrans);
} else {
data.translationIsDefaultPose = true;
@ -2015,7 +2014,6 @@ void Rig::copyJointsFromJointData(const QVector<JointData>& jointDataVec) {
std::vector<glm::quat> rotations;
rotations.reserve(numJoints);
const glm::quat rigToGeometryRot(glmExtractRotation(_rigToGeometryTransform));
const glm::vec3 rigToGeometryScale(extractScale(_rigToGeometryTransform));
for (int i = 0; i < numJoints; i++) {
const JointData& data = jointDataVec.at(i);
@ -2041,8 +2039,8 @@ void Rig::copyJointsFromJointData(const QVector<JointData>& jointDataVec) {
if (data.translationIsDefaultPose) {
_internalPoseSet._relativePoses[i].trans() = relativeDefaultPoses[i].trans();
} else {
// JointData translations are in scaled relative-frame so we scale back to regular relative-frame
_internalPoseSet._relativePoses[i].trans() = rigToGeometryScale * data.translation;
// JointData translations are in relative-frame
_internalPoseSet._relativePoses[i].trans() = data.translation;
}
}
}

View file

@ -324,8 +324,8 @@ void Avatar::removeAvatarEntitiesFromTree() {
}
}
void Avatar::updateGrabs() {
bool Avatar::updateGrabs() {
bool grabAddedOrRemoved = false;
// update the Grabs according to any changes in _avatarGrabData
_avatarGrabsLock.withWriteLock([&] {
if (_avatarGrabDataChanged) {
@ -385,6 +385,7 @@ void Avatar::updateGrabs() {
entityTree->updateEntityQueryAACube(target, packetSender, force, iShouldTellServer);
});
}
grabAddedOrRemoved = true;
}
_avatarGrabs.remove(grabID);
_changedAvatarGrabs.remove(grabID);
@ -402,9 +403,11 @@ void Avatar::updateGrabs() {
target->addGrab(grab);
// only clear this entry from the _changedAvatarGrabs if we found the entity.
changeItr.remove();
grabAddedOrRemoved = true;
}
}
});
return grabAddedOrRemoved;
}
void Avatar::accumulateGrabPositions(std::map<QUuid, GrabLocationAccumulator>& grabAccumulators) {

View file

@ -538,7 +538,7 @@ protected:
// protected methods...
bool isLookingAtMe(AvatarSharedPointer avatar) const;
void updateGrabs();
bool updateGrabs();
void relayJointDataToChildren();
void fade(render::Transaction& transaction, render::Transition::Type type);

View file

@ -54,7 +54,8 @@ using namespace std;
const QString AvatarData::FRAME_NAME = "com.highfidelity.recording.AvatarData";
static const int TRANSLATION_COMPRESSION_RADIX = 12;
static const int TRANSLATION_COMPRESSION_RADIX = 14;
static const int FAUX_JOINT_COMPRESSION_RADIX = 12;
static const int SENSOR_TO_WORLD_SCALE_RADIX = 10;
static const float AUDIO_LOUDNESS_SCALE = 1024.0f;
static const float DEFAULT_AVATAR_DENSITY = 1000.0f; // density of water
@ -73,6 +74,7 @@ size_t AvatarDataPacket::maxJointDataSize(size_t numJoints, bool hasGrabJoints)
totalSize += validityBitsSize; // Orientations mask
totalSize += numJoints * sizeof(SixByteQuat); // Orientations
totalSize += validityBitsSize; // Translations mask
totalSize += sizeof(float); // maxTranslationDimension
totalSize += numJoints * sizeof(SixByteTrans); // Translations
size_t NUM_FAUX_JOINT = 2;
@ -85,6 +87,23 @@ size_t AvatarDataPacket::maxJointDataSize(size_t numJoints, bool hasGrabJoints)
return totalSize;
}
size_t AvatarDataPacket::minJointDataSize(size_t numJoints) {
const size_t validityBitsSize = calcBitVectorSize((int)numJoints);
size_t totalSize = sizeof(uint8_t); // numJoints
totalSize += validityBitsSize; // Orientations mask
// assume no valid rotations
totalSize += validityBitsSize; // Translations mask
totalSize += sizeof(float); // maxTranslationDimension
// assume no valid translations
size_t NUM_FAUX_JOINT = 2;
totalSize += NUM_FAUX_JOINT * (sizeof(SixByteQuat) + sizeof(SixByteTrans)); // faux joints
return totalSize;
}
size_t AvatarDataPacket::maxJointDefaultPoseFlagsSize(size_t numJoints) {
const size_t bitVectorSize = calcBitVectorSize((int)numJoints);
size_t totalSize = sizeof(uint8_t); // numJoints
@ -611,13 +630,24 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
assert(numJoints <= 255);
const int jointBitVectorSize = calcBitVectorSize(numJoints);
// Start joints if room for at least the faux joints.
IF_AVATAR_SPACE(PACKET_HAS_JOINT_DATA, 1 + 2 * jointBitVectorSize + AvatarDataPacket::FAUX_JOINTS_SIZE) {
// include jointData if there is room for the most minimal section. i.e. no translations or rotations.
IF_AVATAR_SPACE(PACKET_HAS_JOINT_DATA, AvatarDataPacket::minJointDataSize(numJoints)) {
// Allow for faux joints + translation bit-vector:
const ptrdiff_t minSizeForJoint = sizeof(AvatarDataPacket::SixByteQuat)
+ jointBitVectorSize + AvatarDataPacket::FAUX_JOINTS_SIZE;
auto startSection = destinationBuffer;
// compute maxTranslationDimension before we send any joint data.
float maxTranslationDimension = 0.001f;
for (int i = sendStatus.rotationsSent; i < numJoints; ++i) {
const JointData& data = jointData[i];
if (!data.translationIsDefaultPose) {
maxTranslationDimension = glm::max(fabsf(data.translation.x), maxTranslationDimension);
maxTranslationDimension = glm::max(fabsf(data.translation.y), maxTranslationDimension);
maxTranslationDimension = glm::max(fabsf(data.translation.z), maxTranslationDimension);
}
}
// joint rotation data
*destinationBuffer++ = (uint8_t)numJoints;
@ -684,9 +714,11 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
memset(destinationBuffer, 0, jointBitVectorSize);
destinationBuffer += jointBitVectorSize; // Move pointer past the validity bytes
// write maxTranslationDimension
AVATAR_MEMCPY(maxTranslationDimension);
float minTranslation = (distanceAdjust && cullSmallChanges) ? getDistanceBasedMinTranslationDistance(viewerPosition) : AVATAR_MIN_TRANSLATION;
float maxTranslationDimension = 0.0;
i = sendStatus.translationsSent;
for (; i < numJoints; ++i) {
const JointData& data = joints[i];
@ -700,12 +732,8 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
#ifdef WANT_DEBUG
translationSentCount++;
#endif
maxTranslationDimension = glm::max(fabsf(data.translation.x), maxTranslationDimension);
maxTranslationDimension = glm::max(fabsf(data.translation.y), maxTranslationDimension);
maxTranslationDimension = glm::max(fabsf(data.translation.z), maxTranslationDimension);
destinationBuffer +=
packFloatVec3ToSignedTwoByteFixed(destinationBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX);
destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, data.translation / maxTranslationDimension,
TRANSLATION_COMPRESSION_RADIX);
if (sentJoints) {
sentJoints[i].translation = data.translation;
@ -727,12 +755,12 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
Transform controllerLeftHandTransform = Transform(getControllerLeftHandMatrix());
destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, controllerLeftHandTransform.getRotation());
destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, controllerLeftHandTransform.getTranslation(),
TRANSLATION_COMPRESSION_RADIX);
FAUX_JOINT_COMPRESSION_RADIX);
Transform controllerRightHandTransform = Transform(getControllerRightHandMatrix());
destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, controllerRightHandTransform.getRotation());
destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, controllerRightHandTransform.getTranslation(),
TRANSLATION_COMPRESSION_RADIX);
FAUX_JOINT_COMPRESSION_RADIX);
IF_AVATAR_SPACE(PACKET_HAS_GRAB_JOINTS, sizeof (AvatarDataPacket::FarGrabJoints)) {
// the far-grab joints may range further than 3 meters, so we can't use packFloatVec3ToSignedTwoByteFixed etc
@ -785,7 +813,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
outboundDataRateOut->jointDataRate.increment(numBytes);
}
}
IF_AVATAR_SPACE(PACKET_HAS_JOINT_DEFAULT_POSE_FLAGS, 1 + 2 * jointBitVectorSize) {
auto startSection = destinationBuffer;
@ -871,7 +899,7 @@ const unsigned char* unpackFauxJoint(const unsigned char* sourceBuffer, ThreadSa
glm::vec3 position;
Transform transform;
sourceBuffer += unpackOrientationQuatFromSixBytes(sourceBuffer, orientation);
sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, position, TRANSLATION_COMPRESSION_RADIX);
sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, position, FAUX_JOINT_COMPRESSION_RADIX);
transform.setTranslation(position);
transform.setRotation(orientation);
matrixCache.set(transform.getMatrix());
@ -1280,6 +1308,12 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
}
} // 1 + bytesOfValidity bytes
// read maxTranslationDimension
float maxTranslationDimension;
PACKET_READ_CHECK(JointMaxTranslationDimension, sizeof(float));
memcpy(&maxTranslationDimension, sourceBuffer, sizeof(float));
sourceBuffer += sizeof(float);
// each joint translation component is stored in 6 bytes.
const int COMPRESSED_TRANSLATION_SIZE = 6;
PACKET_READ_CHECK(JointTranslation, numValidJointTranslations * COMPRESSED_TRANSLATION_SIZE);
@ -1288,6 +1322,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
JointData& data = _jointData[i];
if (validTranslations[i]) {
sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX);
data.translation *= maxTranslationDimension;
_hasNewJointData = true;
data.translationIsDefaultPose = false;
}

View file

@ -277,8 +277,8 @@ namespace AvatarDataPacket {
uint8_t rotationValidityBits[ceil(numJoints / 8)]; // one bit per joint, if true then a compressed rotation follows.
SixByteQuat rotation[numValidRotations]; // encodeded and compressed by packOrientationQuatToSixBytes()
uint8_t translationValidityBits[ceil(numJoints / 8)]; // one bit per joint, if true then a compressed translation follows.
SixByteTrans translation[numValidTranslations]; // encodeded and compressed by packFloatVec3ToSignedTwoByteFixed()
float maxTranslationDimension; // used to normalize fixed point translation values.
SixByteTrans translation[numValidTranslations]; // normalized and compressed by packFloatVec3ToSignedTwoByteFixed()
SixByteQuat leftHandControllerRotation;
SixByteTrans leftHandControllerTranslation;
SixByteQuat rightHandControllerRotation;
@ -286,6 +286,7 @@ namespace AvatarDataPacket {
};
*/
size_t maxJointDataSize(size_t numJoints, bool hasGrabJoints);
size_t minJointDataSize(size_t numJoints);
/*
struct JointDefaultPoseFlags {

View file

@ -841,10 +841,14 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* @property {number} priority=0 - The priority for applying the material to its parent. Only the highest priority material is
* applied, with materials of the same priority randomly assigned. Materials that come with the model have a priority of
* <code>0</code>.
* @property {string|number} parentMaterialName="0" - Selects the submesh or submeshes within the parent to apply the material
* to. If in the format <code>"mat::string"</code>, all submeshes with material name <code>"string"</code> are replaced.
* Otherwise the property value is parsed as an unsigned integer, specifying the mesh index to modify. Invalid values are
* parsed to <code>0</code>.
* @property {string} parentMaterialName="0" - Selects the mesh part or parts within the parent to which to apply the material.
* If in the format <code>"mat::string"</code>, all mesh parts with material name <code>"string"</code> are replaced.
* Otherwise the property value is parsed as an unsigned integer, specifying the mesh part index to modify. If <code>"all"</code>,
* all mesh parts will be replaced. If an array (starts with <code>"["</code> and ends with <code>"]"</code>), the string will be
* split at each <code>","</code> and each element will be parsed as either a number or a string if it starts with
* <code>"mat::"</code>. In other words, <code>"[0,1,mat::string,mat::string2]"</code> will replace mesh parts 0 and 1, and any
* mesh parts with material <code>"string"</code> or <code>"string2"</code>. Do not put spaces around the commas. Invalid values
* are parsed to <code>0</code>.
* @property {string} materialMappingMode="uv" - How the material is mapped to the entity. Either <code>"uv"</code> or
* <code>"projected"</code>. In "uv" mode, the material will be evaluated within the UV space of the mesh it is applied to. In
* "projected" mode, the 3D transform of the Material Entity will be used to evaluate the texture coordinates for the material.

View file

@ -3008,8 +3008,8 @@ void EntityTree::updateEntityQueryAACubeWorker(SpatiallyNestablePointer object,
// if the queryBox has changed, tell the entity-server
EntityItemPointer entity = std::dynamic_pointer_cast<EntityItem>(object);
if (entity) {
bool tellServerThis = tellServer && (entity->getEntityHostType() != entity::HostType::AVATAR);
if ((entity->updateQueryAACube() || force)) {
// NOTE: we rely on side-effects of the entity->updateQueryAACube() call in the following if() conditional:
if (entity->updateQueryAACube() || force) {
bool success;
AACube newCube = entity->getQueryAACube(success);
if (success) {
@ -3017,7 +3017,7 @@ void EntityTree::updateEntityQueryAACubeWorker(SpatiallyNestablePointer object,
}
// send an edit packet to update the entity-server about the queryAABox. We do this for domain-hosted
// entities as well as for avatar-entities; the packet-sender will route the update accordingly
if (tellServerThis && packetSender && (entity->isDomainEntity() || entity->isAvatarEntity())) {
if (tellServer && packetSender && (entity->isDomainEntity() || entity->isAvatarEntity())) {
quint64 now = usecTimestampNow();
EntityItemProperties properties = entity->getProperties();
properties.setQueryAACubeDirty();

View file

@ -38,10 +38,10 @@ PacketVersion versionForPacketType(PacketType packetType) {
return static_cast<PacketVersion>(EntityQueryPacketVersion::ConicalFrustums);
case PacketType::AvatarIdentity:
case PacketType::AvatarData:
return static_cast<PacketVersion>(AvatarMixerPacketVersion::CollisionFlag);
return static_cast<PacketVersion>(AvatarMixerPacketVersion::SendMaxTranslationDimension);
case PacketType::BulkAvatarData:
case PacketType::KillAvatar:
return static_cast<PacketVersion>(AvatarMixerPacketVersion::FasterAvatarEntities);
return static_cast<PacketVersion>(AvatarMixerPacketVersion::SendMaxTranslationDimension);
case PacketType::MessagesData:
return static_cast<PacketVersion>(MessageDataVersion::TextOrBinaryData);
// ICE packets

View file

@ -312,7 +312,8 @@ enum class AvatarMixerPacketVersion : PacketVersion {
GrabTraits,
CollisionFlag,
AvatarTraitsAck,
FasterAvatarEntities
FasterAvatarEntities,
SendMaxTranslationDimension
};
enum class DomainConnectRequestVersion : PacketVersion {

View file

@ -1486,29 +1486,56 @@ bool Model::isRenderable() const {
return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty());
}
std::vector<unsigned int> Model::getMeshIDsFromMaterialID(QString parentMaterialName) {
// try to find all meshes with materials that match parentMaterialName as a string
// if none, return parentMaterialName as a uint
std::vector<unsigned int> toReturn;
const QString MATERIAL_NAME_PREFIX = "mat::";
if (parentMaterialName.startsWith(MATERIAL_NAME_PREFIX)) {
parentMaterialName.replace(0, MATERIAL_NAME_PREFIX.size(), QString(""));
for (unsigned int i = 0; i < (unsigned int)_modelMeshMaterialNames.size(); i++) {
if (_modelMeshMaterialNames[i] == parentMaterialName.toStdString()) {
toReturn.push_back(i);
}
}
}
std::set<unsigned int> Model::getMeshIDsFromMaterialID(QString parentMaterialName) {
std::set<unsigned int> toReturn;
if (toReturn.empty()) {
toReturn.push_back(parentMaterialName.toUInt());
const QString all("all");
if (parentMaterialName == all) {
for (unsigned int i = 0; i < (unsigned int)_modelMeshRenderItemIDs.size(); i++) {
toReturn.insert(i);
}
} else if (!parentMaterialName.isEmpty()) {
auto parseFunc = [this, &toReturn] (QString& target) {
if (target.isEmpty()) {
return;
}
// if target starts with "mat::", try to find all meshes with materials that match target as a string
// otherwise, return target as a uint
const QString MATERIAL_NAME_PREFIX("mat::");
if (target.startsWith(MATERIAL_NAME_PREFIX)) {
std::string targetStdString = target.replace(0, MATERIAL_NAME_PREFIX.size(), "").toStdString();
for (unsigned int i = 0; i < (unsigned int)_modelMeshMaterialNames.size(); i++) {
if (_modelMeshMaterialNames[i] == targetStdString) {
toReturn.insert(i);
}
}
return;
}
toReturn.insert(target.toUInt());
};
if (parentMaterialName.length() > 2 && parentMaterialName.startsWith("[") && parentMaterialName.endsWith("]")) {
QStringList list = parentMaterialName.split(",", QString::SkipEmptyParts);
for (int i = 0; i < list.length(); i++) {
auto& target = list[i];
if (i == 0) {
target = target.replace(0, 1, "");
}
if (i == list.length() - 1) {
target = target.replace(target.length() - 1, 1, "");
}
parseFunc(target);
}
} else {
parseFunc(parentMaterialName);
}
}
return toReturn;
}
void Model::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {
std::vector<unsigned int> shapeIDs = getMeshIDsFromMaterialID(QString(parentMaterialName.c_str()));
std::set<unsigned int> shapeIDs = getMeshIDsFromMaterialID(QString(parentMaterialName.c_str()));
render::Transaction transaction;
for (auto shapeID : shapeIDs) {
if (shapeID < _modelMeshRenderItemIDs.size()) {
@ -1531,7 +1558,7 @@ void Model::addMaterial(graphics::MaterialLayer material, const std::string& par
}
void Model::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {
std::vector<unsigned int> shapeIDs = getMeshIDsFromMaterialID(QString(parentMaterialName.c_str()));
std::set<unsigned int> shapeIDs = getMeshIDsFromMaterialID(QString(parentMaterialName.c_str()));
render::Transaction transaction;
for (auto shapeID : shapeIDs) {
if (shapeID < _modelMeshRenderItemIDs.size()) {

View file

@ -513,7 +513,7 @@ private:
void calculateTextureInfo();
std::vector<unsigned int> getMeshIDsFromMaterialID(QString parentMaterialName);
std::set<unsigned int> getMeshIDsFromMaterialID(QString parentMaterialName);
};
Q_DECLARE_METATYPE(ModelPointer)

View file

@ -14,7 +14,7 @@ public:
};
// Used by the avatar mixer to describe a single joint
// Translations relative to their parent and are in meters.
// Translations relative to their parent joint
// Rotations are absolute (i.e. not relative to parent) and are in rig space.
class JointData {
public:

View file

@ -82,15 +82,18 @@ private:
}
#ifdef OCULUS_APP_ID
if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) {
if (ovr_PlatformInitializeWindows(OCULUS_APP_ID) != ovrPlatformInitialize_Success) {
qCWarning(oculusLog) << "Unable to initialize the platform for entitlement check - fail the check" << ovr::getError();
return;
} else {
qCDebug(oculusLog) << "Performing Oculus Platform entitlement check";
ovr_Entitlement_GetIsViewerEntitled();
static std::once_flag once;
std::call_once(once, []() {
if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) {
if (ovr_PlatformInitializeWindows(OCULUS_APP_ID) != ovrPlatformInitialize_Success) {
qCWarning(oculusLog) << "Unable to initialize the platform for entitlement check - fail the check" << ovr::getError();
return;
} else {
qCDebug(oculusLog) << "Performing Oculus Platform entitlement check";
ovr_Entitlement_GetIsViewerEntitled();
}
}
}
});
#endif
ovrGraphicsLuid luid;

View file

@ -11,7 +11,7 @@
Entities, enableDispatcherModule, disableDispatcherModule, entityIsGrabbable, makeDispatcherModuleParameters, MSECS_PER_SEC,
HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC,
projectOntoEntityXYPlane, ContextOverlay, HMD, Picks, makeLaserLockInfo, makeLaserParams, AddressManager,
getEntityParents, Selection, DISPATCHER_HOVERING_LIST, unhighlightTargetEntity, Messages, findGroupParent,
getEntityParents, Selection, DISPATCHER_HOVERING_LIST, unhighlightTargetEntity, Messages, findGrabbableGroupParent,
worldPositionToRegistrationFrameMatrix, DISPATCHER_PROPERTIES
*/
@ -308,7 +308,7 @@ Script.include("/~/system/libraries/controllers.js");
var gtProps = Entities.getEntityProperties(targetEntity, DISPATCHER_PROPERTIES);
if (entityIsGrabbable(gtProps)) {
// if we've attempted to grab a child, roll up to the root of the tree
var groupRootProps = findGroupParent(controllerData, gtProps);
var groupRootProps = findGrabbableGroupParent(controllerData, gtProps);
if (entityIsGrabbable(groupRootProps)) {
return groupRootProps;
}

View file

@ -8,9 +8,10 @@
/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, getControllerJointIndex, enableDispatcherModule,
disableDispatcherModule, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, TRIGGER_OFF_VALUE,
makeDispatcherModuleParameters, entityIsGrabbable, makeRunningValues, NEAR_GRAB_RADIUS, findGroupParent, Vec3, cloneEntity,
entityIsCloneable, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, distanceBetweenPointAndEntityBoundingBox,
getGrabbableData, getEnabledModuleByName, DISPATCHER_PROPERTIES, HMD, NEAR_GRAB_DISTANCE
makeDispatcherModuleParameters, entityIsGrabbable, makeRunningValues, NEAR_GRAB_RADIUS, findGrabbableGroupParent, Vec3,
cloneEntity, entityIsCloneable, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE,
distanceBetweenPointAndEntityBoundingBox, getGrabbableData, getEnabledModuleByName, DISPATCHER_PROPERTIES, HMD,
NEAR_GRAB_DISTANCE
*/
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
@ -80,9 +81,6 @@ Script.include("/~/system/libraries/controllers.js");
this.endNearGrabEntity = function () {
this.endGrab();
this.grabbing = false;
this.targetEntityID = null;
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
Entities.callEntityMethod(this.targetEntityID, "releaseGrab", args);
Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({
@ -90,6 +88,9 @@ Script.include("/~/system/libraries/controllers.js");
grabbedEntity: this.targetEntityID,
joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"
}));
this.grabbing = false;
this.targetEntityID = null;
};
this.getTargetProps = function (controllerData) {
@ -110,7 +111,7 @@ Script.include("/~/system/libraries/controllers.js");
if (entityIsGrabbable(props) || entityIsCloneable(props)) {
if (!entityIsCloneable(props)) {
// if we've attempted to grab a non-cloneable child, roll up to the root of the tree
var groupRootProps = findGroupParent(controllerData, props);
var groupRootProps = findGrabbableGroupParent(controllerData, props);
if (entityIsGrabbable(groupRootProps)) {
return groupRootProps;
}

View file

@ -47,7 +47,7 @@
makeLaserLockInfo:true,
entityHasActions:true,
ensureDynamic:true,
findGroupParent:true,
findGrabbableGroupParent:true,
BUMPER_ON_VALUE:true,
getEntityParents:true,
findHandChildEntities:true,
@ -451,7 +451,7 @@ ensureDynamic = function (entityID) {
}
};
findGroupParent = function (controllerData, targetProps) {
findGrabbableGroupParent = function (controllerData, targetProps) {
while (targetProps.grab.grabDelegateToParent &&
targetProps.parentID &&
targetProps.parentID !== Uuid.NULL &&
@ -460,6 +460,9 @@ findGroupParent = function (controllerData, targetProps) {
if (!parentProps) {
break;
}
if (!entityIsGrabbable(parentProps)) {
break;
}
parentProps.id = targetProps.parentID;
targetProps = parentProps;
controllerData.nearbyEntityPropertiesByID[targetProps.id] = targetProps;
@ -605,7 +608,7 @@ if (typeof module !== 'undefined') {
unhighlightTargetEntity: unhighlightTargetEntity,
clearHighlightedEntities: clearHighlightedEntities,
makeRunningValues: makeRunningValues,
findGroupParent: findGroupParent,
findGrabbableGroupParent: findGrabbableGroupParent,
LEFT_HAND: LEFT_HAND,
RIGHT_HAND: RIGHT_HAND,
BUMPER_ON_VALUE: BUMPER_ON_VALUE,

View file

@ -379,6 +379,9 @@ function decode_avatar_data_packet(buf)
i = i + num_validity_bytes
result["valid_translations"] = "Valid Translations: " .. string.format("(%d/%d) {", #indices, num_joints) .. table.concat(indices, ", ") .. "}"
-- TODO: skip maxTranslationDimension
i = i + 4
-- TODO: skip translations for now
i = i + #indices * 6