mirror of
https://github.com/lubosz/overte.git
synced 2025-04-24 09:23:17 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into spectator-camera
This commit is contained in:
commit
d786820670
20 changed files with 717 additions and 84 deletions
|
@ -604,6 +604,24 @@ void Agent::processAgentAvatar() {
|
|||
|
||||
AvatarData::AvatarDataDetail dataDetail = (randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO) ? AvatarData::SendAllData : AvatarData::CullSmallData;
|
||||
QByteArray avatarByteArray = scriptedAvatar->toByteArrayStateful(dataDetail);
|
||||
|
||||
int maximumByteArraySize = NLPacket::maxPayloadSize(PacketType::AvatarData) - sizeof(AvatarDataSequenceNumber);
|
||||
|
||||
if (avatarByteArray.size() > maximumByteArraySize) {
|
||||
qWarning() << " scriptedAvatar->toByteArrayStateful() resulted in very large buffer:" << avatarByteArray.size() << "... attempt to drop facial data";
|
||||
avatarByteArray = scriptedAvatar->toByteArrayStateful(dataDetail, true);
|
||||
|
||||
if (avatarByteArray.size() > maximumByteArraySize) {
|
||||
qWarning() << " scriptedAvatar->toByteArrayStateful() without facial data resulted in very large buffer:" << avatarByteArray.size() << "... reduce to MinimumData";
|
||||
avatarByteArray = scriptedAvatar->toByteArrayStateful(AvatarData::MinimumData, true);
|
||||
|
||||
if (avatarByteArray.size() > maximumByteArraySize) {
|
||||
qWarning() << " scriptedAvatar->toByteArrayStateful() MinimumData resulted in very large buffer:" << avatarByteArray.size() << "... FAIL!!";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scriptedAvatar->doneEncoding(true);
|
||||
|
||||
static AvatarDataSequenceNumber sequenceNumber = 0;
|
||||
|
|
|
@ -85,7 +85,22 @@ void AvatarMixer::handleReplicatedPacket(QSharedPointer<ReceivedMessage> message
|
|||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
auto nodeID = QUuid::fromRfc4122(message->peek(NUM_BYTES_RFC4122_UUID));
|
||||
|
||||
auto replicatedNode = addOrUpdateReplicatedNode(nodeID, message->getSenderSockAddr());
|
||||
SharedNodePointer replicatedNode;
|
||||
|
||||
if (message->getType() == PacketType::ReplicatedKillAvatar) {
|
||||
// this is a kill packet, which we should only process if we already have the node in our list
|
||||
// since it of course does not make sense to add a node just to remove it an instant later
|
||||
replicatedNode = nodeList->nodeWithUUID(nodeID);
|
||||
|
||||
if (!replicatedNode) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
replicatedNode = addOrUpdateReplicatedNode(nodeID, message->getSenderSockAddr());
|
||||
}
|
||||
|
||||
// we better have a node to work with at this point
|
||||
assert(replicatedNode);
|
||||
|
||||
if (message->getType() == PacketType::ReplicatedAvatarIdentity) {
|
||||
handleAvatarIdentityPacket(message, replicatedNode);
|
||||
|
|
|
@ -383,11 +383,11 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
|||
qCWarning(avatars) << "otherAvatar.toByteArray() without facial data resulted in very large buffer:" << bytes.size() << "... reduce to MinimumData";
|
||||
bytes = otherAvatar->toByteArray(AvatarData::MinimumData, lastEncodeForOther, lastSentJointsForOther,
|
||||
hasFlagsOut, dropFaceTracking, distanceAdjust, viewerPosition, &lastSentJointsForOther);
|
||||
}
|
||||
|
||||
if (bytes.size() > MAX_ALLOWED_AVATAR_DATA) {
|
||||
qCWarning(avatars) << "otherAvatar.toByteArray() MinimumData resulted in very large buffer:" << bytes.size() << "... FAIL!!";
|
||||
includeThisAvatar = false;
|
||||
if (bytes.size() > MAX_ALLOWED_AVATAR_DATA) {
|
||||
qCWarning(avatars) << "otherAvatar.toByteArray() MinimumData resulted in very large buffer:" << bytes.size() << "... FAIL!!";
|
||||
includeThisAvatar = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "ScriptableAvatar.h"
|
||||
|
||||
|
||||
QByteArray ScriptableAvatar::toByteArrayStateful(AvatarDataDetail dataDetail) {
|
||||
QByteArray ScriptableAvatar::toByteArrayStateful(AvatarDataDetail dataDetail, bool dropFaceTracking) {
|
||||
_globalPosition = getPosition();
|
||||
return AvatarData::toByteArrayStateful(dataDetail);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
Q_INVOKABLE AnimationDetails getAnimationDetails();
|
||||
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override;
|
||||
|
||||
virtual QByteArray toByteArrayStateful(AvatarDataDetail dataDetail) override;
|
||||
virtual QByteArray toByteArrayStateful(AvatarDataDetail dataDetail, bool dropFaceTracking = false) override;
|
||||
|
||||
|
||||
private slots:
|
||||
|
|
|
@ -99,7 +99,13 @@ StackView {
|
|||
height: parent.height
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: keyboard.top
|
||||
}
|
||||
|
||||
propagateComposedEvents: true
|
||||
onPressed: {
|
||||
parent.forceActiveFocus();
|
||||
|
|
|
@ -295,7 +295,7 @@ void MyAvatar::simulateAttachments(float deltaTime) {
|
|||
// don't update attachments here, do it in harvestResultsFromPhysicsSimulation()
|
||||
}
|
||||
|
||||
QByteArray MyAvatar::toByteArrayStateful(AvatarDataDetail dataDetail) {
|
||||
QByteArray MyAvatar::toByteArrayStateful(AvatarDataDetail dataDetail, bool dropFaceTracking) {
|
||||
CameraMode mode = qApp->getCamera().getMode();
|
||||
_globalPosition = getPosition();
|
||||
// This might not be right! Isn't the capsule local offset in avatar space, and don't we need to add the radius to the y as well? -HRS 5/26/17
|
||||
|
@ -1356,6 +1356,7 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
|||
Avatar::setSkeletonModelURL(skeletonModelURL);
|
||||
_skeletonModel->setVisibleInScene(true, qApp->getMain3DScene());
|
||||
_headBoneSet.clear();
|
||||
emit skeletonChanged();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -606,12 +606,13 @@ signals:
|
|||
void onLoadComplete();
|
||||
void wentAway();
|
||||
void wentActive();
|
||||
void skeletonChanged();
|
||||
|
||||
private:
|
||||
|
||||
bool requiresSafeLanding(const glm::vec3& positionIn, glm::vec3& positionOut);
|
||||
|
||||
virtual QByteArray toByteArrayStateful(AvatarDataDetail dataDetail) override;
|
||||
virtual QByteArray toByteArrayStateful(AvatarDataDetail dataDetail, bool dropFaceTracking) override;
|
||||
|
||||
void simulate(float deltaTime);
|
||||
void updateFromTrackers(float deltaTime);
|
||||
|
|
|
@ -451,7 +451,7 @@ void Web3DOverlay::handlePointerEventAsTouch(const PointerEvent& event) {
|
|||
// In Qt 5.9 mouse events must be sent before touch events to make sure some QtQuick components will
|
||||
// receive mouse events
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
|
||||
if (!(this->_pressed && event.getType() == PointerEvent::Move)) {
|
||||
if (event.getType() == PointerEvent::Move) {
|
||||
QMouseEvent* mouseEvent = new QMouseEvent(mouseType, windowPoint, windowPoint, windowPoint, button, buttons, Qt::NoModifier);
|
||||
QCoreApplication::postEvent(_webSurface->getWindow(), mouseEvent);
|
||||
}
|
||||
|
@ -459,11 +459,10 @@ void Web3DOverlay::handlePointerEventAsTouch(const PointerEvent& event) {
|
|||
QCoreApplication::postEvent(_webSurface->getWindow(), touchEvent);
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 9, 0)
|
||||
if (this->_pressed && event.getType() == PointerEvent::Move) {
|
||||
return;
|
||||
if (event.getType() == PointerEvent::Move) {
|
||||
QMouseEvent* mouseEvent = new QMouseEvent(mouseType, windowPoint, windowPoint, windowPoint, button, buttons, Qt::NoModifier);
|
||||
QCoreApplication::postEvent(_webSurface->getWindow(), mouseEvent);
|
||||
}
|
||||
QMouseEvent* mouseEvent = new QMouseEvent(mouseType, windowPoint, windowPoint, windowPoint, button, buttons, Qt::NoModifier);
|
||||
QCoreApplication::postEvent(_webSurface->getWindow(), mouseEvent);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,27 @@ static const float DEFAULT_AVATAR_DENSITY = 1000.0f; // density of water
|
|||
|
||||
#define ASSERT(COND) do { if (!(COND)) { abort(); } } while(0)
|
||||
|
||||
size_t AvatarDataPacket::maxFaceTrackerInfoSize(size_t numBlendshapeCoefficients) {
|
||||
return FACE_TRACKER_INFO_SIZE + numBlendshapeCoefficients * sizeof(float);
|
||||
}
|
||||
|
||||
size_t AvatarDataPacket::maxJointDataSize(size_t numJoints) {
|
||||
const size_t validityBitsSize = (size_t)std::ceil(numJoints / (float)BITS_IN_BYTE);
|
||||
|
||||
size_t totalSize = sizeof(uint8_t); // numJoints
|
||||
|
||||
totalSize += validityBitsSize; // Orientations mask
|
||||
totalSize += numJoints * sizeof(SixByteQuat); // Orientations
|
||||
totalSize += validityBitsSize; // Translations mask
|
||||
totalSize += numJoints * sizeof(SixByteTrans); // Translations
|
||||
|
||||
size_t NUM_FAUX_JOINT = 2;
|
||||
totalSize += NUM_FAUX_JOINT * (sizeof(SixByteQuat) + sizeof(SixByteTrans)); // faux joints
|
||||
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
|
||||
AvatarData::AvatarData() :
|
||||
SpatiallyNestable(NestableType::Avatar, QUuid()),
|
||||
_handPosition(0.0f),
|
||||
|
@ -73,19 +94,6 @@ AvatarData::AvatarData() :
|
|||
setBodyPitch(0.0f);
|
||||
setBodyYaw(-90.0f);
|
||||
setBodyRoll(0.0f);
|
||||
|
||||
ASSERT(sizeof(AvatarDataPacket::Header) == AvatarDataPacket::HEADER_SIZE);
|
||||
ASSERT(sizeof(AvatarDataPacket::AvatarGlobalPosition) == AvatarDataPacket::AVATAR_GLOBAL_POSITION_SIZE);
|
||||
ASSERT(sizeof(AvatarDataPacket::AvatarLocalPosition) == AvatarDataPacket::AVATAR_LOCAL_POSITION_SIZE);
|
||||
ASSERT(sizeof(AvatarDataPacket::AvatarBoundingBox) == AvatarDataPacket::AVATAR_BOUNDING_BOX_SIZE);
|
||||
ASSERT(sizeof(AvatarDataPacket::AvatarOrientation) == AvatarDataPacket::AVATAR_ORIENTATION_SIZE);
|
||||
ASSERT(sizeof(AvatarDataPacket::AvatarScale) == AvatarDataPacket::AVATAR_SCALE_SIZE);
|
||||
ASSERT(sizeof(AvatarDataPacket::LookAtPosition) == AvatarDataPacket::LOOK_AT_POSITION_SIZE);
|
||||
ASSERT(sizeof(AvatarDataPacket::AudioLoudness) == AvatarDataPacket::AUDIO_LOUDNESS_SIZE);
|
||||
ASSERT(sizeof(AvatarDataPacket::SensorToWorldMatrix) == AvatarDataPacket::SENSOR_TO_WORLD_SIZE);
|
||||
ASSERT(sizeof(AvatarDataPacket::AdditionalFlags) == AvatarDataPacket::ADDITIONAL_FLAGS_SIZE);
|
||||
ASSERT(sizeof(AvatarDataPacket::ParentInfo) == AvatarDataPacket::PARENT_INFO_SIZE);
|
||||
ASSERT(sizeof(AvatarDataPacket::FaceTrackerInfo) == AvatarDataPacket::FACE_TRACKER_INFO_SIZE);
|
||||
}
|
||||
|
||||
AvatarData::~AvatarData() {
|
||||
|
@ -169,12 +177,12 @@ float AvatarData::getDistanceBasedMinTranslationDistance(glm::vec3 viewerPositio
|
|||
|
||||
|
||||
// we want to track outbound data in this case...
|
||||
QByteArray AvatarData::toByteArrayStateful(AvatarDataDetail dataDetail) {
|
||||
QByteArray AvatarData::toByteArrayStateful(AvatarDataDetail dataDetail, bool dropFaceTracking) {
|
||||
AvatarDataPacket::HasFlags hasFlagsOut;
|
||||
auto lastSentTime = _lastToByteArray;
|
||||
_lastToByteArray = usecTimestampNow();
|
||||
return AvatarData::toByteArray(dataDetail, lastSentTime, getLastSentJointData(),
|
||||
hasFlagsOut, false, false, glm::vec3(0), nullptr,
|
||||
hasFlagsOut, dropFaceTracking, false, glm::vec3(0), nullptr,
|
||||
&_outboundDataRate);
|
||||
}
|
||||
|
||||
|
@ -189,15 +197,11 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
|||
|
||||
lazyInitHeadData();
|
||||
|
||||
QByteArray avatarDataByteArray(udt::MAX_PACKET_SIZE, 0);
|
||||
unsigned char* destinationBuffer = reinterpret_cast<unsigned char*>(avatarDataByteArray.data());
|
||||
unsigned char* startPosition = destinationBuffer;
|
||||
|
||||
// special case, if we were asked for no data, then just include the flags all set to nothing
|
||||
if (dataDetail == NoData) {
|
||||
AvatarDataPacket::HasFlags packetStateFlags = 0;
|
||||
memcpy(destinationBuffer, &packetStateFlags, sizeof(packetStateFlags));
|
||||
return avatarDataByteArray.left(sizeof(packetStateFlags));
|
||||
QByteArray avatarDataByteArray(reinterpret_cast<char*>(&packetStateFlags), sizeof(packetStateFlags));
|
||||
return avatarDataByteArray;
|
||||
}
|
||||
|
||||
// FIXME -
|
||||
|
@ -258,6 +262,15 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
|||
hasJointData = sendAll || !sendMinimum;
|
||||
}
|
||||
|
||||
|
||||
const size_t byteArraySize = AvatarDataPacket::MAX_CONSTANT_HEADER_SIZE +
|
||||
(hasFaceTrackerInfo ? AvatarDataPacket::maxFaceTrackerInfoSize(_headData->getNumSummedBlendshapeCoefficients()) : 0) +
|
||||
(hasJointData ? AvatarDataPacket::maxJointDataSize(_jointData.size()) : 0);
|
||||
|
||||
QByteArray avatarDataByteArray((int)byteArraySize, 0);
|
||||
unsigned char* destinationBuffer = reinterpret_cast<unsigned char*>(avatarDataByteArray.data());
|
||||
unsigned char* startPosition = destinationBuffer;
|
||||
|
||||
// Leading flags, to indicate how much data is actually included in the packet...
|
||||
AvatarDataPacket::HasFlags packetStateFlags =
|
||||
(hasAvatarGlobalPosition ? AvatarDataPacket::PACKET_HAS_AVATAR_GLOBAL_POSITION : 0)
|
||||
|
@ -478,12 +491,15 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
|||
unsigned char* validityPosition = destinationBuffer;
|
||||
unsigned char validity = 0;
|
||||
int validityBit = 0;
|
||||
int numValidityBytes = (int)std::ceil(numJoints / (float)BITS_IN_BYTE);
|
||||
|
||||
#ifdef WANT_DEBUG
|
||||
int rotationSentCount = 0;
|
||||
unsigned char* beforeRotations = destinationBuffer;
|
||||
#endif
|
||||
|
||||
destinationBuffer += numValidityBytes; // Move pointer past the validity bytes
|
||||
|
||||
if (sentJointDataOut) {
|
||||
sentJointDataOut->resize(_jointData.size()); // Make sure the destination is resized before using it
|
||||
}
|
||||
|
@ -503,6 +519,8 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
|||
#ifdef WANT_DEBUG
|
||||
rotationSentCount++;
|
||||
#endif
|
||||
destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, data.rotation);
|
||||
|
||||
if (sentJointDataOut) {
|
||||
auto jointDataOut = *sentJointDataOut;
|
||||
jointDataOut[i].rotation = data.rotation;
|
||||
|
@ -512,28 +530,14 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
|||
}
|
||||
}
|
||||
if (++validityBit == BITS_IN_BYTE) {
|
||||
*destinationBuffer++ = validity;
|
||||
*validityPosition++ = validity;
|
||||
validityBit = validity = 0;
|
||||
}
|
||||
}
|
||||
if (validityBit != 0) {
|
||||
*destinationBuffer++ = validity;
|
||||
*validityPosition++ = validity;
|
||||
}
|
||||
|
||||
validityBit = 0;
|
||||
validity = *validityPosition++;
|
||||
for (int i = 0; i < _jointData.size(); i++) {
|
||||
const JointData& data = _jointData[i];
|
||||
if (validity & (1 << validityBit)) {
|
||||
destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, data.rotation);
|
||||
}
|
||||
if (++validityBit == BITS_IN_BYTE) {
|
||||
validityBit = 0;
|
||||
validity = *validityPosition++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// joint translation data
|
||||
validityPosition = destinationBuffer;
|
||||
validity = 0;
|
||||
|
@ -544,6 +548,8 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
|||
unsigned char* beforeTranslations = destinationBuffer;
|
||||
#endif
|
||||
|
||||
destinationBuffer += numValidityBytes; // Move pointer past the validity bytes
|
||||
|
||||
float minTranslation = !distanceAdjust ? AVATAR_MIN_TRANSLATION : getDistanceBasedMinTranslationDistance(viewerPosition);
|
||||
|
||||
float maxTranslationDimension = 0.0;
|
||||
|
@ -562,6 +568,9 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
|||
maxTranslationDimension = glm::max(fabsf(data.translation.y), maxTranslationDimension);
|
||||
maxTranslationDimension = glm::max(fabsf(data.translation.z), maxTranslationDimension);
|
||||
|
||||
destinationBuffer +=
|
||||
packFloatVec3ToSignedTwoByteFixed(destinationBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX);
|
||||
|
||||
if (sentJointDataOut) {
|
||||
auto jointDataOut = *sentJointDataOut;
|
||||
jointDataOut[i].translation = data.translation;
|
||||
|
@ -571,27 +580,13 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
|||
}
|
||||
}
|
||||
if (++validityBit == BITS_IN_BYTE) {
|
||||
*destinationBuffer++ = validity;
|
||||
*validityPosition++ = validity;
|
||||
validityBit = validity = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (validityBit != 0) {
|
||||
*destinationBuffer++ = validity;
|
||||
}
|
||||
|
||||
validityBit = 0;
|
||||
validity = *validityPosition++;
|
||||
for (int i = 0; i < _jointData.size(); i++) {
|
||||
const JointData& data = _jointData[i];
|
||||
if (validity & (1 << validityBit)) {
|
||||
destinationBuffer +=
|
||||
packFloatVec3ToSignedTwoByteFixed(destinationBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX);
|
||||
}
|
||||
if (++validityBit == BITS_IN_BYTE) {
|
||||
validityBit = 0;
|
||||
validity = *validityPosition++;
|
||||
}
|
||||
*validityPosition++ = validity;
|
||||
}
|
||||
|
||||
// faux joints
|
||||
|
@ -624,6 +619,12 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
|||
}
|
||||
|
||||
int avatarDataSize = destinationBuffer - startPosition;
|
||||
|
||||
if (avatarDataSize > (int)byteArraySize) {
|
||||
qCCritical(avatars) << "AvatarData::toByteArray buffer overflow"; // We've overflown into the heap
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
return avatarDataByteArray.left(avatarDataSize);
|
||||
}
|
||||
// NOTE: This is never used in a "distanceAdjust" mode, so it's ok that it doesn't use a variable minimum rotation/translation
|
||||
|
@ -1743,6 +1744,24 @@ void AvatarData::sendAvatarDataPacket() {
|
|||
bool cullSmallData = (randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO);
|
||||
auto dataDetail = cullSmallData ? SendAllData : CullSmallData;
|
||||
QByteArray avatarByteArray = toByteArrayStateful(dataDetail);
|
||||
|
||||
int maximumByteArraySize = NLPacket::maxPayloadSize(PacketType::AvatarData) - sizeof(AvatarDataSequenceNumber);
|
||||
|
||||
if (avatarByteArray.size() > maximumByteArraySize) {
|
||||
qCWarning(avatars) << "toByteArrayStateful() resulted in very large buffer:" << avatarByteArray.size() << "... attempt to drop facial data";
|
||||
avatarByteArray = toByteArrayStateful(dataDetail, true);
|
||||
|
||||
if (avatarByteArray.size() > maximumByteArraySize) {
|
||||
qCWarning(avatars) << "toByteArrayStateful() without facial data resulted in very large buffer:" << avatarByteArray.size() << "... reduce to MinimumData";
|
||||
avatarByteArray = toByteArrayStateful(MinimumData, true);
|
||||
|
||||
if (avatarByteArray.size() > maximumByteArraySize) {
|
||||
qCWarning(avatars) << "toByteArrayStateful() MinimumData resulted in very large buffer:" << avatarByteArray.size() << "... FAIL!!";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
doneEncoding(cullSmallData);
|
||||
|
||||
static AvatarDataSequenceNumber sequenceNumber = 0;
|
||||
|
|
|
@ -140,35 +140,41 @@ namespace AvatarDataPacket {
|
|||
const HasFlags PACKET_HAS_JOINT_DATA = 1U << 11;
|
||||
const size_t AVATAR_HAS_FLAGS_SIZE = 2;
|
||||
|
||||
using SixByteQuat = uint8_t[6];
|
||||
using SixByteTrans = uint8_t[6];
|
||||
|
||||
// NOTE: AvatarDataPackets start with a uint16_t sequence number that is not reflected in the Header structure.
|
||||
|
||||
PACKED_BEGIN struct Header {
|
||||
HasFlags packetHasFlags; // state flags, indicated which additional records are included in the packet
|
||||
} PACKED_END;
|
||||
const size_t HEADER_SIZE = 2;
|
||||
static_assert(sizeof(Header) == HEADER_SIZE, "AvatarDataPacket::Header size doesn't match.");
|
||||
|
||||
PACKED_BEGIN struct AvatarGlobalPosition {
|
||||
float globalPosition[3]; // avatar's position
|
||||
} PACKED_END;
|
||||
const size_t AVATAR_GLOBAL_POSITION_SIZE = 12;
|
||||
static_assert(sizeof(AvatarGlobalPosition) == AVATAR_GLOBAL_POSITION_SIZE, "AvatarDataPacket::AvatarGlobalPosition size doesn't match.");
|
||||
|
||||
PACKED_BEGIN struct AvatarBoundingBox {
|
||||
float avatarDimensions[3]; // avatar's bounding box in world space units, but relative to the position.
|
||||
float boundOriginOffset[3]; // offset from the position of the avatar to the origin of the bounding box
|
||||
} PACKED_END;
|
||||
const size_t AVATAR_BOUNDING_BOX_SIZE = 24;
|
||||
static_assert(sizeof(AvatarBoundingBox) == AVATAR_BOUNDING_BOX_SIZE, "AvatarDataPacket::AvatarBoundingBox size doesn't match.");
|
||||
|
||||
|
||||
using SixByteQuat = uint8_t[6];
|
||||
PACKED_BEGIN struct AvatarOrientation {
|
||||
SixByteQuat avatarOrientation; // encodeded and compressed by packOrientationQuatToSixBytes()
|
||||
} PACKED_END;
|
||||
const size_t AVATAR_ORIENTATION_SIZE = 6;
|
||||
static_assert(sizeof(AvatarOrientation) == AVATAR_ORIENTATION_SIZE, "AvatarDataPacket::AvatarOrientation size doesn't match.");
|
||||
|
||||
PACKED_BEGIN struct AvatarScale {
|
||||
SmallFloat scale; // avatar's scale, compressed by packFloatRatioToTwoByte()
|
||||
} PACKED_END;
|
||||
const size_t AVATAR_SCALE_SIZE = 2;
|
||||
static_assert(sizeof(AvatarScale) == AVATAR_SCALE_SIZE, "AvatarDataPacket::AvatarScale size doesn't match.");
|
||||
|
||||
PACKED_BEGIN struct LookAtPosition {
|
||||
float lookAtPosition[3]; // world space position that eyes are focusing on.
|
||||
|
@ -180,11 +186,13 @@ namespace AvatarDataPacket {
|
|||
// POTENTIAL SAVINGS - 12 bytes
|
||||
} PACKED_END;
|
||||
const size_t LOOK_AT_POSITION_SIZE = 12;
|
||||
static_assert(sizeof(LookAtPosition) == LOOK_AT_POSITION_SIZE, "AvatarDataPacket::LookAtPosition size doesn't match.");
|
||||
|
||||
PACKED_BEGIN struct AudioLoudness {
|
||||
uint8_t audioLoudness; // current loudness of microphone compressed with packFloatGainToByte()
|
||||
} PACKED_END;
|
||||
const size_t AUDIO_LOUDNESS_SIZE = 1;
|
||||
static_assert(sizeof(AudioLoudness) == AUDIO_LOUDNESS_SIZE, "AvatarDataPacket::AudioLoudness size doesn't match.");
|
||||
|
||||
PACKED_BEGIN struct SensorToWorldMatrix {
|
||||
// FIXME - these 20 bytes are only used by viewers if my avatar has "attachments"
|
||||
|
@ -199,11 +207,13 @@ namespace AvatarDataPacket {
|
|||
// relative to the avatar position.
|
||||
} PACKED_END;
|
||||
const size_t SENSOR_TO_WORLD_SIZE = 20;
|
||||
static_assert(sizeof(SensorToWorldMatrix) == SENSOR_TO_WORLD_SIZE, "AvatarDataPacket::SensorToWorldMatrix size doesn't match.");
|
||||
|
||||
PACKED_BEGIN struct AdditionalFlags {
|
||||
uint8_t flags; // additional flags: hand state, key state, eye tracking
|
||||
} PACKED_END;
|
||||
const size_t ADDITIONAL_FLAGS_SIZE = 1;
|
||||
static_assert(sizeof(AdditionalFlags) == ADDITIONAL_FLAGS_SIZE, "AvatarDataPacket::AdditionalFlags size doesn't match.");
|
||||
|
||||
// only present if HAS_REFERENTIAL flag is set in AvatarInfo.flags
|
||||
PACKED_BEGIN struct ParentInfo {
|
||||
|
@ -211,6 +221,7 @@ namespace AvatarDataPacket {
|
|||
uint16_t parentJointIndex;
|
||||
} PACKED_END;
|
||||
const size_t PARENT_INFO_SIZE = 18;
|
||||
static_assert(sizeof(ParentInfo) == PARENT_INFO_SIZE, "AvatarDataPacket::ParentInfo size doesn't match.");
|
||||
|
||||
// will only ever be included if the avatar has a parent but can change independent of changes to parent info
|
||||
// and so we keep it a separate record
|
||||
|
@ -218,6 +229,22 @@ namespace AvatarDataPacket {
|
|||
float localPosition[3]; // parent frame translation of the avatar
|
||||
} PACKED_END;
|
||||
const size_t AVATAR_LOCAL_POSITION_SIZE = 12;
|
||||
static_assert(sizeof(AvatarLocalPosition) == AVATAR_LOCAL_POSITION_SIZE, "AvatarDataPacket::AvatarLocalPosition size doesn't match.");
|
||||
|
||||
const size_t MAX_CONSTANT_HEADER_SIZE = HEADER_SIZE +
|
||||
AVATAR_GLOBAL_POSITION_SIZE +
|
||||
AVATAR_BOUNDING_BOX_SIZE +
|
||||
AVATAR_ORIENTATION_SIZE +
|
||||
AVATAR_SCALE_SIZE +
|
||||
LOOK_AT_POSITION_SIZE +
|
||||
AUDIO_LOUDNESS_SIZE +
|
||||
SENSOR_TO_WORLD_SIZE +
|
||||
ADDITIONAL_FLAGS_SIZE +
|
||||
PARENT_INFO_SIZE +
|
||||
AVATAR_LOCAL_POSITION_SIZE;
|
||||
|
||||
|
||||
// variable length structure follows
|
||||
|
||||
// only present if IS_FACE_TRACKER_CONNECTED flag is set in AvatarInfo.flags
|
||||
PACKED_BEGIN struct FaceTrackerInfo {
|
||||
|
@ -229,8 +256,9 @@ namespace AvatarDataPacket {
|
|||
// float blendshapeCoefficients[numBlendshapeCoefficients];
|
||||
} PACKED_END;
|
||||
const size_t FACE_TRACKER_INFO_SIZE = 17;
|
||||
static_assert(sizeof(FaceTrackerInfo) == FACE_TRACKER_INFO_SIZE, "AvatarDataPacket::FaceTrackerInfo size doesn't match.");
|
||||
size_t maxFaceTrackerInfoSize(size_t numBlendshapeCoefficients);
|
||||
|
||||
// variable length structure follows
|
||||
/*
|
||||
struct JointData {
|
||||
uint8_t numJoints;
|
||||
|
@ -240,6 +268,7 @@ namespace AvatarDataPacket {
|
|||
SixByteTrans translation[numValidTranslations]; // encodeded and compressed by packFloatVec3ToSignedTwoByteFixed()
|
||||
};
|
||||
*/
|
||||
size_t maxJointDataSize(size_t numJoints);
|
||||
}
|
||||
|
||||
static const float MAX_AVATAR_SCALE = 1000.0f;
|
||||
|
@ -387,7 +416,7 @@ public:
|
|||
SendAllData
|
||||
} AvatarDataDetail;
|
||||
|
||||
virtual QByteArray toByteArrayStateful(AvatarDataDetail dataDetail);
|
||||
virtual QByteArray toByteArrayStateful(AvatarDataDetail dataDetail, bool dropFaceTracking = false);
|
||||
|
||||
virtual QByteArray toByteArray(AvatarDataDetail dataDetail, quint64 lastSentTime, const QVector<JointData>& lastSentJointData,
|
||||
AvatarDataPacket::HasFlags& hasFlagsOut, bool dropFaceTracking, bool distanceAdjust, glm::vec3 viewerPosition,
|
||||
|
|
|
@ -83,6 +83,11 @@ static const QMap<QString, int>& getBlendshapesLookupMap() {
|
|||
return blendshapeLookupMap;
|
||||
}
|
||||
|
||||
int HeadData::getNumSummedBlendshapeCoefficients() const {
|
||||
int maxSize = std::max(_blendshapeCoefficients.size(), _transientBlendshapeCoefficients.size());
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
const QVector<float>& HeadData::getSummedBlendshapeCoefficients() {
|
||||
int maxSize = std::max(_blendshapeCoefficients.size(), _transientBlendshapeCoefficients.size());
|
||||
if (_summedBlendshapeCoefficients.size() != maxSize) {
|
||||
|
|
|
@ -57,6 +57,7 @@ public:
|
|||
void setBlendshape(QString name, float val);
|
||||
const QVector<float>& getBlendshapeCoefficients() const { return _blendshapeCoefficients; }
|
||||
const QVector<float>& getSummedBlendshapeCoefficients();
|
||||
int getNumSummedBlendshapeCoefficients() const;
|
||||
void setBlendshapeCoefficients(const QVector<float>& blendshapeCoefficients) { _blendshapeCoefficients = blendshapeCoefficients; }
|
||||
|
||||
const glm::vec3& getLookAtPosition() const { return _lookAtPosition; }
|
||||
|
|
|
@ -197,8 +197,12 @@ public:
|
|||
*lockWaitOut = (endLock - start);
|
||||
}
|
||||
|
||||
std::vector<SharedNodePointer> nodes(_nodeHash.size());
|
||||
std::transform(_nodeHash.cbegin(), _nodeHash.cend(), nodes.begin(), [](const NodeHash::value_type& it) {
|
||||
// Size of _nodeHash could change at any time,
|
||||
// so reserve enough memory for the current size
|
||||
// and then back insert all the nodes found
|
||||
std::vector<SharedNodePointer> nodes;
|
||||
nodes.reserve(_nodeHash.size());
|
||||
std::transform(_nodeHash.cbegin(), _nodeHash.cend(), std::back_inserter(nodes), [&](const NodeHash::value_type& it) {
|
||||
return it.second;
|
||||
});
|
||||
auto endTransform = usecTimestampNow();
|
||||
|
|
|
@ -831,7 +831,9 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even
|
|||
mouseEvent->screenPos(), mouseEvent->button(),
|
||||
mouseEvent->buttons(), mouseEvent->modifiers());
|
||||
if (event->type() == QEvent::MouseMove) {
|
||||
_qmlContext->setContextProperty("lastMousePosition", transformedPos);
|
||||
// TODO - this line necessary for the QML Tooltop to work (which is not currently being used), but it causes interface to crash on launch on a fresh install
|
||||
// need to investigate into why this crash is happening.
|
||||
//_qmlContext->setContextProperty("lastMousePosition", transformedPos);
|
||||
}
|
||||
mappedEvent.ignore();
|
||||
if (QCoreApplication::sendEvent(_quickWindow, &mappedEvent)) {
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
/* global MyAvatar, Entities, Script, Camera, Vec3, Reticle, Overlays, getEntityCustomData, Messages, Quat, Controller */
|
||||
/* global MyAvatar, Entities, Script, Camera, Vec3, Reticle, Overlays, getEntityCustomData, Messages, Quat, Controller,
|
||||
isInEditMode, HMD */
|
||||
|
||||
|
||||
(function() { // BEGIN LOCAL_SCOPE
|
||||
|
@ -22,6 +23,8 @@
|
|||
Script.include("/~/system/libraries/utils.js");
|
||||
var MAX_SOLID_ANGLE = 0.01; // objects that appear smaller than this can't be grabbed
|
||||
|
||||
var DELAY_FOR_30HZ = 33; // milliseconds
|
||||
|
||||
var ZERO_VEC3 = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
|
@ -46,7 +49,7 @@ var ACTION_TTL = 10; // seconds
|
|||
function getTag() {
|
||||
return "grab-" + MyAvatar.sessionUUID;
|
||||
}
|
||||
|
||||
|
||||
var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position
|
||||
var DISTANCE_HOLDING_UNITY_MASS = 1200; // The mass at which the distance holding action timeframe is unmodified
|
||||
var DISTANCE_HOLDING_UNITY_DISTANCE = 6; // The distance at which the distance holding action timeframe is unmodified
|
||||
|
@ -411,10 +414,15 @@ Grabber.prototype.pressEvent = function(event) {
|
|||
};
|
||||
|
||||
Grabber.prototype.releaseEvent = function(event) {
|
||||
if (event.isLeftButton!==true ||event.isRightButton===true || event.isMiddleButton===true) {
|
||||
if (event.isLeftButton!==true || event.isRightButton===true || event.isMiddleButton===true) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.moveEventTimer) {
|
||||
Script.clearTimeout(this.moveEventTimer);
|
||||
this.moveEventTimer = null;
|
||||
}
|
||||
|
||||
if (this.isGrabbing) {
|
||||
// this.deactivateEntity(this.entityID);
|
||||
this.isGrabbing = false;
|
||||
|
@ -439,12 +447,28 @@ Grabber.prototype.releaseEvent = function(event) {
|
|||
}
|
||||
};
|
||||
|
||||
Grabber.prototype.scheduleMouseMoveProcessor = function(event) {
|
||||
var _this = this;
|
||||
if (!this.moveEventTimer) {
|
||||
this.moveEventTimer = Script.setTimeout(function() {
|
||||
_this.moveEventProcess();
|
||||
}, DELAY_FOR_30HZ);
|
||||
}
|
||||
};
|
||||
|
||||
Grabber.prototype.moveEvent = function(event) {
|
||||
// during the handling of the event, do as little as possible. We save the updated mouse position,
|
||||
// and start a timer to react to the change. If more changes arrive before the timer fires, only
|
||||
// the last update will be considered. This is done to avoid backing-up Qt's event queue.
|
||||
if (!this.isGrabbing) {
|
||||
return;
|
||||
}
|
||||
mouse.updateDrag(event);
|
||||
this.scheduleMouseMoveProcessor();
|
||||
};
|
||||
|
||||
Grabber.prototype.moveEventProcess = function() {
|
||||
this.moveEventTimer = null;
|
||||
// see if something added/restored gravity
|
||||
var entityProperties = Entities.getEntityProperties(this.entityID);
|
||||
if (!entityProperties || !entityProperties.gravity) {
|
||||
|
@ -489,7 +513,7 @@ Grabber.prototype.moveEvent = function(event) {
|
|||
|
||||
} else {
|
||||
var newPointOnPlane;
|
||||
|
||||
|
||||
if (this.mode === "verticalCylinder") {
|
||||
// for this mode we recompute the plane based on current Camera
|
||||
var planeNormal = Quat.getForward(Camera.getOrientation());
|
||||
|
@ -505,7 +529,7 @@ Grabber.prototype.moveEvent = function(event) {
|
|||
};
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
newPointOnPlane = mouseIntersectionWithPlane(
|
||||
this.pointOnPlane, this.planeNormal, mouse.current, this.maxDistance);
|
||||
var relativePosition = Vec3.subtract(newPointOnPlane, cameraPosition);
|
||||
|
@ -538,6 +562,8 @@ Grabber.prototype.moveEvent = function(event) {
|
|||
} else {
|
||||
Entities.updateAction(this.entityID, this.actionID, actionArgs);
|
||||
}
|
||||
|
||||
this.scheduleMouseMoveProcessor();
|
||||
};
|
||||
|
||||
Grabber.prototype.keyReleaseEvent = function(event) {
|
||||
|
|
|
@ -14,8 +14,6 @@ Script.include(Script.resolvePath("../libraries/utils.js"));
|
|||
Script.include(Script.resolvePath("../libraries/controllers.js"));
|
||||
Script.include(Script.resolvePath("../libraries/Xform.js"));
|
||||
|
||||
var VEC3_ZERO = {x: 0, y: 0, z: 0};
|
||||
var X_AXIS = {x: 1, y: 0, z: 0};
|
||||
var Y_AXIS = {x: 0, y: 1, z: 0};
|
||||
var DEFAULT_DPI = 34;
|
||||
var DEFAULT_WIDTH = 0.4375;
|
||||
|
@ -25,12 +23,13 @@ var CAMERA_MATRIX = -7;
|
|||
var ROT_Y_180 = {x: 0.0, y: 1.0, z: 0, w: 0};
|
||||
var ROT_LANDSCAPE = {x: 1.0, y: 1.0, z: 0, w: 0};
|
||||
var ROT_LANDSCAPE_WINDOW = {x: 0.0, y: 0.0, z: 0.0, w: 0};
|
||||
var ROT_IDENT = {x: 0, y: 0, z: 0, w: 1};
|
||||
var TABLET_TEXTURE_RESOLUTION = { x: 480, y: 706 };
|
||||
var INCHES_TO_METERS = 1 / 39.3701;
|
||||
var AVATAR_SELF_ID = "{00000000-0000-0000-0000-000000000001}";
|
||||
|
||||
var NO_HANDS = -1;
|
||||
var DELAY_FOR_30HZ = 33; // milliseconds
|
||||
|
||||
|
||||
// will need to be recaclulated if dimensions of fbx model change.
|
||||
var TABLET_NATURAL_DIMENSIONS = {x: 33.797, y: 50.129, z: 2.269};
|
||||
|
@ -561,9 +560,29 @@ function rayIntersectPlane(planePosition, planeNormal, rayStart, rayDirection) {
|
|||
}
|
||||
}
|
||||
|
||||
WebTablet.prototype.scheduleMouseMoveProcessor = function() {
|
||||
var _this = this;
|
||||
if (!this.moveEventTimer) {
|
||||
this.moveEventTimer = Script.setTimeout(function() {
|
||||
_this.mouseMoveProcessor();
|
||||
}, DELAY_FOR_30HZ);
|
||||
}
|
||||
};
|
||||
|
||||
WebTablet.prototype.mouseMoveEvent = function (event) {
|
||||
if (this.dragging) {
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
this.currentMouse = {
|
||||
x: event.x,
|
||||
y: event.y
|
||||
};
|
||||
this.scheduleMouseMoveProcessor();
|
||||
}
|
||||
};
|
||||
|
||||
WebTablet.prototype.mouseMoveProcessor = function () {
|
||||
this.moveEventTimer = null;
|
||||
if (this.dragging) {
|
||||
var pickRay = Camera.computePickRay(this.currentMouse.x, this.currentMouse.y);
|
||||
|
||||
// transform pickRay into camera local coordinates
|
||||
var invCameraXform = new Xform(Camera.orientation, Camera.position).inv();
|
||||
|
@ -582,6 +601,7 @@ WebTablet.prototype.mouseMoveEvent = function (event) {
|
|||
localPosition: localPosition
|
||||
});
|
||||
}
|
||||
this.scheduleMouseMoveProcessor();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
107
unpublishedScripts/marketplace/laser/laser-a.svg
Normal file
107
unpublishedScripts/marketplace/laser/laser-a.svg
Normal file
|
@ -0,0 +1,107 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="140mm"
|
||||
height="140mm"
|
||||
viewBox="0 0 140 140"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.1 r15371"
|
||||
sodipodi:docname="laser-a.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="1"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.35"
|
||||
inkscape:cx="1038.9217"
|
||||
inkscape:cy="879.1901"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
objecttolerance="3"
|
||||
inkscape:window-width="2194"
|
||||
inkscape:window-height="1171"
|
||||
inkscape:window-x="2186"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:pagecheckerboard="true" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-157)">
|
||||
<circle
|
||||
id="path3680"
|
||||
cx="53.672615"
|
||||
cy="245.59525"
|
||||
r="20.410715"
|
||||
style="stroke-width:0.26458332;fill:#000000;stroke:#000000;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
id="path3684"
|
||||
sodipodi:sides="5"
|
||||
sodipodi:cx="48.380951"
|
||||
sodipodi:cy="175.29166"
|
||||
sodipodi:r1="47.150944"
|
||||
sodipodi:r2="13.598276"
|
||||
sodipodi:arg1="1.0897856"
|
||||
sodipodi:arg2="1.6872054"
|
||||
inkscape:flatsided="false"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="M 70.196535,217.09228 46.801561,188.7979 15.367586,208.95661 35.047691,177.96323 6.161985,154.29712 l 35.557948,9.13941 13.581627,-34.78516 2.295916,36.64185 37.279613,2.16768 -34.138995,13.5065 z"
|
||||
inkscape:transform-center-x="1.9762951"
|
||||
inkscape:transform-center-y="1.2684232"
|
||||
style="stroke-width:0.26458332;fill:#000000;stroke:#000000;stroke-opacity:1"
|
||||
transform="matrix(0.75680215,0,0,0.80599932,17.17868,104.2376)" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
id="path3694"
|
||||
sodipodi:sides="5"
|
||||
sodipodi:cx="53.381914"
|
||||
sodipodi:cy="244.31365"
|
||||
sodipodi:r1="48.628967"
|
||||
sodipodi:r2="10.608823"
|
||||
sodipodi:arg1="1.7183633"
|
||||
sodipodi:arg2="2.3466818"
|
||||
inkscape:flatsided="false"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="M 46.231899,292.4141 45.95204,251.88623 5.4261854,252.37744 43.883994,239.58748 30.893657,201.19689 54.941748,233.82012 87.439133,209.60223 63.843862,242.55446 96.918688,265.97757 58.287917,253.71993 Z"
|
||||
inkscape:transform-center-x="3.6110896"
|
||||
inkscape:transform-center-y="0.36477657"
|
||||
style="stroke-width:0.26458332;fill:#000000;stroke:#000000;stroke-opacity:1" />
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:7.708;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 56.694008,239.30541 135.65246,167.44572"
|
||||
id="path3702"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:transform-center-x="-1.5119048"
|
||||
inkscape:transform-center-y="23.434524" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.8 KiB |
106
unpublishedScripts/marketplace/laser/laser.svg
Normal file
106
unpublishedScripts/marketplace/laser/laser.svg
Normal file
|
@ -0,0 +1,106 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="140mm"
|
||||
height="140mm"
|
||||
viewBox="0 0 140 140"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.1 r15371"
|
||||
sodipodi:docname="laser.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.35"
|
||||
inkscape:cx="1523.2074"
|
||||
inkscape:cy="879.1901"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
objecttolerance="3"
|
||||
inkscape:window-width="2194"
|
||||
inkscape:window-height="1171"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-157)">
|
||||
<circle
|
||||
id="path3680"
|
||||
cx="53.672615"
|
||||
cy="245.59525"
|
||||
r="20.410715"
|
||||
style="stroke-width:0.26458332;fill:#ffffff;stroke:#ffffff;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
id="path3684"
|
||||
sodipodi:sides="5"
|
||||
sodipodi:cx="48.380951"
|
||||
sodipodi:cy="175.29166"
|
||||
sodipodi:r1="47.150944"
|
||||
sodipodi:r2="13.598276"
|
||||
sodipodi:arg1="1.0897856"
|
||||
sodipodi:arg2="1.6872054"
|
||||
inkscape:flatsided="false"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="M 70.196535,217.09228 46.801561,188.7979 15.367586,208.95661 35.047691,177.96323 6.161985,154.29712 l 35.557948,9.13941 13.581627,-34.78516 2.295916,36.64185 37.279613,2.16768 -34.138995,13.5065 z"
|
||||
inkscape:transform-center-x="1.9762951"
|
||||
inkscape:transform-center-y="1.2684232"
|
||||
style="stroke-width:0.26458332;fill:#ffffff;stroke:#ffffff;stroke-opacity:1"
|
||||
transform="matrix(0.75680215,0,0,0.80599932,17.17868,104.2376)" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
id="path3694"
|
||||
sodipodi:sides="5"
|
||||
sodipodi:cx="53.381914"
|
||||
sodipodi:cy="244.31365"
|
||||
sodipodi:r1="48.628967"
|
||||
sodipodi:r2="10.608823"
|
||||
sodipodi:arg1="1.7183633"
|
||||
sodipodi:arg2="2.3466818"
|
||||
inkscape:flatsided="false"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="M 46.231899,292.4141 45.95204,251.88623 5.4261854,252.37744 43.883994,239.58748 30.893657,201.19689 54.941748,233.82012 87.439133,209.60223 63.843862,242.55446 96.918688,265.97757 58.287917,253.71993 Z"
|
||||
inkscape:transform-center-x="3.6110896"
|
||||
inkscape:transform-center-y="0.36477657"
|
||||
style="stroke-width:0.26458332;fill:#ffffff;stroke:#ffffff;stroke-opacity:1" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:7.70800018;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 56.694008,239.30541 135.65246,167.44572"
|
||||
id="path3702"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:transform-center-x="-1.5119048"
|
||||
inkscape:transform-center-y="23.434524" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.7 KiB |
274
unpublishedScripts/marketplace/laser/laserPointerApp.js
Normal file
274
unpublishedScripts/marketplace/laser/laserPointerApp.js
Normal file
|
@ -0,0 +1,274 @@
|
|||
//
|
||||
// Created by Alan-Michael Moody on 6/4/2017
|
||||
//
|
||||
|
||||
'use strict';
|
||||
|
||||
(function () {
|
||||
Script.include("/~/system/libraries/controllers.js");
|
||||
|
||||
var APP_NAME = 'LASER',
|
||||
APP_ICON = Script.resolvePath('laser.svg'),
|
||||
APP_ICON_ACTIVE = Script.resolvePath('laser-a.svg');
|
||||
|
||||
var POINT_INDEX_CHANNEL = "Hifi-Point-Index",
|
||||
GRAB_DISABLE_CHANNEL = "Hifi-Grab-Disable",
|
||||
POINTER_DISABLE_CHANNEL = "Hifi-Pointer-Disable";
|
||||
|
||||
var TRIGGER_PRESSURE = 0.95;
|
||||
|
||||
var tablet = Tablet.getTablet('com.highfidelity.interface.tablet.system');
|
||||
|
||||
var button = tablet.addButton({
|
||||
icon: APP_ICON,
|
||||
activeIcon: APP_ICON_ACTIVE,
|
||||
text: APP_NAME
|
||||
});
|
||||
|
||||
var laserEntities = {
|
||||
left: {
|
||||
beam: null,
|
||||
sphere: null
|
||||
},
|
||||
right: {
|
||||
beam: null,
|
||||
sphere: null
|
||||
}
|
||||
};
|
||||
|
||||
var rayExclusionList = [];
|
||||
|
||||
function laser(hand) {
|
||||
|
||||
var PICK_MAX_DISTANCE = 500;
|
||||
var FORWARD_OFFSET = 0.05;
|
||||
|
||||
var isNewEntityNeeded = (laserEntities[hand].beam === null);
|
||||
|
||||
var jointName = hand === 'right' ? 'RightHandIndex4' : 'LeftHandIndex4'; //'RightHand' : 'LeftHand';
|
||||
|
||||
var _hand = hand === 'right' ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
|
||||
var controllerLocation = getControllerWorldLocation(_hand, true);
|
||||
|
||||
var worldControllerPosition = controllerLocation.position;
|
||||
var worldControllerRotation = controllerLocation.orientation;
|
||||
|
||||
var jointExists = (MyAvatar.getJointIndex(jointName) > 0) ;
|
||||
var CONTROLLER_FORWARD_OFFSET = Vec3.multiply(Quat.getUp(worldControllerRotation), FORWARD_OFFSET);
|
||||
|
||||
var pickRay = {
|
||||
origin: worldControllerPosition,
|
||||
direction: Quat.getUp(worldControllerRotation),
|
||||
length: PICK_MAX_DISTANCE
|
||||
};
|
||||
|
||||
if (jointExists) {
|
||||
pickRay.origin = MyAvatar.getJointPosition(jointName);
|
||||
pickRay.direction = MyAvatar.jointToWorldDirection(Vec3.UP, MyAvatar.getJointIndex(jointName));
|
||||
}
|
||||
|
||||
var ray = Entities.findRayIntersection(pickRay, true, [], rayExclusionList, true);
|
||||
var avatarRay = AvatarManager.findRayIntersection(pickRay, true, [], rayExclusionList, true);
|
||||
|
||||
var dist = PICK_MAX_DISTANCE;
|
||||
var intersection = null;
|
||||
|
||||
if (avatarRay.intersects) {
|
||||
intersection = avatarRay.intersection;
|
||||
dist = Vec3.distance(pickRay.origin, avatarRay.intersection);
|
||||
} else if (ray.intersects) {
|
||||
intersection = ray.intersection;
|
||||
dist = Vec3.distance(pickRay.origin, ray.intersection);
|
||||
}
|
||||
|
||||
var sphereSize = dist * 0.01;
|
||||
|
||||
if (isNewEntityNeeded) {
|
||||
|
||||
var sphere = {
|
||||
lifetime: 360,
|
||||
type: 'Sphere',
|
||||
dimensions: {x: sphereSize, y: sphereSize, z: sphereSize},
|
||||
color: {red: 0, green: 255, blue: 0},
|
||||
position: intersection,
|
||||
collisionless: true,
|
||||
visible: false
|
||||
};
|
||||
|
||||
var beam = {
|
||||
lifetime: 360,
|
||||
type: 'Line',
|
||||
glow: 1.0,
|
||||
lineWidth: 5,
|
||||
alpha: 0.5,
|
||||
ignoreRayIntersection: true,
|
||||
drawInFront: true,
|
||||
color: {red: 0, green: 255, blue: 0},
|
||||
parentID: MyAvatar.sessionUUID,
|
||||
dimensions: Vec3.multiply(PICK_MAX_DISTANCE * 2, Vec3.ONE),
|
||||
linePoints: [Vec3.ZERO, {x: 0, y: dist - FORWARD_OFFSET, z: 0}]
|
||||
};
|
||||
|
||||
if(jointExists) {
|
||||
beam.parentJointIndex = MyAvatar.getJointIndex(jointName);
|
||||
beam.localPosition = {x: 0, y: FORWARD_OFFSET, z: 0};
|
||||
beam.localRotation = Quat.normalize({});
|
||||
} else {
|
||||
beam.position = Vec3.sum(pickRay.origin, CONTROLLER_FORWARD_OFFSET);
|
||||
beam.rotation = worldControllerRotation;
|
||||
}
|
||||
|
||||
laserEntities[hand].beam = Entities.addEntity(beam,true);
|
||||
rayExclusionList.push(laserEntities[hand].beam);
|
||||
|
||||
laserEntities[hand].sphere = Entities.addEntity(sphere,true);
|
||||
rayExclusionList.push(laserEntities[hand].sphere);
|
||||
|
||||
if (ray.intersects || avatarRay.intersects) {
|
||||
Entities.editEntity(laserEntities[hand].sphere, {
|
||||
visible: true
|
||||
});
|
||||
}
|
||||
|
||||
} else {
|
||||
if (ray.intersects || avatarRay.intersects) {
|
||||
if(jointExists) {
|
||||
Entities.editEntity(laserEntities[hand].beam, {
|
||||
parentID: MyAvatar.sessionUUID,
|
||||
parentJointIndex: MyAvatar.getJointIndex(jointName),
|
||||
localPosition: {x: 0, y: FORWARD_OFFSET, z: 0},
|
||||
localRotation: Quat.normalize({}),
|
||||
dimensions: Vec3.multiply(PICK_MAX_DISTANCE * 2, Vec3.ONE),
|
||||
linePoints: [Vec3.ZERO, {x: 0, y: dist - FORWARD_OFFSET, z: 0}]
|
||||
});
|
||||
} else {
|
||||
Entities.editEntity(laserEntities[hand].beam, {
|
||||
parentID: MyAvatar.sessionUUID,
|
||||
parentJointIndex: MyAvatar.getJointIndex(jointName),
|
||||
position: Vec3.sum(pickRay.origin, CONTROLLER_FORWARD_OFFSET),
|
||||
rotation: worldControllerRotation,
|
||||
dimensions: Vec3.multiply(PICK_MAX_DISTANCE * 2, Vec3.ONE),
|
||||
linePoints: [Vec3.ZERO, {x: 0, y: dist - FORWARD_OFFSET, z: 0}]
|
||||
});
|
||||
}
|
||||
|
||||
Entities.editEntity(laserEntities[hand].sphere, {
|
||||
dimensions: {x: sphereSize, y: sphereSize, z: sphereSize},
|
||||
position: intersection,
|
||||
visible: true
|
||||
});
|
||||
} else {
|
||||
if(jointExists) {
|
||||
Entities.editEntity(laserEntities[hand].beam, {
|
||||
parentID: MyAvatar.sessionUUID,
|
||||
parentJointIndex: MyAvatar.getJointIndex(jointName),
|
||||
localPosition: {x: 0, y: FORWARD_OFFSET, z: 0},
|
||||
localRotation: Quat.normalize({}),
|
||||
dimensions: Vec3.multiply(PICK_MAX_DISTANCE * 2, Vec3.ONE),
|
||||
linePoints: [Vec3.ZERO, {x: 0, y: dist - FORWARD_OFFSET, z: 0}]
|
||||
});
|
||||
} else {
|
||||
Entities.editEntity(laserEntities[hand].beam, {
|
||||
parentID: MyAvatar.sessionUUID,
|
||||
parentJointIndex: MyAvatar.getJointIndex(jointName),
|
||||
position: Vec3.sum(pickRay.origin, CONTROLLER_FORWARD_OFFSET),
|
||||
rotation: worldControllerRotation,
|
||||
dimensions: Vec3.multiply(PICK_MAX_DISTANCE * 2, Vec3.ONE),
|
||||
linePoints: [Vec3.ZERO, {x: 0, y: dist - FORWARD_OFFSET, z: 0}]
|
||||
});
|
||||
}
|
||||
|
||||
Entities.editEntity(laserEntities[hand].sphere, {
|
||||
visible: false
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function triggerWatcher(deltaTime) {
|
||||
|
||||
var deleteBeamLeft = true,
|
||||
deleteBeamRight = true;
|
||||
|
||||
if (Controller.getValue(Controller.Standard.LT) > TRIGGER_PRESSURE) {
|
||||
deleteBeamLeft = false;
|
||||
laser('left');
|
||||
}
|
||||
|
||||
if (Controller.getValue(Controller.Standard.RT) > TRIGGER_PRESSURE) {
|
||||
deleteBeamRight = false;
|
||||
laser('right');
|
||||
}
|
||||
|
||||
if (deleteBeamLeft && laserEntities.left.beam !== null) {
|
||||
Entities.deleteEntity(laserEntities.left.beam);
|
||||
Entities.deleteEntity(laserEntities.left.sphere);
|
||||
|
||||
laserEntities.left.beam = null;
|
||||
laserEntities.left.sphere = null;
|
||||
|
||||
}
|
||||
if (deleteBeamRight && laserEntities.right.beam !== null) {
|
||||
Entities.deleteEntity(laserEntities.right.beam);
|
||||
Entities.deleteEntity(laserEntities.right.sphere);
|
||||
|
||||
laserEntities.right.beam = null;
|
||||
laserEntities.right.sphere = null;
|
||||
|
||||
}
|
||||
if (deleteBeamRight && deleteBeamLeft) {
|
||||
rayExclusionList = [];
|
||||
}
|
||||
}
|
||||
|
||||
function selectionBeamSwitch(bool) {
|
||||
Messages.sendMessage(GRAB_DISABLE_CHANNEL, JSON.stringify({
|
||||
holdEnabled: bool,
|
||||
nearGrabEnabled: bool,
|
||||
farGrabEnabled: bool
|
||||
}), true);
|
||||
Messages.sendMessage(POINTER_DISABLE_CHANNEL, JSON.stringify({
|
||||
pointerEnabled: bool
|
||||
}), true);
|
||||
Messages.sendMessage(POINT_INDEX_CHANNEL, JSON.stringify({
|
||||
pointIndex: !bool
|
||||
}), true);
|
||||
}
|
||||
|
||||
var _switch = true;
|
||||
|
||||
function buttonSwitch() {
|
||||
if (_switch) {
|
||||
Script.update.connect(triggerWatcher);
|
||||
Messages.subscribe(POINT_INDEX_CHANNEL);
|
||||
Messages.subscribe(GRAB_DISABLE_CHANNEL);
|
||||
Messages.subscribe(POINTER_DISABLE_CHANNEL);
|
||||
} else {
|
||||
Script.update.disconnect(triggerWatcher);
|
||||
Messages.unsubscribe(POINT_INDEX_CHANNEL);
|
||||
Messages.unsubscribe(GRAB_DISABLE_CHANNEL);
|
||||
Messages.unsubscribe(POINTER_DISABLE_CHANNEL);
|
||||
}
|
||||
button.editProperties({isActive: _switch});
|
||||
|
||||
selectionBeamSwitch(!_switch);
|
||||
|
||||
_switch = !_switch;
|
||||
}
|
||||
|
||||
button.clicked.connect(buttonSwitch);
|
||||
|
||||
function clean() {
|
||||
tablet.removeButton(button);
|
||||
Script.update.disconnect(triggerWatcher);
|
||||
|
||||
Messages.unsubscribe(POINT_INDEX_CHANNEL);
|
||||
Messages.unsubscribe(GRAB_DISABLE_CHANNEL);
|
||||
Messages.unsubscribe(POINTER_DISABLE_CHANNEL);
|
||||
rayExclusionList = [];
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(clean);
|
||||
}());
|
Loading…
Reference in a new issue