mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 17:24:24 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into edit-always-on
This commit is contained in:
commit
77c78689d1
21 changed files with 1410 additions and 760 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -3,7 +3,7 @@ CMakeCache.txt
|
||||||
CMakeFiles/
|
CMakeFiles/
|
||||||
CMakeScripts/
|
CMakeScripts/
|
||||||
cmake_install.cmake
|
cmake_install.cmake
|
||||||
build/
|
build*/
|
||||||
Makefile
|
Makefile
|
||||||
*.user
|
*.user
|
||||||
|
|
||||||
|
|
118
examples/blocks.js
Normal file
118
examples/blocks.js
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
//
|
||||||
|
// Blocks.js
|
||||||
|
//
|
||||||
|
// Created by Philip Rosedale on January 26, 2015
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Create a bunch of building blocks and drop them onto a playing surface 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 FLOOR_SIZE = 7.5;
|
||||||
|
var FLOOR_THICKNESS = 0.10;
|
||||||
|
var EDGE_THICKESS = 0.25;
|
||||||
|
var SCALE = 0.25;
|
||||||
|
|
||||||
|
var NUM_BLOCKS = 25;
|
||||||
|
var DROP_HEIGHT = SCALE * 8.0;
|
||||||
|
|
||||||
|
var GRAVITY = -1.0;
|
||||||
|
var LIFETIME = 6000;
|
||||||
|
var DAMPING = 0.50;
|
||||||
|
|
||||||
|
var blockTypes = [];
|
||||||
|
blockTypes.push({ x: 1, y: 1, z: 1, red: 255, green: 0, blue: 0 });
|
||||||
|
blockTypes.push({ x: 1, y: 1, z: 2, red: 0, green: 255, blue: 0 });
|
||||||
|
blockTypes.push({ x: 1, y: 2, z: 5, red: 0, green: 0, blue: 255 });
|
||||||
|
blockTypes.push({ x: 1, y: 2, z: 2, red: 255, green: 255, blue: 0 });
|
||||||
|
blockTypes.push({ x: 1, y: 1, z: 5, red: 0, green: 255, blue: 255 });
|
||||||
|
|
||||||
|
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(FLOOR_SIZE * 2.0, Quat.getFront(Camera.getOrientation())));
|
||||||
|
|
||||||
|
var floor = Entities.addEntity(
|
||||||
|
{ type: "Box",
|
||||||
|
position: Vec3.subtract(center, { x: 0, y: SCALE / 2.0, z: 0 }),
|
||||||
|
dimensions: { x: FLOOR_SIZE, y: FLOOR_THICKNESS, z: FLOOR_SIZE },
|
||||||
|
color: { red: 128, green: 128, blue: 128 },
|
||||||
|
gravity: { x: 0, y: 0, z: 0 },
|
||||||
|
ignoreCollisions: false,
|
||||||
|
locked: true,
|
||||||
|
lifetime: LIFETIME });
|
||||||
|
|
||||||
|
var edge1 = Entities.addEntity(
|
||||||
|
{ type: "Box",
|
||||||
|
position: Vec3.sum(center, { x: FLOOR_SIZE / 2.0, y: FLOOR_THICKNESS / 2.0, z: 0 }),
|
||||||
|
dimensions: { x: EDGE_THICKESS, y: EDGE_THICKESS, z: FLOOR_SIZE },
|
||||||
|
color: { red: 128, green: 128, blue: 128 },
|
||||||
|
gravity: { x: 0, y: 0, z: 0 },
|
||||||
|
ignoreCollisions: false,
|
||||||
|
visible: true,
|
||||||
|
locked: true,
|
||||||
|
lifetime: LIFETIME });
|
||||||
|
|
||||||
|
var edge2 = Entities.addEntity(
|
||||||
|
{ type: "Box",
|
||||||
|
position: Vec3.sum(center, { x: -FLOOR_SIZE / 2.0, y: FLOOR_THICKNESS / 2.0, z: 0 }),
|
||||||
|
dimensions: { x: EDGE_THICKESS, y: EDGE_THICKESS, z: FLOOR_SIZE },
|
||||||
|
color: { red: 128, green: 128, blue: 128 },
|
||||||
|
gravity: { x: 0, y: 0, z: 0 },
|
||||||
|
ignoreCollisions: false,
|
||||||
|
visible: true,
|
||||||
|
locked: true,
|
||||||
|
lifetime: LIFETIME });
|
||||||
|
|
||||||
|
var edge3 = Entities.addEntity(
|
||||||
|
{ type: "Box",
|
||||||
|
position: Vec3.sum(center, { x: 0, y: FLOOR_THICKNESS / 2.0, z: -FLOOR_SIZE / 2.0 }),
|
||||||
|
dimensions: { x: FLOOR_SIZE, y: EDGE_THICKESS, z: EDGE_THICKESS },
|
||||||
|
color: { red: 128, green: 128, blue: 128 },
|
||||||
|
gravity: { x: 0, y: 0, z: 0 },
|
||||||
|
ignoreCollisions: false,
|
||||||
|
visible: true,
|
||||||
|
locked: true,
|
||||||
|
lifetime: LIFETIME });
|
||||||
|
|
||||||
|
var edge4 = Entities.addEntity(
|
||||||
|
{ type: "Box",
|
||||||
|
position: Vec3.sum(center, { x: 0, y: FLOOR_THICKNESS / 2.0, z: FLOOR_SIZE / 2.0 }),
|
||||||
|
dimensions: { x: FLOOR_SIZE, y: EDGE_THICKESS, z: EDGE_THICKESS },
|
||||||
|
color: { red: 128, green: 128, blue: 128 },
|
||||||
|
gravity: { x: 0, y: 0, z: 0 },
|
||||||
|
ignoreCollisions: false,
|
||||||
|
visible: true,
|
||||||
|
locked: true,
|
||||||
|
lifetime: LIFETIME });
|
||||||
|
|
||||||
|
blocks = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < NUM_BLOCKS; i++) {
|
||||||
|
var which = Math.floor(Math.random() * blockTypes.length);
|
||||||
|
var type = blockTypes[which];
|
||||||
|
blocks.push(Entities.addEntity(
|
||||||
|
{ type: "Box",
|
||||||
|
position: { x: center.x + (Math.random() - 0.5) * (FLOOR_SIZE * 0.75),
|
||||||
|
y: center.y + DROP_HEIGHT,
|
||||||
|
z: center.z + (Math.random() - 0.5) * (FLOOR_SIZE * 0.75) },
|
||||||
|
dimensions: { x: type.x * SCALE, y: type.y * SCALE, z: type.z * SCALE },
|
||||||
|
color: { red: type.red, green: type.green, blue: type.blue },
|
||||||
|
gravity: { x: 0, y: GRAVITY, z: 0 },
|
||||||
|
ignoreCollisions: false,
|
||||||
|
damping: DAMPING,
|
||||||
|
lifetime: LIFETIME,
|
||||||
|
collisionsWillMove: true }));
|
||||||
|
}
|
||||||
|
|
||||||
|
function scriptEnding() {
|
||||||
|
Entities.deleteEntity(edge1);
|
||||||
|
Entities.deleteEntity(edge2);
|
||||||
|
Entities.deleteEntity(edge3);
|
||||||
|
Entities.deleteEntity(edge4);
|
||||||
|
Entities.deleteEntity(floor);
|
||||||
|
|
||||||
|
for (var i = 0; i < NUM_BLOCKS; i++) {
|
||||||
|
Entities.deleteEntity(blocks[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(scriptEnding);
|
|
@ -304,7 +304,6 @@ function makePlatform(gravity, scale, size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function entityCollisionWithEntity(entity1, entity2, collision) {
|
function entityCollisionWithEntity(entity1, entity2, collision) {
|
||||||
|
|
||||||
if (((entity1.id == bulletID.id) || (entity1.id == targetID.id)) &&
|
if (((entity1.id == bulletID.id) || (entity1.id == targetID.id)) &&
|
||||||
((entity2.id == bulletID.id) || (entity2.id == targetID.id))) {
|
((entity2.id == bulletID.id) || (entity2.id == targetID.id))) {
|
||||||
score++;
|
score++;
|
||||||
|
@ -502,6 +501,7 @@ function scriptEnding() {
|
||||||
Overlays.deleteOverlay(pointer[1]);
|
Overlays.deleteOverlay(pointer[1]);
|
||||||
Overlays.deleteOverlay(text);
|
Overlays.deleteOverlay(text);
|
||||||
MyAvatar.detachOne(gunModel);
|
MyAvatar.detachOne(gunModel);
|
||||||
|
MyAvatar.detachOne(gunModel);
|
||||||
clearPose();
|
clearPose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,8 @@ var entityPropertyDialogBox = EntityPropertyDialogBox;
|
||||||
|
|
||||||
var MIN_ANGULAR_SIZE = 2;
|
var MIN_ANGULAR_SIZE = 2;
|
||||||
var MAX_ANGULAR_SIZE = 45;
|
var MAX_ANGULAR_SIZE = 45;
|
||||||
var allowLargeModels = false;
|
var allowLargeModels = true;
|
||||||
var allowSmallModels = false;
|
var allowSmallModels = true;
|
||||||
var wantEntityGlow = false;
|
var wantEntityGlow = false;
|
||||||
|
|
||||||
var LEFT = 0;
|
var LEFT = 0;
|
||||||
|
@ -28,15 +28,16 @@ var RIGHT = 1;
|
||||||
|
|
||||||
var jointList = MyAvatar.getJointNames();
|
var jointList = MyAvatar.getJointNames();
|
||||||
|
|
||||||
var STICKS = 0;
|
var LASER_WIDTH = 3;
|
||||||
var MAPPED = 1;
|
var LASER_COLOR = { red: 50, green: 150, blue: 200 };
|
||||||
var mode = STICKS;
|
var DROP_COLOR = { red: 200, green: 200, blue: 200 };
|
||||||
|
var DROP_WIDTH = 4;
|
||||||
|
var DROP_DISTANCE = 5.0;
|
||||||
|
|
||||||
var LASER_WIDTH = 4;
|
|
||||||
var LASER_COLOR = [{ red: 200, green: 150, blue: 50 }, // STICKS
|
|
||||||
{ red: 50, green: 150, blue: 200 }]; // MAPPED
|
|
||||||
var LASER_LENGTH_FACTOR = 500;
|
var LASER_LENGTH_FACTOR = 500;
|
||||||
|
|
||||||
|
var velocity = { x: 0, y: 0, z: 0 };
|
||||||
|
|
||||||
var lastAccurateIntersection = null;
|
var lastAccurateIntersection = null;
|
||||||
var accurateIntersections = 0;
|
var accurateIntersections = 0;
|
||||||
var totalIntersections = 0;
|
var totalIntersections = 0;
|
||||||
|
@ -107,6 +108,7 @@ function controller(wichSide) {
|
||||||
|
|
||||||
this.positionAtGrab;
|
this.positionAtGrab;
|
||||||
this.rotationAtGrab;
|
this.rotationAtGrab;
|
||||||
|
this.gravityAtGrab;
|
||||||
this.modelPositionAtGrab;
|
this.modelPositionAtGrab;
|
||||||
this.modelRotationAtGrab;
|
this.modelRotationAtGrab;
|
||||||
this.jointsIntersectingFromStart = [];
|
this.jointsIntersectingFromStart = [];
|
||||||
|
@ -114,13 +116,21 @@ function controller(wichSide) {
|
||||||
this.laser = Overlays.addOverlay("line3d", {
|
this.laser = Overlays.addOverlay("line3d", {
|
||||||
start: { x: 0, y: 0, z: 0 },
|
start: { x: 0, y: 0, z: 0 },
|
||||||
end: { x: 0, y: 0, z: 0 },
|
end: { x: 0, y: 0, z: 0 },
|
||||||
color: LASER_COLOR[mode],
|
color: LASER_COLOR,
|
||||||
alpha: 1,
|
alpha: 1,
|
||||||
visible: false,
|
visible: false,
|
||||||
lineWidth: LASER_WIDTH,
|
lineWidth: LASER_WIDTH,
|
||||||
anchor: "MyAvatar"
|
anchor: "MyAvatar"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.dropLine = Overlays.addOverlay("line3d", {
|
||||||
|
start: { x: 0, y: 0, z: 0 },
|
||||||
|
end: { x: 0, y: 0, z: 0 },
|
||||||
|
color: DROP_COLOR,
|
||||||
|
alpha: 1,
|
||||||
|
visible: false,
|
||||||
|
lineWidth: DROP_WIDTH });
|
||||||
|
|
||||||
this.guideScale = 0.02;
|
this.guideScale = 0.02;
|
||||||
this.ball = Overlays.addOverlay("sphere", {
|
this.ball = Overlays.addOverlay("sphere", {
|
||||||
position: { x: 0, y: 0, z: 0 },
|
position: { x: 0, y: 0, z: 0 },
|
||||||
|
@ -158,6 +168,7 @@ function controller(wichSide) {
|
||||||
this.entityID = entityID;
|
this.entityID = entityID;
|
||||||
this.modelURL = properties.modelURL;
|
this.modelURL = properties.modelURL;
|
||||||
|
|
||||||
|
|
||||||
this.oldModelPosition = properties.position;
|
this.oldModelPosition = properties.position;
|
||||||
this.oldModelRotation = properties.rotation;
|
this.oldModelRotation = properties.rotation;
|
||||||
this.oldModelHalfDiagonal = Vec3.length(properties.dimensions) / 2.0;
|
this.oldModelHalfDiagonal = Vec3.length(properties.dimensions) / 2.0;
|
||||||
|
@ -166,6 +177,10 @@ function controller(wichSide) {
|
||||||
this.rotationAtGrab = this.rotation;
|
this.rotationAtGrab = this.rotation;
|
||||||
this.modelPositionAtGrab = properties.position;
|
this.modelPositionAtGrab = properties.position;
|
||||||
this.modelRotationAtGrab = properties.rotation;
|
this.modelRotationAtGrab = properties.rotation;
|
||||||
|
this.gravityAtGrab = properties.gravity;
|
||||||
|
Entities.editEntity(entityID, { gravity: { x: 0, y: 0, z: 0 }, velocity: { x: 0, y: 0, z: 0 } });
|
||||||
|
|
||||||
|
|
||||||
this.jointsIntersectingFromStart = [];
|
this.jointsIntersectingFromStart = [];
|
||||||
for (var i = 0; i < jointList.length; i++) {
|
for (var i = 0; i < jointList.length; i++) {
|
||||||
var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition);
|
var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition);
|
||||||
|
@ -174,10 +189,14 @@ function controller(wichSide) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.showLaser(false);
|
this.showLaser(false);
|
||||||
|
Overlays.editOverlay(this.dropLine, { visible: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.release = function () {
|
this.release = function () {
|
||||||
if (this.grabbing) {
|
if (this.grabbing) {
|
||||||
|
|
||||||
|
Entities.editEntity(this.entityID, { gravity: this.gravityAtGrab });
|
||||||
|
|
||||||
jointList = MyAvatar.getJointNames();
|
jointList = MyAvatar.getJointNames();
|
||||||
|
|
||||||
var closestJointIndex = -1;
|
var closestJointIndex = -1;
|
||||||
|
@ -216,6 +235,8 @@ function controller(wichSide) {
|
||||||
Entities.deleteEntity(this.entityID);
|
Entities.deleteEntity(this.entityID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Overlays.editOverlay(this.dropLine, { visible: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.grabbing = false;
|
this.grabbing = false;
|
||||||
|
@ -288,7 +309,6 @@ function controller(wichSide) {
|
||||||
end: endPosition
|
end: endPosition
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
Overlays.editOverlay(this.ball, {
|
Overlays.editOverlay(this.ball, {
|
||||||
position: endPosition
|
position: endPosition
|
||||||
});
|
});
|
||||||
|
@ -300,7 +320,7 @@ function controller(wichSide) {
|
||||||
start: Vec3.sum(endPosition, Vec3.multiply(this.up, 2 * this.guideScale)),
|
start: Vec3.sum(endPosition, Vec3.multiply(this.up, 2 * this.guideScale)),
|
||||||
end: Vec3.sum(endPosition, Vec3.multiply(this.up, -2 * this.guideScale))
|
end: Vec3.sum(endPosition, Vec3.multiply(this.up, -2 * this.guideScale))
|
||||||
});
|
});
|
||||||
this.showLaser(!this.grabbing || mode == STICKS);
|
this.showLaser(!this.grabbing);
|
||||||
|
|
||||||
if (this.glowedIntersectingModel.isKnownID) {
|
if (this.glowedIntersectingModel.isKnownID) {
|
||||||
Entities.editEntity(this.glowedIntersectingModel, { glowLevel: 0.0 });
|
Entities.editEntity(this.glowedIntersectingModel, { glowLevel: 0.0 });
|
||||||
|
@ -332,7 +352,7 @@ function controller(wichSide) {
|
||||||
Overlays.editOverlay(this.leftRight, { visible: show });
|
Overlays.editOverlay(this.leftRight, { visible: show });
|
||||||
Overlays.editOverlay(this.topDown, { visible: show });
|
Overlays.editOverlay(this.topDown, { visible: show });
|
||||||
}
|
}
|
||||||
this.moveEntity = function () {
|
this.moveEntity = function (deltaTime) {
|
||||||
if (this.grabbing) {
|
if (this.grabbing) {
|
||||||
if (!this.entityID.isKnownID) {
|
if (!this.entityID.isKnownID) {
|
||||||
print("Unknown grabbed ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID);
|
print("Unknown grabbed ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID);
|
||||||
|
@ -344,55 +364,34 @@ function controller(wichSide) {
|
||||||
var newPosition;
|
var newPosition;
|
||||||
var newRotation;
|
var newRotation;
|
||||||
|
|
||||||
switch (mode) {
|
var CONSTANT_SCALING_FACTOR = 5.0;
|
||||||
case STICKS:
|
var MINIMUM_SCALING_DISTANCE = 2.0;
|
||||||
newPosition = Vec3.sum(this.palmPosition,
|
var distanceToModel = Vec3.length(Vec3.subtract(this.oldModelPosition, this.palmPosition));
|
||||||
Vec3.multiply(this.front, this.x));
|
if (distanceToModel < MINIMUM_SCALING_DISTANCE) {
|
||||||
newPosition = Vec3.sum(newPosition,
|
distanceToModel = MINIMUM_SCALING_DISTANCE;
|
||||||
Vec3.multiply(this.up, this.y));
|
|
||||||
newPosition = Vec3.sum(newPosition,
|
|
||||||
Vec3.multiply(this.right, this.z));
|
|
||||||
|
|
||||||
|
|
||||||
newRotation = Quat.multiply(this.rotation,
|
|
||||||
Quat.inverse(this.oldRotation));
|
|
||||||
newRotation = Quat.multiply(newRotation,
|
|
||||||
this.oldModelRotation);
|
|
||||||
break;
|
|
||||||
case MAPPED:
|
|
||||||
var forward = Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -1 });
|
|
||||||
var d = Vec3.dot(forward, MyAvatar.position);
|
|
||||||
|
|
||||||
var factor1 = Vec3.dot(forward, this.positionAtGrab) - d;
|
|
||||||
var factor2 = Vec3.dot(forward, this.modelPositionAtGrab) - d;
|
|
||||||
var vector = Vec3.subtract(this.palmPosition, this.positionAtGrab);
|
|
||||||
|
|
||||||
if (factor2 < 0) {
|
|
||||||
factor2 = 0;
|
|
||||||
}
|
|
||||||
if (factor1 <= 0) {
|
|
||||||
factor1 = 1;
|
|
||||||
factor2 = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
newPosition = Vec3.sum(this.modelPositionAtGrab,
|
|
||||||
Vec3.multiply(vector,
|
|
||||||
factor2 / factor1));
|
|
||||||
|
|
||||||
newRotation = Quat.multiply(this.rotation,
|
|
||||||
Quat.inverse(this.rotationAtGrab));
|
|
||||||
newRotation = Quat.multiply(newRotation, newRotation);
|
|
||||||
newRotation = Quat.multiply(newRotation,
|
|
||||||
this.modelRotationAtGrab);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var deltaPalm = Vec3.multiply(distanceToModel * CONSTANT_SCALING_FACTOR, Vec3.subtract(this.palmPosition, this.oldPalmPosition));
|
||||||
|
newPosition = Vec3.sum(this.oldModelPosition, deltaPalm);
|
||||||
|
|
||||||
|
newRotation = Quat.multiply(this.rotation,
|
||||||
|
Quat.inverse(this.rotationAtGrab));
|
||||||
|
newRotation = Quat.multiply(newRotation, newRotation);
|
||||||
|
newRotation = Quat.multiply(newRotation,
|
||||||
|
this.modelRotationAtGrab);
|
||||||
|
|
||||||
|
velocity = Vec3.multiply(1.0 / deltaTime, Vec3.subtract(newPosition, this.oldModelPosition));
|
||||||
|
|
||||||
Entities.editEntity(this.entityID, {
|
Entities.editEntity(this.entityID, {
|
||||||
position: newPosition,
|
position: newPosition,
|
||||||
rotation: newRotation
|
rotation: newRotation,
|
||||||
|
velocity: velocity
|
||||||
});
|
});
|
||||||
this.oldModelRotation = newRotation;
|
this.oldModelRotation = newRotation;
|
||||||
this.oldModelPosition = newPosition;
|
this.oldModelPosition = newPosition;
|
||||||
|
|
||||||
|
Overlays.editOverlay(this.dropLine, { start: newPosition, end: Vec3.sum(newPosition, { x: 0, y: -DROP_DISTANCE, z: 0 }) });
|
||||||
|
|
||||||
var indicesToRemove = [];
|
var indicesToRemove = [];
|
||||||
for (var i = 0; i < this.jointsIntersectingFromStart.length; ++i) {
|
for (var i = 0; i < this.jointsIntersectingFromStart.length; ++i) {
|
||||||
var distance = Vec3.distance(MyAvatar.getJointPosition(this.jointsIntersectingFromStart[i]), this.oldModelPosition);
|
var distance = Vec3.distance(MyAvatar.getJointPosition(this.jointsIntersectingFromStart[i]), this.oldModelPosition);
|
||||||
|
@ -428,15 +427,6 @@ function controller(wichSide) {
|
||||||
this.triggerValue = Controller.getTriggerValue(this.trigger);
|
this.triggerValue = Controller.getTriggerValue(this.trigger);
|
||||||
|
|
||||||
var bumperValue = Controller.isButtonPressed(this.bumper);
|
var bumperValue = Controller.isButtonPressed(this.bumper);
|
||||||
if (bumperValue && !this.bumperValue) {
|
|
||||||
if (mode === STICKS) {
|
|
||||||
mode = MAPPED;
|
|
||||||
} else if (mode === MAPPED) {
|
|
||||||
mode = STICKS;
|
|
||||||
}
|
|
||||||
Overlays.editOverlay(leftController.laser, { color: LASER_COLOR[mode] });
|
|
||||||
Overlays.editOverlay(rightController.laser, { color: LASER_COLOR[mode] });
|
|
||||||
}
|
|
||||||
this.bumperValue = bumperValue;
|
this.bumperValue = bumperValue;
|
||||||
|
|
||||||
|
|
||||||
|
@ -548,61 +538,37 @@ function controller(wichSide) {
|
||||||
var leftController = new controller(LEFT);
|
var leftController = new controller(LEFT);
|
||||||
var rightController = new controller(RIGHT);
|
var rightController = new controller(RIGHT);
|
||||||
|
|
||||||
function moveEntities() {
|
function moveEntities(deltaTime) {
|
||||||
if (leftController.grabbing && rightController.grabbing && rightController.entityID.id == leftController.entityID.id) {
|
if (leftController.grabbing && rightController.grabbing && rightController.entityID.id == leftController.entityID.id) {
|
||||||
var newPosition = leftController.oldModelPosition;
|
var newPosition = leftController.oldModelPosition;
|
||||||
var rotation = leftController.oldModelRotation;
|
var rotation = leftController.oldModelRotation;
|
||||||
var ratio = 1;
|
var ratio = 1;
|
||||||
|
|
||||||
|
var u = Vec3.normalize(Vec3.subtract(rightController.oldPalmPosition, leftController.oldPalmPosition));
|
||||||
|
var v = Vec3.normalize(Vec3.subtract(rightController.palmPosition, leftController.palmPosition));
|
||||||
|
|
||||||
switch (mode) {
|
var cos_theta = Vec3.dot(u, v);
|
||||||
case STICKS:
|
if (cos_theta > 1) {
|
||||||
var oldLeftPoint = Vec3.sum(leftController.oldPalmPosition, Vec3.multiply(leftController.oldFront, leftController.x));
|
cos_theta = 1;
|
||||||
var oldRightPoint = Vec3.sum(rightController.oldPalmPosition, Vec3.multiply(rightController.oldFront, rightController.x));
|
|
||||||
|
|
||||||
var oldMiddle = Vec3.multiply(Vec3.sum(oldLeftPoint, oldRightPoint), 0.5);
|
|
||||||
var oldLength = Vec3.length(Vec3.subtract(oldLeftPoint, oldRightPoint));
|
|
||||||
|
|
||||||
|
|
||||||
var leftPoint = Vec3.sum(leftController.palmPosition, Vec3.multiply(leftController.front, leftController.x));
|
|
||||||
var rightPoint = Vec3.sum(rightController.palmPosition, Vec3.multiply(rightController.front, rightController.x));
|
|
||||||
|
|
||||||
var middle = Vec3.multiply(Vec3.sum(leftPoint, rightPoint), 0.5);
|
|
||||||
var length = Vec3.length(Vec3.subtract(leftPoint, rightPoint));
|
|
||||||
|
|
||||||
|
|
||||||
ratio = length / oldLength;
|
|
||||||
newPosition = Vec3.sum(middle,
|
|
||||||
Vec3.multiply(Vec3.subtract(leftController.oldModelPosition, oldMiddle), ratio));
|
|
||||||
break;
|
|
||||||
case MAPPED:
|
|
||||||
var u = Vec3.normalize(Vec3.subtract(rightController.oldPalmPosition, leftController.oldPalmPosition));
|
|
||||||
var v = Vec3.normalize(Vec3.subtract(rightController.palmPosition, leftController.palmPosition));
|
|
||||||
|
|
||||||
var cos_theta = Vec3.dot(u, v);
|
|
||||||
if (cos_theta > 1) {
|
|
||||||
cos_theta = 1;
|
|
||||||
}
|
|
||||||
var angle = Math.acos(cos_theta) / Math.PI * 180;
|
|
||||||
if (angle < 0.1) {
|
|
||||||
return;
|
|
||||||
|
|
||||||
}
|
|
||||||
var w = Vec3.normalize(Vec3.cross(u, v));
|
|
||||||
|
|
||||||
rotation = Quat.multiply(Quat.angleAxis(angle, w), leftController.oldModelRotation);
|
|
||||||
|
|
||||||
|
|
||||||
leftController.positionAtGrab = leftController.palmPosition;
|
|
||||||
leftController.rotationAtGrab = leftController.rotation;
|
|
||||||
leftController.modelPositionAtGrab = leftController.oldModelPosition;
|
|
||||||
leftController.modelRotationAtGrab = rotation;
|
|
||||||
rightController.positionAtGrab = rightController.palmPosition;
|
|
||||||
rightController.rotationAtGrab = rightController.rotation;
|
|
||||||
rightController.modelPositionAtGrab = rightController.oldModelPosition;
|
|
||||||
rightController.modelRotationAtGrab = rotation;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
var angle = Math.acos(cos_theta) / Math.PI * 180;
|
||||||
|
if (angle < 0.1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var w = Vec3.normalize(Vec3.cross(u, v));
|
||||||
|
|
||||||
|
rotation = Quat.multiply(Quat.angleAxis(angle, w), leftController.oldModelRotation);
|
||||||
|
|
||||||
|
|
||||||
|
leftController.positionAtGrab = leftController.palmPosition;
|
||||||
|
leftController.rotationAtGrab = leftController.rotation;
|
||||||
|
leftController.modelPositionAtGrab = leftController.oldModelPosition;
|
||||||
|
leftController.modelRotationAtGrab = rotation;
|
||||||
|
rightController.positionAtGrab = rightController.palmPosition;
|
||||||
|
rightController.rotationAtGrab = rightController.rotation;
|
||||||
|
rightController.modelPositionAtGrab = rightController.oldModelPosition;
|
||||||
|
rightController.modelRotationAtGrab = rotation;
|
||||||
|
|
||||||
Entities.editEntity(leftController.entityID, {
|
Entities.editEntity(leftController.entityID, {
|
||||||
position: newPosition,
|
position: newPosition,
|
||||||
rotation: rotation,
|
rotation: rotation,
|
||||||
|
@ -612,7 +578,6 @@ function moveEntities() {
|
||||||
y: leftController.oldModelHalfDiagonal * ratio,
|
y: leftController.oldModelHalfDiagonal * ratio,
|
||||||
z: leftController.oldModelHalfDiagonal * ratio }
|
z: leftController.oldModelHalfDiagonal * ratio }
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
leftController.oldModelPosition = newPosition;
|
leftController.oldModelPosition = newPosition;
|
||||||
leftController.oldModelRotation = rotation;
|
leftController.oldModelRotation = rotation;
|
||||||
|
@ -623,8 +588,8 @@ function moveEntities() {
|
||||||
rightController.oldModelHalfDiagonal *= ratio;
|
rightController.oldModelHalfDiagonal *= ratio;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
leftController.moveEntity();
|
leftController.moveEntity(deltaTime);
|
||||||
rightController.moveEntity();
|
rightController.moveEntity(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
var hydraConnected = false;
|
var hydraConnected = false;
|
||||||
|
@ -642,7 +607,7 @@ function checkController(deltaTime) {
|
||||||
|
|
||||||
leftController.update();
|
leftController.update();
|
||||||
rightController.update();
|
rightController.update();
|
||||||
moveEntities();
|
moveEntities(deltaTime);
|
||||||
} else {
|
} else {
|
||||||
if (hydraConnected) {
|
if (hydraConnected) {
|
||||||
hydraConnected = false;
|
hydraConnected = false;
|
||||||
|
|
|
@ -10,29 +10,42 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||||
|
|
||||||
|
hitSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-ballhitsandcatches/billiards/collision1.wav");
|
||||||
|
var rightHandAnimation = HIFI_PUBLIC_BUCKET + "animations/RightHandAnimPhilip.fbx";
|
||||||
|
var leftHandAnimation = HIFI_PUBLIC_BUCKET + "animations/LeftHandAnimPhilip.fbx";
|
||||||
|
|
||||||
var BALL_SIZE = 0.08;
|
var BALL_SIZE = 0.08;
|
||||||
var PADDLE_SIZE = 0.20;
|
var PADDLE_SIZE = 0.20;
|
||||||
var PADDLE_THICKNESS = 0.06;
|
var PADDLE_THICKNESS = 0.06;
|
||||||
var PADDLE_COLOR = { red: 184, green: 134, blue: 11 };
|
var PADDLE_COLOR = { red: 184, green: 134, blue: 11 };
|
||||||
var BALL_COLOR = { red: 255, green: 0, blue: 0 };
|
var BALL_COLOR = { red: 255, green: 0, blue: 0 };
|
||||||
var LINE_COLOR = { red: 255, green: 255, blue: 0 };
|
var LINE_COLOR = { red: 255, green: 255, blue: 0 };
|
||||||
var PADDLE_OFFSET = { x: 0.05, y: 0.0, z: 0.0 };
|
var PADDLE_BOX_OFFSET = { x: 0.05, y: 0.0, z: 0.0 };
|
||||||
|
|
||||||
|
var HOLD_POSITION_LEFT_OFFSET = { x: -0.15, y: 0.05, z: -0.05 };
|
||||||
|
var HOLD_POSITION_RIGHT_OFFSET = { x: -0.15, y: 0.05, z: 0.05 };
|
||||||
|
var PADDLE_ORIENTATION = Quat.fromPitchYawRollDegrees(0,0,0);
|
||||||
var GRAVITY = 0.0;
|
var GRAVITY = 0.0;
|
||||||
var SPRING_FORCE = 15.0;
|
var SPRING_FORCE = 15.0;
|
||||||
var lastSoundTime = 0;
|
var lastSoundTime = 0;
|
||||||
var gameOn = false;
|
var gameOn = false;
|
||||||
var leftHanded = false;
|
var leftHanded = true;
|
||||||
var controllerID;
|
var controllerID;
|
||||||
|
|
||||||
if (leftHanded) {
|
|
||||||
controllerID = 1;
|
function setControllerID() {
|
||||||
} else {
|
if (leftHanded) {
|
||||||
controllerID = 3;
|
controllerID = 1;
|
||||||
|
} else {
|
||||||
|
controllerID = 3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setControllerID();
|
||||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
Menu.addMenu("PaddleBall");
|
||||||
hitSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-ballhitsandcatches/billiards/collision1.wav");
|
Menu.addMenuItem({ menuName: "PaddleBall", menuItemName: "Left-Handed", isCheckable: true, isChecked: true });
|
||||||
|
|
||||||
var screenSize = Controller.getViewportDimensions();
|
var screenSize = Controller.getViewportDimensions();
|
||||||
var offButton = Overlays.addOverlay("image", {
|
var offButton = Overlays.addOverlay("image", {
|
||||||
|
@ -73,7 +86,7 @@ function createEntities() {
|
||||||
modelURL = "http://public.highfidelity.io/models/attachments/pong_paddle.fbx";
|
modelURL = "http://public.highfidelity.io/models/attachments/pong_paddle.fbx";
|
||||||
paddleModel = Entities.addEntity(
|
paddleModel = Entities.addEntity(
|
||||||
{ type: "Model",
|
{ type: "Model",
|
||||||
position: Vec3.sum(Controller.getSpatialControlPosition(controllerID), PADDLE_OFFSET),
|
position: Vec3.sum(Controller.getSpatialControlPosition(controllerID), PADDLE_BOX_OFFSET),
|
||||||
dimensions: { x: PADDLE_SIZE * 1.5, y: PADDLE_THICKNESS, z: PADDLE_SIZE * 1.25 },
|
dimensions: { x: PADDLE_SIZE * 1.5, y: PADDLE_THICKNESS, z: PADDLE_SIZE * 1.25 },
|
||||||
color: PADDLE_COLOR,
|
color: PADDLE_COLOR,
|
||||||
gravity: { x: 0, y: 0, z: 0 },
|
gravity: { x: 0, y: 0, z: 0 },
|
||||||
|
@ -90,6 +103,10 @@ function createEntities() {
|
||||||
alpha: 1,
|
alpha: 1,
|
||||||
visible: true,
|
visible: true,
|
||||||
lineWidth: 2 });
|
lineWidth: 2 });
|
||||||
|
|
||||||
|
MyAvatar.stopAnimation(leftHandAnimation);
|
||||||
|
MyAvatar.stopAnimation(rightHandAnimation);
|
||||||
|
MyAvatar.startAnimation(leftHanded ? leftHandAnimation: rightHandAnimation, 15.0, 1.0, false, true, 0.0, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteEntities() {
|
function deleteEntities() {
|
||||||
|
@ -97,6 +114,7 @@ function deleteEntities() {
|
||||||
Entities.deleteEntity(paddle);
|
Entities.deleteEntity(paddle);
|
||||||
Entities.deleteEntity(paddleModel);
|
Entities.deleteEntity(paddleModel);
|
||||||
Overlays.deleteOverlay(line);
|
Overlays.deleteOverlay(line);
|
||||||
|
MyAvatar.stopAnimation(leftHanded ? leftHandAnimation: rightHandAnimation);
|
||||||
}
|
}
|
||||||
|
|
||||||
function update(deltaTime) {
|
function update(deltaTime) {
|
||||||
|
@ -120,18 +138,23 @@ function update(deltaTime) {
|
||||||
if (!ball.isKnownID) {
|
if (!ball.isKnownID) {
|
||||||
ball = Entities.identifyEntity(ball);
|
ball = Entities.identifyEntity(ball);
|
||||||
} else {
|
} else {
|
||||||
|
var paddleOrientation = leftHanded ? PADDLE_ORIENTATION : Quat.multiply(PADDLE_ORIENTATION, Quat.fromPitchYawRollDegrees(0, 180, 0));
|
||||||
|
var paddleWorldOrientation = Quat.multiply(Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(controllerID)), paddleOrientation);
|
||||||
|
var holdPosition = Vec3.sum(leftHanded ? MyAvatar.getLeftPalmPosition() : MyAvatar.getRightPalmPosition(),
|
||||||
|
Vec3.multiplyQbyV(paddleWorldOrientation, leftHanded ? HOLD_POSITION_LEFT_OFFSET : HOLD_POSITION_RIGHT_OFFSET ));
|
||||||
|
|
||||||
var props = Entities.getEntityProperties(ball);
|
var props = Entities.getEntityProperties(ball);
|
||||||
var spring = Vec3.subtract(palmPosition, props.position);
|
var spring = Vec3.subtract(holdPosition, props.position);
|
||||||
var paddleWorldOrientation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(controllerID));
|
|
||||||
var springLength = Vec3.length(spring);
|
var springLength = Vec3.length(spring);
|
||||||
|
|
||||||
spring = Vec3.normalize(spring);
|
spring = Vec3.normalize(spring);
|
||||||
var ballVelocity = Vec3.sum(props.velocity, Vec3.multiply(springLength * SPRING_FORCE * deltaTime, spring));
|
var ballVelocity = Vec3.sum(props.velocity, Vec3.multiply(springLength * SPRING_FORCE * deltaTime, spring));
|
||||||
Entities.editEntity(ball, { velocity: ballVelocity });
|
Entities.editEntity(ball, { velocity: ballVelocity });
|
||||||
Overlays.editOverlay(line, { start: props.position, end: palmPosition });
|
Overlays.editOverlay(line, { start: props.position, end: holdPosition });
|
||||||
Entities.editEntity(paddle, { position: palmPosition,
|
Entities.editEntity(paddle, { position: holdPosition,
|
||||||
velocity: Controller.getSpatialControlVelocity(controllerID),
|
velocity: Controller.getSpatialControlVelocity(controllerID),
|
||||||
rotation: paddleWorldOrientation });
|
rotation: paddleWorldOrientation });
|
||||||
Entities.editEntity(paddleModel, { position: Vec3.sum(palmPosition, Vec3.multiplyQbyV(paddleWorldOrientation, PADDLE_OFFSET)),
|
Entities.editEntity(paddleModel, { position: Vec3.sum(holdPosition, Vec3.multiplyQbyV(paddleWorldOrientation, PADDLE_BOX_OFFSET)),
|
||||||
velocity: Controller.getSpatialControlVelocity(controllerID),
|
velocity: Controller.getSpatialControlVelocity(controllerID),
|
||||||
rotation: paddleWorldOrientation });
|
rotation: paddleWorldOrientation });
|
||||||
}
|
}
|
||||||
|
@ -159,14 +182,30 @@ function mousePressEvent(event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function menuItemEvent(menuItem) {
|
||||||
|
oldHanded = leftHanded;
|
||||||
|
if (menuItem == "Left-Handed") {
|
||||||
|
leftHanded = Menu.isOptionChecked("Left-Handed");
|
||||||
|
}
|
||||||
|
if ((leftHanded != oldHanded) && gameOn) {
|
||||||
|
setControllerID();
|
||||||
|
deleteEntities();
|
||||||
|
createEntities();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function scriptEnding() {
|
function scriptEnding() {
|
||||||
if (gameOn) {
|
if (gameOn) {
|
||||||
deleteEntities();
|
deleteEntities();
|
||||||
}
|
}
|
||||||
Overlays.deleteOverlay(offButton);
|
Overlays.deleteOverlay(offButton);
|
||||||
|
MyAvatar.stopAnimation(leftHandAnimation);
|
||||||
|
MyAvatar.stopAnimation(rightHandAnimation);
|
||||||
|
Menu.removeMenu("PaddleBall");
|
||||||
}
|
}
|
||||||
|
|
||||||
Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity);
|
Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity);
|
||||||
|
Menu.menuItemEvent.connect(menuItemEvent);
|
||||||
Controller.mousePressEvent.connect(mousePressEvent);
|
Controller.mousePressEvent.connect(mousePressEvent);
|
||||||
Script.scriptEnding.connect(scriptEnding);
|
Script.scriptEnding.connect(scriptEnding);
|
||||||
Script.update.connect(update);
|
Script.update.connect(update);
|
||||||
|
|
|
@ -12,34 +12,38 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||||
Script.include("libraries/stringHelpers.js");
|
|
||||||
Script.include("libraries/dataviewHelpers.js");
|
|
||||||
Script.include("libraries/httpMultiPart.js");
|
|
||||||
Script.include("libraries/modelUploader.js");
|
|
||||||
Script.include("libraries/toolBars.js");
|
|
||||||
Script.include("libraries/progressDialog.js");
|
|
||||||
|
|
||||||
Script.include("libraries/entitySelectionTool.js");
|
Script.include([
|
||||||
|
"http://public.highfidelity.io/scripts/libraries/stringHelpers.js",
|
||||||
|
"http://public.highfidelity.io/scripts/libraries/dataviewHelpers.js",
|
||||||
|
"http://public.highfidelity.io/scripts/libraries/httpMultiPart.js",
|
||||||
|
"http://public.highfidelity.io/scripts/libraries/modelUploader.js",
|
||||||
|
"http://public.highfidelity.io/scripts/libraries/toolBars.js",
|
||||||
|
"http://public.highfidelity.io/scripts/libraries/progressDialog.js",
|
||||||
|
|
||||||
|
"http://public.highfidelity.io/scripts/libraries/entitySelectionTool.js",
|
||||||
|
"http://public.highfidelity.io/scripts/libraries/ModelImporter.js",
|
||||||
|
|
||||||
|
"http://public.highfidelity.io/scripts/libraries/ExportMenu.js",
|
||||||
|
"http://public.highfidelity.io/scripts/libraries/ToolTip.js",
|
||||||
|
|
||||||
|
"http://public.highfidelity.io/scripts/libraries/entityPropertyDialogBox.js",
|
||||||
|
"http://public.highfidelity.io/scripts/libraries/entityCameraTool.js",
|
||||||
|
"http://public.highfidelity.io/scripts/libraries/gridTool.js",
|
||||||
|
"http://public.highfidelity.io/scripts/libraries/entityList.js",
|
||||||
|
]);
|
||||||
|
|
||||||
var selectionDisplay = SelectionDisplay;
|
var selectionDisplay = SelectionDisplay;
|
||||||
var selectionManager = SelectionManager;
|
var selectionManager = SelectionManager;
|
||||||
|
|
||||||
Script.include("libraries/ModelImporter.js");
|
|
||||||
var modelImporter = new ModelImporter();
|
var modelImporter = new ModelImporter();
|
||||||
|
|
||||||
Script.include("libraries/ExportMenu.js");
|
|
||||||
Script.include("libraries/ToolTip.js");
|
|
||||||
|
|
||||||
Script.include("libraries/entityPropertyDialogBox.js");
|
|
||||||
var entityPropertyDialogBox = EntityPropertyDialogBox;
|
var entityPropertyDialogBox = EntityPropertyDialogBox;
|
||||||
|
|
||||||
Script.include("libraries/entityCameraTool.js");
|
|
||||||
var cameraManager = new CameraManager();
|
var cameraManager = new CameraManager();
|
||||||
|
|
||||||
Script.include("libraries/gridTool.js");
|
|
||||||
var grid = Grid();
|
var grid = Grid();
|
||||||
gridTool = GridTool({ horizontalGrid: grid });
|
gridTool = GridTool({ horizontalGrid: grid });
|
||||||
|
gridTool.setVisible(false);
|
||||||
|
|
||||||
Script.include("libraries/entityList.js");
|
|
||||||
var entityListTool = EntityListTool();
|
var entityListTool = EntityListTool();
|
||||||
|
|
||||||
var hasShownPropertiesTool = false;
|
var hasShownPropertiesTool = false;
|
||||||
|
@ -52,8 +56,10 @@ selectionManager.addEventListener(function() {
|
||||||
// Open properties and model list, but force selection of model list tab
|
// Open properties and model list, but force selection of model list tab
|
||||||
propertiesTool.setVisible(false);
|
propertiesTool.setVisible(false);
|
||||||
entityListTool.setVisible(false);
|
entityListTool.setVisible(false);
|
||||||
|
gridTool.setVisible(false);
|
||||||
propertiesTool.setVisible(true);
|
propertiesTool.setVisible(true);
|
||||||
entityListTool.setVisible(true);
|
entityListTool.setVisible(true);
|
||||||
|
gridTool.setVisible(true);
|
||||||
hasShownPropertiesTool = true;
|
hasShownPropertiesTool = true;
|
||||||
}
|
}
|
||||||
if (!selectionManager.hasSelection()) {
|
if (!selectionManager.hasSelection()) {
|
||||||
|
@ -246,7 +252,6 @@ var toolBar = (function () {
|
||||||
} else {
|
} else {
|
||||||
hasShownPropertiesTool = false;
|
hasShownPropertiesTool = false;
|
||||||
cameraManager.enable();
|
cameraManager.enable();
|
||||||
gridTool.setVisible(true);
|
|
||||||
grid.setEnabled(true);
|
grid.setEnabled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -514,7 +519,7 @@ function mousePressEvent(event) {
|
||||||
mouseHasMovedSincePress = false;
|
mouseHasMovedSincePress = false;
|
||||||
mouseCapturedByTool = false;
|
mouseCapturedByTool = false;
|
||||||
|
|
||||||
if (toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event) || gridTool.mousePressEvent(event)) {
|
if (toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event)) {
|
||||||
mouseCapturedByTool = true;
|
mouseCapturedByTool = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -825,13 +830,15 @@ function handeMenuEvent(menuItem) {
|
||||||
Menu.menuItemEvent.connect(handeMenuEvent);
|
Menu.menuItemEvent.connect(handeMenuEvent);
|
||||||
|
|
||||||
Controller.keyPressEvent.connect(function(event) {
|
Controller.keyPressEvent.connect(function(event) {
|
||||||
if (event.text == 'w' || event.text == 'a' || event.text == 's' || event.text == 'd'
|
if (isActive) {
|
||||||
|| event.text == 'UP' || event.text == 'DOWN' || event.text == 'LEFT' || event.text == 'RIGHT') {
|
cameraManager.keyPressEvent(event);
|
||||||
toolBar.setActive(false);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Controller.keyReleaseEvent.connect(function (event) {
|
Controller.keyReleaseEvent.connect(function (event) {
|
||||||
|
if (isActive) {
|
||||||
|
cameraManager.keyReleaseEvent(event);
|
||||||
|
}
|
||||||
// since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items
|
// since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items
|
||||||
if (event.text == "BACKSPACE" || event.text == "DELETE") {
|
if (event.text == "BACKSPACE" || event.text == "DELETE") {
|
||||||
deleteSelectedEntities();
|
deleteSelectedEntities();
|
||||||
|
@ -857,55 +864,6 @@ Controller.keyReleaseEvent.connect(function (event) {
|
||||||
newPosition = Vec3.subtract(newPosition, { x: 0, y: selectionManager.worldDimensions.y * 0.5, z: 0 });
|
newPosition = Vec3.subtract(newPosition, { x: 0, y: selectionManager.worldDimensions.y * 0.5, z: 0 });
|
||||||
grid.setPosition(newPosition);
|
grid.setPosition(newPosition);
|
||||||
}
|
}
|
||||||
} else if (isActive) {
|
|
||||||
var delta = null;
|
|
||||||
var increment = event.isShifted ? grid.getMajorIncrement() : grid.getMinorIncrement();
|
|
||||||
|
|
||||||
if (event.text == 'UP') {
|
|
||||||
if (event.isControl || event.isAlt) {
|
|
||||||
delta = { x: 0, y: increment, z: 0 };
|
|
||||||
} else {
|
|
||||||
delta = { x: 0, y: 0, z: -increment };
|
|
||||||
}
|
|
||||||
} else if (event.text == 'DOWN') {
|
|
||||||
if (event.isControl || event.isAlt) {
|
|
||||||
delta = { x: 0, y: -increment, z: 0 };
|
|
||||||
} else {
|
|
||||||
delta = { x: 0, y: 0, z: increment };
|
|
||||||
}
|
|
||||||
} else if (event.text == 'LEFT') {
|
|
||||||
delta = { x: -increment, y: 0, z: 0 };
|
|
||||||
} else if (event.text == 'RIGHT') {
|
|
||||||
delta = { x: increment, y: 0, z: 0 };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (delta != null) {
|
|
||||||
// Adjust delta so that movements are relative to the current camera orientation
|
|
||||||
var lookDirection = Quat.getFront(Camera.getOrientation());
|
|
||||||
lookDirection.z *= -1;
|
|
||||||
|
|
||||||
var angle = Math.atan2(lookDirection.z, lookDirection.x);
|
|
||||||
angle -= (Math.PI / 4);
|
|
||||||
|
|
||||||
var rotation = Math.floor(angle / (Math.PI / 2)) * (Math.PI / 2);
|
|
||||||
var rotator = Quat.fromPitchYawRollRadians(0, rotation, 0);
|
|
||||||
|
|
||||||
delta = Vec3.multiplyQbyV(rotator, delta);
|
|
||||||
|
|
||||||
SelectionManager.saveProperties();
|
|
||||||
|
|
||||||
for (var i = 0; i < selectionManager.selections.length; i++) {
|
|
||||||
var entityID = selectionManager.selections[i];
|
|
||||||
var properties = Entities.getEntityProperties(entityID);
|
|
||||||
Entities.editEntity(entityID, {
|
|
||||||
position: Vec3.sum(properties.position, delta)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pushCommandForSelections();
|
|
||||||
|
|
||||||
selectionManager._update();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,17 @@
|
||||||
// Pool Table
|
// Billiards.js
|
||||||
|
//
|
||||||
|
// Created by Philip Rosedale on January 21, 2015
|
||||||
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Creates a pool table in front of you. Hold and release space ball to shoot a ball.
|
||||||
|
// Cue ball will return if falls off table. Delete and reset to restart.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||||
|
|
||||||
var tableParts = [];
|
var tableParts = [];
|
||||||
var balls = [];
|
var balls = [];
|
||||||
var cueBall;
|
var cueBall;
|
||||||
|
@ -19,6 +32,10 @@ var cuePosition;
|
||||||
|
|
||||||
var startStroke = 0;
|
var startStroke = 0;
|
||||||
|
|
||||||
|
// Sounds to use
|
||||||
|
hitSounds = [];
|
||||||
|
hitSounds.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "Collisions-ballhitsandcatches/billiards/collision1.wav"));
|
||||||
|
|
||||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||||
var screenSize = Controller.getViewportDimensions();
|
var screenSize = Controller.getViewportDimensions();
|
||||||
var reticle = Overlays.addOverlay("image", {
|
var reticle = Overlays.addOverlay("image", {
|
||||||
|
@ -122,6 +139,7 @@ function makeBalls(pos) {
|
||||||
}
|
}
|
||||||
ballPosition.x += (BALL_GAP + Math.sqrt(3.0) / 2.0 * BALL_SIZE) * SCALE;
|
ballPosition.x += (BALL_GAP + Math.sqrt(3.0) / 2.0 * BALL_SIZE) * SCALE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cue Ball
|
// Cue Ball
|
||||||
cuePosition = { x: pos.x - (LENGTH / 4.0) * SCALE, y: pos.y + HEIGHT / 2.0 + DROP_HEIGHT, z: pos.z };
|
cuePosition = { x: pos.x - (LENGTH / 4.0) * SCALE, y: pos.y + HEIGHT / 2.0 + DROP_HEIGHT, z: pos.z };
|
||||||
cueBall = Entities.addEntity(
|
cueBall = Entities.addEntity(
|
||||||
|
@ -138,6 +156,15 @@ function makeBalls(pos) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isObjectBall(id) {
|
||||||
|
for (var i; i < balls.length; i++) {
|
||||||
|
if (balls[i].id == id) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function shootCue(velocity) {
|
function shootCue(velocity) {
|
||||||
var DISTANCE_FROM_CAMERA = BALL_SIZE * 5.0 * SCALE;
|
var DISTANCE_FROM_CAMERA = BALL_SIZE * 5.0 * SCALE;
|
||||||
var camera = Camera.getPosition();
|
var camera = Camera.getPosition();
|
||||||
|
@ -213,12 +240,28 @@ function update(deltaTime) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function entityCollisionWithEntity(entity1, entity2, collision) {
|
||||||
|
/*
|
||||||
|
NOT WORKING YET
|
||||||
|
if ((entity1.id == cueBall.id) || (entity2.id == cueBall.id)) {
|
||||||
|
print("Cue ball collision!");
|
||||||
|
//audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||||
|
//Audio.playSound(hitSounds[0], { position: Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())) });
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (isObjectBall(entity1.id) || isObjectBall(entity2.id)) {
|
||||||
|
print("Object ball collision");
|
||||||
|
} */
|
||||||
|
}
|
||||||
|
|
||||||
tableCenter = Vec3.sum(MyAvatar.position, Vec3.multiply(4.0, Quat.getFront(Camera.getOrientation())));
|
tableCenter = Vec3.sum(MyAvatar.position, Vec3.multiply(4.0, Quat.getFront(Camera.getOrientation())));
|
||||||
|
|
||||||
makeTable(tableCenter);
|
makeTable(tableCenter);
|
||||||
makeBalls(tableCenter);
|
makeBalls(tableCenter);
|
||||||
|
|
||||||
|
Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity);
|
||||||
Script.scriptEnding.connect(cleanup);
|
Script.scriptEnding.connect(cleanup);
|
||||||
Controller.keyPressEvent.connect(keyPressEvent);
|
Controller.keyPressEvent.connect(keyPressEvent);
|
||||||
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
||||||
Script.update.connect(update);
|
Script.update.connect(update);
|
||||||
|
|
||||||
|
|
166
examples/html/gridControls.html
Normal file
166
examples/html/gridControls.html
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" type="text/css" href="style.css">
|
||||||
|
<script>
|
||||||
|
function loaded() {
|
||||||
|
var gridColor = { red: 0, green: 0, blue: 0 };
|
||||||
|
var gridColors = [
|
||||||
|
{ red: 0, green: 0, blue: 0 },
|
||||||
|
{ red: 255, green: 255, blue: 255 },
|
||||||
|
{ red: 255, green: 0, blue: 0 },
|
||||||
|
{ red: 0, green: 255, blue: 0},
|
||||||
|
{ red: 0, green: 0, blue: 255 },
|
||||||
|
];
|
||||||
|
var gridColorIndex = 0;
|
||||||
|
|
||||||
|
elPosY = document.getElementById("horiz-y");
|
||||||
|
elMinorSpacing = document.getElementById("minor-spacing");
|
||||||
|
elMajorSpacing = document.getElementById("major-spacing");
|
||||||
|
elSnapToGrid = document.getElementById("snap-to-grid");
|
||||||
|
elHorizontalGridVisible = document.getElementById("horiz-grid-visible");
|
||||||
|
elMoveToSelection = document.getElementById("move-to-selection");
|
||||||
|
elMoveToAvatar = document.getElementById("move-to-avatar");
|
||||||
|
|
||||||
|
if (window.EventBridge !== undefined) {
|
||||||
|
EventBridge.scriptEventReceived.connect(function(data) {
|
||||||
|
data = JSON.parse(data);
|
||||||
|
|
||||||
|
if (data.origin) {
|
||||||
|
var origin = data.origin;
|
||||||
|
elPosY.value = origin.y.toFixed(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.minorGridSpacing !== undefined) {
|
||||||
|
elMinorSpacing.value = data.minorGridSpacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.majorGridEvery !== undefined) {
|
||||||
|
elMajorSpacing.value = data.majorGridEvery;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.gridColor) {
|
||||||
|
gridColor = data.gridColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.snapToGrid !== undefined) {
|
||||||
|
elSnapToGrid.checked = data.snapToGrid == true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.visible !== undefined) {
|
||||||
|
elHorizontalGridVisible.checked = data.visible == true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function emitUpdate() {
|
||||||
|
EventBridge.emitWebEvent(JSON.stringify({
|
||||||
|
type: "update",
|
||||||
|
origin: {
|
||||||
|
y: elPosY.value,
|
||||||
|
},
|
||||||
|
minorGridSpacing: elMinorSpacing.value,
|
||||||
|
majorGridEvery: elMajorSpacing.value,
|
||||||
|
gridColor: gridColor,
|
||||||
|
colorIndex: gridColorIndex,
|
||||||
|
snapToGrid: elSnapToGrid.checked,
|
||||||
|
visible: elHorizontalGridVisible.checked,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
elPosY.addEventListener("change", emitUpdate);
|
||||||
|
elMinorSpacing.addEventListener("change", emitUpdate);
|
||||||
|
elMajorSpacing.addEventListener("change", emitUpdate);
|
||||||
|
elSnapToGrid.addEventListener("change", emitUpdate);
|
||||||
|
elHorizontalGridVisible.addEventListener("change", emitUpdate);
|
||||||
|
|
||||||
|
elMoveToAvatar.addEventListener("click", function() {
|
||||||
|
EventBridge.emitWebEvent(JSON.stringify({
|
||||||
|
type: "action",
|
||||||
|
action: "moveToAvatar",
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
elMoveToSelection.addEventListener("click", function() {
|
||||||
|
EventBridge.emitWebEvent(JSON.stringify({
|
||||||
|
type: "action",
|
||||||
|
action: "moveToSelection",
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
var gridColorBox = document.getElementById('grid-color');
|
||||||
|
|
||||||
|
for (var i = 0; i < gridColors.length; i++) {
|
||||||
|
var colors = gridColors[i];
|
||||||
|
var box = document.createElement('div');
|
||||||
|
box.setAttribute('class', 'color-box');
|
||||||
|
box.style.background = 'rgb(' + colors.red + ', ' + colors.green + ', ' + colors.blue + ')';
|
||||||
|
document.getElementById("grid-colors").appendChild(box);
|
||||||
|
box.addEventListener("click", function(color, index) {
|
||||||
|
return function() {
|
||||||
|
gridColor = color;
|
||||||
|
gridColorIndex = index;
|
||||||
|
emitUpdate();
|
||||||
|
}
|
||||||
|
}({ red: colors.red, green: colors.green, blue: colors.blue }, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
EventBridge.emitWebEvent(JSON.stringify({ type: 'init' }));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload='loaded();'>
|
||||||
|
<div class="grid-section">
|
||||||
|
|
||||||
|
<div class="property-section">
|
||||||
|
<label>Visible</label>
|
||||||
|
<span>
|
||||||
|
<input type='checkbox' id="horiz-grid-visible">
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="property-section">
|
||||||
|
<label>Snap to grid</label>
|
||||||
|
<span>
|
||||||
|
<input type='checkbox' id="snap-to-grid">
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="horizontal-position" class="property-section">
|
||||||
|
<label>Position (Y Axis)</label>
|
||||||
|
<span>
|
||||||
|
<input type='number' id="horiz-y" class="number" value="0.0" step="0.1"></input>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="property-section">
|
||||||
|
<label>Minor Grid Size</label>
|
||||||
|
<span>
|
||||||
|
<input type='number' id="minor-spacing" min="0" step="0.01", ></input>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="property-section">
|
||||||
|
<label>Major Grid Every</label>
|
||||||
|
<span>
|
||||||
|
<input type='number' id="major-spacing" min="2" step="1", ></input>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="property-section">
|
||||||
|
<label>Grid Color</label>
|
||||||
|
<span id="grid-colors"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="property-section">
|
||||||
|
<span>
|
||||||
|
<input type="button" id="move-to-selection" value="Move to Selection">
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="property-section">
|
||||||
|
<span>
|
||||||
|
<input type="button" id="move-to-avatar" value="Move to Avatar">
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -73,8 +73,6 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid-section {
|
.grid-section {
|
||||||
border-top: 0.75pt solid #DDD;
|
|
||||||
background-color: #efefef;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type=button] {
|
input[type=button] {
|
||||||
|
@ -169,7 +167,7 @@ input {
|
||||||
color: rgb(150, 150, 150);
|
color: rgb(150, 150, 150);
|
||||||
}
|
}
|
||||||
|
|
||||||
#properties-list input, #properties-list textarea {
|
input, textarea {
|
||||||
background-color: rgb(102, 102, 102);
|
background-color: rgb(102, 102, 102);
|
||||||
color: rgb(204, 204, 204);
|
color: rgb(204, 204, 204);
|
||||||
border: none;
|
border: none;
|
||||||
|
|
|
@ -15,6 +15,9 @@ var MOUSE_SENSITIVITY = 0.9;
|
||||||
var SCROLL_SENSITIVITY = 0.05;
|
var SCROLL_SENSITIVITY = 0.05;
|
||||||
var PAN_ZOOM_SCALE_RATIO = 0.4;
|
var PAN_ZOOM_SCALE_RATIO = 0.4;
|
||||||
|
|
||||||
|
var KEY_ORBIT_SENSITIVITY = 40;
|
||||||
|
var KEY_ZOOM_SENSITIVITY = 10;
|
||||||
|
|
||||||
// Scaling applied based on the size of the object being focused
|
// Scaling applied based on the size of the object being focused
|
||||||
var FOCUS_ZOOM_SCALE = 1.3;
|
var FOCUS_ZOOM_SCALE = 1.3;
|
||||||
|
|
||||||
|
@ -43,6 +46,10 @@ var easeOutCubic = function(t) {
|
||||||
|
|
||||||
EASE_TIME = 0.5;
|
EASE_TIME = 0.5;
|
||||||
|
|
||||||
|
function clamp(value, minimum, maximum) {
|
||||||
|
return Math.min(Math.max(value, minimum), maximum);
|
||||||
|
}
|
||||||
|
|
||||||
function mergeObjects(obj1, obj2) {
|
function mergeObjects(obj1, obj2) {
|
||||||
var newObj = {};
|
var newObj = {};
|
||||||
for (key in obj1) {
|
for (key in obj1) {
|
||||||
|
@ -60,6 +67,49 @@ CameraManager = function() {
|
||||||
that.enabled = false;
|
that.enabled = false;
|
||||||
that.mode = MODE_INACTIVE;
|
that.mode = MODE_INACTIVE;
|
||||||
|
|
||||||
|
var actions = {
|
||||||
|
orbitLeft: 0,
|
||||||
|
orbitRight: 0,
|
||||||
|
orbitUp: 0,
|
||||||
|
orbitDown: 0,
|
||||||
|
orbitForward: 0,
|
||||||
|
orbitBackward: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
var keyToActionMapping = {
|
||||||
|
"a": "orbitLeft",
|
||||||
|
"d": "orbitRight",
|
||||||
|
"w": "orbitForward",
|
||||||
|
"s": "orbitBackward",
|
||||||
|
"e": "orbitUp",
|
||||||
|
"c": "orbitDown",
|
||||||
|
|
||||||
|
"LEFT": "orbitLeft",
|
||||||
|
"RIGHT": "orbitRight",
|
||||||
|
"UP": "orbitForward",
|
||||||
|
"DOWN": "orbitBackward",
|
||||||
|
}
|
||||||
|
|
||||||
|
var CAPTURED_KEYS = [];
|
||||||
|
for (key in keyToActionMapping) {
|
||||||
|
CAPTURED_KEYS.push(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getActionForKeyEvent(event) {
|
||||||
|
var action = keyToActionMapping[event.text];
|
||||||
|
if (action !== undefined) {
|
||||||
|
if (event.isShifted) {
|
||||||
|
if (action == "orbitForward") {
|
||||||
|
action = "orbitUp";
|
||||||
|
} else if (action == "orbitBackward") {
|
||||||
|
action = "orbitDown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
that.zoomDistance = INITIAL_ZOOM_DISTANCE;
|
that.zoomDistance = INITIAL_ZOOM_DISTANCE;
|
||||||
that.targetZoomDistance = INITIAL_ZOOM_DISTANCE;
|
that.targetZoomDistance = INITIAL_ZOOM_DISTANCE;
|
||||||
|
|
||||||
|
@ -82,6 +132,10 @@ CameraManager = function() {
|
||||||
that.enable = function() {
|
that.enable = function() {
|
||||||
if (Camera.mode == "independent" || that.enabled) return;
|
if (Camera.mode == "independent" || that.enabled) return;
|
||||||
|
|
||||||
|
for (var i = 0; i < CAPTURED_KEYS.length; i++) {
|
||||||
|
Controller.captureKeyEvents({ text: CAPTURED_KEYS[i] });
|
||||||
|
}
|
||||||
|
|
||||||
that.enabled = true;
|
that.enabled = true;
|
||||||
that.mode = MODE_INACTIVE;
|
that.mode = MODE_INACTIVE;
|
||||||
|
|
||||||
|
@ -112,6 +166,11 @@ CameraManager = function() {
|
||||||
|
|
||||||
that.disable = function(ignoreCamera) {
|
that.disable = function(ignoreCamera) {
|
||||||
if (!that.enabled) return;
|
if (!that.enabled) return;
|
||||||
|
|
||||||
|
for (var i = 0; i < CAPTURED_KEYS.length; i++) {
|
||||||
|
Controller.releaseKeyEvents({ text: CAPTURED_KEYS[i] });
|
||||||
|
}
|
||||||
|
|
||||||
that.enabled = false;
|
that.enabled = false;
|
||||||
that.mode = MODE_INACTIVE;
|
that.mode = MODE_INACTIVE;
|
||||||
|
|
||||||
|
@ -303,6 +362,20 @@ CameraManager = function() {
|
||||||
that.mode = MODE_INACTIVE;
|
that.mode = MODE_INACTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
that.keyPressEvent = function(event) {
|
||||||
|
var action = getActionForKeyEvent(event);
|
||||||
|
if (action) {
|
||||||
|
actions[action] = 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
that.keyReleaseEvent = function(event) {
|
||||||
|
var action = getActionForKeyEvent(event);
|
||||||
|
if (action) {
|
||||||
|
actions[action] = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
that.wheelEvent = function(event) {
|
that.wheelEvent = function(event) {
|
||||||
if (!that.enabled) return;
|
if (!that.enabled) return;
|
||||||
|
|
||||||
|
@ -356,6 +429,14 @@ CameraManager = function() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update based on current actions
|
||||||
|
that.targetYaw += (actions.orbitRight - actions.orbitLeft) * dt * KEY_ORBIT_SENSITIVITY;
|
||||||
|
that.targetPitch += (actions.orbitUp - actions.orbitDown) * dt * KEY_ORBIT_SENSITIVITY;
|
||||||
|
that.targetPitch = clamp(that.targetPitch, -90, 90);
|
||||||
|
that.targetZoomDistance += (actions.orbitBackward - actions.orbitForward) * dt * KEY_ZOOM_SENSITIVITY;
|
||||||
|
that.targetZoomDistance = clamp(that.targetZoomDistance, MIN_ZOOM_DISTANCE, MAX_ZOOM_DISTANCE);
|
||||||
|
|
||||||
|
|
||||||
if (easing) {
|
if (easing) {
|
||||||
easingTime = Math.min(EASE_TIME, easingTime + dt);
|
easingTime = Math.min(EASE_TIME, easingTime + dt);
|
||||||
}
|
}
|
||||||
|
@ -407,6 +488,7 @@ CameraManager = function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
Script.update.connect(that.update);
|
Script.update.connect(that.update);
|
||||||
|
Script.scriptEnding.connect(that.disable);
|
||||||
|
|
||||||
Controller.wheelEvent.connect(that.wheelEvent);
|
Controller.wheelEvent.connect(that.wheelEvent);
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,11 @@ Grid = function(opts) {
|
||||||
var that = {};
|
var that = {};
|
||||||
|
|
||||||
var colors = [
|
var colors = [
|
||||||
{ red: 0, green: 255, blue: 0 },
|
|
||||||
{ red: 255, green: 255, blue: 255 },
|
|
||||||
{ red: 0, green: 0, blue: 0 },
|
{ red: 0, green: 0, blue: 0 },
|
||||||
{ red: 0, green: 0, blue: 255 },
|
{ red: 255, green: 255, blue: 255 },
|
||||||
{ red: 255, green: 0, blue: 0 },
|
{ red: 255, green: 0, blue: 0 },
|
||||||
|
{ red: 0, green: 255, blue: 0 },
|
||||||
|
{ red: 0, green: 0, blue: 255 },
|
||||||
];
|
];
|
||||||
var colorIndex = 0;
|
var colorIndex = 0;
|
||||||
var gridAlpha = 0.6;
|
var gridAlpha = 0.6;
|
||||||
|
@ -224,273 +224,50 @@ Grid = function(opts) {
|
||||||
GridTool = function(opts) {
|
GridTool = function(opts) {
|
||||||
var that = {};
|
var that = {};
|
||||||
|
|
||||||
var UI_URL = HIFI_PUBLIC_BUCKET + "images/tools/grid-toolbar.svg";
|
|
||||||
var UI_WIDTH = 854;
|
|
||||||
var UI_HEIGHT = 37;
|
|
||||||
|
|
||||||
var horizontalGrid = opts.horizontalGrid;
|
var horizontalGrid = opts.horizontalGrid;
|
||||||
|
var verticalGrid = opts.verticalGrid;
|
||||||
|
var listeners = [];
|
||||||
|
|
||||||
var uiOverlays = {};
|
var url = Script.resolvePath('html/gridControls.html');
|
||||||
var allOverlays = [];
|
var webView = new WebWindow('Grid', url, 200, 280);
|
||||||
|
|
||||||
function addUIOverlay(key, overlay, x, y, width, height) {
|
horizontalGrid.addListener(function(data) {
|
||||||
uiOverlays[key] = {
|
webView.eventBridge.emitScriptEvent(JSON.stringify(data));
|
||||||
overlay: overlay,
|
selectionDisplay.updateHandles();
|
||||||
x: x,
|
});
|
||||||
y: y,
|
|
||||||
width: width,
|
|
||||||
height: height,
|
|
||||||
};
|
|
||||||
allOverlays.push(overlay);
|
|
||||||
}
|
|
||||||
|
|
||||||
var lastKnownWindowWidth = null;
|
webView.eventBridge.webEventReceived.connect(function(data) {
|
||||||
function repositionUI() {
|
data = JSON.parse(data);
|
||||||
if (lastKnownWindowWidth == Window.innerWidth) {
|
if (data.type == "init") {
|
||||||
return;
|
horizontalGrid.emitUpdate();
|
||||||
}
|
} else if (data.type == "update") {
|
||||||
|
horizontalGrid.update(data);
|
||||||
lastKnownWindowWidth = Window.innerWidth;
|
for (var i = 0; i < listeners.length; i++) {
|
||||||
var x = Window.innerWidth / 2 - UI_WIDTH / 2;
|
listeners[i](data);
|
||||||
var y = 10;
|
|
||||||
|
|
||||||
for (var key in uiOverlays) {
|
|
||||||
info = uiOverlays[key];
|
|
||||||
Overlays.editOverlay(info.overlay, {
|
|
||||||
x: x + info.x,
|
|
||||||
y: y + info.y,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// "Spritesheet" is laid out horizontally in this order
|
|
||||||
var UI_SPRITE_LIST = [
|
|
||||||
{ name: "gridText", width: 54 },
|
|
||||||
{ name: "visibleCheckbox", width: 60 },
|
|
||||||
{ name: "snapToGridCheckbox", width: 105 },
|
|
||||||
|
|
||||||
{ name: "color0", width: 27 },
|
|
||||||
{ name: "color1", width: 27 },
|
|
||||||
{ name: "color2", width: 27 },
|
|
||||||
{ name: "color3", width: 27 },
|
|
||||||
{ name: "color4", width: 27 },
|
|
||||||
|
|
||||||
{ name: "minorGridIcon", width: 34 },
|
|
||||||
{ name: "minorGridDecrease", width: 25 },
|
|
||||||
{ name: "minorGridInput", width: 26 },
|
|
||||||
{ name: "minorGridIncrease", width: 25 },
|
|
||||||
|
|
||||||
{ name: "majorGridIcon", width: 40 },
|
|
||||||
{ name: "majorGridDecrease", width: 25 },
|
|
||||||
{ name: "majorGridInput", width: 26 },
|
|
||||||
{ name: "majorGridIncrease", width: 25 },
|
|
||||||
|
|
||||||
{ name: "yPositionLabel", width: 160 },
|
|
||||||
{ name: "moveToLabel", width: 54 },
|
|
||||||
{ name: "moveToAvatar", width: 26 },
|
|
||||||
{ name: "moveToSelection", width: 34 },
|
|
||||||
];
|
|
||||||
|
|
||||||
// Add all overlays from spritesheet
|
|
||||||
var baseOverlay = null;
|
|
||||||
var x = 0;
|
|
||||||
for (var i = 0; i < UI_SPRITE_LIST.length; i++) {
|
|
||||||
var info = UI_SPRITE_LIST[i];
|
|
||||||
|
|
||||||
var props = {
|
|
||||||
imageURL: UI_URL,
|
|
||||||
subImage: { x: x, y: 0, width: info.width, height: UI_HEIGHT },
|
|
||||||
width: info.width,
|
|
||||||
height: UI_HEIGHT,
|
|
||||||
alpha: 1.0,
|
|
||||||
visible: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
var overlay;
|
|
||||||
if (baseOverlay == null) {
|
|
||||||
overlay = Overlays.addOverlay("image", {
|
|
||||||
imageURL: UI_URL,
|
|
||||||
});
|
|
||||||
baseOverlay = overlay;
|
|
||||||
} else {
|
|
||||||
overlay = Overlays.cloneOverlay(baseOverlay);
|
|
||||||
}
|
|
||||||
|
|
||||||
Overlays.editOverlay(overlay, props);
|
|
||||||
|
|
||||||
addUIOverlay(info.name, overlay, x, 0, info.width, UI_HEIGHT);
|
|
||||||
|
|
||||||
x += info.width;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add Text overlays
|
|
||||||
var textProperties = {
|
|
||||||
color: { red: 255, green: 255, blue: 255 },
|
|
||||||
topMargin: 6,
|
|
||||||
leftMargin: 4,
|
|
||||||
alpha: 1,
|
|
||||||
backgroundAlpha: 0,
|
|
||||||
text: "",
|
|
||||||
font: { size: 12 },
|
|
||||||
visible: false,
|
|
||||||
};
|
|
||||||
var minorGridWidthText = Overlays.addOverlay("text", textProperties);
|
|
||||||
var majorGridEveryText = Overlays.addOverlay("text", textProperties);
|
|
||||||
var yPositionText = Overlays.addOverlay("text", textProperties);
|
|
||||||
|
|
||||||
addUIOverlay('minorGridWidthText', minorGridWidthText, 414, 8, 24, 24);
|
|
||||||
addUIOverlay('majorGridEveryText', majorGridEveryText, 530, 8, 24, 24);
|
|
||||||
addUIOverlay('yPositionText', yPositionText, 660, 8, 24, 24);
|
|
||||||
|
|
||||||
var NUM_COLORS = 5;
|
|
||||||
function updateColorIndex(index) {
|
|
||||||
if (index < 0 || index >= NUM_COLORS) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0 ; i < NUM_COLORS; i++) {
|
|
||||||
var info = uiOverlays['color' + i];
|
|
||||||
Overlays.editOverlay(info.overlay, {
|
|
||||||
subImage: {
|
|
||||||
x: info.x,
|
|
||||||
y: i == index ? UI_HEIGHT : 0,
|
|
||||||
width: info.width,
|
|
||||||
height: info.height,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateGridVisible(value) {
|
|
||||||
var info = uiOverlays.visibleCheckbox;
|
|
||||||
Overlays.editOverlay(info.overlay, {
|
|
||||||
subImage: {
|
|
||||||
x: info.x,
|
|
||||||
y: value ? UI_HEIGHT : 0,
|
|
||||||
width: info.width,
|
|
||||||
height: info.height,
|
|
||||||
}
|
}
|
||||||
});
|
} else if (data.type == "action") {
|
||||||
}
|
var action = data.action;
|
||||||
|
if (action == "moveToAvatar") {
|
||||||
function updateSnapToGrid(value) {
|
|
||||||
var info = uiOverlays.snapToGridCheckbox;
|
|
||||||
Overlays.editOverlay(info.overlay, {
|
|
||||||
subImage: {
|
|
||||||
x: info.x,
|
|
||||||
y: value ? UI_HEIGHT : 0,
|
|
||||||
width: info.width,
|
|
||||||
height: info.height,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateMinorGridWidth(value) {
|
|
||||||
Overlays.editOverlay(minorGridWidthText, {
|
|
||||||
text: value.toFixed(1),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateMajorGridEvery(value) {
|
|
||||||
Overlays.editOverlay(majorGridEveryText, {
|
|
||||||
text: value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateYPosition(value) {
|
|
||||||
Overlays.editOverlay(yPositionText, {
|
|
||||||
text: value.toFixed(2),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateOverlays() {
|
|
||||||
updateGridVisible(horizontalGrid.getVisible());
|
|
||||||
updateSnapToGrid(horizontalGrid.getSnapToGrid());
|
|
||||||
updateColorIndex(horizontalGrid.getColorIndex());
|
|
||||||
|
|
||||||
updateMinorGridWidth(horizontalGrid.getMinorGridWidth());
|
|
||||||
updateMajorGridEvery(horizontalGrid.getMajorGridEvery());
|
|
||||||
|
|
||||||
updateYPosition(horizontalGrid.getOrigin().y);
|
|
||||||
}
|
|
||||||
|
|
||||||
that.setVisible = function(visible) {
|
|
||||||
for (var i = 0; i < allOverlays.length; i++) {
|
|
||||||
Overlays.editOverlay(allOverlays[i], { visible: visible });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
that.mousePressEvent = function(event) {
|
|
||||||
var overlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
|
|
||||||
|
|
||||||
if (allOverlays.indexOf(overlay) >= 0) {
|
|
||||||
if (overlay == uiOverlays.color0.overlay) {
|
|
||||||
horizontalGrid.setColorIndex(0);
|
|
||||||
} else if (overlay == uiOverlays.color1.overlay) {
|
|
||||||
horizontalGrid.setColorIndex(1);
|
|
||||||
} else if (overlay == uiOverlays.color2.overlay) {
|
|
||||||
horizontalGrid.setColorIndex(2);
|
|
||||||
} else if (overlay == uiOverlays.color3.overlay) {
|
|
||||||
horizontalGrid.setColorIndex(3);
|
|
||||||
} else if (overlay == uiOverlays.color4.overlay) {
|
|
||||||
horizontalGrid.setColorIndex(4);
|
|
||||||
} else if (overlay == uiOverlays.visibleCheckbox.overlay) {
|
|
||||||
horizontalGrid.setVisible(!horizontalGrid.getVisible());
|
|
||||||
} else if (overlay == uiOverlays.snapToGridCheckbox.overlay) {
|
|
||||||
horizontalGrid.setSnapToGrid(!horizontalGrid.getSnapToGrid());
|
|
||||||
} else if (overlay == uiOverlays.moveToAvatar.overlay) {
|
|
||||||
var position = MyAvatar.getJointPosition("LeftFoot");
|
var position = MyAvatar.getJointPosition("LeftFoot");
|
||||||
if (position.x == 0 && position.y == 0 && position.z == 0) {
|
if (position.x == 0 && position.y == 0 && position.z == 0) {
|
||||||
position = MyAvatar.position;
|
position = MyAvatar.position;
|
||||||
}
|
}
|
||||||
horizontalGrid.setPosition(position);
|
horizontalGrid.setPosition(position);
|
||||||
} else if (overlay == uiOverlays.moveToSelection.overlay) {
|
} else if (action == "moveToSelection") {
|
||||||
var newPosition = selectionManager.worldPosition;
|
var newPosition = selectionManager.worldPosition;
|
||||||
newPosition = Vec3.subtract(newPosition, { x: 0, y: selectionManager.worldDimensions.y * 0.5, z: 0 });
|
newPosition = Vec3.subtract(newPosition, { x: 0, y: selectionManager.worldDimensions.y * 0.5, z: 0 });
|
||||||
horizontalGrid.setPosition(newPosition);
|
grid.setPosition(newPosition);
|
||||||
} else if (overlay == uiOverlays.minorGridDecrease.overlay) {
|
|
||||||
var newValue = Math.max(0.1, horizontalGrid.getMinorGridWidth() - 0.1);
|
|
||||||
horizontalGrid.setMinorGridWidth(newValue);
|
|
||||||
} else if (overlay == uiOverlays.minorGridIncrease.overlay) {
|
|
||||||
horizontalGrid.setMinorGridWidth(horizontalGrid.getMinorGridWidth() + 0.1);
|
|
||||||
} else if (overlay == uiOverlays.majorGridDecrease.overlay) {
|
|
||||||
var newValue = Math.max(2, horizontalGrid.getMajorGridEvery() - 1);
|
|
||||||
horizontalGrid.setMajorGridEvery(newValue);
|
|
||||||
} else if (overlay == uiOverlays.majorGridIncrease.overlay) {
|
|
||||||
horizontalGrid.setMajorGridEvery(horizontalGrid.getMajorGridEvery() + 1);
|
|
||||||
} else if (overlay == uiOverlays.yPositionLabel.overlay) {
|
|
||||||
var newValue = Window.prompt("Y Position:", horizontalGrid.getOrigin().y.toFixed(4));
|
|
||||||
if (newValue !== null) {
|
|
||||||
var y = parseFloat(newValue)
|
|
||||||
if (isNaN(y)) {
|
|
||||||
Window.alert("Invalid position");
|
|
||||||
} else {
|
|
||||||
horizontalGrid.setPosition({ x: 0, y: y, z: 0 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clicking anywhere within the toolbar will "consume" this press event
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
Script.scriptEnding.connect(function() {
|
|
||||||
for (var i = 0; i < allOverlays.length; i++) {
|
|
||||||
Overlays.deleteOverlay(allOverlays[i]);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Script.update.connect(repositionUI);
|
|
||||||
|
|
||||||
horizontalGrid.addListener(function() {
|
that.addListener = function(callback) {
|
||||||
selectionDisplay.updateHandles();
|
listeners.push(callback);
|
||||||
updateOverlays();
|
}
|
||||||
});
|
|
||||||
|
|
||||||
updateOverlays();
|
that.setVisible = function(visible) {
|
||||||
repositionUI();
|
webView.setVisible(visible);
|
||||||
|
}
|
||||||
|
|
||||||
return that;
|
return that;
|
||||||
};
|
};
|
||||||
|
|
|
@ -52,18 +52,16 @@
|
||||||
// 2. Declare a text string.
|
// 2. Declare a text string.
|
||||||
// 3. Call createNotifications(text) parsing the text.
|
// 3. Call createNotifications(text) parsing the text.
|
||||||
// example:
|
// example:
|
||||||
|
// var welcome;
|
||||||
// if (key.text == "q") { //queries number of users online
|
// if (key.text == "q") { //queries number of users online
|
||||||
// var numUsers = GlobalServices.onlineUsers.length;
|
// var welcome = "There are " + GlobalServices.onlineUsers.length + " users online now.";
|
||||||
// var welcome = "There are " + numUsers + " users online now.";
|
// createNotification(welcome);
|
||||||
// createNotification(welcome);
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
var width = 340.0; //width of notification overlay
|
var width = 340.0; //width of notification overlay
|
||||||
var height = 40.0; // height of a single line notification overlay
|
|
||||||
var windowDimensions = Controller.getViewportDimensions(); // get the size of the interface window
|
var windowDimensions = Controller.getViewportDimensions(); // get the size of the interface window
|
||||||
var overlayLocationX = (windowDimensions.x - (width + 20.0));// positions window 20px from the right of the interface window
|
var overlayLocationX = (windowDimensions.x - (width + 20.0)); // positions window 20px from the right of the interface window
|
||||||
var buttonLocationX = overlayLocationX + (width - 28.0);
|
var buttonLocationX = overlayLocationX + (width - 28.0);
|
||||||
var locationY = 20.0; // position down from top of interface window
|
var locationY = 20.0; // position down from top of interface window
|
||||||
var topMargin = 13.0;
|
var topMargin = 13.0;
|
||||||
var leftMargin = 10.0;
|
var leftMargin = 10.0;
|
||||||
|
@ -71,264 +69,79 @@ var textColor = { red: 228, green: 228, blue: 228}; // text color
|
||||||
var backColor = { red: 2, green: 2, blue: 2}; // background color was 38,38,38
|
var backColor = { red: 2, green: 2, blue: 2}; // background color was 38,38,38
|
||||||
var backgroundAlpha = 0;
|
var backgroundAlpha = 0;
|
||||||
var fontSize = 12.0;
|
var fontSize = 12.0;
|
||||||
var persistTime = 10.0; // time in seconds before notification fades
|
var PERSIST_TIME_2D = 10.0; // Time in seconds before notification fades
|
||||||
|
var PERSIST_TIME_3D = 15.0;
|
||||||
|
var persistTime = PERSIST_TIME_2D;
|
||||||
var clickedText = false;
|
var clickedText = false;
|
||||||
var frame = 0;
|
var frame = 0;
|
||||||
var ourWidth = Window.innerWidth;
|
var ourWidth = Window.innerWidth;
|
||||||
var ourHeight = Window.innerHeight;
|
var ourHeight = Window.innerHeight;
|
||||||
var text = "placeholder";
|
var text = "placeholder";
|
||||||
var last_users = GlobalServices.onlineUsers;
|
var last_users = GlobalServices.onlineUsers;
|
||||||
var users = [];
|
var users = [];
|
||||||
var ctrlIsPressed = false;
|
var ctrlIsPressed = false;
|
||||||
var ready = true;
|
var ready = true;
|
||||||
|
|
||||||
// When our script shuts down, we should clean up all of our overlays
|
|
||||||
function scriptEnding() {
|
|
||||||
for (i = 0; i < notifications.length; i++) {
|
|
||||||
Overlays.deleteOverlay(notifications[i]);
|
|
||||||
Overlays.deleteOverlay(buttons[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Script.scriptEnding.connect(scriptEnding);
|
|
||||||
|
|
||||||
var notifications = [];
|
var notifications = [];
|
||||||
var buttons = [];
|
var buttons = [];
|
||||||
var times = [];
|
var times = [];
|
||||||
var heights = [];
|
var heights = [];
|
||||||
var myAlpha = [];
|
var myAlpha = [];
|
||||||
var arrays = [];
|
var arrays = [];
|
||||||
|
var isOnHMD = false,
|
||||||
|
ENABLE_VR_MODE = "Enable VR Mode",
|
||||||
|
NOTIFICATIONS_3D_DIRECTION = 0.0, // Degrees from avatar orientation.
|
||||||
|
NOTIFICATIONS_3D_DISTANCE = 0.6, // Horizontal distance from avatar position.
|
||||||
|
NOTIFICATIONS_3D_ELEVATION = -0.8, // Height of top middle of top notification relative to avatar eyes.
|
||||||
|
NOTIFICATIONS_3D_YAW = 0.0, // Degrees relative to notifications direction.
|
||||||
|
NOTIFICATIONS_3D_PITCH = -60.0, // Degrees from vertical.
|
||||||
|
NOTIFICATION_3D_SCALE = 0.002, // Multiplier that converts 2D overlay dimensions to 3D overlay dimensions.
|
||||||
|
NOTIFICATION_3D_BUTTON_WIDTH = 40 * NOTIFICATION_3D_SCALE, // Need a little more room for button in 3D.
|
||||||
|
overlay3DDetails = [];
|
||||||
|
|
||||||
// This function creates and sizes the overlays
|
// push data from above to the 2 dimensional array
|
||||||
function createNotification(text) {
|
function createArrays(notice, button, createTime, height, myAlpha) {
|
||||||
var count = (text.match(/\n/g) || []).length;
|
arrays.push([notice, button, createTime, height, myAlpha]);
|
||||||
var breakPoint = 43.0; // length when new line is added
|
|
||||||
var extraLine = 0;
|
|
||||||
var breaks = 0;
|
|
||||||
var height = 40.0;
|
|
||||||
var stack = 0;
|
|
||||||
if (text.length >= breakPoint) {
|
|
||||||
breaks = count;
|
|
||||||
}
|
|
||||||
var extraLine = breaks * 16.0;
|
|
||||||
for (i = 0; i < heights.length; i++) {
|
|
||||||
stack = stack + heights[i];
|
|
||||||
}
|
|
||||||
var level = (stack + 20.0);
|
|
||||||
height = height + extraLine;
|
|
||||||
var overlayProperties = {
|
|
||||||
x: overlayLocationX,
|
|
||||||
y: level,
|
|
||||||
width: width,
|
|
||||||
height: height,
|
|
||||||
color: textColor,
|
|
||||||
backgroundColor: backColor,
|
|
||||||
alpha: backgroundAlpha,
|
|
||||||
topMargin: topMargin,
|
|
||||||
leftMargin: leftMargin,
|
|
||||||
font: {size: fontSize},
|
|
||||||
text: text,
|
|
||||||
};
|
|
||||||
var bLevel = level + 12.0;
|
|
||||||
var buttonProperties = {
|
|
||||||
x: buttonLocationX,
|
|
||||||
y: bLevel,
|
|
||||||
width: 10.0,
|
|
||||||
height: 10.0,
|
|
||||||
subImage: { x: 0, y: 0, width: 10, height: 10 },
|
|
||||||
imageURL: "http://hifi-public.s3.amazonaws.com/images/close-small-light.svg",
|
|
||||||
color: { red: 255, green: 255, blue: 255},
|
|
||||||
visible: true,
|
|
||||||
alpha: backgroundAlpha,
|
|
||||||
};
|
|
||||||
|
|
||||||
Notify(overlayProperties, buttonProperties, height);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pushes data to each array and sets up data for 2nd dimension array
|
// This handles the final dismissal of a notification after fading
|
||||||
// to handle auxiliary data not carried by the overlay class
|
function dismiss(firstNoteOut, firstButOut, firstOut) {
|
||||||
// specifically notification "heights", "times" of creation, and .
|
Overlays.deleteOverlay(firstNoteOut);
|
||||||
function Notify(notice, button, height){
|
Overlays.deleteOverlay(firstButOut);
|
||||||
|
notifications.splice(firstOut, 1);
|
||||||
notifications.push((Overlays.addOverlay("text", notice)));
|
buttons.splice(firstOut, 1);
|
||||||
buttons.push((Overlays.addOverlay("image",button)));
|
times.splice(firstOut, 1);
|
||||||
times.push(new Date().getTime() / 1000);
|
heights.splice(firstOut, 1);
|
||||||
height = height + 1.0;
|
myAlpha.splice(firstOut, 1);
|
||||||
heights.push(height);
|
overlay3DDetails.splice(firstOut, 1);
|
||||||
myAlpha.push(0);
|
|
||||||
var last = notifications.length - 1;
|
|
||||||
createArrays(notifications[last], buttons[last], times[last], heights[last], myAlpha[last]);
|
|
||||||
fadeIn(notifications[last], buttons[last])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function fadeIn(noticeIn, buttonIn) {
|
function fadeIn(noticeIn, buttonIn) {
|
||||||
var myLength = arrays.length;
|
var q = 0,
|
||||||
var q = 0;
|
qFade,
|
||||||
var pauseTimer = null;
|
pauseTimer = null;
|
||||||
pauseTimer = Script.setInterval(function() {
|
|
||||||
q++;
|
pauseTimer = Script.setInterval(function () {
|
||||||
|
q += 1;
|
||||||
qFade = q / 10.0;
|
qFade = q / 10.0;
|
||||||
Overlays.editOverlay(noticeIn, {alpha: qFade});
|
Overlays.editOverlay(noticeIn, { alpha: qFade });
|
||||||
Overlays.editOverlay(buttonIn, {alpha: qFade});
|
Overlays.editOverlay(buttonIn, { alpha: qFade });
|
||||||
if (q >= 9.0) {
|
if (q >= 9.0) {
|
||||||
Script.clearInterval(pauseTimer);
|
Script.clearInterval(pauseTimer);
|
||||||
}
|
}
|
||||||
}, 10);
|
}, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// push data from above to the 2 dimensional array
|
|
||||||
function createArrays(notice, button, createTime, height, myAlpha) {
|
|
||||||
arrays.push([notice, button, createTime, height, myAlpha]);
|
|
||||||
}
|
|
||||||
// handles mouse clicks on buttons
|
|
||||||
function mousePressEvent(event) {
|
|
||||||
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); //identify which overlay was clicked
|
|
||||||
for (i = 0; i < buttons.length; i++) { //if user clicked a button
|
|
||||||
if(clickedOverlay == buttons[i]) {
|
|
||||||
Overlays.deleteOverlay(notifications[i]);
|
|
||||||
Overlays.deleteOverlay(buttons[i]);
|
|
||||||
notifications.splice(i, 1);
|
|
||||||
buttons.splice(i, 1);
|
|
||||||
times.splice(i, 1);
|
|
||||||
heights.splice(i, 1);
|
|
||||||
myAlpha.splice(i, 1);
|
|
||||||
arrays.splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Control key remains active only while key is held down
|
|
||||||
function keyReleaseEvent(key) {
|
|
||||||
if (key.key == 16777249) {
|
|
||||||
ctrlIsPressed = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Triggers notification on specific key driven events
|
|
||||||
function keyPressEvent(key) {
|
|
||||||
if (key.key == 16777249) {
|
|
||||||
ctrlIsPressed = true;
|
|
||||||
}
|
|
||||||
if (key.text == "q") { //queries number of users online
|
|
||||||
var numUsers = GlobalServices.onlineUsers.length;
|
|
||||||
var welcome = "There are " + numUsers + " users online now.";
|
|
||||||
createNotification(welcome);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key.text == "s") {
|
|
||||||
if (ctrlIsPressed == true){
|
|
||||||
var noteString = "Snapshot taken.";
|
|
||||||
createNotification(noteString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// formats string to add newline every 43 chars
|
|
||||||
function wordWrap(str) {
|
|
||||||
var result = stringDivider(str, 43.0, "\n");
|
|
||||||
createNotification(result);
|
|
||||||
}
|
|
||||||
// wraps whole word to newline
|
|
||||||
function stringDivider(str, slotWidth, spaceReplacer) {
|
|
||||||
if (str.length > slotWidth) {
|
|
||||||
var p = slotWidth;
|
|
||||||
for (; p > 0 && str[p] != ' '; p--) {
|
|
||||||
}
|
|
||||||
if (p > 0) {
|
|
||||||
var left = str.substring(0, p);
|
|
||||||
var right = str.substring(p + 1);
|
|
||||||
return left + spaceReplacer + stringDivider(right, slotWidth, spaceReplacer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This fires a notification on window resize
|
|
||||||
function checkSize(){
|
|
||||||
if((Window.innerWidth != ourWidth)||(Window.innerHeight != ourHeight)) {
|
|
||||||
var windowResize = "Window has been resized";
|
|
||||||
ourWidth = Window.innerWidth;
|
|
||||||
ourHeight = Window.innerHeight;
|
|
||||||
windowDimensions = Controller.getViewportDimensions();
|
|
||||||
overlayLocationX = (windowDimensions.x - (width + 60.0));
|
|
||||||
buttonLocationX = overlayLocationX + (width - 35.0);
|
|
||||||
createNotification(windowResize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Triggers notification if a user logs on or off
|
|
||||||
function onOnlineUsersChanged(users) {
|
|
||||||
if (!isStartingUp()) { // Skip user notifications at startup.
|
|
||||||
for (user in users) {
|
|
||||||
if (last_users.indexOf(users[user]) == -1.0) {
|
|
||||||
createNotification(users[user] + " has joined");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (user in last_users) {
|
|
||||||
if (users.indexOf(last_users[user]) == -1.0) {
|
|
||||||
createNotification(last_users[user] + " has left");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
last_users = users;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Triggers notification if @MyUserName is mentioned in chat and returns the message to the notification.
|
|
||||||
function onIncomingMessage(user, message) {
|
|
||||||
var myMessage = message;
|
|
||||||
var alertMe = "@" + GlobalServices.myUsername;
|
|
||||||
var thisAlert = user + ": " + myMessage;
|
|
||||||
if (myMessage.indexOf(alertMe) > -1.0) {
|
|
||||||
wordWrap(thisAlert);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Triggers mic mute notification
|
|
||||||
function onMuteStateChanged() {
|
|
||||||
var muteState = AudioDevice.getMuted() ? "muted" : "unmuted";
|
|
||||||
var muteString = "Microphone is now " + muteState;
|
|
||||||
createNotification(muteString);
|
|
||||||
}
|
|
||||||
|
|
||||||
function update(){
|
|
||||||
frame++;
|
|
||||||
if ((frame % 60.0) == 0) { // only update once a second
|
|
||||||
checkSize(); // checks for size change to trigger windowResize notification
|
|
||||||
locationY = 20.0;
|
|
||||||
for (var i = 0; i < arrays.length; i++) { //repositions overlays as others fade
|
|
||||||
var nextOverlay = Overlays.getOverlayAtPoint({x: overlayLocationX, y: locationY});
|
|
||||||
Overlays.editOverlay(notifications[i], { x:overlayLocationX, y:locationY});
|
|
||||||
Overlays.editOverlay(buttons[i], { x:buttonLocationX, y:locationY + 12.0});
|
|
||||||
locationY = locationY + arrays[i][3];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This checks the age of the notification and prepares to fade it after 9.0 seconds (var persistTime - 1)
|
|
||||||
for (var i = 0; i < arrays.length; i++) {
|
|
||||||
if (ready){
|
|
||||||
var j = arrays[i][2];
|
|
||||||
var k = j + persistTime;
|
|
||||||
if (k < (new Date().getTime() / 1000)) {
|
|
||||||
ready = false;
|
|
||||||
noticeOut = arrays[i][0];
|
|
||||||
buttonOut = arrays[i][1];
|
|
||||||
var arraysOut = i;
|
|
||||||
fadeOut(noticeOut, buttonOut, arraysOut);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// this fades the notification ready for dismissal, and removes it from the arrays
|
// this fades the notification ready for dismissal, and removes it from the arrays
|
||||||
function fadeOut(noticeOut, buttonOut, arraysOut) {
|
function fadeOut(noticeOut, buttonOut, arraysOut) {
|
||||||
var myLength = arrays.length;
|
var r = 9.0,
|
||||||
var r = 9.0;
|
rFade,
|
||||||
var pauseTimer = null;
|
pauseTimer = null;
|
||||||
pauseTimer = Script.setInterval(function() {
|
|
||||||
r--;
|
pauseTimer = Script.setInterval(function () {
|
||||||
rFade = r / 10.0;
|
r -= 1;
|
||||||
Overlays.editOverlay(noticeOut, {alpha: rFade});
|
rFade = r / 10.0;
|
||||||
Overlays.editOverlay(buttonOut, {alpha: rFade});
|
Overlays.editOverlay(noticeOut, { alpha: rFade });
|
||||||
|
Overlays.editOverlay(buttonOut, { alpha: rFade });
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
dismiss(noticeOut, buttonOut, arraysOut);
|
dismiss(noticeOut, buttonOut, arraysOut);
|
||||||
arrays.splice(arraysOut, 1);
|
arrays.splice(arraysOut, 1);
|
||||||
|
@ -338,29 +151,283 @@ function fadeOut(noticeOut, buttonOut, arraysOut) {
|
||||||
}, 20);
|
}, 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This handles the final dismissal of a notification after fading
|
function calculate3DOverlayPositions(noticeWidth, noticeHeight, y) {
|
||||||
function dismiss(firstNoteOut, firstButOut, firstOut) {
|
// Calculates overlay positions and orientations in avatar coordinates.
|
||||||
var working = firstOut
|
var noticeY,
|
||||||
Overlays.deleteOverlay(firstNoteOut);
|
originOffset,
|
||||||
Overlays.deleteOverlay(firstButOut);
|
notificationOrientation,
|
||||||
notifications.splice(firstOut, 1);
|
notificationPosition,
|
||||||
buttons.splice(firstOut, 1);
|
buttonPosition;
|
||||||
times.splice(firstOut, 1);
|
|
||||||
heights.splice(firstOut, 1);
|
// Notification plane positions
|
||||||
myAlpha.splice(firstOut,1);
|
noticeY = -y * NOTIFICATION_3D_SCALE - noticeHeight / 2;
|
||||||
|
notificationPosition = { x: 0, y: noticeY, z: 0 };
|
||||||
|
buttonPosition = { x: (noticeWidth - NOTIFICATION_3D_BUTTON_WIDTH) / 2, y: noticeY, z: 0.001 };
|
||||||
|
|
||||||
|
// Rotate plane
|
||||||
|
notificationOrientation = Quat.fromPitchYawRollDegrees(NOTIFICATIONS_3D_PITCH,
|
||||||
|
NOTIFICATIONS_3D_DIRECTION + NOTIFICATIONS_3D_YAW, 0);
|
||||||
|
notificationPosition = Vec3.multiplyQbyV(notificationOrientation, notificationPosition);
|
||||||
|
buttonPosition = Vec3.multiplyQbyV(notificationOrientation, buttonPosition);
|
||||||
|
|
||||||
|
// Translate plane
|
||||||
|
originOffset = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, NOTIFICATIONS_3D_DIRECTION, 0),
|
||||||
|
{ x: 0, y: 0, z: -NOTIFICATIONS_3D_DISTANCE });
|
||||||
|
originOffset.y += NOTIFICATIONS_3D_ELEVATION;
|
||||||
|
notificationPosition = Vec3.sum(originOffset, notificationPosition);
|
||||||
|
buttonPosition = Vec3.sum(originOffset, buttonPosition);
|
||||||
|
|
||||||
|
return {
|
||||||
|
notificationOrientation: notificationOrientation,
|
||||||
|
notificationPosition: notificationPosition,
|
||||||
|
buttonPosition: buttonPosition
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// This reports the number of users online at startup
|
// Pushes data to each array and sets up data for 2nd dimension array
|
||||||
function reportUsers() {
|
// to handle auxiliary data not carried by the overlay class
|
||||||
var numUsers = GlobalServices.onlineUsers.length;
|
// specifically notification "heights", "times" of creation, and .
|
||||||
var welcome = "Welcome! There are " + numUsers + " users online now.";
|
function notify(notice, button, height) {
|
||||||
createNotification(welcome);
|
var noticeWidth,
|
||||||
|
noticeHeight,
|
||||||
|
positions,
|
||||||
|
last;
|
||||||
|
|
||||||
|
if (isOnHMD) {
|
||||||
|
// Calculate 3D values from 2D overlay properties.
|
||||||
|
|
||||||
|
noticeWidth = notice.width * NOTIFICATION_3D_SCALE + NOTIFICATION_3D_BUTTON_WIDTH;
|
||||||
|
noticeHeight = notice.height * NOTIFICATION_3D_SCALE;
|
||||||
|
|
||||||
|
notice.size = { x: noticeWidth, y: noticeHeight };
|
||||||
|
notice.topMargin = 0.75 * notice.topMargin * NOTIFICATION_3D_SCALE;
|
||||||
|
notice.leftMargin = 2 * notice.leftMargin * NOTIFICATION_3D_SCALE;
|
||||||
|
notice.bottomMargin = 0;
|
||||||
|
notice.rightMargin = 0;
|
||||||
|
notice.lineHeight = 10.0 * (fontSize / 12.0) * NOTIFICATION_3D_SCALE;
|
||||||
|
notice.isFacingAvatar = false;
|
||||||
|
|
||||||
|
button.url = button.imageURL;
|
||||||
|
button.scale = button.width * NOTIFICATION_3D_SCALE;
|
||||||
|
button.isFacingAvatar = false;
|
||||||
|
|
||||||
|
positions = calculate3DOverlayPositions(noticeWidth, noticeHeight, notice.y);
|
||||||
|
|
||||||
|
notifications.push((Overlays.addOverlay("text3d", notice)));
|
||||||
|
buttons.push((Overlays.addOverlay("billboard", button)));
|
||||||
|
overlay3DDetails.push({
|
||||||
|
notificationOrientation: positions.notificationOrientation,
|
||||||
|
notificationPosition: positions.notificationPosition,
|
||||||
|
buttonPosition: positions.buttonPosition,
|
||||||
|
width: noticeWidth,
|
||||||
|
height: noticeHeight
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
notifications.push((Overlays.addOverlay("text", notice)));
|
||||||
|
buttons.push((Overlays.addOverlay("image", button)));
|
||||||
|
}
|
||||||
|
|
||||||
|
height = height + 1.0;
|
||||||
|
heights.push(height);
|
||||||
|
times.push(new Date().getTime() / 1000);
|
||||||
|
myAlpha.push(0);
|
||||||
|
last = notifications.length - 1;
|
||||||
|
createArrays(notifications[last], buttons[last], times[last], heights[last], myAlpha[last]);
|
||||||
|
fadeIn(notifications[last], buttons[last]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function creates and sizes the overlays
|
||||||
|
function createNotification(text) {
|
||||||
|
var count = (text.match(/\n/g) || []).length,
|
||||||
|
breakPoint = 43.0, // length when new line is added
|
||||||
|
extraLine = 0,
|
||||||
|
breaks = 0,
|
||||||
|
height = 40.0,
|
||||||
|
stack = 0,
|
||||||
|
level,
|
||||||
|
noticeProperties,
|
||||||
|
bLevel,
|
||||||
|
buttonProperties,
|
||||||
|
i;
|
||||||
|
|
||||||
|
if (text.length >= breakPoint) {
|
||||||
|
breaks = count;
|
||||||
|
}
|
||||||
|
extraLine = breaks * 16.0;
|
||||||
|
for (i = 0; i < heights.length; i += 1) {
|
||||||
|
stack = stack + heights[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
level = (stack + 20.0);
|
||||||
|
height = height + extraLine;
|
||||||
|
noticeProperties = {
|
||||||
|
x: overlayLocationX,
|
||||||
|
y: level,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
color: textColor,
|
||||||
|
backgroundColor: backColor,
|
||||||
|
alpha: backgroundAlpha,
|
||||||
|
topMargin: topMargin,
|
||||||
|
leftMargin: leftMargin,
|
||||||
|
font: {size: fontSize},
|
||||||
|
text: text
|
||||||
|
};
|
||||||
|
|
||||||
|
bLevel = level + 12.0;
|
||||||
|
buttonProperties = {
|
||||||
|
x: buttonLocationX,
|
||||||
|
y: bLevel,
|
||||||
|
width: 10.0,
|
||||||
|
height: 10.0,
|
||||||
|
subImage: { x: 0, y: 0, width: 10, height: 10 },
|
||||||
|
imageURL: "http://hifi-public.s3.amazonaws.com/images/close-small-light.svg",
|
||||||
|
color: { red: 255, green: 255, blue: 255},
|
||||||
|
visible: true,
|
||||||
|
alpha: backgroundAlpha
|
||||||
|
};
|
||||||
|
|
||||||
|
notify(noticeProperties, buttonProperties, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteNotification(index) {
|
||||||
|
Overlays.deleteOverlay(notifications[index]);
|
||||||
|
Overlays.deleteOverlay(buttons[index]);
|
||||||
|
notifications.splice(index, 1);
|
||||||
|
buttons.splice(index, 1);
|
||||||
|
times.splice(index, 1);
|
||||||
|
heights.splice(index, 1);
|
||||||
|
myAlpha.splice(index, 1);
|
||||||
|
overlay3DDetails.splice(index, 1);
|
||||||
|
arrays.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// wraps whole word to newline
|
||||||
|
function stringDivider(str, slotWidth, spaceReplacer) {
|
||||||
|
var p,
|
||||||
|
left,
|
||||||
|
right;
|
||||||
|
|
||||||
|
if (str.length > slotWidth) {
|
||||||
|
p = slotWidth;
|
||||||
|
while (p > 0 && str[p] !== ' ') {
|
||||||
|
p -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p > 0) {
|
||||||
|
left = str.substring(0, p);
|
||||||
|
right = str.substring(p + 1);
|
||||||
|
return left + spaceReplacer + stringDivider(right, slotWidth, spaceReplacer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// formats string to add newline every 43 chars
|
||||||
|
function wordWrap(str) {
|
||||||
|
var result = stringDivider(str, 43.0, "\n");
|
||||||
|
createNotification(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This fires a notification on window resize
|
||||||
|
function checkSize() {
|
||||||
|
if ((Window.innerWidth !== ourWidth) || (Window.innerHeight !== ourHeight)) {
|
||||||
|
var windowResize = "Window has been resized";
|
||||||
|
ourWidth = Window.innerWidth;
|
||||||
|
ourHeight = Window.innerHeight;
|
||||||
|
windowDimensions = Controller.getViewportDimensions();
|
||||||
|
overlayLocationX = (windowDimensions.x - (width + 60.0));
|
||||||
|
buttonLocationX = overlayLocationX + (width - 35.0);
|
||||||
|
createNotification(windowResize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
var nextOverlay,
|
||||||
|
noticeOut,
|
||||||
|
buttonOut,
|
||||||
|
arraysOut,
|
||||||
|
defaultEyePosition,
|
||||||
|
avatarOrientation,
|
||||||
|
notificationPosition,
|
||||||
|
notificationOrientation,
|
||||||
|
buttonPosition,
|
||||||
|
positions,
|
||||||
|
i,
|
||||||
|
j,
|
||||||
|
k;
|
||||||
|
|
||||||
|
if (isOnHMD !== Menu.isOptionChecked(ENABLE_VR_MODE)) {
|
||||||
|
while (arrays.length > 0) {
|
||||||
|
deleteNotification(0);
|
||||||
|
}
|
||||||
|
isOnHMD = !isOnHMD;
|
||||||
|
persistTime = isOnHMD ? PERSIST_TIME_3D : PERSIST_TIME_2D;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame += 1;
|
||||||
|
if ((frame % 60.0) === 0) { // only update once a second
|
||||||
|
checkSize(); // checks for size change to trigger windowResize notification
|
||||||
|
locationY = 20.0;
|
||||||
|
for (i = 0; i < arrays.length; i += 1) { //repositions overlays as others fade
|
||||||
|
nextOverlay = Overlays.getOverlayAtPoint({ x: overlayLocationX, y: locationY });
|
||||||
|
Overlays.editOverlay(notifications[i], { x: overlayLocationX, y: locationY });
|
||||||
|
Overlays.editOverlay(buttons[i], { x: buttonLocationX, y: locationY + 12.0 });
|
||||||
|
if (isOnHMD) {
|
||||||
|
positions = calculate3DOverlayPositions(overlay3DDetails[i].width, overlay3DDetails[i].height, locationY);
|
||||||
|
overlay3DDetails[i].notificationOrientation = positions.notificationOrientation;
|
||||||
|
overlay3DDetails[i].notificationPosition = positions.notificationPosition;
|
||||||
|
overlay3DDetails[i].buttonPosition = positions.buttonPosition;
|
||||||
|
}
|
||||||
|
locationY = locationY + arrays[i][3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This checks the age of the notification and prepares to fade it after 9.0 seconds (var persistTime - 1)
|
||||||
|
for (i = 0; i < arrays.length; i += 1) {
|
||||||
|
if (ready) {
|
||||||
|
j = arrays[i][2];
|
||||||
|
k = j + persistTime;
|
||||||
|
if (k < (new Date().getTime() / 1000)) {
|
||||||
|
ready = false;
|
||||||
|
noticeOut = arrays[i][0];
|
||||||
|
buttonOut = arrays[i][1];
|
||||||
|
arraysOut = i;
|
||||||
|
fadeOut(noticeOut, buttonOut, arraysOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isOnHMD && notifications.length > 0) {
|
||||||
|
// Update 3D overlays to maintain positions relative to avatar
|
||||||
|
defaultEyePosition = MyAvatar.getDefaultEyePosition();
|
||||||
|
avatarOrientation = MyAvatar.orientation;
|
||||||
|
|
||||||
|
for (i = 0; i < notifications.length; i += 1) {
|
||||||
|
notificationPosition = Vec3.sum(defaultEyePosition,
|
||||||
|
Vec3.multiplyQbyV(avatarOrientation, overlay3DDetails[i].notificationPosition));
|
||||||
|
notificationOrientation = Quat.multiply(avatarOrientation, overlay3DDetails[i].notificationOrientation);
|
||||||
|
buttonPosition = Vec3.sum(defaultEyePosition,
|
||||||
|
Vec3.multiplyQbyV(avatarOrientation, overlay3DDetails[i].buttonPosition));
|
||||||
|
Overlays.editOverlay(notifications[i], { position: notificationPosition, rotation: notificationOrientation });
|
||||||
|
Overlays.editOverlay(buttons[i], { position: buttonPosition, rotation: notificationOrientation });
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var STARTUP_TIMEOUT = 500, // ms
|
var STARTUP_TIMEOUT = 500, // ms
|
||||||
startingUp = true,
|
startingUp = true,
|
||||||
startupTimer = null;
|
startupTimer = null;
|
||||||
|
|
||||||
|
// This reports the number of users online at startup
|
||||||
|
function reportUsers() {
|
||||||
|
var welcome;
|
||||||
|
|
||||||
|
welcome = "Welcome! There are " + GlobalServices.onlineUsers.length + " users online now.";
|
||||||
|
createNotification(welcome);
|
||||||
|
}
|
||||||
|
|
||||||
function finishStartup() {
|
function finishStartup() {
|
||||||
startingUp = false;
|
startingUp = false;
|
||||||
Script.clearTimeout(startupTimer);
|
Script.clearTimeout(startupTimer);
|
||||||
|
@ -378,6 +445,113 @@ function isStartingUp() {
|
||||||
return startingUp;
|
return startingUp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Triggers notification if a user logs on or off
|
||||||
|
function onOnlineUsersChanged(users) {
|
||||||
|
var i;
|
||||||
|
|
||||||
|
if (!isStartingUp()) { // Skip user notifications at startup.
|
||||||
|
for (i = 0; i < users.length; i += 1) {
|
||||||
|
if (last_users.indexOf(users[i]) === -1.0) {
|
||||||
|
createNotification(users[i] + " has joined");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < last_users.length; i += 1) {
|
||||||
|
if (users.indexOf(last_users[i]) === -1.0) {
|
||||||
|
createNotification(last_users[i] + " has left");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
last_users = users;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Triggers notification if @MyUserName is mentioned in chat and returns the message to the notification.
|
||||||
|
function onIncomingMessage(user, message) {
|
||||||
|
var myMessage,
|
||||||
|
alertMe,
|
||||||
|
thisAlert;
|
||||||
|
|
||||||
|
myMessage = message;
|
||||||
|
alertMe = "@" + GlobalServices.myUsername;
|
||||||
|
thisAlert = user + ": " + myMessage;
|
||||||
|
|
||||||
|
if (myMessage.indexOf(alertMe) > -1.0) {
|
||||||
|
wordWrap(thisAlert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Triggers mic mute notification
|
||||||
|
function onMuteStateChanged() {
|
||||||
|
var muteState,
|
||||||
|
muteString;
|
||||||
|
|
||||||
|
muteState = AudioDevice.getMuted() ? "muted" : "unmuted";
|
||||||
|
muteString = "Microphone is now " + muteState;
|
||||||
|
createNotification(muteString);
|
||||||
|
}
|
||||||
|
|
||||||
|
// handles mouse clicks on buttons
|
||||||
|
function mousePressEvent(event) {
|
||||||
|
var pickRay,
|
||||||
|
clickedOverlay,
|
||||||
|
i;
|
||||||
|
|
||||||
|
if (isOnHMD) {
|
||||||
|
pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
|
clickedOverlay = Overlays.findRayIntersection(pickRay).overlayID;
|
||||||
|
} else {
|
||||||
|
clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < buttons.length; i += 1) {
|
||||||
|
if (clickedOverlay === buttons[i]) {
|
||||||
|
deleteNotification(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Control key remains active only while key is held down
|
||||||
|
function keyReleaseEvent(key) {
|
||||||
|
if (key.key === 16777249) {
|
||||||
|
ctrlIsPressed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Triggers notification on specific key driven events
|
||||||
|
function keyPressEvent(key) {
|
||||||
|
var numUsers,
|
||||||
|
welcome,
|
||||||
|
noteString;
|
||||||
|
|
||||||
|
if (key.key === 16777249) {
|
||||||
|
ctrlIsPressed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.text === "q") { //queries number of users online
|
||||||
|
numUsers = GlobalServices.onlineUsers.length;
|
||||||
|
welcome = "There are " + numUsers + " users online now.";
|
||||||
|
createNotification(welcome);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.text === "s") {
|
||||||
|
if (ctrlIsPressed === true) {
|
||||||
|
noteString = "Snapshot taken.";
|
||||||
|
createNotification(noteString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When our script shuts down, we should clean up all of our overlays
|
||||||
|
function scriptEnding() {
|
||||||
|
var i;
|
||||||
|
|
||||||
|
for (i = 0; i < notifications.length; i += 1) {
|
||||||
|
Overlays.deleteOverlay(notifications[i]);
|
||||||
|
Overlays.deleteOverlay(buttons[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AudioDevice.muteToggled.connect(onMuteStateChanged);
|
AudioDevice.muteToggled.connect(onMuteStateChanged);
|
||||||
Controller.keyPressEvent.connect(keyPressEvent);
|
Controller.keyPressEvent.connect(keyPressEvent);
|
||||||
|
@ -386,3 +560,4 @@ GlobalServices.onlineUsersChanged.connect(onOnlineUsersChanged);
|
||||||
GlobalServices.incomingMessage.connect(onIncomingMessage);
|
GlobalServices.incomingMessage.connect(onIncomingMessage);
|
||||||
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
||||||
Script.update.connect(update);
|
Script.update.connect(update);
|
||||||
|
Script.scriptEnding.connect(scriptEnding);
|
||||||
|
|
182
examples/popcorn.js
Normal file
182
examples/popcorn.js
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
//
|
||||||
|
// popcorn.js
|
||||||
|
// examples
|
||||||
|
//
|
||||||
|
// Created by Philip Rosedale on January 25, 2014
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Creates a bunch of physical balls trapped in a box with a rotating wall in the middle that smacks them around,
|
||||||
|
// and a periodic 'pop' force that shoots them into the air.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
var BALL_SIZE = 0.07;
|
||||||
|
var WALL_THICKNESS = 0.10;
|
||||||
|
var SCALE = 1.0;
|
||||||
|
|
||||||
|
var GRAVITY = -1.0;
|
||||||
|
var LIFETIME = 600;
|
||||||
|
var DAMPING = 0.50;
|
||||||
|
|
||||||
|
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(SCALE * 3.0, Quat.getFront(Camera.getOrientation())));
|
||||||
|
|
||||||
|
var floor = Entities.addEntity(
|
||||||
|
{ type: "Box",
|
||||||
|
position: Vec3.subtract(center, { x: 0, y: SCALE / 2.0, z: 0 }),
|
||||||
|
dimensions: { x: SCALE, y: WALL_THICKNESS, z: SCALE },
|
||||||
|
color: { red: 0, green: 255, blue: 0 },
|
||||||
|
gravity: { x: 0, y: 0, z: 0 },
|
||||||
|
ignoreCollisions: false,
|
||||||
|
lifetime: LIFETIME });
|
||||||
|
|
||||||
|
var ceiling = Entities.addEntity(
|
||||||
|
{ type: "Box",
|
||||||
|
position: Vec3.sum(center, { x: 0, y: SCALE / 2.0, z: 0 }),
|
||||||
|
dimensions: { x: SCALE, y: WALL_THICKNESS, z: SCALE },
|
||||||
|
color: { red: 128, green: 128, blue: 128 },
|
||||||
|
gravity: { x: 0, y: 0, z: 0 },
|
||||||
|
ignoreCollisions: false,
|
||||||
|
visible: true,
|
||||||
|
lifetime: LIFETIME });
|
||||||
|
|
||||||
|
var wall1 = Entities.addEntity(
|
||||||
|
{ type: "Box",
|
||||||
|
position: Vec3.sum(center, { x: SCALE / 2.0, y: 0, z: 0 }),
|
||||||
|
dimensions: { x: WALL_THICKNESS, y: SCALE, z: SCALE },
|
||||||
|
color: { red: 0, green: 255, blue: 0 },
|
||||||
|
gravity: { x: 0, y: 0, z: 0 },
|
||||||
|
ignoreCollisions: false,
|
||||||
|
visible: false,
|
||||||
|
lifetime: LIFETIME });
|
||||||
|
|
||||||
|
var wall2 = Entities.addEntity(
|
||||||
|
{ type: "Box",
|
||||||
|
position: Vec3.subtract(center, { x: SCALE / 2.0, y: 0, z: 0 }),
|
||||||
|
dimensions: { x: WALL_THICKNESS, y: SCALE, z: SCALE },
|
||||||
|
color: { red: 0, green: 255, blue: 0 },
|
||||||
|
gravity: { x: 0, y: 0, z: 0 },
|
||||||
|
ignoreCollisions: false,
|
||||||
|
visible: false,
|
||||||
|
lifetime: LIFETIME });
|
||||||
|
|
||||||
|
var wall3 = Entities.addEntity(
|
||||||
|
{ type: "Box",
|
||||||
|
position: Vec3.subtract(center, { x: 0, y: 0, z: SCALE / 2.0 }),
|
||||||
|
dimensions: { x: SCALE, y: SCALE, z: WALL_THICKNESS },
|
||||||
|
color: { red: 0, green: 255, blue: 0 },
|
||||||
|
gravity: { x: 0, y: 0, z: 0 },
|
||||||
|
ignoreCollisions: false,
|
||||||
|
visible: false,
|
||||||
|
lifetime: LIFETIME });
|
||||||
|
|
||||||
|
var wall4 = Entities.addEntity(
|
||||||
|
{ type: "Box",
|
||||||
|
position: Vec3.sum(center, { x: 0, y: 0, z: SCALE / 2.0 }),
|
||||||
|
dimensions: { x: SCALE, y: SCALE, z: WALL_THICKNESS },
|
||||||
|
color: { red: 0, green: 255, blue: 0 },
|
||||||
|
gravity: { x: 0, y: 0, z: 0 },
|
||||||
|
ignoreCollisions: false,
|
||||||
|
visible: false,
|
||||||
|
lifetime: LIFETIME });
|
||||||
|
|
||||||
|
var corner1 = Entities.addEntity(
|
||||||
|
{ type: "Box",
|
||||||
|
position: Vec3.sum(center, { x: -SCALE / 2.0, y: 0, z: SCALE / 2.0 }),
|
||||||
|
dimensions: { x: WALL_THICKNESS, y: SCALE, z: WALL_THICKNESS },
|
||||||
|
color: { red: 128, green: 128, blue: 128 },
|
||||||
|
ignoreCollisions: false,
|
||||||
|
visible: true,
|
||||||
|
lifetime: LIFETIME });
|
||||||
|
|
||||||
|
var corner2 = Entities.addEntity(
|
||||||
|
{ type: "Box",
|
||||||
|
position: Vec3.sum(center, { x: -SCALE / 2.0, y: 0, z: -SCALE / 2.0 }),
|
||||||
|
dimensions: { x: WALL_THICKNESS, y: SCALE, z: WALL_THICKNESS },
|
||||||
|
color: { red: 128, green: 128, blue: 128 },
|
||||||
|
ignoreCollisions: false,
|
||||||
|
visible: true,
|
||||||
|
lifetime: LIFETIME });
|
||||||
|
|
||||||
|
var corner3 = Entities.addEntity(
|
||||||
|
{ type: "Box",
|
||||||
|
position: Vec3.sum(center, { x: SCALE / 2.0, y: 0, z: SCALE / 2.0 }),
|
||||||
|
dimensions: { x: WALL_THICKNESS, y: SCALE, z: WALL_THICKNESS },
|
||||||
|
color: { red: 128, green: 128, blue: 128 },
|
||||||
|
ignoreCollisions: false,
|
||||||
|
visible: true,
|
||||||
|
lifetime: LIFETIME });
|
||||||
|
|
||||||
|
var corner4 = Entities.addEntity(
|
||||||
|
{ type: "Box",
|
||||||
|
position: Vec3.sum(center, { x: SCALE / 2.0, y: 0, z: -SCALE / 2.0 }),
|
||||||
|
dimensions: { x: WALL_THICKNESS, y: SCALE, z: WALL_THICKNESS },
|
||||||
|
color: { red: 128, green: 128, blue: 128 },
|
||||||
|
ignoreCollisions: false,
|
||||||
|
visible: true,
|
||||||
|
lifetime: LIFETIME });
|
||||||
|
|
||||||
|
var spinner = Entities.addEntity(
|
||||||
|
{ type: "Box",
|
||||||
|
position: center,
|
||||||
|
dimensions: { x: SCALE / 1.5, y: SCALE / 3.0, z: SCALE / 8.0 },
|
||||||
|
color: { red: 255, green: 0, blue: 0 },
|
||||||
|
angularVelocity: { x: 0, y: 360, z: 0 },
|
||||||
|
angularDamping: 0.0,
|
||||||
|
gravity: { x: 0, y: 0, z: 0 },
|
||||||
|
ignoreCollisions: false,
|
||||||
|
visible: true,
|
||||||
|
lifetime: LIFETIME });
|
||||||
|
|
||||||
|
var NUM_BALLS = 70;
|
||||||
|
|
||||||
|
balls = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < NUM_BALLS; i++) {
|
||||||
|
balls.push(Entities.addEntity(
|
||||||
|
{ type: "Sphere",
|
||||||
|
position: { x: center.x + (Math.random() - 0.5) * (SCALE - BALL_SIZE - WALL_THICKNESS),
|
||||||
|
y: center.y + (Math.random() - 0.5) * (SCALE - BALL_SIZE - WALL_THICKNESS) ,
|
||||||
|
z: center.z + (Math.random() - 0.5) * (SCALE - BALL_SIZE - WALL_THICKNESS) },
|
||||||
|
dimensions: { x: BALL_SIZE, y: BALL_SIZE, z: BALL_SIZE },
|
||||||
|
color: { red: Math.random() * 255, green: Math.random() * 255, blue: Math.random() * 255 },
|
||||||
|
gravity: { x: 0, y: GRAVITY, z: 0 },
|
||||||
|
ignoreCollisions: false,
|
||||||
|
damping: DAMPING,
|
||||||
|
lifetime: LIFETIME,
|
||||||
|
collisionsWillMove: true }));
|
||||||
|
}
|
||||||
|
|
||||||
|
var VEL_MAG = 2.0;
|
||||||
|
var CHANCE_OF_POP = 0.007; // 0.01;
|
||||||
|
function update(deltaTime) {
|
||||||
|
for (var i = 0; i < NUM_BALLS; i++) {
|
||||||
|
if (Math.random() < CHANCE_OF_POP) {
|
||||||
|
Entities.editEntity(balls[i], { velocity: { x: (Math.random() - 0.5) * VEL_MAG, y: Math.random() * VEL_MAG, z: (Math.random() - 0.5) * VEL_MAG }});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function scriptEnding() {
|
||||||
|
Entities.deleteEntity(wall1);
|
||||||
|
Entities.deleteEntity(wall2);
|
||||||
|
Entities.deleteEntity(wall3);
|
||||||
|
Entities.deleteEntity(wall4);
|
||||||
|
Entities.deleteEntity(corner1);
|
||||||
|
Entities.deleteEntity(corner2);
|
||||||
|
Entities.deleteEntity(corner3);
|
||||||
|
Entities.deleteEntity(corner4);
|
||||||
|
Entities.deleteEntity(floor);
|
||||||
|
Entities.deleteEntity(ceiling);
|
||||||
|
Entities.deleteEntity(spinner);
|
||||||
|
|
||||||
|
for (var i = 0; i < NUM_BALLS; i++) {
|
||||||
|
Entities.deleteEntity(balls[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(scriptEnding);
|
||||||
|
Script.update.connect(update);
|
|
@ -51,7 +51,7 @@ public:
|
||||||
// getters
|
// getters
|
||||||
float getLeanScale() const { return _leanScale; }
|
float getLeanScale() const { return _leanScale; }
|
||||||
glm::vec3 getGravity() const { return _gravity; }
|
glm::vec3 getGravity() const { return _gravity; }
|
||||||
glm::vec3 getDefaultEyePosition() const;
|
Q_INVOKABLE glm::vec3 getDefaultEyePosition() const;
|
||||||
bool getShouldRenderLocally() const { return _shouldRender; }
|
bool getShouldRenderLocally() const { return _shouldRender; }
|
||||||
|
|
||||||
const QList<AnimationHandlePointer>& getAnimationHandles() const { return _animationHandles; }
|
const QList<AnimationHandlePointer>& getAnimationHandles() const { return _animationHandles; }
|
||||||
|
|
|
@ -45,7 +45,6 @@ ImageOverlay::~ImageOverlay() {
|
||||||
// TODO: handle setting image multiple times, how do we manage releasing the bound texture?
|
// TODO: handle setting image multiple times, how do we manage releasing the bound texture?
|
||||||
void ImageOverlay::setImageURL(const QUrl& url) {
|
void ImageOverlay::setImageURL(const QUrl& url) {
|
||||||
_imageURL = url;
|
_imageURL = url;
|
||||||
|
|
||||||
if (url.isEmpty()) {
|
if (url.isEmpty()) {
|
||||||
_isLoaded = true;
|
_isLoaded = true;
|
||||||
_renderImage = false;
|
_renderImage = false;
|
||||||
|
|
|
@ -254,7 +254,16 @@ bool Texture::assignStoredMip(uint16 level, const Element& format, Size size, co
|
||||||
}
|
}
|
||||||
|
|
||||||
// THen check that the mem buffer passed make sense with its format
|
// THen check that the mem buffer passed make sense with its format
|
||||||
if (size == evalStoredMipSize(level, format)) {
|
Size expectedSize = evalStoredMipSize(level, format);
|
||||||
|
if (size == expectedSize) {
|
||||||
|
_storage->assignMipData(level, format, size, bytes);
|
||||||
|
_stamp++;
|
||||||
|
return true;
|
||||||
|
} else if (size > expectedSize) {
|
||||||
|
// NOTE: We are facing this case sometime because apparently QImage (from where we get the bits) is generating images
|
||||||
|
// and alligning the line of pixels to 32 bits.
|
||||||
|
// We should probably consider something a bit more smart to get the correct result but for now (UI elements)
|
||||||
|
// it seems to work...
|
||||||
_storage->assignMipData(level, format, size, bytes);
|
_storage->assignMipData(level, format, size, bytes);
|
||||||
_stamp++;
|
_stamp++;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -387,7 +387,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, TextureType type, const QByteArr
|
||||||
if (!url.isValid()) {
|
if (!url.isValid()) {
|
||||||
_loaded = true;
|
_loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// default to white/blue/black
|
// default to white/blue/black
|
||||||
/* glBindTexture(GL_TEXTURE_2D, getID());
|
/* glBindTexture(GL_TEXTURE_2D, getID());
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -458,13 +458,18 @@ void ImageReader::run() {
|
||||||
int originalWidth = image.width();
|
int originalWidth = image.width();
|
||||||
int originalHeight = image.height();
|
int originalHeight = image.height();
|
||||||
|
|
||||||
// enforce a fixed maximum
|
// enforce a fixed maximum area (1024 * 2048)
|
||||||
const int MAXIMUM_SIZE = 1024;
|
const int MAXIMUM_AREA_SIZE = 2097152;
|
||||||
if (image.width() > MAXIMUM_SIZE || image.height() > MAXIMUM_SIZE) {
|
|
||||||
qDebug() << "Image greater than maximum size:" << _url << image.width() << image.height();
|
|
||||||
image = image.scaled(MAXIMUM_SIZE, MAXIMUM_SIZE, Qt::KeepAspectRatio);
|
|
||||||
}
|
|
||||||
int imageArea = image.width() * image.height();
|
int imageArea = image.width() * image.height();
|
||||||
|
if (imageArea > MAXIMUM_AREA_SIZE) {
|
||||||
|
float scaleRatio = sqrtf((float)MAXIMUM_AREA_SIZE) / sqrtf((float)imageArea);
|
||||||
|
int resizeWidth = static_cast<int>(std::floor(scaleRatio * static_cast<float>(image.width())));
|
||||||
|
int resizeHeight = static_cast<int>(std::floor(scaleRatio * static_cast<float>(image.height())));
|
||||||
|
qDebug() << "Image greater than maximum size:" << _url << image.width() << image.height() <<
|
||||||
|
" scaled to:" << resizeWidth << resizeHeight;
|
||||||
|
image = image.scaled(resizeWidth, resizeHeight, Qt::IgnoreAspectRatio);
|
||||||
|
imageArea = image.width() * image.height();
|
||||||
|
}
|
||||||
|
|
||||||
const int EIGHT_BIT_MAXIMUM = 255;
|
const int EIGHT_BIT_MAXIMUM = 255;
|
||||||
if (!image.hasAlphaChannel()) {
|
if (!image.hasAlphaChannel()) {
|
||||||
|
|
79
libraries/script-engine/src/BatchLoader.cpp
Normal file
79
libraries/script-engine/src/BatchLoader.cpp
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
//
|
||||||
|
// BatchLoader.cpp
|
||||||
|
// libraries/script-engine/src
|
||||||
|
//
|
||||||
|
// Created by Ryan Huffman on 01/22/15
|
||||||
|
// Copyright 2015 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 <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
#include "BatchLoader.h"
|
||||||
|
#include <NetworkAccessManager.h>
|
||||||
|
|
||||||
|
BatchLoader::BatchLoader(const QList<QUrl>& urls)
|
||||||
|
: QObject(),
|
||||||
|
_started(false),
|
||||||
|
_finished(false),
|
||||||
|
_urls(urls.toSet()),
|
||||||
|
_data() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchLoader::start() {
|
||||||
|
if (_started) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_started = true;
|
||||||
|
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||||
|
for (QUrl url : _urls) {
|
||||||
|
if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "ftp") {
|
||||||
|
QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url));
|
||||||
|
|
||||||
|
qDebug() << "Downloading file at" << url;
|
||||||
|
|
||||||
|
connect(reply, &QNetworkReply::finished, [=]() {
|
||||||
|
if (reply->error()) {
|
||||||
|
_data.insert(url, QString());
|
||||||
|
} else {
|
||||||
|
_data.insert(url, reply->readAll());
|
||||||
|
}
|
||||||
|
reply->deleteLater();
|
||||||
|
checkFinished();
|
||||||
|
});
|
||||||
|
|
||||||
|
// If we end up being destroyed before the reply finishes, clean it up
|
||||||
|
connect(this, &QObject::destroyed, reply, &QObject::deleteLater);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
#ifdef _WIN32
|
||||||
|
QString fileName = url.toString();
|
||||||
|
#else
|
||||||
|
QString fileName = url.toLocalFile();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
qDebug() << "Reading file at " << fileName;
|
||||||
|
|
||||||
|
QFile scriptFile(fileName);
|
||||||
|
if (scriptFile.open(QFile::ReadOnly | QFile::Text)) {
|
||||||
|
QTextStream in(&scriptFile);
|
||||||
|
_data.insert(url, in.readAll());
|
||||||
|
} else {
|
||||||
|
_data.insert(url, QString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchLoader::checkFinished() {
|
||||||
|
if (!_finished && _urls.size() == _data.size()) {
|
||||||
|
_finished = true;
|
||||||
|
emit finished(_data);
|
||||||
|
}
|
||||||
|
}
|
42
libraries/script-engine/src/BatchLoader.h
Normal file
42
libraries/script-engine/src/BatchLoader.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
//
|
||||||
|
// BatchLoader.h
|
||||||
|
// libraries/script-engine/src
|
||||||
|
//
|
||||||
|
// Created by Ryan Huffman on 01/22/15
|
||||||
|
// Copyright 2015 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
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_BatchLoader_h
|
||||||
|
#define hifi_BatchLoader_h
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QSet>
|
||||||
|
#include <QString>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
class BatchLoader : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
BatchLoader(const QList<QUrl>& urls) ;
|
||||||
|
|
||||||
|
void start();
|
||||||
|
bool isFinished() const { return _finished; };
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void finished(const QMap<QUrl, QString>& data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void checkFinished();
|
||||||
|
|
||||||
|
bool _started;
|
||||||
|
bool _finished;
|
||||||
|
QSet<QUrl> _urls;
|
||||||
|
QMap<QUrl, QString> _data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_BatchLoader_h
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
#include "AnimationObject.h"
|
#include "AnimationObject.h"
|
||||||
#include "ArrayBufferViewClass.h"
|
#include "ArrayBufferViewClass.h"
|
||||||
|
#include "BatchLoader.h"
|
||||||
#include "DataViewClass.h"
|
#include "DataViewClass.h"
|
||||||
#include "EventTypes.h"
|
#include "EventTypes.h"
|
||||||
#include "MenuItemProperties.h"
|
#include "MenuItemProperties.h"
|
||||||
|
@ -111,7 +112,7 @@ void ScriptEngine::setIsAvatar(bool isAvatar) {
|
||||||
_avatarIdentityTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS);
|
_avatarIdentityTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS);
|
||||||
_avatarBillboardTimer->start(AVATAR_BILLBOARD_PACKET_SEND_INTERVAL_MSECS);
|
_avatarBillboardTimer->start(AVATAR_BILLBOARD_PACKET_SEND_INTERVAL_MSECS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_isAvatar) {
|
if (!_isAvatar) {
|
||||||
delete _avatarIdentityTimer;
|
delete _avatarIdentityTimer;
|
||||||
_avatarIdentityTimer = NULL;
|
_avatarIdentityTimer = NULL;
|
||||||
|
@ -304,7 +305,7 @@ QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileN
|
||||||
QScriptValue result = QScriptEngine::evaluate(program, fileName, lineNumber);
|
QScriptValue result = QScriptEngine::evaluate(program, fileName, lineNumber);
|
||||||
if (hasUncaughtException()) {
|
if (hasUncaughtException()) {
|
||||||
int line = uncaughtExceptionLineNumber();
|
int line = uncaughtExceptionLineNumber();
|
||||||
qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ": " << result.toString();
|
qDebug() << "Uncaught exception at (" << _fileNameString << " : " << fileName << ") line" << line << ": " << result.toString();
|
||||||
}
|
}
|
||||||
emit evaluationFinished(result, hasUncaughtException());
|
emit evaluationFinished(result, hasUncaughtException());
|
||||||
clearExceptions();
|
clearExceptions();
|
||||||
|
@ -595,46 +596,57 @@ void ScriptEngine::print(const QString& message) {
|
||||||
emit printedMessage(message);
|
emit printedMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::include(const QString& includeFile) {
|
/**
|
||||||
QUrl url = resolvePath(includeFile);
|
* If a callback is specified, the included files will be loaded asynchronously and the callback will be called
|
||||||
QString includeContents;
|
* when all of the files have finished loading.
|
||||||
|
* If no callback is specified, the included files will be loaded synchronously and will block execution until
|
||||||
|
* all of the files have finished loading.
|
||||||
|
*/
|
||||||
|
void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callback) {
|
||||||
|
QList<QUrl> urls;
|
||||||
|
for (QString file : includeFiles) {
|
||||||
|
urls.append(resolvePath(file));
|
||||||
|
}
|
||||||
|
|
||||||
if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "ftp") {
|
BatchLoader* loader = new BatchLoader(urls);
|
||||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
|
||||||
QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url));
|
auto evaluateScripts = [=](const QMap<QUrl, QString>& data) {
|
||||||
qDebug() << "Downloading included script at" << includeFile;
|
for (QUrl url : urls) {
|
||||||
QEventLoop loop;
|
QString contents = data[url];
|
||||||
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
if (contents.isNull()) {
|
||||||
loop.exec();
|
qDebug() << "Error loading file: " << url;
|
||||||
includeContents = reply->readAll();
|
} else {
|
||||||
reply->deleteLater();
|
QScriptValue result = evaluate(contents, url.toString());
|
||||||
} else {
|
}
|
||||||
#ifdef _WIN32
|
|
||||||
QString fileName = url.toString();
|
|
||||||
#else
|
|
||||||
QString fileName = url.toLocalFile();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QFile scriptFile(fileName);
|
|
||||||
if (scriptFile.open(QFile::ReadOnly | QFile::Text)) {
|
|
||||||
qDebug() << "Including file:" << fileName;
|
|
||||||
QTextStream in(&scriptFile);
|
|
||||||
includeContents = in.readAll();
|
|
||||||
} else {
|
|
||||||
qDebug() << "ERROR Including file:" << fileName;
|
|
||||||
emit errorMessage("ERROR Including file:" + fileName);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
QScriptValue result = evaluate(includeContents);
|
if (callback.isFunction()) {
|
||||||
if (hasUncaughtException()) {
|
QScriptValue(callback).call();
|
||||||
int line = uncaughtExceptionLineNumber();
|
}
|
||||||
qDebug() << "Uncaught exception at (" << includeFile << ") line" << line << ":" << result.toString();
|
|
||||||
emit errorMessage("Uncaught exception at (" + includeFile + ") line" + QString::number(line) + ":" + result.toString());
|
loader->deleteLater();
|
||||||
clearExceptions();
|
};
|
||||||
|
|
||||||
|
connect(loader, &BatchLoader::finished, this, evaluateScripts);
|
||||||
|
|
||||||
|
// If we are destroyed before the loader completes, make sure to clean it up
|
||||||
|
connect(this, &QObject::destroyed, loader, &QObject::deleteLater);
|
||||||
|
|
||||||
|
loader->start();
|
||||||
|
|
||||||
|
if (!callback.isFunction() && !loader->isFinished()) {
|
||||||
|
QEventLoop loop;
|
||||||
|
QObject::connect(loader, &BatchLoader::finished, &loop, &QEventLoop::quit);
|
||||||
|
loop.exec();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::include(const QString& includeFile, QScriptValue callback) {
|
||||||
|
QStringList urls;
|
||||||
|
urls.append(includeFile);
|
||||||
|
include(urls, callback);
|
||||||
|
}
|
||||||
|
|
||||||
void ScriptEngine::load(const QString& loadFile) {
|
void ScriptEngine::load(const QString& loadFile) {
|
||||||
QUrl url = resolvePath(loadFile);
|
QUrl url = resolvePath(loadFile);
|
||||||
emit loadScript(url.toString(), false);
|
emit loadScript(url.toString(), false);
|
||||||
|
|
|
@ -96,7 +96,8 @@ public slots:
|
||||||
QObject* setTimeout(const QScriptValue& function, int timeoutMS);
|
QObject* setTimeout(const QScriptValue& function, int timeoutMS);
|
||||||
void clearInterval(QObject* timer) { stopTimer(reinterpret_cast<QTimer*>(timer)); }
|
void clearInterval(QObject* timer) { stopTimer(reinterpret_cast<QTimer*>(timer)); }
|
||||||
void clearTimeout(QObject* timer) { stopTimer(reinterpret_cast<QTimer*>(timer)); }
|
void clearTimeout(QObject* timer) { stopTimer(reinterpret_cast<QTimer*>(timer)); }
|
||||||
void include(const QString& includeFile);
|
void include(const QStringList& includeFiles, QScriptValue callback = QScriptValue());
|
||||||
|
void include(const QString& includeFile, QScriptValue callback = QScriptValue());
|
||||||
void load(const QString& loadfile);
|
void load(const QString& loadfile);
|
||||||
void print(const QString& message);
|
void print(const QString& message);
|
||||||
QUrl resolvePath(const QString& path) const;
|
QUrl resolvePath(const QString& path) const;
|
||||||
|
|
Loading…
Reference in a new issue