mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 14:53:24 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into stack-manager
This commit is contained in:
commit
ec6be93938
20 changed files with 246 additions and 752 deletions
assignment-client/src
examples
libraries/script-engine/src
unpublishedScripts
|
@ -223,7 +223,6 @@ void Agent::executeScript() {
|
|||
AvatarData::fromFrame(frame->data, *scriptedAvatar);
|
||||
});
|
||||
|
||||
|
||||
using namespace recording;
|
||||
static const FrameType AUDIO_FRAME_TYPE = Frame::registerFrameType(AudioConstants::AUDIO_FRAME_NAME);
|
||||
Frame::registerFrameHandler(AUDIO_FRAME_TYPE, [this, &scriptedAvatar](Frame::ConstPointer frame) {
|
||||
|
@ -280,6 +279,11 @@ void Agent::executeScript() {
|
|||
setFinished(true);
|
||||
}
|
||||
|
||||
QUuid Agent::getSessionUUID() const {
|
||||
return DependencyManager::get<NodeList>()->getSessionUUID();
|
||||
}
|
||||
|
||||
|
||||
void Agent::setIsAvatar(bool isAvatar) {
|
||||
_isAvatar = isAvatar;
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <QtScript/QScriptEngine>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QUuid>
|
||||
|
||||
#include <EntityEditPacketSender.h>
|
||||
#include <EntityTree.h>
|
||||
|
@ -35,6 +36,8 @@ class Agent : public ThreadedAssignment {
|
|||
Q_PROPERTY(bool isPlayingAvatarSound READ isPlayingAvatarSound)
|
||||
Q_PROPERTY(bool isListeningToAudioStream READ isListeningToAudioStream WRITE setIsListeningToAudioStream)
|
||||
Q_PROPERTY(float lastReceivedAudioLoudness READ getLastReceivedAudioLoudness)
|
||||
Q_PROPERTY(QUuid sessionUUID READ getSessionUUID)
|
||||
|
||||
public:
|
||||
Agent(NLPacket& packet);
|
||||
|
||||
|
@ -47,6 +50,7 @@ public:
|
|||
void setIsListeningToAudioStream(bool isListeningToAudioStream) { _isListeningToAudioStream = isListeningToAudioStream; }
|
||||
|
||||
float getLastReceivedAudioLoudness() const { return _lastReceivedAudioLoudness; }
|
||||
QUuid getSessionUUID() const;
|
||||
|
||||
virtual void aboutToFinish();
|
||||
|
||||
|
|
|
@ -271,7 +271,7 @@ function loadBirds(howMany) {
|
|||
dimensions: { x: BIRD_SIZE, y: BIRD_SIZE, z: BIRD_SIZE },
|
||||
gravity: { x: 0, y: BIRD_GRAVITY, z: 0 },
|
||||
velocity: { x: 0, y: -0.1, z: 0 },
|
||||
linearDamping: LINEAR_DAMPING,
|
||||
damping: LINEAR_DAMPING,
|
||||
collisionsWillMove: true,
|
||||
lifetime: STARTING_LIFETIME,
|
||||
color: colors[whichBird]
|
||||
|
|
|
@ -1,673 +0,0 @@
|
|||
//
|
||||
// bot_procedural.js
|
||||
// hifi
|
||||
//
|
||||
// Created by Ben Arnold on 7/29/2013
|
||||
//
|
||||
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||
//
|
||||
// This is an example script that demonstrates an NPC avatar.
|
||||
//
|
||||
//
|
||||
|
||||
//For procedural walk animation
|
||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||
Script.include(HIFI_PUBLIC_BUCKET + "scripts/acScripts/proceduralAnimationAPI.js");
|
||||
|
||||
var procAnimAPI = new ProcAnimAPI();
|
||||
|
||||
function getRandomFloat(min, max) {
|
||||
return Math.random() * (max - min) + min;
|
||||
}
|
||||
|
||||
function getRandomInt (min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
function printVector(string, vector) {
|
||||
print(string + " " + vector.x + ", " + vector.y + ", " + vector.z);
|
||||
}
|
||||
|
||||
var CHANCE_OF_MOVING = 0.005;
|
||||
var CHANCE_OF_SOUND = 0.005;
|
||||
var CHANCE_OF_HEAD_TURNING = 0.01;
|
||||
var CHANCE_OF_BIG_MOVE = 1.0;
|
||||
|
||||
var isMoving = false;
|
||||
var isTurningHead = false;
|
||||
var isPlayingAudio = false;
|
||||
|
||||
var X_MIN = 0.50;
|
||||
var X_MAX = 15.60;
|
||||
var Z_MIN = 0.50;
|
||||
var Z_MAX = 15.10;
|
||||
var Y_FEET = 0.0;
|
||||
var AVATAR_PELVIS_HEIGHT = 0.84;
|
||||
var Y_PELVIS = Y_FEET + AVATAR_PELVIS_HEIGHT;
|
||||
var MAX_PELVIS_DELTA = 2.5;
|
||||
|
||||
var MOVE_RANGE_SMALL = 3.0;
|
||||
var MOVE_RANGE_BIG = 10.0;
|
||||
var TURN_RANGE = 70.0;
|
||||
var STOP_TOLERANCE = 0.05;
|
||||
var MOVE_RATE = 0.05;
|
||||
var TURN_RATE = 0.2;
|
||||
var HEAD_TURN_RATE = 0.05;
|
||||
var PITCH_RANGE = 15.0;
|
||||
var YAW_RANGE = 35.0;
|
||||
|
||||
var firstPosition = { x: getRandomFloat(X_MIN, X_MAX), y: Y_PELVIS, z: getRandomFloat(Z_MIN, Z_MAX) };
|
||||
var targetPosition = { x: 0, y: 0, z: 0 };
|
||||
var targetOrientation = { x: 0, y: 0, z: 0, w: 0 };
|
||||
var currentOrientation = { x: 0, y: 0, z: 0, w: 0 };
|
||||
var targetHeadPitch = 0.0;
|
||||
var targetHeadYaw = 0.0;
|
||||
|
||||
var basePelvisHeight = 0.0;
|
||||
var pelvisOscillatorPosition = 0.0;
|
||||
var pelvisOscillatorVelocity = 0.0;
|
||||
|
||||
function clamp(val, min, max){
|
||||
return Math.max(min, Math.min(max, val))
|
||||
}
|
||||
|
||||
//Array of all valid bot numbers
|
||||
var validBotNumbers = [];
|
||||
|
||||
// right now we only use bot 63, since many other bots have messed up skeletons and LOD issues
|
||||
var botNumber = 63;//getRandomInt(0, 99);
|
||||
|
||||
var newFaceFilePrefix = "ron";
|
||||
|
||||
var newBodyFilePrefix = "bot" + botNumber;
|
||||
|
||||
// set the face model fst using the bot number
|
||||
// there is no need to change the body model - we're using the default
|
||||
Avatar.faceModelURL = HIFI_PUBLIC_BUCKET + "meshes/" + newFaceFilePrefix + ".fst";
|
||||
Avatar.skeletonModelURL = HIFI_PUBLIC_BUCKET + "meshes/" + newBodyFilePrefix + "_a.fst";
|
||||
Avatar.billboardURL = HIFI_PUBLIC_BUCKET + "meshes/billboards/bot" + botNumber + ".png";
|
||||
|
||||
Agent.isAvatar = true;
|
||||
Agent.isListeningToAudioStream = true;
|
||||
|
||||
// change the avatar's position to the random one
|
||||
Avatar.position = firstPosition;
|
||||
basePelvisHeight = firstPosition.y;
|
||||
printVector("New dancer, position = ", Avatar.position);
|
||||
|
||||
function loadSounds() {
|
||||
var sound_filenames = ["AB1.raw", "Anchorman2.raw", "B1.raw", "B1.raw", "Bale1.raw", "Bandcamp.raw",
|
||||
"Big1.raw", "Big2.raw", "Brian1.raw", "Buster1.raw", "CES1.raw", "CES2.raw", "CES3.raw", "CES4.raw",
|
||||
"Carrie1.raw", "Carrie3.raw", "Charlotte1.raw", "EN1.raw", "EN2.raw", "EN3.raw", "Eugene1.raw", "Francesco1.raw",
|
||||
"Italian1.raw", "Japanese1.raw", "Leigh1.raw", "Lucille1.raw", "Lucille2.raw", "MeanGirls.raw", "Murray2.raw",
|
||||
"Nigel1.raw", "PennyLane.raw", "Pitt1.raw", "Ricardo.raw", "SN.raw", "Sake1.raw", "Samantha1.raw", "Samantha2.raw",
|
||||
"Spicoli1.raw", "Supernatural.raw", "Swearengen1.raw", "TheDude.raw", "Tony.raw", "Triumph1.raw", "Uma1.raw",
|
||||
"Walken1.raw", "Walken2.raw", "Z1.raw", "Z2.raw"
|
||||
];
|
||||
|
||||
var footstep_filenames = ["FootstepW2Left-12db.wav", "FootstepW2Right-12db.wav", "FootstepW3Left-12db.wav", "FootstepW3Right-12db.wav",
|
||||
"FootstepW5Left-12db.wav", "FootstepW5Right-12db.wav"];
|
||||
|
||||
var SOUND_BASE_URL = HIFI_PUBLIC_BUCKET + "sounds/Cocktail+Party+Snippets/Raws/";
|
||||
|
||||
var FOOTSTEP_BASE_URL = HIFI_PUBLIC_BUCKET + "sounds/Footsteps/";
|
||||
|
||||
for (var i = 0; i < sound_filenames.length; i++) {
|
||||
sounds.push(SoundCache.getSound(SOUND_BASE_URL + sound_filenames[i]));
|
||||
}
|
||||
|
||||
for (var i = 0; i < footstep_filenames.length; i++) {
|
||||
footstepSounds.push(SoundCache.getSound(FOOTSTEP_BASE_URL + footstep_filenames[i]));
|
||||
}
|
||||
}
|
||||
|
||||
var sounds = [];
|
||||
var footstepSounds = [];
|
||||
loadSounds();
|
||||
|
||||
|
||||
function playRandomSound() {
|
||||
if (!Agent.isPlayingAvatarSound) {
|
||||
var whichSound = Math.floor((Math.random() * sounds.length));
|
||||
Agent.playAvatarSound(sounds[whichSound]);
|
||||
}
|
||||
}
|
||||
|
||||
function playRandomFootstepSound() {
|
||||
var whichSound = Math.floor((Math.random() * footstepSounds.length));
|
||||
Audio.playSound(footstepSounds[whichSound], {
|
||||
position: Avatar.position,
|
||||
volume: 1.0
|
||||
});
|
||||
}
|
||||
|
||||
// ************************************ Facial Animation **********************************
|
||||
var allBlendShapes = [];
|
||||
var targetBlendCoefficient = [];
|
||||
var currentBlendCoefficient = [];
|
||||
|
||||
//Blendshape constructor
|
||||
function addBlendshapeToPose(pose, shapeIndex, val) {
|
||||
var index = pose.blendShapes.length;
|
||||
pose.blendShapes[index] = {shapeIndex: shapeIndex, val: val };
|
||||
}
|
||||
//The mood of the avatar, determines face. 0 = happy, 1 = angry, 2 = sad.
|
||||
|
||||
//Randomly pick avatar mood. 80% happy, 10% mad 10% sad
|
||||
var randMood = Math.floor(Math.random() * 11);
|
||||
var avatarMood;
|
||||
if (randMood == 0) {
|
||||
avatarMood = 1;
|
||||
} else if (randMood == 2) {
|
||||
avatarMood = 2;
|
||||
} else {
|
||||
avatarMood = 0;
|
||||
}
|
||||
|
||||
var currentExpression = -1;
|
||||
//Face pose constructor
|
||||
var happyPoses = [];
|
||||
|
||||
happyPoses[0] = {blendShapes: []};
|
||||
addBlendshapeToPose(happyPoses[0], 28, 0.7); //MouthSmile_L
|
||||
addBlendshapeToPose(happyPoses[0], 29, 0.7); //MouthSmile_R
|
||||
|
||||
happyPoses[1] = {blendShapes: []};
|
||||
addBlendshapeToPose(happyPoses[1], 28, 1.0); //MouthSmile_L
|
||||
addBlendshapeToPose(happyPoses[1], 29, 1.0); //MouthSmile_R
|
||||
addBlendshapeToPose(happyPoses[1], 21, 0.2); //JawOpen
|
||||
|
||||
happyPoses[2] = {blendShapes: []};
|
||||
addBlendshapeToPose(happyPoses[2], 28, 1.0); //MouthSmile_L
|
||||
addBlendshapeToPose(happyPoses[2], 29, 1.0); //MouthSmile_R
|
||||
addBlendshapeToPose(happyPoses[2], 21, 0.5); //JawOpen
|
||||
addBlendshapeToPose(happyPoses[2], 46, 1.0); //CheekSquint_L
|
||||
addBlendshapeToPose(happyPoses[2], 47, 1.0); //CheekSquint_R
|
||||
addBlendshapeToPose(happyPoses[2], 17, 1.0); //BrowsU_L
|
||||
addBlendshapeToPose(happyPoses[2], 18, 1.0); //BrowsU_R
|
||||
|
||||
var angryPoses = [];
|
||||
|
||||
angryPoses[0] = {blendShapes: []};
|
||||
addBlendshapeToPose(angryPoses[0], 26, 0.6); //MouthFrown_L
|
||||
addBlendshapeToPose(angryPoses[0], 27, 0.6); //MouthFrown_R
|
||||
addBlendshapeToPose(angryPoses[0], 14, 0.6); //BrowsD_L
|
||||
addBlendshapeToPose(angryPoses[0], 15, 0.6); //BrowsD_R
|
||||
|
||||
angryPoses[1] = {blendShapes: []};
|
||||
addBlendshapeToPose(angryPoses[1], 26, 0.9); //MouthFrown_L
|
||||
addBlendshapeToPose(angryPoses[1], 27, 0.9); //MouthFrown_R
|
||||
addBlendshapeToPose(angryPoses[1], 14, 0.9); //BrowsD_L
|
||||
addBlendshapeToPose(angryPoses[1], 15, 0.9); //BrowsD_R
|
||||
|
||||
angryPoses[2] = {blendShapes: []};
|
||||
addBlendshapeToPose(angryPoses[2], 26, 1.0); //MouthFrown_L
|
||||
addBlendshapeToPose(angryPoses[2], 27, 1.0); //MouthFrown_R
|
||||
addBlendshapeToPose(angryPoses[2], 14, 1.0); //BrowsD_L
|
||||
addBlendshapeToPose(angryPoses[2], 15, 1.0); //BrowsD_R
|
||||
addBlendshapeToPose(angryPoses[2], 21, 0.5); //JawOpen
|
||||
addBlendshapeToPose(angryPoses[2], 46, 1.0); //CheekSquint_L
|
||||
addBlendshapeToPose(angryPoses[2], 47, 1.0); //CheekSquint_R
|
||||
|
||||
var sadPoses = [];
|
||||
|
||||
sadPoses[0] = {blendShapes: []};
|
||||
addBlendshapeToPose(sadPoses[0], 26, 0.6); //MouthFrown_L
|
||||
addBlendshapeToPose(sadPoses[0], 27, 0.6); //MouthFrown_R
|
||||
addBlendshapeToPose(sadPoses[0], 16, 0.2); //BrowsU_C
|
||||
addBlendshapeToPose(sadPoses[0], 2, 0.6); //EyeSquint_L
|
||||
addBlendshapeToPose(sadPoses[0], 3, 0.6); //EyeSquint_R
|
||||
|
||||
sadPoses[1] = {blendShapes: []};
|
||||
addBlendshapeToPose(sadPoses[1], 26, 0.9); //MouthFrown_L
|
||||
addBlendshapeToPose(sadPoses[1], 27, 0.9); //MouthFrown_R
|
||||
addBlendshapeToPose(sadPoses[1], 16, 0.6); //BrowsU_C
|
||||
addBlendshapeToPose(sadPoses[1], 2, 0.9); //EyeSquint_L
|
||||
addBlendshapeToPose(sadPoses[1], 3, 0.9); //EyeSquint_R
|
||||
|
||||
sadPoses[2] = {blendShapes: []};
|
||||
addBlendshapeToPose(sadPoses[2], 26, 1.0); //MouthFrown_L
|
||||
addBlendshapeToPose(sadPoses[2], 27, 1.0); //MouthFrown_R
|
||||
addBlendshapeToPose(sadPoses[2], 16, 0.1); //BrowsU_C
|
||||
addBlendshapeToPose(sadPoses[2], 2, 1.0); //EyeSquint_L
|
||||
addBlendshapeToPose(sadPoses[2], 3, 1.0); //EyeSquint_R
|
||||
addBlendshapeToPose(sadPoses[2], 21, 0.3); //JawOpen
|
||||
|
||||
var facePoses = [];
|
||||
facePoses[0] = happyPoses;
|
||||
facePoses[1] = angryPoses;
|
||||
facePoses[2] = sadPoses;
|
||||
|
||||
|
||||
function addBlendShape(s) {
|
||||
allBlendShapes[allBlendShapes.length] = s;
|
||||
}
|
||||
|
||||
//It is imperative that the following blendshapes are all present and are in the correct order
|
||||
addBlendShape("EyeBlink_L"); //0
|
||||
addBlendShape("EyeBlink_R"); //1
|
||||
addBlendShape("EyeSquint_L"); //2
|
||||
addBlendShape("EyeSquint_R"); //3
|
||||
addBlendShape("EyeDown_L"); //4
|
||||
addBlendShape("EyeDown_R"); //5
|
||||
addBlendShape("EyeIn_L"); //6
|
||||
addBlendShape("EyeIn_R"); //7
|
||||
addBlendShape("EyeOpen_L"); //8
|
||||
addBlendShape("EyeOpen_R"); //9
|
||||
addBlendShape("EyeOut_L"); //10
|
||||
addBlendShape("EyeOut_R"); //11
|
||||
addBlendShape("EyeUp_L"); //12
|
||||
addBlendShape("EyeUp_R"); //13
|
||||
addBlendShape("BrowsD_L"); //14
|
||||
addBlendShape("BrowsD_R"); //15
|
||||
addBlendShape("BrowsU_C"); //16
|
||||
addBlendShape("BrowsU_L"); //17
|
||||
addBlendShape("BrowsU_R"); //18
|
||||
addBlendShape("JawFwd"); //19
|
||||
addBlendShape("JawLeft"); //20
|
||||
addBlendShape("JawOpen"); //21
|
||||
addBlendShape("JawChew"); //22
|
||||
addBlendShape("JawRight"); //23
|
||||
addBlendShape("MouthLeft"); //24
|
||||
addBlendShape("MouthRight"); //25
|
||||
addBlendShape("MouthFrown_L"); //26
|
||||
addBlendShape("MouthFrown_R"); //27
|
||||
addBlendShape("MouthSmile_L"); //28
|
||||
addBlendShape("MouthSmile_R"); //29
|
||||
addBlendShape("MouthDimple_L"); //30
|
||||
addBlendShape("MouthDimple_R"); //31
|
||||
addBlendShape("LipsStretch_L"); //32
|
||||
addBlendShape("LipsStretch_R"); //33
|
||||
addBlendShape("LipsUpperClose"); //34
|
||||
addBlendShape("LipsLowerClose"); //35
|
||||
addBlendShape("LipsUpperUp"); //36
|
||||
addBlendShape("LipsLowerDown"); //37
|
||||
addBlendShape("LipsUpperOpen"); //38
|
||||
addBlendShape("LipsLowerOpen"); //39
|
||||
addBlendShape("LipsFunnel"); //40
|
||||
addBlendShape("LipsPucker"); //41
|
||||
addBlendShape("ChinLowerRaise"); //42
|
||||
addBlendShape("ChinUpperRaise"); //43
|
||||
addBlendShape("Sneer"); //44
|
||||
addBlendShape("Puff"); //45
|
||||
addBlendShape("CheekSquint_L"); //46
|
||||
addBlendShape("CheekSquint_R"); //47
|
||||
|
||||
for (var i = 0; i < allBlendShapes.length; i++) {
|
||||
targetBlendCoefficient[i] = 0;
|
||||
currentBlendCoefficient[i] = 0;
|
||||
}
|
||||
|
||||
function setRandomExpression() {
|
||||
|
||||
//Clear all expression data for current expression
|
||||
if (currentExpression != -1) {
|
||||
var expression = facePoses[avatarMood][currentExpression];
|
||||
for (var i = 0; i < expression.blendShapes.length; i++) {
|
||||
targetBlendCoefficient[expression.blendShapes[i].shapeIndex] = 0.0;
|
||||
}
|
||||
}
|
||||
//Get a new current expression
|
||||
currentExpression = Math.floor(Math.random() * facePoses[avatarMood].length);
|
||||
var expression = facePoses[avatarMood][currentExpression];
|
||||
for (var i = 0; i < expression.blendShapes.length; i++) {
|
||||
targetBlendCoefficient[expression.blendShapes[i].shapeIndex] = expression.blendShapes[i].val;
|
||||
}
|
||||
}
|
||||
|
||||
var expressionChangeSpeed = 0.1;
|
||||
function updateBlendShapes(deltaTime) {
|
||||
|
||||
for (var i = 0; i < allBlendShapes.length; i++) {
|
||||
currentBlendCoefficient[i] += (targetBlendCoefficient[i] - currentBlendCoefficient[i]) * expressionChangeSpeed;
|
||||
Avatar.setBlendshape(allBlendShapes[i], currentBlendCoefficient[i]);
|
||||
}
|
||||
}
|
||||
|
||||
var BLINK_SPEED = 0.15;
|
||||
var CHANCE_TO_BLINK = 0.0025;
|
||||
var MAX_BLINK = 0.85;
|
||||
var blink = 0.0;
|
||||
var isBlinking = false;
|
||||
function updateBlinking(deltaTime) {
|
||||
if (isBlinking == false) {
|
||||
if (Math.random() < CHANCE_TO_BLINK) {
|
||||
isBlinking = true;
|
||||
} else {
|
||||
blink -= BLINK_SPEED;
|
||||
if (blink < 0.0) blink = 0.0;
|
||||
}
|
||||
} else {
|
||||
blink += BLINK_SPEED;
|
||||
if (blink > MAX_BLINK) {
|
||||
blink = MAX_BLINK;
|
||||
isBlinking = false;
|
||||
}
|
||||
}
|
||||
|
||||
currentBlendCoefficient[0] = blink;
|
||||
currentBlendCoefficient[1] = blink;
|
||||
targetBlendCoefficient[0] = blink;
|
||||
targetBlendCoefficient[1] = blink;
|
||||
}
|
||||
|
||||
// *************************************************************************************
|
||||
|
||||
//Procedural walk animation using two keyframes
|
||||
//We use a separate array for front and back joints
|
||||
//Pitch, yaw, and roll for the joints
|
||||
var rightAngles = [];
|
||||
var leftAngles = [];
|
||||
//for non mirrored joints such as the spine
|
||||
var middleAngles = [];
|
||||
|
||||
//Actual joint mappings
|
||||
var SHOULDER_JOINT_NUMBER = 15;
|
||||
var ELBOW_JOINT_NUMBER = 16;
|
||||
var JOINT_R_HIP = 1;
|
||||
var JOINT_R_KNEE = 2;
|
||||
var JOINT_L_HIP = 6;
|
||||
var JOINT_L_KNEE = 7;
|
||||
var JOINT_R_ARM = 15;
|
||||
var JOINT_R_FOREARM = 16;
|
||||
var JOINT_L_ARM = 39;
|
||||
var JOINT_L_FOREARM = 40;
|
||||
var JOINT_SPINE = 11;
|
||||
var JOINT_R_FOOT = 3;
|
||||
var JOINT_L_FOOT = 8;
|
||||
var JOINT_R_TOE = 4;
|
||||
var JOINT_L_TOE = 9;
|
||||
|
||||
// ******************************* Animation Is Defined Below *************************************
|
||||
|
||||
var NUM_FRAMES = 2;
|
||||
for (var i = 0; i < NUM_FRAMES; i++) {
|
||||
rightAngles[i] = [];
|
||||
leftAngles[i] = [];
|
||||
middleAngles[i] = [];
|
||||
}
|
||||
//Joint order for actual joint mappings, should be interleaved R,L,R,L,...S,S,S for R = right, L = left, S = single
|
||||
var JOINT_ORDER = [];
|
||||
//*** right / left joints ***
|
||||
var HIP = 0;
|
||||
JOINT_ORDER.push(JOINT_R_HIP);
|
||||
JOINT_ORDER.push(JOINT_L_HIP);
|
||||
var KNEE = 1;
|
||||
JOINT_ORDER.push(JOINT_R_KNEE);
|
||||
JOINT_ORDER.push(JOINT_L_KNEE);
|
||||
var ARM = 2;
|
||||
JOINT_ORDER.push(JOINT_R_ARM);
|
||||
JOINT_ORDER.push(JOINT_L_ARM);
|
||||
var FOREARM = 3;
|
||||
JOINT_ORDER.push(JOINT_R_FOREARM);
|
||||
JOINT_ORDER.push(JOINT_L_FOREARM);
|
||||
var FOOT = 4;
|
||||
JOINT_ORDER.push(JOINT_R_FOOT);
|
||||
JOINT_ORDER.push(JOINT_L_FOOT);
|
||||
var TOE = 5;
|
||||
JOINT_ORDER.push(JOINT_R_TOE);
|
||||
JOINT_ORDER.push(JOINT_L_TOE);
|
||||
//*** middle joints ***
|
||||
var SPINE = 0;
|
||||
JOINT_ORDER.push(JOINT_SPINE);
|
||||
|
||||
//We have to store the angles so we can invert yaw and roll when making the animation
|
||||
//symmetrical
|
||||
|
||||
//Front refers to leg, not arm.
|
||||
//Legs Extending
|
||||
rightAngles[0][HIP] = [30.0, 0.0, 8.0];
|
||||
rightAngles[0][KNEE] = [-15.0, 0.0, 0.0];
|
||||
rightAngles[0][ARM] = [85.0, -25.0, 0.0];
|
||||
rightAngles[0][FOREARM] = [0.0, 0.0, -15.0];
|
||||
rightAngles[0][FOOT] = [0.0, 0.0, 0.0];
|
||||
rightAngles[0][TOE] = [0.0, 0.0, 0.0];
|
||||
|
||||
leftAngles[0][HIP] = [-15, 0.0, 8.0];
|
||||
leftAngles[0][KNEE] = [-26, 0.0, 0.0];
|
||||
leftAngles[0][ARM] = [85.0, 20.0, 0.0];
|
||||
leftAngles[0][FOREARM] = [10.0, 0.0, -25.0];
|
||||
leftAngles[0][FOOT] = [-13.0, 0.0, 0.0];
|
||||
leftAngles[0][TOE] = [34.0, 0.0, 0.0];
|
||||
|
||||
middleAngles[0][SPINE] = [0.0, -15.0, 5.0];
|
||||
|
||||
//Legs Passing
|
||||
rightAngles[1][HIP] = [6.0, 0.0, 8.0];
|
||||
rightAngles[1][KNEE] = [-12.0, 0.0, 0.0];
|
||||
rightAngles[1][ARM] = [85.0, 0.0, 0.0];
|
||||
rightAngles[1][FOREARM] = [0.0, 0.0, -15.0];
|
||||
rightAngles[1][FOOT] = [6.0, -8.0, 0.0];
|
||||
rightAngles[1][TOE] = [0.0, 0.0, 0.0];
|
||||
|
||||
leftAngles[1][HIP] = [10.0, 0.0, 8.0];
|
||||
leftAngles[1][KNEE] = [-60.0, 0.0, 0.0];
|
||||
leftAngles[1][ARM] = [85.0, 0.0, 0.0];
|
||||
leftAngles[1][FOREARM] = [0.0, 0.0, -15.0];
|
||||
leftAngles[1][FOOT] = [0.0, 0.0, 0.0];
|
||||
leftAngles[1][TOE] = [0.0, 0.0, 0.0];
|
||||
|
||||
middleAngles[1][SPINE] = [0.0, 0.0, 0.0];
|
||||
|
||||
//Actual keyframes for the animation
|
||||
var walkKeyFrames = procAnimAPI.generateKeyframes(rightAngles, leftAngles, middleAngles, NUM_FRAMES);
|
||||
|
||||
// ******************************* Animation Is Defined Above *************************************
|
||||
|
||||
// ********************************** Standing Key Frame ******************************************
|
||||
//We don't have to do any mirroring or anything, since this is just a single pose.
|
||||
var rightQuats = [];
|
||||
var leftQuats = [];
|
||||
var middleQuats = [];
|
||||
|
||||
rightQuats[HIP] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 7.0);
|
||||
rightQuats[KNEE] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0);
|
||||
rightQuats[ARM] = Quat.fromPitchYawRollDegrees(85.0, 0.0, 0.0);
|
||||
rightQuats[FOREARM] = Quat.fromPitchYawRollDegrees(0.0, 0.0, -10.0);
|
||||
rightQuats[FOOT] = Quat.fromPitchYawRollDegrees(0.0, -8.0, 0.0);
|
||||
rightQuats[TOE] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0);
|
||||
|
||||
leftQuats[HIP] = Quat.fromPitchYawRollDegrees(0, 0.0, -7.0);
|
||||
leftQuats[KNEE] = Quat.fromPitchYawRollDegrees(0, 0.0, 0.0);
|
||||
leftQuats[ARM] = Quat.fromPitchYawRollDegrees(85.0, 0.0, 0.0);
|
||||
leftQuats[FOREARM] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 10.0);
|
||||
leftQuats[FOOT] = Quat.fromPitchYawRollDegrees(0.0, 8.0, 0.0);
|
||||
leftQuats[TOE] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0);
|
||||
|
||||
middleQuats[SPINE] = Quat.fromPitchYawRollDegrees(0.0, 0.0, 0.0);
|
||||
|
||||
var standingKeyFrame = new procAnimAPI.KeyFrame(rightQuats, leftQuats, middleQuats);
|
||||
|
||||
// ************************************************************************************************
|
||||
|
||||
|
||||
var currentFrame = 0;
|
||||
|
||||
var walkTime = 0.0;
|
||||
|
||||
var walkWheelRadius = 0.5;
|
||||
var walkWheelRate = 2.0 * 3.141592 * walkWheelRadius / 8.0;
|
||||
|
||||
var avatarAcceleration = 0.75;
|
||||
var avatarVelocity = 0.0;
|
||||
var avatarMaxVelocity = 1.4;
|
||||
|
||||
function handleAnimation(deltaTime) {
|
||||
|
||||
updateBlinking(deltaTime);
|
||||
updateBlendShapes(deltaTime);
|
||||
|
||||
if (Math.random() < 0.01) {
|
||||
setRandomExpression();
|
||||
}
|
||||
|
||||
if (avatarVelocity == 0.0) {
|
||||
walkTime = 0.0;
|
||||
currentFrame = 0;
|
||||
} else {
|
||||
walkTime += avatarVelocity * deltaTime;
|
||||
if (walkTime > walkWheelRate) {
|
||||
walkTime = 0.0;
|
||||
currentFrame++;
|
||||
if (currentFrame % 2 == 1) {
|
||||
playRandomFootstepSound();
|
||||
}
|
||||
if (currentFrame > 3) {
|
||||
currentFrame = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var frame = walkKeyFrames[currentFrame];
|
||||
|
||||
var walkInterp = walkTime / walkWheelRate;
|
||||
var animInterp = avatarVelocity / (avatarMaxVelocity / 1.3);
|
||||
if (animInterp > 1.0) animInterp = 1.0;
|
||||
|
||||
for (var i = 0; i < JOINT_ORDER.length; i++) {
|
||||
var walkJoint = procAnimAPI.deCasteljau(frame.rotations[i], frame.nextFrame.rotations[i], frame.controlPoints[i][0], frame.controlPoints[i][1], walkInterp);
|
||||
var standJoint = standingKeyFrame.rotations[i];
|
||||
var finalJoint = Quat.mix(standJoint, walkJoint, animInterp);
|
||||
Avatar.setJointData(JOINT_ORDER[i], finalJoint);
|
||||
}
|
||||
}
|
||||
|
||||
function jumpWithLoudness(deltaTime) {
|
||||
// potentially change pelvis height depending on trailing average loudness
|
||||
|
||||
pelvisOscillatorVelocity += deltaTime * Agent.lastReceivedAudioLoudness * 700.0 ;
|
||||
|
||||
pelvisOscillatorVelocity -= pelvisOscillatorPosition * 0.75;
|
||||
pelvisOscillatorVelocity *= 0.97;
|
||||
pelvisOscillatorPosition += deltaTime * pelvisOscillatorVelocity;
|
||||
Avatar.headPitch = pelvisOscillatorPosition * 60.0;
|
||||
|
||||
var pelvisPosition = Avatar.position;
|
||||
pelvisPosition.y = (Y_PELVIS - 0.35) + pelvisOscillatorPosition;
|
||||
|
||||
if (pelvisPosition.y < Y_PELVIS) {
|
||||
pelvisPosition.y = Y_PELVIS;
|
||||
} else if (pelvisPosition.y > Y_PELVIS + 1.0) {
|
||||
pelvisPosition.y = Y_PELVIS + 1.0;
|
||||
}
|
||||
|
||||
Avatar.position = pelvisPosition;
|
||||
}
|
||||
|
||||
var forcedMove = false;
|
||||
|
||||
var wasMovingLastFrame = false;
|
||||
|
||||
function handleHeadTurn() {
|
||||
if (!isTurningHead && (Math.random() < CHANCE_OF_HEAD_TURNING)) {
|
||||
targetHeadPitch = getRandomFloat(-PITCH_RANGE, PITCH_RANGE);
|
||||
targetHeadYaw = getRandomFloat(-YAW_RANGE, YAW_RANGE);
|
||||
isTurningHead = true;
|
||||
} else {
|
||||
Avatar.headPitch = Avatar.headPitch + (targetHeadPitch - Avatar.headPitch) * HEAD_TURN_RATE;
|
||||
Avatar.headYaw = Avatar.headYaw + (targetHeadYaw - Avatar.headYaw) * HEAD_TURN_RATE;
|
||||
if (Math.abs(Avatar.headPitch - targetHeadPitch) < STOP_TOLERANCE &&
|
||||
Math.abs(Avatar.headYaw - targetHeadYaw) < STOP_TOLERANCE) {
|
||||
isTurningHead = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function stopWalking() {
|
||||
avatarVelocity = 0.0;
|
||||
isMoving = false;
|
||||
}
|
||||
|
||||
var MAX_ATTEMPTS = 40;
|
||||
function handleWalking(deltaTime) {
|
||||
|
||||
if (forcedMove || (!isMoving && Math.random() < CHANCE_OF_MOVING)) {
|
||||
// Set new target location
|
||||
|
||||
var moveRange;
|
||||
if (Math.random() < CHANCE_OF_BIG_MOVE) {
|
||||
moveRange = MOVE_RANGE_BIG;
|
||||
} else {
|
||||
moveRange = MOVE_RANGE_SMALL;
|
||||
}
|
||||
|
||||
//Keep trying new orientations if the desired target location is out of bounds
|
||||
var attempts = 0;
|
||||
do {
|
||||
targetOrientation = Quat.multiply(Avatar.orientation, Quat.angleAxis(getRandomFloat(-TURN_RANGE, TURN_RANGE), { x:0, y:1, z:0 }));
|
||||
var front = Quat.getFront(targetOrientation);
|
||||
|
||||
targetPosition = Vec3.sum(Avatar.position, Vec3.multiply(front, getRandomFloat(0.0, moveRange)));
|
||||
}
|
||||
while ((targetPosition.x < X_MIN || targetPosition.x > X_MAX || targetPosition.z < Z_MIN || targetPosition.z > Z_MAX)
|
||||
&& attempts < MAX_ATTEMPTS);
|
||||
|
||||
targetPosition.x = clamp(targetPosition.x, X_MIN, X_MAX);
|
||||
targetPosition.z = clamp(targetPosition.z, Z_MIN, Z_MAX);
|
||||
targetPosition.y = Y_PELVIS;
|
||||
|
||||
wasMovingLastFrame = true;
|
||||
isMoving = true;
|
||||
forcedMove = false;
|
||||
} else if (isMoving) {
|
||||
|
||||
var targetVector = Vec3.subtract(targetPosition, Avatar.position);
|
||||
var distance = Vec3.length(targetVector);
|
||||
if (distance <= avatarVelocity * deltaTime) {
|
||||
Avatar.position = targetPosition;
|
||||
stopWalking();
|
||||
} else {
|
||||
var direction = Vec3.normalize(targetVector);
|
||||
//Figure out if we should be slowing down
|
||||
var t = avatarVelocity / avatarAcceleration;
|
||||
var d = (avatarVelocity / 2.0) * t;
|
||||
if (distance < d) {
|
||||
avatarVelocity -= avatarAcceleration * deltaTime;
|
||||
if (avatarVelocity <= 0) {
|
||||
stopWalking();
|
||||
}
|
||||
} else {
|
||||
avatarVelocity += avatarAcceleration * deltaTime;
|
||||
if (avatarVelocity > avatarMaxVelocity) avatarVelocity = avatarMaxVelocity;
|
||||
}
|
||||
Avatar.position = Vec3.sum(Avatar.position, Vec3.multiply(direction, avatarVelocity * deltaTime));
|
||||
Avatar.orientation = Quat.mix(Avatar.orientation, targetOrientation, TURN_RATE);
|
||||
|
||||
wasMovingLastFrame = true;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleTalking() {
|
||||
if (Math.random() < CHANCE_OF_SOUND) {
|
||||
playRandomSound();
|
||||
}
|
||||
}
|
||||
|
||||
function changePelvisHeight(newHeight) {
|
||||
var newPosition = Avatar.position;
|
||||
newPosition.y = newHeight;
|
||||
Avatar.position = newPosition;
|
||||
}
|
||||
|
||||
function updateBehavior(deltaTime) {
|
||||
|
||||
if (AvatarList.containsAvatarWithDisplayName("mrdj")) {
|
||||
if (wasMovingLastFrame) {
|
||||
isMoving = false;
|
||||
}
|
||||
|
||||
// we have a DJ, shouldn't we be dancing?
|
||||
jumpWithLoudness(deltaTime);
|
||||
} else {
|
||||
|
||||
// no DJ, let's just chill on the dancefloor - randomly walking and talking
|
||||
handleHeadTurn();
|
||||
handleAnimation(deltaTime);
|
||||
handleWalking(deltaTime);
|
||||
handleTalking();
|
||||
}
|
||||
}
|
||||
|
||||
Script.update.connect(updateBehavior);
|
|
@ -10,7 +10,7 @@
|
|||
//
|
||||
|
||||
// Set the following variables to the values needed
|
||||
var channel = "PlaybackChannel1";
|
||||
var commandChannel = "com.highfidelity.PlaybackChannel1";
|
||||
var clip_url = null;
|
||||
var playFromCurrentLocation = true;
|
||||
var useDisplayName = true;
|
||||
|
@ -18,7 +18,9 @@ var useAttachments = true;
|
|||
var useAvatarModel = true;
|
||||
|
||||
// ID of the agent. Two agents can't have the same ID.
|
||||
var id = 0;
|
||||
var announceIDChannel = "com.highfidelity.playbackAgent.announceID";
|
||||
var UNKNOWN_AGENT_ID = -2;
|
||||
var id = UNKNOWN_AGENT_ID; // unknown until aknowledged
|
||||
|
||||
// Set position/orientation/scale here if playFromCurrentLocation is true
|
||||
Avatar.position = { x:0, y: 0, z: 0 };
|
||||
|
@ -45,7 +47,6 @@ Recording.setPlayerUseHeadModel(false);
|
|||
Recording.setPlayerUseSkeletonModel(useAvatarModel);
|
||||
|
||||
function getAction(channel, message, senderID) {
|
||||
|
||||
if(subscribed) {
|
||||
var command = JSON.parse(message);
|
||||
print("I'm the agent " + id + " and I received this: ID: " + command.id_key + " Action: " + command.action_key + " URL: " + command.clip_url_key);
|
||||
|
@ -53,24 +54,8 @@ function getAction(channel, message, senderID) {
|
|||
if (command.id_key == id || command.id_key == -1) {
|
||||
if (command.action_key === 6) {
|
||||
clip_url = command.clip_url_key;
|
||||
|
||||
// If the id is -1 (broadcast) and the action is 6, in the url should be the performance file
|
||||
// with all the clips recorded in a session (not just the single clip url).
|
||||
// It has to be computed here in order to retrieve the url for the single agent.
|
||||
// Checking the id we can assign the correct url to the correct agent.
|
||||
|
||||
if (command.id_key == -1) {
|
||||
Assets.downloadData(clip_url, function (data) {
|
||||
var myJSONObject = JSON.parse(data);
|
||||
var hash = myJSONObject.results[id].hashATP;
|
||||
});
|
||||
|
||||
Assets.downloadData(hash, function (data) {
|
||||
clip_url = JSON.parse(data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
action = command.action_key;
|
||||
print("That command was for me!");
|
||||
print("My clip is: " + clip_url);
|
||||
|
@ -139,17 +124,41 @@ function getAction(channel, message, senderID) {
|
|||
}
|
||||
|
||||
|
||||
function update(deltaTime) {
|
||||
function update(deltaTime) {
|
||||
|
||||
totalTime += deltaTime;
|
||||
|
||||
if (totalTime > WAIT_FOR_AUDIO_MIXER && !subscribed) {
|
||||
Messages.subscribe(channel);
|
||||
subscribed = true;
|
||||
print("I'm the agent and I am ready to receive!")
|
||||
if (totalTime > WAIT_FOR_AUDIO_MIXER) {
|
||||
if (!subscribed) {
|
||||
Messages.subscribe(commandChannel); // command channel
|
||||
Messages.subscribe(announceIDChannel); // id announce channel
|
||||
subscribed = true;
|
||||
print("I'm the agent and I am ready to receive!");
|
||||
}
|
||||
if (subscribed && id == UNKNOWN_AGENT_ID) {
|
||||
print("sending ready, id:" + id);
|
||||
Messages.sendMessage(announceIDChannel, "ready");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Script.update.connect(update);
|
||||
Messages.messageReceived.connect(getAction);
|
||||
Messages.messageReceived.connect(function (channel, message, senderID) {
|
||||
if (channel == announceIDChannel && message != "ready") {
|
||||
// If I don't yet know if my ID has been recieved, then check to see if the master has acknowledged me
|
||||
if (id == UNKNOWN_AGENT_ID) {
|
||||
var parts = message.split(".");
|
||||
var agentID = parts[0];
|
||||
var agentIndex = parts[1];
|
||||
if (agentID == Agent.sessionUUID) {
|
||||
id = agentIndex;
|
||||
Messages.unsubscribe(announceIDChannel); // id announce channel
|
||||
}
|
||||
}
|
||||
}
|
||||
if (channel == commandChannel) {
|
||||
getAction(channel, message, senderID);
|
||||
}
|
||||
});
|
||||
|
||||
Script.update.connect(update);
|
||||
|
|
|
@ -14,11 +14,16 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
|||
|
||||
var ac_number = 1; // This is the default number of ACs. Their ID need to be unique and between 0 (included) and ac_number (excluded)
|
||||
var names = new Array(); // It is possible to specify the name of the ACs in this array. ACs names ordered by IDs (Default name is "ACx", x = ID + 1))
|
||||
var channel = "PlaybackChannel1";
|
||||
var channel = "com.highfidelity.PlaybackChannel1";
|
||||
var subscribed = false;
|
||||
var clip_url = null;
|
||||
var input_text = null;
|
||||
|
||||
var knownAgents = new Array; // We will add our known agents here when we discover them
|
||||
|
||||
// available playbackAgents will announce their sessionID here.
|
||||
var announceIDChannel = "com.highfidelity.playbackAgent.announceID";
|
||||
|
||||
// Script. DO NOT MODIFY BEYOND THIS LINE.
|
||||
Script.include("../libraries/toolBars.js");
|
||||
|
||||
|
@ -51,8 +56,9 @@ setupPlayback();
|
|||
|
||||
function setupPlayback() {
|
||||
ac_number = Window.prompt("Insert number of agents: ","1");
|
||||
if (ac_number === "" || ac_number === null)
|
||||
if (ac_number === "" || ac_number === null) {
|
||||
ac_number = 1;
|
||||
}
|
||||
Messages.subscribe(channel);
|
||||
subscribed = true;
|
||||
setupToolBars();
|
||||
|
@ -134,7 +140,6 @@ function setupToolBars() {
|
|||
}
|
||||
|
||||
function sendCommand(id, action) {
|
||||
|
||||
if (action === SHOW) {
|
||||
toolBars[id].selectTool(onOffIcon[id], false);
|
||||
toolBars[id].setAlpha(ALPHA_ON, playIcon[id]);
|
||||
|
@ -151,8 +156,9 @@ function sendCommand(id, action) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (id == (toolBars.length - 1))
|
||||
if (id == (toolBars.length - 1)) {
|
||||
id = -1; // Master command becomes broadcast.
|
||||
}
|
||||
|
||||
var message = {
|
||||
id_key: id,
|
||||
|
@ -249,12 +255,30 @@ function scriptEnding() {
|
|||
Overlays.deleteOverlay(nameOverlays[i]);
|
||||
}
|
||||
|
||||
if(subscribed)
|
||||
if (subscribed) {
|
||||
Messages.unsubscribe(channel);
|
||||
}
|
||||
Messages.unsubscribe(announceIDChannel);
|
||||
}
|
||||
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
Script.update.connect(update);
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
||||
|
||||
|
||||
Messages.subscribe(announceIDChannel);
|
||||
Messages.messageReceived.connect(function (channel, message, senderID) {
|
||||
if (channel == announceIDChannel && message == "ready") {
|
||||
// check to see if we know about this agent
|
||||
if (knownAgents.indexOf(senderID) < 0) {
|
||||
var indexOfNewAgent = knownAgents.length;
|
||||
knownAgents[indexOfNewAgent] = senderID;
|
||||
var acknowledgeMessage = senderID + "." + indexOfNewAgent;
|
||||
Messages.sendMessage(announceIDChannel, acknowledgeMessage);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
moveUI();
|
|
@ -16,24 +16,33 @@
|
|||
|
||||
var _this;
|
||||
var isAvatarRecording = false;
|
||||
var channel = "groupRecordingChannel";
|
||||
var startMessage = "RECONDING STARTED";
|
||||
var stopMessage = "RECONDING ENDED";
|
||||
var MASTER_TO_CLIENTS_CHANNEL = "startStopChannel";
|
||||
var CLIENTS_TO_MASTER_CHANNEL = "resultsChannel";
|
||||
var START_MESSAGE = "recordingStarted";
|
||||
var STOP_MESSAGE = "recordingEnded";
|
||||
var PARTICIPATING_MESSAGE = "participatingToRecording";
|
||||
|
||||
function recordingEntity() {
|
||||
_this = this;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
function receivingMessage(channel, message, senderID) {
|
||||
print("message received on channel:" + channel + ", message:" + message + ", senderID:" + senderID);
|
||||
if(message === startMessage) {
|
||||
_this.startRecording();
|
||||
} else if(message === stopMessage) {
|
||||
_this.stopRecording();
|
||||
if (channel === MASTER_TO_CLIENTS_CHANNEL) {
|
||||
print("CLIENT received message:" + message);
|
||||
if (message === START_MESSAGE) {
|
||||
_this.startRecording();
|
||||
} else if (message === STOP_MESSAGE) {
|
||||
_this.stopRecording();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function getClipUrl(url) {
|
||||
Messages.sendMessage(CLIENTS_TO_MASTER_CHANNEL, url); //send back the url to the master
|
||||
print("clip uploaded and url sent to master");
|
||||
};
|
||||
|
||||
recordingEntity.prototype = {
|
||||
|
||||
preload: function (entityID) {
|
||||
|
@ -50,19 +59,19 @@
|
|||
|
||||
enterEntity: function (entityID) {
|
||||
print("entering in the recording area");
|
||||
Messages.subscribe(channel);
|
||||
|
||||
Messages.subscribe(MASTER_TO_CLIENTS_CHANNEL);
|
||||
},
|
||||
|
||||
leaveEntity: function (entityID) {
|
||||
print("leaving the recording area");
|
||||
_this.stopRecording();
|
||||
Messages.unsubscribe(channel);
|
||||
Messages.unsubscribe(MASTER_TO_CLIENTS_CHANNEL);
|
||||
},
|
||||
|
||||
startRecording: function (entityID) {
|
||||
if (!isAvatarRecording) {
|
||||
print("RECORDING STARTED");
|
||||
Messages.sendMessage(CLIENTS_TO_MASTER_CHANNEL, PARTICIPATING_MESSAGE); //tell to master that I'm participating
|
||||
Recording.startRecording();
|
||||
isAvatarRecording = true;
|
||||
}
|
||||
|
@ -73,17 +82,19 @@
|
|||
print("RECORDING ENDED");
|
||||
Recording.stopRecording();
|
||||
isAvatarRecording = false;
|
||||
recordingFile = Window.save("Save recording to file", "./groupRecording", "Recordings (*.hfr)");
|
||||
|
||||
var recordingFile = Window.save("Save recording to file", "./groupRecording", "Recordings (*.hfr)");
|
||||
if (!(recordingFile === "null" || recordingFile === null || recordingFile === "")) {
|
||||
Recording.saveRecording(recordingFile);
|
||||
Recording.saveRecording(recordingFile); //save the clip locally
|
||||
}
|
||||
Recording.saveRecordingToAsset(getClipUrl); //save the clip to the asset and link a callback to get its url
|
||||
}
|
||||
},
|
||||
|
||||
unload: function (entityID) {
|
||||
print("RECORDING ENTITY UNLOAD");
|
||||
_this.stopRecording();
|
||||
Messages.unsubscribe(channel);
|
||||
Messages.unsubscribe(MASTER_TO_CLIENTS_CHANNEL);
|
||||
Messages.messageReceived.disconnect(receivingMessage);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,11 +22,24 @@ var TOOL_ICON_URL = HIFI_PUBLIC_BUCKET + "images/tools/";
|
|||
var ALPHA_ON = 1.0;
|
||||
var ALPHA_OFF = 0.7;
|
||||
var COLOR_TOOL_BAR = { red: 0, green: 0, blue: 0 };
|
||||
var MASTER_TO_CLIENTS_CHANNEL = "startStopChannel";
|
||||
var CLIENTS_TO_MASTER_CHANNEL = "resultsChannel";
|
||||
var START_MESSAGE = "recordingStarted";
|
||||
var STOP_MESSAGE = "recordingEnded";
|
||||
var PARTICIPATING_MESSAGE = "participatingToRecording";
|
||||
var TIMEOUT = 20;
|
||||
|
||||
var toolBar = null;
|
||||
var recordIcon;
|
||||
var isRecording = false;
|
||||
var channel = "groupRecordingChannel";
|
||||
var performanceJSON = { "avatarClips" : [] };
|
||||
var responsesExpected = 0;
|
||||
var waitingForPerformanceFile = true;
|
||||
var totalWaitingTime = 0;
|
||||
var extension = "txt";
|
||||
|
||||
|
||||
Messages.subscribe(CLIENTS_TO_MASTER_CHANNEL);
|
||||
setupToolBar();
|
||||
|
||||
function setupToolBar() {
|
||||
|
@ -55,22 +68,72 @@ function mousePressEvent(event) {
|
|||
if (recordIcon === toolBar.clicked(clickedOverlay, false)) {
|
||||
if (!isRecording) {
|
||||
print("I'm the master. I want to start recording");
|
||||
var message = "RECONDING STARTED";
|
||||
Messages.sendMessage(channel, message);
|
||||
Messages.sendMessage(MASTER_TO_CLIENTS_CHANNEL, START_MESSAGE);
|
||||
isRecording = true;
|
||||
} else {
|
||||
print("I want to stop recording");
|
||||
var message = "RECONDING ENDED";
|
||||
Messages.sendMessage(channel, message);
|
||||
waitingForPerformanceFile = true;
|
||||
Script.update.connect(update);
|
||||
Messages.sendMessage(MASTER_TO_CLIENTS_CHANNEL, STOP_MESSAGE);
|
||||
isRecording = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function masterReceivingMessage(channel, message, senderID) {
|
||||
if (channel === CLIENTS_TO_MASTER_CHANNEL) {
|
||||
print("MASTER received message:" + message );
|
||||
if (message === PARTICIPATING_MESSAGE) {
|
||||
//increment the counter of all the participants
|
||||
responsesExpected++;
|
||||
} else if (waitingForPerformanceFile) {
|
||||
//I get an atp url from one participant
|
||||
performanceJSON.avatarClips[performanceJSON.avatarClips.length] = message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function update(deltaTime) {
|
||||
if (waitingForPerformanceFile) {
|
||||
totalWaitingTime += deltaTime;
|
||||
if (totalWaitingTime > TIMEOUT || performanceJSON.avatarClips.length === responsesExpected) {
|
||||
print("UPLOADING PERFORMANCE FILE");
|
||||
if (performanceJSON.avatarClips.length !== 0) {
|
||||
//I can upload the performance file on the asset
|
||||
Assets.uploadData(JSON.stringify(performanceJSON), extension, uploadFinished);
|
||||
}
|
||||
//clean things after upload performance file to asset
|
||||
waitingForPerformanceFile = false;
|
||||
responsesExpected = 0;
|
||||
totalWaitingTime = 0;
|
||||
Script.update.disconnect(update);
|
||||
performanceJSON = { "avatarClips" : [] };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function uploadFinished(url){
|
||||
//need to print somehow the url here this way the master can copy the url
|
||||
print("PERFORMANCE FILE URL: " + url);
|
||||
Assets.downloadData(url, function (data) {
|
||||
printPerformanceJSON(JSON.parse(data));
|
||||
});
|
||||
}
|
||||
|
||||
function printPerformanceJSON(obj) {
|
||||
print("some info:");
|
||||
print("downloaded performance file from asset and examinating its content...");
|
||||
var avatarClips = obj.avatarClips;
|
||||
avatarClips.forEach(function(param) {
|
||||
print("clip url obtained: " + param);
|
||||
});
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
toolBar.cleanup();
|
||||
Messages.unsubscribe(channel);
|
||||
Messages.unsubscribe(CLIENTS_TO_MASTER_CHANNEL);
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
Messages.messageReceived.connect(masterReceivingMessage);
|
|
@ -76,7 +76,7 @@ var playerSphere = Entities.addEntity({
|
|||
z: 0
|
||||
},
|
||||
collisionsWillMove: true,
|
||||
linearDamping: 0.2
|
||||
damping: 0.2
|
||||
});
|
||||
|
||||
Script.setInterval(function(){
|
||||
|
|
|
@ -41,7 +41,7 @@ var rack = Entities.addEntity({
|
|||
y: -9.8,
|
||||
z: 0
|
||||
},
|
||||
linearDamping: 1,
|
||||
damping: 1,
|
||||
dimensions: {
|
||||
x: 0.4,
|
||||
y: 1.37,
|
||||
|
@ -83,7 +83,7 @@ function createBalls() {
|
|||
z: DIAMETER
|
||||
},
|
||||
restitution: 1.0,
|
||||
linearDamping: 0.00001,
|
||||
damping: 0.00001,
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -9.8,
|
||||
|
|
|
@ -46,7 +46,7 @@ function makeBasketball() {
|
|||
collisionSoundURL: collisionSoundURL,
|
||||
modelURL: basketballURL,
|
||||
restitution: 1.0,
|
||||
linearDamping: 0.00001,
|
||||
damping: 0.00001,
|
||||
shapeType: "sphere"
|
||||
});
|
||||
originalPosition = position;
|
||||
|
|
|
@ -88,7 +88,7 @@ var topBlock = Entities.addEntity({
|
|||
dimensions: blockDimensions,
|
||||
position: topBlock_position,
|
||||
rotation: topBlock_rotation,
|
||||
linearDamping: LINEAR_DAMPING,
|
||||
damping: LINEAR_DAMPING,
|
||||
gravity: BLOCK_GRAVITY,
|
||||
collisionsWillMove: true,
|
||||
velocity: {
|
||||
|
@ -106,7 +106,7 @@ var sideBlock1 = Entities.addEntity({
|
|||
dimensions: blockDimensions,
|
||||
position: sideBlock1_position,
|
||||
rotation: sideBlock1_rotation,
|
||||
linearDamping: LINEAR_DAMPING,
|
||||
damping: LINEAR_DAMPING,
|
||||
gravity: BLOCK_GRAVITY,
|
||||
collisionsWillMove: true
|
||||
});
|
||||
|
@ -120,7 +120,7 @@ var sideBlock2 = Entities.addEntity({
|
|||
position: sideBlock2_position,
|
||||
rotation: sideBlock2_rotation,
|
||||
collsionsWillMove: true,
|
||||
linearDamping: LINEAR_DAMPING,
|
||||
damping: LINEAR_DAMPING,
|
||||
gravity: BLOCK_GRAVITY,
|
||||
collisionsWillMove: true
|
||||
});
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
var BUBBLE_LIFETIME_MAX = 8;
|
||||
var BUBBLE_SIZE_MIN = 0.02;
|
||||
var BUBBLE_SIZE_MAX = 0.1;
|
||||
var BUBBLE_LINEAR_DAMPING = 0.4;
|
||||
var BUBBLE_LINEAR_DAMPING = 0.2;
|
||||
var BUBBLE_GRAVITY_MIN = 0.1;
|
||||
var BUBBLE_GRAVITY_MAX = 0.3;
|
||||
var GROWTH_FACTOR = 0.005;
|
||||
|
@ -163,7 +163,7 @@
|
|||
dimensions: BUBBLE_INITIAL_DIMENSIONS,
|
||||
collisionsWillMove: false,
|
||||
ignoreForCollisions: true,
|
||||
linearDamping: BUBBLE_LINEAR_DAMPING,
|
||||
damping: BUBBLE_LINEAR_DAMPING,
|
||||
shapeType: "sphere"
|
||||
});
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@
|
|||
type:'Sphere',
|
||||
color: BALL_COLOR,
|
||||
dimensions: BALL_DIMENSIONS,
|
||||
linearDamping: BALL_LINEAR_DAMPING,
|
||||
damping: BALL_LINEAR_DAMPING,
|
||||
gravity: BALL_GRAVITY,
|
||||
restitution: BALL_RESTITUTION,
|
||||
collisionsWillMove: true,
|
||||
|
|
|
@ -18,10 +18,18 @@
|
|||
#include <recording/Frame.h>
|
||||
#include <recording/ClipCache.h>
|
||||
|
||||
|
||||
#include <QtScript/QScriptValue>
|
||||
#include <AssetClient.h>
|
||||
#include <AssetUpload.h>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtWidgets/QFileDialog>
|
||||
|
||||
#include "ScriptEngineLogging.h"
|
||||
|
||||
using namespace recording;
|
||||
|
||||
static const QString HFR_EXTENSION = "hfr";
|
||||
|
||||
RecordingScriptingInterface::RecordingScriptingInterface() {
|
||||
_player = DependencyManager::get<Deck>();
|
||||
|
@ -171,6 +179,47 @@ void RecordingScriptingInterface::saveRecording(const QString& filename) {
|
|||
recording::Clip::toFile(filename, _lastClip);
|
||||
}
|
||||
|
||||
bool RecordingScriptingInterface::saveRecordingToAsset(QScriptValue getClipAtpUrl) {
|
||||
if (!getClipAtpUrl.isFunction()) {
|
||||
qCWarning(scriptengine) << "The argument is not a function.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "saveRecordingToAsset", Qt::BlockingQueuedConnection,
|
||||
Q_ARG(QScriptValue, getClipAtpUrl));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_lastClip) {
|
||||
qWarning() << "There is no recording to save";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (auto upload = DependencyManager::get<AssetClient>()->createUpload(recording::Clip::toBuffer(_lastClip), HFR_EXTENSION)) {
|
||||
QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable {
|
||||
QString clip_atp_url = "";
|
||||
|
||||
if (upload->getError() == AssetUpload::NoError) {
|
||||
|
||||
clip_atp_url = QString("%1:%2.%3").arg(URL_SCHEME_ATP, hash, upload->getExtension());
|
||||
upload->deleteLater();
|
||||
} else {
|
||||
qCWarning(scriptengine) << "Error during the Asset upload.";
|
||||
}
|
||||
|
||||
QScriptValueList args;
|
||||
args << clip_atp_url;
|
||||
getClipAtpUrl.call(QScriptValue(), args);
|
||||
});
|
||||
upload->start();
|
||||
return true;
|
||||
}
|
||||
|
||||
qCWarning(scriptengine) << "Saving on asset failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
void RecordingScriptingInterface::loadLastRecording() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "loadLastRecording", Qt::BlockingQueuedConnection);
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include <recording/Forward.h>
|
||||
#include <recording/Frame.h>
|
||||
|
||||
class QScriptValue;
|
||||
|
||||
class RecordingScriptingInterface : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -60,6 +62,7 @@ public slots:
|
|||
float recorderElapsed() const;
|
||||
|
||||
void saveRecording(const QString& filename);
|
||||
bool saveRecordingToAsset(QScriptValue getClipAtpUrl);
|
||||
void loadLastRecording();
|
||||
|
||||
protected:
|
||||
|
|
|
@ -62,7 +62,7 @@ static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine){
|
|||
}
|
||||
message += context->argument(i).toString();
|
||||
}
|
||||
qCDebug(scriptengine) << "script:print()<<" << message;
|
||||
qCDebug(scriptengine).noquote() << "script:print()<<" << message; // noquote() so that \n is treated as newline
|
||||
|
||||
message = message.replace("\\", "\\\\")
|
||||
.replace("\n", "\\n")
|
||||
|
|
|
@ -75,7 +75,7 @@ var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
|||
z: DIAMETER
|
||||
},
|
||||
restitution: 1.0,
|
||||
linearDamping: 0.00001,
|
||||
damping: 0.00001,
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -9.8,
|
||||
|
|
|
@ -253,7 +253,7 @@
|
|||
y: -9.8,
|
||||
z: 0
|
||||
},
|
||||
linearDamping: 1,
|
||||
damping: 1,
|
||||
dimensions: {
|
||||
x: 0.4,
|
||||
y: 1.37,
|
||||
|
@ -301,7 +301,7 @@
|
|||
z: DIAMETER
|
||||
},
|
||||
restitution: 1.0,
|
||||
linearDamping: 0.00001,
|
||||
damping: 0.00001,
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -9.8,
|
||||
|
@ -871,7 +871,7 @@
|
|||
y: -100,
|
||||
z: 0
|
||||
},
|
||||
linearDamping: 1,
|
||||
damping: 1,
|
||||
angularDamping: 10,
|
||||
mass: 10,
|
||||
userData: JSON.stringify({
|
||||
|
@ -990,7 +990,7 @@
|
|||
z: 0
|
||||
},
|
||||
restitution: 10,
|
||||
linearDamping: 0.0,
|
||||
damping: 0.0,
|
||||
velocity: {
|
||||
x: 0,
|
||||
y: -0.01,
|
||||
|
@ -1113,7 +1113,7 @@
|
|||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
linearDamping: 0.4,
|
||||
damping: 0.4,
|
||||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true
|
||||
|
@ -1156,7 +1156,7 @@
|
|||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
linearDamping: 0.2,
|
||||
damping: 0.2,
|
||||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true
|
||||
|
|
|
@ -233,7 +233,7 @@ MasterReset = function() {
|
|||
y: -9.8,
|
||||
z: 0
|
||||
},
|
||||
linearDamping: 1,
|
||||
damping: 1,
|
||||
dimensions: {
|
||||
x: 0.4,
|
||||
y: 1.37,
|
||||
|
@ -282,7 +282,7 @@ MasterReset = function() {
|
|||
z: DIAMETER
|
||||
},
|
||||
restitution: 1.0,
|
||||
linearDamping: 0.00001,
|
||||
damping: 0.00001,
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -9.8,
|
||||
|
@ -853,7 +853,7 @@ MasterReset = function() {
|
|||
y: -100,
|
||||
z: 0
|
||||
},
|
||||
linearDamping: 1,
|
||||
damping: 1,
|
||||
angularDamping: 10,
|
||||
mass: 10,
|
||||
userData: JSON.stringify({
|
||||
|
@ -973,7 +973,7 @@ MasterReset = function() {
|
|||
z: 0
|
||||
},
|
||||
restitution: 10,
|
||||
linearDamping: 0.0,
|
||||
damping: 0.01,
|
||||
velocity: {
|
||||
x: 0,
|
||||
y: -0.01,
|
||||
|
@ -1096,7 +1096,7 @@ MasterReset = function() {
|
|||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
linearDamping: 0.4,
|
||||
damping: 0.4,
|
||||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true
|
||||
|
@ -1139,7 +1139,7 @@ MasterReset = function() {
|
|||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
linearDamping: 0.2,
|
||||
damping: 0.2,
|
||||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true
|
||||
|
|
Loading…
Reference in a new issue