mirror of
https://github.com/JulianGro/overte.git
synced 2025-05-07 13:00:23 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into sharks
This commit is contained in:
commit
489e08aef0
64 changed files with 1170 additions and 756 deletions
|
@ -127,7 +127,7 @@ void AudioMixer::queueReplicatedAudioPacket(QSharedPointer<ReceivedMessage> mess
|
||||||
// construct a "fake" audio received message from the byte array and packet list information
|
// construct a "fake" audio received message from the byte array and packet list information
|
||||||
auto audioData = message->getMessage().mid(NUM_BYTES_RFC4122_UUID);
|
auto audioData = message->getMessage().mid(NUM_BYTES_RFC4122_UUID);
|
||||||
|
|
||||||
PacketType rewrittenType = REPLICATED_PACKET_MAPPING.key(message->getType());
|
PacketType rewrittenType = PacketTypeEnum::getReplicatedPacketMapping().key(message->getType());
|
||||||
|
|
||||||
if (rewrittenType == PacketType::Unknown) {
|
if (rewrittenType == PacketType::Unknown) {
|
||||||
qDebug() << "Cannot unwrap replicated packet type not present in REPLICATED_PACKET_WRAPPING";
|
qDebug() << "Cannot unwrap replicated packet type not present in REPLICATED_PACKET_WRAPPING";
|
||||||
|
|
|
@ -125,11 +125,11 @@ void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, c
|
||||||
// now make sure it's a packet type that we want to replicate
|
// now make sure it's a packet type that we want to replicate
|
||||||
|
|
||||||
// first check if it is an original type that we should replicate
|
// first check if it is an original type that we should replicate
|
||||||
PacketType mirroredType = REPLICATED_PACKET_MAPPING.value(message.getType());
|
PacketType mirroredType = PacketTypeEnum::getReplicatedPacketMapping().value(message.getType());
|
||||||
|
|
||||||
if (mirroredType == PacketType::Unknown) {
|
if (mirroredType == PacketType::Unknown) {
|
||||||
// if it wasn't check if it is a replicated type that we should re-replicate
|
// if it wasn't check if it is a replicated type that we should re-replicate
|
||||||
if (REPLICATED_PACKET_MAPPING.key(message.getType()) != PacketType::Unknown) {
|
if (PacketTypeEnum::getReplicatedPacketMapping().key(message.getType()) != PacketType::Unknown) {
|
||||||
mirroredType = message.getType();
|
mirroredType = message.getType();
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Packet passed to optionallyReplicatePacket was not a replicatable type - returning";
|
qDebug() << "Packet passed to optionallyReplicatePacket was not a replicatable type - returning";
|
||||||
|
|
|
@ -144,10 +144,10 @@ void AvatarMixer::optionallyReplicatePacket(ReceivedMessage& message, const Node
|
||||||
// check if this is a packet type we replicate
|
// check if this is a packet type we replicate
|
||||||
// which means it must be a packet type present in REPLICATED_PACKET_MAPPING or must be the
|
// which means it must be a packet type present in REPLICATED_PACKET_MAPPING or must be the
|
||||||
// replicated version of one of those packet types
|
// replicated version of one of those packet types
|
||||||
PacketType replicatedType = REPLICATED_PACKET_MAPPING.value(message.getType());
|
PacketType replicatedType = PacketTypeEnum::getReplicatedPacketMapping().value(message.getType());
|
||||||
|
|
||||||
if (replicatedType == PacketType::Unknown) {
|
if (replicatedType == PacketType::Unknown) {
|
||||||
if (REPLICATED_PACKET_MAPPING.key(message.getType()) != PacketType::Unknown) {
|
if (PacketTypeEnum::getReplicatedPacketMapping().key(message.getType()) != PacketType::Unknown) {
|
||||||
replicatedType = message.getType();
|
replicatedType = message.getType();
|
||||||
} else {
|
} else {
|
||||||
qDebug() << __FUNCTION__ << "called without replicatable packet type - returning";
|
qDebug() << __FUNCTION__ << "called without replicatable packet type - returning";
|
||||||
|
|
|
@ -126,24 +126,6 @@
|
||||||
"weightVar": "headWeight",
|
"weightVar": "headWeight",
|
||||||
"weight": 4.0,
|
"weight": 4.0,
|
||||||
"flexCoefficients": [1, 0.5, 0.25, 0.2, 0.1]
|
"flexCoefficients": [1, 0.5, 0.25, 0.2, 0.1]
|
||||||
},
|
|
||||||
{
|
|
||||||
"jointName": "LeftArm",
|
|
||||||
"positionVar": "leftArmPosition",
|
|
||||||
"rotationVar": "leftArmRotation",
|
|
||||||
"typeVar": "leftArmType",
|
|
||||||
"weightVar": "leftArmWeight",
|
|
||||||
"weight": 0.75,
|
|
||||||
"flexCoefficients": [1.0, 0.35, 0.2, 0.1, 0.05, 0.0, 0.0, 0.0]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"jointName": "RightArm",
|
|
||||||
"positionVar": "rightArmPosition",
|
|
||||||
"rotationVar": "rightArmRotation",
|
|
||||||
"typeVar": "rightArmType",
|
|
||||||
"weightVar": "rightArmWeight",
|
|
||||||
"weight": 0.75,
|
|
||||||
"flexCoefficients": [1.0, 0.35, 0.2, 0.1, 0.05, 0.0, 0.0, 0.0]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -50,7 +50,7 @@ Item {
|
||||||
margins: 4
|
margins: 4
|
||||||
}
|
}
|
||||||
clip: true
|
clip: true
|
||||||
snapMode: ListView.SnapToItem
|
cacheBuffer: 4000
|
||||||
|
|
||||||
model: ListModel {}
|
model: ListModel {}
|
||||||
delegate: Item {
|
delegate: Item {
|
||||||
|
|
|
@ -145,12 +145,13 @@ Rectangle {
|
||||||
visible: headPuckBox.checked
|
visible: headPuckBox.checked
|
||||||
HifiControls.SpinBox {
|
HifiControls.SpinBox {
|
||||||
id: headYOffset
|
id: headYOffset
|
||||||
decimals: 4
|
decimals: 1
|
||||||
width: 112
|
width: 112
|
||||||
label: "Y: offset"
|
label: "Y Offset"
|
||||||
|
suffix: " cm"
|
||||||
minimumValue: -10
|
minimumValue: -10
|
||||||
stepSize: 0.0254
|
stepSize: 1
|
||||||
value: -0.05
|
value: -5
|
||||||
colorScheme: hifi.colorSchemes.dark
|
colorScheme: hifi.colorSchemes.dark
|
||||||
|
|
||||||
onEditingFinished: {
|
onEditingFinished: {
|
||||||
|
@ -162,11 +163,12 @@ Rectangle {
|
||||||
HifiControls.SpinBox {
|
HifiControls.SpinBox {
|
||||||
id: headZOffset
|
id: headZOffset
|
||||||
width: 112
|
width: 112
|
||||||
label: "Z: offset"
|
label: "Z Offset"
|
||||||
minimumValue: -10
|
minimumValue: -10
|
||||||
stepSize: 0.0254
|
stepSize: 1
|
||||||
decimals: 4
|
decimals: 1
|
||||||
value: -0.05
|
suffix: " cm"
|
||||||
|
value: -5
|
||||||
colorScheme: hifi.colorSchemes.dark
|
colorScheme: hifi.colorSchemes.dark
|
||||||
|
|
||||||
onEditingFinished: {
|
onEditingFinished: {
|
||||||
|
@ -175,7 +177,6 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RalewayBold {
|
RalewayBold {
|
||||||
id: hands
|
id: hands
|
||||||
|
|
||||||
|
@ -254,11 +255,12 @@ Rectangle {
|
||||||
|
|
||||||
HifiControls.SpinBox {
|
HifiControls.SpinBox {
|
||||||
id: handYOffset
|
id: handYOffset
|
||||||
decimals: 4
|
decimals: 1
|
||||||
width: 112
|
width: 112
|
||||||
label: "Y: offset"
|
suffix: " cm"
|
||||||
|
label: "Y Offset"
|
||||||
minimumValue: -10
|
minimumValue: -10
|
||||||
stepSize: 0.0254
|
stepSize: 1
|
||||||
colorScheme: hifi.colorSchemes.dark
|
colorScheme: hifi.colorSchemes.dark
|
||||||
|
|
||||||
onEditingFinished: {
|
onEditingFinished: {
|
||||||
|
@ -270,10 +272,11 @@ Rectangle {
|
||||||
HifiControls.SpinBox {
|
HifiControls.SpinBox {
|
||||||
id: handZOffset
|
id: handZOffset
|
||||||
width: 112
|
width: 112
|
||||||
label: "Z: offset"
|
label: "Z Offset"
|
||||||
|
suffix: " cm"
|
||||||
minimumValue: -10
|
minimumValue: -10
|
||||||
stepSize: 0.0254
|
stepSize: 1
|
||||||
decimals: 4
|
decimals: 1
|
||||||
colorScheme: hifi.colorSchemes.dark
|
colorScheme: hifi.colorSchemes.dark
|
||||||
|
|
||||||
onEditingFinished: {
|
onEditingFinished: {
|
||||||
|
@ -488,15 +491,55 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: shoulderAdditionalConfig
|
||||||
|
visible: shoulderBox.checked
|
||||||
|
anchors.top: shoulderConfig.bottom
|
||||||
|
anchors.topMargin: 5
|
||||||
|
anchors.left: openVrConfiguration.left
|
||||||
|
anchors.leftMargin: leftMargin + 20
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
HifiControls.SpinBox {
|
||||||
|
id: armCircumference
|
||||||
|
decimals: 1
|
||||||
|
width: 160
|
||||||
|
suffix: " cm"
|
||||||
|
label: "Arm Circumference"
|
||||||
|
minimumValue: 0
|
||||||
|
stepSize: 1.0
|
||||||
|
colorScheme: hifi.colorSchemes.dark
|
||||||
|
value: 33.0
|
||||||
|
|
||||||
|
onEditingFinished: {
|
||||||
|
sendConfigurationSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiControls.SpinBox {
|
||||||
|
id: shoulderWidth
|
||||||
|
width: 160
|
||||||
|
label: "Shoulder Width"
|
||||||
|
suffix: " cm"
|
||||||
|
minimumValue: 0
|
||||||
|
stepSize: 1.0
|
||||||
|
decimals: 1
|
||||||
|
colorScheme: hifi.colorSchemes.dark
|
||||||
|
value: 48
|
||||||
|
|
||||||
|
onEditingFinished: {
|
||||||
|
sendConfigurationSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Separator {
|
Separator {
|
||||||
id: bottomSeperator
|
id: bottomSeperator
|
||||||
width: parent.width
|
width: parent.width
|
||||||
anchors.top: shoulderConfig.bottom
|
anchors.top: shoulderAdditionalConfig.visible ? shoulderAdditionalConfig.bottom : shoulderConfig.bottom
|
||||||
anchors.topMargin: 10
|
anchors.topMargin: (shoulderAdditionalConfig.visible ? 25 : 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: calibrationButton
|
id: calibrationButton
|
||||||
property int color: hifi.buttons.blue
|
property int color: hifi.buttons.blue
|
||||||
|
@ -835,6 +878,9 @@ Rectangle {
|
||||||
var viveController = settings["handController"];
|
var viveController = settings["handController"];
|
||||||
var desktopMode = settings["desktopMode"];
|
var desktopMode = settings["desktopMode"];
|
||||||
|
|
||||||
|
armCircumference.value = settings.armCircumference;
|
||||||
|
shoulderWidth.value = settings.shoulderWidth;
|
||||||
|
|
||||||
if (HmdHead) {
|
if (HmdHead) {
|
||||||
headBox.checked = true;
|
headBox.checked = true;
|
||||||
headPuckBox.checked = false;
|
headPuckBox.checked = false;
|
||||||
|
@ -1010,6 +1056,8 @@ Rectangle {
|
||||||
"bodyConfiguration": trackerConfiguration,
|
"bodyConfiguration": trackerConfiguration,
|
||||||
"headConfiguration": headObject,
|
"headConfiguration": headObject,
|
||||||
"handConfiguration": handObject,
|
"handConfiguration": handObject,
|
||||||
|
"armCircumference": armCircumference.value,
|
||||||
|
"shoulderWidth": shoulderWidth.value,
|
||||||
"desktopMode": viveInDesktop.checked
|
"desktopMode": viveInDesktop.checked
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -114,6 +114,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearMenus() {
|
function clearMenus() {
|
||||||
|
topMenu = null
|
||||||
d.clear()
|
d.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -231,6 +231,7 @@ static const QString FBX_EXTENSION = ".fbx";
|
||||||
static const QString OBJ_EXTENSION = ".obj";
|
static const QString OBJ_EXTENSION = ".obj";
|
||||||
static const QString AVA_JSON_EXTENSION = ".ava.json";
|
static const QString AVA_JSON_EXTENSION = ".ava.json";
|
||||||
static const QString WEB_VIEW_TAG = "noDownload=true";
|
static const QString WEB_VIEW_TAG = "noDownload=true";
|
||||||
|
static const QString ZIP_EXTENSION = ".zip";
|
||||||
|
|
||||||
static const float MIRROR_FULLSCREEN_DISTANCE = 0.389f;
|
static const float MIRROR_FULLSCREEN_DISTANCE = 0.389f;
|
||||||
|
|
||||||
|
@ -262,7 +263,8 @@ const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensi
|
||||||
{ AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl },
|
{ AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl },
|
||||||
{ JSON_EXTENSION, &Application::importJSONFromURL },
|
{ JSON_EXTENSION, &Application::importJSONFromURL },
|
||||||
{ JS_EXTENSION, &Application::askToLoadScript },
|
{ JS_EXTENSION, &Application::askToLoadScript },
|
||||||
{ FST_EXTENSION, &Application::askToSetAvatarUrl }
|
{ FST_EXTENSION, &Application::askToSetAvatarUrl },
|
||||||
|
{ ZIP_EXTENSION, &Application::importFromZIP }
|
||||||
};
|
};
|
||||||
|
|
||||||
class DeadlockWatchdogThread : public QThread {
|
class DeadlockWatchdogThread : public QThread {
|
||||||
|
@ -2262,7 +2264,7 @@ void Application::paintGL() {
|
||||||
QMutexLocker viewLocker(&_viewMutex);
|
QMutexLocker viewLocker(&_viewMutex);
|
||||||
_viewFrustum.calculate();
|
_viewFrustum.calculate();
|
||||||
}
|
}
|
||||||
renderArgs = RenderArgs(_gpuContext, getEntities(), lodManager->getOctreeSizeScale(),
|
renderArgs = RenderArgs(_gpuContext, lodManager->getOctreeSizeScale(),
|
||||||
lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE,
|
lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE,
|
||||||
RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
|
RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
|
||||||
{
|
{
|
||||||
|
@ -2792,6 +2794,20 @@ bool Application::importSVOFromURL(const QString& urlString) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::onPresent(quint32 frameCount) {
|
||||||
|
if (shouldPaint()) {
|
||||||
|
postEvent(this, new QEvent(static_cast<QEvent::Type>(Idle)), Qt::HighEventPriority);
|
||||||
|
postEvent(this, new QEvent(static_cast<QEvent::Type>(Paint)), Qt::HighEventPriority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Application::importFromZIP(const QString& filePath) {
|
||||||
|
qDebug() << "A zip file has been dropped in: " << filePath;
|
||||||
|
QUrl empty;
|
||||||
|
qApp->getFileDownloadInterface()->runUnzip(filePath, empty, true, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool _renderRequested { false };
|
bool _renderRequested { false };
|
||||||
|
|
||||||
bool Application::event(QEvent* event) {
|
bool Application::event(QEvent* event) {
|
||||||
|
@ -2808,23 +2824,9 @@ bool Application::event(QEvent* event) {
|
||||||
// Explicit idle keeps the idle running at a lower interval, but without any rendering
|
// Explicit idle keeps the idle running at a lower interval, but without any rendering
|
||||||
// see (windowMinimizedChanged)
|
// see (windowMinimizedChanged)
|
||||||
case Event::Idle:
|
case Event::Idle:
|
||||||
{
|
idle();
|
||||||
float nsecsElapsed = (float)_lastTimeUpdated.nsecsElapsed();
|
// Clear the event queue of pending idle calls
|
||||||
_lastTimeUpdated.start();
|
removePostedEvents(this, Idle);
|
||||||
idle(nsecsElapsed);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case Event::Present:
|
|
||||||
if (!_renderRequested) {
|
|
||||||
float nsecsElapsed = (float)_lastTimeUpdated.nsecsElapsed();
|
|
||||||
if (shouldPaint(nsecsElapsed)) {
|
|
||||||
_renderRequested = true;
|
|
||||||
_lastTimeUpdated.start();
|
|
||||||
idle(nsecsElapsed);
|
|
||||||
postEvent(this, new QEvent(static_cast<QEvent::Type>(Paint)), Qt::HighEventPriority);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case Event::Paint:
|
case Event::Paint:
|
||||||
|
@ -2832,9 +2834,8 @@ bool Application::event(QEvent* event) {
|
||||||
// or AvatarInputs will mysteriously move to the bottom-right
|
// or AvatarInputs will mysteriously move to the bottom-right
|
||||||
AvatarInputs::getInstance()->update();
|
AvatarInputs::getInstance()->update();
|
||||||
paintGL();
|
paintGL();
|
||||||
// wait for the next present event before starting idle / paint again
|
// Clear the event queue of pending paint calls
|
||||||
removePostedEvents(this, Present);
|
removePostedEvents(this, Paint);
|
||||||
_renderRequested = false;
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -3653,7 +3654,7 @@ bool Application::acceptSnapshot(const QString& urlString) {
|
||||||
|
|
||||||
static uint32_t _renderedFrameIndex { INVALID_FRAME };
|
static uint32_t _renderedFrameIndex { INVALID_FRAME };
|
||||||
|
|
||||||
bool Application::shouldPaint(float nsecsElapsed) {
|
bool Application::shouldPaint() {
|
||||||
if (_aboutToQuit) {
|
if (_aboutToQuit) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -3673,11 +3674,9 @@ bool Application::shouldPaint(float nsecsElapsed) {
|
||||||
(float)paintDelaySamples / paintDelayUsecs << "us";
|
(float)paintDelaySamples / paintDelayUsecs << "us";
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
float msecondsSinceLastUpdate = nsecsElapsed / NSECS_PER_USEC / USECS_PER_MSEC;
|
|
||||||
|
|
||||||
// Throttle if requested
|
// Throttle if requested
|
||||||
if (displayPlugin->isThrottled() && (msecondsSinceLastUpdate < THROTTLED_SIM_FRAME_PERIOD_MS)) {
|
if (displayPlugin->isThrottled() && (_lastTimeUpdated.elapsed() < THROTTLED_SIM_FRAME_PERIOD_MS)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3894,7 +3893,7 @@ void setupCpuMonitorThread() {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void Application::idle(float nsecsElapsed) {
|
void Application::idle() {
|
||||||
PerformanceTimer perfTimer("idle");
|
PerformanceTimer perfTimer("idle");
|
||||||
|
|
||||||
// Update the deadlock watchdog
|
// Update the deadlock watchdog
|
||||||
|
@ -3951,7 +3950,8 @@ void Application::idle(float nsecsElapsed) {
|
||||||
steamClient->runCallbacks();
|
steamClient->runCallbacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
float secondsSinceLastUpdate = nsecsElapsed / NSECS_PER_MSEC / MSECS_PER_SECOND;
|
float secondsSinceLastUpdate = (float)_lastTimeUpdated.nsecsElapsed() / NSECS_PER_MSEC / MSECS_PER_SECOND;
|
||||||
|
_lastTimeUpdated.start();
|
||||||
|
|
||||||
// If the offscreen Ui has something active that is NOT the root, then assume it has keyboard focus.
|
// If the offscreen Ui has something active that is NOT the root, then assume it has keyboard focus.
|
||||||
if (_keyboardDeviceHasFocus && offscreenUi && offscreenUi->getWindow()->activeFocusItem() != offscreenUi->getRootItem()) {
|
if (_keyboardDeviceHasFocus && offscreenUi && offscreenUi->getWindow()->activeFocusItem() != offscreenUi->getRootItem()) {
|
||||||
|
@ -4185,6 +4185,7 @@ void Application::loadSettings() {
|
||||||
//DependencyManager::get<LODManager>()->setAutomaticLODAdjust(false);
|
//DependencyManager::get<LODManager>()->setAutomaticLODAdjust(false);
|
||||||
|
|
||||||
Menu::getInstance()->loadSettings();
|
Menu::getInstance()->loadSettings();
|
||||||
|
|
||||||
// If there is a preferred plugin, we probably messed it up with the menu settings, so fix it.
|
// If there is a preferred plugin, we probably messed it up with the menu settings, so fix it.
|
||||||
auto pluginManager = PluginManager::getInstance();
|
auto pluginManager = PluginManager::getInstance();
|
||||||
auto plugins = pluginManager->getPreferredDisplayPlugins();
|
auto plugins = pluginManager->getPreferredDisplayPlugins();
|
||||||
|
@ -4198,24 +4199,44 @@ void Application::loadSettings() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
Setting::Handle<bool> firstRun { Settings::firstRun, true };
|
||||||
|
bool isFirstPerson = false;
|
||||||
|
if (firstRun.get()) {
|
||||||
// If this is our first run, and no preferred devices were set, default to
|
// If this is our first run, and no preferred devices were set, default to
|
||||||
// an HMD device if available.
|
// an HMD device if available.
|
||||||
Setting::Handle<bool> firstRun { Settings::firstRun, true };
|
auto displayPlugins = pluginManager->getDisplayPlugins();
|
||||||
if (firstRun.get()) {
|
for (auto& plugin : displayPlugins) {
|
||||||
auto displayPlugins = pluginManager->getDisplayPlugins();
|
if (plugin->isHmd()) {
|
||||||
for (auto& plugin : displayPlugins) {
|
if (auto action = menu->getActionForOption(plugin->getName())) {
|
||||||
if (plugin->isHmd()) {
|
action->setChecked(true);
|
||||||
if (auto action = menu->getActionForOption(plugin->getName())) {
|
action->trigger();
|
||||||
action->setChecked(true);
|
break;
|
||||||
action->trigger();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isFirstPerson = (qApp->isHMDMode());
|
||||||
|
} else {
|
||||||
|
// if this is not the first run, the camera will be initialized differently depending on user settings
|
||||||
|
|
||||||
|
if (qApp->isHMDMode()) {
|
||||||
|
// if the HMD is active, use first-person camera, unless the appropriate setting is checked
|
||||||
|
isFirstPerson = menu->isOptionChecked(MenuOption::FirstPersonHMD);
|
||||||
|
} else {
|
||||||
|
// if HMD is not active, only use first person if the menu option is checked
|
||||||
|
isFirstPerson = menu->isOptionChecked(MenuOption::FirstPerson);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// finish initializing the camera, based on everything we checked above. Third person camera will be used if no settings
|
||||||
|
// dictated that we should be in first person
|
||||||
|
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, isFirstPerson);
|
||||||
|
Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !isFirstPerson);
|
||||||
|
_myCamera.setMode((isFirstPerson) ? CAMERA_MODE_FIRST_PERSON : CAMERA_MODE_THIRD_PERSON);
|
||||||
|
cameraMenuChanged();
|
||||||
|
|
||||||
auto inputs = pluginManager->getInputPlugins();
|
auto inputs = pluginManager->getInputPlugins();
|
||||||
for (auto plugin : inputs) {
|
for (auto plugin : inputs) {
|
||||||
if (!plugin->isActive()) {
|
if (!plugin->isActive()) {
|
||||||
|
@ -4264,7 +4285,6 @@ void Application::init() {
|
||||||
DependencyManager::get<DeferredLightingEffect>()->init();
|
DependencyManager::get<DeferredLightingEffect>()->init();
|
||||||
|
|
||||||
DependencyManager::get<AvatarManager>()->init();
|
DependencyManager::get<AvatarManager>()->init();
|
||||||
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON);
|
|
||||||
|
|
||||||
_timerStart.start();
|
_timerStart.start();
|
||||||
_lastTimeUpdated.start();
|
_lastTimeUpdated.start();
|
||||||
|
@ -4416,10 +4436,9 @@ void Application::updateMyAvatarLookAtPosition() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// I am not looking at anyone else, so just look forward
|
// I am not looking at anyone else, so just look forward
|
||||||
auto headPose = myAvatar->getHeadControllerPoseInSensorFrame();
|
auto headPose = myAvatar->getControllerPoseInWorldFrame(controller::Action::HEAD);
|
||||||
if (headPose.isValid()) {
|
if (headPose.isValid()) {
|
||||||
glm::mat4 worldHeadMat = myAvatar->getSensorToWorldMatrix() * headPose.getMatrix();
|
lookAtSpot = transformPoint(headPose.getMatrix(), glm::vec3(0.0f, 0.0f, TREE_SCALE));
|
||||||
lookAtSpot = transformPoint(worldHeadMat, glm::vec3(0.0f, 0.0f, TREE_SCALE));
|
|
||||||
} else {
|
} else {
|
||||||
lookAtSpot = myAvatar->getHead()->getEyePosition() +
|
lookAtSpot = myAvatar->getHead()->getEyePosition() +
|
||||||
(myAvatar->getHead()->getFinalOrientationInWorldFrame() * glm::vec3(0.0f, 0.0f, -TREE_SCALE));
|
(myAvatar->getHead()->getFinalOrientationInWorldFrame() * glm::vec3(0.0f, 0.0f, -TREE_SCALE));
|
||||||
|
@ -4833,52 +4852,76 @@ void Application::update(float deltaTime) {
|
||||||
myAvatar->setDriveKey(MyAvatar::ZOOM, userInputMapper->getActionState(controller::Action::TRANSLATE_CAMERA_Z));
|
myAvatar->setDriveKey(MyAvatar::ZOOM, userInputMapper->getActionState(controller::Action::TRANSLATE_CAMERA_Z));
|
||||||
}
|
}
|
||||||
|
|
||||||
controller::Pose leftHandPose = userInputMapper->getPoseState(controller::Action::LEFT_HAND);
|
static const std::vector<controller::Action> avatarControllerActions = {
|
||||||
controller::Pose rightHandPose = userInputMapper->getPoseState(controller::Action::RIGHT_HAND);
|
controller::Action::LEFT_HAND,
|
||||||
auto myAvatarMatrix = createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition());
|
controller::Action::RIGHT_HAND,
|
||||||
auto worldToSensorMatrix = glm::inverse(myAvatar->getSensorToWorldMatrix());
|
controller::Action::LEFT_FOOT,
|
||||||
auto avatarToSensorMatrix = worldToSensorMatrix * myAvatarMatrix;
|
controller::Action::RIGHT_FOOT,
|
||||||
myAvatar->setHandControllerPosesInSensorFrame(leftHandPose.transform(avatarToSensorMatrix), rightHandPose.transform(avatarToSensorMatrix));
|
controller::Action::HIPS,
|
||||||
|
controller::Action::SPINE2,
|
||||||
|
controller::Action::HEAD,
|
||||||
|
controller::Action::LEFT_HAND_THUMB1,
|
||||||
|
controller::Action::LEFT_HAND_THUMB2,
|
||||||
|
controller::Action::LEFT_HAND_THUMB3,
|
||||||
|
controller::Action::LEFT_HAND_THUMB4,
|
||||||
|
controller::Action::LEFT_HAND_INDEX1,
|
||||||
|
controller::Action::LEFT_HAND_INDEX2,
|
||||||
|
controller::Action::LEFT_HAND_INDEX3,
|
||||||
|
controller::Action::LEFT_HAND_INDEX4,
|
||||||
|
controller::Action::LEFT_HAND_MIDDLE1,
|
||||||
|
controller::Action::LEFT_HAND_MIDDLE2,
|
||||||
|
controller::Action::LEFT_HAND_MIDDLE3,
|
||||||
|
controller::Action::LEFT_HAND_MIDDLE4,
|
||||||
|
controller::Action::LEFT_HAND_RING1,
|
||||||
|
controller::Action::LEFT_HAND_RING2,
|
||||||
|
controller::Action::LEFT_HAND_RING3,
|
||||||
|
controller::Action::LEFT_HAND_RING4,
|
||||||
|
controller::Action::LEFT_HAND_PINKY1,
|
||||||
|
controller::Action::LEFT_HAND_PINKY2,
|
||||||
|
controller::Action::LEFT_HAND_PINKY3,
|
||||||
|
controller::Action::LEFT_HAND_PINKY4,
|
||||||
|
controller::Action::RIGHT_HAND_THUMB1,
|
||||||
|
controller::Action::RIGHT_HAND_THUMB2,
|
||||||
|
controller::Action::RIGHT_HAND_THUMB3,
|
||||||
|
controller::Action::RIGHT_HAND_THUMB4,
|
||||||
|
controller::Action::RIGHT_HAND_INDEX1,
|
||||||
|
controller::Action::RIGHT_HAND_INDEX2,
|
||||||
|
controller::Action::RIGHT_HAND_INDEX3,
|
||||||
|
controller::Action::RIGHT_HAND_INDEX4,
|
||||||
|
controller::Action::RIGHT_HAND_MIDDLE1,
|
||||||
|
controller::Action::RIGHT_HAND_MIDDLE2,
|
||||||
|
controller::Action::RIGHT_HAND_MIDDLE3,
|
||||||
|
controller::Action::RIGHT_HAND_MIDDLE4,
|
||||||
|
controller::Action::RIGHT_HAND_RING1,
|
||||||
|
controller::Action::RIGHT_HAND_RING2,
|
||||||
|
controller::Action::RIGHT_HAND_RING3,
|
||||||
|
controller::Action::RIGHT_HAND_RING4,
|
||||||
|
controller::Action::RIGHT_HAND_PINKY1,
|
||||||
|
controller::Action::RIGHT_HAND_PINKY2,
|
||||||
|
controller::Action::RIGHT_HAND_PINKY3,
|
||||||
|
controller::Action::RIGHT_HAND_PINKY4,
|
||||||
|
controller::Action::LEFT_ARM,
|
||||||
|
controller::Action::RIGHT_ARM,
|
||||||
|
controller::Action::LEFT_SHOULDER,
|
||||||
|
controller::Action::RIGHT_SHOULDER,
|
||||||
|
controller::Action::LEFT_FORE_ARM,
|
||||||
|
controller::Action::RIGHT_FORE_ARM,
|
||||||
|
controller::Action::LEFT_LEG,
|
||||||
|
controller::Action::RIGHT_LEG,
|
||||||
|
controller::Action::LEFT_UP_LEG,
|
||||||
|
controller::Action::RIGHT_UP_LEG,
|
||||||
|
controller::Action::LEFT_TOE_BASE,
|
||||||
|
controller::Action::RIGHT_TOE_BASE
|
||||||
|
};
|
||||||
|
|
||||||
// If have previously done finger poses or there are new valid finger poses, update finger pose values. This so that if
|
// copy controller poses from userInputMapper to myAvatar.
|
||||||
// fingers are not being controlled, finger joints are not updated in MySkeletonModel.
|
glm::mat4 myAvatarMatrix = createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition());
|
||||||
// Assumption: Finger poses are either all present and valid or not present at all; thus can test just one joint.
|
glm::mat4 worldToSensorMatrix = glm::inverse(myAvatar->getSensorToWorldMatrix());
|
||||||
MyAvatar::FingerPosesMap leftHandFingerPoses;
|
glm::mat4 avatarToSensorMatrix = worldToSensorMatrix * myAvatarMatrix;
|
||||||
if (myAvatar->getLeftHandFingerControllerPosesInSensorFrame().size() > 0
|
for (auto& action : avatarControllerActions) {
|
||||||
|| userInputMapper->getPoseState(controller::Action::LEFT_HAND_THUMB1).isValid()) {
|
controller::Pose pose = userInputMapper->getPoseState(action);
|
||||||
for (int i = (int)controller::Action::LEFT_HAND_THUMB1; i <= (int)controller::Action::LEFT_HAND_PINKY4; i++) {
|
myAvatar->setControllerPoseInSensorFrame(action, pose.transform(avatarToSensorMatrix));
|
||||||
leftHandFingerPoses[i] = {
|
|
||||||
userInputMapper->getPoseState((controller::Action)i).transform(avatarToSensorMatrix),
|
|
||||||
userInputMapper->getActionName((controller::Action)i)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
MyAvatar::FingerPosesMap rightHandFingerPoses;
|
|
||||||
if (myAvatar->getRightHandFingerControllerPosesInSensorFrame().size() > 0
|
|
||||||
|| userInputMapper->getPoseState(controller::Action::RIGHT_HAND_THUMB1).isValid()) {
|
|
||||||
for (int i = (int)controller::Action::RIGHT_HAND_THUMB1; i <= (int)controller::Action::RIGHT_HAND_PINKY4; i++) {
|
|
||||||
rightHandFingerPoses[i] = {
|
|
||||||
userInputMapper->getPoseState((controller::Action)i).transform(avatarToSensorMatrix),
|
|
||||||
userInputMapper->getActionName((controller::Action)i)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
myAvatar->setFingerControllerPosesInSensorFrame(leftHandFingerPoses, rightHandFingerPoses);
|
|
||||||
|
|
||||||
controller::Pose leftFootPose = userInputMapper->getPoseState(controller::Action::LEFT_FOOT);
|
|
||||||
controller::Pose rightFootPose = userInputMapper->getPoseState(controller::Action::RIGHT_FOOT);
|
|
||||||
myAvatar->setFootControllerPosesInSensorFrame(leftFootPose.transform(avatarToSensorMatrix), rightFootPose.transform(avatarToSensorMatrix));
|
|
||||||
|
|
||||||
controller::Pose hipsPose = userInputMapper->getPoseState(controller::Action::HIPS);
|
|
||||||
controller::Pose spine2Pose = userInputMapper->getPoseState(controller::Action::SPINE2);
|
|
||||||
myAvatar->setSpineControllerPosesInSensorFrame(hipsPose.transform(avatarToSensorMatrix), spine2Pose.transform(avatarToSensorMatrix));
|
|
||||||
|
|
||||||
controller::Pose headPose = userInputMapper->getPoseState(controller::Action::HEAD);
|
|
||||||
myAvatar->setHeadControllerPoseInSensorFrame(headPose.transform(avatarToSensorMatrix));
|
|
||||||
|
|
||||||
controller::Pose leftArmPose = userInputMapper->getPoseState(controller::Action::LEFT_ARM);
|
|
||||||
controller::Pose rightArmPose = userInputMapper->getPoseState(controller::Action::RIGHT_ARM);
|
|
||||||
myAvatar->setArmControllerPosesInSensorFrame(leftArmPose.transform(avatarToSensorMatrix), rightArmPose.transform(avatarToSensorMatrix));
|
|
||||||
|
|
||||||
updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
|
updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
|
||||||
updateDialogs(deltaTime); // update various stats dialogs if present
|
updateDialogs(deltaTime); // update various stats dialogs if present
|
||||||
|
@ -6242,7 +6285,7 @@ void Application::addAssetToWorldFromURLRequestFinished() {
|
||||||
if (tempFile.open(QIODevice::WriteOnly)) {
|
if (tempFile.open(QIODevice::WriteOnly)) {
|
||||||
tempFile.write(request->getData());
|
tempFile.write(request->getData());
|
||||||
addAssetToWorldInfoClear(filename); // Remove message from list; next one added will have a different key.
|
addAssetToWorldInfoClear(filename); // Remove message from list; next one added will have a different key.
|
||||||
qApp->getFileDownloadInterface()->runUnzip(downloadPath, url, true);
|
qApp->getFileDownloadInterface()->runUnzip(downloadPath, url, true, false);
|
||||||
} else {
|
} else {
|
||||||
QString errorInfo = "Couldn't open temporary file for download";
|
QString errorInfo = "Couldn't open temporary file for download";
|
||||||
qWarning(interfaceapp) << errorInfo;
|
qWarning(interfaceapp) << errorInfo;
|
||||||
|
@ -6272,12 +6315,18 @@ void Application::addAssetToWorldUnzipFailure(QString filePath) {
|
||||||
addAssetToWorldError(filename, "Couldn't unzip file " + filename + ".");
|
addAssetToWorldError(filename, "Couldn't unzip file " + filename + ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::addAssetToWorld(QString filePath) {
|
void Application::addAssetToWorld(QString filePath, QString zipFile, bool isZip) {
|
||||||
// Automatically upload and add asset to world as an alternative manual process initiated by showAssetServerWidget().
|
// Automatically upload and add asset to world as an alternative manual process initiated by showAssetServerWidget().
|
||||||
|
QString mapping;
|
||||||
QString path = QUrl(filePath).toLocalFile();
|
QString path = filePath;
|
||||||
QString filename = filenameFromPath(path);
|
QString filename = filenameFromPath(path);
|
||||||
QString mapping = "/" + filename;
|
if (isZip) {
|
||||||
|
QString assetFolder = zipFile.section("/", -1);
|
||||||
|
assetFolder.remove(".zip");
|
||||||
|
mapping = "/" + assetFolder + "/" + filename;
|
||||||
|
} else {
|
||||||
|
mapping = "/" + filename;
|
||||||
|
}
|
||||||
|
|
||||||
// Test repeated because possibly different code paths.
|
// Test repeated because possibly different code paths.
|
||||||
if (!DependencyManager::get<NodeList>()->getThisNodeCanWriteAssets()) {
|
if (!DependencyManager::get<NodeList>()->getThisNodeCanWriteAssets()) {
|
||||||
|
@ -6358,7 +6407,13 @@ void Application::addAssetToWorldSetMapping(QString filePath, QString mapping, Q
|
||||||
qWarning(interfaceapp) << "Error downloading model: " + errorInfo;
|
qWarning(interfaceapp) << "Error downloading model: " + errorInfo;
|
||||||
addAssetToWorldError(filenameFromPath(filePath), errorInfo);
|
addAssetToWorldError(filenameFromPath(filePath), errorInfo);
|
||||||
} else {
|
} else {
|
||||||
addAssetToWorldAddEntity(filePath, mapping);
|
// to prevent files that aren't models from being loaded into world automatically
|
||||||
|
if (filePath.endsWith(".obj") || filePath.endsWith(".fbx")) {
|
||||||
|
addAssetToWorldAddEntity(filePath, mapping);
|
||||||
|
} else {
|
||||||
|
qCDebug(interfaceapp) << "Zipped contents are not supported entity files";
|
||||||
|
addAssetToWorldInfoDone(filenameFromPath(filePath));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
request->deleteLater();
|
request->deleteLater();
|
||||||
});
|
});
|
||||||
|
@ -6648,15 +6703,18 @@ void Application::onAssetToWorldMessageBoxClosed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Application::handleUnzip(QString zipFile, QString unzipFile, bool autoAdd) {
|
void Application::handleUnzip(QString zipFile, QStringList unzipFile, bool autoAdd, bool isZip) {
|
||||||
if (autoAdd) {
|
if (autoAdd) {
|
||||||
if (!unzipFile.isEmpty()) {
|
if (!unzipFile.isEmpty()) {
|
||||||
addAssetToWorld(unzipFile);
|
for (int i = 0; i < unzipFile.length(); i++) {
|
||||||
|
qCDebug(interfaceapp) << "Preparing file for asset server: " << unzipFile.at(i);
|
||||||
|
addAssetToWorld(unzipFile.at(i), zipFile, isZip);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
addAssetToWorldUnzipFailure(zipFile);
|
addAssetToWorldUnzipFailure(zipFile);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
showAssetServerWidget(unzipFile);
|
showAssetServerWidget(unzipFile.first());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7119,6 +7177,7 @@ void Application::updateDisplayMode() {
|
||||||
|
|
||||||
auto oldDisplayPlugin = _displayPlugin;
|
auto oldDisplayPlugin = _displayPlugin;
|
||||||
if (_displayPlugin) {
|
if (_displayPlugin) {
|
||||||
|
disconnect(_displayPluginPresentConnection);
|
||||||
_displayPlugin->deactivate();
|
_displayPlugin->deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7159,6 +7218,7 @@ void Application::updateDisplayMode() {
|
||||||
_offscreenContext->makeCurrent();
|
_offscreenContext->makeCurrent();
|
||||||
getApplicationCompositor().setDisplayPlugin(newDisplayPlugin);
|
getApplicationCompositor().setDisplayPlugin(newDisplayPlugin);
|
||||||
_displayPlugin = newDisplayPlugin;
|
_displayPlugin = newDisplayPlugin;
|
||||||
|
_displayPluginPresentConnection = connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent);
|
||||||
offscreenUi->getDesktop()->setProperty("repositionLocked", wasRepositionLocked);
|
offscreenUi->getDesktop()->setProperty("repositionLocked", wasRepositionLocked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -129,8 +129,7 @@ public:
|
||||||
virtual DisplayPluginPointer getActiveDisplayPlugin() const override;
|
virtual DisplayPluginPointer getActiveDisplayPlugin() const override;
|
||||||
|
|
||||||
enum Event {
|
enum Event {
|
||||||
Present = DisplayPlugin::Present,
|
Paint = QEvent::User + 1,
|
||||||
Paint,
|
|
||||||
Idle,
|
Idle,
|
||||||
Lambda
|
Lambda
|
||||||
};
|
};
|
||||||
|
@ -332,14 +331,14 @@ public slots:
|
||||||
// FIXME: Move addAssetToWorld* methods to own class?
|
// FIXME: Move addAssetToWorld* methods to own class?
|
||||||
void addAssetToWorldFromURL(QString url);
|
void addAssetToWorldFromURL(QString url);
|
||||||
void addAssetToWorldFromURLRequestFinished();
|
void addAssetToWorldFromURLRequestFinished();
|
||||||
void addAssetToWorld(QString filePath);
|
void addAssetToWorld(QString filePath, QString zipFile, bool isZip);
|
||||||
void addAssetToWorldUnzipFailure(QString filePath);
|
void addAssetToWorldUnzipFailure(QString filePath);
|
||||||
void addAssetToWorldWithNewMapping(QString filePath, QString mapping, int copy);
|
void addAssetToWorldWithNewMapping(QString filePath, QString mapping, int copy);
|
||||||
void addAssetToWorldUpload(QString filePath, QString mapping);
|
void addAssetToWorldUpload(QString filePath, QString mapping);
|
||||||
void addAssetToWorldSetMapping(QString filePath, QString mapping, QString hash);
|
void addAssetToWorldSetMapping(QString filePath, QString mapping, QString hash);
|
||||||
void addAssetToWorldAddEntity(QString filePath, QString mapping);
|
void addAssetToWorldAddEntity(QString filePath, QString mapping);
|
||||||
|
|
||||||
void handleUnzip(QString sourceFile, QString destinationFile, bool autoAdd);
|
void handleUnzip(QString sourceFile, QStringList destinationFile, bool autoAdd, bool isZip);
|
||||||
|
|
||||||
FileScriptingInterface* getFileDownloadInterface() { return _fileDownload; }
|
FileScriptingInterface* getFileDownloadInterface() { return _fileDownload; }
|
||||||
|
|
||||||
|
@ -409,6 +408,7 @@ private slots:
|
||||||
void clearDomainOctreeDetails();
|
void clearDomainOctreeDetails();
|
||||||
void clearDomainAvatars();
|
void clearDomainAvatars();
|
||||||
void onAboutToQuit();
|
void onAboutToQuit();
|
||||||
|
void onPresent(quint32 frameCount);
|
||||||
|
|
||||||
void resettingDomain();
|
void resettingDomain();
|
||||||
|
|
||||||
|
@ -455,8 +455,8 @@ private:
|
||||||
|
|
||||||
void cleanupBeforeQuit();
|
void cleanupBeforeQuit();
|
||||||
|
|
||||||
bool shouldPaint(float nsecsElapsed);
|
bool shouldPaint();
|
||||||
void idle(float nsecsElapsed);
|
void idle();
|
||||||
void update(float deltaTime);
|
void update(float deltaTime);
|
||||||
|
|
||||||
// Various helper functions called during update()
|
// Various helper functions called during update()
|
||||||
|
@ -481,6 +481,7 @@ private:
|
||||||
|
|
||||||
bool importJSONFromURL(const QString& urlString);
|
bool importJSONFromURL(const QString& urlString);
|
||||||
bool importSVOFromURL(const QString& urlString);
|
bool importSVOFromURL(const QString& urlString);
|
||||||
|
bool importFromZIP(const QString& filePath);
|
||||||
|
|
||||||
bool nearbyEntitiesAreReadyForPhysics();
|
bool nearbyEntitiesAreReadyForPhysics();
|
||||||
int processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode);
|
int processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode);
|
||||||
|
@ -518,6 +519,7 @@ private:
|
||||||
|
|
||||||
OffscreenGLCanvas* _offscreenContext { nullptr };
|
OffscreenGLCanvas* _offscreenContext { nullptr };
|
||||||
DisplayPluginPointer _displayPlugin;
|
DisplayPluginPointer _displayPlugin;
|
||||||
|
QMetaObject::Connection _displayPluginPresentConnection;
|
||||||
mutable std::mutex _displayPluginLock;
|
mutable std::mutex _displayPluginLock;
|
||||||
InputPluginList _activeInputPlugins;
|
InputPluginList _activeInputPlugins;
|
||||||
|
|
||||||
|
|
|
@ -134,9 +134,9 @@ bool AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::
|
||||||
// fetch the hand controller pose
|
// fetch the hand controller pose
|
||||||
controller::Pose pose;
|
controller::Pose pose;
|
||||||
if (isRightHand) {
|
if (isRightHand) {
|
||||||
pose = myAvatar->getRightHandControllerPoseInWorldFrame();
|
pose = myAvatar->getControllerPoseInWorldFrame(controller::Action::RIGHT_HAND);
|
||||||
} else {
|
} else {
|
||||||
pose = myAvatar->getLeftHandControllerPoseInWorldFrame();
|
pose = myAvatar->getControllerPoseInWorldFrame(controller::Action::LEFT_HAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pose.isValid()) {
|
if (pose.isValid()) {
|
||||||
|
|
|
@ -429,7 +429,7 @@ void MyAvatar::update(float deltaTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_DRAW_HMD_MOVING_AVERAGE
|
#ifdef DEBUG_DRAW_HMD_MOVING_AVERAGE
|
||||||
glm::vec3 p = transformPoint(getSensorToWorldMatrix(), getHeadControllerPoseInAvatarFrame() *
|
glm::vec3 p = transformPoint(getSensorToWorldMatrix(), getControllerPoseInAvatarFrame(controller::Pose::HEAD) *
|
||||||
glm::vec3(_headControllerFacingMovingAverage.x, 0.0f, _headControllerFacingMovingAverage.y));
|
glm::vec3(_headControllerFacingMovingAverage.x, 0.0f, _headControllerFacingMovingAverage.y));
|
||||||
DebugDraw::getInstance().addMarker("facing-avg", getOrientation(), p, glm::vec4(1.0f));
|
DebugDraw::getInstance().addMarker("facing-avg", getOrientation(), p, glm::vec4(1.0f));
|
||||||
p = transformPoint(getSensorToWorldMatrix(), getHMDSensorPosition() +
|
p = transformPoint(getSensorToWorldMatrix(), getHMDSensorPosition() +
|
||||||
|
@ -664,7 +664,7 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
|
||||||
|
|
||||||
_hmdSensorPosition = newHmdSensorPosition;
|
_hmdSensorPosition = newHmdSensorPosition;
|
||||||
_hmdSensorOrientation = glm::quat_cast(hmdSensorMatrix);
|
_hmdSensorOrientation = glm::quat_cast(hmdSensorMatrix);
|
||||||
auto headPose = _headControllerPoseInSensorFrameCache.get();
|
auto headPose = getControllerPoseInSensorFrame(controller::Action::HEAD);
|
||||||
if (headPose.isValid()) {
|
if (headPose.isValid()) {
|
||||||
_headControllerFacing = getFacingDir2D(headPose.rotation);
|
_headControllerFacing = getFacingDir2D(headPose.rotation);
|
||||||
} else {
|
} else {
|
||||||
|
@ -760,37 +760,37 @@ void MyAvatar::updateFromTrackers(float deltaTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 MyAvatar::getLeftHandPosition() const {
|
glm::vec3 MyAvatar::getLeftHandPosition() const {
|
||||||
auto pose = getLeftHandControllerPoseInAvatarFrame();
|
auto pose = getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND);
|
||||||
return pose.isValid() ? pose.getTranslation() : glm::vec3(0.0f);
|
return pose.isValid() ? pose.getTranslation() : glm::vec3(0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 MyAvatar::getRightHandPosition() const {
|
glm::vec3 MyAvatar::getRightHandPosition() const {
|
||||||
auto pose = getRightHandControllerPoseInAvatarFrame();
|
auto pose = getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND);
|
||||||
return pose.isValid() ? pose.getTranslation() : glm::vec3(0.0f);
|
return pose.isValid() ? pose.getTranslation() : glm::vec3(0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 MyAvatar::getLeftHandTipPosition() const {
|
glm::vec3 MyAvatar::getLeftHandTipPosition() const {
|
||||||
const float TIP_LENGTH = 0.3f;
|
const float TIP_LENGTH = 0.3f;
|
||||||
auto pose = getLeftHandControllerPoseInAvatarFrame();
|
auto pose = getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND);
|
||||||
return pose.isValid() ? pose.getTranslation() * pose.getRotation() + glm::vec3(0.0f, TIP_LENGTH, 0.0f) : glm::vec3(0.0f);
|
return pose.isValid() ? pose.getTranslation() * pose.getRotation() + glm::vec3(0.0f, TIP_LENGTH, 0.0f) : glm::vec3(0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 MyAvatar::getRightHandTipPosition() const {
|
glm::vec3 MyAvatar::getRightHandTipPosition() const {
|
||||||
const float TIP_LENGTH = 0.3f;
|
const float TIP_LENGTH = 0.3f;
|
||||||
auto pose = getRightHandControllerPoseInAvatarFrame();
|
auto pose = getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND);
|
||||||
return pose.isValid() ? pose.getTranslation() * pose.getRotation() + glm::vec3(0.0f, TIP_LENGTH, 0.0f) : glm::vec3(0.0f);
|
return pose.isValid() ? pose.getTranslation() * pose.getRotation() + glm::vec3(0.0f, TIP_LENGTH, 0.0f) : glm::vec3(0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
controller::Pose MyAvatar::getLeftHandPose() const {
|
controller::Pose MyAvatar::getLeftHandPose() const {
|
||||||
return getLeftHandControllerPoseInAvatarFrame();
|
return getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
controller::Pose MyAvatar::getRightHandPose() const {
|
controller::Pose MyAvatar::getRightHandPose() const {
|
||||||
return getRightHandControllerPoseInAvatarFrame();
|
return getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
controller::Pose MyAvatar::getLeftHandTipPose() const {
|
controller::Pose MyAvatar::getLeftHandTipPose() const {
|
||||||
auto pose = getLeftHandControllerPoseInAvatarFrame();
|
auto pose = getLeftHandPose();
|
||||||
glm::vec3 tipTrans = getLeftHandTipPosition();
|
glm::vec3 tipTrans = getLeftHandTipPosition();
|
||||||
pose.velocity += glm::cross(pose.getAngularVelocity(), pose.getTranslation() - tipTrans);
|
pose.velocity += glm::cross(pose.getAngularVelocity(), pose.getTranslation() - tipTrans);
|
||||||
pose.translation = tipTrans;
|
pose.translation = tipTrans;
|
||||||
|
@ -798,7 +798,7 @@ controller::Pose MyAvatar::getLeftHandTipPose() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
controller::Pose MyAvatar::getRightHandTipPose() const {
|
controller::Pose MyAvatar::getRightHandTipPose() const {
|
||||||
auto pose = getRightHandControllerPoseInAvatarFrame();
|
auto pose = getRightHandPose();
|
||||||
glm::vec3 tipTrans = getRightHandTipPosition();
|
glm::vec3 tipTrans = getRightHandTipPosition();
|
||||||
pose.velocity += glm::cross(pose.getAngularVelocity(), pose.getTranslation() - tipTrans);
|
pose.velocity += glm::cross(pose.getAngularVelocity(), pose.getTranslation() - tipTrans);
|
||||||
pose.translation = tipTrans;
|
pose.translation = tipTrans;
|
||||||
|
@ -1430,159 +1430,43 @@ void MyAvatar::rebuildCollisionShape() {
|
||||||
_characterController.setLocalBoundingBox(corner, diagonal);
|
_characterController.setLocalBoundingBox(corner, diagonal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MyAvatar::setControllerPoseInSensorFrame(controller::Action action, const controller::Pose& pose) {
|
||||||
void MyAvatar::setHandControllerPosesInSensorFrame(const controller::Pose& left, const controller::Pose& right) {
|
std::lock_guard<std::mutex> guard(_controllerPoseMapMutex);
|
||||||
_leftHandControllerPoseInSensorFrameCache.set(left);
|
auto iter = _controllerPoseMap.find(action);
|
||||||
_rightHandControllerPoseInSensorFrameCache.set(right);
|
if (iter != _controllerPoseMap.end()) {
|
||||||
|
iter->second = pose;
|
||||||
|
} else {
|
||||||
|
_controllerPoseMap.insert({ action, pose });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
controller::Pose MyAvatar::getLeftHandControllerPoseInSensorFrame() const {
|
controller::Pose MyAvatar::getControllerPoseInSensorFrame(controller::Action action) const {
|
||||||
return _leftHandControllerPoseInSensorFrameCache.get();
|
std::lock_guard<std::mutex> guard(_controllerPoseMapMutex);
|
||||||
|
auto iter = _controllerPoseMap.find(action);
|
||||||
|
if (iter != _controllerPoseMap.end()) {
|
||||||
|
return iter->second;
|
||||||
|
} else {
|
||||||
|
return controller::Pose(); // invalid pose
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
controller::Pose MyAvatar::getRightHandControllerPoseInSensorFrame() const {
|
controller::Pose MyAvatar::getControllerPoseInWorldFrame(controller::Action action) const {
|
||||||
return _rightHandControllerPoseInSensorFrameCache.get();
|
auto pose = getControllerPoseInSensorFrame(action);
|
||||||
|
if (pose.valid) {
|
||||||
|
return pose.transform(getSensorToWorldMatrix());
|
||||||
|
} else {
|
||||||
|
return controller::Pose(); // invalid pose
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
controller::Pose MyAvatar::getLeftHandControllerPoseInWorldFrame() const {
|
controller::Pose MyAvatar::getControllerPoseInAvatarFrame(controller::Action action) const {
|
||||||
return _leftHandControllerPoseInSensorFrameCache.get().transform(getSensorToWorldMatrix());
|
auto pose = getControllerPoseInWorldFrame(action);
|
||||||
}
|
if (pose.valid) {
|
||||||
|
glm::mat4 invAvatarMatrix = glm::inverse(createMatFromQuatAndPos(getOrientation(), getPosition()));
|
||||||
controller::Pose MyAvatar::getRightHandControllerPoseInWorldFrame() const {
|
return pose.transform(invAvatarMatrix);
|
||||||
return _rightHandControllerPoseInSensorFrameCache.get().transform(getSensorToWorldMatrix());
|
} else {
|
||||||
}
|
return controller::Pose(); // invalid pose
|
||||||
|
}
|
||||||
controller::Pose MyAvatar::getLeftHandControllerPoseInAvatarFrame() const {
|
|
||||||
glm::mat4 invAvatarMatrix = glm::inverse(createMatFromQuatAndPos(getOrientation(), getPosition()));
|
|
||||||
return getLeftHandControllerPoseInWorldFrame().transform(invAvatarMatrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
controller::Pose MyAvatar::getRightHandControllerPoseInAvatarFrame() const {
|
|
||||||
glm::mat4 invAvatarMatrix = glm::inverse(createMatFromQuatAndPos(getOrientation(), getPosition()));
|
|
||||||
return getRightHandControllerPoseInWorldFrame().transform(invAvatarMatrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyAvatar::setFingerControllerPosesInSensorFrame(const FingerPosesMap& left, const FingerPosesMap& right) {
|
|
||||||
_leftHandFingerPosesInSensorFramceCache.set(left);
|
|
||||||
_rightHandFingerPosesInSensorFramceCache.set(right);
|
|
||||||
}
|
|
||||||
|
|
||||||
MyAvatar::FingerPosesMap MyAvatar::getLeftHandFingerControllerPosesInSensorFrame() const {
|
|
||||||
return _leftHandFingerPosesInSensorFramceCache.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
MyAvatar::FingerPosesMap MyAvatar::getRightHandFingerControllerPosesInSensorFrame() const {
|
|
||||||
return _rightHandFingerPosesInSensorFramceCache.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyAvatar::setFootControllerPosesInSensorFrame(const controller::Pose& left, const controller::Pose& right) {
|
|
||||||
_leftFootControllerPoseInSensorFrameCache.set(left);
|
|
||||||
_rightFootControllerPoseInSensorFrameCache.set(right);
|
|
||||||
}
|
|
||||||
|
|
||||||
controller::Pose MyAvatar::getLeftFootControllerPoseInSensorFrame() const {
|
|
||||||
return _leftFootControllerPoseInSensorFrameCache.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
controller::Pose MyAvatar::getRightFootControllerPoseInSensorFrame() const {
|
|
||||||
return _rightFootControllerPoseInSensorFrameCache.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
controller::Pose MyAvatar::getLeftFootControllerPoseInWorldFrame() const {
|
|
||||||
return _leftFootControllerPoseInSensorFrameCache.get().transform(getSensorToWorldMatrix());
|
|
||||||
}
|
|
||||||
|
|
||||||
controller::Pose MyAvatar::getRightFootControllerPoseInWorldFrame() const {
|
|
||||||
return _rightFootControllerPoseInSensorFrameCache.get().transform(getSensorToWorldMatrix());
|
|
||||||
}
|
|
||||||
|
|
||||||
controller::Pose MyAvatar::getLeftFootControllerPoseInAvatarFrame() const {
|
|
||||||
glm::mat4 invAvatarMatrix = glm::inverse(createMatFromQuatAndPos(getOrientation(), getPosition()));
|
|
||||||
return getLeftFootControllerPoseInWorldFrame().transform(invAvatarMatrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
controller::Pose MyAvatar::getRightFootControllerPoseInAvatarFrame() const {
|
|
||||||
glm::mat4 invAvatarMatrix = glm::inverse(createMatFromQuatAndPos(getOrientation(), getPosition()));
|
|
||||||
return getRightFootControllerPoseInWorldFrame().transform(invAvatarMatrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyAvatar::setSpineControllerPosesInSensorFrame(const controller::Pose& hips, const controller::Pose& spine2) {
|
|
||||||
_hipsControllerPoseInSensorFrameCache.set(hips);
|
|
||||||
_spine2ControllerPoseInSensorFrameCache.set(spine2);
|
|
||||||
}
|
|
||||||
|
|
||||||
controller::Pose MyAvatar::getHipsControllerPoseInSensorFrame() const {
|
|
||||||
return _hipsControllerPoseInSensorFrameCache.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
controller::Pose MyAvatar::getSpine2ControllerPoseInSensorFrame() const {
|
|
||||||
return _spine2ControllerPoseInSensorFrameCache.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
controller::Pose MyAvatar::getHipsControllerPoseInWorldFrame() const {
|
|
||||||
return _hipsControllerPoseInSensorFrameCache.get().transform(getSensorToWorldMatrix());
|
|
||||||
}
|
|
||||||
|
|
||||||
controller::Pose MyAvatar::getSpine2ControllerPoseInWorldFrame() const {
|
|
||||||
return _spine2ControllerPoseInSensorFrameCache.get().transform(getSensorToWorldMatrix());
|
|
||||||
}
|
|
||||||
|
|
||||||
controller::Pose MyAvatar::getHipsControllerPoseInAvatarFrame() const {
|
|
||||||
glm::mat4 invAvatarMatrix = glm::inverse(createMatFromQuatAndPos(getOrientation(), getPosition()));
|
|
||||||
return getHipsControllerPoseInWorldFrame().transform(invAvatarMatrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
controller::Pose MyAvatar::getSpine2ControllerPoseInAvatarFrame() const {
|
|
||||||
glm::mat4 invAvatarMatrix = glm::inverse(createMatFromQuatAndPos(getOrientation(), getPosition()));
|
|
||||||
return getSpine2ControllerPoseInWorldFrame().transform(invAvatarMatrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyAvatar::setHeadControllerPoseInSensorFrame(const controller::Pose& head) {
|
|
||||||
_headControllerPoseInSensorFrameCache.set(head);
|
|
||||||
}
|
|
||||||
|
|
||||||
controller::Pose MyAvatar::getHeadControllerPoseInSensorFrame() const {
|
|
||||||
return _headControllerPoseInSensorFrameCache.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
controller::Pose MyAvatar::getHeadControllerPoseInWorldFrame() const {
|
|
||||||
return _headControllerPoseInSensorFrameCache.get().transform(getSensorToWorldMatrix());
|
|
||||||
}
|
|
||||||
|
|
||||||
controller::Pose MyAvatar::getHeadControllerPoseInAvatarFrame() const {
|
|
||||||
glm::mat4 invAvatarMatrix = glm::inverse(createMatFromQuatAndPos(getOrientation(), getPosition()));
|
|
||||||
return getHeadControllerPoseInWorldFrame().transform(invAvatarMatrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyAvatar::setArmControllerPosesInSensorFrame(const controller::Pose& left, const controller::Pose& right) {
|
|
||||||
_leftArmControllerPoseInSensorFrameCache.set(left);
|
|
||||||
_rightArmControllerPoseInSensorFrameCache.set(right);
|
|
||||||
}
|
|
||||||
|
|
||||||
controller::Pose MyAvatar::getLeftArmControllerPoseInSensorFrame() const {
|
|
||||||
return _leftArmControllerPoseInSensorFrameCache.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
controller::Pose MyAvatar::getRightArmControllerPoseInSensorFrame() const {
|
|
||||||
return _rightArmControllerPoseInSensorFrameCache.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
controller::Pose MyAvatar::getLeftArmControllerPoseInWorldFrame() const {
|
|
||||||
return getLeftArmControllerPoseInSensorFrame().transform(getSensorToWorldMatrix());
|
|
||||||
}
|
|
||||||
|
|
||||||
controller::Pose MyAvatar::getRightArmControllerPoseInWorldFrame() const {
|
|
||||||
return getRightArmControllerPoseInSensorFrame().transform(getSensorToWorldMatrix());
|
|
||||||
}
|
|
||||||
|
|
||||||
controller::Pose MyAvatar::getLeftArmControllerPoseInAvatarFrame() const {
|
|
||||||
glm::mat4 worldToAvatarMat = glm::inverse(createMatFromQuatAndPos(getOrientation(), getPosition()));
|
|
||||||
return getLeftArmControllerPoseInWorldFrame().transform(worldToAvatarMat);
|
|
||||||
}
|
|
||||||
|
|
||||||
controller::Pose MyAvatar::getRightArmControllerPoseInAvatarFrame() const {
|
|
||||||
glm::mat4 worldToAvatarMat = glm::inverse(createMatFromQuatAndPos(getOrientation(), getPosition()));
|
|
||||||
return getRightArmControllerPoseInWorldFrame().transform(worldToAvatarMat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::updateMotors() {
|
void MyAvatar::updateMotors() {
|
||||||
|
@ -1645,7 +1529,7 @@ void MyAvatar::prepareForPhysicsSimulation() {
|
||||||
_characterController.setParentVelocity(parentVelocity);
|
_characterController.setParentVelocity(parentVelocity);
|
||||||
|
|
||||||
_characterController.setPositionAndOrientation(getPosition(), getOrientation());
|
_characterController.setPositionAndOrientation(getPosition(), getOrientation());
|
||||||
auto headPose = getHeadControllerPoseInAvatarFrame();
|
auto headPose = getControllerPoseInAvatarFrame(controller::Action::HEAD);
|
||||||
if (headPose.isValid()) {
|
if (headPose.isValid()) {
|
||||||
_follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput());
|
_follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput());
|
||||||
} else {
|
} else {
|
||||||
|
@ -1899,8 +1783,8 @@ void MyAvatar::postUpdate(float deltaTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_enableDebugDrawHandControllers) {
|
if (_enableDebugDrawHandControllers) {
|
||||||
auto leftHandPose = getLeftHandControllerPoseInWorldFrame();
|
auto leftHandPose = getControllerPoseInWorldFrame(controller::Action::LEFT_HAND);
|
||||||
auto rightHandPose = getRightHandControllerPoseInWorldFrame();
|
auto rightHandPose = getControllerPoseInWorldFrame(controller::Action::RIGHT_HAND);
|
||||||
|
|
||||||
if (leftHandPose.isValid()) {
|
if (leftHandPose.isValid()) {
|
||||||
DebugDraw::getInstance().addMarker("leftHandController", leftHandPose.getRotation(), leftHandPose.getTranslation(), glm::vec4(1));
|
DebugDraw::getInstance().addMarker("leftHandController", leftHandPose.getRotation(), leftHandPose.getTranslation(), glm::vec4(1));
|
||||||
|
@ -2053,7 +1937,7 @@ void MyAvatar::updateOrientation(float deltaTime) {
|
||||||
|
|
||||||
getHead()->setBasePitch(getHead()->getBasePitch() + getDriveKey(PITCH) * _pitchSpeed * deltaTime);
|
getHead()->setBasePitch(getHead()->getBasePitch() + getDriveKey(PITCH) * _pitchSpeed * deltaTime);
|
||||||
|
|
||||||
auto headPose = getHeadControllerPoseInAvatarFrame();
|
auto headPose = getControllerPoseInAvatarFrame(controller::Action::HEAD);
|
||||||
if (headPose.isValid()) {
|
if (headPose.isValid()) {
|
||||||
glm::quat localOrientation = headPose.rotation * Quaternions::Y_180;
|
glm::quat localOrientation = headPose.rotation * Quaternions::Y_180;
|
||||||
// these angles will be in radians
|
// these angles will be in radians
|
||||||
|
@ -2689,10 +2573,10 @@ bool MyAvatar::isDriveKeyDisabled(DriveKeys key) const {
|
||||||
glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const {
|
glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const {
|
||||||
glm::vec3 headPosition;
|
glm::vec3 headPosition;
|
||||||
glm::quat headOrientation;
|
glm::quat headOrientation;
|
||||||
auto headPose = getHeadControllerPoseInSensorFrame();
|
auto headPose = getControllerPoseInSensorFrame(controller::Action::HEAD);
|
||||||
if (headPose.isValid()) {
|
if (headPose.isValid()) {
|
||||||
headPosition = getHeadControllerPoseInSensorFrame().translation;
|
headPosition = headPose.translation;
|
||||||
headOrientation = getHeadControllerPoseInSensorFrame().rotation * Quaternions::Y_180;
|
headOrientation = headPose.rotation * Quaternions::Y_180;
|
||||||
}
|
}
|
||||||
const glm::quat headOrientationYawOnly = cancelOutRollAndPitch(headOrientation);
|
const glm::quat headOrientationYawOnly = cancelOutRollAndPitch(headOrientation);
|
||||||
|
|
||||||
|
@ -3002,19 +2886,19 @@ glm::quat MyAvatar::getAbsoluteJointRotationInObjectFrame(int index) const {
|
||||||
|
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case CONTROLLER_LEFTHAND_INDEX: {
|
case CONTROLLER_LEFTHAND_INDEX: {
|
||||||
return getLeftHandControllerPoseInAvatarFrame().getRotation();
|
return getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).getRotation();
|
||||||
}
|
}
|
||||||
case CONTROLLER_RIGHTHAND_INDEX: {
|
case CONTROLLER_RIGHTHAND_INDEX: {
|
||||||
return getRightHandControllerPoseInAvatarFrame().getRotation();
|
return getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).getRotation();
|
||||||
}
|
}
|
||||||
case CAMERA_RELATIVE_CONTROLLER_LEFTHAND_INDEX: {
|
case CAMERA_RELATIVE_CONTROLLER_LEFTHAND_INDEX: {
|
||||||
auto pose = _leftHandControllerPoseInSensorFrameCache.get();
|
auto pose = getControllerPoseInSensorFrame(controller::Action::LEFT_HAND);
|
||||||
glm::mat4 controllerSensorMatrix = createMatFromQuatAndPos(pose.rotation, pose.translation);
|
glm::mat4 controllerSensorMatrix = createMatFromQuatAndPos(pose.rotation, pose.translation);
|
||||||
glm::mat4 result = computeCameraRelativeHandControllerMatrix(controllerSensorMatrix);
|
glm::mat4 result = computeCameraRelativeHandControllerMatrix(controllerSensorMatrix);
|
||||||
return glmExtractRotation(result);
|
return glmExtractRotation(result);
|
||||||
}
|
}
|
||||||
case CAMERA_RELATIVE_CONTROLLER_RIGHTHAND_INDEX: {
|
case CAMERA_RELATIVE_CONTROLLER_RIGHTHAND_INDEX: {
|
||||||
auto pose = _rightHandControllerPoseInSensorFrameCache.get();
|
auto pose = getControllerPoseInSensorFrame(controller::Action::RIGHT_HAND);
|
||||||
glm::mat4 controllerSensorMatrix = createMatFromQuatAndPos(pose.rotation, pose.translation);
|
glm::mat4 controllerSensorMatrix = createMatFromQuatAndPos(pose.rotation, pose.translation);
|
||||||
glm::mat4 result = computeCameraRelativeHandControllerMatrix(controllerSensorMatrix);
|
glm::mat4 result = computeCameraRelativeHandControllerMatrix(controllerSensorMatrix);
|
||||||
return glmExtractRotation(result);
|
return glmExtractRotation(result);
|
||||||
|
@ -3039,19 +2923,19 @@ glm::vec3 MyAvatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
|
||||||
|
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case CONTROLLER_LEFTHAND_INDEX: {
|
case CONTROLLER_LEFTHAND_INDEX: {
|
||||||
return getLeftHandControllerPoseInAvatarFrame().getTranslation();
|
return getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).getTranslation();
|
||||||
}
|
}
|
||||||
case CONTROLLER_RIGHTHAND_INDEX: {
|
case CONTROLLER_RIGHTHAND_INDEX: {
|
||||||
return getRightHandControllerPoseInAvatarFrame().getTranslation();
|
return getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).getTranslation();
|
||||||
}
|
}
|
||||||
case CAMERA_RELATIVE_CONTROLLER_LEFTHAND_INDEX: {
|
case CAMERA_RELATIVE_CONTROLLER_LEFTHAND_INDEX: {
|
||||||
auto pose = _leftHandControllerPoseInSensorFrameCache.get();
|
auto pose = getControllerPoseInSensorFrame(controller::Action::LEFT_HAND);
|
||||||
glm::mat4 controllerSensorMatrix = createMatFromQuatAndPos(pose.rotation, pose.translation);
|
glm::mat4 controllerSensorMatrix = createMatFromQuatAndPos(pose.rotation, pose.translation);
|
||||||
glm::mat4 result = computeCameraRelativeHandControllerMatrix(controllerSensorMatrix);
|
glm::mat4 result = computeCameraRelativeHandControllerMatrix(controllerSensorMatrix);
|
||||||
return extractTranslation(result);
|
return extractTranslation(result);
|
||||||
}
|
}
|
||||||
case CAMERA_RELATIVE_CONTROLLER_RIGHTHAND_INDEX: {
|
case CAMERA_RELATIVE_CONTROLLER_RIGHTHAND_INDEX: {
|
||||||
auto pose = _rightHandControllerPoseInSensorFrameCache.get();
|
auto pose = getControllerPoseInSensorFrame(controller::Action::RIGHT_HAND);
|
||||||
glm::mat4 controllerSensorMatrix = createMatFromQuatAndPos(pose.rotation, pose.translation);
|
glm::mat4 controllerSensorMatrix = createMatFromQuatAndPos(pose.rotation, pose.translation);
|
||||||
glm::mat4 result = computeCameraRelativeHandControllerMatrix(controllerSensorMatrix);
|
glm::mat4 result = computeCameraRelativeHandControllerMatrix(controllerSensorMatrix);
|
||||||
return extractTranslation(result);
|
return extractTranslation(result);
|
||||||
|
|
|
@ -473,49 +473,12 @@ public:
|
||||||
|
|
||||||
virtual void rebuildCollisionShape() override;
|
virtual void rebuildCollisionShape() override;
|
||||||
|
|
||||||
void setHandControllerPosesInSensorFrame(const controller::Pose& left, const controller::Pose& right);
|
|
||||||
controller::Pose getLeftHandControllerPoseInSensorFrame() const;
|
|
||||||
controller::Pose getRightHandControllerPoseInSensorFrame() const;
|
|
||||||
controller::Pose getLeftHandControllerPoseInWorldFrame() const;
|
|
||||||
controller::Pose getRightHandControllerPoseInWorldFrame() const;
|
|
||||||
controller::Pose getLeftHandControllerPoseInAvatarFrame() const;
|
|
||||||
controller::Pose getRightHandControllerPoseInAvatarFrame() const;
|
|
||||||
|
|
||||||
typedef std::map<int, std::pair<controller::Pose, QString>> FingerPosesMap;
|
|
||||||
void setFingerControllerPosesInSensorFrame(const FingerPosesMap& left, const FingerPosesMap& right);
|
|
||||||
FingerPosesMap getLeftHandFingerControllerPosesInSensorFrame() const;
|
|
||||||
FingerPosesMap getRightHandFingerControllerPosesInSensorFrame() const;
|
|
||||||
|
|
||||||
void setFootControllerPosesInSensorFrame(const controller::Pose& left, const controller::Pose& right);
|
|
||||||
controller::Pose getLeftFootControllerPoseInSensorFrame() const;
|
|
||||||
controller::Pose getRightFootControllerPoseInSensorFrame() const;
|
|
||||||
controller::Pose getLeftFootControllerPoseInWorldFrame() const;
|
|
||||||
controller::Pose getRightFootControllerPoseInWorldFrame() const;
|
|
||||||
controller::Pose getLeftFootControllerPoseInAvatarFrame() const;
|
|
||||||
controller::Pose getRightFootControllerPoseInAvatarFrame() const;
|
|
||||||
|
|
||||||
void setSpineControllerPosesInSensorFrame(const controller::Pose& hips, const controller::Pose& spine2);
|
|
||||||
controller::Pose getHipsControllerPoseInSensorFrame() const;
|
|
||||||
controller::Pose getSpine2ControllerPoseInSensorFrame() const;
|
|
||||||
controller::Pose getHipsControllerPoseInWorldFrame() const;
|
|
||||||
controller::Pose getSpine2ControllerPoseInWorldFrame() const;
|
|
||||||
controller::Pose getHipsControllerPoseInAvatarFrame() const;
|
|
||||||
controller::Pose getSpine2ControllerPoseInAvatarFrame() const;
|
|
||||||
|
|
||||||
void setHeadControllerPoseInSensorFrame(const controller::Pose& head);
|
|
||||||
controller::Pose getHeadControllerPoseInSensorFrame() const;
|
|
||||||
controller::Pose getHeadControllerPoseInWorldFrame() const;
|
|
||||||
controller::Pose getHeadControllerPoseInAvatarFrame() const;
|
|
||||||
const glm::vec2& getHeadControllerFacingMovingAverage() const { return _headControllerFacingMovingAverage; }
|
const glm::vec2& getHeadControllerFacingMovingAverage() const { return _headControllerFacingMovingAverage; }
|
||||||
|
|
||||||
|
void setControllerPoseInSensorFrame(controller::Action action, const controller::Pose& pose);
|
||||||
void setArmControllerPosesInSensorFrame(const controller::Pose& left, const controller::Pose& right);
|
controller::Pose getControllerPoseInSensorFrame(controller::Action action) const;
|
||||||
controller::Pose getLeftArmControllerPoseInSensorFrame() const;
|
controller::Pose getControllerPoseInWorldFrame(controller::Action action) const;
|
||||||
controller::Pose getRightArmControllerPoseInSensorFrame() const;
|
controller::Pose getControllerPoseInAvatarFrame(controller::Action action) const;
|
||||||
controller::Pose getLeftArmControllerPoseInWorldFrame() const;
|
|
||||||
controller::Pose getRightArmControllerPoseInWorldFrame() const;
|
|
||||||
controller::Pose getLeftArmControllerPoseInAvatarFrame() const;
|
|
||||||
controller::Pose getRightArmControllerPoseInAvatarFrame() const;
|
|
||||||
|
|
||||||
bool hasDriveInput() const;
|
bool hasDriveInput() const;
|
||||||
|
|
||||||
|
@ -804,18 +767,9 @@ private:
|
||||||
bool _hoverReferenceCameraFacingIsCaptured { false };
|
bool _hoverReferenceCameraFacingIsCaptured { false };
|
||||||
glm::vec3 _hoverReferenceCameraFacing { 0.0f, 0.0f, -1.0f }; // hmd sensor space
|
glm::vec3 _hoverReferenceCameraFacing { 0.0f, 0.0f, -1.0f }; // hmd sensor space
|
||||||
|
|
||||||
// These are stored in SENSOR frame
|
// all poses are in sensor-frame
|
||||||
ThreadSafeValueCache<controller::Pose> _leftHandControllerPoseInSensorFrameCache { controller::Pose() };
|
std::map<controller::Action, controller::Pose> _controllerPoseMap;
|
||||||
ThreadSafeValueCache<controller::Pose> _rightHandControllerPoseInSensorFrameCache { controller::Pose() };
|
mutable std::mutex _controllerPoseMapMutex;
|
||||||
ThreadSafeValueCache<FingerPosesMap> _leftHandFingerPosesInSensorFramceCache { };
|
|
||||||
ThreadSafeValueCache<FingerPosesMap> _rightHandFingerPosesInSensorFramceCache { };
|
|
||||||
ThreadSafeValueCache<controller::Pose> _leftFootControllerPoseInSensorFrameCache { controller::Pose() };
|
|
||||||
ThreadSafeValueCache<controller::Pose> _rightFootControllerPoseInSensorFrameCache { controller::Pose() };
|
|
||||||
ThreadSafeValueCache<controller::Pose> _hipsControllerPoseInSensorFrameCache { controller::Pose() };
|
|
||||||
ThreadSafeValueCache<controller::Pose> _spine2ControllerPoseInSensorFrameCache { controller::Pose() };
|
|
||||||
ThreadSafeValueCache<controller::Pose> _headControllerPoseInSensorFrameCache { controller::Pose() };
|
|
||||||
ThreadSafeValueCache<controller::Pose> _leftArmControllerPoseInSensorFrameCache { controller::Pose() };
|
|
||||||
ThreadSafeValueCache<controller::Pose> _rightArmControllerPoseInSensorFrameCache { controller::Pose() };
|
|
||||||
|
|
||||||
bool _hmdLeanRecenterEnabled = true;
|
bool _hmdLeanRecenterEnabled = true;
|
||||||
AnimPose _prePhysicsRoomPose;
|
AnimPose _prePhysicsRoomPose;
|
||||||
|
|
|
@ -36,7 +36,7 @@ MyCharacterController::~MyCharacterController() {
|
||||||
|
|
||||||
void MyCharacterController::setDynamicsWorld(btDynamicsWorld* world) {
|
void MyCharacterController::setDynamicsWorld(btDynamicsWorld* world) {
|
||||||
CharacterController::setDynamicsWorld(world);
|
CharacterController::setDynamicsWorld(world);
|
||||||
if (world) {
|
if (world && _rigidBody) {
|
||||||
initRayShotgun(world);
|
initRayShotgun(world);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ glm::quat MyHead::getHeadOrientation() const {
|
||||||
// always the same.
|
// always the same.
|
||||||
|
|
||||||
MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar);
|
MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar);
|
||||||
auto headPose = myAvatar->getHeadControllerPoseInWorldFrame();
|
auto headPose = myAvatar->getControllerPoseInWorldFrame(controller::Action::HEAD);
|
||||||
if (headPose.isValid()) {
|
if (headPose.isValid()) {
|
||||||
return headPose.rotation * Quaternions::Y_180;
|
return headPose.rotation * Quaternions::Y_180;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,105 +46,82 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
||||||
}
|
}
|
||||||
|
|
||||||
MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar);
|
MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar);
|
||||||
|
assert(myAvatar);
|
||||||
|
|
||||||
Rig::ControllerParameters params;
|
Rig::ControllerParameters params;
|
||||||
|
|
||||||
AnimPose avatarToRigPose(glm::vec3(1.0f), Quaternions::Y_180, glm::vec3(0.0f));
|
AnimPose avatarToRigPose(glm::vec3(1.0f), Quaternions::Y_180, glm::vec3(0.0f));
|
||||||
|
|
||||||
// input action is the highest priority source for head orientation.
|
// input action is the highest priority source for head orientation.
|
||||||
auto avatarHeadPose = myAvatar->getHeadControllerPoseInAvatarFrame();
|
auto avatarHeadPose = myAvatar->getControllerPoseInAvatarFrame(controller::Action::HEAD);
|
||||||
if (avatarHeadPose.isValid()) {
|
if (avatarHeadPose.isValid()) {
|
||||||
AnimPose pose(avatarHeadPose.getRotation(), avatarHeadPose.getTranslation());
|
AnimPose pose(avatarHeadPose.getRotation(), avatarHeadPose.getTranslation());
|
||||||
params.controllerPoses[Rig::ControllerType_Head] = avatarToRigPose * pose;
|
params.primaryControllerPoses[Rig::PrimaryControllerType_Head] = avatarToRigPose * pose;
|
||||||
params.controllerActiveFlags[Rig::ControllerType_Head] = true;
|
params.primaryControllerActiveFlags[Rig::PrimaryControllerType_Head] = true;
|
||||||
} else {
|
} else {
|
||||||
// even though full head IK is disabled, the rig still needs the head orientation to rotate the head up and
|
// even though full head IK is disabled, the rig still needs the head orientation to rotate the head up and
|
||||||
// down in desktop mode.
|
// down in desktop mode.
|
||||||
// preMult 180 is necessary to convert from avatar to rig coordinates.
|
// preMult 180 is necessary to convert from avatar to rig coordinates.
|
||||||
// postMult 180 is necessary to convert head from -z forward to z forward.
|
// postMult 180 is necessary to convert head from -z forward to z forward.
|
||||||
glm::quat headRot = Quaternions::Y_180 * head->getFinalOrientationInLocalFrame() * Quaternions::Y_180;
|
glm::quat headRot = Quaternions::Y_180 * head->getFinalOrientationInLocalFrame() * Quaternions::Y_180;
|
||||||
params.controllerPoses[Rig::ControllerType_Head] = AnimPose(glm::vec3(1.0f), headRot, glm::vec3(0.0f));
|
params.primaryControllerPoses[Rig::PrimaryControllerType_Head] = AnimPose(glm::vec3(1.0f), headRot, glm::vec3(0.0f));
|
||||||
params.controllerActiveFlags[Rig::ControllerType_Head] = false;
|
params.primaryControllerActiveFlags[Rig::PrimaryControllerType_Head] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto avatarHipsPose = myAvatar->getHipsControllerPoseInAvatarFrame();
|
//
|
||||||
if (avatarHipsPose.isValid()) {
|
// primary controller poses, control IK targets directly.
|
||||||
AnimPose pose(avatarHipsPose.getRotation(), avatarHipsPose.getTranslation());
|
//
|
||||||
params.controllerPoses[Rig::ControllerType_Hips] = avatarToRigPose * pose;
|
|
||||||
params.controllerActiveFlags[Rig::ControllerType_Hips] = true;
|
static const std::vector<std::pair<controller::Action, Rig::PrimaryControllerType>> primaryControllers = {
|
||||||
} else {
|
{ controller::Action::LEFT_HAND, Rig::PrimaryControllerType_LeftHand },
|
||||||
params.controllerPoses[Rig::ControllerType_Hips] = AnimPose::identity;
|
{ controller::Action::RIGHT_HAND, Rig::PrimaryControllerType_RightHand },
|
||||||
params.controllerActiveFlags[Rig::ControllerType_Hips] = false;
|
{ controller::Action::HIPS, Rig::PrimaryControllerType_Hips },
|
||||||
|
{ controller::Action::LEFT_FOOT, Rig::PrimaryControllerType_LeftFoot },
|
||||||
|
{ controller::Action::RIGHT_FOOT, Rig::PrimaryControllerType_RightFoot },
|
||||||
|
{ controller::Action::SPINE2, Rig::PrimaryControllerType_Spine2 }
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto pair : primaryControllers) {
|
||||||
|
auto controllerPose = myAvatar->getControllerPoseInAvatarFrame(pair.first);
|
||||||
|
if (controllerPose.isValid()) {
|
||||||
|
AnimPose pose(controllerPose.getRotation(), controllerPose.getTranslation());
|
||||||
|
params.primaryControllerPoses[pair.second] = avatarToRigPose * pose;
|
||||||
|
params.primaryControllerActiveFlags[pair.second] = true;
|
||||||
|
} else {
|
||||||
|
params.primaryControllerPoses[pair.second] = AnimPose::identity;
|
||||||
|
params.primaryControllerActiveFlags[pair.second] = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto avatarSpine2Pose = myAvatar->getSpine2ControllerPoseInAvatarFrame();
|
//
|
||||||
if (avatarSpine2Pose.isValid()) {
|
// secondary controller poses, influence the pose of the skeleton indirectly.
|
||||||
AnimPose pose(avatarSpine2Pose.getRotation(), avatarSpine2Pose.getTranslation());
|
//
|
||||||
params.controllerPoses[Rig::ControllerType_Spine2] = avatarToRigPose * pose;
|
|
||||||
params.controllerActiveFlags[Rig::ControllerType_Spine2] = true;
|
|
||||||
} else {
|
|
||||||
params.controllerPoses[Rig::ControllerType_Spine2] = AnimPose::identity;
|
|
||||||
params.controllerActiveFlags[Rig::ControllerType_Spine2] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto avatarRightArmPose = myAvatar->getRightArmControllerPoseInAvatarFrame();
|
static const std::vector<std::pair<controller::Action, Rig::SecondaryControllerType>> secondaryControllers = {
|
||||||
if (avatarRightArmPose.isValid()) {
|
{ controller::Action::LEFT_SHOULDER, Rig::SecondaryControllerType_LeftShoulder },
|
||||||
AnimPose pose(avatarRightArmPose.getRotation(), avatarRightArmPose.getTranslation());
|
{ controller::Action::RIGHT_SHOULDER, Rig::SecondaryControllerType_RightShoulder },
|
||||||
params.controllerPoses[Rig::ControllerType_RightArm] = avatarToRigPose * pose;
|
{ controller::Action::LEFT_ARM, Rig::SecondaryControllerType_LeftArm },
|
||||||
params.controllerActiveFlags[Rig::ControllerType_RightArm] = true;
|
{ controller::Action::RIGHT_ARM, Rig::SecondaryControllerType_RightArm },
|
||||||
} else {
|
{ controller::Action::LEFT_FORE_ARM, Rig::SecondaryControllerType_LeftForeArm },
|
||||||
params.controllerPoses[Rig::ControllerType_RightArm] = AnimPose::identity;
|
{ controller::Action::RIGHT_FORE_ARM, Rig::SecondaryControllerType_RightForeArm },
|
||||||
params.controllerActiveFlags[Rig::ControllerType_RightArm] = false;
|
{ controller::Action::LEFT_UP_LEG, Rig::SecondaryControllerType_LeftUpLeg },
|
||||||
}
|
{ controller::Action::RIGHT_UP_LEG, Rig::SecondaryControllerType_RightUpLeg },
|
||||||
|
{ controller::Action::LEFT_LEG, Rig::SecondaryControllerType_LeftLeg },
|
||||||
auto avatarLeftArmPose = myAvatar->getLeftArmControllerPoseInAvatarFrame();
|
{ controller::Action::RIGHT_LEG, Rig::SecondaryControllerType_RightLeg },
|
||||||
if (avatarLeftArmPose.isValid()) {
|
{ controller::Action::LEFT_TOE_BASE, Rig::SecondaryControllerType_LeftToeBase },
|
||||||
AnimPose pose(avatarLeftArmPose.getRotation(), avatarLeftArmPose.getTranslation());
|
{ controller::Action::RIGHT_TOE_BASE, Rig::SecondaryControllerType_RightToeBase }
|
||||||
params.controllerPoses[Rig::ControllerType_LeftArm] = avatarToRigPose * pose;
|
};
|
||||||
params.controllerActiveFlags[Rig::ControllerType_LeftArm] = true;
|
|
||||||
} else {
|
|
||||||
params.controllerPoses[Rig::ControllerType_LeftArm] = AnimPose::identity;
|
|
||||||
params.controllerActiveFlags[Rig::ControllerType_LeftArm] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto avatarLeftHandPose = myAvatar->getLeftHandControllerPoseInAvatarFrame();
|
for (auto pair : secondaryControllers) {
|
||||||
if (avatarLeftHandPose.isValid()) {
|
auto controllerPose = myAvatar->getControllerPoseInAvatarFrame(pair.first);
|
||||||
AnimPose pose(avatarLeftHandPose.getRotation(), avatarLeftHandPose.getTranslation());
|
if (controllerPose.isValid()) {
|
||||||
params.controllerPoses[Rig::ControllerType_LeftHand] = avatarToRigPose * pose;
|
AnimPose pose(controllerPose.getRotation(), controllerPose.getTranslation());
|
||||||
params.controllerActiveFlags[Rig::ControllerType_LeftHand] = true;
|
params.secondaryControllerPoses[pair.second] = avatarToRigPose * pose;
|
||||||
} else {
|
params.secondaryControllerActiveFlags[pair.second] = true;
|
||||||
params.controllerPoses[Rig::ControllerType_LeftHand] = AnimPose::identity;
|
} else {
|
||||||
params.controllerActiveFlags[Rig::ControllerType_LeftHand] = false;
|
params.secondaryControllerPoses[pair.second] = AnimPose::identity;
|
||||||
}
|
params.secondaryControllerActiveFlags[pair.second] = false;
|
||||||
|
}
|
||||||
auto avatarRightHandPose = myAvatar->getRightHandControllerPoseInAvatarFrame();
|
|
||||||
if (avatarRightHandPose.isValid()) {
|
|
||||||
AnimPose pose(avatarRightHandPose.getRotation(), avatarRightHandPose.getTranslation());
|
|
||||||
params.controllerPoses[Rig::ControllerType_RightHand] = avatarToRigPose * pose;
|
|
||||||
params.controllerActiveFlags[Rig::ControllerType_RightHand] = true;
|
|
||||||
} else {
|
|
||||||
params.controllerPoses[Rig::ControllerType_RightHand] = AnimPose::identity;
|
|
||||||
params.controllerActiveFlags[Rig::ControllerType_RightHand] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto avatarLeftFootPose = myAvatar->getLeftFootControllerPoseInAvatarFrame();
|
|
||||||
if (avatarLeftFootPose.isValid()) {
|
|
||||||
AnimPose pose(avatarLeftFootPose.getRotation(), avatarLeftFootPose.getTranslation());
|
|
||||||
params.controllerPoses[Rig::ControllerType_LeftFoot] = avatarToRigPose * pose;
|
|
||||||
params.controllerActiveFlags[Rig::ControllerType_LeftFoot] = true;
|
|
||||||
} else {
|
|
||||||
params.controllerPoses[Rig::ControllerType_LeftFoot] = AnimPose::identity;
|
|
||||||
params.controllerActiveFlags[Rig::ControllerType_LeftFoot] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto avatarRightFootPose = myAvatar->getRightFootControllerPoseInAvatarFrame();
|
|
||||||
if (avatarRightFootPose.isValid()) {
|
|
||||||
AnimPose pose(avatarRightFootPose.getRotation(), avatarRightFootPose.getTranslation());
|
|
||||||
params.controllerPoses[Rig::ControllerType_RightFoot] = avatarToRigPose * pose;
|
|
||||||
params.controllerActiveFlags[Rig::ControllerType_RightFoot] = true;
|
|
||||||
} else {
|
|
||||||
params.controllerPoses[Rig::ControllerType_RightFoot] = AnimPose::identity;
|
|
||||||
params.controllerActiveFlags[Rig::ControllerType_RightFoot] = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
params.bodyCapsuleRadius = myAvatar->getCharacterController()->getCapsuleRadius();
|
params.bodyCapsuleRadius = myAvatar->getCharacterController()->getCapsuleRadius();
|
||||||
|
@ -175,49 +152,106 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
||||||
|
|
||||||
_rig.updateFromEyeParameters(eyeParams);
|
_rig.updateFromEyeParameters(eyeParams);
|
||||||
|
|
||||||
updateFingers(myAvatar->getLeftHandFingerControllerPosesInSensorFrame());
|
updateFingers();
|
||||||
updateFingers(myAvatar->getRightHandFingerControllerPosesInSensorFrame());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MySkeletonModel::updateFingers(const MyAvatar::FingerPosesMap& fingerPoses) {
|
void MySkeletonModel::updateFingers() {
|
||||||
// Assumes that finger poses are kept in order in the poses map.
|
|
||||||
|
|
||||||
if (fingerPoses.size() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto posesMapItr = fingerPoses.begin();
|
|
||||||
|
|
||||||
bool isLeftHand = posesMapItr->first < (int)controller::Action::RIGHT_HAND_THUMB1;
|
|
||||||
|
|
||||||
MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar);
|
MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar);
|
||||||
auto handPose = isLeftHand
|
|
||||||
? myAvatar->getLeftHandControllerPoseInSensorFrame()
|
|
||||||
: myAvatar->getRightHandControllerPoseInSensorFrame();
|
|
||||||
auto handJointRotation = handPose.getRotation();
|
|
||||||
|
|
||||||
bool isHandValid = handPose.isValid();
|
static std::vector<std::vector<std::pair<controller::Action, QString>>> fingerChains = {
|
||||||
bool isFingerValid = false;
|
{
|
||||||
glm::quat previousJointRotation;
|
{ controller::Action::LEFT_HAND, "LeftHand" },
|
||||||
|
{ controller::Action::LEFT_HAND_THUMB1, "LeftHandThumb1" },
|
||||||
while (posesMapItr != fingerPoses.end()) {
|
{ controller::Action::LEFT_HAND_THUMB2, "LeftHandThumb2" },
|
||||||
auto jointName = posesMapItr->second.second;
|
{ controller::Action::LEFT_HAND_THUMB3, "LeftHandThumb3" },
|
||||||
if (isHandValid && jointName.right(1) == "1") {
|
{ controller::Action::LEFT_HAND_THUMB4, "LeftHandThumb4" }
|
||||||
isFingerValid = posesMapItr->second.first.isValid();
|
},
|
||||||
previousJointRotation = handJointRotation;
|
{
|
||||||
|
{ controller::Action::LEFT_HAND, "LeftHand" },
|
||||||
|
{ controller::Action::LEFT_HAND_INDEX1, "LeftHandIndex1" },
|
||||||
|
{ controller::Action::LEFT_HAND_INDEX2, "LeftHandIndex2" },
|
||||||
|
{ controller::Action::LEFT_HAND_INDEX3, "LeftHandIndex3" },
|
||||||
|
{ controller::Action::LEFT_HAND_INDEX4, "LeftHandIndex4" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ controller::Action::LEFT_HAND, "LeftHand" },
|
||||||
|
{ controller::Action::LEFT_HAND_MIDDLE1, "LeftHandMiddle1" },
|
||||||
|
{ controller::Action::LEFT_HAND_MIDDLE2, "LeftHandMiddle2" },
|
||||||
|
{ controller::Action::LEFT_HAND_MIDDLE3, "LeftHandMiddle3" },
|
||||||
|
{ controller::Action::LEFT_HAND_MIDDLE4, "LeftHandMiddle4" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ controller::Action::LEFT_HAND, "LeftHand" },
|
||||||
|
{ controller::Action::LEFT_HAND_RING1, "LeftHandRing1" },
|
||||||
|
{ controller::Action::LEFT_HAND_RING2, "LeftHandRing2" },
|
||||||
|
{ controller::Action::LEFT_HAND_RING3, "LeftHandRing3" },
|
||||||
|
{ controller::Action::LEFT_HAND_RING4, "LeftHandRing4" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ controller::Action::LEFT_HAND, "LeftHand" },
|
||||||
|
{ controller::Action::LEFT_HAND_PINKY1, "LeftHandPinky1" },
|
||||||
|
{ controller::Action::LEFT_HAND_PINKY2, "LeftHandPinky2" },
|
||||||
|
{ controller::Action::LEFT_HAND_PINKY3, "LeftHandPinky3" },
|
||||||
|
{ controller::Action::LEFT_HAND_PINKY4, "LeftHandPinky4" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ controller::Action::RIGHT_HAND, "RightHand" },
|
||||||
|
{ controller::Action::RIGHT_HAND_THUMB1, "RightHandThumb1" },
|
||||||
|
{ controller::Action::RIGHT_HAND_THUMB2, "RightHandThumb2" },
|
||||||
|
{ controller::Action::RIGHT_HAND_THUMB3, "RightHandThumb3" },
|
||||||
|
{ controller::Action::RIGHT_HAND_THUMB4, "RightHandThumb4" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ controller::Action::RIGHT_HAND, "RightHand" },
|
||||||
|
{ controller::Action::RIGHT_HAND_INDEX1, "RightHandIndex1" },
|
||||||
|
{ controller::Action::RIGHT_HAND_INDEX2, "RightHandIndex2" },
|
||||||
|
{ controller::Action::RIGHT_HAND_INDEX3, "RightHandIndex3" },
|
||||||
|
{ controller::Action::RIGHT_HAND_INDEX4, "RightHandIndex4" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ controller::Action::RIGHT_HAND, "RightHand" },
|
||||||
|
{ controller::Action::RIGHT_HAND_MIDDLE1, "RightHandMiddle1" },
|
||||||
|
{ controller::Action::RIGHT_HAND_MIDDLE2, "RightHandMiddle2" },
|
||||||
|
{ controller::Action::RIGHT_HAND_MIDDLE3, "RightHandMiddle3" },
|
||||||
|
{ controller::Action::RIGHT_HAND_MIDDLE4, "RightHandMiddle4" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ controller::Action::RIGHT_HAND, "RightHand" },
|
||||||
|
{ controller::Action::RIGHT_HAND_RING1, "RightHandRing1" },
|
||||||
|
{ controller::Action::RIGHT_HAND_RING2, "RightHandRing2" },
|
||||||
|
{ controller::Action::RIGHT_HAND_RING3, "RightHandRing3" },
|
||||||
|
{ controller::Action::RIGHT_HAND_RING4, "RightHandRing4" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ controller::Action::RIGHT_HAND, "RightHand" },
|
||||||
|
{ controller::Action::RIGHT_HAND_PINKY1, "RightHandPinky1" },
|
||||||
|
{ controller::Action::RIGHT_HAND_PINKY2, "RightHandPinky2" },
|
||||||
|
{ controller::Action::RIGHT_HAND_PINKY3, "RightHandPinky3" },
|
||||||
|
{ controller::Action::RIGHT_HAND_PINKY4, "RightHandPinky4" }
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (isHandValid && isFingerValid) {
|
const float CONTROLLER_PRIORITY = 2.0f;
|
||||||
auto thisJointRotation = posesMapItr->second.first.getRotation();
|
|
||||||
const float CONTROLLER_PRIORITY = 2.0f;
|
for (auto& chain : fingerChains) {
|
||||||
_rig.setJointRotation(_rig.indexOfJoint(jointName), true, glm::inverse(previousJointRotation) * thisJointRotation,
|
glm::quat prevAbsRot = Quaternions::IDENTITY;
|
||||||
CONTROLLER_PRIORITY);
|
for (auto& link : chain) {
|
||||||
previousJointRotation = thisJointRotation;
|
int index = _rig.indexOfJoint(link.second);
|
||||||
} else {
|
if (index >= 0) {
|
||||||
_rig.clearJointAnimationPriority(_rig.indexOfJoint(jointName));
|
auto pose = myAvatar->getControllerPoseInSensorFrame(link.first);
|
||||||
|
if (pose.valid) {
|
||||||
|
glm::quat relRot = glm::inverse(prevAbsRot) * pose.getRotation();
|
||||||
|
// only set the rotation for the finger joints, not the hands.
|
||||||
|
if (link.first != controller::Action::LEFT_HAND && link.first != controller::Action::RIGHT_HAND) {
|
||||||
|
_rig.setJointRotation(index, true, relRot, CONTROLLER_PRIORITY);
|
||||||
|
}
|
||||||
|
prevAbsRot = pose.getRotation();
|
||||||
|
} else {
|
||||||
|
_rig.clearJointAnimationPriority(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
posesMapItr++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ public:
|
||||||
void updateRig(float deltaTime, glm::mat4 parentTransform) override;
|
void updateRig(float deltaTime, glm::mat4 parentTransform) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateFingers(const MyAvatar::FingerPosesMap& fingerPoses);
|
void updateFingers();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_MySkeletonModel_h
|
#endif // hifi_MySkeletonModel_h
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include <shared/QtHelpers.h>
|
#include <shared/QtHelpers.h>
|
||||||
|
#include <plugins/DisplayPlugin.h>
|
||||||
|
|
||||||
#include "AudioDevices.h"
|
#include "AudioDevices.h"
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
//#include "Application.h"
|
|
||||||
#include "ResourceImageItem.h"
|
#include "ResourceImageItem.h"
|
||||||
|
|
||||||
#include <QOpenGLFramebufferObjectFormat>
|
#include <QOpenGLFramebufferObjectFormat>
|
||||||
|
@ -16,6 +15,8 @@
|
||||||
#include <QOpenGLExtraFunctions>
|
#include <QOpenGLExtraFunctions>
|
||||||
#include <QOpenGLContext>
|
#include <QOpenGLContext>
|
||||||
|
|
||||||
|
#include <plugins/DisplayPlugin.h>
|
||||||
|
|
||||||
ResourceImageItem::ResourceImageItem() : QQuickFramebufferObject() {
|
ResourceImageItem::ResourceImageItem() : QQuickFramebufferObject() {
|
||||||
auto textureCache = DependencyManager::get<TextureCache>();
|
auto textureCache = DependencyManager::get<TextureCache>();
|
||||||
connect(textureCache.data(), SIGNAL(spectatorCameraFramebufferReset()), this, SLOT(update()));
|
connect(textureCache.data(), SIGNAL(spectatorCameraFramebufferReset()), this, SLOT(update()));
|
||||||
|
|
|
@ -13,8 +13,9 @@
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
#include <QtCore/QString>
|
#include <QtCore/QString>
|
||||||
#include <QtGui/QImage>
|
#include <QtGui/QImage>
|
||||||
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
|
|
||||||
#include <QtConcurrent/qtconcurrentrun.h>
|
#include <plugins/DisplayPlugin.h>
|
||||||
#include "SnapshotAnimated.h"
|
#include "SnapshotAnimated.h"
|
||||||
|
|
||||||
QTimer* SnapshotAnimated::snapshotAnimatedTimer = NULL;
|
QTimer* SnapshotAnimated::snapshotAnimatedTimer = NULL;
|
||||||
|
|
|
@ -257,15 +257,23 @@ void ContextOverlayInterface::openMarketplace() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextOverlayInterface::enableEntityHighlight(const EntityItemID& entityItemID) {
|
void ContextOverlayInterface::enableEntityHighlight(const EntityItemID& entityItemID) {
|
||||||
if (!qApp->getEntities()->getTree()->findEntityByEntityItemID(entityItemID)->getShouldHighlight()) {
|
auto entityTree = qApp->getEntities()->getTree();
|
||||||
qCDebug(context_overlay) << "Setting 'shouldHighlight' to 'true' for Entity ID:" << entityItemID;
|
entityTree->withReadLock([&] {
|
||||||
qApp->getEntities()->getTree()->findEntityByEntityItemID(entityItemID)->setShouldHighlight(true);
|
auto entityItem = entityTree->findEntityByEntityItemID(entityItemID);
|
||||||
}
|
if ((entityItem != NULL) && !entityItem->getShouldHighlight()) {
|
||||||
|
qCDebug(context_overlay) << "Setting 'shouldHighlight' to 'true' for Entity ID:" << entityItemID;
|
||||||
|
entityItem->setShouldHighlight(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextOverlayInterface::disableEntityHighlight(const EntityItemID& entityItemID) {
|
void ContextOverlayInterface::disableEntityHighlight(const EntityItemID& entityItemID) {
|
||||||
if (qApp->getEntities()->getTree()->findEntityByEntityItemID(entityItemID)->getShouldHighlight()) {
|
auto entityTree = qApp->getEntities()->getTree();
|
||||||
qCDebug(context_overlay) << "Setting 'shouldHighlight' to 'false' for Entity ID:" << entityItemID;
|
entityTree->withReadLock([&] {
|
||||||
qApp->getEntities()->getTree()->findEntityByEntityItemID(entityItemID)->setShouldHighlight(false);
|
auto entityItem = entityTree->findEntityByEntityItemID(entityItemID);
|
||||||
}
|
if ((entityItem != NULL) && entityItem->getShouldHighlight()) {
|
||||||
|
qCDebug(context_overlay) << "Setting 'shouldHighlight' to 'false' for Entity ID:" << entityItemID;
|
||||||
|
entityItem->setShouldHighlight(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,8 +127,9 @@ QString Web3DOverlay::pickURL() {
|
||||||
QUrl sourceUrl(_url);
|
QUrl sourceUrl(_url);
|
||||||
if (sourceUrl.scheme() == "http" || sourceUrl.scheme() == "https" ||
|
if (sourceUrl.scheme() == "http" || sourceUrl.scheme() == "https" ||
|
||||||
_url.toLower().endsWith(".htm") || _url.toLower().endsWith(".html")) {
|
_url.toLower().endsWith(".htm") || _url.toLower().endsWith(".html")) {
|
||||||
|
if (_webSurface) {
|
||||||
_webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
|
_webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
|
||||||
|
}
|
||||||
return "Web3DOverlay.qml";
|
return "Web3DOverlay.qml";
|
||||||
} else {
|
} else {
|
||||||
return QUrl::fromLocalFile(PathUtils::resourcesPath()).toString() + "/" + _url;
|
return QUrl::fromLocalFile(PathUtils::resourcesPath()).toString() + "/" + _url;
|
||||||
|
@ -252,7 +253,7 @@ void Web3DOverlay::render(RenderArgs* args) {
|
||||||
if (overlayID == selfOverlayID && (self->_pressed || (!self->_activeTouchPoints.empty() && self->_touchBeginAccepted))) {
|
if (overlayID == selfOverlayID && (self->_pressed || (!self->_activeTouchPoints.empty() && self->_touchBeginAccepted))) {
|
||||||
PointerEvent endEvent(PointerEvent::Release, event.getID(), event.getPos2D(), event.getPos3D(), event.getNormal(), event.getDirection(),
|
PointerEvent endEvent(PointerEvent::Release, event.getID(), event.getPos2D(), event.getPos3D(), event.getNormal(), event.getDirection(),
|
||||||
event.getButton(), event.getButtons(), event.getKeyboardModifiers());
|
event.getButton(), event.getButtons(), event.getKeyboardModifiers());
|
||||||
forwardPointerEvent(overlayID, event);
|
forwardPointerEvent(overlayID, endEvent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -23,12 +23,13 @@
|
||||||
#include "CubicHermiteSpline.h"
|
#include "CubicHermiteSpline.h"
|
||||||
#include "AnimUtil.h"
|
#include "AnimUtil.h"
|
||||||
|
|
||||||
|
static const int MAX_TARGET_MARKERS = 30;
|
||||||
static const float JOINT_CHAIN_INTERP_TIME = 0.25f;
|
static const float JOINT_CHAIN_INTERP_TIME = 0.25f;
|
||||||
|
|
||||||
static void lookupJointInfo(const AnimInverseKinematics::JointChainInfo& jointChainInfo,
|
static void lookupJointInfo(const AnimInverseKinematics::JointChainInfo& jointChainInfo,
|
||||||
int indexA, int indexB,
|
int indexA, int indexB,
|
||||||
const AnimInverseKinematics::JointInfo** jointInfoA,
|
const AnimInverseKinematics::JointInfo** jointInfoA,
|
||||||
const AnimInverseKinematics::JointInfo** jointInfoB) {
|
const AnimInverseKinematics::JointInfo** jointInfoB) {
|
||||||
*jointInfoA = nullptr;
|
*jointInfoA = nullptr;
|
||||||
*jointInfoB = nullptr;
|
*jointInfoB = nullptr;
|
||||||
for (size_t i = 0; i < jointChainInfo.jointInfoVec.size(); i++) {
|
for (size_t i = 0; i < jointChainInfo.jointInfoVec.size(); i++) {
|
||||||
|
@ -97,6 +98,12 @@ AnimInverseKinematics::~AnimInverseKinematics() {
|
||||||
_rotationAccumulators.clear();
|
_rotationAccumulators.clear();
|
||||||
_translationAccumulators.clear();
|
_translationAccumulators.clear();
|
||||||
_targetVarVec.clear();
|
_targetVarVec.clear();
|
||||||
|
|
||||||
|
// remove markers
|
||||||
|
for (int i = 0; i < MAX_TARGET_MARKERS; i++) {
|
||||||
|
QString name = QString("ikTarget%1").arg(i);
|
||||||
|
DebugDraw::getInstance().removeMyAvatarMarker(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimInverseKinematics::loadDefaultPoses(const AnimPoseVec& poses) {
|
void AnimInverseKinematics::loadDefaultPoses(const AnimPoseVec& poses) {
|
||||||
|
@ -1015,19 +1022,30 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
||||||
// debug render ik targets
|
// debug render ik targets
|
||||||
if (context.getEnableDebugDrawIKTargets()) {
|
if (context.getEnableDebugDrawIKTargets()) {
|
||||||
const vec4 WHITE(1.0f);
|
const vec4 WHITE(1.0f);
|
||||||
|
const vec4 GREEN(0.0f, 1.0f, 0.0f, 1.0f);
|
||||||
glm::mat4 rigToAvatarMat = createMatFromQuatAndPos(Quaternions::Y_180, glm::vec3());
|
glm::mat4 rigToAvatarMat = createMatFromQuatAndPos(Quaternions::Y_180, glm::vec3());
|
||||||
|
int targetNum = 0;
|
||||||
|
|
||||||
for (auto& target : targets) {
|
for (auto& target : targets) {
|
||||||
glm::mat4 geomTargetMat = createMatFromQuatAndPos(target.getRotation(), target.getTranslation());
|
glm::mat4 geomTargetMat = createMatFromQuatAndPos(target.getRotation(), target.getTranslation());
|
||||||
glm::mat4 avatarTargetMat = rigToAvatarMat * context.getGeometryToRigMatrix() * geomTargetMat;
|
glm::mat4 avatarTargetMat = rigToAvatarMat * context.getGeometryToRigMatrix() * geomTargetMat;
|
||||||
|
|
||||||
QString name = QString("ikTarget%1").arg(target.getIndex());
|
QString name = QString("ikTarget%1").arg(targetNum);
|
||||||
DebugDraw::getInstance().addMyAvatarMarker(name, glmExtractRotation(avatarTargetMat), extractTranslation(avatarTargetMat), WHITE);
|
DebugDraw::getInstance().addMyAvatarMarker(name, glmExtractRotation(avatarTargetMat), extractTranslation(avatarTargetMat), WHITE);
|
||||||
|
targetNum++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw secondary ik targets
|
||||||
|
for (auto& iter : _secondaryTargetsInRigFrame) {
|
||||||
|
glm::mat4 avatarTargetMat = rigToAvatarMat * (glm::mat4)iter.second;
|
||||||
|
QString name = QString("ikTarget%1").arg(targetNum);
|
||||||
|
DebugDraw::getInstance().addMyAvatarMarker(name, glmExtractRotation(avatarTargetMat), extractTranslation(avatarTargetMat), GREEN);
|
||||||
|
targetNum++;
|
||||||
}
|
}
|
||||||
} else if (context.getEnableDebugDrawIKTargets() != _previousEnableDebugIKTargets) {
|
} else if (context.getEnableDebugDrawIKTargets() != _previousEnableDebugIKTargets) {
|
||||||
// remove markers if they were added last frame.
|
// remove markers if they were added last frame.
|
||||||
for (auto& target : targets) {
|
for (int i = 0; i < MAX_TARGET_MARKERS; i++) {
|
||||||
QString name = QString("ikTarget%1").arg(target.getIndex());
|
QString name = QString("ikTarget%1").arg(i);
|
||||||
DebugDraw::getInstance().removeMyAvatarMarker(name);
|
DebugDraw::getInstance().removeMyAvatarMarker(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1038,7 +1056,9 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
||||||
{
|
{
|
||||||
PROFILE_RANGE_EX(simulation_animation, "ik/ccd", 0xffff00ff, 0);
|
PROFILE_RANGE_EX(simulation_animation, "ik/ccd", 0xffff00ff, 0);
|
||||||
|
|
||||||
|
setSecondaryTargets(context);
|
||||||
preconditionRelativePosesToAvoidLimbLock(context, targets);
|
preconditionRelativePosesToAvoidLimbLock(context, targets);
|
||||||
|
|
||||||
solve(context, targets, dt, jointChainInfoVec);
|
solve(context, targets, dt, jointChainInfoVec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1125,6 +1145,22 @@ void AnimInverseKinematics::clearIKJointLimitHistory() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AnimInverseKinematics::setSecondaryTargetInRigFrame(int jointIndex, const AnimPose& pose) {
|
||||||
|
auto iter = _secondaryTargetsInRigFrame.find(jointIndex);
|
||||||
|
if (iter != _secondaryTargetsInRigFrame.end()) {
|
||||||
|
iter->second = pose;
|
||||||
|
} else {
|
||||||
|
_secondaryTargetsInRigFrame.insert({ jointIndex, pose });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimInverseKinematics::clearSecondaryTarget(int jointIndex) {
|
||||||
|
auto iter = _secondaryTargetsInRigFrame.find(jointIndex);
|
||||||
|
if (iter != _secondaryTargetsInRigFrame.end()) {
|
||||||
|
_secondaryTargetsInRigFrame.erase(iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RotationConstraint* AnimInverseKinematics::getConstraint(int index) const {
|
RotationConstraint* AnimInverseKinematics::getConstraint(int index) const {
|
||||||
RotationConstraint* constraint = nullptr;
|
RotationConstraint* constraint = nullptr;
|
||||||
std::map<int, RotationConstraint*>::const_iterator constraintItr = _constraints.find(index);
|
std::map<int, RotationConstraint*>::const_iterator constraintItr = _constraints.find(index);
|
||||||
|
@ -1575,7 +1611,7 @@ void AnimInverseKinematics::debugDrawRelativePoses(const AnimContext& context) c
|
||||||
const vec4 GREEN(0.0f, 1.0f, 0.0f, 1.0f);
|
const vec4 GREEN(0.0f, 1.0f, 0.0f, 1.0f);
|
||||||
const vec4 BLUE(0.0f, 0.0f, 1.0f, 1.0f);
|
const vec4 BLUE(0.0f, 0.0f, 1.0f, 1.0f);
|
||||||
const vec4 GRAY(0.2f, 0.2f, 0.2f, 1.0f);
|
const vec4 GRAY(0.2f, 0.2f, 0.2f, 1.0f);
|
||||||
const float AXIS_LENGTH = 2.0f; // cm
|
const float AXIS_LENGTH = 10.0f; // cm
|
||||||
|
|
||||||
// draw each pose
|
// draw each pose
|
||||||
for (int i = 0; i < (int)poses.size(); i++) {
|
for (int i = 0; i < (int)poses.size(); i++) {
|
||||||
|
@ -1605,8 +1641,10 @@ void AnimInverseKinematics::debugDrawIKChain(const JointChainInfo& jointChainInf
|
||||||
// copy debug joint rotations into the relative poses
|
// copy debug joint rotations into the relative poses
|
||||||
for (size_t i = 0; i < jointChainInfo.jointInfoVec.size(); i++) {
|
for (size_t i = 0; i < jointChainInfo.jointInfoVec.size(); i++) {
|
||||||
const JointInfo& info = jointChainInfo.jointInfoVec[i];
|
const JointInfo& info = jointChainInfo.jointInfoVec[i];
|
||||||
poses[info.jointIndex].rot() = info.rot;
|
if (info.jointIndex != _hipsIndex) {
|
||||||
poses[info.jointIndex].trans() = info.trans;
|
poses[info.jointIndex].rot() = info.rot;
|
||||||
|
poses[info.jointIndex].trans() = info.trans;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert relative poses to absolute
|
// convert relative poses to absolute
|
||||||
|
@ -1825,6 +1863,59 @@ void AnimInverseKinematics::preconditionRelativePosesToAvoidLimbLock(const AnimC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// overwrites _relativePoses with secondary poses.
|
||||||
|
void AnimInverseKinematics::setSecondaryTargets(const AnimContext& context) {
|
||||||
|
|
||||||
|
if (_secondaryTargetsInRigFrame.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// special case for arm secondary poses.
|
||||||
|
// determine if shoulder joint should look-at position of arm joint.
|
||||||
|
bool shoulderShouldLookAtArm = false;
|
||||||
|
const int leftArmIndex = _skeleton->nameToJointIndex("LeftArm");
|
||||||
|
const int rightArmIndex = _skeleton->nameToJointIndex("RightArm");
|
||||||
|
const int leftShoulderIndex = _skeleton->nameToJointIndex("LeftShoulder");
|
||||||
|
const int rightShoulderIndex = _skeleton->nameToJointIndex("RightShoulder");
|
||||||
|
for (auto& iter : _secondaryTargetsInRigFrame) {
|
||||||
|
if (iter.first == leftShoulderIndex || iter.first == rightShoulderIndex) {
|
||||||
|
shoulderShouldLookAtArm = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimPose rigToGeometryPose = AnimPose(glm::inverse(context.getGeometryToRigMatrix()));
|
||||||
|
for (auto& iter : _secondaryTargetsInRigFrame) {
|
||||||
|
AnimPose absPose = rigToGeometryPose * iter.second;
|
||||||
|
absPose.scale() = glm::vec3(1.0f);
|
||||||
|
|
||||||
|
AnimPose parentAbsPose;
|
||||||
|
int parentIndex = _skeleton->getParentIndex(iter.first);
|
||||||
|
if (parentIndex >= 0) {
|
||||||
|
parentAbsPose = _skeleton->getAbsolutePose(parentIndex, _relativePoses);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if parent should "look-at" child joint position.
|
||||||
|
if (shoulderShouldLookAtArm && (iter.first == leftArmIndex || iter.first == rightArmIndex)) {
|
||||||
|
|
||||||
|
AnimPose grandParentAbsPose;
|
||||||
|
int grandParentIndex = _skeleton->getParentIndex(parentIndex);
|
||||||
|
if (parentIndex >= 0) {
|
||||||
|
grandParentAbsPose = _skeleton->getAbsolutePose(grandParentIndex, _relativePoses);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the shoulder should rotate toward the arm joint via "look-at" constraint
|
||||||
|
parentAbsPose = boneLookAt(absPose.trans(), parentAbsPose);
|
||||||
|
_relativePoses[parentIndex] = grandParentAbsPose.inverse() * parentAbsPose;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore translation on secondary poses, to prevent them from distorting the skeleton.
|
||||||
|
glm::vec3 origTrans = _relativePoses[iter.first].trans();
|
||||||
|
_relativePoses[iter.first] = parentAbsPose.inverse() * absPose;
|
||||||
|
_relativePoses[iter.first].trans() = origTrans;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AnimInverseKinematics::initRelativePosesFromSolutionSource(SolutionSource solutionSource, const AnimPoseVec& underPoses) {
|
void AnimInverseKinematics::initRelativePosesFromSolutionSource(SolutionSource solutionSource, const AnimPoseVec& underPoses) {
|
||||||
const float RELAX_BLEND_FACTOR = (1.0f / 16.0f);
|
const float RELAX_BLEND_FACTOR = (1.0f / 16.0f);
|
||||||
const float COPY_BLEND_FACTOR = 1.0f;
|
const float COPY_BLEND_FACTOR = 1.0f;
|
||||||
|
|
|
@ -70,6 +70,9 @@ public:
|
||||||
NumSolutionSources,
|
NumSolutionSources,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void setSecondaryTargetInRigFrame(int jointIndex, const AnimPose& pose);
|
||||||
|
void clearSecondaryTarget(int jointIndex);
|
||||||
|
|
||||||
void setSolutionSource(SolutionSource solutionSource) { _solutionSource = solutionSource; }
|
void setSolutionSource(SolutionSource solutionSource) { _solutionSource = solutionSource; }
|
||||||
void setSolutionSourceVar(const QString& solutionSourceVar) { _solutionSourceVar = solutionSourceVar; }
|
void setSolutionSourceVar(const QString& solutionSourceVar) { _solutionSourceVar = solutionSourceVar; }
|
||||||
|
|
||||||
|
@ -88,6 +91,7 @@ protected:
|
||||||
void initRelativePosesFromSolutionSource(SolutionSource solutionSource, const AnimPoseVec& underPose);
|
void initRelativePosesFromSolutionSource(SolutionSource solutionSource, const AnimPoseVec& underPose);
|
||||||
void blendToPoses(const AnimPoseVec& targetPoses, const AnimPoseVec& underPose, float blendFactor);
|
void blendToPoses(const AnimPoseVec& targetPoses, const AnimPoseVec& underPose, float blendFactor);
|
||||||
void preconditionRelativePosesToAvoidLimbLock(const AnimContext& context, const std::vector<IKTarget>& targets);
|
void preconditionRelativePosesToAvoidLimbLock(const AnimContext& context, const std::vector<IKTarget>& targets);
|
||||||
|
void setSecondaryTargets(const AnimContext& context);
|
||||||
AnimPose applyHipsOffset() const;
|
AnimPose applyHipsOffset() const;
|
||||||
|
|
||||||
// used to pre-compute information about each joint influeced by a spline IK target.
|
// used to pre-compute information about each joint influeced by a spline IK target.
|
||||||
|
@ -142,6 +146,8 @@ protected:
|
||||||
AnimPoseVec _relativePoses; // current relative poses
|
AnimPoseVec _relativePoses; // current relative poses
|
||||||
AnimPoseVec _limitCenterPoses; // relative
|
AnimPoseVec _limitCenterPoses; // relative
|
||||||
|
|
||||||
|
std::map<int, AnimPose> _secondaryTargetsInRigFrame;
|
||||||
|
|
||||||
mutable std::map<int, std::vector<SplineJointInfo>> _splineJointInfoMap;
|
mutable std::map<int, std::vector<SplineJointInfo>> _splineJointInfoMap;
|
||||||
|
|
||||||
// experimental data for moving hips during IK
|
// experimental data for moving hips during IK
|
||||||
|
|
|
@ -96,3 +96,14 @@ float accumulateTime(float startFrame, float endFrame, float timeScale, float cu
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rotate bone's y-axis with target.
|
||||||
|
AnimPose boneLookAt(const glm::vec3& target, const AnimPose& bone) {
|
||||||
|
glm::vec3 u, v, w;
|
||||||
|
generateBasisVectors(target - bone.trans(), bone.rot() * Vectors::UNIT_X, u, v, w);
|
||||||
|
glm::mat4 lookAt(glm::vec4(v, 0.0f),
|
||||||
|
glm::vec4(u, 0.0f),
|
||||||
|
// AJT: TODO REVISIT THIS, this could be -w.
|
||||||
|
glm::vec4(glm::normalize(glm::cross(v, u)), 0.0f),
|
||||||
|
glm::vec4(bone.trans(), 1.0f));
|
||||||
|
return AnimPose(lookAt);
|
||||||
|
}
|
||||||
|
|
|
@ -31,4 +31,6 @@ inline glm::quat safeLerp(const glm::quat& a, const glm::quat& b, float alpha) {
|
||||||
return glm::normalize(glm::lerp(a, bTemp, alpha));
|
return glm::normalize(glm::lerp(a, bTemp, alpha));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AnimPose boneLookAt(const glm::vec3& target, const AnimPose& bone);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1399,24 +1399,25 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo
|
||||||
_animVars.set("isTalking", params.isTalking);
|
_animVars.set("isTalking", params.isTalking);
|
||||||
_animVars.set("notIsTalking", !params.isTalking);
|
_animVars.set("notIsTalking", !params.isTalking);
|
||||||
|
|
||||||
bool headEnabled = params.controllerActiveFlags[ControllerType_Head];
|
bool headEnabled = params.primaryControllerActiveFlags[PrimaryControllerType_Head];
|
||||||
bool leftHandEnabled = params.controllerActiveFlags[ControllerType_LeftHand];
|
bool leftHandEnabled = params.primaryControllerActiveFlags[PrimaryControllerType_LeftHand];
|
||||||
bool rightHandEnabled = params.controllerActiveFlags[ControllerType_RightHand];
|
bool rightHandEnabled = params.primaryControllerActiveFlags[PrimaryControllerType_RightHand];
|
||||||
bool hipsEnabled = params.controllerActiveFlags[ControllerType_Hips];
|
bool hipsEnabled = params.primaryControllerActiveFlags[PrimaryControllerType_Hips];
|
||||||
bool leftFootEnabled = params.controllerActiveFlags[ControllerType_LeftFoot];
|
bool leftFootEnabled = params.primaryControllerActiveFlags[PrimaryControllerType_LeftFoot];
|
||||||
bool rightFootEnabled = params.controllerActiveFlags[ControllerType_RightFoot];
|
bool rightFootEnabled = params.primaryControllerActiveFlags[PrimaryControllerType_RightFoot];
|
||||||
bool leftArmEnabled = params.controllerActiveFlags[ControllerType_LeftArm];
|
bool spine2Enabled = params.primaryControllerActiveFlags[PrimaryControllerType_Spine2];
|
||||||
bool rightArmEnabled = params.controllerActiveFlags[ControllerType_RightArm];
|
|
||||||
bool spine2Enabled = params.controllerActiveFlags[ControllerType_Spine2];
|
|
||||||
|
|
||||||
updateHead(headEnabled, hipsEnabled, params.controllerPoses[ControllerType_Head]);
|
bool leftArmEnabled = params.secondaryControllerActiveFlags[SecondaryControllerType_LeftArm];
|
||||||
|
bool rightArmEnabled = params.secondaryControllerActiveFlags[SecondaryControllerType_RightArm];
|
||||||
|
|
||||||
|
updateHead(headEnabled, hipsEnabled, params.primaryControllerPoses[PrimaryControllerType_Head]);
|
||||||
|
|
||||||
updateHands(leftHandEnabled, rightHandEnabled, hipsEnabled, leftArmEnabled, rightArmEnabled, dt,
|
updateHands(leftHandEnabled, rightHandEnabled, hipsEnabled, leftArmEnabled, rightArmEnabled, dt,
|
||||||
params.controllerPoses[ControllerType_LeftHand], params.controllerPoses[ControllerType_RightHand],
|
params.primaryControllerPoses[PrimaryControllerType_LeftHand], params.primaryControllerPoses[PrimaryControllerType_RightHand],
|
||||||
params.bodyCapsuleRadius, params.bodyCapsuleHalfHeight, params.bodyCapsuleLocalOffset);
|
params.bodyCapsuleRadius, params.bodyCapsuleHalfHeight, params.bodyCapsuleLocalOffset);
|
||||||
|
|
||||||
updateFeet(leftFootEnabled, rightFootEnabled,
|
updateFeet(leftFootEnabled, rightFootEnabled,
|
||||||
params.controllerPoses[ControllerType_LeftFoot], params.controllerPoses[ControllerType_RightFoot]);
|
params.primaryControllerPoses[PrimaryControllerType_LeftFoot], params.primaryControllerPoses[PrimaryControllerType_RightFoot]);
|
||||||
|
|
||||||
// if the hips or the feet are being controlled.
|
// if the hips or the feet are being controlled.
|
||||||
if (hipsEnabled || rightFootEnabled || leftFootEnabled) {
|
if (hipsEnabled || rightFootEnabled || leftFootEnabled) {
|
||||||
|
@ -1437,34 +1438,46 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo
|
||||||
|
|
||||||
if (hipsEnabled) {
|
if (hipsEnabled) {
|
||||||
_animVars.set("hipsType", (int)IKTarget::Type::RotationAndPosition);
|
_animVars.set("hipsType", (int)IKTarget::Type::RotationAndPosition);
|
||||||
_animVars.set("hipsPosition", params.controllerPoses[ControllerType_Hips].trans());
|
_animVars.set("hipsPosition", params.primaryControllerPoses[PrimaryControllerType_Hips].trans());
|
||||||
_animVars.set("hipsRotation", params.controllerPoses[ControllerType_Hips].rot());
|
_animVars.set("hipsRotation", params.primaryControllerPoses[PrimaryControllerType_Hips].rot());
|
||||||
} else {
|
} else {
|
||||||
_animVars.set("hipsType", (int)IKTarget::Type::Unknown);
|
_animVars.set("hipsType", (int)IKTarget::Type::Unknown);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hipsEnabled && spine2Enabled) {
|
if (hipsEnabled && spine2Enabled) {
|
||||||
_animVars.set("spine2Type", (int)IKTarget::Type::Spline);
|
_animVars.set("spine2Type", (int)IKTarget::Type::Spline);
|
||||||
_animVars.set("spine2Position", params.controllerPoses[ControllerType_Spine2].trans());
|
_animVars.set("spine2Position", params.primaryControllerPoses[PrimaryControllerType_Spine2].trans());
|
||||||
_animVars.set("spine2Rotation", params.controllerPoses[ControllerType_Spine2].rot());
|
_animVars.set("spine2Rotation", params.primaryControllerPoses[PrimaryControllerType_Spine2].rot());
|
||||||
} else {
|
} else {
|
||||||
_animVars.set("spine2Type", (int)IKTarget::Type::Unknown);
|
_animVars.set("spine2Type", (int)IKTarget::Type::Unknown);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leftArmEnabled) {
|
// set secondary targets
|
||||||
_animVars.set("leftArmType", (int)IKTarget::Type::RotationAndPosition);
|
static const std::vector<QString> secondaryControllerJointNames = {
|
||||||
_animVars.set("leftArmPosition", params.controllerPoses[ControllerType_LeftArm].trans());
|
"LeftShoulder",
|
||||||
_animVars.set("leftArmRotation", params.controllerPoses[ControllerType_LeftArm].rot());
|
"RightShoulder",
|
||||||
} else {
|
"LeftArm",
|
||||||
_animVars.set("leftArmType", (int)IKTarget::Type::Unknown);
|
"RightArm",
|
||||||
}
|
"LeftForeArm",
|
||||||
|
"RightForeArm",
|
||||||
|
"LeftUpLeg",
|
||||||
|
"RightUpLeg",
|
||||||
|
"LeftLeg",
|
||||||
|
"RightLeg",
|
||||||
|
"LeftToeBase",
|
||||||
|
"RightToeBase"
|
||||||
|
};
|
||||||
|
|
||||||
if (rightArmEnabled) {
|
std::shared_ptr<AnimInverseKinematics> ikNode = getAnimInverseKinematicsNode();
|
||||||
_animVars.set("rightArmType", (int)IKTarget::Type::RotationAndPosition);
|
for (int i = 0; i < (int)NumSecondaryControllerTypes; i++) {
|
||||||
_animVars.set("rightArmPosition", params.controllerPoses[ControllerType_RightArm].trans());
|
int index = indexOfJoint(secondaryControllerJointNames[i]);
|
||||||
_animVars.set("rightArmRotation", params.controllerPoses[ControllerType_RightArm].rot());
|
if (index >= 0) {
|
||||||
} else {
|
if (params.secondaryControllerActiveFlags[i]) {
|
||||||
_animVars.set("rightArmType", (int)IKTarget::Type::Unknown);
|
ikNode->setSecondaryTargetInRigFrame(index, params.secondaryControllerPoses[i]);
|
||||||
|
} else {
|
||||||
|
ikNode->clearSecondaryTarget(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,22 +41,39 @@ public:
|
||||||
bool useNames;
|
bool useNames;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ControllerType {
|
enum PrimaryControllerType {
|
||||||
ControllerType_Head = 0,
|
PrimaryControllerType_Head = 0,
|
||||||
ControllerType_LeftHand,
|
PrimaryControllerType_LeftHand,
|
||||||
ControllerType_RightHand,
|
PrimaryControllerType_RightHand,
|
||||||
ControllerType_Hips,
|
PrimaryControllerType_Hips,
|
||||||
ControllerType_LeftFoot,
|
PrimaryControllerType_LeftFoot,
|
||||||
ControllerType_RightFoot,
|
PrimaryControllerType_RightFoot,
|
||||||
ControllerType_LeftArm,
|
PrimaryControllerType_Spine2,
|
||||||
ControllerType_RightArm,
|
NumPrimaryControllerTypes
|
||||||
ControllerType_Spine2,
|
};
|
||||||
NumControllerTypes
|
|
||||||
|
// NOTE: These should ordered such that joint parents appear before their children.
|
||||||
|
enum SecondaryControllerType {
|
||||||
|
SecondaryControllerType_LeftShoulder = 0,
|
||||||
|
SecondaryControllerType_RightShoulder,
|
||||||
|
SecondaryControllerType_LeftArm,
|
||||||
|
SecondaryControllerType_RightArm,
|
||||||
|
SecondaryControllerType_LeftForeArm,
|
||||||
|
SecondaryControllerType_RightForeArm,
|
||||||
|
SecondaryControllerType_LeftUpLeg,
|
||||||
|
SecondaryControllerType_RightUpLeg,
|
||||||
|
SecondaryControllerType_LeftLeg,
|
||||||
|
SecondaryControllerType_RightLeg,
|
||||||
|
SecondaryControllerType_LeftToeBase,
|
||||||
|
SecondaryControllerType_RightToeBase,
|
||||||
|
NumSecondaryControllerTypes
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ControllerParameters {
|
struct ControllerParameters {
|
||||||
AnimPose controllerPoses[NumControllerTypes]; // rig space
|
AnimPose primaryControllerPoses[NumPrimaryControllerTypes]; // rig space
|
||||||
bool controllerActiveFlags[NumControllerTypes];
|
bool primaryControllerActiveFlags[NumPrimaryControllerTypes];
|
||||||
|
AnimPose secondaryControllerPoses[NumSecondaryControllerTypes]; // rig space
|
||||||
|
bool secondaryControllerActiveFlags[NumSecondaryControllerTypes];
|
||||||
bool isTalking;
|
bool isTalking;
|
||||||
float bodyCapsuleRadius;
|
float bodyCapsuleRadius;
|
||||||
float bodyCapsuleHalfHeight;
|
float bodyCapsuleHalfHeight;
|
||||||
|
|
|
@ -101,6 +101,7 @@ enum class Action {
|
||||||
// Bisected aliases for TRANSLATE_CAMERA_Z
|
// Bisected aliases for TRANSLATE_CAMERA_Z
|
||||||
BOOM_IN,
|
BOOM_IN,
|
||||||
BOOM_OUT,
|
BOOM_OUT,
|
||||||
|
|
||||||
LEFT_ARM,
|
LEFT_ARM,
|
||||||
RIGHT_ARM,
|
RIGHT_ARM,
|
||||||
|
|
||||||
|
@ -146,6 +147,17 @@ enum class Action {
|
||||||
RIGHT_HAND_PINKY3,
|
RIGHT_HAND_PINKY3,
|
||||||
RIGHT_HAND_PINKY4,
|
RIGHT_HAND_PINKY4,
|
||||||
|
|
||||||
|
LEFT_SHOULDER,
|
||||||
|
RIGHT_SHOULDER,
|
||||||
|
LEFT_FORE_ARM,
|
||||||
|
RIGHT_FORE_ARM,
|
||||||
|
LEFT_LEG,
|
||||||
|
RIGHT_LEG,
|
||||||
|
LEFT_UP_LEG,
|
||||||
|
RIGHT_UP_LEG,
|
||||||
|
LEFT_TOE_BASE,
|
||||||
|
RIGHT_TOE_BASE,
|
||||||
|
|
||||||
TRACKED_OBJECT_00,
|
TRACKED_OBJECT_00,
|
||||||
TRACKED_OBJECT_01,
|
TRACKED_OBJECT_01,
|
||||||
TRACKED_OBJECT_02,
|
TRACKED_OBJECT_02,
|
||||||
|
@ -163,7 +175,7 @@ enum class Action {
|
||||||
TRACKED_OBJECT_14,
|
TRACKED_OBJECT_14,
|
||||||
TRACKED_OBJECT_15,
|
TRACKED_OBJECT_15,
|
||||||
|
|
||||||
NUM_ACTIONS,
|
NUM_ACTIONS
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
|
@ -69,7 +69,7 @@ RenderableWebEntityItem::~RenderableWebEntityItem() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenderableWebEntityItem::buildWebSurface(QSharedPointer<EntityTreeRenderer> renderer) {
|
bool RenderableWebEntityItem::buildWebSurface() {
|
||||||
if (_currentWebCount >= MAX_CONCURRENT_WEB_VIEWS) {
|
if (_currentWebCount >= MAX_CONCURRENT_WEB_VIEWS) {
|
||||||
qWarning() << "Too many concurrent web views to create new view";
|
qWarning() << "Too many concurrent web views to create new view";
|
||||||
return false;
|
return false;
|
||||||
|
@ -132,6 +132,8 @@ bool RenderableWebEntityItem::buildWebSurface(QSharedPointer<EntityTreeRenderer>
|
||||||
handlePointerEvent(event);
|
handlePointerEvent(event);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto renderer = DependencyManager::get<EntityTreeRenderer>();
|
||||||
_mousePressConnection = QObject::connect(renderer.data(), &EntityTreeRenderer::mousePressOnEntity, forwardPointerEvent);
|
_mousePressConnection = QObject::connect(renderer.data(), &EntityTreeRenderer::mousePressOnEntity, forwardPointerEvent);
|
||||||
_mouseReleaseConnection = QObject::connect(renderer.data(), &EntityTreeRenderer::mouseReleaseOnEntity, forwardPointerEvent);
|
_mouseReleaseConnection = QObject::connect(renderer.data(), &EntityTreeRenderer::mouseReleaseOnEntity, forwardPointerEvent);
|
||||||
_mouseMoveConnection = QObject::connect(renderer.data(), &EntityTreeRenderer::mouseMoveOnEntity, forwardPointerEvent);
|
_mouseMoveConnection = QObject::connect(renderer.data(), &EntityTreeRenderer::mouseMoveOnEntity, forwardPointerEvent);
|
||||||
|
@ -185,8 +187,7 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!_webSurface) {
|
if (!_webSurface) {
|
||||||
auto renderer = qSharedPointerCast<EntityTreeRenderer>(args->_renderData);
|
if (!buildWebSurface()) {
|
||||||
if (!buildWebSurface(renderer)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_fadeStartTime = usecTimestampNow();
|
_fadeStartTime = usecTimestampNow();
|
||||||
|
|
|
@ -57,7 +57,7 @@ public:
|
||||||
virtual QObject* getRootItem() override;
|
virtual QObject* getRootItem() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool buildWebSurface(QSharedPointer<EntityTreeRenderer> renderer);
|
bool buildWebSurface();
|
||||||
void destroyWebSurface();
|
void destroyWebSurface();
|
||||||
glm::vec2 getWindowSize() const;
|
glm::vec2 getWindowSize() const;
|
||||||
|
|
||||||
|
|
|
@ -196,8 +196,6 @@ GLBackend::GLBackend() {
|
||||||
|
|
||||||
|
|
||||||
GLBackend::~GLBackend() {
|
GLBackend::~GLBackend() {
|
||||||
resetStages();
|
|
||||||
|
|
||||||
killInput();
|
killInput();
|
||||||
killTransform();
|
killTransform();
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings = Shader::BindingSet());
|
static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings = Shader::BindingSet());
|
||||||
|
|
||||||
~GLBackend();
|
virtual ~GLBackend();
|
||||||
|
|
||||||
void setCameraCorrection(const Mat4& correction);
|
void setCameraCorrection(const Mat4& correction);
|
||||||
void render(const Batch& batch) final override;
|
void render(const Batch& batch) final override;
|
||||||
|
|
|
@ -43,6 +43,11 @@ public:
|
||||||
|
|
||||||
explicit GL41Backend(bool syncCache) : Parent(syncCache) {}
|
explicit GL41Backend(bool syncCache) : Parent(syncCache) {}
|
||||||
GL41Backend() : Parent() {}
|
GL41Backend() : Parent() {}
|
||||||
|
virtual ~GL41Backend() {
|
||||||
|
// call resetStages here rather than in ~GLBackend dtor because it will call releaseResourceBuffer
|
||||||
|
// which is pure virtual from GLBackend's dtor.
|
||||||
|
resetStages();
|
||||||
|
}
|
||||||
|
|
||||||
static const std::string GL41_VERSION;
|
static const std::string GL41_VERSION;
|
||||||
const std::string& getVersion() const override { return GL41_VERSION; }
|
const std::string& getVersion() const override { return GL41_VERSION; }
|
||||||
|
|
|
@ -39,6 +39,11 @@ public:
|
||||||
|
|
||||||
explicit GL45Backend(bool syncCache) : Parent(syncCache) {}
|
explicit GL45Backend(bool syncCache) : Parent(syncCache) {}
|
||||||
GL45Backend() : Parent() {}
|
GL45Backend() : Parent() {}
|
||||||
|
virtual ~GL45Backend() {
|
||||||
|
// call resetStages here rather than in ~GLBackend dtor because it will call releaseResourceBuffer
|
||||||
|
// which is pure virtual from GLBackend's dtor.
|
||||||
|
resetStages();
|
||||||
|
}
|
||||||
|
|
||||||
static const std::string GL45_VERSION;
|
static const std::string GL45_VERSION;
|
||||||
const std::string& getVersion() const override { return GL45_VERSION; }
|
const std::string& getVersion() const override { return GL45_VERSION; }
|
||||||
|
|
|
@ -220,7 +220,7 @@ bool LimitedNodeList::packetVersionMatch(const udt::Packet& packet) {
|
||||||
const HifiSockAddr& senderSockAddr = packet.getSenderSockAddr();
|
const HifiSockAddr& senderSockAddr = packet.getSenderSockAddr();
|
||||||
QUuid sourceID;
|
QUuid sourceID;
|
||||||
|
|
||||||
if (NON_SOURCED_PACKETS.contains(headerType)) {
|
if (PacketTypeEnum::getNonSourcedPackets().contains(headerType)) {
|
||||||
hasBeenOutput = versionDebugSuppressMap.contains(senderSockAddr, headerType);
|
hasBeenOutput = versionDebugSuppressMap.contains(senderSockAddr, headerType);
|
||||||
|
|
||||||
if (!hasBeenOutput) {
|
if (!hasBeenOutput) {
|
||||||
|
@ -256,8 +256,8 @@ bool LimitedNodeList::packetSourceAndHashMatchAndTrackBandwidth(const udt::Packe
|
||||||
|
|
||||||
PacketType headerType = NLPacket::typeInHeader(packet);
|
PacketType headerType = NLPacket::typeInHeader(packet);
|
||||||
|
|
||||||
if (NON_SOURCED_PACKETS.contains(headerType)) {
|
if (PacketTypeEnum::getNonSourcedPackets().contains(headerType)) {
|
||||||
if (REPLICATED_PACKET_MAPPING.key(headerType) != PacketType::Unknown) {
|
if (PacketTypeEnum::getReplicatedPacketMapping().key(headerType) != PacketType::Unknown) {
|
||||||
// this is a replicated packet type - make sure the socket that sent it to us matches
|
// this is a replicated packet type - make sure the socket that sent it to us matches
|
||||||
// one from one of our current upstream nodes
|
// one from one of our current upstream nodes
|
||||||
|
|
||||||
|
@ -298,7 +298,7 @@ bool LimitedNodeList::packetSourceAndHashMatchAndTrackBandwidth(const udt::Packe
|
||||||
SharedNodePointer matchingNode = nodeWithUUID(sourceID);
|
SharedNodePointer matchingNode = nodeWithUUID(sourceID);
|
||||||
|
|
||||||
if (matchingNode) {
|
if (matchingNode) {
|
||||||
if (!NON_VERIFIED_PACKETS.contains(headerType)) {
|
if (!PacketTypeEnum::getNonVerifiedPackets().contains(headerType)) {
|
||||||
|
|
||||||
QByteArray packetHeaderHash = NLPacket::verificationHashInHeader(packet);
|
QByteArray packetHeaderHash = NLPacket::verificationHashInHeader(packet);
|
||||||
QByteArray expectedHash = NLPacket::hashForPacketAndSecret(packet, matchingNode->getConnectionSecret());
|
QByteArray expectedHash = NLPacket::hashForPacketAndSecret(packet, matchingNode->getConnectionSecret());
|
||||||
|
@ -345,13 +345,13 @@ void LimitedNodeList::collectPacketStats(const NLPacket& packet) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimitedNodeList::fillPacketHeader(const NLPacket& packet, const QUuid& connectionSecret) {
|
void LimitedNodeList::fillPacketHeader(const NLPacket& packet, const QUuid& connectionSecret) {
|
||||||
if (!NON_SOURCED_PACKETS.contains(packet.getType())) {
|
if (!PacketTypeEnum::getNonSourcedPackets().contains(packet.getType())) {
|
||||||
packet.writeSourceID(getSessionUUID());
|
packet.writeSourceID(getSessionUUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!connectionSecret.isNull()
|
if (!connectionSecret.isNull()
|
||||||
&& !NON_SOURCED_PACKETS.contains(packet.getType())
|
&& !PacketTypeEnum::getNonSourcedPackets().contains(packet.getType())
|
||||||
&& !NON_VERIFIED_PACKETS.contains(packet.getType())) {
|
&& !PacketTypeEnum::getNonVerifiedPackets().contains(packet.getType())) {
|
||||||
packet.writeVerificationHashGivenSecret(connectionSecret);
|
packet.writeVerificationHashGivenSecret(connectionSecret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
#include "NLPacket.h"
|
#include "NLPacket.h"
|
||||||
|
|
||||||
int NLPacket::localHeaderSize(PacketType type) {
|
int NLPacket::localHeaderSize(PacketType type) {
|
||||||
bool nonSourced = NON_SOURCED_PACKETS.contains(type);
|
bool nonSourced = PacketTypeEnum::getNonSourcedPackets().contains(type);
|
||||||
bool nonVerified = NON_VERIFIED_PACKETS.contains(type);
|
bool nonVerified = PacketTypeEnum::getNonVerifiedPackets().contains(type);
|
||||||
qint64 optionalSize = (nonSourced ? 0 : NUM_BYTES_RFC4122_UUID) + ((nonSourced || nonVerified) ? 0 : NUM_BYTES_MD5_HASH);
|
qint64 optionalSize = (nonSourced ? 0 : NUM_BYTES_RFC4122_UUID) + ((nonSourced || nonVerified) ? 0 : NUM_BYTES_MD5_HASH);
|
||||||
return sizeof(PacketType) + sizeof(PacketVersion) + optionalSize;
|
return sizeof(PacketType) + sizeof(PacketVersion) + optionalSize;
|
||||||
}
|
}
|
||||||
|
@ -198,13 +198,13 @@ void NLPacket::readVersion() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void NLPacket::readSourceID() {
|
void NLPacket::readSourceID() {
|
||||||
if (!NON_SOURCED_PACKETS.contains(_type)) {
|
if (!PacketTypeEnum::getNonSourcedPackets().contains(_type)) {
|
||||||
_sourceID = sourceIDInHeader(*this);
|
_sourceID = sourceIDInHeader(*this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NLPacket::writeSourceID(const QUuid& sourceID) const {
|
void NLPacket::writeSourceID(const QUuid& sourceID) const {
|
||||||
Q_ASSERT(!NON_SOURCED_PACKETS.contains(_type));
|
Q_ASSERT(!PacketTypeEnum::getNonSourcedPackets().contains(_type));
|
||||||
|
|
||||||
auto offset = Packet::totalHeaderSize(isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion);
|
auto offset = Packet::totalHeaderSize(isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion);
|
||||||
memcpy(_packet.get() + offset, sourceID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID);
|
memcpy(_packet.get() + offset, sourceID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID);
|
||||||
|
@ -213,7 +213,8 @@ void NLPacket::writeSourceID(const QUuid& sourceID) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void NLPacket::writeVerificationHashGivenSecret(const QUuid& connectionSecret) const {
|
void NLPacket::writeVerificationHashGivenSecret(const QUuid& connectionSecret) const {
|
||||||
Q_ASSERT(!NON_SOURCED_PACKETS.contains(_type) && !NON_VERIFIED_PACKETS.contains(_type));
|
Q_ASSERT(!PacketTypeEnum::getNonSourcedPackets().contains(_type) &&
|
||||||
|
!PacketTypeEnum::getNonVerifiedPackets().contains(_type));
|
||||||
|
|
||||||
auto offset = Packet::totalHeaderSize(isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion)
|
auto offset = Packet::totalHeaderSize(isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion)
|
||||||
+ NUM_BYTES_RFC4122_UUID;
|
+ NUM_BYTES_RFC4122_UUID;
|
||||||
|
|
|
@ -29,11 +29,9 @@ int NodePtrMetaTypeId = qRegisterMetaType<Node*>("Node*");
|
||||||
int sharedPtrNodeMetaTypeId = qRegisterMetaType<QSharedPointer<Node>>("QSharedPointer<Node>");
|
int sharedPtrNodeMetaTypeId = qRegisterMetaType<QSharedPointer<Node>>("QSharedPointer<Node>");
|
||||||
int sharedNodePtrMetaTypeId = qRegisterMetaType<SharedNodePointer>("SharedNodePointer");
|
int sharedNodePtrMetaTypeId = qRegisterMetaType<SharedNodePointer>("SharedNodePointer");
|
||||||
|
|
||||||
namespace NodeType {
|
|
||||||
QHash<NodeType_t, QString> TypeNameHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeType::init() {
|
void NodeType::init() {
|
||||||
|
QHash<NodeType_t, QString>& TypeNameHash = Node::getTypeNameHash();
|
||||||
|
|
||||||
TypeNameHash.insert(NodeType::DomainServer, "Domain Server");
|
TypeNameHash.insert(NodeType::DomainServer, "Domain Server");
|
||||||
TypeNameHash.insert(NodeType::EntityServer, "Entity Server");
|
TypeNameHash.insert(NodeType::EntityServer, "Entity Server");
|
||||||
TypeNameHash.insert(NodeType::Agent, "Agent");
|
TypeNameHash.insert(NodeType::Agent, "Agent");
|
||||||
|
@ -50,6 +48,7 @@ void NodeType::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString& NodeType::getNodeTypeName(NodeType_t nodeType) {
|
const QString& NodeType::getNodeTypeName(NodeType_t nodeType) {
|
||||||
|
QHash<NodeType_t, QString>& TypeNameHash = Node::getTypeNameHash();
|
||||||
QHash<NodeType_t, QString>::iterator matchedTypeName = TypeNameHash.find(nodeType);
|
QHash<NodeType_t, QString>::iterator matchedTypeName = TypeNameHash.find(nodeType);
|
||||||
return matchedTypeName != TypeNameHash.end() ? matchedTypeName.value() : UNKNOWN_NodeType_t_NAME;
|
return matchedTypeName != TypeNameHash.end() ? matchedTypeName.value() : UNKNOWN_NodeType_t_NAME;
|
||||||
}
|
}
|
||||||
|
@ -85,6 +84,7 @@ NodeType_t NodeType::downstreamType(NodeType_t primaryType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeType_t NodeType::fromString(QString type) {
|
NodeType_t NodeType::fromString(QString type) {
|
||||||
|
QHash<NodeType_t, QString>& TypeNameHash = Node::getTypeNameHash();
|
||||||
return TypeNameHash.key(type, NodeType::Unassigned);
|
return TypeNameHash.key(type, NodeType::Unassigned);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,11 @@ public:
|
||||||
|
|
||||||
bool isIgnoreRadiusEnabled() const { return _ignoreRadiusEnabled; }
|
bool isIgnoreRadiusEnabled() const { return _ignoreRadiusEnabled; }
|
||||||
|
|
||||||
|
static QHash<NodeType_t, QString>& getTypeNameHash() {
|
||||||
|
static QHash<NodeType_t, QString> TypeNameHash;
|
||||||
|
return TypeNameHash;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// privatize copy and assignment operator to disallow Node copying
|
// privatize copy and assignment operator to disallow Node copying
|
||||||
Node(const Node &otherNode);
|
Node(const Node &otherNode);
|
||||||
|
|
|
@ -32,7 +32,7 @@ bool PacketReceiver::registerListenerForTypes(PacketTypeList types, QObject* lis
|
||||||
|
|
||||||
// Partition types based on whether they are sourced or not (non sourced in front)
|
// Partition types based on whether they are sourced or not (non sourced in front)
|
||||||
auto middle = std::partition(std::begin(types), std::end(types), [](PacketType type) {
|
auto middle = std::partition(std::begin(types), std::end(types), [](PacketType type) {
|
||||||
return NON_SOURCED_PACKETS.contains(type);
|
return PacketTypeEnum::getNonSourcedPackets().contains(type);
|
||||||
});
|
});
|
||||||
|
|
||||||
QMetaMethod nonSourcedMethod, sourcedMethod;
|
QMetaMethod nonSourcedMethod, sourcedMethod;
|
||||||
|
@ -123,7 +123,7 @@ QMetaMethod PacketReceiver::matchingMethodForListener(PacketType type, QObject*
|
||||||
SIGNATURE_TEMPLATE.arg(slot, NON_SOURCED_MESSAGE_LISTENER_PARAMETERS)
|
SIGNATURE_TEMPLATE.arg(slot, NON_SOURCED_MESSAGE_LISTENER_PARAMETERS)
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!NON_SOURCED_PACKETS.contains(type)) {
|
if (!PacketTypeEnum::getNonSourcedPackets().contains(type)) {
|
||||||
static const QString SOURCED_MESSAGE_LISTENER_PARAMETERS = "QSharedPointer<ReceivedMessage>,QSharedPointer<Node>";
|
static const QString SOURCED_MESSAGE_LISTENER_PARAMETERS = "QSharedPointer<ReceivedMessage>,QSharedPointer<Node>";
|
||||||
static const QString TYPEDEF_SOURCED_MESSAGE_LISTENER_PARAMETERS = "QSharedPointer<ReceivedMessage>,SharedNodePointer";
|
static const QString TYPEDEF_SOURCED_MESSAGE_LISTENER_PARAMETERS = "QSharedPointer<ReceivedMessage>,SharedNodePointer";
|
||||||
|
|
||||||
|
|
|
@ -22,38 +22,6 @@
|
||||||
Q_DECLARE_METATYPE(PacketType);
|
Q_DECLARE_METATYPE(PacketType);
|
||||||
int packetTypeMetaTypeId = qRegisterMetaType<PacketType>();
|
int packetTypeMetaTypeId = qRegisterMetaType<PacketType>();
|
||||||
|
|
||||||
const QSet<PacketType> NON_VERIFIED_PACKETS = QSet<PacketType>()
|
|
||||||
<< PacketType::NodeJsonStats << PacketType::EntityQuery
|
|
||||||
<< PacketType::OctreeDataNack << PacketType::EntityEditNack
|
|
||||||
<< PacketType::DomainListRequest << PacketType::StopNode
|
|
||||||
<< PacketType::DomainDisconnectRequest << PacketType::UsernameFromIDRequest
|
|
||||||
<< PacketType::NodeKickRequest << PacketType::NodeMuteRequest;
|
|
||||||
|
|
||||||
const QSet<PacketType> NON_SOURCED_PACKETS = QSet<PacketType>()
|
|
||||||
<< PacketType::StunResponse << PacketType::CreateAssignment << PacketType::RequestAssignment
|
|
||||||
<< PacketType::DomainServerRequireDTLS << PacketType::DomainConnectRequest
|
|
||||||
<< PacketType::DomainList << PacketType::DomainConnectionDenied
|
|
||||||
<< PacketType::DomainServerPathQuery << PacketType::DomainServerPathResponse
|
|
||||||
<< PacketType::DomainServerAddedNode << PacketType::DomainServerConnectionToken
|
|
||||||
<< PacketType::DomainSettingsRequest << PacketType::DomainSettings
|
|
||||||
<< PacketType::ICEServerPeerInformation << PacketType::ICEServerQuery << PacketType::ICEServerHeartbeat
|
|
||||||
<< PacketType::ICEServerHeartbeatACK << PacketType::ICEPing << PacketType::ICEPingReply
|
|
||||||
<< PacketType::ICEServerHeartbeatDenied << PacketType::AssignmentClientStatus << PacketType::StopNode
|
|
||||||
<< PacketType::DomainServerRemovedNode << PacketType::UsernameFromIDReply << PacketType::OctreeFileReplacement
|
|
||||||
<< PacketType::ReplicatedMicrophoneAudioNoEcho << PacketType::ReplicatedMicrophoneAudioWithEcho
|
|
||||||
<< PacketType::ReplicatedInjectAudio << PacketType::ReplicatedSilentAudioFrame
|
|
||||||
<< PacketType::ReplicatedAvatarIdentity << PacketType::ReplicatedKillAvatar << PacketType::ReplicatedBulkAvatarData;
|
|
||||||
|
|
||||||
const QHash<PacketType, PacketType> REPLICATED_PACKET_MAPPING {
|
|
||||||
{ PacketType::MicrophoneAudioNoEcho, PacketType::ReplicatedMicrophoneAudioNoEcho },
|
|
||||||
{ PacketType::MicrophoneAudioWithEcho, PacketType::ReplicatedMicrophoneAudioWithEcho },
|
|
||||||
{ PacketType::InjectAudio, PacketType::ReplicatedInjectAudio },
|
|
||||||
{ PacketType::SilentAudioFrame, PacketType::ReplicatedSilentAudioFrame },
|
|
||||||
{ PacketType::AvatarIdentity, PacketType::ReplicatedAvatarIdentity },
|
|
||||||
{ PacketType::KillAvatar, PacketType::ReplicatedKillAvatar },
|
|
||||||
{ PacketType::BulkAvatarData, PacketType::ReplicatedBulkAvatarData }
|
|
||||||
};
|
|
||||||
|
|
||||||
PacketVersion versionForPacketType(PacketType packetType) {
|
PacketVersion versionForPacketType(PacketType packetType) {
|
||||||
switch (packetType) {
|
switch (packetType) {
|
||||||
case PacketType::DomainList:
|
case PacketType::DomainList:
|
||||||
|
|
|
@ -123,19 +123,58 @@ public:
|
||||||
ReplicatedBulkAvatarData,
|
ReplicatedBulkAvatarData,
|
||||||
NUM_PACKET_TYPE
|
NUM_PACKET_TYPE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const static QHash<PacketTypeEnum::Value, PacketTypeEnum::Value> getReplicatedPacketMapping() {
|
||||||
|
const static QHash<PacketTypeEnum::Value, PacketTypeEnum::Value> REPLICATED_PACKET_MAPPING {
|
||||||
|
{ PacketTypeEnum::Value::MicrophoneAudioNoEcho, PacketTypeEnum::Value::ReplicatedMicrophoneAudioNoEcho },
|
||||||
|
{ PacketTypeEnum::Value::MicrophoneAudioWithEcho, PacketTypeEnum::Value::ReplicatedMicrophoneAudioWithEcho },
|
||||||
|
{ PacketTypeEnum::Value::InjectAudio, PacketTypeEnum::Value::ReplicatedInjectAudio },
|
||||||
|
{ PacketTypeEnum::Value::SilentAudioFrame, PacketTypeEnum::Value::ReplicatedSilentAudioFrame },
|
||||||
|
{ PacketTypeEnum::Value::AvatarIdentity, PacketTypeEnum::Value::ReplicatedAvatarIdentity },
|
||||||
|
{ PacketTypeEnum::Value::KillAvatar, PacketTypeEnum::Value::ReplicatedKillAvatar },
|
||||||
|
{ PacketTypeEnum::Value::BulkAvatarData, PacketTypeEnum::Value::ReplicatedBulkAvatarData }
|
||||||
|
};
|
||||||
|
return REPLICATED_PACKET_MAPPING;
|
||||||
|
}
|
||||||
|
|
||||||
|
const static QSet<PacketTypeEnum::Value> getNonVerifiedPackets() {
|
||||||
|
const static QSet<PacketTypeEnum::Value> NON_VERIFIED_PACKETS = QSet<PacketTypeEnum::Value>()
|
||||||
|
<< PacketTypeEnum::Value::NodeJsonStats << PacketTypeEnum::Value::EntityQuery
|
||||||
|
<< PacketTypeEnum::Value::OctreeDataNack << PacketTypeEnum::Value::EntityEditNack
|
||||||
|
<< PacketTypeEnum::Value::DomainListRequest << PacketTypeEnum::Value::StopNode
|
||||||
|
<< PacketTypeEnum::Value::DomainDisconnectRequest << PacketTypeEnum::Value::UsernameFromIDRequest
|
||||||
|
<< PacketTypeEnum::Value::NodeKickRequest << PacketTypeEnum::Value::NodeMuteRequest;
|
||||||
|
return NON_VERIFIED_PACKETS;
|
||||||
|
}
|
||||||
|
|
||||||
|
const static QSet<PacketTypeEnum::Value> getNonSourcedPackets() {
|
||||||
|
const static QSet<PacketTypeEnum::Value> NON_SOURCED_PACKETS = QSet<PacketTypeEnum::Value>()
|
||||||
|
<< PacketTypeEnum::Value::StunResponse << PacketTypeEnum::Value::CreateAssignment
|
||||||
|
<< PacketTypeEnum::Value::RequestAssignment << PacketTypeEnum::Value::DomainServerRequireDTLS
|
||||||
|
<< PacketTypeEnum::Value::DomainConnectRequest << PacketTypeEnum::Value::DomainList
|
||||||
|
<< PacketTypeEnum::Value::DomainConnectionDenied << PacketTypeEnum::Value::DomainServerPathQuery
|
||||||
|
<< PacketTypeEnum::Value::DomainServerPathResponse << PacketTypeEnum::Value::DomainServerAddedNode
|
||||||
|
<< PacketTypeEnum::Value::DomainServerConnectionToken << PacketTypeEnum::Value::DomainSettingsRequest
|
||||||
|
<< PacketTypeEnum::Value::DomainSettings << PacketTypeEnum::Value::ICEServerPeerInformation
|
||||||
|
<< PacketTypeEnum::Value::ICEServerQuery << PacketTypeEnum::Value::ICEServerHeartbeat
|
||||||
|
<< PacketTypeEnum::Value::ICEServerHeartbeatACK << PacketTypeEnum::Value::ICEPing
|
||||||
|
<< PacketTypeEnum::Value::ICEPingReply << PacketTypeEnum::Value::ICEServerHeartbeatDenied
|
||||||
|
<< PacketTypeEnum::Value::AssignmentClientStatus << PacketTypeEnum::Value::StopNode
|
||||||
|
<< PacketTypeEnum::Value::DomainServerRemovedNode << PacketTypeEnum::Value::UsernameFromIDReply
|
||||||
|
<< PacketTypeEnum::Value::OctreeFileReplacement << PacketTypeEnum::Value::ReplicatedMicrophoneAudioNoEcho
|
||||||
|
<< PacketTypeEnum::Value::ReplicatedMicrophoneAudioWithEcho << PacketTypeEnum::Value::ReplicatedInjectAudio
|
||||||
|
<< PacketTypeEnum::Value::ReplicatedSilentAudioFrame << PacketTypeEnum::Value::ReplicatedAvatarIdentity
|
||||||
|
<< PacketTypeEnum::Value::ReplicatedKillAvatar << PacketTypeEnum::Value::ReplicatedBulkAvatarData;
|
||||||
|
return NON_SOURCED_PACKETS;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using PacketType = PacketTypeEnum::Value;
|
using PacketType = PacketTypeEnum::Value;
|
||||||
|
|
||||||
extern const QHash<PacketType, PacketType> REPLICATED_PACKET_MAPPING;
|
|
||||||
|
|
||||||
const int NUM_BYTES_MD5_HASH = 16;
|
const int NUM_BYTES_MD5_HASH = 16;
|
||||||
|
|
||||||
typedef char PacketVersion;
|
typedef char PacketVersion;
|
||||||
|
|
||||||
extern const QSet<PacketType> NON_VERIFIED_PACKETS;
|
|
||||||
extern const QSet<PacketType> NON_SOURCED_PACKETS;
|
|
||||||
|
|
||||||
PacketVersion versionForPacketType(PacketType packetType);
|
PacketVersion versionForPacketType(PacketType packetType);
|
||||||
QByteArray protocolVersionsSignature(); /// returns a unqiue signature for all the current protocols
|
QByteArray protocolVersionsSignature(); /// returns a unqiue signature for all the current protocols
|
||||||
QString protocolVersionsSignatureBase64();
|
QString protocolVersionsSignatureBase64();
|
||||||
|
|
|
@ -18,6 +18,19 @@ void DisplayPlugin::incrementPresentCount() {
|
||||||
|
|
||||||
++_presentedFrameIndex;
|
++_presentedFrameIndex;
|
||||||
|
|
||||||
// Alert the app that it needs to paint a new presentation frame
|
{
|
||||||
qApp->postEvent(qApp, new QEvent(static_cast<QEvent::Type>(Present)), Qt::HighEventPriority);
|
QMutexLocker locker(&_presentMutex);
|
||||||
|
_presentCondition.wakeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
emit presented(_presentedFrameIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisplayPlugin::waitForPresent() {
|
||||||
|
QMutexLocker locker(&_presentMutex);
|
||||||
|
while (isActive()) {
|
||||||
|
if (_presentCondition.wait(&_presentMutex, MSECS_PER_SECOND)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,8 @@
|
||||||
#include <QtCore/QPoint>
|
#include <QtCore/QPoint>
|
||||||
#include <QtCore/QElapsedTimer>
|
#include <QtCore/QElapsedTimer>
|
||||||
#include <QtCore/QJsonObject>
|
#include <QtCore/QJsonObject>
|
||||||
|
#include <QtCore/QMutex>
|
||||||
|
#include <QtCore/QWaitCondition>
|
||||||
|
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
#include <RegisteredMetaTypes.h>
|
#include <RegisteredMetaTypes.h>
|
||||||
|
@ -116,10 +118,6 @@ class DisplayPlugin : public Plugin, public HmdDisplay {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
using Parent = Plugin;
|
using Parent = Plugin;
|
||||||
public:
|
public:
|
||||||
enum Event {
|
|
||||||
Present = QEvent::User + 1
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual int getRequiredThreadCount() const { return 0; }
|
virtual int getRequiredThreadCount() const { return 0; }
|
||||||
virtual bool isHmd() const { return false; }
|
virtual bool isHmd() const { return false; }
|
||||||
virtual int getHmdScreen() const { return -1; }
|
virtual int getHmdScreen() const { return -1; }
|
||||||
|
@ -203,12 +201,15 @@ public:
|
||||||
|
|
||||||
virtual void cycleDebugOutput() {}
|
virtual void cycleDebugOutput() {}
|
||||||
|
|
||||||
|
void waitForPresent();
|
||||||
|
|
||||||
static const QString& MENU_PATH();
|
static const QString& MENU_PATH();
|
||||||
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void recommendedFramebufferSizeChanged(const QSize& size);
|
void recommendedFramebufferSizeChanged(const QSize& size);
|
||||||
void resetSensorsRequested();
|
void resetSensorsRequested();
|
||||||
|
void presented(quint32 frame);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void incrementPresentCount();
|
void incrementPresentCount();
|
||||||
|
@ -216,6 +217,8 @@ protected:
|
||||||
gpu::ContextPointer _gpuContext;
|
gpu::ContextPointer _gpuContext;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QMutex _presentMutex;
|
||||||
|
QWaitCondition _presentCondition;
|
||||||
std::atomic<uint32_t> _presentedFrameIndex;
|
std::atomic<uint32_t> _presentedFrameIndex;
|
||||||
mutable std::mutex _paintDelayMutex;
|
mutable std::mutex _paintDelayMutex;
|
||||||
QElapsedTimer _paintDelayTimer;
|
QElapsedTimer _paintDelayTimer;
|
||||||
|
|
|
@ -77,7 +77,6 @@ namespace render {
|
||||||
Args() {}
|
Args() {}
|
||||||
|
|
||||||
Args(const gpu::ContextPointer& context,
|
Args(const gpu::ContextPointer& context,
|
||||||
QSharedPointer<QObject> renderData = QSharedPointer<QObject>(nullptr),
|
|
||||||
float sizeScale = 1.0f,
|
float sizeScale = 1.0f,
|
||||||
int boundaryLevelAdjust = 0,
|
int boundaryLevelAdjust = 0,
|
||||||
RenderMode renderMode = DEFAULT_RENDER_MODE,
|
RenderMode renderMode = DEFAULT_RENDER_MODE,
|
||||||
|
@ -85,7 +84,6 @@ namespace render {
|
||||||
DebugFlags debugFlags = RENDER_DEBUG_NONE,
|
DebugFlags debugFlags = RENDER_DEBUG_NONE,
|
||||||
gpu::Batch* batch = nullptr) :
|
gpu::Batch* batch = nullptr) :
|
||||||
_context(context),
|
_context(context),
|
||||||
_renderData(renderData),
|
|
||||||
_sizeScale(sizeScale),
|
_sizeScale(sizeScale),
|
||||||
_boundaryLevelAdjust(boundaryLevelAdjust),
|
_boundaryLevelAdjust(boundaryLevelAdjust),
|
||||||
_renderMode(renderMode),
|
_renderMode(renderMode),
|
||||||
|
@ -110,7 +108,6 @@ namespace render {
|
||||||
std::shared_ptr<gpu::Context> _context;
|
std::shared_ptr<gpu::Context> _context;
|
||||||
std::shared_ptr<gpu::Framebuffer> _blitFramebuffer;
|
std::shared_ptr<gpu::Framebuffer> _blitFramebuffer;
|
||||||
std::shared_ptr<render::ShapePipeline> _shapePipeline;
|
std::shared_ptr<render::ShapePipeline> _shapePipeline;
|
||||||
QSharedPointer<QObject> _renderData;
|
|
||||||
std::stack<ViewFrustum> _viewFrustums;
|
std::stack<ViewFrustum> _viewFrustums;
|
||||||
glm::ivec4 _viewport { 0.0f, 0.0f, 1.0f, 1.0f };
|
glm::ivec4 _viewport { 0.0f, 0.0f, 1.0f, 1.0f };
|
||||||
glm::vec3 _boomOffset { 0.0f, 0.0f, 1.0f };
|
glm::vec3 _boomOffset { 0.0f, 0.0f, 1.0f };
|
||||||
|
|
|
@ -32,26 +32,54 @@ FileScriptingInterface::FileScriptingInterface(QObject* parent) : QObject(parent
|
||||||
// nothing for now
|
// nothing for now
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd) {
|
void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd, bool isZip) {
|
||||||
qCDebug(scriptengine) << "Url that was downloaded: " + url.toString();
|
qCDebug(scriptengine) << "Url that was downloaded: " + url.toString();
|
||||||
qCDebug(scriptengine) << "Path where download is saved: " + path;
|
qCDebug(scriptengine) << "Path where download is saved: " + path;
|
||||||
QString fileName = "/" + path.section("/", -1);
|
QString fileName = "/" + path.section("/", -1);
|
||||||
QString tempDir = path;
|
QString tempDir = path;
|
||||||
tempDir.remove(fileName);
|
if (!isZip) {
|
||||||
|
tempDir.remove(fileName);
|
||||||
|
} else {
|
||||||
|
QTemporaryDir zipTemp;
|
||||||
|
tempDir = zipTemp.path();
|
||||||
|
path.remove("file:///");
|
||||||
|
}
|
||||||
|
|
||||||
qCDebug(scriptengine) << "Temporary directory at: " + tempDir;
|
qCDebug(scriptengine) << "Temporary directory at: " + tempDir;
|
||||||
if (!isTempDir(tempDir)) {
|
if (!isTempDir(tempDir)) {
|
||||||
qCDebug(scriptengine) << "Temporary directory mismatch; risk of losing files";
|
qCDebug(scriptengine) << "Temporary directory mismatch; risk of losing files";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString file = unzipFile(path, tempDir);
|
QStringList fileList = unzipFile(path, tempDir);
|
||||||
QString filename = QUrl::fromLocalFile(file).toString();
|
QString filename = QUrl::fromLocalFile(fileList.first()).toString();
|
||||||
if (file != "") {
|
|
||||||
|
if (filename != "") {
|
||||||
qCDebug(scriptengine) << "File to upload: " + filename;
|
qCDebug(scriptengine) << "File to upload: " + filename;
|
||||||
} else {
|
} else {
|
||||||
qCDebug(scriptengine) << "Unzip failed";
|
qCDebug(scriptengine) << "Unzip failed";
|
||||||
}
|
}
|
||||||
emit unzipResult(path, filename, autoAdd);
|
emit unzipResult(path, fileList, autoAdd, isZip);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList FileScriptingInterface::unzipFile(QString path, QString tempDir) {
|
||||||
|
|
||||||
|
QDir dir(path);
|
||||||
|
QString dirName = dir.path();
|
||||||
|
qCDebug(scriptengine) << "Directory to unzip: " << dirName;
|
||||||
|
QString target = tempDir + "/model_repo";
|
||||||
|
QStringList list = JlCompress::extractDir(dirName, target);
|
||||||
|
|
||||||
|
qCDebug(scriptengine) << list;
|
||||||
|
|
||||||
|
if (!list.isEmpty()) {
|
||||||
|
return list;
|
||||||
|
} else {
|
||||||
|
qCDebug(scriptengine) << "Extraction failed";
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// fix to check that we are only referring to a temporary directory
|
// fix to check that we are only referring to a temporary directory
|
||||||
|
@ -92,24 +120,6 @@ void FileScriptingInterface::downloadZip(QString path, const QString link) {
|
||||||
request->send();
|
request->send();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString FileScriptingInterface::unzipFile(QString path, QString tempDir) {
|
|
||||||
|
|
||||||
QDir dir(path);
|
|
||||||
QString dirName = dir.path();
|
|
||||||
QString target = tempDir + "/model_repo";
|
|
||||||
QStringList list = JlCompress::extractDir(dirName, target);
|
|
||||||
|
|
||||||
qCDebug(scriptengine) << list;
|
|
||||||
|
|
||||||
if (!list.isEmpty()) {
|
|
||||||
return list.front();
|
|
||||||
} else {
|
|
||||||
qCDebug(scriptengine) << "Extraction failed";
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// this function is not in use
|
// this function is not in use
|
||||||
void FileScriptingInterface::recursiveFileScan(QFileInfo file, QString* dirName) {
|
void FileScriptingInterface::recursiveFileScan(QFileInfo file, QString* dirName) {
|
||||||
/*if (!file.isDir()) {
|
/*if (!file.isDir()) {
|
||||||
|
|
|
@ -24,15 +24,15 @@ public:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
QString convertUrlToPath(QUrl url);
|
QString convertUrlToPath(QUrl url);
|
||||||
void runUnzip(QString path, QUrl url, bool autoAdd);
|
void runUnzip(QString path, QUrl url, bool autoAdd, bool isZip);
|
||||||
QString getTempDir();
|
QString getTempDir();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void unzipResult(QString zipFile, QString unzipFile, bool autoAdd);
|
void unzipResult(QString zipFile, QStringList unzipFile, bool autoAdd, bool isZip);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isTempDir(QString tempDir);
|
bool isTempDir(QString tempDir);
|
||||||
QString unzipFile(QString path, QString tempDir);
|
QStringList unzipFile(QString path, QString tempDir);
|
||||||
void recursiveFileScan(QFileInfo file, QString* dirName);
|
void recursiveFileScan(QFileInfo file, QString* dirName);
|
||||||
void downloadZip(QString path, const QString link);
|
void downloadZip(QString path, const QString link);
|
||||||
|
|
||||||
|
|
|
@ -605,3 +605,55 @@ float coneSphereAngle(const glm::vec3& coneCenter, const glm::vec3& coneDirectio
|
||||||
|
|
||||||
return glm::max(0.0f, theta - phi);
|
return glm::max(0.0f, theta - phi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// given a set of points, compute a best fit plane that passes as close as possible through all the points.
|
||||||
|
// http://www.ilikebigbits.com/blog/2015/3/2/plane-from-points
|
||||||
|
bool findPlaneFromPoints(const glm::vec3* points, size_t numPoints, glm::vec3& planeNormalOut, glm::vec3& pointOnPlaneOut) {
|
||||||
|
if (numPoints < 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
glm::vec3 sum;
|
||||||
|
for (size_t i = 0; i < numPoints; i++) {
|
||||||
|
sum += points[i];
|
||||||
|
}
|
||||||
|
glm::vec3 centroid = sum * (1.0f / (float)numPoints);
|
||||||
|
float xx = 0.0f, xy = 0.0f, xz = 0.0f;
|
||||||
|
float yy = 0.0f, yz = 0.0f, zz = 0.0f;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < numPoints; i++) {
|
||||||
|
glm::vec3 r = points[i] - centroid;
|
||||||
|
xx += r.x * r.x;
|
||||||
|
xy += r.x * r.y;
|
||||||
|
xz += r.x * r.z;
|
||||||
|
yy += r.y * r.y;
|
||||||
|
yz += r.y * r.z;
|
||||||
|
zz += r.z * r.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
float det_x = yy * zz - yz * yz;
|
||||||
|
float det_y = xx * zz - xz * xz;
|
||||||
|
float det_z = xx * yy - xy * xy;
|
||||||
|
float det_max = std::max(std::max(det_x, det_y), det_z);
|
||||||
|
|
||||||
|
if (det_max == 0.0f) {
|
||||||
|
return false; // The points don't span a plane
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 dir;
|
||||||
|
if (det_max == det_x) {
|
||||||
|
float a = (xz * yz - xy * zz) / det_x;
|
||||||
|
float b = (xy * yz - xz * yy) / det_x;
|
||||||
|
dir = glm::vec3(1.0f, a, b);
|
||||||
|
} else if (det_max == det_y) {
|
||||||
|
float a = (yz * xz - xy * zz) / det_y;
|
||||||
|
float b = (xy * xz - yz * xx) / det_y;
|
||||||
|
dir = glm::vec3(a, 1.0f, b);
|
||||||
|
} else {
|
||||||
|
float a = (yz * xy - xz * yy) / det_z;
|
||||||
|
float b = (xz * xy - yz * xx) / det_z;
|
||||||
|
dir = glm::vec3(a, b, 1.0f);
|
||||||
|
}
|
||||||
|
pointOnPlaneOut = centroid;
|
||||||
|
planeNormalOut = glm::normalize(dir);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -163,5 +163,7 @@ private:
|
||||||
static void copyCleanArray(int& lengthA, glm::vec2* vertexArrayA, int& lengthB, glm::vec2* vertexArrayB);
|
static void copyCleanArray(int& lengthA, glm::vec2* vertexArrayA, int& lengthB, glm::vec2* vertexArrayB);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// given a set of points, compute a best fit plane that passes as close as possible through all the points.
|
||||||
|
bool findPlaneFromPoints(const glm::vec3* points, size_t numPoints, glm::vec3& planeNormalOut, glm::vec3& pointOnPlaneOut);
|
||||||
|
|
||||||
#endif // hifi_GeometryUtil_h
|
#endif // hifi_GeometryUtil_h
|
||||||
|
|
|
@ -10,29 +10,71 @@
|
||||||
|
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
|
|
||||||
|
// Support for viewing the thread name in the debugger.
|
||||||
|
// Note, Qt actually does this for you but only in debug builds
|
||||||
|
// Code from https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
|
||||||
|
// and matches logic in `qt_set_thread_name` in qthread_win.cpp
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#include <qt_windows.h>
|
||||||
|
#pragma pack(push,8)
|
||||||
|
struct THREADNAME_INFO {
|
||||||
|
DWORD dwType; // Must be 0x1000.
|
||||||
|
LPCSTR szName; // Pointer to name (in user addr space).
|
||||||
|
DWORD dwThreadID; // Thread ID (-1=caller thread).
|
||||||
|
DWORD dwFlags; // Reserved for future use, must be zero.
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void setThreadName(const std::string& name) {
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
static const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
||||||
|
THREADNAME_INFO info{ 0x1000, name.c_str(), (DWORD)-1, 0 };
|
||||||
|
__try {
|
||||||
|
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
|
||||||
|
} __except (EXCEPTION_EXECUTE_HANDLER) { }
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void moveToNewNamedThread(QObject* object, const QString& name, std::function<void(QThread*)> preStartCallback, std::function<void()> startCallback, QThread::Priority priority) {
|
||||||
|
Q_ASSERT(QThread::currentThread() == object->thread());
|
||||||
|
|
||||||
|
// Create the target thread
|
||||||
|
QThread* thread = new QThread();
|
||||||
|
thread->setObjectName(name);
|
||||||
|
|
||||||
|
// Execute any additional work to do before the thread starts like moving members to the target thread.
|
||||||
|
// This is required as QObject::moveToThread isn't virutal, so we can't override it on objects that contain
|
||||||
|
// an OpenGLContext and ensure that the context moves to the target thread as well.
|
||||||
|
preStartCallback(thread);
|
||||||
|
|
||||||
|
// Link the in-thread initialization code
|
||||||
|
QObject::connect(thread, &QThread::started, [name, startCallback] {
|
||||||
|
if (!name.isEmpty()) {
|
||||||
|
// Make it easy to spot our thread processes inside the debugger
|
||||||
|
setThreadName("Hifi_" + name.toStdString());
|
||||||
|
}
|
||||||
|
startCallback();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Make sure the thread will be destroyed and cleaned up. The assumption here is that the incoming object
|
||||||
|
// will be destroyed and the thread will quit when that occurs.
|
||||||
|
QObject::connect(object, &QObject::destroyed, thread, &QThread::quit);
|
||||||
|
// When the thread itself stops running, it should also be deleted.
|
||||||
|
QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||||||
|
|
||||||
|
// put the object on the thread
|
||||||
|
object->moveToThread(thread);
|
||||||
|
thread->start();
|
||||||
|
if (priority != QThread::InheritPriority) {
|
||||||
|
thread->setPriority(priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void moveToNewNamedThread(QObject* object, const QString& name, std::function<void()> startCallback, QThread::Priority priority) {
|
void moveToNewNamedThread(QObject* object, const QString& name, std::function<void()> startCallback, QThread::Priority priority) {
|
||||||
Q_ASSERT(QThread::currentThread() == object->thread());
|
moveToNewNamedThread(object, name, [](QThread*){}, startCallback, priority);
|
||||||
// setup a thread for the NodeList and its PacketReceiver
|
|
||||||
QThread* thread = new QThread();
|
|
||||||
thread->setObjectName(name);
|
|
||||||
|
|
||||||
QString tempName = name;
|
|
||||||
QObject::connect(thread, &QThread::started, [startCallback] {
|
|
||||||
startCallback();
|
|
||||||
});
|
|
||||||
// Make sure the thread will be destroyed and cleaned up
|
|
||||||
QObject::connect(object, &QObject::destroyed, thread, &QThread::quit);
|
|
||||||
QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
|
||||||
|
|
||||||
// put the object on the thread
|
|
||||||
object->moveToThread(thread);
|
|
||||||
thread->start();
|
|
||||||
if (priority != QThread::InheritPriority) {
|
|
||||||
thread->setPriority(priority);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void moveToNewNamedThread(QObject* object, const QString& name, QThread::Priority priority) {
|
void moveToNewNamedThread(QObject* object, const QString& name, QThread::Priority priority) {
|
||||||
moveToNewNamedThread(object, name, [] {}, priority);
|
moveToNewNamedThread(object, name, [](QThread*){}, []{}, priority);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,8 +32,17 @@ void withLock(QMutex& lock, F function) {
|
||||||
function();
|
function();
|
||||||
}
|
}
|
||||||
|
|
||||||
void moveToNewNamedThread(QObject* object, const QString& name, std::function<void()> startCallback, QThread::Priority priority = QThread::InheritPriority);
|
void moveToNewNamedThread(QObject* object, const QString& name,
|
||||||
void moveToNewNamedThread(QObject* object, const QString& name, QThread::Priority priority = QThread::InheritPriority);
|
std::function<void(QThread*)> preStartCallback,
|
||||||
|
std::function<void()> startCallback,
|
||||||
|
QThread::Priority priority = QThread::InheritPriority);
|
||||||
|
|
||||||
|
void moveToNewNamedThread(QObject* object, const QString& name,
|
||||||
|
std::function<void()> startCallback,
|
||||||
|
QThread::Priority priority = QThread::InheritPriority);
|
||||||
|
|
||||||
|
void moveToNewNamedThread(QObject* object, const QString& name,
|
||||||
|
QThread::Priority priority = QThread::InheritPriority);
|
||||||
|
|
||||||
class ConditionalGuard {
|
class ConditionalGuard {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -11,11 +11,24 @@
|
||||||
#include <QtCore/QThread>
|
#include <QtCore/QThread>
|
||||||
#include <QtCore/QCoreApplication>
|
#include <QtCore/QCoreApplication>
|
||||||
#include <QtCore/QLoggingCategory>
|
#include <QtCore/QLoggingCategory>
|
||||||
|
#include <QtCore/QReadWriteLock>
|
||||||
|
|
||||||
|
#include "../Profile.h"
|
||||||
Q_LOGGING_CATEGORY(thread_safety, "hifi.thread_safety")
|
Q_LOGGING_CATEGORY(thread_safety, "hifi.thread_safety")
|
||||||
|
|
||||||
namespace hifi { namespace qt {
|
namespace hifi { namespace qt {
|
||||||
|
|
||||||
|
static QHash<QThread*, QString> threadHash;
|
||||||
|
static QReadWriteLock threadHashLock;
|
||||||
|
|
||||||
|
void addBlockingForbiddenThread(const QString& name, QThread* thread) {
|
||||||
|
if (!thread) {
|
||||||
|
thread = QThread::currentThread();
|
||||||
|
}
|
||||||
|
QWriteLocker locker(&threadHashLock);
|
||||||
|
threadHash[thread] = name;
|
||||||
|
}
|
||||||
|
|
||||||
bool blockingInvokeMethod(
|
bool blockingInvokeMethod(
|
||||||
const char* function,
|
const char* function,
|
||||||
QObject *obj, const char *member,
|
QObject *obj, const char *member,
|
||||||
|
@ -30,9 +43,23 @@ bool blockingInvokeMethod(
|
||||||
QGenericArgument val7,
|
QGenericArgument val7,
|
||||||
QGenericArgument val8,
|
QGenericArgument val8,
|
||||||
QGenericArgument val9) {
|
QGenericArgument val9) {
|
||||||
if (QThread::currentThread() == qApp->thread()) {
|
auto currentThread = QThread::currentThread();
|
||||||
|
if (currentThread == qApp->thread()) {
|
||||||
qCWarning(thread_safety) << "BlockingQueuedConnection invoked on main thread from " << function;
|
qCWarning(thread_safety) << "BlockingQueuedConnection invoked on main thread from " << function;
|
||||||
|
return QMetaObject::invokeMethod(obj, member,
|
||||||
|
Qt::BlockingQueuedConnection, ret, val0, val1, val2, val3, val4, val5, val6, val7, val8, val9);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
QReadLocker locker(&threadHashLock);
|
||||||
|
for (const auto& thread : threadHash.keys()) {
|
||||||
|
if (currentThread == thread) {
|
||||||
|
qCWarning(thread_safety) << "BlockingQueuedConnection invoked on forbidden thread " << threadHash[thread];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PROFILE_RANGE(app, function);
|
||||||
return QMetaObject::invokeMethod(obj, member,
|
return QMetaObject::invokeMethod(obj, member,
|
||||||
Qt::BlockingQueuedConnection, ret, val0, val1, val2, val3, val4, val5, val6, val7, val8, val9);
|
Qt::BlockingQueuedConnection, ret, val0, val1, val2, val3, val4, val5, val6, val7, val8, val9);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
|
|
||||||
namespace hifi { namespace qt {
|
namespace hifi { namespace qt {
|
||||||
|
void addBlockingForbiddenThread(const QString& name, QThread* thread = nullptr);
|
||||||
|
|
||||||
bool blockingInvokeMethod(
|
bool blockingInvokeMethod(
|
||||||
const char* function,
|
const char* function,
|
||||||
|
|
|
@ -28,11 +28,9 @@ const QString SYSTEM_TOOLBAR = "com.highfidelity.interface.toolbar.system";
|
||||||
const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system";
|
const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system";
|
||||||
|
|
||||||
TabletScriptingInterface::TabletScriptingInterface() {
|
TabletScriptingInterface::TabletScriptingInterface() {
|
||||||
qCDebug(uiLogging) << "Building tablet scripting interface";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TabletScriptingInterface::~TabletScriptingInterface() {
|
TabletScriptingInterface::~TabletScriptingInterface() {
|
||||||
qCDebug(uiLogging) << "Destroying tablet scripting interface";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ToolbarProxy* TabletScriptingInterface::getSystemToolbarProxy() {
|
ToolbarProxy* TabletScriptingInterface::getSystemToolbarProxy() {
|
||||||
|
@ -191,7 +189,6 @@ TabletProxy::TabletProxy(QObject* parent, const QString& name) : QObject(parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
TabletProxy::~TabletProxy() {
|
TabletProxy::~TabletProxy() {
|
||||||
qCDebug(uiLogging) << "Destroying tablet proxy " << _name;
|
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
qCWarning(uiLogging) << "Destroying tablet proxy on wrong thread" << _name;
|
qCWarning(uiLogging) << "Destroying tablet proxy on wrong thread" << _name;
|
||||||
}
|
}
|
||||||
|
@ -846,7 +843,6 @@ TabletButtonProxy::TabletButtonProxy(const QVariantMap& properties) :
|
||||||
}
|
}
|
||||||
|
|
||||||
TabletButtonProxy::~TabletButtonProxy() {
|
TabletButtonProxy::~TabletButtonProxy() {
|
||||||
qCDebug(uiLogging) << "Destroying tablet button proxy " ;
|
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
qCWarning(uiLogging) << "Destroying tablet button proxy on wrong thread";
|
qCWarning(uiLogging) << "Destroying tablet button proxy on wrong thread";
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ if (WIN32)
|
||||||
include_hifi_library_headers(octree)
|
include_hifi_library_headers(octree)
|
||||||
|
|
||||||
add_dependency_external_projects(OpenVR)
|
add_dependency_external_projects(OpenVR)
|
||||||
|
|
||||||
find_package(OpenVR REQUIRED)
|
find_package(OpenVR REQUIRED)
|
||||||
target_include_directories(${TARGET_NAME} PRIVATE ${OPENVR_INCLUDE_DIRS})
|
target_include_directories(${TARGET_NAME} PRIVATE ${OPENVR_INCLUDE_DIRS})
|
||||||
target_link_libraries(${TARGET_NAME} ${OPENVR_LIBRARIES})
|
target_link_libraries(${TARGET_NAME} ${OPENVR_LIBRARIES})
|
||||||
|
|
|
@ -35,7 +35,6 @@
|
||||||
#include <Plugins/InputConfiguration.h>
|
#include <Plugins/InputConfiguration.h>
|
||||||
#include <controllers/StandardControls.h>
|
#include <controllers/StandardControls.h>
|
||||||
|
|
||||||
|
|
||||||
extern PoseData _nextSimPoseData;
|
extern PoseData _nextSimPoseData;
|
||||||
|
|
||||||
vr::IVRSystem* acquireOpenVrSystem();
|
vr::IVRSystem* acquireOpenVrSystem();
|
||||||
|
@ -168,6 +167,7 @@ void ViveControllerManager::setConfigurationSettings(const QJsonObject configura
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_inputDevice->configureCalibrationSettings(configurationSettings);
|
_inputDevice->configureCalibrationSettings(configurationSettings);
|
||||||
|
saveSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,6 +188,8 @@ QString ViveControllerManager::configurationLayout() {
|
||||||
bool ViveControllerManager::activate() {
|
bool ViveControllerManager::activate() {
|
||||||
InputPlugin::activate();
|
InputPlugin::activate();
|
||||||
|
|
||||||
|
loadSettings();
|
||||||
|
|
||||||
if (!_system) {
|
if (!_system) {
|
||||||
_system = acquireOpenVrSystem();
|
_system = acquireOpenVrSystem();
|
||||||
}
|
}
|
||||||
|
@ -230,6 +232,8 @@ void ViveControllerManager::deactivate() {
|
||||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||||
userInputMapper->removeDevice(_inputDevice->_deviceID);
|
userInputMapper->removeDevice(_inputDevice->_deviceID);
|
||||||
_registeredWithInputMapper = false;
|
_registeredWithInputMapper = false;
|
||||||
|
|
||||||
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ViveControllerManager::isHeadControllerMounted() const {
|
bool ViveControllerManager::isHeadControllerMounted() const {
|
||||||
|
@ -282,7 +286,38 @@ void ViveControllerManager::pluginUpdate(float deltaTime, const controller::Inpu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ViveControllerManager::InputDevice::InputDevice(vr::IVRSystem*& system) : controller::InputDevice("Vive"), _system(system) {
|
void ViveControllerManager::loadSettings() {
|
||||||
|
Settings settings;
|
||||||
|
QString nameString = getName();
|
||||||
|
settings.beginGroup(nameString);
|
||||||
|
{
|
||||||
|
if (_inputDevice) {
|
||||||
|
const double DEFAULT_ARM_CIRCUMFERENCE = 0.33;
|
||||||
|
const double DEFAULT_SHOULDER_WIDTH = 0.48;
|
||||||
|
_inputDevice->_armCircumference = settings.value("armCircumference", QVariant(DEFAULT_ARM_CIRCUMFERENCE)).toDouble();
|
||||||
|
_inputDevice->_shoulderWidth = settings.value("shoulderWidth", QVariant(DEFAULT_SHOULDER_WIDTH)).toDouble();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settings.endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViveControllerManager::saveSettings() const {
|
||||||
|
Settings settings;
|
||||||
|
QString nameString = getName();
|
||||||
|
settings.beginGroup(nameString);
|
||||||
|
{
|
||||||
|
if (_inputDevice) {
|
||||||
|
settings.setValue(QString("armCircumference"), _inputDevice->_armCircumference);
|
||||||
|
settings.setValue(QString("shoulderWidth"), _inputDevice->_shoulderWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settings.endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ViveControllerManager::InputDevice::InputDevice(vr::IVRSystem*& system) :
|
||||||
|
controller::InputDevice("Vive"),
|
||||||
|
_system(system) {
|
||||||
|
|
||||||
_configStringMap[Config::None] = QString("None");
|
_configStringMap[Config::None] = QString("None");
|
||||||
_configStringMap[Config::Feet] = QString("Feet");
|
_configStringMap[Config::Feet] = QString("Feet");
|
||||||
|
@ -371,6 +406,9 @@ void ViveControllerManager::InputDevice::calibrateFromUI(const controller::Input
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const float CM_TO_M = 0.01f;
|
||||||
|
static const float M_TO_CM = 100.0f;
|
||||||
|
|
||||||
void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJsonObject configurationSettings) {
|
void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJsonObject configurationSettings) {
|
||||||
Locker locker(_lock);
|
Locker locker(_lock);
|
||||||
if (!configurationSettings.empty()) {
|
if (!configurationSettings.empty()) {
|
||||||
|
@ -384,8 +422,8 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso
|
||||||
bool overrideHead = headObject["override"].toBool();
|
bool overrideHead = headObject["override"].toBool();
|
||||||
if (overrideHead) {
|
if (overrideHead) {
|
||||||
_headConfig = HeadConfig::Puck;
|
_headConfig = HeadConfig::Puck;
|
||||||
_headPuckYOffset = headObject["Y"].toDouble();
|
_headPuckYOffset = headObject["Y"].toDouble() * CM_TO_M;
|
||||||
_headPuckZOffset = headObject["Z"].toDouble();
|
_headPuckZOffset = headObject["Z"].toDouble() * CM_TO_M;
|
||||||
} else {
|
} else {
|
||||||
_headConfig = HeadConfig::HMD;
|
_headConfig = HeadConfig::HMD;
|
||||||
}
|
}
|
||||||
|
@ -394,11 +432,15 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso
|
||||||
bool overrideHands = handsObject["override"].toBool();
|
bool overrideHands = handsObject["override"].toBool();
|
||||||
if (overrideHands) {
|
if (overrideHands) {
|
||||||
_handConfig = HandConfig::Pucks;
|
_handConfig = HandConfig::Pucks;
|
||||||
_handPuckYOffset = handsObject["Y"].toDouble();
|
_handPuckYOffset = handsObject["Y"].toDouble() * CM_TO_M;
|
||||||
_handPuckZOffset = handsObject["Z"].toDouble();
|
_handPuckZOffset = handsObject["Z"].toDouble() * CM_TO_M;
|
||||||
} else {
|
} else {
|
||||||
_handConfig = HandConfig::HandController;
|
_handConfig = HandConfig::HandController;
|
||||||
}
|
}
|
||||||
|
} else if (iter.key() == "armCircumference") {
|
||||||
|
_armCircumference = (float)iter.value().toDouble() * CM_TO_M;
|
||||||
|
} else if (iter.key() == "shoulderWidth") {
|
||||||
|
_shoulderWidth = (float)iter.value().toDouble() * CM_TO_M;
|
||||||
}
|
}
|
||||||
iter++;
|
iter++;
|
||||||
}
|
}
|
||||||
|
@ -417,6 +459,8 @@ QJsonObject ViveControllerManager::InputDevice::configurationSettings() {
|
||||||
configurationSettings["HMDHead"] = (_headConfig == HeadConfig::HMD);
|
configurationSettings["HMDHead"] = (_headConfig == HeadConfig::HMD);
|
||||||
configurationSettings["handController"] = (_handConfig == HandConfig::HandController);
|
configurationSettings["handController"] = (_handConfig == HandConfig::HandController);
|
||||||
configurationSettings["puckCount"] = (int)_validTrackedObjects.size();
|
configurationSettings["puckCount"] = (int)_validTrackedObjects.size();
|
||||||
|
configurationSettings["armCircumference"] = (double)_armCircumference * M_TO_CM;
|
||||||
|
configurationSettings["shoulderWidth"] = (double)_shoulderWidth * M_TO_CM;
|
||||||
return configurationSettings;
|
return configurationSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,7 +578,7 @@ void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ViveControllerManager::InputDevice::configureHands(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
|
bool ViveControllerManager::InputDevice::configureHands(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
|
||||||
std::sort(_validTrackedObjects.begin(), _validTrackedObjects.end(), sortPucksXPosition);
|
std::sort(_validTrackedObjects.begin(), _validTrackedObjects.end(), sortPucksXPosition);
|
||||||
int puckCount = (int)_validTrackedObjects.size();
|
int puckCount = (int)_validTrackedObjects.size();
|
||||||
if (_handConfig == HandConfig::Pucks && puckCount >= MIN_PUCK_COUNT) {
|
if (_handConfig == HandConfig::Pucks && puckCount >= MIN_PUCK_COUNT) {
|
||||||
|
@ -569,7 +613,7 @@ bool ViveControllerManager::InputDevice::configureHands(glm::mat4& defaultToRefe
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ViveControllerManager::InputDevice::configureHead(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
|
bool ViveControllerManager::InputDevice::configureHead(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
|
||||||
std::sort(_validTrackedObjects.begin(), _validTrackedObjects.end(), sortPucksYPosition);
|
std::sort(_validTrackedObjects.begin(), _validTrackedObjects.end(), sortPucksYPosition);
|
||||||
int puckCount = (int)_validTrackedObjects.size();
|
int puckCount = (int)_validTrackedObjects.size();
|
||||||
if (_headConfig == HeadConfig::Puck && puckCount >= MIN_HEAD) {
|
if (_headConfig == HeadConfig::Puck && puckCount >= MIN_HEAD) {
|
||||||
|
@ -583,7 +627,7 @@ bool ViveControllerManager::InputDevice::configureHead(glm::mat4& defaultToRefer
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ViveControllerManager::InputDevice::configureBody(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
|
bool ViveControllerManager::InputDevice::configureBody(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
|
||||||
std::sort(_validTrackedObjects.begin(), _validTrackedObjects.end(), sortPucksYPosition);
|
std::sort(_validTrackedObjects.begin(), _validTrackedObjects.end(), sortPucksYPosition);
|
||||||
int puckCount = (int)_validTrackedObjects.size();
|
int puckCount = (int)_validTrackedObjects.size();
|
||||||
glm::vec3 headXAxis = getReferenceHeadXAxis(defaultToReferenceMat, inputCalibration.defaultHeadMat);
|
glm::vec3 headXAxis = getReferenceHeadXAxis(defaultToReferenceMat, inputCalibration.defaultHeadMat);
|
||||||
|
@ -624,7 +668,8 @@ bool ViveControllerManager::InputDevice::configureBody(glm::mat4& defaultToRefer
|
||||||
|
|
||||||
void ViveControllerManager::InputDevice::uncalibrate() {
|
void ViveControllerManager::InputDevice::uncalibrate() {
|
||||||
_config = Config::None;
|
_config = Config::None;
|
||||||
_pucksOffset.clear();
|
_pucksPostOffset.clear();
|
||||||
|
_pucksPreOffset.clear();
|
||||||
_jointToPuckMap.clear();
|
_jointToPuckMap.clear();
|
||||||
_calibrated = false;
|
_calibrated = false;
|
||||||
_overrideHead = false;
|
_overrideHead = false;
|
||||||
|
@ -654,10 +699,17 @@ controller::Pose ViveControllerManager::InputDevice::addOffsetToPuckPose(int joi
|
||||||
if (puck != _jointToPuckMap.end()) {
|
if (puck != _jointToPuckMap.end()) {
|
||||||
uint32_t puckIndex = puck->second;
|
uint32_t puckIndex = puck->second;
|
||||||
auto puckPose = _poseStateMap.find(puckIndex);
|
auto puckPose = _poseStateMap.find(puckIndex);
|
||||||
auto puckOffset = _pucksOffset.find(puckIndex);
|
auto puckPostOffset = _pucksPostOffset.find(puckIndex);
|
||||||
|
auto puckPreOffset = _pucksPreOffset.find(puckIndex);
|
||||||
|
|
||||||
if ((puckPose != _poseStateMap.end()) && (puckOffset != _pucksOffset.end())) {
|
if (puckPose != _poseStateMap.end()) {
|
||||||
return puckPose->second.postTransform(puckOffset->second);
|
if (puckPreOffset != _pucksPreOffset.end() && puckPostOffset != _pucksPostOffset.end()) {
|
||||||
|
return puckPose->second.postTransform(puckPostOffset->second).transform(puckPreOffset->second);
|
||||||
|
} else if (puckPostOffset != _pucksPostOffset.end()) {
|
||||||
|
return puckPose->second.postTransform(puckPostOffset->second);
|
||||||
|
} else if (puckPreOffset != _pucksPreOffset.end()) {
|
||||||
|
return puckPose->second.transform(puckPreOffset->second);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return controller::Pose();
|
return controller::Pose();
|
||||||
|
@ -708,7 +760,7 @@ void ViveControllerManager::InputDevice::handleHandController(float deltaTime, u
|
||||||
// pseudo buttons the depend on both of the above for-loops
|
// pseudo buttons the depend on both of the above for-loops
|
||||||
partitionTouchpad(controller::LS, controller::LX, controller::LY, controller::LS_CENTER, controller::LS_X, controller::LS_Y);
|
partitionTouchpad(controller::LS, controller::LX, controller::LY, controller::LS_CENTER, controller::LS_X, controller::LS_Y);
|
||||||
partitionTouchpad(controller::RS, controller::RX, controller::RY, controller::RS_CENTER, controller::RS_X, controller::RS_Y);
|
partitionTouchpad(controller::RS, controller::RX, controller::RY, controller::RS_CENTER, controller::RS_X, controller::RS_Y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -942,7 +994,7 @@ void ViveControllerManager::InputDevice::hapticsHelper(float deltaTime, bool lef
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViveControllerManager::InputDevice::calibrateLeftHand(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair) {
|
void ViveControllerManager::InputDevice::calibrateLeftHand(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair) {
|
||||||
controller::Pose& handPose = handPair.second;
|
controller::Pose& handPose = handPair.second;
|
||||||
glm::mat4 handPoseAvatarMat = createMatFromQuatAndPos(handPose.getRotation(), handPose.getTranslation());
|
glm::mat4 handPoseAvatarMat = createMatFromQuatAndPos(handPose.getRotation(), handPose.getTranslation());
|
||||||
glm::vec3 handPoseTranslation = extractTranslation(handPoseAvatarMat);
|
glm::vec3 handPoseTranslation = extractTranslation(handPoseAvatarMat);
|
||||||
|
@ -970,10 +1022,10 @@ void ViveControllerManager::InputDevice::calibrateLeftHand(glm::mat4& defaultToR
|
||||||
glm::mat4 offsetMat = createMatFromQuatAndPos(rotationOffset, translationOffset);
|
glm::mat4 offsetMat = createMatFromQuatAndPos(rotationOffset, translationOffset);
|
||||||
|
|
||||||
_jointToPuckMap[controller::LEFT_HAND] = handPair.first;
|
_jointToPuckMap[controller::LEFT_HAND] = handPair.first;
|
||||||
_pucksOffset[handPair.first] = offsetMat;
|
_pucksPostOffset[handPair.first] = offsetMat;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViveControllerManager::InputDevice::calibrateRightHand(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair) {
|
void ViveControllerManager::InputDevice::calibrateRightHand(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair) {
|
||||||
controller::Pose& handPose = handPair.second;
|
controller::Pose& handPose = handPair.second;
|
||||||
glm::mat4 handPoseAvatarMat = createMatFromQuatAndPos(handPose.getRotation(), handPose.getTranslation());
|
glm::mat4 handPoseAvatarMat = createMatFromQuatAndPos(handPose.getRotation(), handPose.getTranslation());
|
||||||
glm::vec3 handPoseTranslation = extractTranslation(handPoseAvatarMat);
|
glm::vec3 handPoseTranslation = extractTranslation(handPoseAvatarMat);
|
||||||
|
@ -1001,11 +1053,11 @@ void ViveControllerManager::InputDevice::calibrateRightHand(glm::mat4& defaultTo
|
||||||
glm::mat4 offsetMat = createMatFromQuatAndPos(rotationOffset, translationOffset);
|
glm::mat4 offsetMat = createMatFromQuatAndPos(rotationOffset, translationOffset);
|
||||||
|
|
||||||
_jointToPuckMap[controller::RIGHT_HAND] = handPair.first;
|
_jointToPuckMap[controller::RIGHT_HAND] = handPair.first;
|
||||||
_pucksOffset[handPair.first] = offsetMat;
|
_pucksPostOffset[handPair.first] = offsetMat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ViveControllerManager::InputDevice::calibrateFeet(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
|
void ViveControllerManager::InputDevice::calibrateFeet(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
|
||||||
glm::vec3 headXAxis = getReferenceHeadXAxis(defaultToReferenceMat, inputCalibration.defaultHeadMat);
|
glm::vec3 headXAxis = getReferenceHeadXAxis(defaultToReferenceMat, inputCalibration.defaultHeadMat);
|
||||||
glm::vec3 headPosition = getReferenceHeadPosition(defaultToReferenceMat, inputCalibration.defaultHeadMat);
|
glm::vec3 headPosition = getReferenceHeadPosition(defaultToReferenceMat, inputCalibration.defaultHeadMat);
|
||||||
auto& firstFoot = _validTrackedObjects[FIRST_FOOT];
|
auto& firstFoot = _validTrackedObjects[FIRST_FOOT];
|
||||||
|
@ -1022,7 +1074,7 @@ void ViveControllerManager::InputDevice::calibrateFeet(glm::mat4& defaultToRefer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViveControllerManager::InputDevice::calibrateFoot(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& footPair, bool isLeftFoot){
|
void ViveControllerManager::InputDevice::calibrateFoot(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& footPair, bool isLeftFoot){
|
||||||
controller::Pose footPose = footPair.second;
|
controller::Pose footPose = footPair.second;
|
||||||
glm::mat4 puckPoseAvatarMat = createMatFromQuatAndPos(footPose.getRotation(), footPose.getTranslation());
|
glm::mat4 puckPoseAvatarMat = createMatFromQuatAndPos(footPose.getRotation(), footPose.getTranslation());
|
||||||
glm::mat4 defaultFoot = isLeftFoot ? inputCalibration.defaultLeftFoot : inputCalibration.defaultRightFoot;
|
glm::mat4 defaultFoot = isLeftFoot ? inputCalibration.defaultLeftFoot : inputCalibration.defaultRightFoot;
|
||||||
|
@ -1037,48 +1089,96 @@ void ViveControllerManager::InputDevice::calibrateFoot(glm::mat4& defaultToRefer
|
||||||
|
|
||||||
if (isLeftFoot) {
|
if (isLeftFoot) {
|
||||||
_jointToPuckMap[controller::LEFT_FOOT] = footPair.first;
|
_jointToPuckMap[controller::LEFT_FOOT] = footPair.first;
|
||||||
_pucksOffset[footPair.first] = finalOffset;
|
_pucksPostOffset[footPair.first] = finalOffset;
|
||||||
} else {
|
} else {
|
||||||
_jointToPuckMap[controller::RIGHT_FOOT] = footPair.first;
|
_jointToPuckMap[controller::RIGHT_FOOT] = footPair.first;
|
||||||
_pucksOffset[footPair.first] = finalOffset;
|
_pucksPostOffset[footPair.first] = finalOffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViveControllerManager::InputDevice::calibrateHips(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
|
void ViveControllerManager::InputDevice::calibrateHips(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
|
||||||
_jointToPuckMap[controller::HIPS] = _validTrackedObjects[HIP].first;
|
_jointToPuckMap[controller::HIPS] = _validTrackedObjects[HIP].first;
|
||||||
_pucksOffset[_validTrackedObjects[HIP].first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultHips, _validTrackedObjects[HIP].second);
|
_pucksPostOffset[_validTrackedObjects[HIP].first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultHips, _validTrackedObjects[HIP].second);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViveControllerManager::InputDevice::calibrateChest(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
|
void ViveControllerManager::InputDevice::calibrateChest(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
|
||||||
_jointToPuckMap[controller::SPINE2] = _validTrackedObjects[CHEST].first;
|
_jointToPuckMap[controller::SPINE2] = _validTrackedObjects[CHEST].first;
|
||||||
_pucksOffset[_validTrackedObjects[CHEST].first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultSpine2, _validTrackedObjects[CHEST].second);
|
_pucksPostOffset[_validTrackedObjects[CHEST].first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultSpine2, _validTrackedObjects[CHEST].second);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViveControllerManager::InputDevice::calibrateShoulders(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration,
|
// y axis comes out of puck usb port/green light
|
||||||
|
// -z axis comes out of puck center/vive logo
|
||||||
|
static glm::vec3 computeUserShoulderPositionFromMeasurements(float armCirc, float shoulderSpan, const glm::mat4& headMat, const controller::Pose& armPuck, bool isLeftHand) {
|
||||||
|
|
||||||
|
float armRadius = armCirc / TWO_PI;
|
||||||
|
|
||||||
|
float sign = isLeftHand ? 1.0f : -1.0f;
|
||||||
|
float localArmX = sign * shoulderSpan / 2.0f;
|
||||||
|
|
||||||
|
controller::Pose localPuck = armPuck.transform(glm::inverse(headMat));
|
||||||
|
glm::mat4 localPuckMat = localPuck.getMatrix();
|
||||||
|
glm::vec3 localArmCenter = extractTranslation(localPuckMat) + armRadius * transformVectorFast(localPuckMat, Vectors::UNIT_Z);
|
||||||
|
|
||||||
|
return transformPoint(headMat, glm::vec3(localArmX, localArmCenter.y, localArmCenter.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViveControllerManager::InputDevice::calibrateShoulders(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration,
|
||||||
int firstShoulderIndex, int secondShoulderIndex) {
|
int firstShoulderIndex, int secondShoulderIndex) {
|
||||||
const PuckPosePair& firstShoulder = _validTrackedObjects[firstShoulderIndex];
|
const PuckPosePair& firstShoulder = _validTrackedObjects[firstShoulderIndex];
|
||||||
const PuckPosePair& secondShoulder = _validTrackedObjects[secondShoulderIndex];
|
const PuckPosePair& secondShoulder = _validTrackedObjects[secondShoulderIndex];
|
||||||
const controller::Pose& firstShoulderPose = firstShoulder.second;
|
const controller::Pose& firstShoulderPose = firstShoulder.second;
|
||||||
const controller::Pose& secondShoulderPose = secondShoulder.second;
|
const controller::Pose& secondShoulderPose = secondShoulder.second;
|
||||||
|
|
||||||
|
glm::mat4 refLeftArm = defaultToReferenceMat * inputCalibration.defaultLeftArm;
|
||||||
|
glm::mat4 refRightArm = defaultToReferenceMat * inputCalibration.defaultRightArm;
|
||||||
|
|
||||||
|
glm::mat4 userRefLeftArm = refLeftArm;
|
||||||
|
glm::mat4 userRefRightArm = refRightArm;
|
||||||
|
|
||||||
|
glm::mat4 headMat = defaultToReferenceMat * inputCalibration.defaultHeadMat;
|
||||||
|
|
||||||
if (firstShoulderPose.translation.x < secondShoulderPose.translation.x) {
|
if (firstShoulderPose.translation.x < secondShoulderPose.translation.x) {
|
||||||
_jointToPuckMap[controller::LEFT_ARM] = firstShoulder.first;
|
_jointToPuckMap[controller::LEFT_ARM] = firstShoulder.first;
|
||||||
_pucksOffset[firstShoulder.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultLeftArm, firstShoulder.second);
|
|
||||||
_jointToPuckMap[controller::RIGHT_ARM] = secondShoulder.first;
|
_jointToPuckMap[controller::RIGHT_ARM] = secondShoulder.first;
|
||||||
_pucksOffset[secondShoulder.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultRightArm, secondShoulder.second);
|
|
||||||
|
glm::vec3 leftPos = computeUserShoulderPositionFromMeasurements(_armCircumference, _shoulderWidth, headMat, firstShoulderPose, true);
|
||||||
|
userRefLeftArm[3] = glm::vec4(leftPos, 1.0f);
|
||||||
|
glm::vec3 rightPos = computeUserShoulderPositionFromMeasurements(_armCircumference, _shoulderWidth, headMat, secondShoulderPose, false);
|
||||||
|
userRefRightArm[3] = glm::vec4(rightPos, 1.0f);
|
||||||
|
|
||||||
|
// compute the post offset from the userRefArm
|
||||||
|
_pucksPostOffset[firstShoulder.first] = computeOffset(Matrices::IDENTITY, userRefLeftArm, firstShoulderPose);
|
||||||
|
_pucksPostOffset[secondShoulder.first] = computeOffset(Matrices::IDENTITY, userRefRightArm, secondShoulderPose);
|
||||||
|
|
||||||
|
// compute the pre offset from the diff between userRefArm and refArm transforms.
|
||||||
|
// as an optimization we don't do a full inverse, but subtract the translations.
|
||||||
|
_pucksPreOffset[firstShoulder.first] = createMatFromQuatAndPos(glm::quat(), extractTranslation(userRefLeftArm) - extractTranslation(refLeftArm));
|
||||||
|
_pucksPreOffset[secondShoulder.first] = createMatFromQuatAndPos(glm::quat(), extractTranslation(userRefRightArm) - extractTranslation(refRightArm));
|
||||||
} else {
|
} else {
|
||||||
_jointToPuckMap[controller::LEFT_ARM] = secondShoulder.first;
|
_jointToPuckMap[controller::LEFT_ARM] = secondShoulder.first;
|
||||||
_pucksOffset[secondShoulder.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultLeftArm, secondShoulder.second);
|
|
||||||
_jointToPuckMap[controller::RIGHT_ARM] = firstShoulder.first;
|
_jointToPuckMap[controller::RIGHT_ARM] = firstShoulder.first;
|
||||||
_pucksOffset[firstShoulder.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultRightArm, firstShoulder.second);
|
|
||||||
|
glm::vec3 leftPos = computeUserShoulderPositionFromMeasurements(_armCircumference, _shoulderWidth, headMat, secondShoulderPose, true);
|
||||||
|
userRefLeftArm[3] = glm::vec4(leftPos, 1.0f);
|
||||||
|
glm::vec3 rightPos = computeUserShoulderPositionFromMeasurements(_armCircumference, _shoulderWidth, headMat, firstShoulderPose, false);
|
||||||
|
userRefRightArm[3] = glm::vec4(rightPos, 1.0f);
|
||||||
|
|
||||||
|
// compute the post offset from the userRefArm
|
||||||
|
_pucksPostOffset[secondShoulder.first] = computeOffset(Matrices::IDENTITY, userRefLeftArm, secondShoulderPose);
|
||||||
|
_pucksPostOffset[firstShoulder.first] = computeOffset(Matrices::IDENTITY, userRefRightArm, firstShoulderPose);
|
||||||
|
|
||||||
|
// compute the pre offset from the diff between userRefArm and refArm transforms.
|
||||||
|
// as an optimization we don't do a full inverse, but subtract the translations.
|
||||||
|
_pucksPreOffset[secondShoulder.first] = createMatFromQuatAndPos(glm::quat(), extractTranslation(userRefLeftArm) - extractTranslation(refLeftArm));
|
||||||
|
_pucksPreOffset[firstShoulder.first] = createMatFromQuatAndPos(glm::quat(), extractTranslation(userRefRightArm) - extractTranslation(refRightArm));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViveControllerManager::InputDevice::calibrateHead(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
|
void ViveControllerManager::InputDevice::calibrateHead(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
|
||||||
size_t headIndex = _validTrackedObjects.size() - 1;
|
size_t headIndex = _validTrackedObjects.size() - 1;
|
||||||
const PuckPosePair& head = _validTrackedObjects[headIndex];
|
const PuckPosePair& head = _validTrackedObjects[headIndex];
|
||||||
_jointToPuckMap[controller::HEAD] = head.first;
|
_jointToPuckMap[controller::HEAD] = head.first;
|
||||||
_pucksOffset[head.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultHeadMat, head.second);
|
_pucksPostOffset[head.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultHeadMat, head.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ViveControllerManager::InputDevice::configToString(Config config) {
|
QString ViveControllerManager::InputDevice::configToString(Config config) {
|
||||||
|
|
|
@ -57,6 +57,9 @@ public:
|
||||||
|
|
||||||
void setRenderControllers(bool renderControllers) { _renderControllers = renderControllers; }
|
void setRenderControllers(bool renderControllers) { _renderControllers = renderControllers; }
|
||||||
|
|
||||||
|
virtual void saveSettings() const override;
|
||||||
|
virtual void loadSettings() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class InputDevice : public controller::InputDevice {
|
class InputDevice : public controller::InputDevice {
|
||||||
public:
|
public:
|
||||||
|
@ -93,18 +96,18 @@ private:
|
||||||
void partitionTouchpad(int sButton, int xAxis, int yAxis, int centerPsuedoButton, int xPseudoButton, int yPseudoButton);
|
void partitionTouchpad(int sButton, int xAxis, int yAxis, int centerPsuedoButton, int xPseudoButton, int yPseudoButton);
|
||||||
void printDeviceTrackingResultChange(uint32_t deviceIndex);
|
void printDeviceTrackingResultChange(uint32_t deviceIndex);
|
||||||
void setConfigFromString(const QString& value);
|
void setConfigFromString(const QString& value);
|
||||||
bool configureHead(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
|
bool configureHead(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
|
||||||
bool configureHands(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
|
bool configureHands(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
|
||||||
bool configureBody(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
|
bool configureBody(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
|
||||||
void calibrateLeftHand(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair);
|
void calibrateLeftHand(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair);
|
||||||
void calibrateRightHand(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair);
|
void calibrateRightHand(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair);
|
||||||
void calibrateFeet(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
|
void calibrateFeet(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
|
||||||
void calibrateFoot(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& footPair, bool isLeftFoot);
|
void calibrateFoot(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& footPair, bool isLeftFoot);
|
||||||
void calibrateHips(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
|
void calibrateHips(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
|
||||||
void calibrateChest(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
|
void calibrateChest(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
|
||||||
void calibrateShoulders(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration,
|
void calibrateShoulders(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration,
|
||||||
int firstShoulderIndex, int secondShoulderIndex);
|
int firstShoulderIndex, int secondShoulderIndex);
|
||||||
void calibrateHead(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
|
void calibrateHead(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
|
||||||
void calibrateFromHandController(const controller::InputCalibrationData& inputCalibrationData);
|
void calibrateFromHandController(const controller::InputCalibrationData& inputCalibrationData);
|
||||||
void calibrateFromUI(const controller::InputCalibrationData& inputCalibrationData);
|
void calibrateFromUI(const controller::InputCalibrationData& inputCalibrationData);
|
||||||
void emitCalibrationStatus();
|
void emitCalibrationStatus();
|
||||||
|
@ -161,7 +164,8 @@ private:
|
||||||
FilteredStick _filteredRightStick;
|
FilteredStick _filteredRightStick;
|
||||||
|
|
||||||
std::vector<PuckPosePair> _validTrackedObjects;
|
std::vector<PuckPosePair> _validTrackedObjects;
|
||||||
std::map<uint32_t, glm::mat4> _pucksOffset;
|
std::map<uint32_t, glm::mat4> _pucksPostOffset;
|
||||||
|
std::map<uint32_t, glm::mat4> _pucksPreOffset;
|
||||||
std::map<int, uint32_t> _jointToPuckMap;
|
std::map<int, uint32_t> _jointToPuckMap;
|
||||||
std::map<Config, QString> _configStringMap;
|
std::map<Config, QString> _configStringMap;
|
||||||
PoseData _lastSimPoseData;
|
PoseData _lastSimPoseData;
|
||||||
|
@ -181,6 +185,8 @@ private:
|
||||||
float _headPuckZOffset { -0.05f };
|
float _headPuckZOffset { -0.05f };
|
||||||
float _handPuckYOffset { 0.0f };
|
float _handPuckYOffset { 0.0f };
|
||||||
float _handPuckZOffset { 0.0f };
|
float _handPuckZOffset { 0.0f };
|
||||||
|
float _armCircumference { 0.33f };
|
||||||
|
float _shoulderWidth { 0.48f };
|
||||||
bool _triggersPressedHandled { false };
|
bool _triggersPressedHandled { false };
|
||||||
bool _calibrated { false };
|
bool _calibrated { false };
|
||||||
bool _timeTilCalibrationSet { false };
|
bool _timeTilCalibrationSet { false };
|
||||||
|
|
|
@ -43,17 +43,20 @@ var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
// Independent and Entity mode make people sick; disable them in hmd.
|
// Independent and Entity mode make people sick; disable them in hmd.
|
||||||
var desktopOnlyViews = ['Independent Mode', 'Entity Mode'];
|
var desktopOnlyViews = ['Independent Mode', 'Entity Mode'];
|
||||||
|
|
||||||
|
var switchToVR = "ENTER VR";
|
||||||
|
var switchToDesktop = "EXIT VR";
|
||||||
|
|
||||||
function onHmdChanged(isHmd) {
|
function onHmdChanged(isHmd) {
|
||||||
HMD.closeTablet();
|
HMD.closeTablet();
|
||||||
if (isHmd) {
|
if (isHmd) {
|
||||||
button.editProperties({
|
button.editProperties({
|
||||||
icon: "icons/tablet-icons/switch-desk-i.svg",
|
icon: "icons/tablet-icons/switch-desk-i.svg",
|
||||||
text: "DESKTOP"
|
text: switchToDesktop
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
button.editProperties({
|
button.editProperties({
|
||||||
icon: "icons/tablet-icons/switch-vr-i.svg",
|
icon: "icons/tablet-icons/switch-vr-i.svg",
|
||||||
text: "VR"
|
text: switchToVR
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
desktopOnlyViews.forEach(function (view) {
|
desktopOnlyViews.forEach(function (view) {
|
||||||
|
@ -70,7 +73,7 @@ function onClicked() {
|
||||||
if (headset) {
|
if (headset) {
|
||||||
button = tablet.addButton({
|
button = tablet.addButton({
|
||||||
icon: HMD.active ? "icons/tablet-icons/switch-desk-i.svg" : "icons/tablet-icons/switch-vr-i.svg",
|
icon: HMD.active ? "icons/tablet-icons/switch-desk-i.svg" : "icons/tablet-icons/switch-vr-i.svg",
|
||||||
text: HMD.active ? "DESKTOP" : "VR",
|
text: HMD.active ? switchToDesktop : switchToVR,
|
||||||
sortOrder: 2
|
sortOrder: 2
|
||||||
});
|
});
|
||||||
onHmdChanged(HMD.active);
|
onHmdChanged(HMD.active);
|
||||||
|
|
|
@ -195,7 +195,7 @@
|
||||||
<div class="ChatLog" id="ChatLog"></div>
|
<div class="ChatLog" id="ChatLog"></div>
|
||||||
|
|
||||||
<div class="ChatInput">
|
<div class="ChatInput">
|
||||||
<input type="text" class="ChatInputText" id="ChatInputText" size="256"/>
|
<input type="text" class="ChatInputText" id="ChatInputText" size="256" maxlength="256" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
BIN
scripts/system/html/img/blocks-tile.png
Normal file
BIN
scripts/system/html/img/blocks-tile.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
|
@ -33,8 +33,8 @@
|
||||||
$("head").append(
|
$("head").append(
|
||||||
'<style>' +
|
'<style>' +
|
||||||
'#marketplace-navigation { font-family: Arial, Helvetica, sans-serif; width: 100%; height: 50px; background: #00b4ef; position: fixed; bottom: 0; z-index: 1000; }' +
|
'#marketplace-navigation { font-family: Arial, Helvetica, sans-serif; width: 100%; height: 50px; background: #00b4ef; position: fixed; bottom: 0; z-index: 1000; }' +
|
||||||
'#marketplace-navigation .glyph { margin-left: 20px; margin-right: 3px; font-family: sans-serif; color: #fff; font-size: 24px; line-height: 50px; }' +
|
'#marketplace-navigation .glyph { margin-left: 10px; margin-right: 3px; font-family: sans-serif; color: #fff; font-size: 24px; line-height: 50px; }' +
|
||||||
'#marketplace-navigation .text { color: #fff; font-size: 18px; line-height: 50px; vertical-align: top; position: relative; top: 1px; }' +
|
'#marketplace-navigation .text { color: #fff; font-size: 16px; line-height: 50px; vertical-align: top; position: relative; top: 1px; }' +
|
||||||
'#marketplace-navigation input#back-button { position: absolute; left: 20px; margin-top: 12px; padding-left: 0; padding-right: 5px; }' +
|
'#marketplace-navigation input#back-button { position: absolute; left: 20px; margin-top: 12px; padding-left: 0; padding-right: 5px; }' +
|
||||||
'#marketplace-navigation input#all-markets { position: absolute; right: 20px; margin-top: 12px; padding-left: 15px; padding-right: 15px; }' +
|
'#marketplace-navigation input#all-markets { position: absolute; right: 20px; margin-top: 12px; padding-left: 15px; padding-right: 15px; }' +
|
||||||
'#marketplace-navigation .right { position: absolute; right: 20px; }' +
|
'#marketplace-navigation .right { position: absolute; right: 20px; }' +
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
$("body").append(
|
$("body").append(
|
||||||
'<div id="marketplace-navigation">' +
|
'<div id="marketplace-navigation">' +
|
||||||
(!isInitialHiFiPage ? '<input id="back-button" type="button" class="white" value="< Back" />' : '') +
|
(!isInitialHiFiPage ? '<input id="back-button" type="button" class="white" value="< Back" />' : '') +
|
||||||
(isInitialHiFiPage ? '<span class="glyph">🛈</span> <span class="text">See also other marketplaces.</span>' : '') +
|
(isInitialHiFiPage ? '<span class="glyph">🛈</span> <span class="text">Get items from Clara.io!</span>' : '') +
|
||||||
(!isDirectoryPage ? '<input id="all-markets" type="button" class="white" value="See All Markets" />' : '') +
|
(!isDirectoryPage ? '<input id="all-markets" type="button" class="white" value="See All Markets" />' : '') +
|
||||||
(isDirectoryPage ? '<span class="right"><span class="glyph">🛈</span> <span class="text">Select a marketplace to explore.</span><span>' : '') +
|
(isDirectoryPage ? '<span class="right"><span class="glyph">🛈</span> <span class="text">Select a marketplace to explore.</span><span>' : '') +
|
||||||
'</div>'
|
'</div>'
|
||||||
|
@ -65,7 +65,7 @@
|
||||||
|
|
||||||
// Footer actions.
|
// Footer actions.
|
||||||
$("#back-button").on("click", function () {
|
$("#back-button").on("click", function () {
|
||||||
window.history.back();
|
(window.history.state != null) ? window.history.back() : window.location = "https://metaverse.highfidelity.com/marketplace?";
|
||||||
});
|
});
|
||||||
$("#all-markets").on("click", function () {
|
$("#all-markets").on("click", function () {
|
||||||
EventBridge.emitWebEvent(GOTO_DIRECTORY);
|
EventBridge.emitWebEvent(GOTO_DIRECTORY);
|
||||||
|
|
|
@ -25,25 +25,25 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="marketplace-tile-second-column">
|
<div class="marketplace-tile-second-column">
|
||||||
<p class="marketplace-tile-description">This is the default High Fidelity marketplace. Viewing and downloading content from here is fully supported in Interface.</p>
|
<p class="marketplace-tile-description">This is the default High Fidelity marketplace. Viewing and downloading content from here is fully supported in Interface.</p>
|
||||||
<div class="exploreButton-holder">
|
|
||||||
<input class="blue exploreButton" type="button" value="Explore" id="exploreHifiMarketplace" />
|
|
||||||
</div>
|
|
||||||
<hr class="tile-divider">
|
|
||||||
</div>
|
</div>
|
||||||
<div class="marketplace-tile">
|
<div class="exploreButton-holder">
|
||||||
<div class="marketplace-tile-first-column">
|
<input class="blue exploreButton" type="button" value="Explore" id="exploreHifiMarketplace" />
|
||||||
<img class="marketplace-tile-image" src="img/clara-tile.png">
|
</div>
|
||||||
</div>
|
<hr class="tile-divider">
|
||||||
<div class="marketplace-tile-second-column">
|
</div>
|
||||||
<p class="marketplace-tile-description">Clara.io has thousands of models available for importing into High Fidelity. Follow these steps for the best experience:</p>
|
<div class="marketplace-tile">
|
||||||
<ol class="marketplace-clara-steps">
|
<div class="marketplace-tile-first-column">
|
||||||
<li><a id="claraSignUp" href="http://www.clara.io/signup">Create an account here </a>or log in as an existing user.</li>
|
<img class="marketplace-tile-image" src="img/clara-tile.png">
|
||||||
<li>Choose a model from the list and click “Download to High Fidelity”.</li>
|
</div>
|
||||||
</ol>
|
<div class="marketplace-tile-second-column">
|
||||||
<div class="exploreButton-holder">
|
<p class="marketplace-tile-description">Clara.io has thousands of models available for importing into High Fidelity. Follow these steps for the best experience:</p>
|
||||||
<input class="blue exploreButton" type="button" value="Explore" id="exploreClaraMarketplace" />
|
<ol class="marketplace-clara-steps">
|
||||||
</div>
|
<li><a id="claraSignUp" href="http://www.clara.io/signup">Create an account here </a>or log in as an existing user.</li>
|
||||||
</div>
|
<li>Choose a model from the list and click “Download to High Fidelity”.</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
<div class="exploreButton-holder">
|
||||||
|
<input class="blue exploreButton" type="button" value="Explore" id="exploreClaraMarketplace" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -42,7 +42,7 @@ var LOCAL_TABLET_MODEL_PATH = Script.resourcesPath() + "meshes/tablet-with-home-
|
||||||
// returns object with two fields:
|
// returns object with two fields:
|
||||||
// * position - position in front of the user
|
// * position - position in front of the user
|
||||||
// * rotation - rotation of entity so it faces the user.
|
// * rotation - rotation of entity so it faces the user.
|
||||||
function calcSpawnInfo(hand, tabletHeight) {
|
function calcSpawnInfo(hand, tabletHeight, landscape) {
|
||||||
var finalPosition;
|
var finalPosition;
|
||||||
|
|
||||||
var headPos = (HMD.active && Camera.mode === "first person") ? HMD.position : Camera.position;
|
var headPos = (HMD.active && Camera.mode === "first person") ? HMD.position : Camera.position;
|
||||||
|
@ -81,7 +81,7 @@ function calcSpawnInfo(hand, tabletHeight) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
position: position,
|
position: position,
|
||||||
rotation: rotation
|
rotation: landscape ? Quat.multiply(rotation, { x: 0.0, y: 0.0, z: 0.707, w: 0.707 }) : rotation
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
var forward = Quat.getForward(headRot);
|
var forward = Quat.getForward(headRot);
|
||||||
|
@ -89,7 +89,7 @@ function calcSpawnInfo(hand, tabletHeight) {
|
||||||
var orientation = Quat.lookAt({x: 0, y: 0, z: 0}, forward, {x: 0, y: 1, z: 0});
|
var orientation = Quat.lookAt({x: 0, y: 0, z: 0}, forward, {x: 0, y: 1, z: 0});
|
||||||
return {
|
return {
|
||||||
position: finalPosition,
|
position: finalPosition,
|
||||||
rotation: Quat.multiply(orientation, {x: 0, y: 1, z: 0, w: 0})
|
rotation: landscape ? Quat.multiply(orientation, ROT_LANDSCAPE) : Quat.multiply(orientation, ROT_Y_180)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -424,7 +424,7 @@ WebTablet.prototype.calculateTabletAttachmentProperties = function (hand, useMou
|
||||||
tabletProperties.parentJointIndex = SENSOR_TO_ROOM_MATRIX;
|
tabletProperties.parentJointIndex = SENSOR_TO_ROOM_MATRIX;
|
||||||
|
|
||||||
// compute the appropriate position of the tablet, near the hand controller that was used to spawn it.
|
// compute the appropriate position of the tablet, near the hand controller that was used to spawn it.
|
||||||
var spawnInfo = calcSpawnInfo(hand, this.height);
|
var spawnInfo = calcSpawnInfo(hand, this.height, this.landscape);
|
||||||
tabletProperties.position = spawnInfo.position;
|
tabletProperties.position = spawnInfo.position;
|
||||||
tabletProperties.rotation = spawnInfo.rotation;
|
tabletProperties.rotation = spawnInfo.rotation;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -681,7 +681,7 @@ private:
|
||||||
_renderCount = _renderThread._presentCount.load();
|
_renderCount = _renderThread._presentCount.load();
|
||||||
update();
|
update();
|
||||||
|
|
||||||
RenderArgs renderArgs(_renderThread._gpuContext, _octree, DEFAULT_OCTREE_SIZE_SCALE,
|
RenderArgs renderArgs(_renderThread._gpuContext, DEFAULT_OCTREE_SIZE_SCALE,
|
||||||
0, RenderArgs::DEFAULT_RENDER_MODE,
|
0, RenderArgs::DEFAULT_RENDER_MODE,
|
||||||
RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
|
RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
||||||
#pragma GCC diagnostic ignored "-Wunused-result"
|
#pragma GCC diagnostic ignored "-Wunused-result"
|
||||||
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
|
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
|
||||||
|
#pragma GCC diagnostic ignored "-Wtype-limits"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <gli/gli.hpp>
|
#include <gli/gli.hpp>
|
||||||
|
|
Loading…
Reference in a new issue