OK this is definitely working

This commit is contained in:
Zach Fox 2019-06-21 13:41:11 -07:00
parent 21454f6256
commit 5067fd4cd2
310 changed files with 3 additions and 34897 deletions

View file

@ -114,7 +114,7 @@ QUrl expandScriptUrl(const QUrl& rawScriptURL) {
url = QUrl::fromLocalFile(fileInfo.canonicalFilePath());
QUrl defaultScriptsLoc = PathUtils::defaultScriptsLocation();
if (!defaultScriptsLoc.isParentOf(url) && defaultScriptsLoc != url) {
if (!defaultScriptsLoc.isParentOf(url) /*&& defaultScriptsLoc != url*/) {
qCWarning(scriptengine) << "Script.include() ignoring file path"
<< "-- outside of standard libraries: "
<< url.path()

View file

@ -1,129 +0,0 @@
"use strict";
/* jslint vars: true, plusplus: true */
//
// defaultScripts.js
// examples
//
// Copyright 2014 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 DEFAULT_SCRIPTS_COMBINED = [
"system/progress.js",
"system/+android_interface/touchscreenvirtualpad.js",
"system/+android_interface/actionbar.js",
"system/+android_interface/audio.js" ,
"system/+android_interface/modes.js",
"system/makeUserConnection.js"/*,
"system/away.js",
"system/controllers/controllerDisplayManager.js",
"system/controllers/handControllerGrabAndroid.js",
"system/controllers/handControllerPointerAndroid.js",
"system/controllers/squeezeHands.js",
"system/controllers/grab.js",
"system/controllers/teleport.js",
"system/controllers/toggleAdvancedMovementForHandControllers.js",
"system/dialTone.js",
"system/firstPersonHMD.js",
"system/bubble.js",
"system/android.js",
"developer/debugging/debugAndroidMouse.js"*/
];
var DEBUG_SCRIPTS = [
"system/+android_interface/stats.js"
];
var DEFAULT_SCRIPTS_SEPARATE = [ ];
// add a menu item for debugging
var MENU_CATEGORY = "Developer";
var MENU_ITEM = "Debug defaultScripts.js";
var SETTINGS_KEY = '_debugDefaultScriptsIsChecked';
var previousSetting = Settings.getValue(SETTINGS_KEY);
if (previousSetting === '' || previousSetting === false || previousSetting === 'false') {
previousSetting = false;
}
if (previousSetting === true || previousSetting === 'true') {
previousSetting = true;
}
if (Menu.menuExists(MENU_CATEGORY) && !Menu.menuItemExists(MENU_CATEGORY, MENU_ITEM)) {
Menu.addMenuItem({
menuName: MENU_CATEGORY,
menuItemName: MENU_ITEM,
isCheckable: true,
isChecked: previousSetting,
grouping: "Advanced"
});
}
function loadSeparateDefaults() {
for (var i in DEFAULT_SCRIPTS_SEPARATE) {
Script.load(DEFAULT_SCRIPTS_SEPARATE[i]);
}
}
function runDefaultsTogether() {
for (var i in DEFAULT_SCRIPTS_COMBINED) {
Script.include(DEFAULT_SCRIPTS_COMBINED[i]);
}
if (Script.isDebugMode()) {
for (var i in DEBUG_SCRIPTS) {
Script.include(DEBUG_SCRIPTS[i]);
}
}
loadSeparateDefaults();
}
function runDefaultsSeparately() {
for (var i in DEFAULT_SCRIPTS_COMBINED) {
Script.load(DEFAULT_SCRIPTS_COMBINED[i]);
}
if (Script.isDebugMode()) {
for (var i in DEBUG_SCRIPTS) {
Script.load(DEBUG_SCRIPTS[i]);
}
}
loadSeparateDefaults();
}
// start all scripts
if (Menu.isOptionChecked(MENU_ITEM)) {
// we're debugging individual default scripts
// so we load each into its own ScriptEngine instance
runDefaultsSeparately();
} else {
// include all default scripts into this ScriptEngine
runDefaultsTogether();
}
function menuItemEvent(menuItem) {
if (menuItem === MENU_ITEM) {
var isChecked = Menu.isOptionChecked(MENU_ITEM);
if (isChecked === true) {
Settings.setValue(SETTINGS_KEY, true);
} else if (isChecked === false) {
Settings.setValue(SETTINGS_KEY, false);
}
Menu.triggerOption("Reload All Scripts");
}
}
function removeMenuItem() {
if (!Menu.isOptionChecked(MENU_ITEM)) {
Menu.removeMenuItem(MENU_CATEGORY, MENU_ITEM);
}
}
Script.scriptEnding.connect(function() {
removeMenuItem();
});
Menu.menuItemEvent.connect(menuItemEvent);

View file

@ -1,120 +0,0 @@
"use strict";
/* jslint vars: true, plusplus: true */
//
// defaultScripts.js
// examples
//
// Copyright 2014 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 DEFAULT_SCRIPTS_COMBINED = [
"system/request-service.js",
"system/progress.js",
"system/away.js",
//"system/hmd.js",
"system/menu.js",
"system/bubble.js",
"system/pal.js", // "system/mod.js", // older UX, if you prefer
"system/avatarapp.js",
"system/makeUserConnection.js",
"system/tablet-goto.js",
"system/notifications.js",
"system/commerce/wallet.js",
"system/dialTone.js",
"system/marketplaces/marketplaces.js",
"system/quickGoto.js",
"system/firstPersonHMD.js",
"system/tablet-ui/tabletUI.js",
"system/miniTablet.js"
];
var DEFAULT_SCRIPTS_SEPARATE = [
"system/controllers/controllerScripts.js",
//"system/chat.js"
];
if (Window.interstitialModeEnabled) {
// Insert interstitial scripts at front so that they're started first.
DEFAULT_SCRIPTS_COMBINED.splice(0, 0, "system/interstitialPage.js", "system/redirectOverlays.js");
}
// add a menu item for debugging
var MENU_CATEGORY = "Developer > Scripting";
var MENU_ITEM = "Debug defaultScripts.js";
var SETTINGS_KEY = '_debugDefaultScriptsIsChecked';
var previousSetting = Settings.getValue(SETTINGS_KEY);
if (previousSetting === '' || previousSetting === false || previousSetting === 'false') {
previousSetting = false;
}
if (previousSetting === true || previousSetting === 'true') {
previousSetting = true;
}
if (Menu.menuExists(MENU_CATEGORY) && !Menu.menuItemExists(MENU_CATEGORY, MENU_ITEM)) {
Menu.addMenuItem({
menuName: MENU_CATEGORY,
menuItemName: MENU_ITEM,
isCheckable: true,
isChecked: previousSetting,
});
}
function loadSeparateDefaults() {
for (var i in DEFAULT_SCRIPTS_SEPARATE) {
Script.load(DEFAULT_SCRIPTS_SEPARATE[i]);
}
}
function runDefaultsTogether() {
for (var i in DEFAULT_SCRIPTS_COMBINED) {
Script.include(DEFAULT_SCRIPTS_COMBINED[i]);
}
loadSeparateDefaults();
}
function runDefaultsSeparately() {
for (var i in DEFAULT_SCRIPTS_COMBINED) {
Script.load(DEFAULT_SCRIPTS_COMBINED[i]);
}
loadSeparateDefaults();
}
// start all scripts
if (Menu.isOptionChecked(MENU_ITEM)) {
// we're debugging individual default scripts
// so we load each into its own ScriptEngine instance
runDefaultsSeparately();
} else {
// include all default scripts into this ScriptEngine
runDefaultsTogether();
}
function menuItemEvent(menuItem) {
if (menuItem === MENU_ITEM) {
var isChecked = Menu.isOptionChecked(MENU_ITEM);
if (isChecked === true) {
Settings.setValue(SETTINGS_KEY, true);
} else if (isChecked === false) {
Settings.setValue(SETTINGS_KEY, false);
}
Menu.triggerOption("Reload All Scripts");
}
}
function removeMenuItem() {
if (!Menu.isOptionChecked(MENU_ITEM)) {
Menu.removeMenuItem(MENU_CATEGORY, MENU_ITEM);
}
}
Script.scriptEnding.connect(function() {
removeMenuItem();
});
Menu.menuItemEvent.connect(menuItemEvent);

View file

@ -1,275 +0,0 @@
"use strict";
//
// EZrecord.js
//
// Created by David Rowe on 24 Jun 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
//
(function () {
var APP_NAME = "EZRECORD",
APP_ICON_INACTIVE = "icons/tablet-icons/avatar-record-i.svg",
APP_ICON_ACTIVE = "icons/tablet-icons/avatar-record-a.svg",
SHORTCUT_KEY = "r", // Alt modifier is assumed.
tablet,
button,
RecordingIndicator,
Recorder;
function log(message) {
print(APP_NAME + ": " + message);
}
function logDetails() {
return {
current_domain: location.placename
};
}
RecordingIndicator = (function () {
// Displays "recording" overlay.
var hmdOverlay,
HMD_FONT_SIZE = 0.08,
desktopOverlay,
DESKTOP_FONT_SIZE = 24;
function show() {
// Create both overlays in case user switches desktop/HMD mode.
var screenSize = Controller.getViewportDimensions(),
recordingText = "REC", // Unicode circle \u25cf doesn't render in HMD.
CAMERA_JOINT_INDEX = -7;
if (HMD.active) {
// 3D overlay attached to avatar.
hmdOverlay = Overlays.addOverlay("text3d", {
text: recordingText,
dimensions: { x: 3 * HMD_FONT_SIZE, y: HMD_FONT_SIZE },
parentID: MyAvatar.sessionUUID,
parentJointIndex: CAMERA_JOINT_INDEX,
localPosition: { x: 0.95, y: 0.95, z: -2.0 },
color: { red: 255, green: 0, blue: 0 },
alpha: 0.9,
lineHeight: HMD_FONT_SIZE,
backgroundAlpha: 0,
ignoreRayIntersection: true,
isFacingAvatar: true,
drawInFront: true,
visible: true
});
} else {
// 2D overlay on desktop.
desktopOverlay = Overlays.addOverlay("text", {
text: recordingText,
width: 3 * DESKTOP_FONT_SIZE,
height: DESKTOP_FONT_SIZE,
x: screenSize.x - 4 * DESKTOP_FONT_SIZE,
y: DESKTOP_FONT_SIZE,
font: { size: DESKTOP_FONT_SIZE },
color: { red: 255, green: 8, blue: 8 },
alpha: 1.0,
backgroundAlpha: 0,
visible: true
});
}
}
function hide() {
if (desktopOverlay) {
Overlays.deleteOverlay(desktopOverlay);
}
if (hmdOverlay) {
Overlays.deleteOverlay(hmdOverlay);
}
}
return {
show: show,
hide: hide
};
}());
Recorder = (function () {
var IDLE = 0,
COUNTING_DOWN = 1,
RECORDING = 2,
recordingState = IDLE,
countdownTimer,
countdownSeconds,
COUNTDOWN_SECONDS = 3,
tickSound,
startRecordingSound,
finishRecordingSound,
TICK_SOUND = "../system/assets/sounds/countdown-tick.wav",
START_RECORDING_SOUND = "../system/assets/sounds/start-recording.wav",
FINISH_RECORDING_SOUND = "../system/assets/sounds/finish-recording.wav",
START_RECORDING_SOUND_DURATION = 1200,
SOUND_VOLUME = 0.2;
function playSound(sound) {
Audio.playSound(sound, {
position: MyAvatar.position,
localOnly: true,
volume: SOUND_VOLUME
});
}
function isRecording() {
return recordingState === COUNTING_DOWN || recordingState === RECORDING;
}
function startRecording() {
if (recordingState !== IDLE) {
return;
}
log("Start countdown");
countdownSeconds = COUNTDOWN_SECONDS;
playSound(tickSound);
countdownTimer = Script.setInterval(function () {
countdownSeconds -= 1;
if (countdownSeconds <= 0) {
Script.clearInterval(countdownTimer);
playSound(startRecordingSound);
log("Start recording");
Script.setTimeout(function () {
// Delay start so that start beep is not included in recorded sound.
Recording.startRecording();
RecordingIndicator.show();
}, START_RECORDING_SOUND_DURATION);
recordingState = RECORDING;
} else {
playSound(tickSound);
}
}, 1000);
recordingState = COUNTING_DOWN;
}
function cancelRecording() {
log("Cancel recording");
if (recordingState === COUNTING_DOWN) {
Script.clearInterval(countdownTimer);
} else {
Recording.stopRecording();
RecordingIndicator.hide();
}
recordingState = IDLE;
}
function finishRecording() {
playSound(finishRecordingSound);
Recording.stopRecording();
RecordingIndicator.hide();
var filename = (new Date()).toISOString(); // yyyy-mm-ddThh:mm:ss.sssZ
filename = filename.replace(/[\-:]|\.\d*Z$/g, "").replace("T", "-") + ".hfr"; // yyyymmmdd-hhmmss.hfr
filename = Recording.getDefaultRecordingSaveDirectory() + filename;
log("Finish recording: " + filename);
Recording.saveRecording(filename);
recordingState = IDLE;
UserActivityLogger.logAction("ezrecord_finish_recording", logDetails());
}
function stopRecording() {
if (recordingState === COUNTING_DOWN) {
cancelRecording();
} else if (recordingState === RECORDING) {
finishRecording();
}
}
function setUp() {
tickSound = SoundCache.getSound(Script.resolvePath(TICK_SOUND));
startRecordingSound = SoundCache.getSound(Script.resolvePath(START_RECORDING_SOUND));
finishRecordingSound = SoundCache.getSound(Script.resolvePath(FINISH_RECORDING_SOUND));
}
function tearDown() {
if (recordingState !== IDLE) {
cancelRecording();
}
}
return {
isRecording: isRecording,
startRecording: startRecording,
stopRecording: stopRecording,
setUp: setUp,
tearDown: tearDown
};
}());
function toggleRecording() {
if (Recorder.isRecording()) {
Recorder.stopRecording();
} else {
Recorder.startRecording();
}
button.editProperties({ isActive: Recorder.isRecording() });
}
function onKeyPressEvent(event) {
if (event.isAlt && event.text === SHORTCUT_KEY && !event.isControl && !event.isMeta && !event.isAutoRepeat) {
toggleRecording();
}
}
function onButtonClicked() {
toggleRecording();
}
function setUp() {
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
if (!tablet) {
return;
}
Recorder.setUp();
// tablet/toolbar button.
button = tablet.addButton({
icon: APP_ICON_INACTIVE,
activeIcon: APP_ICON_ACTIVE,
text: APP_NAME,
isActive: false
});
if (button) {
button.clicked.connect(onButtonClicked);
}
Controller.keyPressEvent.connect(onKeyPressEvent);
UserActivityLogger.logAction("ezrecord_run_script", logDetails());
}
function tearDown() {
Controller.keyPressEvent.disconnect(onKeyPressEvent);
Recorder.tearDown();
if (!tablet) {
return;
}
if (button) {
button.clicked.disconnect(onButtonClicked);
tablet.removeButton(button);
button = null;
}
tablet = null;
}
setUp();
Script.scriptEnding.connect(tearDown);
}());

View file

@ -1,222 +0,0 @@
var LEFT_HAND_INDEX = 0;
var RIGHT_HAND_INDEX = 1;
var LEFT_FOOT_INDEX = 2;
var RIGHT_FOOT_INDEX = 3;
var HIPS_INDEX = 4;
var SPINE2_INDEX = 5;
var mappingJson = {
name: "com.highfidelity.testing.accelerationTest",
channels: [
{
from: "Standard.LeftHand",
to: "Actions.LeftHand",
filters: [
{
type: "accelerationLimiter",
rotationAccelerationLimit: 2000.0,
translationAccelerationLimit: 100.0,
}
]
},
{
from: "Standard.RightHand",
to: "Actions.RightHand",
filters: [
{
type: "accelerationLimiter",
rotationAccelerationLimit: 2000.0,
translationAccelerationLimit: 100.0,
}
]
},
{
from: "Standard.LeftFoot",
to: "Actions.LeftFoot",
filters: [
{
type: "accelerationLimiter",
rotationAccelerationLimit: 2000.0,
translationAccelerationLimit: 100.0,
}
]
},
{
from: "Standard.RightFoot",
to: "Actions.RightFoot",
filters: [
{
type: "accelerationLimiter",
rotationAccelerationLimit: 2000.0,
translationAccelerationLimit: 100.0,
}
]
},
{
from: "Standard.Hips",
to: "Actions.Hips",
filters: [
{
type: "accelerationLimiter",
rotationAccelerationLimit: 2000.0,
translationAccelerationLimit: 100.0,
}
]
},
{
from: "Standard.Spine2",
to: "Actions.Spine2",
filters: [
{
type: "accelerationLimiter",
rotationAccelerationLimit: 2000.0,
translationAccelerationLimit: 100.0,
}
]
}
]
};
//
// tablet app boiler plate
//
var TABLET_BUTTON_NAME = "ACCFILT";
var HTML_URL = "https://s3.amazonaws.com/hifi-public/tony/html/accelerationFilterApp.html?2";
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var tabletButton = tablet.addButton({
text: TABLET_BUTTON_NAME,
icon: "https://s3.amazonaws.com/hifi-public/tony/icons/tpose-i.svg",
activeIcon: "https://s3.amazonaws.com/hifi-public/tony/icons/tpose-a.svg"
});
tabletButton.clicked.connect(function () {
if (shown) {
tablet.gotoHomeScreen();
} else {
tablet.gotoWebScreen(HTML_URL);
}
});
var shown = false;
function onScreenChanged(type, url) {
if (type === "Web" && url === HTML_URL) {
tabletButton.editProperties({isActive: true});
if (!shown) {
// hook up to event bridge
tablet.webEventReceived.connect(onWebEventReceived);
shownChanged(true);
}
shown = true;
} else {
tabletButton.editProperties({isActive: false});
if (shown) {
// disconnect from event bridge
tablet.webEventReceived.disconnect(onWebEventReceived);
shownChanged(false);
}
shown = false;
}
}
function getTranslationAccelerationLimit(i) {
return mappingJson.channels[i].filters[0].translationAccelerationLimit;
}
function setTranslationAccelerationLimit(i, value) {
mappingJson.channels[i].filters[0].translationAccelerationLimit = value;
mappingChanged();
}
function getRotationAccelerationLimit(i) {
return mappingJson.channels[i].filters[0].rotationAccelerationLimit;
}
function setRotationAccelerationLimit(i, value) {
mappingJson.channels[i].filters[0].rotationAccelerationLimit = value; mappingChanged();
}
function onWebEventReceived(msg) {
if (msg.name === "init-complete") {
var values = [
{name: "left-hand-translation-acceleration-limit", val: getTranslationAccelerationLimit(LEFT_HAND_INDEX), checked: false},
{name: "left-hand-rotation-acceleration-limit", val: getRotationAccelerationLimit(LEFT_HAND_INDEX), checked: false},
{name: "right-hand-translation-acceleration-limit", val: getTranslationAccelerationLimit(RIGHT_HAND_INDEX), checked: false},
{name: "right-hand-rotation-acceleration-limit", val: getRotationAccelerationLimit(RIGHT_HAND_INDEX), checked: false},
{name: "left-foot-translation-acceleration-limit", val: getTranslationAccelerationLimit(LEFT_FOOT_INDEX), checked: false},
{name: "left-foot-rotation-acceleration-limit", val: getRotationAccelerationLimit(LEFT_FOOT_INDEX), checked: false},
{name: "right-foot-translation-acceleration-limit", val: getTranslationAccelerationLimit(RIGHT_FOOT_INDEX), checked: false},
{name: "right-foot-rotation-acceleration-limit", val: getRotationAccelerationLimit(RIGHT_FOOT_INDEX), checked: false},
{name: "hips-translation-acceleration-limit", val: getTranslationAccelerationLimit(HIPS_INDEX), checked: false},
{name: "hips-rotation-acceleration-limit", val: getRotationAccelerationLimit(HIPS_INDEX), checked: false},
{name: "spine2-translation-acceleration-limit", val: getTranslationAccelerationLimit(SPINE2_INDEX), checked: false},
{name: "spine2-rotation-acceleration-limit", val: getRotationAccelerationLimit(SPINE2_INDEX), checked: false}
];
tablet.emitScriptEvent(JSON.stringify(values));
} else if (msg.name === "left-hand-translation-acceleration-limit") {
setTranslationAccelerationLimit(LEFT_HAND_INDEX, parseInt(msg.val, 10));
} else if (msg.name === "left-hand-rotation-acceleration-limit") {
setRotationAccelerationLimit(LEFT_HAND_INDEX, parseInt(msg.val, 10));
} else if (msg.name === "right-hand-translation-acceleration-limit") {
setTranslationAccelerationLimit(RIGHT_HAND_INDEX, parseInt(msg.val, 10));
} else if (msg.name === "right-hand-rotation-acceleration-limit") {
setRotationAccelerationLimit(RIGHT_HAND_INDEX, parseInt(msg.val, 10));
} else if (msg.name === "left-foot-translation-acceleration-limit") {
setTranslationAccelerationLimit(LEFT_FOOT_INDEX, parseInt(msg.val, 10));
} else if (msg.name === "left-foot-rotation-acceleration-limit") {
setRotationAccelerationLimit(LEFT_FOOT_INDEX, parseInt(msg.val, 10));
} else if (msg.name === "right-foot-translation-acceleration-limit") {
setTranslationAccelerationLimit(RIGHT_FOOT_INDEX, parseInt(msg.val, 10));
} else if (msg.name === "right-foot-rotation-acceleration-limit") {
setRotationAccelerationLimit(RIGHT_FOOT_INDEX, parseInt(msg.val, 10));
} else if (msg.name === "hips-translation-acceleration-limit") {
setTranslationAccelerationLimit(HIPS_INDEX, parseInt(msg.val, 10));
} else if (msg.name === "hips-rotation-acceleration-limit") {
setRotationAccelerationLimit(HIPS_INDEX, parseInt(msg.val, 10));
} else if (msg.name === "spine2-translation-acceleration-limit") {
setTranslationAccelerationLimit(SPINE2_INDEX, parseInt(msg.val, 10));
} else if (msg.name === "spine2-rotation-acceleration-limit") {
setRotationAccelerationLimit(SPINE2_INDEX, parseInt(msg.val, 10));
}
}
tablet.screenChanged.connect(onScreenChanged);
function shutdownTabletApp() {
tablet.removeButton(tabletButton);
if (shown) {
tablet.webEventReceived.disconnect(onWebEventReceived);
tablet.gotoHomeScreen();
}
tablet.screenChanged.disconnect(onScreenChanged);
}
//
// end tablet app boiler plate
//
var mapping;
function mappingChanged() {
if (mapping) {
mapping.disable();
}
mapping = Controller.parseMapping(JSON.stringify(mappingJson));
mapping.enable();
}
function shownChanged(newShown) {
if (newShown) {
mappingChanged();
} else {
mapping.disable();
}
}
mappingChanged();
Script.scriptEnding.connect(function() {
if (mapping) {
mapping.disable();
}
tablet.removeButton(tabletButton);
});

View file

@ -1,138 +0,0 @@
"use strict";
(function(){
var AppUi = Script.require("appUi");
var ui;
var onCreateAvatarInputsBarEntity = false;
var micBarEntity = null;
var bubbleIconEntity = null;
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var AVATAR_INPUTS_EDIT_QML_SOURCE = "hifi/EditAvatarInputsBar.qml";
// DPI
var ENTITY_DPI = 60.0;
// QML NATURAL DIMENSIONS
var MIC_BAR_DIMENSIONS = Vec3.multiply(30.0 / ENTITY_DPI, {x: 0.036, y: 0.048, z: 0.3});
var BUBBLE_ICON_DIMENSIONS = Vec3.multiply(30.0 / ENTITY_DPI, {x: 0.036, y: 0.036, z: 0.3});
// ENTITY NAMES
var MIC_BAR_NAME = "AvatarInputsMicBarEntity";
var BUBBLE_ICON_NAME = "AvatarInputsBubbleIconEntity";
// CONSTANTS
var LOCAL_POSITION_X_OFFSET = -0.2;
var LOCAL_POSITION_Y_OFFSET = -0.125;
var LOCAL_POSITION_Z_OFFSET = -0.5;
function fromQml(message) {
if (message.method === "reposition") {
var micBarLocalPosition = Entities.getEntityProperties(micBarEntity).localPosition;
var bubbleIconLocalPosition = Entities.getEntityProperties(bubbleIconEntity).localPosition;
var newMicBarLocalPosition, newBubbleIconLocalPosition;
if (message.x !== undefined) {
newMicBarLocalPosition = { x: -((MIC_BAR_DIMENSIONS.x) / 2) + message.x, y: micBarLocalPosition.y, z: micBarLocalPosition.z };
newBubbleIconLocalPosition = { x: ((MIC_BAR_DIMENSIONS.x) * 1.2 / 2) + message.x, y: bubbleIconLocalPosition.y, z: bubbleIconLocalPosition.z };
} else if (message.y !== undefined) {
newMicBarLocalPosition = { x: micBarLocalPosition.x, y: message.y, z: micBarLocalPosition.z };
newBubbleIconLocalPosition = { x: bubbleIconLocalPosition.x, y: ((MIC_BAR_DIMENSIONS.y - BUBBLE_ICON_DIMENSIONS.y) / 2 + message.y), z: bubbleIconLocalPosition.z };
} else if (message.z !== undefined) {
newMicBarLocalPosition = { x: micBarLocalPosition.x, y: micBarLocalPosition.y, z: message.z };
newBubbleIconLocalPosition = { x: bubbleIconLocalPosition.x, y: bubbleIconLocalPosition.y, z: message.z };
}
var micBarProps = {
localPosition: newMicBarLocalPosition
};
var bubbleIconProps = {
localPosition: newBubbleIconLocalPosition
};
Entities.editEntity(micBarEntity, micBarProps);
Entities.editEntity(bubbleIconEntity, bubbleIconProps);
} else if (message.method === "setVisible") {
if (message.visible !== undefined) {
var props = {
visible: message.visible
};
Entities.editEntity(micBarEntity, props);
Entities.editEntity(bubbleIconEntity, props);
}
} else if (message.method === "print") {
// prints the local position into the hifi log.
var micBarLocalPosition = Entities.getEntityProperties(micBarEntity).localPosition;
var bubbleIconLocalPosition = Entities.getEntityProperties(bubbleIconEntity).localPosition;
console.log("mic bar local position is at " + JSON.stringify(micBarLocalPosition));
console.log("bubble icon local position is at " + JSON.stringify(bubbleIconLocalPosition));
}
};
function createEntities() {
if (micBarEntity != null && bubbleIconEntity != null) {
return;
}
// POSITIONS
var micBarLocalPosition = {x: (-(MIC_BAR_DIMENSIONS.x / 2)) + LOCAL_POSITION_X_OFFSET, y: LOCAL_POSITION_Y_OFFSET, z: LOCAL_POSITION_Z_OFFSET};
var bubbleIconLocalPosition = {x: (MIC_BAR_DIMENSIONS.x * 1.2 / 2) + LOCAL_POSITION_X_OFFSET, y: ((MIC_BAR_DIMENSIONS.y - BUBBLE_ICON_DIMENSIONS.y) / 2 + LOCAL_POSITION_Y_OFFSET), z: LOCAL_POSITION_Z_OFFSET};
var props = {
type: "Web",
name: MIC_BAR_NAME,
parentID: MyAvatar.SELF_ID,
parentJointIndex: MyAvatar.getJointIndex("_CAMERA_MATRIX"),
localPosition: micBarLocalPosition,
localRotation: Quat.cancelOutRollAndPitch(Quat.lookAtSimple(Camera.orientation, micBarLocalPosition)),
sourceUrl: Script.resourcesPath() + "qml/hifi/audio/MicBarApplication.qml",
// cutoff alpha for detecting transparency
alpha: 0.98,
dimensions: MIC_BAR_DIMENSIONS,
dpi: ENTITY_DPI,
drawInFront: true,
userData: {
grabbable: false
},
};
micBarEntity = Entities.addEntity(props, "local");
var props = {
type: "Web",
name: BUBBLE_ICON_NAME,
parentID: MyAvatar.SELF_ID,
parentJointIndex: MyAvatar.getJointIndex("_CAMERA_MATRIX"),
localPosition: bubbleIconLocalPosition,
localRotation: Quat.cancelOutRollAndPitch(Quat.lookAtSimple(Camera.orientation, bubbleIconLocalPosition)),
sourceUrl: Script.resourcesPath() + "qml/BubbleIcon.qml",
// cutoff alpha for detecting transparency
alpha: 0.98,
dimensions: BUBBLE_ICON_DIMENSIONS,
dpi: ENTITY_DPI,
drawInFront: true,
userData: {
grabbable: false
},
};
bubbleIconEntity = Entities.addEntity(props, "local");
tablet.loadQMLSource(AVATAR_INPUTS_EDIT_QML_SOURCE);
};
function cleanup() {
if (micBarEntity) {
Entities.deleteEntity(micBarEntity);
}
if (bubbleIconEntity) {
Entities.deleteEntity(bubbleIconEntity);
}
};
function setup() {
ui = new AppUi({
buttonName: "AVBAR",
home: Script.resourcesPath() + "qml/hifi/EditAvatarInputsBar.qml",
onMessage: fromQml,
onOpened: createEntities,
// onClosed: cleanup,
normalButton: "icons/tablet-icons/edit-i.svg",
activeButton: "icons/tablet-icons/edit-a.svg",
});
};
setup();
Script.scriptEnding.connect(cleanup);
}());

View file

@ -1,240 +0,0 @@
var LEFT_HAND_INDEX = 0;
var RIGHT_HAND_INDEX = 1;
var LEFT_FOOT_INDEX = 2;
var RIGHT_FOOT_INDEX = 3;
var HIPS_INDEX = 4;
var SPINE2_INDEX = 5;
var HAND_SMOOTHING_TRANSLATION = 0.3;
var HAND_SMOOTHING_ROTATION = 0.15;
var FOOT_SMOOTHING_TRANSLATION = 0.3;
var FOOT_SMOOTHING_ROTATION = 0.15;
var TORSO_SMOOTHING_TRANSLATION = 0.3;
var TORSO_SMOOTHING_ROTATION = 0.16;
var mappingJson = {
name: "com.highfidelity.testing.exponentialFilterApp",
channels: [
{
from: "Standard.LeftHand",
to: "Actions.LeftHand",
filters: [
{
type: "exponentialSmoothing",
translation: HAND_SMOOTHING_TRANSLATION,
rotation: HAND_SMOOTHING_ROTATION
}
]
},
{
from: "Standard.RightHand",
to: "Actions.RightHand",
filters: [
{
type: "exponentialSmoothing",
translation: HAND_SMOOTHING_TRANSLATION,
rotation: HAND_SMOOTHING_ROTATION
}
]
},
{
from: "Standard.LeftFoot",
to: "Actions.LeftFoot",
filters: [
{
type: "exponentialSmoothing",
translation: FOOT_SMOOTHING_TRANSLATION,
rotation: FOOT_SMOOTHING_ROTATION
}
]
},
{
from: "Standard.RightFoot",
to: "Actions.RightFoot",
filters: [
{
type: "exponentialSmoothing",
translation: FOOT_SMOOTHING_TRANSLATION,
rotation: FOOT_SMOOTHING_ROTATION
}
]
},
{
from: "Standard.Hips",
to: "Actions.Hips",
filters: [
{
type: "exponentialSmoothing",
translation: TORSO_SMOOTHING_TRANSLATION,
rotation: TORSO_SMOOTHING_ROTATION
}
]
},
{
from: "Standard.Spine2",
to: "Actions.Spine2",
filters: [
{
type: "exponentialSmoothing",
translation: TORSO_SMOOTHING_TRANSLATION,
rotation: TORSO_SMOOTHING_ROTATION
}
]
}
]
};
//
// tablet app boiler plate
//
var TABLET_BUTTON_NAME = "EXPFILT";
var HTML_URL = "https://s3.amazonaws.com/hifi-public/tony/html/exponentialFilterApp.html?7";
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var tabletButton = tablet.addButton({
text: TABLET_BUTTON_NAME,
icon: "https://s3.amazonaws.com/hifi-public/tony/icons/tpose-i.svg",
activeIcon: "https://s3.amazonaws.com/hifi-public/tony/icons/tpose-a.svg"
});
tabletButton.clicked.connect(function () {
if (shown) {
tablet.gotoHomeScreen();
} else {
tablet.gotoWebScreen(HTML_URL);
}
});
var shown = false;
function onScreenChanged(type, url) {
if (type === "Web" && url === HTML_URL) {
tabletButton.editProperties({isActive: true});
if (!shown) {
// hook up to event bridge
tablet.webEventReceived.connect(onWebEventReceived);
shownChanged(true);
}
shown = true;
} else {
tabletButton.editProperties({isActive: false});
if (shown) {
// disconnect from event bridge
tablet.webEventReceived.disconnect(onWebEventReceived);
shownChanged(false);
}
shown = false;
}
}
function getTranslation(i) {
return mappingJson.channels[i].filters[0].translation;
}
function setTranslation(i, value) {
mappingJson.channels[i].filters[0].translation = value;
mappingChanged();
}
function getRotation(i) {
return mappingJson.channels[i].filters[0].rotation;
}
function setRotation(i, value) {
mappingJson.channels[i].filters[0].rotation = value; mappingChanged();
}
function onWebEventReceived(msg) {
if (msg.name === "init-complete") {
var values = [
{name: "enable-filtering", val: filterEnabled ? "on" : "off", checked: false},
{name: "left-hand-translation", val: getTranslation(LEFT_HAND_INDEX), checked: false},
{name: "left-hand-rotation", val: getRotation(LEFT_HAND_INDEX), checked: false},
{name: "right-hand-translation", val: getTranslation(RIGHT_HAND_INDEX), checked: false},
{name: "right-hand-rotation", val: getRotation(RIGHT_HAND_INDEX), checked: false},
{name: "left-foot-translation", val: getTranslation(LEFT_FOOT_INDEX), checked: false},
{name: "left-foot-rotation", val: getRotation(LEFT_FOOT_INDEX), checked: false},
{name: "right-foot-translation", val: getTranslation(RIGHT_FOOT_INDEX), checked: false},
{name: "right-foot-rotation", val: getRotation(RIGHT_FOOT_INDEX), checked: false},
{name: "hips-translation", val: getTranslation(HIPS_INDEX), checked: false},
{name: "hips-rotation", val: getRotation(HIPS_INDEX), checked: false},
{name: "spine2-translation", val: getTranslation(SPINE2_INDEX), checked: false},
{name: "spine2-rotation", val: getRotation(SPINE2_INDEX), checked: false}
];
tablet.emitScriptEvent(JSON.stringify(values));
} else if (msg.name === "enable-filtering") {
if (msg.val === "on") {
filterEnabled = true;
} else if (msg.val === "off") {
filterEnabled = false;
}
mappingChanged();
} else if (msg.name === "left-hand-translation") {
setTranslation(LEFT_HAND_INDEX, Number(msg.val));
} else if (msg.name === "left-hand-rotation") {
setRotation(LEFT_HAND_INDEX, Number(msg.val));
} else if (msg.name === "right-hand-translation") {
setTranslation(RIGHT_HAND_INDEX, Number(msg.val));
} else if (msg.name === "right-hand-rotation") {
setRotation(RIGHT_HAND_INDEX, Number(msg.val));
} else if (msg.name === "left-foot-translation") {
setTranslation(LEFT_FOOT_INDEX, Number(msg.val));
} else if (msg.name === "left-foot-rotation") {
setRotation(LEFT_FOOT_INDEX, Number(msg.val));
} else if (msg.name === "right-foot-translation") {
setTranslation(RIGHT_FOOT_INDEX, Number(msg.val));
} else if (msg.name === "right-foot-rotation") {
setRotation(RIGHT_FOOT_INDEX, Number(msg.val));
} else if (msg.name === "hips-translation") {
setTranslation(HIPS_INDEX, Number(msg.val));
} else if (msg.name === "hips-rotation") {
setRotation(HIPS_INDEX, Number(msg.val));
} else if (msg.name === "spine2-translation") {
setTranslation(SPINE2_INDEX, Number(msg.val));
} else if (msg.name === "spine2-rotation") {
setRotation(SPINE2_INDEX, Number(msg.val));
}
}
tablet.screenChanged.connect(onScreenChanged);
function shutdownTabletApp() {
tablet.removeButton(tabletButton);
if (shown) {
tablet.webEventReceived.disconnect(onWebEventReceived);
tablet.gotoHomeScreen();
}
tablet.screenChanged.disconnect(onScreenChanged);
}
//
// end tablet app boiler plate
//
var filterEnabled = true;
var mapping;
function mappingChanged() {
if (mapping) {
mapping.disable();
}
if (filterEnabled) {
mapping = Controller.parseMapping(JSON.stringify(mappingJson));
mapping.enable();
}
}
function shownChanged(newShown) {
if (newShown) {
mappingChanged();
} else {
mapping.disable();
}
}
mappingChanged();
Script.scriptEnding.connect(function() {
if (mapping) {
mapping.disable();
}
tablet.removeButton(tabletButton);
});

View file

@ -1,374 +0,0 @@
//
// facialExpressions.js
// A script to set different emotions using blend shapes
//
// Author: Elisa Lupin-Jimenez
// Copyright High Fidelity 2018
//
// Licensed under the Apache 2.0 License
// See accompanying license file or http://apache.org/
//
// All assets are under CC Attribution Non-Commerical
// http://creativecommons.org/licenses/
//
(function() {
var TABLET_BUTTON_NAME = "EMOTIONS";
// TODO: ADD HTML LANDING PAGE
var TRANSITION_TIME_SECONDS = 0.25;
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var icon = "https://hifi-content.s3.amazonaws.com/elisalj/emoji_scripts/icons/emoji-i.svg";
var activeIcon = "https://hifi-content.s3.amazonaws.com/elisalj/emoji_scripts/icons/emoji-a.svg";
var isActive = true;
var controllerMappingName;
var controllerMapping;
var tabletButton = tablet.addButton({
icon: icon,
activeIcon: activeIcon,
text: TABLET_BUTTON_NAME,
isActive: true
});
var toggle = function() {
isActive = !isActive;
tabletButton.editProperties({isActive: isActive});
if (isActive) {
Controller.enableMapping(controllerMappingName);
} else {
setEmotion(DEFAULT);
Controller.disableMapping(controllerMappingName);
}
};
tabletButton.clicked.connect(toggle);
var DEFAULT = {
"EyeOpen_L": 0.00,
"EyeOpen_R": 0.00,
"EyeBlink_L": 0.00,
"EyeBlink_R": 0.00,
"EyeSquint_L": 0.00,
"EyeSquint_R": 0.00,
"BrowsD_L": 0.00,
"BrowsD_R": 0.00,
"BrowsU_L": 0.00,
"BrowsU_C": 0.00,
"JawOpen": 0.00,
"JawFwd": 0.00,
"MouthFrown_L": 0.00,
"MouthFrown_R": 0.00,
"MouthSmile_L": 0.00,
"MouthSmile_R": 0.00,
"MouthDimple_L": 0.00,
"MouthDimple_R": 0.00,
"LipsUpperClose": 0.00,
"LipsLowerClose": 0.00,
"LipsLowerOpen": 0.00,
"ChinUpperRaise": 0.00,
"Sneer": 0.00,
"Puff": 0.00
};
var SMILE = {
"EyeOpen_L": 0.00,
"EyeOpen_R": 0.00,
"EyeBlink_L": 0.30,
"EyeBlink_R": 0.30,
"EyeSquint_L": 0.90,
"EyeSquint_R": 0.90,
"BrowsD_L": 1.00,
"BrowsD_R": 1.00,
"BrowsU_L": 0.00,
"BrowsU_C": 0.00,
"JawOpen": 0.00,
"JawFwd": 0.00,
"MouthFrown_L": 0.00,
"MouthFrown_R": 0.00,
"MouthSmile_L": 1.00,
"MouthSmile_R": 1.00,
"MouthDimple_L": 1.00,
"MouthDimple_R": 1.00,
"LipsUpperClose": 0.40,
"LipsLowerClose": 0.30,
"LipsLowerOpen": 0.25,
"ChinUpperRaise": 0.35,
"Sneer": 0.00,
"Puff": 0.00
};
var LAUGH = {
"EyeOpen_L": 0.00,
"EyeOpen_R": 0.00,
"EyeBlink_L": 0.45,
"EyeBlink_R": 0.45,
"EyeSquint_L": 0.75,
"EyeSquint_R": 0.75,
"BrowsD_L": 0.00,
"BrowsD_R": 0.00,
"BrowsU_L": 0.00,
"BrowsU_C": 0.50,
"JawOpen": 0.50,
"JawFwd": 0.00,
"MouthFrown_L": 0.00,
"MouthFrown_R": 0.00,
"MouthSmile_L": 1.00,
"MouthSmile_R": 1.00,
"MouthDimple_L": 1.00,
"MouthDimple_R": 1.00,
"LipsUpperClose": 0.00,
"LipsLowerClose": 0.00,
"LipsLowerOpen": 0.00,
"ChinUpperRaise": 0.30,
"Sneer": 1.00,
"Puff": 0.30
};
var FLIRT = {
"EyeOpen_L": 0.00,
"EyeOpen_R": 0.00,
"EyeBlink_L": 0.50,
"EyeBlink_R": 0.50,
"EyeSquint_L": 0.25,
"EyeSquint_R": 0.25,
"BrowsD_L": 0.00,
"BrowsD_R": 1.00,
"BrowsU_L": 0.55,
"BrowsU_C": 0.00,
"JawOpen": 0.00,
"JawFwd": 0.00,
"MouthFrown_L": 0.00,
"MouthFrown_R": 0.00,
"MouthSmile_L": 0.50,
"MouthSmile_R": 0.00,
"MouthDimple_L": 1.00,
"MouthDimple_R": 1.00,
"LipsUpperClose": 0.00,
"LipsLowerClose": 0.00,
"LipsLowerOpen": 0.00,
"ChinUpperRaise": 0.00,
"Sneer": 0.00,
"Puff": 0.00
};
var SAD = {
"EyeOpen_L": 0.00,
"EyeOpen_R": 0.00,
"EyeBlink_L": 0.30,
"EyeBlink_R": 0.30,
"EyeSquint_L": 0.30,
"EyeSquint_R": 0.30,
"BrowsD_L": 0.00,
"BrowsD_R": 0.00,
"BrowsU_L": 0.00,
"BrowsU_C": 0.50,
"JawOpen": 0.00,
"JawFwd": 0.80,
"MouthFrown_L": 0.80,
"MouthFrown_R": 0.80,
"MouthSmile_L": 0.00,
"MouthSmile_R": 0.00,
"MouthDimple_L": 0.00,
"MouthDimple_R": 0.00,
"LipsUpperClose": 0.00,
"LipsLowerClose": 0.50,
"LipsLowerOpen": 0.00,
"ChinUpperRaise": 0.00,
"Sneer": 0.00,
"Puff": 0.00
};
var ANGRY = {
"EyeOpen_L": 1.00,
"EyeOpen_R": 1.00,
"EyeBlink_L": 0.00,
"EyeBlink_R": 0.00,
"EyeSquint_L": 1.00,
"EyeSquint_R": 1.00,
"BrowsD_L": 1.00,
"BrowsD_R": 1.00,
"BrowsU_L": 0.00,
"BrowsU_C": 0.00,
"JawOpen": 0.00,
"JawFwd": 0.00,
"MouthFrown_L": 0.50,
"MouthFrown_R": 0.50,
"MouthSmile_L": 0.00,
"MouthSmile_R": 0.00,
"MouthDimple_L": 0.00,
"MouthDimple_R": 0.00,
"LipsUpperClose": 0.50,
"LipsLowerClose": 0.50,
"LipsLowerOpen": 0.00,
"ChinUpperRaise": 0.00,
"Sneer": 0.50,
"Puff": 0.00
};
var FEAR = {
"EyeOpen_L": 1.00,
"EyeOpen_R": 1.00,
"EyeBlink_L": 0.00,
"EyeBlink_R": 0.00,
"EyeSquint_L": 0.00,
"EyeSquint_R": 0.00,
"BrowsD_L": 0.00,
"BrowsD_R": 0.00,
"BrowsU_L": 0.00,
"BrowsU_C": 1.00,
"JawOpen": 0.15,
"JawFwd": 0.00,
"MouthFrown_L": 0.30,
"MouthFrown_R": 0.30,
"MouthSmile_L": 0.00,
"MouthSmile_R": 0.00,
"MouthDimple_L": 0.00,
"MouthDimple_R": 0.00,
"LipsUpperClose": 0.00,
"LipsLowerClose": 0.00,
"LipsLowerOpen": 0.00,
"ChinUpperRaise": 0.00,
"Sneer": 0.00,
"Puff": 0.00
};
var DISGUST = {
"EyeOpen_L": 0.00,
"EyeOpen_R": 0.00,
"EyeBlink_L": 0.25,
"EyeBlink_R": 0.25,
"EyeSquint_L": 1.00,
"EyeSquint_R": 1.00,
"BrowsD_L": 1.00,
"BrowsD_R": 1.00,
"BrowsU_L": 0.00,
"BrowsU_C": 0.00,
"JawOpen": 0.00,
"JawFwd": 0.00,
"MouthFrown_L": 1.00,
"MouthFrown_R": 1.00,
"MouthSmile_L": 0.00,
"MouthSmile_R": 0.00,
"MouthDimple_L": 0.00,
"MouthDimple_R": 0.00,
"LipsUpperClose": 0.00,
"LipsLowerClose": 0.75,
"LipsLowerOpen": 0.00,
"ChinUpperRaise": 0.75,
"Sneer": 1.00,
"Puff": 0.00
};
function mixValue(valueA, valueB, percentage) {
return valueA + ((valueB - valueA) * percentage);
}
var lastEmotionUsed = DEFAULT;
var emotion = DEFAULT;
var isChangingEmotion = false;
var changingEmotionPercentage = 0.0;
Script.update.connect(function(deltaTime) {
if (!isChangingEmotion) {
return;
}
changingEmotionPercentage += deltaTime / TRANSITION_TIME_SECONDS;
if (changingEmotionPercentage >= 1.0) {
changingEmotionPercentage = 1.0;
isChangingEmotion = false;
if (emotion === DEFAULT) {
MyAvatar.hasScriptedBlendshapes = false;
}
}
for (var blendshape in emotion) {
MyAvatar.setBlendshape(blendshape,
mixValue(lastEmotionUsed[blendshape], emotion[blendshape], changingEmotionPercentage));
}
});
function setEmotion(currentEmotion) {
if (emotion !== lastEmotionUsed) {
lastEmotionUsed = emotion;
}
if (currentEmotion !== lastEmotionUsed) {
changingEmotionPercentage = 0.0;
emotion = currentEmotion;
isChangingEmotion = true;
MyAvatar.hasScriptedBlendshapes = true;
}
}
controllerMappingName = 'Hifi-FacialExpressions-Mapping';
controllerMapping = Controller.newMapping(controllerMappingName);
controllerMapping.from(Controller.Hardware.Keyboard.H).to(function(value) {
if (value !== 0) {
setEmotion(SMILE);
}
});
controllerMapping.from(Controller.Hardware.Keyboard.J).to(function(value) {
if (value !== 0) {
setEmotion(LAUGH);
}
});
controllerMapping.from(Controller.Hardware.Keyboard.K).to(function(value) {
if (value !== 0) {
setEmotion(FLIRT);
}
});
controllerMapping.from(Controller.Hardware.Keyboard.L).to(function(value) {
if (value !== 0) {
setEmotion(SAD);
}
});
controllerMapping.from(Controller.Hardware.Keyboard.V).to(function(value) {
if (value !== 0) {
setEmotion(ANGRY);
}
});
controllerMapping.from(Controller.Hardware.Keyboard.B).to(function(value) {
if (value !== 0) {
setEmotion(FEAR);
}
});
controllerMapping.from(Controller.Hardware.Keyboard.M).to(function(value) {
if (value !== 0) {
setEmotion(DISGUST);
}
});
controllerMapping.from(Controller.Hardware.Keyboard.N).to(function(value) {
if (value !== 0) {
setEmotion(DEFAULT);
}
});
Controller.enableMapping(controllerMappingName);
Script.scriptEnding.connect(function() {
tabletButton.clicked.disconnect(toggle);
tablet.removeButton(tabletButton);
Controller.disableMapping(controllerMappingName);
if (emotion !== DEFAULT || isChangingEmotion) {
isChangingEmotion = false;
for (var blendshape in DEFAULT) {
MyAvatar.setBlendshape(blendshape, DEFAULT[blendshape]);
}
MyAvatar.hasScriptedBlendshapes = false;
}
});
}());

View file

@ -1,17 +0,0 @@
//
// hmdRollControlDisable.js
//
// Created by David Rowe on 4 Jun 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
//
var hmdRollControlEnabled = false;
//print("HMD roll control: " + hmdRollControlEnabled);
MyAvatar.hmdRollControlEnabled = hmdRollControlEnabled;
Script.stop();

View file

@ -1,21 +0,0 @@
//
// hmdRollControlEnable.js
//
// Created by David Rowe on 4 Jun 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
//
var hmdRollControlEnabled = true;
var hmdRollControlDeadZone = 8.0; // deg
var hmdRollControlRate = 2.5; // deg/sec/deg
//print("HMD roll control: " + hmdRollControlEnabled + ", " + hmdRollControlDeadZone + ", " + hmdRollControlRate);
MyAvatar.hmdRollControlEnabled = hmdRollControlEnabled;
MyAvatar.hmdRollControlDeadZone = hmdRollControlDeadZone;
MyAvatar.hmdRollControlRate = hmdRollControlRate;
Script.stop();

View file

@ -1,103 +0,0 @@
//
// Created by Dante Ruiz 2017/04/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 recording = false;
var onRecordingScreen = false;
var passedSaveDirectory = false;
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var button = tablet.addButton({
text: "IRecord"
});
function onClick() {
if (onRecordingScreen) {
tablet.gotoHomeScreen();
onRecordingScreen = false;
} else {
tablet.loadQMLSource("hifi/tablet/InputRecorder.qml");
onRecordingScreen = true;
}
}
function onScreenChanged(type, url) {
onRecordingScreen = false;
passedSaveDirectory = false;
}
button.clicked.connect(onClick);
tablet.fromQml.connect(fromQml);
tablet.screenChanged.connect(onScreenChanged);
function fromQml(message) {
switch (message.method) {
case "Start":
startRecording();
break;
case "Stop":
stopRecording();
break;
case "Save":
saveRecording();
break;
case "Load":
loadRecording(message.params.file);
break;
case "playback":
startPlayback();
break;
}
}
function startRecording() {
Controller.startInputRecording();
recording = true;
}
function stopRecording() {
Controller.stopInputRecording();
recording = false;
}
function saveRecording() {
Controller.saveInputRecording();
}
function loadRecording(file) {
Controller.loadInputRecording(file);
}
function startPlayback() {
Controller.startInputPlayback();
}
function sendToQml(message) {
tablet.sendToQml(message);
}
function update() {
if (!passedSaveDirectory) {
var directory = Controller.getInputRecorderSaveDirectory();
sendToQml({method: "path", params: directory});
passedSaveDirectory = true;
}
sendToQml({method: "update", params: recording});
}
Script.setInterval(update, 60);
Script.scriptEnding.connect(function () {
button.clicked.disconnect(onClick);
if (tablet) {
tablet.removeButton(button);
}
Controller.stopInputRecording();
});
}());

View file

@ -1,85 +0,0 @@
(function() {
var BALLOT_X = '&#10007;';
var CHECKMARK = '&#10003;';
var DOWN_RIGHT_ARROW = '&#8627;';
var PASSED = 'passed';
var lastSpecStartTime;
function ConsoleReporter(options) {
var startTime = new Date().getTime();
var errorCount = 0, pending = [];
this.jasmineStarted = function (obj) {
print('Jasmine started with ' + obj.totalSpecsDefined + ' tests.');
};
this.jasmineDone = function (obj) {
var ERROR = errorCount === 1 ? 'error' : 'errors';
var endTime = new Date().getTime();
print('<hr />');
if (errorCount === 0) {
print ('<span style="color:green">All enabled tests passed!</span>');
} else {
print('<span style="color:red">Tests completed with ' +
errorCount + ' ' + ERROR + '.<span>');
}
if (pending.length) {
print ('<span style="color:darkorange">disabled: <br />&nbsp;&nbsp;&nbsp;'+
pending.join('<br />&nbsp;&nbsp;&nbsp;')+'</span>');
}
print('Tests completed in ' + (endTime - startTime) + 'ms.');
};
this.suiteStarted = function(obj) {
print(obj.fullName);
};
this.suiteDone = function(obj) {
print('');
};
this.specStarted = function(obj) {
lastSpecStartTime = new Date().getTime();
};
this.specDone = function(obj) {
if (obj.status === 'pending') {
pending.push(obj.fullName);
return print('...(pending ' + obj.fullName +')');
}
var specEndTime = new Date().getTime();
var symbol = obj.status === PASSED ?
'<span style="color:green">' + CHECKMARK + '</span>' :
'<span style="color:red">' + BALLOT_X + '</span>';
print('... ' + obj.fullName + ' ' + symbol + ' ' + '<span style="color:orange">[' +
(specEndTime - lastSpecStartTime) + 'ms]</span>');
var specErrors = obj.failedExpectations.length;
errorCount += specErrors;
for (var i = 0; i < specErrors; i++) {
print('<span style="margin-right:0.5em"></span>' + DOWN_RIGHT_ARROW +
'<span style="color:red"> ' +
obj.failedExpectations[i].message + '</span>');
}
};
return this;
}
setTimeout = Script.setTimeout;
setInterval = Script.setInterval;
clearTimeout = Script.clearTimeout;
clearInterval = Script.clearInterval;
var jasmine = this.jasmine = jasmineRequire.core(jasmineRequire);
var env = jasmine.getEnv();
env.addReporter(new ConsoleReporter());
var jasmineInterface = jasmineRequire.interface(jasmine, env);
extend(this, jasmineInterface);
function extend(destination, source) {
for (var property in source) {
if (source.hasOwnProperty(property)) {
destination[property] = source[property];
}
}
return destination;
}
}());

File diff suppressed because it is too large Load diff

View file

@ -1,315 +0,0 @@
//
// 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
//
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);
}
}
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)
};
}
map = function(value, min1, max1, min2, max2) {
return min2 + (max2 - min2) * ((value - min1) / (max1 - min1));
}
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));
}
randomColor = function() {
return {
red: randInt(0, 255),
green: randInt(0, 255),
blue: randInt(0, 255)
}
}
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))
}
easeIn = function(t) {
return Math.pow(t / 1, 5);
}

View file

@ -1,381 +0,0 @@
"use strict";
/*jslint nomen: true, plusplus: true, vars: true */
/*global Messages, Script, MyAvatar, AvatarList, Entities, print */
// Created by Howard Stearns
// 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
//
// Allows cooperating scripts to pass a "virtual baton" between them,
// which is useful when part of a script should only be executed by
// the one participant that is holding this particular baton.
//
// A virtual baton is simply any string agreed upon by the scripts
// that use it. Only one script at a time can hold the baton, and it
// holds it until that script releases it, or the other scripts
// determine that the holding script is not responding. The script
// automatically determines who among claimants has the baton, if anyone,
// and holds an "election" if necessary.
//
// See entityScript/tribble.js as an example, and the functions
// virtualBaton(), claim(), release().
//
// Answers a new virtualBaton for the given parameters, of which 'key'
// is required.
function virtualBatonf(options) {
// Answer averages (number +/- variability). Avoids having everyone act in lockstep.
function randomize(number, variability) {
var allowedDeviation = number * variability; // one side of the deviation range
var allowedDeviationRange = allowedDeviation * 2; // total range for +/- deviation
var randomDeviation = Math.random() * allowedDeviationRange;
var result = number - allowedDeviation + randomDeviation;
return result;
}
// Allow testing outside in a harness outside of High Fidelity.
// See sourceCodeSandbox/tests/mocha/test/testVirtualBaton.js
var globals = options.globals || {},
messages = globals.Messages || Messages,
myAvatar = globals.MyAvatar || MyAvatar,
avatarList = globals.AvatarList || AvatarList,
entities = globals.Entities || Entities,
timers = globals.Script || Script,
log = globals.print || print;
var batonName = options.batonName, // The identify of the baton.
// instanceId is the identify of this particular copy of the script among all copies using the same batonName
// in the domain. For example, if you wanted only one entity among multiple entity scripts to hold the baton,
// you could specify virtualBaton({batonName: 'someBatonName', instanceId: MyAvatar.sessionUUID + entityID}).
instanceId = options.instanceId || myAvatar.sessionUUID,
// virtualBaton() returns the exports object with properties. You can pass in an object to be side-effected.
exports = options.exports || {},
// Handy to set false if we believe the optimizations are wrong, or to use both values in a test harness.
useOptimizations = (options.useOptimizations === undefined) ? true : options.useOptimizations,
electionTimeout = options.electionTimeout || randomize(500, 0.2), // ms. If no winner in this time, hold a new election.
recheckInterval = options.recheckInterval || randomize(500, 0.2), // ms. Check that winners remain connected.
// If you supply your own instanceId, you might also supply a connectionTest that answers
// truthy iff the given id is still valid and connected, and is run at recheckInterval. You
// can use exports.validId (see below), and the default answers truthy if id is valid or a
// concatenation of two valid ids. (This handles the most common cases of instanceId being
// either (the default) MyAvatar.sessionUUID, an entityID, or the concatenation (in either
// order) of both.)
connectionTest = options.connectionTest || function connectionTest(id) {
var idLength = 38;
if (id.length === idLength) {
return exports.validId(id);
}
return (id.length === 2 * idLength) && exports.validId(id.slice(0, idLength)) && exports.validId(id.slice(idLength));
};
if (!batonName) {
throw new Error("A virtualBaton must specify a batonName.");
}
// Truthy if id exists as either a connected avatar or valid entity.
exports.validId = function validId(id) {
var avatar = avatarList.getAvatar(id);
if (avatar && (avatar.sessionUUID === id)) {
return true;
}
var properties = entities.getEntityProperties(id, ['type']);
return properties && properties.type;
};
// Various logging, controllable through options.
function debug() { // Display the arguments not just [Object object].
log.apply(null, [].map.call(arguments, JSON.stringify));
}
function debugFlow() {
if (options.debugFlow) {
debug.apply(null, arguments);
}
}
function debugSend(destination, operation, data) {
if (options.debugSend) {
debug('baton:', batonName, instanceId, 's=>', destination, operation, data);
}
}
function debugReceive(senderID, operation, data) { // senderID is client sessionUUID -- not necessarily instanceID!
if (options.debugReceive) {
debug('baton:', batonName, senderID, '=>r', instanceId, operation, data);
}
}
// Messages: Just synactic sugar for hooking things up to Messages system.
// We create separate subchannel strings for each operation within our general channelKey, instead of using
// a switch in the receiver.
var channelKey = "io.highfidelity.virtualBaton:" + batonName,
subchannelHandlers = {}, // Message channel string => {receiver, op}
subchannelKeys = {}; // operation => Message channel string
function subchannelKey(operation) {
return channelKey + ':' + operation;
}
function receive(operation, handler) { // Record a handler for an operation on our channelKey
var subKey = subchannelKey(operation);
subchannelHandlers[subKey] = {receiver: handler, op: operation};
subchannelKeys[operation] = subKey;
messages.subscribe(subKey);
}
function sendHelper(subchannel, data) {
var message = JSON.stringify(data);
messages.sendMessage(subchannel, message);
}
function send1(operation, destination, data) { // Send data for an operation to just one destination on our channelKey.
debugSend(destination, operation, data);
sendHelper(subchannelKey(operation) + destination, data);
}
function send(operation, data) { // Send data for an operation on our channelKey.
debugSend('-', operation, data);
sendHelper(subchannelKeys[operation], data);
}
function messageHandler(channel, messageString, senderID) {
var handler = subchannelHandlers[channel];
if (!handler) {
return;
}
var data = JSON.parse(messageString);
debugReceive(senderID, handler.op, data);
handler.receiver(data);
}
messages.messageReceived.connect(messageHandler);
var nPromises = 0, nAccepted = 0, electionWatchdog;
// It would be great if we had a way to know how many subscribers our channel has. Failing that...
var nNack = 0, previousNSubscribers = 0, lastGathering = 0, thisTimeout = electionTimeout;
function nSubscribers() { // Answer the number of subscribers.
// To find nQuorum, we need to know how many scripts are being run using this batonName, which isn't
// the same as the number of clients!
//
// If we overestimate by too much, we may fail to reach consensus, which triggers a new
// election proposal, so we take the number of acceptors to be the max(nPromises, nAccepted)
// + nNack reported in the previous round.
//
// If we understimate by too much, there can be different pockets on the Internet that each
// believe they have agreement on different holders of the baton, which is precisely what
// the virtualBaton is supposed to avoid. Therefore we need to allow 'nack' to gather stragglers.
var now = Date.now(), elapsed = now - lastGathering;
if (elapsed >= thisTimeout) {
previousNSubscribers = Math.max(nPromises, nAccepted) + nNack;
lastGathering = now;
} // ...otherwise we use the previous value unchanged.
// On startup, we do one proposal that we cannot possibly close, so that we'll
// lock things up for the full electionTimeout to gather responses.
if (!previousNSubscribers) {
var LARGE_INTEGER = Number.MAX_SAFE_INTEGER || (-1 >>> 1); // QT doesn't define the ECMA constant. Max int will do for our purposes.
previousNSubscribers = LARGE_INTEGER;
}
return previousNSubscribers;
}
// MAIN ALGORITHM
//
// Internally, this uses the Paxos algorith to hold elections.
// Alternatively, we could have the message server pick and maintain a winner, but it would
// still have to deal with the same issues of verification in the presence of lost/delayed/reordered messages.
// Paxos is known to be optimal under these circumstances, except that its best to have a dedicated proposer
// (such as the server).
function betterNumber(number, best) {
return (number.number || 0) > best.number;
}
// Paxos Proposer behavior
var proposalNumber = 0,
nQuorum = 0,
bestPromise = {number: 0},
claimCallback,
releaseCallback;
function propose() { // Make a new proposal, so that we learn/update the proposalNumber and winner.
// Even though we send back a 'nack' if the proposal is obsolete, with network errors
// there's no way to know for certain that we've failed. The electionWatchdog will try a new
// proposal if we have not been accepted by a quorum after election Timeout.
if (electionWatchdog) {
// If we had a means of determining nSubscribers other than by counting, we could just
// timers.clearTimeout(electionWatchdog) and not return.
return;
}
thisTimeout = randomize(electionTimeout, 0.5); // Note use in nSubcribers.
electionWatchdog = timers.setTimeout(function () {
electionWatchdog = null;
propose();
}, thisTimeout);
var nAcceptors = nSubscribers();
nQuorum = Math.floor(nAcceptors / 2) + 1;
proposalNumber = Math.max(proposalNumber, bestPromise.number) + 1;
debugFlow('baton:', batonName, instanceId, 'propose', proposalNumber,
'claim:', !!claimCallback, 'nAcceptors:', nAcceptors, nPromises, nAccepted, nNack);
nPromises = nAccepted = nNack = 0;
send('prepare!', {number: proposalNumber, proposerId: instanceId});
}
// We create a distinguished promise subchannel for our id, because promises need only be sent to the proposer.
receive('promise' + instanceId, function (data) {
if (betterNumber(data, bestPromise)) {
bestPromise = data;
}
if ((data.proposalNumber === proposalNumber) && (++nPromises >= nQuorum)) { // Note check for not being a previous round
var answer = {number: data.proposalNumber, proposerId: data.proposerId, winner: bestPromise.winner}; // Not data.number.
if (!answer.winner || (answer.winner === instanceId)) { // We get to pick.
answer.winner = claimCallback ? instanceId : null;
}
send('accept!', answer);
}
});
receive('nack' + instanceId, function (data) { // An acceptor reports more recent data...
if (data.proposalNumber === proposalNumber) {
nNack++; // For updating nQuorum.
// IWBNI if we started our next proposal right now/here, but we need a decent nNack count.
// Lets save that optimization for another day...
}
});
// Paxos Acceptor behavior
var bestProposal = {number: 0}, accepted = {};
function acceptedId() {
return accepted && accepted.winner;
}
receive('prepare!', function (data) {
var response = {proposalNumber: data.number, proposerId: data.proposerId};
if (betterNumber(data, bestProposal)) {
bestProposal = data;
if (accepted.winner && connectionTest(accepted.winner)) {
response.number = accepted.number;
response.winner = accepted.winner;
}
send1('promise', data.proposerId, response);
} else {
send1('nack', data.proposerId, response);
}
});
receive('accept!', function (data) {
if (!betterNumber(bestProposal, data)) {
bestProposal = accepted = data; // Update both with current data. Might have missed the proposal earlier.
if (useOptimizations) {
// The Paxos literature describes every acceptor sending 'accepted' to
// every proposer and learner. In our case, these are the same nodes that received
// the 'accept!' message, so we can send to just the originating proposer and invoke
// our own accepted handler directly.
// Note that this optimization cannot be used with Byzantine Paxos (which needs another
// multi-broadcast to detect lying and collusion).
debugSend('/', 'accepted', data);
debugReceive(instanceId, 'accepted', data); // direct on next line, which doesn't get logging.
subchannelHandlers[subchannelKey('accepted') + instanceId].receiver(data);
if (data.proposerId !== instanceId) { // i.e., we didn't already do it directly on the line above.
send1('accepted', data.proposerId, data);
}
} else {
send('accepted', data);
}
} else {
send1('nack', data.proposerId, {proposalNumber: data.number});
}
});
// Paxos Learner behavior.
function localRelease() {
var callback = releaseCallback;
debugFlow('baton:', batonName, 'localRelease', 'callback:', !!releaseCallback);
if (!releaseCallback) {
return;
} // Already released, but we might still receive a stale message. That's ok.
releaseCallback = undefined;
callback(batonName); // Pass batonName so that clients may use the same handler for different batons.
}
receive('accepted' + (useOptimizations ? instanceId : ''), function (data) { // See note in 'accept!' regarding use of instanceId here.
if (betterNumber(accepted, data)) { // Especially when !useOptimizations, we can receive other acceptances late.
return;
}
var oldAccepted = accepted;
debugFlow('baton:', batonName, instanceId, 'accepted', data.number, data.winner);
accepted = data;
// If we are proposer, make sure we get a quorum of acceptances.
if ((data.proposerId === instanceId) && (data.number === proposalNumber) && (++nAccepted >= nQuorum)) {
if (electionWatchdog) {
timers.clearTimeout(electionWatchdog);
electionWatchdog = null;
}
}
// If we are the winner -- regardless of whether we were the proposer.
if (acceptedId() === instanceId) {
if (claimCallback) {
var callback = claimCallback;
claimCallback = undefined;
callback(batonName);
} else if (!releaseCallback) { // We won, but have been released and are no longer interested.
// Propose that someone else take the job.
timers.setTimeout(propose, 0); // Asynchronous to queue message handling if some are synchronous and others not.
}
} else if (releaseCallback && (oldAccepted.winner === instanceId)) { // We've been released by someone else!
localRelease(); // This can happen if enough people thought we'd disconnected.
}
});
// Public Interface
//
// Registers an intent to hold the baton:
// Calls onElection(batonName) once, if you are elected by the scripts
// to be the unique holder of the baton, which may be never.
// Calls onRelease(batonName) once, if the baton held by you is released,
// whether this is by you calling release(), or by losing
// an election when you become disconnected.
// You may claim again at any time after the start of onRelease
// being called.
exports.claim = function claim(onElection, onRelease) {
debugFlow('baton:', batonName, instanceId, 'claim');
if (claimCallback) {
log("Ignoring attempt to claim virtualBaton " + batonName + ", which is already waiting for claim.");
return;
}
if (releaseCallback) {
log("Ignoring attempt to claim virtualBaton " + batonName + ", which is somehow incorrect released, and that should not happen.");
return;
}
claimCallback = onElection;
releaseCallback = onRelease;
propose();
return exports; // Allows chaining. e.g., var baton = virtualBaton({batonName: 'foo'}.claim(onClaim, onRelease);
};
// Release the baton you hold, or just log that you are not holding it.
exports.release = function release(optionalReplacementOnRelease) {
debugFlow('baton:', batonName, instanceId, 'release');
if (optionalReplacementOnRelease) { // If you want to change.
releaseCallback = optionalReplacementOnRelease;
}
if (acceptedId() !== instanceId) {
log("Ignoring attempt to release virtualBaton " + batonName + ", which is not being held.");
return;
}
localRelease();
if (!claimCallback) { // No claim set in release callback.
propose();
}
return exports;
};
exports.recheckWatchdog = timers.setInterval(function recheck() {
var holder = acceptedId(); // If we're waiting and we notice the holder is gone, ...
if (holder && claimCallback && !electionWatchdog && !connectionTest(holder)) {
bestPromise.winner = null; // used if the quorum agrees that old winner is not there
propose(); // ... propose an election.
}
}, recheckInterval);
exports.unload = function unload() { // Disconnect from everything.
messages.messageReceived.disconnect(messageHandler);
timers.clearInterval(exports.recheckWatchdog);
if (electionWatchdog) {
timers.clearTimeout(electionWatchdog);
}
electionWatchdog = claimCallback = releaseCallback = null;
Object.keys(subchannelHandlers).forEach(messages.unsubscribe);
debugFlow('baton:', batonName, instanceId, 'unload');
return exports;
};
// Gather nAcceptors by making two proposals with some gathering time, even without a claim.
propose();
return exports;
}
if (typeof module !== 'undefined') { // Allow testing in nodejs.
module.exports = virtualBatonf;
} else {
virtualBaton = virtualBatonf;
}

View file

@ -1,325 +0,0 @@
//
// sunModel.js
// scripts/developer
//
// Created by Nissim Hadar on 2017/12/27.
// Copyright 2013 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
//
// Sun angle is based on the NOAA model - see https://www.esrl.noaa.gov/gmd/grad/solcalc/
//
(function() {
// Utility functions for trig. calculations
function toRadians(angle_degs) {
return angle_degs * (Math.PI / 180);
}
function toDegrees(angle_rads) {
return angle_rads * (180.0 / Math.PI);
}
// Code to check if Daylight Savings is active
Date.prototype.stdTimezoneOffset = function() {
var fy = this.getFullYear();
if (!Date.prototype.stdTimezoneOffset.cache.hasOwnProperty(fy)) {
var maxOffset = new Date(fy, 0, 1).getTimezoneOffset();
var monthsTestOrder = [6, 7, 5, 8, 4, 9, 3, 10, 2, 11, 1];
for(var mi = 0;mi < 12; ++mi) {
var offset = new Date(fy, monthsTestOrder[mi], 1).getTimezoneOffset();
if (offset != maxOffset) {
maxOffset = Math.max(maxOffset, offset);
break;
}
}
Date.prototype.stdTimezoneOffset.cache[fy] = maxOffset;
}
return Date.prototype.stdTimezoneOffset.cache[fy];
};
// Cache the result for per year stdTimezoneOffset so that you don't need to recalculate it when testing multiple dates in
// the same year.
Date.prototype.stdTimezoneOffset.cache = {};
Date.prototype.isDST = function() {
return this.getTimezoneOffset() < this.stdTimezoneOffset();
};
// The Julian Date is the number of days (fractional) that have elapsed since Jan 1st, 4713 BC
// See https://quasar.as.utexas.edu/BillInfo/JulianDatesG.html
function getJulianDay(dateTime) {
var month = dateTime.getMonth() + 1;
var day = dateTime.getDate() + 1;
var year = dateTime.getFullYear();
if (month <= 2) {
year -= 1;
month += 12;
}
var A = Math.floor(year / 100);
var B = 2 - A + Math.floor(A / 4);
return Math.floor(365.25 * (year + 4716)) + Math.floor(30.6001 * (month + 1)) + day + B - 1524.5;
}
function getMinutes(dateTime) {
var hours = dateTime.getHours();
var minutes = dateTime.getMinutes();
var seconds = dateTime.getSeconds();
if (Date.prototype.isDST()) {
hour -= 1;
}
return hours * 60 + minutes + seconds / 60.0;
}
function calcGeomMeanAnomalySun(t) {
var M = 357.52911 + t * (35999.05029 - 0.0001537 * t);
return M; // in degrees
}
function calcSunEqOfCenter(t) {
var m = calcGeomMeanAnomalySun(t);
var mrad = toRadians(m);
var sinm = Math.sin(mrad);
var sin2m = Math.sin(mrad + mrad);
var sin3m = Math.sin(mrad + mrad + mrad);
var C = sinm * (1.914602 - t * (0.004817 + 0.000014 * t)) + sin2m * (0.019993 - 0.000101 * t) + sin3m * 0.000289;
return C; // in degrees
}
function calcGeomMeanLongSun(t) {
var L0 = 280.46646 + t * (36000.76983 + t*(0.0003032))
while(L0 > 360.0) {
L0 -= 360.0
}
while(L0 < 0.0) {
L0 += 360.0
}
return L0 // in degrees
}
function calcSunTrueLong(t) {
var l0 = calcGeomMeanLongSun(t);
var c = calcSunEqOfCenter(t);
var O = l0 + c;
return O; // in degrees
}
function calcSunApparentLong(t) {
var o = calcSunTrueLong(t);
var omega = 125.04 - 1934.136 * t;
var lambda = o - 0.00569 - 0.00478 * Math.sin(toRadians(omega));
return lambda; // in degrees
}
function calcMeanObliquityOfEcliptic(t) {
var seconds = 21.448 - t * (46.8150 + t * (0.00059 - t * (0.001813)));
var e0 = 23.0 + (26.0 + (seconds / 60.0)) / 60.0;
return e0; // in degrees
}
function calcObliquityCorrection(t) {
var e0 = calcMeanObliquityOfEcliptic(t);
var omega = 125.04 - 1934.136 * t;
var e = e0 + 0.00256 * Math.cos(toRadians(omega));
return e; // in degrees
}
function calcSunDeclination(t) {
var e = calcObliquityCorrection(t);
var lambda = calcSunApparentLong(t);
var sint = Math.sin(toRadians(e)) * Math.sin(toRadians(lambda));
var theta = toDegrees(Math.asin(sint));
return theta; // in degrees
}
function calcEccentricityEarthOrbit(t) {
var e = 0.016708634 - t * (0.000042037 + 0.0000001267 * t);
return e; // unitless
}
function calcEquationOfTime(t) {
// Converts from "mean" solar day (i.e. days that are exactly 24 hours)
// to apparent solar day (as observed)
// This is essentially the east-west component of the analemma.
//
// This is caused by 2 effects: the obliquity of the ecliptic, the eccentricity of earth's orbit
var epsilon = calcObliquityCorrection(t);
var l0 = calcGeomMeanLongSun(t);
var e = calcEccentricityEarthOrbit(t);
var m = calcGeomMeanAnomalySun(t);
var y = Math.tan(toRadians(epsilon) / 2.0);
y *= y;
var sin2l0 = Math.sin(2.0 * toRadians(l0));
var sinm = Math.sin(toRadians(m));
var cos2l0 = Math.cos(2.0 * toRadians(l0));
var sin4l0 = Math.sin(4.0 * toRadians(l0));
var sin2m = Math.sin(2.0 * toRadians(m));
var Etime = y * sin2l0 - 2.0 * e * sinm + 4.0 * e * y * sinm * cos2l0 -
0.5 * y * y * sin4l0 - 1.25 * e * e * sin2m;
return toDegrees(Etime) * 4.0; // in minutes of time
}
function calcSunTrueAnomaly(t) {
var m = calcGeomMeanAnomalySun(t);
var c = calcSunEqOfCenter(t);
var v = m + c;
return v; // in degrees
}
function calcSunRadVector(t) {
var v = calcSunTrueAnomaly(t);
var e = calcEccentricityEarthOrbit(t);
var R = (1.000001018 * (1 - e * e)) / (1 + e * Math.cos(toRadians(v)));
return R; // in AUs
}
function parseJSON(json) {
try {
return JSON.parse(json);
} catch (e) {
return undefined;
}
}
var COMPUTATION_CYCLE = 5000; // Run every 5 seconds
this.preload = function(entityID) { // We don't have the entityID before the preload
// Define user data
var userDataProperties = {
"userData": "{ \"latitude\": 47.0, \"longitude\": 122.0 }"
};
Entities.editEntity(entityID, userDataProperties);
Script.setInterval(
function() {
// Read back user data
var userData = Entities.getEntityProperties(entityID, 'userData').userData;
var data = parseJSON(userData);
var latitude_degs = data.latitude;
var longitude_degs = data.longitude;
// These are used a lot
var latitude = toRadians(latitude_degs);
var longitude = toRadians(longitude_degs);
var dateTime = new Date();
var julianDay = getJulianDay(dateTime);
var localTimeMinutes = getMinutes(dateTime);
var timeZone = -dateTime.getTimezoneOffset() / 60;
var totalTime = julianDay + localTimeMinutes/1440.0 - timeZone / 24.0;
// J2000.0 is the epoch starting Jan 1st, 2000 (noon), expressed as a Julian day
var J2000 = 2451545.0
// Number of years that have passed since J2000.0
var julianDayModified = (J2000 - 2451545.0)/36525.0;
var eqTime = calcEquationOfTime(julianDayModified)
var theta_rads = toRadians(calcSunDeclination(julianDayModified));
var solarTimeFix = eqTime + 4.0 * longitude_degs - 60.0 * timeZone;
var earthRadVec = calcSunRadVector(julianDayModified);
var trueSolarTime = localTimeMinutes + solarTimeFix;
while (trueSolarTime > 1440) {
trueSolarTime -= 1440;
}
var hourAngle = trueSolarTime / 4.0 - 180.0;
if (hourAngle < -180.0) {
hourAngle += 360.0;
}
var hourAngleRadians = toRadians(hourAngle);
var csz = Math.sin(latitude) * Math.sin(theta_rads) +
Math.cos(latitude) * Math.cos(theta_rads) * Math.cos(hourAngleRadians);
csz = Math.min(1.0, Math.max(-1.0, csz));
var zenith_degs = toDegrees(Math.acos(csz));
var azDenom = ( Math.cos(latitude) * Math.sin(toRadians(zenith_degs)));
if (Math.abs(azDenom) > 0.001) {
azRad = (( Math.sin(latitude) * Math.cos(toRadians(zenith_degs)) ) - Math.sin(theta_rads)) / azDenom;
if (Math.abs(azRad) > 1.0) {
if (azRad < 0.0) {
azRad = -1.0;
} else {
azRad = 1.0;
}
}
var solarAzimuth_degs = 180.0 - toDegrees(Math.acos(azRad))
if (hourAngle > 0.0) {
solarAzimuth_degs = -solarAzimuth_degs;
}
} else {
if (latitude_degs > 0.0) {
solarAzimuth_degs = 180.0;
} else {
solarAzimuth_degs = 0.0;
}
}
if (solarAzimuth_degs < 0.0) {
solarAzimuth_degs += 360.0;
}
// Atmospheric Refraction correction
var exoatmElevation = 90.0 - zenith_degs;
if (exoatmElevation > 85.0) {
var refractionCorrection = 0.0;
} else {
var te = Math.tan(toRadians(exoatmElevation));
if (exoatmElevation > 5.0) {
var refractionCorrection = 58.1 / te - 0.07 / (te * te * te) + 0.000086 / (te * te * te * te * te);
} else if (exoatmElevation > -0.575) {
var refractionCorrection =
1735.0 + exoatmElevation *
(-518.2 + exoatmElevation * (103.4 + exoatmElevation * (-12.79 + exoatmElevation * 0.711)));
} else {
var refractionCorrection = -20.774 / te;
}
refractionCorrection = refractionCorrection / 3600.0;
}
var solarZenith = zenith_degs - refractionCorrection;
var solarAltitude_degs = 90.0 - solarZenith; // aka solar elevation
// Convert to XYZ
var solarAltitude = toRadians(solarAltitude_degs);
var solarAzimuth = toRadians(solarAzimuth_degs);
var xPos = Math.cos(solarAltitude) * Math.sin(solarAzimuth);
var zPos = Math.cos(solarAltitude) * Math.cos(solarAzimuth);
var yPos = -Math.sin(solarAltitude);
// Compute intensity, modelling the atmosphere as a spherical shell
// The optical air mass ratio at zenith is 1.0, and around 38.0 at the horizon
// The ratio is limited between 1 and 38
var EARTH_RADIUS_KM = 6371.0;
var ATMOSPHERE_THICKNESS_KM = 9.0;
var r = EARTH_RADIUS_KM / ATMOSPHERE_THICKNESS_KM;
var opticalAirMassRatio = Math.sqrt(r * r * csz * csz + 2 * r + 1) - r * csz;
opticalAirMassRatio = Math.min(38.0, Math.max(1.0, opticalAirMassRatio));
Entities.editEntity(
entityID, {
keyLight : {
direction: { x: xPos, y: yPos, z: zPos },
intensity: 1.0 / opticalAirMassRatio
}
}
);
},
COMPUTATION_CYCLE
);
};
});

View file

@ -1 +0,0 @@
cube_texture.ktx

View file

@ -1,96 +0,0 @@
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import stylesUit 1.0 as HifiStylesUit
import controlsUit 1.0 as HifiControlsUit
Item {
visible: true
width: 640
height: 480
Introspector {
id: introspector
properties: ['realFrom', 'realTo', 'realValue', 'realStepSize', 'decimals']
visible: true
y: 50
x: 130
}
HifiStylesUit.HifiConstants {
id: hifi
}
TabBar {
id: bar
width: parent.width
TabButton {
text: "Spinbox"
}
TabButton {
text: "... Other Controls"
}
}
StackLayout {
id: controlsLayout
currentIndex: bar.currentIndex
anchors.top: bar.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 20
Item {
id: spinboxTab
anchors.fill: parent
Column {
spacing: 20
HifiControlsUit.SpinBox {
realValue: 5.0
realFrom: 16.0
realTo: 20.0
decimals: 2
realStepSize: 0.01
width: 100
height: 30
colorScheme: hifi.colorSchemes.dark
onFocusChanged: {
if(focus) {
introspector.object = this
}
}
}
HifiControlsUit.SpinBox {
realValue: 5.0
realFrom: 1.0
realTo: 20.0
decimals: 2
realStepSize: 0.01
width: 100
height: 30
colorScheme: hifi.colorSchemes.light
onFocusChanged: {
if(focus) {
introspector.object = this
}
}
}
}
}
Item {
id: otherTab
}
}
}

View file

@ -1,166 +0,0 @@
import QtQuick 2.1;
import QtQuick.Window 2.1;
MouseArea {
id: base;
opacity: 0.65;
// anchors.fill: parent;
width: 400;
height: 300;
drag.target: list;
onWheel: { }
onClicked: { object = null }
property var object: null
onObjectChanged: {
visible = (object != null)
}
property var properties: []
onPropertiesChanged: {
console.debug('properties: ', JSON.stringify(properties, 4, 0))
}
function getPropertiesList(obj) {
var props = [];
var propertiesObject = obj;
if(properties.length !== 0) {
propertiesObject = {};
for(var i = 0; i < properties.length; ++i) {
propertiesObject[properties[i]] = properties[i];
}
}
for(var prop in propertiesObject) {
var info = {'name' : prop};
var value = obj[prop];
var typeOfValue = typeof(value);
if(typeof(value) === 'string') {
info['type'] = 'string'
} else if(typeof(value) === 'number') {
if(Number.isInteger(value))
info['type'] = 'int'
else
info['type'] = 'float'
} else if(typeof(value) === 'boolean') {
info['type'] = 'boolean'
} else if(typeof(value) === 'function') {
continue;
}
/*
if(prop !== 'parent' && prop !== 'data' && prop !== 'children')
console.debug('typeof(value): ', typeof(value), JSON.stringify(value, null, 4));
*/
info['subName'] = ''
props.push(info);
}
return props;
}
Rectangle {
color: "lightgray";
anchors.fill: list;
anchors.margins: -50;
}
ListView {
id: list;
x: 50;
y: 50;
width: 400;
height: 300;
spacing: 5;
model: object !== null ? getPropertiesList(object) : [];
header: Text {
text: object !== null ? object.toString () : '';
font.bold: true;
font.pixelSize: 20;
}
delegate: Row {
spacing: 20;
Column {
width: 180;
Text {
text: (modelData ["subName"] !== "" ? (modelData ["name"] + "." + modelData ["subName"]) : modelData ["name"]);
font.pixelSize: 16;
}
}
Column {
width: 200;
Text {
text: {
return modelData ["type"]
}
font.pixelSize: 10;
}
TextInput {
id: input;
text: display;
width: parent.width;
font.pixelSize: 16;
font.underline: (text !== display);
Keys.onReturnPressed: { save (); }
Keys.onEnterPressed: { save (); }
Keys.onEscapePressed: { cancel (); }
property string display : "";
function save () {
var tmp;
switch (modelData ["type"]) {
case 'boolean':
tmp = (text === "true" || text === "1");
break;
case 'float':
tmp = parseFloat (text);
break;
case 'int':
tmp = parseInt (text);
break;
case 'string':
tmp = text;
break;
default:
break;
}
if (modelData ["subName"] !== "") {
object [modelData ["name"]][modelData ["subName"]] = tmp;
}
else {
object [modelData ["name"]] = tmp;
}
text = display;
}
function cancel () {
text = display;
}
Binding on text { value: input.display; }
Binding on display {
value: {
var ret = (modelData ["subName"] !== ""
? object [modelData ["name"]][modelData ["subName"]]
: object [modelData ["name"]]);
return ret.toString ();
}
}
Rectangle {
z: -1;
color: "white";
anchors.fill: parent;
}
}
}
}
}
}

View file

@ -1,55 +0,0 @@
// agentAPITest.js
// scripts/developer/tests
//
// Created by Thijs Wenker on 7/23/18.
// Copyright 2018 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 SOUND_DATA = { url: "http://hifi-content.s3.amazonaws.com/howard/sounds/piano1.wav" };
// getSound function from crowd-agent.js
function getSound(data, callback) { // callback(sound) when downloaded (which may be immediate).
var sound = SoundCache.getSound(data.url);
if (sound.downloaded) {
return callback(sound);
}
function onDownloaded() {
sound.ready.disconnect(onDownloaded);
callback(sound);
}
sound.ready.connect(onDownloaded);
}
function agentAPITest() {
console.warn('Agent.isAvatar =', Agent.isAvatar);
Agent.isAvatar = true;
console.warn('Agent.isAvatar =', Agent.isAvatar);
console.warn('Agent.isListeningToAudioStream =', Agent.isListeningToAudioStream);
Agent.isListeningToAudioStream = true;
console.warn('Agent.isListeningToAudioStream =', Agent.isListeningToAudioStream);
console.warn('Agent.isNoiseGateEnabled =', Agent.isNoiseGateEnabled);
Agent.isNoiseGateEnabled = true;
console.warn('Agent.isNoiseGateEnabled =', Agent.isNoiseGateEnabled);
console.warn('Agent.lastReceivedAudioLoudness =', Agent.lastReceivedAudioLoudness);
console.warn('Agent.sessionUUID =', Agent.sessionUUID);
getSound(SOUND_DATA, function (sound) {
console.warn('Agent.isPlayingAvatarSound =', Agent.isPlayingAvatarSound);
Agent.playAvatarSound(sound);
console.warn('Agent.isPlayingAvatarSound =', Agent.isPlayingAvatarSound);
});
}
if (Script.context === "agent") {
agentAPITest();
} else {
console.error('This script should be run as agent script. EXITING.');
}

View file

@ -1,19 +0,0 @@
var WAVE = 'http://cdn.rawgit.com/ambisonictoolkit/atk-sounds/aa31005c/stereo/Aurora_Surgit-Lux_Aeterna.wav';
var uuid = Entities.addEntity({
type: "Shape",
shape: "Icosahedron",
dimensions: Vec3.HALF,
script: Script.resolvePath('../../tutorials/entity_scripts/ambientSound.js'),
position: Vec3.sum(Vec3.multiply(5, Quat.getForward(MyAvatar.orientation)), MyAvatar.position),
userData: JSON.stringify({
soundURL: WAVE,
maxVolume: 0.1,
range: 25,
disabled: true,
grab: { triggerable: true }
}),
lifetime: 600,
});
Script.scriptEnding.connect(function() {
Entities.deleteEntity(uuid);
});

View file

@ -1,192 +0,0 @@
//
// avatarAttachmentTest.js
// examples/tests
//
// Created by Anthony Thibault on January 7, 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
//
// Test for MyAvatar attachment API
// MyAvatar.setAttachmentData();
// MyAvatar.getAttachmentData();
// Toggle button helper
function ToggleButtonBuddy(x, y, width, height, urls) {
this.up = Overlays.addOverlay("image", {
x: x, y: y, width: width, height: height,
subImage: { x: 0, y: 0, width: width, height: height},
imageURL: urls.up,
visible: true,
alpha: 1.0
});
this.down = Overlays.addOverlay("image", {
x: x, y: y, width: width, height: height,
subImage: { x: 0, y: 0, width: width, height: height},
imageURL: urls.down,
visible: false,
alpha: 1.0
});
this.callbacks = [];
var self = this;
Controller.mousePressEvent.connect(function (event) {
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
if (clickedOverlay === self.up) {
// flip visiblity
Overlays.editOverlay(self.up, {visible: false});
Overlays.editOverlay(self.down, {visible: true});
self.onToggle(true);
} else if (clickedOverlay === self.down) {
// flip visiblity
Overlays.editOverlay(self.up, {visible: true});
Overlays.editOverlay(self.down, {visible: false});
self.onToggle(false);
}
});
}
ToggleButtonBuddy.prototype.destroy = function () {
Overlays.deleteOverlay(this.up);
Overlays.deleteOverlay(this.down);
};
ToggleButtonBuddy.prototype.addToggleHandler = function (callback) {
this.callbacks.push(callback);
return callback;
};
ToggleButtonBuddy.prototype.removeToggleHandler = function (callback) {
var index = this.callbacks.indexOf(callback);
if (index !== -1) {
this.callbacks.splice(index, 1);
}
};
ToggleButtonBuddy.prototype.onToggle = function (isDown) {
var i, l = this.callbacks.length;
for (i = 0; i < l; i++) {
this.callbacks[i](isDown);
}
};
var windowDimensions = Controller.getViewportDimensions();
var BUTTON_WIDTH = 64;
var BUTTON_HEIGHT = 64;
var BUTTON_PADDING = 10;
var buttonPositionX = windowDimensions.x - BUTTON_PADDING - BUTTON_WIDTH;
var buttonPositionY = (windowDimensions.y - BUTTON_HEIGHT) / 2 - (BUTTON_HEIGHT + BUTTON_PADDING);
var hatButton = new ToggleButtonBuddy(buttonPositionX, buttonPositionY, BUTTON_WIDTH, BUTTON_HEIGHT, {
up: "https://s3.amazonaws.com/hifi-public/tony/icons/hat-up.svg",
down: "https://s3.amazonaws.com/hifi-public/tony/icons/hat-down.svg"
});
buttonPositionY += BUTTON_HEIGHT + BUTTON_PADDING;
var coatButton = new ToggleButtonBuddy(buttonPositionX, buttonPositionY, BUTTON_WIDTH, BUTTON_HEIGHT, {
up: "https://s3.amazonaws.com/hifi-public/tony/icons/coat-up.svg",
down: "https://s3.amazonaws.com/hifi-public/tony/icons/coat-down.svg"
});
buttonPositionY += BUTTON_HEIGHT + BUTTON_PADDING;
var coatButton2 = new ToggleButtonBuddy(buttonPositionX, buttonPositionY, BUTTON_WIDTH, BUTTON_HEIGHT, {
up: "https://s3.amazonaws.com/hifi-public/tony/icons/coat-up.svg",
down: "https://s3.amazonaws.com/hifi-public/tony/icons/coat-down.svg"
});
var AVATAR_ATTACHMENT = 0;
var AVATAR_SOFT_ATTACHMENT = 1;
var ENTITY_ATTACHMENT = 2;
var HAT_ATTACHMENT = {
modelURL: "https://s3.amazonaws.com/hifi-public/tony/cowboy-hat.fbx",
jointName: "Head",
translation: {"x": 0, "y": 0.25, "z": 0.03},
rotation: {"x": 0, "y": 0, "z": 0, "w": 1},
scale: 0.052,
type: AVATAR_ATTACHMENT
};
var COAT_ATTACHMENT = {
modelURL: "https://hifi-content.s3.amazonaws.com/ozan/dev/clothes/coat/coat_rig.fbx",
jointName: "Hips",
translation: {"x": 0, "y": 0, "z": 0},
rotation: {"x": 0, "y": 0, "z": 0, "w": 1},
scale: 1,
type: AVATAR_SOFT_ATTACHMENT
};
var COAT_ENTITY_ATTACHMENT = {
modelURL: "https://hifi-content.s3.amazonaws.com/ozan/dev/clothes/coat/coat_rig.fbx",
jointName: "Hips",
translation: {"x": 0, "y": 0, "z": 0},
rotation: {"x": 0, "y": 0, "z": 0, "w": 1},
scale: 1,
type: ENTITY_ATTACHMENT
};
hatButton.addToggleHandler(function (isDown) {
if (isDown) {
wearAttachment(HAT_ATTACHMENT);
} else {
removeAttachment(HAT_ATTACHMENT);
}
});
coatButton.addToggleHandler(function (isDown) {
if (isDown) {
wearAttachment(COAT_ATTACHMENT);
} else {
removeAttachment(COAT_ATTACHMENT);
}
});
coatButton2.addToggleHandler(function (isDown) {
if (isDown) {
wearAttachment(COAT_ENTITY_ATTACHMENT);
} else {
removeAttachment(COAT_ENTITY_ATTACHMENT);
}
});
function wearAttachment(attachment) {
if (attachment.type === AVATAR_ATTACHMENT || attachment.type === AVATAR_SOFT_ATTACHMENT) {
MyAvatar.attach(attachment.modelURL,
attachment.jointName,
attachment.translation,
attachment.rotation,
attachment.scale,
(attachment.type === AVATAR_SOFT_ATTACHMENT));
} else {
attachment.entityID = Entities.addEntity({
name: "attachment",
type: "Model",
modelURL: attachment.modelURL,
parentID: MyAvatar.sessionUUID,
relayParentJoints: true,
position: attachment.position,
rotation: attachment.rotation,
parentJointIndex: -1
}, true);
}
}
function removeAttachment(attachment) {
if (attachment.type === AVATAR_ATTACHMENT || attachment.type === AVATAR_SOFT_ATTACHMENT) {
var attachments = MyAvatar.attachmentData;
var i, l = attachments.length;
for (i = 0; i < l; i++) {
if (attachments[i].modelURL === attachment.modelURL) {
attachments.splice(i, 1);
MyAvatar.attachmentData = attachments;
break;
}
}
} else {
Entities.deleteEntity(attachment.entityID);
}
}
Script.scriptEnding.connect(function() {
hatButton.destroy();
coatButton.destroy();
coatButton2.destroy();
});

View file

@ -1,79 +0,0 @@
var debugSphereBaseProperties = {
type: "Sphere",
dimensions: { x: 0.2, y: 0.2, z: 0.2 },
dynamic: false,
collisionless: true,
gravity: { x: 0, y: 0, z: 0 },
lifetime: 10.0,
userData: "{ \"grabbableKey\": { \"grabbable\": false, \"kinematic\": false } }"
};
var debugBoxBaseProperties = {
type: "Box",
dimensions: { x: 0.2, y: 0.2, z: 0.2 },
dynamic: false,
collisionless: true,
gravity: { x: 0, y: 0, z: 0 },
lifetime: 10.0,
userData: "{ \"grabbableKey\": { \"grabbable\": false, \"kinematic\": false } }"
};
//jointToWorldPoint
// create sphere for finger on left hand
// each frame, calculate world position of finger, with some offset
// update sphere to match this position
var jointToWorldPointTest_sphereEntity;
function jointToWorldPointTest() {
var jointIndex = MyAvatar.getJointIndex("LeftHandPinky4");
var jointOffset_WorldSpace = { x: 0.1, y: 0, z: 0 };
var worldPos = MyAvatar.jointToWorldPoint(jointOffset_WorldSpace, jointIndex);
var jointSphereProps = Object.create(debugSphereBaseProperties);
jointSphereProps.name = "jointToWorldPointTest_Sphere";
jointSphereProps.color = { blue: 240, green: 150, red: 150 };
jointSphereProps.position = worldPos;
jointToWorldPointTest_sphereEntity = Entities.addEntity(jointSphereProps);
}
function jointToWorldPointTest_update(deltaTime) {
var jointIndex = MyAvatar.getJointIndex("LeftHandPinky4");
var jointOffset_WorldSpace = { x: 0.1, y: 0, z: 0 };
var worldPos = MyAvatar.jointToWorldPoint(jointOffset_WorldSpace, jointIndex);
var newProperties = { position: worldPos };
Entities.editEntity(jointToWorldPointTest_sphereEntity, newProperties);
}
//jointToWorldRotation
// create box in world space
// each frame calculate world space rotation of players head
// update box rotation to match
var jointToWorldRotationTest_boxEntity;
function jointToWorldRotationTest() {
var jointIndex = MyAvatar.getJointIndex("Head");
var jointPosition_WorldSpace = MyAvatar.getJointPosition(jointIndex);
var jointRot = MyAvatar.getJointRotation(jointIndex);
var jointRot_WorldSpace = MyAvatar.jointToWorldRotation(jointRot, jointIndex);
var boxProps = Object.create(debugBoxBaseProperties);
boxProps.name = "jointToWorldRotationTest_Box";
boxProps.color = { blue: 250, green: 250, red: 250 };
boxProps.position = jointPosition_WorldSpace;
boxProps.rotation = jointRot_WorldSpace;
jointToWorldRotationTest_boxEntity = Entities.addEntity(boxProps);
}
function jointToWorldRotationTest_update(deltaTime) {
var jointIndex = MyAvatar.getJointIndex("Head");
var jointPosition_WorldSpace = MyAvatar.getJointPosition(jointIndex);
var jointRot = MyAvatar.getJointRotation(jointIndex);
var jointRot_WorldSpace = MyAvatar.jointToWorldRotation(jointRot, jointIndex);
var newProperties = { position: jointPosition_WorldSpace, rotation: jointRot_WorldSpace };
Entities.editEntity(jointToWorldRotationTest_boxEntity, newProperties);
}
jointToWorldPointTest();
Script.update.connect(jointToWorldPointTest_update);
jointToWorldDirectionTest();
Script.update.connect(jointToWorldDirection_update);
jointToWorldRotationTest();
Script.update.connect(jointToWorldRotationTest_update);

View file

@ -1,31 +0,0 @@
var orientation = Camera.getOrientation();
orientation = Quat.safeEulerAngles(orientation);
orientation.x = 0;
orientation = Quat.fromVec3Degrees(orientation);
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getForward(orientation)));
// Math.random ensures no caching of script
var SCRIPT_URL = Script.resolvePath("myEntityScript.js")
var myEntity = Entities.addEntity({
type: "Sphere",
color: {
red: 200,
green: 10,
blue: 200
},
position: center,
dimensions: {
x: 1,
y: 1,
z: 1
},
script: SCRIPT_URL
})
function cleanup() {
// Entities.deleteEntity(myEntity);
}
Script.scriptEnding.connect(cleanup);

View file

@ -1,23 +0,0 @@
(function() {
var _this;
MyEntity = function() {
_this = this;
};
MyEntity.prototype = {
preload: function(entityID) {
this.entityID = entityID;
var randNum = Math.random().toFixed(3);
print("PRELOAD ENTITY SCRIPT!!!", randNum)
},
};
// entity scripts always need to return a newly constructed object of our type
return new MyEntity();
});

View file

@ -1,30 +0,0 @@
// compute a position to create the object relative to avatar
var forwardOffset = Vec3.multiply(2.0, Quat.getFront(MyAvatar.orientation));
var objectPosition = Vec3.sum(MyAvatar.position, forwardOffset);
var LIFETIME = 1800; //seconds
var DIM_HEIGHT = 1, DIM_WIDTH = 1, DIM_DEPTH = 1;
var COLOR_R = 100, COLOR_G = 10, COLOR_B = 200;
var properties = {
name: "ShapeSpawnTest",
type: "Shape",
shape: "Cylinder",
dimensions: {x: DIM_WIDTH, y: DIM_HEIGHT, z: DIM_DEPTH},
color: {red: COLOR_R, green: COLOR_G, blue: COLOR_B},
position: objectPosition,
lifetime: LIFETIME,
};
// create the object
var entityId = Entities.addEntity(properties);
function cleanup() {
Entities.deleteEntity(entityId);
}
// delete the object when this script is stopped
Script.scriptEnding.connect(cleanup);

View file

@ -1,85 +0,0 @@
(function() {
Script.include("../../libraries/virtualBaton.js");
var baton;
var _this;
BatonSoundEntity = function() {
_this = this;
_this.drumSound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Drums/deepdrum1.wav");
_this.injectorOptions = {position: MyAvatar.position, loop: false, volume: 1};
_this.soundIntervalConnected = false;
_this.batonDebugModel = Entities.addEntity({
type: "Box",
color: {red: 200, green: 10, blue: 200},
position: Vec3.sum(MyAvatar.position, {x: 0, y: 1, z: 0}),
dimensions: {x: 0.5, y: 1, z: 0},
parentID: MyAvatar.sessionUUID,
visible: false
});
};
function startUpdate() {
// We are claiming the baton! So start our clip
if (!_this.soundInjector) {
// This client hasn't created their injector yet so create one
_this.soundInjector = Audio.playSound(_this.drumSound, _this.injectorOptions);
} else {
// We already have our injector so just restart it
_this.soundInjector.restart();
}
print("EBL START UPDATE");
Entities.editEntity(_this.batonDebugModel, {visible: true});
_this.playSoundInterval = Script.setInterval(function() {
_this.soundInjector.restart();
}, _this.drumSound.duration * 1000); // Duration is in seconds so convert to ms
_this.soundIntervalConnected = true;
}
function stopUpdateAndReclaim() {
print("EBL STOP UPDATE AND RECLAIM")
// when the baton is release
if (_this.soundIntervalConnected === true) {
Script.clearInterval(_this.playSoundInterval);
_this.soundIntervalConnected = false;
print("EBL CLEAR INTERVAL")
}
Entities.editEntity(_this.batonDebugModel, {visible: false});
// hook up callbacks to the baton
baton.claim(startUpdate, stopUpdateAndReclaim);
}
BatonSoundEntity.prototype = {
preload: function(entityID) {
_this.entityID = entityID;
print("EBL PRELOAD ENTITY SCRIPT!!!");
baton = virtualBaton({
// One winner for each entity
batonName: "io.highfidelity.soundEntityBatonTest:" + _this.entityID,
// debugFlow: true
});
stopUpdateAndReclaim();
},
unload: function() {
print("EBL UNLOAD");
// baton.release();
baton.unload();
Entities.deleteEntity(_this.batonDebugModel);
if (_this.soundIntervalConnected === true) {
Script.clearInterval(_this.playSoundInterval);
_this.soundIntervalConnected = false;
_this.soundInjector.stop();
delete _this.soundInjector;
}
}
};
// entity scripts always need to return a newly constructed object of our type
return new BatonSoundEntity();
});

View file

@ -1,31 +0,0 @@
var orientation = Camera.getOrientation();
orientation = Quat.safeEulerAngles(orientation);
orientation.x = 0;
orientation = Quat.fromVec3Degrees(orientation);
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getForward(orientation)));
// Math.random ensures no caching of script
var SCRIPT_URL = Script.resolvePath("batonSoundTestEntityScript.js")
var soundEntity = Entities.addEntity({
type: "Box",
color: {
red: 200,
green: 10,
blue: 10
},
position: center,
dimensions: {
x: 0.1,
y: 0.1,
z: 0.1
},
script: SCRIPT_URL
});
function cleanup() {
// Entities.deleteEntity(soundEntity);
}
Script.scriptEnding.connect(cleanup);

View file

@ -1,114 +0,0 @@
// Examples and understanding of console object. Include console methods like
// info, log, debug, warn, error, exception, trace, clear, asserts, group, groupCollapsed, groupEnd, time, timeEnd.
// Useful in debugging and exclusively made for JavaScript files.
// To view the logs click on Developer -> script logs [logs on debug window] and for text file logs go to Logs/log file.
main();
function main() {
var someObject = { str: "Some text", id: 5 };
var someValue = 5;
// console.info examples
console.info("[console.info] Hello World.");
console.info(5 + 6);
console.info(someObject.str);
console.info(a = 2 * 6);
console.info(someValue);
console.info('someObject id ' + someObject.id);
console.info('Hello World ', 'someObject.id = ', someObject.id, "a = 2 * 6 = ", a = 2 * 6);
// console.log examples
console.log("[console.log] Hello World");
console.log(5 + 6);
console.log(someObject.str);
console.log(a = 2 * 6);
console.log(someValue);
console.log('someObject id ' + someObject.id);
console.log('Hello World ', 'someObject.id = ', someObject.id, "a = 2 * 6 = ", a = 2 * 6);
// console.debug examples
console.debug("[console.debug] Hello World.");
console.debug(5 + 6);
console.debug(someObject.str);
console.debug(a = 2 * 6);
console.debug(someValue);
console.debug('someObject id ' + someObject.id);
console.debug('Hello World ', 'someObject.id = ', someObject.id, "a = 2 * 6 = ", a = 2 * 6);
// console.warn examples
console.warn("[console.warn] This is warning message.");
console.warn(5 + 6);
console.warn(someObject.str);
console.warn(a = 2 * 6);
console.warn(someValue);
console.warn('someObject id ' + someObject.id);
console.warn('Hello World ', 'someObject.id = ', someObject.id, "a = 2 * 6 = ", a = 2 * 6);
// console.error examples
console.error('An error occurred!');
console.error('An error occurred! ', 'Value = ', someValue);
console.error('An error occurred! ' + 'Value = ' + someValue);
// console.exception examples
console.exception('An exception occurred!');
console.exception('An exception occurred! ', 'Value = ', someValue);
console.exception('An exception occurred! ' + 'Value = ' + someValue);
// console.trace examples
function fooA() {
function fooB() {
function fooC() {
console.trace();
}
fooC();
}
fooB();
}
fooA();
// console.assert() examples
var valA = 1, valB = "1";
console.assert(valA === valB, "Value A doesn't equal to B");
console.assert(valA === valB);
console.assert(5 === 5, "5 equals to 5");
console.assert(5 === 5);
console.assert(5 > 6, "5 is not greater than 6");
console.assert(5 > 6, "5 is not greater than 6", "This assertion will fail");
// console.group() examples.
console.group("Group 1");
console.log("Sentence 1");
console.log("Sentence 2");
console.group("Group 2");
console.log("Sentence 3");
console.log("Sentence 4");
console.groupCollapsed("Group 3");
console.log("Sentence 5");
console.log("Sentence 6");
console.groupEnd();
console.log("Sentence 7");
console.groupEnd();
console.log("Sentence 8");
console.groupEnd();
console.log("Sentence 9");
// console.time(),console.timeEnd() examples
console.time('MyTimer');
// Do some process
sleep(1000);
console.timeEnd('MyTimer');
// use console.clear() to clean Debug Window logs
// console.clear();
}
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}

View file

@ -1,77 +0,0 @@
ControllerTest = function() {
var standard = Controller.Standard;
var actions = Controller.Actions;
var xbox = Controller.Hardware.GamePad;
this.mappingEnabled = false;
this.mapping = Controller.newMapping();
this.mapping.from(standard.LX).when([standard.LB, standard.RB]).to(actions.Yaw);
this.mapping.from(standard.RX).to(actions.StepYaw);
this.mapping.from(standard.RY).invert().to(actions.Pitch);
this.mapping.from(standard.RY).invert().to(actions.Pitch);
var testMakeAxis = false;
if (testMakeAxis) {
this.mapping.makeAxis(standard.LB, standard.RB).pulse(0.25).scale(40.0).to(actions.StepYaw);
}
var testStepYaw = false;
if (!testMakeAxis && testStepYaw){
this.mapping.from(standard.LB).pulse(0.10).invert().scale(40.0).to(actions.StepYaw);
this.mapping.from(standard.RB).pulse(0.10).scale(15.0).to(actions.StepYaw);
}
var testFunctionSource = false;
if (testFunctionSource) {
this.mapping.from(function(){
return Math.sin(Date.now() / 250);
}).to(actions.Yaw);
}
var testFunctionDest = true;
if (testFunctionDest) {
this.mapping.from(standard.DU).pulse(1.0).to(function(value){
if (value != 0.0) {
print(value);
}
});
}
this.mapping.enable();
this.mappingEnabled = true;
var dumpInputs = false;
if (dumpInputs) {
print("Actions");
for (var prop in Controller.Actions) {
print("\t" + prop);
}
print("Standard");
for (var prop in Controller.Standard) {
print("\t" + prop);
}
print("Hardware");
for (var prop in Controller.Hardware) {
print("\t" + prop);
for (var prop2 in Controller.Hardware[prop]) {
print("\t\t" + prop2);
}
}
print("Done");
}
var that = this;
Script.scriptEnding.connect(function() {
that.onCleanup();
});
}
ControllerTest.prototype.onCleanup = function() {
if (this.mappingEnabled) {
this.mapping.disable();
}
}
new ControllerTest();

View file

@ -1,278 +0,0 @@
"use strict";
/* jslint bitwise: true */
/* global Script, Entities, MyAvatar, Vec3, Quat, Mat4, Overlays */
(function() { // BEGIN LOCAL_SCOPE
// var lifetime = -1;
var lifetime = 600;
var tableSections = 32;
var tableRadius = 9;
var sectionRelativeRotation = 0;
var sectionRotation = 0;
var sectionRelativeCenterA = 0;
var sectionRelativeCenterB = 0;
var sectionRelativeCenterSign = 0;
var sectionCenterA = 0;
var sectionCenterB = 0;
var sectionCenterSign = 0;
var yFlip = 0;
var objects = [];
var overlays = [];
var testNames = [
"FarActionGrab",
"NearParentGrabEntity",
"NearParentGrabOverlay",
"Clone Entity (dynamic)",
"Clone Entity (non-dynamic"
];
function createCloneDynamicEntity(index) {
createPropsCube(index, false, false, true, true);
createPropsModel(index, false, false, true, true);
createSign(index, "Clone Dynamic Entity");
}
function createCloneEntity(index) {
createPropsCube(index, false, false, true, false);
createPropsModel(index, false, false, true, false);
createSign(index, "Clone Non-Dynamic Entity");
}
function createNearGrabOverlay(index) {
createPropsCubeOverlay(index, false, false, true, true);
createPropsModelOverlay(index, false, false, true, true);
createSign(index, "Near Grab Overlay");
}
function createNearGrabEntity(index) {
createPropsCube(index, false, false, false, false);
createPropsModel(index, false, false, false, false);
createSign(index, "Near Grab Entity");
}
function createFarGrabEntity(index) {
createPropsCube(index, true, false, false, false);
createPropsModel(index, true, false, false, false);
createSign(index, "Far Grab Entity");
}
function createPropsModel(i, dynamic, collisionless, clone, cloneDynamic) {
var propsModel = {
name: "controller-tests model object " + i,
type: "Model",
modelURL: "http://headache.hungry.com/~seth/hifi/controller-tests/color-cube.obj",
position: sectionCenterA,
rotation: sectionRotation,
gravity: (dynamic && !collisionless) ? { x: 0, y: -1, z: 0 } : { x: 0, y: 0, z: 0 },
dimensions: { x: 0.2, y: 0.2, z: 0.2 },
userData: JSON.stringify({
grabbableKey: {
grabbable: true,
cloneLimit: 10,
cloneable: clone,
cloneDynamic: cloneDynamic
},
controllerTestEntity: true
}),
lifetime: lifetime,
shapeType: "box",
dynamic: dynamic,
collisionless: collisionless
};
objects.push(Entities.addEntity(propsModel));
}
function createPropsModelOverlay(i, dynamic, collisionless, clone, cloneDynamic) {
var propsModel = {
name: "controller-tests model object " + i,
type: "Model",
modelURL: "http://headache.hungry.com/~seth/hifi/controller-tests/color-cube.obj",
url: "http://headache.hungry.com/~seth/hifi/controller-tests/color-cube.obj",
grabbable: true,
position: sectionCenterA,
rotation: sectionRotation,
dimensions: { x: 0.2, y: 0.2, z: 0.2 },
userData: JSON.stringify({
grabbableKey: {
grabbable: true,
},
controllerTestEntity: true
}),
lifetime: lifetime,
visible: true,
};
overlays.push(Overlays.addOverlay("model", propsModel));
}
function createPropsCubeOverlay(i, dynamic, collisionless, clone, cloneDynamic) {
var propsCube = {
name: "controller-tests cube object " + i,
type: "Box",
color: { "blue": 200, "green": 10, "red": 20 },
position: sectionCenterB,
rotation: sectionRotation,
grabbable: true,
dimensions: { x: 0.2, y: 0.2, z: 0.2 },
userData: JSON.stringify({
grabbableKey: {
grabbable: true,
},
controllerTestEntity: true
}),
lifetime: lifetime,
solid: true,
visible: true,
};
overlays.push(Overlays.addOverlay("cube", propsCube));
}
function createPropsCube(i, dynamic, collisionless, clone, cloneDynamic) {
var propsCube = {
name: "controller-tests cube object " + i,
type: "Box",
shape: "Cube",
color: { "blue": 200, "green": 10, "red": 20 },
position: sectionCenterB,
rotation: sectionRotation,
gravity: dynamic ? { x: 0, y: -1, z: 0 } : { x: 0, y: 0, z: 0 },
dimensions: { x: 0.2, y: 0.2, z: 0.2 },
userData: JSON.stringify({
grabbableKey: {
grabbable: true,
cloneLimit: 10,
cloneable: clone,
cloneDynamic: cloneDynamic
},
controllerTestEntity: true
}),
lifetime: lifetime,
shapeType: "box",
dynamic: dynamic,
collisionless: collisionless
};
objects.push(Entities.addEntity(propsCube));
}
function createSign(i, signText) {
var propsLabel = {
name: "controller-tests sign " + i,
type: "Text",
lineHeight: 0.125,
position: sectionCenterSign,
rotation: Quat.multiply(sectionRotation, yFlip),
text: signText,
dimensions: { x: 1, y: 1, z: 0.01 },
lifetime: lifetime,
userData: JSON.stringify({
grabbableKey: {
grabbable: false,
},
controllerTestEntity: true
})
};
objects.push(Entities.addEntity(propsLabel));
}
function chooseType(index) {
switch (index) {
case 0:
createFarGrabEntity(index);
break;
case 1:
createNearGrabEntity(index);
break;
case 2:
createNearGrabOverlay(index);
break;
case 3:
createCloneDynamicEntity();
break;
case 4:
createCloneEntity(index);
break;
}
}
function setupControllerTests(testBaseTransform) {
// var tableID =
objects.push(Entities.addEntity({
name: "controller-tests table",
type: "Model",
modelURL: "http://headache.hungry.com/~seth/hifi/controller-tests/controller-tests-table.obj.gz",
position: Mat4.transformPoint(testBaseTransform, { x: 0, y: 1, z: 0 }),
rotation: Mat4.extractRotation(testBaseTransform),
userData: JSON.stringify({
grabbableKey: { grabbable: false },
soundKey: {
url: "http://headache.hungry.com/~seth/hifi/sound/clock-ticking-3.wav",
volume: 0.4,
loop: true,
playbackGap: 0,
playbackGapRange: 0
},
controllerTestEntity: true
}),
shapeType: "static-mesh",
lifetime: lifetime
}));
var Xdynamic = 1;
var Xcollisionless = 2;
var Xkinematic = 4;
var XignoreIK = 8;
yFlip = Quat.fromPitchYawRollDegrees(0, 180, 0);
for (var i = 0; i < 16; i++) {
sectionRelativeRotation = Quat.fromPitchYawRollDegrees(0, -360 * i / tableSections, 0);
sectionRotation = Quat.multiply(Mat4.extractRotation(testBaseTransform), sectionRelativeRotation);
sectionRelativeCenterA = Vec3.multiplyQbyV(sectionRotation, { x: -0.2, y: 1.25, z: tableRadius - 0.8 });
sectionRelativeCenterB = Vec3.multiplyQbyV(sectionRotation, { x: 0.2, y: 1.25, z: tableRadius - 0.8 });
sectionRelativeCenterSign = Vec3.multiplyQbyV(sectionRotation, { x: 0, y: 1.5, z: tableRadius + 1.0 });
sectionCenterA = Mat4.transformPoint(testBaseTransform, sectionRelativeCenterA);
sectionCenterB = Mat4.transformPoint(testBaseTransform, sectionRelativeCenterB);
sectionCenterSign = Mat4.transformPoint(testBaseTransform, sectionRelativeCenterSign);
var dynamic = (i & Xdynamic) ? true : false;
var collisionless = (i & Xcollisionless) ? true : false;
var kinematic = (i & Xkinematic) ? true : false;
var ignoreIK = (i & XignoreIK) ? true : false;
chooseType(i);
}
}
// This assumes the avatar is standing on a flat floor with plenty of space.
// Find the floor:
var pickRay = {
origin: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 2, z: -1 })),
direction: { x: 0, y: -1, z: 0 },
length: 20
};
var intersection = Entities.findRayIntersection(pickRay, true, [], [], true);
if (intersection.intersects) {
var testBaseTransform = Mat4.createFromRotAndTrans(MyAvatar.rotation, intersection.intersection);
setupControllerTests(testBaseTransform);
}
Script.scriptEnding.connect(function () {
for (var i = 0; i < objects.length; i++) {
var nearbyID = objects[i];
Entities.deleteEntity(nearbyID);
}
for (var j = 0; j < overlays.length; j++) {
var overlayID = overlays[j];
Overlays.deleteOverlay(overlayID);
}
});
}()); // END LOCAL_SCOPE

View file

@ -1,23 +0,0 @@
(function() { // BEGIN LOCAL_SCOPE
console.debug('controlsGallery: creating window')
var qml = Script.resolvePath('ControlsGallery.qml');
var qmlWindow = new OverlayWindow({
title: 'Hifi Controls Gallery',
source: qml,
height: 480,
width: 640,
visible: true
});
console.debug('controlsGallery: creating window... done')
qmlWindow.closed.connect(function() { Script.stop(); });
Script.scriptEnding.connect(function() {
console.debug('controlsGallery: end of scripting')
delete qmlWindow;
});
}()); // END LOCAL_SCOPE

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

View file

@ -1,34 +0,0 @@
var TRACKED_OBJECT_POSES = [
"TrackedObject00", "TrackedObject01", "TrackedObject02", "TrackedObject03",
"TrackedObject04", "TrackedObject05", "TrackedObject06", "TrackedObject07",
"TrackedObject08", "TrackedObject09", "TrackedObject10", "TrackedObject11",
"TrackedObject12", "TrackedObject13", "TrackedObject14", "TrackedObject15"
];
function init() {
Script.update.connect(update);
}
function shutdown() {
Script.update.disconnect(update);
TRACKED_OBJECT_POSES.forEach(function (key) {
DebugDraw.removeMyAvatarMarker(key);
});
}
var BLUE = {x: 0, y: 0, z: 1, w: 1};
function update(dt) {
TRACKED_OBJECT_POSES.forEach(function (key) {
var pose = Controller.getPoseValue(Controller.Standard[key]);
if (pose.valid) {
DebugDraw.addMyAvatarMarker(key, pose.rotation, pose.translation, BLUE);
} else {
DebugDraw.removeMyAvatarMarker(key);
}
});
}
init();

View file

@ -1,76 +0,0 @@
//
// dynamics-tests-interface.js
// scripts/developer/tests/dynamics/
//
// Created by Seth Alves 2017-4-30
// 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
//
"use strict";
/* globals $, EventBridge */
var parameters = {
"lifetime":"integer"
};
function getQueryArgByName(name, url) {
if (!url) {
url = window.location.href;
}
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
function addCommandParameters(params) {
// copy from html elements into an associative-array which will get passed (as JSON) through the EventBridge
for (var parameterName in parameters) {
if (parameters.hasOwnProperty(parameterName)) {
var parameterType = parameters[parameterName];
var strVal = $("#" + parameterName).val();
if (parameterType == "integer") {
params[parameterName] = parseInt(strVal);
} else if (parameterType == "float") {
params[parameterName] = parseFloat(strVal);
} else {
params[parameterName] = strVal;
}
}
}
return params;
}
$(document).ready(function() {
// hook all buttons to EventBridge
$(":button").each(function(index) {
$(this).click(function() {
EventBridge.emitWebEvent(JSON.stringify(addCommandParameters({ "dynamics-tests-command": this.id })));
});
});
// copy parameters from query-args into elements
for (var parameterName in parameters) {
if (parameters.hasOwnProperty(parameterName)) {
var val = getQueryArgByName(parameterName);
if (val) {
var parameterType = parameters[parameterName];
if (parameterType == "integer") {
val = parseInt(val);
} else if (parameterType == "float") {
val = parseFloat(val);
}
$("#" + parameterName).val(val.toString());
}
}
}
});

View file

@ -1,37 +0,0 @@
<html>
<head>
<title>Dynamics Tests</title>
<meta charset="utf-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="dynamics-tests-interface.js"></script>
</head>
<body>
lifetime: <input id="lifetime" type="text" size=6>
<hr>
<input type="button" id="cone-twist-and-tractor-lever-test" value="Cone-Twist and Tractor-Action Lever"><br>
A platform with a lever. The lever can be moved in a cone and rotated. A tractor brings it back to its neutral position.
<hr>
<input type="button" id="door-vs-world-test" value="Hinge Between Swinging Door and World"><br>
A grabbable door with a hinge between it and world-space.
<hr>
<input type="button" id="hinge-chain-test" value="Hinge Chain"><br>
A chain of blocks connected by hinges.
<hr>
<input type="button" id="slider-vs-world-test" value="Slider vs World"><br>
The block can only move up and down over a range of 1/2 meter.
<hr>
<input type="button" id="slider-chain-test" value="Slider Chain"><br>
A chain of blocks connected by slider constraints.
<hr>
<input type="button" id="ball-socket-between-test" value="Ball-Socket Between Spheres Chain"><br>
A chain of spheres connected by ball-and-socket joints between the spheres.
<hr>
<input type="button" id="ball-socket-coincident-test" value="Ball-Socket Coincident Spheres Chain"><br>
A chain of spheres connected by ball-and-socket joints coincident-with the spheres.
<hr>
<input type="button" id="ragdoll-test" value="Ragdoll"><br>
A self-righting ragdoll. The head is on a weak tractor vs the body.
</body>
</html>

View file

@ -1,757 +0,0 @@
//
// dynamicsTests.js
// scripts/developer/tests/dynamics/
//
// Created by Seth Alves 2017-4-30
// 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
//
"use strict";
/* global Entities, Script, Tablet, MyAvatar, Vec3 */
(function() { // BEGIN LOCAL_SCOPE
var DYNAMICS_TESTS_URL = Script.resolvePath("dynamics-tests.html");
var DEFAULT_LIFETIME = 120; // seconds
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var button = tablet.addButton({
icon: Script.resolvePath("dynamicsTests.svg"),
text: "Dynamics"
});
function coneTwistAndTractorLeverTest(params) {
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: -0.5, z: -2}));
var lifetime = params.lifetime;
var baseID = Entities.addEntity({
name: "cone-twist test -- base",
type: "Box",
color: { blue: 128, green: 100, red: 20 },
dimensions: { x: 0.5, y: 0.2, z: 0.5 },
position: Vec3.sum(pos, { x: 0, y: 0, z:0 }),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: 0, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
var leverID = Entities.addEntity({
name: "cone-twist test -- lever",
type: "Box",
color: { blue: 128, green: 100, red: 200 },
dimensions: { x: 0.05, y: 1, z: 0.05 },
position: Vec3.sum(pos, { x: 0, y: 0.7, z:0 }),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: 0, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addEntity({
name: "cone-twist test -- handle",
type: "Box",
color: { blue: 30, green: 100, red: 200 },
dimensions: { x: 0.1, y: 0.08, z: 0.08 },
position: Vec3.sum(pos, { x: 0, y: 0.7 + 0.5, z:0 }),
dynamic: false,
collisionless: true,
gravity: { x: 0, y: 0, z: 0 },
lifetime: lifetime,
parentID: leverID,
userData: "{ \"grabbableKey\": { \"grabbable\": false } }"
});
Entities.addAction("cone-twist", baseID, {
pivot: { x: 0, y: 0.2, z: 0 },
axis: { x: 0, y: 1, z: 0 },
otherEntityID: leverID,
otherPivot: { x: 0, y: -0.55, z: 0 },
otherAxis: { x: 0, y: 1, z: 0 },
swingSpan1: Math.PI / 4,
swingSpan2: Math.PI / 4,
twistSpan: Math.PI / 2,
tag: "cone-twist test"
});
Entities.addAction("tractor", leverID, {
targetRotation: { x: 0, y: 0, z: 0, w: 1 },
angularTimeScale: 0.2,
tag: "cone-twist test tractor"
});
Entities.editEntity(baseID, { gravity: { x: 0, y: -5, z: 0 } });
}
function doorVSWorldTest(params) {
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.1, z: -2}));
var lifetime = params.lifetime;
var doorID = Entities.addEntity({
name: "door test",
type: "Box",
color: { blue: 128, green: 20, red: 20 },
dimensions: { x: 1.0, y: 2, z: 0.1 },
position: pos,
dynamic: true,
collisionless: false,
lifetime: lifetime,
gravity: { x: 0, y: 0, z: 0 },
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("hinge", doorID, {
pivot: { x: -0.5, y: 0, z: 0 },
axis: { x: 0, y: 1, z: 0 },
low: 0,
high: Math.PI,
tag: "door hinge test"
});
}
function hingeChainTest(params) {
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.1, z: -2}));
var lifetime = params.lifetime;
var offset = 0.28;
var prevEntityID = null;
for (var i = 0; i < 5; i++) {
var newID = Entities.addEntity({
name: "hinge test " + i,
type: "Box",
color: { blue: 128, green: 40 * i, red: 20 },
dimensions: { x: 0.2, y: 0.2, z: 0.1 },
position: Vec3.sum(pos, {x: 0, y: offset * i, z:0}),
dynamic: true,
collisionless: false,
lifetime: lifetime,
gravity: { x: 0, y: 0, z: 0 },
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
if (prevEntityID) {
Entities.addAction("hinge", prevEntityID, {
pivot: { x: 0, y: offset / 2, z: 0 },
axis: { x: 1, y: 0, z: 0 },
otherEntityID: newID,
otherPivot: { x: 0, y: -offset / 2, z: 0 },
otherAxis: { x: 1, y: 0, z: 0 },
tag: "A/B hinge test " + i
});
}
prevEntityID = newID;
}
}
function sliderVSWorldTest(params) {
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.1, z: -2}));
var lifetime = params.lifetime;
var sliderEntityID = Entities.addEntity({
name: "slider test",
type: "Box",
color: { blue: 128, green: 20, red: 20 },
dimensions: { x: 0.2, y: 0.2, z: 0.2 },
position: pos,
dynamic: true,
collisionless: false,
gravity: { x: 0, y: 0, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("slider", sliderEntityID, {
point: { x: -0.5, y: 0, z: 0 },
axis: { x: 0, y: 1, z: 0 },
linearLow: 0,
linearHigh: 0.6,
tag: "slider test"
});
}
function sliderChainTest(params) {
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.1, z: -2}));
var lifetime = params.lifetime;
var offset = 0.28;
var prevEntityID = null;
for (var i = 0; i < 7; i++) {
var newID = Entities.addEntity({
name: "slider test " + i,
type: "Box",
color: { blue: 128, green: 40 * i, red: 20 },
dimensions: { x: 0.2, y: 0.1, z: 0.2 },
position: Vec3.sum(pos, {x: 0, y: offset * i, z:0}),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: 0, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
if (prevEntityID) {
Entities.addAction("slider", prevEntityID, {
point: { x: 0, y: 0, z: 0 },
axis: { x: 0, y: 1, z: 0 },
otherEntityID: newID,
otherPoint: { x: 0, y: -offset / 2, z: 0 },
otherAxis: { x: 0, y: 1, z: 0 },
linearLow: 0,
linearHigh: 0.6,
tag: "A/B slider test " + i
});
}
prevEntityID = newID;
}
}
function ballSocketBetweenTest(params) {
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.1, z: -2}));
var lifetime = params.lifetime;
var offset = 0.2;
var diameter = offset - 0.01;
var prevEntityID = null;
for (var i = 0; i < 7; i++) {
var newID = Entities.addEntity({
name: "ball and socket test " + i,
type: "Sphere",
color: { blue: 128, green: 40 * i, red: 20 },
dimensions: { x: diameter, y: diameter, z: diameter },
position: Vec3.sum(pos, {x: 0, y: offset * i, z:0}),
dynamic: true,
collisionless: false,
lifetime: lifetime,
gravity: { x: 0, y: 0, z: 0 },
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
if (prevEntityID) {
Entities.addAction("ball-socket", prevEntityID, {
pivot: { x: 0, y: offset / 2, z: 0 },
otherEntityID: newID,
otherPivot: { x: 0, y: -offset / 2, z: 0 },
tag: "A/B ball-and-socket test " + i
});
}
prevEntityID = newID;
}
}
function ballSocketCoincidentTest(params) {
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.1, z: -2}));
var lifetime = params.lifetime;
var offset = 0.2;
var diameter = offset - 0.01;
var prevEntityID = null;
for (var i = 0; i < 7; i++) {
var newID = Entities.addEntity({
name: "ball and socket test " + i,
type: "Sphere",
color: { blue: 128, green: 40 * i, red: 20 },
dimensions: { x: diameter, y: diameter, z: diameter },
position: Vec3.sum(pos, {x: 0, y: offset * i, z:0}),
dynamic: true,
collisionless: false,
lifetime: lifetime,
gravity: { x: 0, y: 0, z: 0 },
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
if (prevEntityID) {
Entities.addAction("ball-socket", prevEntityID, {
pivot: { x: 0, y: 0, z: 0 },
otherEntityID: newID,
otherPivot: { x: 0, y: offset, z: 0 },
tag: "A/B ball-and-socket test " + i
});
}
prevEntityID = newID;
}
}
function ragdollTest(params) {
var scale = 1.6;
var lifetime = params.lifetime;
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 1.0, z: -2}));
var neckLength = scale * 0.05;
var shoulderGap = scale * 0.1;
var elbowGap = scale * 0.06;
var hipGap = scale * 0.07;
var kneeGap = scale * 0.08;
var ankleGap = scale * 0.06;
var ankleMin = 0;
var ankleMax = Math.PI / 4;
var headSize = scale * 0.2;
var bodyHeight = scale * 0.4;
var bodyWidth = scale * 0.3;
var bodyDepth = scale * 0.2;
var upperArmThickness = scale * 0.05;
var upperArmLength = scale * 0.2;
var lowerArmThickness = scale * 0.05;
var lowerArmLength = scale * 0.2;
var legLength = scale * 0.3;
var legThickness = scale * 0.08;
var shinLength = scale * 0.2;
var shinThickness = scale * 0.06;
var footLength = scale * 0.2;
var footThickness = scale * 0.03;
var footWidth = scale * 0.08;
//
// body
//
var bodyID = Entities.addEntity({
name: "ragdoll body",
type: "Box",
color: { blue: 128, green: 100, red: 20 },
dimensions: { x: bodyDepth, y: bodyHeight, z: bodyWidth },
position: Vec3.sum(pos, { x: 0, y: scale * 0.0, z:0 }),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: 0, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
//
// head
//
var headID = Entities.addEntity({
name: "ragdoll head",
type: "Box",
color: { blue: 128, green: 100, red: 20 },
dimensions: { x: headSize, y: headSize, z: headSize },
position: Vec3.sum(pos, { x: 0, y: bodyHeight / 2 + headSize / 2 + neckLength, z:0 }),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: 0.5, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("tractor", headID, {
targetRotation: { x: 0, y: 0, z: 0, w: 1 },
angularTimeScale: 2.0,
otherID: bodyID,
tag: "cone-twist test tractor"
});
var noseID = Entities.addEntity({
name: "ragdoll nose",
type: "Box",
color: { blue: 128, green: 100, red: 100 },
dimensions: { x: headSize / 5, y: headSize / 5, z: headSize / 5 },
localPosition: { x: headSize / 2 + headSize / 10, y: 0, z: 0 },
dynamic: false,
collisionless: true,
lifetime: lifetime,
parentID: headID,
userData: "{ \"grabbableKey\": { \"grabbable\": false } }"
});
Entities.addAction("cone-twist", headID, {
pivot: { x: 0, y: -headSize / 2 - neckLength / 2, z: 0 },
axis: { x: 0, y: 1, z: 0 },
otherEntityID: bodyID,
otherPivot: { x: 0, y: bodyHeight / 2 + neckLength / 2, z: 0 },
otherAxis: { x: 0, y: 1, z: 0 },
swingSpan1: Math.PI / 4,
swingSpan2: Math.PI / 4,
twistSpan: Math.PI / 2,
tag: "ragdoll neck joint"
});
//
// right upper arm
//
var rightUpperArmID = Entities.addEntity({
name: "ragdoll right arm",
type: "Box",
color: { blue: 128, green: 100, red: 20 },
dimensions: { x: upperArmThickness, y: upperArmThickness, z: upperArmLength },
position: Vec3.sum(pos, { x: 0,
y: bodyHeight / 2 + upperArmThickness / 2,
z: bodyWidth / 2 + shoulderGap + upperArmLength / 2
}),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: 0, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("cone-twist", bodyID, {
pivot: { x: 0, y: bodyHeight / 2 + upperArmThickness / 2, z: bodyWidth / 2 + shoulderGap / 2 },
axis: { x: 0, y: 0, z: 1 },
otherEntityID: rightUpperArmID,
otherPivot: { x: 0, y: 0, z: -upperArmLength / 2 - shoulderGap / 2 },
otherAxis: { x: 0, y: 0, z: 1 },
swingSpan1: Math.PI / 2,
swingSpan2: Math.PI / 2,
twistSpan: 0,
tag: "ragdoll right shoulder joint"
});
//
// left upper arm
//
var leftUpperArmID = Entities.addEntity({
name: "ragdoll left arm",
type: "Box",
color: { blue: 128, green: 100, red: 20 },
dimensions: { x: upperArmThickness, y: upperArmThickness, z: upperArmLength },
position: Vec3.sum(pos, { x: 0,
y: bodyHeight / 2 + upperArmThickness / 2,
z: -bodyWidth / 2 - shoulderGap - upperArmLength / 2
}),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: 0, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("cone-twist", bodyID, {
pivot: { x: 0, y: bodyHeight / 2 + upperArmThickness / 2, z: -bodyWidth / 2 - shoulderGap / 2 },
axis: { x: 0, y: 0, z: -1 },
otherEntityID: leftUpperArmID,
otherPivot: { x: 0, y: 0, z: upperArmLength / 2 + shoulderGap / 2 },
otherAxis: { x: 0, y: 0, z: -1 },
swingSpan1: Math.PI / 2,
swingSpan2: Math.PI / 2,
twistSpan: 0,
tag: "ragdoll left shoulder joint"
});
//
// right lower arm
//
var rightLowerArmID = Entities.addEntity({
name: "ragdoll right lower arm",
type: "Box",
color: { blue: 128, green: 100, red: 20 },
dimensions: { x: lowerArmThickness, y: lowerArmThickness, z: lowerArmLength },
position: Vec3.sum(pos, { x: 0,
y: bodyHeight / 2 - upperArmThickness / 2,
z: bodyWidth / 2 + shoulderGap + upperArmLength + elbowGap + lowerArmLength / 2
}),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: -1, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("hinge", rightLowerArmID, {
pivot: { x: 0, y: 0, z: -lowerArmLength / 2 - elbowGap / 2 },
axis: { x: 0, y: 1, z: 0 },
otherEntityID: rightUpperArmID,
otherPivot: { x: 0, y: 0, z: upperArmLength / 2 + elbowGap / 2 },
otherAxis: { x: 0, y: 1, z: 0 },
low: Math.PI / -2,
high: 0,
tag: "ragdoll right elbow joint"
});
//
// left lower arm
//
var leftLowerArmID = Entities.addEntity({
name: "ragdoll left lower arm",
type: "Box",
color: { blue: 128, green: 100, red: 20 },
dimensions: { x: lowerArmThickness, y: lowerArmThickness, z: lowerArmLength },
position: Vec3.sum(pos, { x: 0,
y: bodyHeight / 2 - upperArmThickness / 2,
z: -bodyWidth / 2 - shoulderGap - upperArmLength - elbowGap - lowerArmLength / 2
}),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: -1, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("hinge", leftLowerArmID, {
pivot: { x: 0, y: 0, z: lowerArmLength / 2 + elbowGap / 2 },
axis: { x: 0, y: 1, z: 0 },
otherEntityID: leftUpperArmID,
otherPivot: { x: 0, y: 0, z: -upperArmLength / 2 - elbowGap / 2 },
otherAxis: { x: 0, y: 1, z: 0 },
low: 0,
high: Math.PI / 2,
tag: "ragdoll left elbow joint"
});
//
// right leg
//
var rightLegID = Entities.addEntity({
name: "ragdoll right arm",
type: "Box",
color: { blue: 20, green: 200, red: 20 },
dimensions: { x: legThickness, y: legLength, z: legThickness },
position: Vec3.sum(pos, { x: 0, y: -bodyHeight / 2 - hipGap - legLength / 2, z: bodyWidth / 2 - legThickness / 2 }),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: 0, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("cone-twist", rightLegID, {
pivot: { x: 0, y: legLength / 2 + hipGap / 2, z: 0 },
axis: { x: 0, y: 1, z: 0 },
otherEntityID: bodyID,
otherPivot: { x: 0, y: -bodyHeight / 2 - hipGap / 2, z: bodyWidth / 2 - legThickness / 2 },
otherAxis: Vec3.normalize({ x: -1, y: 1, z: 0 }),
swingSpan1: Math.PI / 4,
swingSpan2: Math.PI / 4,
twistSpan: 0,
tag: "ragdoll right hip joint"
});
//
// left leg
//
var leftLegID = Entities.addEntity({
name: "ragdoll left arm",
type: "Box",
color: { blue: 20, green: 200, red: 20 },
dimensions: { x: legThickness, y: legLength, z: legThickness },
position: Vec3.sum(pos, { x: 0, y: -bodyHeight / 2 - hipGap - legLength / 2, z: -bodyWidth / 2 + legThickness / 2 }),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: 0, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("cone-twist", leftLegID, {
pivot: { x: 0, y: legLength / 2 + hipGap / 2, z: 0 },
axis: { x: 0, y: 1, z: 0 },
otherEntityID: bodyID,
otherPivot: { x: 0, y: -bodyHeight / 2 - hipGap / 2, z: -bodyWidth / 2 + legThickness / 2 },
otherAxis: Vec3.normalize({ x: -1, y: 1, z: 0 }),
swingSpan1: Math.PI / 4,
swingSpan2: Math.PI / 4,
twistSpan: 0,
tag: "ragdoll left hip joint"
});
//
// right shin
//
var rightShinID = Entities.addEntity({
name: "ragdoll right shin",
type: "Box",
color: { blue: 20, green: 200, red: 20 },
dimensions: { x: shinThickness, y: shinLength, z: shinThickness },
position: Vec3.sum(pos, { x: 0,
y: -bodyHeight / 2 - hipGap - legLength - kneeGap - shinLength / 2,
z: bodyWidth / 2 - legThickness / 2
}),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: -2, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("hinge", rightShinID, {
pivot: { x: 0, y: shinLength / 2 + kneeGap / 2, z: 0 },
axis: { x: 0, y: 0, z: 1 },
otherEntityID: rightLegID,
otherPivot: { x: 0, y: -legLength / 2 - kneeGap / 2, z: 0 },
otherAxis: { x: 0, y: 0, z: 1 },
low: 0,
high: Math.PI / 2,
tag: "ragdoll right knee joint"
});
//
// left shin
//
var leftShinID = Entities.addEntity({
name: "ragdoll left shin",
type: "Box",
color: { blue: 20, green: 200, red: 20 },
dimensions: { x: shinThickness, y: shinLength, z: shinThickness },
position: Vec3.sum(pos, { x: 0,
y: -bodyHeight / 2 - hipGap - legLength - kneeGap - shinLength / 2,
z: -bodyWidth / 2 + legThickness / 2
}),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: -2, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("hinge", leftShinID, {
pivot: { x: 0, y: shinLength / 2 + kneeGap / 2, z: 0 },
axis: { x: 0, y: 0, z: 1 },
otherEntityID: leftLegID,
otherPivot: { x: 0, y: -legLength / 2 - kneeGap / 2, z: 0 },
otherAxis: { x: 0, y: 0, z: 1 },
low: 0,
high: Math.PI / 2,
tag: "ragdoll left knee joint"
});
//
// right foot
//
var rightFootID = Entities.addEntity({
name: "ragdoll right foot",
type: "Box",
color: { blue: 128, green: 100, red: 20 },
dimensions: { x: footLength, y: footThickness, z: footWidth },
position: Vec3.sum(pos, { x: -shinThickness / 2 + footLength / 2,
y: -bodyHeight / 2 - hipGap - legLength - kneeGap - shinLength - ankleGap - footThickness / 2,
z: bodyWidth / 2 - legThickness / 2
}),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: -5, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("hinge", rightFootID, {
pivot: { x: -footLength / 2 + shinThickness / 2, y: ankleGap / 2, z: 0 },
axis: { x: 0, y: 0, z: 1 },
otherEntityID: rightShinID,
otherPivot: { x: 0, y: -shinLength / 2 - ankleGap / 2, z: 0 },
otherAxis: { x: 0, y: 0, z: 1 },
low: ankleMin,
high: ankleMax,
tag: "ragdoll right ankle joint"
});
//
// left foot
//
var leftFootID = Entities.addEntity({
name: "ragdoll left foot",
type: "Box",
color: { blue: 128, green: 100, red: 20 },
dimensions: { x: footLength, y: footThickness, z: footWidth },
position: Vec3.sum(pos, { x: -shinThickness / 2 + footLength / 2,
y: -bodyHeight / 2 - hipGap - legLength - kneeGap - shinLength - ankleGap - footThickness / 2,
z: bodyWidth / 2 - legThickness / 2
}),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: -5, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("hinge", leftFootID, {
pivot: { x: -footLength / 2 + shinThickness / 2, y: ankleGap / 2, z: 0 },
axis: { x: 0, y: 0, z: 1 },
otherEntityID: leftShinID,
otherPivot: { x: 0, y: -shinLength / 2 - ankleGap / 2, z: 0 },
otherAxis: { x: 0, y: 0, z: 1 },
low: ankleMin,
high: ankleMax,
tag: "ragdoll left ankle joint"
});
}
function onWebEventReceived(eventString) {
if (typeof eventString === "string") {
var event;
try {
event = JSON.parse(eventString);
} catch(e) {
return;
}
if (event["dynamics-tests-command"]) {
var commandToFunctionMap = {
"cone-twist-and-tractor-lever-test": coneTwistAndTractorLeverTest,
"door-vs-world-test": doorVSWorldTest,
"hinge-chain-test": hingeChainTest,
"slider-vs-world-test": sliderVSWorldTest,
"slider-chain-test": sliderChainTest,
"ball-socket-between-test": ballSocketBetweenTest,
"ball-socket-coincident-test": ballSocketCoincidentTest,
"ragdoll-test": ragdollTest
};
var cmd = event["dynamics-tests-command"];
if (commandToFunctionMap.hasOwnProperty(cmd)) {
var func = commandToFunctionMap[cmd];
func(event);
}
}
}
}
var onDynamicsTestsScreen = false;
var shouldActivateButton = false;
function onClicked() {
if (onDynamicsTestsScreen) {
tablet.gotoHomeScreen();
} else {
shouldActivateButton = true;
tablet.gotoWebScreen(DYNAMICS_TESTS_URL +
"?lifetime=" + DEFAULT_LIFETIME.toString()
);
onDynamicsTestsScreen = true;
}
}
function onScreenChanged() {
// for toolbar mode: change button to active when window is first openend, false otherwise.
button.editProperties({isActive: shouldActivateButton});
shouldActivateButton = false;
onDynamicsTestsScreen = shouldActivateButton;
}
function cleanup() {
button.clicked.disconnect(onClicked);
tablet.removeButton(button);
}
button.clicked.connect(onClicked);
tablet.webEventReceived.connect(onWebEventReceived);
tablet.screenChanged.connect(onScreenChanged);
Script.scriptEnding.connect(cleanup);
}()); // END LOCAL_SCOPE

View file

@ -1,69 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 744.09448819 1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="dynamicsTests.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.35"
inkscape:cx="-482.14286"
inkscape:cy="520"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="2815"
inkscape:window-height="1776"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
sodipodi:type="spiral"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:20;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4136"
sodipodi:cx="351.42856"
sodipodi:cy="532.36218"
sodipodi:expansion="1"
sodipodi:revolution="3"
sodipodi:radius="189.2628"
sodipodi:argument="-18.34539"
sodipodi:t0="0"
d="m 351.42856,532.36218 c 8.30865,4.58408 -2.08005,13.46152 -7.61904,13.80953 -15.01033,0.94307 -22.49738,-16.46931 -20.00001,-29.04761 4.46719,-22.49963 30.09017,-32.38647 50.47618,-26.1905 29.91728,9.09285 42.49805,43.8703 32.38097,71.90475 -13.48446,37.36552 -57.7036,52.70019 -93.33331,38.57147 -44.83636,-17.77957 -62.94832,-71.56146 -44.76195,-114.76189 22.02613,-52.32152 85.43296,-73.22291 136.19046,-50.95243 59.81595,26.24498 83.51408,99.31294 57.14291,157.61902 -30.44656,67.31668 -113.1986,93.81634 -179.0476,63.3334 C 208.03536,622.01126 178.73083,529.55968 213.33329,456.17176 252.15203,373.8416 354.3141,341.72978 435.23803,380.45739 c 89.8409,42.99499 124.76183,154.87556 81.90485,243.3333"
transform="matrix(1.6331701,0,0,2.2153757,-219.59811,-629.37371)" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -1,25 +0,0 @@
// entityEditStressTest.js
//
// Created by Seiji Emery on 8/31/15
// Copyright 2015 High Fidelity, Inc.
//
// Stress tests the client + server-side entity trees by spawning huge numbers of entities in
// close proximity to your avatar and updating them continuously (ie. applying position edits),
// with the intent of discovering crashes and other bugs related to the entity, scripting,
// rendering, networking, and/or physics subsystems.
//
// This script was originally created to find + diagnose an a clientside crash caused by improper
// locking of the entity tree, but can be reused for other purposes.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("./entitySpawnTool.js");
ENTITY_SPAWNER({
count: 20000,
spawnLimit: 1000,
spawnInterval: 0.1,
updateInterval: 0.05
});

View file

@ -1,104 +0,0 @@
// Creates a large number of entities on the cardinal planes of the octree (all
// objects will live in the root octree element). Measures how long it takes
// to update the properties of the first and last entity. The difference
// between the two measurements shows how the cost of lookup changes as a
// function of the number of entities. For best results run this in an
// otherwise empty domain.
var firstId;
var lastId;
var NUM_ENTITIES_ON_SIDE = 25;
// create the objects
createObjects = function () {
var STRIDE = 0.75;
var WIDTH = 0.5;
var DIMENSIONS = { x: WIDTH, y: WIDTH, z: WIDTH };
var LIFETIME = 20;
var properties = {
name: "",
type : "Box",
dimensions : DIMENSIONS,
position : { x: 0, y: 0, z: 0},
lifetime : LIFETIME,
color : { red:255, green: 64, blue: 255 }
};
// xy
var planeName = "xy";
for (var i = 0; i < NUM_ENTITIES_ON_SIDE; ++i) {
for (var j = 0; j < NUM_ENTITIES_ON_SIDE; ++j) {
properties.name = "Box-" + planeName + "-" + i + "." + j;
properties.position = { x: i * STRIDE, y: j * STRIDE, z: 0 };
var red = i * 255 / NUM_ENTITIES_ON_SIDE;
var green = j * 255 / NUM_ENTITIES_ON_SIDE;
var blue = 0;
properties.color = { red: red, green: green, blue: blue };
if (i == 0 && j == 0) {
firstId = Entities.addEntity(properties);
} else {
Entities.addEntity(properties);
}
}
}
// yz
var planeName = "yz";
for (var i = 0; i < NUM_ENTITIES_ON_SIDE; ++i) {
for (var j = 0; j < NUM_ENTITIES_ON_SIDE; ++j) {
properties.name = "Box-" + planeName + "-" + i + "." + j;
properties.position = { x: 0, y: i * STRIDE, z: j * STRIDE };
var red = 0;
var green = i * 255 / NUM_ENTITIES_ON_SIDE;
var blue = j * 255 / NUM_ENTITIES_ON_SIDE;
properties.color = { red: red, green: green, blue: blue };
Entities.addEntity(properties);
}
}
// zx
var planeName = "zx";
for (var i = 0; i < NUM_ENTITIES_ON_SIDE; ++i) {
for (var j = 0; j < NUM_ENTITIES_ON_SIDE; ++j) {
properties.name = "Box-" + planeName + "-" + i + "." + j;
properties.position = { x: j * STRIDE, y: 0, z: i * STRIDE };
var red = j * 255 / NUM_ENTITIES_ON_SIDE;
var green = 0;
var blue = i * 255 / NUM_ENTITIES_ON_SIDE;
properties.color = { red: red, green: green, blue: blue };
lastId = Entities.addEntity(properties);
}
}
};
createObjects();
// measure the time it takes to edit the first and last entities many times
// (requires a lookup by entityId each time)
changeProperties = function (id) {
var newProperties = { color : { red: 255, green: 255, blue: 255 } };
Entities.editEntity(id, newProperties);
}
// first
var NUM_CHANGES = 10000;
var firstStart = Date.now();
for (var k = 0; k < NUM_CHANGES; ++k) {
changeProperties(firstId);
}
var firstEnd = Date.now();
var firstDt = firstEnd - firstStart;
// last
var lastStart = Date.now();
for (var k = 0; k < NUM_CHANGES; ++k) {
changeProperties(lastId);
}
var lastEnd = Date.now();
var lastDt = lastEnd - lastStart;
// print the results
var numEntities = 3 * NUM_ENTITIES_ON_SIDE * NUM_ENTITIES_ON_SIDE;
print("numEntities = " + numEntities + " numEdits = " + NUM_CHANGES + " firstDt = " + firstDt + " lastDt = " + lastDt);

View file

@ -1,21 +0,0 @@
(function() {
return {
preload: function(uuid) {
var props = Entities.getEntityProperties(uuid);
var shape = props.shape === 'Sphere' ? 'Hexagon' : 'Sphere';
Entities.editEntity(uuid, {
shape: shape,
color: { red: 0xff, green: 0xff, blue: 0xff },
});
this.name = props.name;
print("preload", this.name);
},
unload: function(uuid) {
print("unload", this.name);
Entities.editEntity(uuid, {
color: { red: 0x0f, green: 0x0f, blue: 0xff },
});
},
};
})

View file

@ -1,33 +0,0 @@
var NUM_ENTITIES = 100;
var RADIUS = 2;
var DIV = NUM_ENTITIES / Math.PI / 2;
var PASS_SCRIPT_URL = Script.resolvePath('entityServerStampedeTest-entity.js');
var FAIL_SCRIPT_URL = Script.resolvePath('entityStampedeTest-entity-fail.js');
var origin = Vec3.sum(MyAvatar.position, Vec3.multiply(5, Quat.getForward(MyAvatar.orientation)));
origin.y += HMD.eyeHeight;
var uuids = [];
Script.scriptEnding.connect(function() {
uuids.forEach(function(id) {
Entities.deleteEntity(id);
});
});
for (var i=0; i < NUM_ENTITIES; i++) {
var failGroup = i % 2;
uuids.push(Entities.addEntity({
type: 'Shape',
shape: failGroup ? 'Sphere' : 'Icosahedron',
name: 'SERVER-entityStampedeTest-' + i,
lifetime: 120,
position: Vec3.sum(origin, Vec3.multiplyQbyV(
MyAvatar.orientation, { x: Math.sin(i / DIV) * RADIUS, y: Math.cos(i / DIV) * RADIUS, z: 0 }
)),
serverScripts: (failGroup ? FAIL_SCRIPT_URL : PASS_SCRIPT_URL) + Settings.getValue('cache_buster'),
dimensions: Vec3.HALF,
color: { red: 0, green: 0, blue: 0 },
}, !Entities.serversExist()));
}

View file

@ -1,183 +0,0 @@
// entityEditStressTest.js
//
// Created by Seiji Emery on 8/31/15
// Copyright 2015 High Fidelity, Inc.
//
// Stress tests the client + server-side entity trees by spawning huge numbers of entities in
// close proximity to your avatar and updating them continuously (ie. applying position edits),
// with the intent of discovering crashes and other bugs related to the entity, scripting,
// rendering, networking, and/or physics subsystems.
//
// This script was originally created to find + diagnose an a clientside crash caused by improper
// locking of the entity tree, but can be reused for other purposes.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
ENTITY_SPAWNER = function (properties) {
properties = properties || {};
var RADIUS = properties.radius || 5.0; // Spawn within this radius (square)
var Y_OFFSET = properties.yOffset || 1.5; // Spawn at an offset below the avatar
var TEST_ENTITY_NAME = properties.entityName || "EntitySpawnTest";
var NUM_ENTITIES = properties.count || 1000; // number of entities to spawn
var ENTITY_SPAWN_LIMIT = properties.spawnLimit || 100;
var ENTITY_SPAWN_INTERVAL = properties.spawnInterval || properties.interval || 1.0;
var UPDATE_INTERVAL = properties.updateInterval || properties.interval || 0.1; // Re-randomize the entity's position every x seconds / ms
var ENTITY_LIFETIME = properties.lifetime || 30; // Entity timeout (when/if we crash, we need the entities to delete themselves)
var KEEPALIVE_INTERVAL = properties.keepAlive || 5; // Refreshes the timeout every X seconds
var UPDATES = properties.updates || false
var SHAPES = properties.shapes || ["Icosahedron", "Tetrahedron", "Cube", "Sphere" ];
function makeEntity(properties) {
var entity = Entities.addEntity(properties);
return {
update: function (properties) {
Entities.editEntity(entity, properties);
},
destroy: function () {
Entities.deleteEntity(entity)
},
getAge: function () {
return Entities.getEntityProperties(entity).age;
}
};
}
function randomPositionXZ(center, radius) {
return {
x: center.x + (Math.random() * radius * 2.0) - radius,
y: center.y,
z: center.z + (Math.random() * radius * 2.0) - radius
};
}
function randomPosition(center, radius) {
return {
x: center.x + (Math.random() * radius * 2.0) - radius,
y: center.y + (Math.random() * radius * 2.0) - radius,
z: center.z + (Math.random() * radius * 2.0) - radius
};
}
function randomColor() {
return {
red: Math.floor(Math.random() * 255),
green: Math.floor(Math.random() * 255),
blue: Math.floor(Math.random() * 255),
};
}
function randomDimensions() {
return {
x: 0.1 + Math.random() * 0.5,
y: 0.1 + Math.random() * 0.1,
z: 0.1 + Math.random() * 0.5
};
}
var entities = [];
var entitiesToCreate = 0;
var entitiesSpawned = 0;
var spawnTimer = 0.0;
var keepAliveTimer = 0.0;
var updateTimer = 0.0;
function clear () {
var ids = Entities.findEntities(MyAvatar.position, 50);
var that = this;
ids.forEach(function(id) {
var properties = Entities.getEntityProperties(id);
if (properties.name == TEST_ENTITY_NAME) {
Entities.deleteEntity(id);
}
}, this);
}
function createEntities () {
print("Creating " + NUM_ENTITIES + " entities (UPDATE_INTERVAL = " + UPDATE_INTERVAL + ", KEEPALIVE_INTERVAL = " + KEEPALIVE_INTERVAL + ")");
entitiesToCreate = NUM_ENTITIES;
Script.update.connect(spawnEntities);
}
function spawnEntities (dt) {
if (entitiesToCreate <= 0) {
Script.update.disconnect(spawnEntities);
print("Finished spawning entities");
}
else if ((spawnTimer -= dt) < 0.0){
spawnTimer = ENTITY_SPAWN_INTERVAL;
var n = Math.min(entitiesToCreate, ENTITY_SPAWN_LIMIT);
print("Spawning " + n + " entities (" + (entitiesSpawned += n) + ")");
entitiesToCreate -= n;
var center = MyAvatar.position;
center.y -= Y_OFFSET;
for (; n > 0; --n) {
entities.push(makeEntity({
type: "Shape",
shape: SHAPES[n % SHAPES.length],
name: TEST_ENTITY_NAME,
position: randomPosition(center, RADIUS),
color: randomColor(),
dimensions: randomDimensions(),
lifetime: ENTITY_LIFETIME
}));
}
}
}
function despawnEntities () {
print("despawning entities");
entities.forEach(function (entity) {
entity.destroy();
});
entities = [];
}
// Runs the following entity updates:
// a) refreshes the timeout interval every KEEPALIVE_INTERVAL seconds, and
// b) re-randomizes its position every UPDATE_INTERVAL seconds.
// This should be sufficient to crash the client until the entity tree bug is fixed (and thereafter if it shows up again).
function updateEntities (dt) {
var updateLifetime = ((keepAliveTimer -= dt) < 0.0) ? ((keepAliveTimer = KEEPALIVE_INTERVAL), true) : false;
var updateProperties = ((updateTimer -= dt) < 0.0) ? ((updateTimer = UPDATE_INTERVAL), true) : false;
if (updateLifetime || updateProperties) {
var center = MyAvatar.position;
center.y -= Y_OFFSET;
entities.forEach((updateLifetime && updateProperties && function (entity) {
entity.update({
lifetime: entity.getAge() + ENTITY_LIFETIME,
position: randomPosition(center, RADIUS)
});
}) || (updateLifetime && function (entity) {
entity.update({
lifetime: entity.getAge() + ENTITY_LIFETIME
});
}) || (updateProperties && function (entity) {
entity.update({
position: randomPosition(center, RADIUS)
});
}) || null, this);
}
}
function init () {
Script.update.disconnect(init);
clear();
createEntities();
Script.update.connect(updateEntities);
Script.scriptEnding.connect(despawnEntities);
}
Script.update.connect(init);
};

View file

@ -1,3 +0,0 @@
(function() {
throw new Error(Script.resolvePath(''));
})

View file

@ -1,21 +0,0 @@
(function() {
return {
preload: function(uuid) {
var props = Entities.getEntityProperties(uuid);
var shape = props.shape === 'Sphere' ? 'Cube' : 'Sphere';
Entities.editEntity(uuid, {
shape: shape,
color: { red: 0xff, green: 0xff, blue: 0xff },
});
this.name = props.name;
print("preload", this.name);
},
unload: function(uuid) {
print("unload", this.name);
Entities.editEntity(uuid, {
color: { red: 0xff, green: 0x0f, blue: 0x0f },
});
},
};
})

View file

@ -1,32 +0,0 @@
var NUM_ENTITIES = 100;
var RADIUS = 2;
var DIV = NUM_ENTITIES / Math.PI / 2;
var PASS_SCRIPT_URL = Script.resolvePath('').replace('.js', '-entity.js');
var FAIL_SCRIPT_URL = Script.resolvePath('').replace('.js', '-entity-fail.js');
var origin = Vec3.sum(MyAvatar.position, Vec3.multiply(5, Quat.getForward(MyAvatar.orientation)));
origin.y += HMD.eyeHeight;
var uuids = [];
Script.scriptEnding.connect(function() {
uuids.forEach(function(id) {
Entities.deleteEntity(id);
});
});
for (var i=0; i < NUM_ENTITIES; i++) {
var failGroup = i % 2;
uuids.push(Entities.addEntity({
type: 'Shape',
shape: failGroup ? 'Sphere' : 'Icosahedron',
name: 'entityStampedeTest-' + i,
lifetime: 120,
position: Vec3.sum(origin, Vec3.multiplyQbyV(
MyAvatar.orientation, { x: Math.sin(i / DIV) * RADIUS, y: Math.cos(i / DIV) * RADIUS, z: 0 }
)),
script: (failGroup ? FAIL_SCRIPT_URL : PASS_SCRIPT_URL) + Settings.getValue('cache_buster'),
dimensions: Vec3.HALF,
color: { red: 0, green: 0, blue: 0 },
}, !Entities.serversExist()));
}

View file

@ -1,438 +0,0 @@
//
// Created by Anthony J. Thibault on 2017/06/20
// Modified by Robbie Uvanni to support multiple pucks and easier placement of pucks on entities, on 2017/08/01
// 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
//
// When this script is running, a new app button, named "PUCKTACH", will be added to the toolbar/tablet.
// Click this app to bring up the puck attachment panel.
//
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
/* global Xform */
Script.include("/~/system/libraries/Xform.js");
(function() { // BEGIN LOCAL_SCOPE
var TABLET_BUTTON_NAME = "PUCKATTACH";
var TABLET_APP_URL = "https://s3.amazonaws.com/hifi-public/tony/html/filtered-puck-attach.html?2";
var NUM_TRACKED_OBJECTS = 16;
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var tabletButton = tablet.addButton({
text: TABLET_BUTTON_NAME,
icon: "https://s3.amazonaws.com/hifi-public/tony/icons/puck-i.svg",
activeIcon: "https://s3.amazonaws.com/hifi-public/tony/icons/puck-a.svg"
});
var shown = false;
function onScreenChanged(type, url) {
if (type === "Web" && url === TABLET_APP_URL) {
tabletButton.editProperties({isActive: true});
if (!shown) {
// hook up to event bridge
tablet.webEventReceived.connect(onWebEventReceived);
shownChanged(true);
}
shown = true;
} else {
tabletButton.editProperties({isActive: false});
if (shown) {
// disconnect from event bridge
tablet.webEventReceived.disconnect(onWebEventReceived);
shownChanged(false);
}
shown = false;
}
}
tablet.screenChanged.connect(onScreenChanged);
function pad(num, size) {
var tempString = "000000000" + num;
return tempString.substr(tempString.length - size);
}
function indexToTrackedObjectName(index) {
return "TrackedObject" + pad(index, 2);
}
function getAvailableTrackedObjects() {
var available = [];
var i;
for (i = 0; i < NUM_TRACKED_OBJECTS; i++) {
var key = indexToTrackedObjectName(i);
var pose = Controller.getPoseValue(Controller.Standard[key]);
if (pose && pose.valid) {
available.push(i);
}
}
return available;
}
function sendAvailableTrackedObjects() {
tablet.emitScriptEvent(JSON.stringify({
pucks: getAvailableTrackedObjects(),
selectedPuck: ((lastPuck === undefined) ? -1 : lastPuck.name)
}));
}
function getRelativePosition(origin, rotation, offset) {
var relativeOffset = Vec3.multiplyQbyV(rotation, offset);
var worldPosition = Vec3.sum(origin, relativeOffset);
return worldPosition;
}
function getPropertyForEntity(entityID, propertyName) {
return Entities.getEntityProperties(entityID, [propertyName])[propertyName];
}
function entityExists(entityID) {
return Object.keys(Entities.getEntityProperties(entityID)).length > 0;
}
var VIVE_PUCK_MODEL = "https://s3.amazonaws.com/hifi-public/tony/vive_tracker_puck_y180z180.obj";
var VIVE_PUCK_DIMENSIONS = { x: 0.0945, y: 0.0921, z: 0.0423 }; // 1/1000th scale of model
var VIVE_PUCK_SEARCH_DISTANCE = 1.5; // metres
var VIVE_PUCK_SPAWN_DISTANCE = 0.5; // metres
var VIVE_PUCK_TRACKED_OBJECT_MAX_DISTANCE = 10.0; // metres
var VIVE_PUCK_NAME = "Tracked Puck";
var trackedPucks = { };
var lastPuck;
var DEFAULT_ROTATION_SMOOTHING_CONSTANT = 1.0; // no smoothing
var DEFAULT_TRANSLATION_SMOOTHING_CONSTANT = 1.0; // no smoothing
var DEFAULT_TRANSLATION_ACCELERATION_LIMIT = 1000; // only extreme accelerations are smoothed
var DEFAULT_ROTATION_ACCELERATION_LIMIT = 10000; // only extreme accelerations are smoothed
var DEFAULT_TRANSLATION_SNAP_THRESHOLD = 0; // no snapping
var DEFAULT_ROTATION_SNAP_THRESHOLD = 0; // no snapping
function buildMappingJson() {
var obj = {name: "com.highfidelity.testing.filteredPuckAttach", channels: []};
var i;
for (i = 0; i < NUM_TRACKED_OBJECTS; i++) {
obj.channels.push({
from: "Vive." + indexToTrackedObjectName(i),
to: "Standard." + indexToTrackedObjectName(i),
filters: [
{
type: "accelerationLimiter",
translationAccelerationLimit: DEFAULT_TRANSLATION_ACCELERATION_LIMIT,
rotationAccelerationLimit: DEFAULT_ROTATION_ACCELERATION_LIMIT,
translationSnapThreshold: DEFAULT_TRANSLATION_SNAP_THRESHOLD,
rotationSnapThreshold: DEFAULT_ROTATION_SNAP_THRESHOLD,
},
{
type: "exponentialSmoothing",
translation: DEFAULT_TRANSLATION_SMOOTHING_CONSTANT,
rotation: DEFAULT_ROTATION_SMOOTHING_CONSTANT
}
]
});
}
return obj;
}
var mappingJson = buildMappingJson();
var mapping;
function mappingChanged() {
if (mapping) {
mapping.disable();
}
mapping = Controller.parseMapping(JSON.stringify(mappingJson));
mapping.enable();
}
function shownChanged(newShown) {
if (newShown) {
mappingChanged();
} else {
mapping.disable();
}
}
function setTranslationAccelerationLimit(value) {
var i;
for (i = 0; i < NUM_TRACKED_OBJECTS; i++) {
mappingJson.channels[i].filters[0].translationAccelerationLimit = value;
}
mappingChanged();
}
function setTranslationSnapThreshold(value) {
// convert from mm
var MM_PER_M = 1000;
var meters = value / MM_PER_M;
var i;
for (i = 0; i < NUM_TRACKED_OBJECTS; i++) {
mappingJson.channels[i].filters[0].translationSnapThreshold = meters;
}
mappingChanged();
}
function setRotationAccelerationLimit(value) {
var i;
for (i = 0; i < NUM_TRACKED_OBJECTS; i++) {
mappingJson.channels[i].filters[0].rotationAccelerationLimit = value;
}
mappingChanged();
}
function setRotationSnapThreshold(value) {
// convert from degrees
var PI_IN_DEGREES = 180;
var radians = value * (Math.pi / PI_IN_DEGREES);
var i;
for (i = 0; i < NUM_TRACKED_OBJECTS; i++) {
mappingJson.channels[i].filters[0].translationSnapThreshold = radians;
}
mappingChanged();
}
function setTranslationSmoothingConstant(value) {
var i;
for (i = 0; i < NUM_TRACKED_OBJECTS; i++) {
mappingJson.channels[i].filters[1].translation = value;
}
mappingChanged();
}
function setRotationSmoothingConstant(value) {
var i;
for (i = 0; i < NUM_TRACKED_OBJECTS; i++) {
mappingJson.channels[i].filters[1].rotation = value;
}
mappingChanged();
}
function createPuck(puck) {
// create a puck entity and add it to our list of pucks
var action = indexToTrackedObjectName(puck.puckno);
var pose = Controller.getPoseValue(Controller.Standard[action]);
if (pose && pose.valid) {
var spawnOffset = Vec3.multiply(Vec3.FRONT, VIVE_PUCK_SPAWN_DISTANCE);
var spawnPosition = getRelativePosition(MyAvatar.position, MyAvatar.orientation, spawnOffset);
// should be an overlay
var puckEntityProperties = {
name: "Tracked Puck",
type: "Model",
modelURL: VIVE_PUCK_MODEL,
dimensions: VIVE_PUCK_DIMENSIONS,
position: spawnPosition,
userData: '{ "grabbableKey": { "grabbable": true, "kinematic": false } }'
};
var puckEntityID = Entities.addEntity(puckEntityProperties);
// if we've already created this puck, destroy it
if (trackedPucks.hasOwnProperty(puck.puckno)) {
destroyPuck(puck.puckno);
}
// if we had an unfinalized puck, destroy it
if (lastPuck !== undefined) {
destroyPuck(lastPuck.name);
}
// create our new unfinalized puck
trackedPucks[puck.puckno] = {
puckEntityID: puckEntityID,
trackedEntityID: ""
};
lastPuck = trackedPucks[puck.puckno];
lastPuck.name = Number(puck.puckno);
}
}
function finalizePuck(puckName) {
// find nearest entity and change its parent to the puck
if (!trackedPucks.hasOwnProperty(puckName)) {
print('2');
return;
}
if (lastPuck === undefined) {
print('3');
return;
}
if (lastPuck.name !== Number(puckName)) {
print('1');
return;
}
var puckPosition = getPropertyForEntity(lastPuck.puckEntityID, "position");
var foundEntities = Entities.findEntities(puckPosition, VIVE_PUCK_SEARCH_DISTANCE);
var foundEntity;
var leastDistance = Number.MAX_VALUE;
for (var i = 0; i < foundEntities.length; i++) {
var entity = foundEntities[i];
if (getPropertyForEntity(entity, "name") !== VIVE_PUCK_NAME) {
var entityPosition = getPropertyForEntity(entity, "position");
var d = Vec3.distance(entityPosition, puckPosition);
if (d < leastDistance) {
leastDistance = d;
foundEntity = entity;
}
}
}
if (foundEntity) {
lastPuck.trackedEntityID = foundEntity;
// remember the userdata and collisionless flag for the tracked entity since
// we're about to remove it and make it ungrabbable and collisionless
lastPuck.trackedEntityUserData = getPropertyForEntity(foundEntity, "userData");
lastPuck.trackedEntityCollisionFlag = getPropertyForEntity(foundEntity, "collisionless");
// update properties of the tracked entity
Entities.editEntity(lastPuck.trackedEntityID, {
"parentID": lastPuck.puckEntityID,
"userData": '{ "grabbableKey": { "grabbable": false } }',
"collisionless": 1
});
// remove reference to puck since it is now calibrated and finalized
lastPuck = undefined;
}
}
function updatePucks() {
// for each puck, update its position and orientation
for (var puckName in trackedPucks) {
if (!trackedPucks.hasOwnProperty(puckName)) {
continue;
}
var action = indexToTrackedObjectName(puckName);
var pose = Controller.getPoseValue(Controller.Standard[action]);
if (pose && pose.valid) {
var puck = trackedPucks[puckName];
if (puck.trackedEntityID) {
if (entityExists(puck.trackedEntityID)) {
var avatarXform = new Xform(MyAvatar.orientation, MyAvatar.position);
var puckXform = new Xform(pose.rotation, pose.translation);
var finalXform = Xform.mul(avatarXform, puckXform);
var d = Vec3.distance(MyAvatar.position, finalXform.pos);
if (d > VIVE_PUCK_TRACKED_OBJECT_MAX_DISTANCE) {
print('tried to move tracked object too far away: ' + d);
return;
}
Entities.editEntity(puck.puckEntityID, {
position: finalXform.pos,
rotation: finalXform.rot
});
// in case someone grabbed both entities and destroyed the
// child/parent relationship
Entities.editEntity(puck.trackedEntityID, {
parentID: puck.puckEntityID
});
} else {
destroyPuck(puckName);
}
}
}
}
}
function destroyPuck(puckName) {
// unparent entity and delete its parent
if (!trackedPucks.hasOwnProperty(puckName)) {
return;
}
var puck = trackedPucks[puckName];
var puckEntityID = puck.puckEntityID;
var trackedEntityID = puck.trackedEntityID;
// remove the puck as a parent entity and restore the tracked entities
// former userdata and collision flag
Entities.editEntity(trackedEntityID, {
"parentID": "{00000000-0000-0000-0000-000000000000}",
"userData": puck.trackedEntityUserData,
"collisionless": puck.trackedEntityCollisionFlag
});
delete trackedPucks[puckName];
// in some cases, the entity deletion may occur before the parent change
// has been processed, resulting in both the puck and the tracked entity
// to be deleted so we wait 100ms before deleting the puck, assuming
// that the parent change has occured
var DELETE_TIMEOUT = 100; // ms
Script.setTimeout(function() {
// delete the puck
Entities.deleteEntity(puckEntityID);
}, DELETE_TIMEOUT);
}
function destroyPucks() {
// remove all pucks and unparent entities
for (var puckName in trackedPucks) {
if (trackedPucks.hasOwnProperty(puckName)) {
destroyPuck(puckName);
}
}
}
function onWebEventReceived(msg) {
var obj = {};
try {
obj = JSON.parse(msg);
} catch (err) {
return;
}
switch (obj.cmd) {
case "ready":
sendAvailableTrackedObjects();
break;
case "create":
createPuck(obj);
break;
case "finalize":
finalizePuck(obj.puckno);
break;
case "destroy":
destroyPuck(obj.puckno);
break;
case "translation-acceleration-limit":
setTranslationAccelerationLimit(Number(obj.val));
break;
case "translation-snap-threshold":
setTranslationSnapThreshold(Number(obj.val));
break;
case "rotation-acceleration-limit":
setRotationAccelerationLimit(Number(obj.val));
break;
case "rotation-snap-threshold":
setRotationSnapThreshold(Number(obj.val));
break;
case "translation-smoothing-constant":
setTranslationSmoothingConstant(Number(obj.val));
break;
case "rotation-smoothing-constant":
setRotationSmoothingConstant(Number(obj.val));
break;
}
}
Script.update.connect(updatePucks);
Script.scriptEnding.connect(function () {
tablet.removeButton(tabletButton);
destroyPucks();
if (shown) {
tablet.webEventReceived.disconnect(onWebEventReceived);
tablet.gotoHomeScreen();
}
tablet.screenChanged.disconnect(onScreenChanged);
if (mapping) {
mapping.disable();
}
});
tabletButton.clicked.connect(function () {
if (shown) {
tablet.gotoHomeScreen();
} else {
tablet.gotoWebScreen(TABLET_APP_URL);
}
});
}()); // END LOCAL_SCOPE

View file

@ -1,45 +0,0 @@
//
// Gravity Script 1.0
// ************
//
// Created by Cain Kilgore on 9/14/2017
// Javascript for the Gravity Modifier Implementation to test
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
function menuParameters(menuNameSelection, menuItemNameSelection) {
Menu.addMenuItem({
menuName: menuNameSelection,
menuItemName: menuItemNameSelection,
isCheckable: false
});
}
function setupMenu() {
if (!Menu.menuExists("Gravity")) {
Menu.addMenu("Gravity");
for (var i = -5; i <= 5; i++) {
menuParameters("Gravity", i);
}
}
}
function menuItemEvent(menuItem) {
for (var i = -5; i <= 5; i++) {
if (menuItem == i) {
MyAvatar.setGravity(i);
}
}
}
function onScriptEnding() {
Menu.removeMenu("Gravity");
}
setupMenu();
Menu.menuItemEvent.connect(menuItemEvent);
Script.scriptEnding.connect(onScriptEnding);

View file

@ -1,5 +0,0 @@
var ORIGIN = {x: -68.7, y: 27.4, z: 487.7};
var ROT_IDENT = {x: 0, y: 0.901, z: 0, w: 0.434};
MyAvatar.position = ORIGIN;
MyAvatar.orientation = ROT_IDENT;

View file

@ -1,105 +0,0 @@
//
// hipsControllerTest.js
//
// Created by Anthony Thibault on 4/24/17
// Copyright 2017 High Fidelity, Inc.
//
// Test procedural manipulation of the Avatar hips via the controller system.
// Pull the left and right triggers on your hand controllers, you hips should begin to gyrate in an amusing mannor.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
/* global Xform */
Script.include("/~/system/libraries/Xform.js");
var triggerPressHandled = false;
var rightTriggerPressed = false;
var leftTriggerPressed = false;
var MAPPING_NAME = "com.highfidelity.hipsIkTest";
var mapping = Controller.newMapping(MAPPING_NAME);
mapping.from([Controller.Standard.RTClick]).peek().to(function (value) {
rightTriggerPressed = (value !== 0) ? true : false;
});
mapping.from([Controller.Standard.LTClick]).peek().to(function (value) {
leftTriggerPressed = (value !== 0) ? true : false;
});
Controller.enableMapping(MAPPING_NAME);
var CONTROLLER_MAPPING_NAME = "com.highfidelity.hipsIkTest.controller";
var controllerMapping;
var ZERO = {x: 0, y: 0, z: 0};
var X_AXIS = {x: 1, y: 0, z: 0};
var Y_AXIS = {x: 0, y: 1, z: 0};
var Y_180 = {x: 0, y: 1, z: 0, w: 0};
var Y_180_XFORM = new Xform(Y_180, {x: 0, y: 0, z: 0});
var hips = undefined;
function computeCurrentXform(jointIndex) {
var currentXform = new Xform(MyAvatar.getAbsoluteJointRotationInObjectFrame(jointIndex),
MyAvatar.getAbsoluteJointTranslationInObjectFrame(jointIndex));
return currentXform;
}
function calibrate() {
hips = computeCurrentXform(MyAvatar.getJointIndex("Hips"));
}
function circleOffset(radius, theta, normal) {
var pos = {x: radius * Math.cos(theta), y: radius * Math.sin(theta), z: 0};
var lookAtRot = Quat.lookAt(normal, ZERO, X_AXIS);
return Vec3.multiplyQbyV(lookAtRot, pos);
}
var calibrationCount = 0;
function update(dt) {
if (rightTriggerPressed && leftTriggerPressed) {
if (!triggerPressHandled) {
triggerPressHandled = true;
if (controllerMapping) {
hips = undefined;
Controller.disableMapping(CONTROLLER_MAPPING_NAME + calibrationCount);
controllerMapping = undefined;
} else {
calibrate();
calibrationCount++;
controllerMapping = Controller.newMapping(CONTROLLER_MAPPING_NAME + calibrationCount);
var n = Y_AXIS;
var t = 0;
if (hips) {
controllerMapping.from(function () {
t += (1 / 60) * 4;
return {
valid: true,
translation: Vec3.sum(hips.pos, circleOffset(0.1, t, n)),
rotation: hips.rot,
velocity: ZERO,
angularVelocity: ZERO
};
}).to(Controller.Standard.Hips);
}
Controller.enableMapping(CONTROLLER_MAPPING_NAME + calibrationCount);
}
}
} else {
triggerPressHandled = false;
}
}
Script.update.connect(update);
Script.scriptEnding.connect(function () {
Controller.disableMapping(MAPPING_NAME);
if (controllerMapping) {
Controller.disableMapping(CONTROLLER_MAPPING_NAME + calibrationCount);
}
Script.update.disconnect(update);
});

View file

@ -1,118 +0,0 @@
//
// hipsIKTest.js
//
// Created by Anthony Thibault on 4/24/17
// Copyright 2017 High Fidelity, Inc.
//
// Test procedural manipulation of the Avatar hips IK target.
// Pull the left and right triggers on your hand controllers, you hips should begin to gyrate in an amusing mannor.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
/* global Xform */
Script.include("/~/system/libraries/Xform.js");
var calibrated = false;
var rightTriggerPressed = false;
var leftTriggerPressed = false;
var MAPPING_NAME = "com.highfidelity.hipsIkTest";
var mapping = Controller.newMapping(MAPPING_NAME);
mapping.from([Controller.Standard.RTClick]).peek().to(function (value) {
rightTriggerPressed = (value !== 0) ? true : false;
});
mapping.from([Controller.Standard.LTClick]).peek().to(function (value) {
leftTriggerPressed = (value !== 0) ? true : false;
});
Controller.enableMapping(MAPPING_NAME);
var ANIM_VARS = [
"headType",
"hipsType",
"hipsPosition",
"hipsRotation"
];
var ZERO = {x: 0, y: 0, z: 0};
var X_AXIS = {x: 1, y: 0, z: 0};
var Y_AXIS = {x: 0, y: 1, z: 0};
var Y_180 = {x: 0, y: 1, z: 0, w: 0};
var Y_180_XFORM = new Xform(Y_180, {x: 0, y: 0, z: 0});
var hips = undefined;
function computeCurrentXform(jointIndex) {
var currentXform = new Xform(MyAvatar.getAbsoluteJointRotationInObjectFrame(jointIndex),
MyAvatar.getAbsoluteJointTranslationInObjectFrame(jointIndex));
return Xform.mul(Y_180_XFORM, currentXform);
}
function calibrate() {
hips = computeCurrentXform(MyAvatar.getJointIndex("Hips"));
}
var ikTypes = {
RotationAndPosition: 0,
RotationOnly: 1,
HmdHead: 2,
HipsRelativeRotationAndPosition: 3,
Off: 4
};
function circleOffset(radius, theta, normal) {
var pos = {x: radius * Math.cos(theta), y: radius * Math.sin(theta), z: 0};
var lookAtRot = Quat.lookAt(normal, ZERO, X_AXIS);
return Vec3.multiplyQbyV(lookAtRot, pos);
}
var handlerId;
function update(dt) {
if (rightTriggerPressed && leftTriggerPressed) {
if (!calibrated) {
calibrate();
calibrated = true;
if (handlerId) {
MyAvatar.removeAnimationStateHandler(handlerId);
handlerId = undefined;
} else {
var n = Y_AXIS;
var t = 0;
handlerId = MyAvatar.addAnimationStateHandler(function (props) {
t += (1 / 60) * 4;
var result = {}, xform;
if (hips) {
xform = hips;
result.hipsType = ikTypes.RotationAndPosition;
result.hipsPosition = Vec3.sum(xform.pos, circleOffset(0.1, t, n));
result.hipsRotation = xform.rot;
result.headType = ikTypes.RotationAndPosition;
} else {
result.headType = ikTypes.HmdHead;
result.hipsType = props.hipsType;
result.hipsPosition = props.hipsPosition;
result.hipsRotation = props.hipsRotation;
}
return result;
}, ANIM_VARS);
}
}
} else {
calibrated = false;
}
}
Script.update.connect(update);
Script.scriptEnding.connect(function () {
Controller.disableMapping(MAPPING_NAME);
Script.update.disconnect(update);
});

View file

@ -1,42 +0,0 @@
//
// injectorTests.js
// examples
//
// Created by Stephen Birarda on 11/16/15.
// Copyright 2014 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 soundURL = "http://hifi-public.s3.amazonaws.com/birarda/medium-crowd.wav";
var audioOptions = {
position: { x: 0.0, y: 0.0, z: 0.0 },
volume: 0.5
};
var sound = SoundCache.getSound(soundURL);
var injector = null;
var restarting = false;
Script.update.connect(function(){
if (sound.downloaded) {
if (!injector) {
injector = Audio.playSound(sound, audioOptions);
} else if (!injector.isPlaying && !restarting) {
restarting = true;
Script.setTimeout(function(){
print("Calling restart for a stopped injector from script.");
injector.restart();
}, 1000);
} else if (injector.isPlaying) {
restarting = false;
if (Math.random() < 0.0001) {
print("Calling restart for a running injector from script.");
injector.restart();
}
}
}
})

View file

@ -1,34 +0,0 @@
//
// interactiveWindowTest.js
//
// Created by Thijs Wenker on 2018-07-03
// Copyright 2018 High Fidelity, Inc.
//
// An example of an interactive window that toggles presentation mode when toggling HMD on/off
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
function getPreferredPresentationMode() {
return HMD.active ? Desktop.PresentationMode.VIRTUAL : Desktop.PresentationMode.NATIVE;
}
function getPreferredTitle() {
return HMD.active ? 'Virtual Desktop Window' : 'Native Desktop Window';
}
var virtualWindow = Desktop.createWindow(Script.resourcesPath() + 'qml/OverlayWindowTest.qml', {
title: getPreferredTitle(),
flags: Desktop.ALWAYS_ON_TOP,
presentationMode: getPreferredPresentationMode(),
size: {x: 500, y: 400}
});
HMD.displayModeChanged.connect(function() {
virtualWindow.presentationMode = getPreferredPresentationMode();
virtualWindow.title = getPreferredTitle();
});
Script.scriptEnding.connect(function() {
virtualWindow.close();
});

View file

@ -1,192 +0,0 @@
"use strict";
/*jslint vars: true, plusplus: true*/
/*globals Script, MyAvatar, Quat, Render, ScriptDiscoveryService, Window, LODManager, Entities, print*/
//
// loadedMachine.js
// scripts/developer/tests/
//
// Created by Howard Stearns on 6/6/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
//
// Characterises the performance of heavily loaded or struggling machines.
// There is no point in running this on a machine that producing the target 60 or 90 hz rendering rate.
//
// The script examines several source of load, including each running script and a couple of Entity types.
// It turns all of these off, as well as LOD management, and twirls in place to get a baseline render rate.
// Then it turns each load on, one at a time, and records a new render rate.
// At the end, it reports the ordered results (in a popup), restores the original loads and LOD management, and quits.
//
// Small performance changes are not meaningful.
// If you think you find something that is significant, you should probably run again to make sure that it isn't random variation.
// You can also compare (e.g., the baseline) for different conditions such as domain, version, server settings, etc.
// This does not profile scripts as they are used -- it merely measures the effect of having the script loaded and running quietly.
var NUMBER_OF_TWIRLS_PER_LOAD = 10;
var MILLISECONDS_PER_SECOND = 1000;
var WAIT_TIME_MILLISECONDS = MILLISECONDS_PER_SECOND;
var accumulatedRotation = 0;
var start;
var frames = 0;
var config = Render.getConfig("Stats");
var thisPath = Script.resolvePath('');
var scriptData = ScriptDiscoveryService.getRunning();
var scripts = scriptData.filter(function (datum) { return datum.name !== 'defaultScripts.js'; }).map(function (script) { return script.path; });
// If defaultScripts.js is running, we leave it running, because restarting it safely is a mess.
var otherScripts = scripts.filter(function (path) { return path !== thisPath; });
var numberLeftRunning = scriptData.length - otherScripts.length;
print('initially running', otherScripts.length, 'scripts. Leaving', numberLeftRunning, 'and stopping otherScripts');
var typedEntities = {Light: [], ParticleEffect: []};
var interestingTypes = Object.keys(typedEntities);
var propertiedEntities = {dynamic: []};
var interestingProperties = Object.keys(propertiedEntities);
var loads = ['ignore', 'baseline'].concat(otherScripts, interestingTypes, interestingProperties);
var loadIndex = 0, nLoads = loads.length, load;
var results = [];
var initialLodIsAutomatic = LODManager.getAutomaticLODAdjust();
var SEARCH_RADIUS = 17000;
var DEFAULT_LOD = 32768 * 400;
LODManager.setAutomaticLODAdjust(false);
LODManager.setOctreeSizeScale(DEFAULT_LOD);
// Fill the typedEnties with the entityIDs that are already visible. It would be nice if this were more efficient.
var allEntities = Entities.findEntities(MyAvatar.position, SEARCH_RADIUS);
print('Searching', allEntities.length, 'entities for', interestingTypes, 'and', interestingProperties);
var propertiesToGet = ['type', 'visible'].concat(interestingProperties);
allEntities.forEach(function (entityID) {
var properties = Entities.getEntityProperties(entityID, propertiesToGet);
if (properties.visible) {
if (interestingTypes.indexOf(properties.type) >= 0) {
typedEntities[properties.type].push(entityID);
} else {
interestingProperties.forEach(function (property) {
if (entityID && properties[property]) {
propertiedEntities[property].push(entityID);
entityID = false; // Put in only one bin
}
});
}
}
});
allEntities = undefined; // free them
interestingTypes.forEach(function (type) {
print('There are', typedEntities[type].length, type, 'entities.');
});
interestingProperties.forEach(function (property) {
print('There are', propertiedEntities[property].length, property, 'entities.');
});
function toggleVisibility(type, on) {
typedEntities[type].forEach(function (entityID) {
Entities.editEntity(entityID, {visible: on});
});
}
function toggleProperty(property, on) {
propertiedEntities[property].forEach(function (entityID) {
var properties = {};
properties[property] = on;
Entities.editEntity(entityID, properties);
});
}
function restoreOneTest(load) {
print('restore', load);
switch (load) {
case 'baseline':
case 'ignore': // ignore is used to do a twirl to make sure everything is loaded.
break;
case 'Light':
case 'ParticleEffect':
toggleVisibility(load, true);
break;
case 'dynamic':
toggleProperty(load, 1);
break;
default:
Script.load(load);
}
}
function undoOneTest(load) {
print('stop', load);
switch (load) {
case 'baseline':
case 'ignore':
break;
case 'Light':
case 'ParticleEffect':
toggleVisibility(load, false);
break;
case 'dynamic':
toggleProperty(load, 0);
break;
default:
ScriptDiscoveryService.stopScript(load);
}
}
loads.forEach(undoOneTest);
function finalReport() {
var baseline = results[0];
results.forEach(function (result) {
result.ratio = (baseline.fps / result.fps);
});
results.sort(function (a, b) { return b.ratio - a.ratio; });
var report = 'Performance Report:\nBaseline: ' + baseline.fps.toFixed(1) + ' fps.';
results.forEach(function (result) {
report += '\n' + result.ratio.toFixed(2) + ' (' + result.fps.toFixed(1) + ' fps over ' + result.elapsed + ' seconds) for ' + result.name;
});
Window.alert(report);
LODManager.setAutomaticLODAdjust(initialLodIsAutomatic);
loads.forEach(restoreOneTest);
Script.stop();
}
function onNewStats() { // Accumulates frames on signal during load test
frames++;
}
var DEGREES_PER_FULL_TWIRL = 360;
var DEGREES_PER_UPDATE = 6;
function onUpdate() { // Spins on update signal during load test
MyAvatar.orientation = Quat.fromPitchYawRollDegrees(0, accumulatedRotation, 0);
accumulatedRotation += DEGREES_PER_UPDATE;
if (accumulatedRotation >= (DEGREES_PER_FULL_TWIRL * NUMBER_OF_TWIRLS_PER_LOAD)) {
tearDown();
}
}
function startTest() {
print('start', load);
accumulatedRotation = frames = 0;
start = Date.now();
Script.update.connect(onUpdate);
config.newStats.connect(onNewStats);
}
function setup() {
if (loadIndex >= nLoads) {
return finalReport();
}
load = loads[loadIndex];
restoreOneTest(load);
Script.setTimeout(startTest, WAIT_TIME_MILLISECONDS);
}
function tearDown() {
var now = Date.now();
var elapsed = (now - start) / MILLISECONDS_PER_SECOND;
Script.update.disconnect(onUpdate);
config.newStats.disconnect(onNewStats);
if (load !== 'ignore') {
results.push({name: load, fps: frames / elapsed, elapsed: elapsed});
}
undoOneTest(load);
loadIndex++;
setup();
}
function waitUntilStopped() { // Wait until all the scripts have stopped
var count = ScriptDiscoveryService.getRunning().length;
if (count === numberLeftRunning) {
return setup();
}
print('Still', count, 'scripts running');
Script.setTimeout(waitUntilStopped, WAIT_TIME_MILLISECONDS);
}
waitUntilStopped();

View file

@ -1,40 +0,0 @@
//
// lodTest.js
// examples/tests
//
// Created by Ryan Huffman on 11/19/15.
// 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
//
var MIN_DIM = 0.001;
var MAX_DIM = 2.0;
var NUM_SPHERES = 20;
// Rough estimate of the width the spheres will span, not taking into account MIN_DIM
var WIDTH = MAX_DIM * NUM_SPHERES;
var entities = [];
var right = Quat.getRight(Camera.orientation);
// Starting position will be 30 meters in front of the camera
var position = Vec3.sum(Camera.position, Vec3.multiply(30, Quat.getForward(Camera.orientation)));
position = Vec3.sum(position, Vec3.multiply(-WIDTH/2, right));
for (var i = 0; i < NUM_SPHERES; ++i) {
var dim = (MAX_DIM - MIN_DIM) * ((i + 1) / NUM_SPHERES);
entities.push(Entities.addEntity({
type: "Sphere",
dimensions: { x: dim, y: dim, z: dim },
position: position,
}));
position = Vec3.sum(position, Vec3.multiply(dim * 2, right));
}
Script.scriptEnding.connect(function() {
for (var i = 0; i < entities.length; ++i) {
Entities.deleteEntity(entities[i]);
}
})

View file

@ -1,165 +0,0 @@
//
// mat4test.js
// examples/tests
//
// Created by Anthony Thibault on 2016/3/7
// 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 IDENTITY = {r0c0: 1, r0c1: 0, r0c2: 0, r0c3: 0,
r1c0: 0, r1c1: 1, r1c2: 0, r1c3: 0,
r2c0: 0, r2c1: 0, r2c2: 1, r2c3: 0,
r3c0: 0, r3c1: 0, r3c2: 0, r3c3: 1};
var ROT_ZERO = {x: 0, y: 0, z: 0, w: 1};
var ROT_Y_180 = {x: 0, y: 1, z: 0, w: 0};
var ONE = {x: 1, y: 1, z: 1};
var ZERO = {x: 0, y: 0, z: 0};
var ONE_TWO_THREE = {x: 1, y: 2, z: 3};
var ONE_HALF = {x: 0.5, y: 0.5, z: 0.5};
var EPSILON = 0.000001;
function mat4FuzzyEqual(a, b) {
var r, c;
for (r = 0; r < 4; r++) {
for (c = 0; c < 4; c++) {
if (Math.abs(a["r" + r + "c" + c] - b["r" + r + "c" + c]) > EPSILON) {
return false;
}
}
}
return true;
}
function vec3FuzzyEqual(a, b) {
if (Math.abs(a.x - b.x) > EPSILON ||
Math.abs(a.y - b.y) > EPSILON ||
Math.abs(a.z - b.z) > EPSILON) {
return false;
}
return true;
}
function quatFuzzyEqual(a, b) {
if (Math.abs(a.x - b.x) > EPSILON ||
Math.abs(a.y - b.y) > EPSILON ||
Math.abs(a.z - b.z) > EPSILON ||
Math.abs(a.w - b.w) > EPSILON) {
return false;
}
return true;
}
var failureCount = 0;
var testCount = 0;
function assert(test) {
testCount++;
if (!test) {
print("MAT4 TEST " + testCount + " failed!");
failureCount++;
}
}
function testCreate() {
var test0 = Mat4.createFromScaleRotAndTrans(ONE, {x: 0, y: 0, z: 0, w: 1}, ZERO);
assert(mat4FuzzyEqual(test0, IDENTITY));
var test1 = Mat4.createFromRotAndTrans({x: 0, y: 0, z: 0, w: 1}, ZERO);
assert(mat4FuzzyEqual(test1, IDENTITY));
var test2 = Mat4.createFromRotAndTrans(ROT_Y_180, ONE_TWO_THREE);
assert(mat4FuzzyEqual(test2, {r0c0: -1, r0c1: 0, r0c2: 0, r0c3: 1,
r1c0: 0, r1c1: 1, r1c2: 0, r1c3: 2,
r2c0: 0, r2c1: 0, r2c2: -1, r2c3: 3,
r3c0: 0, r3c1: 0, r3c2: 0, r3c3: 1}));
var test3 = Mat4.createFromScaleRotAndTrans(ONE_HALF, ROT_Y_180, ONE_TWO_THREE);
assert(mat4FuzzyEqual(test3, {r0c0: -0.5, r0c1: 0, r0c2: 0, r0c3: 1,
r1c0: 0, r1c1: 0.5, r1c2: 0, r1c3: 2,
r2c0: 0, r2c1: 0, r2c2: -0.5, r2c3: 3,
r3c0: 0, r3c1: 0, r3c2: 0, r3c3: 1}));
}
function testExtractTranslation() {
var test0 = Mat4.extractTranslation(IDENTITY);
assert(vec3FuzzyEqual(ZERO, test0));
var test1 = Mat4.extractTranslation(Mat4.createFromRotAndTrans(ROT_Y_180, ONE_TWO_THREE));
assert(vec3FuzzyEqual(ONE_TWO_THREE, test1));
}
function testExtractRotation() {
var test0 = Mat4.extractRotation(IDENTITY);
assert(quatFuzzyEqual(ROT_ZERO, test0));
var test1 = Mat4.extractRotation(Mat4.createFromRotAndTrans(ROT_Y_180, ONE_TWO_THREE));
assert(quatFuzzyEqual(ROT_Y_180, test1));
}
function testExtractScale() {
var test0 = Mat4.extractScale(IDENTITY);
assert(vec3FuzzyEqual(ONE, test0));
var test1 = Mat4.extractScale(Mat4.createFromScaleRotAndTrans(ONE_HALF, ROT_Y_180, ONE_TWO_THREE));
assert(vec3FuzzyEqual(ONE_HALF, test1));
var test2 = Mat4.extractScale(Mat4.createFromScaleRotAndTrans(ONE_TWO_THREE, ROT_ZERO, ONE_TWO_THREE));
assert(vec3FuzzyEqual(ONE_TWO_THREE, test2));
}
function testTransformPoint() {
var test0 = Mat4.transformPoint(IDENTITY, ONE);
assert(vec3FuzzyEqual(ONE, test0));
var m = Mat4.createFromScaleRotAndTrans(ONE_HALF, ROT_Y_180, ONE_TWO_THREE);
var test1 = Mat4.transformPoint(m, ONE);
assert(vec3FuzzyEqual({x: 0.5, y: 2.5, z: 2.5}, test1));
}
function testTransformVector() {
var test0 = Mat4.transformVector(IDENTITY, ONE);
assert(vec3FuzzyEqual(ONE, test0));
var m = Mat4.createFromScaleRotAndTrans(ONE_HALF, ROT_Y_180, ONE_TWO_THREE);
var test1 = Mat4.transformVector(m, ONE);
assert(vec3FuzzyEqual({x: -0.5, y: 0.5, z: -0.5}, test1));
}
function testInverse() {
var test0 = IDENTITY;
assert(mat4FuzzyEqual(IDENTITY, Mat4.multiply(test0, Mat4.inverse(test0))));
var test1 = Mat4.createFromScaleRotAndTrans(ONE_HALF, ROT_Y_180, ONE_TWO_THREE);
assert(mat4FuzzyEqual(IDENTITY, Mat4.multiply(test1, Mat4.inverse(test1))));
var test2 = Mat4.extractScale(Mat4.createFromScaleRotAndTrans(ONE_TWO_THREE, ROT_ZERO, ONE_TWO_THREE));
assert(mat4FuzzyEqual(IDENTITY, Mat4.multiply(test2, Mat4.inverse(test2))));
}
function testForward() {
var test0 = IDENTITY;
assert(mat4FuzzyEqual({x: 0, y: 0, z: -1}, Mat4.getForward(test0)));
var test1 = Mat4.createFromScaleRotAndTrans(ONE_HALF, ROT_Y_180, ONE_TWO_THREE);
assert(mat4FuzzyEqual({x: 0, y: 0, z: 1}, Mat4.getForward(test1)));
}
function testMat4() {
testCreate();
testExtractTranslation();
testExtractRotation();
testExtractScale();
testTransformPoint();
testTransformVector();
testInverse();
testForward();
print("MAT4 TEST complete! (" + (testCount - failureCount) + "/" + testCount + ") tests passed!");
}
testMat4();

View file

@ -1,38 +0,0 @@
var channelName = "com.highfidelity.example.dataMessages";
Messages.subscribe(channelName);
//messageReceived(QString channel, QString message, QUuid senderUUID, bool localOnly);
Messages.messageReceived.connect(function(channel, message, sender, local) {
print("message received on ", channel, " message:", message, " from:", sender, " local:", local);
});
Messages.dataReceived.connect(function(channel, data, sender, local) {
var int8data = new Int8Array(data);
var dataAsString = "";
for (var i = 0; i < int8data.length; i++) {
if (i > 0) {
dataAsString += ", ";
}
dataAsString += int8data[i];
}
print("data received on ", channel, " from:", sender, " local:", local, "length of data:", int8data.length, " data:", dataAsString);
});
var counter = 0;
Script.update.connect(function(){
counter++;
if (counter == 100) {
Messages.sendMessage(channelName, "foo");
} else if (counter == 200) {
var data = new Int8Array([0,1,10,2,20,3,30]);
print("about to call sendData() data.length:", data.length);
Messages.sendData(channelName, data.buffer);
counter = 0;
}
});
Script.scriptEnding.connect(function(){
Messages.unsubscribe(channelName);
});

View file

@ -1,46 +0,0 @@
MouseTracker = function() {
this.WIDTH = 60;
this.HEIGHT = 60;
this.overlay = Overlays.addOverlay("image", {
imageURL: Script.resolvePath("dot.png"),
width: this.HEIGHT,
height: this.WIDTH,
x: 100,
y: 100,
visible: true
});
var that = this;
Script.scriptEnding.connect(function() {
that.onCleanup();
});
Controller.mousePressEvent.connect(function(event) {
that.onMousePress(event);
});
Controller.mouseMoveEvent.connect(function(event) {
that.onMouseMove(event);
});
}
MouseTracker.prototype.onCleanup = function() {
Overlays.deleteOverlay(this.overlay);
}
MouseTracker.prototype.onMousePress = function(event) {
}
MouseTracker.prototype.onMouseMove = function(event) {
var width = Overlays.width();
var height = Overlays.height();
var x = Math.max(event.x, 0);
x = Math.min(x, width);
var y = Math.max(event.y, 0);
y = Math.min(y, height);
Overlays.editOverlay(this.overlay, {x: x - this.WIDTH / 2.0, y: y - this.HEIGHT / 2.0});
}
new MouseTracker();

View file

@ -1,101 +0,0 @@
//
// particleOrientationTest.js
// examples/tests
//
// Created by Piper.Peppercorn.
// 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
//
var emitterBone = 'Head'
var particleEntities = [];
function emitter(jointName) {
var jointID = MyAvatar.jointNames.indexOf(jointName);
var newEmitter = Entities.addEntity({
name: 'particleEmitter ' + jointName,
type: 'ParticleEffect',
emitterShouldTrail: true,
textures: 'https://dl.dropboxusercontent.com/u/96759331/ParticleTest.png',
position: Vec3.sum(MyAvatar.getAbsoluteJointRotationInObjectFrame(jointID), MyAvatar.position),
parentJointIndex: jointID,
position: MyAvatar.getJointPosition(jointName),
color: {
red: 255,
green: 255,
blue: 255
},
isEmitting: 1,
maxParticles: 1,
lifespan: 2.0
,
emitRate: 1,
emitSpeed: 0.0,
speedSpread: 0.0,
/*
emitOrientation: {
x: -0.7035577893257141,
y: -0.000015259007341228426,
z: -0.000015259007341228426,
w: 1.7106381058692932
},
*/
emitOrientation: {
x:0,
y: 0,
z: 0,
w: 1
},
emitRadiusStart: 0,
polarStart: 0,
polarFinish: 0,
azimuthFinish: 3.1415927410125732,
emitAcceleration: {
x: 0,
y: 0,
z: 0
},
accelerationSpread: {
x: 0,
y: 0,
z: 0
},
particleRadius: 2.0,
radiusSpread: 1.0,
radiusStart: 2.0,
radiusFinish: 2.0,
colorSpread: {
red: 0,
green: 0,
blue: 0
},
colorStart: {
red: 255,
green: 255,
blue: 255
},
colorFinish: {
red: 255,
green: 255,
blue: 255
},
alpha: 1,
alphaSpread: 0,
alphaStart: 1,
alphaFinish: 1
});
return newEmitter;
}
Script.scriptEnding.connect(function() {
for (var i = 0; i < particleEntities.length; i++) {
// Fixes a crash on shutdown:
Entities.editEntity(particleEntities[i], { parentID: '' });
Entities.deleteEntity(particleEntities[i]);
}
});
particleEntities.push(emitter(emitterBone));

View file

@ -1,161 +0,0 @@
// entityEditStressTest.js
//
// Created by Seiji Emery on 8/31/15
// Copyright 2015 High Fidelity, Inc.
//
// Stress tests the client + server-side entity trees by spawning huge numbers of entities in
// close proximity to your avatar and updating them continuously (ie. applying position edits),
// with the intent of discovering crashes and other bugs related to the entity, scripting,
// rendering, networking, and/or physics subsystems.
//
// This script was originally created to find + diagnose an a clientside crash caused by improper
// locking of the entity tree, but can be reused for other purposes.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var NUM_ENTITIES = 20; // number of entities to spawn
var ENTITY_SPAWN_INTERVAL = 0.01;
var ENTITY_SPAWN_LIMIT = 1000;
var Y_OFFSET = 1.5;
var ENTITY_LIFETIME = 600; // Entity timeout (when/if we crash, we need the entities to delete themselves)
var KEEPALIVE_INTERVAL = 15; // Refreshes the timeout every X seconds
var RADIUS = 0.5; // Spawn within this radius (square)
var TEST_ENTITY_NAME = "EntitySpawnTest";
var UPDATE_INTERVAL = 0.1;
(function () {
this.makeEntity = function (properties) {
var entity = Entities.addEntity(properties);
return {
update: function (properties) {
Entities.editEntity(entity, properties);
},
destroy: function () {
Entities.deleteEntity(entity)
},
getAge: function () {
return Entities.getEntityProperties(entity).age;
}
};
}
this.randomPositionXZ = function (center, radius) {
return {
x: center.x + (Math.random() * radius * 2.0) - radius,
y: center.y,
z: center.z + (Math.random() * radius * 2.0) - radius
};
}
this.randomDimensions = function () {
return {
x: 0.1 + Math.random() * 0.1,
y: 0.1 + Math.random() * 0.05,
z: 0.1 + Math.random() * 0.1
};
}
})();
(function () {
var entities = [];
var entitiesToCreate = 0;
var entitiesSpawned = 0;
function clear () {
var ids = Entities.findEntities(MyAvatar.position, 50);
var that = this;
ids.forEach(function(id) {
var properties = Entities.getEntityProperties(id);
if (properties.name == TEST_ENTITY_NAME) {
Entities.deleteEntity(id);
}
}, this);
}
function createEntities () {
print("Creating " + NUM_ENTITIES + " entities (UPDATE_INTERVAL = " + UPDATE_INTERVAL + ", KEEPALIVE_INTERVAL = " + KEEPALIVE_INTERVAL + ")");
entitiesToCreate = NUM_ENTITIES;
Script.update.connect(spawnEntities);
}
var spawnTimer = 0.0;
function spawnEntities (dt) {
if (entitiesToCreate <= 0) {
Script.update.disconnect(spawnEntities);
print("Finished spawning entities");
}
else if ((spawnTimer -= dt) < 0.0){
spawnTimer = ENTITY_SPAWN_INTERVAL;
var n = Math.min(entitiesToCreate, ENTITY_SPAWN_LIMIT);
print("Spawning " + n + " entities (" + (entitiesSpawned += n) + ")");
entitiesToCreate -= n;
var center = { x: 0, y: 0, z: 0 } //MyAvatar.position;
// center.y += 1.0;
for (; n > 0; --n) {
entities.push(makeEntity({
type: "Model",
name: TEST_ENTITY_NAME,
position: randomPositionXZ(center, RADIUS),
dimensions: randomDimensions(),
modelURL: "https://s3.amazonaws.com/DreamingContent/models/console.fbx",
lifetime: ENTITY_LIFETIME
}));
}
}
}
function despawnEntities () {
print("despawning entities");
entities.forEach(function (entity) {
entity.destroy();
});
entities = [];
}
var keepAliveTimer = 0.0;
var updateTimer = 0.0;
// Runs the following entity updates:
// a) refreshes the timeout interval every KEEPALIVE_INTERVAL seconds, and
// b) re-randomizes its position every UPDATE_INTERVAL seconds.
// This should be sufficient to crash the client until the entity tree bug is fixed (and thereafter if it shows up again).
function updateEntities (dt) {
var updateLifetime = ((keepAliveTimer -= dt) < 0.0) ? ((keepAliveTimer = KEEPALIVE_INTERVAL), true) : false;
var updateProperties = ((updateTimer -= dt) < 0.0) ? ((updateTimer = UPDATE_INTERVAL), true) : false;
if (updateLifetime || updateProperties) {
var center = MyAvatar.position;
center.y -= Y_OFFSET;
entities.forEach((updateLifetime && updateProperties && function (entity) {
entity.update({
lifetime: entity.getAge() + ENTITY_LIFETIME,
position: randomPositionXZ(center, RADIUS)
});
}) || (updateLifetime && function (entity) {
entity.update({
lifetime: entity.getAge() + ENTITY_LIFETIME
});
}) || (updateProperties && function (entity) {
entity.update({
position: randomPositionXZ(center, RADIUS)
});
}) || null, this);
}
}
function init () {
Script.update.disconnect(init);
clear();
createEntities();
//Script.update.connect(updateEntities);
Script.scriptEnding.connect(despawnEntities);
}
Script.update.connect(init);
})();

View file

@ -1,166 +0,0 @@
"use strict";
/*jslint vars: true, plusplus: true*/
/*global Agent, Avatar, Script, Entities, Vec3, Quat, print*/
//
// crowd-agent.js
// scripts/developer/tests/performance/
//
// Created by Howard Stearns on 9/29/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
//
// Add this to domain-settings scripts url with n instances. It will lie dormant until
// a script like summon.js calls up to n avatars to be around you.
var MESSAGE_CHANNEL = "io.highfidelity.summon-crowd";
print('crowd-agent version 5');
/* Observations:
- File urls for AC scripts silently fail. Use a local server (e.g., python SimpleHTTPServer) for development.
- URLs are cached regardless of server headers. Must use cache-defeating query parameters.
- JSON.stringify(Avatar) silently fails (even when Agent.isAvatar)
- If you run from a dev build directory, you must link assignment-client/<target>/resources to ../../interface/<target>/resources
*/
function messageSend(message) {
Messages.sendMessage(MESSAGE_CHANNEL, JSON.stringify(message));
}
function getSound(data, callback) { // callback(sound) when downloaded (which may be immediate).
var sound = SoundCache.getSound(data.url);
if (sound.downloaded) {
return callback(sound);
}
function onDownloaded() {
sound.ready.disconnect(onDownloaded);
callback(sound);
}
sound.ready.connect(onDownloaded);
}
function onFinishedPlaying() {
messageSend({key: 'finishedSound'});
}
var attachment;
var stopper;
function clearStopper() {
if (!stopper) {
return;
}
Script.clearTimeout(stopper);
stopper = null;
}
function stopAgent(parameters) {
function stop() {
clearStopper();
if (attachment) {
Avatar.detachOne(attachment.modelURL, attachment.jointName);
attachment = undefined;
}
Agent.isListeningToAudioStream = false;
Agent.isAvatar = false;
print('crowd-agent stopped', JSON.stringify(parameters), JSON.stringify(Agent));
}
// Shutting down lots of agents at once can be hard on other parts of the system. (See fogbugz 2095.)
// For now, accept a parameter to delay for the given number of milliseconds before stopping.
// (We cannot count on summoning scripts to spread out the STOP messages, because they might be doing so
// on scriptEnding, in which case they are not allowed to create new delays.)
if (parameters.delay) {
if (!stopper) { // Let the first stopper do the deed.
stopper = Script.setTimeout(stop, parameters.delay);
}
} else {
stop();
}
}
var MILLISECONDS_IN_SECOND = 1000;
function startAgent(parameters) { // Can also be used to update.
print('crowd-agent starting params', JSON.stringify(parameters), JSON.stringify(Agent));
clearStopper();
var wasOff = !Agent.isAvatar;
Agent.isAvatar = true;
if (parameters.displayName !== undefined) {
Avatar.displayName = parameters.displayName;
}
if (parameters.position) {
Avatar.position = parameters.position;
}
if (parameters.orientation) {
Avatar.orientation = parameters.orientation;
}
if (parameters.skeletonModelURL) {
Avatar.skeletonModelURL = parameters.skeletonModelURL;
}
if (parameters.listen != undefined) {
Agent.isListeningToAudioStream = parameters.listen; // Send silence when not chattering.
} else if (wasOff) {
Agent.isListeningToAudioStream = true;
}
if (parameters.soundData) {
getSound(parameters.soundData, function (sound) {
Script.setTimeout(onFinishedPlaying, sound.duration * MILLISECONDS_IN_SECOND);
Agent.playAvatarSound(sound);
});
}
if (parameters.animationData) {
var data = parameters.animationData;
Avatar.startAnimation(data.url, data.fps || 30, 1.0, (data.loopFlag === undefined) ? true : data.loopFlag, false, data.startFrame || 0, data.endFrame);
}
if (parameters.attachment) {
attachment = parameters.attachment;
Avatar.attach(attachment.modelURL, attachment.jointName, attachment.translation, attachment.rotation, attachment.scale, attachment.isSoft);
} else {
attachment = undefined;
}
print('crowd-agent avatars started');
}
function messageHandler(channel, messageString, senderID) {
if (channel !== MESSAGE_CHANNEL) {
return;
}
print('crowd-agent message', channel, messageString, senderID);
if (Agent.sessionUUID === senderID) { // ignore my own
return;
}
var message = {};
try {
message = JSON.parse(messageString);
} catch (e) {
}
switch (message.key) {
case "HELO":
messageSend({key: 'hello'}); // Allow the coordinator to count responses and make assignments.
break;
case 'hello': // ignore responses (e.g., from other agents)
case 'finishedSound':
break;
case "SUMMON":
if (message.rcpt === Agent.sessionUUID) {
startAgent(message);
}
break;
case "STOP":
if (message.rcpt === Agent.sessionUUID) {
stopAgent(message);
}
break;
default:
print("crowd-agent received unrecognized message:", channel, messageString, senderID);
}
}
Messages.subscribe(MESSAGE_CHANNEL);
Messages.messageReceived.connect(messageHandler);
Script.scriptEnding.connect(function () {
print('crowd-agent shutting down');
Messages.messageReceived.disconnect(messageHandler);
Messages.unsubscribe(MESSAGE_CHANNEL);
print('crowd-agent unsubscribed');
});

View file

@ -1,345 +0,0 @@
"use strict";
/*jslint vars: true, plusplus: true*/
/*globals Script, MyAvatar, Quat, Vec3, Render, ScriptDiscoveryService, Window, LODManager, Entities, Messages, AvatarList, Menu, Stats, HMD, location, print*/
//
// loadedMachine.js
// scripts/developer/tests/
//
// Created by Howard Stearns on 6/6/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
//
// Confirms that the specified domain is operating within specified constraints.
var MINIMUM_DESKTOP_FRAMERATE = 57; // frames per second
var MINIMUM_HMD_FRAMERATE = 86;
var EXPECTED_DESKTOP_FRAMERATE = 60;
var EXPECTED_HMD_FRAMERATE = 90;
var NOMINAL_LOAD_TIME = 30; // seconds
var MAXIMUM_LOAD_TIME = NOMINAL_LOAD_TIME * 2;
var MINIMUM_AVATARS = 25; // changeable by prompt
// If we add or remove things too quickly, we get problems (e.g., audio, fogbugz 2095).
// For now, spread them out this timing apart.
var SPREAD_TIME_MS = 500;
var DENSITY = 0.3; // square meters per person. Some say 10 sq ft is arm's length (0.9m^2), 4.5 is crowd (0.4m^2), 2.5 is mosh pit (0.2m^2).
var SOUND_DATA = {url: "http://hifi-content.s3.amazonaws.com/howard/sounds/piano1.wav"};
var AVATARS_CHATTERING_AT_ONCE = 4; // How many of the agents should we request to play SOUND at once.
var NEXT_SOUND_SPREAD = 500; // millisecond range of how long to wait after one sound finishes, before playing the next
var ANIMATION_DATA = {
"url": "http://hifi-content.s3.amazonaws.com/howard/resources/avatar/animations/idle.fbx",
// "url": "http://hifi-content.s3.amazonaws.com/howard/resources/avatar/animations/walk_fwd.fbx", // alternative example
"startFrame": 0.0,
"endFrame": 300.0,
"timeScale": 1.0,
"loopFlag": true
};
var version = 4;
function debug() {
print.apply(null, [].concat.apply(['hrs fixme', version], [].map.call(arguments, JSON.stringify)));
}
function canonicalizePlacename(name) {
var prefix = 'dev-';
name = name.toLowerCase();
if (name.indexOf(prefix) === 0) {
name = name.slice(prefix.length);
}
return name;
}
var cachePlaces = ['localhost', 'welcome'].map(canonicalizePlacename); // For now, list the lighter weight one first.
var defaultPlace = location.hostname;
var prompt = "domain-check.js version " + version + "\n\nWhat place should we enter?";
debug(cachePlaces, defaultPlace, prompt);
var entryPlace = Window.prompt(prompt, defaultPlace);
var runTribbles = Window.confirm("Run tribbles?\n\n\
At most, only one participant should say yes.");
MINIMUM_AVATARS = parseInt(Window.prompt("Total avatars (including yourself and any already present)?", MINIMUM_AVATARS.toString()) || "0", 10);
AVATARS_CHATTERING_AT_ONCE = MINIMUM_AVATARS ? parseInt(Window.prompt("Number making sound?", Math.min(MINIMUM_AVATARS - 1, AVATARS_CHATTERING_AT_ONCE).toString()) || "0", 10) : 0;
function placesMatch(a, b) { // handling case and 'dev-' variations
return canonicalizePlacename(a) === canonicalizePlacename(b);
}
function isNowIn(place) { // true if currently in specified place
placesMatch(location.hostname, place);
}
function go(place) { // handle (dev-)welcome in the appropriate version-specific way
debug('go', place);
if (placesMatch(place, 'welcome')) {
location.goToEntry();
} else {
location.handleLookupString(place);
}
}
var spread = Math.sqrt(MINIMUM_AVATARS * DENSITY); // meters
var turnSpread = 90; // How many degrees should turn from front range over.
function coord() { return (Math.random() * spread) - (spread / 2); } // randomly distribute a coordinate zero += spread/2.
function contains(array, item) { return array.indexOf(item) >= 0; }
function without(array, itemsToRemove) { return array.filter(function (item) { return !contains(itemsToRemove, item); }); }
function nextAfter(array, id) { // Wrapping next element in array after id.
var index = array.indexOf(id) + 1;
return array[(index >= array.length) ? 0 : index];
}
var summonedAgents = [];
var chattering = [];
var accumulatedDelay = 0;
var MESSAGE_CHANNEL = "io.highfidelity.summon-crowd";
function messageSend(message) {
Messages.sendMessage(MESSAGE_CHANNEL, JSON.stringify(message));
}
function messageHandler(channel, messageString, senderID) {
if (channel !== MESSAGE_CHANNEL) {
return;
}
debug('message', channel, messageString, senderID);
if (MyAvatar.sessionUUID === senderID) { // ignore my own
return;
}
var message = {}, avatarIdentifiers;
try {
message = JSON.parse(messageString);
} catch (e) {
}
switch (message.key) {
case "hello":
Script.setTimeout(function () {
// There can be avatars we've summoned that do not yet appear in the AvatarList.
avatarIdentifiers = without(AvatarList.getAvatarIdentifiers(), summonedAgents);
debug('present', avatarIdentifiers, summonedAgents);
if ((summonedAgents.length + avatarIdentifiers.length) < MINIMUM_AVATARS) {
var chatter = chattering.length < AVATARS_CHATTERING_AT_ONCE;
if (chatter) {
chattering.push(senderID);
}
summonedAgents.push(senderID);
messageSend({
key: 'SUMMON',
rcpt: senderID,
position: Vec3.sum(MyAvatar.position, {x: coord(), y: 0, z: coord()}),
orientation: Quat.fromPitchYawRollDegrees(0, Quat.safeEulerAngles(MyAvatar.orientation).y + (turnSpread * (Math.random() - 0.5)), 0),
soundData: chatter && SOUND_DATA,
listen: true,
skeletonModelURL: "http://hifi-content.s3.amazonaws.com/howard/resources/meshes/defaultAvatar_full.fst",
animationData: ANIMATION_DATA
});
}
}, accumulatedDelay);
accumulatedDelay += SPREAD_TIME_MS; // assume we'll get all the hello respsponses more or less together.
break;
case "finishedSound": // Give someone else a chance.
chattering = without(chattering, [senderID]);
Script.setTimeout(function () {
messageSend({
key: 'SUMMON',
rcpt: nextAfter(without(summonedAgents, chattering), senderID),
soundData: SOUND_DATA
});
}, Math.random() * NEXT_SOUND_SPREAD);
break;
case "HELO":
Window.alert("Someone else is summoning avatars.");
break;
default:
print("crowd-agent received unrecognized message");
}
}
Messages.subscribe(MESSAGE_CHANNEL);
Messages.messageReceived.connect(messageHandler);
Script.scriptEnding.connect(function () {
debug('stopping agents', summonedAgents);
Messages.messageReceived.disconnect(messageHandler); // don't respond to any messages during shutdown
accumulatedDelay = 0;
summonedAgents.forEach(function (id) {
messageSend({key: 'STOP', rcpt: id, delay: accumulatedDelay});
accumulatedDelay += SPREAD_TIME_MS;
});
debug('agents stopped');
Messages.unsubscribe(MESSAGE_CHANNEL);
debug('unsubscribed');
});
var fail = false, results = "";
function addResult(label, actual, nominal, minimum, maximum) {
if ((minimum !== undefined) && (actual < minimum)) {
fail = ' FAILED: ' + label + ' below ' + minimum;
}
if ((maximum !== undefined) && (actual > maximum)) {
fail = ' FAILED: ' + label + ' above ' + maximum;
}
results += "\n" + label + ": " + actual.toFixed(0) + " (" + ((100 * actual) / nominal).toFixed(0) + "%)";
}
function giveReport() {
Window.alert(entryPlace + (fail || " OK") + "\n" + results + "\nwith " + summonedAgents.length + " avatars added,\nand " + AVATARS_CHATTERING_AT_ONCE + " making noise.");
}
// Tests are performed domain-wide, at full LOD
var initialLodIsAutomatic = LODManager.getAutomaticLODAdjust();
var LOD = 32768 * 400;
LODManager.setAutomaticLODAdjust(false);
LODManager.setOctreeSizeScale(LOD);
Script.scriptEnding.connect(function () { LODManager.setAutomaticLODAdjust(initialLodIsAutomatic); });
function startTwirl(targetRotation, degreesPerUpdate, interval, strafeDistance, optionalCallback) {
var initialRotation = Quat.safeEulerAngles(MyAvatar.orientation).y;
var accumulatedRotation = 0;
function tick() {
MyAvatar.orientation = Quat.fromPitchYawRollDegrees(0, accumulatedRotation + initialRotation, 0);
if (strafeDistance) {
MyAvatar.position = Vec3.sum(MyAvatar.position, Vec3.multiply(strafeDistance, Quat.getRight(MyAvatar.orientation)));
}
accumulatedRotation += degreesPerUpdate;
if (accumulatedRotation >= targetRotation) {
return optionalCallback && optionalCallback();
}
Script.setTimeout(tick, interval);
}
tick();
}
function doLoad(place, continuationWithLoadTime) { // Go to place and call continuationWithLoadTime(loadTimeInSeconds)
var start = Date.now(), timeout, onDownloadUpdate, finishedTwirl = false, loadTime;
// There are two ways to learn of changes: connect to change signals, or poll.
// Until we get reliable results, we'll poll.
var POLL_INTERVAL = 500, poll;
function setHandlers() {
//Stats.downloadsPendingChanged.connect(onDownloadUpdate); downloadsChanged, and physics...
poll = Script.setInterval(onDownloadUpdate, POLL_INTERVAL);
}
function clearHandlers() {
debug('clearHandlers');
//Stats.downloadsPendingChanged.disconnect(onDownloadUpdate); downloadsChanged, and physics..
Script.clearInterval(poll);
}
function waitForLoad(flag) {
debug('entry', place, 'initial downloads/pending', Stats.downloads, Stats.downloadsPending);
location.hostChanged.disconnect(waitForLoad);
timeout = Script.setTimeout(function () {
debug('downloads timeout', Date());
clearHandlers();
Window.alert("Timeout during " + place + " load. FAILED");
Script.stop();
}, MAXIMUM_LOAD_TIME * 1000);
startTwirl(360, 6, 90, null, function () {
finishedTwirl = true;
if (loadTime) {
continuationWithLoadTime(loadTime);
}
});
setHandlers();
}
function isLoading() {
// FIXME: We should also confirm that textures have loaded.
return Stats.downloads || Stats.downloadsPending || !Window.isPhysicsEnabled();
}
onDownloadUpdate = function onDownloadUpdate() {
debug('update downloads/pending', Stats.downloads, Stats.downloadsPending);
if (isLoading()) {
return;
}
Script.clearTimeout(timeout);
clearHandlers();
loadTime = (Date.now() - start) / 1000;
if (finishedTwirl) {
continuationWithLoadTime(loadTime);
}
};
location.hostChanged.connect(waitForLoad);
go(place);
}
var config = Render.getConfig("Stats");
function doRender(continuation) {
var start = Date.now(), frames = 0;
function onNewStats() { // Accumulates frames on signal during load test
frames++;
}
if (MINIMUM_AVATARS) {
messageSend({key: 'HELO'}); // Ask agents to report in now.
}
config.newStats.connect(onNewStats);
startTwirl(720, 1, 20, 0.08, function () {
var end = Date.now();
config.newStats.disconnect(onNewStats);
addResult('frame rate', 1000 * frames / (end - start),
HMD.active ? EXPECTED_HMD_FRAMERATE : EXPECTED_DESKTOP_FRAMERATE,
HMD.active ? MINIMUM_HMD_FRAMERATE : MINIMUM_DESKTOP_FRAMERATE);
var total = AvatarList.getAvatarIdentifiers().length;
if (MINIMUM_AVATARS && !fail) {
if (0 === summonedAgents.length) {
fail = "FAIL: No agents reported.\nPlease run " + MINIMUM_AVATARS + " instances of\n\
http://hifi-content.s3.amazonaws.com/howard/scripts/tests/performance/crowd-agent.js?v=3\n\
on your domain server.";
} else if (total < MINIMUM_AVATARS) {
fail = "FAIL: Only " + summonedAgents.length + " agents reported. Now missing " + (MINIMUM_AVATARS - total) + " avatars, total.";
}
}
continuation();
});
}
var TELEPORT_PAUSE = 500;
function prepareCache(continuation) {
function loadNext() {
var place = cachePlaces.shift();
doLoad(place, function (prepTime) {
debug(place, 'ready', prepTime);
if (cachePlaces.length) {
loadNext();
} else {
continuation();
}
});
}
// remove entryPlace target from cachePlaces
var targetInCache = cachePlaces.indexOf(canonicalizePlacename(entryPlace));
if (targetInCache !== -1) {
cachePlaces.splice(targetInCache, 1);
}
debug('cachePlaces', cachePlaces);
go(cachePlaces[1] || entryPlace); // Not quite right for entryPlace case (allows some qt pre-caching), but close enough.
Script.setTimeout(function () {
Menu.triggerOption("Reload Content (Clears all caches)");
Script.setTimeout(loadNext, TELEPORT_PAUSE);
}, TELEPORT_PAUSE);
}
function maybeRunTribbles(continuation) {
if (runTribbles) {
Script.load('http://cdn.highfidelity.com/davidkelly/production/scripts/tests/performance/tribbles.js');
Script.setTimeout(continuation, 3000);
} else {
continuation();
}
}
if (!entryPlace) {
Window.alert("domain-check.js cancelled");
Script.stop();
} else {
prepareCache(function (prepTime) {
debug('cache ready', prepTime);
doLoad(entryPlace, function (loadTime) {
addResult("load time", loadTime, NOMINAL_LOAD_TIME, undefined, MAXIMUM_LOAD_TIME);
LODManager.setAutomaticLODAdjust(initialLodIsAutomatic); // after loading, restore lod.
maybeRunTribbles(function () {
doRender(function () {
giveReport();
Script.stop();
});
});
});
});
}
Script.scriptEnding.connect(function () { print("domain-check completed"); });

View file

@ -1,39 +0,0 @@
(function() {
// The attached entity will move away from you if you are too close, checking at distanceRate.
// See tests/performance/simpleKeepAway.js
var entityID,
distanceRate = 1, // hertz
distanceAllowance = 3, // meters
distanceScale = 0.5, // meters/second
distanceTimer;
function moveDistance() { // every user checks their distance and tries to claim if close enough.
var me = MyAvatar.position,
ball = Entities.getEntityProperties(entityID, ['position']).position;
ball.y = me.y;
var vector = Vec3.subtract(ball, me);
if (Vec3.length(vector) < distanceAllowance) {
Entities.editEntity(entityID, {
velocity: Vec3.multiply(distanceScale, Vec3.normalize(vector))
});
}
}
this.preload = function(givenEntityID) {
var properties = Entities.getEntityProperties(givenEntityID, ['userData']),
userData = properties.userData && JSON.parse(properties.userData);
entityID = givenEntityID;
if (userData) {
distanceRate = userData.distanceRate || distanceRate;
distanceAllowance = userData.distanceAllowance || distanceAllowance;
distanceScale = userData.distanceScale || distanceScale;
}
// run all the time by everyone:
distanceTimer = Script.setInterval(moveDistance, distanceRate);
};
this.unload = function() {
Script.clearTimeout(distanceTimer);
};
})

View file

@ -1,130 +0,0 @@
//
// rayPickingPerformance.js
// examples
//
// Created by Brad Hefta-Gaub on 5/13/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
//
var MIN_RANGE = -3;
var MAX_RANGE = 3;
var RANGE_DELTA = 0.5;
var OUTER_LOOPS = 10;
// NOTE: These expected results depend completely on the model, and the range settings above
var EXPECTED_TESTS = 1385 * OUTER_LOOPS;
var EXPECTED_INTERSECTIONS = 1286 * OUTER_LOOPS;
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(Camera.getOrientation())));
var model_url = "http://hifi-content.s3.amazonaws.com/caitlyn/production/Scansite/buddhaReduced.fbx";
var rayPickOverlays = Array();
var modelEntity = Entities.addEntity({
type: "Model",
modelURL: model_url,
dimensions: {
x: 0.671,
y: 1.21,
z: 0.938
},
position: center
});
function rayCastTest() {
var tests = 0;
var intersections = 0;
var testStart = Date.now();
for (var t = 0; t < OUTER_LOOPS; t++) {
print("beginning loop:" + t);
for (var x = MIN_RANGE; x < MAX_RANGE; x += RANGE_DELTA) {
for (var y = MIN_RANGE; y < MAX_RANGE; y += RANGE_DELTA) {
for (var z = MIN_RANGE; z < MAX_RANGE; z += RANGE_DELTA) {
if ((x <= -2 || x >= 2) ||
(y <= -2 || y >= 2) ||
(z <= -2 || z >= 2)) {
tests++;
var origin = { x: center.x + x,
y: center.y + y,
z: center.z + z };
var direction = Vec3.subtract(center, origin);
var pickRay = {
origin: origin,
direction: direction
};
var pickResults = Entities.findRayIntersection(pickRay, true);
var color;
var visible;
if (pickResults.intersects && pickResults.entityID == modelEntity) {
intersections++;
color = {
red: 0,
green: 255,
blue: 0
};
visible = false;
} else {
/*
print("NO INTERSECTION?");
Vec3.print("origin:", origin);
Vec3.print("direction:", direction);
*/
color = {
red: 255,
green: 0,
blue: 0
};
visible = true;
}
var overlayID = Overlays.addOverlay("line3d", {
color: color,
alpha: 1,
visible: visible,
start: origin,
end: Vec3.sum(origin,Vec3.multiply(5,direction))
});
rayPickOverlays.push(overlayID);
}
}
}
}
print("ending loop:" + t);
}
var testEnd = Date.now();
var testElapsed = testEnd - testStart;
print("EXPECTED tests:" + EXPECTED_TESTS + " intersections:" + EXPECTED_INTERSECTIONS);
print("ACTUAL tests:" + tests + " intersections:" + intersections);
print("ELAPSED TIME:" + testElapsed + " ms");
}
function cleanup() {
Entities.deleteEntity(modelEntity);
rayPickOverlays.forEach(function(item){
Overlays.deleteOverlay(item);
});
}
Script.scriptEnding.connect(cleanup);
rayCastTest(); // run ray cast test immediately

View file

@ -1,113 +0,0 @@
"use strict";
/*jslint nomen: true, plusplus: true, vars: true*/
var Vec3, Quat, MyAvatar, Entities, Camera, Script, print;
//
// Created by Howard Stearns
// 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
//
// Drops a bunch of physical spheres which each run an entity script that moves away
// from you once a second if you are within range.
//
// This is a test of how many physical, entity-scripted objects can be around if
// they are mostly not doing anything -- i.e., just the basic overhead of such objects.
// They do need a moment to settle out of active physics after being dropped, but only
// a moment -- that's why they are in a sparse grid.
var USE_FLAT_FLOOR = true; // Give 'em a flat place to settle on.
var ROWS_X = 30;
var ROWS_Z = 30;
var SEPARATION = 1; // meters
var LIFETIME = 60; // seconds
var DISTANCE_RATE = 1; // hz
var DISTANCE_ALLOWANCE = 3; // meters. Must be this close to cause entity to move
var DISTANCE_SCALE = 0.5; // velocity will be scale x vector from user to entity
var SIZE = 0.5;
var TYPE = "Sphere";
// Note that when creating things quickly, the entity server will ignore data if we send updates too quickly.
// like Internet MTU, these rates are set by th domain operator, so in this script there is a RATE_PER_SECOND
// variable letting you set this speed. If entities are missing from the grid after a relog, this number
// being too high may be the reason.
var RATE_PER_SECOND = 600; // The entity server will drop data if we create things too fast.
var SCRIPT_INTERVAL = 100;
var GRAVITY = { x: 0, y: -9.8, z: 0 };
var VELOCITY = { x: 0.0, y: 0.1, z: 0 };
var DAMPING = 0.75;
var ANGULAR_DAMPING = 0.75;
var RANGE = 3;
var HOW_FAR_UP = 2; // for uneven ground
var x = 0;
var z = 0;
var totalCreated = 0;
var xDim = ROWS_X * SEPARATION;
var zDim = ROWS_Z * SEPARATION;
var totalToCreate = ROWS_X * ROWS_Z;
var origin = Vec3.sum(MyAvatar.position, {x: xDim / -2, y: HOW_FAR_UP, z: zDim / -2});
print("Creating " + totalToCreate + " origined on " + JSON.stringify(MyAvatar.position) +
", starting at " + JSON.stringify(origin));
var parameters = JSON.stringify({
distanceRate: DISTANCE_RATE,
distanceScale: DISTANCE_SCALE,
distanceAllowance: DISTANCE_ALLOWANCE
});
var startTime = new Date();
if (USE_FLAT_FLOOR) {
Entities.addEntity({
type: 'Box',
name: 'keepAwayFloor',
lifetime: LIFETIME,
collisionsWillMove: false,
color: {red: 255, green: 0, blue: 0},
position: Vec3.sum(origin, {x: xDim / 2, y: -1 - HOW_FAR_UP, z: zDim / 2}),
dimensions: {x: xDim + SEPARATION, y: 0.2, z: zDim + SEPARATION}
});
}
Script.setInterval(function () {
if (!Entities.serversExist() || !Entities.canRez()) {
return;
}
var i, properties, numToCreate = Math.min(RATE_PER_SECOND * (SCRIPT_INTERVAL / 1000.0), totalToCreate - totalCreated);
for (i = 0; i < numToCreate; i++) {
properties = {
userData: parameters,
type: TYPE,
name: "keepAway-" + totalCreated,
position: {
x: origin.x + SIZE + (x * SEPARATION),
y: origin.y,
z: origin.z + SIZE + (z * SEPARATION)
},
dimensions: {x: SIZE, y: SIZE, z: SIZE},
color: {red: Math.random() * 255, green: Math.random() * 255, blue: Math.random() * 255},
velocity: VELOCITY,
damping: DAMPING,
angularDamping: ANGULAR_DAMPING,
gravity: GRAVITY,
collisionsWillMove: true,
lifetime: LIFETIME,
script: Script.resolvePath("keepAwayEntity.js")
};
Entities.addEntity(properties);
totalCreated++;
x++;
if (x === ROWS_X) {
x = 0;
z++;
print("Created: " + totalCreated);
}
if (z === ROWS_Z) {
print("Total: " + totalCreated + " entities in " + ((new Date() - startTime) / 1000.0) + " seconds.");
Script.stop();
}
}
}, SCRIPT_INTERVAL);

View file

@ -1,96 +0,0 @@
"use strict";
/*jslint nomen: true, plusplus: true, vars: true*/
var Entities, Script, print, Vec3, MyAvatar;
//
// Created by Howard Stearns
// 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
//
// Creates a rectangular matrix of objects overhed, and edits them at EDIT_FREQUENCY_TARGET.
// Reports ms since last edit, ms to edit all the created entities, and average ms to edit one entity,
// so that you can measure how many edits can be made.
//
var LIFETIME = 15;
var ROWS_X = 10;
var ROWS_Y = 2;
var ROWS_Z = 10;
var SEPARATION = 10.0;
var SIZE = 1.0;
// Note that when creating things quickly, the entity server will ignore data if we send updates too quickly.
// like Internet MTU, these rates are set by th domain operator, so in this script there is a RATE_PER_SECOND
// variable letting you set this speed. If entities are missing from the grid after a relog, this number
// being too high may be the reason.
var RATE_PER_SECOND = 600; // The entity server will drop data if we create things too fast.
var SCRIPT_INTERVAL = 100;
var x = 0;
var y = 0;
var z = 0;
var o = Vec3.sum(MyAvatar.position, {x: ROWS_X * SEPARATION / -2, y: SEPARATION, z: ROWS_Z * SEPARATION / -2});
var totalCreated = 0;
var startTime = new Date();
var totalToCreate = ROWS_X * ROWS_Y * ROWS_Z;
print("Creating " + totalToCreate + " entities starting at " + startTime);
var ids = [], colors = [], flasher, lastService = Date.now();
function doFlash() { // One could call this in an interval timer, an update, or even a separate entity script.
var i, oldColor, newColor;
var start = Date.now();
for (i = 0; i < ids.length; i++) {
oldColor = colors[i];
newColor = {red: oldColor.green, green: oldColor.blue, blue: oldColor.red};
colors[i] = newColor;
Entities.editEntity(ids[i], {color: newColor});
}
var elapsed = Date.now() - start, serviceTime = start - lastService;
lastService = start;
print(serviceTime, elapsed, elapsed / totalCreated); // ms since last flash, ms to edit all entities, average ms to edit one entity
}
function stopFlash() {
Script.clearTimeout(flasher);
Script.stop();
}
var creator = Script.setInterval(function () {
if (!Entities.serversExist() || !Entities.canRez()) {
return;
}
var numToCreate = Math.min(RATE_PER_SECOND * (SCRIPT_INTERVAL / 1000.0), totalToCreate - totalCreated);
var i, properties;
for (i = 0; i < numToCreate; i++) {
properties = {
position: { x: o.x + SIZE + (x * SEPARATION), y: o.y + SIZE + (y * SEPARATION), z: o.z + SIZE + (z * SEPARATION) },
name: "gridTest",
type: 'Box',
dimensions: {x: SIZE, y: SIZE, z: SIZE},
ignoreCollisions: true,
collisionsWillMove: false,
lifetime: LIFETIME,
color: {red: x / ROWS_X * 255, green: y / ROWS_Y * 255, blue: z / ROWS_Z * 255}
};
colors.push(properties.color);
ids.push(Entities.addEntity(properties));
totalCreated++;
x++;
if (x === ROWS_X) {
x = 0;
y++;
if (y === ROWS_Y) {
y = 0;
z++;
print("Created: " + totalCreated);
}
}
if (z === ROWS_Z) {
print("Total: " + totalCreated + " entities in " + ((new Date() - startTime) / 1000.0) + " seconds.");
Script.clearTimeout(creator);
flasher = Script.setInterval(doFlash, 1000 / 60); // I.e., spin as fast as we have time for.
Script.setTimeout(stopFlash, LIFETIME * 1000);
}
}
}, SCRIPT_INTERVAL);
Script.scriptEnding.connect(function () { Script.clearTimeout(flasher); });

View file

@ -1,157 +0,0 @@
"use strict";
/*jslint vars: true, plusplus: true*/
/*global Agent, Avatar, Script, Entities, Vec3, Quat, print*/
//
// crowd-agent.js
// scripts/developer/tests/performance/
//
// Created by Howard Stearns on 9/29/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
//
// See crowd-agent.js
var version = 3;
var label = "summon";
function debug() {
print.apply(null, [].concat.apply([label, version], [].map.call(arguments, JSON.stringify)));
}
var MINIMUM_AVATARS = 25; // We will summon agents to produce this many total. (Of course, there might not be enough agents.)
var N_LISTENING = MINIMUM_AVATARS - 1;
var AVATARS_CHATTERING_AT_ONCE = 4; // How many of the agents should we request to play SOUND_DATA at once.
var initialBubble = Users.getIgnoreRadiusEnabled();
debug('startup seeking:', MINIMUM_AVATARS, 'listening:', N_LISTENING, 'chattering:', AVATARS_CHATTERING_AT_ONCE, 'had bubble:', initialBubble);
// If we add or remove things too quickly, we get problems (e.g., audio, fogbugz 2095).
// For now, spread them out this timing apart.
var SPREAD_TIME_MS = 500;
var DENSITY = 0.3; // square meters per person. Some say 10 sq ft is arm's length (0.9m^2), 4.5 is crowd (0.4m^2), 2.5 is mosh pit (0.2m^2).
var SOUND_DATA = {url: "http://hifi-content.s3.amazonaws.com/howard/sounds/piano1.wav"};
var NEXT_SOUND_SPREAD = 500; // millisecond range of how long to wait after one sound finishes, before playing the next
var ANIMATION_DATA = {
"url": "http://hifi-content.s3.amazonaws.com/howard/resources/avatar/animations/idle.fbx",
// "url": "http://hifi-content.s3.amazonaws.com/howard/resources/avatar/animations/walk_fwd.fbx", // alternative example
"startFrame": 0.0,
"endFrame": 300.0,
"timeScale": 1.0,
"loopFlag": true
};
var spread = Math.sqrt(MINIMUM_AVATARS * DENSITY); // meters
var turnSpread = 90; // How many degrees should turn from front range over.
function coord() { return (Math.random() * spread) - (spread / 2); } // randomly distribute a coordinate zero += spread/2.
function contains(array, item) { return array.indexOf(item) >= 0; }
function without(array, itemsToRemove) { return array.filter(function (item) { return !contains(itemsToRemove, item); }); }
function nextAfter(array, id) { // Wrapping next element in array after id.
var index = array.indexOf(id) + 1;
return array[(index >= array.length) ? 0 : index];
}
var summonedAgents = [];
var chattering = [];
var nListening = 0;
var accumulatedDelay = 0;
var MESSAGE_CHANNEL = "io.highfidelity.summon-crowd";
function messageSend(message) {
Messages.sendMessage(MESSAGE_CHANNEL, JSON.stringify(message));
}
function messageHandler(channel, messageString, senderID) {
if (channel !== MESSAGE_CHANNEL) {
return;
}
debug('message', channel, messageString, senderID);
if (MyAvatar.sessionUUID === senderID) { // ignore my own
return;
}
var message = {};
try {
message = JSON.parse(messageString);
} catch (e) {
}
switch (message.key) {
case "hello":
Script.setTimeout(function () {
// There can be avatars we've summoned that do not yet appear in the AvatarList.
var avatarIdentifiers = without(AvatarList.getAvatarIdentifiers(), summonedAgents);
var nSummoned = summonedAgents.length;
debug('present', avatarIdentifiers, summonedAgents);
if ((nSummoned + avatarIdentifiers.length) < MINIMUM_AVATARS ) {
var chatter = chattering.length < AVATARS_CHATTERING_AT_ONCE;
var listen = nListening < N_LISTENING;
if (chatter) {
chattering.push(senderID);
}
if (listen) {
nListening++;
}
summonedAgents.push(senderID);
messageSend({
key: 'SUMMON',
rcpt: senderID,
displayName: "crowd " + nSummoned + " " + senderID,
position: Vec3.sum(MyAvatar.position, {x: coord(), y: 0, z: coord()}),
orientation: Quat.fromPitchYawRollDegrees(0, Quat.safeEulerAngles(MyAvatar.orientation).y + (turnSpread * (Math.random() - 0.5)), 0),
soundData: chatter && SOUND_DATA,
listen: listen,
skeletonModelURL: "http://hifi-content.s3.amazonaws.com/howard/resources/meshes/defaultAvatar_full.fst",
animationData: ANIMATION_DATA
});
}
}, accumulatedDelay);
accumulatedDelay += SPREAD_TIME_MS; // assume we'll get all the hello responses more or less together.
break;
case "finishedSound": // Give someone else a chance.
chattering = without(chattering, [senderID]);
Script.setTimeout(function () {
messageSend({
key: 'SUMMON',
rcpt: nextAfter(without(summonedAgents, chattering), senderID),
soundData: SOUND_DATA
});
}, Math.random() * NEXT_SOUND_SPREAD);
break;
case "HELO":
Window.alert("Someone else is summoning avatars.");
break;
default:
print("crowd summon.js received unrecognized message");
}
}
Messages.subscribe(MESSAGE_CHANNEL);
Messages.messageReceived.connect(messageHandler);
Script.scriptEnding.connect(function () {
debug('stopping agents', summonedAgents);
Users.requestsDomainListData = false;
if (initialBubble && !Users.getIgnoreRadiusEnabled()) { Users.toggleIgnoreRadius(); }
Messages.messageReceived.disconnect(messageHandler); // don't respond to any messages during shutdown
accumulatedDelay = 0;
summonedAgents.forEach(function (id) {
messageSend({key: 'STOP', rcpt: id, delay: accumulatedDelay});
accumulatedDelay += SPREAD_TIME_MS;
});
debug('agents stopped');
Messages.unsubscribe(MESSAGE_CHANNEL);
debug('unsubscribed');
});
Users.requestsDomainListData = true; // Get avatar data for the whole domain, even if not in our view.
if (initialBubble) { Users.toggleIgnoreRadius(); }
messageSend({key: 'HELO'}); // Ask agents to report in now.
Script.setTimeout(function () {
var total = AvatarList.getAvatarIdentifiers().length;
if (0 === summonedAgents.length) {
Window.alert("No agents reported.\n\Please run " + MINIMUM_AVATARS + " instances of\n\
http://hifi-content.s3.amazonaws.com/howard/scripts/tests/performance/crowd-agent.js?v=someDate\n\
on your domain server.");
} else if (total < MINIMUM_AVATARS) {
Window.alert("Only " + summonedAgents.length + " agents reported. Now missing " + (MINIMUM_AVATARS - total) + " avatars, total.");
}
Users.requestsDomainListData = false;
}, MINIMUM_AVATARS * SPREAD_TIME_MS )

View file

@ -1,101 +0,0 @@
(function () {
// See tests/performance/tribbles.js
Script.include("../../libraries/virtualBaton.js");
var dimensions, oldColor, entityID,
editRate = 60,
moveRate = 1,
scale = 2,
accumulated = 0,
increment = {red: 1, green: 1, blue: 1},
hasUpdate = false,
shutdown = false,
baton;
function nextWavelength(color) {
var old = oldColor[color];
if (old === 255) {
increment[color] = -1;
} else if (old === 0) {
increment[color] = 1;
}
var next = (old + increment[color]) % 256;
return next;
}
function update(delta) { // High frequency stuff is done in update in case we fall behind.
accumulated += delta;
if (accumulated > (1 / editRate)) {
var newColor = {red: nextWavelength('red'), green: nextWavelength('green'), blue: nextWavelength('blue')};
oldColor = newColor;
Entities.editEntity(entityID, {color: newColor});
accumulated = 0;
}
}
function randomCentered() {
return Math.random() - 0.5;
}
function randomVector() {
return {x: randomCentered() * dimensions.x, y: randomCentered() * dimensions.y, z: randomCentered() * dimensions.z};
}
function move() {
var newData = {velocity: Vec3.sum({x: 0, y: 1, z: 0}, randomVector()), angularVelocity: Vec3.multiply(Math.PI, randomVector())};
var nextChange = Math.ceil(Math.random() * 2000 / moveRate);
Entities.editEntity(entityID, newData);
if (!shutdown) {
Script.setTimeout(move, nextChange);
}
}
function startUpdate() {
print('startUpdate', entityID);
hasUpdate = true;
Script.update.connect(update);
}
function stopUpdate() {
print('stopUpdate', entityID, hasUpdate);
if (!hasUpdate) {
return;
}
hasUpdate = false;
Script.update.disconnect(update);
}
function stopUpdateAndReclaim() {
print('stopUpdateAndReclaim', entityID);
stopUpdate();
baton.claim(startUpdate, stopUpdateAndReclaim);
}
this.preload = function (givenEntityID) {
entityID = givenEntityID;
var properties = Entities.getEntityProperties(entityID);
var userData = properties.userData && JSON.parse(properties.userData);
var moveTimeout = userData ? userData.moveTimeout : 0;
var editTimeout = userData ? userData.editTimeout : 0;
var debug = (userData && userData.debug) || {};
editRate = (userData && userData.editRate) || editRate;
moveRate = (moveRate && userData.moveRate) || moveRate;
oldColor = properties.color;
dimensions = Vec3.multiply(scale, properties.dimensions);
baton = virtualBaton({
batonName: 'io.highfidelity.tribble:' + entityID, // One winner for each entity
debugFlow: debug.flow,
debugSend: debug.send,
debugReceive: debug.receive
});
if (editTimeout) {
baton.claim(startUpdate, stopUpdateAndReclaim);
if (editTimeout > 0) {
Script.setTimeout(stopUpdate, editTimeout * 1000);
}
}
if (moveTimeout) {
Script.setTimeout(move, 1000);
if (moveTimeout > 0) {
Script.setTimeout(function () {
shutdown = true;
}, moveTimeout * 1000);
}
}
};
this.unload = function () {
baton.unload();
shutdown = true;
stopUpdate();
};
})

View file

@ -1,99 +0,0 @@
"use strict";
/*jslint nomen: true, plusplus: true, vars: true*/
var Vec3, Quat, MyAvatar, Entities, Camera, Script, print;
//
// Created by Howard Stearns
// 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
//
// Drops a bunch of physical spheres in front of you, each running a script that will:
// * Edit color at EDIT_RATE for EDIT_TIMEOUT.
// * Randomly move at an average of MOVE_RATE for MOVE_TIMEOUT.
// The _TIMEOUT parameters can be 0 for no activity, and -1 to be active indefinitely.
//
var NUMBER_TO_CREATE = 100;
var LIFETIME = 120; // seconds
var EDIT_RATE = 60; // hz
var EDIT_TIMEOUT = -1;
var MOVE_RATE = 1; // hz
var MOVE_TIMEOUT = LIFETIME / 2;
var SIZE = 0.5;
var TYPE = "Sphere";
// Note that when creating things quickly, the entity server will ignore data if we send updates too quickly.
// like Internet MTU, these rates are set by th domain operator, so in this script there is a RATE_PER_SECOND
// variable letting you set this speed. If entities are missing from the grid after a relog, this number
// being too high may be the reason.
var RATE_PER_SECOND = 600; // The entity server will drop data if we create things too fast.
var SCRIPT_INTERVAL = 100;
var GRAVITY = { x: 0, y: -9.8, z: 0 };
var VELOCITY = { x: 0.0, y: 0, z: 0 };
var ANGULAR_VELOCITY = { x: 1, y: 1, z: 1 };
var DAMPING = 0.5;
var ANGULAR_DAMPING = 0.5;
var RANGE = 3;
var HOW_FAR_IN_FRONT_OF_ME = RANGE * 3;
var HOW_FAR_UP = RANGE / 1.5; // higher (for uneven ground) above range/2 (for distribution)
var totalCreated = 0;
var offset = Vec3.sum(Vec3.multiply(HOW_FAR_UP, Vec3.UNIT_Y),
Vec3.multiply(HOW_FAR_IN_FRONT_OF_ME, Quat.getForward(Camera.orientation)));
var center = Vec3.sum(MyAvatar.position, offset);
function randomVector(range) {
return {
x: (Math.random() - 0.5) * range.x,
y: (Math.random() - 0.5) * range.y,
z: (Math.random() - 0.5) * range.z
};
}
if (!Entities.canRezTmp()) {
Window.alert("Cannot create temp objects here.");
Script.stop();
} else {
Script.setInterval(function () {
if (!Entities.serversExist()) {
return;
}
if (totalCreated >= NUMBER_TO_CREATE) {
print("Created " + totalCreated + " tribbles.");
Script.stop();
}
var i, numToCreate = RATE_PER_SECOND * (SCRIPT_INTERVAL / 1000.0);
var parameters = JSON.stringify({
moveTimeout: MOVE_TIMEOUT,
moveRate: MOVE_RATE,
editTimeout: EDIT_TIMEOUT,
editRate: EDIT_RATE,
debug: {flow: false, send: false, receive: false}
});
for (i = 0; (i < numToCreate) && (totalCreated < NUMBER_TO_CREATE); i++) {
Entities.addEntity({
userData: parameters,
type: TYPE,
name: "tribble-" + totalCreated,
position: Vec3.sum(center, randomVector({ x: RANGE, y: RANGE, z: RANGE })),
dimensions: {x: SIZE, y: SIZE, z: SIZE},
color: {red: Math.random() * 255, green: Math.random() * 255, blue: Math.random() * 255},
velocity: VELOCITY,
angularVelocity: Vec3.multiply(Math.random(), ANGULAR_VELOCITY),
damping: DAMPING,
angularDamping: ANGULAR_DAMPING,
gravity: GRAVITY,
collisionsWillMove: true,
lifetime: LIFETIME,
script: Script.resolvePath("tribbleEntity.js")
});
totalCreated++;
}
}, SCRIPT_INTERVAL);
}

View file

@ -1,10 +0,0 @@
var qml = Script.resolvePath('playaPerformanceTest.qml');
qmlWindow = new OverlayWindow({
title: 'Test Qml',
source: qml,
height: 320,
width: 640,
visible: true
});

View file

@ -1,221 +0,0 @@
import QtQuick 2.5
import QtQuick.Controls 1.4
import Qt.labs.settings 1.0
Rectangle {
id: root
width: parent ? parent.width : 100
height: parent ? parent.height : 100
signal sendToScript(var message);
property var values: [];
property alias destination: addressLine.text
readonly property string nullDestination: "169.254.0.1"
property bool running: false
function statusReport() {
console.log("PERF status connected: " + AddressManager.isConnected);
}
Timer {
id: readyStateTimer
interval: 500
repeat: true
running: false
onTriggered: {
if (!root.running) {
stop();
return;
}
if (AddressManager.isConnected) {
console.log("PERF already connected, disconnecting");
AddressManager.handleLookupString(root.nullDestination);
return;
}
stop();
console.log("PERF disconnected, moving to target " + root.destination);
AddressManager.handleLookupString(root.destination);
// If we've arrived, start running the test
console.log("PERF starting timers and frame timing");
FrameTimings.start();
rotationTimer.start();
stopTimer.start();
}
}
function startTest() {
console.log("PERF startTest()");
if (!root.running) {
root.running = true
readyStateTimer.start();
}
}
function stopTest() {
console.log("PERF stopTest()");
if (root.running) {
root.running = false;
stopTimer.stop();
rotationTimer.stop();
FrameTimings.finish();
root.values = FrameTimings.getValues();
AddressManager.handleLookupString(root.nullDestination);
resultGraph.requestPaint();
console.log("PERF Value Count: " + root.values.length);
console.log("PERF Max: " + FrameTimings.max);
console.log("PERF Min: " + FrameTimings.min);
console.log("PERF Avg: " + FrameTimings.mean);
console.log("PERF StdDev: " + FrameTimings.standardDeviation);
}
}
function yaw(a) {
var y = -Math.sin( a / 2.0 );
var w = Math.cos( a / 2.0 );
var l = Math.sqrt((y * y) + (w * w));
return Qt.quaternion(w / l, 0, y / l, 0);
}
function rotate() {
MyAvatar.setOrientationVar(yaw(Date.now() / 1000));
}
Timer {
id: stopTimer
interval: 30 * 1000
repeat: false
running: false
onTriggered: stopTest();
}
Timer {
id: rotationTimer
interval: 100
repeat: true
running: false
onTriggered: rotate();
}
Row {
id: row
anchors { left: parent.left; right: parent.right; top: parent.top; margins: 16 }
spacing: 8
Button {
text: root.running ? "Stop" : "Run"
onClicked: root.running ? stopTest() : startTest();
}
Button {
text: "Disconnect"
onClicked: AddressManager.handleLookupString(root.nullDestination);
}
Button {
text: "Connect"
onClicked: AddressManager.handleLookupString(root.destination);
}
Button {
text: "Status"
onClicked: statusReport();
}
}
TextField {
id: addressLine
anchors {
left: parent.left; right: parent.right;
top: row.bottom; margins: 16;
}
text: "Playa"
onTextChanged: console.log("PERF new target " + text);
}
Settings {
category: "Qml.Performance.RenderTest"
property alias destination: addressLine.text
}
// Rectangle {
// anchors { left: parent.left; right: parent.right; top: row.bottom; topMargin: 8; bottom: parent.bottom; }
// //anchors.fill: parent
// color: "#7fff0000"
// }
// Return the maximum value from a set of values
function vv(i, max) {
var perValue = values.length / max;
var start = Math.floor(perValue * i);
var end = Math.min(values.length, Math.floor(start + perValue));
var result = 0;
for (var j = start; j <= end; ++j) {
result = Math.max(result, values[j]);
}
return result;
}
Canvas {
id: resultGraph
anchors { left: parent.left; right: parent.right; top: addressLine.bottom; margins: 16; bottom: parent.bottom; }
property real maxValue: 200;
property real perFrame: 10000;
property real k1: (5 / maxValue) * height;
property real k2: (10 / maxValue) * height;
property real k3: (100 / maxValue) * height;
onPaint: {
var ctx = getContext("2d");
if (values.length === 0) {
ctx.fillStyle = Qt.rgba(1, 0, 0, 1);
ctx.fillRect(0, 0, width, height);
return;
}
//ctx.setTransform(1, 0, 0, -1, 0, 0);
ctx.fillStyle = Qt.rgba(0, 0, 0, 1);
ctx.fillRect(0, 0, width, height);
ctx.strokeStyle= "gray";
ctx.lineWidth="1";
ctx.beginPath();
for (var i = 0; i < width; ++i) {
var value = vv(i, width); //values[Math.min(i, values.length - 1)];
value /= 10000;
value /= maxValue;
ctx.moveTo(i, height);
ctx.lineTo(i, height - (height * value));
}
ctx.stroke();
ctx.strokeStyle= "green";
ctx.lineWidth="2";
ctx.beginPath();
var lineHeight = height - k1;
ctx.moveTo(0, lineHeight);
ctx.lineTo(width, lineHeight);
ctx.stroke();
ctx.strokeStyle= "yellow";
ctx.lineWidth="2";
ctx.beginPath();
lineHeight = height - k2;
ctx.moveTo(0, lineHeight);
ctx.lineTo(width, lineHeight);
ctx.stroke();
ctx.strokeStyle= "red";
ctx.lineWidth="2";
ctx.beginPath();
lineHeight = height - k3;
ctx.moveTo(0, lineHeight);
ctx.lineTo(width, lineHeight);
ctx.stroke();
}
}
}

View file

@ -1,24 +0,0 @@
// entityEditStressTest.js
//
// Created by Seiji Emery on 8/31/15
// Copyright 2015 High Fidelity, Inc.
//
// Stress tests the client + server-side entity trees by spawning huge numbers of entities in
// close proximity to your avatar and updating them continuously (ie. applying position edits),
// with the intent of discovering crashes and other bugs related to the entity, scripting,
// rendering, networking, and/or physics subsystems.
//
// This script was originally created to find + diagnose an a clientside crash caused by improper
// locking of the entity tree, but can be reused for other purposes.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("./entitySpawnTool.js");
ENTITY_SPAWNER({
updateInterval: 2.0
})

View file

@ -1,39 +0,0 @@
/* eslint-env jasmine */
// this test generates sample print, Script.print, etc. output
main();
function main() {
// to match with historical behavior, Script.print(message) output only triggers
// the printedMessage signal (and therefore doesn't show up in the application log)
Script.print('[Script.print] hello world');
// the rest of these should show up in both the application log and signaled print handlers
print('[print]', 'hello', 'world');
// note: these trigger the equivalent of an emit
Script.printedMessage('[Script.printedMessage] hello world', '{filename}');
Script.infoMessage('[Script.infoMessage] hello world', '{filename}');
Script.warningMessage('[Script.warningMessage] hello world', '{filename}');
Script.errorMessage('[Script.errorMessage] hello world', '{filename}');
{
Vec3.print('[Vec3.print]', Vec3.HALF);
var q = Quat.fromPitchYawRollDegrees(45, 45, 45);
Quat.print('[Quat.print]', q);
Quat.print('[Quat.print (euler)]', q, true);
function vec4(x,y,z,w) {
return { x: x, y: y, z: z, w: w };
}
var m = Mat4.createFromColumns(
vec4(1,2,3,4), vec4(5,6,7,8), vec4(9,10,11,12), vec4(13,14,15,16)
);
Mat4.print('[Mat4.print (col major)]', m);
Mat4.print('[Mat4.print (row major)]', m, true);
Uuid.print('[Uuid.print]', Uuid.fromString(Uuid.toString(0)));
}
}

View file

@ -1,307 +0,0 @@
//
// Created by Anthony J. Thibault on 2017/06/20
// Modified by Robbie Uvanni to support multiple pucks and easier placement of pucks on entities, on 2017/08/01
// 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
//
// When this script is running, a new app button, named "PUCKTACH", will be added to the toolbar/tablet.
// Click this app to bring up the puck attachment panel.
//
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
/* global Xform */
Script.include("/~/system/libraries/Xform.js");
(function() { // BEGIN LOCAL_SCOPE
var TABLET_BUTTON_NAME = "PUCKTACH";
var TABLET_APP_URL = "https://hifi-content.s3.amazonaws.com/seefo/production/puck-attach/puck-attach.html";
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var tabletButton = tablet.addButton({
text: TABLET_BUTTON_NAME,
icon: "https://s3.amazonaws.com/hifi-public/tony/icons/puck-i.svg",
activeIcon: "https://s3.amazonaws.com/hifi-public/tony/icons/puck-a.svg"
});
var shown = false;
function onScreenChanged(type, url) {
if (type === "Web" && url === TABLET_APP_URL) {
tabletButton.editProperties({isActive: true});
if (!shown) {
// hook up to event bridge
tablet.webEventReceived.connect(onWebEventReceived);
}
shown = true;
} else {
tabletButton.editProperties({isActive: false});
if (shown) {
// disconnect from event bridge
tablet.webEventReceived.disconnect(onWebEventReceived);
}
shown = false;
}
}
tablet.screenChanged.connect(onScreenChanged);
function pad(num, size) {
var tempString = "000000000" + num;
return tempString.substr(tempString.length - size);
}
function indexToTrackedObjectName(index) {
return "TrackedObject" + pad(index, 2);
}
function getAvailableTrackedObjects() {
var available = [];
var NUM_TRACKED_OBJECTS = 16;
var i;
for (i = 0; i < NUM_TRACKED_OBJECTS; i++) {
var key = indexToTrackedObjectName(i);
var pose = Controller.getPoseValue(Controller.Standard[key]);
if (pose && pose.valid) {
available.push(i);
}
}
return available;
}
function sendAvailableTrackedObjects() {
tablet.emitScriptEvent(JSON.stringify({
pucks: getAvailableTrackedObjects(),
selectedPuck: ((lastPuck === undefined) ? -1 : lastPuck.name)
}));
}
function getRelativePosition(origin, rotation, offset) {
var relativeOffset = Vec3.multiplyQbyV(rotation, offset);
var worldPosition = Vec3.sum(origin, relativeOffset);
return worldPosition;
}
function getPropertyForEntity(entityID, propertyName) {
return Entities.getEntityProperties(entityID, [propertyName])[propertyName];
}
function entityExists(entityID) {
return Object.keys(Entities.getEntityProperties(entityID)).length > 0;
}
var VIVE_PUCK_MODEL = "https://s3.amazonaws.com/hifi-public/tony/vive_tracker_puck_y180z180.obj";
var VIVE_PUCK_DIMENSIONS = { x: 0.0945, y: 0.0921, z: 0.0423 }; // 1/1000th scale of model
var VIVE_PUCK_SEARCH_DISTANCE = 1.5; // metres
var VIVE_PUCK_SPAWN_DISTANCE = 0.5; // metres
var VIVE_PUCK_TRACKED_OBJECT_MAX_DISTANCE = 10.0; // metres
var VIVE_PUCK_NAME = "Tracked Puck";
var trackedPucks = { };
var lastPuck;
function createPuck(puck) {
// create a puck entity and add it to our list of pucks
var action = indexToTrackedObjectName(puck.puckno);
var pose = Controller.getPoseValue(Controller.Standard[action]);
if (pose && pose.valid) {
var spawnOffset = Vec3.multiply(Vec3.FRONT, VIVE_PUCK_SPAWN_DISTANCE);
var spawnPosition = getRelativePosition(MyAvatar.position, MyAvatar.orientation, spawnOffset);
// should be an overlay
var puckEntityProperties = {
name: "Tracked Puck",
type: "Model",
modelURL: VIVE_PUCK_MODEL,
dimensions: VIVE_PUCK_DIMENSIONS,
position: spawnPosition,
userData: '{ "grabbableKey": { "grabbable": true, "kinematic": false } }'
};
var puckEntityID = Entities.addEntity(puckEntityProperties);
// if we've already created this puck, destroy it
if (trackedPucks.hasOwnProperty(puck.puckno)) {
destroyPuck(puck.puckno);
}
// if we had an unfinalized puck, destroy it
if (lastPuck !== undefined) {
destroyPuck(lastPuck.name);
}
// create our new unfinalized puck
trackedPucks[puck.puckno] = {
puckEntityID: puckEntityID,
trackedEntityID: ""
};
lastPuck = trackedPucks[puck.puckno];
lastPuck.name = Number(puck.puckno);
}
}
function finalizePuck(puckName) {
// find nearest entity and change its parent to the puck
if (!trackedPucks.hasOwnProperty(puckName)) {
print('2');
return;
}
if (lastPuck === undefined) {
print('3');
return;
}
if (lastPuck.name !== Number(puckName)) {
print('1');
return;
}
var puckPosition = getPropertyForEntity(lastPuck.puckEntityID, "position");
var foundEntities = Entities.findEntities(puckPosition, VIVE_PUCK_SEARCH_DISTANCE);
var foundEntity;
var leastDistance = Number.MAX_VALUE;
for (var i = 0; i < foundEntities.length; i++) {
var entity = foundEntities[i];
if (getPropertyForEntity(entity, "name") !== VIVE_PUCK_NAME) {
var entityPosition = getPropertyForEntity(entity, "position");
var d = Vec3.distance(entityPosition, puckPosition);
if (d < leastDistance) {
leastDistance = d;
foundEntity = entity;
}
}
}
if (foundEntity) {
lastPuck.trackedEntityID = foundEntity;
// remember the userdata and collisionless flag for the tracked entity since
// we're about to remove it and make it ungrabbable and collisionless
lastPuck.trackedEntityUserData = getPropertyForEntity(foundEntity, "userData");
lastPuck.trackedEntityCollisionFlag = getPropertyForEntity(foundEntity, "collisionless");
// update properties of the tracked entity
Entities.editEntity(lastPuck.trackedEntityID, {
"parentID": lastPuck.puckEntityID,
"userData": '{ "grabbableKey": { "grabbable": false } }',
"collisionless": 1
});
// remove reference to puck since it is now calibrated and finalized
lastPuck = undefined;
}
}
function updatePucks() {
// for each puck, update its position and orientation
for (var puckName in trackedPucks) {
if (!trackedPucks.hasOwnProperty(puckName)) {
continue;
}
var action = indexToTrackedObjectName(puckName);
var pose = Controller.getPoseValue(Controller.Standard[action]);
if (pose && pose.valid) {
var puck = trackedPucks[puckName];
if (puck.trackedEntityID) {
if (entityExists(puck.trackedEntityID)) {
var avatarXform = new Xform(MyAvatar.orientation, MyAvatar.position);
var puckXform = new Xform(pose.rotation, pose.translation);
var finalXform = Xform.mul(avatarXform, puckXform);
var d = Vec3.distance(MyAvatar.position, finalXform.pos);
if (d > VIVE_PUCK_TRACKED_OBJECT_MAX_DISTANCE) {
print('tried to move tracked object too far away: ' + d);
return;
}
Entities.editEntity(puck.puckEntityID, {
position: finalXform.pos,
rotation: finalXform.rot
});
// in case someone grabbed both entities and destroyed the
// child/parent relationship
Entities.editEntity(puck.trackedEntityID, {
parentID: puck.puckEntityID
});
} else {
destroyPuck(puckName);
}
}
}
}
}
function destroyPuck(puckName) {
// unparent entity and delete its parent
if (!trackedPucks.hasOwnProperty(puckName)) {
return;
}
var puck = trackedPucks[puckName];
var puckEntityID = puck.puckEntityID;
var trackedEntityID = puck.trackedEntityID;
// remove the puck as a parent entity and restore the tracked entities
// former userdata and collision flag
Entities.editEntity(trackedEntityID, {
"parentID": "{00000000-0000-0000-0000-000000000000}",
"userData": puck.trackedEntityUserData,
"collisionless": puck.trackedEntityCollisionFlag
});
delete trackedPucks[puckName];
// in some cases, the entity deletion may occur before the parent change
// has been processed, resulting in both the puck and the tracked entity
// to be deleted so we wait 100ms before deleting the puck, assuming
// that the parent change has occured
Script.setTimeout(function() {
// delete the puck
Entities.deleteEntity(puckEntityID);
}, 100);
}
function destroyPucks() {
// remove all pucks and unparent entities
for (var puckName in trackedPucks) {
if (trackedPucks.hasOwnProperty(puckName)) {
destroyPuck(puckName);
}
}
}
function onWebEventReceived(msg) {
var obj = {};
try {
obj = JSON.parse(msg);
} catch (err) {
return;
}
switch (obj.cmd) {
case "ready":
sendAvailableTrackedObjects();
break;
case "create":
createPuck(obj);
break;
case "finalize":
finalizePuck(obj.puckno);
break;
case "destroy":
destroyPuck(obj.puckno);
break;
}
}
Script.update.connect(updatePucks);
Script.scriptEnding.connect(function () {
tablet.removeButton(tabletButton);
destroyPucks();
if (shown) {
tablet.webEventReceived.disconnect(onWebEventReceived);
tablet.gotoHomeScreen();
}
tablet.screenChanged.disconnect(onScreenChanged);
});
tabletButton.clicked.connect(function () {
if (shown) {
tablet.gotoHomeScreen();
} else {
tablet.gotoWebScreen(TABLET_APP_URL);
}
});
}()); // END LOCAL_SCOPE

View file

@ -1,12 +0,0 @@
print("Launching web window");
qmlWindow = new OverlayWindow({
title: 'Test Qml',
source: "qrc:///qml/OverlayWindowTest.qml",
height: 240,
width: 320,
visible: true
});
Script.setInterval(function() {
qmlWindow.raise();
}, 2 * 1000);

View file

@ -1,91 +0,0 @@
// rapidProceduralChangeTest.js
// examples/tests/rapidProceduralChange
//
// Created by Eric Levin on 3/9/2016.
// Copyright 2016 High Fidelity, Inc.
//
// This test creates primitives with fragment shaders and rapidly updates its uniforms, as well as a skybox.
// For the test to pass:
// - The primitives (cube and sphere) should update at rate of update loop, cycling through red values.
// - The skymap should do the same, although its periodicity may be different.
//
// Under the hood, the primitives are driven by a uniform, while the skymap is driven by a timer.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var orientation = Camera.getOrientation();
orientation = Quat.safeEulerAngles(orientation);
orientation.x = 0;
orientation = Quat.fromVec3Degrees(orientation);
var centerUp = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getForward(orientation)));
centerUp.y += 0.5;
var centerDown = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getForward(orientation)));
centerDown.y -= 0.5;
var ENTITY_SHADER_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/shaders/uniformTest.fs";
var SKYBOX_SHADER_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/shaders/timerTest.fs";
var entityData = {
ProceduralEntity: {
shaderUrl: ENTITY_SHADER_URL,
uniforms: { red: 0.0 }
}
};
var skyboxData = {
ProceduralEntity: {
shaderUrl: SKYBOX_SHADER_URL,
uniforms: { red: 0.0 }
}
};
var testBox = Entities.addEntity({
type: "Box",
dimensions: { x: 0.5, y: 0.5, z: 0.5 },
position: centerUp,
userData: JSON.stringify(entityData)
});
var testSphere = Entities.addEntity({
type: "Sphere",
dimensions: { x: 0.5, y: 0.5, z: 0.5 },
position: centerDown,
userData: JSON.stringify(entityData)
});
var testZone = Entities.addEntity({
type: "Zone",
dimensions: { x: 50, y: 50, z: 50 },
position: MyAvatar.position,
userData: JSON.stringify(skyboxData),
backgroundMode: "skybox",
skybox: { url: "http://kyoub.googlecode.com/svn/trunk/KYouB/textures/skybox_test.png" }
});
var currentTime = 0;
function update(deltaTime) {
var red = (Math.sin(currentTime) + 1) / 2;
entityData.ProceduralEntity.uniforms.red = red;
skyboxData.ProceduralEntity.uniforms.red = red;
entityEdit = { userData: JSON.stringify(entityData) };
skyboxEdit = { userData: JSON.stringify(skyboxData) };
Entities.editEntity(testBox, entityEdit);
Entities.editEntity(testSphere, entityEdit);
Entities.editEntity(testZone, skyboxEdit);
currentTime += deltaTime;
}
Script.update.connect(update);
Script.scriptEnding.connect(cleanup);
function cleanup() {
Entities.deleteEntity(testBox);
Entities.deleteEntity(testSphere);
Entities.deleteEntity(testZone);
}

View file

@ -1,21 +0,0 @@
//
// timerTest.fs
// examples/tests/rapidProceduralChange
//
// Created by Eric Levin on 3/9/16.
// Copyright 2016 High Fidelity, Inc.
//
// This fragment shader is designed to test the rapid changing of a uniform on the timer.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
uniform float red;
vec3 getSkyboxColor() {
float blue = red;
blue = (cos(iGlobalTime) + 1) / 2;
return vec3(1.0, 0.0, blue);
}

View file

@ -1,27 +0,0 @@
//
// uniformTest.fs
// examples/tests/rapidProceduralChange
//
// Created by Eric Levin on 3/9/16.
// Copyright 2016 High Fidelity, Inc.
//
// This fragment shader is designed to test the rapid changing of a uniform.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
uniform float red;
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
fragColor = vec4(red, 0.0, 1.0, 1.0);
}
vec4 getProceduralColor() {
vec4 result;
vec2 position = _position.xz;
position += 0.5;
mainImage(result, position * iWorldScale.xz);
return result;
}

View file

@ -1,73 +0,0 @@
// raypickTester.js
//
// display intersection details (including material) when hovering over entities/avatars/overlays
//
/* eslint-disable comma-dangle, no-empty, no-magic-numbers */
var PICK_FILTERS = Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS | Picks.PICK_AVATARS | Picks.PICK_INCLUDE_NONCOLLIDABLE;
var HAND_JOINT = '_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND'.replace('RIGHT', MyAvatar.getDominantHand().toUpperCase());
var JOINT_NAME = HMD.active ? HAND_JOINT : 'Mouse';
var UPDATE_MS = 1000/30;
// create tect3d overlay to display hover results
var overlayID = Overlays.addOverlay('text3d', {
text: 'hover',
visible: false,
backgroundAlpha: 0,
isFacingAvatar: true,
lineHeight: 0.05,
dimensions: Vec3.HALF,
});
Script.scriptEnding.connect(function() {
Overlays.deleteOverlay(overlayID);
});
// create raycast picker
var pickID = Picks.createPick(PickType.Ray, {
joint: JOINT_NAME,
filter: PICK_FILTERS,
enabled: true,
});
var blacklist = [ overlayID ]; // exclude hover text from ray pick results
Picks.setIgnoreItems(pickID, blacklist);
Script.scriptEnding.connect(function() {
Picks.removePick(pickID);
});
// query object materials (using the Graphics.* API)
function getSubmeshMaterial(objectID, shapeID) {
try {
var materialLayers = Graphics.getModel(objectID).materialLayers;
var shapeMaterialLayers = materialLayers[shapeID];
return shapeMaterialLayers[0].material;
} catch (e) {
return { name: '<unknown>' };
}
}
// refresh hover overlay text based on intersection results
function updateOverlay(overlayID, result) {
var material = this.getSubmeshMaterial(result.objectID, result.extraInfo.shapeID);
var position = Vec3.mix(result.searchRay.origin, result.intersection, 0.5);
var extraInfo = result.extraInfo;
var text = [
'mesh: ' + extraInfo.subMeshName,
'materialName: ' + material.name,
'type: ' + Entities.getNestableType(result.objectID),
'distance: ' + result.distance.toFixed(2)+'m',
['submesh: ' + extraInfo.subMeshIndex, 'part: '+extraInfo.partIndex, 'shape: '+extraInfo.shapeID].join(' | '),
].filter(Boolean).join('\n');
Overlays.editOverlay(overlayID, {
text: text,
position: position,
visible: result.intersects,
});
}
// monitor for enw results at 30fps
Script.setInterval(function() {
var result = Picks.getPrevPickResult(pickID);
updateOverlay(overlayID, result);
}, UPDATE_MS);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -1,98 +0,0 @@
//
// lib.js
// scripts/developer/tests/scriptableResource
//
// Created by Zach Pomerantz on 4/20/16.
// Copyright 2016 High Fidelity, Inc.
//
// Preloads textures to play a simple movie, plays it, and frees those textures.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var NUM_FRAMES = 158; // 158 available
var FRAME_RATE = 30; // 30 default
function getFrame(callback) {
// A model exported from blender with a texture named 'Picture' on one face.
var FRAME_URL = "http://hifi-production.s3.amazonaws.com/tutorials/pictureFrame/finalFrame.fbx";
var model = ModelCache.prefetch(FRAME_URL);
if (model.state === Resource.State.FINISHED) {
makeFrame(Resource.State.FINISHED);
} else {
model.stateChanged.connect(makeFrame);
}
function makeFrame(state) {
if (state === Resource.State.FAILED) { throw "Failed to load frame"; }
if (state !== Resource.State.FINISHED) { return; }
var pictureFrameProperties = {
name: 'scriptableResourceTest Picture Frame',
type: 'Model',
position: getPosition(),
modelURL: FRAME_URL,
dynamic: true,
};
callback(Entities.addEntity(pictureFrameProperties));
}
function getPosition() {
// Always put it 5 meters in front of you
var position = MyAvatar.position;
var yaw = MyAvatar.bodyYaw + MyAvatar.getHeadFinalYaw();
var rads = (yaw / 180) * Math.PI;
position.y += 0.5;
position.x += - 5 * Math.sin(rads);
position.z += - 5 * Math.cos(rads);
return position;
}
}
function prefetch(callback) {
// A folder full of individual frames.
var MOVIE_URL = "http://hifi-content.s3.amazonaws.com/james/vidtest/";
var frames = [];
var numLoading = 0;
for (var i = 1; i <= NUM_FRAMES; ++i) {
var padded = pad(i, 3);
var filepath = MOVIE_URL + padded + '.jpg';
var texture = TextureCache.prefetch(filepath);
frames.push(texture);
if (texture.state !== Resource.State.FINISHED) {
numLoading++;
texture.stateChanged.connect(function(state) {
if (state === Resource.State.FAILED || state === Resource.State.FINISHED) {
--numLoading;
if (!numLoading) { callback(frames); }
}
});
}
}
if (!numLoading) { callback(frames); }
function pad(num, size) { // left-pad num with zeros until it is size digits
var s = num.toString();
while (s.length < size) { s = "0" + s; }
return s;
}
}
function play(model, frames, callback) {
var frame = 0;
var movieInterval = Script.setInterval(function() {
Entities.editEntity(model, { textures: JSON.stringify({ Picture: frames[frame].url }) });
if (++frame >= frames.length) {
Script.clearInterval(movieInterval);
callback();
}
}, 1000 / FRAME_RATE);
}

View file

@ -1,34 +0,0 @@
//
// loadPerfTest.js
// scripts/developer/tests/scriptableResource
//
// Created by Zach Pomerantz on 4/27/16.
// Copyright 2016 High Fidelity, Inc.
//
// Preloads 158 textures 50 times for performance profiling.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var TIMES = 50;
Script.include([
'../../../developer/utilities/cache/cacheStats.js',
'lib.js',
], function() {
var fetch = function() {
prefetch(function(frames) {
while (frames.length) { frames.pop(); }
Script.requestGarbageCollection();
if (--TIMES > 0) {
// Pause a bit to avoid a deadlock
var DEADLOCK_AVOIDANCE_TIMEOUT = 100;
Script.setTimeout(fetch, DEADLOCK_AVOIDANCE_TIMEOUT);
}
});
};
fetch();
});

View file

@ -1,42 +0,0 @@
//
// movieTest.js
// scripts/developer/tests/scriptableResource
//
// Created by Zach Pomerantz on 4/27/16.
// Copyright 2016 High Fidelity, Inc.
//
// Preloads textures, plays them on a frame model, and unloads them.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var entity;
Script.include([
'../../../developer/utilities/cache/cacheStats.js',
'lib.js',
], function() {
getFrame(function(frame) {
entity = frame;
prefetch(function(frames) {
play(frame, frames, function() {
// Delete each texture, so the next garbage collection cycle will release them.
// Setting frames = null breaks the reference,
// but will not delete frames from the calling scope.
// Instead, we must mutate it in-place to free its elements for GC
// (assuming the elements are not held elsewhere).
while (frames.length) { frames.pop(); }
// Alternatively, forcibly release each texture without relying on GC.
// frames.forEach(function(texture) { texture.release(); });
Entities.deleteEntity(entity);
Script.requestGarbageCollection();
});
});
});
});
Script.scriptEnding.connect(function() { entity && Entities.deleteEntity(entity); });

View file

@ -1,33 +0,0 @@
//
// prefetchTest.js
// scripts/developer/tests/scriptableResource
//
// Created by Zach Pomerantz on 4/27/16.
// Copyright 2016 High Fidelity, Inc.
//
// Preloads textures and unloads them.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include([
'../../../developer/utilities/cache/cacheStats.js',
'lib.js',
], function() {
prefetch(function(frames) {
// Delete each texture, so the next garbage collection cycle will release them.
// Setting frames = null breaks the reference,
// but will not delete frames from the calling scope.
// Instead, we must mutate it in-place to free its elements for GC
// (assuming the elements are not held elsewhere).
while (frames.length) { frames.pop(); }
// Alternatively, forcibly release each texture without relying on GC.
// frames.forEach(function(texture) { texture.release(); });
Script.requestGarbageCollection();
});
});

View file

@ -1,18 +0,0 @@
//
// px.fs
// examples/tests/skybox
//
// Created by Zach Pomerantz on 3/10/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
vec3 getSkyboxColor() {
float red = (cos(iGlobalTime) + 1) / 2;
vec3 color = vec3(red, 1.0, 1.0);
return color;
}

View file

@ -1,20 +0,0 @@
//
// px_rgba.fs
// examples/tests/skybox
//
// Created by Zach Pomerantz on 3/10/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
vec3 getSkyboxColor() {
float red = (cos(iGlobalTime) + 1) / 2;
vec3 color = vec3(red, 1.0, 1.0);
color *= skybox.color.rgb;
return color;
}

View file

@ -1,22 +0,0 @@
//
// px_rgba.fs
// examples/tests/skybox
//
// Created by Zach Pomerantz on 3/10/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
vec3 getSkyboxColor() {
float red = (cos(iGlobalTime) + 1) / 2;
vec3 color = vec3(red, 1.0, 1.0);
vec3 coord = normalize(_normal);
vec3 texel = texture(cubeMap, coord).rgb;
color *= texel;
return color;
}

View file

@ -1,24 +0,0 @@
//
// px_rgba.fs
// examples/tests/skybox
//
// Created by Zach Pomerantz on 3/10/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
vec3 getSkyboxColor() {
float red = (cos(iGlobalTime) + 1) / 2;
vec3 color = vec3(red, 1.0, 1.0);
vec3 coord = normalize(_normal);
vec3 texel = texture(cubeMap, coord).rgb;
color *= texel;
color *= skybox.color.rgb;
return color;
}

View file

@ -1,83 +0,0 @@
// skyboxTest.js
// examples/tests/skybox
//
// Created by Zach Pomerantz on 3/10/2016.
// Copyright 2016 High Fidelity, Inc.
//
// This test cycles through different variations on the skybox with a mouseclick.
// For the test to pass, you should observe the following cycle:
// - Procedural skybox (no texture, no color)
// - Procedural skybox (no texture, with color)
// - Procedural skybox (with texture, no color)
// - Procedural skybox (with texture, with color)
// - Color skybox (no texture)
// - Color skybox (with texture)
// - Texture skybox (no color)
//
// As you run the test, descriptions of the expected rendered skybox will appear as overlays.
//
// NOTE: This does not test uniforms/textures applied to a procedural shader through userData.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var PX_URL = Script.resolvePath('px.fs');
var PX_RGBA_URL = Script.resolvePath('px_rgba.fs');
var PX_TEX_URL = Script.resolvePath('px_tex.fs');
var PX_TEX_RGBA_URL = Script.resolvePath('px_tex_rgba.fs');
var TEX_URL = 'https://hifi-public.s3.amazonaws.com/alan/Playa/Skies/Test-Sky_out.png';
var NO_TEX = '';
var COLOR = { red: 255, green: 0, blue: 255 };
var NO_COLOR = { red: 0, green: 0, blue: 0 };
var data = { ProceduralEntity: { shaderUrl: PX_URL } };
var zone = Entities.addEntity({
type: 'Zone',
dimensions: { x: 50, y: 50, z: 50 },
position: MyAvatar.position,
backgroundMode: 'skybox'
});
var text = Overlays.addOverlay('text', {
text: 'Click this box to advance tests; note that red value cycling means white->light blue',
x: Window.innerWidth / 2 - 250, y: Window.innerHeight / 2 - 25,
width: 500, height: 50
});
print('Zone:', zone);
print('Text:', text);
var edits = [
['Red value should cycle', getEdit(PX_URL, NO_TEX, NO_COLOR)],
['Red value should cycle, no green', getEdit(PX_RGBA_URL, NO_TEX, COLOR)],
['Red value should cycle, each face tinted differently', getEdit(PX_TEX_URL, TEX_URL, NO_COLOR)],
['Red value should cycle, each face tinted differently, no green', getEdit(PX_TEX_RGBA_URL, TEX_URL, COLOR)],
['No green', getEdit(null, NO_TEX, COLOR)],
['Each face colored differently, no green', getEdit(null, TEX_URL, COLOR)],
['Each face colored differently', getEdit(null, TEX_URL, NO_COLOR)],
];
Controller.mousePressEvent.connect(function(e) { if (Overlays.getOverlayAtPoint(e) === text) next(); });
Script.scriptEnding.connect(function() {
Overlays.deleteOverlay(text);
Entities.deleteEntity(zone);
});
var i = 0;
function next() {
var edit = edits[i];
Overlays.editOverlay(text, { text: edit[0] });
Entities.editEntity(zone, edit[1]);
i++;
i %= edits.length;
}
function getEdit(px, url, color) {
return { userData: px ? getUserData(px) : '', backgroundMode: 'skybox', skybox: { url: url, color: color } }
}
function getUserData(px) { return JSON.stringify({ ProceduralEntity: { shaderUrl: px } }); }

View file

@ -1,157 +0,0 @@
<!--
// quick_start_template.html
//
// Created by Faye Li on 3 Feb 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
-->
<html>
<head>
<title>Slider Test</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css?family=Raleway:300,400,600,700"" rel="stylesheet">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/9.7.2/css/bootstrap-slider.min.css">
<!-- <link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css" /> -->
<style>
body {
margin: 0;
width: 100%;
font-family: 'Raleway', sans-serif;
color: white;
background: linear-gradient(#2b2b2b, #0f212e);
}
.top-bar {
height: 90px;
background: linear-gradient(#2b2b2b, #1e1e1e);
font-weight: bold;
padding-left: 30px;
padding-right: 30px;
display: flex;
align-items: center;
position: fixed;
width: 480px;
top: 0;
z-index: 1;
}
.content {
margin-top: 90px;
padding: 30px;
}
input[type=button] {
font-family: 'Raleway';
font-weight: bold;
font-size: 13px;
text-transform: uppercase;
vertical-align: top;
height: 28px;
min-width: 120px;
padding: 0px 18px;
margin-right: 6px;
border-radius: 5px;
border: none;
color: #fff;
background-color: #000;
background: linear-gradient(#343434 20%, #000 100%);
cursor: pointer;
}
input[type=button].red {
color: #fff;
background-color: #94132e;
background: linear-gradient(#d42043 20%, #94132e 100%);
}
input[type=button].blue {
color: #fff;
background-color: #1080b8;
background: linear-gradient(#00b4ef 20%, #1080b8 100%);
}
input[type=button].white {
color: #121212;
background-color: #afafaf;
background: linear-gradient(#fff 20%, #afafaf 100%);
}
input[type=button]:enabled:hover {
background: linear-gradient(#000, #000);
border: none;
}
input[type=button].red:enabled:hover {
background: linear-gradient(#d42043, #d42043);
border: none;
}
input[type=button].blue:enabled:hover {
background: linear-gradient(#00b4ef, #00b4ef);
border: none;
}
input[type=button].white:enabled:hover {
background: linear-gradient(#fff, #fff);
border: none;
}
input[type=button]:active {
background: linear-gradient(#343434, #343434);
}
input[type=button].red:active {
background: linear-gradient(#94132e, #94132e);
}
input[type=button].blue:active {
background: linear-gradient(#1080b8, #1080b8);
}
input[type=button].white:active {
background: linear-gradient(#afafaf, #afafaf);
}
input[type=button]:disabled {
color: #252525;
background: linear-gradient(#575757 20%, #252525 100%);
}
input[type=button][pressed=pressed] {
color: #00b4ef;
}
</style>
</head>
<body>
<div class="top-bar">
<h4>Slider Test</h4>
</div>
<div class="content">
<p>Native Input Range Slider</p>
<p>
<input type="range" name="native-slider" id="native-slider" value="60" min="0" max="100">
</p>
<p>Bootstrap Slider</p>
<p>
<input
id="bootstrap-slider"
type="text"
data-provide="slider"
data-slider-min="0"
data-slider-max="100"
data-slider-step="1"
data-slider-value="60"
data-slider-tooltip="hide"
>
</p>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/9.7.2/bootstrap-slider.min.js"></script>
<script>
function main() {
console.log("ready");
}
$(document).ready(main);
</script>
</body>
</html>

View file

@ -1,35 +0,0 @@
(function () {
var HTML_URL = Script.resolvePath("sliderTest.html");
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var button = tablet.addButton({
text: "SLIDER"
});
function onClicked() {
tablet.gotoWebScreen(HTML_URL);
}
button.clicked.connect(onClicked);
var onSliderTestScreen = false;
function onScreenChanged(type, url) {
if (type === "Web" && url === HTML_URL) {
// when switching to the slider page, change inputMode to "Mouse", this should make the sliders work.
onSliderTestScreen = true;
Overlays.editOverlay(HMD.tabletScreenID, { inputMode: "Mouse" });
} else if (onSliderTestScreen) {
// when switching off of the slider page, change inputMode to back to "Touch".
onSliderTestScreen = false;
Overlays.editOverlay(HMD.tabletScreenID, { inputMode: "Touch" });
}
}
tablet.screenChanged.connect(onScreenChanged);
function cleanup() {
tablet.removeButton(button);
tablet.screenChanged.disconnect(onScreenChanged);
}
Script.scriptEnding.connect(cleanup);
}());

View file

@ -1,66 +0,0 @@
//
// sphereLodTest.js
// examples/tests
//
// Created by Eric Levin on 1/21/16.
// Copyright 2016 High Fidelity, Inc.
// A test script for testing LODing of sphere entities and sphere overlays
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
MyAvatar.orientation = Quat.fromPitchYawRollDegrees(0, 0, 0);
orientation = Quat.safeEulerAngles(MyAvatar.orientation);
orientation.x = 0;
orientation = Quat.fromVec3Degrees(orientation);
var tablePosition = Vec3.sum(MyAvatar.position, Quat.getForward(orientation));
tablePosition.y += 0.5;
var tableDimensions = {
x: 1,
y: 0.2,
z: 1
};
var table = Entities.addEntity({
type: "Box",
position: tablePosition,
dimensions: tableDimensions,
color: {
red: 70,
green: 21,
blue: 21
}
});
var sphereDimensions = {x: 0.01, y: 0.01, z: 0.01};
var entitySpherePosition = Vec3.sum(tablePosition, {x: 0, y: tableDimensions.y/2 + sphereDimensions.y/2, z: 0});
var entitySphere = Entities.addEntity({
type: "Sphere",
position: entitySpherePosition,
color: {red: 200, green: 20, blue: 200},
dimensions: sphereDimensions
});
var overlaySpherePosition = Vec3.sum(tablePosition, {x: sphereDimensions.x, y: tableDimensions.y/2 + sphereDimensions.y/2, z: 0});
var overlaySphere = Overlays.addOverlay("sphere", {
position: overlaySpherePosition,
size: 0.01,
color: { red: 20, green: 200, blue: 0},
alpha: 1.0,
solid: true,
});
function cleanup() {
Entities.deleteEntity(table);
Entities.deleteEntity(entitySphere);
Overlays.deleteOverlay(overlaySphere);
}
Script.scriptEnding.connect(cleanup);

View file

@ -1,107 +0,0 @@
//
// tabletEventBridgeTest.js
//
// Created by Anthony J. Thibault on 2016-12-15
// 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
//
// Adds a button to the tablet that will switch to a web page.
// This web page contains buttons that will use the event bridge to trigger sounds.
/* globals Tablet */
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var tabletButton = tablet.addButton({
text: "SOUNDS",
icon: "http://s3.amazonaws.com/hifi-public/tony/icons/trombone-i.png",
activeIcon: "http://s3.amazonaws.com/hifi-public/tony/icons/trombone-a.png"
});
var WEB_BRIDGE_TEST_HTML = "https://s3.amazonaws.com/hifi-public/tony/webBridgeTest.html?2";
var TROMBONE_URL = "https://s3.amazonaws.com/hifi-public/tony/audio/sad-trombone.wav";
var SCREAM_URL = "https://s3.amazonaws.com/hifi-public/tony/audio/wilhelm-scream.wav";
tabletButton.clicked.connect(function () {
if (shown) {
tablet.gotoHomeScreen();
} else {
tablet.gotoWebScreen(WEB_BRIDGE_TEST_HTML);
}
});
var shown = false;
function onScreenChanged(type, url) {
if (type === "Web" && url === WEB_BRIDGE_TEST_HTML) {
tabletButton.editProperties({isActive: true});
if (!shown) {
// hook up to the event bridge
tablet.webEventReceived.connect(onWebEventReceived);
}
shown = true;
} else {
tabletButton.editProperties({isActive: false});
if (shown) {
// disconnect from the event bridge
tablet.webEventReceived.disconnect(onWebEventReceived);
}
shown = false;
}
}
tablet.screenChanged.connect(onScreenChanged);
// ctor
function SoundBuddy(url) {
this.sound = SoundCache.getSound(url);
this.injector = null;
}
SoundBuddy.prototype.play = function (options, doneCallback) {
if (this.sound.downloaded) {
if (this.injector) {
this.injector.setOptions(options);
this.injector.restart();
} else {
this.injector = Audio.playSound(this.sound, options);
this.injector.finished.connect(function () {
if (doneCallback) {
doneCallback();
}
});
}
}
};
var tromboneSound = new SoundBuddy(TROMBONE_URL);
var screamSound = new SoundBuddy(SCREAM_URL);
var soundOptions = { position: MyAvatar.position, volume: 1.0, loop: false, localOnly: true };
function onWebEventReceived(msg) {
Script.print("HIFI: recv web event = " + JSON.stringify(msg));
if (msg === "button-1-play") {
soundOptions.position = MyAvatar.position;
tromboneSound.play(soundOptions, function () {
tablet.emitScriptEvent("button-1-done");
});
} else if (msg === "button-2-play") {
soundOptions.position = MyAvatar.position;
screamSound.play(soundOptions, function () {
tablet.emitScriptEvent("button-2-done");
});
}
}
Script.scriptEnding.connect(function () {
tablet.removeButton(tabletButton);
if (shown) {
tablet.webEventReceived.disconnect(onWebEventReceived);
}
});

View file

@ -1,45 +0,0 @@
//
// tabletTest.js
//
// Created by Anthony J. Thibault on 2016-12-15
// 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
//
// Adds a BAM! button to the tablet ui.
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var button = tablet.addButton({
text: "BAM!!!"
});
var TEST_BUTTON_COUNT = 10;
for (var i = 0; i < TEST_BUTTON_COUNT; i++) {
tablet.addButton({
text: "TEST_" + i,
inDebugMode: true
});
}
// change the name and isActive state every second...
var names = ["BAM!", "BAM!!", "BAM!!!", "BAM!!!!"];
var nameIndex = 0;
Script.setInterval(function () {
nameIndex = (nameIndex + 1) % names.length;
button.editProperties({
isActive: (nameIndex & 0x1) == 0,
text: names[nameIndex]
});
}, 1000);
button.clicked.connect(function () {
print("AJT: BAM!!! CLICK from JS!");
var url = "https://news.ycombinator.com/";
tablet.gotoWebScreen(url);
});
Script.scriptEnding.connect(function () {
tablet.removeButton(button);
});

View file

@ -1,244 +0,0 @@
// Tester, try testing these different settings.
//
// Changing the TIMER_HZ will show different performance results. It's expected that at 90hz you'll see a fair
// amount of variance, as Qt Timers simply aren't accurate enough. In general RPC peformance should match the timer
// without significant difference in variance.
var TIMER_HZ = 50; // Change this for different values
var TIMER_INTERVAL = 1000 / TIMER_HZ;
var TIMER_WORK_EFFORT = 0; // 1000 is light work, 1000000 ~= 30ms
var UPDATE_HZ = 60; // standard script update rate
var UPDATE_INTERVAL = 1000/UPDATE_HZ; // standard script update interval
var UPDATE_WORK_EFFORT = 0; // 1000 is light work, 1000000 ~= 30ms
var basePosition = Vec3.sum(Camera.getPosition(), Quat.getForward(Camera.getOrientation()));
var timerBox = Entities.addEntity(
{ type: "Box",
position: basePosition,
dimensions: { x: 0.1, y: 0.1, z: 0.1 },
color: { red: 255, green: 0, blue: 255 },
dynamic: false,
collisionless: true
});
var lastTick = Date.now();
var deltaTick = 0;
var tickSamples = 0;
var totalVariance = 0;
var tickCount = 0;
var totalWork = 0;
var highVarianceCount = 0;
var varianceCount = 0;
print("Set interval = " + TIMER_INTERVAL);
var timerTime = 0.0;
var range = 0.5;
var rotationFactor = 0.5; // smaller == faster
var omega = 2.0 * Math.PI / rotationFactor;
var ticker = Script.setInterval(function() {
tickCount++;
var tickNow = Date.now();
deltaTick = tickNow - lastTick;
var variance = Math.abs(deltaTick - TIMER_INTERVAL);
totalVariance += variance;
if (variance > 1) {
varianceCount++;
}
if (variance > 5) {
highVarianceCount++;
}
var preWork = Date.now();
var y = 2;
for (var x = 0; x < TIMER_WORK_EFFORT; x++) {
y = y * y;
}
var postWork = Date.now();
deltaWork = postWork - preWork;
totalWork += deltaWork;
// move a box
var deltaTime = deltaTick / 1000;
timerTime += deltaTime;
rotation = Quat.angleAxis(timerTime * omega / Math.PI * 180.0, { x: 0, y: 1, z: 0 });
Entities.editEntity(timerBox,
{
position: { x: basePosition.x + Math.sin(timerTime * omega) / 2.0 * range,
y: basePosition.y,
z: basePosition.z },
//rotation: rotation
});
tickSamples = tickSamples + deltaTick;
lastTick = tickNow;
// report about every 5 seconds
if(tickCount == (TIMER_HZ * 5)) {
print("TIMER -- For " + tickCount + " samples average interval = " + tickSamples/tickCount + " ms"
+ " average variance:" + totalVariance/tickCount + " ms"
+ " min variance:" + varianceCount + " [" + (varianceCount/tickCount) * 100 + " %] "
+ " high variance:" + highVarianceCount + " [" + (highVarianceCount/tickCount) * 100 + " %] "
+ " average work:" + totalWork/tickCount + " ms");
tickCount = 0;
tickSamples = 0;
totalWork = 0;
totalVariance = 0;
varianceCount = 0;
highVarianceCount = 0;
}
}, TIMER_INTERVAL);
/////////////////////////////////////////////////////////////////////////
var rpcPosition = Vec3.sum(basePosition, { x:0, y: 0.2, z: 0});
var theRpcFunctionInclude = Script.resolvePath("testIntervalRpcFunction.js");
print("theRpcFunctionInclude:" + theRpcFunctionInclude);
var rpcBox = Entities.addEntity(
{ type: "Box",
position: rpcPosition,
dimensions: { x: 0.1, y: 0.1, z: 0.1 },
color: { red: 255, green: 255, blue: 0 },
dynamic: false,
collisionless: true,
script: theRpcFunctionInclude
});
var rpcLastTick = Date.now();
var rpcTotalTicks = 0;
var rpcCount = 0;
var rpcTotalVariance = 0;
var rpcTickCount = 0;
var rpcVarianceCount = 0;
var rpcHighVarianceCount = 0;
var rpcTicker = Script.setInterval(function() {
rpcTickCount++;
var tickNow = Date.now();
var deltaTick = tickNow - rpcLastTick;
var variance = Math.abs(deltaTick - TIMER_INTERVAL);
rpcTotalVariance += variance;
if (variance > 1) {
rpcVarianceCount++;
}
if (variance > 5) {
rpcHighVarianceCount++;
}
rpcTotalTicks += deltaTick;
rpcLastTick = tickNow;
var args = [range, rotationFactor, omega, TIMER_INTERVAL, TIMER_HZ];
Entities.callEntityMethod(rpcBox, "doRPC", args);
// report about every 5 seconds
if(rpcTickCount == (TIMER_HZ * 5)) {
print("RPCTIMER- For " + rpcTickCount + " samples average interval = " + rpcTotalTicks/rpcTickCount + " ms"
+ " average variance:" + rpcTotalVariance/rpcTickCount + " ms"
+ " min variance:" + rpcVarianceCount + " [" + (rpcVarianceCount/rpcTickCount) * 100 + " %] "
+ " high variance:" + rpcHighVarianceCount + " [" + (rpcHighVarianceCount/rpcTickCount) * 100 + " %] "
);
rpcTickCount = 0;
rpcTotalTicks = 0;
rpcTotalVariance = 0;
rpcVarianceCount = 0;
rpcHighVarianceCount = 0;
}
}, TIMER_INTERVAL);
var updateCount = 0;
var updateTotalElapsed = 0;
var lastUpdate = Date.now();
var updateTotalWork = 0;
var updateTotalVariance = 0;
var updateVarianceCount = 0;
var updateHighVarianceCount = 0;
var updatePosition = Vec3.sum(basePosition, { x:0, y: -0.2, z: 0});
var updateBox = Entities.addEntity(
{ type: "Box",
position: updatePosition,
dimensions: { x: 0.1, y: 0.1, z: 0.1 },
color: { red: 0, green: 255, blue: 255 },
dynamic: false,
collisionless: true
});
var updateTime = 0;
var updateFunction = function(deltaTime){
updateCount++;
var updateAt = Date.now();
deltaUpdate = updateAt - lastUpdate;
updateTotalElapsed += deltaUpdate;
lastUpdate = updateAt;
var variance = Math.abs(deltaUpdate - UPDATE_INTERVAL);
updateTotalVariance += variance;
if (variance > 1) {
updateVarianceCount++;
}
if (variance > 5) {
updateHighVarianceCount++;
}
var preWork = Date.now();
var y = 2;
for (var x = 0; x < UPDATE_WORK_EFFORT; x++) {
y = y * y;
}
var postWork = Date.now();
deltaWork = postWork - preWork;
updateTotalWork += deltaWork;
// move a box
updateTime += deltaTime;
rotation = Quat.angleAxis(updateTime * omega / Math.PI * 180.0, { x: 0, y: 1, z: 0 });
Entities.editEntity(updateBox,
{
position: { x: updatePosition.x + Math.sin(updateTime * omega) / 2.0 * range,
y: updatePosition.y,
z: updatePosition.z },
});
if(updateCount == (UPDATE_HZ * 5)) {
print("UPDATE -- For " + updateCount + " samples average update = " + updateTotalElapsed/updateCount + " ms"
+ " average variance:" + updateTotalVariance/updateCount + " ms"
+ " min variance:" + updateVarianceCount + " [" + (updateVarianceCount/updateCount) * 100 + " %] "
+ " high variance:" + updateHighVarianceCount + " [" + (updateHighVarianceCount/updateCount) * 100 + " %] "
+ " average work:" + updateTotalWork/updateCount + " ms");
updateCount = 0;
updateTotalElapsed = 0;
updateTotalWork = 0;
updateTotalVariance = 0;
updateVarianceCount = 0;
updateHighVarianceCount = 0;
}
};
Script.update.connect(updateFunction);
Script.scriptEnding.connect(function(){
Entities.deleteEntity(timerBox);
Entities.deleteEntity(rpcBox);
Entities.deleteEntity(updateBox);
});

View file

@ -1,77 +0,0 @@
(function() {
var x = false;
var y = false;
var z = false;
var entityLastTick = Date.now();
var entityTotalTicks = 0;
var entityCount = 0;
var entityTotalVariance = 0;
var entityTickCount = 0;
var entityVarianceCount = 0;
var entityHighVarianceCount = 0;
var _entityID;
var time = 0;
function Foo() { return; };
Foo.prototype = {
preload: function(entityID) { print('Foo preload'); _entityID = entityID; },
doRPC: function(entityID, args) {
var range = args[0];
var rotationFactor = args[1];
var omega = args[2];
var TIMER_INTERVAL = args[3];
var TIMER_HZ = args[4];
// first time, set our x,y,z
if (x === false) {
var position = Entities.getEntityProperties(_entityID, "position").position;
x = position.x;
y = position.y;
z = position.z;
}
entityTickCount++;
var tickNow = Date.now();
var deltaTick = tickNow - entityLastTick;
var variance = Math.abs(deltaTick - TIMER_INTERVAL);
entityTotalVariance += variance;
if (variance > 1) {
entityVarianceCount++;
}
if (variance > 5) {
entityHighVarianceCount++;
}
entityTotalTicks += deltaTick;
entityLastTick = tickNow;
// move self!!
var deltaTime = deltaTick / 1000;
time += deltaTime;
rotation = Quat.angleAxis(time * omega / Math.PI * 180.0, { x: 0, y: 1, z: 0 });
Entities.editEntity(_entityID,
{
position: { x: x + Math.sin(time * omega) / 2.0 * range,
y: y,
z: z },
});
if(entityTickCount == (TIMER_HZ * 5)) {
print("ENTITY -- For " + entityTickCount + " samples average interval = " + entityTotalTicks/entityTickCount + " ms"
+ " average variance:" + entityTotalVariance/entityTickCount + " ms"
+ " min variance:" + entityVarianceCount + " [" + (entityVarianceCount/entityTickCount) * 100 + " %] "
+ " high variance:" + entityHighVarianceCount + " [" + (entityHighVarianceCount/entityTickCount) * 100 + " %] "
);
entityTickCount = 0;
entityTotalTicks = 0;
entityTotalVariance = 0;
entityVarianceCount = 0;
entityHighVarianceCount = 0;
}
}
};
return new Foo();
});

View file

@ -1,24 +0,0 @@
float aspect(vec2 v) {
return v.x / v.y;
}
vec3 aspectCorrectedTexture() {
vec2 uv;
if (abs(_position.y) > 0.4999) {
uv = _position.xz;
} else if (abs(_position.z) > 0.4999) {
uv = _position.xy;
} else {
uv = _position.yz;
}
uv += 0.5;
uv.y = 1.0 - uv.y;
return texture(iChannel0, uv).rgb;
}
float getProceduralColors(inout vec3 diffuse, inout vec3 specular, inout float shininess) {
specular = aspectCorrectedTexture();
return 1.0;
}

View file

@ -1,66 +0,0 @@
Script.include("https://s3.amazonaws.com/DreamingContent/scripts/Austin.js");
var ENTITY_SPAWN_LIMIT = 500;
var ENTITY_LIFETIME = 600;
var RADIUS = 1.0; // Spawn within this radius (square)
var TEST_ENTITY_NAME = "EntitySpawnTest";
var entities = [];
var textureIndex = 0;
var texture = Script.resolvePath('cube_texture.png');
var shader = Script.resolvePath('textureStress.fs');
var qml = Script.resolvePath('textureStress.qml');
qmlWindow = new OverlayWindow({
title: 'Test Qml',
source: qml,
height: 240,
width: 320,
visible: true
});
function deleteItems(count) {
if (!count) {
var ids = Entities.findEntities(MyAvatar.position, 50);
ids.forEach(function(id) {
var properties = Entities.getEntityProperties(id, ["name"]);
if (properties.name === TEST_ENTITY_NAME) {
Entities.deleteEntity(id);
}
}, this);
entities = [];
return;
} else {
// FIXME... implement
}
}
function createItems(count) {
for (var i = 0; i < count; ++i) {
var newEntity = Entities.addEntity({
type: "Box",
name: TEST_ENTITY_NAME,
position: AUSTIN.avatarRelativePosition(AUSTIN.randomPositionXZ({ x: 0, y: 0, z: -2 }, RADIUS)),
color: { r: 255, g: 255, b: 255 },
dimensions: { x: 0.5, y: 0.5, z: 0.5 }, //AUSTIN.randomDimensions(),
lifetime: ENTITY_LIFETIME,
userData: JSON.stringify({
ProceduralEntity: {
version: 2,
shaderUrl: shader,
channels: [ texture + "?" + textureIndex++ ]
}
})
});
entities.push(newEntity);
}
}
qmlWindow.fromQml.connect(function(message){
print(message);
if (message[0] === "create") {
var count = message[1] || 1;
createItems(message[1] || 1);
} else if (message[0] === "delete") {
deleteItems(message[1]);
}
});

View file

@ -1,69 +0,0 @@
import QtQuick 2.5
import QtQuick.Controls 1.4
Rectangle {
id: root
width: parent ? parent.width : 100
height: parent ? parent.height : 100
signal sendToScript(var message);
Text {
id: label
text: "GPU Texture Usage: "
}
Text {
id: usage
anchors.left: label.right
anchors.leftMargin: 8
text: "N/A"
Timer {
repeat: true
running: true
interval: 500
onTriggered: {
usage.text = Render.getConfig("Stats")["textureGPUMemoryUsage"];
}
}
}
Column {
anchors { left: parent.left; right: parent.right; top: label.bottom; topMargin: 8; bottom: parent.bottom }
spacing: 8
Button {
text: "Add 1"
onClicked: root.sendToScript(["create", 1]);
}
Button {
text: "Add 10"
onClicked: root.sendToScript(["create", 10]);
}
Button {
text: "Add 100"
onClicked: root.sendToScript(["create", 100]);
}
/*
Button {
text: "Delete 1"
onClicked: root.sendToScript(["delete", 1]);
}
Button {
text: "Delete 10"
onClicked: root.sendToScript(["delete", 10]);
}
Button {
text: "Delete 100"
onClicked: root.sendToScript(["delete", 100]);
}
*/
Button {
text: "Delete All"
onClicked: root.sendToScript(["delete", 0]);
}
}
}

Some files were not shown because too many files have changed in this diff Show more