mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 03:44:02 +02:00
Merge branch 'master' into tony/wrong-way-overlay
This commit is contained in:
commit
886457939d
44 changed files with 1502 additions and 163 deletions
|
@ -589,6 +589,9 @@ Section "-Core installation"
|
|||
Delete "$INSTDIR\version"
|
||||
Delete "$INSTDIR\xinput1_3.dll"
|
||||
|
||||
; Rename the incorrectly cased Raleway font
|
||||
Rename "$INSTDIR\resources\qml\styles-uit\RalewaySemibold.qml" "$INSTDIR\resources\qml\styles-uit\RalewaySemiBold.qml"
|
||||
|
||||
; Remove the Old Interface directory and vcredist_x64.exe (from installs prior to Server Console)
|
||||
RMDir /r "$INSTDIR\Interface"
|
||||
Delete "$INSTDIR\vcredist_x64.exe"
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
//
|
||||
|
||||
var DEBUGGING = false;
|
||||
var angularVelocityTrailingAverage = 0.0; // Global trailing average used to decide whether to move reticle at all
|
||||
var angularVelocityTrailingAverage = 0.0; // Global trailing average used to decide whether to move reticle at all
|
||||
var lastX = 0;
|
||||
var lastY = 0;
|
||||
var lastY = 0;
|
||||
|
||||
Math.clamp=function(a,b,c) {
|
||||
return Math.max(b,Math.min(c,a));
|
||||
|
@ -54,9 +54,11 @@ function debugPrint(message) {
|
|||
var leftRightBias = 0.0;
|
||||
var filteredRotatedLeft = Vec3.UNIT_NEG_Y;
|
||||
var filteredRotatedRight = Vec3.UNIT_NEG_Y;
|
||||
var lastAlpha = 0;
|
||||
|
||||
Script.update.connect(function(deltaTime) {
|
||||
|
||||
// avatar frame
|
||||
var poseRight = Controller.getPoseValue(Controller.Standard.RightHand);
|
||||
var poseLeft = Controller.getPoseValue(Controller.Standard.LeftHand);
|
||||
|
||||
|
@ -65,53 +67,59 @@ Script.update.connect(function(deltaTime) {
|
|||
var screenSizeX = screenSize.x;
|
||||
var screenSizeY = screenSize.y;
|
||||
|
||||
var rotatedRight = Vec3.multiplyQbyV(poseRight.rotation, Vec3.UNIT_NEG_Y);
|
||||
var rotatedLeft = Vec3.multiplyQbyV(poseLeft.rotation, Vec3.UNIT_NEG_Y);
|
||||
// transform hand facing vectors from avatar frame into sensor frame.
|
||||
var worldToSensorMatrix = Mat4.inverse(MyAvatar.sensorToWorldMatrix);
|
||||
var rotatedRight = Mat4.transformVector(worldToSensorMatrix, Vec3.multiplyQbyV(MyAvatar.orientation, Vec3.multiplyQbyV(poseRight.rotation, Vec3.UNIT_NEG_Y)));
|
||||
var rotatedLeft = Mat4.transformVector(worldToSensorMatrix, Vec3.multiplyQbyV(MyAvatar.orientation, Vec3.multiplyQbyV(poseLeft.rotation, Vec3.UNIT_NEG_Y)));
|
||||
|
||||
lastRotatedRight = rotatedRight;
|
||||
|
||||
|
||||
// Decide which hand should be controlling the pointer
|
||||
// by comparing which one is moving more, and by
|
||||
// tending to stay with the one moving more.
|
||||
var BIAS_ADJUST_RATE = 0.5;
|
||||
var BIAS_ADJUST_DEADZONE = 0.05;
|
||||
leftRightBias += (Vec3.length(poseRight.angularVelocity) - Vec3.length(poseLeft.angularVelocity)) * BIAS_ADJUST_RATE;
|
||||
if (leftRightBias < BIAS_ADJUST_DEADZONE) {
|
||||
leftRightBias = 0.0;
|
||||
} else if (leftRightBias > (1.0 - BIAS_ADJUST_DEADZONE)) {
|
||||
leftRightBias = 1.0;
|
||||
// by comparing which one is moving more, and by
|
||||
// tending to stay with the one moving more.
|
||||
if (deltaTime > 0.001) {
|
||||
// leftRightBias is a running average of the difference in angular hand speed.
|
||||
// a positive leftRightBias indicates the right hand is spinning faster then the left hand.
|
||||
// a negative leftRightBias indicates the left hand is spnning faster.
|
||||
var BIAS_ADJUST_PERIOD = 1.0;
|
||||
var tau = Math.clamp(deltaTime / BIAS_ADJUST_PERIOD, 0, 1);
|
||||
newLeftRightBias = Vec3.length(poseRight.angularVelocity) - Vec3.length(poseLeft.angularVelocity);
|
||||
leftRightBias = (1 - tau) * leftRightBias + tau * newLeftRightBias;
|
||||
}
|
||||
|
||||
// add a bit of hysteresis to prevent control flopping back and forth
|
||||
// between hands when they are both mostly stationary.
|
||||
var alpha;
|
||||
var HYSTERESIS_OFFSET = 0.25;
|
||||
if (lastAlpha > 0.5) {
|
||||
// prefer right hand over left
|
||||
alpha = leftRightBias > -HYSTERESIS_OFFSET ? 1 : 0;
|
||||
} else {
|
||||
alpha = leftRightBias > HYSTERESIS_OFFSET ? 1 : 0;
|
||||
}
|
||||
lastAlpha = alpha;
|
||||
|
||||
// Velocity filter the hand rotation used to position reticle so that it is easier to target small things with the hand controllers
|
||||
var VELOCITY_FILTER_GAIN = 0.5;
|
||||
filteredRotatedLeft = Vec3.mix(filteredRotatedLeft, rotatedLeft, Math.clamp(Vec3.length(poseLeft.angularVelocity) * VELOCITY_FILTER_GAIN, 0.0, 1.0));
|
||||
filteredRotatedRight = Vec3.mix(filteredRotatedRight, rotatedRight, Math.clamp(Vec3.length(poseRight.angularVelocity) * VELOCITY_FILTER_GAIN, 0.0, 1.0));
|
||||
var rotated = Vec3.mix(filteredRotatedLeft, filteredRotatedRight, leftRightBias);
|
||||
var rotated = Vec3.mix(filteredRotatedLeft, filteredRotatedRight, alpha);
|
||||
|
||||
var absolutePitch = rotated.y; // from 1 down to -1 up ... but note: if you rotate down "too far" it starts to go up again...
|
||||
var absoluteYaw = -rotated.x; // from -1 left to 1 right
|
||||
|
||||
var ROTATION_BOUND = 0.6;
|
||||
var clampYaw = Math.clamp(absoluteYaw, -ROTATION_BOUND, ROTATION_BOUND);
|
||||
var clampPitch = Math.clamp(absolutePitch, -ROTATION_BOUND, ROTATION_BOUND);
|
||||
|
||||
// using only from -ROTATION_BOUND to ROTATION_BOUND
|
||||
var xRatio = (clampYaw + ROTATION_BOUND) / (2 * ROTATION_BOUND);
|
||||
var yRatio = (clampPitch + ROTATION_BOUND) / (2 * ROTATION_BOUND);
|
||||
|
||||
var x = screenSizeX * xRatio;
|
||||
var y = screenSizeY * yRatio;
|
||||
var x = Math.clamp(screenSizeX * (absoluteYaw + 0.5), 0, screenSizeX);
|
||||
var y = Math.clamp(screenSizeX * absolutePitch, 0, screenSizeY);
|
||||
|
||||
// don't move the reticle with the hand controllers unless the controllers are actually being moved
|
||||
// take a time average of angular velocity, and don't move mouse at all if it's below threshold
|
||||
|
||||
|
||||
var AVERAGING_INTERVAL = 0.95;
|
||||
var MINIMUM_CONTROLLER_ANGULAR_VELOCITY = 0.03;
|
||||
var angularVelocityMagnitude = Vec3.length(poseLeft.angularVelocity) * (1.0 - leftRightBias) + Vec3.length(poseRight.angularVelocity) * leftRightBias;
|
||||
var angularVelocityMagnitude = Vec3.length(poseLeft.angularVelocity) * (1.0 - alpha) + Vec3.length(poseRight.angularVelocity) * alpha;
|
||||
angularVelocityTrailingAverage = angularVelocityTrailingAverage * AVERAGING_INTERVAL + angularVelocityMagnitude * (1.0 - AVERAGING_INTERVAL);
|
||||
|
||||
if (!(xRatio == 0.5 && yRatio == 0) && (angularVelocityTrailingAverage > MINIMUM_CONTROLLER_ANGULAR_VELOCITY) && ((x != lastX) || (y != lastY))) {
|
||||
if ((angularVelocityTrailingAverage > MINIMUM_CONTROLLER_ANGULAR_VELOCITY) && ((x != lastX) || (y != lastY))) {
|
||||
moveReticleAbsolute(x, y);
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
|
@ -121,5 +129,3 @@ Script.update.connect(function(deltaTime) {
|
|||
Script.scriptEnding.connect(function(){
|
||||
mapping.disable();
|
||||
});
|
||||
|
||||
|
||||
|
|
106
examples/fireflies/firefly.js
Normal file
106
examples/fireflies/firefly.js
Normal file
|
@ -0,0 +1,106 @@
|
|||
//
|
||||
// Created by Philip Rosedale on March 7, 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
// A firefly which is animated by passerbys. It's physical, no gravity, periodic forces applied.
|
||||
// If a firefly is found to
|
||||
//
|
||||
|
||||
(function () {
|
||||
var entityID,
|
||||
timeoutID = null,
|
||||
properties,
|
||||
shouldSimulate = false,
|
||||
ACTIVE_CHECK_INTERVAL = 100, // milliseconds
|
||||
INACTIVE_CHECK_INTERVAL = 1000, // milliseconds
|
||||
MAX_DISTANCE_TO_SIMULATE = 20, // meters
|
||||
LIGHT_LIFETIME = 1400, // milliseconds a firefly light will stay alive
|
||||
BUMP_SPEED = 1.5, // average velocity given by a bump
|
||||
BUMP_CHANCE = 0.33,
|
||||
MIN_SPEED = 0.125, // below this speed, firefly gets a new bump
|
||||
SPIN_SPEED = 3.5,
|
||||
BRIGHTNESS = 0.25,
|
||||
wantDebug = false
|
||||
|
||||
function randomVector(size) {
|
||||
return { x: (Math.random() - 0.5) * size,
|
||||
y: (Math.random() - 0.5) * size,
|
||||
z: (Math.random() - 0.5) * size };
|
||||
}
|
||||
|
||||
function printDebug(message) {
|
||||
if (wantDebug) {
|
||||
print(message);
|
||||
}
|
||||
}
|
||||
|
||||
function maybe() {
|
||||
properties = Entities.getEntityProperties(entityID);
|
||||
var speed = Vec3.length(properties.velocity);
|
||||
var distance = Vec3.distance(MyAvatar.position, properties.position);
|
||||
printDebug("maybe: speed: " + speed + ", distance: " + distance);
|
||||
if (shouldSimulate) {
|
||||
// We are simulating this firefly, so do stuff:
|
||||
if (distance > MAX_DISTANCE_TO_SIMULATE) {
|
||||
shouldSimulate = false;
|
||||
} else if ((speed < MIN_SPEED) && (Math.random() < BUMP_CHANCE)) {
|
||||
bump();
|
||||
makeLight();
|
||||
}
|
||||
} else if (Vec3.length(properties.velocity) == 0.0) {
|
||||
// We've found a firefly that is not being simulated, so maybe take it over
|
||||
if (distance < MAX_DISTANCE_TO_SIMULATE) {
|
||||
shouldSimulate = true;
|
||||
}
|
||||
}
|
||||
timeoutID = Script.setTimeout(maybe, (shouldSimulate == true) ? ACTIVE_CHECK_INTERVAL : INACTIVE_CHECK_INTERVAL);
|
||||
}
|
||||
|
||||
function bump() {
|
||||
// Give the firefly a little brownian hop
|
||||
printDebug("bump!");
|
||||
var velocity = randomVector(BUMP_SPEED);
|
||||
if (velocity.y < 0.0) { velocity.y *= -1.0 };
|
||||
Entities.editEntity(entityID, { velocity: velocity,
|
||||
angularVelocity: randomVector(SPIN_SPEED) });
|
||||
}
|
||||
|
||||
function makeLight() {
|
||||
printDebug("make light!");
|
||||
// create a light attached to the firefly that lives for a while
|
||||
Entities.addEntity({
|
||||
type: "Light",
|
||||
name: "firefly light",
|
||||
intensity: 4.0 * BRIGHTNESS,
|
||||
falloffRadius: 8.0 * BRIGHTNESS,
|
||||
dimensions: {
|
||||
x: 30 * BRIGHTNESS,
|
||||
y: 30 * BRIGHTNESS,
|
||||
z: 30 * BRIGHTNESS
|
||||
},
|
||||
position: Vec3.sum(properties.position, { x: 0, y: 0.2, z: 0 }),
|
||||
parentID: entityID,
|
||||
color: {
|
||||
red: 150 + Math.random() * 100,
|
||||
green: 100 + Math.random() * 50,
|
||||
blue: 150 + Math.random() * 100
|
||||
},
|
||||
lifetime: LIGHT_LIFETIME / 1000
|
||||
});
|
||||
}
|
||||
|
||||
this.preload = function (givenEntityID) {
|
||||
printDebug("preload firefly...");
|
||||
entityID = givenEntityID;
|
||||
timeoutID = Script.setTimeout(maybe, ACTIVE_CHECK_INTERVAL);
|
||||
};
|
||||
this.unload = function () {
|
||||
printDebug("unload firefly...");
|
||||
if (timeoutID !== undefined) {
|
||||
Script.clearTimeout(timeoutID);
|
||||
}
|
||||
};
|
||||
})
|
77
examples/fireflies/makeFireflies.js
Normal file
77
examples/fireflies/makeFireflies.js
Normal file
|
@ -0,0 +1,77 @@
|
|||
//
|
||||
// Created by Philip Rosedale on March 7, 2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
// Make some fireflies
|
||||
//
|
||||
|
||||
var SIZE = 0.05;
|
||||
//var ENTITY_URL = "file:///c:/users/dev/philip/examples/fireflies/firefly.js?"+Math.random()
|
||||
var ENTITY_URL = "https://s3.amazonaws.com/hifi-public/scripts/fireflies/firefly.js"
|
||||
|
||||
var RATE_PER_SECOND = 50; // The entity server will drop data if we create things too fast.
|
||||
var SCRIPT_INTERVAL = 100;
|
||||
var LIFETIME = 120;
|
||||
|
||||
var NUMBER_TO_CREATE = 100;
|
||||
|
||||
var GRAVITY = { x: 0, y: -1.0, z: 0 };
|
||||
|
||||
var DAMPING = 0.5;
|
||||
var ANGULAR_DAMPING = 0.5;
|
||||
|
||||
var collidable = true;
|
||||
var gravity = true;
|
||||
|
||||
var RANGE = 10;
|
||||
var HEIGHT = 3;
|
||||
var HOW_FAR_IN_FRONT_OF_ME = 1.0;
|
||||
|
||||
var totalCreated = 0;
|
||||
|
||||
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(HOW_FAR_IN_FRONT_OF_ME, Quat.getFront(Camera.orientation)));
|
||||
|
||||
|
||||
function randomVector(range) {
|
||||
return {
|
||||
x: (Math.random() - 0.5) * range.x,
|
||||
y: (Math.random() - 0.5) * range.y,
|
||||
z: (Math.random() - 0.5) * range.z
|
||||
}
|
||||
}
|
||||
|
||||
Vec3.print("Center: ", center);
|
||||
|
||||
Script.setInterval(function () {
|
||||
if (!Entities.serversExist() || !Entities.canRez() || (totalCreated > NUMBER_TO_CREATE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var numToCreate = RATE_PER_SECOND * (SCRIPT_INTERVAL / 1000.0);
|
||||
for (var i = 0; (i < numToCreate) && (totalCreated < NUMBER_TO_CREATE); i++) {
|
||||
|
||||
var position = Vec3.sum(center, randomVector({ x: RANGE, y: HEIGHT, z: RANGE }));
|
||||
position.y += HEIGHT / 2.0;
|
||||
|
||||
Entities.addEntity({
|
||||
type: "Box",
|
||||
name: "firefly",
|
||||
position: position,
|
||||
dimensions: { x: SIZE, y: SIZE, z: SIZE },
|
||||
color: { red: 150 + Math.random() * 100, green: 100 + Math.random() * 50, blue: 0 },
|
||||
damping: DAMPING,
|
||||
angularDamping: ANGULAR_DAMPING,
|
||||
gravity: (gravity ? GRAVITY : { x: 0, y: 0, z: 0}),
|
||||
dynamic: collidable,
|
||||
script: ENTITY_URL,
|
||||
lifetime: LIFETIME
|
||||
});
|
||||
|
||||
totalCreated++;
|
||||
print("Firefly #" + totalCreated);
|
||||
}
|
||||
}, SCRIPT_INTERVAL);
|
||||
|
165
examples/tests/mat4test.js
Normal file
165
examples/tests/mat4test.js
Normal file
|
@ -0,0 +1,165 @@
|
|||
//
|
||||
// mat4test.js
|
||||
// examples/tests
|
||||
//
|
||||
// Created by Anthony Thibault on 2016/3/7
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var IDENTITY = {r0c0: 1, r0c1: 0, r0c2: 0, r0c3: 0,
|
||||
r1c0: 0, r1c1: 1, r1c2: 0, r1c3: 0,
|
||||
r2c0: 0, r2c1: 0, r2c2: 1, r2c3: 0,
|
||||
r3c0: 0, r3c1: 0, r3c2: 0, r3c3: 1};
|
||||
|
||||
var ROT_ZERO = {x: 0, y: 0, z: 0, w: 1};
|
||||
var ROT_Y_180 = {x: 0, y: 1, z: 0, w: 0};
|
||||
|
||||
var ONE = {x: 1, y: 1, z: 1};
|
||||
var ZERO = {x: 0, y: 0, z: 0};
|
||||
var ONE_TWO_THREE = {x: 1, y: 2, z: 3};
|
||||
var ONE_HALF = {x: 0.5, y: 0.5, z: 0.5};
|
||||
|
||||
var EPSILON = 0.000001;
|
||||
|
||||
function mat4FuzzyEqual(a, b) {
|
||||
var r, c;
|
||||
for (r = 0; r < 4; r++) {
|
||||
for (c = 0; c < 4; c++) {
|
||||
if (Math.abs(a["r" + r + "c" + c] - b["r" + r + "c" + c]) > EPSILON) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function vec3FuzzyEqual(a, b) {
|
||||
if (Math.abs(a.x - b.x) > EPSILON ||
|
||||
Math.abs(a.y - b.y) > EPSILON ||
|
||||
Math.abs(a.z - b.z) > EPSILON) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function quatFuzzyEqual(a, b) {
|
||||
if (Math.abs(a.x - b.x) > EPSILON ||
|
||||
Math.abs(a.y - b.y) > EPSILON ||
|
||||
Math.abs(a.z - b.z) > EPSILON ||
|
||||
Math.abs(a.w - b.w) > EPSILON) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
var failureCount = 0;
|
||||
var testCount = 0;
|
||||
function assert(test) {
|
||||
testCount++;
|
||||
if (!test) {
|
||||
print("MAT4 TEST " + testCount + " failed!");
|
||||
failureCount++;
|
||||
}
|
||||
}
|
||||
|
||||
function testCreate() {
|
||||
var test0 = Mat4.createFromScaleRotAndTrans(ONE, {x: 0, y: 0, z: 0, w: 1}, ZERO);
|
||||
assert(mat4FuzzyEqual(test0, IDENTITY));
|
||||
|
||||
var test1 = Mat4.createFromRotAndTrans({x: 0, y: 0, z: 0, w: 1}, ZERO);
|
||||
assert(mat4FuzzyEqual(test1, IDENTITY));
|
||||
|
||||
var test2 = Mat4.createFromRotAndTrans(ROT_Y_180, ONE_TWO_THREE);
|
||||
assert(mat4FuzzyEqual(test2, {r0c0: -1, r0c1: 0, r0c2: 0, r0c3: 1,
|
||||
r1c0: 0, r1c1: 1, r1c2: 0, r1c3: 2,
|
||||
r2c0: 0, r2c1: 0, r2c2: -1, r2c3: 3,
|
||||
r3c0: 0, r3c1: 0, r3c2: 0, r3c3: 1}));
|
||||
|
||||
var test3 = Mat4.createFromScaleRotAndTrans(ONE_HALF, ROT_Y_180, ONE_TWO_THREE);
|
||||
assert(mat4FuzzyEqual(test3, {r0c0: -0.5, r0c1: 0, r0c2: 0, r0c3: 1,
|
||||
r1c0: 0, r1c1: 0.5, r1c2: 0, r1c3: 2,
|
||||
r2c0: 0, r2c1: 0, r2c2: -0.5, r2c3: 3,
|
||||
r3c0: 0, r3c1: 0, r3c2: 0, r3c3: 1}));
|
||||
}
|
||||
|
||||
function testExtractTranslation() {
|
||||
var test0 = Mat4.extractTranslation(IDENTITY);
|
||||
assert(vec3FuzzyEqual(ZERO, test0));
|
||||
|
||||
var test1 = Mat4.extractTranslation(Mat4.createFromRotAndTrans(ROT_Y_180, ONE_TWO_THREE));
|
||||
assert(vec3FuzzyEqual(ONE_TWO_THREE, test1));
|
||||
}
|
||||
|
||||
function testExtractRotation() {
|
||||
var test0 = Mat4.extractRotation(IDENTITY);
|
||||
assert(quatFuzzyEqual(ROT_ZERO, test0));
|
||||
|
||||
var test1 = Mat4.extractRotation(Mat4.createFromRotAndTrans(ROT_Y_180, ONE_TWO_THREE));
|
||||
assert(quatFuzzyEqual(ROT_Y_180, test1));
|
||||
}
|
||||
|
||||
function testExtractScale() {
|
||||
var test0 = Mat4.extractScale(IDENTITY);
|
||||
assert(vec3FuzzyEqual(ONE, test0));
|
||||
|
||||
var test1 = Mat4.extractScale(Mat4.createFromScaleRotAndTrans(ONE_HALF, ROT_Y_180, ONE_TWO_THREE));
|
||||
assert(vec3FuzzyEqual(ONE_HALF, test1));
|
||||
|
||||
var test2 = Mat4.extractScale(Mat4.createFromScaleRotAndTrans(ONE_TWO_THREE, ROT_ZERO, ONE_TWO_THREE));
|
||||
assert(vec3FuzzyEqual(ONE_TWO_THREE, test2));
|
||||
}
|
||||
|
||||
function testTransformPoint() {
|
||||
var test0 = Mat4.transformPoint(IDENTITY, ONE);
|
||||
assert(vec3FuzzyEqual(ONE, test0));
|
||||
|
||||
var m = Mat4.createFromScaleRotAndTrans(ONE_HALF, ROT_Y_180, ONE_TWO_THREE);
|
||||
var test1 = Mat4.transformPoint(m, ONE);
|
||||
assert(vec3FuzzyEqual({x: 0.5, y: 2.5, z: 2.5}, test1));
|
||||
}
|
||||
|
||||
function testTransformVector() {
|
||||
var test0 = Mat4.transformVector(IDENTITY, ONE);
|
||||
assert(vec3FuzzyEqual(ONE, test0));
|
||||
|
||||
var m = Mat4.createFromScaleRotAndTrans(ONE_HALF, ROT_Y_180, ONE_TWO_THREE);
|
||||
var test1 = Mat4.transformVector(m, ONE);
|
||||
assert(vec3FuzzyEqual({x: -0.5, y: 0.5, z: -0.5}, test1));
|
||||
}
|
||||
|
||||
function testInverse() {
|
||||
var test0 = IDENTITY;
|
||||
assert(mat4FuzzyEqual(IDENTITY, Mat4.multiply(test0, Mat4.inverse(test0))));
|
||||
|
||||
var test1 = Mat4.createFromScaleRotAndTrans(ONE_HALF, ROT_Y_180, ONE_TWO_THREE);
|
||||
assert(mat4FuzzyEqual(IDENTITY, Mat4.multiply(test1, Mat4.inverse(test1))));
|
||||
|
||||
var test2 = Mat4.extractScale(Mat4.createFromScaleRotAndTrans(ONE_TWO_THREE, ROT_ZERO, ONE_TWO_THREE));
|
||||
assert(mat4FuzzyEqual(IDENTITY, Mat4.multiply(test2, Mat4.inverse(test2))));
|
||||
}
|
||||
|
||||
function testFront() {
|
||||
var test0 = IDENTITY;
|
||||
assert(mat4FuzzyEqual({x: 0, y: 0, z: -1}, Mat4.getFront(test0)));
|
||||
|
||||
var test1 = Mat4.createFromScaleRotAndTrans(ONE_HALF, ROT_Y_180, ONE_TWO_THREE);
|
||||
assert(mat4FuzzyEqual({x: 0, y: 0, z: 1}, Mat4.getFront(test1)));
|
||||
}
|
||||
|
||||
function testMat4() {
|
||||
testCreate();
|
||||
testExtractTranslation();
|
||||
testExtractRotation();
|
||||
testExtractScale();
|
||||
testTransformPoint();
|
||||
testTransformVector();
|
||||
testInverse();
|
||||
testFront();
|
||||
|
||||
print("MAT4 TEST complete! (" + (testCount - failureCount) + "/" + testCount + ") tests passed!");
|
||||
}
|
||||
|
||||
testMat4();
|
|
@ -115,7 +115,7 @@ Item {
|
|||
color: root.fontColor
|
||||
font.pixelSize: root.fontSize
|
||||
visible: root.expanded;
|
||||
text: "Voxel max ping: " + 0
|
||||
text: "Messages max ping: " + root.messagePing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -236,6 +236,48 @@ const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensi
|
|||
{ AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl }
|
||||
};
|
||||
|
||||
class DeadlockWatchdogThread : public QThread {
|
||||
public:
|
||||
static const unsigned long HEARTBEAT_CHECK_INTERVAL_SECS = 1;
|
||||
static const unsigned long HEARTBEAT_UPDATE_INTERVAL_SECS = 1;
|
||||
#ifdef DEBUG
|
||||
static const unsigned long MAX_HEARTBEAT_AGE_USECS = 600 * USECS_PER_SECOND;
|
||||
#else
|
||||
static const unsigned long MAX_HEARTBEAT_AGE_USECS = 10 * USECS_PER_SECOND;
|
||||
#endif
|
||||
|
||||
// Set the heartbeat on launch
|
||||
DeadlockWatchdogThread() {
|
||||
QTimer* heartbeatTimer = new QTimer();
|
||||
// Give the heartbeat an initial value
|
||||
_heartbeat = usecTimestampNow();
|
||||
connect(heartbeatTimer, &QTimer::timeout, [this] {
|
||||
_heartbeat = usecTimestampNow();
|
||||
});
|
||||
heartbeatTimer->start(HEARTBEAT_UPDATE_INTERVAL_SECS * MSECS_PER_SECOND);
|
||||
}
|
||||
|
||||
void deadlockDetectionCrash() {
|
||||
uint32_t* crashTrigger = nullptr;
|
||||
*crashTrigger = 0xDEAD10CC;
|
||||
}
|
||||
|
||||
void run() override {
|
||||
while (!qApp->isAboutToQuit()) {
|
||||
QThread::sleep(HEARTBEAT_UPDATE_INTERVAL_SECS);
|
||||
auto now = usecTimestampNow();
|
||||
auto lastHeartbeatAge = now - _heartbeat;
|
||||
if (lastHeartbeatAge > MAX_HEARTBEAT_AGE_USECS) {
|
||||
deadlockDetectionCrash();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static std::atomic<uint64_t> _heartbeat;
|
||||
};
|
||||
|
||||
std::atomic<uint64_t> DeadlockWatchdogThread::_heartbeat;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
class MyNativeEventFilter : public QAbstractNativeEventFilter {
|
||||
public:
|
||||
|
@ -458,6 +500,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
// Set up a watchdog thread to intentionally crash the application on deadlocks
|
||||
(new DeadlockWatchdogThread())->start();
|
||||
|
||||
qCDebug(interfaceapp) << "[VERSION] Build sequence:" << qPrintable(applicationVersion());
|
||||
|
||||
_bookmarks = new Bookmarks(); // Before setting up the menu
|
||||
|
@ -4961,6 +5006,15 @@ void Application::crashApplication() {
|
|||
Q_UNUSED(value);
|
||||
}
|
||||
|
||||
void Application::deadlockApplication() {
|
||||
qCDebug(interfaceapp) << "Intentionally deadlocked Interface";
|
||||
// Using a loop that will *technically* eventually exit (in ~600 billion years)
|
||||
// to avoid compiler warnings about a loop that will never exit
|
||||
for (uint64_t i = 1; i != 0; ++i) {
|
||||
QThread::sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
void Application::setActiveDisplayPlugin(const QString& pluginName) {
|
||||
auto menu = Menu::getInstance();
|
||||
foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) {
|
||||
|
|
|
@ -276,6 +276,7 @@ public slots:
|
|||
void reloadResourceCaches();
|
||||
|
||||
void crashApplication();
|
||||
void deadlockApplication();
|
||||
|
||||
void rotationModeChanged();
|
||||
|
||||
|
|
|
@ -592,6 +592,8 @@ Menu::Menu() {
|
|||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisplayCrashOptions, 0, true);
|
||||
// Developer > Crash Application
|
||||
addActionToQMenuAndActionHash(developerMenu, MenuOption::CrashInterface, 0, qApp, SLOT(crashApplication()));
|
||||
// Developer > Deadlock Application
|
||||
addActionToQMenuAndActionHash(developerMenu, MenuOption::DeadlockInterface, 0, qApp, SLOT(deadlockApplication()));
|
||||
|
||||
// Developer > Log...
|
||||
addActionToQMenuAndActionHash(developerMenu, MenuOption::Log, Qt::CTRL | Qt::SHIFT | Qt::Key_L,
|
||||
|
|
|
@ -66,6 +66,7 @@ namespace MenuOption {
|
|||
const QString CopyPath = "Copy Path to Clipboard";
|
||||
const QString CoupleEyelids = "Couple Eyelids";
|
||||
const QString CrashInterface = "Crash Interface";
|
||||
const QString DeadlockInterface = "Deadlock Interface";
|
||||
const QString DecreaseAvatarSize = "Decrease Avatar Size";
|
||||
const QString DeleteBookmark = "Delete Bookmark...";
|
||||
const QString DisableActivityLogger = "Disable Activity Logger";
|
||||
|
|
|
@ -416,8 +416,9 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
// thread-safe
|
||||
glm::mat4 MyAvatar::getSensorToWorldMatrix() const {
|
||||
return _sensorToWorldMatrix;
|
||||
return _sensorToWorldMatrixCache.get();
|
||||
}
|
||||
|
||||
// Pass a recent sample of the HMD to the avatar.
|
||||
|
@ -446,6 +447,8 @@ void MyAvatar::updateSensorToWorldMatrix() {
|
|||
if (_enableDebugDrawSensorToWorldMatrix) {
|
||||
DebugDraw::getInstance().addMarker("sensorToWorldMatrix", glmExtractRotation(_sensorToWorldMatrix), extractTranslation(_sensorToWorldMatrix), glm::vec4(1));
|
||||
}
|
||||
|
||||
_sensorToWorldMatrixCache.set(_sensorToWorldMatrix);
|
||||
}
|
||||
|
||||
// Update avatar head rotation with sensor data
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "Avatar.h"
|
||||
#include "AtRestDetector.h"
|
||||
#include "MyCharacterController.h"
|
||||
|
||||
#include <ThreadSafeValueCache.h>
|
||||
|
||||
class ModelItemID;
|
||||
|
||||
|
@ -78,6 +78,9 @@ class MyAvatar : public Avatar {
|
|||
Q_PROPERTY(controller::Pose rightHandPose READ getRightHandPose)
|
||||
Q_PROPERTY(controller::Pose leftHandTipPose READ getLeftHandTipPose)
|
||||
Q_PROPERTY(controller::Pose rightHandTipPose READ getRightHandTipPose)
|
||||
|
||||
Q_PROPERTY(glm::mat4 sensorToWorldMatrix READ getSensorToWorldMatrix)
|
||||
|
||||
Q_PROPERTY(float energy READ getEnergy WRITE setEnergy)
|
||||
|
||||
public:
|
||||
|
@ -98,8 +101,9 @@ public:
|
|||
const glm::vec3& getHMDSensorPosition() const { return _hmdSensorPosition; }
|
||||
const glm::quat& getHMDSensorOrientation() const { return _hmdSensorOrientation; }
|
||||
const glm::vec2& getHMDSensorFacingMovingAverage() const { return _hmdSensorFacingMovingAverage; }
|
||||
glm::mat4 getSensorToWorldMatrix() const;
|
||||
|
||||
// thread safe
|
||||
Q_INVOKABLE glm::mat4 getSensorToWorldMatrix() const;
|
||||
|
||||
// Pass a recent sample of the HMD to the avatar.
|
||||
// This can also update the avatar's position to follow the HMD
|
||||
|
@ -391,6 +395,7 @@ private:
|
|||
|
||||
// used to transform any sensor into world space, including the _hmdSensorMat, or hand controllers.
|
||||
glm::mat4 _sensorToWorldMatrix;
|
||||
ThreadSafeValueCache<glm::mat4> _sensorToWorldMatrixCache { glm::mat4() };
|
||||
|
||||
struct FollowHelper {
|
||||
FollowHelper();
|
||||
|
|
|
@ -136,10 +136,12 @@ void Stats::updateStats(bool force) {
|
|||
SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer);
|
||||
SharedNodePointer avatarMixerNode = nodeList->soloNodeOfType(NodeType::AvatarMixer);
|
||||
SharedNodePointer assetServerNode = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||
SharedNodePointer messageMixerNode = nodeList->soloNodeOfType(NodeType::MessagesMixer);
|
||||
STAT_UPDATE(audioPing, audioMixerNode ? audioMixerNode->getPingMs() : -1);
|
||||
STAT_UPDATE(avatarPing, avatarMixerNode ? avatarMixerNode->getPingMs() : -1);
|
||||
STAT_UPDATE(assetPing, assetServerNode ? assetServerNode->getPingMs() : -1);
|
||||
|
||||
STAT_UPDATE(messagePing, messageMixerNode ? messageMixerNode->getPingMs() : -1);
|
||||
|
||||
//// Now handle entity servers, since there could be more than one, we average their ping times
|
||||
int totalPingOctree = 0;
|
||||
int octreeServerCount = 0;
|
||||
|
|
|
@ -45,7 +45,8 @@ class Stats : public QQuickItem {
|
|||
STATS_PROPERTY(int, avatarPing, 0)
|
||||
STATS_PROPERTY(int, entitiesPing, 0)
|
||||
STATS_PROPERTY(int, assetPing, 0)
|
||||
STATS_PROPERTY(QVector3D, position, QVector3D(0, 0, 0) )
|
||||
STATS_PROPERTY(int, messagePing, 0)
|
||||
STATS_PROPERTY(QVector3D, position, QVector3D(0, 0, 0))
|
||||
STATS_PROPERTY(float, speed, 0)
|
||||
STATS_PROPERTY(float, yaw, 0)
|
||||
STATS_PROPERTY(int, avatarMixerInKbps, 0)
|
||||
|
@ -123,6 +124,7 @@ signals:
|
|||
void avatarPingChanged();
|
||||
void entitiesPingChanged();
|
||||
void assetPingChanged();
|
||||
void messagePingChanged();
|
||||
void positionChanged();
|
||||
void speedChanged();
|
||||
void yawChanged();
|
||||
|
|
|
@ -132,6 +132,7 @@ void Animation::animationParseSuccess(FBXGeometry* geometry) {
|
|||
void Animation::animationParseError(int error, QString str) {
|
||||
qCCritical(animation) << "Animation failure parsing " << _url.toDisplayString() << "code =" << error << str;
|
||||
emit failed(QNetworkReply::UnknownContentError);
|
||||
finishedLoading(false);
|
||||
}
|
||||
|
||||
AnimationDetails::AnimationDetails() :
|
||||
|
|
|
@ -80,6 +80,8 @@ void Sound::downloadFinished(const QByteArray& data) {
|
|||
qCDebug(audio) << "Unknown sound file type";
|
||||
}
|
||||
|
||||
finishedLoading(true);
|
||||
|
||||
_isReady = true;
|
||||
emit ready();
|
||||
}
|
||||
|
|
|
@ -114,8 +114,8 @@ public:
|
|||
// use this method if you have a pointer to the entity (avoid an extra entity lookup)
|
||||
bool updateEntity(EntityItemPointer entity, const EntityItemProperties& properties, const SharedNodePointer& senderNode = SharedNodePointer(nullptr));
|
||||
|
||||
void deleteEntity(const EntityItemID& entityID, bool force = false, bool ignoreWarnings = false);
|
||||
void deleteEntities(QSet<EntityItemID> entityIDs, bool force = false, bool ignoreWarnings = false);
|
||||
void deleteEntity(const EntityItemID& entityID, bool force = false, bool ignoreWarnings = true);
|
||||
void deleteEntities(QSet<EntityItemID> entityIDs, bool force = false, bool ignoreWarnings = true);
|
||||
|
||||
/// \param position point of query in world-frame (meters)
|
||||
/// \param targetRadius radius of query (meters)
|
||||
|
|
|
@ -867,11 +867,10 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
}
|
||||
} else if (object.name == "Material") {
|
||||
FBXMaterial material;
|
||||
if (object.properties.at(1).toByteArray().contains("StingrayPBS")) {
|
||||
material.isPBSMaterial = true;
|
||||
}
|
||||
material.name = (object.properties.at(1).toString());
|
||||
foreach (const FBXNode& subobject, object.children) {
|
||||
bool properties = false;
|
||||
|
||||
QByteArray propertyName;
|
||||
int index;
|
||||
if (subobject.name == "Properties60") {
|
||||
|
@ -884,25 +883,36 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
propertyName = "P";
|
||||
index = 4;
|
||||
}
|
||||
if (!material.isPBSMaterial && properties) {
|
||||
foreach (const FBXNode& property, subobject.children) {
|
||||
if (properties) {
|
||||
std::vector<std::string> unknowns;
|
||||
foreach(const FBXNode& property, subobject.children) {
|
||||
if (property.name == propertyName) {
|
||||
if (property.properties.at(0) == "DiffuseColor") {
|
||||
material.diffuseColor = getVec3(property.properties, index);
|
||||
} else if (property.properties.at(0) == "Diffuse") {
|
||||
material.diffuseColor = getVec3(property.properties, index);
|
||||
} else if (property.properties.at(0) == "DiffuseFactor") {
|
||||
material.diffuseFactor = property.properties.at(index).value<double>();
|
||||
} else if (property.properties.at(0) == "Diffuse") {
|
||||
// NOTE: this is uneeded but keep it for now for debug
|
||||
// material.diffuseColor = getVec3(property.properties, index);
|
||||
// material.diffuseFactor = 1.0;
|
||||
|
||||
} else if (property.properties.at(0) == "SpecularColor") {
|
||||
material.specularColor = getVec3(property.properties, index);
|
||||
} else if (property.properties.at(0) == "Specular") {
|
||||
material.specularColor = getVec3(property.properties, index);
|
||||
} else if (property.properties.at(0) == "SpecularFactor") {
|
||||
material.specularFactor = property.properties.at(index).value<double>();
|
||||
} else if (property.properties.at(0) == "Specular") {
|
||||
// NOTE: this is uneeded but keep it for now for debug
|
||||
// material.specularColor = getVec3(property.properties, index);
|
||||
// material.specularFactor = 1.0;
|
||||
|
||||
} else if (property.properties.at(0) == "Emissive") {
|
||||
} else if (property.properties.at(0) == "EmissiveColor") {
|
||||
material.emissiveColor = getVec3(property.properties, index);
|
||||
} else if (property.properties.at(0) == "EmissiveFactor") {
|
||||
material.emissiveFactor = property.properties.at(index).value<double>();
|
||||
} else if (property.properties.at(0) == "Emissive") {
|
||||
// NOTE: this is uneeded but keep it for now for debug
|
||||
// material.emissiveColor = getVec3(property.properties, index);
|
||||
// material.emissiveFactor = 1.0;
|
||||
|
||||
} else if (property.properties.at(0) == "Shininess") {
|
||||
material.shininess = property.properties.at(index).value<double>();
|
||||
|
@ -910,45 +920,50 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
} else if (property.properties.at(0) == "Opacity") {
|
||||
material.opacity = property.properties.at(index).value<double>();
|
||||
}
|
||||
#if defined(DEBUG_FBXREADER)
|
||||
else {
|
||||
const QString propname = property.properties.at(0).toString();
|
||||
if (propname == "EmissiveFactor") {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} else if (material.isPBSMaterial && properties) {
|
||||
std::vector<std::string> unknowns;
|
||||
foreach(const FBXNode& property, subobject.children) {
|
||||
if (property.name == propertyName) {
|
||||
if (property.properties.at(0) == "Maya|use_normal_map") {
|
||||
|
||||
// Sting Ray Material Properties!!!!
|
||||
else if (property.properties.at(0) == "Maya|use_normal_map") {
|
||||
material.isPBSMaterial = true;
|
||||
material.useNormalMap = (bool)property.properties.at(index).value<double>();
|
||||
|
||||
} else if (property.properties.at(0) == "Maya|base_color") {
|
||||
material.isPBSMaterial = true;
|
||||
material.diffuseColor = getVec3(property.properties, index);
|
||||
|
||||
} else if (property.properties.at(0) == "Maya|use_color_map") {
|
||||
material.isPBSMaterial = true;
|
||||
material.useAlbedoMap = (bool) property.properties.at(index).value<double>();
|
||||
|
||||
} else if (property.properties.at(0) == "Maya|roughness") {
|
||||
material.isPBSMaterial = true;
|
||||
material.roughness = property.properties.at(index).value<double>();
|
||||
|
||||
} else if (property.properties.at(0) == "Maya|use_roughness_map") {
|
||||
material.isPBSMaterial = true;
|
||||
material.useRoughnessMap = (bool)property.properties.at(index).value<double>();
|
||||
|
||||
} else if (property.properties.at(0) == "Maya|metallic") {
|
||||
material.isPBSMaterial = true;
|
||||
material.metallic = property.properties.at(index).value<double>();
|
||||
|
||||
} else if (property.properties.at(0) == "Maya|use_metallic_map") {
|
||||
material.isPBSMaterial = true;
|
||||
material.useMetallicMap = (bool)property.properties.at(index).value<double>();
|
||||
|
||||
} else if (property.properties.at(0) == "Maya|emissive") {
|
||||
material.isPBSMaterial = true;
|
||||
material.emissiveColor = getVec3(property.properties, index);
|
||||
|
||||
} else if (property.properties.at(0) == "Maya|emissive_intensity") {
|
||||
material.isPBSMaterial = true;
|
||||
material.emissiveIntensity = property.properties.at(index).value<double>();
|
||||
|
||||
} else if (property.properties.at(0) == "Maya|use_emissive_map") {
|
||||
material.isPBSMaterial = true;
|
||||
material.useEmissiveMap = (bool)property.properties.at(index).value<double>();
|
||||
|
||||
} else if (property.properties.at(0) == "Maya|use_ao_map") {
|
||||
material.isPBSMaterial = true;
|
||||
material.useOcclusionMap = (bool)property.properties.at(index).value<double>();
|
||||
|
||||
} else {
|
||||
|
@ -1073,7 +1088,9 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
if (connection.properties.at(0) == "OP") {
|
||||
int counter = 0;
|
||||
QByteArray type = connection.properties.at(3).toByteArray().toLower();
|
||||
if ((type.contains("diffuse") && !type.contains("tex_global_diffuse"))) {
|
||||
if (type.contains("DiffuseFactor")) {
|
||||
diffuseFactorTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||
} else if ((type.contains("diffuse") && !type.contains("tex_global_diffuse"))) {
|
||||
diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||
} else if (type.contains("tex_color_map")) {
|
||||
diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||
|
|
|
@ -138,19 +138,22 @@ public:
|
|||
opacity(opacity) {}
|
||||
|
||||
glm::vec3 diffuseColor{ 1.0f };
|
||||
float diffuseFactor = 1.0f;
|
||||
float diffuseFactor{ 1.0f };
|
||||
glm::vec3 specularColor{ 0.02f };
|
||||
float specularFactor = 1.0f;
|
||||
float specularFactor{ 1.0f };
|
||||
|
||||
glm::vec3 emissiveColor{ 0.0f };
|
||||
float shininess = 23.0f;
|
||||
float opacity = 1.0f;
|
||||
float emissiveFactor{ 0.0f };
|
||||
|
||||
float shininess{ 23.0f };
|
||||
float opacity{ 1.0f };
|
||||
|
||||
float metallic{ 0.0f };
|
||||
float roughness{ 1.0f };
|
||||
float emissiveIntensity{ 1.0f };
|
||||
|
||||
QString materialID;
|
||||
QString name;
|
||||
model::MaterialPointer _material;
|
||||
|
||||
FBXTexture normalTexture;
|
||||
|
@ -421,6 +424,7 @@ public:
|
|||
|
||||
|
||||
QHash<QString, QString> diffuseTextures;
|
||||
QHash<QString, QString> diffuseFactorTextures;
|
||||
QHash<QString, QString> transparentTextures;
|
||||
QHash<QString, QString> bumpTextures;
|
||||
QHash<QString, QString> normalTextures;
|
||||
|
|
|
@ -75,12 +75,24 @@ void FBXReader::consolidateFBXMaterials() {
|
|||
// the pure material associated with this part
|
||||
bool detectDifferentUVs = false;
|
||||
FBXTexture diffuseTexture;
|
||||
FBXTexture diffuseFactorTexture;
|
||||
QString diffuseTextureID = diffuseTextures.value(material.materialID);
|
||||
if (!diffuseTextureID.isNull()) {
|
||||
QString diffuseFactorTextureID = diffuseFactorTextures.value(material.materialID);
|
||||
|
||||
// If both factor and color textures are specified, the texture bound to DiffuseColor wins
|
||||
if (!diffuseFactorTextureID.isNull() || !diffuseTextureID.isNull()) {
|
||||
if (!diffuseFactorTextureID.isNull() && diffuseTextureID.isNull()) {
|
||||
diffuseTextureID = diffuseFactorTextureID;
|
||||
// If the diffuseTextureID comes from the Texture bound to DiffuseFactor, we know it s exported from maya
|
||||
// And the DiffuseFactor is forced to 0.5 by Maya which is bad
|
||||
// So we need to force it to 1.0
|
||||
material.diffuseFactor = 1.0;
|
||||
}
|
||||
|
||||
diffuseTexture = getTexture(diffuseTextureID);
|
||||
|
||||
|
||||
// FBX files generated by 3DSMax have an intermediate texture parent, apparently
|
||||
foreach (const QString& childTextureID, _connectionChildMap.values(diffuseTextureID)) {
|
||||
foreach(const QString& childTextureID, _connectionChildMap.values(diffuseTextureID)) {
|
||||
if (_textureFilenames.contains(childTextureID)) {
|
||||
diffuseTexture = getTexture(diffuseTextureID);
|
||||
}
|
||||
|
@ -180,11 +192,13 @@ void FBXReader::consolidateFBXMaterials() {
|
|||
|
||||
// Finally create the true material representation
|
||||
material._material = std::make_shared<model::Material>();
|
||||
material._material->setEmissive(material.emissiveColor);
|
||||
|
||||
auto diffuse = material.diffuseColor;
|
||||
// FIXME: Do not use the Diffuse Factor yet as some FBX models have it set to 0
|
||||
// diffuse *= material.diffuseFactor;
|
||||
// Emissive color is the mix of emissiveColor with emissiveFactor
|
||||
auto emissive = material.emissiveColor * material.emissiveFactor;
|
||||
material._material->setEmissive(emissive);
|
||||
|
||||
// Final diffuse color is the mix of diffuseColor with diffuseFactor
|
||||
auto diffuse = material.diffuseColor * material.diffuseFactor;
|
||||
material._material->setAlbedo(diffuse);
|
||||
|
||||
if (material.isPBSMaterial) {
|
||||
|
|
|
@ -15,6 +15,7 @@ NetworkShader::NetworkShader(const QUrl& url, bool delayLoad)
|
|||
|
||||
void NetworkShader::downloadFinished(const QByteArray& data) {
|
||||
_source = QString::fromUtf8(data);
|
||||
finishedLoading(true);
|
||||
}
|
||||
|
||||
ShaderCache& ShaderCache::instance() {
|
||||
|
|
|
@ -348,4 +348,3 @@ void NetworkTexture::setImage(const QImage& image, void* voidTexture, int origin
|
|||
|
||||
emit networkTextureCreated(qWeakPointerCast<NetworkTexture, Resource> (_self));
|
||||
}
|
||||
|
||||
|
|
|
@ -132,6 +132,8 @@ signals:
|
|||
|
||||
protected:
|
||||
|
||||
virtual bool isCacheable() const override { return _loaded; }
|
||||
|
||||
virtual void downloadFinished(const QByteArray& data) override;
|
||||
|
||||
Q_INVOKABLE void loadContent(const QByteArray& content);
|
||||
|
|
|
@ -278,20 +278,20 @@ void Resource::refresh() {
|
|||
}
|
||||
|
||||
void Resource::allReferencesCleared() {
|
||||
if (_cache) {
|
||||
if (_cache && isCacheable()) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "allReferencesCleared");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// create and reinsert new shared pointer
|
||||
QSharedPointer<Resource> self(this, &Resource::allReferencesCleared);
|
||||
setSelf(self);
|
||||
reinsert();
|
||||
|
||||
|
||||
// add to the unused list
|
||||
_cache->addUnusedResource(self);
|
||||
|
||||
|
||||
} else {
|
||||
delete this;
|
||||
}
|
||||
|
@ -371,7 +371,6 @@ void Resource::handleReplyFinished() {
|
|||
auto extraInfo = _url == _activeUrl ? "" : QString(", %1").arg(_activeUrl.toDisplayString());
|
||||
qCDebug(networking).noquote() << QString("Request finished for %1%2").arg(_url.toDisplayString(), extraInfo);
|
||||
|
||||
finishedLoading(true);
|
||||
emit loaded(_data);
|
||||
downloadFinished(_data);
|
||||
} else {
|
||||
|
@ -409,10 +408,6 @@ void Resource::handleReplyFinished() {
|
|||
_request = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void Resource::downloadFinished(const QByteArray& data) {
|
||||
}
|
||||
|
||||
uint qHash(const QPointer<QObject>& value, uint seed) {
|
||||
return qHash(value.data(), seed);
|
||||
}
|
||||
|
|
|
@ -177,13 +177,14 @@ public:
|
|||
const QByteArray& getData() const { return _data; }
|
||||
|
||||
signals:
|
||||
/// Fired when the resource has been loaded.
|
||||
/// Fired when the resource has been downloaded.
|
||||
/// This can be used instead of downloadFinished to access data before it is processed.
|
||||
void loaded(const QByteArray& request);
|
||||
|
||||
/// Fired when resource failed to load.
|
||||
/// Fired when the resource failed to load.
|
||||
void failed(QNetworkReply::NetworkError error);
|
||||
|
||||
/// Fired when resource is refreshed.
|
||||
/// Fired when the resource is refreshed.
|
||||
void onRefresh();
|
||||
|
||||
protected slots:
|
||||
|
@ -192,10 +193,15 @@ protected slots:
|
|||
protected:
|
||||
virtual void init();
|
||||
|
||||
/// Called when the download has finished
|
||||
virtual void downloadFinished(const QByteArray& data);
|
||||
/// Checks whether the resource is cacheable.
|
||||
virtual bool isCacheable() const { return true; }
|
||||
|
||||
/// Should be called by subclasses when all the loading that will be done has been done.
|
||||
/// Called when the download has finished.
|
||||
/// This should be overridden by subclasses that need to process the data once it is downloaded.
|
||||
virtual void downloadFinished(const QByteArray& data) { finishedLoading(true); }
|
||||
|
||||
/// Called when the download is finished and processed.
|
||||
/// This should be called by subclasses that override downloadFinished to mark the end of processing.
|
||||
Q_INVOKABLE void finishedLoading(bool success);
|
||||
|
||||
/// Reinserts this resource into the cache.
|
||||
|
|
|
@ -23,6 +23,7 @@ void NetworkClip::init(const QByteArray& clipData) {
|
|||
|
||||
void NetworkClipLoader::downloadFinished(const QByteArray& data) {
|
||||
_clip->init(data);
|
||||
finishedLoading(true);
|
||||
}
|
||||
|
||||
ClipCache& ClipCache::instance() {
|
||||
|
|
71
libraries/script-engine/src/Mat4.cpp
Normal file
71
libraries/script-engine/src/Mat4.cpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
//
|
||||
// Mat4.cpp
|
||||
// libraries/script-engine/src
|
||||
//
|
||||
// Created by Anthony Thibault on 3/7/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QDebug>
|
||||
#include <GLMHelpers.h>
|
||||
#include "ScriptEngineLogging.h"
|
||||
#include "Mat4.h"
|
||||
|
||||
glm::mat4 Mat4::multiply(const glm::mat4& m1, const glm::mat4& m2) const {
|
||||
return m1 * m2;
|
||||
}
|
||||
|
||||
glm::mat4 Mat4::createFromRotAndTrans(const glm::quat& rot, const glm::vec3& trans) const {
|
||||
return ::createMatFromQuatAndPos(rot, trans);
|
||||
}
|
||||
|
||||
glm::mat4 Mat4::createFromScaleRotAndTrans(const glm::vec3& scale, const glm::quat& rot, const glm::vec3& trans) const {
|
||||
return createMatFromScaleQuatAndPos(scale, rot, trans);
|
||||
}
|
||||
|
||||
glm::vec3 Mat4::extractTranslation(const glm::mat4& m) const {
|
||||
return ::extractTranslation(m);
|
||||
}
|
||||
|
||||
glm::quat Mat4::extractRotation(const glm::mat4& m) const {
|
||||
return ::glmExtractRotation(m);
|
||||
}
|
||||
|
||||
glm::vec3 Mat4::extractScale(const glm::mat4& m) const {
|
||||
return ::extractScale(m);
|
||||
}
|
||||
|
||||
glm::vec3 Mat4::transformPoint(const glm::mat4& m, const glm::vec3& point) const {
|
||||
return ::transformPoint(m, point);
|
||||
}
|
||||
|
||||
glm::vec3 Mat4::transformVector(const glm::mat4& m, const glm::vec3& vector) const {
|
||||
return ::transformVectorFast(m, vector);
|
||||
}
|
||||
|
||||
glm::mat4 Mat4::inverse(const glm::mat4& m) const {
|
||||
return glm::inverse(m);
|
||||
}
|
||||
|
||||
glm::vec3 Mat4::getFront(const glm::mat4& m) const {
|
||||
return glm::vec3(-m[0][2], -m[1][2], -m[2][2]);
|
||||
}
|
||||
|
||||
glm::vec3 Mat4::getRight(const glm::mat4& m) const {
|
||||
return glm::vec3(m[0][0], m[1][0], m[2][0]);
|
||||
}
|
||||
|
||||
glm::vec3 Mat4::getUp(const glm::mat4& m) const {
|
||||
return glm::vec3(m[0][1], m[1][1], m[2][1]);
|
||||
}
|
||||
|
||||
void Mat4::print(const QString& label, const glm::mat4& m) const {
|
||||
qCDebug(scriptengine) << qPrintable(label) <<
|
||||
"row0 =" << m[0][0] << "," << m[1][0] << "," << m[2][0] << "," << m[3][0] <<
|
||||
"row1 =" << m[0][1] << "," << m[1][1] << "," << m[2][1] << "," << m[3][1] <<
|
||||
"row2 =" << m[0][2] << "," << m[1][2] << "," << m[2][2] << "," << m[3][2] <<
|
||||
"row3 =" << m[0][3] << "," << m[1][3] << "," << m[2][3] << "," << m[3][3];
|
||||
}
|
45
libraries/script-engine/src/Mat4.h
Normal file
45
libraries/script-engine/src/Mat4.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// Mat4.h
|
||||
// libraries/script-engine/src
|
||||
//
|
||||
// Created by Anthony Thibault on 3/7/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Scriptable 4x4 Matrix class library.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_Mat4_h
|
||||
#define hifi_Mat4_h
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
/// Scriptable Mat4 object. Used exclusively in the JavaScript API
|
||||
class Mat4 : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public slots:
|
||||
glm::mat4 multiply(const glm::mat4& m1, const glm::mat4& m2) const;
|
||||
glm::mat4 createFromRotAndTrans(const glm::quat& rot, const glm::vec3& trans) const;
|
||||
glm::mat4 createFromScaleRotAndTrans(const glm::vec3& scale, const glm::quat& rot, const glm::vec3& trans) const;
|
||||
|
||||
glm::vec3 extractTranslation(const glm::mat4& m) const;
|
||||
glm::quat extractRotation(const glm::mat4& m) const;
|
||||
glm::vec3 extractScale(const glm::mat4& m) const;
|
||||
|
||||
glm::vec3 transformPoint(const glm::mat4& m, const glm::vec3& point) const;
|
||||
glm::vec3 transformVector(const glm::mat4& m, const glm::vec3& vector) const;
|
||||
|
||||
glm::mat4 inverse(const glm::mat4& m) const;
|
||||
|
||||
glm::vec3 getFront(const glm::mat4& m) const;
|
||||
glm::vec3 getRight(const glm::mat4& m) const;
|
||||
glm::vec3 getUp(const glm::mat4& m) const;
|
||||
|
||||
void print(const QString& label, const glm::mat4& m) const;
|
||||
};
|
||||
|
||||
#endif // hifi_Mat4_h
|
|
@ -315,6 +315,7 @@ void ScriptEngine::init() {
|
|||
registerGlobalObject("Entities", entityScriptingInterface.data());
|
||||
registerGlobalObject("Quat", &_quatLibrary);
|
||||
registerGlobalObject("Vec3", &_vec3Library);
|
||||
registerGlobalObject("Mat4", &_mat4Library);
|
||||
registerGlobalObject("Uuid", &_uuidLibrary);
|
||||
registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCache>().data());
|
||||
registerGlobalObject("Messages", DependencyManager::get<MessagesClient>().data());
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "ArrayBufferClass.h"
|
||||
#include "AudioScriptingInterface.h"
|
||||
#include "Quat.h"
|
||||
#include "Mat4.h"
|
||||
#include "ScriptCache.h"
|
||||
#include "ScriptUUID.h"
|
||||
#include "Vec3.h"
|
||||
|
@ -199,6 +200,7 @@ protected:
|
|||
QString _fileNameString;
|
||||
Quat _quatLibrary;
|
||||
Vec3 _vec3Library;
|
||||
Mat4 _mat4Library;
|
||||
ScriptUUID _uuidLibrary;
|
||||
std::atomic<bool> _isUserLoaded { false };
|
||||
bool _isReloading { false };
|
||||
|
@ -219,4 +221,4 @@ protected:
|
|||
static std::atomic<bool> _stoppingAllScripts;
|
||||
};
|
||||
|
||||
#endif // hifi_ScriptEngine_h
|
||||
#endif // hifi_ScriptEngine_h
|
||||
|
|
|
@ -376,6 +376,15 @@ glm::mat4 createMatFromQuatAndPos(const glm::quat& q, const glm::vec3& p) {
|
|||
return m;
|
||||
}
|
||||
|
||||
// create matrix from a non-uniform scale, orientation and position
|
||||
glm::mat4 createMatFromScaleQuatAndPos(const glm::vec3& scale, const glm::quat& rot, const glm::vec3& trans) {
|
||||
glm::vec3 xAxis = rot * glm::vec3(scale.x, 0.0f, 0.0f);
|
||||
glm::vec3 yAxis = rot * glm::vec3(0.0f, scale.y, 0.0f);
|
||||
glm::vec3 zAxis = rot * glm::vec3(0.0f, 0.0f, scale.z);
|
||||
return glm::mat4(glm::vec4(xAxis, 0.0f), glm::vec4(yAxis, 0.0f),
|
||||
glm::vec4(zAxis, 0.0f), glm::vec4(trans, 1.0f));
|
||||
}
|
||||
|
||||
// cancel out roll and pitch
|
||||
glm::quat cancelOutRollAndPitch(const glm::quat& q) {
|
||||
glm::vec3 zAxis = q * glm::vec3(0.0f, 0.0f, 1.0f);
|
||||
|
|
|
@ -212,6 +212,7 @@ glm::detail::tvec4<T, P> lerp(const glm::detail::tvec4<T, P>& x, const glm::deta
|
|||
}
|
||||
|
||||
glm::mat4 createMatFromQuatAndPos(const glm::quat& q, const glm::vec3& p);
|
||||
glm::mat4 createMatFromScaleQuatAndPos(const glm::vec3& scale, const glm::quat& rot, const glm::vec3& trans);
|
||||
glm::quat cancelOutRollAndPitch(const glm::quat& q);
|
||||
glm::mat4 cancelOutRollAndPitch(const glm::mat4& m);
|
||||
glm::vec3 transformPoint(const glm::mat4& m, const glm::vec3& p);
|
||||
|
|
|
@ -34,6 +34,7 @@ static int collisionMetaTypeId = qRegisterMetaType<Collision>();
|
|||
static int qMapURLStringMetaTypeId = qRegisterMetaType<QMap<QUrl,QString>>();
|
||||
|
||||
void registerMetaTypes(QScriptEngine* engine) {
|
||||
qScriptRegisterMetaType(engine, mat4toScriptValue, mat4FromScriptValue);
|
||||
qScriptRegisterMetaType(engine, vec4toScriptValue, vec4FromScriptValue);
|
||||
qScriptRegisterMetaType(engine, vec3toScriptValue, vec3FromScriptValue);
|
||||
qScriptRegisterMetaType(engine, qVectorVec3ToScriptValue, qVectorVec3FromScriptValue);
|
||||
|
@ -53,6 +54,46 @@ void registerMetaTypes(QScriptEngine* engine) {
|
|||
qScriptRegisterMetaType(engine, aaCubeToScriptValue, aaCubeFromScriptValue);
|
||||
}
|
||||
|
||||
QScriptValue mat4toScriptValue(QScriptEngine* engine, const glm::mat4& mat4) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty("r0c0", mat4[0][0]);
|
||||
obj.setProperty("r1c0", mat4[0][1]);
|
||||
obj.setProperty("r2c0", mat4[0][2]);
|
||||
obj.setProperty("r3c0", mat4[0][3]);
|
||||
obj.setProperty("r0c1", mat4[1][0]);
|
||||
obj.setProperty("r1c1", mat4[1][1]);
|
||||
obj.setProperty("r2c1", mat4[1][2]);
|
||||
obj.setProperty("r3c1", mat4[1][3]);
|
||||
obj.setProperty("r0c2", mat4[2][0]);
|
||||
obj.setProperty("r1c2", mat4[2][1]);
|
||||
obj.setProperty("r2c2", mat4[2][2]);
|
||||
obj.setProperty("r3c2", mat4[2][3]);
|
||||
obj.setProperty("r0c3", mat4[3][0]);
|
||||
obj.setProperty("r1c3", mat4[3][1]);
|
||||
obj.setProperty("r2c3", mat4[3][2]);
|
||||
obj.setProperty("r3c3", mat4[3][3]);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void mat4FromScriptValue(const QScriptValue& object, glm::mat4& mat4) {
|
||||
mat4[0][0] = object.property("r0c0").toVariant().toFloat();
|
||||
mat4[0][1] = object.property("r1c0").toVariant().toFloat();
|
||||
mat4[0][2] = object.property("r2c0").toVariant().toFloat();
|
||||
mat4[0][3] = object.property("r3c0").toVariant().toFloat();
|
||||
mat4[1][0] = object.property("r0c1").toVariant().toFloat();
|
||||
mat4[1][1] = object.property("r1c1").toVariant().toFloat();
|
||||
mat4[1][2] = object.property("r2c1").toVariant().toFloat();
|
||||
mat4[1][3] = object.property("r3c1").toVariant().toFloat();
|
||||
mat4[2][0] = object.property("r0c2").toVariant().toFloat();
|
||||
mat4[2][1] = object.property("r1c2").toVariant().toFloat();
|
||||
mat4[2][2] = object.property("r2c2").toVariant().toFloat();
|
||||
mat4[2][3] = object.property("r3c2").toVariant().toFloat();
|
||||
mat4[3][0] = object.property("r0c3").toVariant().toFloat();
|
||||
mat4[3][1] = object.property("r1c3").toVariant().toFloat();
|
||||
mat4[3][2] = object.property("r2c3").toVariant().toFloat();
|
||||
mat4[3][3] = object.property("r3c3").toVariant().toFloat();
|
||||
}
|
||||
|
||||
QScriptValue vec4toScriptValue(QScriptEngine* engine, const glm::vec4& vec4) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty("x", vec4.x);
|
||||
|
|
|
@ -28,6 +28,7 @@ Q_DECLARE_METATYPE(glm::vec4)
|
|||
Q_DECLARE_METATYPE(glm::vec3)
|
||||
Q_DECLARE_METATYPE(glm::vec2)
|
||||
Q_DECLARE_METATYPE(glm::quat)
|
||||
Q_DECLARE_METATYPE(glm::mat4)
|
||||
Q_DECLARE_METATYPE(xColor)
|
||||
Q_DECLARE_METATYPE(QVector<glm::vec3>)
|
||||
Q_DECLARE_METATYPE(QVector<float>)
|
||||
|
@ -35,6 +36,10 @@ Q_DECLARE_METATYPE(AACube)
|
|||
|
||||
void registerMetaTypes(QScriptEngine* engine);
|
||||
|
||||
// Mat4
|
||||
QScriptValue mat4toScriptValue(QScriptEngine* engine, const glm::mat4& mat4);
|
||||
void mat4FromScriptValue(const QScriptValue& object, glm::mat4& mat4);
|
||||
|
||||
// Vec4
|
||||
QScriptValue vec4toScriptValue(QScriptEngine* engine, const glm::vec4& vec4);
|
||||
void vec4FromScriptValue(const QScriptValue& object, glm::vec4& vec4);
|
||||
|
|
|
@ -326,8 +326,8 @@ QVariant OffscreenUi::inputDialog(const Icon icon, const QString& title, const Q
|
|||
QVariant result;
|
||||
QMetaObject::invokeMethod(this, "inputDialog", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QVariant, result),
|
||||
Q_ARG(QString, title),
|
||||
Q_ARG(Icon, icon),
|
||||
Q_ARG(QString, title),
|
||||
Q_ARG(QString, label),
|
||||
Q_ARG(QVariant, current));
|
||||
return result;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
this.initialize = function(entityId) {
|
||||
var properties = Entities.getEntityProperties(entityId);
|
||||
if (properties.userData.length === 0 || properties.hasOwnProperty('userData') === false) {
|
||||
if (properties.userData.length === 0 || properties.hasOwnProperty('userData') === false || properties.userData==="") {
|
||||
self.initTimeout = Script.setTimeout(function() {
|
||||
// print(' no user data yet, try again in one second')
|
||||
self.initialize(entityId);
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -8,7 +8,7 @@
|
|||
var numDynein = 2;
|
||||
var numKinesin = 2;
|
||||
var percentOnMainMT = 100;
|
||||
//print('RUNNING AC!!');
|
||||
|
||||
var baseLocation;
|
||||
if (USE_LOCAL_HOST === true) {
|
||||
baseLocation = "http://localhost:8080/";
|
||||
|
@ -16,13 +16,32 @@ if (USE_LOCAL_HOST === true) {
|
|||
baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"
|
||||
}
|
||||
|
||||
var WORLD_OFFSET = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
}
|
||||
|
||||
var WORLD_SCALE_AMOUNT = 1.0;
|
||||
|
||||
function offsetVectorToWorld(vector) {
|
||||
var newVector;
|
||||
|
||||
newVector = Vec3.sum(vector, WORLD_OFFSET);
|
||||
|
||||
print('JBP NEW VECTOR IS:: ' + JSON.stringify(newVector))
|
||||
return newVector
|
||||
}
|
||||
|
||||
var USE_LOCAL_HOST = false;
|
||||
|
||||
EntityViewer.setPosition({
|
||||
var basePosition = offsetVectorToWorld({
|
||||
x: 3000,
|
||||
y: 13500,
|
||||
z: 3000
|
||||
});
|
||||
|
||||
EntityViewer.setPosition(basePosition);
|
||||
EntityViewer.setKeyholeRadius(60000);
|
||||
var octreeQueryInterval = Script.setInterval(function() {
|
||||
EntityViewer.queryOctree();
|
||||
|
@ -44,11 +63,12 @@ var scriptURL = this.baseLocation + "Scripts/clickToRideAndLook.js?" + Math.rand
|
|||
|
||||
var t = 0;
|
||||
var tInc = 0.001;
|
||||
var sceneOffset = {
|
||||
var sceneOffset = offsetVectorToWorld({
|
||||
x: 3000,
|
||||
y: 13500,
|
||||
z: 3000
|
||||
};
|
||||
});
|
||||
|
||||
var yOffset = {
|
||||
dynein: 16,
|
||||
kinesin: -28
|
||||
|
@ -60,11 +80,11 @@ var terms;
|
|||
var secondaryInit = false;
|
||||
|
||||
function deleteAllMotorProteins() {
|
||||
var position = {
|
||||
var position = offsetVectorToWorld({
|
||||
x: 3280,
|
||||
y: 13703,
|
||||
z: 4405
|
||||
};
|
||||
});
|
||||
|
||||
if (secondaryInit === true) {
|
||||
return;
|
||||
|
@ -83,7 +103,7 @@ function deleteAllMotorProteins() {
|
|||
results.forEach(function(r) {
|
||||
var name = Entities.getEntityProperties(r, 'name').name;
|
||||
if (name.indexOf('Hifi-Motor-Protein-Anchor') > -1) {
|
||||
// print('Script.clearTimeout DELETING A MOTOR PROTEIN::' + r)
|
||||
// print('Script.clearTimeout DELETING A MOTOR PROTEIN::' + r)
|
||||
Entities.deleteEntity(r);
|
||||
}
|
||||
|
||||
|
@ -95,7 +115,7 @@ function deleteAllMotorProteins() {
|
|||
}
|
||||
|
||||
function makeAll() {
|
||||
// print('CREATING MOTOR PROTEINS')
|
||||
// print('CREATING MOTOR PROTEINS')
|
||||
var segment;
|
||||
var segments = shuffleSegments();
|
||||
var lastSegment = [];
|
||||
|
@ -195,11 +215,11 @@ function update(deltaTime) {
|
|||
print("servers exist -- makeAll...");
|
||||
Entities.setPacketsPerSecond(6000);
|
||||
print("PPS:" + Entities.getPacketsPerSecond());
|
||||
Script.setTimeout(function(){
|
||||
Script.setTimeout(function() {
|
||||
//print('SETTING TIMEOUT')
|
||||
deleteAllMotorProteins()
|
||||
},10000)
|
||||
|
||||
deleteAllMotorProteins()
|
||||
}, 10000)
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
return;
|
||||
|
|
|
@ -4,12 +4,29 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
var WORLD_OFFSET = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
}
|
||||
|
||||
var basePosition = {
|
||||
var WORLD_SCALE_AMOUNT = 1.0;
|
||||
|
||||
|
||||
function offsetVectorToWorld(vector) {
|
||||
var newVector;
|
||||
|
||||
newVector = Vec3.sum(vector, WORLD_OFFSET);
|
||||
|
||||
print('JBP NEW VECTOR IS:: ' + JSON.stringify(newVector))
|
||||
return newVector
|
||||
}
|
||||
|
||||
var basePosition = offsetVectorToWorld({
|
||||
x: 3000,
|
||||
y: 13500,
|
||||
z: 3000
|
||||
};
|
||||
}, WORLD_OFFSET);
|
||||
|
||||
var initialized = false;
|
||||
|
||||
|
|
|
@ -4,12 +4,29 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
var WORLD_OFFSET = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
}
|
||||
|
||||
var basePosition = {
|
||||
var WORLD_SCALE_AMOUNT = 1.0;
|
||||
|
||||
function offsetVectorToWorld(vector) {
|
||||
var newVector;
|
||||
|
||||
newVector = Vec3.sum(vector, WORLD_OFFSET);
|
||||
|
||||
print('JBP NEW VECTOR IS:: ' + JSON.stringify(newVector))
|
||||
return newVector
|
||||
}
|
||||
|
||||
var basePosition = offsetVectorToWorld({
|
||||
x: 3000,
|
||||
y: 13500,
|
||||
z: 3000
|
||||
};
|
||||
}, WORLD_OFFSET);
|
||||
|
||||
|
||||
var initialized = false;
|
||||
|
||||
|
|
94
unpublishedScripts/DomainContent/Home/plant/flower.fs
Normal file
94
unpublishedScripts/DomainContent/Home/plant/flower.fs
Normal file
|
@ -0,0 +1,94 @@
|
|||
//
|
||||
// flowers.fs
|
||||
// examples/homeContent/plant
|
||||
//
|
||||
// Created by Eric Levin on 3/7/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// This fragment shader is designed to shader a sphere to create the effect of a blooming flower
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
|
||||
#define TWO_PI 6.28318530718
|
||||
|
||||
uniform float iBloomPct = 0.2;
|
||||
uniform vec3 iHSLColor = vec3(0.7, 0.5, 0.5);
|
||||
|
||||
|
||||
float hue2rgb(float f1, float f2, float hue) {
|
||||
if (hue < 0.0)
|
||||
hue += 1.0;
|
||||
else if (hue > 1.0)
|
||||
hue -= 1.0;
|
||||
float res;
|
||||
if ((6.0 * hue) < 1.0)
|
||||
res = f1 + (f2 - f1) * 6.0 * hue;
|
||||
else if ((2.0 * hue) < 1.0)
|
||||
res = f2;
|
||||
else if ((3.0 * hue) < 2.0)
|
||||
res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0;
|
||||
else
|
||||
res = f1;
|
||||
return res;
|
||||
}
|
||||
|
||||
vec3 hsl2rgb(vec3 hsl) {
|
||||
vec3 rgb;
|
||||
|
||||
if (hsl.y == 0.0) {
|
||||
rgb = vec3(hsl.z); // Luminance
|
||||
} else {
|
||||
float f2;
|
||||
|
||||
if (hsl.z < 0.5)
|
||||
f2 = hsl.z * (1.0 + hsl.y);
|
||||
else
|
||||
f2 = hsl.z + hsl.y - hsl.y * hsl.z;
|
||||
|
||||
float f1 = 2.0 * hsl.z - f2;
|
||||
|
||||
rgb.r = hue2rgb(f1, f2, hsl.x + (1.0/3.0));
|
||||
rgb.g = hue2rgb(f1, f2, hsl.x);
|
||||
rgb.b = hue2rgb(f1, f2, hsl.x - (1.0/3.0));
|
||||
}
|
||||
return rgb;
|
||||
}
|
||||
|
||||
vec3 hsl2rgb(float h, float s, float l) {
|
||||
return hsl2rgb(vec3(h, s, l));
|
||||
}
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
|
||||
vec2 st = fragCoord.xy/iWorldScale.xz;
|
||||
vec3 color = vec3(0.0, 0.0, 0.0);
|
||||
|
||||
vec2 toCenter = vec2(0.5) - st;
|
||||
float angle = atan(toCenter.y, toCenter.x);
|
||||
float radius = length(toCenter) * 2.0;
|
||||
|
||||
// Second check is so we discard the top half of the sphere
|
||||
if ( iBloomPct < radius || _position.y > 0) {
|
||||
discard;
|
||||
}
|
||||
|
||||
// simulate ambient occlusion
|
||||
float brightness = pow(radius, 0.8);
|
||||
vec3 hslColor = iHSLColor + (abs(angle) * 0.02);
|
||||
hslColor.z = 0.15 + pow(radius, 2.);
|
||||
vec3 rgbColor = hsl2rgb(hslColor);
|
||||
fragColor = vec4(rgbColor, 1.0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
vec4 getProceduralColor() {
|
||||
vec4 result;
|
||||
vec2 position = _position.xz;
|
||||
position += 0.5;
|
||||
|
||||
mainImage(result, position * iWorldScale.xz);
|
||||
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
//
|
||||
// growingPlantEntityScript.js
|
||||
// examples/homeContent/plant
|
||||
//
|
||||
// Created by Eric Levin on 2/10/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// This entity script handles the logic for growing a plant when it has water poured on it
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
|
||||
|
||||
(function() {
|
||||
Script.include('../../../../libraries/utils.js');
|
||||
|
||||
var _this;
|
||||
GrowingPlant = function() {
|
||||
_this = this;
|
||||
_this.flowers = [];
|
||||
// _this.STARTING_FLOWER_DIMENSIONS = {x: 0.1, y: 0.001, z: 0.1}
|
||||
_this.STARTING_FLOWER_DIMENSIONS = {
|
||||
x: 0.001,
|
||||
y: 0.001,
|
||||
z: 0.001
|
||||
}
|
||||
|
||||
_this.MAX_FLOWERS = 50;
|
||||
_this.MIN_FLOWER_TO_FLOWER_DISTANCE = 0.03;
|
||||
|
||||
_this.debounceRange = {
|
||||
min: 500,
|
||||
max: 1000
|
||||
};
|
||||
_this.canCreateFlower = true;
|
||||
_this.SHADER_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/shaders/flower.fs";
|
||||
// _this.SHADER_URL = "file:///C:/Users/Eric/hifi/unpublishedScripts/DomainContent/Home/plant/flower.fs";
|
||||
|
||||
_this.flowerHSLColors = [{
|
||||
hue: 19 / 360,
|
||||
saturation: 0.92,
|
||||
light: 0.31
|
||||
}, {
|
||||
hue: 161 / 360,
|
||||
saturation: 0.28,
|
||||
light: 0.62
|
||||
}];
|
||||
|
||||
};
|
||||
|
||||
GrowingPlant.prototype = {
|
||||
|
||||
|
||||
continueWatering: function(entityID, data) {
|
||||
// we're being watered- every now and then spawn a new flower to add to our growing list
|
||||
// If we don't have any flowers yet, immediately grow one
|
||||
var data = JSON.parse(data[0]);
|
||||
|
||||
if (_this.canCreateFlower && _this.flowers.length < _this.MAX_FLOWERS) {
|
||||
_this.createFlower(data.position, data.surfaceNormal);
|
||||
_this.canCreateFlower = false;
|
||||
Script.setTimeout(function() {
|
||||
_this.canCreateFlower = true;
|
||||
}, randFloat(_this.debounceRange.min, this.debounceRange.max));
|
||||
|
||||
}
|
||||
|
||||
_this.flowers.forEach(function(flower) {
|
||||
flower.grow();
|
||||
});
|
||||
|
||||
|
||||
},
|
||||
|
||||
createFlower: function(position, surfaceNormal) {
|
||||
if (_this.previousFlowerPosition && Vec3.distance(position, _this.previousFlowerPosition) < _this.MIN_FLOWER_TO_FLOWER_DISTANCE) {
|
||||
// Reduces flower overlap
|
||||
return;
|
||||
}
|
||||
var xzGrowthRate = randFloat(0.00006, 0.00016);
|
||||
var growthRate = {x: xzGrowthRate, y: randFloat(0.001, 0.003), z: xzGrowthRate};
|
||||
|
||||
var flower = {
|
||||
dimensions: {
|
||||
x: _this.STARTING_FLOWER_DIMENSIONS.x,
|
||||
y: _this.STARTING_FLOWER_DIMENSIONS.y,
|
||||
z: _this.STARTING_FLOWER_DIMENSIONS.z
|
||||
},
|
||||
startingPosition: position,
|
||||
rotation: Quat.rotationBetween(Vec3.UNIT_Y, surfaceNormal),
|
||||
maxYDimension: randFloat(0.4, 1.1),
|
||||
// startingHSLColor: {
|
||||
// hue: 80 / 360,
|
||||
// saturation: 0.47,
|
||||
// light: 0.48
|
||||
// },
|
||||
// endingHSLColor: {
|
||||
// hue: 19 / 260,
|
||||
// saturation: 0.92,
|
||||
// light: 0.41
|
||||
// },
|
||||
hslColor: Math.random() < 0.5 ? _this.flowerHSLColors[0] : _this.flowerHSLColors[1],
|
||||
growthRate: growthRate
|
||||
};
|
||||
flower.userData = {
|
||||
ProceduralEntity: {
|
||||
shaderUrl: _this.SHADER_URL,
|
||||
uniforms: {
|
||||
iBloomPct: randFloat(0.4, 0.8),
|
||||
iHSLColor: [flower.hslColor.hue, flower.hslColor.saturation, flower.hslColor.light]
|
||||
}
|
||||
}
|
||||
};
|
||||
flower.id = Entities.addEntity({
|
||||
type: "Sphere",
|
||||
name: "flower",
|
||||
lifetime: 3600,
|
||||
position: position,
|
||||
collisionless: true,
|
||||
rotation: flower.rotation,
|
||||
dimensions: _this.STARTING_FLOWER_DIMENSIONS,
|
||||
userData: JSON.stringify(flower.userData)
|
||||
});
|
||||
flower.grow = function() {
|
||||
// grow flower a bit
|
||||
if (flower.dimensions.y > flower.maxYDimension) {
|
||||
return;
|
||||
}
|
||||
flower.dimensions = Vec3.sum(flower.dimensions, flower.growthRate);
|
||||
flower.position = Vec3.sum(flower.startingPosition, Vec3.multiply(Quat.getUp(flower.rotation), flower.dimensions.y / 2));
|
||||
//As we grow we must also move ourselves in direction we grow!
|
||||
//TODO: Add this color changing back once we fix bug https://app.asana.com/0/inbox/31759584831096/96943843100173/98022172055918
|
||||
// var newHue = map(flower.dimensions.y, _this.STARTING_FLOWER_DIMENSIONS.y, flower.maxYDimension, flower.startingHSLColor.hue, flower.endingHSLColor.hue);
|
||||
// var newSaturation = map(flower.dimensions.y, _this.STARTING_FLOWER_DIMENSIONS.y, flower.maxYDimension, flower.startingHSLColor.saturation, flower.endingHSLColor.saturation);
|
||||
// var newLight = map(flower.dimensions.y, _this.STARTING_FLOWER_DIMENSIONS.y, flower.maxYDimension, flower.startingHSLColor.light, flower.endingHSLColor.light);
|
||||
// flower.userData.PrsoceduralEntity.uniforms.iHSLColor = [newHue, newSaturation, newLight];
|
||||
Entities.editEntity(flower.id, {
|
||||
dimensions: flower.dimensions,
|
||||
position: flower.position,
|
||||
});
|
||||
}
|
||||
_this.flowers.push(flower);
|
||||
_this.previousFlowerPosition = position;
|
||||
},
|
||||
|
||||
preload: function(entityID) {
|
||||
_this.entityID = entityID;
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
// entity scripts always need to return a newly constructed object of our type
|
||||
return new GrowingPlant();
|
||||
});
|
|
@ -0,0 +1,139 @@
|
|||
//
|
||||
// growingPlantSpawner.js
|
||||
// examples/homeContent/plant
|
||||
//
|
||||
// Created by Eric Levin on 2/10/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// This entity script handles the logic for growing a plant when it has water poured on it
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
|
||||
var orientation = Camera.getOrientation();
|
||||
orientation = Quat.safeEulerAngles(orientation);
|
||||
orientation.x = 0;
|
||||
orientation = Quat.fromVec3Degrees(orientation);
|
||||
|
||||
|
||||
var bowlPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(orientation)));
|
||||
var BOWL_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Flowers--Bowl.fbx";
|
||||
var bowlDimensions = {
|
||||
x: 0.518,
|
||||
y: 0.1938,
|
||||
z: 0.5518
|
||||
};
|
||||
var bowl = Entities.addEntity({
|
||||
type: "Model",
|
||||
modelURL: BOWL_MODEL_URL,
|
||||
dimensions: bowlDimensions,
|
||||
name: "plant bowl",
|
||||
position: bowlPosition
|
||||
});
|
||||
|
||||
|
||||
var PLANT_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Flowers--Moss-Rock.fbx";
|
||||
var PLANT_SCRIPT_URL = Script.resolvePath("growingPlantEntityScript.js?v1" + Math.random().toFixed(2));
|
||||
var plantDimensions = {
|
||||
x: 0.52,
|
||||
y: 0.2600,
|
||||
z: 0.52
|
||||
};
|
||||
var plantPosition = Vec3.sum(bowlPosition, {
|
||||
x: 0,
|
||||
y: plantDimensions.y / 2,
|
||||
z: 0
|
||||
});
|
||||
var plant = Entities.addEntity({
|
||||
type: "Model",
|
||||
modelURL: PLANT_MODEL_URL,
|
||||
name: "hifi-growable-plant",
|
||||
dimensions: plantDimensions,
|
||||
position: plantPosition,
|
||||
script: PLANT_SCRIPT_URL,
|
||||
parentID: bowl
|
||||
});
|
||||
|
||||
var WATER_CAN_MODEL_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/waterCan.fbx?v1" + Math.random();
|
||||
var WATER_CAN_SCRIPT_URL = Script.resolvePath("waterCanEntityScript.js?v2" + Math.random().toFixed());
|
||||
var waterCanPosition = Vec3.sum(plantPosition, Vec3.multiply(0.6, Quat.getRight(orientation)));
|
||||
var waterCanRotation = orientation;
|
||||
var waterCan = Entities.addEntity({
|
||||
type: "Model",
|
||||
shapeType: 'box',
|
||||
name: "hifi-water-can",
|
||||
modelURL: WATER_CAN_MODEL_URL,
|
||||
script: WATER_CAN_SCRIPT_URL,
|
||||
dimensions: {
|
||||
x: 0.1859,
|
||||
y: 0.2762,
|
||||
z: 0.4115
|
||||
},
|
||||
position: waterCanPosition,
|
||||
angularDamping: 1,
|
||||
dynamic: true,
|
||||
gravity: {
|
||||
x: 0.0,
|
||||
y: -2.0,
|
||||
z: 0
|
||||
},
|
||||
rotation: waterCanRotation,
|
||||
userData: JSON.stringify({
|
||||
wearable: {
|
||||
joints: {
|
||||
RightHand: [{
|
||||
x: 0.024,
|
||||
y: 0.173,
|
||||
z: 0.152
|
||||
}, {
|
||||
x: 0.374,
|
||||
y: 0.636,
|
||||
z: -0.638,
|
||||
w: -0.215
|
||||
}],
|
||||
LeftHand: [{
|
||||
x: -0.0348,
|
||||
y: 0.201,
|
||||
z: 0.166
|
||||
}, {
|
||||
x: 0.4095,
|
||||
y: -0.625,
|
||||
z: 0.616,
|
||||
w: -0.247
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
var waterSpoutPosition = Vec3.sum(waterCanPosition, Vec3.multiply(0.2, Quat.getFront(orientation)))
|
||||
var waterSpoutRotation = Quat.multiply(waterCanRotation, Quat.fromPitchYawRollDegrees(10, 0, 0));
|
||||
var waterSpout = Entities.addEntity({
|
||||
type: "Box",
|
||||
name: "hifi-water-spout",
|
||||
dimensions: {
|
||||
x: 0.02,
|
||||
y: 0.02,
|
||||
z: 0.07
|
||||
},
|
||||
color: {
|
||||
red: 200,
|
||||
green: 10,
|
||||
blue: 200
|
||||
},
|
||||
position: waterSpoutPosition,
|
||||
rotation: waterSpoutRotation,
|
||||
parentID: waterCan,
|
||||
visible: false
|
||||
});
|
||||
|
||||
function cleanup() {
|
||||
// Entities.deleteEntity(plant);
|
||||
// Entities.deleteEntity(bowl);
|
||||
// Entities.deleteEntity(waterCan);
|
||||
// Entities.deleteEntity(waterSpout);
|
||||
}
|
||||
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
|
@ -0,0 +1,242 @@
|
|||
//
|
||||
// waterCanEntityScript.js
|
||||
// examples/homeContent/plant
|
||||
//
|
||||
// Created by Eric Levin on 2/15/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// This entity script handles the logic for pouring water when a user tilts the entity the script is attached too.
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
|
||||
(function() {
|
||||
|
||||
Script.include('../../../../libraries/utils.js');
|
||||
|
||||
var _this;
|
||||
WaterSpout = function() {
|
||||
_this = this;
|
||||
_this.waterSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/eric/Sounds/shower.wav");
|
||||
_this.POUR_ANGLE_THRESHOLD = 0;
|
||||
_this.waterPouring = false;
|
||||
_this.WATER_SPOUT_NAME = "hifi-water-spout";
|
||||
_this.GROWABLE_ENTITIES_SEARCH_RANGE = 100;
|
||||
|
||||
};
|
||||
|
||||
WaterSpout.prototype = {
|
||||
|
||||
startNearGrab: function() {
|
||||
_this.startHold();
|
||||
},
|
||||
|
||||
startEquip: function() {
|
||||
_this.startHold();
|
||||
},
|
||||
|
||||
startHold: function() {
|
||||
_this.findGrowableEntities();
|
||||
},
|
||||
|
||||
releaseEquip: function() {
|
||||
_this.releaseHold();
|
||||
},
|
||||
|
||||
releaseGrab: function() {
|
||||
_this.releaseHold();
|
||||
},
|
||||
|
||||
releaseHold: function() {
|
||||
_this.stopPouring();
|
||||
},
|
||||
|
||||
stopPouring: function() {
|
||||
Entities.editEntity(_this.waterEffect, {
|
||||
isEmitting: false
|
||||
});
|
||||
_this.waterPouring = false;
|
||||
//water no longer pouring...
|
||||
if (_this.waterInjector) {
|
||||
_this.waterInjector.stop();
|
||||
}
|
||||
Entities.callEntityMethod(_this.mostRecentIntersectedGrowableEntity, 'stopWatering');
|
||||
},
|
||||
continueEquip: function() {
|
||||
_this.continueHolding();
|
||||
},
|
||||
|
||||
continueNearGrab: function() {
|
||||
_this.continueHolding();
|
||||
},
|
||||
|
||||
continueHolding: function() {
|
||||
if (!_this.waterSpout) {
|
||||
return;
|
||||
}
|
||||
// Check rotation of water can along it's z axis. If it's beyond a threshold, then start spraying water
|
||||
_this.castRay();
|
||||
var rotation = Entities.getEntityProperties(_this.entityID, "rotation").rotation;
|
||||
var pitch = Quat.safeEulerAngles(rotation).x;
|
||||
if (pitch < _this.POUR_ANGLE_THRESHOLD) {
|
||||
// Water is pouring
|
||||
var spoutProps = Entities.getEntityProperties(_this.waterSpout, ["rotation", "position"]);
|
||||
if (!_this.waterPouring) {
|
||||
Entities.editEntity(_this.waterEffect, {
|
||||
isEmitting: true
|
||||
});
|
||||
_this.waterPouring = true;
|
||||
if (!_this.waterInjector) {
|
||||
_this.waterInjector = Audio.playSound(_this.waterSound, {
|
||||
position: spoutProps.position,
|
||||
loop: true
|
||||
});
|
||||
|
||||
} else {
|
||||
_this.waterInjector.restart();
|
||||
}
|
||||
}
|
||||
_this.waterSpoutRotation = spoutProps.rotation;
|
||||
var waterEmitOrientation = Quat.multiply(_this.waterSpoutRotation, Quat.fromPitchYawRollDegrees(0, 180, 0));
|
||||
Entities.editEntity(_this.waterEffect, {
|
||||
emitOrientation: waterEmitOrientation
|
||||
});
|
||||
} else if (pitch > _this.POUR_ANGLE_THRESHOLD && _this.waterPouring) {
|
||||
_this.stopPouring();
|
||||
}
|
||||
},
|
||||
|
||||
castRay: function() {
|
||||
var spoutProps = Entities.getEntityProperties(_this.waterSpout, ["position, rotation"]);
|
||||
var direction = Quat.getFront(spoutProps.rotation)
|
||||
var end = Vec3.sum(spoutProps.position, Vec3.multiply(5, direction));
|
||||
|
||||
var pickRay = {
|
||||
origin: spoutProps.position,
|
||||
direction: direction
|
||||
};
|
||||
var intersection = Entities.findRayIntersection(pickRay, true, _this.growableEntities);
|
||||
|
||||
if (intersection.intersects) {
|
||||
//We've intersected with a waterable object
|
||||
var data = JSON.stringify({
|
||||
position: intersection.intersection,
|
||||
surfaceNormal: intersection.surfaceNormal
|
||||
});
|
||||
_this.mostRecentIntersectedGrowableEntity = intersection.entityID;
|
||||
Entities.callEntityMethod(intersection.entityID, 'continueWatering', [data]);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
||||
|
||||
createWaterEffect: function() {
|
||||
var waterEffectPosition = Vec3.sum(_this.waterSpoutPosition, Vec3.multiply(Quat.getFront(_this.waterSpoutRotation), -0.04));
|
||||
_this.waterEffect = Entities.addEntity({
|
||||
type: "ParticleEffect",
|
||||
name: "water particle effect",
|
||||
position: waterEffectPosition,
|
||||
isEmitting: false,
|
||||
parentID: _this.waterSpout,
|
||||
colorStart: {
|
||||
red: 90,
|
||||
green: 90,
|
||||
blue: 110
|
||||
},
|
||||
color: {
|
||||
red: 70,
|
||||
green: 70,
|
||||
blue: 130
|
||||
},
|
||||
colorFinish: {
|
||||
red: 23,
|
||||
green: 195,
|
||||
blue: 206
|
||||
},
|
||||
maxParticles: 20000,
|
||||
lifespan: 2,
|
||||
emitRate: 2000,
|
||||
emitSpeed: .3,
|
||||
speedSpread: 0.1,
|
||||
emitDimensions: {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0
|
||||
},
|
||||
emitAcceleration: {
|
||||
x: 0.0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
polarStart: 0.0,
|
||||
polarFinish: 0.1,
|
||||
accelerationSpread: {
|
||||
x: 0.01,
|
||||
y: 0.0,
|
||||
z: 0.01
|
||||
},
|
||||
emitOrientation: Quat.fromPitchYawRollDegrees(0, 0, 0),
|
||||
radiusSpread: 0.0001,
|
||||
radiusStart: 0.005,
|
||||
particleRadius: 0.003,
|
||||
radiusFinish: 0.001,
|
||||
alphaSpread: 0,
|
||||
alphaStart: 0.1,
|
||||
alpha: 1.0,
|
||||
alphaFinish: 1.0,
|
||||
emitterShouldTrail: true,
|
||||
textures: "https://s3-us-west-1.amazonaws.com/hifi-content/eric/images/raindrop.png",
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
findGrowableEntities: function() {
|
||||
_this.growableEntities = [];
|
||||
var entities = Entities.findEntities(_this.position, _this.GROWABLE_ENTITIES_SEARCH_RANGE);
|
||||
entities.forEach(function(entity) {
|
||||
var name = Entities.getEntityProperties(entity, "name").name;
|
||||
if (name.length > 0 && name.indexOf("growable") !== -1) {
|
||||
_this.growableEntities.push(entity);
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
preload: function(entityID) {
|
||||
_this.entityID = entityID;
|
||||
_this.position = Entities.getEntityProperties(_this.entityID, "position").position;
|
||||
// Wait a a bit for spout to spawn for case where preload is initial spawn, then save it
|
||||
Script.setTimeout(function() {
|
||||
var entities = Entities.findEntities(_this.position, 1);
|
||||
entities.forEach(function(entity) {
|
||||
var name = Entities.getEntityProperties(entity, "name").name;
|
||||
if (name === _this.WATER_SPOUT_NAME) {
|
||||
_this.waterSpout = entity;
|
||||
}
|
||||
});
|
||||
|
||||
if (_this.waterSpout) {
|
||||
_this.waterSpoutPosition = Entities.getEntityProperties(_this.waterSpout, "position").position;
|
||||
_this.waterSpoutRotation = Entities.getEntityProperties(_this.waterSpout, "rotation").rotation;
|
||||
_this.createWaterEffect();
|
||||
}
|
||||
|
||||
}, 3000);
|
||||
|
||||
},
|
||||
|
||||
|
||||
unload: function() {
|
||||
Entities.deleteEntity(_this.waterEffect);
|
||||
if (_this.waterInjector) {
|
||||
_this.waterInjector.stop();
|
||||
delete _this.waterInjector;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// entity scripts always need to return a newly constructed object of our type
|
||||
return new WaterSpout();
|
||||
});
|
Loading…
Reference in a new issue