mirror of
https://github.com/overte-org/overte.git
synced 2025-08-07 15:30:38 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into red
This commit is contained in:
commit
b2f6360020
11 changed files with 319 additions and 80 deletions
|
@ -680,11 +680,11 @@ void AudioMixer::domainSettingsRequestComplete() {
|
||||||
void AudioMixer::broadcastMixes() {
|
void AudioMixer::broadcastMixes() {
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
int nextFrame = 0;
|
int64_t nextFrame = 0;
|
||||||
QElapsedTimer timer;
|
QElapsedTimer timer;
|
||||||
timer.start();
|
timer.start();
|
||||||
|
|
||||||
int usecToSleep = AudioConstants::NETWORK_FRAME_USECS;
|
int64_t usecToSleep = AudioConstants::NETWORK_FRAME_USECS;
|
||||||
|
|
||||||
const int TRAILING_AVERAGE_FRAMES = 100;
|
const int TRAILING_AVERAGE_FRAMES = 100;
|
||||||
int framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES;
|
int framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES;
|
||||||
|
@ -826,12 +826,7 @@ void AudioMixer::broadcastMixes() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
usecToSleep = (++nextFrame * AudioConstants::NETWORK_FRAME_USECS) - timer.nsecsElapsed() / 1000; // ns to us
|
usecToSleep = (++nextFrame * AudioConstants::NETWORK_FRAME_USECS) - (timer.nsecsElapsed() / 1000);
|
||||||
|
|
||||||
if (usecToSleep > int(USECS_PER_SECOND)) {
|
|
||||||
qDebug() << "DANGER: amount to sleep is" << usecToSleep;
|
|
||||||
qDebug() << "NextFrame is" << nextFrame << "and timer nsecs elapsed is" << timer.nsecsElapsed();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (usecToSleep > 0) {
|
if (usecToSleep > 0) {
|
||||||
usleep(usecToSleep);
|
usleep(usecToSleep);
|
||||||
|
|
182
examples/FlockOfFish.js
Normal file
182
examples/FlockOfFish.js
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
//
|
||||||
|
// flockOfFish.js
|
||||||
|
// examples
|
||||||
|
//
|
||||||
|
// Philip Rosedale
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
// Fish smimming around in a space in front of you
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
|
||||||
|
|
||||||
|
var LIFETIME = 300; // Fish live for 5 minutes
|
||||||
|
var NUM_FISH = 20;
|
||||||
|
var TANK_WIDTH = 3.0;
|
||||||
|
var TANK_HEIGHT = 1.0;
|
||||||
|
var FISH_WIDTH = 0.03;
|
||||||
|
var FISH_LENGTH = 0.15;
|
||||||
|
var MAX_SIGHT_DISTANCE = 0.8;
|
||||||
|
var MIN_SEPARATION = 0.15;
|
||||||
|
var AVOIDANCE_FORCE = 0.2;
|
||||||
|
var COHESION_FORCE = 0.05;
|
||||||
|
var ALIGNMENT_FORCE = 0.05;
|
||||||
|
var SWIMMING_FORCE = 0.05;
|
||||||
|
var SWIMMING_SPEED = 1.5;
|
||||||
|
|
||||||
|
var fishLoaded = false;
|
||||||
|
var fish = [];
|
||||||
|
|
||||||
|
var lowerCorner = { x: 0, y: 0, z: 0 };
|
||||||
|
var upperCorner = { x: 0, y: 0, z: 0 };
|
||||||
|
|
||||||
|
function randomVector(scale) {
|
||||||
|
return { x: Math.random() * scale - scale / 2.0, y: Math.random() * scale - scale / 2.0, z: Math.random() * scale - scale / 2.0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateFish(deltaTime) {
|
||||||
|
if (!Entities.serversExist() || !Entities.canRez()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!fishLoaded) {
|
||||||
|
loadFish(NUM_FISH);
|
||||||
|
fishLoaded = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var averageVelocity = { x: 0, y: 0, z: 0 };
|
||||||
|
var averagePosition = { x: 0, y: 0, z: 0 };
|
||||||
|
var birdPositionsCounted = 0;
|
||||||
|
var birdVelocitiesCounted = 0;
|
||||||
|
|
||||||
|
// First pre-load an array with properties on all the other fish so our per-fish loop
|
||||||
|
// isn't doing it.
|
||||||
|
var flockProperties = [];
|
||||||
|
for (var i = 0; i < fish.length; i++) {
|
||||||
|
var otherProps = Entities.getEntityProperties(fish[i].entityId, ["position", "velocity", "rotation"]);
|
||||||
|
flockProperties.push(otherProps);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < fish.length; i++) {
|
||||||
|
if (fish[i].entityId) {
|
||||||
|
// Get only the properties we need, because that is faster
|
||||||
|
var properties = flockProperties[i];
|
||||||
|
// If fish has been deleted, bail
|
||||||
|
if (properties.id != fish[i].entityId) {
|
||||||
|
fish[i].entityId = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store old values so we can check if they have changed enough to update
|
||||||
|
var velocity = { x: properties.velocity.x, y: properties.velocity.y, z: properties.velocity.z };
|
||||||
|
var position = { x: properties.position.x, y: properties.position.y, z: properties.position.z };
|
||||||
|
averageVelocity = { x: 0, y: 0, z: 0 };
|
||||||
|
averagePosition = { x: 0, y: 0, z: 0 };
|
||||||
|
|
||||||
|
var othersCounted = 0;
|
||||||
|
for (var j = 0; j < fish.length; j++) {
|
||||||
|
if (i != j) {
|
||||||
|
// Get only the properties we need, because that is faster
|
||||||
|
var otherProps = flockProperties[j];
|
||||||
|
var separation = Vec3.distance(properties.position, otherProps.position);
|
||||||
|
if (separation < MAX_SIGHT_DISTANCE) {
|
||||||
|
averageVelocity = Vec3.sum(averageVelocity, otherProps.velocity);
|
||||||
|
averagePosition = Vec3.sum(averagePosition, otherProps.position);
|
||||||
|
othersCounted++;
|
||||||
|
}
|
||||||
|
if (separation < MIN_SEPARATION) {
|
||||||
|
var pushAway = Vec3.multiply(Vec3.normalize(Vec3.subtract(properties.position, otherProps.position)), AVOIDANCE_FORCE);
|
||||||
|
velocity = Vec3.sum(velocity, pushAway);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (othersCounted > 0) {
|
||||||
|
averageVelocity = Vec3.multiply(averageVelocity, 1.0 / othersCounted);
|
||||||
|
averagePosition = Vec3.multiply(averagePosition, 1.0 / othersCounted);
|
||||||
|
// Alignment: Follow group's direction and speed
|
||||||
|
velocity = Vec3.mix(velocity, Vec3.multiply(Vec3.normalize(averageVelocity), Vec3.length(velocity)), ALIGNMENT_FORCE);
|
||||||
|
// Cohesion: Steer towards center of flock
|
||||||
|
var towardCenter = Vec3.subtract(averagePosition, position);
|
||||||
|
velocity = Vec3.mix(velocity, Vec3.multiply(Vec3.normalize(towardCenter), Vec3.length(velocity)), COHESION_FORCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to swim at a constant speed
|
||||||
|
velocity = Vec3.mix(velocity, Vec3.multiply(Vec3.normalize(velocity), SWIMMING_SPEED), SWIMMING_FORCE);
|
||||||
|
|
||||||
|
// Keep fish in their 'tank'
|
||||||
|
if (position.x < lowerCorner.x) {
|
||||||
|
position.x = lowerCorner.x;
|
||||||
|
velocity.x *= -1.0;
|
||||||
|
} else if (position.x > upperCorner.x) {
|
||||||
|
position.x = upperCorner.x;
|
||||||
|
velocity.x *= -1.0;
|
||||||
|
}
|
||||||
|
if (position.y < lowerCorner.y) {
|
||||||
|
position.y = lowerCorner.y;
|
||||||
|
velocity.y *= -1.0;
|
||||||
|
} else if (position.y > upperCorner.y) {
|
||||||
|
position.y = upperCorner.y;
|
||||||
|
velocity.y *= -1.0;
|
||||||
|
}
|
||||||
|
if (position.z < lowerCorner.z) {
|
||||||
|
position.z = lowerCorner.z;
|
||||||
|
velocity.z *= -1.0;
|
||||||
|
} else if (position.z > upperCorner.z) {
|
||||||
|
position.z = upperCorner.z;
|
||||||
|
velocity.z *= -1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Orient in direction of velocity
|
||||||
|
var rotation = Quat.rotationBetween(Vec3.UNIT_NEG_Z, velocity);
|
||||||
|
var VELOCITY_FOLLOW_RATE = 0.30;
|
||||||
|
|
||||||
|
// Only update properties if they have changed, to save bandwidth
|
||||||
|
var MIN_POSITION_CHANGE_FOR_UPDATE = 0.001;
|
||||||
|
if (Vec3.distance(properties.position, position) < MIN_POSITION_CHANGE_FOR_UPDATE) {
|
||||||
|
Entities.editEntity(fish[i].entityId, { velocity: velocity, rotation: Quat.mix(properties.rotation, rotation, VELOCITY_FOLLOW_RATE) });
|
||||||
|
} else {
|
||||||
|
Entities.editEntity(fish[i].entityId, { position: position, velocity: velocity, rotation: Quat.slerp(properties.rotation, rotation, VELOCITY_FOLLOW_RATE) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect a call back that happens every frame
|
||||||
|
Script.update.connect(updateFish);
|
||||||
|
|
||||||
|
// Delete our little friends if script is stopped
|
||||||
|
Script.scriptEnding.connect(function() {
|
||||||
|
for (var i = 0; i < fish.length; i++) {
|
||||||
|
Entities.deleteEntity(fish[i].entityId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var STARTING_FRACTION = 0.25;
|
||||||
|
function loadFish(howMany) {
|
||||||
|
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), 2 * TANK_WIDTH));
|
||||||
|
lowerCorner = { x: center.x - TANK_WIDTH / 2, y: center.y, z: center.z - TANK_WIDTH / 2 };
|
||||||
|
upperCorner = { x: center.x + TANK_WIDTH / 2, y: center.y + TANK_HEIGHT, z: center.z + TANK_WIDTH / 2 };
|
||||||
|
|
||||||
|
for (var i = 0; i < howMany; i++) {
|
||||||
|
var position = {
|
||||||
|
x: lowerCorner.x + (upperCorner.x - lowerCorner.x) / 2.0 + (Math.random() - 0.5) * (upperCorner.x - lowerCorner.x) * STARTING_FRACTION,
|
||||||
|
y: lowerCorner.y + (upperCorner.y - lowerCorner.y) / 2.0 + (Math.random() - 0.5) * (upperCorner.y - lowerCorner.y) * STARTING_FRACTION,
|
||||||
|
z: lowerCorner.z + (upperCorner.z - lowerCorner.x) / 2.0 + (Math.random() - 0.5) * (upperCorner.z - lowerCorner.z) * STARTING_FRACTION
|
||||||
|
};
|
||||||
|
|
||||||
|
fish.push({
|
||||||
|
entityId: Entities.addEntity({
|
||||||
|
type: "Box",
|
||||||
|
position: position,
|
||||||
|
rotation: { x: 0, y: 0, z: 0, w: 1 },
|
||||||
|
dimensions: { x: FISH_WIDTH, y: FISH_WIDTH, z: FISH_LENGTH },
|
||||||
|
velocity: { x: SWIMMING_SPEED, y: SWIMMING_SPEED, z: SWIMMING_SPEED },
|
||||||
|
damping: 0.0,
|
||||||
|
dynamic: false,
|
||||||
|
lifetime: LIFETIME,
|
||||||
|
color: { red: 0, green: 255, blue: 255 }
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
// The rectangular area in the domain where the flock will fly
|
// The rectangular area in the domain where the flock will fly
|
||||||
var lowerCorner = { x: 0, y: 0, z: 0 };
|
var lowerCorner = { x: 0, y: 0, z: 0 };
|
||||||
var upperCorner = { x: 10, y: 10, z: 10 };
|
var upperCorner = { x: 30, y: 10, z: 30 };
|
||||||
var STARTING_FRACTION = 0.25;
|
var STARTING_FRACTION = 0.25;
|
||||||
|
|
||||||
var NUM_BIRDS = 50;
|
var NUM_BIRDS = 50;
|
||||||
|
@ -36,7 +36,7 @@ var ALIGNMENT_FORCE = 1.5;
|
||||||
var COHESION_FORCE = 1.0;
|
var COHESION_FORCE = 1.0;
|
||||||
var MAX_COHESION_VELOCITY = 0.5;
|
var MAX_COHESION_VELOCITY = 0.5;
|
||||||
|
|
||||||
var followBirds = true;
|
var followBirds = false;
|
||||||
var AVATAR_FOLLOW_RATE = 0.001;
|
var AVATAR_FOLLOW_RATE = 0.001;
|
||||||
var AVATAR_FOLLOW_VELOCITY_TIMESCALE = 2.0;
|
var AVATAR_FOLLOW_VELOCITY_TIMESCALE = 2.0;
|
||||||
var AVATAR_FOLLOW_ORIENTATION_RATE = 0.005;
|
var AVATAR_FOLLOW_ORIENTATION_RATE = 0.005;
|
||||||
|
|
|
@ -41,6 +41,8 @@ var PICK_WITH_HAND_RAY = true;
|
||||||
|
|
||||||
var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object
|
var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object
|
||||||
var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position
|
var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position
|
||||||
|
var DISTANCE_HOLDING_UNITY_MASS = 1200; // The mass at which the distance holding action timeframe is unmodified
|
||||||
|
var DISTANCE_HOLDING_UNITY_DISTANCE = 6; // The distance at which the distance holding action timeframe is unmodified
|
||||||
var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did
|
var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did
|
||||||
var MOVE_WITH_HEAD = true; // experimental head-control of distantly held objects
|
var MOVE_WITH_HEAD = true; // experimental head-control of distantly held objects
|
||||||
var FAR_TO_NEAR_GRAB_PADDING_FACTOR = 1.2;
|
var FAR_TO_NEAR_GRAB_PADDING_FACTOR = 1.2;
|
||||||
|
@ -114,7 +116,9 @@ var GRABBABLE_PROPERTIES = [
|
||||||
"name",
|
"name",
|
||||||
"shapeType",
|
"shapeType",
|
||||||
"parentID",
|
"parentID",
|
||||||
"parentJointIndex"
|
"parentJointIndex",
|
||||||
|
"density",
|
||||||
|
"dimensions"
|
||||||
];
|
];
|
||||||
|
|
||||||
var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js
|
var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js
|
||||||
|
@ -295,7 +299,7 @@ function MyController(hand) {
|
||||||
this.rawBumperValue = 0;
|
this.rawBumperValue = 0;
|
||||||
//for visualizations
|
//for visualizations
|
||||||
this.overlayLine = null;
|
this.overlayLine = null;
|
||||||
this.particleBeam = null;
|
this.particleBeamObject = null;
|
||||||
|
|
||||||
//for lights
|
//for lights
|
||||||
this.spotlight = null;
|
this.spotlight = null;
|
||||||
|
@ -479,34 +483,32 @@ function MyController(hand) {
|
||||||
this.handleDistantParticleBeam = function(handPosition, objectPosition, color) {
|
this.handleDistantParticleBeam = function(handPosition, objectPosition, color) {
|
||||||
|
|
||||||
var handToObject = Vec3.subtract(objectPosition, handPosition);
|
var handToObject = Vec3.subtract(objectPosition, handPosition);
|
||||||
var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject);
|
var finalRotationObject = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject);
|
||||||
|
|
||||||
var distance = Vec3.distance(handPosition, objectPosition);
|
var distance = Vec3.distance(handPosition, objectPosition);
|
||||||
var speed = 5;
|
var speed = distance * 3;
|
||||||
var spread = 0;
|
var spread = 0;
|
||||||
|
|
||||||
var lifespan = distance / speed;
|
var lifespan = distance / speed;
|
||||||
|
|
||||||
if (this.particleBeam === null) {
|
if (this.particleBeamObject === null) {
|
||||||
this.createParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan);
|
this.createParticleBeam(objectPosition, finalRotationObject, color, speed, spread, lifespan);
|
||||||
} else {
|
} else {
|
||||||
this.updateParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan);
|
this.updateParticleBeam(objectPosition, finalRotationObject, color, speed, spread, lifespan);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.createParticleBeam = function(position, orientation, color, speed, spread, lifespan) {
|
this.createParticleBeam = function(positionObject, orientationObject, color, speed, spread, lifespan) {
|
||||||
|
|
||||||
var particleBeamProperties = {
|
var particleBeamPropertiesObject = {
|
||||||
type: "ParticleEffect",
|
type: "ParticleEffect",
|
||||||
isEmitting: true,
|
isEmitting: true,
|
||||||
position: position,
|
position: positionObject,
|
||||||
visible: false,
|
visible: false,
|
||||||
lifetime: 60,
|
lifetime: 60,
|
||||||
"name": "Particle Beam",
|
"name": "Particle Beam",
|
||||||
"color": color,
|
"color": color,
|
||||||
"maxParticles": 2000,
|
"maxParticles": 2000,
|
||||||
"lifespan": lifespan,
|
"lifespan": lifespan,
|
||||||
"emitRate": 50,
|
"emitRate": 1000,
|
||||||
"emitSpeed": speed,
|
"emitSpeed": speed,
|
||||||
"speedSpread": spread,
|
"speedSpread": spread,
|
||||||
"emitOrientation": {
|
"emitOrientation": {
|
||||||
|
@ -544,26 +546,25 @@ function MyController(hand) {
|
||||||
"additiveBlending": 0,
|
"additiveBlending": 0,
|
||||||
"textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png"
|
"textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png"
|
||||||
}
|
}
|
||||||
|
|
||||||
this.particleBeam = Entities.addEntity(particleBeamProperties);
|
this.particleBeamObject = Entities.addEntity(particleBeamPropertiesObject);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.updateParticleBeam = function(position, orientation, color, speed, spread, lifespan) {
|
this.updateParticleBeam = function(positionObject, orientationObject, color, speed, spread, lifespan) {
|
||||||
Entities.editEntity(this.particleBeam, {
|
Entities.editEntity(this.particleBeamObject, {
|
||||||
rotation: orientation,
|
rotation: orientationObject,
|
||||||
position: position,
|
position: positionObject,
|
||||||
visible: true,
|
visible: true,
|
||||||
color: color,
|
color: color,
|
||||||
emitSpeed: speed,
|
emitSpeed: speed,
|
||||||
speedSpread: spread,
|
speedSpread: spread,
|
||||||
lifespan: lifespan
|
lifespan: lifespan
|
||||||
})
|
})
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.renewParticleBeamLifetime = function() {
|
this.renewParticleBeamLifetime = function() {
|
||||||
var props = Entities.getEntityProperties(this.particleBeam, "age");
|
var props = Entities.getEntityProperties(this.particleBeamObject, "age");
|
||||||
Entities.editEntity(this.particleBeam, {
|
Entities.editEntity(this.particleBeamObject, {
|
||||||
lifetime: TEMPORARY_PARTICLE_BEAM_LIFETIME + props.age // renew lifetime
|
lifetime: TEMPORARY_PARTICLE_BEAM_LIFETIME + props.age // renew lifetime
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -684,9 +685,9 @@ function MyController(hand) {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.particleBeamOff = function() {
|
this.particleBeamOff = function() {
|
||||||
if (this.particleBeam !== null) {
|
if (this.particleBeamObject !== null) {
|
||||||
Entities.deleteEntity(this.particleBeam);
|
Entities.deleteEntity(this.particleBeamObject);
|
||||||
this.particleBeam = null;
|
this.particleBeamObject = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -864,6 +865,7 @@ function MyController(hand) {
|
||||||
// too far away, don't grab
|
// too far away, don't grab
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (distance < minDistance) {
|
if (distance < minDistance) {
|
||||||
this.grabbedEntity = candidateEntities[i];
|
this.grabbedEntity = candidateEntities[i];
|
||||||
minDistance = distance;
|
minDistance = distance;
|
||||||
|
@ -932,6 +934,18 @@ function MyController(hand) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.distanceGrabTimescale = function(mass, distance) {
|
||||||
|
var timeScale = DISTANCE_HOLDING_ACTION_TIMEFRAME * mass / DISTANCE_HOLDING_UNITY_MASS * distance / DISTANCE_HOLDING_UNITY_DISTANCE;
|
||||||
|
if (timeScale < DISTANCE_HOLDING_ACTION_TIMEFRAME) {
|
||||||
|
timeScale = DISTANCE_HOLDING_ACTION_TIMEFRAME;
|
||||||
|
}
|
||||||
|
return timeScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getMass = function(dimensions, density) {
|
||||||
|
return (dimensions.x * dimensions.y * dimensions.z) * density;
|
||||||
|
}
|
||||||
|
|
||||||
this.distanceHolding = function() {
|
this.distanceHolding = function() {
|
||||||
var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition;
|
var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition;
|
||||||
var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
|
var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
|
||||||
|
@ -953,12 +967,17 @@ function MyController(hand) {
|
||||||
this.radiusScalar = 1.0;
|
this.radiusScalar = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// compute the mass for the purpose of energy and how quickly to move object
|
||||||
|
this.mass = this.getMass(grabbedProperties.dimensions, grabbedProperties.density);
|
||||||
|
var distanceToObject = Vec3.length(Vec3.subtract(MyAvatar.position, grabbedProperties.position));
|
||||||
|
var timeScale = this.distanceGrabTimescale(this.mass, distanceToObject);
|
||||||
|
|
||||||
this.actionID = NULL_UUID;
|
this.actionID = NULL_UUID;
|
||||||
this.actionID = Entities.addAction("spring", this.grabbedEntity, {
|
this.actionID = Entities.addAction("spring", this.grabbedEntity, {
|
||||||
targetPosition: this.currentObjectPosition,
|
targetPosition: this.currentObjectPosition,
|
||||||
linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
|
linearTimeScale: timeScale,
|
||||||
targetRotation: this.currentObjectRotation,
|
targetRotation: this.currentObjectRotation,
|
||||||
angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
|
angularTimeScale: timeScale,
|
||||||
tag: getTag(),
|
tag: getTag(),
|
||||||
ttl: ACTION_TTL
|
ttl: ACTION_TTL
|
||||||
});
|
});
|
||||||
|
@ -1135,11 +1154,12 @@ function MyController(hand) {
|
||||||
this.handleSpotlight(this.grabbedEntity);
|
this.handleSpotlight(this.grabbedEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var distanceToObject = Vec3.length(Vec3.subtract(MyAvatar.position, this.currentObjectPosition));
|
||||||
var success = Entities.updateAction(this.grabbedEntity, this.actionID, {
|
var success = Entities.updateAction(this.grabbedEntity, this.actionID, {
|
||||||
targetPosition: targetPosition,
|
targetPosition: targetPosition,
|
||||||
linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
|
linearTimeScale: this.distanceGrabTimescale(this.mass, distanceToObject),
|
||||||
targetRotation: this.currentObjectRotation,
|
targetRotation: this.currentObjectRotation,
|
||||||
angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
|
angularTimeScale: this.distanceGrabTimescale(this.mass, distanceToObject),
|
||||||
ttl: ACTION_TTL
|
ttl: ACTION_TTL
|
||||||
});
|
});
|
||||||
if (success) {
|
if (success) {
|
||||||
|
@ -1607,7 +1627,7 @@ function MyController(hand) {
|
||||||
|
|
||||||
this.cleanup = function() {
|
this.cleanup = function() {
|
||||||
this.release();
|
this.release();
|
||||||
Entities.deleteEntity(this.particleBeam);
|
Entities.deleteEntity(this.particleBeamObject);
|
||||||
Entities.deleteEntity(this.spotLight);
|
Entities.deleteEntity(this.spotLight);
|
||||||
Entities.deleteEntity(this.pointLight);
|
Entities.deleteEntity(this.pointLight);
|
||||||
};
|
};
|
||||||
|
|
|
@ -976,6 +976,42 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="section-header text-section">
|
||||||
|
<label>Text</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-section property">
|
||||||
|
<div class="label">Text Content</div>
|
||||||
|
<div class="value">
|
||||||
|
<input type="text" id="property-text-text">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-section property">
|
||||||
|
<div class="label">Line Height</div>
|
||||||
|
<div class="value">
|
||||||
|
<input class="coord" type='number' id="property-text-line-height" min="0" step="0.005">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-section property">
|
||||||
|
<div class="label">Text Color</div>
|
||||||
|
<div class="value">
|
||||||
|
<div class='color-picker' id="property-text-text-color"></div>
|
||||||
|
<div class="input-area">R <input class="coord" type='number' id="property-text-text-color-red"></div>
|
||||||
|
<div class="input-area">G <input class="coord" type='number' id="property-text-text-color-green"></div>
|
||||||
|
<div class="input-area">B <input class="coord" type='number' id="property-text-text-color-blue"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-section property">
|
||||||
|
<div class="label">Background Color</div>
|
||||||
|
<div class="value">
|
||||||
|
<div class='color-picker' id="property-text-background-color"></div>
|
||||||
|
<div class="input-area">R <input class="coord" type='number' id="property-text-background-color-red"></div>
|
||||||
|
<div class="input-area">G <input class="coord" type='number' id="property-text-background-color-green"></div>
|
||||||
|
<div class="input-area">B <input class="coord" type='number' id="property-text-background-color-blue"></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="section-header zone-section">
|
<div class="section-header zone-section">
|
||||||
<label>Zone</label>
|
<label>Zone</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1088,8 +1124,6 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="sub-section-header zone-section skybox-section">
|
<div class="sub-section-header zone-section skybox-section">
|
||||||
<label>Skybox</label>
|
<label>Skybox</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1103,10 +1137,13 @@
|
||||||
<div class="input-area">B <input class="coord" type='number' id="property-zone-skybox-color-blue"></div>
|
<div class="input-area">B <input class="coord" type='number' id="property-zone-skybox-color-blue"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="zone-section skybox-section property">
|
<div class="zone-section skybox-section property">
|
||||||
<div class="label">Skybox URL</div>
|
<div class="label">Skybox URL</div>
|
||||||
<div class="value">
|
<div class="value">
|
||||||
<input type="text" id="property-zone-skybox-url" class="url">
|
<input type="text" id="property-zone-skybox-url" class="url">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="section-header web-section">
|
<div class="section-header web-section">
|
||||||
<label>Web</label>
|
<label>Web</label>
|
||||||
|
@ -1497,41 +1534,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="section-header text-section">
|
|
||||||
<label>Text</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-section property">
|
|
||||||
<div class="label">Text Content</div>
|
|
||||||
<div class="value">
|
|
||||||
<input type="text" id="property-text-text">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="text-section property">
|
|
||||||
<div class="label">Line Height</div>
|
|
||||||
<div class="value">
|
|
||||||
<input class="coord" type='number' id="property-text-line-height" min="0" step="0.005">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="text-section property">
|
|
||||||
<div class="label">Text Color</div>
|
|
||||||
<div class="value">
|
|
||||||
<div class='color-picker' id="property-text-text-color"></div>
|
|
||||||
<div class="input-area">R <input class="coord" type='number' id="property-text-text-color-red"></div>
|
|
||||||
<div class="input-area">G <input class="coord" type='number' id="property-text-text-color-green"></div>
|
|
||||||
<div class="input-area">B <input class="coord" type='number' id="property-text-text-color-blue"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="text-section property">
|
|
||||||
<div class="label">Background Color</div>
|
|
||||||
<div class="value">
|
|
||||||
<div class='color-picker' id="property-text-background-color"></div>
|
|
||||||
<div class="input-area">R <input class="coord" type='number' id="property-text-background-color-red"></div>
|
|
||||||
<div class="input-area">G <input class="coord" type='number' id="property-text-background-color-green"></div>
|
|
||||||
<div class="input-area">B <input class="coord" type='number' id="property-text-background-color-blue"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="section-header light-section">
|
<div class="section-header light-section">
|
||||||
<label>Light</label>
|
<label>Light</label>
|
||||||
|
|
|
@ -102,6 +102,11 @@ void AudioInjector::restart() {
|
||||||
// reset the current send offset to zero
|
// reset the current send offset to zero
|
||||||
_currentSendOffset = 0;
|
_currentSendOffset = 0;
|
||||||
|
|
||||||
|
// reset state to start sending from beginning again
|
||||||
|
_nextFrame = 0;
|
||||||
|
_frameTimer->invalidate();
|
||||||
|
_hasSentFirstFrame = false;
|
||||||
|
|
||||||
// check our state to decide if we need extra handling for the restart request
|
// check our state to decide if we need extra handling for the restart request
|
||||||
if (_state == State::Finished) {
|
if (_state == State::Finished) {
|
||||||
// we finished playing, need to reset state so we can get going again
|
// we finished playing, need to reset state so we can get going again
|
||||||
|
@ -246,6 +251,11 @@ int64_t AudioInjector::injectNextFrame() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_frameTimer->isValid()) {
|
||||||
|
// in the case where we have been restarted, the frame timer will be invalid and we need to start it back over here
|
||||||
|
_frameTimer->restart();
|
||||||
|
}
|
||||||
|
|
||||||
int totalBytesLeftToCopy = (_options.stereo ? 2 : 1) * AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL;
|
int totalBytesLeftToCopy = (_options.stereo ? 2 : 1) * AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL;
|
||||||
if (!_options.loop) {
|
if (!_options.loop) {
|
||||||
// If we aren't looping, let's make sure we don't read past the end
|
// If we aren't looping, let's make sure we don't read past the end
|
||||||
|
|
|
@ -79,6 +79,12 @@ void AudioInjectorManager::run() {
|
||||||
if (_injectors.size() > 0) {
|
if (_injectors.size() > 0) {
|
||||||
// loop through the injectors in the map and send whatever frames need to go out
|
// loop through the injectors in the map and send whatever frames need to go out
|
||||||
auto front = _injectors.top();
|
auto front = _injectors.top();
|
||||||
|
|
||||||
|
// create an InjectorQueue to hold injectors to be queued
|
||||||
|
// this allows us to call processEvents even if a single injector wants to be re-queued immediately
|
||||||
|
std::vector<TimeInjectorPointerPair> heldInjectors;
|
||||||
|
heldInjectors.reserve(_injectors.size());
|
||||||
|
|
||||||
while (_injectors.size() > 0 && front.first <= usecTimestampNow()) {
|
while (_injectors.size() > 0 && front.first <= usecTimestampNow()) {
|
||||||
// either way we're popping this injector off - get a copy first
|
// either way we're popping this injector off - get a copy first
|
||||||
auto injector = front.second;
|
auto injector = front.second;
|
||||||
|
@ -89,8 +95,8 @@ void AudioInjectorManager::run() {
|
||||||
auto nextCallDelta = injector->injectNextFrame();
|
auto nextCallDelta = injector->injectNextFrame();
|
||||||
|
|
||||||
if (nextCallDelta >= 0 && !injector->isFinished()) {
|
if (nextCallDelta >= 0 && !injector->isFinished()) {
|
||||||
// re-enqueue the injector with the correct timing
|
// enqueue the injector with the correct timing in our holding queue
|
||||||
_injectors.emplace(usecTimestampNow() + nextCallDelta, injector);
|
heldInjectors.emplace(heldInjectors.end(), usecTimestampNow() + nextCallDelta, injector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +107,12 @@ void AudioInjectorManager::run() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if there are injectors in the holding queue, push them to our persistent queue now
|
||||||
|
while (!heldInjectors.empty()) {
|
||||||
|
_injectors.push(heldInjectors.back());
|
||||||
|
heldInjectors.pop_back();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -490,6 +490,9 @@ void NodeList::processDomainServerList(QSharedPointer<ReceivedMessage> message)
|
||||||
// this is a packet from the domain server, reset the count of un-replied check-ins
|
// this is a packet from the domain server, reset the count of un-replied check-ins
|
||||||
_numNoReplyDomainCheckIns = 0;
|
_numNoReplyDomainCheckIns = 0;
|
||||||
|
|
||||||
|
// emit our signal so listeners know we just heard from the DS
|
||||||
|
emit receivedDomainServerList();
|
||||||
|
|
||||||
DependencyManager::get<NodeList>()->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::ReceiveDSList);
|
DependencyManager::get<NodeList>()->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::ReceiveDSList);
|
||||||
|
|
||||||
QDataStream packetStream(message->getMessage());
|
QDataStream packetStream(message->getMessage());
|
||||||
|
|
|
@ -87,6 +87,7 @@ public slots:
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void limitOfSilentDomainCheckInsReached();
|
void limitOfSilentDomainCheckInsReached();
|
||||||
|
void receivedDomainServerList();
|
||||||
private slots:
|
private slots:
|
||||||
void stopKeepalivePingTimer();
|
void stopKeepalivePingTimer();
|
||||||
void sendPendingDSPathQuery();
|
void sendPendingDSPathQuery();
|
||||||
|
|
|
@ -30,6 +30,10 @@ ThreadedAssignment::ThreadedAssignment(ReceivedMessage& message) :
|
||||||
|
|
||||||
connect(&_domainServerTimer, &QTimer::timeout, this, &ThreadedAssignment::checkInWithDomainServerOrExit);
|
connect(&_domainServerTimer, &QTimer::timeout, this, &ThreadedAssignment::checkInWithDomainServerOrExit);
|
||||||
_domainServerTimer.setInterval(DOMAIN_SERVER_CHECK_IN_MSECS);
|
_domainServerTimer.setInterval(DOMAIN_SERVER_CHECK_IN_MSECS);
|
||||||
|
|
||||||
|
// if the NL tells us we got a DS response, clear our member variable of queued check-ins
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
connect(nodeList.data(), &NodeList::receivedDomainServerList, this, &ThreadedAssignment::clearQueuedCheckIns);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadedAssignment::setFinished(bool isFinished) {
|
void ThreadedAssignment::setFinished(bool isFinished) {
|
||||||
|
@ -103,11 +107,18 @@ void ThreadedAssignment::sendStatsPacket() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadedAssignment::checkInWithDomainServerOrExit() {
|
void ThreadedAssignment::checkInWithDomainServerOrExit() {
|
||||||
if (DependencyManager::get<NodeList>()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) {
|
// verify that the number of queued check-ins is not >= our max
|
||||||
|
// the number of queued check-ins is cleared anytime we get a response from the domain-server
|
||||||
|
if (_numQueuedCheckIns >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) {
|
||||||
|
qDebug() << "At least" << MAX_SILENT_DOMAIN_SERVER_CHECK_INS << "have been queued without a response from domain-server"
|
||||||
|
<< "Stopping the current assignment";
|
||||||
setFinished(true);
|
setFinished(true);
|
||||||
} else {
|
} else {
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
QMetaObject::invokeMethod(nodeList.data(), "sendDomainServerCheckIn");
|
QMetaObject::invokeMethod(nodeList.data(), "sendDomainServerCheckIn");
|
||||||
|
|
||||||
|
// increase the number of queued check ins
|
||||||
|
_numQueuedCheckIns++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ public slots:
|
||||||
virtual void run() = 0;
|
virtual void run() = 0;
|
||||||
Q_INVOKABLE virtual void stop() { setFinished(true); }
|
Q_INVOKABLE virtual void stop() { setFinished(true); }
|
||||||
virtual void sendStatsPacket();
|
virtual void sendStatsPacket();
|
||||||
|
void clearQueuedCheckIns() { _numQueuedCheckIns = 0; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void finished();
|
void finished();
|
||||||
|
@ -42,6 +43,7 @@ protected:
|
||||||
bool _isFinished;
|
bool _isFinished;
|
||||||
QTimer _domainServerTimer;
|
QTimer _domainServerTimer;
|
||||||
QTimer _statsTimer;
|
QTimer _statsTimer;
|
||||||
|
int _numQueuedCheckIns { 0 };
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void domainSettingsRequestFailed();
|
void domainSettingsRequestFailed();
|
||||||
|
|
Loading…
Reference in a new issue