content/hifi-content/davidback/oldstuff/hackathon_old/watchScript.js
2022-02-13 22:49:05 +01:00

350 lines
No EOL
11 KiB
JavaScript

//
// watchScript.js
//
// Created by David Back on 10/26/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
//
(function() { // BEGIN LOCAL_SCOPE
const LEFT_FOREARM_JOINT = "LeftForeArm";
const LEFT_HAND_JOINT = "LeftHand";
const RIGHT_HAND_JOINT = "RightHand";
const ACTIVATION_DISTANCE = 0.25;
const DEACTIVATION_DISTANCE = 0.6;
const SWIPE_THRESHOLD = 0.125;
const ACTIVATION_INTERVAL = 50;
const WATCH_Z_OFFSET = -0.05;
const WATCH_FOREARM_HAND_DISTANCE = 0.8;
const LEFT_HAND = 0;
const RIGHT_HAND = 1;
const WATCH_MODEL = Script.resolvePath("watchModel.fbx");
const GHOST_EFFECT = Script.resolvePath("ghost-effect.png");
const PARTICLE_EFFECT = Script.resolvePath("particle-effect.png");
const RESET = Script.resolvePath("reset.png");
const SELECTION_ORDER = [ GHOST_EFFECT, PARTICLE_EFFECT, RESET ];
const DEFAULT_REGISTRATION_POINT = { x: 0.5, y: 0.5, z: 0.5 };
const DEBUG_ACTIVATION_KEY = 70;
var materialEntities = [];
var watchOpen = false;
var debugWatchOpen = false;
var activationInterval = null;
var watchEntity = null;
var projectionEffect = null;
var selectionOverlay = null;
var selectionIndex = 0;
var pointer = null;
var mousePressPickPos2D = null;
var triggerMapping = Controller.newMapping(Script.resolvePath('') + '-click');
function cleanupFromBefore() {
var toDelete = Entities.findEntitiesByName("Hackathon_GhostMaterial", MyAvatar.position, 1000);
for (var i = 0; i < toDelete.length; i++) {
Entities.deleteEntity(toDelete[i]);
}
var toDelete = Entities.findEntitiesByName("Hackathon_Particle", MyAvatar.position, 1000);
for (var i = 0; i < toDelete.length; i++) {
Entities.deleteEntity(toDelete[i]);
}
}
function openWatch() {
print("WATCH - OPEN");
projectionEffect = Entities.addEntity({
alpha: 0,
alphaFinish: 0,
alphaStart: 0.5,
color: {
"blue": 222,
"green": 164,
"red": 18
},
colorSpread: {
"blue": 100,
"green": 50,
"red": 50
},
emitAcceleration: {
"x": 0,
"y": 0.8,
"z": 0
},
emitOrientation: Quat.fromPitchYawRollDegrees(-180, 0, 0),
emitRate: 10,
emitSpeed: 1,
lifespan: 0.8,
maxParticles: 10,
name: "Watch Projection Effect",
parentID: watchEntity,
particleRadius: 0.2,
radiusFinish: 0.1,
radiusStart: 0,
speedSpread: 0,
spinFinish: 0,
spinStart: 0,
textures: "https://content.highfidelity.com/DomainContent/production/Particles/wispy-smoke.png",
type: "ParticleEffect"
}, true);
selectionOverlay = Overlays.addOverlay("image3d", {
name: "Watch Selection",
url: SELECTION_ORDER[selectionIndex],
alpha: 1,
dimensions: { x: 0.4, y: 0.4 },
visible: true,
emissive: true,
ignoreRayIntersection: false,
parentID: watchEntity,
localPosition: { x: 0, y: 0, z: -0.3 },
localRotation: Quat.fromPitchYawRollDegrees(-90, 0, -90)
});
pointer = Pointers.createPointer(PickType.Stylus, {
hand: RIGHT_HAND,
filter: Picks.PICK_OVERLAYS,
enabled: true
});
Pointers.setIncludeItems(pointer, [selectionOverlay]);
Overlays.mousePressOnOverlay.connect(mousePressOnOverlay);
Overlays.mouseReleaseOnOverlay.connect(mouseReleaseOnOverlay);
triggerMapping.enable();
cleanupFromBefore();
watchOpen = true;
}
function closeWatch() {
print("WATCH - CLOSE");
if (projectionEffect !== null) {
Entities.deleteEntity(projectionEffect);
projectionEffect = null;
}
if (selectionOverlay !== null) {
Overlays.deleteOverlay(selectionOverlay);
selectionOverlay = null;
}
if (pointer !== null) {
Pointers.removePointer(pointer);
pointer = null;
}
for (var i = 0; i < materialEntities.length; i++) {
Entities.deleteEntity(materialEntities[i]);
}
Overlays.mousePressOnOverlay.disconnect(mousePressOnOverlay);
Overlays.mouseReleaseOnOverlay.disconnect(mouseReleaseOnOverlay);
triggerMapping.disable();
watchOpen = false;
}
function triggerSelection() {
print("WATCH - TRIGGER SELECTION");
var model = Graphics.getModel(MyAvatar.SELF_ID);
var partID = 0;
for (var i = 0; i < model.meshes.length; i++) {
var mesh = model.meshes[i];
for (var j = 0; j < mesh.parts.length; j++) {
materialEntities.push(Entities.addEntity({
name: "Hackathon_GhostMaterial",
type: "Material",
position: MyAvatar.position,
materialURL: "materialData",
priority: 1,
parentID: MyAvatar.SELF_ID,
parentMaterialName: partID,
materialData: JSON.stringify({
materials: {
albedoMap: "https://drive.google.com/file/d/1zvVO63hpdz5d4zvmT3d5pZG-12X3_KYW/view?usp=sharing",
opacity: 0.2
}
})
}, true));
partID++;
}
}
}
function makeClickHandler(hand) {
return function(clicked) {
if (clicked === 1.0) {
triggerSelection();
}
};
}
function projectOntoOverlayXYPlane(overlayID, worldPos) {
var position = Overlays.getProperty(overlayID, "position");
var rotation = Overlays.getProperty(overlayID, "rotation");
var dimensions = Overlays.getProperty(overlayID, "dimensions");
dimensions.z = 0.01; // we are projecting onto the XY plane of the overlay, so ignore the z dimension
var invRot = Quat.inverse(rotation);
var localPos = Vec3.multiplyQbyV(invRot, Vec3.subtract(worldPos, position));
var invDimensions = {
x: 1 / dimensions.x,
y: 1 / dimensions.y,
z: 1 / dimensions.z
};
var normalizedPos = Vec3.sum(Vec3.multiplyVbyV(localPos, invDimensions), DEFAULT_REGISTRATION_POINT);
return {
x: normalizedPos.x * dimensions.x,
y: (1 - normalizedPos.y) * dimensions.y // flip y-axis
};
}
function mousePressOnOverlay(overlayID, event) {
if (overlayID === selectionOverlay && event.id === pointer) {
//print("mousePressOnOverlay event.button " + event.button + " event.pos2D " + event.pos2D.x + " " + event.pos2D.y);
//mousePressEventPos = event.pos2D;
mousePressPickPos2D = projectOntoOverlayXYPlane(selectionOverlay, Pointers.getPrevPickResult(pointer).intersection);
print("mousePressPickPos2D " + mousePressPickPos2D.x + " " + mousePressPickPos2D.y);
}
}
function mouseReleaseOnOverlay(overlayID, event) {
/*
if (overlayID === selectionOverlay && event.id === pointer) {
print("mouseReleaseOnOverlay event.button " + event.button + " event.pos2D " + event.pos2D.x + " " + event.pos2D.y);
var mouseReleaseEventPos = event.pos2D;
var posDifference = Vec3.subtract(mousePressEventPos, mouseReleaseEventPos);
print("posDifference " + posDifference.x + " " + posDifference.y);
}
*/
}
function checkActivation() {
var watchPosition = Entities.getEntityProperties(watchEntity, ['position']).position;
var rightHandPosition = MyAvatar.getJointPosition(RIGHT_HAND_JOINT);
var distance = Vec3.distance(watchPosition, rightHandPosition);
if (watchOpen && distance > DEACTIVATION_DISTANCE && !debugWatchOpen) {
closeWatch();
} else if (!watchOpen && distance < ACTIVATION_DISTANCE) {
openWatch();
}
}
function keyPressEvent(event) {
if (DEBUG_ACTIVATION_KEY === event.key) {
print("WATCH - DEBUG_ACTIVATION_KEY triggered - watchOpen was " + watchOpen);
if (watchOpen) {
closeWatch();
debugWatchOpen = false;
} else {
openWatch();
debugWatchOpen = true;
}
}
}
function update() {
/*
if (watchEntity) {
var handRotation = MyAvatar.getJointRotation(MyAvatar.getJointIndex(LEFT_HAND_JOINT));
var handPosition = MyAvatar.getJointPosition(MyAvatar.getJointIndex(LEFT_HAND_JOINT));
Entities.editEntity(watchEntity, {
position: handPosition,
rotation: handRotation
});
}
*/
if (mousePressPickPos2D) {
var pickResult = Pointers.getPrevPickResult(pointer);
if (pickResult.type === Picks.INTERSECTED_NONE) {
mousePressPickPos2D = null;
} else {
var pickPos2D = projectOntoOverlayXYPlane(selectionOverlay, Pointers.getPrevPickResult(pointer).intersection);
var positionDifference = Vec3.subtract(pickPos2D, mousePressPickPos2D);
var length = Vec3.length(positionDifference);
if (length >= SWIPE_THRESHOLD) {
var xDifference = pickPos2D.x - mousePressPickPos2D.x;
if (xDifference > 0) {
if (selectionIndex > 0) {
selectionIndex--;
Overlays.editOverlay(selectionOverlay, { url: SELECTION_ORDER[selectionIndex]} );
}
print("WATCH - SWIPE LEFT - new selection is " + selectionIndex);
} else {
if (selectionIndex < SELECTION_ORDER.length - 1) {
selectionIndex++;
Overlays.editOverlay(selectionOverlay, { url: SELECTION_ORDER[selectionIndex]} );
}
print("WATCH - SWIPE RIGHT - new selection is " + selectionIndex);
}
mousePressPickPos2D = null;
}
}
}
for (var i = 0; i < materialEntities.length; i++) {
Entities.editEntity(materialEntities[i], { materialMappingPos: { x: Math.cos(t * 0.03), y: Math.sin(t * 0.02) },
materialMappingScale: {x: 2.0 * Math.sin(t * 0.01) + 0.1, y: 2.0 * Math.sin(t * 0.01) + 0.1 } });
t = t + dt;
}
Entities.editEntity(entities[entities.length - 2], {
isEmitting: Audio.inputLevel > 0.01,
emitRate: 70 * Audio.inputLevel
});
Entities.editEntity(entities[entities.length - 1], {
isEmitting: Audio.inputLevel > 0.01,
emitRate: 70 * Audio.inputLevel
});
}
function shutdown() {
closeWatch();
if (watchEntity !== null) {
Entities.deleteEntity(watchEntity);
}
Controller.keyPressEvent.disconnect(keyPressEvent);
}
function startup() {
watchEntity = Entities.addEntity({
collidesWith: "static,dynamic,kinematic,otherAvatar,",
dimensions: {
x: 0.1,
y: 0.1,
z: 0.02
},
name: "Watch Entity",
parentID: MyAvatar.SELF_ID,
//parentJointIndex: MyAvatar.getJointIndex(LEFT_HAND_JOINT),
//localPosition: { x: 0, y: -0.3 * Vec3.distance(MyAvatar.getJointPosition(WATCH_JOINT), MyAvatar.getJointPosition(LEFT_HAND_JOINT)), z: WATCH_Z_OFFSET},
parentJointIndex: MyAvatar.getJointIndex(LEFT_FOREARM_JOINT),
localPosition: { x: 0, y: WATCH_FOREARM_HAND_DISTANCE * Vec3.distance(MyAvatar.getJointPosition(LEFT_FOREARM_JOINT), MyAvatar.getJointPosition(LEFT_HAND_JOINT)), z: WATCH_Z_OFFSET},
modelURL: WATCH_MODEL,
type: "Model"
}, true);
Script.update.connect(update);
activationInterval = Script.setInterval(function() {
checkActivation();
}, ACTIVATION_INTERVAL);
Controller.keyPressEvent.connect(keyPressEvent);
triggerMapping.from(Controller.Standard.RTClick).peek().to(makeClickHandler(Controller.Standard.RightHand));
}
Script.scriptEnding.connect(shutdown);
startup();
}()); // END LOCAL_SCOPE