Merge branch 'master' of github.com:highfidelity/hifi into groups

This commit is contained in:
Seth Alves 2016-07-22 17:52:49 -07:00
commit 9a69361391
31 changed files with 1636 additions and 806 deletions

View file

@ -28,6 +28,7 @@ module.exports = {
"ModelCache": false,
"MyAvatar": false,
"Overlays": false,
"OverlayWebWindow": false,
"Paths": false,
"Quat": false,
"Rates": false,
@ -40,8 +41,10 @@ module.exports = {
"SoundCache": false,
"Stats": false,
"TextureCache": false,
"Toolbars": false,
"Uuid": false,
"UndoStack": false,
"UserActivityLogger": false,
"Vec3": false,
"WebSocket": false,
"WebWindow": false,
@ -55,6 +58,7 @@ module.exports = {
"comma-dangle": ["error", "never"],
"camelcase": ["error"],
"curly": ["error", "all"],
"eqeqeq": ["error", "always"],
"indent": ["error", 4, { "SwitchCase": 1 }],
"keyword-spacing": ["error", { "before": true, "after": true }],
"max-len": ["error", 128, 4],

View file

@ -65,6 +65,7 @@ Original.CheckBox {
colorScheme: checkBox.colorScheme
x: checkBox.boxSize / 2
wrapMode: Text.Wrap
enabled: checkBox.enabled
}
}
}

View file

@ -117,19 +117,22 @@ FocusScope {
function showList() {
var r = desktop.mapFromItem(root, 0, 0, root.width, root.height);
listView.currentIndex = root.currentIndex
scrollView.x = r.x;
scrollView.y = r.y + r.height;
var bottom = scrollView.y + scrollView.height;
var y = r.y + r.height;
var bottom = y + scrollView.height;
if (bottom > desktop.height) {
scrollView.y -= bottom - desktop.height + 8;
y -= bottom - desktop.height + 8;
}
scrollView.x = r.x;
scrollView.y = y;
popup.visible = true;
popup.forceActiveFocus();
listView.currentIndex = root.currentIndex;
scrollView.hoverEnabled = true;
}
function hideList() {
popup.visible = false;
scrollView.hoverEnabled = false;
}
FocusScope {
@ -161,6 +164,7 @@ FocusScope {
id: scrollView
height: 480
width: root.width + 4
property bool hoverEnabled: false;
style: ScrollViewStyle {
decrementControl: Item {
@ -193,7 +197,8 @@ FocusScope {
delegate: Rectangle {
width: root.width + 4
height: popupText.implicitHeight * 1.4
color: popupHover.containsMouse ? hifi.colors.primaryHighlight : (isLightColorScheme ? hifi.colors.dropDownPressedLight : hifi.colors.dropDownPressedDark)
color: (listView.currentIndex === index) ? hifi.colors.primaryHighlight :
(isLightColorScheme ? hifi.colors.dropDownPressedLight : hifi.colors.dropDownPressedDark)
FiraSansSemiBold {
anchors.left: parent.left
anchors.leftMargin: hifi.dimensions.textPadding
@ -206,9 +211,9 @@ FocusScope {
MouseArea {
id: popupHover
anchors.fill: parent;
hoverEnabled: true
hoverEnabled: scrollView.hoverEnabled;
onEntered: listView.currentIndex = index;
onClicked: popup.selectSpecificItem(index)
onClicked: popup.selectSpecificItem(index);
}
}
}

View file

@ -16,5 +16,6 @@ RalewaySemiBold {
property int colorScheme: hifi.colorSchemes.light
size: hifi.fontSizes.inputLabel
color: colorScheme == hifi.colorSchemes.light ? hifi.colors.lightGray : hifi.colors.lightGrayText
color: enabled ? (colorScheme == hifi.colorSchemes.light ? hifi.colors.lightGray : hifi.colors.lightGrayText)
: (colorScheme == hifi.colorSchemes.light ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight);
}

View file

@ -35,7 +35,7 @@ FocusScope {
}
onHeightChanged: d.handleSizeChanged();
onWidthChanged: d.handleSizeChanged();
// Controls and windows can trigger this signal to ensure the desktop becomes visible
@ -70,8 +70,8 @@ FocusScope {
}
var oldRecommendedRect = recommendedRect;
var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedOverlayRect();
var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y,
newRecommendedRectJS.width,
var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y,
newRecommendedRectJS.width,
newRecommendedRectJS.height);
var oldChildren = expectedChildren;
@ -366,8 +366,8 @@ FocusScope {
}
var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedOverlayRect();
var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y,
newRecommendedRectJS.width,
var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y,
newRecommendedRectJS.width,
newRecommendedRectJS.height);
var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height };
var newX = newRecommendedRect.x + ((newRecommendedRect.width - targetWindow.width) / 2);
@ -402,7 +402,7 @@ FocusScope {
repositionWindow(targetWindow, false, oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions);
}
function repositionWindow(targetWindow, forceReposition,
function repositionWindow(targetWindow, forceReposition,
oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions) {
if (desktop.width === 0 || desktop.height === 0) {
@ -456,6 +456,11 @@ FocusScope {
return inputDialogBuilder.createObject(desktop, properties);
}
Component { id: customInputDialogBuilder; CustomQueryDialog { } }
function customInputDialog(properties) {
return customInputDialogBuilder.createObject(desktop, properties);
}
Component { id: fileDialogBuilder; FileDialog { } }
function fileDialog(properties) {
return fileDialogBuilder.createObject(desktop, properties);
@ -487,7 +492,7 @@ FocusScope {
}
function unfocusWindows() {
// First find the active focus item, and unfocus it, all the way
// First find the active focus item, and unfocus it, all the way
// up the parent chain to the window
var currentFocus = offscreenWindow.activeFocusItem;
var targetWindow = d.getDesktopWindow(currentFocus);

View file

@ -0,0 +1,300 @@
//
// CustomQueryDialog.qml
//
// Created by Zander Otavka on 7/14/16
// Copyright 2016 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;
import QtQuick.Dialogs 1.2 as OriginalDialogs;
import "../controls-uit";
import "../styles-uit";
import "../windows";
ModalWindow {
id: root;
HifiConstants { id: hifi; }
implicitWidth: 640;
implicitHeight: 320;
visible: true;
signal selected(var result);
signal canceled();
property int icon: hifi.icons.none;
property string iconText: "";
property int iconSize: 35;
onIconChanged: updateIcon();
property var textInput;
property var comboBox;
property var checkBox;
onTextInputChanged: {
if (textInput && textInput.text !== undefined) {
textField.text = textInput.text;
}
}
onComboBoxChanged: {
if (comboBox && comboBox.index !== undefined) {
comboBoxField.currentIndex = comboBox.index;
}
}
onCheckBoxChanged: {
if (checkBox && checkBox.checked !== undefined) {
checkBoxField.checked = checkBox.checked;
}
}
property var warning: "";
property var result;
property var implicitCheckState: null;
property int titleWidth: 0;
onTitleWidthChanged: d.resize();
function updateIcon() {
if (!root) {
return;
}
iconText = hifi.glyphForIcon(root.icon);
}
function updateCheckbox() {
if (checkBox.disableForItems) {
var currentItemInDisableList = false;
for (var i in checkBox.disableForItems) {
if (comboBoxField.currentIndex === checkBox.disableForItems[i]) {
currentItemInDisableList = true;
break;
}
}
if (currentItemInDisableList) {
checkBoxField.enabled = false;
if (checkBox.checkStateOnDisable !== null && checkBox.checkStateOnDisable !== undefined) {
root.implicitCheckState = checkBoxField.checked;
checkBoxField.checked = checkBox.checkStateOnDisable;
}
root.warning = checkBox.warningOnDisable;
} else {
checkBoxField.enabled = true;
if (root.implicitCheckState !== null) {
checkBoxField.checked = root.implicitCheckState;
root.implicitCheckState = null;
}
root.warning = "";
}
}
}
Item {
clip: true;
width: pane.width;
height: pane.height;
anchors.margins: 0;
QtObject {
id: d;
readonly property int minWidth: 480;
readonly property int maxWdith: 1280;
readonly property int minHeight: 120;
readonly property int maxHeight: 720;
function resize() {
var targetWidth = Math.max(titleWidth, pane.width);
var targetHeight = (textField.visible ? textField.controlHeight + hifi.dimensions.contentSpacing.y : 0) +
(extraInputs.visible ? extraInputs.height + hifi.dimensions.contentSpacing.y : 0) +
(buttons.height + 3 * hifi.dimensions.contentSpacing.y);
root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth);
root.height = (targetHeight < d.minHeight) ? d.minHeight : ((targetHeight > d.maxHeight) ?
d.maxHeight : targetHeight);
if (checkBoxField.visible && comboBoxField.visible) {
checkBoxField.width = extraInputs.width / 2;
comboBoxField.width = extraInputs.width / 2;
} else if (!checkBoxField.visible && comboBoxField.visible) {
comboBoxField.width = extraInputs.width;
}
}
}
Item {
anchors {
top: parent.top;
bottom: extraInputs.visible ? extraInputs.top : buttons.top;
left: parent.left;
right: parent.right;
margins: 0;
bottomMargin: hifi.dimensions.contentSpacing.y;
}
// FIXME make a text field type that can be bound to a history for autocompletion
TextField {
id: textField;
label: root.textInput.label;
focus: root.textInput ? true : false;
visible: root.textInput ? true : false;
anchors {
left: parent.left;
right: parent.right;
bottom: parent.bottom;
}
}
}
Item {
id: extraInputs;
visible: Boolean(root.checkBox || root.comboBox);
anchors {
left: parent.left;
right: parent.right;
bottom: buttons.top;
bottomMargin: hifi.dimensions.contentSpacing.y;
}
height: comboBoxField.controlHeight;
onHeightChanged: d.resize();
onWidthChanged: d.resize();
CheckBox {
id: checkBoxField;
text: root.checkBox.label;
focus: Boolean(root.checkBox);
visible: Boolean(root.checkBox);
anchors {
left: parent.left;
bottom: parent.bottom;
leftMargin: 6; // Magic number to align with warning icon
}
}
ComboBox {
id: comboBoxField;
label: root.comboBox.label;
focus: Boolean(root.comboBox);
visible: Boolean(root.comboBox);
anchors {
right: parent.right;
bottom: parent.bottom;
}
model: root.comboBox ? root.comboBox.items : [];
onCurrentTextChanged: updateCheckbox();
}
}
Row {
id: buttons;
focus: true;
spacing: hifi.dimensions.contentSpacing.x;
layoutDirection: Qt.RightToLeft;
onHeightChanged: d.resize();
onWidthChanged: {
d.resize();
resizeWarningText();
}
anchors {
bottom: parent.bottom;
left: parent.left;
right: parent.right;
bottomMargin: hifi.dimensions.contentSpacing.y;
}
function resizeWarningText() {
var rowWidth = buttons.width;
var buttonsWidth = acceptButton.width + cancelButton.width + hifi.dimensions.contentSpacing.x * 2;
var warningIconWidth = warningIcon.width + hifi.dimensions.contentSpacing.x;
warningText.width = rowWidth - buttonsWidth - warningIconWidth;
}
Button {
id: cancelButton;
action: cancelAction;
}
Button {
id: acceptButton;
action: acceptAction;
}
Text {
id: warningText;
visible: Boolean(root.warning);
text: root.warning;
wrapMode: Text.WordWrap;
font.italic: true;
maximumLineCount: 2;
}
HiFiGlyphs {
id: warningIcon;
visible: Boolean(root.warning);
text: hifi.glyphs.alert;
size: hifi.dimensions.controlLineHeight;
}
}
Action {
id: cancelAction;
text: qsTr("Cancel");
shortcut: Qt.Key_Escape;
onTriggered: {
root.result = null;
root.canceled();
root.destroy();
}
}
Action {
id: acceptAction;
text: qsTr("Add");
shortcut: Qt.Key_Return;
onTriggered: {
var result = {};
if (textInput) {
result.textInput = textField.text;
}
if (comboBox) {
result.comboBox = comboBoxField.currentIndex;
result.comboBoxText = comboBoxField.currentText;
}
if (checkBox) {
result.checkBox = checkBoxField.enabled ? checkBoxField.checked : null;
}
root.result = JSON.stringify(result);
root.selected(root.result);
root.destroy();
}
}
}
Keys.onPressed: {
if (!visible) {
return;
}
switch (event.key) {
case Qt.Key_Escape:
case Qt.Key_Back:
cancelAction.trigger();
event.accepted = true;
break;
case Qt.Key_Return:
case Qt.Key_Enter:
acceptAction.trigger();
event.accepted = true;
break;
}
}
Component.onCompleted: {
updateIcon();
d.resize();
textField.forceActiveFocus();
}
}

View file

@ -4715,6 +4715,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
scriptEngine->registerGlobalObject("Toolbars", DependencyManager::get<ToolbarScriptingInterface>().data());
scriptEngine->registerGlobalObject("Window", DependencyManager::get<WindowScriptingInterface>().data());
qScriptRegisterMetaType(scriptEngine, CustomPromptResultToScriptValue, CustomPromptResultFromScriptValue);
scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,
LocationScriptingInterface::locationSetter, "Window");
// register `location` on the global object.

View file

@ -29,6 +29,20 @@ static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStanda
static const QString LAST_BROWSE_LOCATION_SETTING = "LastBrowseLocation";
QScriptValue CustomPromptResultToScriptValue(QScriptEngine* engine, const CustomPromptResult& result) {
if (!result.value.isValid()) {
return QScriptValue::UndefinedValue;
}
Q_ASSERT(result.value.userType() == qMetaTypeId<QVariantMap>());
return engine->toScriptValue(result.value.toMap());
}
void CustomPromptResultFromScriptValue(const QScriptValue& object, CustomPromptResult& result) {
result.value = object.toVariant();
}
WindowScriptingInterface::WindowScriptingInterface() {
const DomainHandler& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
connect(&domainHandler, &DomainHandler::connectedToDomain, this, &WindowScriptingInterface::domainChanged);
@ -95,6 +109,14 @@ QScriptValue WindowScriptingInterface::prompt(const QString& message, const QStr
return ok ? QScriptValue(result) : QScriptValue::NullValue;
}
CustomPromptResult WindowScriptingInterface::customPrompt(const QVariant& config) {
CustomPromptResult result;
bool ok = false;
auto configMap = config.toMap();
result.value = OffscreenUi::getCustomInfo(OffscreenUi::ICON_NONE, "", configMap, &ok);
return ok ? result : CustomPromptResult();
}
QString fixupPathForMac(const QString& directory) {
// On OS X `directory` does not work as expected unless a file is included in the path, so we append a bogus
// filename if the directory is valid.

View file

@ -18,6 +18,18 @@
class WebWindowClass;
class CustomPromptResult {
public:
QVariant value;
};
Q_DECLARE_METATYPE(CustomPromptResult);
QScriptValue CustomPromptResultToScriptValue(QScriptEngine* engine, const CustomPromptResult& result);
void CustomPromptResultFromScriptValue(const QScriptValue& object, CustomPromptResult& result);
class WindowScriptingInterface : public QObject, public Dependency {
Q_OBJECT
Q_PROPERTY(int innerWidth READ getInnerWidth)
@ -38,6 +50,7 @@ public slots:
void alert(const QString& message = "");
QScriptValue confirm(const QString& message = "");
QScriptValue prompt(const QString& message = "", const QString& defaultText = "");
CustomPromptResult customPrompt(const QVariant& config);
QScriptValue browse(const QString& title = "", const QString& directory = "", const QString& nameFilter = "");
QScriptValue save(const QString& title = "", const QString& directory = "", const QString& nameFilter = "");
void copyToClipboard(const QString& text);

View file

@ -700,11 +700,12 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
}
info.setParams(type, dimensions, _compoundShapeURL);
} else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) {
updateModelBounds();
// should never fall in here when model not fully loaded
assert(_model && _model->isLoaded());
updateModelBounds();
_model->updateGeometry();
// compute meshPart local transforms
QVector<glm::mat4> localTransforms;
const FBXGeometry& fbxGeometry = _model->getFBXGeometry();

View file

@ -1211,11 +1211,21 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper
void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) const {
// a TerseUpdate includes the transform and its derivatives
properties._position = getLocalPosition();
properties._velocity = getLocalVelocity();
properties._rotation = getLocalOrientation();
properties._angularVelocity = getLocalAngularVelocity();
properties._acceleration = _acceleration;
if (!properties._positionChanged) {
properties._position = getLocalPosition();
}
if (!properties._velocityChanged) {
properties._velocity = getLocalVelocity();
}
if (!properties._rotationChanged) {
properties._rotation = getLocalOrientation();
}
if (!properties._angularVelocityChanged) {
properties._angularVelocity = getLocalAngularVelocity();
}
if (!properties._accelerationChanged) {
properties._acceleration = _acceleration;
}
properties._positionChanged = true;
properties._velocityChanged = true;

View file

@ -723,13 +723,10 @@ void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList<Q
int index = changedProperties.indexOf("velocity");
if (index >= 0) {
glm::vec3 value = properties.getVelocity();
QString changeHint = "0";
if (value.x + value.y + value.z > 0) {
changeHint = "+";
} else if (value.x + value.y + value.z < 0) {
changeHint = "-";
}
changedProperties[index] = QString("velocity:") + changeHint;
changedProperties[index] = QString("velocity:") +
QString::number((int)value.x) + "," +
QString::number((int)value.y) + "," +
QString::number((int)value.z);
}
}

View file

@ -88,6 +88,7 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) {
motionState->updateBodyVelocities();
motionState->updateLastKinematicStep();
body->setSleepingThresholds(KINEMATIC_LINEAR_SPEED_THRESHOLD, KINEMATIC_ANGULAR_SPEED_THRESHOLD);
motionState->clearInternalKinematicChanges();
break;
}
case MOTION_TYPE_DYNAMIC: {

View file

@ -69,7 +69,6 @@ static const btVector3 _unitSphereDirections[NUM_UNIT_SPHERE_DIRECTIONS] = {
// util method
btConvexHullShape* createConvexHull(const ShapeInfo::PointList& points) {
//std::cout << "adebug createConvexHull() points.size() = " << points.size() << std::endl; // adebug
assert(points.size() > 0);
btConvexHullShape* hull = new btConvexHullShape();
@ -241,7 +240,6 @@ void deleteStaticMeshArray(btTriangleIndexVertexArray* dataArray) {
btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) {
btCollisionShape* shape = NULL;
int type = info.getType();
//std::cout << "adebug createShapeFromInfo() type = " << type << std::endl; // adebug
switch(type) {
case SHAPE_TYPE_BOX: {
shape = new btBoxShape(glmToBullet(info.getHalfExtents()));

View file

@ -84,6 +84,7 @@ public:
bool readyToAddToScene(RenderArgs* renderArgs = nullptr) const {
return !_needsReload && isRenderable() && isActive();
}
bool needsReload() const { return _needsReload; }
bool initWhenReady(render::ScenePointer scene);
bool addToScene(std::shared_ptr<render::Scene> scene,
render::PendingChanges& pendingChanges,
@ -232,6 +233,9 @@ public:
const glm::vec3& getRegistrationPoint() const { return _registrationPoint; }
// returns 'true' if needs fullUpdate after geometry change
bool updateGeometry();
protected:
void setPupilDilation(float dilation) { _pupilDilation = dilation; }
@ -297,9 +301,6 @@ protected:
std::unordered_set<int> _cauterizeBoneSet;
bool _cauterizeBones;
// returns 'true' if needs fullUpdate after geometry change
bool updateGeometry();
virtual void initJointStates();
void setScaleInternal(const glm::vec3& scale);

View file

@ -343,6 +343,23 @@ QString OffscreenUi::getItem(const Icon icon, const QString& title, const QStrin
return result.toString();
}
QVariant OffscreenUi::getCustomInfo(const Icon icon, const QString& title, const QVariantMap& config, bool* ok) {
if (ok) {
*ok = false;
}
QVariant result = DependencyManager::get<OffscreenUi>()->customInputDialog(icon, title, config);
if (result.isValid()) {
// We get a JSON encoded result, so we unpack it into a QVariant wrapping a QVariantMap
result = QVariant(QJsonDocument::fromJson(result.toString().toUtf8()).object().toVariantMap());
if (ok) {
*ok = true;
}
}
return result;
}
QVariant OffscreenUi::inputDialog(const Icon icon, const QString& title, const QString& label, const QVariant& current) {
if (QThread::currentThread() != thread()) {
QVariant result;
@ -358,6 +375,20 @@ QVariant OffscreenUi::inputDialog(const Icon icon, const QString& title, const Q
return waitForInputDialogResult(createInputDialog(icon, title, label, current));
}
QVariant OffscreenUi::customInputDialog(const Icon icon, const QString& title, const QVariantMap& config) {
if (QThread::currentThread() != thread()) {
QVariant result;
QMetaObject::invokeMethod(this, "customInputDialog", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(QVariant, result),
Q_ARG(Icon, icon),
Q_ARG(QString, title),
Q_ARG(QVariantMap, config));
return result;
}
return waitForInputDialogResult(createCustomInputDialog(icon, title, config));
}
void OffscreenUi::togglePinned() {
bool invokeResult = QMetaObject::invokeMethod(_desktop, "togglePinned");
if (!invokeResult) {
@ -401,6 +432,23 @@ QQuickItem* OffscreenUi::createInputDialog(const Icon icon, const QString& title
return qvariant_cast<QQuickItem*>(result);
}
QQuickItem* OffscreenUi::createCustomInputDialog(const Icon icon, const QString& title, const QVariantMap& config) {
QVariantMap map = config;
map.insert("title", title);
map.insert("icon", icon);
QVariant result;
bool invokeResult = QMetaObject::invokeMethod(_desktop, "customInputDialog",
Q_RETURN_ARG(QVariant, result),
Q_ARG(QVariant, QVariant::fromValue(map)));
if (!invokeResult) {
qWarning() << "Failed to create custom message box";
return nullptr;
}
return qvariant_cast<QQuickItem*>(result);
}
QVariant OffscreenUi::waitForInputDialogResult(QQuickItem* inputDialog) {
if (!inputDialog) {
return QVariant();

View file

@ -122,7 +122,9 @@ public:
static QString getSaveFileName(void* ignored, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0);
Q_INVOKABLE QVariant inputDialog(const Icon icon, const QString& title, const QString& label = QString(), const QVariant& current = QVariant());
Q_INVOKABLE QVariant customInputDialog(const Icon icon, const QString& title, const QVariantMap& config);
QQuickItem* createInputDialog(const Icon icon, const QString& title, const QString& label, const QVariant& current);
QQuickItem* createCustomInputDialog(const Icon icon, const QString& title, const QVariantMap& config);
QVariant waitForInputDialogResult(QQuickItem* inputDialog);
// Compatibility with QInputDialog::getText
@ -140,6 +142,7 @@ public:
static QString getText(const Icon icon, const QString & title, const QString & label, const QString & text = QString(), bool * ok = 0);
static QString getItem(const Icon icon, const QString & title, const QString & label, const QStringList & items, int current = 0, bool editable = true, bool * ok = 0);
static QVariant getCustomInfo(const Icon icon, const QString& title, const QVariantMap& config, bool* ok = 0);
unsigned int getMenuUserDataId() const;

View file

@ -15,7 +15,7 @@ Script.load("system/users.js");
Script.load("system/mute.js");
Script.load("system/goto.js");
Script.load("system/hmd.js");
Script.load("system/examples.js");
Script.load("system/marketplace.js");
Script.load("system/edit.js");
Script.load("system/ignore.js");
Script.load("system/selectAudioDevice.js");

View file

@ -1915,7 +1915,9 @@ function MyController(hand) {
var handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand");
var reparentProps = {
parentID: MyAvatar.sessionUUID,
parentJointIndex: handJointIndex
parentJointIndex: handJointIndex,
velocity: {x: 0, y: 0, z: 0},
angularVelocity: {x: 0, y: 0, z: 0}
};
if (hasPresetPosition) {
reparentProps["localPosition"] = this.offsetPosition;

File diff suppressed because it is too large Load diff

View file

@ -1,79 +0,0 @@
//
// examples.js
// examples
//
// Created by Eric Levin on 8 Jan 2016
// Copyright 2016 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
//
var toolIconUrl = Script.resolvePath("assets/images/tools/");
var EXAMPLES_URL = "https://metaverse.highfidelity.com/examples";
var examplesWindow = new OverlayWebWindow({
title: 'Examples',
source: "about:blank",
width: 900,
height: 700,
visible: false
});
var toolHeight = 50;
var toolWidth = 50;
var TOOLBAR_MARGIN_Y = 0;
function showExamples(marketplaceID) {
var url = EXAMPLES_URL;
if (marketplaceID) {
url = url + "/items/" + marketplaceID;
}
print("setting examples URL to " + url);
examplesWindow.setURL(url);
examplesWindow.setVisible(true);
UserActivityLogger.openedMarketplace();
}
function hideExamples() {
examplesWindow.setVisible(false);
examplesWindow.setURL("about:blank");
}
function toggleExamples() {
if (examplesWindow.visible) {
hideExamples();
} else {
showExamples();
}
}
var toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
var browseExamplesButton = toolBar.addButton({
imageURL: toolIconUrl + "market.svg",
objectName: "examples",
buttonState: 1,
defaultState: 1,
hoverState: 3,
alpha: 0.9
});
function onExamplesWindowVisibilityChanged() {
browseExamplesButton.writeProperty('buttonState', examplesWindow.visible ? 0 : 1);
browseExamplesButton.writeProperty('defaultState', examplesWindow.visible ? 0 : 1);
browseExamplesButton.writeProperty('hoverState', examplesWindow.visible ? 2 : 3);
}
function onClick() {
toggleExamples();
}
browseExamplesButton.clicked.connect(onClick);
examplesWindow.visibleChanged.connect(onExamplesWindowVisibilityChanged);
Script.scriptEnding.connect(function () {
toolBar.removeButton("examples");
browseExamplesButton.clicked.disconnect(onClick);
examplesWindow.visibleChanged.disconnect(onExamplesWindowVisibilityChanged);
});

View file

@ -0,0 +1,77 @@
//
// marketplace.js
//
// Created by Eric Levin on 8 Jan 2016
// Copyright 2016 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
//
var toolIconUrl = Script.resolvePath("assets/images/tools/");
var MARKETPLACE_URL = "https://metaverse.highfidelity.com/marketplace";
var marketplaceWindow = new OverlayWebWindow({
title: "Marketplace",
source: "about:blank",
width: 900,
height: 700,
visible: false
});
var toolHeight = 50;
var toolWidth = 50;
var TOOLBAR_MARGIN_Y = 0;
function showMarketplace(marketplaceID) {
var url = MARKETPLACE_URL;
if (marketplaceID) {
url = url + "/items/" + marketplaceID;
}
marketplaceWindow.setURL(url);
marketplaceWindow.setVisible(true);
UserActivityLogger.openedMarketplace();
}
function hideMarketplace() {
marketplaceWindow.setVisible(false);
marketplaceWindow.setURL("about:blank");
}
function toggleMarketplace() {
if (marketplaceWindow.visible) {
hideMarketplace();
} else {
showMarketplace();
}
}
var toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
var browseExamplesButton = toolBar.addButton({
imageURL: toolIconUrl + "market.svg",
objectName: "marketplace",
buttonState: 1,
defaultState: 1,
hoverState: 3,
alpha: 0.9
});
function onExamplesWindowVisibilityChanged() {
browseExamplesButton.writeProperty('buttonState', marketplaceWindow.visible ? 0 : 1);
browseExamplesButton.writeProperty('defaultState', marketplaceWindow.visible ? 0 : 1);
browseExamplesButton.writeProperty('hoverState', marketplaceWindow.visible ? 2 : 3);
}
function onClick() {
toggleMarketplace();
}
browseExamplesButton.clicked.connect(onClick);
marketplaceWindow.visibleChanged.connect(onExamplesWindowVisibilityChanged);
Script.scriptEnding.connect(function () {
toolBar.removeButton("marketplace");
browseExamplesButton.clicked.disconnect(onClick);
marketplaceWindow.visibleChanged.disconnect(onExamplesWindowVisibilityChanged);
});

View file

@ -35,8 +35,6 @@
var tiltMazePath = Script.resolvePath("atp:/tiltMaze/wrapper.js")
var whiteboardPath = Script.resolvePath("atp:/whiteboard/wrapper.js");
var cuckooClockPath = Script.resolvePath("atp:/cuckooClock/wrapper.js");
var pingPongGunPath = Script.resolvePath("atp:/pingPongGun/wrapper.js");
@ -51,7 +49,6 @@
Script.include(fishTankPath);
Script.include(tiltMazePath);
Script.include(whiteboardPath);
Script.include(cuckooClockPath);
Script.include(pingPongGunPath);
Script.include(transformerPath);
@ -201,6 +198,7 @@
Script.setTimeout(function() {
_this.createKineticEntities();
_this.createScriptedEntities();
_this.createWhiteboard();
_this.setupDressingRoom();
_this.createMilkPailBalls();
_this.createTarget();
@ -296,6 +294,21 @@
print('HOME after deleting home entities');
},
createWhiteboard: function() {
var WHITEBOARD_URL = "atp:/whiteboard/whiteboardWithSwiper.json"
var success = Clipboard.importEntities(WHITEBOARD_URL);
if (success === true) {
created = Clipboard.pasteEntities({
x: 1105.0955,
y: 460.5000,
z: -77.4409
})
print('created ' + created);
} else {
print('failed to import whiteboard');
}
},
createScriptedEntities: function() {
var fishTank = new FishTank({
x: 1099.2200,
@ -313,16 +326,6 @@
z: -80.4891
});
var whiteboard = new Whiteboard({
x: 1105.0955,
y: 460.5000,
z: -77.4409
}, {
x: -0.0013,
y: -133.0056,
z: -0.0013
});
var pingPongGun = new HomePingPongGun({
x: 1101.2123,
y: 460.2328,

View file

@ -1,128 +1,59 @@
//
// eraserEntityScript.js
// examples/homeContent/eraserEntityScript
//
// Created by Eric Levin on 2/17/15.
// Additions by James B. Pollack @imgntn 6/9/2016
// Copyright 2016 High Fidelity, Inc.
//
// This entity script provides logic for an object with attached script to erase nearby marker strokes
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
(function() {
Script.include('../utils.js');
var TRIGGER_CONTROLS = [
Controller.Standard.LT,
Controller.Standard.RT,
];
Script.include('atp:/whiteboard/utils.js');
var _this;
Eraser = function() {
_this = this;
_this.ERASER_TRIGGER_THRESHOLD = 0.2;
_this.STROKE_NAME = "home_polyline_markerStroke";
_this.ERASER_TO_STROKE_SEARCH_RADIUS = 0.7;
_this.ERASER_RESET_WAIT_TIME = 3000;
_this.STROKE_NAME = "hifi_polyline_markerStroke";
_this.ERASER_TO_STROKE_SEARCH_RADIUS = 0.1;
};
Eraser.prototype = {
startEquip: function(id, params) {
_this.equipped = true;
_this.hand = params[0] == "left" ? 0 : 1;
// We really only need to grab position of marker strokes once, and then just check to see if eraser comes near enough to those strokes
Overlays.editOverlay(_this.searchSphere, {
visible: true
});
},
continueEquip: function() {
continueNearGrab: function() {
_this.eraserPosition = Entities.getEntityProperties(_this.entityID, "position").position;
Overlays.editOverlay(_this.searchSphere, {
position: _this.eraserPosition
});
this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]);
if (_this.triggerValue > _this.ERASER_TRIGGER_THRESHOLD) {
_this.continueHolding();
}
_this.continueHolding();
},
continueHolding: function() {
var strokeIDs = Entities.findEntities(_this.eraserPosition, _this.ERASER_TO_STROKE_SEARCH_RADIUS);
var results = Entities.findEntities(_this.eraserPosition, _this.ERASER_TO_STROKE_SEARCH_RADIUS);
// Create a map of stroke entities and their positions
strokeIDs.forEach(function(strokeID) {
var strokeProps = Entities.getEntityProperties(strokeID, ["position", "name"]);
if (strokeProps.name === _this.STROKE_NAME && Vec3.distance(_this.eraserPosition, strokeProps.position) < _this.ERASER_TO_STROKE_SEARCH_RADIUS) {
Entities.deleteEntity(strokeID);
results.forEach(function(stroke) {
var props = Entities.getEntityProperties(stroke, ["position", "name"]);
if (props.name === _this.STROKE_NAME && Vec3.distance(_this.eraserPosition, props.position) < _this.ERASER_TO_STROKE_SEARCH_RADIUS) {
Entities.deleteEntity(stroke);
}
});
},
releaseEquip: function() {
Overlays.editOverlay(_this.searchSphere, {
visible: false
});
// Once user releases eraser, wait a bit then put marker back to its original position and rotation
// Script.setTimeout(function() {
// var userData = getEntityUserData(_this.entityID);
// Entities.editEntity(_this.entityID, {
// position: userData.originalPosition,
// rotation: userData.originalRotation,
// velocity: {
// x: 0,
// y: -0.01,
// z: 0
// }
// });
// }, _this.ERASER_RESET_WAIT_TIME);
},
collisionWithEntity: function(myID, otherID, collision) {
var otherProps = Entities.getEntityProperties(otherID);
if (otherProps.name === 'home_model_homeset') {
var userData = getEntityUserData(_this.entityID);
Entities.editEntity(_this.entityID, {
position: userData.originalPosition,
rotation: userData.originalRotation,
velocity: {
x: 0,
y: -0.01,
z: 0
},
angularVelocity: {
x: 0,
y: 0,
z: 0
}
});
}
},
preload: function(entityID) {
_this.entityID = entityID;
_this.searchSphere = Overlays.addOverlay('sphere', {
size: _this.ERASER_TO_STROKE_SEARCH_RADIUS,
color: {
red: 200,
green: 10,
blue: 10
},
alpha: 0.2,
solid: true,
visible: false
})
},
unload: function() {
Overlays.deleteOverlay(_this.searchSphere);
}
startEquip: function() {
_this.startNearGrab();
},
continueEquip: function() {
_this.continueNearGrab();
},
};
// entity scripts always need to return a newly constructed object of our type
return new Eraser();
});

View file

@ -1,8 +1,8 @@
//
// markerTipEntityScript.js
// examples/homeContent/markerTipEntityScript
//
// Created by Eric Levin on 2/17/15.
// Additions by James B. Pollack @imgntn 6/9/2016
// Copyright 2016 High Fidelity, Inc.
//
// This script provides the logic for an object to draw marker strokes on its associated whiteboard
@ -10,15 +10,9 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
(function() {
Script.include('../utils.js');
var TRIGGER_CONTROLS = [
Controller.Standard.LT,
Controller.Standard.RT,
];
Script.include('atp:/whiteboard/utils.js');
var MAX_POINTS_PER_STROKE = 40;
var _this;
@ -31,95 +25,74 @@
min: 0.002,
max: 0.01
};
_this.MAX_MARKER_TO_BOARD_DISTANCE = 1.4;
_this.MIN_DISTANCE_BETWEEN_POINTS = 0.002;
_this.MAX_DISTANCE_BETWEEN_POINTS = 0.1;
_this.strokes = [];
_this.PAINTING_TRIGGER_THRESHOLD = 0.2;
_this.STROKE_NAME = "home_polyline_markerStroke";
_this.WHITEBOARD_SURFACE_NAME = "home_box_whiteboardDrawingSurface"
_this.MARKER_RESET_WAIT_TIME = 3000;
_this.STROKE_NAME = "hifi_polyline_markerStroke";
_this.WHITEBOARD_SURFACE_NAME = "hifi-whiteboardDrawingSurface"
};
MarkerTip.prototype = {
startEquip: function(id, params) {
print('start equip')
startNearGrab: function() {
_this.whiteboards = [];
_this.equipped = true;
_this.hand = params[0] == "left" ? 0 : 1;
_this.markerColor = getEntityUserData(_this.entityID).markerColor;
// search for whiteboards
var markerPosition = Entities.getEntityProperties(_this.entityID, "position").position;
var entities = Entities.findEntities(markerPosition, 10);
entities.forEach(function(entity) {
var markerProps = Entities.getEntityProperties(_this.entityID);
_this.DRAW_ON_BOARD_DISTANCE = markerProps.dimensions.z / 2;
var markerPosition = markerProps.position;
var results = Entities.findEntities(markerPosition, 5);
results.forEach(function(entity) {
var entityName = Entities.getEntityProperties(entity, "name").name;
if (entityName === _this.WHITEBOARD_SURFACE_NAME) {
_this.whiteboards.push(entity);
}
});
},
releaseEquip: function() {
releaseGrab: function() {
_this.resetStroke();
Overlays.editOverlay(_this.laserPointer, {
visible: false
});
},
collisionWithEntity: function(myID, otherID, collision) {
var otherProps = Entities.getEntityProperties(otherID);
if (otherProps.name === 'home_model_homeset') {
var userData = getEntityUserData(_this.entityID);
Entities.editEntity(_this.entityID, {
position: userData.originalPosition,
rotation: userData.originalRotation,
velocity: {
x: 0,
y: -0.01,
z: 0
},
angularVelocity: {x: 0, y: 0, z: 0}
})
}
},
continueEquip: function() {
continueNearGrab: function() {
// cast a ray from marker and see if it hits anything
var markerProps = Entities.getEntityProperties(_this.entityID, ["position", "rotation"]);
var markerProps = Entities.getEntityProperties(_this.entityID);
//need to back up the ray to the back of the marker
var markerFront = Quat.getFront(markerProps.rotation);
var howFarBack = markerProps.dimensions.z / 2;
var pulledBack = Vec3.multiply(markerFront, -howFarBack);
var backedOrigin = Vec3.sum(markerProps.position, pulledBack);
var pickRay = {
origin: markerProps.position,
origin: backedOrigin,
direction: Quat.getFront(markerProps.rotation)
}
var intersection = Entities.findRayIntersectionBlocking(pickRay, true, _this.whiteboards);
var intersection = Entities.findRayIntersection(pickRay, true, _this.whiteboards);
if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) < _this.MAX_MARKER_TO_BOARD_DISTANCE) {
if (intersection.intersects && Vec3.distance(intersection.intersection, markerProps.position) <= _this.DRAW_ON_BOARD_DISTANCE) {
_this.currentWhiteboard = intersection.entityID;
var whiteboardRotation = Entities.getEntityProperties(_this.currentWhiteboard, "rotation").rotation;
_this.whiteboardNormal = Quat.getFront(whiteboardRotation);
Overlays.editOverlay(_this.laserPointer, {
visible: true,
position: intersection.intersection,
rotation: whiteboardRotation
})
_this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[_this.hand]);
if (_this.triggerValue > _this.PAINTING_TRIGGER_THRESHOLD) {
_this.paint(intersection.intersection)
} else {
_this.resetStroke();
}
_this.paint(intersection.intersection)
} else {
if (_this.currentStroke) {
_this.resetStroke();
}
Overlays.editOverlay(_this.laserPointer, {
visible: false
});
}
},
startEquip: function() {
_this.startNearGrab();
},
continueEquip: function() {
_this.continueNearGrab();
},
newStroke: function(position) {
@ -135,12 +108,7 @@
position: position,
textures: _this.MARKER_TEXTURE_URL,
color: _this.markerColor,
lifetime: 5000,
userData: JSON.stringify({
'hifiHomeKey': {
'reset': true
}
}),
lifetime: 5000
});
_this.linePoints = [];
@ -170,7 +138,8 @@
_this.normals.push(_this.whiteboardNormal);
var strokeWidths = [];
for (var i = 0; i < _this.linePoints.length; i++) {
var i;
for (i = 0; i < _this.linePoints.length; i++) {
// Create a temp array of stroke widths for calligraphy effect - start and end should be less wide
var pointsFromCenter = Math.abs(_this.linePoints.length / 2 - i);
var pointWidth = map(pointsFromCenter, 0, this.linePoints.length / 2, _this.STROKE_WIDTH_RANGE.max, this.STROKE_WIDTH_RANGE.min);
@ -191,6 +160,7 @@
_this.oldPosition = position;
}
},
resetStroke: function() {
Entities.editEntity(_this.currentStroke, {
@ -203,26 +173,9 @@
preload: function(entityID) {
this.entityID = entityID;
_this.laserPointer = Overlays.addOverlay("circle3d", {
color: {
red: 220,
green: 35,
blue: 53
},
solid: true,
size: 0.01,
});
},
unload: function() {
Overlays.deleteOverlay(_this.laserPointer);
_this.strokes.forEach(function(stroke) {
Entities.deleteEntity(stroke);
});
}
};
// entity scripts always need to return a newly constructed object of our type
return new MarkerTip();
});

View file

@ -1,23 +0,0 @@
//
//
// Created by The Content Team 4/10/216
// Copyright 2016 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
//
var whiteboardPath = Script.resolvePath('wrapper.js');
Script.include(whiteboardPath);
var whiteboard = new Whiteboard({
x: 1104,
y: 460.5,
z: -77
}, {
x: 0,
y: -133,
z: 0
});

View file

@ -0,0 +1,62 @@
// Created by James B. Pollack @imgntn 6/8/2016
// Copyright 2016 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 _this;
Swiper = function() {
_this = this;
}
Swiper.prototype = {
busy: false,
preload: function(entityID) {
this.entityID = entityID;
Script.update.connect(this.update);
},
clickReleaseOnEntity: function() {
this.createSupplies();
},
update: function() {
if (_this.busy === true) {
return;
}
var position = Entities.getEntityProperties(_this.entityID).position;
var TRIGGER_THRESHOLD = 0.11;
var leftHandPosition = MyAvatar.getLeftPalmPosition();
var rightHandPosition = MyAvatar.getRightPalmPosition();
var leftDistance = Vec3.distance(leftHandPosition, position)
var rightDistance = Vec3.distance(rightHandPosition, position)
if (rightDistance < TRIGGER_THRESHOLD || leftDistance < TRIGGER_THRESHOLD) {
_this.createSupplies();
_this.busy = true;
Script.setTimeout(function() {
_this.busy = false;
}, 2000)
}
},
createSupplies: function() {
var myProperties = Entities.getEntityProperties(this.entityID);
Entities.callEntityMethod(myProperties.parentID, "createMarkers");
Entities.callEntityMethod(myProperties.parentID, "createEraser");
},
unload: function() {
Script.update.disconnect(this.update);
}
}
return new Swiper
})

View file

@ -0,0 +1,347 @@
//
// Created by Bradley Austin Davis on 2015/08/29
// Copyright 2015 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
//
map = function(value, min1, max1, min2, max2) {
return min2 + (max2 - min2) * ((value - min1) / (max1 - min1));
}
vec3toStr = function(v, digits) {
if (!digits) {
digits = 3;
}
return "{ " + v.x.toFixed(digits) + ", " + v.y.toFixed(digits) + ", " + v.z.toFixed(digits) + " }";
}
quatToStr = function(q, digits) {
if (!digits) {
digits = 3;
}
return "{ " + q.w.toFixed(digits) + ", " + q.x.toFixed(digits) + ", " +
q.y.toFixed(digits) + ", " + q.z.toFixed(digits) + " }";
}
vec3equal = function(v0, v1) {
return (v0.x == v1.x) && (v0.y == v1.y) && (v0.z == v1.z);
}
colorMix = function(colorA, colorB, mix) {
var result = {};
for (var key in colorA) {
result[key] = (colorA[key] * (1 - mix)) + (colorB[key] * mix);
}
return result;
}
scaleLine = function(start, end, scale) {
var v = Vec3.subtract(end, start);
var length = Vec3.length(v);
v = Vec3.multiply(scale, v);
return Vec3.sum(start, v);
}
findAction = function(name) {
return Controller.findAction(name);
}
addLine = function(origin, vector, color) {
if (!color) {
color = COLORS.WHITE
}
return Entities.addEntity(mergeObjects(LINE_PROTOTYPE, {
position: origin,
linePoints: [
ZERO_VECTOR,
vector,
],
color: color
}));
}
// FIXME fetch from a subkey of user data to support non-destructive modifications
setEntityUserData = function(id, data) {
var json = JSON.stringify(data)
Entities.editEntity(id, {
userData: json
});
}
// FIXME do non-destructive modification of the existing user data
getEntityUserData = function(id) {
var results = null;
var properties = Entities.getEntityProperties(id, "userData");
if (properties.userData) {
try {
results = JSON.parse(properties.userData);
} catch (err) {
logDebug(err);
logDebug(properties.userData);
}
}
return results ? results : {};
}
// Non-destructively modify the user data of an entity.
setEntityCustomData = function(customKey, id, data) {
var userData = getEntityUserData(id);
if (data == null) {
delete userData[customKey];
} else {
userData[customKey] = data;
}
setEntityUserData(id, userData);
}
getEntityCustomData = function(customKey, id, defaultValue) {
var userData = getEntityUserData(id);
if (undefined != userData[customKey]) {
return userData[customKey];
} else {
return defaultValue;
}
}
mergeObjects = function(proto, custom) {
var result = {};
for (var attrname in proto) {
result[attrname] = proto[attrname];
}
for (var attrname in custom) {
result[attrname] = custom[attrname];
}
return result;
}
LOG_WARN = 1;
logWarn = function(str) {
if (LOG_WARN) {
print(str);
}
}
LOG_ERROR = 1;
logError = function(str) {
if (LOG_ERROR) {
print(str);
}
}
LOG_INFO = 1;
logInfo = function(str) {
if (LOG_INFO) {
print(str);
}
}
LOG_DEBUG = 0;
logDebug = function(str) {
if (LOG_DEBUG) {
print(str);
}
}
LOG_TRACE = 0;
logTrace = function(str) {
if (LOG_TRACE) {
print(str);
}
}
// Computes the penetration between a point and a sphere (centered at the origin)
// if point is inside sphere: returns true and stores the result in 'penetration'
// (the vector that would move the point outside the sphere)
// otherwise returns false
findSphereHit = function(point, sphereRadius) {
var EPSILON = 0.000001; //smallish positive number - used as margin of error for some computations
var vectorLength = Vec3.length(point);
if (vectorLength < EPSILON) {
return true;
}
var distance = vectorLength - sphereRadius;
if (distance < 0.0) {
return true;
}
return false;
}
findSpherePointHit = function(sphereCenter, sphereRadius, point) {
return findSphereHit(Vec3.subtract(point, sphereCenter), sphereRadius);
}
findSphereSphereHit = function(firstCenter, firstRadius, secondCenter, secondRadius) {
return findSpherePointHit(firstCenter, firstRadius + secondRadius, secondCenter);
}
// Given a vec3 v, return a vec3 that is the same vector relative to the avatars
// DEFAULT eye position, rotated into the avatars reference frame.
getEyeRelativePosition = function(v) {
return Vec3.sum(MyAvatar.getDefaultEyePosition(), Vec3.multiplyQbyV(MyAvatar.orientation, v));
}
getAvatarRelativeRotation = function(q) {
return Quat.multiply(MyAvatar.orientation, q);
}
pointInExtents = function(point, minPoint, maxPoint) {
return (point.x >= minPoint.x && point.x <= maxPoint.x) &&
(point.y >= minPoint.y && point.y <= maxPoint.y) &&
(point.z >= minPoint.z && point.z <= maxPoint.z);
}
/**
* Converts an HSL color value to RGB. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
* Assumes h, s, and l are contained in the set [0, 1] and
* returns r, g, and b in the set [0, 255].
*
* @param Number h The hue
* @param Number s The saturation
* @param Number l The lightness
* @return Array The RGB representation
*/
hslToRgb = function(hsl) {
var r, g, b;
if (hsl.s == 0) {
r = g = b = hsl.l; // achromatic
} else {
var hue2rgb = function hue2rgb(p, q, t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
}
var q = hsl.l < 0.5 ? hsl.l * (1 + hsl.s) : hsl.l + hsl.s - hsl.l * hsl.s;
var p = 2 * hsl.l - q;
r = hue2rgb(p, q, hsl.h + 1 / 3);
g = hue2rgb(p, q, hsl.h);
b = hue2rgb(p, q, hsl.h - 1 / 3);
}
return {
red: Math.round(r * 255),
green: Math.round(g * 255),
blue: Math.round(b * 255)
};
}
orientationOf = function(vector) {
var Y_AXIS = {
x: 0,
y: 1,
z: 0
};
var X_AXIS = {
x: 1,
y: 0,
z: 0
};
var theta = 0.0;
var RAD_TO_DEG = 180.0 / Math.PI;
var direction, yaw, pitch;
direction = Vec3.normalize(vector);
yaw = Quat.angleAxis(Math.atan2(direction.x, direction.z) * RAD_TO_DEG, Y_AXIS);
pitch = Quat.angleAxis(Math.asin(-direction.y) * RAD_TO_DEG, X_AXIS);
return Quat.multiply(yaw, pitch);
}
randFloat = function(low, high) {
return low + Math.random() * (high - low);
}
randInt = function(low, high) {
return Math.floor(randFloat(low, high));
}
hexToRgb = function(hex) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
red: parseInt(result[1], 16),
green: parseInt(result[2], 16),
blue: parseInt(result[3], 16)
} : null;
}
calculateHandSizeRatio = function() {
// Get the ratio of the current avatar's hand to Owen's hand
var standardCenterHandPoint = 0.11288;
var jointNames = MyAvatar.getJointNames();
//get distance from handJoint up to leftHandIndex3 as a proxy for center of hand
var wristToFingertipDistance = 0;;
for (var i = 0; i < jointNames.length; i++) {
var jointName = jointNames[i];
print(jointName)
if (jointName.indexOf("LeftHandIndex") !== -1) {
// translations are relative to parent joint, so simply add them together
// joints face down the y-axis
var translation = MyAvatar.getDefaultJointTranslation(i).y;
wristToFingertipDistance += translation;
}
}
// Right now units are in cm, so convert to meters
wristToFingertipDistance /= 100;
var centerHandPoint = wristToFingertipDistance / 2;
// Compare against standard hand (Owen)
var handSizeRatio = centerHandPoint / standardCenterHandPoint;
return handSizeRatio;
}
clamp = function(val, min, max) {
return Math.max(min, Math.min(max, val))
}
attachChildToParent = function(childName, parentName, position, searchRadius) {
var childEntity, parentEntity;
var entities = Entities.findEntities(position, searchRadius)
for (var i = 0; i < entities.length; i++) {
// first go through and find the entity we want to attach to its parent
var entity = entities[i];
var name = Entities.getEntityProperties(entity, "name").name;
if (name === childName) {
childEntity = entity;
break;
}
}
if (!childEntity) {
print("You are trying to attach an entity that doesn't exist! Returning");
}
for (var i = 0; i < entities.length; i++) {
// first go through and find the entity we want to attach to its parent
var entity = entities[i];
var name = Entities.getEntityProperties(entity, "name").name;
if (name === parentName) {
parentEntity = entity;
break;
}
}
if (!parentEntity) {
print("You are trying to attach an entity to a parent that doesn't exist! Returning");
return;
}
print("Successfully attached " + childName + " to " + parentName);
Entities.editEntity(childEntity, {parentID: parentEntity});
}

View file

@ -0,0 +1,211 @@
// Created by James B. Pollack @imgntn 6/8/2016
// Copyright 2016 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 _this;
var MARKER_SCRIPT_URL = "atp:/whiteboard/markerEntityScript.js";
var ERASER_SCRIPT_URL = "atp:/whiteboard/eraserEntityScript.js";
Whiteboard = function() {
_this = this;
}
Whiteboard.prototype = {
preload: function(entityID) {
this.entityID = entityID;
this.setup();
},
unload: function() {
},
setup: function() {
var props = Entities.getEntityProperties(_this.entityID);
this.spawnRotation = Quat.safeEulerAngles(props.rotation);
this.spawnPosition = props.position;
this.orientation = Quat.fromPitchYawRollDegrees(this.spawnRotation.x, this.spawnRotation.y, this.spawnRotation.z);
this.markerRotation = Quat.fromVec3Degrees({
x: this.spawnRotation.x + 10,
y: this.spawnRotation.y - 90,
z: this.spawnRotation.z
});
},
createMarkers: function() {
_this.setup();
var modelURLS = [
"atp:/whiteboard/marker-blue.fbx",
"atp:/whiteboard/marker-red.fbx",
"atp:/whiteboard/marker-black.fbx",
];
var markerPosition = Vec3.sum(_this.spawnPosition, Vec3.multiply(Quat.getFront(_this.orientation), -0.1));
_this.createMarker(modelURLS[0], markerPosition, {
red: 10,
green: 10,
blue: 200
});
_this.createMarker(modelURLS[1], markerPosition, {
red: 200,
green: 10,
blue: 10
});
_this.createMarker(modelURLS[2], markerPosition, {
red: 10,
green: 10,
blue: 10
});
},
createMarker: function(modelURL, markerPosition, markerColor) {
var markerProperties = {
type: "Model",
modelURL: modelURL,
rotation: _this.markerRotation,
shapeType: "box",
name: "hifi_model_marker",
dynamic: true,
gravity: {
x: 0,
y: -5,
z: 0
},
velocity: {
x: 0,
y: -0.1,
z: 0
},
position: markerPosition,
dimensions: {
x: 0.027,
y: 0.027,
z: 0.164
},
lifetime: 86400,
script: MARKER_SCRIPT_URL,
userData: JSON.stringify({
'grabbableKey': {
'grabbable': true
},
'hifiHomeKey': {
'reset': true
},
originalPosition: markerPosition,
originalRotation: _this.markerRotation,
markerColor: markerColor,
wearable: {
joints: {
RightHand: [{
x: 0.001,
y: 0.139,
z: 0.050
}, {
x: -0.73,
y: -0.043,
z: -0.108,
w: -0.666
}],
LeftHand: [{
x: 0.007,
y: 0.151,
z: 0.061
}, {
x: -0.417,
y: 0.631,
z: -0.389,
w: -0.525
}]
}
}
})
}
var marker = Entities.addEntity(markerProperties);
},
createEraser: function() {
_this.setup();
var ERASER_MODEL_URL = "atp:/whiteboard/eraser-2.fbx";
var eraserPosition = Vec3.sum(_this.spawnPosition, Vec3.multiply(Quat.getFront(_this.orientation), -0.1));
eraserPosition = Vec3.sum(eraserPosition, Vec3.multiply(-0.5, Quat.getRight(_this.orientation)));
var eraserRotation = _this.markerRotation;
var eraserProps = {
type: "Model",
name: "hifi_model_whiteboardEraser",
modelURL: ERASER_MODEL_URL,
position: eraserPosition,
script: ERASER_SCRIPT_URL,
shapeType: "box",
lifetime: 86400,
dimensions: {
x: 0.0858,
y: 0.0393,
z: 0.2083
},
rotation: eraserRotation,
dynamic: true,
gravity: {
x: 0,
y: -10,
z: 0
},
velocity: {
x: 0,
y: -0.1,
z: 0
},
userData: JSON.stringify({
'hifiHomeKey': {
'reset': true
},
'grabbableKey': {
'grabbable': true
},
originalPosition: eraserPosition,
originalRotation: eraserRotation,
wearable: {
joints: {
RightHand: [{
x: 0.020,
y: 0.120,
z: 0.049
}, {
x: 0.1004,
y: 0.6424,
z: 0.717,
w: 0.250
}],
LeftHand: [{
x: -0.005,
y: 0.1101,
z: 0.053
}, {
x: 0.723,
y: 0.289,
z: 0.142,
w: 0.610
}]
}
}
})
}
var eraser = Entities.addEntity(eraserProps);
}
}
return new Whiteboard();
})

View file

@ -0,0 +1,149 @@
{
"Entities": [{
"clientOnly": 0,
"compoundShapeURL": "atp:/whiteboard/handScannerSwitch_phys.obj",
"created": "2016-06-14T18:08:49Z",
"dimensions": {
"x": 0.11707025021314621,
"y": 0.16469044983386993,
"z": 0.10442595928907394
},
"id": "{21d2185f-4161-484d-bb0f-70bdc307700d}",
"modelURL": "atp:/whiteboard/handScannerSwitch_tall_VR.fbx",
"name": "hifi_whiteboardSwiper",
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
"parentID": "{7b380903-a6d5-46e8-a4b3-4d58eaaa0419}",
"position": {
"x": -0.86872124671936035,
"y": -0.33092412352561951,
"z": 0.072394371032714844
},
"queryAACube": {
"scale": 0.22744926810264587,
"x": 4.9953713417053223,
"y": 0.33575963973999023,
"z": 1.1766284704208374
},
"rotation": {
"w": 0.71929502487182617,
"x": -4.57763671875e-05,
"y": -0.69472801685333252,
"z": -1.52587890625e-05
},
"script": "atp:/whiteboard/swiper.js",
"shapeType": "compound",
"type": "Model",
"userData": "{\"hifiHomeKey\":{\"reset\":true}}"
}, {
"clientOnly": 0,
"color": {
"blue": 200,
"green": 10,
"red": 200
},
"created": "2016-06-14T18:08:49Z",
"dimensions": {
"x": 1.8200000524520874,
"y": 1.7999999523162842,
"z": 0.0099999997764825821
},
"id": "{5572abff-1575-48e8-bc79-1d6373046fe9}",
"name": "hifi-whiteboardDrawingSurface",
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
"parentID": "{7b380903-a6d5-46e8-a4b3-4d58eaaa0419}",
"position": {
"x": -0.019987192004919052,
"y": 0.45400944352149963,
"z": 0.020008884370326996
},
"queryAACube": {
"scale": 2.5597851276397705,
"x": 3.3173346519470215,
"y": -0.045509219169616699,
"z": -0.66857552528381348
},
"rotation": {
"w": 1,
"x": -1.52587890625e-05,
"y": -1.52587890625e-05,
"z": -1.52587890625e-05
},
"shape": "Cube",
"type": "Box",
"visible": 0,
"userData": "{\"hifiHomeKey\":{\"reset\":true}}"
}, {
"clientOnly": 0,
"color": {
"blue": 200,
"green": 10,
"red": 200
},
"created": "2016-06-14T18:08:49Z",
"dimensions": {
"x": 1.8200000524520874,
"y": 1.7999999523162842,
"z": 0.0099999997764825821
},
"id": "{22152131-5ac7-4758-a5bc-3dda3f034eb4}",
"name": "hifi-whiteboardDrawingSurface",
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
"parentID": "{7b380903-a6d5-46e8-a4b3-4d58eaaa0419}",
"position": {
"x": -0.020041000097990036,
"y": 0.45001220703125,
"z": -0.019985578954219818
},
"queryAACube": {
"scale": 2.5597851276397705,
"x": 3.2840065956115723,
"y": -0.049505829811096191,
"z": -0.6464693546295166
},
"rotation": {
"w": 1,
"x": -1.52587890625e-05,
"y": -1.52587890625e-05,
"z": -1.52587890625e-05
},
"shape": "Cube",
"type": "Box",
"visible": 0,
"userData": "{\"hifiHomeKey\":{\"reset\":true}}"
}, {
"clientOnly": 0,
"compoundShapeURL": "atp:/whiteboard/whiteboardCollisionHull.obj",
"created": "2016-06-14T18:08:49Z",
"dimensions": {
"x": 1.8600000143051147,
"y": 2.7000000476837158,
"z": 0.46360000967979431
},
"gravity": {
"x": 0,
"y": -9.8,
"z": 0
},
"id": "{7b380903-a6d5-46e8-a4b3-4d58eaaa0419}",
"modelURL": "atp:/whiteboard/Whiteboard-4.fbx",
"name": "hifi_whiteboard",
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
"queryAACube": {
"scale": 3.3112723827362061,
"x": -1.655636191368103,
"y": -1.655636191368103,
"z": -1.655636191368103
},
"rotation": {
"w": -0.30053186416625977,
"x": -2.1577336156042293e-05,
"y": 0.95376050472259521,
"z": 2.824626790243201e-07
},
"script": "atp:/whiteboard/whiteboard.js",
"shapeType": "compound",
"type": "Model",
"userData": "{\"hifiHomeKey\":{\"reset\":true}}"
}],
"Version": 60
}

View file

@ -1,282 +0,0 @@
//
// whiteboardSpawner.js
// examples/homeContent/whiteboardV2
//
// Created by Eric Levina on 2/17/16
// Copyright 2016 High Fidelity, Inc.
//
// Run this script to spawn a whiteboard, markers, and an eraser.
// To draw on the whiteboard, equip a marker and hold down trigger with marker tip pointed at whiteboard
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
var ERASER_SCRIPT_URL = Script.resolvePath("eraserEntityScript.js");
var MARKER_SCRIPT_URL = Script.resolvePath("markerEntityScript.js");
Whiteboard = function(spawnPosition, spawnRotation) {
var orientation = Quat.fromPitchYawRollDegrees(spawnRotation.x, spawnRotation.y, spawnRotation.z);
var markers = [];
var markerRotation = Quat.fromVec3Degrees({
x: spawnRotation.x + 10,
y: spawnRotation.y - 90,
z: spawnRotation.z
});
var whiteboardPosition = spawnPosition;
var whiteboardRotation = orientation;
var WHITEBOARD_MODEL_URL = "atp:/whiteboard/Whiteboard-6.fbx";
var WHITEBOARD_COLLISION_HULL_URL = "atp:/whiteboard/whiteboardCollisionHull.obj";
var whiteboard = Entities.addEntity({
type: "Model",
name: "home_model_whiteboard",
modelURL: WHITEBOARD_MODEL_URL,
position: whiteboardPosition,
rotation: whiteboardRotation,
shapeType: 'compound',
compoundShapeURL: WHITEBOARD_COLLISION_HULL_URL,
dimensions: {
x: 1.86,
y: 2.7,
z: 0.4636
},
userData: JSON.stringify({
'hifiHomeKey': {
'reset': true
}
}),
});
var whiteboardSurfacePosition = Vec3.sum(whiteboardPosition, {
x: 0.0,
y: 0.45,
z: 0.0
});
whiteboardSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(-0.02, Quat.getRight(whiteboardRotation)));
var moveForwardDistance = 0.02;
whiteboardFrontSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(-moveForwardDistance, Quat.getFront(whiteboardRotation)));
var WHITEBOARD_SURFACE_NAME = "home_box_whiteboardDrawingSurface";
var whiteboardSurfaceSettings = {
type: "Box",
name: WHITEBOARD_SURFACE_NAME,
dimensions: {
x: 1.82,
y: 1.8,
z: 0.01
},
color: {
red: 200,
green: 10,
blue: 200
},
position: whiteboardFrontSurfacePosition,
rotation: whiteboardRotation,
visible: false,
parentID: whiteboard,
userData: JSON.stringify({
'hifiHomeKey': {
'reset': true
}
}),
}
var whiteboardFrontDrawingSurface = Entities.addEntity(whiteboardSurfaceSettings);
whiteboardBackSurfacePosition = Vec3.sum(whiteboardSurfacePosition, Vec3.multiply(moveForwardDistance, Quat.getFront(whiteboardRotation)));
whiteboardSurfaceSettings.position = whiteboardBackSurfacePosition;
var whiteboardBackDrawingSurface = Entities.addEntity(whiteboardSurfaceSettings);
var WHITEBOARD_RACK_DEPTH = 1.9;
// ************ ERASER ************************************************
var ERASER_MODEL_URL = "atp:/whiteboard/eraser-2.fbx";
var eraserPosition = Vec3.sum(spawnPosition, Vec3.multiply(Quat.getFront(whiteboardRotation), -0.1));
eraserPosition = Vec3.sum(eraserPosition, Vec3.multiply(-0.5, Quat.getRight(whiteboardRotation)));
var eraserRotation = markerRotation;
var eraserProps = {
type: "Model",
name: "home_model_whiteboardEraser",
modelURL: ERASER_MODEL_URL,
position: eraserPosition,
script: ERASER_SCRIPT_URL,
shapeType: "box",
dimensions: {
x: 0.0858,
y: 0.0393,
z: 0.2083
},
rotation: eraserRotation,
dynamic: true,
gravity: {
x: 0,
y: -10,
z: 0
},
velocity: {
x: 0,
y: -0.1,
z: 0
},
userData: JSON.stringify({
'hifiHomeKey': {
'reset': true
},
originalPosition: eraserPosition,
originalRotation: eraserRotation,
wearable: {
joints: {
RightHand: [{
x: 0.020,
y: 0.120,
z: 0.049
}, {
x: 0.1004,
y: 0.6424,
z: 0.717,
w: 0.250
}],
LeftHand: [{
x: -0.005,
y: 0.1101,
z: 0.053
}, {
x: 0.723,
y: 0.289,
z: 0.142,
w: 0.610
}]
}
}
})
}
// *************************************************************************************************
function createMarkers() {
var modelURLS = [
"atp:/whiteboard/marker-blue.fbx",
"atp:/whiteboard/marker-red.fbx",
"atp:/whiteboard/marker-black.fbx",
];
var markerPosition = Vec3.sum(spawnPosition, Vec3.multiply(Quat.getFront(whiteboardRotation), -0.1));
createMarker(modelURLS[0], markerPosition, {
red: 10,
green: 10,
blue: 200
});
markerPosition = Vec3.sum(markerPosition, Vec3.multiply(-0.2, Quat.getFront(markerRotation)));
createMarker(modelURLS[1], markerPosition, {
red: 200,
green: 10,
blue: 10
});
markerPosition = Vec3.sum(markerPosition, Vec3.multiply(0.4, Quat.getFront(markerRotation)));
createMarker(modelURLS[2], markerPosition, {
red: 10,
green: 10,
blue: 10
});
}
function createMarker(modelURL, markerPosition, markerColor) {
var marker = Entities.addEntity({
type: "Model",
modelURL: modelURL,
rotation: markerRotation,
shapeType: "box",
name: "home_model_marker",
dynamic: true,
gravity: {
x: 0,
y: -5,
z: 0
},
velocity: {
x: 0,
y: -0.1,
z: 0
},
position: markerPosition,
dimensions: {
x: 0.027,
y: 0.027,
z: 0.164
},
script: MARKER_SCRIPT_URL,
userData: JSON.stringify({
'hifiHomeKey': {
'reset': true
},
originalPosition: markerPosition,
originalRotation: markerRotation,
markerColor: markerColor,
wearable: {
joints: {
RightHand: [{
x: 0.001,
y: 0.139,
z: 0.050
}, {
x: -0.73,
y: -0.043,
z: -0.108,
w: -0.666
}],
LeftHand: [{
x: 0.007,
y: 0.151,
z: 0.061
}, {
x: -0.417,
y: 0.631,
z: -0.389,
w: -0.525
}]
}
}
})
});
markers.push(marker);
}
var eraser;
Script.setTimeout(function() {
eraser = Entities.addEntity(eraserProps);
createMarkers();
}, 1500)
function cleanup() {
print('WHITEBOARD CLEANUP')
Entities.deleteEntity(whiteboard);
Entities.deleteEntity(whiteboardFrontDrawingSurface);
Entities.deleteEntity(whiteboardBackDrawingSurface);
Entities.deleteEntity(eraser);
markers.forEach(function(marker) {
Entities.deleteEntity(marker);
});
}
this.cleanup = cleanup;
print('CREATED WHITEBOARD')
}