diff --git a/examples/dice.js b/examples/dice.js index f313e606b8..515019e740 100644 --- a/examples/dice.js +++ b/examples/dice.js @@ -12,17 +12,17 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var isDice = false; -var NUMBER_OF_DICE = 4; -var LIFETIME = 10000; // Dice will live for about 3 hours +var isDice = false; +var NUMBER_OF_DICE = 4; +var LIFETIME = 10000; // Dice will live for about 3 hours var dice = []; var DIE_SIZE = 0.20; -var madeSound = true; // Set false at start of throw to look for collision +var madeSound = true; // Set false at start of throw to look for collision HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; +SoundCache.getSound("http://s3.amazonaws.com/hifi-public/sounds/dice/diceCollide.wav"); -var rollSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/dice/diceRoll.wav"); var INSUFFICIENT_PERMISSIONS_ERROR_MSG = "You do not have the necessary permissions to create new objects." @@ -32,34 +32,46 @@ var BUTTON_SIZE = 32; var PADDING = 3; var offButton = Overlays.addOverlay("image", { - x: screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING, - y: screenSize.y- (BUTTON_SIZE + PADDING), - width: BUTTON_SIZE, - height: BUTTON_SIZE, - imageURL: HIFI_PUBLIC_BUCKET + "images/close.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1 - }); + x: screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING, + y: screenSize.y - (BUTTON_SIZE + PADDING), + width: BUTTON_SIZE, + height: BUTTON_SIZE, + imageURL: HIFI_PUBLIC_BUCKET + "images/close.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1 +}); var deleteButton = Overlays.addOverlay("image", { - x: screenSize.x / 2 - BUTTON_SIZE, - y: screenSize.y- (BUTTON_SIZE + PADDING), - width: BUTTON_SIZE, - height: BUTTON_SIZE, - imageURL: HIFI_PUBLIC_BUCKET + "images/delete.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1 - }); + x: screenSize.x / 2 - BUTTON_SIZE, + y: screenSize.y - (BUTTON_SIZE + PADDING), + width: BUTTON_SIZE, + height: BUTTON_SIZE, + imageURL: HIFI_PUBLIC_BUCKET + "images/delete.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1 +}); var diceButton = Overlays.addOverlay("image", { - x: screenSize.x / 2 + PADDING, - y: screenSize.y - (BUTTON_SIZE + PADDING), - width: BUTTON_SIZE, - height: BUTTON_SIZE, - imageURL: HIFI_PUBLIC_BUCKET + "images/die.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1 - }); + x: screenSize.x / 2 + PADDING, + y: screenSize.y - (BUTTON_SIZE + PADDING), + width: BUTTON_SIZE, + height: BUTTON_SIZE, + imageURL: HIFI_PUBLIC_BUCKET + "images/die.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1 +}); var GRAVITY = -3.5; @@ -68,74 +80,70 @@ var MAX_ANGULAR_SPEED = Math.PI; function shootDice(position, velocity) { - if (!Entities.canRez()) { - Window.alert(INSUFFICIENT_PERMISSIONS_ERROR_MSG); - } else { - for (var i = 0; i < NUMBER_OF_DICE; i++) { - dice.push(Entities.addEntity( - { type: "Model", - modelURL: HIFI_PUBLIC_BUCKET + "models/props/Dice/goldDie.fbx", - position: position, - velocity: velocity, - rotation: Quat.fromPitchYawRollDegrees(Math.random() * 360, Math.random() * 360, Math.random() * 360), - angularVelocity: { x: Math.random() * MAX_ANGULAR_SPEED, - y: Math.random() * MAX_ANGULAR_SPEED, - z: Math.random() * MAX_ANGULAR_SPEED }, - lifetime: LIFETIME, - gravity: { x: 0, y: GRAVITY, z: 0 }, - shapeType: "box", - collisionsWillMove: true - })); - position = Vec3.sum(position, Vec3.multiply(DIE_SIZE, Vec3.normalize(Quat.getRight(Camera.getOrientation())))); - } + if (!Entities.canRez()) { + Window.alert(INSUFFICIENT_PERMISSIONS_ERROR_MSG); + } else { + for (var i = 0; i < NUMBER_OF_DICE; i++) { + dice.push(Entities.addEntity( + { + type: "Model", + modelURL: HIFI_PUBLIC_BUCKET + "models/props/Dice/goldDie.fbx", + position: position, + velocity: velocity, + rotation: Quat.fromPitchYawRollDegrees(Math.random() * 360, Math.random() * 360, Math.random() * 360), + angularVelocity: { + x: Math.random() * MAX_ANGULAR_SPEED, + y: Math.random() * MAX_ANGULAR_SPEED, + z: Math.random() * MAX_ANGULAR_SPEED + }, + gravity: { + x: 0, + y: GRAVITY, + z: 0 + }, + lifetime: LIFETIME, + shapeType: "box", + collisionsWillMove: true, + collisionSoundURL: "http://s3.amazonaws.com/hifi-public/sounds/dice/diceCollide.wav" + })); + position = Vec3.sum(position, Vec3.multiply(DIE_SIZE, Vec3.normalize(Quat.getRight(Camera.getOrientation())))); } + } } function deleteDice() { - while(dice.length > 0) { - Entities.deleteEntity(dice.pop()); - } + while (dice.length > 0) { + Entities.deleteEntity(dice.pop()); + } } -function entityCollisionWithEntity(entity1, entity2, collision) { - if (!madeSound) { - // Is it one of our dice? - for (var i = 0; i < dice.length; i++) { - if (!dice[i].isKnownID) { - dice[i] = Entities.identifyEntity(dice[i]); - } - if ((entity1.id == dice[i].id) || (entity2.id == dice[i].id)) { - madeSound = true; - Audio.playSound(rollSound, { position: collision.contactPoint, localOnly: true }); - } - } - - } -} + function mousePressEvent(event) { - var clickedText = false; - var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); - if (clickedOverlay == offButton) { - deleteDice(); - Script.stop(); - } else if (clickedOverlay == deleteButton) { - deleteDice(); - } else if (clickedOverlay == diceButton) { - var HOW_HARD = 2.0; - var position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); - var velocity = Vec3.multiply(HOW_HARD, Quat.getFront(Camera.getOrientation())); - shootDice(position, velocity); - madeSound = false; - } + var clickedText = false; + var clickedOverlay = Overlays.getOverlayAtPoint({ + x: event.x, + y: event.y + }); + if (clickedOverlay == offButton) { + deleteDice(); + Script.stop(); + } else if (clickedOverlay == deleteButton) { + deleteDice(); + } else if (clickedOverlay == diceButton) { + var HOW_HARD = 2.0; + var position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())); + var velocity = Vec3.multiply(HOW_HARD, Quat.getFront(Camera.getOrientation())); + shootDice(position, velocity); + madeSound = false; + } } function scriptEnding() { - Overlays.deleteOverlay(offButton); - Overlays.deleteOverlay(diceButton); - Overlays.deleteOverlay(deleteButton); + Overlays.deleteOverlay(offButton); + Overlays.deleteOverlay(diceButton); + Overlays.deleteOverlay(deleteButton); } -Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity); Controller.mousePressEvent.connect(mousePressEvent); -Script.scriptEnding.connect(scriptEnding); +Script.scriptEnding.connect(scriptEnding); \ No newline at end of file diff --git a/examples/edit.js b/examples/edit.js index e034392df0..e4297a94b3 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -207,8 +207,8 @@ var toolBar = (function () { }); newWebButton = toolBar.addTool({ - imageURL: "https://s3.amazonaws.com/Oculus/earth17.svg", - subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + imageURL: "https://hifi-public.s3.amazonaws.com/images/www.svg", + subImage: { x: 0, y: 0, width: 128, height: 128 }, width: toolWidth, height: toolHeight, alpha: 0.9, diff --git a/examples/example/games/airHockey.js b/examples/example/games/airHockey.js index 98bab1d57e..ecef697b3e 100644 --- a/examples/example/games/airHockey.js +++ b/examples/example/games/airHockey.js @@ -10,29 +10,43 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var debugVisible = false; +var debugVisible = false; var FIELD_WIDTH = 1.21; var FIELD_LENGTH = 1.92; var FLOOR_THICKNESS = 0.20; var EDGE_THICKESS = 0.10; var EDGE_HEIGHT = 0.10; -var DROP_HEIGHT = 0.3; +var DROP_HEIGHT = 0.3; var PUCK_SIZE = 0.15; var PUCK_THICKNESS = 0.05; var PADDLE_SIZE = 0.15; var PADDLE_THICKNESS = 0.05; +var ENTITY_SEARCH_RANGE = 500; + var GOAL_WIDTH = 0.35; var GRAVITY = -9.8; -var LIFETIME = 6000; +var LIFETIME = 6000; var PUCK_DAMPING = 0.02; var PADDLE_DAMPING = 0.35; var ANGULAR_DAMPING = 0.4; var PADDLE_ANGULAR_DAMPING = 0.75; var MODEL_SCALE = 1.52; -var MODEL_OFFSET = { x: 0, y: -0.19, z: 0 }; +var MODEL_OFFSET = { + x: 0, + y: -0.19, + z: 0 +}; + +var LIGHT_OFFSET = { + x: 0, + y: 0.2, + z: 0 +}; + +var LIGHT_FLASH_TIME = 700; var scoreSound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Collisions-hitsandslaps/airhockey_score.wav"); @@ -46,221 +60,551 @@ var puckCollisionModel = "http://headache.hungry.com/~seth/hifi/airHockeyPuck-hu var paddleModel = "https://hifi-public.s3.amazonaws.com/ozan/props/airHockeyTable/airHockeyPaddle.obj" var paddleCollisionModel = "http://headache.hungry.com/~seth/hifi/paddle-hull.obj" -var center = Vec3.sum(MyAvatar.position, Vec3.multiply((FIELD_WIDTH + FIELD_LENGTH) * 0.60, Quat.getFront(Camera.getOrientation()))); +HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; +var screenSize = Controller.getViewportDimensions(); +var BUTTON_SIZE = 32; +var PADDING = 3; + +var center; var edgeRestitution = 0.9; var floorFriction = 0.01; -var floor = Entities.addEntity( - { type: "Box", - position: Vec3.subtract(center, { x: 0, y: 0, z: 0 }), - dimensions: { x: FIELD_WIDTH, y: FLOOR_THICKNESS, z: FIELD_LENGTH }, - color: { red: 128, green: 128, blue: 128 }, - gravity: { x: 0, y: 0, z: 0 }, - ignoreCollisions: false, - locked: true, - friction: floorFriction, - visible: debugVisible, - lifetime: LIFETIME }); +var paddle1Pos, paddle2Pos; +var names = ['floor', 'table', 'paddle', 'edge', 'puck', 'hockeyLight']; -var edge1 = Entities.addEntity( - { type: "Box", - collisionSoundURL: hitSideSound, - position: Vec3.sum(center, { x: FIELD_WIDTH / 2.0, y: FLOOR_THICKNESS / 2.0, z: 0 }), - dimensions: { x: EDGE_THICKESS, y: EDGE_HEIGHT, z: FIELD_LENGTH + EDGE_THICKESS }, - color: { red: 100, green: 100, blue: 100 }, - gravity: { x: 0, y: 0, z: 0 }, - ignoreCollisions: false, - visible: debugVisible, - restitution: edgeRestitution, - locked: true, - lifetime: LIFETIME }); +var deleteButton = Overlays.addOverlay("image", { + x: screenSize.x / 2 - BUTTON_SIZE, + y: screenSize.y - (BUTTON_SIZE * 2 + PADDING), + width: BUTTON_SIZE, + height: BUTTON_SIZE, + imageURL: HIFI_PUBLIC_BUCKET + "images/delete.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1 +}); -var edge2 = Entities.addEntity( - { type: "Box", - collisionSoundURL: hitSideSound, - position: Vec3.sum(center, { x: -FIELD_WIDTH / 2.0, y: FLOOR_THICKNESS / 2.0, z: 0 }), - dimensions: { x: EDGE_THICKESS, y: EDGE_HEIGHT, z: FIELD_LENGTH + EDGE_THICKESS }, - color: { red: 100, green: 100, blue: 100 }, - gravity: { x: 0, y: 0, z: 0 }, - ignoreCollisions: false, - visible: debugVisible, - restitution: edgeRestitution, - locked: true, - lifetime: LIFETIME }); +var spawnButton = Overlays.addOverlay("image", { + x: screenSize.x / 2 + PADDING, + y: screenSize.y - (BUTTON_SIZE * 2 + PADDING), + width: BUTTON_SIZE, + height: BUTTON_SIZE, + imageURL: HIFI_PUBLIC_BUCKET + "images/puck.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1 +}); -var edge3a = Entities.addEntity( - { type: "Box", - collisionSoundURL: hitSideSound, - position: Vec3.sum(center, { x: FIELD_WIDTH / 4.0 + (GOAL_WIDTH / 4.0), y: FLOOR_THICKNESS / 2.0, z: -FIELD_LENGTH / 2.0 }), - dimensions: { x: FIELD_WIDTH / 2.0 - GOAL_WIDTH / 2.0, y: EDGE_HEIGHT, z: EDGE_THICKESS }, - color: { red: 100, green: 100, blue: 100 }, - gravity: { x: 0, y: 0, z: 0 }, - ignoreCollisions: false, - visible: debugVisible, - restitution: edgeRestitution, - locked: true, - lifetime: LIFETIME }); -var edge3b = Entities.addEntity( - { type: "Box", - collisionSoundURL: hitSideSound, - position: Vec3.sum(center, { x: -FIELD_WIDTH / 4.0 - (GOAL_WIDTH / 4.0), y: FLOOR_THICKNESS / 2.0, z: -FIELD_LENGTH / 2.0 }), - dimensions: { x: FIELD_WIDTH / 2.0 - GOAL_WIDTH / 2.0, y: EDGE_HEIGHT, z: EDGE_THICKESS }, - color: { red: 100, green: 100, blue: 100 }, - gravity: { x: 0, y: 0, z: 0 }, - ignoreCollisions: false, - visible: debugVisible, - restitution: edgeRestitution, - locked: true, - lifetime: LIFETIME }); - -var edge4a = Entities.addEntity( - { type: "Box", - collisionSoundURL: hitSideSound, - position: Vec3.sum(center, { x: FIELD_WIDTH / 4.0 + (GOAL_WIDTH / 4.0), y: FLOOR_THICKNESS / 2.0, z: FIELD_LENGTH / 2.0 }), - dimensions: { x: FIELD_WIDTH / 2.0 - GOAL_WIDTH / 2.0, y: EDGE_HEIGHT, z: EDGE_THICKESS }, - color: { red: 100, green: 100, blue: 100 }, - gravity: { x: 0, y: 0, z: 0 }, - ignoreCollisions: false, - visible: debugVisible, - restitution: edgeRestitution, - locked: true, - lifetime: LIFETIME }); - -var edge4b = Entities.addEntity( - { type: "Box", - collisionSoundURL: hitSideSound, - position: Vec3.sum(center, { x: -FIELD_WIDTH / 4.0 - (GOAL_WIDTH / 4.0), y: FLOOR_THICKNESS / 2.0, z: FIELD_LENGTH / 2.0 }), - dimensions: { x: FIELD_WIDTH / 2.0 - GOAL_WIDTH / 2.0, y: EDGE_HEIGHT, z: EDGE_THICKESS }, - color: { red: 100, green: 100, blue: 100 }, - gravity: { x: 0, y: 0, z: 0 }, - ignoreCollisions: false, - visible: debugVisible, - restitution: edgeRestitution, - locked: true, - lifetime: LIFETIME }); - -var table = Entities.addEntity( - { type: "Model", - modelURL: polyTable, - dimensions: Vec3.multiply({ x: 0.8, y: 0.45, z: 1.31 }, MODEL_SCALE), - position: Vec3.sum(center, MODEL_OFFSET), - ignoreCollisions: false, - visible: true, - locked: true, - lifetime: LIFETIME }); +var floor, edge1, edge2, edge3a, edge3b, edge4a, edge4b, light; var puck; var paddle1, paddle2; // Create pucks -function makeNewProp(which) { - if (which == "puck") { - return Entities.addEntity( - { type: "Model", - modelURL: puckModel, - compoundShapeURL: puckCollisionModel, - collisionSoundURL: hitSound1, - position: Vec3.sum(center, { x: 0, y: DROP_HEIGHT, z: 0 }), - dimensions: { x: PUCK_SIZE, y: PUCK_THICKNESS, z: PUCK_SIZE }, - gravity: { x: 0, y: GRAVITY, z: 0 }, - velocity: { x: 0, y: 0.05, z: 0 }, - ignoreCollisions: false, - damping: PUCK_DAMPING, - angularDamping: ANGULAR_DAMPING, - lifetime: LIFETIME, - collisionsWillMove: true }); - } - else if (which == "paddle1") { - return Entities.addEntity( - { type: "Model", - modelURL: paddleModel, - compoundShapeURL: paddleCollisionModel, - collisionSoundURL: hitSound2, - position: Vec3.sum(center, { x: 0, y: DROP_HEIGHT * 1.5, z: FIELD_LENGTH * 0.35 }), - dimensions: { x: PADDLE_SIZE, y: PADDLE_THICKNESS, z: PADDLE_SIZE }, - gravity: { x: 0, y: GRAVITY, z: 0 }, - velocity: { x: 0, y: 0.07, z: 0 }, - ignoreCollisions: false, - damping: PADDLE_DAMPING, - angularDamping: PADDLE_ANGULAR_DAMPING, - lifetime: LIFETIME, - collisionsWillMove: true }); - } - else if (which == "paddle2") { - return Entities.addEntity( - { type: "Model", - modelURL: paddleModel, - compoundShapeURL: paddleCollisionModel, - collisionSoundURL: hitSound2, - position: Vec3.sum(center, { x: 0, y: DROP_HEIGHT * 1.5, z: -FIELD_LENGTH * 0.35 }), - dimensions: { x: PADDLE_SIZE, y: PADDLE_THICKNESS, z: PADDLE_SIZE }, - gravity: { x: 0, y: GRAVITY, z: 0 }, - velocity: { x: 0, y: 0.07, z: 0 }, - ignoreCollisions: false, - damping: PADDLE_DAMPING, - angularDamping: PADDLE_ANGULAR_DAMPING, - lifetime: LIFETIME, - collisionsWillMove: true }); - } +function makeNewProp(which, position) { + if (which == "puck") { + return Entities.addEntity({ + name: 'puck', + type: "Model", + modelURL: puckModel, + compoundShapeURL: puckCollisionModel, + collisionSoundURL: hitSound1, + position: Vec3.sum(center, { + x: 0, + y: DROP_HEIGHT, + z: 0 + }), + dimensions: { + x: PUCK_SIZE, + y: PUCK_THICKNESS, + z: PUCK_SIZE + }, + gravity: { + x: 0, + y: GRAVITY, + z: 0 + }, + velocity: { + x: 0, + y: 0.05, + z: 0 + }, + ignoreCollisions: false, + damping: PUCK_DAMPING, + angularDamping: ANGULAR_DAMPING, + lifetime: LIFETIME, + collisionsWillMove: true + }); + } else if (which == "paddle1") { + paddle1Pos = Vec3.sum(center, { + x: 0, + y: DROP_HEIGHT * 1.5, + z: FIELD_LENGTH * 0.35 + }); + return Entities.addEntity({ + name: "paddle", + type: "Model", + modelURL: paddleModel, + compoundShapeURL: paddleCollisionModel, + collisionSoundURL: hitSound2, + position: paddle1Pos, + dimensions: { + x: PADDLE_SIZE, + y: PADDLE_THICKNESS, + z: PADDLE_SIZE + }, + gravity: { + x: 0, + y: GRAVITY, + z: 0 + }, + velocity: { + x: 0, + y: 0.07, + z: 0 + }, + ignoreCollisions: false, + damping: PADDLE_DAMPING, + angularDamping: PADDLE_ANGULAR_DAMPING, + lifetime: LIFETIME, + collisionsWillMove: true + }); + } else if (which == "paddle2") { + paddle2Pos = Vec3.sum(center, { + x: 0, + y: DROP_HEIGHT * 1.5, + z: -FIELD_LENGTH * 0.35 + }); + return Entities.addEntity({ + name: "paddle", + type: "Model", + modelURL: paddleModel, + compoundShapeURL: paddleCollisionModel, + collisionSoundURL: hitSound2, + position: paddle2Pos, + dimensions: { + x: PADDLE_SIZE, + y: PADDLE_THICKNESS, + z: PADDLE_SIZE + }, + gravity: { + x: 0, + y: GRAVITY, + z: 0 + }, + velocity: { + x: 0, + y: 0.07, + z: 0 + }, + ignoreCollisions: false, + damping: PADDLE_DAMPING, + angularDamping: PADDLE_ANGULAR_DAMPING, + lifetime: LIFETIME, + collisionsWillMove: true + }); + } } -puck = makeNewProp("puck"); -paddle1 = makeNewProp("paddle1"); -paddle2 = makeNewProp("paddle2"); function update(deltaTime) { - if (Math.random() < 0.1) { - puckProps = Entities.getEntityProperties(puck); - paddle1Props = Entities.getEntityProperties(paddle1); - paddle2Props = Entities.getEntityProperties(paddle2); - if (puckProps.position.y < (center.y - DROP_HEIGHT)) { - Audio.playSound(scoreSound, { - position: center, - volume: 1.0 - }); - Entities.deleteEntity(puck); - puck = makeNewProp("puck"); - } - - if (paddle1Props.position.y < (center.y - DROP_HEIGHT)) { - Entities.deleteEntity(paddle1); - paddle1 = makeNewProp("paddle1"); - } - if (paddle2Props.position.y < (center.y - DROP_HEIGHT)) { - Entities.deleteEntity(paddle2); - paddle2 = makeNewProp("paddle2"); - } - } + if (Math.random() < 0.1) { + puckProps = Entities.getEntityProperties(puck); + paddle1Props = Entities.getEntityProperties(paddle1); + paddle2Props = Entities.getEntityProperties(paddle2); + if (puckProps.position.y < (center.y - DROP_HEIGHT)) { + score(); + } + + if (paddle1Props.position.y < (center.y - DROP_HEIGHT)) { + Entities.deleteEntity(paddle1); + paddle1 = makeNewProp("paddle1"); + } + if (paddle2Props.position.y < (center.y - DROP_HEIGHT)) { + Entities.deleteEntity(paddle2); + paddle2 = makeNewProp("paddle2"); + } + } +} + +function score() { + Audio.playSound(scoreSound, { + position: center, + volume: 1.0 + }); + puckDropPosition = Entities.getEntityProperties(puck).position; + var newPosition; + if (Vec3.distance(puckDropPosition, paddle1Pos) > Vec3.distance(puckDropPosition, paddle2Pos)) { + newPosition = paddle2Pos; + } else { + newPosition = paddle1Pos; + } + Entities.editEntity(puck, { + position: newPosition, + velocity: { + x: 0, + y: 0.05, + z: 0 + } + }); + + Entities.editEntity(light, { + visible: true + }); + Script.setTimeout(function() { + Entities.editEntity(light, { + visible: false + }); + }, LIGHT_FLASH_TIME); +} + +function mousePressEvent(event) { + var clickedOverlay = Overlays.getOverlayAtPoint({ + x: event.x, + y: event.y + }); + if (clickedOverlay == spawnButton) { + spawnAllTheThings(); + } else if (clickedOverlay == deleteButton) { + deleteAllTheThings(); + } +} + +function spawnAllTheThings() { + center = Vec3.sum(MyAvatar.position, Vec3.multiply((FIELD_WIDTH + FIELD_LENGTH) * 0.60, Quat.getFront(Camera.getOrientation()))); + floor = Entities.addEntity({ + name: "floor", + type: "Box", + position: Vec3.subtract(center, { + x: 0, + y: 0, + z: 0 + }), + dimensions: { + x: FIELD_WIDTH, + y: FLOOR_THICKNESS, + z: FIELD_LENGTH + }, + color: { + red: 128, + green: 128, + blue: 128 + }, + gravity: { + x: 0, + y: 0, + z: 0 + }, + ignoreCollisions: false, + locked: true, + friction: floorFriction, + visible: debugVisible, + lifetime: LIFETIME + }); + + edge1 = Entities.addEntity({ + name: 'edge', + type: "Box", + collisionSoundURL: hitSideSound, + position: Vec3.sum(center, { + x: FIELD_WIDTH / 2.0, + y: FLOOR_THICKNESS / 2.0, + z: 0 + }), + dimensions: { + x: EDGE_THICKESS, + y: EDGE_HEIGHT, + z: FIELD_LENGTH + EDGE_THICKESS + }, + color: { + red: 100, + green: 100, + blue: 100 + }, + gravity: { + x: 0, + y: 0, + z: 0 + }, + ignoreCollisions: false, + visible: debugVisible, + restitution: edgeRestitution, + locked: true, + lifetime: LIFETIME + }); + + edge2 = Entities.addEntity({ + name: 'edge', + type: "Box", + collisionSoundURL: hitSideSound, + position: Vec3.sum(center, { + x: -FIELD_WIDTH / 2.0, + y: FLOOR_THICKNESS / 2.0, + z: 0 + }), + dimensions: { + x: EDGE_THICKESS, + y: EDGE_HEIGHT, + z: FIELD_LENGTH + EDGE_THICKESS + }, + color: { + red: 100, + green: 100, + blue: 100 + }, + gravity: { + x: 0, + y: 0, + z: 0 + }, + ignoreCollisions: false, + visible: debugVisible, + restitution: edgeRestitution, + locked: true, + lifetime: LIFETIME + }); + + edge3a = Entities.addEntity({ + name: 'edge', + type: "Box", + collisionSoundURL: hitSideSound, + position: Vec3.sum(center, { + x: FIELD_WIDTH / 4.0 + (GOAL_WIDTH / 4.0), + y: FLOOR_THICKNESS / 2.0, + z: -FIELD_LENGTH / 2.0 + }), + dimensions: { + x: FIELD_WIDTH / 2.0 - GOAL_WIDTH / 2.0, + y: EDGE_HEIGHT, + z: EDGE_THICKESS + }, + color: { + red: 100, + green: 100, + blue: 100 + }, + gravity: { + x: 0, + y: 0, + z: 0 + }, + ignoreCollisions: false, + visible: debugVisible, + restitution: edgeRestitution, + locked: true, + lifetime: LIFETIME + }); + + edge3b = Entities.addEntity({ + name: 'edge', + type: "Box", + collisionSoundURL: hitSideSound, + position: Vec3.sum(center, { + x: -FIELD_WIDTH / 4.0 - (GOAL_WIDTH / 4.0), + y: FLOOR_THICKNESS / 2.0, + z: -FIELD_LENGTH / 2.0 + }), + dimensions: { + x: FIELD_WIDTH / 2.0 - GOAL_WIDTH / 2.0, + y: EDGE_HEIGHT, + z: EDGE_THICKESS + }, + color: { + red: 100, + green: 100, + blue: 100 + }, + gravity: { + x: 0, + y: 0, + z: 0 + }, + ignoreCollisions: false, + visible: debugVisible, + restitution: edgeRestitution, + locked: true, + lifetime: LIFETIME + }); + + edge4a = Entities.addEntity({ + name: 'edge', + type: "Box", + collisionSoundURL: hitSideSound, + position: Vec3.sum(center, { + x: FIELD_WIDTH / 4.0 + (GOAL_WIDTH / 4.0), + y: FLOOR_THICKNESS / 2.0, + z: FIELD_LENGTH / 2.0 + }), + dimensions: { + x: FIELD_WIDTH / 2.0 - GOAL_WIDTH / 2.0, + y: EDGE_HEIGHT, + z: EDGE_THICKESS + }, + color: { + red: 100, + green: 100, + blue: 100 + }, + gravity: { + x: 0, + y: 0, + z: 0 + }, + ignoreCollisions: false, + visible: debugVisible, + restitution: edgeRestitution, + locked: true, + lifetime: LIFETIME + }); + + edge4b = Entities.addEntity({ + name: 'edge', + type: "Box", + collisionSoundURL: hitSideSound, + position: Vec3.sum(center, { + x: -FIELD_WIDTH / 4.0 - (GOAL_WIDTH / 4.0), + y: FLOOR_THICKNESS / 2.0, + z: FIELD_LENGTH / 2.0 + }), + dimensions: { + x: FIELD_WIDTH / 2.0 - GOAL_WIDTH / 2.0, + y: EDGE_HEIGHT, + z: EDGE_THICKESS + }, + color: { + red: 100, + green: 100, + blue: 100 + }, + gravity: { + x: 0, + y: 0, + z: 0 + }, + ignoreCollisions: false, + visible: debugVisible, + restitution: edgeRestitution, + locked: true, + lifetime: LIFETIME + }); + + table = Entities.addEntity({ + name: "table", + type: "Model", + modelURL: polyTable, + dimensions: Vec3.multiply({ + x: 0.8, + y: 0.45, + z: 1.31 + }, MODEL_SCALE), + position: Vec3.sum(center, MODEL_OFFSET), + ignoreCollisions: false, + visible: true, + locked: true, + lifetime: LIFETIME + }); + + light = Entities.addEntity({ + name: "hockeyLight", + type: "Light", + dimensions: { + x: 5, + y: 5, + z: 5 + }, + position: Vec3.sum(center, LIGHT_OFFSET), + intensity: 5, + color: { + red: 200, + green: 20, + blue: 200 + }, + visible: false + }); + puck = makeNewProp("puck"); + paddle1 = makeNewProp("paddle1"); + paddle2 = makeNewProp("paddle2"); + + Script.update.connect(update); + +} + +function deleteAllTheThings() { + + Script.update.disconnect(update); + //delete all nearby entitites that are named any the names from our names array + var nearbyEntities = Entities.findEntities(MyAvatar.position, ENTITY_SEARCH_RANGE); + for (var i = 0; i < nearbyEntities.length; i++) { + var entityName = Entities.getEntityProperties(nearbyEntities[i]).name; + for (var j = 0; j < names.length; j++) { + if (names[j] === entityName) { + //We have a mach- delete this entity + Entities.editEntity(nearbyEntities[i], { + locked: false + }); + Entities.deleteEntity(nearbyEntities[i]); + } + } + } + + } function scriptEnding() { - Entities.editEntity(edge1, { locked: false }); - Entities.editEntity(edge2, { locked: false }); - Entities.editEntity(edge3a, { locked: false }); - Entities.editEntity(edge3b, { locked: false }); - Entities.editEntity(edge4a, { locked: false }); - Entities.editEntity(edge4b, { locked: false }); - Entities.editEntity(floor, { locked: false }); - Entities.editEntity(table, { locked: false }); + Overlays.deleteOverlay(spawnButton); + Overlays.deleteOverlay(deleteButton); + + Entities.editEntity(edge1, { + locked: false + }); + Entities.editEntity(edge2, { + locked: false + }); + Entities.editEntity(edge3a, { + locked: false + }); + Entities.editEntity(edge3b, { + locked: false + }); + Entities.editEntity(edge4a, { + locked: false + }); + Entities.editEntity(edge4b, { + locked: false + }); + Entities.editEntity(floor, { + locked: false + }); + Entities.editEntity(table, { + locked: false + }); - Entities.deleteEntity(edge1); - Entities.deleteEntity(edge2); - Entities.deleteEntity(edge3a); - Entities.deleteEntity(edge3b); - Entities.deleteEntity(edge4a); - Entities.deleteEntity(edge4b); - Entities.deleteEntity(floor); - Entities.deleteEntity(puck); - Entities.deleteEntity(paddle1); - Entities.deleteEntity(paddle2); - Entities.deleteEntity(table); + + Entities.deleteEntity(edge1); + Entities.deleteEntity(edge2); + Entities.deleteEntity(edge3a); + Entities.deleteEntity(edge3b); + Entities.deleteEntity(edge4a); + Entities.deleteEntity(edge4b); + Entities.deleteEntity(floor); + Entities.deleteEntity(puck); + Entities.deleteEntity(paddle1); + Entities.deleteEntity(paddle2); + Entities.deleteEntity(table); + Entities.deleteEntity(light); + } -Script.update.connect(update); +Controller.mousePressEvent.connect(mousePressEvent); Script.scriptEnding.connect(scriptEnding); \ No newline at end of file diff --git a/examples/example/games/grabHockey.js b/examples/example/games/grabHockey.js index 31597ba32d..5e101e1d48 100644 --- a/examples/example/games/grabHockey.js +++ b/examples/example/games/grabHockey.js @@ -13,7 +13,6 @@ var isGrabbing = false; var grabbedEntity = null; -var lineEntityID = null; var prevMouse = {}; var deltaMouse = { z: 0 @@ -39,9 +38,9 @@ var angularVelocity = { var grabSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/eric/sounds/CloseClamp.wav"); var releaseSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/eric/sounds/ReleaseClamp.wav"); -var VOLUME = 0.10; +var VOLUME = 0.0; -var DROP_DISTANCE = 5.0; +var DROP_DISTANCE = 0.10; var DROP_COLOR = { red: 200, green: 200, @@ -92,14 +91,6 @@ function mousePressEvent(event) { gravity: {x: 0, y: 0, z: 0} }); - lineEntityID = Entities.addEntity({ - type: "Line", - position: nearLinePoint(targetPosition), - dimensions: Vec3.subtract(targetPosition, nearLinePoint(targetPosition)), - color: { red: 255, green: 255, blue: 255 }, - lifetime: 300 // if someone crashes while moving something, don't leave the line there forever. - }); - Audio.playSound(grabSound, { position: props.position, volume: VOLUME @@ -145,8 +136,6 @@ function mouseReleaseEvent() { }); targetPosition = null; - Entities.deleteEntity(lineEntityID); - Audio.playSound(releaseSound, { position: entityProps.position, volume: VOLUME @@ -193,10 +182,6 @@ function mouseMoveEvent(event) { angularVelocity = Vec3.multiply((theta / dT), axisAngle); } - Entities.editEntity(lineEntityID, { - position: nearLinePoint(targetPosition), - dimensions: Vec3.subtract(targetPosition, nearLinePoint(targetPosition)) - }); } prevMouse.x = event.x; prevMouse.y = event.y; diff --git a/examples/grab.js b/examples/grab.js index 019ec2320f..f1e1b6571c 100644 --- a/examples/grab.js +++ b/examples/grab.js @@ -13,7 +13,6 @@ var isGrabbing = false; var grabbedEntity = null; -var lineEntityID = null; var prevMouse = {}; var deltaMouse = { z: 0 @@ -91,14 +90,6 @@ function mousePressEvent(event) { gravity: {x: 0, y: 0, z: 0} }); - lineEntityID = Entities.addEntity({ - type: "Line", - position: nearLinePoint(targetPosition), - dimensions: Vec3.subtract(targetPosition, nearLinePoint(targetPosition)), - color: { red: 255, green: 255, blue: 255 }, - lifetime: 300 // if someone crashes while moving something, don't leave the line there forever. - }); - Audio.playSound(grabSound, { position: props.position, volume: 0.4 @@ -144,8 +135,6 @@ function mouseReleaseEvent() { }); targetPosition = null; - Entities.deleteEntity(lineEntityID); - Audio.playSound(grabSound, { position: entityProps.position, volume: 0.25 @@ -191,11 +180,6 @@ function mouseMoveEvent(event) { axisAngle = Quat.axis(dQ); angularVelocity = Vec3.multiply((theta / dT), axisAngle); } - - Entities.editEntity(lineEntityID, { - position: nearLinePoint(targetPosition), - dimensions: Vec3.subtract(targetPosition, nearLinePoint(targetPosition)) - }); } prevMouse.x = event.x; prevMouse.y = event.y; diff --git a/examples/pointer.js b/examples/pointer.js new file mode 100644 index 0000000000..dfb79569f7 --- /dev/null +++ b/examples/pointer.js @@ -0,0 +1,77 @@ + +var lineEntityID = null; +var lineIsRezzed = false; + + +function nearLinePoint(targetPosition) { + var handPosition = MyAvatar.getRightPalmPosition(); + var along = Vec3.subtract(targetPosition, handPosition); + along = Vec3.normalize(along); + along = Vec3.multiply(along, 0.4); + return Vec3.sum(handPosition, along); +} + + +function removeLine() { + if (lineIsRezzed) { + Entities.deleteEntity(lineEntityID); + lineEntityID = null; + lineIsRezzed = false; + } +} + + +function createOrUpdateLine(event) { + var pickRay = Camera.computePickRay(event.x, event.y); + var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking + var props = Entities.getEntityProperties(intersection.entityID); + + if (intersection.intersects) { + var dim = Vec3.subtract(intersection.intersection, nearLinePoint(intersection.intersection)); + if (lineIsRezzed) { + Entities.editEntity(lineEntityID, { + position: nearLinePoint(intersection.intersection), + dimensions: dim, + lifetime: 15 + props.lifespan // renew lifetime + }); + } else { + lineIsRezzed = true; + lineEntityID = Entities.addEntity({ + type: "Line", + position: nearLinePoint(intersection.intersection), + dimensions: dim, + color: { red: 255, green: 255, blue: 255 }, + lifetime: 15 // if someone crashes while pointing, don't leave the line there forever. + }); + } + } else { + removeLine(); + } +} + + +function mousePressEvent(event) { + if (!event.isLeftButton) { + return; + } + Controller.mouseMoveEvent.connect(mouseMoveEvent); + createOrUpdateLine(event); + } + + +function mouseMoveEvent(event) { + createOrUpdateLine(event); +} + + +function mouseReleaseEvent(event) { + if (!event.isLeftButton) { + return; + } + Controller.mouseMoveEvent.disconnect(mouseMoveEvent); + removeLine(); +} + + +Controller.mousePressEvent.connect(mousePressEvent); +Controller.mouseReleaseEvent.connect(mouseReleaseEvent); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 20c93a7ae5..6665e71642 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3077,13 +3077,10 @@ PickRay Application::computePickRay(float x, float y) const { y /= size.y; PickRay result; if (isHMDMode()) { - ApplicationOverlay::computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction); + getApplicationOverlay().computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction); } else { - if (activeRenderingThread) { - getDisplayViewFrustum()->computePickRay(x, y, result.origin, result.direction); - } else { - getViewFrustum()->computePickRay(x, y, result.origin, result.direction); - } + auto frustum = activeRenderingThread ? getDisplayViewFrustum() : getViewFrustum(); + frustum->computePickRay(x, y, result.origin, result.direction); } return result; } @@ -3111,8 +3108,8 @@ QImage Application::renderAvatarBillboard() { ViewFrustum* Application::getViewFrustum() { #ifdef DEBUG if (QThread::currentThread() == activeRenderingThread) { - // FIXME, should this be an assert? - qWarning() << "Calling Application::getViewFrustum() from the active rendering thread, did you mean Application::getDisplayViewFrustum()?"; + // FIXME, figure out a better way to do this + //qWarning() << "Calling Application::getViewFrustum() from the active rendering thread, did you mean Application::getDisplayViewFrustum()?"; } #endif return &_viewFrustum; @@ -3121,8 +3118,8 @@ ViewFrustum* Application::getViewFrustum() { const ViewFrustum* Application::getViewFrustum() const { #ifdef DEBUG if (QThread::currentThread() == activeRenderingThread) { - // FIXME, should this be an assert? - qWarning() << "Calling Application::getViewFrustum() from the active rendering thread, did you mean Application::getDisplayViewFrustum()?"; + // FIXME, figure out a better way to do this + //qWarning() << "Calling Application::getViewFrustum() from the active rendering thread, did you mean Application::getDisplayViewFrustum()?"; } #endif return &_viewFrustum; @@ -3131,8 +3128,8 @@ const ViewFrustum* Application::getViewFrustum() const { ViewFrustum* Application::getDisplayViewFrustum() { #ifdef DEBUG if (QThread::currentThread() != activeRenderingThread) { - // FIXME, should this be an assert? - qWarning() << "Calling Application::getDisplayViewFrustum() from outside the active rendering thread or outside rendering, did you mean Application::getViewFrustum()?"; + // FIXME, figure out a better way to do this + // qWarning() << "Calling Application::getDisplayViewFrustum() from outside the active rendering thread or outside rendering, did you mean Application::getViewFrustum()?"; } #endif return &_displayViewFrustum; @@ -3141,8 +3138,8 @@ ViewFrustum* Application::getDisplayViewFrustum() { const ViewFrustum* Application::getDisplayViewFrustum() const { #ifdef DEBUG if (QThread::currentThread() != activeRenderingThread) { - // FIXME, should this be an assert? - qWarning() << "Calling Application::getDisplayViewFrustum() from outside the active rendering thread or outside rendering, did you mean Application::getViewFrustum()?"; + // FIXME, figure out a better way to do this + // qWarning() << "Calling Application::getDisplayViewFrustum() from outside the active rendering thread or outside rendering, did you mean Application::getViewFrustum()?"; } #endif return &_displayViewFrustum; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 0d7563f27a..95877b92c4 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -393,7 +393,7 @@ Menu::Menu() { #ifdef HAVE_DDE faceTrackingMenu->addSeparator(); QAction* binaryEyelidControl = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::BinaryEyelidControl, 0, true); - binaryEyelidControl->setVisible(false); + binaryEyelidControl->setVisible(true); // DDE face tracking is on by default QAction* useAudioForMouth = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::UseAudioForMouth, 0, true); useAudioForMouth->setVisible(true); // DDE face tracking is on by default QAction* ddeFiltering = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::VelocityFilter, 0, true); diff --git a/interface/src/devices/DdeFaceTracker.cpp b/interface/src/devices/DdeFaceTracker.cpp index ca2f5bd48e..30165624af 100644 --- a/interface/src/devices/DdeFaceTracker.cpp +++ b/interface/src/devices/DdeFaceTracker.cpp @@ -388,7 +388,7 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { // Compute relative rotation rotation = glm::inverse(_referenceRotation) * rotation; if (isFiltering) { - glm::quat r = rotation * glm::inverse(_headRotation); + glm::quat r = glm::normalize(rotation * glm::inverse(_headRotation)); float theta = 2 * acos(r.w); glm::vec3 angularVelocity; if (theta > EPSILON) { diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index 409f359afa..b517f9d67b 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -213,7 +213,7 @@ void Faceshift::receive(const QByteArray& buffer) { glm::quat newRotation = glm::quat(data.m_headRotation.w, -data.m_headRotation.x, data.m_headRotation.y, -data.m_headRotation.z); // Compute angular velocity of the head - glm::quat r = newRotation * glm::inverse(_headRotation); + glm::quat r = glm::normalize(newRotation * glm::inverse(_headRotation)); float theta = 2 * acos(r.w); if (theta > EPSILON) { float rMag = glm::length(glm::vec3(r.x, r.y, r.z)); diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index b65e75923e..e3f9216c13 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -301,9 +301,14 @@ void ApplicationOverlay::displayOverlayTextureHmd(Camera& whichCamera) { //Update and draw the magnifiers MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); const glm::quat& orientation = myAvatar->getOrientation(); - const glm::vec3& position = myAvatar->getDefaultEyePosition(); + // Always display the HMD overlay relative to the camera position but + // remove the HMD pose offset. This results in an overlay that sticks with you + // even in third person mode, but isn't drawn at a fixed distance. + glm::vec3 position = whichCamera.getPosition(); + position -= qApp->getCamera()->getHmdPosition(); const float scale = myAvatar->getScale() * _oculusUIRadius; +// glm::vec3 eyeOffset = setEyeOffsetPosition; glMatrixMode(GL_MODELVIEW); glPushMatrix(); { glTranslatef(position.x, position.y, position.z); @@ -453,19 +458,32 @@ void ApplicationOverlay::displayOverlayTextureStereo(Camera& whichCamera, float glEnable(GL_LIGHTING); } -void ApplicationOverlay::computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) { - const MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); - cursorPos = 0.5f - cursorPos; - cursorPos *= MOUSE_RANGE; - const glm::quat orientation(glm::vec3(cursorPos, 0.0f)); - const glm::vec3 localDirection = orientation * IDENTITY_FRONT; +void ApplicationOverlay::computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const { + cursorPos *= qApp->getCanvasSize(); + const glm::vec2 projection = screenToSpherical(cursorPos); + // The overlay space orientation of the mouse coordinates + const glm::quat orientation(glm::vec3(-projection.y, projection.x, 0.0f)); + // FIXME We now have the direction of the ray FROM THE DEFAULT HEAD POSE. + // Now we need to account for the actual camera position relative to the overlay + glm::vec3 overlaySpaceDirection = glm::normalize(orientation * IDENTITY_FRONT); - // Get cursor position - const glm::vec3 cursorDir = myAvatar->getDefaultEyePosition() + myAvatar->getOrientation() * localDirection; - // Ray start where the eye position is and stop where the cursor is - origin = myAvatar->getEyePosition(); - direction = cursorDir - origin; + const glm::vec3& hmdPosition = qApp->getCamera()->getHmdPosition(); + const glm::quat& hmdOrientation = qApp->getCamera()->getHmdRotation(); + + // We need the RAW camera orientation and position, because this is what the overlay is + // rendered relative to + const glm::vec3 overlayPosition = qApp->getCamera()->getPosition() - hmdPosition; + const glm::quat overlayOrientation = qApp->getCamera()->getRotation() * glm::inverse(hmdOrientation); + + // Intersection UI overlay space + glm::vec3 worldSpaceDirection = overlayOrientation * overlaySpaceDirection; + glm::vec3 intersectionWithUi = glm::normalize(worldSpaceDirection) * _oculusUIRadius; + intersectionWithUi += overlayPosition; + + // Intersection in world space + origin = overlayPosition + hmdPosition; + direction = glm::normalize(intersectionWithUi - origin); } //Caculate the click location using one of the sixense controllers. Scale is not applied diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index 62bbfa2747..34beb98682 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -58,12 +58,12 @@ public: glm::vec2 overlayToSpherical(const glm::vec2 & overlayPos) const; glm::vec2 screenToOverlay(const glm::vec2 & screenPos) const; glm::vec2 overlayToScreen(const glm::vec2 & overlayPos) const; + void computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const; static glm::vec2 directionToSpherical(const glm::vec3 & direction); static glm::vec3 sphericalToDirection(const glm::vec2 & sphericalPos); static glm::vec2 screenToSpherical(const glm::vec2 & screenPos); static glm::vec2 sphericalToScreen(const glm::vec2 & sphericalPos); - static void computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction); private: // Interleaved vertex data diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 98e9a725b5..fb10403cdf 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -1114,6 +1114,9 @@ void EntityTreeRenderer::changingEntityID(const EntityItemID& oldEntityID, const void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision) { EntityItem* entity = entityTree->findEntityByEntityItemID(id); + if (!entity) { + return; + } QUuid simulatorID = entity->getSimulatorID(); if (simulatorID.isNull() || (simulatorID != myNodeID)) { return; // Only one injector per simulation, please. @@ -1127,20 +1130,24 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT const float linearVelocity = glm::length(collision.penetration) * COLLISION_PENTRATION_TO_VELOCITY; const float energy = mass * linearVelocity * linearVelocity / 2.0f; const glm::vec3 position = collision.contactPoint; - const float COLLISION_ENERGY_AT_FULL_VOLUME = 1.0f; + const float COLLISION_ENERGY_AT_FULL_VOLUME = 0.5f; const float COLLISION_MINIMUM_VOLUME = 0.001f; const float energyFactorOfFull = fmin(1.0f, energy / COLLISION_ENERGY_AT_FULL_VOLUME); if (energyFactorOfFull < COLLISION_MINIMUM_VOLUME) { return; } - SharedSoundPointer sound = DependencyManager::get().data()->getSound(QUrl(collisionSoundURL)); - if (!sound->isReady()) { + auto soundCache = DependencyManager::get(); + if (soundCache.isNull()) { + return; + } + SharedSoundPointer sound = soundCache.data()->getSound(QUrl(collisionSoundURL)); + if (sound.isNull() || !sound->isReady()) { return; } // This is a hack. Quiet sound aren't really heard at all, so we compress everything to the range [1-c, 1], if we play it all. - const float COLLISION_SOUND_COMPRESSION_RANGE = 0.95f; + const float COLLISION_SOUND_COMPRESSION_RANGE = 0.7f; float volume = energyFactorOfFull; volume = (volume * COLLISION_SOUND_COMPRESSION_RANGE) + (1.0f - COLLISION_SOUND_COMPRESSION_RANGE); @@ -1151,6 +1158,7 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT options.volume = volume; AudioInjector* injector = new AudioInjector(sound.data(), options); injector->setLocalAudioInterface(_localAudioInterface); + injector->triggerDeleteAfterFinish(); QThread* injectorThread = new QThread(); injectorThread->setObjectName("Audio Injector Thread"); injector->moveToThread(injectorThread); @@ -1171,7 +1179,7 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons } // Don't respond to small continuous contacts. It causes deadlocks when locking the entityTree. // Note that any entity script is likely to Entities.getEntityProperties(), which locks the tree. - const float COLLISION_MINUMUM_PENETRATION = 0.001; + const float COLLISION_MINUMUM_PENETRATION = 0.005; if ((collision.type != CONTACT_EVENT_TYPE_START) && (glm::length(collision.penetration) < COLLISION_MINUMUM_PENETRATION)) { return; } diff --git a/libraries/entities/src/LineEntityItem.h b/libraries/entities/src/LineEntityItem.h index a834fee816..a8bc867bdd 100644 --- a/libraries/entities/src/LineEntityItem.h +++ b/libraries/entities/src/LineEntityItem.h @@ -53,6 +53,12 @@ class LineEntityItem : public EntityItem { virtual ShapeType getShapeType() const { return SHAPE_TYPE_LINE; } + // never have a ray intersection pick a LineEntityItem. + virtual bool supportsDetailedRayIntersection() const { return true; } + virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + void** intersectedObject, bool precisionPicking) const { return false; } + virtual void debugDump() const; protected: diff --git a/libraries/script-engine/src/ScriptCache.cpp b/libraries/script-engine/src/ScriptCache.cpp index 5025d02918..8f854cfdc3 100644 --- a/libraries/script-engine/src/ScriptCache.cpp +++ b/libraries/script-engine/src/ScriptCache.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -35,7 +36,7 @@ QString ScriptCache::getScript(const QUrl& url, ScriptUser* scriptUser, bool& is isPending = true; bool alreadyWaiting = _scriptUsers.contains(url); _scriptUsers.insert(url, scriptUser); - + if (alreadyWaiting) { qCDebug(scriptengine) << "Already downloading script at:" << url.toString(); } else { @@ -43,7 +44,7 @@ QString ScriptCache::getScript(const QUrl& url, ScriptUser* scriptUser, bool& is QNetworkRequest networkRequest = QNetworkRequest(url); networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); - qCDebug(scriptengine) << "Downloading script at:" << url.toString(); + qCDebug(scriptengine) << "Downloading script at" << url.toString(); QNetworkReply* reply = networkAccessManager.get(networkRequest); connect(reply, &QNetworkReply::finished, this, &ScriptCache::scriptDownloaded); } @@ -56,7 +57,7 @@ void ScriptCache::scriptDownloaded() { QUrl url = reply->url(); QList scriptUsers = _scriptUsers.values(url); _scriptUsers.remove(url); - + if (reply->error() == QNetworkReply::NoError && reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 200) { _scriptCache[url] = reply->readAll(); qCDebug(scriptengine) << "Done downloading script at:" << url.toString(); @@ -65,7 +66,9 @@ void ScriptCache::scriptDownloaded() { user->scriptContentsAvailable(url, _scriptCache[url]); } } else { - qCDebug(scriptengine) << "ERROR Loading file:" << reply->url().toString(); + qCWarning(scriptengine) << "Error loading script from URL " << reply->url().toString() + << "- HTTP status code is" << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() + << "and error from QNetworkReply is" << reply->errorString(); foreach(ScriptUser* user, scriptUsers) { user->errorInLoadingScript(url); } @@ -73,4 +76,4 @@ void ScriptCache::scriptDownloaded() { reply->deleteLater(); } - +