mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 08:57:27 +02:00
OK this is definitely working
This commit is contained in:
parent
21454f6256
commit
5067fd4cd2
310 changed files with 3 additions and 34897 deletions
|
@ -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()
|
||||
|
|
|
@ -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);
|
|
@ -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);
|
|
@ -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);
|
||||
}());
|
|
@ -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);
|
||||
});
|
||||
|
|
@ -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);
|
||||
|
||||
}());
|
|
@ -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);
|
||||
});
|
||||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
|
||||
}());
|
|
@ -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();
|
|
@ -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();
|
|
@ -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();
|
||||
});
|
||||
|
||||
}());
|
|
@ -1,85 +0,0 @@
|
|||
(function() {
|
||||
var BALLOT_X = '✗';
|
||||
var CHECKMARK = '✓';
|
||||
var DOWN_RIGHT_ARROW = '↳';
|
||||
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 /> '+
|
||||
pending.join('<br /> ')+'</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
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
);
|
||||
};
|
||||
});
|
|
@ -1 +0,0 @@
|
|||
cube_texture.ktx
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.');
|
||||
}
|
|
@ -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);
|
||||
});
|
|
@ -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();
|
||||
});
|
|
@ -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);
|
|
@ -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);
|
|
@ -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();
|
||||
});
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
@ -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();
|
||||
});
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
|
@ -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
|
|
@ -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 |
|
@ -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();
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
|
@ -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>
|
|
@ -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
|
|
@ -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 |
|
@ -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
|
||||
});
|
|
@ -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);
|
||||
|
|
@ -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 },
|
||||
});
|
||||
},
|
||||
};
|
||||
})
|
|
@ -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()));
|
||||
}
|
||||
|
|
@ -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);
|
||||
};
|
|
@ -1,3 +0,0 @@
|
|||
(function() {
|
||||
throw new Error(Script.resolvePath(''));
|
||||
})
|
|
@ -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 },
|
||||
});
|
||||
},
|
||||
};
|
||||
})
|
|
@ -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()));
|
||||
}
|
|
@ -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
|
|
@ -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);
|
|
@ -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;
|
|
@ -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);
|
||||
});
|
||||
|
|
@ -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);
|
||||
});
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
|
@ -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();
|
||||
});
|
|
@ -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();
|
|
@ -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]);
|
||||
}
|
||||
})
|
|
@ -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();
|
|
@ -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);
|
||||
});
|
|
@ -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();
|
|
@ -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));
|
|
@ -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);
|
||||
})();
|
|
@ -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');
|
||||
});
|
|
@ -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"); });
|
|
@ -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);
|
||||
};
|
||||
})
|
|
@ -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
|
|
@ -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);
|
|
@ -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); });
|
||||
|
|
@ -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 )
|
|
@ -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();
|
||||
};
|
||||
})
|
|
@ -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);
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
var qml = Script.resolvePath('playaPerformanceTest.qml');
|
||||
qmlWindow = new OverlayWindow({
|
||||
title: 'Test Qml',
|
||||
source: qml,
|
||||
height: 320,
|
||||
width: 640,
|
||||
visible: true
|
||||
});
|
||||
|
||||
|
|
@ -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();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
})
|
||||
|
|
@ -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)));
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 |
|
@ -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);
|
||||
}
|
||||
|
|
@ -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();
|
||||
});
|
|
@ -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); });
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 } }); }
|
||||
|
|
@ -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>
|
|
@ -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);
|
||||
|
||||
}());
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
|
@ -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);
|
||||
});
|
|
@ -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);
|
||||
});
|
|
@ -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();
|
||||
});
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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]);
|
||||
}
|
||||
});
|
|
@ -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
Loading…
Reference in a new issue