679 lines
No EOL
29 KiB
JavaScript
679 lines
No EOL
29 KiB
JavaScript
//
|
|
// draw_app.js
|
|
//
|
|
// Created by Rebecca Stankus on 01/31/19
|
|
// Copyright 2019 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
|
|
//
|
|
|
|
/* global Audio, Camera, Controller, Entities, HMD, Messages, MyAvatar, Quat, Script, Settings, SoundCache,
|
|
Tablet, Vec3, Window */
|
|
|
|
(function() {
|
|
|
|
// *************************************
|
|
// START UTILITY FUNCTIONS
|
|
// *************************************
|
|
|
|
/* PLAY A SOUND: Plays the specified sound at the position of the user's Avatar using the volume and playback
|
|
mode requested. */
|
|
var injector;
|
|
function playSound(sound, volume, position, localOnly, loop){
|
|
if (sound.downloaded) {
|
|
if (injector) {
|
|
injector.stop();
|
|
injector = null;
|
|
}
|
|
injector = Audio.playSound(sound, {
|
|
position: position,
|
|
volume: volume,
|
|
localOnly: localOnly,
|
|
loop: loop
|
|
});
|
|
}
|
|
}
|
|
|
|
// *************************************
|
|
// END UTILITY FUNCTIONS
|
|
// *************************************
|
|
|
|
/* GET RANDOM HIFI COLOR: Choose one of HiFi's brand colors at random and return it's index # */
|
|
var HIFI_COLORS = [
|
|
{ red: 0, green: 0, blue: 0 }, // black
|
|
{ red: 255, green: 0, blue: 26 }, // red
|
|
{ red: 255, green: 66, blue: 167 }, // Magenta
|
|
{ red: 126, green: 140, blue: 129 }, // Neutral 4
|
|
{ red: 183, green: 200, blue: 185 }, // Neutral 3
|
|
{ red: 216, green: 225, blue: 217 }, // Neutral 2
|
|
{ red: 241, green: 243, blue: 238 }, // Neutral 1
|
|
{ red: 23, green: 41, blue: 131 }, // Blue
|
|
{ red: 0, green: 158, blue: 224 }, // Cyan
|
|
{ red: 0, green: 144, blue: 54 }, // Green
|
|
{ red: 255, green: 237, blue: 0 } // Yellow
|
|
];
|
|
var HIFI_COLORS_URLS = [
|
|
Script.resolvePath("assets/textures/black.png"),
|
|
Script.resolvePath("assets/textures/red.png"),
|
|
Script.resolvePath("assets/textures/magenta.png"),
|
|
Script.resolvePath("assets/textures/neutral4.png"),
|
|
Script.resolvePath("assets/textures/neutral3.png"),
|
|
Script.resolvePath("assets/textures/neutral2.png"),
|
|
Script.resolvePath("assets/textures/neutral1.png"),
|
|
Script.resolvePath("assets/textures/blue.png"),
|
|
Script.resolvePath("assets/textures/cyan.png"),
|
|
Script.resolvePath("assets/textures/green.png"),
|
|
Script.resolvePath("assets/textures/yellow.png")
|
|
];
|
|
function getRandomHiFiColorIndex() {
|
|
var numberOfHifiColors = HIFI_COLORS.length;
|
|
return Math.floor(Math.random() * numberOfHifiColors);
|
|
}
|
|
|
|
/* CREATE A PAINTBALL: Checks that paint sphere does not already exist, then calculate position of avatar's hand and
|
|
create a paint sphere there */
|
|
var paintSphere;
|
|
var paintSphereMaterial;
|
|
var parentJointIndex;
|
|
var randomHiFiColorIndex;
|
|
function createPaintSphere() {
|
|
if (paintSphere) {
|
|
return;
|
|
}
|
|
parentJointIndex = MyAvatar.getJointIndex(dominantHandJoint + "Index4");
|
|
if (parentJointIndex === -1) {
|
|
MyAvatar.getJointIndex(dominantHandJoint + "Index3");
|
|
}
|
|
if (parentJointIndex === -1) {
|
|
MyAvatar.getJointIndex(dominantHandJoint);
|
|
print("ERROR: Falling back to dominant hand joint as index finger tip could not be found");
|
|
}
|
|
randomHiFiColorIndex = getRandomHiFiColorIndex();
|
|
paintSphere = Entities.addEntity({
|
|
name: "Draw App Sphere",
|
|
type: "Model",
|
|
modelURL: Script.resolvePath("assets/models/sphere-white-emissive.fbx"),
|
|
parentID: MyAvatar.sessionUUID,
|
|
parentJointIndex: parentJointIndex,
|
|
localPosition: { x: 0, y: 0, z: 0 },
|
|
localDimensions: { x: 0.015, y: 0.015, z: 0.015 },
|
|
grab: { grabbable: false },
|
|
collisionless: true
|
|
}, 'avatar');
|
|
paintSphereMaterial = Entities.addEntity({
|
|
type: "Material",
|
|
name: "Draw App Material",
|
|
materialURL: "materialData",
|
|
priority: 1,
|
|
parentID: paintSphere,
|
|
materialData: JSON.stringify({
|
|
materials: {
|
|
albedo: HIFI_COLORS[randomHiFiColorIndex],
|
|
emissiveMap: HIFI_COLORS_URLS[randomHiFiColorIndex]
|
|
}
|
|
})
|
|
}, 'avatar');
|
|
}
|
|
|
|
/* REGISTER CONTROLLER MAPPING: Listen for controller trigger movements and act when the trigger is pressed or
|
|
released */
|
|
var MINIMUM_TRIGGER_PRESS_VALUE = 0.97;
|
|
var controllerMapping;
|
|
var controllerMappingName = 'Hifi-DrawApp';
|
|
var activeTriggerPress = false;
|
|
var activeGripPress = false;
|
|
function registerControllerMapping() {
|
|
controllerMapping = Controller.newMapping(controllerMappingName);
|
|
controllerMapping.from(Controller.Standard.RT).to(function (value) {
|
|
if (dominantHand === "right") {
|
|
if (value >= MINIMUM_TRIGGER_PRESS_VALUE && !activeTriggerPress) {
|
|
activeTriggerPress = true;
|
|
triggerPressed();
|
|
} else if (value <= MINIMUM_TRIGGER_PRESS_VALUE && activeTriggerPress) {
|
|
triggerReleased();
|
|
}
|
|
}
|
|
});
|
|
controllerMapping.from(Controller.Standard.RightGrip).to(function (value) {
|
|
if (dominantHand === "right") {
|
|
if (value >= MINIMUM_TRIGGER_PRESS_VALUE && !activeGripPress) {
|
|
activeGripPress = true;
|
|
gripPressed();
|
|
} else if (value <= MINIMUM_TRIGGER_PRESS_VALUE && activeGripPress) {
|
|
gripReleased();
|
|
}
|
|
}
|
|
});
|
|
controllerMapping.from(Controller.Standard.LT).to(function (value) {
|
|
if (dominantHand === "left") {
|
|
if (value >= MINIMUM_TRIGGER_PRESS_VALUE && !activeTriggerPress ) {
|
|
activeTriggerPress = true;
|
|
triggerPressed();
|
|
} else if (value <= MINIMUM_TRIGGER_PRESS_VALUE && activeTriggerPress) {
|
|
triggerReleased();
|
|
}
|
|
}
|
|
});
|
|
controllerMapping.from(Controller.Standard.LeftGrip).to(function (value) {
|
|
if (dominantHand === "left") {
|
|
if (value >= MINIMUM_TRIGGER_PRESS_VALUE && !activeGripPress) {
|
|
activeGripPress = true;
|
|
gripPressed();
|
|
} else if (value <= MINIMUM_TRIGGER_PRESS_VALUE && activeGripPress) {
|
|
gripReleased();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/* ON TRIGGER PRESS DRAW: Store the initial point and begin checking distance hand has moved on an interval. If hand
|
|
has moved more than minimum distance, draw a polyline entity with a lifetime of 1 minute and continue checking
|
|
hand distance. Every time hand moves more than the minumum, update the polyline with another node. */
|
|
var REPEAT_DISTANCE_CHECK_MS = 60;
|
|
var MINIMUM_MOVEMENT_TO_DRAW_M = 0.0005;
|
|
var DEFAULT_NORMAL = { x: 0, y: 0, z: 1 };
|
|
var DECAY_TIME_S = 60;
|
|
var MAX_LINE_POINTS = 100;
|
|
var DRAW_SOUND = SoundCache.getSound(Script.resolvePath('assets/sounds/draw.mp3'));
|
|
var DRAW_SOUND_VOLUME = 0.01;
|
|
var distanceCheckInterval = null;
|
|
var polyLine = null;
|
|
var lineStartPosition;
|
|
var previousLinePoint;
|
|
var linePoints = [{x: 0, y: 0, z: 0 }];
|
|
var lineNormals = [DEFAULT_NORMAL, DEFAULT_NORMAL];
|
|
var lineStrokeWidths = [];
|
|
var paintSphereDimensions;
|
|
function triggerPressed() {
|
|
if (tablet.tabletShown || activeGripPress) {
|
|
return;
|
|
}
|
|
lineStartPosition = MyAvatar.getJointPosition(parentJointIndex);
|
|
previousLinePoint = MyAvatar.getJointPosition(parentJointIndex);
|
|
distanceCheckInterval = Script.setInterval(function() {
|
|
var currentLinePoint = MyAvatar.getJointPosition(parentJointIndex);
|
|
if (Vec3.distance(previousLinePoint, currentLinePoint) > MINIMUM_MOVEMENT_TO_DRAW_M) {
|
|
var displacementFromStart = Vec3.subtract(currentLinePoint, lineStartPosition);
|
|
linePoints.push(displacementFromStart);
|
|
if (!polyLine) {
|
|
playSound(DRAW_SOUND, DRAW_SOUND_VOLUME, currentLinePoint, false, true);
|
|
if (paintSphere) {
|
|
paintSphereDimensions = Entities.getEntityProperties(paintSphere, 'dimensions').dimensions;
|
|
}
|
|
lineStrokeWidths = [paintSphereDimensions.x, paintSphereDimensions.x];
|
|
polyLine = Entities.addEntity({
|
|
type: "PolyLine",
|
|
name: "Draw App Polyline",
|
|
position: previousLinePoint,
|
|
linePoints: linePoints,
|
|
normals: lineNormals,
|
|
strokeWidths: lineStrokeWidths,
|
|
color: HIFI_COLORS[randomHiFiColorIndex],
|
|
textures: HIFI_COLORS_URLS[randomHiFiColorIndex],
|
|
isUVModeStretch: true,
|
|
lifetime: DECAY_TIME_S,
|
|
collisionless: true,
|
|
faceCamera: true
|
|
}, 'avatar');
|
|
} else {
|
|
if (injector) {
|
|
injector.options = { position: currentLinePoint };
|
|
}
|
|
var lineProperties = Entities.getEntityProperties(polyLine, ['linePoints', 'normals',
|
|
'strokeWidths', 'age']);
|
|
var linePointsCount = lineProperties.linePoints.length;
|
|
if (linePointsCount > MAX_LINE_POINTS) {
|
|
var lastPointDisplacement = lineProperties.linePoints[linePointsCount - 1];
|
|
linePoints = [lastPointDisplacement, displacementFromStart];
|
|
lineNormals = [DEFAULT_NORMAL, DEFAULT_NORMAL];
|
|
if (paintSphere) {
|
|
paintSphereDimensions = Entities.getEntityProperties(paintSphere, 'dimensions').dimensions;
|
|
}
|
|
lineStrokeWidths = [paintSphereDimensions.x, paintSphereDimensions.x];
|
|
polyLine = Entities.addEntity({
|
|
type: "PolyLine",
|
|
name: "Draw App Polyline",
|
|
position: previousLinePoint,
|
|
linePoints: linePoints,
|
|
normals: lineNormals,
|
|
strokeWidths: lineStrokeWidths,
|
|
color: HIFI_COLORS[randomHiFiColorIndex],
|
|
textures: HIFI_COLORS_URLS[randomHiFiColorIndex],
|
|
isUVModeStretch: true,
|
|
lifetime: DECAY_TIME_S,
|
|
collisionless: true,
|
|
faceCamera: true
|
|
}, 'avatar');
|
|
} else {
|
|
if (paintSphere) {
|
|
paintSphereDimensions = Entities.getEntityProperties(paintSphere, 'dimensions').dimensions;
|
|
}
|
|
lineProperties.linePoints.push(displacementFromStart);
|
|
lineProperties.normals.push(DEFAULT_NORMAL);
|
|
lineProperties.strokeWidths.push(paintSphereDimensions.x);
|
|
Entities.editEntity(polyLine, {
|
|
linePoints: lineProperties.linePoints,
|
|
normals: lineProperties.normals,
|
|
strokeWidths: lineProperties.strokeWidths,
|
|
lifetime: lineProperties.age + DECAY_TIME_S
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}, REPEAT_DISTANCE_CHECK_MS);
|
|
}
|
|
|
|
/* STOP DRAWING THE CURRENT LINE: stop sound, reset current line variables */
|
|
function stopDrawing() {
|
|
if (injector) {
|
|
injector.stop();
|
|
injector = null;
|
|
}
|
|
polyLine = null;
|
|
linePoints = [{x: 0, y: 0, z: 0 }];
|
|
lineNormals = [DEFAULT_NORMAL, DEFAULT_NORMAL];
|
|
lineStrokeWidths = [];
|
|
desktopActionProgress = false;
|
|
}
|
|
|
|
|
|
/* ON TRIGGER RELEASE DRAW: Stop checking distance hand has moved */
|
|
function triggerReleased() {
|
|
if (activeTriggerPress) {
|
|
activeTriggerPress = false;
|
|
if (distanceCheckInterval) {
|
|
Script.clearInterval(distanceCheckInterval);
|
|
distanceCheckInterval = null;
|
|
}
|
|
stopDrawing();
|
|
}
|
|
}
|
|
|
|
/* ON GRIP PRESS ERASE: Set an interval that finds the nearest line within a maximum distance to paint
|
|
sphere tip and erases it */
|
|
var DELETE_AGAIN_MS = 100;
|
|
var MAXIMUM_DISTANCE_TO_SEARCH_M = 1;
|
|
var MAXIMUM_DISTANCE_TO_DELETE_M = 0.03;
|
|
var DISTANCE_TO_DRAW_IN_FRONT_OF_CAMERA_DESKTOP_M = 1.5;
|
|
var deletingInterval;
|
|
function gripPressed() {
|
|
if (tablet.tabletShown || activeTriggerPress) {
|
|
return;
|
|
}
|
|
deletingInterval = Script.setInterval(function() {
|
|
var fingerTipPosition = MyAvatar.getJointPosition(parentJointIndex);
|
|
var foundANearbyLine = false;
|
|
var lineToDelete;
|
|
Entities.findEntitiesByName("Draw App Polyline", fingerTipPosition, MAXIMUM_DISTANCE_TO_SEARCH_M)
|
|
.forEach(function(nearbyDrawAppLine) {
|
|
var lineProperties = Entities.getEntityProperties(nearbyDrawAppLine, ['position', 'linePoints']);
|
|
var lineBoundingBoxCenter = lineProperties.position;
|
|
var numberLinePoints = lineProperties.linePoints.length;
|
|
var shortestDistance = MAXIMUM_DISTANCE_TO_DELETE_M;
|
|
for (var i = 0; i < numberLinePoints; i++) {
|
|
var distanceFromMarkerTip = Vec3.distance(fingerTipPosition,
|
|
Vec3.sum(lineBoundingBoxCenter, lineProperties.linePoints[i]));
|
|
if (distanceFromMarkerTip <= shortestDistance) {
|
|
foundANearbyLine = true;
|
|
lineToDelete = nearbyDrawAppLine;
|
|
shortestDistance = DISTANCE_TO_DRAW_IN_FRONT_OF_CAMERA_DESKTOP_M;
|
|
}
|
|
}
|
|
});
|
|
if (foundANearbyLine) {
|
|
Entities.deleteEntity(lineToDelete);
|
|
}
|
|
}, DELETE_AGAIN_MS);
|
|
}
|
|
|
|
/* ON GRIP RELEASE ERASE: Stop the interval that is searching for lines to delete */
|
|
function gripReleased() {
|
|
if (activeGripPress) {
|
|
activeGripPress = false;
|
|
if (deletingInterval) {
|
|
Script.clearInterval(deletingInterval);
|
|
deletingInterval = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ON MOUSE PRESS: Store the initial point to start line. */
|
|
var previousLinePointDesktop;
|
|
var pickRay;
|
|
var desktopActionProgress = false;
|
|
function mousePressed(event) {
|
|
if (Settings.getValue("io.highfidelity.isEditing", false) || tablet.tabletShown) {
|
|
return;
|
|
}
|
|
if (event.isLeftButton) {
|
|
pickRay = Camera.computePickRay(event.x, event.y);
|
|
desktopActionProgress = true;
|
|
lineStartPosition = Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction,
|
|
DISTANCE_TO_DRAW_IN_FRONT_OF_CAMERA_DESKTOP_M));
|
|
previousLinePoint = Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction,
|
|
DISTANCE_TO_DRAW_IN_FRONT_OF_CAMERA_DESKTOP_M));
|
|
}
|
|
}
|
|
|
|
/* ON MOUSE MOVE: Calculate the next line poi8nt and add it to the entity. If there are too many line points,
|
|
begin a new line. */
|
|
function mouseContinueLine(event) {
|
|
if (tablet.tabletShown) {
|
|
return;
|
|
}
|
|
if (!desktopActionProgress) {
|
|
return;
|
|
}
|
|
if (event.isLeftButton) {
|
|
pickRay = Camera.computePickRay(event.x, event.y);
|
|
var currentLinePoint = Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction,
|
|
DISTANCE_TO_DRAW_IN_FRONT_OF_CAMERA_DESKTOP_M));
|
|
if (Vec3.distance(previousLinePointDesktop, currentLinePoint) > MINIMUM_MOVEMENT_TO_DRAW_M) {
|
|
var displacementFromStart = Vec3.subtract(currentLinePoint, lineStartPosition);
|
|
linePoints.push(displacementFromStart);
|
|
if (!polyLine) {
|
|
playSound(DRAW_SOUND, 1, currentLinePoint, false, true);
|
|
if (paintSphere) {
|
|
paintSphereDimensions = Entities.getEntityProperties(paintSphere, 'dimensions').dimensions;
|
|
}
|
|
lineStrokeWidths = [paintSphereDimensions.x, paintSphereDimensions.x];
|
|
polyLine = Entities.addEntity({
|
|
type: "PolyLine",
|
|
name: "Draw App Polyline",
|
|
position: lineStartPosition,
|
|
linePoints: linePoints,
|
|
normals: lineNormals,
|
|
strokeWidths: lineStrokeWidths,
|
|
color: HIFI_COLORS[randomHiFiColorIndex],
|
|
textures: HIFI_COLORS_URLS[randomHiFiColorIndex],
|
|
isUVModeStretch: true,
|
|
lifetime: DECAY_TIME_S,
|
|
collisionless: true,
|
|
faceCamera: true
|
|
}, 'avatar');
|
|
} else {
|
|
if (injector) {
|
|
injector.options = { position: currentLinePoint };
|
|
}
|
|
var lineProperties = Entities.getEntityProperties(polyLine, ['linePoints', 'normals',
|
|
'strokeWidths', 'age']);
|
|
var linePointsCount = lineProperties.linePoints.length;
|
|
if (linePointsCount > MAX_LINE_POINTS) {
|
|
var lastPointDisplacement = lineProperties.linePoints[linePointsCount - 1];
|
|
linePoints = [lastPointDisplacement, displacementFromStart];
|
|
lineNormals = [DEFAULT_NORMAL, DEFAULT_NORMAL];
|
|
if (paintSphere) {
|
|
paintSphereDimensions = Entities.getEntityProperties(paintSphere, 'dimensions').dimensions;
|
|
}
|
|
lineStrokeWidths = [paintSphereDimensions.x, paintSphereDimensions.x];
|
|
polyLine = Entities.addEntity({
|
|
type: "PolyLine",
|
|
name: "Draw App Polyline",
|
|
position: previousLinePoint,
|
|
linePoints: linePoints,
|
|
normals: lineNormals,
|
|
strokeWidths: lineStrokeWidths,
|
|
color: HIFI_COLORS[randomHiFiColorIndex],
|
|
textures: HIFI_COLORS_URLS[randomHiFiColorIndex],
|
|
isUVModeStretch: true,
|
|
lifetime: DECAY_TIME_S,
|
|
collisionless: true,
|
|
faceCamera: true
|
|
}, 'avatar');
|
|
} else {
|
|
lineProperties.linePoints.push(displacementFromStart);
|
|
lineProperties.normals.push(DEFAULT_NORMAL);
|
|
if (paintSphere) {
|
|
paintSphereDimensions = Entities.getEntityProperties(paintSphere, 'dimensions').dimensions;
|
|
}
|
|
lineProperties.strokeWidths.push(paintSphereDimensions.x);
|
|
Entities.editEntity(polyLine, {
|
|
linePoints: lineProperties.linePoints,
|
|
normals: lineProperties.normals,
|
|
strokeWidths: lineProperties.strokeWidths,
|
|
lifetime: lineProperties.age + DECAY_TIME_S
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ON MOUSE RELEASE: Stop checking distance cursor has moved */
|
|
function mouseReleased(event) {
|
|
if (event.button === "LEFT") {
|
|
stopDrawing();
|
|
desktopActionProgress= false;
|
|
}
|
|
}
|
|
|
|
/* ON CLICKING APP BUTTON: (on the toolbar or tablet) if we are opening the app, play a sound and get the paint sphere.
|
|
If we are closing the app, remove the paint sphere */
|
|
var OPEN_SOUND = SoundCache.getSound(Script.resolvePath('assets/sounds/open.mp3'));
|
|
var OPEN_SOUND_VOLUME = 0.2;
|
|
var CLOSE_SOUND = SoundCache.getSound(Script.resolvePath('assets/sounds/close.mp3'));
|
|
var CLOSE_SOUND_VOLUME = 0.3;
|
|
function onClicked() {
|
|
if (paintSphere) {
|
|
button.editProperties({ isActive: false });
|
|
if (HMD.active) {
|
|
closeHMDMode();
|
|
} else {
|
|
closeDesktopMode();
|
|
}
|
|
Entities.deleteEntity(paintSphere);
|
|
paintSphere = null;
|
|
playSound(CLOSE_SOUND, CLOSE_SOUND_VOLUME, MyAvatar.position, true, false);
|
|
} else {
|
|
if (HMD.active) {
|
|
HMD.closeTablet();
|
|
setUpHMDMode();
|
|
} else {
|
|
setUpDesktopMode();
|
|
}
|
|
button.editProperties({ isActive: true });
|
|
playSound(OPEN_SOUND, OPEN_SOUND_VOLUME, MyAvatar.position, true, false);
|
|
createPaintSphere();
|
|
}
|
|
}
|
|
|
|
/* ON STOPPING THE SCRIPT: Make sure the paint sphere gets deleted and its variable set back to null
|
|
if applicable. Search for any unreferenced paint spheres and delete if found. */
|
|
function appEnding() {
|
|
cleanUp();
|
|
tablet.tabletShownChanged.disconnect(tabletShownChanged);
|
|
MyAvatar.dominantHandChanged.disconnect(handChanged);
|
|
HMD.displayModeChanged.disconnect(displayModeChange);
|
|
button.clicked.disconnect(onClicked);
|
|
Window.domainChanged.disconnect(domainChanged);
|
|
tablet.removeButton(button);
|
|
if (controllerMapping) {
|
|
controllerMapping.disable();
|
|
}
|
|
}
|
|
|
|
/* CLEANUP: Remove paint sphere, search for any unreferenced paint spheres to clean up */
|
|
function cleanUp() {
|
|
if (injector) {
|
|
injector.stop();
|
|
injector = null;
|
|
}
|
|
if (controllerMapping) {
|
|
controllerMapping.disable();
|
|
}
|
|
Messages.sendLocalMessage("Hifi-Hand-Disabler", "none");
|
|
if (animationHandlerID) {
|
|
animationHandlerID = MyAvatar.removeAnimationStateHandler(animationHandlerID);
|
|
}
|
|
if (paintSphere) {
|
|
Entities.deleteEntity(paintSphere);
|
|
paintSphere = null;
|
|
}
|
|
if (distanceCheckInterval) {
|
|
Script.clearInterval(distanceCheckInterval);
|
|
distanceCheckInterval = null;
|
|
}
|
|
if (deletingInterval) {
|
|
Script.clearInterval(deletingInterval);
|
|
deletingInterval = null;
|
|
}
|
|
button.editProperties({ isActive: false });
|
|
MyAvatar.getAvatarEntitiesVariant().forEach(function(avatarEntity) {
|
|
var name = Entities.getEntityProperties(avatarEntity.id, 'name').name;
|
|
if (name === "Draw App Sphere") {
|
|
Entities.deleteEntity(avatarEntity.id);
|
|
paintSphere = null;
|
|
}
|
|
});
|
|
}
|
|
|
|
/* WHEN TOGGLING DISPLAY MODE: Set variable to track which method to use to draw lines */
|
|
function displayModeChange() {
|
|
if (paintSphere) {
|
|
if (HMD.active) {
|
|
closeDesktopMode();
|
|
setUpHMDMode();
|
|
} else {
|
|
closeHMDMode();
|
|
setUpDesktopMode();
|
|
}
|
|
}
|
|
}
|
|
|
|
/* GET ANIMATION DATA: Get correct overrides depending on dominant hand */
|
|
var animationData = {};
|
|
function getAnimationData() {
|
|
if (dominantHand === "right") {
|
|
animationData.rightHandType = 0;
|
|
animationData.isRightHandGrasp = false;
|
|
animationData.isRightIndexPoint = true;
|
|
animationData.isRightThumbRaise = false;
|
|
animationData.isRightIndexPointAndThumbRaise = false;
|
|
} else {
|
|
animationData.leftHandType = 0;
|
|
animationData.isLeftHandGrasp = false;
|
|
animationData.isLeftIndexPoint = true;
|
|
animationData.isLeftThumbRaise = false;
|
|
animationData.isLeftIndexPointAndThumbRaise = false;
|
|
}
|
|
return animationData;
|
|
}
|
|
|
|
/* SET UP HMD MODE: create controller mapping to listen for trigger presses */
|
|
var animationHandlerID;
|
|
function setUpHMDMode() {
|
|
if (controllerMapping) {
|
|
controllerMapping.enable();
|
|
}
|
|
animationHandlerID = MyAvatar.addAnimationStateHandler(getAnimationData, []);
|
|
Messages.sendLocalMessage("Hifi-Hand-Disabler", dominantHand);
|
|
}
|
|
|
|
/* SET UP DESKTOP MODE: Listen for mouse presses */
|
|
var mouseEventsConnected = false;
|
|
function setUpDesktopMode() {
|
|
if (!mouseEventsConnected) {
|
|
mouseEventsConnected = true;
|
|
Controller.mousePressEvent.connect(mousePressed);
|
|
Controller.mouseMoveEvent.connect(mouseContinueLine);
|
|
Controller.mouseReleaseEvent.connect(mouseReleased);
|
|
}
|
|
}
|
|
|
|
/* CLOSE HMD MODE: Remove controller mapping */
|
|
function closeHMDMode() {
|
|
if (controllerMapping) {
|
|
controllerMapping.disable();
|
|
}
|
|
Messages.sendLocalMessage("Hifi-Hand-Disabler", "none");
|
|
if (animationHandlerID) {
|
|
animationHandlerID = MyAvatar.removeAnimationStateHandler(animationHandlerID);
|
|
}
|
|
}
|
|
|
|
/* CLOSE DESKTOP MODE: Stop listening for mouse presses */
|
|
function closeDesktopMode() {
|
|
if (mouseEventsConnected) {
|
|
mouseEventsConnected = false;
|
|
Controller.mousePressEvent.disconnect(mousePressed);
|
|
Controller.mouseMoveEvent.disconnect(mouseContinueLine);
|
|
Controller.mouseReleaseEvent.disconnect(mouseReleased);
|
|
}
|
|
}
|
|
|
|
/* WHEN USER DOMAIN CHANGES: Close app to remove paint sphere in hand when leaving the domain */
|
|
var WAIT_TO_CLEAN_UP_MS = 2000;
|
|
function domainChanged() {
|
|
Script.setTimeout(function() {
|
|
cleanUp();
|
|
}, WAIT_TO_CLEAN_UP_MS);
|
|
}
|
|
|
|
/* WHEN USER CHANGES DOMINANT HAND: Switch default hand to place paint sphere in */
|
|
var WAIT_TO_REOPEN_APP_MS = 500;
|
|
function handChanged() {
|
|
if (MyAvatar.getDominantHand() === dominantHand) {
|
|
return;
|
|
}
|
|
dominantHand = MyAvatar.getDominantHand();
|
|
dominantHandJoint = (dominantHand === "right") ? "RightHand" : "LeftHand";
|
|
if (distanceCheckInterval) {
|
|
Script.clearInterval(distanceCheckInterval);
|
|
distanceCheckInterval = null;
|
|
}
|
|
if (deletingInterval) {
|
|
Script.clearInterval(deletingInterval);
|
|
deletingInterval = null;
|
|
}
|
|
if (paintSphere) {
|
|
onClicked();
|
|
Script.setTimeout(function() {
|
|
onClicked();
|
|
}, WAIT_TO_REOPEN_APP_MS);
|
|
}
|
|
}
|
|
|
|
/* TABLET SHOWN CHANGED: If draw app is open and tablet is shown, disable it. When the tablet closes while draw
|
|
app is open, reenable it */
|
|
function tabletShownChanged() {
|
|
if (!paintSphere) {
|
|
return;
|
|
}
|
|
if (tablet.tabletShown) {
|
|
if (HMD.active) {
|
|
if (activeTriggerPress) {
|
|
triggerReleased();
|
|
} else if (activeGripPress) {
|
|
gripReleased();
|
|
}
|
|
closeHMDMode();
|
|
} else {
|
|
mouseReleased();
|
|
closeDesktopMode();
|
|
}
|
|
} else {
|
|
if (HMD.active) {
|
|
setUpHMDMode();
|
|
} else {
|
|
setUpDesktopMode();
|
|
}
|
|
}
|
|
}
|
|
|
|
var tablet = Tablet.getTablet('com.highfidelity.interface.tablet.system');
|
|
var button = tablet.addButton({
|
|
text: 'DRAW',
|
|
icon: Script.resolvePath('assets/icons/draw-i.png'),
|
|
activeIcon: Script.resolvePath('assets/icons/draw-a.png')
|
|
});
|
|
var dominantHand = MyAvatar.getDominantHand();
|
|
var dominantHandJoint = (dominantHand === "right") ? "RightHand" : "LeftHand";
|
|
MyAvatar.dominantHandChanged.connect(handChanged);
|
|
tablet.tabletShownChanged.connect(tabletShownChanged);
|
|
registerControllerMapping();
|
|
HMD.displayModeChanged.connect(displayModeChange);
|
|
button.clicked.connect(onClicked);
|
|
Window.domainChanged.connect(domainChanged);
|
|
Script.scriptEnding.connect(appEnding);
|
|
}()); |