Merge branch 'master' of https://github.com/highfidelity/hifi into context-overlays

This commit is contained in:
Zach Fox 2017-07-25 09:33:07 -07:00
commit 40038ce54b
44 changed files with 722 additions and 182 deletions

View file

@ -927,9 +927,12 @@ void DomainGatekeeper::getDomainOwnerFriendsList() {
callbackParams.errorCallbackMethod = "getDomainOwnerFriendsListErrorCallback";
const QString GET_FRIENDS_LIST_PATH = "api/v1/user/friends";
DependencyManager::get<AccountManager>()->sendRequest(GET_FRIENDS_LIST_PATH, AccountManagerAuth::Required,
QNetworkAccessManager::GetOperation, callbackParams, QByteArray(),
NULL, QVariantMap());
if (DependencyManager::get<AccountManager>()->hasValidAccessToken()) {
DependencyManager::get<AccountManager>()->sendRequest(GET_FRIENDS_LIST_PATH, AccountManagerAuth::Required,
QNetworkAccessManager::GetOperation, callbackParams, QByteArray(),
NULL, QVariantMap());
}
}
void DomainGatekeeper::getDomainOwnerFriendsListJSONCallback(QNetworkReply& requestReply) {

View file

@ -81,7 +81,11 @@
{ "from": { "makeAxis" : ["Keyboard.MouseMoveLeft", "Keyboard.MouseMoveRight"] },
"when": "Keyboard.RightMouseButton",
"to": "Actions.Yaw"
"to": "Actions.Yaw",
"filters":
[
{ "type": "scale", "scale": 0.6 }
]
},
{ "from": "Keyboard.W", "to": "Actions.LONGITUDINAL_FORWARD" },
@ -102,8 +106,19 @@
{ "from": "Keyboard.PgDown", "to": "Actions.VERTICAL_DOWN" },
{ "from": "Keyboard.PgUp", "to": "Actions.VERTICAL_UP" },
{ "from": "Keyboard.MouseMoveUp", "when": "Keyboard.RightMouseButton", "to": "Actions.PITCH_UP" },
{ "from": "Keyboard.MouseMoveDown", "when": "Keyboard.RightMouseButton", "to": "Actions.PITCH_DOWN" },
{ "from": "Keyboard.MouseMoveUp", "when": "Keyboard.RightMouseButton", "to": "Actions.PITCH_UP",
"filters":
[
{ "type": "scale", "scale": 0.6 }
]
},
{ "from": "Keyboard.MouseMoveDown", "when": "Keyboard.RightMouseButton", "to": "Actions.PITCH_DOWN",
"filters":
[
{ "type": "scale", "scale": 0.6 }
]
},
{ "from": "Keyboard.TouchpadDown", "to": "Actions.PITCH_DOWN" },
{ "from": "Keyboard.TouchpadUp", "to": "Actions.PITCH_UP" },

View file

@ -0,0 +1,71 @@
//
// RadioButton.qml
//
// Created by Cain Kilgore on 20th July 2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import QtQuick.Controls 1.4 as Original
import QtQuick.Controls.Styles 1.4
import "../styles-uit"
import "../controls-uit" as HifiControls
Original.RadioButton {
id: radioButton
HifiConstants { id: hifi }
property int colorScheme: hifi.colorSchemes.light
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
readonly property int boxSize: 14
readonly property int boxRadius: 3
readonly property int checkSize: 10
readonly property int checkRadius: 2
style: RadioButtonStyle {
indicator: Rectangle {
id: box
width: boxSize
height: boxSize
radius: 7
gradient: Gradient {
GradientStop {
position: 0.2
color: pressed || hovered
? (radioButton.isLightColorScheme ? hifi.colors.checkboxDarkStart : hifi.colors.checkboxLightStart)
: (radioButton.isLightColorScheme ? hifi.colors.checkboxLightStart : hifi.colors.checkboxDarkStart)
}
GradientStop {
position: 1.0
color: pressed || hovered
? (radioButton.isLightColorScheme ? hifi.colors.checkboxDarkFinish : hifi.colors.checkboxLightFinish)
: (radioButton.isLightColorScheme ? hifi.colors.checkboxLightFinish : hifi.colors.checkboxDarkFinish)
}
}
Rectangle {
id: check
width: checkSize
height: checkSize
radius: 7
anchors.centerIn: parent
color: "#00B4EF"
border.width: 1
border.color: "#36CDFF"
visible: checked && !pressed || !checked && pressed
}
}
label: RalewaySemiBold {
text: control.text
size: hifi.fontSizes.inputLabel
color: isLightColorScheme ? hifi.colors.lightGray : hifi.colors.lightGrayText
x: radioButton.boxSize / 2
}
}
}

View file

@ -0,0 +1,17 @@
import QtQuick.Controls 1.3 as Original
import QtQuick.Controls.Styles 1.3
import "../styles"
import "."
Original.RadioButton {
text: "Radio Button"
style: RadioButtonStyle {
indicator: FontAwesome {
text: control.checked ? "\uf046" : "\uf096"
}
label: Text {
text: control.text
renderType: Text.QtRendering
}
}
}

View file

@ -0,0 +1,101 @@
//
// PrimaryHandPreference.qml
//
// Created by Cain Kilgore on 20th July 2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import "../../controls-uit"
Preference {
id: root
property alias box1: box1
property alias box2: box2
height: control.height + hifi.dimensions.controlInterlineHeight
Component.onCompleted: {
if (preference.value == "left") {
box1.checked = true;
} else {
box2.checked = true;
}
}
function save() {
if (box1.checked && !box2.checked) {
preference.value = "left";
}
if (!box1.checked && box2.checked) {
preference.value = "right";
}
preference.save();
}
Item {
id: control
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
}
height: Math.max(labelName.height, box1.height, box2.height)
Label {
id: labelName
text: root.label + ":"
colorScheme: hifi.colorSchemes.dark
anchors {
left: parent.left
right: box1.left
rightMargin: hifi.dimensions.labelPadding
verticalCenter: parent.verticalCenter
}
horizontalAlignment: Text.AlignRight
wrapMode: Text.Wrap
}
RadioButton {
id: box1
text: "Left"
width: 60
anchors {
right: box2.left
verticalCenter: parent.verticalCenter
}
onClicked: {
if (box2.checked) {
box2.checked = false;
}
if (!box1.checked && !box2.checked) {
box1.checked = true;
}
}
colorScheme: hifi.colorSchemes.dark
}
RadioButton {
id: box2
text: "Right"
width: 60
anchors {
right: parent.right
verticalCenter: parent.verticalCenter
}
onClicked: {
if (box1.checked) {
box1.checked = false;
}
if (!box1.checked && !box2.checked) {
box2.checked = true;
}
}
colorScheme: hifi.colorSchemes.dark
}
}
}

View file

@ -73,6 +73,7 @@ Preference {
property var buttonBuilder: Component { ButtonPreference { } }
property var comboBoxBuilder: Component { ComboBoxPreference { } }
property var spinnerSliderBuilder: Component { SpinnerSliderPreference { } }
property var primaryHandBuilder: Component { PrimaryHandPreference { } }
property var preferences: []
property int checkBoxCount: 0
@ -134,6 +135,11 @@ Preference {
checkBoxCount = 0;
builder = spinnerSliderBuilder;
break;
case Preference.PrimaryHand:
checkBoxCount++;
builder = primaryHandBuilder;
break;
};
if (builder) {

View file

@ -17,7 +17,7 @@ PreferencesDialog {
id: root
objectName: "GeneralPreferencesDialog"
title: "General Settings"
showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers", "Perception Neuron", "Kinect", "Leap Motion"]
showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Game Controller", "Sixense Controllers", "Perception Neuron", "Kinect", "Leap Motion"]
property var settings: Settings {
category: root.objectName
property alias x: root.x

View file

@ -21,7 +21,7 @@ TabView {
enabled: true
property string originalUrl: ""
Rectangle {
Rectangle {
color: "#404040"
Text {
@ -180,7 +180,7 @@ TabView {
WebView {
id: entityListToolWebView
url: "../../../../../scripts/system/html/entityList.html"
url: Paths.defaultScripts + "/system/html/entityList.html"
anchors.fill: parent
enabled: true
}
@ -194,7 +194,7 @@ TabView {
WebView {
id: entityPropertiesWebView
url: "../../../../../scripts/system/html/entityProperties.html"
url: Paths.defaultScripts + "/system/html/entityProperties.html"
anchors.fill: parent
enabled: true
}
@ -208,7 +208,7 @@ TabView {
WebView {
id: gridControlsWebView
url: "../../../../../scripts/system/html/gridControls.html"
url: Paths.defaultScripts + "/system/html/gridControls.html"
anchors.fill: parent
enabled: true
}
@ -222,7 +222,7 @@ TabView {
WebView {
id: particleExplorerWebView
url: "../../../../../scripts/system/particle_explorer/particleExplorer.html"
url: Paths.defaultScripts + "/system/particle_explorer/particleExplorer.html"
anchors.fill: parent
enabled: true
}
@ -293,16 +293,16 @@ TabView {
break;
case 'list':
editTabView.currentIndex = 1;
break;
break;
case 'properties':
editTabView.currentIndex = 2;
break;
break;
case 'grid':
editTabView.currentIndex = 3;
break;
break;
case 'particle':
editTabView.currentIndex = 4;
break;
break;
default:
console.warn('Attempt to switch to invalid tab:', id);
}
@ -310,4 +310,4 @@ TabView {
console.warn('Attempt to switch tabs with invalid input:', JSON.stringify(id));
}
}
}
}

View file

@ -32,6 +32,6 @@ StackView {
TabletPreferencesDialog {
id: root
objectName: "TabletGeneralPreferences"
showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers", "Perception Neuron", "Kinect", "Vive Pucks Configuration", "Leap Motion"]
showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Game Controller", "Sixense Controllers", "Perception Neuron", "Kinect", "Leap Motion"]
}
}

View file

@ -82,6 +82,7 @@ Preference {
property var buttonBuilder: Component { ButtonPreference { } }
property var comboBoxBuilder: Component { ComboBoxPreference { } }
property var spinnerSliderBuilder: Component { SpinnerSliderPreference { } }
property var primaryHandBuilder: Component { PrimaryHandPreference { } }
property var preferences: []
property int checkBoxCount: 0
@ -144,10 +145,16 @@ Preference {
//to be not overlapped when drop down is active
zpos = root.z + 1000 - itemNum
break;
case Preference.SpinnerSlider:
checkBoxCount = 0;
builder = spinnerSliderBuilder;
break;
case Preference.PrimaryHand:
checkBoxCount++;
builder = primaryHandBuilder;
break;
};
if (builder) {

View file

@ -69,8 +69,8 @@ const float MAX_BOOST_SPEED = 0.5f * MAX_WALKING_SPEED; // action motor gets add
const float MIN_AVATAR_SPEED = 0.05f;
const float MIN_AVATAR_SPEED_SQUARED = MIN_AVATAR_SPEED * MIN_AVATAR_SPEED; // speed is set to zero below this
const float YAW_SPEED_DEFAULT = 120.0f; // degrees/sec
const float PITCH_SPEED_DEFAULT = 90.0f; // degrees/sec
const float YAW_SPEED_DEFAULT = 100.0f; // degrees/sec
const float PITCH_SPEED_DEFAULT = 75.0f; // degrees/sec
// TODO: normalize avatar speed for standard avatar size, then scale all motion logic
// to properly follow avatar size.
@ -255,6 +255,12 @@ MyAvatar::~MyAvatar() {
_lookAtTargetAvatar.reset();
}
void MyAvatar::setDominantHand(const QString& hand) {
if (hand == DOMINANT_LEFT_HAND || hand == DOMINANT_RIGHT_HAND) {
_dominantHand = hand;
}
}
void MyAvatar::registerMetaTypes(QScriptEngine* engine) {
QScriptValue value = engine->newQObject(this, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects);
engine->globalObject().setProperty("MyAvatar", value);
@ -926,6 +932,7 @@ void MyAvatar::saveData() {
Settings settings;
settings.beginGroup("Avatar");
settings.setValue("dominantHand", _dominantHand);
settings.setValue("headPitch", getHead()->getBasePitch());
settings.setValue("scale", _targetScale);
@ -1122,7 +1129,7 @@ void MyAvatar::loadData() {
setCollisionSoundURL(settings.value("collisionSoundURL", DEFAULT_AVATAR_COLLISION_SOUND_URL).toString());
setSnapTurn(settings.value("useSnapTurn", _useSnapTurn).toBool());
setClearOverlayWhenMoving(settings.value("clearOverlayWhenMoving", _clearOverlayWhenMoving).toBool());
setDominantHand(settings.value("dominantHand", _dominantHand).toString().toLower());
settings.endGroup();
setEnableMeshVisible(Menu::getInstance()->isOptionChecked(MenuOption::MeshVisible));

View file

@ -43,6 +43,7 @@ enum AudioListenerMode {
FROM_CAMERA,
CUSTOM
};
Q_DECLARE_METATYPE(AudioListenerMode);
class MyAvatar : public Avatar {
@ -141,6 +142,9 @@ class MyAvatar : public Avatar {
Q_PROPERTY(float hmdRollControlDeadZone READ getHMDRollControlDeadZone WRITE setHMDRollControlDeadZone)
Q_PROPERTY(float hmdRollControlRate READ getHMDRollControlRate WRITE setHMDRollControlRate)
const QString DOMINANT_LEFT_HAND = "left";
const QString DOMINANT_RIGHT_HAND = "right";
public:
enum DriveKeys {
TRANSLATE_X = 0,
@ -339,6 +343,9 @@ public:
Q_INVOKABLE bool getClearOverlayWhenMoving() const { return _clearOverlayWhenMoving; }
Q_INVOKABLE void setClearOverlayWhenMoving(bool on) { _clearOverlayWhenMoving = on; }
Q_INVOKABLE void setDominantHand(const QString& hand);
Q_INVOKABLE QString getDominantHand() const { return _dominantHand; }
Q_INVOKABLE void setHMDLeanRecenterEnabled(bool value) { _hmdLeanRecenterEnabled = value; }
Q_INVOKABLE bool getHMDLeanRecenterEnabled() const { return _hmdLeanRecenterEnabled; }
@ -424,7 +431,6 @@ public:
Q_INVOKABLE QString getFullAvatarModelName() const { return _fullAvatarModelName; }
void resetFullAvatarURL();
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData) override;
MyCharacterController* getCharacterController() { return &_characterController; }
@ -720,6 +726,7 @@ private:
QUrl _fstAnimGraphOverrideUrl;
bool _useSnapTurn { true };
bool _clearOverlayWhenMoving { true };
QString _dominantHand { DOMINANT_RIGHT_HAND };
const float ROLL_CONTROL_DEAD_ZONE_DEFAULT = 8.0f; // deg
const float ROLL_CONTROL_RATE_DEFAULT = 2.5f; // deg/sec/deg

View file

@ -36,6 +36,21 @@ Setting::Handle<QString>& getSetting(bool contextIsHMD, QAudio::Mode mode) {
}
}
static QString getTargetDevice(bool hmd, QAudio::Mode mode) {
QString deviceName;
auto& setting = getSetting(hmd, mode);
if (setting.isSet()) {
deviceName = setting.get();
} else if (hmd) {
if (mode == QAudio::AudioInput) {
deviceName = qApp->getActiveDisplayPlugin()->getPreferredAudioInDevice();
} else { // if (_mode == QAudio::AudioOutput)
deviceName = qApp->getActiveDisplayPlugin()->getPreferredAudioOutDevice();
}
}
return deviceName;
}
QHash<int, QByteArray> AudioDeviceList::_roles {
{ Qt::DisplayRole, "display" },
{ Qt::CheckStateRole, "selected" },
@ -59,10 +74,15 @@ QVariant AudioDeviceList::data(const QModelIndex& index, int role) const {
}
}
void AudioDeviceList::resetDevice(bool contextIsHMD, const QString& device) {
void AudioDeviceList::resetDevice(bool contextIsHMD) {
auto client = DependencyManager::get<AudioClient>().data();
auto deviceName = getSetting(contextIsHMD, _mode).get();
QString deviceName = getTargetDevice(contextIsHMD, _mode);
// FIXME can't use blocking connections here, so we can't determine whether the switch succeeded or not
// We need to have the AudioClient emit signals on switch success / failure
QMetaObject::invokeMethod(client, "switchAudioDevice",
Q_ARG(QAudio::Mode, _mode), Q_ARG(QString, deviceName));
#if 0
bool switchResult = false;
QMetaObject::invokeMethod(client, "switchAudioDevice", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, switchResult),
@ -85,6 +105,7 @@ void AudioDeviceList::resetDevice(bool contextIsHMD, const QString& device) {
QMetaObject::invokeMethod(client, "switchAudioDevice", Q_ARG(QAudio::Mode, _mode));
}
}
#endif
}
void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device) {
@ -137,11 +158,8 @@ AudioDevices::AudioDevices(bool& contextIsHMD) : _contextIsHMD(contextIsHMD) {
}
void AudioDevices::onContextChanged(const QString& context) {
auto input = getSetting(_contextIsHMD, QAudio::AudioInput).get();
auto output = getSetting(_contextIsHMD, QAudio::AudioOutput).get();
_inputs.resetDevice(_contextIsHMD, input);
_outputs.resetDevice(_contextIsHMD, output);
_inputs.resetDevice(_contextIsHMD);
_outputs.resetDevice(_contextIsHMD);
}
void AudioDevices::onDeviceSelected(QAudio::Mode mode, const QAudioDeviceInfo& device, const QAudioDeviceInfo& previousDevice) {
@ -182,8 +200,16 @@ void AudioDevices::onDeviceSelected(QAudio::Mode mode, const QAudioDeviceInfo& d
void AudioDevices::onDeviceChanged(QAudio::Mode mode, const QAudioDeviceInfo& device) {
if (mode == QAudio::AudioInput) {
if (_requestedInputDevice == device) {
onDeviceSelected(QAudio::AudioInput, device, _inputs._selectedDevice);
_requestedInputDevice = QAudioDeviceInfo();
}
_inputs.onDeviceChanged(device);
} else { // if (mode == QAudio::AudioOutput)
if (_requestedOutputDevice == device) {
onDeviceSelected(QAudio::AudioOutput, device, _outputs._selectedDevice);
_requestedOutputDevice = QAudioDeviceInfo();
}
_outputs.onDeviceChanged(device);
}
}
@ -201,28 +227,16 @@ void AudioDevices::onDevicesChanged(QAudio::Mode mode, const QList<QAudioDeviceI
void AudioDevices::chooseInputDevice(const QAudioDeviceInfo& device) {
auto client = DependencyManager::get<AudioClient>();
bool success = false;
_requestedInputDevice = device;
QMetaObject::invokeMethod(client.data(), "switchAudioDevice",
Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, success),
Q_ARG(QAudio::Mode, QAudio::AudioInput),
Q_ARG(const QAudioDeviceInfo&, device));
if (success) {
onDeviceSelected(QAudio::AudioInput, device, _inputs._selectedDevice);
}
}
void AudioDevices::chooseOutputDevice(const QAudioDeviceInfo& device) {
auto client = DependencyManager::get<AudioClient>();
bool success = false;
_requestedOutputDevice = device;
QMetaObject::invokeMethod(client.data(), "switchAudioDevice",
Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, success),
Q_ARG(QAudio::Mode, QAudio::AudioOutput),
Q_ARG(const QAudioDeviceInfo&, device));
if (success) {
onDeviceSelected(QAudio::AudioOutput, device, _outputs._selectedDevice);
}
}

View file

@ -39,7 +39,7 @@ public:
QVariant data(const QModelIndex& index, int role) const override;
// reset device to the last selected device in this context, or the default
void resetDevice(bool contextIsHMD, const QString& device);
void resetDevice(bool contextIsHMD);
signals:
void deviceChanged(const QAudioDeviceInfo& device);
@ -87,8 +87,10 @@ private:
AudioDeviceList _inputs { QAudio::AudioInput };
AudioDeviceList _outputs { QAudio::AudioOutput };
QAudioDeviceInfo _requestedOutputDevice;
QAudioDeviceInfo _requestedInputDevice;
bool& _contextIsHMD;
const bool& _contextIsHMD;
};
};

View file

@ -24,13 +24,14 @@
#include "ScriptHighlighting.h"
const int NO_CURRENT_HISTORY_COMMAND = -1;
const int MAX_HISTORY_SIZE = 64;
const int MAX_HISTORY_SIZE = 256;
const QString HISTORY_FILENAME = "JSConsole.history.json";
const QString COMMAND_STYLE = "color: #266a9b;";
const QString RESULT_SUCCESS_STYLE = "color: #677373;";
const QString RESULT_INFO_STYLE = "color: #223bd1;";
const QString RESULT_WARNING_STYLE = "color: #d13b22;";
const QString RESULT_WARNING_STYLE = "color: #999922;";
const QString RESULT_ERROR_STYLE = "color: #d13b22;";
const QString GUTTER_PREVIOUS_COMMAND = "<span style=\"color: #57b8bb;\">&lt;</span>";
@ -38,14 +39,35 @@ const QString GUTTER_ERROR = "<span style=\"color: #d13b22;\">X</span>";
const QString JSConsole::_consoleFileName { "about:console" };
const QString JSON_KEY = "entries";
QList<QString> _readLines(const QString& filename) {
QFile file(filename);
file.open(QFile::ReadOnly);
auto json = QTextStream(&file).readAll().toUtf8();
auto root = QJsonDocument::fromJson(json).object();
// TODO: check root["version"]
return root[JSON_KEY].toVariant().toStringList();
}
void _writeLines(const QString& filename, const QList<QString>& lines) {
QFile file(filename);
file.open(QFile::WriteOnly);
auto root = QJsonObject();
root["version"] = 1.0;
root["last-modified"] = QDateTime::currentDateTime().toTimeSpec(Qt::OffsetFromUTC).toString(Qt::ISODate);
root[JSON_KEY] = QJsonArray::fromStringList(lines);
auto json = QJsonDocument(root).toJson();
QTextStream(&file) << json;
}
JSConsole::JSConsole(QWidget* parent, ScriptEngine* scriptEngine) :
QWidget(parent),
_ui(new Ui::Console),
_currentCommandInHistory(NO_CURRENT_HISTORY_COMMAND),
_commandHistory(),
_savedHistoryFilename(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/" + HISTORY_FILENAME),
_commandHistory(_readLines(_savedHistoryFilename)),
_ownScriptEngine(scriptEngine == NULL),
_scriptEngine(NULL) {
_ui->setupUi(this);
_ui->promptTextEdit->setLineWrapMode(QTextEdit::NoWrap);
_ui->promptTextEdit->setWordWrapMode(QTextOption::NoWrap);
@ -101,9 +123,12 @@ void JSConsole::setScriptEngine(ScriptEngine* scriptEngine) {
}
void JSConsole::executeCommand(const QString& command) {
_commandHistory.prepend(command);
if (_commandHistory.length() > MAX_HISTORY_SIZE) {
_commandHistory.removeLast();
if (_commandHistory.isEmpty() || _commandHistory.constFirst() != command) {
_commandHistory.prepend(command);
if (_commandHistory.length() > MAX_HISTORY_SIZE) {
_commandHistory.removeLast();
}
_writeLines(_savedHistoryFilename, _commandHistory);
}
_ui->promptTextEdit->setDisabled(true);
@ -182,7 +207,7 @@ bool JSConsole::eventFilter(QObject* sender, QEvent* event) {
// a new QTextBlock isn't created.
keyEvent->setModifiers(keyEvent->modifiers() & ~Qt::ShiftModifier);
} else {
QString command = _ui->promptTextEdit->toPlainText().trimmed();
QString command = _ui->promptTextEdit->toPlainText().replace("\r\n","\n").trimmed();
if (!command.isEmpty()) {
QTextCursor cursor = _ui->promptTextEdit->textCursor();

View file

@ -63,6 +63,7 @@ private:
QFutureWatcher<QScriptValue> _executeWatcher;
Ui::Console* _ui;
int _currentCommandInHistory;
QString _savedHistoryFilename;
QList<QString> _commandHistory;
// Keeps track if the script engine is created inside the JSConsole
bool _ownScriptEngine;

View file

@ -181,6 +181,11 @@ void setupPreferences() {
preference->setStep(1);
preferences->addPreference(preference);
}
{
auto getter = [=]()->QString { return myAvatar->getDominantHand(); };
auto setter = [=](const QString& value) { myAvatar->setDominantHand(value); };
preferences->addPreference(new PrimaryHandPreference(AVATAR_TUNING, "Dominant Hand", getter, setter));
}
{
auto getter = [=]()->float { return myAvatar->getUniformScale(); };
auto setter = [=](float value) { myAvatar->setTargetScale(value); };
@ -300,17 +305,6 @@ void setupPreferences() {
preferences->addPreference(preference);
}
{
auto getter = []()->float { return controller::InputDevice::getReticleMoveSpeed(); };
auto setter = [](float value) { controller::InputDevice::setReticleMoveSpeed(value); };
auto preference = new SpinnerPreference("Sixense Controllers", "Reticle movement speed", getter, setter);
preference->setMin(0);
preference->setMax(100);
preference->setStep(1);
preferences->addPreference(preference);
}
{
static const QString RENDER("Graphics");
auto renderConfig = qApp->getRenderEngine()->getConfiguration();

View file

@ -15,20 +15,6 @@
namespace controller {
const float DEFAULT_HAND_RETICLE_MOVE_SPEED = 37.5f;
float InputDevice::_reticleMoveSpeed = DEFAULT_HAND_RETICLE_MOVE_SPEED;
//Constants for getCursorPixelRangeMultiplier()
const float MIN_PIXEL_RANGE_MULT = 0.4f;
const float MAX_PIXEL_RANGE_MULT = 2.0f;
const float RANGE_MULT = (MAX_PIXEL_RANGE_MULT - MIN_PIXEL_RANGE_MULT) * 0.01f;
//Returns a multiplier to be applied to the cursor range for the controllers
float InputDevice::getCursorPixelRangeMult() {
//scales (0,100) to (MINIMUM_PIXEL_RANGE_MULT, MAXIMUM_PIXEL_RANGE_MULT)
return InputDevice::_reticleMoveSpeed * RANGE_MULT + MIN_PIXEL_RANGE_MULT;
}
float InputDevice::getButton(int channel) const {
if (!_buttonPressedMap.empty()) {
if (_buttonPressedMap.find(channel) != _buttonPressedMap.end()) {

View file

@ -73,10 +73,6 @@ public:
int getDeviceID() { return _deviceID; }
void setDeviceID(int deviceID) { _deviceID = deviceID; }
static float getCursorPixelRangeMult();
static float getReticleMoveSpeed() { return _reticleMoveSpeed; }
static void setReticleMoveSpeed(float reticleMoveSpeed) { _reticleMoveSpeed = reticleMoveSpeed; }
Input makeInput(StandardButtonChannel button) const;
Input makeInput(StandardAxisChannel axis) const;
Input makeInput(StandardPoseChannel pose) const;
@ -99,9 +95,6 @@ protected:
ButtonPressedMap _buttonPressedMap;
AxisStateMap _axisStateMap;
PoseStateMap _poseStateMap;
private:
static float _reticleMoveSpeed;
};
}

View file

@ -23,6 +23,7 @@
#include <PerfStat.h>
#include <render/Scene.h>
#include <DependencyManager.h>
#include <shared/QtHelpers.h>
#include "EntityTreeRenderer.h"
#include "EntitiesRendererLogging.h"
@ -1282,3 +1283,11 @@ void RenderableModelEntityItem::mapJoints(const QStringList& modelJointNames) {
}
}
}
bool RenderableModelEntityItem::getMeshes(MeshProxyList& result) {
if (!_model || !_model->isLoaded()) {
return false;
}
BLOCKING_INVOKE_METHOD(_model.get(), "getMeshes", Q_RETURN_ARG(MeshProxyList, result));
return !result.isEmpty();
}

View file

@ -116,6 +116,8 @@ public:
return _animation;
}
bool getMeshes(MeshProxyList& result) override;
private:
QVariantMap parseTexturesToMap(QString textures);
void remapTextures();

View file

@ -1663,6 +1663,7 @@ bool RenderablePolyVoxEntityItem::getMeshes(MeshProxyList& result) {
// the mesh will be in voxel-space. transform it into object-space
meshProxy = new SimpleMeshProxy(
_mesh->map([=](glm::vec3 position){ return glm::vec3(transform * glm::vec4(position, 1.0f)); },
[=](glm::vec3 color){ return color; },
[=](glm::vec3 normal){ return glm::normalize(glm::vec3(transform * glm::vec4(normal, 0.0f))); },
[&](uint32_t index){ return index; }));
result << meshProxy;

View file

@ -1736,9 +1736,7 @@ glm::mat4 EntityScriptingInterface::getEntityTransform(const QUuid& entityID) {
if (entity) {
glm::mat4 translation = glm::translate(entity->getPosition());
glm::mat4 rotation = glm::mat4_cast(entity->getRotation());
glm::mat4 registration = glm::translate(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT -
entity->getRegistrationPoint());
result = translation * rotation * registration;
result = translation * rotation;
}
});
}
@ -1753,9 +1751,7 @@ glm::mat4 EntityScriptingInterface::getEntityLocalTransform(const QUuid& entityI
if (entity) {
glm::mat4 translation = glm::translate(entity->getLocalPosition());
glm::mat4 rotation = glm::mat4_cast(entity->getLocalOrientation());
glm::mat4 registration = glm::translate(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT -
entity->getRegistrationPoint());
result = translation * rotation * registration;
result = translation * rotation;
}
});
}

View file

@ -118,7 +118,7 @@ glm::vec3 OBJTokenizer::getVec3() {
auto z = getFloat();
auto v = glm::vec3(x, y, z);
while (isNextTokenFloat()) {
// the spec(s) get(s) vague here. might be w, might be a color... chop it off.
// ignore any following floats
nextToken();
}
return v;
@ -139,7 +139,7 @@ bool OBJTokenizer::getVertex(glm::vec3& vertex, glm::vec3& vertexColor) {
// only a single value) that it's a vertex color.
r = getFloat();
if (isNextTokenFloat()) {
// Safe to assume the following values are the green/blue components.
// Safe to assume the following values are the green/blue components.
g = getFloat();
b = getFloat();
@ -351,6 +351,8 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi
bool result = true;
int originalFaceCountForDebugging = 0;
QString currentGroup;
bool anyVertexColor { false };
int vertexCount { 0 };
setMeshPartDefaults(meshPart, QString("dontknow") + QString::number(mesh.parts.count()));
@ -412,14 +414,25 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi
#endif
}
} else if (token == "v") {
glm::vec3 vertex, vertexColor;
glm::vec3 vertex;
glm::vec3 vertexColor { glm::vec3(1.0f) };
bool hasVertexColor = tokenizer.getVertex(vertex, vertexColor);
vertices.append(vertex);
if(hasVertexColor) {
// if any vertex has color, they all need to.
if (hasVertexColor && !anyVertexColor) {
// we've had a gap of zero or more vertices without color, followed
// by one that has color. catch up:
for (int i = 0; i < vertexCount; i++) {
vertexColors.append(glm::vec3(1.0f));
}
anyVertexColor = true;
}
if (anyVertexColor) {
vertexColors.append(vertexColor);
}
vertexCount++;
} else if (token == "vn") {
normals.append(tokenizer.getVec3());
} else if (token == "vt") {

View file

@ -40,8 +40,6 @@ static QString formatFloat(double n) {
}
bool writeOBJToTextStream(QTextStream& out, QList<MeshPointer> meshes) {
int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h
// each mesh's vertices are numbered from zero. We're combining all their vertices into one list here,
// so keep track of the start index for each mesh.
QList<int> meshVertexStartOffset;
@ -49,10 +47,15 @@ bool writeOBJToTextStream(QTextStream& out, QList<MeshPointer> meshes) {
int currentVertexStartOffset = 0;
int currentNormalStartOffset = 0;
// write out vertices
// write out vertices (and maybe colors)
foreach (const MeshPointer& mesh, meshes) {
meshVertexStartOffset.append(currentVertexStartOffset);
const gpu::BufferView& vertexBuffer = mesh->getVertexBuffer();
const gpu::BufferView& colorsBufferView = mesh->getAttributeBuffer(gpu::Stream::COLOR);
gpu::BufferView::Index numColors = (gpu::BufferView::Index)colorsBufferView.getNumElements();
gpu::BufferView::Index colorIndex = 0;
int vertexCount = 0;
gpu::BufferView::Iterator<const glm::vec3> vertexItr = vertexBuffer.cbegin<const glm::vec3>();
while (vertexItr != vertexBuffer.cend<const glm::vec3>()) {
@ -60,7 +63,15 @@ bool writeOBJToTextStream(QTextStream& out, QList<MeshPointer> meshes) {
out << "v ";
out << formatFloat(v[0]) << " ";
out << formatFloat(v[1]) << " ";
out << formatFloat(v[2]) << "\n";
out << formatFloat(v[2]);
if (colorIndex < numColors) {
glm::vec3 color = colorsBufferView.get<glm::vec3>(colorIndex);
out << " " << formatFloat(color[0]);
out << " " << formatFloat(color[1]);
out << " " << formatFloat(color[2]);
colorIndex++;
}
out << "\n";
vertexItr++;
vertexCount++;
}
@ -72,7 +83,7 @@ bool writeOBJToTextStream(QTextStream& out, QList<MeshPointer> meshes) {
bool haveNormals = true;
foreach (const MeshPointer& mesh, meshes) {
meshNormalStartOffset.append(currentNormalStartOffset);
const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(attributeTypeNormal);
const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(gpu::Stream::InputSlot::NORMAL);
gpu::BufferView::Index numNormals = (gpu::BufferView::Index)normalsBufferView.getNumElements();
for (gpu::BufferView::Index i = 0; i < numNormals; i++) {
glm::vec3 normal = normalsBufferView.get<glm::vec3>(i);

View file

@ -192,7 +192,7 @@ public:
BufferView(const BufferPointer& buffer, Size offset, Size size, const Element& element = DEFAULT_ELEMENT);
BufferView(const BufferPointer& buffer, Size offset, Size size, uint16 stride, const Element& element = DEFAULT_ELEMENT);
Size getNumElements() const { return (_size - _offset) / _stride; }
Size getNumElements() const { return _size / _stride; }
//Template iterator with random access on the buffer sysmem
template<typename T>

View file

@ -11,8 +11,6 @@
#include "Geometry.h"
#include <QDebug>
using namespace model;
Mesh::Mesh() :
@ -136,11 +134,13 @@ Box Mesh::evalPartsBound(int partStart, int partEnd) const {
model::MeshPointer Mesh::map(std::function<glm::vec3(glm::vec3)> vertexFunc,
std::function<glm::vec3(glm::vec3)> colorFunc,
std::function<glm::vec3(glm::vec3)> normalFunc,
std::function<uint32_t(uint32_t)> indexFunc) {
std::function<uint32_t(uint32_t)> indexFunc) const {
// vertex data
const gpu::BufferView& vertexBufferView = getVertexBuffer();
gpu::BufferView::Index numVertices = (gpu::BufferView::Index)getNumVertices();
gpu::Resource::Size vertexSize = numVertices * sizeof(glm::vec3);
unsigned char* resultVertexData = new unsigned char[vertexSize];
unsigned char* vertexDataCursor = resultVertexData;
@ -151,6 +151,21 @@ model::MeshPointer Mesh::map(std::function<glm::vec3(glm::vec3)> vertexFunc,
vertexDataCursor += sizeof(pos);
}
// color data
int attributeTypeColor = gpu::Stream::COLOR;
const gpu::BufferView& colorsBufferView = getAttributeBuffer(attributeTypeColor);
gpu::BufferView::Index numColors = (gpu::BufferView::Index)colorsBufferView.getNumElements();
gpu::Resource::Size colorSize = numColors * sizeof(glm::vec3);
unsigned char* resultColorData = new unsigned char[colorSize];
unsigned char* colorDataCursor = resultColorData;
for (gpu::BufferView::Index i = 0; i < numColors; i++) {
glm::vec3 color = colorFunc(colorsBufferView.get<glm::vec3>(i));
memcpy(colorDataCursor, &color, sizeof(color));
colorDataCursor += sizeof(color);
}
// normal data
int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h
const gpu::BufferView& normalsBufferView = getAttributeBuffer(attributeTypeNormal);
@ -187,6 +202,12 @@ model::MeshPointer Mesh::map(std::function<glm::vec3(glm::vec3)> vertexFunc,
gpu::BufferView resultVertexBufferView(resultVertexBufferPointer, vertexElement);
result->setVertexBuffer(resultVertexBufferView);
gpu::Element colorElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ);
gpu::Buffer* resultColorsBuffer = new gpu::Buffer(colorSize, resultColorData);
gpu::BufferPointer resultColorsBufferPointer(resultColorsBuffer);
gpu::BufferView resultColorsBufferView(resultColorsBufferPointer, colorElement);
result->addAttribute(attributeTypeColor, resultColorsBufferView);
gpu::Element normalElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ);
gpu::Buffer* resultNormalsBuffer = new gpu::Buffer(normalSize, resultNormalData);
gpu::BufferPointer resultNormalsBufferPointer(resultNormalsBuffer);
@ -215,6 +236,7 @@ model::MeshPointer Mesh::map(std::function<glm::vec3(glm::vec3)> vertexFunc,
void Mesh::forEach(std::function<void(glm::vec3)> vertexFunc,
std::function<void(glm::vec3)> colorFunc,
std::function<void(glm::vec3)> normalFunc,
std::function<void(uint32_t)> indexFunc) {
// vertex data
@ -224,6 +246,14 @@ void Mesh::forEach(std::function<void(glm::vec3)> vertexFunc,
vertexFunc(vertexBufferView.get<glm::vec3>(i));
}
// color data
int attributeTypeColor = gpu::Stream::InputSlot::COLOR; // libraries/gpu/src/gpu/Stream.h
const gpu::BufferView& colorsBufferView = getAttributeBuffer(attributeTypeColor);
gpu::BufferView::Index numColors = (gpu::BufferView::Index)colorsBufferView.getNumElements();
for (gpu::BufferView::Index i = 0; i < numColors; i++) {
colorFunc(colorsBufferView.get<glm::vec3>(i));
}
// normal data
int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h
const gpu::BufferView& normalsBufferView = getAttributeBuffer(attributeTypeNormal);

View file

@ -123,10 +123,12 @@ public:
// create a copy of this mesh after passing its vertices, normals, and indexes though the provided functions
MeshPointer map(std::function<glm::vec3(glm::vec3)> vertexFunc,
std::function<glm::vec3(glm::vec3)> colorFunc,
std::function<glm::vec3(glm::vec3)> normalFunc,
std::function<uint32_t(uint32_t)> indexFunc);
std::function<uint32_t(uint32_t)> indexFunc) const;
void forEach(std::function<void(glm::vec3)> vertexFunc,
std::function<void(glm::vec3)> colorFunc,
std::function<void(glm::vec3)> normalFunc,
std::function<void(uint32_t)> indexFunc);

View file

@ -24,6 +24,7 @@
#include <PerfStat.h>
#include <ViewFrustum.h>
#include <GLMHelpers.h>
#include <model-networking/SimpleMeshProxy.h>
#include "AbstractViewStateInterface.h"
#include "MeshPartPayload.h"
@ -462,6 +463,41 @@ bool Model::convexHullContains(glm::vec3 point) {
return false;
}
MeshProxyList Model::getMeshes() const {
MeshProxyList result;
const Geometry::Pointer& renderGeometry = getGeometry();
const Geometry::GeometryMeshes& meshes = renderGeometry->getMeshes();
if (!isLoaded()) {
return result;
}
Transform offset;
offset.setScale(_scale);
offset.postTranslate(_offset);
glm::mat4 offsetMat = offset.getMatrix();
for (std::shared_ptr<const model::Mesh> mesh : meshes) {
if (!mesh) {
continue;
}
MeshProxy* meshProxy = new SimpleMeshProxy(
mesh->map(
[=](glm::vec3 position) {
return glm::vec3(offsetMat * glm::vec4(position, 1.0f));
},
[=](glm::vec3 color) { return color; },
[=](glm::vec3 normal) {
return glm::normalize(glm::vec3(offsetMat * glm::vec4(normal, 0.0f)));
},
[&](uint32_t index) { return index; }));
result << meshProxy;
}
return result;
}
void Model::calculateTriangleSets() {
PROFILE_RANGE(render, __FUNCTION__);

View file

@ -257,6 +257,8 @@ public:
int getResourceDownloadAttempts() { return _renderWatcher.getResourceDownloadAttempts(); }
int getResourceDownloadAttemptsRemaining() { return _renderWatcher.getResourceDownloadAttemptsRemaining(); }
Q_INVOKABLE MeshProxyList getMeshes() const;
public slots:
void loadURLFinished(bool success);

View file

@ -38,16 +38,22 @@ QString ModelScriptingInterface::meshToOBJ(MeshProxyList in) {
QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) {
// figure out the size of the resulting mesh
size_t totalVertexCount { 0 };
size_t totalAttributeCount { 0 };
size_t totalColorCount { 0 };
size_t totalNormalCount { 0 };
size_t totalIndexCount { 0 };
foreach (const MeshProxy* meshProxy, in) {
MeshPointer mesh = meshProxy->getMeshPointer();
totalVertexCount += mesh->getNumVertices();
int attributeTypeColor = gpu::Stream::InputSlot::COLOR; // libraries/gpu/src/gpu/Stream.h
const gpu::BufferView& colorsBufferView = mesh->getAttributeBuffer(attributeTypeColor);
gpu::BufferView::Index numColors = (gpu::BufferView::Index)colorsBufferView.getNumElements();
totalColorCount += numColors;
int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h
const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(attributeTypeNormal);
gpu::BufferView::Index numNormals = (gpu::BufferView::Index)normalsBufferView.getNumElements();
totalAttributeCount += numNormals;
totalNormalCount += numNormals;
totalIndexCount += mesh->getNumIndices();
}
@ -57,7 +63,11 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) {
unsigned char* combinedVertexData = new unsigned char[combinedVertexSize];
unsigned char* combinedVertexDataCursor = combinedVertexData;
gpu::Resource::Size combinedNormalSize = totalAttributeCount * sizeof(glm::vec3);
gpu::Resource::Size combinedColorSize = totalColorCount * sizeof(glm::vec3);
unsigned char* combinedColorData = new unsigned char[combinedColorSize];
unsigned char* combinedColorDataCursor = combinedColorData;
gpu::Resource::Size combinedNormalSize = totalNormalCount * sizeof(glm::vec3);
unsigned char* combinedNormalData = new unsigned char[combinedNormalSize];
unsigned char* combinedNormalDataCursor = combinedNormalData;
@ -74,6 +84,10 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) {
memcpy(combinedVertexDataCursor, &position, sizeof(position));
combinedVertexDataCursor += sizeof(position);
},
[&](glm::vec3 color){
memcpy(combinedColorDataCursor, &color, sizeof(color));
combinedColorDataCursor += sizeof(color);
},
[&](glm::vec3 normal){
memcpy(combinedNormalDataCursor, &normal, sizeof(normal));
combinedNormalDataCursor += sizeof(normal);
@ -96,6 +110,13 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) {
gpu::BufferView combinedVertexBufferView(combinedVertexBufferPointer, vertexElement);
result->setVertexBuffer(combinedVertexBufferView);
int attributeTypeColor = gpu::Stream::InputSlot::COLOR; // libraries/gpu/src/gpu/Stream.h
gpu::Element colorElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ);
gpu::Buffer* combinedColorsBuffer = new gpu::Buffer(combinedColorSize, combinedColorData);
gpu::BufferPointer combinedColorsBufferPointer(combinedColorsBuffer);
gpu::BufferView combinedColorsBufferView(combinedColorsBufferPointer, colorElement);
result->addAttribute(attributeTypeColor, combinedColorsBufferView);
int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h
gpu::Element normalElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ);
gpu::Buffer* combinedNormalsBuffer = new gpu::Buffer(combinedNormalSize, combinedNormalData);
@ -132,12 +153,48 @@ QScriptValue ModelScriptingInterface::transformMesh(glm::mat4 transform, MeshPro
}
model::MeshPointer result = mesh->map([&](glm::vec3 position){ return glm::vec3(transform * glm::vec4(position, 1.0f)); },
[&](glm::vec3 color){ return color; },
[&](glm::vec3 normal){ return glm::vec3(transform * glm::vec4(normal, 0.0f)); },
[&](uint32_t index){ return index; });
MeshProxy* resultProxy = new SimpleMeshProxy(result);
return meshToScriptValue(_modelScriptEngine, resultProxy);
}
QScriptValue ModelScriptingInterface::getVertexCount(MeshProxy* meshProxy) {
if (!meshProxy) {
return QScriptValue(false);
}
MeshPointer mesh = meshProxy->getMeshPointer();
if (!mesh) {
return QScriptValue(false);
}
gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices();
return numVertices;
}
QScriptValue ModelScriptingInterface::getVertex(MeshProxy* meshProxy, int vertexIndex) {
if (!meshProxy) {
return QScriptValue(false);
}
MeshPointer mesh = meshProxy->getMeshPointer();
if (!mesh) {
return QScriptValue(false);
}
const gpu::BufferView& vertexBufferView = mesh->getVertexBuffer();
gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices();
if (vertexIndex < 0 || vertexIndex >= numVertices) {
return QScriptValue(false);
}
glm::vec3 pos = vertexBufferView.get<glm::vec3>(vertexIndex);
return vec3toScriptValue(_modelScriptEngine, pos);
}
QScriptValue ModelScriptingInterface::newMesh(const QVector<glm::vec3>& vertices,
const QVector<glm::vec3>& normals,
const QVector<MeshFace>& faces) {

View file

@ -29,6 +29,8 @@ public:
Q_INVOKABLE QScriptValue newMesh(const QVector<glm::vec3>& vertices,
const QVector<glm::vec3>& normals,
const QVector<MeshFace>& faces);
Q_INVOKABLE QScriptValue getVertexCount(MeshProxy* meshProxy);
Q_INVOKABLE QScriptValue getVertex(MeshProxy* meshProxy, int vertexIndex);
private:
QScriptEngine* _modelScriptEngine { nullptr };

View file

@ -13,6 +13,8 @@
#define hifi_PathUtils_h
#include <QtCore/QObject>
#include <QtCore/QUrl>
#include "DependencyManager.h"
/**jsdoc
@ -24,6 +26,7 @@ class PathUtils : public QObject, public Dependency {
Q_OBJECT
SINGLETON_DEPENDENCY
Q_PROPERTY(QString resources READ resourcesPath)
Q_PROPERTY(QUrl defaultScripts READ defaultScriptsLocation)
public:
static const QString& resourcesPath();

View file

@ -56,6 +56,7 @@ public:
Checkbox,
Button,
ComboBox,
PrimaryHand,
// Special casing for an unusual preference
Avatar
};
@ -339,6 +340,14 @@ public:
Type getType() override { return Checkbox; }
};
class PrimaryHandPreference : public StringPreference {
Q_OBJECT
public:
PrimaryHandPreference(const QString& category, const QString& name, Getter getter, Setter setter)
: StringPreference(category, name, getter, setter) { }
Type getType() override { return PrimaryHand; }
};
#endif

View file

@ -367,6 +367,12 @@ void NeuronPlugin::init() {
auto preferences = DependencyManager::get<Preferences>();
static const QString NEURON_PLUGIN { "Perception Neuron" };
{
auto getter = [this]()->bool { return _enabled; };
auto setter = [this](bool value) { _enabled = value; saveSettings(); };
auto preference = new CheckPreference(NEURON_PLUGIN, "Enabled", getter, setter);
preferences->addPreference(preference);
}
{
auto getter = [this]()->QString { return _serverAddress; };
auto setter = [this](const QString& value) { _serverAddress = value; saveSettings(); };
@ -387,12 +393,6 @@ void NeuronPlugin::init() {
preference->setStep(1);
preferences->addPreference(preference);
}
{
auto getter = [this]()->bool { return _enabled; };
auto setter = [this](bool value) { _enabled = value; saveSettings(); };
auto preference = new CheckPreference(NEURON_PLUGIN, "Enabled", getter, setter);
preferences->addPreference(preference);
}
}
bool NeuronPlugin::isSupported() const {
@ -455,6 +455,10 @@ void NeuronPlugin::deactivate() {
}
void NeuronPlugin::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {
if (!_enabled) {
return;
}
std::vector<NeuronJoint> joints;
{
// lock and copy

View file

@ -11,8 +11,10 @@
#include <qapplication.h>
#include <PerfStat.h>
#include <controllers/UserInputMapper.h>
#include <PerfStat.h>
#include <Preferences.h>
#include <SettingHandle.h>
#include "SDL2Manager.h"
@ -38,10 +40,13 @@ static_assert(
(int)controller::RY == (int)SDL_CONTROLLER_AXIS_RIGHTY &&
(int)controller::LT == (int)SDL_CONTROLLER_AXIS_TRIGGERLEFT &&
(int)controller::RT == (int)SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
"SDL2 equvalence: Enums and values from StandardControls.h are assumed to match enums from SDL_gamecontroller.h");
"SDL2 equivalence: Enums and values from StandardControls.h are assumed to match enums from SDL_gamecontroller.h");
const char* SDL2Manager::NAME = "SDL2";
const char* SDL2Manager::SDL2_ID_STRING = "SDL2";
const bool DEFAULT_ENABLED = false;
SDL_JoystickID SDL2Manager::getInstanceId(SDL_GameController* controller) {
SDL_Joystick* joystick = SDL_GameControllerGetJoystick(controller);
@ -49,6 +54,20 @@ SDL_JoystickID SDL2Manager::getInstanceId(SDL_GameController* controller) {
}
void SDL2Manager::init() {
loadSettings();
auto preferences = DependencyManager::get<Preferences>();
static const QString SDL2_PLUGIN { "Game Controller" };
{
auto getter = [this]()->bool { return _isEnabled; };
auto setter = [this](bool value) {
_isEnabled = value;
saveSettings();
};
auto preference = new CheckPreference(SDL2_PLUGIN, "Enabled", getter, setter);
preferences->addPreference(preference);
}
bool initSuccess = (SDL_Init(SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC) == 0);
if (initSuccess) {
@ -110,6 +129,27 @@ void SDL2Manager::deactivate() {
InputPlugin::deactivate();
}
const char* SETTINGS_ENABLED_KEY = "enabled";
void SDL2Manager::saveSettings() const {
Settings settings;
QString idString = getID();
settings.beginGroup(idString);
{
settings.setValue(QString(SETTINGS_ENABLED_KEY), _isEnabled);
}
settings.endGroup();
}
void SDL2Manager::loadSettings() {
Settings settings;
QString idString = getID();
settings.beginGroup(idString);
{
_isEnabled = settings.value(SETTINGS_ENABLED_KEY, QVariant(DEFAULT_ENABLED)).toBool();
}
settings.endGroup();
}
bool SDL2Manager::isSupported() const {
return true;
@ -122,6 +162,10 @@ void SDL2Manager::pluginFocusOutEvent() {
}
void SDL2Manager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {
if (!_isEnabled) {
return;
}
if (_isInitialized) {
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
for (auto joystick : _openJoysticks) {

View file

@ -25,6 +25,7 @@ public:
// Plugin functions
bool isSupported() const override;
const QString getName() const override { return NAME; }
const QString getID() const override { return SDL2_ID_STRING; }
QStringList getSubdeviceNames() override;
@ -39,6 +40,9 @@ public:
void pluginFocusOutEvent() override;
void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override;
virtual void saveSettings() const override;
virtual void loadSettings() override;
signals:
void joystickAdded(Joystick* joystick);
void joystickRemoved(Joystick* joystick);
@ -77,8 +81,10 @@ private:
int buttonRelease() const { return SDL_RELEASED; }
QMap<SDL_JoystickID, Joystick::Pointer> _openJoysticks;
bool _isInitialized { false } ;
bool _isEnabled { false };
bool _isInitialized { false };
static const char* NAME;
static const char* SDL2_ID_STRING;
QStringList _subdeviceNames;
};

View file

@ -29,6 +29,7 @@
#include <PathUtils.h>
#include <PerfStat.h>
#include <ui-plugins/PluginContainer.h>
#include <Preferences.h>
#include <SettingHandle.h>
#include <QLoggingCategory>
@ -46,19 +47,26 @@ static const unsigned int BUTTON_TRIGGER = 1U << 8;
const glm::vec3 SixenseManager::DEFAULT_AVATAR_POSITION { -0.25f, -0.35f, -0.3f }; // in hydra frame
const float SixenseManager::CONTROLLER_THRESHOLD { 0.35f };
bool SixenseManager::_isEnabled = false;
bool SixenseManager::_sixenseLoaded = false;
#define BAIL_IF_NOT_ENABLED \
if (!_isEnabled) { \
return; \
}
#define BAIL_IF_NOT_LOADED \
if (!_sixenseLoaded) { \
return; \
}
const char* SixenseManager::NAME { "Sixense" };
const char* SixenseManager::HYDRA_ID_STRING { "Razer Hydra" };
const char* SixenseManager::SIXENSE_ID_STRING { "Sixense" };
const char* MENU_PARENT { "Developer" };
const bool DEFAULT_ENABLED = false;
const char* MENU_PARENT{ "Developer" };
const char* MENU_NAME { "Sixense" };
const char* MENU_PATH { "Developer" ">" "Sixense" };
const char* TOGGLE_SMOOTH { "Smooth Sixense Movement" };
@ -73,6 +81,22 @@ bool SixenseManager::isSupported() const {
#endif
}
void SixenseManager::init() {
loadSettings();
auto preferences = DependencyManager::get<Preferences>();
static const QString SIXENSE_PLUGIN { "Sixense Controllers" };
{
auto getter = [this]()->bool { return _isEnabled; };
auto setter = [this](bool value) {
_isEnabled = value;
saveSettings();
};
auto preference = new CheckPreference(SIXENSE_PLUGIN, "Enabled", getter, setter);
preferences->addPreference(preference);
}
}
bool SixenseManager::activate() {
InputPlugin::activate();
@ -133,6 +157,7 @@ void SixenseManager::setSixenseFilter(bool filter) {
}
void SixenseManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {
BAIL_IF_NOT_ENABLED
BAIL_IF_NOT_LOADED
#ifdef HAVE_SIXENSE
@ -553,14 +578,19 @@ QString SixenseManager::InputDevice::getDefaultMappingConfig() const {
return MAPPING_JSON;
}
const char* SETTINGS_ENABLED_KEY = "enabled";
const char* SETTINGS_AVATAR_POSITION_KEY = "avatarPosition";
const char* SETTINGS_AVATAR_ROTATION_KEY = "avatarPosition";
// virtual
void SixenseManager::saveSettings() const {
Settings settings;
QString idString = getID();
settings.beginGroup(idString);
{
settings.setVec3Value(QString("avatarPosition"), _inputDevice->_avatarPosition);
settings.setQuatValue(QString("avatarRotation"), _inputDevice->_avatarRotation);
settings.setValue(QString(SETTINGS_ENABLED_KEY), _isEnabled);
settings.setVec3Value(QString(SETTINGS_AVATAR_POSITION_KEY), _inputDevice->_avatarPosition);
settings.setQuatValue(QString(SETTINGS_AVATAR_ROTATION_KEY), _inputDevice->_avatarRotation);
}
settings.endGroup();
}
@ -570,8 +600,9 @@ void SixenseManager::loadSettings() {
QString idString = getID();
settings.beginGroup(idString);
{
settings.getVec3ValueIfValid(QString("avatarPosition"), _inputDevice->_avatarPosition);
settings.getQuatValueIfValid(QString("avatarRotation"), _inputDevice->_avatarRotation);
_isEnabled = settings.value(SETTINGS_ENABLED_KEY, QVariant(DEFAULT_ENABLED)).toBool();
settings.getVec3ValueIfValid(QString(SETTINGS_AVATAR_POSITION_KEY), _inputDevice->_avatarPosition);
settings.getQuatValueIfValid(QString(SETTINGS_AVATAR_ROTATION_KEY), _inputDevice->_avatarRotation);
}
settings.endGroup();
}

View file

@ -29,12 +29,14 @@ public:
// Plugin functions
virtual bool isSupported() const override;
virtual const QString getName() const override { return NAME; }
virtual const QString getID() const override { return HYDRA_ID_STRING; }
virtual const QString getID() const override { return SIXENSE_ID_STRING; }
// Sixense always seems to initialize even if the hydras are not present. Is there
// a way we can properly detect whether the hydras are present?
// bool isHandController() const override { return true; }
virtual void init() override;
virtual bool activate() override;
virtual void deactivate() override;
@ -93,8 +95,9 @@ private:
std::shared_ptr<InputDevice> _inputDevice { std::make_shared<InputDevice>() };
static const char* NAME;
static const char* HYDRA_ID_STRING;
static const char* SIXENSE_ID_STRING;
static bool _isEnabled;
static bool _sixenseLoaded;
};

View file

@ -1041,9 +1041,18 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp) {
function getControllerJointIndex(hand) {
if (HMD.isHandControllerAvailable()) {
return MyAvatar.getJointIndex(hand === RIGHT_HAND ?
"_CONTROLLER_RIGHTHAND" :
"_CONTROLLER_LEFTHAND");
var controllerJointIndex = -1;
if (Camera.mode === "first person") {
controllerJointIndex = MyAvatar.getJointIndex(hand === RIGHT_HAND ?
"_CONTROLLER_RIGHTHAND" :
"_CONTROLLER_LEFTHAND");
} else if (Camera.mode === "third person") {
controllerJointIndex = MyAvatar.getJointIndex(hand === RIGHT_HAND ?
"_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" :
"_CAMERA_RELATIVE_CONTROLLER_LEFTHAND");
}
return controllerJointIndex;
}
return MyAvatar.getJointIndex("Head");

View file

@ -1074,7 +1074,7 @@ function loaded() {
elDimensionsZ.addEventListener('change', dimensionsChangeFunction);
elParentID.addEventListener('change', createEmitTextPropertyUpdateFunction('parentID'));
elParentJointIndex.addEventListener('change', createEmitNumberPropertyUpdateFunction('parentJointIndex'));
elParentJointIndex.addEventListener('change', createEmitNumberPropertyUpdateFunction('parentJointIndex', 0));
var registrationChangeFunction = createEmitVec3PropertyUpdateFunction(
'registrationPoint', elRegistrationX, elRegistrationY, elRegistrationZ);

View file

@ -1560,7 +1560,6 @@ SelectionDisplay = (function() {
visible: rotationOverlaysVisible
});
// TODO: we have not implemented the rotating handle/controls yet... so for now, these handles are hidden
Overlays.editOverlay(yawHandle, {
visible: rotateHandlesVisible,
position: yawCorner,
@ -3615,24 +3614,21 @@ SelectionDisplay = (function() {
onMove: function(event) {
var pickRay = generalComputePickRay(event.x, event.y);
Overlays.editOverlay(selectionBox, {
ignoreRayIntersection: true,
visible: false
});
Overlays.editOverlay(baseOfEntityProjectionOverlay, {
ignoreRayIntersection: true,
visible: false
});
Overlays.editOverlay(rotateOverlayTarget, {
ignoreRayIntersection: false
});
var result = Overlays.findRayIntersection(pickRay);
var result = Overlays.findRayIntersection(pickRay, true, [rotateOverlayTarget]);
if (result.intersects) {
var center = yawCenter;
var zero = yawZero;
// TODO: these vectors are backwards to their names, doesn't matter for this use case (inverted vectors still give same angle)
var centerToZero = Vec3.subtract(center, zero);
var centerToIntersect = Vec3.subtract(center, result.intersection);
// TODO: orientedAngle wants normalized centerToZero and centerToIntersect
var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal);
var distanceFromCenter = Vec3.distance(center, result.intersection);
var snapToInner = distanceFromCenter < innerRadius;
@ -3785,17 +3781,12 @@ SelectionDisplay = (function() {
onMove: function(event) {
var pickRay = generalComputePickRay(event.x, event.y);
Overlays.editOverlay(selectionBox, {
ignoreRayIntersection: true,
visible: false
});
Overlays.editOverlay(baseOfEntityProjectionOverlay, {
ignoreRayIntersection: true,
visible: false
});
Overlays.editOverlay(rotateOverlayTarget, {
ignoreRayIntersection: false
});
var result = Overlays.findRayIntersection(pickRay);
var result = Overlays.findRayIntersection(pickRay, true, [rotateOverlayTarget]);
if (result.intersects) {
var properties = Entities.getEntityProperties(selectionManager.selections[0]);
@ -3947,17 +3938,12 @@ SelectionDisplay = (function() {
onMove: function(event) {
var pickRay = generalComputePickRay(event.x, event.y);
Overlays.editOverlay(selectionBox, {
ignoreRayIntersection: true,
visible: false
});
Overlays.editOverlay(baseOfEntityProjectionOverlay, {
ignoreRayIntersection: true,
visible: false
});
Overlays.editOverlay(rotateOverlayTarget, {
ignoreRayIntersection: false
});
var result = Overlays.findRayIntersection(pickRay);
var result = Overlays.findRayIntersection(pickRay, true, [rotateOverlayTarget]);
if (result.intersects) {
var properties = Entities.getEntityProperties(selectionManager.selections[0]);
@ -4074,21 +4060,8 @@ SelectionDisplay = (function() {
return false;
}
// before we do a ray test for grabbers, disable the ray intersection for our selection box
Overlays.editOverlay(selectionBox, {
ignoreRayIntersection: true
});
Overlays.editOverlay(yawHandle, {
ignoreRayIntersection: true
});
Overlays.editOverlay(pitchHandle, {
ignoreRayIntersection: true
});
Overlays.editOverlay(rollHandle, {
ignoreRayIntersection: true
});
result = Overlays.findRayIntersection(pickRay);
// ignore ray intersection for our selection box and yaw/pitch/roll
result = Overlays.findRayIntersection(pickRay, true, null, [ yawHandle, pitchHandle, rollHandle, selectionBox ] );
if (result.intersects) {
if (wantDebug) {
print("something intersects... ");
@ -4191,17 +4164,8 @@ SelectionDisplay = (function() {
}
// After testing our stretch handles, then check out rotate handles
Overlays.editOverlay(yawHandle, {
ignoreRayIntersection: false
});
Overlays.editOverlay(pitchHandle, {
ignoreRayIntersection: false
});
Overlays.editOverlay(rollHandle, {
ignoreRayIntersection: false
});
var result = Overlays.findRayIntersection(pickRay);
// Only intersect versus yaw/pitch/roll.
var result = Overlays.findRayIntersection(pickRay, true, [ yawHandle, pitchHandle, rollHandle ] );
var overlayOrientation;
var overlayCenter;
@ -4306,6 +4270,7 @@ SelectionDisplay = (function() {
});
// TODO: these three duplicate prior three, remove them.
Overlays.editOverlay(yawHandle, {
visible: false
});
@ -4402,10 +4367,8 @@ SelectionDisplay = (function() {
}
if (!somethingClicked) {
Overlays.editOverlay(selectionBox, {
ignoreRayIntersection: false
});
var result = Overlays.findRayIntersection(pickRay);
// Only intersect versus selectionBox.
var result = Overlays.findRayIntersection(pickRay, true, [selectionBox]);
if (result.intersects) {
switch (result.overlayID) {
case selectionBox:

View file

@ -23,6 +23,7 @@
#include <DependencyManager.h>
#include <SettingHandle.h>
#include <AssetUpload.h>
#include <StatTracker.h>
#include "ATPClientApp.h"
@ -137,6 +138,7 @@ ATPClientApp::ATPClientApp(int argc, char* argv[]) :
Setting::init();
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
DependencyManager::set<StatTracker>();
DependencyManager::set<AccountManager>([&]{ return QString(HIGH_FIDELITY_ATP_CLIENT_USER_AGENT); });
DependencyManager::set<AddressManager>();
DependencyManager::set<NodeList>(NodeType::Agent, _listenPort);

View file

@ -0,0 +1,56 @@
//
// gravity.js
//
// Created by Alan-Michael Moody on 7/24/17
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
(function () {
var _entityID;
this.preload = function (entityID) {
_entityID = entityID;
};
function update(deltatime) {
var planet = Entities.getEntityProperties(_entityID);
//normalization happens in rotationBetween.
var direction = Vec3.subtract(MyAvatar.position, planet.position);
var localUp = Quat.getUp(MyAvatar.orientation);
MyAvatar.orientation = Quat.normalize(Quat.multiply(Quat.rotationBetween(localUp, direction), MyAvatar.orientation));
}
function init() {
Script.update.connect(update);
}
function clean() {
Script.update.disconnect(update);
MyAvatar.orientation = Quat.fromVec3Degrees({
x: 0,
y: 0,
z: 0
});
}
var _switch = true;
this.clickDownOnEntity = function(uuid, mouseEvent) {
if (_switch) {
init();
} else {
clean();
}
_switch = !_switch;
};
Script.scriptEnding.connect(clean);
});