From da6986f759860fa619a1d7b9a98ef0d8e60050aa Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 7 Jul 2015 21:06:12 +0200 Subject: [PATCH 01/58] Planky refactorings and basic planky settings --- examples/example/games/planky.js | 282 +++++++++++++++++++++--------- examples/html/plankySettings.html | 112 ++++++++++++ 2 files changed, 312 insertions(+), 82 deletions(-) create mode 100644 examples/html/plankySettings.html diff --git a/examples/example/games/planky.js b/examples/example/games/planky.js index 00a4e7f61d..cd4a7295be 100644 --- a/examples/example/games/planky.js +++ b/examples/example/games/planky.js @@ -12,23 +12,28 @@ // HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; -const NUM_LAYERS = 16; -const BASE_DIMENSION = { x: 7, y: 2, z: 7 }; -const BLOCKS_PER_LAYER = 3; -const BLOCK_SIZE = {x: 0.2, y: 0.1, z: 0.8}; -const BLOCK_SPACING = BLOCK_SIZE.x / 3; +const DEFAULT_NUM_LAYERS = 16; +const DEFAULT_BASE_DIMENSION = { x: 7, y: 2, z: 7 }; +const DEFAULT_BLOCKS_PER_LAYER = 3; +const DEFAULT_BLOCK_SIZE = {x: 0.2, y: 0.1, z: 0.8}; +const DEFAULT_BLOCK_SPACING = DEFAULT_BLOCK_SIZE.x / DEFAULT_BLOCKS_PER_LAYER; // BLOCK_HEIGHT_VARIATION removes a random percentages of the default block height per block. (for example 0.001 %) -const BLOCK_HEIGHT_VARIATION = 0.001; -const GRAVITY = {x: 0, y: -2.8, z: 0}; -const DENSITY = 2000; -const DAMPING_FACTOR = 0.98; -const ANGULAR_DAMPING_FACTOR = 0.8; -const FRICTION = 0.99; -const RESTITUTION = 0.0; -const SPAWN_DISTANCE = 3; -const BLOCK_YAW_OFFSET = 45; +const DEFAULT_BLOCK_HEIGHT_VARIATION = 0.001; +const DEFAULT_GRAVITY = {x: 0, y: -2.8, z: 0}; +const DEFAULT_DENSITY = 2000; +const DEFAULT_DAMPING_FACTOR = 0.98; +const DEFAULT_ANGULAR_DAMPING_FACTOR = 0.8; +const DEFAULT_FRICTION = 0.99; +const DEFAULT_RESTITUTION = 0.0; +const DEFAULT_SPAWN_DISTANCE = 3; +const DEFAULT_BLOCK_YAW_OFFSET = 45; + +var editMode = false; + const BUTTON_DIMENSIONS = {width: 49, height: 49}; const MAXIMUM_PERCENTAGE = 100.0; +const NO_ANGLE = 0; +const RIGHT_ANGLE = 90; var windowWidth = Window.innerWidth; var size; @@ -36,6 +41,163 @@ var pieces = []; var ground = false; var layerRotated = false; +SettingsWindow = function() { + this.webWindow = null; + this.init = function() { + this.webWindow = new WebWindow('Planky', Script.resolvePath('../../html/plankySettings.html'), 255, 500, true); + this.webWindow.setVisible(false); + }; +}; + +PlankyOptions = function() { + var _this = this; + this.save = function() { + //TODO: save Planky Options here. + }; + this.load = function() { + //TODO: load Planky Options here. + }; + this.setDefaults = function() { + _this.numLayers = DEFAULT_NUM_LAYERS; + _this.baseDimension = DEFAULT_BASE_DIMENSION; + _this.blocksPerLayer = DEFAULT_BLOCKS_PER_LAYER; + _this.blockSize = DEFAULT_BLOCK_SIZE; + _this.blockSpacing = DEFAULT_BLOCK_SPACING; + _this.blockHeightVariation = DEFAULT_BLOCK_HEIGHT_VARIATION; + _this.gravity = DEFAULT_GRAVITY; + _this.density = DEFAULT_DENSITY; + _this.dampingFactor = DEFAULT_DAMPING_FACTOR; + _this.angularDampingFactor = DEFAULT_ANGULAR_DAMPING_FACTOR; + _this.friction = DEFAULT_FRICTION; + _this.restitution = DEFAULT_RESTITUTION; + _this.spawnDistance = DEFAULT_SPAWN_DISTANCE; + _this.blockYawOffset = DEFAULT_BLOCK_YAW_OFFSET; + }; + this.setDefaults(); +}; + +// The PlankyStack exists out of rows and layers +PlankyStack = function() { + var _this = this; + this.planks = []; + this.ground = false; + this.options = new PlankyOptions(); + this.deRez = function() { + _this.planks.forEach(function(plank) { + Entities.deleteEntity(plank.entity); + }); + _this.planks = []; + if (_this.ground) { + Entities.deleteEntity(_this.ground); + } + _this.ground = false; + }; + this.rez = function() { + if (_this.planks.length > 0) { + _this.deRez(); + } + _this.baseRotation = Quat.fromPitchYawRollDegrees(0.0, MyAvatar.bodyYaw, 0.0); + var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(_this.options.spawnDistance, Quat.getFront(_this.baseRotation))); + basePosition.y = grabLowestJointY(); + _this.basePosition = basePosition; + _this.refresh(); + }; + + //private function + var refreshGround = function() { + if (!_this.ground) { + _this.ground = Entities.addEntity({ + type: 'Model', + modelURL: HIFI_PUBLIC_BUCKET + 'eric/models/woodFloor.fbx', + dimensions: _this.options.baseDimension, + position: Vec3.sum(_this.basePosition, {y: -(_this.options.baseDimension.y / 2)}), + rotation: _this.baseRotation, + shapeType: 'box' + }); + return; + } + // move ground to rez position/rotation + Entities.editEntity(_this.ground, {dimensions: _this.options.baseDimension, position: Vec3.sum(_this.basePosition, {y: -(_this.options.baseDimension.y / 2)}), rotation: _this.baseRotation}); + } + var trimDimension = function(dimension, maxIndex) { + _this.planks.forEach(function(plank, index, object) { + if (plank[dimension] > maxIndex) { + Entities.deleteEntity(plank.entity); + object.splice(index, 1); + } + }); + }; + var createOrUpdate = function(layer, row) { + var found = false; + var layerRotated = layer % 2 === 0; + var offset = -(_this.options.blockSpacing); + var layerRotation = Quat.fromPitchYawRollDegrees(0, layerRotated ? NO_ANGLE : RIGHT_ANGLE, 0.0); + var blockPositionXZ = (_this.options.blockSize.x * row) - (((_this.options.blockSize.x * _this.options.blocksPerLayer) / 2) - (_this.options.blockSize.x / 2)); + var localTransform = Vec3.multiplyQbyV(_this.offsetRot, { + x: (layerRotated ? blockPositionXZ + offset: 0), + y: (_this.options.blockSize.y / 2) + (_this.options.blockSize.y * layer), + z: (layerRotated ? 0 : blockPositionXZ + offset) + }); + var newProperties = { + type: 'Model', + modelURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/block.fbx', + shapeType: 'box', + name: 'PlankyBlock' + layer + '-' + row, + dimensions: Vec3.sum(_this.options.blockSize, {x: 0, y: -((_this.options.blockSize.y * (_this.options.blockHeightVariation / MAXIMUM_PERCENTAGE)) * Math.random()), z: 0}), + position: Vec3.sum(_this.basePosition, localTransform), + rotation: Quat.multiply(layerRotation, _this.offsetRot), + //collisionsWillMove: false,//!editMode,//false,//!editMode, + damping: _this.options.dampingFactor, + restitution: _this.options.restitution, + friction: _this.options.friction, + angularDamping: _this.options.angularDampingFactor, + gravity: _this.options.gravity, + density: _this.options.density, + velocity: {x: 0, y: 0, z: 0}, + angularVelocity: Quat.fromPitchYawRollDegrees(0, 0, 0), + ignoreForCollisions: true + }; + _this.planks.forEach(function(plank, index, object) { + if (plank.layer === layer && plank.row === row) { + Entities.editEntity(plank.entity, newProperties); + found = true; + // break loop: + return false; + } + }); + if (!found) { + _this.planks.push({layer: layer, row: row, entity: Entities.addEntity(newProperties)}) + } + }; + this.refresh = function() { + refreshGround(); + trimDimension('layer', _this.options.numLayers); + trimDimension('row', _this.options.blocksPerLayer); + _this.offsetRot = Quat.multiply(_this.baseRotation, Quat.fromPitchYawRollDegrees(0.0, _this.options.blockYawOffset, 0.0)); + for (var layer = 0; layer < _this.options.numLayers; layer++) { + for (var row = 0; row < _this.options.blocksPerLayer; row++) { + createOrUpdate(layer, row); + } + } + if (!editMode) { + _this.planks.forEach(function(plank, index, object) { + print(index + " , " + plank); + Entities.editEntity(plank.entity, {ignoreForCollisions: false, collisionsWillMove: true}); + // Entities.editEntity(plank.entity, {collisionsWillMove: true}); + }); + } + }; + this.isFound = function() { + //TODO: identify entities here until one is found + return _this.planks.length > 0; + }; +}; + +var settingsWindow = new SettingsWindow(); +settingsWindow.init(); + +var plankyStack = new PlankyStack(); + function grabLowestJointY() { var jointNames = MyAvatar.getJointNames(); var floorY = MyAvatar.position.y; @@ -51,6 +213,10 @@ function getButtonPosX() { return windowWidth - ((BUTTON_DIMENSIONS.width / 2) + BUTTON_DIMENSIONS.width); } +function getCogButtonPosX() { + return getButtonPosX() - (BUTTON_DIMENSIONS.width * 1.1); +} + var button = Overlays.addOverlay('image', { x: getButtonPosX(), y: 10, @@ -60,73 +226,26 @@ var button = Overlays.addOverlay('image', { alpha: 0.8 }); - -function resetBlocks() { - pieces.forEach(function(piece) { - Entities.deleteEntity(piece); - }); - pieces = []; - var avatarRot = Quat.fromPitchYawRollDegrees(0.0, MyAvatar.bodyYaw, 0.0); - basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(SPAWN_DISTANCE, Quat.getFront(avatarRot))); - basePosition.y = grabLowestJointY() - (BASE_DIMENSION.y / 2); - if (!ground) { - ground = Entities.addEntity({ - type: 'Model', - modelURL: HIFI_PUBLIC_BUCKET + 'eric/models/woodFloor.fbx', - dimensions: BASE_DIMENSION, - position: basePosition, - rotation: avatarRot, - shapeType: 'box' - }); - } else { - Entities.editEntity(ground, {position: basePosition, rotation: avatarRot}); - } - var offsetRot = Quat.multiply(avatarRot, Quat.fromPitchYawRollDegrees(0.0, BLOCK_YAW_OFFSET, 0.0)); - basePosition.y += (BASE_DIMENSION.y / 2); - for (var layerIndex = 0; layerIndex < NUM_LAYERS; layerIndex++) { - var layerRotated = layerIndex % 2 === 0; - var offset = -(BLOCK_SPACING); - var layerRotation = Quat.fromPitchYawRollDegrees(0, layerRotated ? 0 : 90, 0.0); - for (var blockIndex = 0; blockIndex < BLOCKS_PER_LAYER; blockIndex++) { - var blockPositionXZ = BLOCK_SIZE.x * blockIndex - (BLOCK_SIZE.x * 3 / 2 - BLOCK_SIZE.x / 2); - var localTransform = Vec3.multiplyQbyV(offsetRot, { - x: (layerRotated ? blockPositionXZ + offset: 0), - y: (BLOCK_SIZE.y / 2) + (BLOCK_SIZE.y * layerIndex), - z: (layerRotated ? 0 : blockPositionXZ + offset) - }); - pieces.push(Entities.addEntity({ - type: 'Model', - modelURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/block.fbx', - shapeType: 'box', - name: 'PlankyBlock' + ((layerIndex * BLOCKS_PER_LAYER) + blockIndex), - dimensions: { - x: BLOCK_SIZE.x, - y: BLOCK_SIZE.y - ((BLOCK_SIZE.y * (BLOCK_HEIGHT_VARIATION / MAXIMUM_PERCENTAGE)) * Math.random()), - z: BLOCK_SIZE.z - }, - position: { - x: basePosition.x + localTransform.x, - y: basePosition.y + localTransform.y, - z: basePosition.z + localTransform.z - }, - rotation: Quat.multiply(layerRotation, offsetRot), - collisionsWillMove: true, - damping: DAMPING_FACTOR, - restitution: RESTITUTION, - friction: FRICTION, - angularDamping: ANGULAR_DAMPING_FACTOR, - gravity: GRAVITY, - density: DENSITY - })); - offset += BLOCK_SPACING; - } - } -} +var cogButton = Overlays.addOverlay('image', { + x: getCogButtonPosX(), + y: 10, + width: BUTTON_DIMENSIONS.width, + height: BUTTON_DIMENSIONS.height, + imageURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/cog.svg', + alpha: 0.8 +}); function mousePressEvent(event) { var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); if (clickedOverlay === button) { - resetBlocks(); + if (!plankyStack.isFound()) { + plankyStack.rez(); + return; + } + editMode = !editMode; + plankyStack.refresh(); + } else if (clickedOverlay === cogButton) { + settingsWindow.webWindow.setVisible(true); } } @@ -134,19 +253,18 @@ Controller.mousePressEvent.connect(mousePressEvent); function cleanup() { Overlays.deleteOverlay(button); + Overlays.deleteOverlay(cogButton); if (ground) { Entities.deleteEntity(ground); } - pieces.forEach(function(piece) { - Entities.deleteEntity(piece); - }); - pieces = []; + plankyStack.deRez(); } function onUpdate() { - if (windowWidth != Window.innerWidth) { + if (windowWidth !== Window.innerWidth) { windowWidth = Window.innerWidth; Overlays.editOverlay(button, {x: getButtonPosX()}); + Overlays.editOverlay(cogButton, {x: getCogButtonPosX()}); } } diff --git a/examples/html/plankySettings.html b/examples/html/plankySettings.html new file mode 100644 index 0000000000..9e2a08c650 --- /dev/null +++ b/examples/html/plankySettings.html @@ -0,0 +1,112 @@ + + + + + + + + +
+ + \ No newline at end of file From 90284b8bb46825aca0aee3bc13969b413af0609b Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 7 Jul 2015 21:33:28 +0200 Subject: [PATCH 02/58] fixes mysterious button display bug --- examples/example/games/planky.js | 41 +++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/examples/example/games/planky.js b/examples/example/games/planky.js index cd4a7295be..383e1d57d5 100644 --- a/examples/example/games/planky.js +++ b/examples/example/games/planky.js @@ -40,6 +40,8 @@ var size; var pieces = []; var ground = false; var layerRotated = false; +var button; +var cogButton; SettingsWindow = function() { this.webWindow = null; @@ -217,25 +219,38 @@ function getCogButtonPosX() { return getButtonPosX() - (BUTTON_DIMENSIONS.width * 1.1); } -var button = Overlays.addOverlay('image', { +print(JSON.stringify({ x: getButtonPosX(), y: 10, width: BUTTON_DIMENSIONS.width, height: BUTTON_DIMENSIONS.height, imageURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/planky_button.svg', alpha: 0.8 -}); +})); -var cogButton = Overlays.addOverlay('image', { - x: getCogButtonPosX(), - y: 10, - width: BUTTON_DIMENSIONS.width, - height: BUTTON_DIMENSIONS.height, - imageURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/cog.svg', - alpha: 0.8 -}); +function createButtons() { + button = Overlays.addOverlay('image', { + x: getButtonPosX(), + y: 10, + width: BUTTON_DIMENSIONS.width, + height: BUTTON_DIMENSIONS.height, + imageURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/planky_button.svg', + alpha: 0.8 + }); -function mousePressEvent(event) { + cogButton = Overlays.addOverlay('image', { + x: getCogButtonPosX(), + y: 10, + width: BUTTON_DIMENSIONS.width, + height: BUTTON_DIMENSIONS.height, + imageURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/cog.svg', + alpha: 0.8 + }); +} +// Fixes bug of not showing buttons on startup +Script.setTimeout(createButtons, 1000); + +Controller.mousePressEvent.connect(function(event) { var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); if (clickedOverlay === button) { if (!plankyStack.isFound()) { @@ -247,9 +262,7 @@ function mousePressEvent(event) { } else if (clickedOverlay === cogButton) { settingsWindow.webWindow.setVisible(true); } -} - -Controller.mousePressEvent.connect(mousePressEvent); +}); function cleanup() { Overlays.deleteOverlay(button); From c6b3801d0b2b3774678e1b1e2640597f84545f37 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Thu, 9 Jul 2015 20:53:09 +0200 Subject: [PATCH 03/58] proper block offset calculations --- examples/example/games/planky.js | 42 ++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/examples/example/games/planky.js b/examples/example/games/planky.js index 383e1d57d5..82ae4af9e0 100644 --- a/examples/example/games/planky.js +++ b/examples/example/games/planky.js @@ -83,6 +83,7 @@ PlankyStack = function() { var _this = this; this.planks = []; this.ground = false; + this.editLines = []; this.options = new PlankyOptions(); this.deRez = function() { _this.planks.forEach(function(plank) { @@ -92,7 +93,14 @@ PlankyStack = function() { if (_this.ground) { Entities.deleteEntity(_this.ground); } + this.editLines.forEach(function(line) { + Entities.deleteEntity(line); + }) + if (_this.centerLine) { + Entities.deleteEntity(_this.centerLine); + } _this.ground = false; + _this.centerLine = false; }; this.rez = function() { if (_this.planks.length > 0) { @@ -121,6 +129,20 @@ PlankyStack = function() { // move ground to rez position/rotation Entities.editEntity(_this.ground, {dimensions: _this.options.baseDimension, position: Vec3.sum(_this.basePosition, {y: -(_this.options.baseDimension.y / 2)}), rotation: _this.baseRotation}); } + + var refreshLines = function() { + if (_this.editLines.length === 0) { + _this.editLines.push(Entities.addEntity({ + type: 'Line', + dimensions: {x: 5, y: 21, z: 5}, + position: Vec3.sum(_this.basePosition, {y: -(_this.options.baseDimension.y / 2)}), + lineWidth: 7, + color: {red: 214, green: 91, blue: 67}, + linePoints: [{x: 0, y: 0, z: 0}, {x: 0, y: 10, z: 0}] + })); + return; + } + } var trimDimension = function(dimension, maxIndex) { _this.planks.forEach(function(plank, index, object) { if (plank[dimension] > maxIndex) { @@ -132,13 +154,12 @@ PlankyStack = function() { var createOrUpdate = function(layer, row) { var found = false; var layerRotated = layer % 2 === 0; - var offset = -(_this.options.blockSpacing); - var layerRotation = Quat.fromPitchYawRollDegrees(0, layerRotated ? NO_ANGLE : RIGHT_ANGLE, 0.0); - var blockPositionXZ = (_this.options.blockSize.x * row) - (((_this.options.blockSize.x * _this.options.blocksPerLayer) / 2) - (_this.options.blockSize.x / 2)); + var layerRotation = Quat.fromPitchYawRollDegrees(0, layerRotated ? NO_ANGLE : RIGHT_ANGLE, 0.0); + var blockPositionXZ = ((row - (_this.options.blocksPerLayer / 2) + 0.5) * (_this.options.blockSpacing + _this.options.blockSize.x)); var localTransform = Vec3.multiplyQbyV(_this.offsetRot, { - x: (layerRotated ? blockPositionXZ + offset: 0), + x: (layerRotated ? blockPositionXZ : 0), y: (_this.options.blockSize.y / 2) + (_this.options.blockSize.y * layer), - z: (layerRotated ? 0 : blockPositionXZ + offset) + z: (layerRotated ? 0 : blockPositionXZ) }); var newProperties = { type: 'Model', @@ -173,6 +194,7 @@ PlankyStack = function() { }; this.refresh = function() { refreshGround(); + refreshLines(); trimDimension('layer', _this.options.numLayers); trimDimension('row', _this.options.blocksPerLayer); _this.offsetRot = Quat.multiply(_this.baseRotation, Quat.fromPitchYawRollDegrees(0.0, _this.options.blockYawOffset, 0.0)); @@ -183,7 +205,6 @@ PlankyStack = function() { } if (!editMode) { _this.planks.forEach(function(plank, index, object) { - print(index + " , " + plank); Entities.editEntity(plank.entity, {ignoreForCollisions: false, collisionsWillMove: true}); // Entities.editEntity(plank.entity, {collisionsWillMove: true}); }); @@ -219,15 +240,6 @@ function getCogButtonPosX() { return getButtonPosX() - (BUTTON_DIMENSIONS.width * 1.1); } -print(JSON.stringify({ - x: getButtonPosX(), - y: 10, - width: BUTTON_DIMENSIONS.width, - height: BUTTON_DIMENSIONS.height, - imageURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/planky_button.svg', - alpha: 0.8 -})); - function createButtons() { button = Overlays.addOverlay('image', { x: getButtonPosX(), From 1f453e07e33e20ccb7cf39bbbbdbe1969466d679 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 14 Jul 2015 02:18:17 +0200 Subject: [PATCH 04/58] connection between planky script and web-window -load settings -include toolbar --- examples/example/games/planky.js | 110 +++++++++------ examples/html/plankySettings.html | 214 ++++++++++++++++-------------- 2 files changed, 183 insertions(+), 141 deletions(-) diff --git a/examples/example/games/planky.js b/examples/example/games/planky.js index 82ae4af9e0..60c3b3ad3a 100644 --- a/examples/example/games/planky.js +++ b/examples/example/games/planky.js @@ -12,6 +12,8 @@ // HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; +Script.include("../../libraries/toolBars.js"); + const DEFAULT_NUM_LAYERS = 16; const DEFAULT_BASE_DIMENSION = { x: 7, y: 2, z: 7 }; const DEFAULT_BLOCKS_PER_LAYER = 3; @@ -30,7 +32,7 @@ const DEFAULT_BLOCK_YAW_OFFSET = 45; var editMode = false; -const BUTTON_DIMENSIONS = {width: 49, height: 49}; +const BUTTON_DIMENSIONS = {width: 50, height: 50}; const MAXIMUM_PERCENTAGE = 100.0; const NO_ANGLE = 0; const RIGHT_ANGLE = 90; @@ -42,12 +44,30 @@ var ground = false; var layerRotated = false; var button; var cogButton; +var toolBar; SettingsWindow = function() { + var _this = this; + this.plankyStack = null; this.webWindow = null; - this.init = function() { - this.webWindow = new WebWindow('Planky', Script.resolvePath('../../html/plankySettings.html'), 255, 500, true); - this.webWindow.setVisible(false); + this.init = function(plankyStack) { + _this.webWindow = new WebWindow('Planky', Script.resolvePath('../../html/plankySettings.html'), 255, 500, true); + _this.webWindow.setVisible(false); + _this.webWindow.eventBridge.webEventReceived.connect(_this.onWebEventReceived); + _this.plankyStack = plankyStack; + }; + this.sendData = function(data) { + _this.webWindow.eventBridge.emitScriptEvent(JSON.stringify(data)); + }; + this.onWebEventReceived = function(data) { + data = JSON.parse(data); + switch (data.action) { + case 'loaded': + _this.sendData({action: 'load', options: _this.plankyStack.options.getJSON()}) + break; + default: + Window.alert('unknown action ' + data.action); + } }; }; @@ -59,6 +79,24 @@ PlankyOptions = function() { this.load = function() { //TODO: load Planky Options here. }; + this.getJSON = function() { + return { + numLayers: _this.numLayers, + baseDimension: _this.baseDimension, + blocksPerLayer: _this.blocksPerLayer, + blockSize: _this.blockSize, + blockSpacing: _this.blockSpacing, + blockHeightVariation: _this.blockHeightVariation, + gravity: _this.gravity, + density: _this.density, + dampingFactor: _this.dampingFactor, + angularDampingFactor: _this.angularDampingFactor, + friction: _this.friction, + restitution: _this.restitution, + spawnDistance: _this.spawnDistance, + blockYawOffset: _this.blockYawOffset, + }; + } this.setDefaults = function() { _this.numLayers = DEFAULT_NUM_LAYERS; _this.baseDimension = DEFAULT_BASE_DIMENSION; @@ -74,6 +112,7 @@ PlankyOptions = function() { _this.restitution = DEFAULT_RESTITUTION; _this.spawnDistance = DEFAULT_SPAWN_DISTANCE; _this.blockYawOffset = DEFAULT_BLOCK_YAW_OFFSET; + }; this.setDefaults(); }; @@ -93,7 +132,7 @@ PlankyStack = function() { if (_this.ground) { Entities.deleteEntity(_this.ground); } - this.editLines.forEach(function(line) { + _this.editLines.forEach(function(line) { Entities.deleteEntity(line); }) if (_this.centerLine) { @@ -155,7 +194,7 @@ PlankyStack = function() { var found = false; var layerRotated = layer % 2 === 0; var layerRotation = Quat.fromPitchYawRollDegrees(0, layerRotated ? NO_ANGLE : RIGHT_ANGLE, 0.0); - var blockPositionXZ = ((row - (_this.options.blocksPerLayer / 2) + 0.5) * (_this.options.blockSpacing + _this.options.blockSize.x)); + var blockPositionXZ = (row - (_this.options.blocksPerLayer / 2) + 0.5) * (_this.options.blockSpacing + _this.options.blockSize.x); var localTransform = Vec3.multiplyQbyV(_this.offsetRot, { x: (layerRotated ? blockPositionXZ : 0), y: (_this.options.blockSize.y / 2) + (_this.options.blockSize.y * layer), @@ -217,9 +256,8 @@ PlankyStack = function() { }; var settingsWindow = new SettingsWindow(); -settingsWindow.init(); - var plankyStack = new PlankyStack(); +settingsWindow.init(plankyStack); function grabLowestJointY() { var jointNames = MyAvatar.getJointNames(); @@ -232,66 +270,58 @@ function grabLowestJointY() { return floorY; } -function getButtonPosX() { - return windowWidth - ((BUTTON_DIMENSIONS.width / 2) + BUTTON_DIMENSIONS.width); -} - -function getCogButtonPosX() { - return getButtonPosX() - (BUTTON_DIMENSIONS.width * 1.1); -} - function createButtons() { - button = Overlays.addOverlay('image', { - x: getButtonPosX(), - y: 10, + toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.games.planky", function (windowDimensions, toolbar) { + return { + x: windowDimensions.x - (toolbar.width * 1.1), + y: toolbar.height / 2 + }; + }); + button = toolBar.addTool({ width: BUTTON_DIMENSIONS.width, height: BUTTON_DIMENSIONS.height, imageURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/planky_button.svg', - alpha: 0.8 + alpha: 0.8, + visible: true }); - cogButton = Overlays.addOverlay('image', { - x: getCogButtonPosX(), - y: 10, + cogButton = toolBar.addTool({ width: BUTTON_DIMENSIONS.width, height: BUTTON_DIMENSIONS.height, imageURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/cog.svg', - alpha: 0.8 + alpha: 0.8, + visible: true }); } // Fixes bug of not showing buttons on startup -Script.setTimeout(createButtons, 1000); +Script.setTimeout(createButtons, 2000); Controller.mousePressEvent.connect(function(event) { var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); - if (clickedOverlay === button) { + if (toolBar.clicked(clickedOverlay) === button) { if (!plankyStack.isFound()) { plankyStack.rez(); return; } editMode = !editMode; plankyStack.refresh(); - } else if (clickedOverlay === cogButton) { + } else if (toolBar.clicked(clickedOverlay) === cogButton) { settingsWindow.webWindow.setVisible(true); } }); - -function cleanup() { - Overlays.deleteOverlay(button); - Overlays.deleteOverlay(cogButton); - if (ground) { - Entities.deleteEntity(ground); - } - plankyStack.deRez(); -} -function onUpdate() { +Script.update.connect(function() { if (windowWidth !== Window.innerWidth) { windowWidth = Window.innerWidth; Overlays.editOverlay(button, {x: getButtonPosX()}); Overlays.editOverlay(cogButton, {x: getCogButtonPosX()}); } -} +}) -Script.update.connect(onUpdate) -Script.scriptEnding.connect(cleanup); +Script.scriptEnding.connect(function() { + toolBar.cleanup(); + if (ground) { + Entities.deleteEntity(ground); + } + plankyStack.deRez(); +}); diff --git a/examples/html/plankySettings.html b/examples/html/plankySettings.html index 9e2a08c650..d5f6f78a71 100644 --- a/examples/html/plankySettings.html +++ b/examples/html/plankySettings.html @@ -1,110 +1,122 @@ - - - + + } + EventBridge.emitWebEvent(JSON.stringify({action: 'loaded'})); + +}); +
From 6d1df036174046d2139702bdf5dc64e882791191 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 14 Jul 2015 03:19:23 +0200 Subject: [PATCH 05/58] planky: load / save settings --- examples/example/games/planky.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/examples/example/games/planky.js b/examples/example/games/planky.js index 60c3b3ad3a..abf1e63412 100644 --- a/examples/example/games/planky.js +++ b/examples/example/games/planky.js @@ -74,10 +74,18 @@ SettingsWindow = function() { PlankyOptions = function() { var _this = this; this.save = function() { - //TODO: save Planky Options here. + Settings.setValue('plankyOptions', JSON.stringify(_this.getJSON())); }; this.load = function() { - //TODO: load Planky Options here. + _this.setDefaults(); + var plankyOptions = Settings.getValue('plankyOptions') + if (plankyOptions === null || plankyOptions === '') { + return; + } + var options = JSON.parse(plankyOptions); + options.forEach(function(value, option, object) { + _this[option] = value; + }); }; this.getJSON = function() { return { @@ -112,9 +120,8 @@ PlankyOptions = function() { _this.restitution = DEFAULT_RESTITUTION; _this.spawnDistance = DEFAULT_SPAWN_DISTANCE; _this.blockYawOffset = DEFAULT_BLOCK_YAW_OFFSET; - }; - this.setDefaults(); + this.load(); }; // The PlankyStack exists out of rows and layers From 222234cf1d43576649526cafce4551804f174c26 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 14 Jul 2015 03:40:58 +0200 Subject: [PATCH 06/58] wild planky changes on value change --- examples/example/games/planky.js | 7 +++++++ examples/html/plankySettings.html | 11 +++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/examples/example/games/planky.js b/examples/example/games/planky.js index abf1e63412..0849481a61 100644 --- a/examples/example/games/planky.js +++ b/examples/example/games/planky.js @@ -65,6 +65,9 @@ SettingsWindow = function() { case 'loaded': _this.sendData({action: 'load', options: _this.plankyStack.options.getJSON()}) break; + case 'value_change': + _this.plankyStack.onValueChanged(data.option, data.value); + break; default: Window.alert('unknown action ' + data.action); } @@ -238,6 +241,10 @@ PlankyStack = function() { _this.planks.push({layer: layer, row: row, entity: Entities.addEntity(newProperties)}) } }; + this.onValueChanged = function(option, value) { + _this.options[option] = value; + _this.refresh(); + }; this.refresh = function() { refreshGround(); refreshLines(); diff --git a/examples/html/plankySettings.html b/examples/html/plankySettings.html index d5f6f78a71..a5ad2f2939 100644 --- a/examples/html/plankySettings.html +++ b/examples/html/plankySettings.html @@ -38,13 +38,21 @@ PropertyInput = function(key, label, value, attributes) { this.construct(); }; +var valueChangeHandler = function() { + EventBridge.emitWebEvent(JSON.stringify({ + action: 'value_change', + option: $(this).attr('name'), + value: properties[$(this).attr('name')].getValue() + })); +}; + NumberInput = function(key, label, value, attributes) { PropertyInput.call(this, key, label, value, attributes); }; NumberInput.prototype = Object.create(PropertyInput.prototype); NumberInput.prototype.constructor = NumberInput; NumberInput.prototype.createValue = function() { - this.input = $('').attr('name', this.key).attr('type', 'number').val(this.value); + this.input = $('').attr('name', this.key).attr('type', 'number').val(this.value).on('change', valueChangeHandler); if (this.attributes !== undefined) { this.input.attr(this.attributes); } @@ -114,7 +122,6 @@ $(function() { }); } EventBridge.emitWebEvent(JSON.stringify({action: 'loaded'})); - }); From c8453bec671cbec04f7245e6b2878d08900423d2 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 14 Jul 2015 03:50:06 +0200 Subject: [PATCH 07/58] planky: fix layer setting, restraints on values --- examples/html/plankySettings.html | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/html/plankySettings.html b/examples/html/plankySettings.html index a5ad2f2939..b357e83792 100644 --- a/examples/html/plankySettings.html +++ b/examples/html/plankySettings.html @@ -91,23 +91,23 @@ function addHeader(label) { $(function() { addHeader('Stack Settings'); - properties['numLayers'] = new NumberInput('layers', 'Layers', 17, {'min': 0, 'max': 300, 'step': 1}); + properties['numLayers'] = new NumberInput('numLayers', 'Layers', 17, {'min': 0, 'max': 300, 'step': 1}); properties['baseDimension'] = new CoordinateInput('baseDimension', 'Base dimension', {x: 7, y: 2, z: 7}); - properties['blocksPerLayer'] = new NumberInput('blocksPerLayer', 'Blocks per layer', 4); + properties['blocksPerLayer'] = new NumberInput('blocksPerLayer', 'Blocks per layer', 4, {'min': 1, 'max': 100, 'step': 1}); properties['blockSize'] = new CoordinateInput('blockSize', 'Block size', {x: 0.2, y: 0.1, z: 0.8}); properties['blockSpacing'] = new NumberInput('blockSpacing', 'Block spacing', properties['blockSize'].getValue().x / properties['blocksPerLayer'].getValue()); properties['blockSpacing'].addButton('btn-recalculate-spacing', 'Recalculate spacing'); $('#btn-recalculate-spacing').on('click', function() { properties['blockSpacing'].setValue(properties['blockSize'].getValue().x / properties['blocksPerLayer'].getValue()); }); - properties['blockHeightVariation'] = new NumberInput('blockHeightVariation', 'Block height variation (%)', 0.1); + properties['blockHeightVariation'] = new NumberInput('blockHeightVariation', 'Block height variation (%)', 0.1, {'min': 0, 'max': 1, 'step': 0.01}); addHeader('Physics Settings'); properties['gravity'] = new CoordinateInput('gravity', 'Gravity', {x: 0, y: -2.8, z: 0}); - properties['density'] = new NumberInput('density', 'Density', 4000); - properties['dampingFactor'] = new NumberInput('dampingFactor', 'Damping factor', 0.98); - properties['angularDampingFactor'] = new NumberInput('angularDampingFactor', 'Angular damping factor', 0.8); - properties['friction'] = new NumberInput('friction', 'Friction', 0.99); - properties['restitution'] = new NumberInput('restitution', 'Restitution', 0.0); + properties['density'] = new NumberInput('density', 'Density', 4000, {'min': 0, 'max': 4000, 'step': 1}); + properties['dampingFactor'] = new NumberInput('dampingFactor', 'Damping factor', 0.98, {'min': 0, 'max': 1, 'step': 0.01}); + properties['angularDampingFactor'] = new NumberInput('angularDampingFactor', 'Angular damping factor', 0.8, {'min': 0, 'max': 1, 'step': 0.01}); + properties['friction'] = new NumberInput('friction', 'Friction', 0.99, {'min': 0, 'max': 1, 'step': 0.01}); + properties['restitution'] = new NumberInput('restitution', 'Restitution', 0.0, {'min': 0, 'max': 1, 'step': 0.01}); addHeader('Spawn Settings'); properties['spawnDistance'] = new NumberInput('spawnDistance', 'Spawn distance (meters)', 3); properties['blockYawOffset'] = new NumberInput('blockYawOffset', 'Block yaw offset (degrees)', 45, {'min': 0, 'max': 360, 'step': 1}); From 95948851f1427767e2a8372153a70064aa4d3dda Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 14 Jul 2015 04:36:29 +0200 Subject: [PATCH 08/58] save, clear and reset button --- examples/html/plankySettings.html | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/examples/html/plankySettings.html b/examples/html/plankySettings.html index b357e83792..0a79df6c7b 100644 --- a/examples/html/plankySettings.html +++ b/examples/html/plankySettings.html @@ -5,6 +5,9 @@ From b7110227963d187aca08cfe06de26501c0243546 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 14 Jul 2015 12:28:49 +0200 Subject: [PATCH 09/58] planky: - removed workaround for delayed overlay loading - make buttons functional (reset, cleanup, save-default) - only show live changes for the visual planky properties: blocksize , numLayers etc. (no physical properties) --- examples/example/games/planky.js | 74 +++++++++++++++++++------------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/examples/example/games/planky.js b/examples/example/games/planky.js index 0849481a61..5232201449 100644 --- a/examples/example/games/planky.js +++ b/examples/example/games/planky.js @@ -68,14 +68,28 @@ SettingsWindow = function() { case 'value_change': _this.plankyStack.onValueChanged(data.option, data.value); break; + case 'factory-reset': + _this.plankyStack.options.factoryReset(); + _this.sendData({action: 'load', options: _this.plankyStack.options.getJSON()}) + break; + case 'save-default': + _this.plankyStack.options.save(); + break; + case 'cleanup': + _this.plankyStack.deRez(); + break; default: - Window.alert('unknown action ' + data.action); + Window.alert('[planky] unknown action ' + data.action); } }; }; PlankyOptions = function() { var _this = this; + this.factoryReset = function() { + _this.setDefaults(); + Settings.setValue('plankyOptions', ''); + }; this.save = function() { Settings.setValue('plankyOptions', JSON.stringify(_this.getJSON())); }; @@ -86,9 +100,9 @@ PlankyOptions = function() { return; } var options = JSON.parse(plankyOptions); - options.forEach(function(value, option, object) { - _this[option] = value; - }); + for (option in options) { + _this[option] = options[option]; + } }; this.getJSON = function() { return { @@ -147,9 +161,10 @@ PlankyStack = function() { }) if (_this.centerLine) { Entities.deleteEntity(_this.centerLine); - } + } _this.ground = false; _this.centerLine = false; + _this.editLines = []; }; this.rez = function() { if (_this.planks.length > 0) { @@ -243,7 +258,9 @@ PlankyStack = function() { }; this.onValueChanged = function(option, value) { _this.options[option] = value; - _this.refresh(); + if (['numLayers', 'blocksPerLayer', 'blockSize', 'blockSpacing', 'blockHeightVariation'].indexOf(option) !== -1) { + _this.refresh(); + } }; this.refresh = function() { refreshGround(); @@ -284,31 +301,28 @@ function grabLowestJointY() { return floorY; } -function createButtons() { - toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.games.planky", function (windowDimensions, toolbar) { - return { - x: windowDimensions.x - (toolbar.width * 1.1), - y: toolbar.height / 2 - }; - }); - button = toolBar.addTool({ - width: BUTTON_DIMENSIONS.width, - height: BUTTON_DIMENSIONS.height, - imageURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/planky_button.svg', - alpha: 0.8, - visible: true - }); +toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.games.planky", function (windowDimensions, toolbar) { + return { + x: windowDimensions.x - (toolbar.width * 1.1), + y: toolbar.height / 2 + }; +}); - cogButton = toolBar.addTool({ - width: BUTTON_DIMENSIONS.width, - height: BUTTON_DIMENSIONS.height, - imageURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/cog.svg', - alpha: 0.8, - visible: true - }); -} -// Fixes bug of not showing buttons on startup -Script.setTimeout(createButtons, 2000); +button = toolBar.addTool({ + width: BUTTON_DIMENSIONS.width, + height: BUTTON_DIMENSIONS.height, + imageURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/planky_button.svg', + alpha: 0.8, + visible: true +}); + +cogButton = toolBar.addTool({ + width: BUTTON_DIMENSIONS.width, + height: BUTTON_DIMENSIONS.height, + imageURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/cog.svg', + alpha: 0.8, + visible: true +}); Controller.mousePressEvent.connect(function(event) { var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); From 6926ae9aa3bcdb474360a89dff4f01ba24dbd5cd Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 14 Jul 2015 20:27:51 +0200 Subject: [PATCH 10/58] small planky improvements --- examples/example/games/planky.js | 19 +++++++++++++------ examples/html/plankySettings.html | 21 +++++++++++---------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/examples/example/games/planky.js b/examples/example/games/planky.js index 5232201449..6733749317 100644 --- a/examples/example/games/planky.js +++ b/examples/example/games/planky.js @@ -65,7 +65,7 @@ SettingsWindow = function() { case 'loaded': _this.sendData({action: 'load', options: _this.plankyStack.options.getJSON()}) break; - case 'value_change': + case 'value-change': _this.plankyStack.onValueChanged(data.option, data.value); break; case 'factory-reset': @@ -148,6 +148,7 @@ PlankyStack = function() { this.ground = false; this.editLines = []; this.options = new PlankyOptions(); + this.deRez = function() { _this.planks.forEach(function(plank) { Entities.deleteEntity(plank.entity); @@ -159,13 +160,14 @@ PlankyStack = function() { _this.editLines.forEach(function(line) { Entities.deleteEntity(line); }) + _this.editLines = []; if (_this.centerLine) { Entities.deleteEntity(_this.centerLine); } _this.ground = false; _this.centerLine = false; - _this.editLines = []; }; + this.rez = function() { if (_this.planks.length > 0) { _this.deRez(); @@ -192,7 +194,7 @@ PlankyStack = function() { } // move ground to rez position/rotation Entities.editEntity(_this.ground, {dimensions: _this.options.baseDimension, position: Vec3.sum(_this.basePosition, {y: -(_this.options.baseDimension.y / 2)}), rotation: _this.baseRotation}); - } + }; var refreshLines = function() { if (_this.editLines.length === 0) { @@ -206,7 +208,8 @@ PlankyStack = function() { })); return; } - } + }; + var trimDimension = function(dimension, maxIndex) { _this.planks.forEach(function(plank, index, object) { if (plank[dimension] > maxIndex) { @@ -215,6 +218,7 @@ PlankyStack = function() { } }); }; + var createOrUpdate = function(layer, row) { var found = false; var layerRotated = layer % 2 === 0; @@ -256,17 +260,19 @@ PlankyStack = function() { _this.planks.push({layer: layer, row: row, entity: Entities.addEntity(newProperties)}) } }; + this.onValueChanged = function(option, value) { _this.options[option] = value; if (['numLayers', 'blocksPerLayer', 'blockSize', 'blockSpacing', 'blockHeightVariation'].indexOf(option) !== -1) { _this.refresh(); } }; + this.refresh = function() { refreshGround(); refreshLines(); - trimDimension('layer', _this.options.numLayers); - trimDimension('row', _this.options.blocksPerLayer); + trimDimension('layer', _this.options.numLayers - 1); + trimDimension('row', _this.options.blocksPerLayer - 1); _this.offsetRot = Quat.multiply(_this.baseRotation, Quat.fromPitchYawRollDegrees(0.0, _this.options.blockYawOffset, 0.0)); for (var layer = 0; layer < _this.options.numLayers; layer++) { for (var row = 0; row < _this.options.blocksPerLayer; row++) { @@ -280,6 +286,7 @@ PlankyStack = function() { }); } }; + this.isFound = function() { //TODO: identify entities here until one is found return _this.planks.length > 0; diff --git a/examples/html/plankySettings.html b/examples/html/plankySettings.html index 0a79df6c7b..0eea4948ad 100644 --- a/examples/html/plankySettings.html +++ b/examples/html/plankySettings.html @@ -42,10 +42,11 @@ PropertyInput = function(key, label, value, attributes) { }; var valueChangeHandler = function() { + sendWebEvent({ - action: 'value_change', - option: $(this).attr('name'), - value: properties[$(this).attr('name')].getValue() + action: 'value-change', + option: $(this).data('var-name'), + value: properties[$(this).data('var-name')].getValue() }); }; @@ -55,14 +56,14 @@ NumberInput = function(key, label, value, attributes) { NumberInput.prototype = Object.create(PropertyInput.prototype); NumberInput.prototype.constructor = NumberInput; NumberInput.prototype.createValue = function() { - this.input = $('').attr('name', this.key).attr('type', 'number').val(this.value).on('change', valueChangeHandler); + this.input = $('').data('var-name', this.key).attr('name', this.key).attr('type', 'number').val(this.value).on('change', valueChangeHandler); if (this.attributes !== undefined) { this.input.attr(this.attributes); } return this.input; }; NumberInput.prototype.getValue = function() { - return this.input.val(); + return parseFloat(this.input.val()); }; CoordinateInput = function(key, label, value, attributes) { @@ -71,9 +72,9 @@ CoordinateInput = function(key, label, value, attributes) { CoordinateInput.prototype = Object.create(PropertyInput.prototype); CoordinateInput.prototype.constructor = CoordinateInput; CoordinateInput.prototype.createValue = function() { - this.inputX = $('').attr('name', this.key + '-x').attr('type', 'number').addClass('coord').val(this.value.x); - this.inputY = $('').attr('name', this.key + '-y').attr('type', 'number').addClass('coord').val(this.value.y); - this.inputZ = $('').attr('name', this.key + '-z').attr('type', 'number').addClass('coord').val(this.value.z); + this.inputX = $('').data('var-name', this.key).attr('name', this.key + '-x').attr('type', 'number').addClass('coord').val(this.value.x).on('change', valueChangeHandler); + this.inputY = $('').data('var-name', this.key).attr('name', this.key + '-y').attr('type', 'number').addClass('coord').val(this.value.y).on('change', valueChangeHandler); + this.inputZ = $('').data('var-name', this.key).attr('name', this.key + '-z').attr('type', 'number').addClass('coord').val(this.value.z).on('change', valueChangeHandler); if (this.attributes !== undefined) { this.inputX.attr(this.attributes); this.inputY.attr(this.attributes); @@ -82,7 +83,7 @@ CoordinateInput.prototype.createValue = function() { return [encapsulateInput(this.inputX, 'X'), encapsulateInput(this.inputY, 'Y'), encapsulateInput(this.inputZ, 'Z')]; }; CoordinateInput.prototype.getValue = function() { - return {x: this.inputX.val(), y: this.inputY.val(), z: this.inputZ.val()}; + return {x: parseFloat(this.inputX.val()), y: parseFloat(this.inputY.val()), z: parseFloat(this.inputZ.val())}; }; function encapsulateInput(input, label) { return $('
').addClass('input-area').append(label + ' ').append(input); @@ -95,7 +96,6 @@ function addHeader(label) { $(function() { addHeader('Stack Settings'); properties['numLayers'] = new NumberInput('numLayers', 'Layers', 17, {'min': 0, 'max': 300, 'step': 1}); - properties['baseDimension'] = new CoordinateInput('baseDimension', 'Base dimension', {x: 7, y: 2, z: 7}, {'min': 0.5, 'max': 200, 'step': 0.1}); properties['blocksPerLayer'] = new NumberInput('blocksPerLayer', 'Blocks per layer', 4, {'min': 1, 'max': 100, 'step': 1}); properties['blockSize'] = new CoordinateInput('blockSize', 'Block size', {x: 0.2, y: 0.1, z: 0.8}, {'min': 0.05, 'max': 20, 'step': 0.1}); properties['blockSpacing'] = new NumberInput('blockSpacing', 'Block spacing', properties['blockSize'].getValue().x / properties['blocksPerLayer'].getValue(), {'min': 0, 'max': 20, 'step': 0.01}); @@ -114,6 +114,7 @@ $(function() { addHeader('Spawn Settings'); properties['spawnDistance'] = new NumberInput('spawnDistance', 'Spawn distance (meters)', 3); properties['blockYawOffset'] = new NumberInput('blockYawOffset', 'Block yaw offset (degrees)', 45, {'min': 0, 'max': 360, 'step': 1}); + properties['baseDimension'] = new CoordinateInput('baseDimension', 'Base dimension', {x: 7, y: 2, z: 7}, {'min': 0.5, 'max': 200, 'step': 0.1}); addHeader('Actions'); $('#properties-list') .append($('').val('factory reset').attr('type', 'button').on('click', function() { sendWebEvent({action: 'factory-reset'}); })) From 1b13f837bd052cdc9441aff87795c89cb5b237f7 Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Wed, 15 Jul 2015 14:10:17 -0700 Subject: [PATCH 11/58] Porting AO to new pipeline --- interface/src/Application.cpp | 10 +- .../src/AmbientOcclusionEffect.cpp | 121 ++++++++++++++---- .../render-utils/src/AmbientOcclusionEffect.h | 36 +++++- .../render-utils/src/RenderDeferredTask.cpp | 4 + .../render-utils/src/ambient_occlusion.slf | 22 ++++ .../render-utils/src/ambient_occlusion.slv | 25 ++++ 6 files changed, 179 insertions(+), 39 deletions(-) create mode 100644 libraries/render-utils/src/ambient_occlusion.slf create mode 100644 libraries/render-utils/src/ambient_occlusion.slv diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 00a4440920..51aec20481 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2154,7 +2154,6 @@ void Application::init() { _environment.init(); DependencyManager::get()->init(this); - DependencyManager::get()->init(this); // TODO: move _myAvatar out of Application. Move relevant code to MyAvataar or AvatarManager DependencyManager::get()->init(); @@ -3479,14 +3478,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se renderArgs->_debugFlags = renderDebugFlags; _entities.render(renderArgs); } - - // render the ambient occlusion effect if enabled - if (Menu::getInstance()->isOptionChecked(MenuOption::AmbientOcclusion)) { - PerformanceTimer perfTimer("ambientOcclusion"); - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "Application::displaySide() ... AmbientOcclusion..."); - DependencyManager::get()->render(); - } } // Make sure the WorldBox is in the scene @@ -3564,6 +3555,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se sceneInterface->setEngineFeedOverlay3DItems(engineRC->_numFeedOverlay3DItems); sceneInterface->setEngineDrawnOverlay3DItems(engineRC->_numDrawnOverlay3DItems); } + //Render the sixense lasers if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) { _myAvatar->renderLaserPointers(*renderArgs->_batch); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index f58419ec6e..82034cad12 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -25,12 +25,17 @@ #include "ProgramObject.h" #include "RenderUtil.h" #include "TextureCache.h" +#include "DependencyManager.h" +#include "ViewFrustum.h" + +#include "ambient_occlusion_vert.h" +#include "ambient_occlusion_frag.h" const int ROTATION_WIDTH = 4; const int ROTATION_HEIGHT = 4; void AmbientOcclusionEffect::init(AbstractViewStateInterface* viewState) { - _viewState = viewState; // we will use this for view state services + /*_viewState = viewState; // we will use this for view state services _occlusionProgram = new ProgramObject(); _occlusionProgram->addShaderFromSourceFile(QGLShader::Vertex, PathUtils::resourcesPath() @@ -93,27 +98,27 @@ void AmbientOcclusionEffect::init(AbstractViewStateInterface* viewState) { _blurProgram->setUniformValue("originalTexture", 0); _blurProgram->release(); - _blurScaleLocation = _blurProgram->uniformLocation("blurScale"); + _blurScaleLocation = _blurProgram->uniformLocation("blurScale");*/ } -void AmbientOcclusionEffect::render() { - glDisable(GL_BLEND); +void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext){ + /*glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); - + glBindTexture(GL_TEXTURE_2D, DependencyManager::get()->getPrimaryDepthTextureID()); - + glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, _rotationTextureID); - + // render with the occlusion shader to the secondary/tertiary buffer auto freeFramebuffer = DependencyManager::get()->getFreeFramebuffer(); glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(freeFramebuffer)); - + float left, right, bottom, top, nearVal, farVal; glm::vec4 nearClipPlane, farClipPlane; - _viewState->computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); - + AbstractViewStateInterface::instance()->computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); + int viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); const int VIEWPORT_X_INDEX = 0; @@ -122,7 +127,7 @@ void AmbientOcclusionEffect::render() { auto framebufferSize = DependencyManager::get()->getFrameBufferSize(); float sMin = viewport[VIEWPORT_X_INDEX] / (float)framebufferSize.width(); float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)framebufferSize.width(); - + _occlusionProgram->bind(); _occlusionProgram->setUniformValue(_nearLocation, nearVal); _occlusionProgram->setUniformValue(_farLocation, farVal); @@ -132,37 +137,107 @@ void AmbientOcclusionEffect::render() { framebufferSize.height() / (float)ROTATION_HEIGHT); _occlusionProgram->setUniformValue(_texCoordOffsetLocation, sMin, 0.0f); _occlusionProgram->setUniformValue(_texCoordScaleLocation, sWidth, 1.0f); - + renderFullscreenQuad(); - + _occlusionProgram->release(); - + glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindTexture(GL_TEXTURE_2D, 0); - + glActiveTexture(GL_TEXTURE0); - + // now render secondary to primary with 4x4 blur auto primaryFramebuffer = DependencyManager::get()->getPrimaryFramebuffer(); glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(primaryFramebuffer)); glEnable(GL_BLEND); glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ONE); - + auto freeFramebufferTexture = freeFramebuffer->getRenderBuffer(0); glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(freeFramebufferTexture)); - + _blurProgram->bind(); _blurProgram->setUniformValue(_blurScaleLocation, 1.0f / framebufferSize.width(), 1.0f / framebufferSize.height()); - + renderFullscreenQuad(sMin, sMin + sWidth); - + _blurProgram->release(); - + glBindTexture(GL_TEXTURE_2D, 0); - + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); glEnable(GL_DEPTH_TEST); - glDepthMask(GL_TRUE); + glDepthMask(GL_TRUE);*/ } + + +AmbientOcclusion::AmbientOcclusion() { +} + +const gpu::PipelinePointer& AmbientOcclusion::getAOPipeline() { + if (!_AOPipeline) { + auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(ambient_occlusion_vert))); + auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(ambient_occlusion_frag))); + gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + + gpu::Shader::BindingSet slotBindings; + gpu::Shader::makeProgram(*program, slotBindings); + + //_drawItemBoundPosLoc = program->getUniforms().findLocation("inBoundPos"); + //_drawItemBoundDimLoc = program->getUniforms().findLocation("inBoundDim"); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + + state->setDepthTest(true, false, gpu::LESS_EQUAL); + + // Blend on transparent + state->setBlendFunction(true, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); + + // Good to go add the brand new pipeline + _AOPipeline.reset(gpu::Pipeline::create(program, state)); + } + return _AOPipeline; +} + +void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) { + + // create a simple pipeline that does: + + assert(renderContext->args); + assert(renderContext->args->_viewFrustum); + RenderArgs* args = renderContext->args; + auto& scene = sceneContext->_scene; + + // Allright, something to render let's do it + gpu::Batch batch; + + glm::mat4 projMat; + Transform viewMat; + args->_viewFrustum->evalProjectionMatrix(projMat); + args->_viewFrustum->evalViewTransform(viewMat); + if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { + viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f)); + } + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + batch.setModelTransform(Transform()); + + // bind the one gpu::Pipeline we need + batch.setPipeline(getAOPipeline()); + + //renderFullscreenQuad(); + + args->_context->syncCache(); + renderContext->args->_context->syncCache(); + args->_context->render((batch)); + + // need to fetch forom the z buffer and render something in a new render target a result that combine the z and produce a fake AO result + + + +} + diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index c7acb90133..fbe4a09214 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -14,23 +14,30 @@ #include +#include "render/DrawTask.h" + class AbstractViewStateInterface; class ProgramObject; /// A screen space ambient occlusion effect. See John Chapman's tutorial at /// http://john-chapman-graphics.blogspot.co.uk/2013/01/ssao-tutorial.html for reference. + class AmbientOcclusionEffect : public Dependency { SINGLETON_DEPENDENCY - + public: - + void init(AbstractViewStateInterface* viewState); - void render(); - -private: + + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); + typedef render::Job::Model JobModel; + + AmbientOcclusionEffect() {} virtual ~AmbientOcclusionEffect() {} +private: + ProgramObject* _occlusionProgram; int _nearLocation; int _farLocation; @@ -39,12 +46,27 @@ private: int _noiseScaleLocation; int _texCoordOffsetLocation; int _texCoordScaleLocation; - + ProgramObject* _blurProgram; int _blurScaleLocation; - + GLuint _rotationTextureID; AbstractViewStateInterface* _viewState; }; +class AmbientOcclusion { +public: + + AmbientOcclusion(); + + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); + typedef render::Job::Model JobModel; + + const gpu::PipelinePointer& AmbientOcclusion::getAOPipeline(); + +private: + + gpu::PipelinePointer _AOPipeline; +}; + #endif // hifi_AmbientOcclusionEffect_h diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 55f4f72574..e4740cc8de 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -18,6 +18,7 @@ #include "TextureCache.h" #include "render/DrawStatus.h" +#include "AmbientOcclusionEffect.h" #include @@ -71,10 +72,13 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _jobs.push_back(Job(new DrawTransparentDeferred::JobModel("TransparentDeferred", _jobs.back().getOutput()))); _jobs.push_back(Job(new render::DrawStatus::JobModel("DrawStatus", renderedOpaques))); + + _jobs.back().setEnabled(false); _drawStatusJobIndex = _jobs.size() - 1; _jobs.push_back(Job(new DrawOverlay3D::JobModel("DrawOverlay3D"))); + _jobs.push_back(Job(new AmbientOcclusion::JobModel("AmbientOcclusion"))); _jobs.push_back(Job(new ResetGLState::JobModel())); // Give ourselves 3 frmaes of timer queries diff --git a/libraries/render-utils/src/ambient_occlusion.slf b/libraries/render-utils/src/ambient_occlusion.slf new file mode 100644 index 0000000000..67cf9d3c53 --- /dev/null +++ b/libraries/render-utils/src/ambient_occlusion.slf @@ -0,0 +1,22 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// simple.frag +// fragment shader +// +// Created by Andrzej Kapolka on 9/15/14. +// Copyright 2014 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 DeferredBufferWrite.slh@> + +// the interpolated normal +//varying vec4 interpolatedNormal; + +void main(void) { + gl_FragColor = vec4(0.0, 1.0, 1.0, 1.0); +} diff --git a/libraries/render-utils/src/ambient_occlusion.slv b/libraries/render-utils/src/ambient_occlusion.slv new file mode 100644 index 0000000000..702b1bd59e --- /dev/null +++ b/libraries/render-utils/src/ambient_occlusion.slv @@ -0,0 +1,25 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// simple.vert +// vertex shader +// +// Created by Andrzej Kapolka on 9/15/14. +// Copyright 2014 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 gpu/Transform.slh@> + +<$declareStandardTransform()$> + +// the interpolated normal +//varying vec4 interpolatedNormal; + +void main(void) { + //gl_TexCoord[0] = gl_MultiTexCoord0; + gl_Position = gl_Vertex; +} \ No newline at end of file From 022529f03f967216c83fc649262df07dbfce0986 Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Thu, 16 Jul 2015 09:46:28 -0700 Subject: [PATCH 12/58] Render depth buffer to quad Useful for graphics debugging --- .../src/AmbientOcclusionEffect.cpp | 13 ++++++++++--- .../render-utils/src/RenderDeferredTask.cpp | 4 +++- .../render-utils/src/ambient_occlusion.slf | 18 ++++++++++++++---- .../render-utils/src/ambient_occlusion.slv | 9 +++++---- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 82034cad12..07832179cc 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -27,6 +27,7 @@ #include "TextureCache.h" #include "DependencyManager.h" #include "ViewFrustum.h" +#include "GeometryCache.h" #include "ambient_occlusion_vert.h" #include "ambient_occlusion_frag.h" @@ -190,10 +191,10 @@ const gpu::PipelinePointer& AmbientOcclusion::getAOPipeline() { gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setDepthTest(true, false, gpu::LESS_EQUAL); + state->setDepthTest(false, false, gpu::LESS_EQUAL); // Blend on transparent - state->setBlendFunction(true, + state->setBlendFunction(false, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); @@ -225,11 +226,17 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); batch.setModelTransform(Transform()); + batch.setResourceTexture(0, DependencyManager::get()->getPrimaryDepthTexture()); // bind the one gpu::Pipeline we need batch.setPipeline(getAOPipeline()); - //renderFullscreenQuad(); + glm::vec4 color(0.0f, 0.0f, 0.0f, 1.0f); + glm::vec2 bottomLeft(0.5f, -1.0f); + glm::vec2 topRight(1.0f, -0.5f); + glm::vec2 texCoordTopLeft(0.0f, 0.0f); + glm::vec2 texCoordBottomRight(1.0f, 1.0f); + DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); args->_context->syncCache(); renderContext->args->_context->syncCache(); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index e9a5689747..5b4d8e9d4f 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -59,6 +59,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _jobs.push_back(Job(new ResetGLState::JobModel())); _jobs.push_back(Job(new RenderDeferred::JobModel("RenderDeferred"))); _jobs.push_back(Job(new ResolveDeferred::JobModel("ResolveDeferred"))); + _jobs.push_back(Job(new AmbientOcclusion::JobModel("AmbientOcclusion"))); _jobs.push_back(Job(new FetchItems::JobModel("FetchTransparent", FetchItems( ItemFilter::Builder::transparentShape().withoutLayered(), @@ -77,8 +78,9 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _jobs.back().setEnabled(false); _drawStatusJobIndex = _jobs.size() - 1; + //_jobs.push_back(Job(new AmbientOcclusion::JobModel("AmbientOcclusion"))); _jobs.push_back(Job(new DrawOverlay3D::JobModel("DrawOverlay3D"))); - _jobs.push_back(Job(new AmbientOcclusion::JobModel("AmbientOcclusion"))); + _jobs.push_back(Job(new ResetGLState::JobModel())); // Give ourselves 3 frmaes of timer queries diff --git a/libraries/render-utils/src/ambient_occlusion.slf b/libraries/render-utils/src/ambient_occlusion.slf index 67cf9d3c53..b56e0eb9d5 100644 --- a/libraries/render-utils/src/ambient_occlusion.slf +++ b/libraries/render-utils/src/ambient_occlusion.slf @@ -2,11 +2,11 @@ <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> // -// simple.frag +// ambient_occlusion.frag // fragment shader // -// Created by Andrzej Kapolka on 9/15/14. -// Copyright 2014 High Fidelity, Inc. +// Created by Niraj Venkat on 7/15/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 @@ -17,6 +17,16 @@ // the interpolated normal //varying vec4 interpolatedNormal; +varying vec2 varTexcoord; + +uniform sampler2D depthTexture; + void main(void) { - gl_FragColor = vec4(0.0, 1.0, 1.0, 1.0); + vec4 depthColor = texture2D(depthTexture, varTexcoord.xy); + float z = depthColor.r; // fetch the z-value from our depth texture + float n = 1.0; // the near plane + float f = 30.0; // the far plane + float c = (2.0 * n) / (f + n - z * (f - n)); // convert to linear values + + gl_FragColor = vec4(c, c, c, 1.0); } diff --git a/libraries/render-utils/src/ambient_occlusion.slv b/libraries/render-utils/src/ambient_occlusion.slv index 702b1bd59e..54cc608129 100644 --- a/libraries/render-utils/src/ambient_occlusion.slv +++ b/libraries/render-utils/src/ambient_occlusion.slv @@ -2,11 +2,11 @@ <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> // -// simple.vert +// ambient_occlusion.vert // vertex shader // -// Created by Andrzej Kapolka on 9/15/14. -// Copyright 2014 High Fidelity, Inc. +// Created by Niraj Venkat on 7/15/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 @@ -18,8 +18,9 @@ // the interpolated normal //varying vec4 interpolatedNormal; +varying vec2 varTexcoord; void main(void) { - //gl_TexCoord[0] = gl_MultiTexCoord0; + varTexcoord = gl_MultiTexCoord0.xy; gl_Position = gl_Vertex; } \ No newline at end of file From 9c8e01f3ff64d1401a5706b2c27b644235000753 Mon Sep 17 00:00:00 2001 From: Bing Shearer Date: Fri, 17 Jul 2015 16:10:34 -0700 Subject: [PATCH 13/58] New falling leaf script based on the existing rain.js --- examples/leaves.js | 291 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100755 examples/leaves.js diff --git a/examples/leaves.js b/examples/leaves.js new file mode 100755 index 0000000000..347371ff5b --- /dev/null +++ b/examples/leaves.js @@ -0,0 +1,291 @@ +// +// Leaves.js +// examples +// +// Created by Bing Shearer on 14 Jul 2015 +// 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 +// +var leafName = "scriptLeaf"; +var leafSquall = function (properties) { + var // Properties + squallOrigin, + squallRadius, + leavesPerMinute = 60, + leafSize = { x: 0.1, y: 0.1, z: 0.1 }, + leafFallSpeed = 1, // m/s + leafLifetime = 60, // Seconds + leafSpinMax = 0, // Maximum angular velocity per axis; deg/s + debug = false, // Display origin circle; don't use running on Stack Manager + // Other + squallCircle, + SQUALL_CIRCLE_COLOR = { red: 255, green: 0, blue: 0 }, + SQUALL_CIRCLE_ALPHA = 0.5, + SQUALL_CIRCLE_ROTATION = Quat.fromPitchYawRollDegrees(90, 0, 0), + leafProperties, + leaf_MODEL_URL = "https://hifi-public.s3.amazonaws.com/ozan/support/forBing/palmLeaf.fbx", + leafTimer, + leaves = [], // HACK: Work around leaves not always getting velocities + leafVelocities = [], // HACK: Work around leaves not always getting velocities + DEGREES_TO_RADIANS = Math.PI / 180, + leafDeleteOnTearDown = true, + maxLeaves, + leafCount, + nearbyEntities, + complexMovement = false, + movementTime = 0, + maxSpinRadians = properties.leafSpinMax * DEGREES_TO_RADIANS, + windFactor, + leafDeleteOnGround = false, + floorHeight = null; + + + function processProperties() { + if (!properties.hasOwnProperty("origin")) { + print("ERROR: Leaf squall origin must be specified"); + return; + } + squallOrigin = properties.origin; + + if (!properties.hasOwnProperty("radius")) { + print("ERROR: Leaf squall radius must be specified"); + return; + } + squallRadius = properties.radius; + + if (properties.hasOwnProperty("leavesPerMinute")) { + leavesPerMinute = properties.leavesPerMinute; + } + + if (properties.hasOwnProperty("leafSize")) { + leafSize = properties.leafSize; + } + + if (properties.hasOwnProperty("leafFallSpeed")) { + leafFallSpeed = properties.leafFallSpeed; + } + + if (properties.hasOwnProperty("leafLifetime")) { + leafLifetime = properties.leafLifetime; + } + + if (properties.hasOwnProperty("leafSpinMax")) { + leafSpinMax = properties.leafSpinMax; + } + + if (properties.hasOwnProperty("debug")) { + debug = properties.debug; + } + if (properties.hasOwnProperty("floorHeight")) { + floorHeight = properties.floorHeight; + } + if (properties.hasOwnProperty("maxLeaves")) { + maxLeaves = properties.maxLeaves; + } + if (properties.hasOwnProperty("complexMovement")) { + complexMovement = properties.complexMovement; + } + if (properties.hasOwnProperty("leafDeleteOnGround")) { + leafDeleteOnGround = properties.leafDeleteOnGround; + } + if (properties.hasOwnProperty("windFactor")) { + windFactor = properties.windFactor; + } + else { + print("ERROR: Wind Factor must be defined for complex movement") + } + + leafProperties = { + type: "Model", + name: leafName, + modelURL: leaf_MODEL_URL, + lifetime: leafLifetime, + dimensions: leafSize, + velocity: { x: 0, y: -leafFallSpeed, z: 0 }, + damping: 0, + angularDamping: 0, + ignoreForCollisions: true + + }; + } + + function createleaf() { + var angle, + radius, + offset, + leaf, + spin = { x: 0, y: 0, z: 0 }, + i; + + // HACK: Work around leaves not always getting velocities set at creation + for (i = 0; i < leaves.length; i += 1) { + Entities.editEntity(leaves[i], leafVelocities[i]); + } + + angle = Math.random() * 10; + radius = Math.random() * squallRadius; + offset = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, angle, 0), { x: 0, y: -0.1, z: radius }); + leafProperties.position = Vec3.sum(squallOrigin, offset); + if (properties.leafSpinMax > 0 && !complexMovement) { + spin = { + x: Math.random() * maxSpinRadians, + y: Math.random() * maxSpinRadians, + z: Math.random() * maxSpinRadians + }; + leafProperties.angularVelocity = spin; + } + else if (complexMovement) { + spin = { x: 0, y: 0, z: 0 }; + leafProperties.angularVelocity = spin + } + leaf = Entities.addEntity(leafProperties); + + // HACK: Work around leaves not always getting velocities set at creation + leaves.push(leaf); + leafVelocities.push({ + velocity: leafProperties.velocity, + angularVelocity: spin + }); + if (leaves.length > 5) { + leaves.shift(); + leafVelocities.shift(); + } + } + + function setUp() { + if (debug) { + squallCircle = Overlays.addOverlay("circle3d", { + size: { x: 2 * squallRadius, y: 2 * squallRadius }, + color: SQUALL_CIRCLE_COLOR, + alpha: SQUALL_CIRCLE_ALPHA, + solid: true, + visible: debug, + position: squallOrigin, + rotation: SQUALL_CIRCLE_ROTATION + }); + } + + leafTimer = Script.setInterval(function () { + if (leafCount <= maxLeaves - 1) { + createleaf() + } + }, 60000 / leavesPerMinute); + } + Script.setInterval(function () { + nearbyEntities = Entities.findEntities(squallOrigin, squallRadius); + newLeafMovement() + }, 100); + + function newLeafMovement() { //new additions to leaf code. Operates at 10 Hz or every 100 ms + movementTime += 0.1; + var currentLeaf, + randomRotationSpeed = { + x: maxSpinRadians * Math.sin(movementTime), + y: maxSpinRadians * Math.random(), + z: maxSpinRadians * Math.sin(movementTime / 7) + }; + for (var i = 0; i < nearbyEntities.length; i++) { + var entityProperties = Entities.getEntityProperties(nearbyEntities[i]); + var entityName = entityProperties.name; + if (leafName === entityName) { + currentLeaf = nearbyEntities[i]; + var leafHeight = entityProperties.position.y; + if (complexMovement && leafHeight > floorHeight || complexMovement && floorHeight == null) { //actual new movement code; + var currentLeafVelocity = entityProperties.velocity, + currentLeafRot = entityProperties.rotation, + yVec = { x: 0, y: 1, z: 0 }, + leafYinWFVec = Vec3.multiplyQbyV(currentLeafRot, yVec), + leafLocalHorVec = Vec3.cross(leafYinWFVec, yVec), + leafMostDownVec = Vec3.cross(leafYinWFVec, leafLocalHorVec), + leafDesiredVel = Vec3.multiply(leafMostDownVec, windFactor); + Entities.editEntity(currentLeaf, { + angularVelocity: randomRotationSpeed, + velocity: { + x: (leafDesiredVel.x - currentLeafVelocity.x) * windFactor + currentLeafVelocity.x, + y: (leafDesiredVel.y - currentLeafVelocity.y) * windFactor + currentLeafVelocity.y, + z: (leafDesiredVel.z - currentLeafVelocity.z) * windFactor + currentLeafVelocity.z + } + }) + } + else if (leafHeight <= floorHeight) { + if (!leafDeleteOnGround) { + Entities.editEntity(nearbyEntities[i], { + locked: false, + velocity: { x: 0, y: 0, z: 0 }, + angularVelocity: { x: 0, y: 0, z: 0 } + }) + } + else { + Entity.deleteEntity(currentLeaf); + } + } + } + } + } + + + + getLeafCount = Script.setInterval(function () { + leafCount = 0 + for (var i = 0; i < nearbyEntities.length; i++) { + var entityName = Entities.getEntityProperties(nearbyEntities[i]).name; + //Stop Leaves at floorHeight + if (leafName === entityName) { + leafCount++; + if (i == nearbyEntities.length - 1) { + //print(leafCount); + } + } + } + }, 1000) + + + + function tearDown() { + Script.clearInterval(leafTimer); + Overlays.deleteOverlay(squallCircle); + if (leafDeleteOnTearDown) { + for (var i = 0; i < nearbyEntities.length; i++) { + var entityName = Entities.getEntityProperties(nearbyEntities[i]).name; + if (leafName === entityName) { + //We have a match - delete this entity + Entities.editEntity(nearbyEntities[i], { + locked: false + }); + Entities.deleteEntity(nearbyEntities[i]); + } + } + } + } + + + + processProperties(); + setUp(); + Script.scriptEnding.connect(tearDown); + + return { + }; +}; + +var leafSquall1 = new leafSquall({ + origin: { x: 3071.5, y: 2170, z: 6765.3 }, + radius: 100, + leavesPerMinute: 30, + leafSize: { x: 0.3, y: 0.00, z: .3}, + leafFallSpeed: .4, + leafLifetime: 100, + leafSpinMax: 30, + debug: false, + maxLeaves: 100, + leafDeleteOnTearDown: true, + complexMovement: true, + floorHeight: 2143.5, + windFactor: .5, + leafDeleteOnGround: false +}); + +// todo +//deal with depth issue \ No newline at end of file From 0580c8477e1c3a89879176e21702765fe2e7eae0 Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Fri, 17 Jul 2015 16:42:03 -0700 Subject: [PATCH 14/58] 3-step groundwork for AO in the pipeline --- interface/src/Application.cpp | 1 - libraries/gpu/src/gpu/GLBackendTexture.cpp | 32 ++++ .../src/AmbientOcclusionEffect.cpp | 149 ++++++++++++++++-- .../render-utils/src/AmbientOcclusionEffect.h | 18 ++- .../render-utils/src/ambient_occlusion.slf | 3 - .../render-utils/src/ambient_occlusion.slv | 4 +- libraries/render-utils/src/gaussian_blur.slf | 42 +++++ .../src/gaussian_blur_horizontal.slv | 41 +++++ .../src/gaussian_blur_vertical.slv | 41 +++++ 9 files changed, 306 insertions(+), 25 deletions(-) create mode 100644 libraries/render-utils/src/gaussian_blur.slf create mode 100644 libraries/render-utils/src/gaussian_blur_horizontal.slv create mode 100644 libraries/render-utils/src/gaussian_blur_vertical.slv diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8b04223463..537003ec02 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -274,7 +274,6 @@ bool setupEssentials(int& argc, char** argv) { auto audio = DependencyManager::set(); auto audioScope = DependencyManager::set(); auto deferredLightingEffect = DependencyManager::set(); - auto ambientOcclusionEffect = DependencyManager::set(); auto textureCache = DependencyManager::set(); auto animationCache = DependencyManager::set(); auto ddeFaceTracker = DependencyManager::set(); diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 72c7de8504..2696d17596 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -144,6 +144,38 @@ public: case gpu::RGB: case gpu::RGBA: texel.internalFormat = GL_RED; + /* switch (dstFormat.getType()) { + case gpu::UINT32: + case gpu::INT32: + case gpu::NUINT32: + case gpu::NINT32: { + texel.internalFormat = GL_DEPTH_COMPONENT32; + break; + } + case gpu::NFLOAT: + case gpu::FLOAT: { + texel.internalFormat = GL_DEPTH_COMPONENT32F; + break; + } + case gpu::UINT16: + case gpu::INT16: + case gpu::NUINT16: + case gpu::NINT16: + case gpu::HALF: + case gpu::NHALF: { + texel.internalFormat = GL_DEPTH_COMPONENT16; + break; + } + case gpu::UINT8: + case gpu::INT8: + case gpu::NUINT8: + case gpu::NINT8: { + texel.internalFormat = GL_DEPTH_COMPONENT24; + break; + } + case gpu::NUM_TYPES: { // quiet compiler + Q_UNREACHABLE(); + }*/ break; case gpu::DEPTH: texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 07832179cc..7e6b5c7e75 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -31,12 +31,16 @@ #include "ambient_occlusion_vert.h" #include "ambient_occlusion_frag.h" +#include "gaussian_blur_vertical_vert.h" +#include "gaussian_blur_horizontal_vert.h" +#include "gaussian_blur_frag.h" const int ROTATION_WIDTH = 4; const int ROTATION_HEIGHT = 4; - + +/* void AmbientOcclusionEffect::init(AbstractViewStateInterface* viewState) { - /*_viewState = viewState; // we will use this for view state services + _viewState = viewState; // we will use this for view state services _occlusionProgram = new ProgramObject(); _occlusionProgram->addShaderFromSourceFile(QGLShader::Vertex, PathUtils::resourcesPath() @@ -99,11 +103,11 @@ void AmbientOcclusionEffect::init(AbstractViewStateInterface* viewState) { _blurProgram->setUniformValue("originalTexture", 0); _blurProgram->release(); - _blurScaleLocation = _blurProgram->uniformLocation("blurScale");*/ + _blurScaleLocation = _blurProgram->uniformLocation("blurScale"); } void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext){ - /*glDisable(GL_BLEND); + glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); @@ -170,15 +174,15 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); glEnable(GL_DEPTH_TEST); - glDepthMask(GL_TRUE);*/ + glDepthMask(GL_TRUE) } - +*/ AmbientOcclusion::AmbientOcclusion() { } -const gpu::PipelinePointer& AmbientOcclusion::getAOPipeline() { - if (!_AOPipeline) { +const gpu::PipelinePointer& AmbientOcclusion::getOcclusionPipeline() { + if (!_occlusionPipeline) { auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(ambient_occlusion_vert))); auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(ambient_occlusion_frag))); gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); @@ -198,10 +202,85 @@ const gpu::PipelinePointer& AmbientOcclusion::getAOPipeline() { gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); + // Link the occlusion FBO to texture + _occlusionBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, + DependencyManager::get()->getFrameBufferSize().width(), DependencyManager::get()->getFrameBufferSize().height())); + auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); + auto width = _occlusionBuffer->getWidth(); + auto height = _occlusionBuffer->getHeight(); + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); + _occlusionTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); + // Good to go add the brand new pipeline - _AOPipeline.reset(gpu::Pipeline::create(program, state)); + _occlusionPipeline.reset(gpu::Pipeline::create(program, state)); } - return _AOPipeline; + return _occlusionPipeline; +} + +const gpu::PipelinePointer& AmbientOcclusion::getVBlurPipeline() { + if (!_vBlurPipeline) { + auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(gaussian_blur_vertical_vert))); + auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(gaussian_blur_frag))); + gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + + gpu::Shader::BindingSet slotBindings; + gpu::Shader::makeProgram(*program, slotBindings); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + + state->setDepthTest(false, false, gpu::LESS_EQUAL); + + // Blend on transparent + state->setBlendFunction(false, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); + + // Link the horizontal blur FBO to texture + _vBlurBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, + DependencyManager::get()->getFrameBufferSize().width(), DependencyManager::get()->getFrameBufferSize().height())); + auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); + auto width = _vBlurBuffer->getWidth(); + auto height = _vBlurBuffer->getHeight(); + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); + _vBlurTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); + + // Good to go add the brand new pipeline + _vBlurPipeline.reset(gpu::Pipeline::create(program, state)); + } + return _vBlurPipeline; +} + +const gpu::PipelinePointer& AmbientOcclusion::getHBlurPipeline() { + if (!_hBlurPipeline) { + auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(gaussian_blur_horizontal_vert))); + auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(gaussian_blur_frag))); + gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + + gpu::Shader::BindingSet slotBindings; + gpu::Shader::makeProgram(*program, slotBindings); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + + state->setDepthTest(false, false, gpu::LESS_EQUAL); + + // Blend on transparent + state->setBlendFunction(false, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); + + // Link the horizontal blur FBO to texture + _hBlurBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, + DependencyManager::get()->getFrameBufferSize().width(), DependencyManager::get()->getFrameBufferSize().height())); + auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); + auto width = _hBlurBuffer->getWidth(); + auto height = _hBlurBuffer->getHeight(); + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); + _hBlurTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); + + // Good to go add the brand new pipeline + _hBlurPipeline.reset(gpu::Pipeline::create(program, state)); + } + return _hBlurPipeline; } void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) { @@ -226,18 +305,57 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); batch.setModelTransform(Transform()); - batch.setResourceTexture(0, DependencyManager::get()->getPrimaryDepthTexture()); - // bind the one gpu::Pipeline we need - batch.setPipeline(getAOPipeline()); + // Occlusion step + getOcclusionPipeline(); + batch.setResourceTexture(0, DependencyManager::get()->getPrimaryDepthTexture()); + _occlusionBuffer->setRenderBuffer(0, _occlusionTexture); + batch.setFramebuffer(_occlusionBuffer); + + // bind the first gpu::Pipeline we need - for calculating occlusion buffer + batch.setPipeline(getOcclusionPipeline()); glm::vec4 color(0.0f, 0.0f, 0.0f, 1.0f); - glm::vec2 bottomLeft(0.5f, -1.0f); - glm::vec2 topRight(1.0f, -0.5f); + glm::vec2 bottomLeft(-1.0f, -1.0f); + glm::vec2 topRight(1.0f, 1.0f); glm::vec2 texCoordTopLeft(0.0f, 0.0f); glm::vec2 texCoordBottomRight(1.0f, 1.0f); DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); + // Vertical blur step + getVBlurPipeline(); + batch.setResourceTexture(0, _occlusionTexture); + _vBlurBuffer->setRenderBuffer(0, _vBlurTexture); + batch.setFramebuffer(_vBlurBuffer); + + // bind the second gpu::Pipeline we need - for calculating blur buffer + batch.setPipeline(getVBlurPipeline()); + + DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); + + // Horizontal blur step + getHBlurPipeline(); + batch.setResourceTexture(0, _vBlurTexture); + _hBlurBuffer->setRenderBuffer(0, _hBlurTexture); + batch.setFramebuffer(_hBlurBuffer); + + // bind the second gpu::Pipeline we need - for calculating blur buffer + batch.setPipeline(getHBlurPipeline()); + + DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); + + // "Blend" step + batch.setResourceTexture(0, _hBlurTexture); + batch.setFramebuffer(DependencyManager::get()->getPrimaryFramebuffer()); + + // bind the second gpu::Pipeline we need + batch.setPipeline(getOcclusionPipeline()); + + glm::vec2 bottomLeftSmall(0.5f, -1.0f); + glm::vec2 topRightSmall(1.0f, -0.5f); + DependencyManager::get()->renderQuad(batch, bottomLeftSmall, topRightSmall, texCoordTopLeft, texCoordBottomRight, color); + + // Ready to render args->_context->syncCache(); renderContext->args->_context->syncCache(); args->_context->render((batch)); @@ -247,4 +365,3 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons } - diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index fbe4a09214..8fce5e3d0c 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -22,6 +22,7 @@ class ProgramObject; /// A screen space ambient occlusion effect. See John Chapman's tutorial at /// http://john-chapman-graphics.blogspot.co.uk/2013/01/ssao-tutorial.html for reference. +/* class AmbientOcclusionEffect : public Dependency { SINGLETON_DEPENDENCY @@ -53,6 +54,7 @@ private: GLuint _rotationTextureID; AbstractViewStateInterface* _viewState; }; +*/ class AmbientOcclusion { public: @@ -62,11 +64,23 @@ public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); typedef render::Job::Model JobModel; - const gpu::PipelinePointer& AmbientOcclusion::getAOPipeline(); + const gpu::PipelinePointer& AmbientOcclusion::getOcclusionPipeline(); + const gpu::PipelinePointer& AmbientOcclusion::getHBlurPipeline(); + const gpu::PipelinePointer& AmbientOcclusion::getVBlurPipeline(); private: - gpu::PipelinePointer _AOPipeline; + gpu::PipelinePointer _occlusionPipeline; + gpu::PipelinePointer _hBlurPipeline; + gpu::PipelinePointer _vBlurPipeline; + + gpu::FramebufferPointer _occlusionBuffer; + gpu::FramebufferPointer _hBlurBuffer; + gpu::FramebufferPointer _vBlurBuffer; + + gpu::TexturePointer _occlusionTexture; + gpu::TexturePointer _hBlurTexture; + gpu::TexturePointer _vBlurTexture; }; #endif // hifi_AmbientOcclusionEffect_h diff --git a/libraries/render-utils/src/ambient_occlusion.slf b/libraries/render-utils/src/ambient_occlusion.slf index b56e0eb9d5..bdeb59e82a 100644 --- a/libraries/render-utils/src/ambient_occlusion.slf +++ b/libraries/render-utils/src/ambient_occlusion.slf @@ -14,9 +14,6 @@ <@include DeferredBufferWrite.slh@> -// the interpolated normal -//varying vec4 interpolatedNormal; - varying vec2 varTexcoord; uniform sampler2D depthTexture; diff --git a/libraries/render-utils/src/ambient_occlusion.slv b/libraries/render-utils/src/ambient_occlusion.slv index 54cc608129..81f196dd46 100644 --- a/libraries/render-utils/src/ambient_occlusion.slv +++ b/libraries/render-utils/src/ambient_occlusion.slv @@ -16,11 +16,9 @@ <$declareStandardTransform()$> -// the interpolated normal -//varying vec4 interpolatedNormal; varying vec2 varTexcoord; void main(void) { varTexcoord = gl_MultiTexCoord0.xy; gl_Position = gl_Vertex; -} \ No newline at end of file +} diff --git a/libraries/render-utils/src/gaussian_blur.slf b/libraries/render-utils/src/gaussian_blur.slf new file mode 100644 index 0000000000..5b66a0b751 --- /dev/null +++ b/libraries/render-utils/src/gaussian_blur.slf @@ -0,0 +1,42 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// gaussian_blur.frag +// fragment shader +// +// Created by Niraj Venkat on 7/17/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 DeferredBufferWrite.slh@> + +// the interpolated normal +//varying vec4 interpolatedNormal; + +varying vec2 varTexcoord; +varying vec2 varBlurTexcoords[14]; + +uniform sampler2D occlusionTexture; + +void main(void) { + gl_FragColor = vec4(0.0); + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 0])*0.0044299121055113265; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 1])*0.00895781211794; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 2])*0.0215963866053; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 3])*0.0443683338718; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 4])*0.0776744219933; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 5])*0.115876621105; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 6])*0.147308056121; + gl_FragColor += texture2D(occlusionTexture, varTexcoord )*0.159576912161; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 7])*0.147308056121; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 8])*0.115876621105; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 9])*0.0776744219933; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[10])*0.0443683338718; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[11])*0.0215963866053; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[12])*0.00895781211794; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[13])*0.0044299121055113265; +} diff --git a/libraries/render-utils/src/gaussian_blur_horizontal.slv b/libraries/render-utils/src/gaussian_blur_horizontal.slv new file mode 100644 index 0000000000..94631b4b08 --- /dev/null +++ b/libraries/render-utils/src/gaussian_blur_horizontal.slv @@ -0,0 +1,41 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// guassian_blur_horizontal.vert +// vertex shader +// +// Created by Niraj Venkat on 7/17/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 gpu/Transform.slh@> + +<$declareStandardTransform()$> + +varying vec2 varTexcoord; +varying vec2 varBlurTexcoords[14]; + +void main(void) { + varTexcoord = gl_MultiTexCoord0.xy; + gl_Position = gl_Vertex; + + varBlurTexcoords[ 0] = varTexcoord + vec2(-0.028, 0.0); + varBlurTexcoords[ 1] = varTexcoord + vec2(-0.024, 0.0); + varBlurTexcoords[ 2] = varTexcoord + vec2(-0.020, 0.0); + varBlurTexcoords[ 3] = varTexcoord + vec2(-0.016, 0.0); + varBlurTexcoords[ 4] = varTexcoord + vec2(-0.012, 0.0); + varBlurTexcoords[ 5] = varTexcoord + vec2(-0.008, 0.0); + varBlurTexcoords[ 6] = varTexcoord + vec2(-0.004, 0.0); + varBlurTexcoords[ 7] = varTexcoord + vec2( 0.004, 0.0); + varBlurTexcoords[ 8] = varTexcoord + vec2( 0.008, 0.0); + varBlurTexcoords[ 9] = varTexcoord + vec2( 0.012, 0.0); + varBlurTexcoords[10] = varTexcoord + vec2( 0.016, 0.0); + varBlurTexcoords[11] = varTexcoord + vec2( 0.020, 0.0); + varBlurTexcoords[12] = varTexcoord + vec2( 0.024, 0.0); + varBlurTexcoords[13] = varTexcoord + vec2( 0.028, 0.0); +} + \ No newline at end of file diff --git a/libraries/render-utils/src/gaussian_blur_vertical.slv b/libraries/render-utils/src/gaussian_blur_vertical.slv new file mode 100644 index 0000000000..0d6de35b85 --- /dev/null +++ b/libraries/render-utils/src/gaussian_blur_vertical.slv @@ -0,0 +1,41 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// guassian_blur_vertical.vert +// vertex shader +// +// Created by Niraj Venkat on 7/17/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 gpu/Transform.slh@> + +<$declareStandardTransform()$> + +varying vec2 varTexcoord; +varying vec2 varBlurTexcoords[14]; + +void main(void) { + varTexcoord = gl_MultiTexCoord0.xy; + gl_Position = gl_Vertex; + + varBlurTexcoords[ 0] = varTexcoord + vec2(0.0, -0.028); + varBlurTexcoords[ 1] = varTexcoord + vec2(0.0, -0.024); + varBlurTexcoords[ 2] = varTexcoord + vec2(0.0, -0.020); + varBlurTexcoords[ 3] = varTexcoord + vec2(0.0, -0.016); + varBlurTexcoords[ 4] = varTexcoord + vec2(0.0, -0.012); + varBlurTexcoords[ 5] = varTexcoord + vec2(0.0, -0.008); + varBlurTexcoords[ 6] = varTexcoord + vec2(0.0, -0.004); + varBlurTexcoords[ 7] = varTexcoord + vec2(0.0, 0.004); + varBlurTexcoords[ 8] = varTexcoord + vec2(0.0, 0.008); + varBlurTexcoords[ 9] = varTexcoord + vec2(0.0, 0.012); + varBlurTexcoords[10] = varTexcoord + vec2(0.0, 0.016); + varBlurTexcoords[11] = varTexcoord + vec2(0.0, 0.020); + varBlurTexcoords[12] = varTexcoord + vec2(0.0, 0.024); + varBlurTexcoords[13] = varTexcoord + vec2(0.0, 0.028); +} + \ No newline at end of file From 1d48eeab10085969028092d2d0ffcaf1334a673f Mon Sep 17 00:00:00 2001 From: "Kevin M. Thomas" Date: Sat, 18 Jul 2015 18:32:39 -0400 Subject: [PATCH 15/58] commit 20485 --- examples/afk.js | 120 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 examples/afk.js diff --git a/examples/afk.js b/examples/afk.js new file mode 100644 index 0000000000..5e0c443e11 --- /dev/null +++ b/examples/afk.js @@ -0,0 +1,120 @@ +// +// #20485: AFK - Away From Keyboard Setting +// ***************************************** +// +// Created by Kevin M. Thomas and Thoys 07/16/15. +// Copyright 2015 High Fidelity, Inc. +// kevintown.net +// +// JavaScript for the High Fidelity interface that creates an away from keyboard functionality by providing a UI and keyPressEvent which will mute toggle the connected microphone, face tracking dde and set the avatar to a hand raise pose. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +var originalOutputDevice; +var originalName; +var muted = false; +var wasAudioEnabled; +var afkText = "AFK - I Will Return!\n"; + +// Set up toggleMuteButton text overlay. +var toggleMuteButton = Overlays.addOverlay("text", { + x: 10, + y: 275, + width: 60, + height: 28, + backgroundColor: { red: 0, green: 0, blue: 0}, + color: { red: 255, green: 255, blue: 0}, + font: {size: 15}, + topMargin: 8 +}); + +// Function that overlays text upon state change. +function onMuteStateChanged() { + Overlays.editOverlay(toggleMuteButton, muted ? {text: "Go Live", leftMargin: 5} : {text: "Go AFK", leftMargin: 5}); +} + +// Function that adds mousePressEvent functionality to toggle mic mute, AFK message above display name and toggle avatar arms upward. +function mousePressEvent(event) { + if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleMuteButton) { + if (!muted) { + if (!AudioDevice.getMuted()) { + AudioDevice.toggleMute(); + } + originalOutputDevice = AudioDevice.getOutputDevice(); + Menu.setIsOptionChecked("Mute Face Tracking", true); + originalName = MyAvatar.displayName; + AudioDevice.setOutputDevice("none"); + MyAvatar.displayName = afkText + MyAvatar.displayName; + MyAvatar.setJointData("LeftShoulder", Quat.fromPitchYawRollDegrees(0, 180, 0)); + MyAvatar.setJointData("RightShoulder", Quat.fromPitchYawRollDegrees(0, 180, 0)); + } else { + if (AudioDevice.getMuted()) { + AudioDevice.toggleMute(); + } + AudioDevice.setOutputDevice(originalOutputDevice); + Menu.setIsOptionChecked("Mute Face Tracking", false); + MyAvatar.setJointData("LeftShoulder", Quat.fromPitchYawRollDegrees(0, 0, 0)); + MyAvatar.setJointData("RightShoulder", Quat.fromPitchYawRollDegrees(0, 0, 0)); + MyAvatar.clearJointData("LeftShoulder"); + MyAvatar.clearJointData("RightShoulder"); + MyAvatar.displayName = originalName; + } + onMuteStateChanged(); + muted = !muted; + } +} + +// Call functions. +onMuteStateChanged(); + +//AudioDevice.muteToggled.connect(onMuteStateChanged); +Controller.mousePressEvent.connect(mousePressEvent); + +// Function that adds keyPressEvent functionality to toggle mic mute, AFK message above display name and toggle avatar arms upward. +Controller.keyPressEvent.connect(function(event) { + if (event.text == "y") { + if (!muted) { + if (!AudioDevice.getMuted()) { + AudioDevice.toggleMute(); + } + originalOutputDevice = AudioDevice.getOutputDevice(); + Menu.setIsOptionChecked("Mute Face Tracking", true); + originalName = MyAvatar.displayName; + AudioDevice.setOutputDevice("none"); + MyAvatar.displayName = afkText + MyAvatar.displayName; + MyAvatar.setJointData("LeftShoulder", Quat.fromPitchYawRollDegrees(0, 180, 0)); + MyAvatar.setJointData("RightShoulder", Quat.fromPitchYawRollDegrees(0, 180, 0)); + } else { + if (AudioDevice.getMuted()) { + AudioDevice.toggleMute(); + } + AudioDevice.setOutputDevice(originalOutputDevice); + Menu.setIsOptionChecked("Mute Face Tracking", false); + MyAvatar.setJointData("LeftShoulder", Quat.fromPitchYawRollDegrees(0, 0, 0)); + MyAvatar.setJointData("RightShoulder", Quat.fromPitchYawRollDegrees(0, 0, 0)); + MyAvatar.clearJointData("LeftShoulder"); + MyAvatar.clearJointData("RightShoulder"); + MyAvatar.displayName = originalName; + } + onMuteStateChanged(); + muted = !muted; + } +}); + +// Function that sets a timeout value of 1 second so that the display name does not get overwritten in the event of a crash. +Script.setTimeout(function() { + MyAvatar.displayName = MyAvatar.displayName.replace(afkText, ""); +}, 1000); + +// Function that calls upon exit to restore avatar display name to original state. +Script.scriptEnding.connect(function(){ + if (muted) { + AudioDevice.setOutputDevice(originalOutputDevice); + Overlays.deleteOverlay(toggleMuteButton); + MyAvatar.displayName = originalName; + } + Overlays.deleteOverlay(toggleMuteButton); +}); \ No newline at end of file From eb48aa10185e8b5323ea2b3e2365fd1b6259e43d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Sun, 19 Jul 2015 12:10:37 -0700 Subject: [PATCH 16/58] Update edit.js to swing up on activate --- examples/libraries/entityCameraTool.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/libraries/entityCameraTool.js b/examples/libraries/entityCameraTool.js index d27d95c161..a3b817e300 100644 --- a/examples/libraries/entityCameraTool.js +++ b/examples/libraries/entityCameraTool.js @@ -141,7 +141,7 @@ CameraManager = function() { // Pick a point INITIAL_ZOOM_DISTANCE in front of the camera to use as a focal point that.zoomDistance = INITIAL_ZOOM_DISTANCE; - that.targetZoomDistance = that.zoomDistance; + that.targetZoomDistance = that.zoomDistance + 3.0; var focalPoint = Vec3.sum(Camera.getPosition(), Vec3.multiply(that.zoomDistance, Quat.getFront(Camera.getOrientation()))); @@ -150,6 +150,7 @@ CameraManager = function() { var xzDist = Math.sqrt(dPos.x * dPos.x + dPos.z * dPos.z); that.targetPitch = -Math.atan2(dPos.y, xzDist) * 180 / Math.PI; + that.targetPitch += (90 - that.targetPitch) / 3.0; // Swing camera "up" to look down at the focal point that.targetYaw = Math.atan2(dPos.x, dPos.z) * 180 / Math.PI; that.pitch = that.targetPitch; that.yaw = that.targetYaw; From 48524b1c98999326b4b25ee782e16e107a851124 Mon Sep 17 00:00:00 2001 From: "Kevin M. Thomas" Date: Sun, 19 Jul 2015 18:22:58 -0400 Subject: [PATCH 17/58] Reverted changes from other PR. --- libraries/audio-client/src/AudioClient.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 3a85adbc97..aeea7c07c1 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -55,9 +55,9 @@ static const int NUM_AUDIO_CHANNELS = 2; -static const int DEFAULT_AUDIO_OUTPUT_BUFFER_SIZE_FRAMES = 20; +static const int DEFAULT_AUDIO_OUTPUT_BUFFER_SIZE_FRAMES = 3; static const int MIN_AUDIO_OUTPUT_BUFFER_SIZE_FRAMES = 1; -static const int MAX_AUDIO_OUTPUT_BUFFER_SIZE_FRAMES = 40; +static const int MAX_AUDIO_OUTPUT_BUFFER_SIZE_FRAMES = 20; #if defined(Q_OS_ANDROID) || defined(Q_OS_WIN) static const int DEFAULT_AUDIO_OUTPUT_STARVE_DETECTION_ENABLED = false; #else From 8ec51f981464eac0dbde60eae033c3ae1092629d Mon Sep 17 00:00:00 2001 From: "Kevin M. Thomas" Date: Sun, 19 Jul 2015 18:24:29 -0400 Subject: [PATCH 18/58] Updated afk.js file based on advise from PR. --- examples/afk.js | 80 +++++++++++++++++++------------------------------ 1 file changed, 30 insertions(+), 50 deletions(-) diff --git a/examples/afk.js b/examples/afk.js index 5e0c443e11..5977c6384a 100644 --- a/examples/afk.js +++ b/examples/afk.js @@ -36,34 +36,38 @@ function onMuteStateChanged() { Overlays.editOverlay(toggleMuteButton, muted ? {text: "Go Live", leftMargin: 5} : {text: "Go AFK", leftMargin: 5}); } +function toggleMute() { + if (!muted) { + if (!AudioDevice.getMuted()) { + AudioDevice.toggleMute(); + } + originalOutputDevice = AudioDevice.getOutputDevice(); + Menu.setIsOptionChecked("Mute Face Tracking", true); + originalName = MyAvatar.displayName; + AudioDevice.setOutputDevice("none"); + MyAvatar.displayName = afkText + MyAvatar.displayName; + MyAvatar.setJointData("LeftShoulder", Quat.fromPitchYawRollDegrees(0, 180, 0)); + MyAvatar.setJointData("RightShoulder", Quat.fromPitchYawRollDegrees(0, 180, 0)); + } else { + if (AudioDevice.getMuted()) { + AudioDevice.toggleMute(); + } + AudioDevice.setOutputDevice(originalOutputDevice); + Menu.setIsOptionChecked("Mute Face Tracking", false); + MyAvatar.setJointData("LeftShoulder", Quat.fromPitchYawRollDegrees(0, 0, 0)); + MyAvatar.setJointData("RightShoulder", Quat.fromPitchYawRollDegrees(0, 0, 0)); + MyAvatar.clearJointData("LeftShoulder"); + MyAvatar.clearJointData("RightShoulder"); + MyAvatar.displayName = originalName; + } + muted = !muted; + onMuteStateChanged(); +} + // Function that adds mousePressEvent functionality to toggle mic mute, AFK message above display name and toggle avatar arms upward. function mousePressEvent(event) { if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleMuteButton) { - if (!muted) { - if (!AudioDevice.getMuted()) { - AudioDevice.toggleMute(); - } - originalOutputDevice = AudioDevice.getOutputDevice(); - Menu.setIsOptionChecked("Mute Face Tracking", true); - originalName = MyAvatar.displayName; - AudioDevice.setOutputDevice("none"); - MyAvatar.displayName = afkText + MyAvatar.displayName; - MyAvatar.setJointData("LeftShoulder", Quat.fromPitchYawRollDegrees(0, 180, 0)); - MyAvatar.setJointData("RightShoulder", Quat.fromPitchYawRollDegrees(0, 180, 0)); - } else { - if (AudioDevice.getMuted()) { - AudioDevice.toggleMute(); - } - AudioDevice.setOutputDevice(originalOutputDevice); - Menu.setIsOptionChecked("Mute Face Tracking", false); - MyAvatar.setJointData("LeftShoulder", Quat.fromPitchYawRollDegrees(0, 0, 0)); - MyAvatar.setJointData("RightShoulder", Quat.fromPitchYawRollDegrees(0, 0, 0)); - MyAvatar.clearJointData("LeftShoulder"); - MyAvatar.clearJointData("RightShoulder"); - MyAvatar.displayName = originalName; - } - onMuteStateChanged(); - muted = !muted; + toggleMute(); } } @@ -76,31 +80,7 @@ Controller.mousePressEvent.connect(mousePressEvent); // Function that adds keyPressEvent functionality to toggle mic mute, AFK message above display name and toggle avatar arms upward. Controller.keyPressEvent.connect(function(event) { if (event.text == "y") { - if (!muted) { - if (!AudioDevice.getMuted()) { - AudioDevice.toggleMute(); - } - originalOutputDevice = AudioDevice.getOutputDevice(); - Menu.setIsOptionChecked("Mute Face Tracking", true); - originalName = MyAvatar.displayName; - AudioDevice.setOutputDevice("none"); - MyAvatar.displayName = afkText + MyAvatar.displayName; - MyAvatar.setJointData("LeftShoulder", Quat.fromPitchYawRollDegrees(0, 180, 0)); - MyAvatar.setJointData("RightShoulder", Quat.fromPitchYawRollDegrees(0, 180, 0)); - } else { - if (AudioDevice.getMuted()) { - AudioDevice.toggleMute(); - } - AudioDevice.setOutputDevice(originalOutputDevice); - Menu.setIsOptionChecked("Mute Face Tracking", false); - MyAvatar.setJointData("LeftShoulder", Quat.fromPitchYawRollDegrees(0, 0, 0)); - MyAvatar.setJointData("RightShoulder", Quat.fromPitchYawRollDegrees(0, 0, 0)); - MyAvatar.clearJointData("LeftShoulder"); - MyAvatar.clearJointData("RightShoulder"); - MyAvatar.displayName = originalName; - } - onMuteStateChanged(); - muted = !muted; + toggleMute(); } }); From d76d380512c1f2cc17f125b0cffe35654fbb106d Mon Sep 17 00:00:00 2001 From: "Kevin M. Thomas" Date: Mon, 20 Jul 2015 14:19:16 -0400 Subject: [PATCH 19/58] Added jsstreamplayer. --- examples/html/jsstreamplayer.html | 42 +++++++++ examples/jsstreamplayer.js | 137 ++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+) create mode 100644 examples/html/jsstreamplayer.html create mode 100644 examples/jsstreamplayer.js diff --git a/examples/html/jsstreamplayer.html b/examples/html/jsstreamplayer.html new file mode 100644 index 0000000000..7cf827309c --- /dev/null +++ b/examples/html/jsstreamplayer.html @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/jsstreamplayer.js b/examples/jsstreamplayer.js new file mode 100644 index 0000000000..05ebc7d968 --- /dev/null +++ b/examples/jsstreamplayer.js @@ -0,0 +1,137 @@ +// +// #20622: JS Stream Player +// ************************* +// +// Created by Kevin M. Thomas and Thoys 07/17/15. +// Copyright 2015 High Fidelity, Inc. +// kevintown.net +// +// JavaScript for the High Fidelity interface that creates a stream player with a UI and keyPressEvents for adding a stream URL in addition to play, stop and volume functionality. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +// Declare variables and set up new WebWindow. +var stream; +var volume = 1; +var streamWindow = new WebWindow('Stream', "https://dl.dropboxusercontent.com/u/17344741/jsstreamplayer/jsstreamplayer.html", 0, 0, false); + +// Set up toggleStreamURLButton overlay. +var toggleStreamURLButton = Overlays.addOverlay("text", { + x: 76, + y: 275, + width: 40, + height: 28, + backgroundColor: {red: 0, green: 0, blue: 0}, + color: {red: 255, green: 255, blue: 0}, + font: {size: 15}, + topMargin: 8, + text: " URL" +}); + +// Set up toggleStreamPlayButton overlay. +var toggleStreamPlayButton = Overlays.addOverlay("text", { + x: 122, + y: 275, + width: 38, + height: 28, + backgroundColor: { red: 0, green: 0, blue: 0}, + color: { red: 255, green: 255, blue: 0}, + font: {size: 15}, + topMargin: 8, + text: " Play" +}); + +// Set up toggleStreamStopButton overlay. +var toggleStreamStopButton = Overlays.addOverlay("text", { + x: 166, + y: 275, + width: 40, + height: 28, + backgroundColor: { red: 0, green: 0, blue: 0}, + color: { red: 255, green: 255, blue: 0}, + font: {size: 15}, + topMargin: 8, + text: " Stop" +}); + +// Set up increaseVolumeButton overlay. +var toggleIncreaseVolumeButton = Overlays.addOverlay("text", { + x: 211, + y: 275, + width: 18, + height: 28, + backgroundColor: { red: 0, green: 0, blue: 0}, + color: { red: 255, green: 255, blue: 0}, + font: {size: 15}, + topMargin: 8, + text: " +" +}); + +// Set up decreaseVolumeButton overlay. +var toggleDecreaseVolumeButton = Overlays.addOverlay("text", { + x: 234, + y: 275, + width: 15, + height: 28, + backgroundColor: { red: 0, green: 0, blue: 0}, + color: { red: 255, green: 255, blue: 0}, + font: {size: 15}, + topMargin: 8, + text: " -" +}); + +// Function that adds mousePressEvent functionality to connect UI to enter stream URL, play and stop stream. +function mousePressEvent(event) { + if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleStreamURLButton) { + stream = Window.prompt("Enter Stream: "); + var streamJSON = { + action: "changeStream", + stream: stream + } + streamWindow.eventBridge.emitScriptEvent(JSON.stringify(streamJSON)); + } + if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleStreamPlayButton) { + var streamJSON = { + action: "changeStream", + stream: stream + } + streamWindow.eventBridge.emitScriptEvent(JSON.stringify(streamJSON)); + } + if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleStreamStopButton) { + var streamJSON = { + action: "changeStream", + stream: "" + } + streamWindow.eventBridge.emitScriptEvent(JSON.stringify(streamJSON)); + } + if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleIncreaseVolumeButton) { + volume += 0.2; + var volumeJSON = { + action: "changeVolume", + volume: volume + } + streamWindow.eventBridge.emitScriptEvent(JSON.stringify(volumeJSON)); + } + if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleDecreaseVolumeButton) { + volume -= 0.2; + var volumeJSON = { + action: "changeVolume", + volume: volume + } + streamWindow.eventBridge.emitScriptEvent(JSON.stringify(volumeJSON)); + } +} + +// Call function. +Controller.mousePressEvent.connect(mousePressEvent); +streamWindow.setVisible(false); + +// Function to delete overlays upon exit. +function scriptEnding() { + Overlays.deleteOverlay(toggleStreamURLButton); + Overlays.deleteOverlay(toggleStreamPlayButton); + Overlays.deleteOverlay(toggleStreamStopButton); +} \ No newline at end of file From 2c088ec5a98d76f5786439314dcea635c3e7fc4b Mon Sep 17 00:00:00 2001 From: "Kevin M. Thomas" Date: Mon, 20 Jul 2015 14:21:42 -0400 Subject: [PATCH 20/58] Updated overlay clearing functionality. --- examples/jsstreamplayer.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/jsstreamplayer.js b/examples/jsstreamplayer.js index 05ebc7d968..6bd941f677 100644 --- a/examples/jsstreamplayer.js +++ b/examples/jsstreamplayer.js @@ -130,8 +130,13 @@ Controller.mousePressEvent.connect(mousePressEvent); streamWindow.setVisible(false); // Function to delete overlays upon exit. -function scriptEnding() { +function onScriptEnding() { Overlays.deleteOverlay(toggleStreamURLButton); Overlays.deleteOverlay(toggleStreamPlayButton); Overlays.deleteOverlay(toggleStreamStopButton); -} \ No newline at end of file + Overlays.deleteOverlay(toggleIncreaseVolumeButton); + Overlays.deleteOverlay(toggleDecreaseVolumeButton); +} + +// Call function. +Script.scriptEnding.connect(onScriptEnding); \ No newline at end of file From 075c9f05de9a3b340554f1792c35a74288ca7fcd Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Mon, 20 Jul 2015 16:34:02 -0700 Subject: [PATCH 21/58] Introducing blend stage in the AO pipeline --- .../src/AmbientOcclusionEffect.cpp | 47 +++++++++++++++++-- .../render-utils/src/AmbientOcclusionEffect.h | 42 +---------------- .../render-utils/src/ambient_occlusion.slf | 4 +- .../render-utils/src/occlusion_blend.slf | 24 ++++++++++ .../render-utils/src/occlusion_blend.slv | 24 ++++++++++ 5 files changed, 94 insertions(+), 47 deletions(-) create mode 100644 libraries/render-utils/src/occlusion_blend.slf create mode 100644 libraries/render-utils/src/occlusion_blend.slv diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 65d7313efb..a6646d8e4a 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -21,7 +21,6 @@ #include "AbstractViewStateInterface.h" #include "AmbientOcclusionEffect.h" -#include "ProgramObject.h" #include "RenderUtil.h" #include "TextureCache.h" #include "DependencyManager.h" @@ -33,6 +32,8 @@ #include "gaussian_blur_vertical_vert.h" #include "gaussian_blur_horizontal_vert.h" #include "gaussian_blur_frag.h" +#include "occlusion_blend_vert.h" +#include "occlusion_blend_frag.h" const int ROTATION_WIDTH = 4; const int ROTATION_HEIGHT = 4; @@ -187,6 +188,9 @@ const gpu::PipelinePointer& AmbientOcclusion::getOcclusionPipeline() { gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("depthTexture"), 0)); + slotBindings.insert(gpu::Shader::Binding(std::string("normalTexture"), 1)); + gpu::Shader::makeProgram(*program, slotBindings); //_drawItemBoundPosLoc = program->getUniforms().findLocation("inBoundPos"); @@ -282,6 +286,39 @@ const gpu::PipelinePointer& AmbientOcclusion::getHBlurPipeline() { return _hBlurPipeline; } +const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() { + if (!_blendPipeline) { + auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(occlusion_blend_vert))); + auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(occlusion_blend_frag))); + gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + + gpu::Shader::BindingSet slotBindings; + gpu::Shader::makeProgram(*program, slotBindings); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + + state->setDepthTest(false, false, gpu::LESS_EQUAL); + + // Blend on transparent + state->setBlendFunction(true, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); + + // Link the horizontal blur FBO to texture + _hBlurBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, + DependencyManager::get()->getFrameBufferSize().width(), DependencyManager::get()->getFrameBufferSize().height())); + auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); + auto width = _hBlurBuffer->getWidth(); + auto height = _hBlurBuffer->getHeight(); + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); + _hBlurTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); + + // Good to go add the brand new pipeline + _blendPipeline.reset(gpu::Pipeline::create(program, state)); + } + return _blendPipeline; +} + void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) { // create a simple pipeline that does: @@ -308,7 +345,7 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons // Occlusion step getOcclusionPipeline(); batch.setResourceTexture(0, DependencyManager::get()->getPrimaryDepthTexture()); - batch.setResourceTexture(1, DependencyManager::get()->getPrimaryNormalTexture()); + batch.setResourceTexture(1, DependencyManager::get()->getPrimaryFramebuffer()->getRenderBuffer(0)); _occlusionBuffer->setRenderBuffer(0, _occlusionTexture); batch.setFramebuffer(_occlusionBuffer); @@ -339,7 +376,7 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons _hBlurBuffer->setRenderBuffer(0, _hBlurTexture); batch.setFramebuffer(_hBlurBuffer); - // bind the second gpu::Pipeline we need - for calculating blur buffer + // bind the third gpu::Pipeline we need - for calculating blur buffer batch.setPipeline(getHBlurPipeline()); DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); @@ -348,8 +385,8 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons batch.setResourceTexture(0, _hBlurTexture); batch.setFramebuffer(DependencyManager::get()->getPrimaryFramebuffer()); - // bind the second gpu::Pipeline we need - batch.setPipeline(getOcclusionPipeline()); + // bind the fourth gpu::Pipeline we need - for + batch.setPipeline(getBlendPipeline()); glm::vec2 bottomLeftSmall(0.5f, -1.0f); glm::vec2 topRightSmall(1.0f, -0.5f); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index a8ae33b690..d38624f24c 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -16,46 +16,6 @@ #include "render/DrawTask.h" -class AbstractViewStateInterface; -class ProgramObject; - -/// A screen space ambient occlusion effect. See John Chapman's tutorial at -/// http://john-chapman-graphics.blogspot.co.uk/2013/01/ssao-tutorial.html for reference. - -/* -class AmbientOcclusionEffect : public Dependency { - SINGLETON_DEPENDENCY - -public: - - void init(AbstractViewStateInterface* viewState); - - void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); - typedef render::Job::Model JobModel; - - - AmbientOcclusionEffect() {} - virtual ~AmbientOcclusionEffect() {} - -private: - - ProgramObject* _occlusionProgram; - int _nearLocation; - int _farLocation; - int _leftBottomLocation; - int _rightTopLocation; - int _noiseScaleLocation; - int _texCoordOffsetLocation; - int _texCoordScaleLocation; - - ProgramObject* _blurProgram; - int _blurScaleLocation; - - GLuint _rotationTextureID; - AbstractViewStateInterface* _viewState; -}; -*/ - class AmbientOcclusion { public: @@ -67,12 +27,14 @@ public: const gpu::PipelinePointer& getOcclusionPipeline(); const gpu::PipelinePointer& getHBlurPipeline(); const gpu::PipelinePointer& getVBlurPipeline(); + const gpu::PipelinePointer& getBlendPipeline(); private: gpu::PipelinePointer _occlusionPipeline; gpu::PipelinePointer _hBlurPipeline; gpu::PipelinePointer _vBlurPipeline; + gpu::PipelinePointer _blendPipeline; gpu::FramebufferPointer _occlusionBuffer; gpu::FramebufferPointer _hBlurBuffer; diff --git a/libraries/render-utils/src/ambient_occlusion.slf b/libraries/render-utils/src/ambient_occlusion.slf index 4b7d6bfe2b..342f4148d2 100644 --- a/libraries/render-utils/src/ambient_occlusion.slf +++ b/libraries/render-utils/src/ambient_occlusion.slf @@ -40,9 +40,9 @@ void main(void) { float c = (2.0 * n) / (f + n - z * (f - n)); // convert to linear values //gl_FragColor = vec4(c, c, c, 1.0); - gl_FragColor = normalColor; + gl_FragColor = mix(depthColor, normalColor, normalColor.a); //vec3 p = getPosition(i.uv); //vec3 n = getNormal(i.uv); - vec2 rand = vec2(getRandom(varTexcoord.xy), getRandom(varTexcoord.yx)); + //vec2 rand = vec2(getRandom(varTexcoord.xy), getRandom(varTexcoord.yx)); } diff --git a/libraries/render-utils/src/occlusion_blend.slf b/libraries/render-utils/src/occlusion_blend.slf new file mode 100644 index 0000000000..30d3173f90 --- /dev/null +++ b/libraries/render-utils/src/occlusion_blend.slf @@ -0,0 +1,24 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// occlusion_blend.frag +// fragment shader +// +// Created by Niraj Venkat on 7/20/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 DeferredBufferWrite.slh@> + +varying vec2 varTexcoord; + +uniform sampler2D blurredOcclusionTexture; + +void main(void) { + vec4 depthColor = texture2D(blurredOcclusionTexture, varTexcoord.xy); + gl_FragColor = depthColor; +} diff --git a/libraries/render-utils/src/occlusion_blend.slv b/libraries/render-utils/src/occlusion_blend.slv new file mode 100644 index 0000000000..53380a494f --- /dev/null +++ b/libraries/render-utils/src/occlusion_blend.slv @@ -0,0 +1,24 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// occlusion_blend.vert +// vertex shader +// +// Created by Niraj Venkat on 7/20/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 gpu/Transform.slh@> + +<$declareStandardTransform()$> + +varying vec2 varTexcoord; + +void main(void) { + varTexcoord = gl_MultiTexCoord0.xy; + gl_Position = gl_Vertex; +} From 0d0f12164a0c529ebd2cee6e42d6319722b28c27 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 21 Jul 2015 16:57:02 +0200 Subject: [PATCH 22/58] planky, enabling properties button --- examples/example/games/planky.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/example/games/planky.js b/examples/example/games/planky.js index 6733749317..4181eb541e 100644 --- a/examples/example/games/planky.js +++ b/examples/example/games/planky.js @@ -32,7 +32,7 @@ const DEFAULT_BLOCK_YAW_OFFSET = 45; var editMode = false; -const BUTTON_DIMENSIONS = {width: 50, height: 50}; +const BUTTON_DIMENSIONS = {width: 49, height: 49}; const MAXIMUM_PERCENTAGE = 100.0; const NO_ANGLE = 0; const RIGHT_ANGLE = 90; @@ -326,10 +326,11 @@ button = toolBar.addTool({ cogButton = toolBar.addTool({ width: BUTTON_DIMENSIONS.width, height: BUTTON_DIMENSIONS.height, - imageURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/cog.svg', + imageURL: "https://dl.dropboxusercontent.com/u/14997455/hifi/planky/cog.svg", //HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/cog.svg', + subImage: { x: 0, y: BUTTON_DIMENSIONS.height, width: BUTTON_DIMENSIONS.width, height: BUTTON_DIMENSIONS.height }, alpha: 0.8, visible: true -}); +}, true, false); Controller.mousePressEvent.connect(function(event) { var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); @@ -341,6 +342,7 @@ Controller.mousePressEvent.connect(function(event) { editMode = !editMode; plankyStack.refresh(); } else if (toolBar.clicked(clickedOverlay) === cogButton) { + toolBar.selectTool(cogButton, true); settingsWindow.webWindow.setVisible(true); } }); From e0634de4032c7fce30606cf411b5f35ebe935b7f Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Tue, 21 Jul 2015 12:14:09 -0700 Subject: [PATCH 23/58] Turn on/off debug AO from menu item --- interface/src/Application.cpp | 2 ++ interface/src/Menu.h | 2 +- .../render-utils/src/AmbientOcclusionEffect.cpp | 14 ++++++++------ libraries/render-utils/src/RenderDeferredTask.cpp | 8 +++++++- libraries/render-utils/src/RenderDeferredTask.h | 5 +++++ libraries/render-utils/src/ambient_occlusion.slf | 5 +++-- libraries/render/src/render/Engine.h | 2 ++ 7 files changed, 28 insertions(+), 10 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d5ac230f0c..891caa8418 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3336,6 +3336,8 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se renderContext._drawItemStatus = sceneInterface->doEngineDisplayItemStatus(); + renderContext._occlusionStatus = Menu::getInstance()->isOptionChecked(MenuOption::AmbientOcclusion); + renderArgs->_shouldRender = LODManager::shouldRender; renderContext.args = renderArgs; diff --git a/interface/src/Menu.h b/interface/src/Menu.h index b6c2e47329..c8685fe714 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -134,7 +134,7 @@ namespace MenuOption { const QString AddressBar = "Show Address Bar"; const QString AlignForearmsWithWrists = "Align Forearms with Wrists"; const QString AlternateIK = "Alternate IK"; - const QString AmbientOcclusion = "Ambient Occlusion"; + const QString AmbientOcclusion = "Debug Ambient Occlusion"; const QString Animations = "Animations..."; const QString Atmosphere = "Atmosphere"; const QString Attachments = "Attachments..."; diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index a6646d8e4a..2b1113d61b 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -193,8 +193,10 @@ const gpu::PipelinePointer& AmbientOcclusion::getOcclusionPipeline() { gpu::Shader::makeProgram(*program, slotBindings); - //_drawItemBoundPosLoc = program->getUniforms().findLocation("inBoundPos"); - //_drawItemBoundDimLoc = program->getUniforms().findLocation("inBoundDim"); + _gScaleLoc = program->getUniforms().findLocation("g_scale"); + _gBiasLoc = program->getUniforms().findLocation("g_bias"); + _gSampleRadiusLoc = program->getUniforms().findLocation("g_sample_rad"); + _gIntensityLoc = program->getUniforms().findLocation("g_intensity"); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); @@ -345,7 +347,7 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons // Occlusion step getOcclusionPipeline(); batch.setResourceTexture(0, DependencyManager::get()->getPrimaryDepthTexture()); - batch.setResourceTexture(1, DependencyManager::get()->getPrimaryFramebuffer()->getRenderBuffer(0)); + batch.setResourceTexture(1, DependencyManager::get()->getPrimaryNormalTexture()); _occlusionBuffer->setRenderBuffer(0, _occlusionTexture); batch.setFramebuffer(_occlusionBuffer); @@ -380,12 +382,12 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons batch.setPipeline(getHBlurPipeline()); DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); - + // "Blend" step - batch.setResourceTexture(0, _hBlurTexture); + batch.setResourceTexture(0, _occlusionTexture); batch.setFramebuffer(DependencyManager::get()->getPrimaryFramebuffer()); - // bind the fourth gpu::Pipeline we need - for + // bind the fourth gpu::Pipeline we need - for blending the primary framefuffer with blurred occlusion texture batch.setPipeline(getBlendPipeline()); glm::vec2 bottomLeftSmall(0.5f, -1.0f); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 1ab8a4ce01..eea343972e 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -61,6 +61,10 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _jobs.push_back(Job(new RenderDeferred::JobModel("RenderDeferred"))); _jobs.push_back(Job(new ResolveDeferred::JobModel("ResolveDeferred"))); _jobs.push_back(Job(new AmbientOcclusion::JobModel("AmbientOcclusion"))); + + _jobs.back().setEnabled(false); + _occlusionJobIndex = _jobs.size() - 1; + _jobs.push_back(Job(new FetchItems::JobModel("FetchTransparent", FetchItems( ItemFilter::Builder::transparentShape().withoutLayered(), @@ -79,7 +83,6 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _jobs.back().setEnabled(false); _drawStatusJobIndex = _jobs.size() - 1; - //_jobs.push_back(Job(new AmbientOcclusion::JobModel("AmbientOcclusion"))); _jobs.push_back(Job(new DrawOverlay3D::JobModel("DrawOverlay3D"))); _jobs.push_back(Job(new ResetGLState::JobModel())); @@ -110,6 +113,9 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend // Make sure we turn the displayItemStatus on/off setDrawItemStatus(renderContext->_drawItemStatus); + // TODO: turn on/off AO through menu item + setOcclusionStatus(renderContext->_occlusionStatus); + renderContext->args->_context->syncCache(); for (auto job : _jobs) { diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 4040606c62..5c9764eb52 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -75,6 +75,11 @@ public: void setDrawItemStatus(bool draw) { if (_drawStatusJobIndex >= 0) { _jobs[_drawStatusJobIndex].setEnabled(draw); } } bool doDrawItemStatus() const { if (_drawStatusJobIndex >= 0) { return _jobs[_drawStatusJobIndex].isEnabled(); } else { return false; } } + int _occlusionJobIndex = -1; + + void setOcclusionStatus(bool draw) { if (_occlusionJobIndex >= 0) { _jobs[_occlusionJobIndex].setEnabled(draw); } } + bool doOcclusionStatus() const { if (_occlusionJobIndex >= 0) { return _jobs[_occlusionJobIndex].isEnabled(); } else { return false; } } + virtual void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); diff --git a/libraries/render-utils/src/ambient_occlusion.slf b/libraries/render-utils/src/ambient_occlusion.slf index 342f4148d2..10b687ad1f 100644 --- a/libraries/render-utils/src/ambient_occlusion.slf +++ b/libraries/render-utils/src/ambient_occlusion.slf @@ -39,8 +39,9 @@ void main(void) { float f = 30.0; // the far plane float c = (2.0 * n) / (f + n - z * (f - n)); // convert to linear values - //gl_FragColor = vec4(c, c, c, 1.0); - gl_FragColor = mix(depthColor, normalColor, normalColor.a); + vec4 linearizedDepthColor = vec4(c, c, c, 1.0); + gl_FragColor = mix(linearizedDepthColor, normalColor, 0.5); + //gl_FragColor = linearizedDepthColor; //vec3 p = getPosition(i.uv); //vec3 n = getNormal(i.uv); diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index 1c600b13d6..5bfece96cc 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -51,6 +51,8 @@ public: bool _drawItemStatus = false; + bool _occlusionStatus = false; + RenderContext() {} }; typedef std::shared_ptr RenderContextPointer; From cd58dc11ceb92bf3a4c0e959a41f2ddaeb3a0f7c Mon Sep 17 00:00:00 2001 From: "Kevin M. Thomas" Date: Tue, 21 Jul 2015 18:10:13 -0400 Subject: [PATCH 24/58] Initial file placement into job. --- .../jsstreamplayerdomain-zone-entity.js | 33 +++ examples/example/jsstreamplayerdomain-zone.js | 203 ++++++++++++++++++ examples/html/jsstreamplayerdomain-zone.html | 42 ++++ 3 files changed, 278 insertions(+) create mode 100644 examples/example/entities/jsstreamplayerdomain-zone-entity.js create mode 100644 examples/example/jsstreamplayerdomain-zone.js create mode 100644 examples/html/jsstreamplayerdomain-zone.html diff --git a/examples/example/entities/jsstreamplayerdomain-zone-entity.js b/examples/example/entities/jsstreamplayerdomain-zone-entity.js new file mode 100644 index 0000000000..9a8cb8b8b4 --- /dev/null +++ b/examples/example/entities/jsstreamplayerdomain-zone-entity.js @@ -0,0 +1,33 @@ +// +// #20628: JS Stream Player Domain-Zone-Entity +// ******************************************** +// +// Created by Kevin M. Thomas and Thoys 07/20/15. +// Copyright 2015 High Fidelity, Inc. +// kevintown.net +// +// JavaScript for the High Fidelity interface that is an entity script to be placed in a chosen entity inside a domain-zone. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +// Function which exists inside of an entity which triggers as a user approches it. +(function() { + const SCRIPT_NAME = "https://dl.dropboxusercontent.com/u/17344741/jsstreamplayer/jsstreamplayerdomain-zone.js"; + function isScriptRunning(script) { + script = script.toLowerCase().trim(); + var runningScripts = ScriptDiscoveryService.getRunning(); + for (i in runningScripts) { + if (runningScripts[i].url.toLowerCase().trim() == script) { + return true; + } + } + return false; + }; + + if (!isScriptRunning(SCRIPT_NAME)) { + Script.load(SCRIPT_NAME); + } +}) \ No newline at end of file diff --git a/examples/example/jsstreamplayerdomain-zone.js b/examples/example/jsstreamplayerdomain-zone.js new file mode 100644 index 0000000000..fab5792dd7 --- /dev/null +++ b/examples/example/jsstreamplayerdomain-zone.js @@ -0,0 +1,203 @@ +// +// #20628: JS Stream Player Domain-Zone +// ************************************* +// +// Created by Kevin M. Thomas and Thoys 07/20/15. +// Copyright 2015 High Fidelity, Inc. +// kevintown.net +// +// JavaScript for the High Fidelity interface that creates a stream player with a UI for playing a domain-zone specificed stream URL in addition to play, stop and volume functionality which is resident only in the domain-zone. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +// Declare variables and set up new WebWindow. +var stream = "http://listen.radionomy.com/80sMixTape"; +var volume; +var streamWindow = new WebWindow('Stream', "https://dl.dropboxusercontent.com/u/17344741/jsstreamplayer/jsstreamplayerdomain-zone.html", 0, 0, false); +var visible = false; + +// Set up toggleStreamPlayButton overlay. +var toggleStreamPlayButton = Overlays.addOverlay("text", { + x: 122, + y: 310, + width: 38, + height: 28, + backgroundColor: { red: 0, green: 0, blue: 0}, + color: { red: 255, green: 255, blue: 0}, + font: {size: 15}, + topMargin: 8, + visible: false, + text: " Play" +}); + +// Set up toggleStreamStopButton overlay. +var toggleStreamStopButton = Overlays.addOverlay("text", { + x: 166, + y: 310, + width: 40, + height: 28, + backgroundColor: { red: 0, green: 0, blue: 0}, + color: { red: 255, green: 255, blue: 0}, + font: {size: 15}, + topMargin: 8, + visible: false, + text: " Stop" +}); + +// Set up increaseVolumeButton overlay. +var toggleIncreaseVolumeButton = Overlays.addOverlay("text", { + x: 211, + y: 310, + width: 18, + height: 28, + backgroundColor: { red: 0, green: 0, blue: 0}, + color: { red: 255, green: 255, blue: 0}, + font: {size: 15}, + topMargin: 8, + visible: false, + text: " +" +}); + +// Set up decreaseVolumeButton overlay. +var toggleDecreaseVolumeButton = Overlays.addOverlay("text", { + x: 234, + y: 310, + width: 15, + height: 28, + backgroundColor: { red: 0, green: 0, blue: 0}, + color: { red: 255, green: 255, blue: 0}, + font: {size: 15}, + topMargin: 8, + visible: false, + text: " -" +}); + +// Function to change JSON object stream. +function changeStream(stream) { + var streamJSON = { + action: "changeStream", + stream: stream + } + streamWindow.eventBridge.emitScriptEvent(JSON.stringify(streamJSON)); +} + +// Function to change JSON object volume. +function changeVolume(volume) { + var volumeJSON = { + action: "changeVolume", + volume: volume + } + streamWindow.eventBridge.emitScriptEvent(JSON.stringify(volumeJSON)); +} + +// Function that adds mousePressEvent functionality to connect UI to enter stream URL, play and stop stream. +function mousePressEvent(event) { + if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleStreamPlayButton) { + changeStream(stream); + volume = 0.25; + changeVolume(volume); + } + if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleStreamStopButton) { + changeStream(""); + } + if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleIncreaseVolumeButton) { + volume += 0.25; + changeVolume(volume); + } + if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleDecreaseVolumeButton) { + volume -= 0.25; + changeVolume(volume); + } +} + +// Function checking bool if in proper zone. +function isOurZone(properties) { + return properties.type == "Zone" && properties.name == "Zone2"; +} + +// Function checking if avatar is in zone. +function isInZone() { + var entities = Entities.findEntities(MyAvatar.position, 10000); + + for (var i in entities) { + var properties = Entities.getEntityProperties(entities[i]); + + if (isOurZone(properties)) { + var minX = properties.position.x - (properties.dimensions.x / 2); + var maxX = properties.position.x + (properties.dimensions.x / 2); + var minY = properties.position.y - (properties.dimensions.y / 2); + var maxY = properties.position.y + (properties.dimensions.y / 2); + var minZ = properties.position.z - (properties.dimensions.z / 2); + var maxZ = properties.position.z + (properties.dimensions.z / 2); + + if (MyAvatar.position.x >= minX && MyAvatar.position.x <= maxX && MyAvatar.position.y >= minY && MyAvatar.position.y <= maxY && MyAvatar.position.z >= minZ && MyAvatar.position.z <= maxZ) { + return true; + } + } + } + return false; +} + +// Function to toggle visibile the overlay. +function toggleVisible(newVisibility) { + if (newVisibility != visible) { + visible = newVisibility; + Overlays.editOverlay(toggleStreamPlayButton, {visible: visible}); + Overlays.editOverlay(toggleStreamStopButton, {visible: visible}); + Overlays.editOverlay(toggleIncreaseVolumeButton, {visible: visible}); + Overlays.editOverlay(toggleDecreaseVolumeButton, {visible: visible}); + } +} + +// Function to check if avatar is in proper domain. +Window.domainChanged.connect(function() { + if (Window.location.hostname != "Music" && Window.location.hostname != "LiveMusic") { + Script.stop(); + } +}); + +// Function to check if avatar is within zone. +Entities.enterEntity.connect(function(entityID) { + print("Entered..." + JSON.stringify(entityID)); + var properties = Entities.getEntityProperties(entityID); + if (isOurZone(properties)) { + print("Entering Zone!"); + toggleVisible(true); + } +}) + +// Function to check if avatar is leaving zone. +Entities.leaveEntity.connect(function(entityID) { + print("Left..." + JSON.stringify(entityID)); + var properties = Entities.getEntityProperties(entityID); + if (isOurZone(properties)) { + print("Leaving Zone!"); + toggleVisible(false); + changeStream(""); + } +}) + +// Function to delete overlays upon exit. +function onScriptEnding() { + Overlays.deleteOverlay(toggleStreamPlayButton); + Overlays.deleteOverlay(toggleStreamStopButton); + Overlays.deleteOverlay(toggleIncreaseVolumeButton); + Overlays.deleteOverlay(toggleDecreaseVolumeButton); + changeStream(""); + streamWindow.deleteLater(); +} + +// Function call to ensure that if you log in to the zone visibility is true. +if (isInZone()) { + toggleVisible(true); +} + +// Connect mouse and hide WebWindow. +Controller.mousePressEvent.connect(mousePressEvent); +streamWindow.setVisible(false); + +// Call function upon ending script. +Script.scriptEnding.connect(onScriptEnding); \ No newline at end of file diff --git a/examples/html/jsstreamplayerdomain-zone.html b/examples/html/jsstreamplayerdomain-zone.html new file mode 100644 index 0000000000..28b2202591 --- /dev/null +++ b/examples/html/jsstreamplayerdomain-zone.html @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 75fa789b79591b25d6240479d74c671ba2eb0b2d Mon Sep 17 00:00:00 2001 From: "Kevin M. Thomas" Date: Tue, 21 Jul 2015 18:13:26 -0400 Subject: [PATCH 25/58] Changeable zone var declaration. --- examples/example/jsstreamplayerdomain-zone.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/example/jsstreamplayerdomain-zone.js b/examples/example/jsstreamplayerdomain-zone.js index fab5792dd7..543a95b839 100644 --- a/examples/example/jsstreamplayerdomain-zone.js +++ b/examples/example/jsstreamplayerdomain-zone.js @@ -14,6 +14,7 @@ // Declare variables and set up new WebWindow. +var zone = "Zone2"; var stream = "http://listen.radionomy.com/80sMixTape"; var volume; var streamWindow = new WebWindow('Stream', "https://dl.dropboxusercontent.com/u/17344741/jsstreamplayer/jsstreamplayerdomain-zone.html", 0, 0, false); @@ -115,7 +116,7 @@ function mousePressEvent(event) { // Function checking bool if in proper zone. function isOurZone(properties) { - return properties.type == "Zone" && properties.name == "Zone2"; + return properties.type == "Zone" && properties.name == zone; } // Function checking if avatar is in zone. From de116c4e3b35b26f8014641074d84d6f2796d431 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Wed, 22 Jul 2015 10:21:13 +0200 Subject: [PATCH 26/58] editMode on and off switch by clicking the COG, proper removal of planks when rows/columns removed --- examples/example/games/planky.js | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/examples/example/games/planky.js b/examples/example/games/planky.js index 4181eb541e..8abc697353 100644 --- a/examples/example/games/planky.js +++ b/examples/example/games/planky.js @@ -203,20 +203,29 @@ PlankyStack = function() { dimensions: {x: 5, y: 21, z: 5}, position: Vec3.sum(_this.basePosition, {y: -(_this.options.baseDimension.y / 2)}), lineWidth: 7, - color: {red: 214, green: 91, blue: 67}, - linePoints: [{x: 0, y: 0, z: 0}, {x: 0, y: 10, z: 0}] + color: {red: 20, green: 20, blue: 20}, + linePoints: [{x: 0, y: 0, z: 0}, {x: 0, y: 10, z: 0}], + visible: editMode })); return; } + _this.editLines.forEach(function(line) { + Entities.editEntity(line, {visible: editMode}); + }) }; var trimDimension = function(dimension, maxIndex) { + var removingPlanks = []; _this.planks.forEach(function(plank, index, object) { if (plank[dimension] > maxIndex) { - Entities.deleteEntity(plank.entity); - object.splice(index, 1); + removingPlanks.push(index); } }); + removingPlanks.reverse(); + for (var i = 0; i < removingPlanks.length; i++) { + Entities.deleteEntity(_this.planks[removingPlanks[i]].entity); + _this.planks.splice(removingPlanks[i], 1); + } }; var createOrUpdate = function(layer, row) { @@ -237,7 +246,6 @@ PlankyStack = function() { dimensions: Vec3.sum(_this.options.blockSize, {x: 0, y: -((_this.options.blockSize.y * (_this.options.blockHeightVariation / MAXIMUM_PERCENTAGE)) * Math.random()), z: 0}), position: Vec3.sum(_this.basePosition, localTransform), rotation: Quat.multiply(layerRotation, _this.offsetRot), - //collisionsWillMove: false,//!editMode,//false,//!editMode, damping: _this.options.dampingFactor, restitution: _this.options.restitution, friction: _this.options.friction, @@ -282,7 +290,6 @@ PlankyStack = function() { if (!editMode) { _this.planks.forEach(function(plank, index, object) { Entities.editEntity(plank.entity, {ignoreForCollisions: false, collisionsWillMove: true}); - // Entities.editEntity(plank.entity, {collisionsWillMove: true}); }); } }; @@ -326,7 +333,7 @@ button = toolBar.addTool({ cogButton = toolBar.addTool({ width: BUTTON_DIMENSIONS.width, height: BUTTON_DIMENSIONS.height, - imageURL: "https://dl.dropboxusercontent.com/u/14997455/hifi/planky/cog.svg", //HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/cog.svg', + imageURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/cog.svg', subImage: { x: 0, y: BUTTON_DIMENSIONS.height, width: BUTTON_DIMENSIONS.width, height: BUTTON_DIMENSIONS.height }, alpha: 0.8, visible: true @@ -339,11 +346,14 @@ Controller.mousePressEvent.connect(function(event) { plankyStack.rez(); return; } - editMode = !editMode; plankyStack.refresh(); } else if (toolBar.clicked(clickedOverlay) === cogButton) { - toolBar.selectTool(cogButton, true); - settingsWindow.webWindow.setVisible(true); + editMode = !editMode; + toolBar.selectTool(cogButton, editMode); + settingsWindow.webWindow.setVisible(editMode); + if(plankyStack.planks.length) { + plankyStack.refresh(); + } } }); From 3cac781cdca985a1a81891f0af40bab61debba4f Mon Sep 17 00:00:00 2001 From: Bing Shearer Date: Wed, 22 Jul 2015 10:47:27 -0700 Subject: [PATCH 27/58] Fixed indentation and number formats, as well as streamlining calculation of leaf velocity to make it more readable. --- examples/leaves.js | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/examples/leaves.js b/examples/leaves.js index 347371ff5b..e611eb7de6 100755 --- a/examples/leaves.js +++ b/examples/leaves.js @@ -175,7 +175,7 @@ var leafSquall = function (properties) { } Script.setInterval(function () { nearbyEntities = Entities.findEntities(squallOrigin, squallRadius); - newLeafMovement() + newLeafMovement() }, 100); function newLeafMovement() { //new additions to leaf code. Operates at 10 Hz or every 100 ms @@ -193,20 +193,18 @@ var leafSquall = function (properties) { currentLeaf = nearbyEntities[i]; var leafHeight = entityProperties.position.y; if (complexMovement && leafHeight > floorHeight || complexMovement && floorHeight == null) { //actual new movement code; - var currentLeafVelocity = entityProperties.velocity, - currentLeafRot = entityProperties.rotation, + var leafCurrentVel = entityProperties.velocity, + leafCurrentRot = entityProperties.rotation, yVec = { x: 0, y: 1, z: 0 }, - leafYinWFVec = Vec3.multiplyQbyV(currentLeafRot, yVec), + leafYinWFVec = Vec3.multiplyQbyV(leafCurrentRot, yVec), leafLocalHorVec = Vec3.cross(leafYinWFVec, yVec), leafMostDownVec = Vec3.cross(leafYinWFVec, leafLocalHorVec), - leafDesiredVel = Vec3.multiply(leafMostDownVec, windFactor); + leafDesiredVel = Vec3.multiply(leafMostDownVec, windFactor), + leafVelDelt = Vec3.subtract(leafDesiredVel, leafCurrentVel), + leafNewVel = Vec3.sum(leafCurrentVel, Vec3.multiply(leafVelDelt, windFactor)); Entities.editEntity(currentLeaf, { angularVelocity: randomRotationSpeed, - velocity: { - x: (leafDesiredVel.x - currentLeafVelocity.x) * windFactor + currentLeafVelocity.x, - y: (leafDesiredVel.y - currentLeafVelocity.y) * windFactor + currentLeafVelocity.y, - z: (leafDesiredVel.z - currentLeafVelocity.z) * windFactor + currentLeafVelocity.z - } + velocity: leafNewVel }) } else if (leafHeight <= floorHeight) { @@ -274,8 +272,8 @@ var leafSquall1 = new leafSquall({ origin: { x: 3071.5, y: 2170, z: 6765.3 }, radius: 100, leavesPerMinute: 30, - leafSize: { x: 0.3, y: 0.00, z: .3}, - leafFallSpeed: .4, + leafSize: { x: 0.3, y: 0.00, z: 0.3}, + leafFallSpeed: 0.4, leafLifetime: 100, leafSpinMax: 30, debug: false, @@ -283,7 +281,7 @@ var leafSquall1 = new leafSquall({ leafDeleteOnTearDown: true, complexMovement: true, floorHeight: 2143.5, - windFactor: .5, + windFactor: 0.5, leafDeleteOnGround: false }); From 216c499d1472abecc29968bd9f2ba6b0aa7be7ac Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Thu, 23 Jul 2015 18:53:43 -0700 Subject: [PATCH 28/58] HAO (Horrendous Ambient Occlusion) --- .../src/AmbientOcclusionEffect.cpp | 114 ++++++++++++------ .../render-utils/src/AmbientOcclusionEffect.h | 17 +++ .../render-utils/src/ambient_occlusion.slf | 104 ++++++++++++---- .../render-utils/src/occlusion_blend.slf | 13 +- .../render-utils/src/occlusion_result.slf | 23 ++++ 5 files changed, 211 insertions(+), 60 deletions(-) create mode 100644 libraries/render-utils/src/occlusion_result.slf diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 2b1113d61b..e4220243ff 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -2,7 +2,7 @@ // AmbientOcclusionEffect.cpp // interface/src/renderer // -// Created by Andrzej Kapolka on 7/14/13. +// Created by Niraj Venkat on 7/14/13. // Copyright 2013 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. @@ -19,10 +19,11 @@ #include #include -#include "AbstractViewStateInterface.h" +#include "gpu/StandardShaderLib.h" #include "AmbientOcclusionEffect.h" #include "RenderUtil.h" #include "TextureCache.h" +#include "FramebufferCache.h" #include "DependencyManager.h" #include "ViewFrustum.h" #include "GeometryCache.h" @@ -34,9 +35,8 @@ #include "gaussian_blur_frag.h" #include "occlusion_blend_vert.h" #include "occlusion_blend_frag.h" - -const int ROTATION_WIDTH = 4; -const int ROTATION_HEIGHT = 4; +//#include "occlusion_result_vert.h" +#include "occlusion_result_frag.h" /* void AmbientOcclusionEffect::init(AbstractViewStateInterface* viewState) { @@ -197,6 +197,8 @@ const gpu::PipelinePointer& AmbientOcclusion::getOcclusionPipeline() { _gBiasLoc = program->getUniforms().findLocation("g_bias"); _gSampleRadiusLoc = program->getUniforms().findLocation("g_sample_rad"); _gIntensityLoc = program->getUniforms().findLocation("g_intensity"); + _bufferWidthLoc = program->getUniforms().findLocation("bufferWidth"); + _bufferHeightLoc = program->getUniforms().findLocation("bufferHeight"); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); @@ -209,7 +211,7 @@ const gpu::PipelinePointer& AmbientOcclusion::getOcclusionPipeline() { // Link the occlusion FBO to texture _occlusionBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, - DependencyManager::get()->getFrameBufferSize().width(), DependencyManager::get()->getFrameBufferSize().height())); + DependencyManager::get()->getFrameBufferSize().width(), DependencyManager::get()->getFrameBufferSize().height())); auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); auto width = _occlusionBuffer->getWidth(); auto height = _occlusionBuffer->getHeight(); @@ -242,7 +244,7 @@ const gpu::PipelinePointer& AmbientOcclusion::getVBlurPipeline() { // Link the horizontal blur FBO to texture _vBlurBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, - DependencyManager::get()->getFrameBufferSize().width(), DependencyManager::get()->getFrameBufferSize().height())); + DependencyManager::get()->getFrameBufferSize().width(), DependencyManager::get()->getFrameBufferSize().height())); auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); auto width = _vBlurBuffer->getWidth(); auto height = _vBlurBuffer->getHeight(); @@ -275,7 +277,7 @@ const gpu::PipelinePointer& AmbientOcclusion::getHBlurPipeline() { // Link the horizontal blur FBO to texture _hBlurBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, - DependencyManager::get()->getFrameBufferSize().width(), DependencyManager::get()->getFrameBufferSize().height())); + DependencyManager::get()->getFrameBufferSize().width(), DependencyManager::get()->getFrameBufferSize().height())); auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); auto width = _hBlurBuffer->getWidth(); auto height = _hBlurBuffer->getHeight(); @@ -295,6 +297,9 @@ const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() { gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); gpu::Shader::BindingSet slotBindings; + slotBindings.insert(gpu::Shader::Binding(std::string("blurredOcclusionTexture"), 0)); + slotBindings.insert(gpu::Shader::Binding(std::string("colorTexture"), 1)); + gpu::Shader::makeProgram(*program, slotBindings); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); @@ -303,17 +308,16 @@ const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() { // Blend on transparent state->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); - // Link the horizontal blur FBO to texture - _hBlurBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, - DependencyManager::get()->getFrameBufferSize().width(), DependencyManager::get()->getFrameBufferSize().height())); + // Link the blend FBO to texture + _blendBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, + DependencyManager::get()->getFrameBufferSize().width(), DependencyManager::get()->getFrameBufferSize().height())); auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); - auto width = _hBlurBuffer->getWidth(); - auto height = _hBlurBuffer->getHeight(); + auto width = _blendBuffer->getWidth(); + auto height = _blendBuffer->getHeight(); auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); - _hBlurTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); + _blendTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); // Good to go add the brand new pipeline _blendPipeline.reset(gpu::Pipeline::create(program, state)); @@ -321,38 +325,67 @@ const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() { return _blendPipeline; } +const gpu::PipelinePointer& AmbientOcclusion::getAOResultPipeline() { + if (!_AOResultPipeline) { + auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(ambient_occlusion_vert))); + auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(occlusion_result_frag))); + gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + //gpu::ShaderPointer program = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawTransformUnitQuadVS(), gpu::StandardShaderLib::getDrawTexturePS()); + + gpu::Shader::BindingSet slotBindings; + gpu::Shader::makeProgram(*program, slotBindings); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + + state->setDepthTest(false, false, gpu::LESS_EQUAL); + + // Blend on transparent + state->setBlendFunction(false, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); + + // Good to go add the brand new pipeline + _AOResultPipeline.reset(gpu::Pipeline::create(program, state)); + } + return _AOResultPipeline; +} + void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) { - - // create a simple pipeline that does: - assert(renderContext->args); assert(renderContext->args->_viewFrustum); RenderArgs* args = renderContext->args; auto& scene = sceneContext->_scene; - // Allright, something to render let's do it gpu::Batch batch; glm::mat4 projMat; Transform viewMat; args->_viewFrustum->evalProjectionMatrix(projMat); args->_viewFrustum->evalViewTransform(viewMat); - if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) { - viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f)); - } batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); batch.setModelTransform(Transform()); // Occlusion step getOcclusionPipeline(); - batch.setResourceTexture(0, DependencyManager::get()->getPrimaryDepthTexture()); - batch.setResourceTexture(1, DependencyManager::get()->getPrimaryNormalTexture()); + batch.setResourceTexture(0, DependencyManager::get()->getPrimaryDepthTexture()); + batch.setResourceTexture(1, DependencyManager::get()->getPrimaryNormalTexture()); _occlusionBuffer->setRenderBuffer(0, _occlusionTexture); batch.setFramebuffer(_occlusionBuffer); - // bind the first gpu::Pipeline we need - for calculating occlusion buffer + // Occlusion uniforms + g_scale = 1.0f; + g_bias = 1.0f; + g_sample_rad = 1.0f; + g_intensity = 1.0f; + + // Bind the first gpu::Pipeline we need - for calculating occlusion buffer batch.setPipeline(getOcclusionPipeline()); + batch._glUniform1f(_gScaleLoc, g_scale); + batch._glUniform1f(_gBiasLoc, g_bias); + batch._glUniform1f(_gSampleRadiusLoc, g_sample_rad); + batch._glUniform1f(_gIntensityLoc, g_intensity); + batch._glUniform1f(_bufferWidthLoc, DependencyManager::get()->getFrameBufferSize().width()); + batch._glUniform1f(_bufferHeightLoc, DependencyManager::get()->getFrameBufferSize().height()); glm::vec4 color(0.0f, 0.0f, 0.0f, 1.0f); glm::vec2 bottomLeft(-1.0f, -1.0f); @@ -367,7 +400,7 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons _vBlurBuffer->setRenderBuffer(0, _vBlurTexture); batch.setFramebuffer(_vBlurBuffer); - // bind the second gpu::Pipeline we need - for calculating blur buffer + // Bind the second gpu::Pipeline we need - for calculating blur buffer batch.setPipeline(getVBlurPipeline()); DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); @@ -378,29 +411,38 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons _hBlurBuffer->setRenderBuffer(0, _hBlurTexture); batch.setFramebuffer(_hBlurBuffer); - // bind the third gpu::Pipeline we need - for calculating blur buffer + // Bind the third gpu::Pipeline we need - for calculating blur buffer batch.setPipeline(getHBlurPipeline()); DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); - // "Blend" step - batch.setResourceTexture(0, _occlusionTexture); - batch.setFramebuffer(DependencyManager::get()->getPrimaryFramebuffer()); + // Blend step + getBlendPipeline(); + batch.setResourceTexture(0, _hBlurTexture); + batch.setResourceTexture(1, DependencyManager::get()->getPrimaryColorTexture()); + batch.setFramebuffer(_blendBuffer); - // bind the fourth gpu::Pipeline we need - for blending the primary framefuffer with blurred occlusion texture + // Bind the fourth gpu::Pipeline we need - for blending the primary color buffer with blurred occlusion texture batch.setPipeline(getBlendPipeline()); + DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); + + // Final AO result step + getAOResultPipeline(); + batch.setResourceTexture(0, _hBlurTexture); + batch.setFramebuffer(DependencyManager::get()->getPrimaryFramebuffer()); + + // Bind the fifth gpu::Pipeline we need - for displaying the blended texture + batch.setPipeline(getAOResultPipeline()); + glm::vec2 bottomLeftSmall(0.5f, -1.0f); glm::vec2 topRightSmall(1.0f, -0.5f); - DependencyManager::get()->renderQuad(batch, bottomLeftSmall, topRightSmall, texCoordTopLeft, texCoordBottomRight, color); + DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); // Ready to render args->_context->syncCache(); - renderContext->args->_context->syncCache(); args->_context->render((batch)); // need to fetch forom the z buffer and render something in a new render target a result that combine the z and produce a fake AO result - - } diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index d38624f24c..ec0314016c 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -28,21 +28,38 @@ public: const gpu::PipelinePointer& getHBlurPipeline(); const gpu::PipelinePointer& getVBlurPipeline(); const gpu::PipelinePointer& getBlendPipeline(); + const gpu::PipelinePointer& getAOResultPipeline(); private: + // Uniforms for AO + gpu::int32 _gScaleLoc; + gpu::int32 _gBiasLoc; + gpu::int32 _gSampleRadiusLoc; + gpu::int32 _gIntensityLoc; + gpu::int32 _bufferWidthLoc; + gpu::int32 _bufferHeightLoc; + float g_scale; + float g_bias; + float g_sample_rad; + float g_intensity; + gpu::PipelinePointer _occlusionPipeline; gpu::PipelinePointer _hBlurPipeline; gpu::PipelinePointer _vBlurPipeline; gpu::PipelinePointer _blendPipeline; + gpu::PipelinePointer _AOResultPipeline; gpu::FramebufferPointer _occlusionBuffer; gpu::FramebufferPointer _hBlurBuffer; gpu::FramebufferPointer _vBlurBuffer; + gpu::FramebufferPointer _blendBuffer; gpu::TexturePointer _occlusionTexture; gpu::TexturePointer _hBlurTexture; gpu::TexturePointer _vBlurTexture; + gpu::TexturePointer _blendTexture; + }; #endif // hifi_AmbientOcclusionEffect_h diff --git a/libraries/render-utils/src/ambient_occlusion.slf b/libraries/render-utils/src/ambient_occlusion.slf index 10b687ad1f..023fe2552c 100644 --- a/libraries/render-utils/src/ambient_occlusion.slf +++ b/libraries/render-utils/src/ambient_occlusion.slf @@ -14,36 +14,96 @@ <@include DeferredBufferWrite.slh@> +<@include gpu/Transform.slh@> + +<$declareStandardTransform()$> + varying vec2 varTexcoord; uniform sampler2D depthTexture; uniform sampler2D normalTexture; -float getRandom(vec2 co) { - return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); +uniform float g_scale; +uniform float g_bias; +uniform float g_sample_rad; +uniform float g_intensity; +uniform float bufferWidth; +uniform float bufferHeight; + +#define SAMPLE_COUNT 4 + +float getRandom(vec2 uv) { + return fract(sin(dot(uv.xy ,vec2(12.9898,78.233))) * 43758.5453); } -/* -float doAmbientOcclusion(vec2 tcoord, vec2 uv, vec3 p, vec3 cnorm) { - vec3 diff = getPosition(tcoord + uv) - p; - vec3 v = normalize(diff); - float d = length(diff) * g_scale; - return max(0.0, dot(cnorm, v) - g_bias) * (1.0/(1.0 + d)) * g_intensity; -} -*/ + void main(void) { + vec3 sampleKernel[4] = { vec3(0.2, 0.0, 0.0), + vec3(0.0, 0.2, 0.0), + vec3(0.0, 0.0, 0.2), + vec3(0.2, 0.2, 0.2) }; - vec4 depthColor = texture2D(depthTexture, varTexcoord.xy); - vec4 normalColor = texture2D(normalTexture, varTexcoord.xy); - float z = depthColor.r; // fetch the z-value from our depth texture - float n = 1.0; // the near plane - float f = 30.0; // the far plane - float c = (2.0 * n) / (f + n - z * (f - n)); // convert to linear values + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); - vec4 linearizedDepthColor = vec4(c, c, c, 1.0); - gl_FragColor = mix(linearizedDepthColor, normalColor, 0.5); - //gl_FragColor = linearizedDepthColor; + vec3 eyeDir = vec3(0.0); + vec3 cameraPositionWorldSpace; + <$transformEyeToWorldDir(cam, eyeDir, cameraPositionWorldSpace)$> - //vec3 p = getPosition(i.uv); - //vec3 n = getNormal(i.uv); - //vec2 rand = vec2(getRandom(varTexcoord.xy), getRandom(varTexcoord.yx)); + vec4 depthColor = texture2D(depthTexture, varTexcoord); + + // z in non linear range [0,1] + float depthVal = depthColor.r; + // conversion into NDC [-1,1] + float zNDC = depthVal * 2.0 - 1.0; + float n = 1.0; // the near plane + float f = 30.0; // the far plane + float l = -1.0; // left + float r = 1.0; // right + float b = -1.0; // bottom + float t = 1.0; // top + + // conversion into eye space + float zEye = 2*f*n / (zNDC*(f-n)-(f+n)); + // Converting from pixel coordinates to NDC + float xNDC = gl_FragCoord.x/bufferWidth * 2.0 - 1.0; + float yNDC = gl_FragCoord.y/bufferHeight * 2.0 - 1.0; + // Unprojecting X and Y from NDC to eye space + float xEye = -zEye*(xNDC*(r-l)+(r+l))/(2.0*n); + float yEye = -zEye*(yNDC*(t-b)+(t+b))/(2.0*n); + vec3 currentFragEyeSpace = vec3(xEye, yEye, zEye); + vec3 currentFragWorldSpace; + <$transformEyeToWorldDir(cam, currentFragEyeSpace, currentFragWorldSpace)$> + + vec3 cameraToPositionRay = normalize(currentFragWorldSpace - cameraPositionWorldSpace); + vec3 origin = cameraToPositionRay * depthVal + cameraPositionWorldSpace; + + vec3 normal = normalize(texture2D(normalTexture, varTexcoord).xyz); + //normal = normalize(normal * normalMatrix); + + vec3 rvec = vec3(getRandom(varTexcoord.xy), getRandom(varTexcoord.yx), getRandom(varTexcoord.xx)) * 2.0 - 1.0; + vec3 tangent = normalize(rvec - normal * dot(rvec, normal)); + vec3 bitangent = cross(normal, tangent); + mat3 tbn = mat3(tangent, bitangent, normal); + + float occlusion = 0.0; + + for (int i = 0; i < SAMPLE_COUNT; ++i) { + vec3 samplePos = origin + (tbn * sampleKernel[i]) * g_sample_rad; + vec4 offset = cam._projectionViewUntranslated * vec4(samplePos, 1.0); + + offset.xy = (offset.xy / offset.w) * 0.5 + 0.5; + float depth = length(samplePos - cameraPositionWorldSpace); + + float sampleDepthVal = texture2D(depthTexture, offset.xy).r; + + float rangeDelta = abs(depthVal - sampleDepthVal); + float rangeCheck = smoothstep(0.0, 1.0, g_sample_rad / rangeDelta); + + occlusion += rangeCheck * step(sampleDepthVal, depth); + } + + occlusion = 1.0 - occlusion / float(SAMPLE_COUNT); + occlusion = clamp(pow(occlusion, g_intensity), 0.0, 1.0); + gl_FragColor = vec4(occlusion, occlusion, occlusion, 1.0); } + diff --git a/libraries/render-utils/src/occlusion_blend.slf b/libraries/render-utils/src/occlusion_blend.slf index 30d3173f90..64103e38c9 100644 --- a/libraries/render-utils/src/occlusion_blend.slf +++ b/libraries/render-utils/src/occlusion_blend.slf @@ -17,8 +17,17 @@ varying vec2 varTexcoord; uniform sampler2D blurredOcclusionTexture; +uniform sampler2D colorTexture; void main(void) { - vec4 depthColor = texture2D(blurredOcclusionTexture, varTexcoord.xy); - gl_FragColor = depthColor; + vec4 occlusionColor = texture2D(blurredOcclusionTexture, varTexcoord); + vec4 currentColor = texture2D(colorTexture, varTexcoord); + + if(occlusionColor.r == 1.0) { + gl_FragColor = currentColor; + } + else { + gl_FragColor = mix(occlusionColor, currentColor, 0.5); + } + gl_FragColor = occlusionColor; } diff --git a/libraries/render-utils/src/occlusion_result.slf b/libraries/render-utils/src/occlusion_result.slf new file mode 100644 index 0000000000..3b7e895dc6 --- /dev/null +++ b/libraries/render-utils/src/occlusion_result.slf @@ -0,0 +1,23 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// occlusion_result.frag +// fragment shader +// +// Created by Niraj Venkat on 7/23/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 DeferredBufferWrite.slh@> + +varying vec2 varTexcoord; + +uniform sampler2D resultTexture; + +void main(void) { + gl_FragColor = texture2D(resultTexture, varTexcoord); +} From fc612ab8cd03997dc767df3e4e72a0240ab22ffe Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Fri, 24 Jul 2015 11:29:52 -0700 Subject: [PATCH 29/58] Merge conflict fix --- interface/src/Application.cpp | 5 ----- libraries/render-utils/src/AmbientOcclusionEffect.cpp | 1 - 2 files changed, 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4d2fcbce11..3ba66cf2a0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3287,11 +3287,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se sceneInterface->setEngineDrawnOverlay3DItems(engineRC->_numDrawnOverlay3DItems); } - //Render the sixense lasers - if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) { - _myAvatar->renderLaserPointers(*renderArgs->_batch); - } - if (!selfAvatarOnly) { // give external parties a change to hook in { diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index f46ae1719b..d8b56f5ba1 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -21,7 +21,6 @@ #include "gpu/StandardShaderLib.h" #include "AmbientOcclusionEffect.h" -#include "RenderUtil.h" #include "TextureCache.h" #include "FramebufferCache.h" #include "DependencyManager.h" From ddada17b08bfa12219eb7f04b5f60966b28c9c46 Mon Sep 17 00:00:00 2001 From: "Kevin M. Thomas" Date: Fri, 24 Jul 2015 15:27:16 -0400 Subject: [PATCH 30/58] move jsstreamplayer.html into example/html move jssstreamplayer.js script into example/example/audio --- examples/jsstreamplayer.js | 142 ------------------------------------- 1 file changed, 142 deletions(-) delete mode 100644 examples/jsstreamplayer.js diff --git a/examples/jsstreamplayer.js b/examples/jsstreamplayer.js deleted file mode 100644 index 6bd941f677..0000000000 --- a/examples/jsstreamplayer.js +++ /dev/null @@ -1,142 +0,0 @@ -// -// #20622: JS Stream Player -// ************************* -// -// Created by Kevin M. Thomas and Thoys 07/17/15. -// Copyright 2015 High Fidelity, Inc. -// kevintown.net -// -// JavaScript for the High Fidelity interface that creates a stream player with a UI and keyPressEvents for adding a stream URL in addition to play, stop and volume functionality. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - - -// Declare variables and set up new WebWindow. -var stream; -var volume = 1; -var streamWindow = new WebWindow('Stream', "https://dl.dropboxusercontent.com/u/17344741/jsstreamplayer/jsstreamplayer.html", 0, 0, false); - -// Set up toggleStreamURLButton overlay. -var toggleStreamURLButton = Overlays.addOverlay("text", { - x: 76, - y: 275, - width: 40, - height: 28, - backgroundColor: {red: 0, green: 0, blue: 0}, - color: {red: 255, green: 255, blue: 0}, - font: {size: 15}, - topMargin: 8, - text: " URL" -}); - -// Set up toggleStreamPlayButton overlay. -var toggleStreamPlayButton = Overlays.addOverlay("text", { - x: 122, - y: 275, - width: 38, - height: 28, - backgroundColor: { red: 0, green: 0, blue: 0}, - color: { red: 255, green: 255, blue: 0}, - font: {size: 15}, - topMargin: 8, - text: " Play" -}); - -// Set up toggleStreamStopButton overlay. -var toggleStreamStopButton = Overlays.addOverlay("text", { - x: 166, - y: 275, - width: 40, - height: 28, - backgroundColor: { red: 0, green: 0, blue: 0}, - color: { red: 255, green: 255, blue: 0}, - font: {size: 15}, - topMargin: 8, - text: " Stop" -}); - -// Set up increaseVolumeButton overlay. -var toggleIncreaseVolumeButton = Overlays.addOverlay("text", { - x: 211, - y: 275, - width: 18, - height: 28, - backgroundColor: { red: 0, green: 0, blue: 0}, - color: { red: 255, green: 255, blue: 0}, - font: {size: 15}, - topMargin: 8, - text: " +" -}); - -// Set up decreaseVolumeButton overlay. -var toggleDecreaseVolumeButton = Overlays.addOverlay("text", { - x: 234, - y: 275, - width: 15, - height: 28, - backgroundColor: { red: 0, green: 0, blue: 0}, - color: { red: 255, green: 255, blue: 0}, - font: {size: 15}, - topMargin: 8, - text: " -" -}); - -// Function that adds mousePressEvent functionality to connect UI to enter stream URL, play and stop stream. -function mousePressEvent(event) { - if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleStreamURLButton) { - stream = Window.prompt("Enter Stream: "); - var streamJSON = { - action: "changeStream", - stream: stream - } - streamWindow.eventBridge.emitScriptEvent(JSON.stringify(streamJSON)); - } - if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleStreamPlayButton) { - var streamJSON = { - action: "changeStream", - stream: stream - } - streamWindow.eventBridge.emitScriptEvent(JSON.stringify(streamJSON)); - } - if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleStreamStopButton) { - var streamJSON = { - action: "changeStream", - stream: "" - } - streamWindow.eventBridge.emitScriptEvent(JSON.stringify(streamJSON)); - } - if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleIncreaseVolumeButton) { - volume += 0.2; - var volumeJSON = { - action: "changeVolume", - volume: volume - } - streamWindow.eventBridge.emitScriptEvent(JSON.stringify(volumeJSON)); - } - if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleDecreaseVolumeButton) { - volume -= 0.2; - var volumeJSON = { - action: "changeVolume", - volume: volume - } - streamWindow.eventBridge.emitScriptEvent(JSON.stringify(volumeJSON)); - } -} - -// Call function. -Controller.mousePressEvent.connect(mousePressEvent); -streamWindow.setVisible(false); - -// Function to delete overlays upon exit. -function onScriptEnding() { - Overlays.deleteOverlay(toggleStreamURLButton); - Overlays.deleteOverlay(toggleStreamPlayButton); - Overlays.deleteOverlay(toggleStreamStopButton); - Overlays.deleteOverlay(toggleIncreaseVolumeButton); - Overlays.deleteOverlay(toggleDecreaseVolumeButton); -} - -// Call function. -Script.scriptEnding.connect(onScriptEnding); \ No newline at end of file From d4d5c9f9359729cf97bec92cd5a920f1730529b6 Mon Sep 17 00:00:00 2001 From: "Kevin M. Thomas" Date: Fri, 24 Jul 2015 15:43:50 -0400 Subject: [PATCH 31/58] Created a folder in examples called "zones" then moved files to location. --- examples/example/jsstreamplayerdomain-zone.js | 204 ------------------ examples/html/jsstreamplayerdomain-zone.html | 42 ---- 2 files changed, 246 deletions(-) delete mode 100644 examples/example/jsstreamplayerdomain-zone.js delete mode 100644 examples/html/jsstreamplayerdomain-zone.html diff --git a/examples/example/jsstreamplayerdomain-zone.js b/examples/example/jsstreamplayerdomain-zone.js deleted file mode 100644 index 543a95b839..0000000000 --- a/examples/example/jsstreamplayerdomain-zone.js +++ /dev/null @@ -1,204 +0,0 @@ -// -// #20628: JS Stream Player Domain-Zone -// ************************************* -// -// Created by Kevin M. Thomas and Thoys 07/20/15. -// Copyright 2015 High Fidelity, Inc. -// kevintown.net -// -// JavaScript for the High Fidelity interface that creates a stream player with a UI for playing a domain-zone specificed stream URL in addition to play, stop and volume functionality which is resident only in the domain-zone. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - - -// Declare variables and set up new WebWindow. -var zone = "Zone2"; -var stream = "http://listen.radionomy.com/80sMixTape"; -var volume; -var streamWindow = new WebWindow('Stream', "https://dl.dropboxusercontent.com/u/17344741/jsstreamplayer/jsstreamplayerdomain-zone.html", 0, 0, false); -var visible = false; - -// Set up toggleStreamPlayButton overlay. -var toggleStreamPlayButton = Overlays.addOverlay("text", { - x: 122, - y: 310, - width: 38, - height: 28, - backgroundColor: { red: 0, green: 0, blue: 0}, - color: { red: 255, green: 255, blue: 0}, - font: {size: 15}, - topMargin: 8, - visible: false, - text: " Play" -}); - -// Set up toggleStreamStopButton overlay. -var toggleStreamStopButton = Overlays.addOverlay("text", { - x: 166, - y: 310, - width: 40, - height: 28, - backgroundColor: { red: 0, green: 0, blue: 0}, - color: { red: 255, green: 255, blue: 0}, - font: {size: 15}, - topMargin: 8, - visible: false, - text: " Stop" -}); - -// Set up increaseVolumeButton overlay. -var toggleIncreaseVolumeButton = Overlays.addOverlay("text", { - x: 211, - y: 310, - width: 18, - height: 28, - backgroundColor: { red: 0, green: 0, blue: 0}, - color: { red: 255, green: 255, blue: 0}, - font: {size: 15}, - topMargin: 8, - visible: false, - text: " +" -}); - -// Set up decreaseVolumeButton overlay. -var toggleDecreaseVolumeButton = Overlays.addOverlay("text", { - x: 234, - y: 310, - width: 15, - height: 28, - backgroundColor: { red: 0, green: 0, blue: 0}, - color: { red: 255, green: 255, blue: 0}, - font: {size: 15}, - topMargin: 8, - visible: false, - text: " -" -}); - -// Function to change JSON object stream. -function changeStream(stream) { - var streamJSON = { - action: "changeStream", - stream: stream - } - streamWindow.eventBridge.emitScriptEvent(JSON.stringify(streamJSON)); -} - -// Function to change JSON object volume. -function changeVolume(volume) { - var volumeJSON = { - action: "changeVolume", - volume: volume - } - streamWindow.eventBridge.emitScriptEvent(JSON.stringify(volumeJSON)); -} - -// Function that adds mousePressEvent functionality to connect UI to enter stream URL, play and stop stream. -function mousePressEvent(event) { - if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleStreamPlayButton) { - changeStream(stream); - volume = 0.25; - changeVolume(volume); - } - if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleStreamStopButton) { - changeStream(""); - } - if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleIncreaseVolumeButton) { - volume += 0.25; - changeVolume(volume); - } - if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleDecreaseVolumeButton) { - volume -= 0.25; - changeVolume(volume); - } -} - -// Function checking bool if in proper zone. -function isOurZone(properties) { - return properties.type == "Zone" && properties.name == zone; -} - -// Function checking if avatar is in zone. -function isInZone() { - var entities = Entities.findEntities(MyAvatar.position, 10000); - - for (var i in entities) { - var properties = Entities.getEntityProperties(entities[i]); - - if (isOurZone(properties)) { - var minX = properties.position.x - (properties.dimensions.x / 2); - var maxX = properties.position.x + (properties.dimensions.x / 2); - var minY = properties.position.y - (properties.dimensions.y / 2); - var maxY = properties.position.y + (properties.dimensions.y / 2); - var minZ = properties.position.z - (properties.dimensions.z / 2); - var maxZ = properties.position.z + (properties.dimensions.z / 2); - - if (MyAvatar.position.x >= minX && MyAvatar.position.x <= maxX && MyAvatar.position.y >= minY && MyAvatar.position.y <= maxY && MyAvatar.position.z >= minZ && MyAvatar.position.z <= maxZ) { - return true; - } - } - } - return false; -} - -// Function to toggle visibile the overlay. -function toggleVisible(newVisibility) { - if (newVisibility != visible) { - visible = newVisibility; - Overlays.editOverlay(toggleStreamPlayButton, {visible: visible}); - Overlays.editOverlay(toggleStreamStopButton, {visible: visible}); - Overlays.editOverlay(toggleIncreaseVolumeButton, {visible: visible}); - Overlays.editOverlay(toggleDecreaseVolumeButton, {visible: visible}); - } -} - -// Function to check if avatar is in proper domain. -Window.domainChanged.connect(function() { - if (Window.location.hostname != "Music" && Window.location.hostname != "LiveMusic") { - Script.stop(); - } -}); - -// Function to check if avatar is within zone. -Entities.enterEntity.connect(function(entityID) { - print("Entered..." + JSON.stringify(entityID)); - var properties = Entities.getEntityProperties(entityID); - if (isOurZone(properties)) { - print("Entering Zone!"); - toggleVisible(true); - } -}) - -// Function to check if avatar is leaving zone. -Entities.leaveEntity.connect(function(entityID) { - print("Left..." + JSON.stringify(entityID)); - var properties = Entities.getEntityProperties(entityID); - if (isOurZone(properties)) { - print("Leaving Zone!"); - toggleVisible(false); - changeStream(""); - } -}) - -// Function to delete overlays upon exit. -function onScriptEnding() { - Overlays.deleteOverlay(toggleStreamPlayButton); - Overlays.deleteOverlay(toggleStreamStopButton); - Overlays.deleteOverlay(toggleIncreaseVolumeButton); - Overlays.deleteOverlay(toggleDecreaseVolumeButton); - changeStream(""); - streamWindow.deleteLater(); -} - -// Function call to ensure that if you log in to the zone visibility is true. -if (isInZone()) { - toggleVisible(true); -} - -// Connect mouse and hide WebWindow. -Controller.mousePressEvent.connect(mousePressEvent); -streamWindow.setVisible(false); - -// Call function upon ending script. -Script.scriptEnding.connect(onScriptEnding); \ No newline at end of file diff --git a/examples/html/jsstreamplayerdomain-zone.html b/examples/html/jsstreamplayerdomain-zone.html deleted file mode 100644 index 28b2202591..0000000000 --- a/examples/html/jsstreamplayerdomain-zone.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From 5dd16d9f801cb79cbaa786d1582a3eeca16a443a Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Fri, 24 Jul 2015 16:07:30 -0700 Subject: [PATCH 32/58] Blend function applied to reduce one FBO --- .../src/AmbientOcclusionEffect.cpp | 189 +----------------- .../render-utils/src/occlusion_blend.slf | 13 +- .../render-utils/src/occlusion_blend.slv | 24 --- .../render-utils/src/occlusion_result.slf | 23 --- 4 files changed, 8 insertions(+), 241 deletions(-) delete mode 100644 libraries/render-utils/src/occlusion_blend.slv delete mode 100644 libraries/render-utils/src/occlusion_result.slf diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index d8b56f5ba1..da081f7811 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -32,150 +32,8 @@ #include "gaussian_blur_vertical_vert.h" #include "gaussian_blur_horizontal_vert.h" #include "gaussian_blur_frag.h" -#include "occlusion_blend_vert.h" #include "occlusion_blend_frag.h" -//#include "occlusion_result_vert.h" -#include "occlusion_result_frag.h" -/* -void AmbientOcclusionEffect::init(AbstractViewStateInterface* viewState) { - _viewState = viewState; // we will use this for view state services - - _occlusionProgram = new ProgramObject(); - _occlusionProgram->addShaderFromSourceFile(QGLShader::Vertex, PathUtils::resourcesPath() - + "shaders/ambient_occlusion.vert"); - _occlusionProgram->addShaderFromSourceFile(QGLShader::Fragment, PathUtils::resourcesPath() - + "shaders/ambient_occlusion.frag"); - _occlusionProgram->link(); - - // create the sample kernel: an array of hemispherically distributed offset vectors - const int SAMPLE_KERNEL_SIZE = 16; - QVector3D sampleKernel[SAMPLE_KERNEL_SIZE]; - for (int i = 0; i < SAMPLE_KERNEL_SIZE; i++) { - // square the length in order to increase density towards the center - glm::vec3 vector = glm::sphericalRand(1.0f); - float scale = randFloat(); - const float MIN_VECTOR_LENGTH = 0.01f; - const float MAX_VECTOR_LENGTH = 1.0f; - vector *= glm::mix(MIN_VECTOR_LENGTH, MAX_VECTOR_LENGTH, scale * scale); - sampleKernel[i] = QVector3D(vector.x, vector.y, vector.z); - } - - _occlusionProgram->bind(); - _occlusionProgram->setUniformValue("depthTexture", 0); - _occlusionProgram->setUniformValue("rotationTexture", 1); - _occlusionProgram->setUniformValueArray("sampleKernel", sampleKernel, SAMPLE_KERNEL_SIZE); - _occlusionProgram->setUniformValue("radius", 0.1f); - _occlusionProgram->release(); - - _nearLocation = _occlusionProgram->uniformLocation("near"); - _farLocation = _occlusionProgram->uniformLocation("far"); - _leftBottomLocation = _occlusionProgram->uniformLocation("leftBottom"); - _rightTopLocation = _occlusionProgram->uniformLocation("rightTop"); - _noiseScaleLocation = _occlusionProgram->uniformLocation("noiseScale"); - _texCoordOffsetLocation = _occlusionProgram->uniformLocation("texCoordOffset"); - _texCoordScaleLocation = _occlusionProgram->uniformLocation("texCoordScale"); - - // generate the random rotation texture - glGenTextures(1, &_rotationTextureID); - glBindTexture(GL_TEXTURE_2D, _rotationTextureID); - const int ELEMENTS_PER_PIXEL = 3; - unsigned char rotationData[ROTATION_WIDTH * ROTATION_HEIGHT * ELEMENTS_PER_PIXEL]; - unsigned char* rotation = rotationData; - for (int i = 0; i < ROTATION_WIDTH * ROTATION_HEIGHT; i++) { - glm::vec3 vector = glm::sphericalRand(1.0f); - *rotation++ = ((vector.x + 1.0f) / 2.0f) * 255.0f; - *rotation++ = ((vector.y + 1.0f) / 2.0f) * 255.0f; - *rotation++ = ((vector.z + 1.0f) / 2.0f) * 255.0f; - } - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ROTATION_WIDTH, ROTATION_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, rotationData); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glBindTexture(GL_TEXTURE_2D, 0); - - _blurProgram = new ProgramObject(); - _blurProgram->addShaderFromSourceFile(QGLShader::Vertex, PathUtils::resourcesPath() + "shaders/ambient_occlusion.vert"); - _blurProgram->addShaderFromSourceFile(QGLShader::Fragment, PathUtils::resourcesPath() + "shaders/occlusion_blur.frag"); - _blurProgram->link(); - - _blurProgram->bind(); - _blurProgram->setUniformValue("originalTexture", 0); - _blurProgram->release(); - - _blurScaleLocation = _blurProgram->uniformLocation("blurScale"); -} - -void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext){ - glDisable(GL_BLEND); - glDisable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); - - glBindTexture(GL_TEXTURE_2D, DependencyManager::get()->getPrimaryDepthTextureID()); - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, _rotationTextureID); - - // render with the occlusion shader to the secondary/tertiary buffer - auto freeFramebuffer = nullptr; // DependencyManager::get()->getFreeFramebuffer(); // FIXME - glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(freeFramebuffer)); - - float left, right, bottom, top, nearVal, farVal; - glm::vec4 nearClipPlane, farClipPlane; - AbstractViewStateInterface::instance()->computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); - - int viewport[4]; - glGetIntegerv(GL_VIEWPORT, viewport); - const int VIEWPORT_X_INDEX = 0; - const int VIEWPORT_WIDTH_INDEX = 2; - - auto framebufferSize = DependencyManager::get()->getFrameBufferSize(); - float sMin = viewport[VIEWPORT_X_INDEX] / (float)framebufferSize.width(); - float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)framebufferSize.width(); - - _occlusionProgram->bind(); - _occlusionProgram->setUniformValue(_nearLocation, nearVal); - _occlusionProgram->setUniformValue(_farLocation, farVal); - _occlusionProgram->setUniformValue(_leftBottomLocation, left, bottom); - _occlusionProgram->setUniformValue(_rightTopLocation, right, top); - _occlusionProgram->setUniformValue(_noiseScaleLocation, viewport[VIEWPORT_WIDTH_INDEX] / (float)ROTATION_WIDTH, - framebufferSize.height() / (float)ROTATION_HEIGHT); - _occlusionProgram->setUniformValue(_texCoordOffsetLocation, sMin, 0.0f); - _occlusionProgram->setUniformValue(_texCoordScaleLocation, sWidth, 1.0f); - - renderFullscreenQuad(); - - _occlusionProgram->release(); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - glBindTexture(GL_TEXTURE_2D, 0); - - glActiveTexture(GL_TEXTURE0); - - // now render secondary to primary with 4x4 blur - auto primaryFramebuffer = DependencyManager::get()->getPrimaryFramebuffer(); - glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(primaryFramebuffer)); - - glEnable(GL_BLEND); - glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ONE); - - auto freeFramebufferTexture = freeFramebuffer->getRenderBuffer(0); - glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(freeFramebufferTexture)); - - _blurProgram->bind(); - _blurProgram->setUniformValue(_blurScaleLocation, 1.0f / framebufferSize.width(), 1.0f / framebufferSize.height()); - - renderFullscreenQuad(sMin, sMin + sWidth); - - _blurProgram->release(); - - glBindTexture(GL_TEXTURE_2D, 0); - - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); - glEnable(GL_DEPTH_TEST); - glDepthMask(GL_TRUE) -} -*/ AmbientOcclusion::AmbientOcclusion() { } @@ -297,7 +155,6 @@ const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() { gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("blurredOcclusionTexture"), 0)); - slotBindings.insert(gpu::Shader::Binding(std::string("colorTexture"), 1)); gpu::Shader::makeProgram(*program, slotBindings); @@ -306,8 +163,8 @@ const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() { state->setDepthTest(false, false, gpu::LESS_EQUAL); // Blend on transparent - state->setBlendFunction(false, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); + state->setBlendFunction(true, + gpu::State::SRC_COLOR, gpu::State::BLEND_OP_ADD, gpu::State::DEST_COLOR); // Link the blend FBO to texture _blendBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, @@ -324,30 +181,6 @@ const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() { return _blendPipeline; } -const gpu::PipelinePointer& AmbientOcclusion::getAOResultPipeline() { - if (!_AOResultPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(ambient_occlusion_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(occlusion_result_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); - //gpu::ShaderPointer program = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawTransformUnitQuadVS(), gpu::StandardShaderLib::getDrawTexturePS()); - - gpu::Shader::BindingSet slotBindings; - gpu::Shader::makeProgram(*program, slotBindings); - - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - - state->setDepthTest(false, false, gpu::LESS_EQUAL); - - // Blend on transparent - state->setBlendFunction(false, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); - - // Good to go add the brand new pipeline - _AOResultPipeline.reset(gpu::Pipeline::create(program, state)); - } - return _AOResultPipeline; -} - void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) { assert(renderContext->args); assert(renderContext->args->_viewFrustum); @@ -418,30 +251,14 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons // Blend step getBlendPipeline(); batch.setResourceTexture(0, _hBlurTexture); - batch.setResourceTexture(1, DependencyManager::get()->getPrimaryColorTexture()); - batch.setFramebuffer(_blendBuffer); + batch.setFramebuffer(DependencyManager::get()->getPrimaryFramebuffer()); // Bind the fourth gpu::Pipeline we need - for blending the primary color buffer with blurred occlusion texture batch.setPipeline(getBlendPipeline()); DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); - - // Final AO result step - getAOResultPipeline(); - batch.setResourceTexture(0, _blendTexture); - batch.setFramebuffer(DependencyManager::get()->getPrimaryFramebuffer()); - - // Bind the fifth gpu::Pipeline we need - for displaying the blended texture - batch.setPipeline(getAOResultPipeline()); - - glm::vec2 bottomLeftSmall(0.5f, -1.0f); - glm::vec2 topRightSmall(1.0f, -0.5f); - DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color); // Ready to render args->_context->syncCache(); args->_context->render((batch)); - - // need to fetch forom the z buffer and render something in a new render target a result that combine the z and produce a fake AO result - } diff --git a/libraries/render-utils/src/occlusion_blend.slf b/libraries/render-utils/src/occlusion_blend.slf index 00b09b0cbd..6c0101eb6f 100644 --- a/libraries/render-utils/src/occlusion_blend.slf +++ b/libraries/render-utils/src/occlusion_blend.slf @@ -17,17 +17,14 @@ varying vec2 varTexcoord; uniform sampler2D blurredOcclusionTexture; -uniform sampler2D colorTexture; void main(void) { vec4 occlusionColor = texture2D(blurredOcclusionTexture, varTexcoord); - vec4 currentColor = texture2D(colorTexture, varTexcoord); - /* - if(occlusionColor.r == 1.0) { - gl_FragColor = currentColor; + + if(occlusionColor.r > 0.8 && occlusionColor.r <= 1.0) { + gl_FragColor = vec4(vec3(0.0), 1.0); } else { - gl_FragColor = mix(occlusionColor, currentColor, 0.5); - }*/ - gl_FragColor = currentColor; + gl_FragColor = vec4(vec3(0.2), 1.0); + } } diff --git a/libraries/render-utils/src/occlusion_blend.slv b/libraries/render-utils/src/occlusion_blend.slv deleted file mode 100644 index 53380a494f..0000000000 --- a/libraries/render-utils/src/occlusion_blend.slv +++ /dev/null @@ -1,24 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// occlusion_blend.vert -// vertex shader -// -// Created by Niraj Venkat on 7/20/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 gpu/Transform.slh@> - -<$declareStandardTransform()$> - -varying vec2 varTexcoord; - -void main(void) { - varTexcoord = gl_MultiTexCoord0.xy; - gl_Position = gl_Vertex; -} diff --git a/libraries/render-utils/src/occlusion_result.slf b/libraries/render-utils/src/occlusion_result.slf deleted file mode 100644 index 3b7e895dc6..0000000000 --- a/libraries/render-utils/src/occlusion_result.slf +++ /dev/null @@ -1,23 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// occlusion_result.frag -// fragment shader -// -// Created by Niraj Venkat on 7/23/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 DeferredBufferWrite.slh@> - -varying vec2 varTexcoord; - -uniform sampler2D resultTexture; - -void main(void) { - gl_FragColor = texture2D(resultTexture, varTexcoord); -} From 6bc3d65bf4cfe58e3ba12a75979baa13ce3228ce Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Fri, 24 Jul 2015 16:16:18 -0700 Subject: [PATCH 33/58] Fixing build errors --- libraries/render-utils/src/AmbientOcclusionEffect.cpp | 11 +---------- libraries/render-utils/src/AmbientOcclusionEffect.h | 4 ---- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index da081f7811..d7fa88b276 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -149,7 +149,7 @@ const gpu::PipelinePointer& AmbientOcclusion::getHBlurPipeline() { const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() { if (!_blendPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(occlusion_blend_vert))); + auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(ambient_occlusion_vert))); auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(occlusion_blend_frag))); gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); @@ -166,15 +166,6 @@ const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() { state->setBlendFunction(true, gpu::State::SRC_COLOR, gpu::State::BLEND_OP_ADD, gpu::State::DEST_COLOR); - // Link the blend FBO to texture - _blendBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32, - DependencyManager::get()->getFrameBufferSize().width(), DependencyManager::get()->getFrameBufferSize().height())); - auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); - auto width = _blendBuffer->getWidth(); - auto height = _blendBuffer->getHeight(); - auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); - _blendTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); - // Good to go add the brand new pipeline _blendPipeline.reset(gpu::Pipeline::create(program, state)); } diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index ec0314016c..76cb0b063d 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -28,7 +28,6 @@ public: const gpu::PipelinePointer& getHBlurPipeline(); const gpu::PipelinePointer& getVBlurPipeline(); const gpu::PipelinePointer& getBlendPipeline(); - const gpu::PipelinePointer& getAOResultPipeline(); private: @@ -48,17 +47,14 @@ private: gpu::PipelinePointer _hBlurPipeline; gpu::PipelinePointer _vBlurPipeline; gpu::PipelinePointer _blendPipeline; - gpu::PipelinePointer _AOResultPipeline; gpu::FramebufferPointer _occlusionBuffer; gpu::FramebufferPointer _hBlurBuffer; gpu::FramebufferPointer _vBlurBuffer; - gpu::FramebufferPointer _blendBuffer; gpu::TexturePointer _occlusionTexture; gpu::TexturePointer _hBlurTexture; gpu::TexturePointer _vBlurTexture; - gpu::TexturePointer _blendTexture; }; From ca8d0d542012f93dea2be32d2ea066d7bd1b1eca Mon Sep 17 00:00:00 2001 From: "Kevin M. Thomas" Date: Sat, 25 Jul 2015 07:56:57 -0400 Subject: [PATCH 34/58] Added files to zone folder and made change to jstreamplayerdomain-zone.js to allow for zone entity data field to load a stream url rather than have it hard coded in the js file. This allows for many zones to be created and simply having to put a new stream url in each data field in each zone to work. --- .../zones/jsstreamplayerdomain-zone-entity.js | 33 ++++ examples/zones/jsstreamplayerdomain-zone.html | 42 +++++ examples/zones/jsstreamplayerdomain-zone.js | 176 ++++++++++++++++++ 3 files changed, 251 insertions(+) create mode 100644 examples/zones/jsstreamplayerdomain-zone-entity.js create mode 100644 examples/zones/jsstreamplayerdomain-zone.html create mode 100644 examples/zones/jsstreamplayerdomain-zone.js diff --git a/examples/zones/jsstreamplayerdomain-zone-entity.js b/examples/zones/jsstreamplayerdomain-zone-entity.js new file mode 100644 index 0000000000..9a8cb8b8b4 --- /dev/null +++ b/examples/zones/jsstreamplayerdomain-zone-entity.js @@ -0,0 +1,33 @@ +// +// #20628: JS Stream Player Domain-Zone-Entity +// ******************************************** +// +// Created by Kevin M. Thomas and Thoys 07/20/15. +// Copyright 2015 High Fidelity, Inc. +// kevintown.net +// +// JavaScript for the High Fidelity interface that is an entity script to be placed in a chosen entity inside a domain-zone. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +// Function which exists inside of an entity which triggers as a user approches it. +(function() { + const SCRIPT_NAME = "https://dl.dropboxusercontent.com/u/17344741/jsstreamplayer/jsstreamplayerdomain-zone.js"; + function isScriptRunning(script) { + script = script.toLowerCase().trim(); + var runningScripts = ScriptDiscoveryService.getRunning(); + for (i in runningScripts) { + if (runningScripts[i].url.toLowerCase().trim() == script) { + return true; + } + } + return false; + }; + + if (!isScriptRunning(SCRIPT_NAME)) { + Script.load(SCRIPT_NAME); + } +}) \ No newline at end of file diff --git a/examples/zones/jsstreamplayerdomain-zone.html b/examples/zones/jsstreamplayerdomain-zone.html new file mode 100644 index 0000000000..28b2202591 --- /dev/null +++ b/examples/zones/jsstreamplayerdomain-zone.html @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/zones/jsstreamplayerdomain-zone.js b/examples/zones/jsstreamplayerdomain-zone.js new file mode 100644 index 0000000000..33d7364709 --- /dev/null +++ b/examples/zones/jsstreamplayerdomain-zone.js @@ -0,0 +1,176 @@ +// +// #20628: JS Stream Player Domain-Zone +// ************************************* +// +// Created by Kevin M. Thomas, Thoys and Konstantin 07/24/15. +// Copyright 2015 High Fidelity, Inc. +// kevintown.net +// +// JavaScript for the High Fidelity interface that creates a stream player with a UI for playing a domain-zone specificed stream URL in addition to play, stop and volume functionality which is resident only in the domain-zone. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +// Declare variables and set up new WebWindow. +var lastZone = ""; +var volume = 0.5; +var stream = ""; +var streamWindow = new WebWindow('Stream', "https://dl.dropboxusercontent.com/u/17344741/jsstreamplayer/jsstreamplayerdomain-zone.html", 0, 0, false); +var visible = false; + +// Set up toggleStreamPlayButton overlay. +var toggleStreamPlayButton = Overlays.addOverlay("text", { + x: 122, + y: 310, + width: 38, + height: 28, + backgroundColor: { red: 0, green: 0, blue: 0}, + color: { red: 255, green: 255, blue: 0}, + font: {size: 15}, + topMargin: 8, + visible: false, + text: " Play" +}); + +// Set up toggleStreamStopButton overlay. +var toggleStreamStopButton = Overlays.addOverlay("text", { + x: 166, + y: 310, + width: 40, + height: 28, + backgroundColor: { red: 0, green: 0, blue: 0}, + color: { red: 255, green: 255, blue: 0}, + font: {size: 15}, + topMargin: 8, + visible: false, + text: " Stop" +}); + +// Set up increaseVolumeButton overlay. +var toggleIncreaseVolumeButton = Overlays.addOverlay("text", { + x: 211, + y: 310, + width: 18, + height: 28, + backgroundColor: { red: 0, green: 0, blue: 0}, + color: { red: 255, green: 255, blue: 0}, + font: {size: 15}, + topMargin: 8, + visible: false, + text: " +" +}); + +// Set up decreaseVolumeButton overlay. +var toggleDecreaseVolumeButton = Overlays.addOverlay("text", { + x: 234, + y: 310, + width: 15, + height: 28, + backgroundColor: { red: 0, green: 0, blue: 0}, + color: { red: 255, green: 255, blue: 0}, + font: {size: 15}, + topMargin: 8, + visible: false, + text: " -" +}); + +// Function to change JSON object stream. +function changeStream(stream) { + var streamJSON = { + action: "changeStream", + stream: stream + } + streamWindow.eventBridge.emitScriptEvent(JSON.stringify(streamJSON)); +} + +// Function to change JSON object volume. +function changeVolume(volume) { + var volumeJSON = { + action: "changeVolume", + volume: volume + } + streamWindow.eventBridge.emitScriptEvent(JSON.stringify(volumeJSON)); +} + +// Function that adds mousePressEvent functionality to connect UI to enter stream URL, play and stop stream. +function mousePressEvent(event) { + if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleStreamPlayButton) { + changeStream(stream); + volume = 0.25; + changeVolume(volume); + } + if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleStreamStopButton) { + changeStream(""); + } + if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleIncreaseVolumeButton) { + volume += 0.25; + changeVolume(volume); + } + if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleDecreaseVolumeButton) { + volume -= 0.25; + changeVolume(volume); + } +} + +// Function checking bool if in proper zone. +function isOurZone(properties) { + return stream != "" && properties.type == "Zone"; +} + +// Function to toggle visibile the overlay. +function toggleVisible(newVisibility) { + if (newVisibility != visible) { + visible = newVisibility; + Overlays.editOverlay(toggleStreamPlayButton, {visible: visible}); + Overlays.editOverlay(toggleStreamStopButton, {visible: visible}); + Overlays.editOverlay(toggleIncreaseVolumeButton, {visible: visible}); + Overlays.editOverlay(toggleDecreaseVolumeButton, {visible: visible}); + } +} + +// Function to check if avatar is in proper domain. +Window.domainChanged.connect(function() { + Script.stop(); +}); + +// Function to check if avatar is within zone. +Entities.enterEntity.connect(function(entityID) { + print("Entered..." + JSON.stringify(entityID)); + var properties = Entities.getEntityProperties(entityID); + stream = properties.userData; + if(isOurZone(properties)) + { + lastZone = properties.name; + toggleVisible(true); + } +}) + +// Function to check if avatar is leaving zone. +Entities.leaveEntity.connect(function(entityID) { + print("Left..." + JSON.stringify(entityID)); + var properties = Entities.getEntityProperties(entityID); + if (properties.name == lastZone && properties.type == "Zone") { + print("Leaving Zone!"); + toggleVisible(false); + changeStream(""); + } +}) + +// Function to delete overlays upon exit. +function onScriptEnding() { + Overlays.deleteOverlay(toggleStreamPlayButton); + Overlays.deleteOverlay(toggleStreamStopButton); + Overlays.deleteOverlay(toggleIncreaseVolumeButton); + Overlays.deleteOverlay(toggleDecreaseVolumeButton); + changeStream(""); + streamWindow.deleteLater(); +} + +// Connect mouse and hide WebWindow. +Controller.mousePressEvent.connect(mousePressEvent); +streamWindow.setVisible(false); + +// Call function upon ending script. +Script.scriptEnding.connect(onScriptEnding); \ No newline at end of file From d17ddae53787a3ad094f82f65fc5491c75774a4f Mon Sep 17 00:00:00 2001 From: "Kevin M. Thomas" Date: Mon, 27 Jul 2015 12:14:50 -0400 Subject: [PATCH 35/58] Added .js file to examples/example/audio and added public bucket url functionality. --- examples/example/audio/jsstreamplayer.js | 145 +++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 examples/example/audio/jsstreamplayer.js diff --git a/examples/example/audio/jsstreamplayer.js b/examples/example/audio/jsstreamplayer.js new file mode 100644 index 0000000000..27ed32e3b5 --- /dev/null +++ b/examples/example/audio/jsstreamplayer.js @@ -0,0 +1,145 @@ +// +// #20622: JS Stream Player +// ************************* +// +// Created by Kevin M. Thomas and Thoys 07/17/15. +// Copyright 2015 High Fidelity, Inc. +// kevintown.net +// +// JavaScript for the High Fidelity interface that creates a stream player with a UI and keyPressEvents for adding a stream URL in addition to play, stop and volume functionality. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +// Declare HiFi public bucket. +HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; + +// Declare variables and set up new WebWindow. +var stream; +var volume = 1; +var streamWindow = new WebWindow('Stream', HIFI_PUBLIC_BUCKET + "examples/html/jsstreamplayer.html", 0, 0, false); + +// Set up toggleStreamURLButton overlay. +var toggleStreamURLButton = Overlays.addOverlay("text", { + x: 76, + y: 275, + width: 40, + height: 28, + backgroundColor: {red: 0, green: 0, blue: 0}, + color: {red: 255, green: 255, blue: 0}, + font: {size: 15}, + topMargin: 8, + text: " URL" +}); + +// Set up toggleStreamPlayButton overlay. +var toggleStreamPlayButton = Overlays.addOverlay("text", { + x: 122, + y: 275, + width: 38, + height: 28, + backgroundColor: { red: 0, green: 0, blue: 0}, + color: { red: 255, green: 255, blue: 0}, + font: {size: 15}, + topMargin: 8, + text: " Play" +}); + +// Set up toggleStreamStopButton overlay. +var toggleStreamStopButton = Overlays.addOverlay("text", { + x: 166, + y: 275, + width: 40, + height: 28, + backgroundColor: { red: 0, green: 0, blue: 0}, + color: { red: 255, green: 255, blue: 0}, + font: {size: 15}, + topMargin: 8, + text: " Stop" +}); + +// Set up increaseVolumeButton overlay. +var toggleIncreaseVolumeButton = Overlays.addOverlay("text", { + x: 211, + y: 275, + width: 18, + height: 28, + backgroundColor: { red: 0, green: 0, blue: 0}, + color: { red: 255, green: 255, blue: 0}, + font: {size: 15}, + topMargin: 8, + text: " +" +}); + +// Set up decreaseVolumeButton overlay. +var toggleDecreaseVolumeButton = Overlays.addOverlay("text", { + x: 234, + y: 275, + width: 15, + height: 28, + backgroundColor: { red: 0, green: 0, blue: 0}, + color: { red: 255, green: 255, blue: 0}, + font: {size: 15}, + topMargin: 8, + text: " -" +}); + +// Function that adds mousePressEvent functionality to connect UI to enter stream URL, play and stop stream. +function mousePressEvent(event) { + if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleStreamURLButton) { + stream = Window.prompt("Enter Stream: "); + var streamJSON = { + action: "changeStream", + stream: stream + } + streamWindow.eventBridge.emitScriptEvent(JSON.stringify(streamJSON)); + } + if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleStreamPlayButton) { + var streamJSON = { + action: "changeStream", + stream: stream + } + streamWindow.eventBridge.emitScriptEvent(JSON.stringify(streamJSON)); + } + if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleStreamStopButton) { + var streamJSON = { + action: "changeStream", + stream: "" + } + streamWindow.eventBridge.emitScriptEvent(JSON.stringify(streamJSON)); + } + if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleIncreaseVolumeButton) { + volume += 0.2; + var volumeJSON = { + action: "changeVolume", + volume: volume + } + streamWindow.eventBridge.emitScriptEvent(JSON.stringify(volumeJSON)); + } + if (Overlays.getOverlayAtPoint({x: event.x, y: event.y}) == toggleDecreaseVolumeButton) { + volume -= 0.2; + var volumeJSON = { + action: "changeVolume", + volume: volume + } + streamWindow.eventBridge.emitScriptEvent(JSON.stringify(volumeJSON)); + } +} + +// Call function. +Controller.mousePressEvent.connect(mousePressEvent); +streamWindow.setVisible(false); + +// Function to delete overlays upon exit. +function onScriptEnding() { + Overlays.deleteOverlay(toggleStreamURLButton); + Overlays.deleteOverlay(toggleStreamPlayButton); + Overlays.deleteOverlay(toggleStreamStopButton); + Overlays.deleteOverlay(toggleIncreaseVolumeButton); + Overlays.deleteOverlay(toggleDecreaseVolumeButton); +} + +// Call function. +Script.scriptEnding.connect(onScriptEnding); \ No newline at end of file From d54543e83cb06f25e2c4d0007d1ea9d664803693 Mon Sep 17 00:00:00 2001 From: Bing Shearer Date: Mon, 27 Jul 2015 10:19:42 -0700 Subject: [PATCH 36/58] Tidied up per Brad's request --- examples/leaves.js | 618 ++++++++++++++++++++++++--------------------- 1 file changed, 330 insertions(+), 288 deletions(-) diff --git a/examples/leaves.js b/examples/leaves.js index e611eb7de6..af3c2f0e23 100755 --- a/examples/leaves.js +++ b/examples/leaves.js @@ -1,289 +1,331 @@ -// -// Leaves.js -// examples -// -// Created by Bing Shearer on 14 Jul 2015 -// 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 -// -var leafName = "scriptLeaf"; -var leafSquall = function (properties) { - var // Properties - squallOrigin, - squallRadius, - leavesPerMinute = 60, - leafSize = { x: 0.1, y: 0.1, z: 0.1 }, - leafFallSpeed = 1, // m/s - leafLifetime = 60, // Seconds - leafSpinMax = 0, // Maximum angular velocity per axis; deg/s - debug = false, // Display origin circle; don't use running on Stack Manager - // Other - squallCircle, - SQUALL_CIRCLE_COLOR = { red: 255, green: 0, blue: 0 }, - SQUALL_CIRCLE_ALPHA = 0.5, - SQUALL_CIRCLE_ROTATION = Quat.fromPitchYawRollDegrees(90, 0, 0), - leafProperties, - leaf_MODEL_URL = "https://hifi-public.s3.amazonaws.com/ozan/support/forBing/palmLeaf.fbx", - leafTimer, - leaves = [], // HACK: Work around leaves not always getting velocities - leafVelocities = [], // HACK: Work around leaves not always getting velocities - DEGREES_TO_RADIANS = Math.PI / 180, - leafDeleteOnTearDown = true, - maxLeaves, - leafCount, - nearbyEntities, - complexMovement = false, - movementTime = 0, - maxSpinRadians = properties.leafSpinMax * DEGREES_TO_RADIANS, - windFactor, - leafDeleteOnGround = false, - floorHeight = null; - - - function processProperties() { - if (!properties.hasOwnProperty("origin")) { - print("ERROR: Leaf squall origin must be specified"); - return; - } - squallOrigin = properties.origin; - - if (!properties.hasOwnProperty("radius")) { - print("ERROR: Leaf squall radius must be specified"); - return; - } - squallRadius = properties.radius; - - if (properties.hasOwnProperty("leavesPerMinute")) { - leavesPerMinute = properties.leavesPerMinute; - } - - if (properties.hasOwnProperty("leafSize")) { - leafSize = properties.leafSize; - } - - if (properties.hasOwnProperty("leafFallSpeed")) { - leafFallSpeed = properties.leafFallSpeed; - } - - if (properties.hasOwnProperty("leafLifetime")) { - leafLifetime = properties.leafLifetime; - } - - if (properties.hasOwnProperty("leafSpinMax")) { - leafSpinMax = properties.leafSpinMax; - } - - if (properties.hasOwnProperty("debug")) { - debug = properties.debug; - } - if (properties.hasOwnProperty("floorHeight")) { - floorHeight = properties.floorHeight; - } - if (properties.hasOwnProperty("maxLeaves")) { - maxLeaves = properties.maxLeaves; - } - if (properties.hasOwnProperty("complexMovement")) { - complexMovement = properties.complexMovement; - } - if (properties.hasOwnProperty("leafDeleteOnGround")) { - leafDeleteOnGround = properties.leafDeleteOnGround; - } - if (properties.hasOwnProperty("windFactor")) { - windFactor = properties.windFactor; - } - else { - print("ERROR: Wind Factor must be defined for complex movement") - } - - leafProperties = { - type: "Model", - name: leafName, - modelURL: leaf_MODEL_URL, - lifetime: leafLifetime, - dimensions: leafSize, - velocity: { x: 0, y: -leafFallSpeed, z: 0 }, - damping: 0, - angularDamping: 0, - ignoreForCollisions: true - - }; - } - - function createleaf() { - var angle, - radius, - offset, - leaf, - spin = { x: 0, y: 0, z: 0 }, - i; - - // HACK: Work around leaves not always getting velocities set at creation - for (i = 0; i < leaves.length; i += 1) { - Entities.editEntity(leaves[i], leafVelocities[i]); - } - - angle = Math.random() * 10; - radius = Math.random() * squallRadius; - offset = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, angle, 0), { x: 0, y: -0.1, z: radius }); - leafProperties.position = Vec3.sum(squallOrigin, offset); - if (properties.leafSpinMax > 0 && !complexMovement) { - spin = { - x: Math.random() * maxSpinRadians, - y: Math.random() * maxSpinRadians, - z: Math.random() * maxSpinRadians - }; - leafProperties.angularVelocity = spin; - } - else if (complexMovement) { - spin = { x: 0, y: 0, z: 0 }; - leafProperties.angularVelocity = spin - } - leaf = Entities.addEntity(leafProperties); - - // HACK: Work around leaves not always getting velocities set at creation - leaves.push(leaf); - leafVelocities.push({ - velocity: leafProperties.velocity, - angularVelocity: spin - }); - if (leaves.length > 5) { - leaves.shift(); - leafVelocities.shift(); - } - } - - function setUp() { - if (debug) { - squallCircle = Overlays.addOverlay("circle3d", { - size: { x: 2 * squallRadius, y: 2 * squallRadius }, - color: SQUALL_CIRCLE_COLOR, - alpha: SQUALL_CIRCLE_ALPHA, - solid: true, - visible: debug, - position: squallOrigin, - rotation: SQUALL_CIRCLE_ROTATION - }); - } - - leafTimer = Script.setInterval(function () { - if (leafCount <= maxLeaves - 1) { - createleaf() - } - }, 60000 / leavesPerMinute); - } - Script.setInterval(function () { - nearbyEntities = Entities.findEntities(squallOrigin, squallRadius); - newLeafMovement() - }, 100); - - function newLeafMovement() { //new additions to leaf code. Operates at 10 Hz or every 100 ms - movementTime += 0.1; - var currentLeaf, - randomRotationSpeed = { - x: maxSpinRadians * Math.sin(movementTime), - y: maxSpinRadians * Math.random(), - z: maxSpinRadians * Math.sin(movementTime / 7) - }; - for (var i = 0; i < nearbyEntities.length; i++) { - var entityProperties = Entities.getEntityProperties(nearbyEntities[i]); - var entityName = entityProperties.name; - if (leafName === entityName) { - currentLeaf = nearbyEntities[i]; - var leafHeight = entityProperties.position.y; - if (complexMovement && leafHeight > floorHeight || complexMovement && floorHeight == null) { //actual new movement code; - var leafCurrentVel = entityProperties.velocity, - leafCurrentRot = entityProperties.rotation, - yVec = { x: 0, y: 1, z: 0 }, - leafYinWFVec = Vec3.multiplyQbyV(leafCurrentRot, yVec), - leafLocalHorVec = Vec3.cross(leafYinWFVec, yVec), - leafMostDownVec = Vec3.cross(leafYinWFVec, leafLocalHorVec), - leafDesiredVel = Vec3.multiply(leafMostDownVec, windFactor), - leafVelDelt = Vec3.subtract(leafDesiredVel, leafCurrentVel), - leafNewVel = Vec3.sum(leafCurrentVel, Vec3.multiply(leafVelDelt, windFactor)); - Entities.editEntity(currentLeaf, { - angularVelocity: randomRotationSpeed, - velocity: leafNewVel - }) - } - else if (leafHeight <= floorHeight) { - if (!leafDeleteOnGround) { - Entities.editEntity(nearbyEntities[i], { - locked: false, - velocity: { x: 0, y: 0, z: 0 }, - angularVelocity: { x: 0, y: 0, z: 0 } - }) - } - else { - Entity.deleteEntity(currentLeaf); - } - } - } - } - } - - - - getLeafCount = Script.setInterval(function () { - leafCount = 0 - for (var i = 0; i < nearbyEntities.length; i++) { - var entityName = Entities.getEntityProperties(nearbyEntities[i]).name; - //Stop Leaves at floorHeight - if (leafName === entityName) { - leafCount++; - if (i == nearbyEntities.length - 1) { - //print(leafCount); - } - } - } - }, 1000) - - - - function tearDown() { - Script.clearInterval(leafTimer); - Overlays.deleteOverlay(squallCircle); - if (leafDeleteOnTearDown) { - for (var i = 0; i < nearbyEntities.length; i++) { - var entityName = Entities.getEntityProperties(nearbyEntities[i]).name; - if (leafName === entityName) { - //We have a match - delete this entity - Entities.editEntity(nearbyEntities[i], { - locked: false - }); - Entities.deleteEntity(nearbyEntities[i]); - } - } - } - } - - - - processProperties(); - setUp(); - Script.scriptEnding.connect(tearDown); - - return { - }; -}; - -var leafSquall1 = new leafSquall({ - origin: { x: 3071.5, y: 2170, z: 6765.3 }, - radius: 100, - leavesPerMinute: 30, - leafSize: { x: 0.3, y: 0.00, z: 0.3}, - leafFallSpeed: 0.4, - leafLifetime: 100, - leafSpinMax: 30, - debug: false, - maxLeaves: 100, - leafDeleteOnTearDown: true, - complexMovement: true, - floorHeight: 2143.5, - windFactor: 0.5, - leafDeleteOnGround: false -}); - -// todo +// +// Leaves.js +// examples +// +// Created by Bing Shearer on 14 Jul 2015 +// 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 +// +var leafName = "scriptLeaf"; +var leafSquall = function (properties) { + var // Properties + squallOrigin, + squallRadius, + leavesPerMinute = 60, + leafSize = { + x: 0.1, + y: 0.1, + z: 0.1 + }, + leafFallSpeed = 1, // m/s + leafLifetime = 60, // Seconds + leafSpinMax = 0, // Maximum angular velocity per axis; deg/s + debug = false, // Display origin circle; don't use running on Stack Manager + // Other + squallCircle, + SQUALL_CIRCLE_COLOR = { + red: 255, + green: 0, + blue: 0 + }, + SQUALL_CIRCLE_ALPHA = 0.5, + SQUALL_CIRCLE_ROTATION = Quat.fromPitchYawRollDegrees(90, 0, 0), + leafProperties, + leaf_MODEL_URL = "https://hifi-public.s3.amazonaws.com/ozan/support/forBing/palmLeaf.fbx", + leafTimer, + leaves = [], // HACK: Work around leaves not always getting velocities + leafVelocities = [], // HACK: Work around leaves not always getting velocities + DEGREES_TO_RADIANS = Math.PI / 180, + leafDeleteOnTearDown = true, + maxLeaves, + leafCount, + nearbyEntities, + complexMovement = false, + movementTime = 0, + maxSpinRadians = properties.leafSpinMax * DEGREES_TO_RADIANS, + windFactor, + leafDeleteOnGround = false, + floorHeight = null; + + + function processProperties() { + if (!properties.hasOwnProperty("origin")) { + print("ERROR: Leaf squall origin must be specified"); + return; + } + squallOrigin = properties.origin; + + if (!properties.hasOwnProperty("radius")) { + print("ERROR: Leaf squall radius must be specified"); + return; + } + squallRadius = properties.radius; + + if (properties.hasOwnProperty("leavesPerMinute")) { + leavesPerMinute = properties.leavesPerMinute; + } + + if (properties.hasOwnProperty("leafSize")) { + leafSize = properties.leafSize; + } + + if (properties.hasOwnProperty("leafFallSpeed")) { + leafFallSpeed = properties.leafFallSpeed; + } + + if (properties.hasOwnProperty("leafLifetime")) { + leafLifetime = properties.leafLifetime; + } + + if (properties.hasOwnProperty("leafSpinMax")) { + leafSpinMax = properties.leafSpinMax; + } + + if (properties.hasOwnProperty("debug")) { + debug = properties.debug; + } + if (properties.hasOwnProperty("floorHeight")) { + floorHeight = properties.floorHeight; + } + if (properties.hasOwnProperty("maxLeaves")) { + maxLeaves = properties.maxLeaves; + } + if (properties.hasOwnProperty("complexMovement")) { + complexMovement = properties.complexMovement; + } + if (properties.hasOwnProperty("leafDeleteOnGround")) { + leafDeleteOnGround = properties.leafDeleteOnGround; + } + if (properties.hasOwnProperty("windFactor")) { + windFactor = properties.windFactor; + } else { + print("ERROR: Wind Factor must be defined for complex movement") + } + + leafProperties = { + type: "Model", + name: leafName, + modelURL: leaf_MODEL_URL, + lifetime: leafLifetime, + dimensions: leafSize, + velocity: { + x: 0, + y: -leafFallSpeed, + z: 0 + }, + damping: 0, + angularDamping: 0, + ignoreForCollisions: true + + }; + } + + function createleaf() { + var angle, + radius, + offset, + leaf, + spin = { + x: 0, + y: 0, + z: 0 + }, + i; + + // HACK: Work around leaves not always getting velocities set at creation + for (i = 0; i < leaves.length; i++) { + Entities.editEntity(leaves[i], leafVelocities[i]); + } + + angle = Math.random() * leafSpinMax; + radius = Math.random() * squallRadius; + offset = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, angle, 0), { + x: 0, + y: -0.1, + z: radius + }); + leafProperties.position = Vec3.sum(squallOrigin, offset); + if (properties.leafSpinMax > 0 && !complexMovement) { + spin = { + x: Math.random() * maxSpinRadians, + y: Math.random() * maxSpinRadians, + z: Math.random() * maxSpinRadians + }; + leafProperties.angularVelocity = spin; + } else if (complexMovement) { + spin = { + x: 0, + y: 0, + z: 0 + }; + leafProperties.angularVelocity = spin + } + leaf = Entities.addEntity(leafProperties); + + // HACK: Work around leaves not always getting velocities set at creation + leaves.push(leaf); + leafVelocities.push({ + velocity: leafProperties.velocity, + angularVelocity: spin + }); + if (leaves.length > 5) { + leaves.shift(); + leafVelocities.shift(); + } + } + + function setUp() { + if (debug) { + squallCircle = Overlays.addOverlay("circle3d", { + size: { + x: 2 * squallRadius, + y: 2 * squallRadius + }, + color: SQUALL_CIRCLE_COLOR, + alpha: SQUALL_CIRCLE_ALPHA, + solid: true, + visible: debug, + position: squallOrigin, + rotation: SQUALL_CIRCLE_ROTATION + }); + } + + leafTimer = Script.setInterval(function () { + if (leafCount <= maxLeaves - 1) { + createleaf() + } + }, 60000 / leavesPerMinute); + } + Script.setInterval(function () { + nearbyEntities = Entities.findEntities(squallOrigin, squallRadius); + newLeafMovement() + }, 100); + + function newLeafMovement() { //new additions to leaf code. Operates at 10 Hz or every 100 ms + movementTime += 0.1; + var currentLeaf, + randomRotationSpeed = { + x: maxSpinRadians * Math.sin(movementTime), + y: maxSpinRadians * Math.random(), + z: maxSpinRadians * Math.sin(movementTime / 7) + }; + for (var i = 0; i < nearbyEntities.length; i++) { + var entityProperties = Entities.getEntityProperties(nearbyEntities[i]); + var entityName = entityProperties.name; + if (leafName === entityName) { + currentLeaf = nearbyEntities[i]; + var leafHeight = entityProperties.position.y; + if (complexMovement && leafHeight > floorHeight || complexMovement && floorHeight == null) { //actual new movement code; + var leafCurrentVel = entityProperties.velocity, + leafCurrentRot = entityProperties.rotation, + yVec = { + x: 0, + y: 1, + z: 0 + }, + leafYinWFVec = Vec3.multiplyQbyV(leafCurrentRot, yVec), + leafLocalHorVec = Vec3.cross(leafYinWFVec, yVec), + leafMostDownVec = Vec3.cross(leafYinWFVec, leafLocalHorVec), + leafDesiredVel = Vec3.multiply(leafMostDownVec, windFactor), + leafVelDelt = Vec3.subtract(leafDesiredVel, leafCurrentVel), + leafNewVel = Vec3.sum(leafCurrentVel, Vec3.multiply(leafVelDelt, windFactor)); + Entities.editEntity(currentLeaf, { + angularVelocity: randomRotationSpeed, + velocity: leafNewVel + }) + } else if (leafHeight <= floorHeight) { + if (!leafDeleteOnGround) { + Entities.editEntity(nearbyEntities[i], { + locked: false, + velocity: { + x: 0, + y: 0, + z: 0 + }, + angularVelocity: { + x: 0, + y: 0, + z: 0 + } + }) + } else { + Entity.deleteEntity(currentLeaf); + } + } + } + } + } + + + + getLeafCount = Script.setInterval(function () { + leafCount = 0 + for (var i = 0; i < nearbyEntities.length; i++) { + var entityName = Entities.getEntityProperties(nearbyEntities[i]).name; + //Stop Leaves at floorHeight + if (leafName === entityName) { + leafCount++; + if (i == nearbyEntities.length - 1) { + //print(leafCount); + } + } + } + }, 1000) + + + + function tearDown() { + Script.clearInterval(leafTimer); + Overlays.deleteOverlay(squallCircle); + if (leafDeleteOnTearDown) { + for (var i = 0; i < nearbyEntities.length; i++) { + var entityName = Entities.getEntityProperties(nearbyEntities[i]).name; + if (leafName === entityName) { + //We have a match - delete this entity + Entities.editEntity(nearbyEntities[i], { + locked: false + }); + Entities.deleteEntity(nearbyEntities[i]); + } + } + } + } + + + + processProperties(); + setUp(); + Script.scriptEnding.connect(tearDown); + + return {}; +}; + +var leafSquall1 = new leafSquall({ + origin: { + x: 3071.5, + y: 2170, + z: 6765.3 + }, + radius: 100, + leavesPerMinute: 30, + leafSize: { + x: 0.3, + y: 0.00, + z: 0.3 + }, + leafFallSpeed: 0.4, + leafLifetime: 100, + leafSpinMax: 30, + debug: false, + maxLeaves: 100, + leafDeleteOnTearDown: true, + complexMovement: true, + floorHeight: 2143.5, + windFactor: 0.5, + leafDeleteOnGround: false +}); + +// todo //deal with depth issue \ No newline at end of file From 92595583ec280e81a3e9a5783a696bfce2b17063 Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Mon, 27 Jul 2015 11:55:17 -0700 Subject: [PATCH 37/58] Coding standard and building --- libraries/gpu/src/gpu/GLBackendTexture.cpp | 32 ------------------- .../render-utils/src/ambient_occlusion.slf | 4 +-- .../render-utils/src/occlusion_blend.slf | 7 ++-- 3 files changed, 5 insertions(+), 38 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 2696d17596..72c7de8504 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -144,38 +144,6 @@ public: case gpu::RGB: case gpu::RGBA: texel.internalFormat = GL_RED; - /* switch (dstFormat.getType()) { - case gpu::UINT32: - case gpu::INT32: - case gpu::NUINT32: - case gpu::NINT32: { - texel.internalFormat = GL_DEPTH_COMPONENT32; - break; - } - case gpu::NFLOAT: - case gpu::FLOAT: { - texel.internalFormat = GL_DEPTH_COMPONENT32F; - break; - } - case gpu::UINT16: - case gpu::INT16: - case gpu::NUINT16: - case gpu::NINT16: - case gpu::HALF: - case gpu::NHALF: { - texel.internalFormat = GL_DEPTH_COMPONENT16; - break; - } - case gpu::UINT8: - case gpu::INT8: - case gpu::NUINT8: - case gpu::NINT8: { - texel.internalFormat = GL_DEPTH_COMPONENT24; - break; - } - case gpu::NUM_TYPES: { // quiet compiler - Q_UNREACHABLE(); - }*/ break; case gpu::DEPTH: texel.format = GL_DEPTH_COMPONENT; // It's depth component to load it diff --git a/libraries/render-utils/src/ambient_occlusion.slf b/libraries/render-utils/src/ambient_occlusion.slf index 023fe2552c..7a80dd559e 100644 --- a/libraries/render-utils/src/ambient_occlusion.slf +++ b/libraries/render-utils/src/ambient_occlusion.slf @@ -45,7 +45,7 @@ void main(void) { TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); - vec3 eyeDir = vec3(0.0); + vec3 eyeDir = vec3(0.0, 0.0, -3.0); vec3 cameraPositionWorldSpace; <$transformEyeToWorldDir(cam, eyeDir, cameraPositionWorldSpace)$> @@ -104,6 +104,6 @@ void main(void) { occlusion = 1.0 - occlusion / float(SAMPLE_COUNT); occlusion = clamp(pow(occlusion, g_intensity), 0.0, 1.0); - gl_FragColor = vec4(occlusion, occlusion, occlusion, 1.0); + gl_FragColor = vec4(vec3(occlusion), 1.0); } diff --git a/libraries/render-utils/src/occlusion_blend.slf b/libraries/render-utils/src/occlusion_blend.slf index 6c0101eb6f..965d806759 100644 --- a/libraries/render-utils/src/occlusion_blend.slf +++ b/libraries/render-utils/src/occlusion_blend.slf @@ -22,9 +22,8 @@ void main(void) { vec4 occlusionColor = texture2D(blurredOcclusionTexture, varTexcoord); if(occlusionColor.r > 0.8 && occlusionColor.r <= 1.0) { - gl_FragColor = vec4(vec3(0.0), 1.0); - } - else { - gl_FragColor = vec4(vec3(0.2), 1.0); + gl_FragColor = vec4(vec3(0.0), 0.0); + } else { + gl_FragColor = vec4(vec3(occlusionColor.r), 1.0); } } From c46e73434c3819d3f2b043be95af123c498d5bd6 Mon Sep 17 00:00:00 2001 From: Bing Shearer Date: Mon, 27 Jul 2015 11:59:09 -0700 Subject: [PATCH 38/58] Added small fix to error message code --- examples/leaves.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/leaves.js b/examples/leaves.js index af3c2f0e23..4610cd2ef0 100755 --- a/examples/leaves.js +++ b/examples/leaves.js @@ -100,7 +100,7 @@ var leafSquall = function (properties) { } if (properties.hasOwnProperty("windFactor")) { windFactor = properties.windFactor; - } else { + } else if (complexMovement == true){ print("ERROR: Wind Factor must be defined for complex movement") } From 1193b89918dba29ab25a0d5d14ee0d2c2b9b525f Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Mon, 27 Jul 2015 12:14:29 -0700 Subject: [PATCH 39/58] Coding standard and tab fixes --- libraries/render-utils/src/AmbientOcclusionEffect.cpp | 6 +++--- libraries/render-utils/src/AmbientOcclusionEffect.h | 6 +++--- libraries/render-utils/src/gaussian_blur.slf | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index d7fa88b276..f19fa6e18a 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -1,9 +1,9 @@ // // AmbientOcclusionEffect.cpp -// interface/src/renderer +// libraries/render-utils/src/ // -// Created by Niraj Venkat on 7/14/13. -// Copyright 2013 High Fidelity, Inc. +// Created by Niraj Venkat on 7/15/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 diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 76cb0b063d..0b695dd2ad 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -1,9 +1,9 @@ // // AmbientOcclusionEffect.h -// interface/src/renderer +// libraries/render-utils/src/ // -// Created by Andrzej Kapolka on 7/14/13. -// Copyright 2013 High Fidelity, Inc. +// Created by Niraj Venkat on 7/15/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 diff --git a/libraries/render-utils/src/gaussian_blur.slf b/libraries/render-utils/src/gaussian_blur.slf index 5b66a0b751..772a80249c 100644 --- a/libraries/render-utils/src/gaussian_blur.slf +++ b/libraries/render-utils/src/gaussian_blur.slf @@ -23,7 +23,7 @@ varying vec2 varBlurTexcoords[14]; uniform sampler2D occlusionTexture; void main(void) { - gl_FragColor = vec4(0.0); + gl_FragColor = vec4(0.0); gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 0])*0.0044299121055113265; gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 1])*0.00895781211794; gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 2])*0.0215963866053; From d2ee74f7c7c844783fd7558771d1aaf51efc22af Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Mon, 27 Jul 2015 12:20:41 -0700 Subject: [PATCH 40/58] Shader code indentation --- .../render-utils/src/ambient_occlusion.slf | 12 ++++---- libraries/render-utils/src/gaussian_blur.slf | 22 +++++++-------- .../src/gaussian_blur_horizontal.slv | 28 +++++++++---------- .../src/gaussian_blur_vertical.slv | 28 +++++++++---------- 4 files changed, 45 insertions(+), 45 deletions(-) diff --git a/libraries/render-utils/src/ambient_occlusion.slf b/libraries/render-utils/src/ambient_occlusion.slf index 7a80dd559e..3a49accf58 100644 --- a/libraries/render-utils/src/ambient_occlusion.slf +++ b/libraries/render-utils/src/ambient_occlusion.slf @@ -80,10 +80,10 @@ void main(void) { vec3 normal = normalize(texture2D(normalTexture, varTexcoord).xyz); //normal = normalize(normal * normalMatrix); - vec3 rvec = vec3(getRandom(varTexcoord.xy), getRandom(varTexcoord.yx), getRandom(varTexcoord.xx)) * 2.0 - 1.0; + vec3 rvec = vec3(getRandom(varTexcoord.xy), getRandom(varTexcoord.yx), getRandom(varTexcoord.xx)) * 2.0 - 1.0; vec3 tangent = normalize(rvec - normal * dot(rvec, normal)); - vec3 bitangent = cross(normal, tangent); - mat3 tbn = mat3(tangent, bitangent, normal); + vec3 bitangent = cross(normal, tangent); + mat3 tbn = mat3(tangent, bitangent, normal); float occlusion = 0.0; @@ -91,13 +91,13 @@ void main(void) { vec3 samplePos = origin + (tbn * sampleKernel[i]) * g_sample_rad; vec4 offset = cam._projectionViewUntranslated * vec4(samplePos, 1.0); - offset.xy = (offset.xy / offset.w) * 0.5 + 0.5; + offset.xy = (offset.xy / offset.w) * 0.5 + 0.5; float depth = length(samplePos - cameraPositionWorldSpace); float sampleDepthVal = texture2D(depthTexture, offset.xy).r; - float rangeDelta = abs(depthVal - sampleDepthVal); - float rangeCheck = smoothstep(0.0, 1.0, g_sample_rad / rangeDelta); + float rangeDelta = abs(depthVal - sampleDepthVal); + float rangeCheck = smoothstep(0.0, 1.0, g_sample_rad / rangeDelta); occlusion += rangeCheck * step(sampleDepthVal, depth); } diff --git a/libraries/render-utils/src/gaussian_blur.slf b/libraries/render-utils/src/gaussian_blur.slf index 772a80249c..63ba14a07c 100644 --- a/libraries/render-utils/src/gaussian_blur.slf +++ b/libraries/render-utils/src/gaussian_blur.slf @@ -24,17 +24,17 @@ uniform sampler2D occlusionTexture; void main(void) { gl_FragColor = vec4(0.0); - gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 0])*0.0044299121055113265; - gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 1])*0.00895781211794; - gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 2])*0.0215963866053; - gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 3])*0.0443683338718; - gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 4])*0.0776744219933; - gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 5])*0.115876621105; - gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 6])*0.147308056121; - gl_FragColor += texture2D(occlusionTexture, varTexcoord )*0.159576912161; - gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 7])*0.147308056121; - gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 8])*0.115876621105; - gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[ 9])*0.0776744219933; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[0])*0.0044299121055113265; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[1])*0.00895781211794; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[2])*0.0215963866053; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[3])*0.0443683338718; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[4])*0.0776744219933; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[5])*0.115876621105; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[6])*0.147308056121; + gl_FragColor += texture2D(occlusionTexture, varTexcoord)*0.159576912161; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[7])*0.147308056121; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[8])*0.115876621105; + gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[9])*0.0776744219933; gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[10])*0.0443683338718; gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[11])*0.0215963866053; gl_FragColor += texture2D(occlusionTexture, varBlurTexcoords[12])*0.00895781211794; diff --git a/libraries/render-utils/src/gaussian_blur_horizontal.slv b/libraries/render-utils/src/gaussian_blur_horizontal.slv index 94631b4b08..c3f326daac 100644 --- a/libraries/render-utils/src/gaussian_blur_horizontal.slv +++ b/libraries/render-utils/src/gaussian_blur_horizontal.slv @@ -23,19 +23,19 @@ void main(void) { varTexcoord = gl_MultiTexCoord0.xy; gl_Position = gl_Vertex; - varBlurTexcoords[ 0] = varTexcoord + vec2(-0.028, 0.0); - varBlurTexcoords[ 1] = varTexcoord + vec2(-0.024, 0.0); - varBlurTexcoords[ 2] = varTexcoord + vec2(-0.020, 0.0); - varBlurTexcoords[ 3] = varTexcoord + vec2(-0.016, 0.0); - varBlurTexcoords[ 4] = varTexcoord + vec2(-0.012, 0.0); - varBlurTexcoords[ 5] = varTexcoord + vec2(-0.008, 0.0); - varBlurTexcoords[ 6] = varTexcoord + vec2(-0.004, 0.0); - varBlurTexcoords[ 7] = varTexcoord + vec2( 0.004, 0.0); - varBlurTexcoords[ 8] = varTexcoord + vec2( 0.008, 0.0); - varBlurTexcoords[ 9] = varTexcoord + vec2( 0.012, 0.0); - varBlurTexcoords[10] = varTexcoord + vec2( 0.016, 0.0); - varBlurTexcoords[11] = varTexcoord + vec2( 0.020, 0.0); - varBlurTexcoords[12] = varTexcoord + vec2( 0.024, 0.0); - varBlurTexcoords[13] = varTexcoord + vec2( 0.028, 0.0); + varBlurTexcoords[0] = varTexcoord + vec2(-0.028, 0.0); + varBlurTexcoords[1] = varTexcoord + vec2(-0.024, 0.0); + varBlurTexcoords[2] = varTexcoord + vec2(-0.020, 0.0); + varBlurTexcoords[3] = varTexcoord + vec2(-0.016, 0.0); + varBlurTexcoords[4] = varTexcoord + vec2(-0.012, 0.0); + varBlurTexcoords[5] = varTexcoord + vec2(-0.008, 0.0); + varBlurTexcoords[6] = varTexcoord + vec2(-0.004, 0.0); + varBlurTexcoords[7] = varTexcoord + vec2(0.004, 0.0); + varBlurTexcoords[8] = varTexcoord + vec2(0.008, 0.0); + varBlurTexcoords[9] = varTexcoord + vec2(0.012, 0.0); + varBlurTexcoords[10] = varTexcoord + vec2(0.016, 0.0); + varBlurTexcoords[11] = varTexcoord + vec2(0.020, 0.0); + varBlurTexcoords[12] = varTexcoord + vec2(0.024, 0.0); + varBlurTexcoords[13] = varTexcoord + vec2(0.028, 0.0); } \ No newline at end of file diff --git a/libraries/render-utils/src/gaussian_blur_vertical.slv b/libraries/render-utils/src/gaussian_blur_vertical.slv index 0d6de35b85..fc35a96bf0 100644 --- a/libraries/render-utils/src/gaussian_blur_vertical.slv +++ b/libraries/render-utils/src/gaussian_blur_vertical.slv @@ -23,19 +23,19 @@ void main(void) { varTexcoord = gl_MultiTexCoord0.xy; gl_Position = gl_Vertex; - varBlurTexcoords[ 0] = varTexcoord + vec2(0.0, -0.028); - varBlurTexcoords[ 1] = varTexcoord + vec2(0.0, -0.024); - varBlurTexcoords[ 2] = varTexcoord + vec2(0.0, -0.020); - varBlurTexcoords[ 3] = varTexcoord + vec2(0.0, -0.016); - varBlurTexcoords[ 4] = varTexcoord + vec2(0.0, -0.012); - varBlurTexcoords[ 5] = varTexcoord + vec2(0.0, -0.008); - varBlurTexcoords[ 6] = varTexcoord + vec2(0.0, -0.004); - varBlurTexcoords[ 7] = varTexcoord + vec2(0.0, 0.004); - varBlurTexcoords[ 8] = varTexcoord + vec2(0.0, 0.008); - varBlurTexcoords[ 9] = varTexcoord + vec2(0.0, 0.012); - varBlurTexcoords[10] = varTexcoord + vec2(0.0, 0.016); - varBlurTexcoords[11] = varTexcoord + vec2(0.0, 0.020); - varBlurTexcoords[12] = varTexcoord + vec2(0.0, 0.024); - varBlurTexcoords[13] = varTexcoord + vec2(0.0, 0.028); + varBlurTexcoords[0] = varTexcoord + vec2(0.0, -0.028); + varBlurTexcoords[1] = varTexcoord + vec2(0.0, -0.024); + varBlurTexcoords[2] = varTexcoord + vec2(0.0, -0.020); + varBlurTexcoords[3] = varTexcoord + vec2(0.0, -0.016); + varBlurTexcoords[4] = varTexcoord + vec2(0.0, -0.012); + varBlurTexcoords[5] = varTexcoord + vec2(0.0, -0.008); + varBlurTexcoords[6] = varTexcoord + vec2(0.0, -0.004); + varBlurTexcoords[7] = varTexcoord + vec2(0.0, 0.004); + varBlurTexcoords[8] = varTexcoord + vec2(0.0, 0.008); + varBlurTexcoords[9] = varTexcoord + vec2(0.0, 0.012); + varBlurTexcoords[10] = varTexcoord + vec2(0.0, 0.016); + varBlurTexcoords[11] = varTexcoord + vec2(0.0, 0.020); + varBlurTexcoords[12] = varTexcoord + vec2(0.0, 0.024); + varBlurTexcoords[13] = varTexcoord + vec2(0.0, 0.028); } \ No newline at end of file From 34e400ac67a04983976ec276711ec39ff3816fdf Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Mon, 27 Jul 2015 17:14:09 -0700 Subject: [PATCH 41/58] Changing var name to 'DebugAmbientOcclusion' --- interface/src/Application.cpp | 2 +- interface/src/Menu.cpp | 2 +- interface/src/Menu.h | 2 +- tests/ui/src/main.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9d28e40a66..093f87b494 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3265,7 +3265,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se renderContext._drawItemStatus = sceneInterface->doEngineDisplayItemStatus(); - renderContext._occlusionStatus = Menu::getInstance()->isOptionChecked(MenuOption::AmbientOcclusion); + renderContext._occlusionStatus = Menu::getInstance()->isOptionChecked(MenuOption::DebugAmbientOcclusion); renderArgs->_shouldRender = LODManager::shouldRender; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 91ae6a4d02..ea284d4f23 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -330,7 +330,7 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere, 0, // QML Qt::SHIFT | Qt::Key_A, true); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AmbientOcclusion); + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DebugAmbientOcclusion); MenuWrapper* ambientLightMenu = renderOptionsMenu->addMenu(MenuOption::RenderAmbientLight); QActionGroup* ambientLightGroup = new QActionGroup(ambientLightMenu); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 8ad71bbdaa..4c3e9332a1 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -134,7 +134,6 @@ namespace MenuOption { const QString AddressBar = "Show Address Bar"; const QString AlignForearmsWithWrists = "Align Forearms with Wrists"; const QString AlternateIK = "Alternate IK"; - const QString AmbientOcclusion = "Debug Ambient Occlusion"; const QString Animations = "Animations..."; const QString Atmosphere = "Atmosphere"; const QString Attachments = "Attachments..."; @@ -165,6 +164,7 @@ namespace MenuOption { const QString ControlWithSpeech = "Control With Speech"; const QString CopyAddress = "Copy Address to Clipboard"; const QString CopyPath = "Copy Path to Clipboard"; + const QString DebugAmbientOcclusion = "Debug Ambient Occlusion"; const QString DecreaseAvatarSize = "Decrease Avatar Size"; const QString DeleteBookmark = "Delete Bookmark..."; const QString DisableActivityLogger = "Disable Activity Logger"; diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp index f5647bd176..919c27f32f 100644 --- a/tests/ui/src/main.cpp +++ b/tests/ui/src/main.cpp @@ -86,7 +86,6 @@ public: AddressBar, AlignForearmsWithWrists, AlternateIK, - AmbientOcclusion, Animations, Atmosphere, Attachments, @@ -111,6 +110,7 @@ public: ControlWithSpeech, CopyAddress, CopyPath, + DebugAmbientOcclusion, DecreaseAvatarSize, DeleteBookmark, DisableActivityLogger, From f4a23065b4adbd86ec5a674cf5c65b886bad8a6a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 27 Jul 2015 19:06:14 -0700 Subject: [PATCH 42/58] if obj data isn't from a url, don't dereference null url pointer --- libraries/fbx/src/OBJReader.cpp | 72 +++++++++++++++++++-------------- libraries/fbx/src/OBJReader.h | 7 ++-- 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 2ec80e3d85..f16c6ba215 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -195,7 +195,10 @@ void OBJFace::addFrom(const OBJFace* face, int index) { // add using data from f } bool OBJReader::isValidTexture(const QByteArray &filename) { - QUrl candidateUrl = url->resolved(QUrl(filename)); + if (!_url) { + return false; + } + QUrl candidateUrl = _url->resolved(QUrl(filename)); QNetworkReply *netReply = request(candidateUrl, true); bool isValid = netReply->isFinished() && (netReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200); netReply->deleteLater(); @@ -242,7 +245,7 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { } else if ((token == "map_Kd") || (token == "map_Ks")) { QByteArray filename = QUrl(tokenizer.getLineAsDatum()).fileName().toUtf8(); if (filename.endsWith(".tga")) { - qCDebug(modelformat) << "OBJ Reader WARNING: currently ignoring tga texture " << filename << " in " << url; + qCDebug(modelformat) << "OBJ Reader WARNING: currently ignoring tga texture " << filename << " in " << _url; break; } if (isValidTexture(filename)) { @@ -252,7 +255,7 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { currentMaterial.specularTextureFilename = filename; } } else { - qCDebug(modelformat) << "OBJ Reader WARNING: " << url << " ignoring missing texture " << filename; + qCDebug(modelformat) << "OBJ Reader WARNING: " << _url << " ignoring missing texture " << filename; } } } @@ -316,7 +319,7 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi QByteArray groupName = tokenizer.getDatum(); currentGroup = groupName; //qCDebug(modelformat) << "new group:" << groupName; - } else if (token == "mtllib") { + } else if (token == "mtllib" && _url) { if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { break; } @@ -325,13 +328,15 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi break; // Some files use mtllib over and over again for the same libraryName } librariesSeen[libraryName] = true; - QUrl libraryUrl = url->resolved(QUrl(libraryName).fileName()); // Throw away any path part of libraryName, and merge against original url. + // Throw away any path part of libraryName, and merge against original url. + QUrl libraryUrl = _url->resolved(QUrl(libraryName).fileName()); qCDebug(modelformat) << "OBJ Reader new library:" << libraryName << " at:" << libraryUrl; QNetworkReply* netReply = request(libraryUrl, false); if (netReply->isFinished() && (netReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200)) { parseMaterialLibrary(netReply); } else { - qCDebug(modelformat) << "OBJ Reader " << libraryName << " did not answer. Got " << netReply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString(); + qCDebug(modelformat) << "OBJ Reader " << libraryName << " did not answer. Got " + << netReply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString(); } netReply->deleteLater(); } else if (token == "usemtl") { @@ -406,10 +411,10 @@ FBXGeometry OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, Q OBJTokenizer tokenizer(device); float scaleGuess = 1.0f; - this->url = url; + _url = url; geometry.meshExtents.reset(); geometry.meshes.append(FBXMesh()); - + try { // call parseOBJGroup as long as it's returning true. Each successful call will // add a new meshPart to the geometry's single mesh. @@ -417,7 +422,7 @@ FBXGeometry OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, Q FBXMesh& mesh = geometry.meshes[0]; mesh.meshIndex = 0; - + geometry.joints.resize(1); geometry.joints[0].isFree = false; geometry.joints[0].parentIndex = -1; @@ -440,37 +445,44 @@ FBXGeometry OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, Q 0, 0, 1, 0, 0, 0, 0, 1); mesh.clusters.append(cluster); - - // Some .obj files use the convention that a group with uv coordinates that doesn't define a material, should use a texture with the same basename as the .obj file. - QString filename = url->fileName(); - int extIndex = filename.lastIndexOf('.'); // by construction, this does not fail - QString basename = filename.remove(extIndex + 1, sizeof("obj")); - OBJMaterial& preDefinedMaterial = materials[SMART_DEFAULT_MATERIAL_NAME]; - preDefinedMaterial.diffuseColor = glm::vec3(1.0f); - QVector extensions = {"jpg", "jpeg", "png", "tga"}; - QByteArray base = basename.toUtf8(), textName = ""; - for (int i = 0; i < extensions.count(); i++) { - QByteArray candidateString = base + extensions[i]; - if (isValidTexture(candidateString)) { - textName = candidateString; - break; + + // Some .obj files use the convention that a group with uv coordinates that doesn't define a material, should use + // a texture with the same basename as the .obj file. + if (url) { + QString filename = url->fileName(); + int extIndex = filename.lastIndexOf('.'); // by construction, this does not fail + QString basename = filename.remove(extIndex + 1, sizeof("obj")); + OBJMaterial& preDefinedMaterial = materials[SMART_DEFAULT_MATERIAL_NAME]; + preDefinedMaterial.diffuseColor = glm::vec3(1.0f); + QVector extensions = {"jpg", "jpeg", "png", "tga"}; + QByteArray base = basename.toUtf8(), textName = ""; + for (int i = 0; i < extensions.count(); i++) { + QByteArray candidateString = base + extensions[i]; + if (isValidTexture(candidateString)) { + textName = candidateString; + break; + } } + + if (!textName.isEmpty()) { + preDefinedMaterial.diffuseTextureFilename = textName; + } + materials[SMART_DEFAULT_MATERIAL_NAME] = preDefinedMaterial; } - if (!textName.isEmpty()) { - preDefinedMaterial.diffuseTextureFilename = textName; - } - materials[SMART_DEFAULT_MATERIAL_NAME] = preDefinedMaterial; - + for (int i = 0, meshPartCount = 0; i < mesh.parts.count(); i++, meshPartCount++) { FBXMeshPart& meshPart = mesh.parts[i]; FaceGroup faceGroup = faceGroups[meshPartCount]; OBJFace leadFace = faceGroup[0]; // All the faces in the same group will have the same name and material. QString groupMaterialName = leadFace.materialName; if (groupMaterialName.isEmpty() && (leadFace.textureUVIndices.count() > 0)) { - qCDebug(modelformat) << "OBJ Reader WARNING: " << url << " needs a texture that isn't specified. Using default mechanism."; + qCDebug(modelformat) << "OBJ Reader WARNING: " << url + << " needs a texture that isn't specified. Using default mechanism."; groupMaterialName = SMART_DEFAULT_MATERIAL_NAME; } else if (!groupMaterialName.isEmpty() && !materials.contains(groupMaterialName)) { - qCDebug(modelformat) << "OBJ Reader WARNING: " << url << " specifies a material " << groupMaterialName << " that is not defined. Using default mechanism."; + qCDebug(modelformat) << "OBJ Reader WARNING: " << url + << " specifies a material " << groupMaterialName + << " that is not defined. Using default mechanism."; groupMaterialName = SMART_DEFAULT_MATERIAL_NAME; } if (!groupMaterialName.isEmpty()) { diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h index 771c0b1b63..2e7b050b0a 100644 --- a/libraries/fbx/src/OBJReader.h +++ b/libraries/fbx/src/OBJReader.h @@ -69,12 +69,13 @@ public: QVector faceGroups; QString currentMaterialName; QHash materials; - QUrl* url; - + QNetworkReply* request(QUrl& url, bool isTest); FBXGeometry readOBJ(const QByteArray& model, const QVariantHash& mapping); FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping, QUrl* url); private: + QUrl* _url = nullptr; + QHash librariesSeen; bool parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, float& scaleGuess); void parseMaterialLibrary(QIODevice* device); @@ -83,4 +84,4 @@ private: // What are these utilities doing here? One is used by fbx loading code in VHACD Utils, and the other a general debugging utility. void setMeshPartDefaults(FBXMeshPart& meshPart, QString materialID); -void fbxDebugDump(const FBXGeometry& fbxgeo); \ No newline at end of file +void fbxDebugDump(const FBXGeometry& fbxgeo); From 8a7cdb1c64f0fd13f5473252ca13a5df1f59da6d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 27 Jul 2015 19:53:38 -0700 Subject: [PATCH 43/58] Make Throttle FPS If Not Focus be enabled by default --- interface/src/Application.cpp | 2 +- interface/src/Menu.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bb564824b0..161e36d649 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -330,7 +330,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _lastNackTime(usecTimestampNow()), _lastSendDownstreamAudioStats(usecTimestampNow()), _isVSyncOn(true), - _isThrottleFPSEnabled(false), + _isThrottleFPSEnabled(true), _aboutToQuit(false), _notifiedPacketVersionMismatchThisDomain(false), _glWidget(new GLCanvas()), diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 91ae6a4d02..424c9b2227 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -368,7 +368,7 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::RenderTargetFramerateVSyncOn, 0, true, qApp, SLOT(setVSyncEnabled())); #endif - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ThrottleFPSIfNotFocus, 0, false, + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ThrottleFPSIfNotFocus, 0, true, qApp, SLOT(setThrottleFPSEnabled())); } From 2aa453b6102f0fb092283a5644498fcf7c355aeb Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 28 Jul 2015 12:05:45 -0700 Subject: [PATCH 44/58] fix build errors for shared-tests --- tests/shared/src/AngularConstraintTests.cpp | 1 + tests/shared/src/AngularConstraintTests.h | 7 ++----- tests/shared/src/MovingPercentileTests.cpp | 1 + tests/shared/src/MovingPercentileTests.h | 1 - tests/shared/src/TransformTests.cpp | 4 +++- tests/shared/src/TransformTests.h | 2 -- 6 files changed, 7 insertions(+), 9 deletions(-) diff --git a/tests/shared/src/AngularConstraintTests.cpp b/tests/shared/src/AngularConstraintTests.cpp index 95c5db18c2..4dcf3d7296 100644 --- a/tests/shared/src/AngularConstraintTests.cpp +++ b/tests/shared/src/AngularConstraintTests.cpp @@ -16,6 +16,7 @@ #include #include "AngularConstraintTests.h" +#include "../QTestExtensions.h" // Computes the error value between two quaternions (using glm::dot) float getErrorDifference(const glm::quat& a, const glm::quat& b) { diff --git a/tests/shared/src/AngularConstraintTests.h b/tests/shared/src/AngularConstraintTests.h index df2fe8e9c3..705639b571 100644 --- a/tests/shared/src/AngularConstraintTests.h +++ b/tests/shared/src/AngularConstraintTests.h @@ -12,6 +12,7 @@ #ifndef hifi_AngularConstraintTests_h #define hifi_AngularConstraintTests_h +#include #include class AngularConstraintTests : public QObject { @@ -21,10 +22,6 @@ private slots: void testConeRollerConstraint(); }; -// Use QCOMPARE_WITH_ABS_ERROR and define it for glm::quat -#include -float getErrorDifference (const glm::quat& a, const glm::quat& b); -QTextStream & operator << (QTextStream& stream, const glm::quat& q); -#include "../QTestExtensions.h" +float getErrorDifference(const glm::quat& a, const glm::quat& b); #endif // hifi_AngularConstraintTests_h diff --git a/tests/shared/src/MovingPercentileTests.cpp b/tests/shared/src/MovingPercentileTests.cpp index b9593fca83..fbbc3c7b9e 100644 --- a/tests/shared/src/MovingPercentileTests.cpp +++ b/tests/shared/src/MovingPercentileTests.cpp @@ -16,6 +16,7 @@ #include #include +#include <../QTestExtensions.h> QTEST_MAIN(MovingPercentileTests) diff --git a/tests/shared/src/MovingPercentileTests.h b/tests/shared/src/MovingPercentileTests.h index 4a1d4b33d2..ffc8ddb0f6 100644 --- a/tests/shared/src/MovingPercentileTests.h +++ b/tests/shared/src/MovingPercentileTests.h @@ -13,7 +13,6 @@ #define hifi_MovingPercentileTests_h #include -#include <../QTestExtensions.h> class MovingPercentileTests : public QObject { Q_OBJECT diff --git a/tests/shared/src/TransformTests.cpp b/tests/shared/src/TransformTests.cpp index 93b0583aa6..be22914b9d 100644 --- a/tests/shared/src/TransformTests.cpp +++ b/tests/shared/src/TransformTests.cpp @@ -8,10 +8,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "TransformTests.h" + #include -#include "TransformTests.h" #include "SharedLogging.h" +#include <../QTestExtensions.h> using namespace glm; diff --git a/tests/shared/src/TransformTests.h b/tests/shared/src/TransformTests.h index ab5c8cf144..a4d9b2a6c0 100644 --- a/tests/shared/src/TransformTests.h +++ b/tests/shared/src/TransformTests.h @@ -40,8 +40,6 @@ inline QTextStream& operator<< (QTextStream& stream, const glm::mat4& matrix) { return stream; } -#include <../QTestExtensions.h> - class TransformTests : public QObject { Q_OBJECT private slots: From d03a7d1b701d0459468ac7d4afe908d973957707 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 28 Jul 2015 12:24:17 -0700 Subject: [PATCH 45/58] fix physics-tests build errors --- tests/physics/src/BulletUtilTests.cpp | 7 +- tests/physics/src/BulletUtilTests.h | 3 - tests/physics/src/CollisionInfoTests.cpp | 70 ------------------- tests/physics/src/CollisionInfoTests.h | 29 -------- tests/physics/src/MeshMassPropertiesTests.cpp | 8 ++- tests/physics/src/MeshMassPropertiesTests.h | 6 -- tests/physics/src/ShapeColliderTests.cpp | 14 ++-- tests/physics/src/ShapeColliderTests.h | 7 -- 8 files changed, 18 insertions(+), 126 deletions(-) delete mode 100644 tests/physics/src/CollisionInfoTests.cpp delete mode 100644 tests/physics/src/CollisionInfoTests.h diff --git a/tests/physics/src/BulletUtilTests.cpp b/tests/physics/src/BulletUtilTests.cpp index bbd88f88b7..181d22327e 100644 --- a/tests/physics/src/BulletUtilTests.cpp +++ b/tests/physics/src/BulletUtilTests.cpp @@ -9,13 +9,16 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "BulletUtilTests.h" + #include -//#include "PhysicsTestUtil.h" #include #include -#include "BulletUtilTests.h" +// Add additional qtest functionality (the include order is important!) +#include "GlmTestUtils.h" +#include "../QTestExtensions.h" // Constants const glm::vec3 origin(0.0f); diff --git a/tests/physics/src/BulletUtilTests.h b/tests/physics/src/BulletUtilTests.h index fd4fe13d09..e8fee1e473 100644 --- a/tests/physics/src/BulletUtilTests.h +++ b/tests/physics/src/BulletUtilTests.h @@ -13,9 +13,6 @@ #define hifi_BulletUtilTests_h #include -// Add additional qtest functionality (the include order is important!) -#include "GlmTestUtils.h" -#include "../QTestExtensions.h" class BulletUtilTests : public QObject { Q_OBJECT diff --git a/tests/physics/src/CollisionInfoTests.cpp b/tests/physics/src/CollisionInfoTests.cpp deleted file mode 100644 index 70e2e14bb0..0000000000 --- a/tests/physics/src/CollisionInfoTests.cpp +++ /dev/null @@ -1,70 +0,0 @@ -// -// CollisionInfoTests.cpp -// tests/physics/src -// -// Created by Andrew Meadows on 2/21/2014. -// Copyright 2014 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 - -#include -#include - -#include -#include -#include - -#include "CollisionInfoTests.h" - - - -QTEST_MAIN(CollisionInfoTests) -/* -static glm::vec3 xAxis(1.0f, 0.0f, 0.0f); -static glm::vec3 xZxis(0.0f, 1.0f, 0.0f); -static glm::vec3 xYxis(0.0f, 0.0f, 1.0f); - -void CollisionInfoTests::rotateThenTranslate() { - CollisionInfo collision; - collision._penetration = xAxis; - collision._contactPoint = xYxis; - collision._addedVelocity = xAxis + xYxis + xZxis; - - glm::quat rotation = glm::angleAxis(PI_OVER_TWO, zAxis); - float distance = 3.0f; - glm::vec3 translation = distance * xYxis; - - collision.rotateThenTranslate(rotation, translation); - QCOMPARE(collision._penetration, xYxis); - - glm::vec3 expectedContactPoint = -xAxis + translation; - QCOMPARE(collision._contactPoint, expectedContactPoint); - - glm::vec3 expectedAddedVelocity = xYxis - xAxis + xZxis; - QCOMPARE(collision._addedVelocity, expectedAddedVelocity); -} - -void CollisionInfoTests::translateThenRotate() { - CollisionInfo collision; - collision._penetration = xAxis; - collision._contactPoint = xYxis; - collision._addedVelocity = xAxis + xYxis + xZxis; - - glm::quat rotation = glm::angleAxis( -PI_OVER_TWO, zAxis); - float distance = 3.0f; - glm::vec3 translation = distance * xYxis; - - collision.translateThenRotate(translation, rotation); - QCOMPARE(collision._penetration, -xYxis); - - glm::vec3 expectedContactPoint = (1.0f + distance) * xAxis; - QCOMPARE(collision._contactPoint, expectedContactPoint); - - glm::vec3 expectedAddedVelocity = - xYxis + xAxis + xYxis; - QCOMPARE(collision._addedVelocity, expectedAddedVelocity); -}*/ - diff --git a/tests/physics/src/CollisionInfoTests.h b/tests/physics/src/CollisionInfoTests.h deleted file mode 100644 index d26d39be4b..0000000000 --- a/tests/physics/src/CollisionInfoTests.h +++ /dev/null @@ -1,29 +0,0 @@ -// -// CollisionInfoTests.h -// tests/physics/src -// -// Created by Andrew Meadows on 2/21/2014. -// Copyright 2014 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_CollisionInfoTests_h -#define hifi_CollisionInfoTests_h - -#include - -// Add additional qtest functionality (the include order is important!) -#include "GlmTestUtils.h" -#include "../QTestExtensions.h" - -class CollisionInfoTests : public QObject { - Q_OBJECT - -private slots: -// void rotateThenTranslate(); -// void translateThenRotate(); -}; - -#endif // hifi_CollisionInfoTests_h diff --git a/tests/physics/src/MeshMassPropertiesTests.cpp b/tests/physics/src/MeshMassPropertiesTests.cpp index 794eee0fcf..e88bcae1b7 100644 --- a/tests/physics/src/MeshMassPropertiesTests.cpp +++ b/tests/physics/src/MeshMassPropertiesTests.cpp @@ -9,11 +9,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "MeshMassPropertiesTests.h" + #include -#include #include -#include "MeshMassPropertiesTests.h" +// Add additional qtest functionality (the include order is important!) +#include "BulletTestUtils.h" +#include "GlmTestUtils.h" +#include "../QTestExtensions.h" const btScalar acceptableRelativeError(1.0e-5f); const btScalar acceptableAbsoluteError(1.0e-4f); diff --git a/tests/physics/src/MeshMassPropertiesTests.h b/tests/physics/src/MeshMassPropertiesTests.h index 35471bdbad..b8af9d9db6 100644 --- a/tests/physics/src/MeshMassPropertiesTests.h +++ b/tests/physics/src/MeshMassPropertiesTests.h @@ -13,12 +13,6 @@ #define hifi_MeshMassPropertiesTests_h #include -#include - -// Add additional qtest functionality (the include order is important!) -#include "BulletTestUtils.h" -#include "GlmTestUtils.h" -#include "../QTestExtensions.h" // Relative error macro (see errorTest in BulletTestUtils.h) #define QCOMPARE_WITH_RELATIVE_ERROR(actual, expected, relativeError) \ diff --git a/tests/physics/src/ShapeColliderTests.cpp b/tests/physics/src/ShapeColliderTests.cpp index cb42f534cb..cb51e18fbd 100644 --- a/tests/physics/src/ShapeColliderTests.cpp +++ b/tests/physics/src/ShapeColliderTests.cpp @@ -9,12 +9,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ShapeColliderTests.h" + //#include #include #include #include #include +#include #include #include @@ -25,7 +28,10 @@ #include #include -#include "ShapeColliderTests.h" +// Add additional qtest functionality (the include order is important!) +#include "BulletTestUtils.h" +#include "GlmTestUtils.h" +#include "../QTestExtensions.h" const glm::vec3 origin(0.0f); @@ -1553,8 +1559,6 @@ void ShapeColliderTests::rayHitsCapsule() { intersection._rayDirection = - xAxis; QCOMPARE(capsule.findRayIntersection(intersection), true); float expectedDistance = startDistance - radius * sqrtf(2.0f * delta); // using small angle approximation of cosine -// float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; - // for edge cases we allow a LOT of error QCOMPARE_WITH_ABS_ERROR(intersection._hitDistance, expectedDistance, startDistance * EDGE_CASE_SLOP_FACTOR * EPSILON); } @@ -1564,8 +1568,6 @@ void ShapeColliderTests::rayHitsCapsule() { intersection._rayDirection = - xAxis; QCOMPARE(capsule.findRayIntersection(intersection), true); float expectedDistance = startDistance - radius * sqrtf(2.0f * delta); // using small angle approximation of cosine -// float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; - // for edge cases we allow a LOT of error QCOMPARE_WITH_ABS_ERROR(intersection._hitDistance, expectedDistance, startDistance * EPSILON * EDGE_CASE_SLOP_FACTOR); } @@ -1575,8 +1577,6 @@ void ShapeColliderTests::rayHitsCapsule() { intersection._rayDirection = - xAxis; QCOMPARE(capsule.findRayIntersection(intersection), true); float expectedDistance = startDistance - radius * sqrtf(2.0f * delta); // using small angle approximation of cosine - float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; - // for edge cases we allow a LOT of error QCOMPARE_WITH_ABS_ERROR(intersection._hitDistance, expectedDistance, startDistance * EPSILON * EDGE_CASE_SLOP_FACTOR); } // TODO: test at steep angles near cylinder/cap junction diff --git a/tests/physics/src/ShapeColliderTests.h b/tests/physics/src/ShapeColliderTests.h index 48d9cbd742..73e2b972a9 100644 --- a/tests/physics/src/ShapeColliderTests.h +++ b/tests/physics/src/ShapeColliderTests.h @@ -13,13 +13,6 @@ #define hifi_ShapeColliderTests_h #include -#include - -// Add additional qtest functionality (the include order is important!) -#include "BulletTestUtils.h" -#include "GlmTestUtils.h" -#include "../QTestExtensions.h" - class ShapeColliderTests : public QObject { Q_OBJECT From b46ad0c39780d475de0ed90d2b84029e2616ca96 Mon Sep 17 00:00:00 2001 From: bwent Date: Wed, 15 Jul 2015 11:50:10 -0700 Subject: [PATCH 46/58] Created subpanel panel item --- examples/utilities/tools/cookies.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index 0fdae01c5e..8b4d739c02 100644 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -416,6 +416,8 @@ DirectionBox = function(x,y,width,thumbSize) { this.onValueChanged = function(value) {}; } + + var textFontSize = 12; function PanelItem(name, setter, getter, displayer, x, y, textWidth, valueWidth, height) { @@ -429,7 +431,7 @@ function PanelItem(name, setter, getter, displayer, x, y, textWidth, valueWidth, } else if (value == false) { return "Off"; } - return value.toFixed(2); + return value; }; var topMargin = (height - textFontSize); @@ -616,7 +618,7 @@ Panel = function(x, y) { // print("created Item... colorBox=" + name); }; - this.newDirectionBox= function(name, setValue, getValue, displayValue) { + this.newDirectionBox = function(name, setValue, getValue, displayValue) { var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); @@ -630,6 +632,20 @@ Panel = function(x, y) { // print("created Item... directionBox=" + name); }; + this.newSubPanel = function(name) { + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); + + var panel = new Panel(this.widgetX, this.nextY); + + item.widget = panel; + + item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; + + this.nextY += rawYDelta; + + }; + + this.destroy = function() { for (var i in this.items) { this.items[i].destroy(); From 4ae03184ecfcab1377b9ac7911f792a9b34a0061 Mon Sep 17 00:00:00 2001 From: bwent Date: Tue, 21 Jul 2015 10:23:41 -0700 Subject: [PATCH 47/58] add subpanel functionality --- examples/utilities/tools/cookies.js | 242 +++++++++++++++++++++++++--- 1 file changed, 223 insertions(+), 19 deletions(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index 8b4d739c02..2949626252 100644 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -92,7 +92,6 @@ Slider = function(x,y,width,thumbSize) { this.isMoving = false; }; - // Public members: this.setNormalizedValue = function(value) { if (value < 0.0) { @@ -113,10 +112,19 @@ Slider = function(x,y,width,thumbSize) { this.setNormalizedValue(normValue); }; + this.reset = function(resetValue) { + this.setValue(resetValue); + this.onValueChanged(resetValue); + }; + this.getValue = function() { return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue; }; + this.getHeight = function() { + return 1.5 * this.thumbSize; + } + this.onValueChanged = function(value) {}; this.destroy = function() { @@ -130,6 +138,7 @@ Slider = function(x,y,width,thumbSize) { this.setBackgroundColor = function(color) { Overlays.editOverlay(this.background, {backgroundColor: { red: color.x*255, green: color.y*255, blue: color.z*255 }}); }; + } // The Checkbox class @@ -158,10 +167,12 @@ Checkbox = function(x,y,width,thumbSize) { visible: true }); - + this.thumbSize = thumbSize; var checkX = x + (0.25 * thumbSize); var checkY = y + (0.25 * thumbSize); + var boxCheckStatus; + var clickedBox = false; var checkMark = Overlays.addOverlay("text", { @@ -181,22 +192,22 @@ Checkbox = function(x,y,width,thumbSize) { width: thumbSize / 2.5, height: thumbSize / 2.5, alpha: 1.0, - visible: boxCheckStatus + visible: !boxCheckStatus }); - - var boxCheckStatus; - var clickedBox = false; - this.updateThumb = function() { - if (clickedBox) { - boxCheckStatus = !boxCheckStatus; - if (boxCheckStatus) { - Overlays.editOverlay(unCheckMark, { visible: false }); - } else { - Overlays.editOverlay(unCheckMark, { visible: true }); - } + this.updateThumb = function() { + if(!clickedBox) { + return; + } + + boxCheckStatus = !boxCheckStatus; + if (boxCheckStatus) { + Overlays.editOverlay(unCheckMark, { visible: false }); + } else { + Overlays.editOverlay(unCheckMark, { visible: true }); } + }; this.isClickableOverlayItem = function(item) { @@ -215,10 +226,12 @@ Checkbox = function(x,y,width,thumbSize) { this.onValueChanged(this.getValue()); }; + this.onMouseReleaseEvent = function(event) { this.clickedBox = false; }; + // Public members: this.setNormalizedValue = function(value) { boxCheckStatus = value; @@ -232,10 +245,26 @@ Checkbox = function(x,y,width,thumbSize) { this.setNormalizedValue(value); }; + this.reset = function(resetValue) { + this.setValue(resetValue); + + this.onValueChanged(resetValue); + }; + this.getValue = function() { return boxCheckStatus; }; + this.getHeight = function() { + return 1.5 * this.thumbSize; + } + + this.setterFromWidget = function(value) { + var status = boxCheckStatus; + this.onValueChanged(boxCheckStatus); + this.updateThumb(); + }; + this.onValueChanged = function(value) {}; this.destroy = function() { @@ -267,6 +296,8 @@ ColorBox = function(x,y,width,thumbSize) { this.green.setBackgroundColor({x: 0, y: 1, z: 0}); this.blue.setBackgroundColor({x: 0, y: 0, z: 1}); + + this.isClickableOverlayItem = function(item) { return this.red.isClickableOverlayItem(item) || this.green.isClickableOverlayItem(item) @@ -293,6 +324,7 @@ ColorBox = function(x,y,width,thumbSize) { this.blue.onMousePressEvent(event, clickedOverlay); }; + this.onMouseReleaseEvent = function(event) { this.red.onMouseReleaseEvent(event); this.green.onMouseReleaseEvent(event); @@ -323,11 +355,20 @@ ColorBox = function(x,y,width,thumbSize) { this.updateRGBSliders(value); }; + this.reset = function(resetValue) { + this.setValue(resetValue); + this.onValueChanged(resetValue); + }; + this.getValue = function() { var value = {x:this.red.getValue(), y:this.green.getValue(),z:this.blue.getValue()}; return value; }; + this.getHeight = function() { + return 1.5 * this.thumbSize; + } + this.destroy = function() { this.red.destroy(); this.green.destroy(); @@ -345,6 +386,8 @@ DirectionBox = function(x,y,width,thumbSize) { var sliderWidth = width; this.yaw = new Slider(x, y, width, slideHeight); this.pitch = new Slider(x, y + slideHeight, width, slideHeight); + + this.yaw.setThumbColor({x: 1, y: 0, z: 0}); this.yaw.minValue = -180; @@ -400,6 +443,11 @@ DirectionBox = function(x,y,width,thumbSize) { this.pitch.setValue(direction.y); }; + this.reset = function(resetValue) { + this.setValue(resetValue); + this.onValueChanged(resetValue); + }; + this.getValue = function() { var dirZ = this.pitch.getValue(); var yaw = this.yaw.getValue() * Math.PI / 180; @@ -408,6 +456,10 @@ DirectionBox = function(x,y,width,thumbSize) { return value; }; + this.getHeight = function() { + return 1.5 * this.thumbSize; + } + this.destroy = function() { this.yaw.destroy(); this.pitch.destroy(); @@ -420,6 +472,48 @@ DirectionBox = function(x,y,width,thumbSize) { var textFontSize = 12; +// TODO: Make collapsable +function CollapsablePanelItem(name, x, y, textWidth, height) { + this.name = name; + this.height = height; + + var topMargin = (height - textFontSize); + + this.thumb = Overlays.addOverlay("text", { + backgroundColor: { red: 220, green: 220, blue: 220 }, + textFontSize: 10, + x: x, + y: y, + width: rawHeight, + height: rawHeight, + alpha: 1.0, + backgroundAlpha: 1.0, + visible: true + }); + + this.title = Overlays.addOverlay("text", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + x: x + rawHeight, + y: y, + width: textWidth, + height: height, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true, + text: name, + font: {size: textFontSize}, + topMargin: topMargin, + }); + + this.destroy = function() { + Overlays.deleteOverlay(this.title); + Overlays.deleteOverlay(this.thumb); + if (this.widget != null) { + this.widget.destroy(); + } + } +} + function PanelItem(name, setter, getter, displayer, x, y, textWidth, valueWidth, height) { //print("creating panel item: " + name); @@ -548,15 +642,18 @@ Panel = function(x, y) { // Reset panel item upon double-clicking this.mouseDoublePressEvent = function(event) { + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); for (var i in this.items) { var item = this.items[i]; var widget = item.widget; - if (item.title == clickedOverlay || item.value == clickedOverlay) { - widget.updateThumb(); - widget.onValueChanged(item.resetValue); + if (clickedOverlay == item.title) { + item.activeWidget = widget; + + item.activeWidget.reset(item.resetValue); + break; } } @@ -569,8 +666,56 @@ Panel = function(x, y) { this.activeWidget = null; }; - this.newSlider = function(name, minValue, maxValue, setValue, getValue, displayValue) { + this.onMousePressEvent = function(event, clickedOverlay) { + for (var i in this.items) { + var item = this.items[i]; + if(item.widget.isClickableOverlayItem(clickedOverlay)) { + item.activeWidget = item.widget; + item.activeWidget.onMousePressEvent(event,clickedOverlay); + } + } + } + this.reset = function() { + for (var i in this.items) { + var item = this.items[i]; + if (item.activeWidget) { + item.activeWidget.reset(item.resetValue); + } + } + } + + this.onMouseMoveEvent = function(event) { + for (var i in this.items) { + var item = this.items[i]; + if (item.activeWidget) { + item.activeWidget.onMouseMoveEvent(event); + } + } + } + + this.onMouseReleaseEvent = function(event, clickedOverlay) { + for (var i in this.items) { + var item = this.items[i]; + if (item.activeWidget) { + item.activeWidget.onMouseReleaseEvent(event); + } + item.activeWidget = null; + } + } + + this.onMouseDoublePressEvent = function(event, clickedOverlay) { + + for (var i in this.items) { + var item = this.items[i]; + if (item.activeWidget) { + item.activeWidget.onMouseDoublePressEvent(event); + } + } + } + + this.newSlider = function(name, minValue, maxValue, setValue, getValue, displayValue) { + this.nextY = this.y + this.getHeight(); var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); var slider = new Slider(this.widgetX, this.nextY, widgetWidth, rawHeight); @@ -591,6 +736,8 @@ Panel = function(x, y) { } else if (displayValue == false) { display = function() {return "Off";}; } + + this.nextY = this.y + this.getHeight(); var item = new PanelItem(name, setValue, getValue, display, this.x, this.nextY, textWidth, valueWidth, rawHeight); @@ -600,11 +747,12 @@ Panel = function(x, y) { item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; item.setter(getValue()); this.items[name] = item; - this.nextY += rawYDelta; + //print("created Item... checkbox=" + name); }; this.newColorBox = function(name, setValue, getValue, displayValue) { + this.nextY = this.y + this.getHeight(); var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); @@ -618,7 +766,12 @@ Panel = function(x, y) { // print("created Item... colorBox=" + name); }; +<<<<<<< Updated upstream this.newDirectionBox = function(name, setValue, getValue, displayValue) { +======= + this.newDirectionBox= function(name, setValue, getValue, displayValue) { + this.nextY = this.y + this.getHeight(); +>>>>>>> Stashed changes var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); @@ -632,6 +785,7 @@ Panel = function(x, y) { // print("created Item... directionBox=" + name); }; +<<<<<<< Updated upstream this.newSubPanel = function(name) { var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); @@ -645,6 +799,32 @@ Panel = function(x, y) { }; +======= + var indentation = 30; + + this.newSubPanel = function(name) { + //TODO: make collapsable, fix double-press event + this.nextY = this.y + this.getHeight(); + + var item = new CollapsablePanelItem(name, this.x, this.nextY, textWidth, rawHeight, panel); + item.isSubPanel = true; + + this.nextY += 1.5 * item.height; + + var subPanel = new Panel(this.x + indentation, this.nextY); + + item.widget = subPanel; + this.items[name] = item; + return subPanel; + // print("created Item... subPanel=" + name); + }; + + this.onValueChanged = function(value) { + for (var i in this.items) { + this.items[i].widget.onValueChanged(value); + } + } +>>>>>>> Stashed changes this.destroy = function() { for (var i in this.items) { @@ -652,6 +832,7 @@ Panel = function(x, y) { } } + this.set = function(name, value) { var item = this.items[name]; if (item != null) { @@ -676,6 +857,29 @@ Panel = function(x, y) { return null; } + this.isClickableOverlayItem = function(item) { + for (var i in this.items) { + if (this.items[i].widget.isClickableOverlayItem(item)) { + return true; + } + } + return false; + } + + this.getHeight = function() { + var height = 0; + + for (var i in this.items) { + height += this.items[i].widget.getHeight(); + if(this.items[i].isSubPanel) { + height += 1.5 * rawHeight; + } + } + + + return height; + } + }; From 252780dc5dcebb32866c9b151adcda2f014df260 Mon Sep 17 00:00:00 2001 From: bwent Date: Mon, 27 Jul 2015 13:44:01 -0700 Subject: [PATCH 48/58] fix checkbox class, make subpanels collapsable --- examples/utilities/tools/cookies.js | 1669 ++++++++++++++++----------- 1 file changed, 983 insertions(+), 686 deletions(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index 2949626252..9d064385bf 100644 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -10,663 +10,925 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // // The Slider class -Slider = function(x,y,width,thumbSize) { - this.background = Overlays.addOverlay("text", { - backgroundColor: { red: 200, green: 200, blue: 255 }, - x: x, - y: y, - width: width, - height: thumbSize, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true - }); - this.thumb = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: x, - y: y, - width: thumbSize, - height: thumbSize, - alpha: 1.0, - backgroundAlpha: 1.0, - visible: true - }); - - - this.thumbSize = thumbSize; - this.thumbHalfSize = 0.5 * thumbSize; - - this.minThumbX = x + this.thumbHalfSize; - this.maxThumbX = x + width - this.thumbHalfSize; - this.thumbX = this.minThumbX; - - this.minValue = 0.0; - this.maxValue = 1.0; - - this.clickOffsetX = 0; - this.isMoving = false; - - this.updateThumb = function() { - thumbTruePos = this.thumbX - 0.5 * this.thumbSize; - Overlays.editOverlay(this.thumb, { x: thumbTruePos } ); - }; - - this.isClickableOverlayItem = function(item) { - return (item == this.thumb) || (item == this.background); - }; - - this.onMouseMoveEvent = function(event) { - if (this.isMoving) { - newThumbX = event.x - this.clickOffsetX; - if (newThumbX < this.minThumbX) { - newThumbX = this.minThumbX; - } - if (newThumbX > this.maxThumbX) { - newThumbX = this.maxThumbX; - } - this.thumbX = newThumbX; - this.updateThumb(); - this.onValueChanged(this.getValue()); - } - }; - - this.onMousePressEvent = function(event, clickedOverlay) { - if (!this.isClickableOverlayItem(clickedOverlay)) { - this.isMoving = false; - return; - } - this.isMoving = true; - var clickOffset = event.x - this.thumbX; - if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) { - this.clickOffsetX = clickOffset; - } else { - this.clickOffsetX = 0; - this.thumbX = event.x; - this.updateThumb(); - this.onValueChanged(this.getValue()); - } - - }; - - this.onMouseReleaseEvent = function(event) { - this.isMoving = false; - }; - - // Public members: - this.setNormalizedValue = function(value) { - if (value < 0.0) { - this.thumbX = this.minThumbX; - } else if (value > 1.0) { - this.thumbX = this.maxThumbX; - } else { - this.thumbX = value * (this.maxThumbX - this.minThumbX) + this.minThumbX; - } - this.updateThumb(); - }; - this.getNormalizedValue = function() { - return (this.thumbX - this.minThumbX) / (this.maxThumbX - this.minThumbX); - }; - - this.setValue = function(value) { - var normValue = (value - this.minValue) / (this.maxValue - this.minValue); - this.setNormalizedValue(normValue); - }; - - this.reset = function(resetValue) { - this.setValue(resetValue); - this.onValueChanged(resetValue); - }; - - this.getValue = function() { - return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue; - }; - - this.getHeight = function() { - return 1.5 * this.thumbSize; - } - - this.onValueChanged = function(value) {}; - - this.destroy = function() { - Overlays.deleteOverlay(this.background); - Overlays.deleteOverlay(this.thumb); - }; - - this.setThumbColor = function(color) { - Overlays.editOverlay(this.thumb, {backgroundColor: { red: color.x*255, green: color.y*255, blue: color.z*255 }}); - }; - this.setBackgroundColor = function(color) { - Overlays.editOverlay(this.background, {backgroundColor: { red: color.x*255, green: color.y*255, blue: color.z*255 }}); - }; - -} - -// The Checkbox class -Checkbox = function(x,y,width,thumbSize) { - - this.background = Overlays.addOverlay("text", { - backgroundColor: { red: 125, green: 125, blue: 255 }, - x: x, - y: y, - width: width, - height: thumbSize, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true - }); - - this.thumb = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - textFontSize: 10, - x: x, - y: y, - width: thumbSize, - height: thumbSize, - alpha: 1.0, - backgroundAlpha: 1.0, - visible: true - }); - - - this.thumbSize = thumbSize; - var checkX = x + (0.25 * thumbSize); - var checkY = y + (0.25 * thumbSize); - var boxCheckStatus; - var clickedBox = false; - - - var checkMark = Overlays.addOverlay("text", { - backgroundColor: { red: 0, green: 255, blue: 0 }, - x: checkX, - y: checkY, - width: thumbSize / 2.0, - height: thumbSize / 2.0, - alpha: 1.0, - visible: true - }); - - var unCheckMark = Overlays.addOverlay("image", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: checkX + 1.0, - y: checkY + 1.0, - width: thumbSize / 2.5, - height: thumbSize / 2.5, - alpha: 1.0, - visible: !boxCheckStatus - }); - - - this.updateThumb = function() { - if(!clickedBox) { - return; - } +(function () { + var Slider = function(x,y,width,thumbSize) { - boxCheckStatus = !boxCheckStatus; - if (boxCheckStatus) { - Overlays.editOverlay(unCheckMark, { visible: false }); - } else { - Overlays.editOverlay(unCheckMark, { visible: true }); - } + this.background = Overlays.addOverlay("text", { + backgroundColor: { red: 200, green: 200, blue: 255 }, + x: x, + y: y, + width: width, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true + }); + this.thumb = Overlays.addOverlay("text", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + x: x, + y: y, + width: thumbSize, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 1.0, + visible: true + }); + + this.thumbSize = thumbSize; - }; + this.thumbHalfSize = 0.5 * thumbSize; + + this.minThumbX = x + this.thumbHalfSize; + this.maxThumbX = x + width - this.thumbHalfSize; + this.thumbX = this.minThumbX; + + this.minValue = 0.0; + this.maxValue = 1.0; - this.isClickableOverlayItem = function(item) { - return (item == this.thumb) || (item == checkMark) || (item == unCheckMark); + this.y = y; + + this.clickOffsetX = 0; + this.isMoving = false; + this.visible = true; }; - this.onMousePressEvent = function(event, clickedOverlay) { - if (!this.isClickableOverlayItem(clickedOverlay)) { - this.isMoving = false; - clickedBox = false; - return; - } - - clickedBox = true; - this.updateThumb(); - this.onValueChanged(this.getValue()); - }; - - - this.onMouseReleaseEvent = function(event) { - this.clickedBox = false; - }; - - - // Public members: - this.setNormalizedValue = function(value) { - boxCheckStatus = value; - }; - - this.getNormalizedValue = function() { - return boxCheckStatus; - }; - - this.setValue = function(value) { - this.setNormalizedValue(value); - }; - - this.reset = function(resetValue) { - this.setValue(resetValue); - - this.onValueChanged(resetValue); - }; - - this.getValue = function() { - return boxCheckStatus; - }; - - this.getHeight = function() { - return 1.5 * this.thumbSize; - } - - this.setterFromWidget = function(value) { - var status = boxCheckStatus; - this.onValueChanged(boxCheckStatus); - this.updateThumb(); - }; - - this.onValueChanged = function(value) {}; - - this.destroy = function() { - Overlays.deleteOverlay(this.background); - Overlays.deleteOverlay(this.thumb); - Overlays.deleteOverlay(checkMark); - Overlays.deleteOverlay(unCheckMark); - }; - - this.setThumbColor = function(color) { - Overlays.editOverlay(this.thumb, { red: 255, green: 255, blue: 255 } ); - }; - this.setBackgroundColor = function(color) { - Overlays.editOverlay(this.background, { red: 125, green: 125, blue: 255 }); - }; - -} - -// The ColorBox class -ColorBox = function(x,y,width,thumbSize) { - var self = this; + Slider.prototype.updateThumb = function() { + var thumbTruePos = this.thumbX - 0.5 * this.thumbSize; + Overlays.editOverlay(this.thumb, { x: thumbTruePos } ); + }; - var slideHeight = thumbSize / 3; - var sliderWidth = width; - this.red = new Slider(x, y, width, slideHeight); - this.green = new Slider(x, y + slideHeight, width, slideHeight); - this.blue = new Slider(x, y + 2 * slideHeight, width, slideHeight); - this.red.setBackgroundColor({x: 1, y: 0, z: 0}); - this.green.setBackgroundColor({x: 0, y: 1, z: 0}); - this.blue.setBackgroundColor({x: 0, y: 0, z: 1}); - - - - this.isClickableOverlayItem = function(item) { - return this.red.isClickableOverlayItem(item) - || this.green.isClickableOverlayItem(item) - || this.blue.isClickableOverlayItem(item); - }; - - this.onMouseMoveEvent = function(event) { - this.red.onMouseMoveEvent(event); - this.green.onMouseMoveEvent(event); - this.blue.onMouseMoveEvent(event); - }; - - this.onMousePressEvent = function(event, clickedOverlay) { - this.red.onMousePressEvent(event, clickedOverlay); - if (this.red.isMoving) { - return; - } - - this.green.onMousePressEvent(event, clickedOverlay); - if (this.green.isMoving) { - return; - } - - this.blue.onMousePressEvent(event, clickedOverlay); - }; - - - this.onMouseReleaseEvent = function(event) { - this.red.onMouseReleaseEvent(event); - this.green.onMouseReleaseEvent(event); - this.blue.onMouseReleaseEvent(event); - }; - - this.setterFromWidget = function(value) { - var color = self.getValue(); - self.onValueChanged(color); - self.updateRGBSliders(color); - }; - - this.red.onValueChanged = this.setterFromWidget; - this.green.onValueChanged = this.setterFromWidget; - this.blue.onValueChanged = this.setterFromWidget; - - this.updateRGBSliders = function(color) { - this.red.setThumbColor({x: color.x, y: 0, z: 0}); - this.green.setThumbColor({x: 0, y: color.y, z: 0}); - this.blue.setThumbColor({x: 0, y: 0, z: color.z}); - }; - - // Public members: - this.setValue = function(value) { - this.red.setValue(value.x); - this.green.setValue(value.y); - this.blue.setValue(value.z); - this.updateRGBSliders(value); - }; - - this.reset = function(resetValue) { - this.setValue(resetValue); - this.onValueChanged(resetValue); - }; - - this.getValue = function() { - var value = {x:this.red.getValue(), y:this.green.getValue(),z:this.blue.getValue()}; - return value; - }; - - this.getHeight = function() { - return 1.5 * this.thumbSize; - } - - this.destroy = function() { - this.red.destroy(); - this.green.destroy(); - this.blue.destroy(); - }; - - this.onValueChanged = function(value) {}; -} - -// The DirectionBox class -DirectionBox = function(x,y,width,thumbSize) { - var self = this; + Slider.prototype.isClickableOverlayItem = function(item) { + return (item == this.thumb) || (item == this.background); + }; - var slideHeight = thumbSize / 2; - var sliderWidth = width; - this.yaw = new Slider(x, y, width, slideHeight); - this.pitch = new Slider(x, y + slideHeight, width, slideHeight); - - - - this.yaw.setThumbColor({x: 1, y: 0, z: 0}); - this.yaw.minValue = -180; - this.yaw.maxValue = +180; - - this.pitch.setThumbColor({x: 0, y: 0, z: 1}); - this.pitch.minValue = -1; - this.pitch.maxValue = +1; - - this.isClickableOverlayItem = function(item) { - return this.yaw.isClickableOverlayItem(item) - || this.pitch.isClickableOverlayItem(item); - }; - - this.onMouseMoveEvent = function(event) { - this.yaw.onMouseMoveEvent(event); - this.pitch.onMouseMoveEvent(event); - }; - - this.onMousePressEvent = function(event, clickedOverlay) { - this.yaw.onMousePressEvent(event, clickedOverlay); - if (this.yaw.isMoving) { - return; - } - this.pitch.onMousePressEvent(event, clickedOverlay); - }; - - this.onMouseReleaseEvent = function(event) { - this.yaw.onMouseReleaseEvent(event); - this.pitch.onMouseReleaseEvent(event); - }; - - this.setterFromWidget = function(value) { - var yawPitch = self.getValue(); - self.onValueChanged(yawPitch); - }; - - this.yaw.onValueChanged = this.setterFromWidget; - this.pitch.onValueChanged = this.setterFromWidget; - - // Public members: - this.setValue = function(direction) { - var flatXZ = Math.sqrt(direction.x * direction.x + direction.z * direction.z); - if (flatXZ > 0.0) { - var flatX = direction.x / flatXZ; - var flatZ = direction.z / flatXZ; - var yaw = Math.acos(flatX) * 180 / Math.PI; - if (flatZ < 0) { - yaw = -yaw; + Slider.prototype.onMouseMoveEvent = function(event) { + if (this.isMoving) { + var newThumbX = event.x - this.clickOffsetX; + if (newThumbX < this.minThumbX) { + newThumbX = this.minThumbX; + } + if (newThumbX > this.maxThumbX) { + newThumbX = this.maxThumbX; + } + this.thumbX = newThumbX; + this.updateThumb(); + this.onValueChanged(this.getValue()); } - this.yaw.setValue(yaw); + }; + + Slider.prototype.onMousePressEvent = function(event, clickedOverlay) { + if (!this.isClickableOverlayItem(clickedOverlay)) { + this.isMoving = false; + return; + } + this.isMoving = true; + var clickOffset = event.x - this.thumbX; + if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) { + this.clickOffsetX = clickOffset; + } else { + this.clickOffsetX = 0; + this.thumbX = event.x; + this.updateThumb(); + this.onValueChanged(this.getValue()); + } + + }; + + Slider.prototype.onMouseReleaseEvent = function(event) { + this.isMoving = false; + }; + + // Public members: + Slider.prototype.setNormalizedValue = function(value) { + if (value < 0.0) { + this.thumbX = this.minThumbX; + } else if (value > 1.0) { + this.thumbX = this.maxThumbX; + } else { + this.thumbX = value * (this.maxThumbX - this.minThumbX) + this.minThumbX; + } + this.updateThumb(); + }; + Slider.prototype.getNormalizedValue = function() { + return (this.thumbX - this.minThumbX) / (this.maxThumbX - this.minThumbX); + }; + + Slider.prototype.setValue = function(value) { + var normValue = (value - this.minValue) / (this.maxValue - this.minValue); + this.setNormalizedValue(normValue); + }; + + Slider.prototype.reset = function(resetValue) { + this.setValue(resetValue); + this.onValueChanged(resetValue); + }; + + Slider.prototype.getValue = function() { + return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue; + }; + + Slider.prototype.getHeight = function() { + if(!this.visible) { + return 0; + } + return 1.5 * this.thumbSize; + }; + + Slider.prototype.moveUp = function(newY) { + Overlays.editOverlay(this.background, {y: newY}); + Overlays.editOverlay(this.thumb, {y: newY}); + }; + + Slider.prototype.moveDown = function() { + Overlays.editOverlay(this.background, {y: this.y}); + Overlays.editOverlay(this.thumb, {y: this.y}); + }; + + Slider.prototype.onValueChanged = function(value) {}; + + Slider.prototype.hide = function() { + Overlays.editOverlay(this.background, {visible: false}); + Overlays.editOverlay(this.thumb, {visible: false}); + this.visible = false; + }; + + Slider.prototype.show = function() { + Overlays.editOverlay(this.background, {visible: true}); + Overlays.editOverlay(this.thumb, {visible: true}); + this.visible = true; + }; + + Slider.prototype.destroy = function() { + Overlays.deleteOverlay(this.background); + Overlays.deleteOverlay(this.thumb); + }; + + Slider.prototype.setThumbColor = function(color) { + Overlays.editOverlay(this.thumb, {backgroundColor: { red: color.x*255, green: color.y*255, blue: color.z*255 }}); + }; + Slider.prototype.setBackgroundColor = function(color) { + Overlays.editOverlay(this.background, {backgroundColor: { red: color.x*255, green: color.y*255, blue: color.z*255 }}); + }; + this.Slider = Slider; + + // The Checkbox class + var Checkbox = function(x,y,width,thumbSize) { + + this.background = Overlays.addOverlay("text", { + backgroundColor: { red: 125, green: 125, blue: 255 }, + x: x, + y: y, + width: width, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true + }); + + this.thumb = Overlays.addOverlay("text", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + textFontSize: 10, + x: x, + y: y, + width: thumbSize, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 1.0, + visible: true + }); + + + this.thumbSize = thumbSize; + var checkX = x + (0.25 * thumbSize); + var checkY = y + (0.25 * thumbSize); + this.y = y; + this.boxCheckStatus = true; + this.clickedBox = false; + this.visible = true; + + + this.checkMark = Overlays.addOverlay("text", { + backgroundColor: { red: 0, green: 255, blue: 0 }, + x: checkX, + y: checkY, + width: thumbSize / 2.0, + height: thumbSize / 2.0, + alpha: 1.0, + visible: true + }); + + this.unCheckMark = Overlays.addOverlay("image", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + x: checkX + 1.0, + y: checkY + 1.0, + width: thumbSize / 2.5, + height: thumbSize / 2.5, + alpha: 1.0, + visible: false + }); + }; + + Checkbox.prototype.updateThumb = function() { + + Overlays.editOverlay(this.unCheckMark, { visible: !this.boxCheckStatus }); + + }; + + Checkbox.prototype.isClickableOverlayItem = function(item) { + return (item == this.thumb) || (item == this.checkMark) || (item == this.unCheckMark); + }; + + Checkbox.prototype.onMousePressEvent = function(event, clickedOverlay) { + + if (!this.isClickableOverlayItem(clickedOverlay)) { + return; + } + + this.boxCheckStatus = !this.boxCheckStatus; + this.onValueChanged(this.getValue()); + this.updateThumb(); + }; + + + Checkbox.prototype.onMouseReleaseEvent = function(event) { }; + + + // Public members: + + Checkbox.prototype.setValue = function(value) { + this.boxCheckStatus = value; + }; + + Checkbox.prototype.reset = function(resetValue) { + this.setValue(resetValue); + }; + + Checkbox.prototype.getValue = function() { + return this.boxCheckStatus; + }; + + Checkbox.prototype.getHeight = function() { + if(!this.visible) { + return 0; } - this.pitch.setValue(direction.y); + return 1.5 * this.thumbSize; + }; + + Checkbox.prototype.moveUp = function(newY) { + Overlays.editOverlay(this.background, {y: newY}); + Overlays.editOverlay(this.thumb, {y: newY}); + Overlays.editOverlay(this.checkMark, {y: newY}); + Overlays.editOverlay(this.unCheckMark, {y: newY}); }; - this.reset = function(resetValue) { - this.setValue(resetValue); - this.onValueChanged(resetValue); + Checkbox.prototype.moveDown = function() { + Overlays.editOverlay(this.background, {y: this.y}); + Overlays.editOverlay(this.thumb, {y: this.y}); + Overlays.editOverlay(this.checkMark, {y: this.y}); + Overlays.editOverlay(this.unCheckMark, {y: this.y}); }; + + Checkbox.prototype.setterFromWidget = function(value) { + this.updateThumb(); + }; + + Checkbox.prototype.onValueChanged = function(value) { }; - this.getValue = function() { - var dirZ = this.pitch.getValue(); - var yaw = this.yaw.getValue() * Math.PI / 180; - var cosY = Math.sqrt(1 - dirZ*dirZ); - var value = {x:cosY * Math.cos(yaw), y:dirZ, z: cosY * Math.sin(yaw)}; - return value; - }; - - this.getHeight = function() { - return 1.5 * this.thumbSize; + Checkbox.prototype.hide = function() { + Overlays.editOverlay(this.background, {visible: false}); + Overlays.editOverlay(this.thumb, {visible: false}); + Overlays.editOverlay(this.checkMark, {visible: false}); + Overlays.editOverlay(this.unCheckMark, {visible: false}); + this.visible = false; } - this.destroy = function() { - this.yaw.destroy(); - this.pitch.destroy(); + Checkbox.prototype.show = function() { + Overlays.editOverlay(this.background, {visible: true}); + Overlays.editOverlay(this.thumb, {visible: true}); + Overlays.editOverlay(this.checkMark, {visible: true}); + Overlays.editOverlay(this.unCheckMark, {visible: true}); + this.visible = true; + } + + Checkbox.prototype.destroy = function() { + Overlays.deleteOverlay(this.background); + Overlays.deleteOverlay(this.thumb); + Overlays.deleteOverlay(this.checkMark); + Overlays.deleteOverlay(this.unCheckMark); + }; + + Checkbox.prototype.setThumbColor = function(color) { + Overlays.editOverlay(this.thumb, { red: 255, green: 255, blue: 255 } ); + }; + Checkbox.prototype.setBackgroundColor = function(color) { + Overlays.editOverlay(this.background, { red: 125, green: 125, blue: 255 }); + }; + this.Checkbox = Checkbox; + + // The ColorBox class + var ColorBox = function(x,y,width,thumbSize) { + var self = this; + + var slideHeight = thumbSize / 3; + var sliderWidth = width; + this.red = new Slider(x, y, width, slideHeight); + this.green = new Slider(x, y + slideHeight, width, slideHeight); + this.blue = new Slider(x, y + 2 * slideHeight, width, slideHeight); + this.red.setBackgroundColor({x: 1, y: 0, z: 0}); + this.green.setBackgroundColor({x: 0, y: 1, z: 0}); + this.blue.setBackgroundColor({x: 0, y: 0, z: 1}); + + this.red.onValueChanged = this.setterFromWidget; + this.green.onValueChanged = this.setterFromWidget; + this.blue.onValueChanged = this.setterFromWidget; + + this.visible = true; + }; + + ColorBox.prototype.isClickableOverlayItem = function(item) { + return this.red.isClickableOverlayItem(item) + || this.green.isClickableOverlayItem(item) + || this.blue.isClickableOverlayItem(item); + }; + + ColorBox.prototype.onMouseMoveEvent = function(event) { + this.red.onMouseMoveEvent(event); + this.green.onMouseMoveEvent(event); + this.blue.onMouseMoveEvent(event); + }; + + ColorBox.prototype.onMousePressEvent = function(event, clickedOverlay) { + this.red.onMousePressEvent(event, clickedOverlay); + if (this.red.isMoving) { + return; + } + + this.green.onMousePressEvent(event, clickedOverlay); + if (this.green.isMoving) { + return; + } + + this.blue.onMousePressEvent(event, clickedOverlay); + }; + + + ColorBox.prototype.onMouseReleaseEvent = function(event) { + this.red.onMouseReleaseEvent(event); + this.green.onMouseReleaseEvent(event); + this.blue.onMouseReleaseEvent(event); + }; + + ColorBox.prototype.setterFromWidget = function(value) { + var color = this.getValue(); + this.onValueChanged(color); + this.updateRGBSliders(color); + }; + + ColorBox.prototype.updateRGBSliders = function(color) { + this.red.setThumbColor({x: color.x, y: 0, z: 0}); + this.green.setThumbColor({x: 0, y: color.y, z: 0}); + this.blue.setThumbColor({x: 0, y: 0, z: color.z}); + }; + + // Public members: + ColorBox.prototype.setValue = function(value) { + this.red.setValue(value.x); + this.green.setValue(value.y); + this.blue.setValue(value.z); + this.updateRGBSliders(value); + }; + + ColorBox.prototype.reset = function(resetValue) { + this.setValue(resetValue); + this.onValueChanged(resetValue); + }; + + ColorBox.prototype.getValue = function() { + var value = {x:this.red.getValue(), y:this.green.getValue(),z:this.blue.getValue()}; + return value; + }; + + ColorBox.prototype.getHeight = function() { + if(!this.visible) { + return 0; + } + return 1.5 * this.thumbSize; + }; + + ColorBox.prototype.moveUp = function(newY) { + this.red.moveUp(newY); + this.green.moveUp(newY); + this.blue.moveUp(newY); }; - this.onValueChanged = function(value) {}; -} + ColorBox.prototype.moveDown = function() { + this.red.moveDown(); + this.green.moveDown(); + this.blue.moveDown(); + }; + ColorBox.prototype.hide = function() { + this.red.hide(); + this.green.hide(); + this.blue.hide(); + this.visible = false; + } - -var textFontSize = 12; - -// TODO: Make collapsable -function CollapsablePanelItem(name, x, y, textWidth, height) { - this.name = name; - this.height = height; - - var topMargin = (height - textFontSize); - - this.thumb = Overlays.addOverlay("text", { - backgroundColor: { red: 220, green: 220, blue: 220 }, - textFontSize: 10, - x: x, - y: y, - width: rawHeight, - height: rawHeight, - alpha: 1.0, - backgroundAlpha: 1.0, - visible: true - }); + ColorBox.prototype.show = function() { + this.red.show(); + this.green.show(); + this.blue.show(); + this.visible = true; + } - this.title = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: x + rawHeight, - y: y, - width: textWidth, - height: height, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true, - text: name, - font: {size: textFontSize}, - topMargin: topMargin, - }); + ColorBox.prototype.destroy = function() { + this.red.destroy(); + this.green.destroy(); + this.blue.destroy(); + }; + + ColorBox.prototype.onValueChanged = function(value) {}; + this.ColorBox = ColorBox; + + // The DirectionBox class + var DirectionBox = function(x,y,width,thumbSize) { + var self = this; + + var slideHeight = thumbSize / 2; + var sliderWidth = width; + this.yaw = new Slider(x, y, width, slideHeight); + this.pitch = new Slider(x, y + slideHeight, width, slideHeight); + + + this.yaw.setThumbColor({x: 1, y: 0, z: 0}); + this.yaw.minValue = -180; + this.yaw.maxValue = +180; + + this.pitch.setThumbColor({x: 0, y: 0, z: 1}); + this.pitch.minValue = -1; + this.pitch.maxValue = +1; + + this.yaw.onValueChanged = this.setterFromWidget; + this.pitch.onValueChanged = this.setterFromWidget; - this.destroy = function() { + this.visible = true; + }; + + DirectionBox.prototype.isClickableOverlayItem = function(item) { + return this.yaw.isClickableOverlayItem(item) + || this.pitch.isClickableOverlayItem(item); + }; + + DirectionBox.prototype.onMouseMoveEvent = function(event) { + this.yaw.onMouseMoveEvent(event); + this.pitch.onMouseMoveEvent(event); + }; + + DirectionBox.prototype.onMousePressEvent = function(event, clickedOverlay) { + this.yaw.onMousePressEvent(event, clickedOverlay); + if (this.yaw.isMoving) { + return; + } + this.pitch.onMousePressEvent(event, clickedOverlay); + }; + + DirectionBox.prototype.onMouseReleaseEvent = function(event) { + this.yaw.onMouseReleaseEvent(event); + this.pitch.onMouseReleaseEvent(event); + }; + + DirectionBox.prototype.setterFromWidget = function(value) { + var yawPitch = this.getValue(); + this.onValueChanged(yawPitch); + }; + + // Public members: + DirectionBox.prototype.setValue = function(direction) { + var flatXZ = Math.sqrt(direction.x * direction.x + direction.z * direction.z); + if (flatXZ > 0.0) { + var flatX = direction.x / flatXZ; + var flatZ = direction.z / flatXZ; + var yaw = Math.acos(flatX) * 180 / Math.PI; + if (flatZ < 0) { + yaw = -yaw; + } + this.yaw.setValue(yaw); + } + this.pitch.setValue(direction.y); + }; + + DirectionBox.prototype.reset = function(resetValue) { + this.setValue(resetValue); + this.onValueChanged(resetValue); + }; + + DirectionBox.prototype.getValue = function() { + var dirZ = this.pitch.getValue(); + var yaw = this.yaw.getValue() * Math.PI / 180; + var cosY = Math.sqrt(1 - dirZ*dirZ); + var value = {x:cosY * Math.cos(yaw), y:dirZ, z: cosY * Math.sin(yaw)}; + return value; + }; + + DirectionBox.prototype.getHeight = function() { + if(!this.visible) { + return 0; + } + return 1.5 * this.thumbSize; + }; + + DirectionBox.prototype.moveUp = function(newY) { + this.pitch.moveUp(newY); + this.yaw.moveUp(newY); + }; + + DirectionBox.prototype.moveDown = function(newY) { + this.pitch.moveDown(); + this.yaw.moveDown(); + }; + + DirectionBox.prototype.hide = function() { + this.pitch.hide(); + this.yaw.hide(); + this.visible = false; + } + + DirectionBox.prototype.show = function() { + this.pitch.show(); + this.yaw.show(); + this.visible = true; + } + + DirectionBox.prototype.destroy = function() { + this.yaw.destroy(); + this.pitch.destroy(); + }; + + DirectionBox.prototype.onValueChanged = function(value) {}; + this.DirectionBox = DirectionBox; + + var textFontSize = 12; + + var CollapsablePanelItem = function (name, x, y, textWidth, height) { + this.name = name; + this.height = height; + this.y = y; + this.isCollapsable = true; + + var topMargin = (height - 1.5 * textFontSize); + + this.thumb = Overlays.addOverlay("text", { + backgroundColor: { red: 220, green: 220, blue: 220 }, + textFontSize: 10, + x: x, + y: y, + width: rawHeight, + height: rawHeight, + alpha: 1.0, + backgroundAlpha: 1.0, + visible: true + }); + + this.title = Overlays.addOverlay("text", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + x: x + rawHeight * 1.5, + y: y, + width: textWidth, + height: height, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true, + text: " " + name, + font: {size: textFontSize}, + topMargin: topMargin + }); + }; + + CollapsablePanelItem.prototype.destroy = function() { Overlays.deleteOverlay(this.title); Overlays.deleteOverlay(this.thumb); - if (this.widget != null) { - this.widget.destroy(); - } - } -} - -function PanelItem(name, setter, getter, displayer, x, y, textWidth, valueWidth, height) { - //print("creating panel item: " + name); + }; - this.name = name; - - this.displayer = typeof displayer !== 'undefined' ? displayer : function(value) { - if(value == true) { - return "On"; - } else if (value == false) { - return "Off"; - } - return value; - }; - - var topMargin = (height - textFontSize); - this.title = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: x, - y: y, - width: textWidth, - height: height, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true, - text: name, - font: {size: textFontSize}, - topMargin: topMargin, - }); - - this.value = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: x + textWidth, - y: y, - width: valueWidth, - height: height, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true, - text: this.displayer(getter()), - font: {size: textFontSize}, - topMargin: topMargin - }); - - this.getter = getter; - this.resetValue = getter(); - - this.setter = function(value) { - - setter(value); - - Overlays.editOverlay(this.value, {text: this.displayer(getter())}); - - if (this.widget) { - this.widget.setValue(value); - } - - //print("successfully set value of widget to " + value); - }; - this.setterFromWidget = function(value) { - setter(value); - // ANd loop back the value after the final setter has been called - var value = getter(); - - if (this.widget) { - this.widget.setValue(value); - } - Overlays.editOverlay(this.value, {text: this.displayer(value)}); - }; - - this.widget = null; + CollapsablePanelItem.prototype.hide = function() { + Overlays.editOverlay(this.title, {visible: false}); + Overlays.editOverlay(this.thumb, {visible: false}); - this.destroy = function() { - Overlays.deleteOverlay(this.title); - Overlays.deleteOverlay(this.value); if (this.widget != null) { - this.widget.destroy(); + this.widget.hide(); + } + }; + + CollapsablePanelItem.prototype.show = function() { + Overlays.editOverlay(this.title, {visible: true}); + Overlays.editOverlay(this.thumb, {visible: true}); + + if (this.widget != null) { + this.widget.show(); + } + }; + + CollapsablePanelItem.prototype.moveUp = function(newY) { + Overlays.editOverlay(this.title, {y: newY}); + Overlays.editOverlay(this.thumb, {y: newY}); + + if (this.widget != null) { + this.widget.moveUp(newY); } } -} -var textWidth = 180; -var valueWidth = 100; -var widgetWidth = 300; -var rawHeight = 20; -var rawYDelta = rawHeight * 1.5; + CollapsablePanelItem.prototype.moveDown = function() { + Overlays.editOverlay(this.title, {y: this.y}); + Overlays.editOverlay(this.thumb, {y: this.y}); -Panel = function(x, y) { + if (this.widget != null) { + this.widget.moveDown(); + } - this.x = x; - this.y = y; - this.nextY = y; + } - this.widgetX = x + textWidth + valueWidth; + this.CollapsablePanelItem = CollapsablePanelItem; + + var PanelItem = function (name, setter, getter, displayer, x, y, textWidth, valueWidth, height) { + //print("creating panel item: " + name); + this.isCollapsable = false; + this.name = name; + this.y = y; + this.isCollapsed = false; + + this.displayer = typeof displayer !== 'undefined' ? displayer : function(value) { + if(value == true) { + return "On"; + } else if (value == false) { + return "Off"; + } + return value.toFixed(2); + }; + + var topMargin = (height - 1.5 * textFontSize); + this.title = Overlays.addOverlay("text", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + x: x, + y: y, + width: textWidth, + height: height, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true, + text: " " + name, + font: {size: textFontSize}, + topMargin: topMargin + }); + + this.value = Overlays.addOverlay("text", { + backgroundColor: { red: 255, green: 255, blue: 255 }, + x: x + textWidth, + y: y, + width: valueWidth, + height: height, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true, + text: this.displayer(getter()), + font: {size: textFontSize}, + topMargin: topMargin + }); + + this.getter = getter; + this.resetValue = getter(); + + this.setter = function(value) { + + setter(value); - this.items = new Array(); - this.activeWidget = null; + Overlays.editOverlay(this.value, {text: this.displayer(getter())}); - this.mouseMoveEvent = function(event) { + if (this.widget) { + this.widget.setValue(value); + } + + //print("successfully set value of widget to " + value); + }; + this.setterFromWidget = function(value) { + setter(value); + // ANd loop back the value after the final setter has been called + var value = getter(); + + if (this.widget) { + this.widget.setValue(value); + } + Overlays.editOverlay(this.value, {text: this.displayer(value)}); + }; + + this.widget = null; + }; + + PanelItem.prototype.hide = function() { + Overlays.editOverlay(this.title, {visible: false}); + Overlays.editOverlay(this.value, {visible: false}); + + if (this.widget != null) { + this.widget.hide(); + } + }; + + + PanelItem.prototype.show = function() { + Overlays.editOverlay(this.title, {visible: true}); + Overlays.editOverlay(this.value, {visible: true}); + + if (this.widget != null) { + this.widget.show(); + } + + }; + + PanelItem.prototype.moveUp = function(newY) { + + Overlays.editOverlay(this.title, {y: newY}); + Overlays.editOverlay(this.value, {y: newY}); + + if (this.widget != null) { + this.widget.moveUp(newY); + } + + }; + + PanelItem.prototype.moveDown = function() { + + Overlays.editOverlay(this.title, {y: this.y}); + Overlays.editOverlay(this.value, {y: this.y}); + + if (this.widget != null) { + this.widget.moveDown(); + } + + }; + + PanelItem.prototype.destroy = function() { + Overlays.deleteOverlay(this.title); + Overlays.deleteOverlay(this.value); + + if (this.widget != null) { + this.widget.destroy(); + } + }; + this.PanelItem = PanelItem; + + var textWidth = 180; + var valueWidth = 100; + var widgetWidth = 300; + var rawHeight = 20; + var rawYDelta = rawHeight * 1.5; + + var Panel = function(x, y) { + + this.x = x; + this.y = y; + + this.nextY = y; print("creating panel at x: " + this.x + " y: " + this.y); + + this.widgetX = x + textWidth + valueWidth; + + this.items = new Array(); + this.activeWidget = null; + this.visible = true; + this.indentation = 30; + + }; + + Panel.prototype.mouseMoveEvent = function(event) { if (this.activeWidget) { this.activeWidget.onMouseMoveEvent(event); } }; - - this.mousePressEvent = function(event) { + + Panel.prototype.mousePressEvent = function(event) { // Make sure we quitted previous widget if (this.activeWidget) { this.activeWidget.onMouseReleaseEvent(event); } this.activeWidget = null; - + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); - + this.handleCollapse(clickedOverlay); + // If the user clicked any of the slider background then... for (var i in this.items) { + var item = this.items[i]; var widget = this.items[i].widget; - + if (widget.isClickableOverlayItem(clickedOverlay)) { this.activeWidget = widget; this.activeWidget.onMousePressEvent(event, clickedOverlay); - break; - } + + } } }; - - // Reset panel item upon double-clicking - this.mouseDoublePressEvent = function(event) { - + + // Reset panel item upon double-clicking + Panel.prototype.mouseDoublePressEvent = function(event) { var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + this.handleReset(clickedOverlay); + } + + Panel.prototype.handleReset = function (clickedOverlay) { for (var i in this.items) { - + var item = this.items[i]; var widget = item.widget; + + if (item.isSubPanel && widget) { + widget.handleReset(clickedOverlay); + } if (clickedOverlay == item.title) { item.activeWidget = widget; - + item.activeWidget.reset(item.resetValue); break; } - } - } + } + }; - this.mouseReleaseEvent = function(event) { + Panel.prototype.handleCollapse = function (clickedOverlay) { + + for (var i in this.items) { + + var item = this.items[i]; + var widget = item.widget; + + if (item.isSubPanel && widget) { + widget.handleCollapse(clickedOverlay); + } + + if (!item.isCollapsed && item.isCollapsable && clickedOverlay == item.thumb) { + this.collapse(clickedOverlay); + item.isCollapsed = true; + break; + } else if (item.isCollapsed && item.isCollapsable && clickedOverlay == item.thumb) { + this.expand(clickedOverlay); + item.isCollapsed = false; + } + } + }; + + Panel.prototype.collapse = function (clickedOverlay) { + var keys = Object.keys(this.items); + + for (var i = 0; i < keys.length; ++i) { + var item = this.items[keys[i]]; + + if(item.isCollapsable && clickedOverlay == item.thumb) { + var panel = item.widget; + panel.hide(); + break; + } + + } + + // Now recalculate new heights of subsequent widgets + for(var j = i + 1; j < keys.length; ++j) { + + this.items[keys[j]].moveUp(this.getCurrentY(keys[j])); + + } + + }; + + + Panel.prototype.expand = function (clickedOverlay) { + var keys = Object.keys(this.items); + + for (var i = 0; i < keys.length; ++i) { + var item = this.items[keys[i]]; + + if(item.isCollapsable && clickedOverlay == item.thumb) { + var panel = item.widget; + panel.show(); + break; + } + + } + + // Now recalculate new heights of subsequent widgets + for(var j = i + 1; j < keys.length; ++j) { + this.items[keys[j]].moveDown(); + } + + }; + + + Panel.prototype.mouseReleaseEvent = function(event) { if (this.activeWidget) { this.activeWidget.onMouseReleaseEvent(event); } this.activeWidget = null; }; - - this.onMousePressEvent = function(event, clickedOverlay) { + + Panel.prototype.onMousePressEvent = function(event, clickedOverlay) { for (var i in this.items) { var item = this.items[i]; if(item.widget.isClickableOverlayItem(clickedOverlay)) { @@ -674,27 +936,19 @@ Panel = function(x, y) { item.activeWidget.onMousePressEvent(event,clickedOverlay); } } - } - - this.reset = function() { - for (var i in this.items) { - var item = this.items[i]; - if (item.activeWidget) { - item.activeWidget.reset(item.resetValue); - } - } - } - - this.onMouseMoveEvent = function(event) { + }; + + + Panel.prototype.onMouseMoveEvent = function(event) { for (var i in this.items) { var item = this.items[i]; if (item.activeWidget) { item.activeWidget.onMouseMoveEvent(event); } } - } - - this.onMouseReleaseEvent = function(event, clickedOverlay) { + }; + + Panel.prototype.onMouseReleaseEvent = function(event, clickedOverlay) { for (var i in this.items) { var item = this.items[i]; if (item.activeWidget) { @@ -702,47 +956,46 @@ Panel = function(x, y) { } item.activeWidget = null; } - } - - this.onMouseDoublePressEvent = function(event, clickedOverlay) { - + }; + + Panel.prototype.onMouseDoublePressEvent = function(event, clickedOverlay) { for (var i in this.items) { var item = this.items[i]; if (item.activeWidget) { item.activeWidget.onMouseDoublePressEvent(event); } } - } - - this.newSlider = function(name, minValue, maxValue, setValue, getValue, displayValue) { + }; + + Panel.prototype.newSlider = function(name, minValue, maxValue, setValue, getValue, displayValue) { this.nextY = this.y + this.getHeight(); - var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); var slider = new Slider(this.widgetX, this.nextY, widgetWidth, rawHeight); slider.minValue = minValue; slider.maxValue = maxValue; - + item.widget = slider; item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; item.setter(getValue()); this.items[name] = item; - this.nextY += rawYDelta; - }; - this.newCheckbox = function(name, setValue, getValue, displayValue) { + }; + + Panel.prototype.newCheckbox = function(name, setValue, getValue, displayValue) { var display; if (displayValue == true) { display = function() {return "On";}; } else if (displayValue == false) { display = function() {return "Off";}; } - + this.nextY = this.y + this.getHeight(); - + var item = new PanelItem(name, setValue, getValue, display, this.x, this.nextY, textWidth, valueWidth, rawHeight); - + var checkbox = new Checkbox(this.widgetX, this.nextY, widgetWidth, rawHeight); - + item.widget = checkbox; item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; item.setter(getValue()); @@ -750,136 +1003,180 @@ Panel = function(x, y) { //print("created Item... checkbox=" + name); }; - - this.newColorBox = function(name, setValue, getValue, displayValue) { + + Panel.prototype.newColorBox = function(name, setValue, getValue, displayValue) { this.nextY = this.y + this.getHeight(); - + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); - + var colorBox = new ColorBox(this.widgetX, this.nextY, widgetWidth, rawHeight); - + item.widget = colorBox; item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; item.setter(getValue()); this.items[name] = item; - this.nextY += rawYDelta; + // print("created Item... colorBox=" + name); }; - -<<<<<<< Updated upstream - this.newDirectionBox = function(name, setValue, getValue, displayValue) { -======= - this.newDirectionBox= function(name, setValue, getValue, displayValue) { + + Panel.prototype.newDirectionBox = function(name, setValue, getValue, displayValue) { this.nextY = this.y + this.getHeight(); ->>>>>>> Stashed changes - + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); var directionBox = new DirectionBox(this.widgetX, this.nextY, widgetWidth, rawHeight); - + item.widget = directionBox; item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; item.setter(getValue()); this.items[name] = item; - this.nextY += rawYDelta; + // print("created Item... directionBox=" + name); }; - -<<<<<<< Updated upstream - this.newSubPanel = function(name) { - var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); - - var panel = new Panel(this.widgetX, this.nextY); - - item.widget = panel; - - item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; + - this.nextY += rawYDelta; - - }; - -======= - var indentation = 30; - - this.newSubPanel = function(name) { + + Panel.prototype.newSubPanel = function(name) { //TODO: make collapsable, fix double-press event this.nextY = this.y + this.getHeight(); - + var item = new CollapsablePanelItem(name, this.x, this.nextY, textWidth, rawHeight, panel); item.isSubPanel = true; + + this.nextY += 1.5 * item.height; + + var subPanel = new Panel(this.x + this.indentation, this.nextY); - this.nextY += 1.5 * item.height; - - var subPanel = new Panel(this.x + indentation, this.nextY); - item.widget = subPanel; this.items[name] = item; return subPanel; // print("created Item... subPanel=" + name); }; - - this.onValueChanged = function(value) { + + Panel.prototype.onValueChanged = function(value) { for (var i in this.items) { this.items[i].widget.onValueChanged(value); } - } ->>>>>>> Stashed changes - - this.destroy = function() { - for (var i in this.items) { - this.items[i].destroy(); - } - } - - - this.set = function(name, value) { + }; + + + Panel.prototype.set = function(name, value) { var item = this.items[name]; if (item != null) { return item.setter(value); } return null; - } - - this.get = function(name) { + }; + + Panel.prototype.get = function(name) { var item = this.items[name]; if (item != null) { return item.getter(); } return null; - } - - this.update = function(name) { + }; + + Panel.prototype.update = function(name) { var item = this.items[name]; if (item != null) { return item.setter(item.getter()); } return null; - } - - this.isClickableOverlayItem = function(item) { + }; + + Panel.prototype.isClickableOverlayItem = function(item) { for (var i in this.items) { if (this.items[i].widget.isClickableOverlayItem(item)) { return true; } } return false; - } - - this.getHeight = function() { + }; + + Panel.prototype.getHeight = function(show) { var height = 0; - + for (var i in this.items) { + height += this.items[i].widget.getHeight(); - if(this.items[i].isSubPanel) { + // if(show) { + // print("widget: " + i + " height: " + this.items[i].widget.getHeight()); + + // } + if(this.items[i].isSubPanel && this.items[i].widget.visible) { + height += 1.5 * rawHeight; - } + + } + } - return height; - } + }; -}; + Panel.prototype.moveUp = function() { + for (var i in this.items) { + this.items[i].widget.moveUp(); + } + + }; + + Panel.prototype.moveDown = function() { + for (var i in this.items) { + this.items[i].widget.moveDown(); + } + }; + + Panel.prototype.getCurrentY = function(key) { + var height = 0; + var keys = Object.keys(this.items); + + for (var i = 0; i < keys.indexOf(key); ++i) { + var item = this.items[keys[i]]; + + height += item.widget.getHeight(); + + if(item.isSubPanel) { + height += 1.5 * rawHeight; + + } + } + + return this.y + height; + }; + + + Panel.prototype.hide = function() { + for (var i in this.items) { + if(this.items[i].isSubPanel) { + this.items[i].widget.hide(); + } + this.items[i].hide(); + } + this.visible = false; + }; + + Panel.prototype.show = function() { + for (var i in this.items) { + if(this.items[i].isSubPanel) { + this.items[i].widget.show(); + } + this.items[i].show(); + } + this.visible = true; + }; + Panel.prototype.destroy = function() { + for (var i in this.items) { + + if(this.items[i].isSubPanel) { + this.items[i].widget.destroy(); + } + this.items[i].destroy(); + } + }; + + + this.Panel = Panel; +})(); \ No newline at end of file From b7d195e8173360ebb45fc1d9e7a771fc030a245c Mon Sep 17 00:00:00 2001 From: bwent Date: Mon, 27 Jul 2015 13:56:25 -0700 Subject: [PATCH 49/58] more subpanel fixes --- examples/utilities/tools/cookies.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index 9d064385bf..44017c66da 100644 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -888,10 +888,10 @@ } } + // Now recalculate new heights of subsequent widgets for(var j = i + 1; j < keys.length; ++j) { - this.items[keys[j]].moveUp(this.getCurrentY(keys[j])); } From 774b4851c323f5adec20173a45f9aa3474edb9fe Mon Sep 17 00:00:00 2001 From: bwent Date: Tue, 28 Jul 2015 12:18:26 -0700 Subject: [PATCH 50/58] Add tab to highlight widgets and update using left and right arrow keys --- examples/utilities/tools/cookies.js | 453 +++++++++++++++++----------- 1 file changed, 282 insertions(+), 171 deletions(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index 44017c66da..b2dc8c1da7 100644 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -9,6 +9,26 @@ // 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 SCALE = 1000; +var THUMB_COLOR = { + red: 150, + green: 150, + blue: 150 +}; +var THUMB_HIGHLIGHT = { + red: 255, + green: 255, + blue: 255 +}; +var CHECK_MARK_COLOR = { + red: 70, + green: 70, + blue: 90 +}; + // The Slider class (function () { var Slider = function(x,y,width,thumbSize) { @@ -24,7 +44,7 @@ visible: true }); this.thumb = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, + backgroundColor: THUMB_COLOR, x: x, y: y, width: thumbSize, @@ -61,6 +81,25 @@ return (item == this.thumb) || (item == this.background); }; + + Slider.prototype.onMousePressEvent = function(event, clickedOverlay) { + if (!this.isClickableOverlayItem(clickedOverlay)) { + this.isMoving = false; + return; + } + this.highlight(); + this.isMoving = true; + var clickOffset = event.x - this.thumbX; + if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) { + this.clickOffsetX = clickOffset; + } else { + this.clickOffsetX = 0; + this.thumbX = event.x; + this.updateThumb(); + this.onValueChanged(this.getValue()); + } + }; + Slider.prototype.onMouseMoveEvent = function(event) { if (this.isMoving) { var newThumbX = event.x - this.clickOffsetX; @@ -76,34 +115,43 @@ } }; - Slider.prototype.onMousePressEvent = function(event, clickedOverlay) { - if (!this.isClickableOverlayItem(clickedOverlay)) { - this.isMoving = false; - return; - } - this.isMoving = true; - var clickOffset = event.x - this.thumbX; - if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) { - this.clickOffsetX = clickOffset; - } else { - this.clickOffsetX = 0; - this.thumbX = event.x; - this.updateThumb(); - this.onValueChanged(this.getValue()); - } - - }; - Slider.prototype.onMouseReleaseEvent = function(event) { this.isMoving = false; + this.unhighlight(); }; - - // Public members: + + Slider.prototype.updateWithKeys = function(direction) { + this.range = this.maxThumbX - this.minThumbX; + this.thumbX += direction * (this.range / SCALE); + this.updateThumb(); + this.onValueChanged(this.getValue()); + }; + + Slider.prototype.highlight = function() { + if(this.highlighted) { + return; + } + Overlays.editOverlay(this.thumb, { + backgroundColor: {red: 255, green: 255, blue: 255} + }); + this.highlighted = true; + }; + + Slider.prototype.unhighlight = function() { + if(!this.highlighted) { + return; + } + Overlays.editOverlay(this.thumb, { + backgroundColor: THUMB_COLOR + }); + this.highlighted = false; + }; + Slider.prototype.setNormalizedValue = function(value) { if (value < 0.0) { this.thumbX = this.minThumbX; } else if (value > 1.0) { - this.thumbX = this.maxThumbX; + this.thumbX = this.maxThsumbX; } else { this.thumbX = value * (this.maxThumbX - this.minThumbX) + this.minThumbX; } @@ -117,16 +165,17 @@ var normValue = (value - this.minValue) / (this.maxValue - this.minValue); this.setNormalizedValue(normValue); }; + Slider.prototype.getValue = function() { + return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue; + }; Slider.prototype.reset = function(resetValue) { this.setValue(resetValue); this.onValueChanged(resetValue); }; - Slider.prototype.getValue = function() { - return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue; - }; - + Slider.prototype.onValueChanged = function(value) {}; + Slider.prototype.getHeight = function() { if(!this.visible) { return 0; @@ -143,8 +192,6 @@ Overlays.editOverlay(this.background, {y: this.y}); Overlays.editOverlay(this.thumb, {y: this.y}); }; - - Slider.prototype.onValueChanged = function(value) {}; Slider.prototype.hide = function() { Overlays.editOverlay(this.background, {visible: false}); @@ -157,36 +204,19 @@ Overlays.editOverlay(this.thumb, {visible: true}); this.visible = true; }; - + Slider.prototype.destroy = function() { Overlays.deleteOverlay(this.background); Overlays.deleteOverlay(this.thumb); }; - - Slider.prototype.setThumbColor = function(color) { - Overlays.editOverlay(this.thumb, {backgroundColor: { red: color.x*255, green: color.y*255, blue: color.z*255 }}); - }; - Slider.prototype.setBackgroundColor = function(color) { - Overlays.editOverlay(this.background, {backgroundColor: { red: color.x*255, green: color.y*255, blue: color.z*255 }}); - }; + this.Slider = Slider; // The Checkbox class var Checkbox = function(x,y,width,thumbSize) { - this.background = Overlays.addOverlay("text", { - backgroundColor: { red: 125, green: 125, blue: 255 }, - x: x, - y: y, - width: width, - height: thumbSize, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true - }); - this.thumb = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, + backgroundColor: THUMB_COLOR, textFontSize: 10, x: x, y: y, @@ -208,64 +238,72 @@ this.checkMark = Overlays.addOverlay("text", { - backgroundColor: { red: 0, green: 255, blue: 0 }, + backgroundColor: CHECK_MARK_COLOR, x: checkX, y: checkY, width: thumbSize / 2.0, height: thumbSize / 2.0, alpha: 1.0, visible: true - }); - - this.unCheckMark = Overlays.addOverlay("image", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: checkX + 1.0, - y: checkY + 1.0, - width: thumbSize / 2.5, - height: thumbSize / 2.5, - alpha: 1.0, - visible: false - }); + }); }; Checkbox.prototype.updateThumb = function() { - - Overlays.editOverlay(this.unCheckMark, { visible: !this.boxCheckStatus }); - + Overlays.editOverlay(this.checkMark, { visible: this.boxCheckStatus }); }; Checkbox.prototype.isClickableOverlayItem = function(item) { - return (item == this.thumb) || (item == this.checkMark) || (item == this.unCheckMark); + return (item == this.thumb) || (item == this.checkMark); }; Checkbox.prototype.onMousePressEvent = function(event, clickedOverlay) { - if (!this.isClickableOverlayItem(clickedOverlay)) { return; - } - + } this.boxCheckStatus = !this.boxCheckStatus; this.onValueChanged(this.getValue()); this.updateThumb(); }; - - Checkbox.prototype.onMouseReleaseEvent = function(event) { }; - - - // Public members: + Checkbox.prototype.onMouseReleaseEvent = function(event) {}; + + Checkbox.prototype.updateWithKeys = function() { + this.boxCheckStatus = !this.boxCheckStatus; + this.onValueChanged(this.getValue()); + this.updateThumb(); + }; + + Checkbox.prototype.highlight = function() { + Overlays.editOverlay(this.thumb, { + backgroundColor: THUMB_HIGHLIGHT + }); + this.highlighted = true; + }; + + Checkbox.prototype.unhighlight = function() { + Overlays.editOverlay(this.thumb, { + backgroundColor: THUMB_COLOR + }); + this.highlighted = false; + }; Checkbox.prototype.setValue = function(value) { this.boxCheckStatus = value; }; + + Checkbox.prototype.setterFromWidget = function(value) { + this.updateThumb(); + }; + + Checkbox.prototype.getValue = function() { + return this.boxCheckStatus; + }; Checkbox.prototype.reset = function(resetValue) { this.setValue(resetValue); }; - - Checkbox.prototype.getValue = function() { - return this.boxCheckStatus; - }; + + Checkbox.prototype.onValueChanged = function(value) { }; Checkbox.prototype.getHeight = function() { if(!this.visible) { @@ -287,12 +325,6 @@ Overlays.editOverlay(this.checkMark, {y: this.y}); Overlays.editOverlay(this.unCheckMark, {y: this.y}); }; - - Checkbox.prototype.setterFromWidget = function(value) { - this.updateThumb(); - }; - - Checkbox.prototype.onValueChanged = function(value) { }; Checkbox.prototype.hide = function() { Overlays.editOverlay(this.background, {visible: false}); @@ -316,13 +348,7 @@ Overlays.deleteOverlay(this.checkMark); Overlays.deleteOverlay(this.unCheckMark); }; - - Checkbox.prototype.setThumbColor = function(color) { - Overlays.editOverlay(this.thumb, { red: 255, green: 255, blue: 255 } ); - }; - Checkbox.prototype.setBackgroundColor = function(color) { - Overlays.editOverlay(this.background, { red: 125, green: 125, blue: 255 }); - }; + this.Checkbox = Checkbox; // The ColorBox class @@ -351,12 +377,6 @@ || this.blue.isClickableOverlayItem(item); }; - ColorBox.prototype.onMouseMoveEvent = function(event) { - this.red.onMouseMoveEvent(event); - this.green.onMouseMoveEvent(event); - this.blue.onMouseMoveEvent(event); - }; - ColorBox.prototype.onMousePressEvent = function(event, clickedOverlay) { this.red.onMousePressEvent(event, clickedOverlay); if (this.red.isMoving) { @@ -370,19 +390,48 @@ this.blue.onMousePressEvent(event, clickedOverlay); }; - + + ColorBox.prototype.onMouseMoveEvent = function(event) { + this.red.onMouseMoveEvent(event); + this.green.onMouseMoveEvent(event); + this.blue.onMouseMoveEvent(event); + }; ColorBox.prototype.onMouseReleaseEvent = function(event) { this.red.onMouseReleaseEvent(event); this.green.onMouseReleaseEvent(event); this.blue.onMouseReleaseEvent(event); }; - + + ColorBox.prototype.updateWithKeys = function(direction) { + this.red.updateWithKeys(direction); + this.green.updateWithKeys(direction); + this.blue.updateWithKeys(direction); + } + + ColorBox.prototype.highlight = function() { + this.red.highlight(); + this.green.highlight(); + this.blue.highlight(); + + this.highlighted = true; + }; + + ColorBox.prototype.unhighlight = function() { + this.red.unhighlight(); + this.green.unhighlight(); + this.blue.unhighlight(); + + this.highlighted = false; + }; + ColorBox.prototype.setterFromWidget = function(value) { var color = this.getValue(); this.onValueChanged(color); this.updateRGBSliders(color); }; + + ColorBox.prototype.onValueChanged = function(value) {}; ColorBox.prototype.updateRGBSliders = function(color) { this.red.setThumbColor({x: color.x, y: 0, z: 0}); @@ -397,17 +446,18 @@ this.blue.setValue(value.z); this.updateRGBSliders(value); }; - - ColorBox.prototype.reset = function(resetValue) { - this.setValue(resetValue); - this.onValueChanged(resetValue); - }; - + ColorBox.prototype.getValue = function() { var value = {x:this.red.getValue(), y:this.green.getValue(),z:this.blue.getValue()}; return value; }; - + + ColorBox.prototype.reset = function(resetValue) { + this.setValue(resetValue); + this.onValueChanged(resetValue); + }; + + ColorBox.prototype.getHeight = function() { if(!this.visible) { return 0; @@ -446,8 +496,7 @@ this.green.destroy(); this.blue.destroy(); }; - - ColorBox.prototype.onValueChanged = function(value) {}; + this.ColorBox = ColorBox; // The DirectionBox class @@ -479,11 +528,6 @@ || this.pitch.isClickableOverlayItem(item); }; - DirectionBox.prototype.onMouseMoveEvent = function(event) { - this.yaw.onMouseMoveEvent(event); - this.pitch.onMouseMoveEvent(event); - }; - DirectionBox.prototype.onMousePressEvent = function(event, clickedOverlay) { this.yaw.onMousePressEvent(event, clickedOverlay); if (this.yaw.isMoving) { @@ -491,18 +535,43 @@ } this.pitch.onMousePressEvent(event, clickedOverlay); }; + + DirectionBox.prototype.onMouseMoveEvent = function(event) { + this.yaw.onMouseMoveEvent(event); + this.pitch.onMouseMoveEvent(event); + }; DirectionBox.prototype.onMouseReleaseEvent = function(event) { this.yaw.onMouseReleaseEvent(event); this.pitch.onMouseReleaseEvent(event); }; + + DirectionBox.prototype.updateWithKeys = function(direction) { + this.yaw.updateWithKeys(direction); + this.pitch.updateWithKeys(direction); + }; + + DirectionBox.prototype.highlight = function() { + this.pitch.highlight(); + this.yaw.highlight(); + + this.highlighted = true; + }; + + DirectionBox.prototype.unhighlight = function() { + this.pitch.unhighlight(); + this.yaw.unhighlight(); + + this.highlighted = false; + }; DirectionBox.prototype.setterFromWidget = function(value) { var yawPitch = this.getValue(); this.onValueChanged(yawPitch); }; - - // Public members: + + DirectionBox.prototype.onValueChanged = function(value) {}; + DirectionBox.prototype.setValue = function(direction) { var flatXZ = Math.sqrt(direction.x * direction.x + direction.z * direction.z); if (flatXZ > 0.0) { @@ -516,13 +585,8 @@ } this.pitch.setValue(direction.y); }; - - DirectionBox.prototype.reset = function(resetValue) { - this.setValue(resetValue); - this.onValueChanged(resetValue); - }; - - DirectionBox.prototype.getValue = function() { + + DirectionBox.prototype.getValue = function() { var dirZ = this.pitch.getValue(); var yaw = this.yaw.getValue() * Math.PI / 180; var cosY = Math.sqrt(1 - dirZ*dirZ); @@ -530,6 +594,11 @@ return value; }; + DirectionBox.prototype.reset = function(resetValue) { + this.setValue(resetValue); + this.onValueChanged(resetValue); + }; + DirectionBox.prototype.getHeight = function() { if(!this.visible) { return 0; @@ -564,7 +633,6 @@ this.pitch.destroy(); }; - DirectionBox.prototype.onValueChanged = function(value) {}; this.DirectionBox = DirectionBox; var textFontSize = 12; @@ -577,15 +645,14 @@ var topMargin = (height - 1.5 * textFontSize); - this.thumb = Overlays.addOverlay("text", { - backgroundColor: { red: 220, green: 220, blue: 220 }, - textFontSize: 10, + this.thumb = Overlays.addOverlay("image", { + color: {red: 255, green: 255, blue: 255}, + imageURL: HIFI_PUBLIC_BUCKET + 'images/tools/min-max-toggle.svg', x: x, y: y, width: rawHeight, height: rawHeight, alpha: 1.0, - backgroundAlpha: 1.0, visible: true }); @@ -644,13 +711,12 @@ if (this.widget != null) { this.widget.moveDown(); } - } - this.CollapsablePanelItem = CollapsablePanelItem; var PanelItem = function (name, setter, getter, displayer, x, y, textWidth, valueWidth, height) { //print("creating panel item: " + name); + this.isCollapsable = false; this.name = name; this.y = y; @@ -780,14 +846,23 @@ var widgetWidth = 300; var rawHeight = 20; var rawYDelta = rawHeight * 1.5; + var outerPanel = true; + var widgets; + var Panel = function(x, y) { - + + if (outerPanel) { + widgets = []; + } + outerPanel = false; + this.x = x; this.y = y; + this.nextY = y; - this.nextY = y; print("creating panel at x: " + this.x + " y: " + this.y); - + print("creating panel at x: " + this.x + " y: " + this.y); + this.widgetX = x + textWidth + valueWidth; this.items = new Array(); @@ -826,12 +901,20 @@ } } }; + + Panel.prototype.mouseReleaseEvent = function(event) { + if (this.activeWidget) { + this.activeWidget.onMouseReleaseEvent(event); + } + this.activeWidget = null; + }; // Reset panel item upon double-clicking Panel.prototype.mouseDoublePressEvent = function(event) { var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); this.handleReset(clickedOverlay); - } + }; + Panel.prototype.handleReset = function (clickedOverlay) { for (var i in this.items) { @@ -845,16 +928,13 @@ if (clickedOverlay == item.title) { item.activeWidget = widget; - item.activeWidget.reset(item.resetValue); - break; } } }; Panel.prototype.handleCollapse = function (clickedOverlay) { - for (var i in this.items) { var item = this.items[i]; @@ -886,19 +966,14 @@ panel.hide(); break; } - } - // Now recalculate new heights of subsequent widgets for(var j = i + 1; j < keys.length; ++j) { this.items[keys[j]].moveUp(this.getCurrentY(keys[j])); - } - }; - Panel.prototype.expand = function (clickedOverlay) { var keys = Object.keys(this.items); @@ -910,23 +985,13 @@ panel.show(); break; } - - } - - // Now recalculate new heights of subsequent widgets + } + // Now recalculate new heights of subsequent widgets for(var j = i + 1; j < keys.length; ++j) { this.items[keys[j]].moveDown(); } + }; - }; - - - Panel.prototype.mouseReleaseEvent = function(event) { - if (this.activeWidget) { - this.activeWidget.onMouseReleaseEvent(event); - } - this.activeWidget = null; - }; Panel.prototype.onMousePressEvent = function(event, clickedOverlay) { for (var i in this.items) { @@ -938,7 +1003,6 @@ } }; - Panel.prototype.onMouseMoveEvent = function(event) { for (var i in this.items) { var item = this.items[i]; @@ -966,7 +1030,63 @@ } } }; - + + var tabView = false; + var tabIndex = 0; + + Panel.prototype.keyPressEvent = function(event) { + if(event.text == "TAB" && !event.isShifted) { + tabView = true; + if(tabIndex < widgets.length) { + if(tabIndex > 0 && widgets[tabIndex - 1].highlighted) { + // Unhighlight previous widget + widgets[tabIndex - 1].unhighlight(); + } + widgets[tabIndex].highlight(); + tabIndex++; + } else { + widgets[tabIndex - 1].unhighlight(); + //Wrap around to front + tabIndex = 0; + widgets[tabIndex].highlight(); + tabIndex++; + } + } else if (tabView && event.isShifted) { + if(tabIndex > 0) { + tabIndex--; + if(tabIndex < widgets.length && widgets[tabIndex + 1].highlighted) { + // Unhighlight previous widget + widgets[tabIndex + 1].unhighlight(); + } + widgets[tabIndex].highlight(); + } else { + widgets[tabIndex].unhighlight(); + //Wrap around to end + tabIndex = widgets.length - 1; + widgets[tabIndex].highlight(); + } + } else if (event.text == "LEFT") { + for(var i = 0; i < widgets.length; i++) { + // Find the highlighted widget, allow control with arrow keys + if(widgets[i].highlighted) { + var k = -1; + widgets[i].updateWithKeys(k); + break; + } + } + } else if (event.text == "RIGHT") { + for(var i = 0; i < widgets.length; i++) { + // Find the highlighted widget, allow control with arrow keys + if(widgets[i].highlighted) { + var k = 1; + widgets[i].updateWithKeys(k); + break; + } + } + } + }; + + // Widget constructors Panel.prototype.newSlider = function(name, minValue, maxValue, setValue, getValue, displayValue) { this.nextY = this.y + this.getHeight(); @@ -974,6 +1094,7 @@ var slider = new Slider(this.widgetX, this.nextY, widgetWidth, rawHeight); slider.minValue = minValue; slider.maxValue = maxValue; + widgets.push(slider); item.widget = slider; item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; @@ -995,6 +1116,7 @@ var item = new PanelItem(name, setValue, getValue, display, this.x, this.nextY, textWidth, valueWidth, rawHeight); var checkbox = new Checkbox(this.widgetX, this.nextY, widgetWidth, rawHeight); + widgets.push(checkbox); item.widget = checkbox; item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; @@ -1010,6 +1132,7 @@ var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); var colorBox = new ColorBox(this.widgetX, this.nextY, widgetWidth, rawHeight); + widgets.push(colorBox); item.widget = colorBox; item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; @@ -1025,6 +1148,7 @@ var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); var directionBox = new DirectionBox(this.widgetX, this.nextY, widgetWidth, rawHeight); + widgets.push(directionBox); item.widget = directionBox; item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; @@ -1034,10 +1158,8 @@ // print("created Item... directionBox=" + name); }; - - Panel.prototype.newSubPanel = function(name) { - //TODO: make collapsable, fix double-press event + this.nextY = this.y + this.getHeight(); var item = new CollapsablePanelItem(name, this.x, this.nextY, textWidth, rawHeight, panel); @@ -1093,22 +1215,14 @@ return false; }; - Panel.prototype.getHeight = function(show) { + Panel.prototype.getHeight = function() { var height = 0; for (var i in this.items) { - height += this.items[i].widget.getHeight(); - // if(show) { - // print("widget: " + i + " height: " + this.items[i].widget.getHeight()); - - // } if(this.items[i].isSubPanel && this.items[i].widget.visible) { - - height += 1.5 * rawHeight; - - } - + height += 1.5 * rawHeight; + } } return height; @@ -1118,7 +1232,6 @@ for (var i in this.items) { this.items[i].widget.moveUp(); } - }; Panel.prototype.moveDown = function() { @@ -1141,7 +1254,6 @@ } } - return this.y + height; }; @@ -1177,6 +1289,5 @@ } }; - this.Panel = Panel; })(); \ No newline at end of file From d9693796bc06a77eb38c1c7fede2eb26d077f3c9 Mon Sep 17 00:00:00 2001 From: bwent Date: Tue, 28 Jul 2015 12:27:37 -0700 Subject: [PATCH 51/58] Capture key events --- examples/utilities/tools/cookies.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index b2dc8c1da7..175d8c2393 100644 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -1288,6 +1288,15 @@ var CHECK_MARK_COLOR = { this.items[i].destroy(); } }; - this.Panel = Panel; -})(); \ No newline at end of file +})(); + + +Script.scriptEnding.connect(function scriptEnding() { + Controller.releaseKeyEvents({text: "left"}); + Controller.releaseKeyEvents({key: "right"}); +}); + + +Controller.captureKeyEvents({text: "left"}); +Controller.captureKeyEvents({text: "right"}); \ No newline at end of file From 2be95997d16ed572aac938af45393f8b8fbcfad1 Mon Sep 17 00:00:00 2001 From: bwent Date: Tue, 28 Jul 2015 12:32:14 -0700 Subject: [PATCH 52/58] clean up formatting --- examples/utilities/tools/cookies.js | 1317 +++++++++++++++------------ 1 file changed, 749 insertions(+), 568 deletions(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index 175d8c2393..24cda69ba2 100644 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -30,204 +30,230 @@ var CHECK_MARK_COLOR = { }; // The Slider class -(function () { - var Slider = function(x,y,width,thumbSize) { - +(function() { + var Slider = function(x, y, width, thumbSize) { + this.background = Overlays.addOverlay("text", { - backgroundColor: { red: 200, green: 200, blue: 255 }, - x: x, - y: y, - width: width, - height: thumbSize, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true - }); + backgroundColor: { + red: 200, + green: 200, + blue: 255 + }, + x: x, + y: y, + width: width, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true + }); this.thumb = Overlays.addOverlay("text", { - backgroundColor: THUMB_COLOR, - x: x, - y: y, - width: thumbSize, - height: thumbSize, - alpha: 1.0, - backgroundAlpha: 1.0, - visible: true - }); - + backgroundColor: THUMB_COLOR, + x: x, + y: y, + width: thumbSize, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 1.0, + visible: true + }); + this.thumbSize = thumbSize; - + this.thumbHalfSize = 0.5 * thumbSize; - + this.minThumbX = x + this.thumbHalfSize; this.maxThumbX = x + width - this.thumbHalfSize; this.thumbX = this.minThumbX; - + this.minValue = 0.0; this.maxValue = 1.0; this.y = y; - + this.clickOffsetX = 0; this.isMoving = false; this.visible = true; }; - - Slider.prototype.updateThumb = function() { - var thumbTruePos = this.thumbX - 0.5 * this.thumbSize; - Overlays.editOverlay(this.thumb, { x: thumbTruePos } ); - }; - - Slider.prototype.isClickableOverlayItem = function(item) { - return (item == this.thumb) || (item == this.background); - }; - - - Slider.prototype.onMousePressEvent = function(event, clickedOverlay) { - if (!this.isClickableOverlayItem(clickedOverlay)) { - this.isMoving = false; - return; - } - this.highlight(); - this.isMoving = true; - var clickOffset = event.x - this.thumbX; - if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) { - this.clickOffsetX = clickOffset; - } else { - this.clickOffsetX = 0; - this.thumbX = event.x; - this.updateThumb(); - this.onValueChanged(this.getValue()); - } - }; - Slider.prototype.onMouseMoveEvent = function(event) { - if (this.isMoving) { - var newThumbX = event.x - this.clickOffsetX; - if (newThumbX < this.minThumbX) { - newThumbX = this.minThumbX; - } - if (newThumbX > this.maxThumbX) { - newThumbX = this.maxThumbX; - } - this.thumbX = newThumbX; - this.updateThumb(); - this.onValueChanged(this.getValue()); - } - }; - - Slider.prototype.onMouseReleaseEvent = function(event) { + Slider.prototype.updateThumb = function() { + var thumbTruePos = this.thumbX - 0.5 * this.thumbSize; + Overlays.editOverlay(this.thumb, { + x: thumbTruePos + }); + }; + + Slider.prototype.isClickableOverlayItem = function(item) { + return (item == this.thumb) || (item == this.background); + }; + + + Slider.prototype.onMousePressEvent = function(event, clickedOverlay) { + if (!this.isClickableOverlayItem(clickedOverlay)) { this.isMoving = false; - this.unhighlight(); - }; + return; + } + this.highlight(); + this.isMoving = true; + var clickOffset = event.x - this.thumbX; + if ((clickOffset > -this.thumbHalfSize) && (clickOffset < this.thumbHalfSize)) { + this.clickOffsetX = clickOffset; + } else { + this.clickOffsetX = 0; + this.thumbX = event.x; + this.updateThumb(); + this.onValueChanged(this.getValue()); + } + }; + + Slider.prototype.onMouseMoveEvent = function(event) { + if (this.isMoving) { + var newThumbX = event.x - this.clickOffsetX; + if (newThumbX < this.minThumbX) { + newThumbX = this.minThumbX; + } + if (newThumbX > this.maxThumbX) { + newThumbX = this.maxThumbX; + } + this.thumbX = newThumbX; + this.updateThumb(); + this.onValueChanged(this.getValue()); + } + }; + + Slider.prototype.onMouseReleaseEvent = function(event) { + this.isMoving = false; + this.unhighlight(); + }; Slider.prototype.updateWithKeys = function(direction) { this.range = this.maxThumbX - this.minThumbX; this.thumbX += direction * (this.range / SCALE); this.updateThumb(); this.onValueChanged(this.getValue()); - }; + }; Slider.prototype.highlight = function() { - if(this.highlighted) { + if (this.highlighted) { return; } Overlays.editOverlay(this.thumb, { - backgroundColor: {red: 255, green: 255, blue: 255} + backgroundColor: { + red: 255, + green: 255, + blue: 255 + } }); - this.highlighted = true; + this.highlighted = true; }; Slider.prototype.unhighlight = function() { - if(!this.highlighted) { + if (!this.highlighted) { return; } Overlays.editOverlay(this.thumb, { backgroundColor: THUMB_COLOR - }); + }); this.highlighted = false; }; Slider.prototype.setNormalizedValue = function(value) { - if (value < 0.0) { - this.thumbX = this.minThumbX; - } else if (value > 1.0) { - this.thumbX = this.maxThsumbX; - } else { - this.thumbX = value * (this.maxThumbX - this.minThumbX) + this.minThumbX; - } - this.updateThumb(); - }; + if (value < 0.0) { + this.thumbX = this.minThumbX; + } else if (value > 1.0) { + this.thumbX = this.maxThsumbX; + } else { + this.thumbX = value * (this.maxThumbX - this.minThumbX) + this.minThumbX; + } + this.updateThumb(); + }; Slider.prototype.getNormalizedValue = function() { - return (this.thumbX - this.minThumbX) / (this.maxThumbX - this.minThumbX); - }; - + return (this.thumbX - this.minThumbX) / (this.maxThumbX - this.minThumbX); + }; + Slider.prototype.setValue = function(value) { - var normValue = (value - this.minValue) / (this.maxValue - this.minValue); - this.setNormalizedValue(normValue); - }; + var normValue = (value - this.minValue) / (this.maxValue - this.minValue); + this.setNormalizedValue(normValue); + }; Slider.prototype.getValue = function() { - return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue; - }; - + return this.getNormalizedValue() * (this.maxValue - this.minValue) + this.minValue; + }; + Slider.prototype.reset = function(resetValue) { - this.setValue(resetValue); - this.onValueChanged(resetValue); - }; + this.setValue(resetValue); + this.onValueChanged(resetValue); + }; Slider.prototype.onValueChanged = function(value) {}; Slider.prototype.getHeight = function() { - if(!this.visible) { - return 0; - } - return 1.5 * this.thumbSize; - }; + if (!this.visible) { + return 0; + } + return 1.5 * this.thumbSize; + }; Slider.prototype.moveUp = function(newY) { - Overlays.editOverlay(this.background, {y: newY}); - Overlays.editOverlay(this.thumb, {y: newY}); + Overlays.editOverlay(this.background, { + y: newY + }); + Overlays.editOverlay(this.thumb, { + y: newY + }); }; Slider.prototype.moveDown = function() { - Overlays.editOverlay(this.background, {y: this.y}); - Overlays.editOverlay(this.thumb, {y: this.y}); + Overlays.editOverlay(this.background, { + y: this.y + }); + Overlays.editOverlay(this.thumb, { + y: this.y + }); }; Slider.prototype.hide = function() { - Overlays.editOverlay(this.background, {visible: false}); - Overlays.editOverlay(this.thumb, {visible: false}); - this.visible = false; - }; + Overlays.editOverlay(this.background, { + visible: false + }); + Overlays.editOverlay(this.thumb, { + visible: false + }); + this.visible = false; + }; Slider.prototype.show = function() { - Overlays.editOverlay(this.background, {visible: true}); - Overlays.editOverlay(this.thumb, {visible: true}); - this.visible = true; - }; + Overlays.editOverlay(this.background, { + visible: true + }); + Overlays.editOverlay(this.thumb, { + visible: true + }); + this.visible = true; + }; Slider.prototype.destroy = function() { - Overlays.deleteOverlay(this.background); - Overlays.deleteOverlay(this.thumb); - }; + Overlays.deleteOverlay(this.background); + Overlays.deleteOverlay(this.thumb); + }; this.Slider = Slider; - + // The Checkbox class - var Checkbox = function(x,y,width,thumbSize) { - + var Checkbox = function(x, y, width, thumbSize) { + this.thumb = Overlays.addOverlay("text", { - backgroundColor: THUMB_COLOR, - textFontSize: 10, - x: x, - y: y, - width: thumbSize, - height: thumbSize, - alpha: 1.0, - backgroundAlpha: 1.0, - visible: true - }); - - + backgroundColor: THUMB_COLOR, + textFontSize: 10, + x: x, + y: y, + width: thumbSize, + height: thumbSize, + alpha: 1.0, + backgroundAlpha: 1.0, + visible: true + }); + + this.thumbSize = thumbSize; var checkX = x + (0.25 * thumbSize); var checkY = y + (0.25 * thumbSize); @@ -235,173 +261,217 @@ var CHECK_MARK_COLOR = { this.boxCheckStatus = true; this.clickedBox = false; this.visible = true; - - + + this.checkMark = Overlays.addOverlay("text", { - backgroundColor: CHECK_MARK_COLOR, - x: checkX, - y: checkY, - width: thumbSize / 2.0, - height: thumbSize / 2.0, - alpha: 1.0, - visible: true - }); + backgroundColor: CHECK_MARK_COLOR, + x: checkX, + y: checkY, + width: thumbSize / 2.0, + height: thumbSize / 2.0, + alpha: 1.0, + visible: true + }); }; - - Checkbox.prototype.updateThumb = function() { - Overlays.editOverlay(this.checkMark, { visible: this.boxCheckStatus }); - }; - + + Checkbox.prototype.updateThumb = function() { + Overlays.editOverlay(this.checkMark, { + visible: this.boxCheckStatus + }); + }; + Checkbox.prototype.isClickableOverlayItem = function(item) { - return (item == this.thumb) || (item == this.checkMark); - }; - + return (item == this.thumb) || (item == this.checkMark); + }; + Checkbox.prototype.onMousePressEvent = function(event, clickedOverlay) { - if (!this.isClickableOverlayItem(clickedOverlay)) { - return; - } - this.boxCheckStatus = !this.boxCheckStatus; - this.onValueChanged(this.getValue()); - this.updateThumb(); - }; - + if (!this.isClickableOverlayItem(clickedOverlay)) { + return; + } + this.boxCheckStatus = !this.boxCheckStatus; + this.onValueChanged(this.getValue()); + this.updateThumb(); + }; + Checkbox.prototype.onMouseReleaseEvent = function(event) {}; Checkbox.prototype.updateWithKeys = function() { this.boxCheckStatus = !this.boxCheckStatus; this.onValueChanged(this.getValue()); this.updateThumb(); - }; + }; Checkbox.prototype.highlight = function() { Overlays.editOverlay(this.thumb, { backgroundColor: THUMB_HIGHLIGHT }); - this.highlighted = true; - }; + this.highlighted = true; + }; Checkbox.prototype.unhighlight = function() { Overlays.editOverlay(this.thumb, { backgroundColor: THUMB_COLOR - }); + }); this.highlighted = false; - }; - + }; + Checkbox.prototype.setValue = function(value) { - this.boxCheckStatus = value; - }; + this.boxCheckStatus = value; + }; Checkbox.prototype.setterFromWidget = function(value) { - this.updateThumb(); - }; + this.updateThumb(); + }; Checkbox.prototype.getValue = function() { - return this.boxCheckStatus; - }; - - Checkbox.prototype.reset = function(resetValue) { - this.setValue(resetValue); - }; + return this.boxCheckStatus; + }; + + Checkbox.prototype.reset = function(resetValue) { + this.setValue(resetValue); + }; + + Checkbox.prototype.onValueChanged = function(value) {}; - Checkbox.prototype.onValueChanged = function(value) { }; - Checkbox.prototype.getHeight = function() { - if(!this.visible) { + if (!this.visible) { return 0; } - return 1.5 * this.thumbSize; - }; + return 1.5 * this.thumbSize; + }; Checkbox.prototype.moveUp = function(newY) { - Overlays.editOverlay(this.background, {y: newY}); - Overlays.editOverlay(this.thumb, {y: newY}); - Overlays.editOverlay(this.checkMark, {y: newY}); - Overlays.editOverlay(this.unCheckMark, {y: newY}); + Overlays.editOverlay(this.background, { + y: newY + }); + Overlays.editOverlay(this.thumb, { + y: newY + }); + Overlays.editOverlay(this.checkMark, { + y: newY + }); + Overlays.editOverlay(this.unCheckMark, { + y: newY + }); }; Checkbox.prototype.moveDown = function() { - Overlays.editOverlay(this.background, {y: this.y}); - Overlays.editOverlay(this.thumb, {y: this.y}); - Overlays.editOverlay(this.checkMark, {y: this.y}); - Overlays.editOverlay(this.unCheckMark, {y: this.y}); + Overlays.editOverlay(this.background, { + y: this.y + }); + Overlays.editOverlay(this.thumb, { + y: this.y + }); + Overlays.editOverlay(this.checkMark, { + y: this.y + }); + Overlays.editOverlay(this.unCheckMark, { + y: this.y + }); }; Checkbox.prototype.hide = function() { - Overlays.editOverlay(this.background, {visible: false}); - Overlays.editOverlay(this.thumb, {visible: false}); - Overlays.editOverlay(this.checkMark, {visible: false}); - Overlays.editOverlay(this.unCheckMark, {visible: false}); + Overlays.editOverlay(this.background, { + visible: false + }); + Overlays.editOverlay(this.thumb, { + visible: false + }); + Overlays.editOverlay(this.checkMark, { + visible: false + }); + Overlays.editOverlay(this.unCheckMark, { + visible: false + }); this.visible = false; } Checkbox.prototype.show = function() { - Overlays.editOverlay(this.background, {visible: true}); - Overlays.editOverlay(this.thumb, {visible: true}); - Overlays.editOverlay(this.checkMark, {visible: true}); - Overlays.editOverlay(this.unCheckMark, {visible: true}); + Overlays.editOverlay(this.background, { + visible: true + }); + Overlays.editOverlay(this.thumb, { + visible: true + }); + Overlays.editOverlay(this.checkMark, { + visible: true + }); + Overlays.editOverlay(this.unCheckMark, { + visible: true + }); this.visible = true; } - + Checkbox.prototype.destroy = function() { - Overlays.deleteOverlay(this.background); - Overlays.deleteOverlay(this.thumb); - Overlays.deleteOverlay(this.checkMark); - Overlays.deleteOverlay(this.unCheckMark); - }; + Overlays.deleteOverlay(this.background); + Overlays.deleteOverlay(this.thumb); + Overlays.deleteOverlay(this.checkMark); + Overlays.deleteOverlay(this.unCheckMark); + }; this.Checkbox = Checkbox; - + // The ColorBox class - var ColorBox = function(x,y,width,thumbSize) { + var ColorBox = function(x, y, width, thumbSize) { var self = this; - + var slideHeight = thumbSize / 3; var sliderWidth = width; this.red = new Slider(x, y, width, slideHeight); this.green = new Slider(x, y + slideHeight, width, slideHeight); this.blue = new Slider(x, y + 2 * slideHeight, width, slideHeight); - this.red.setBackgroundColor({x: 1, y: 0, z: 0}); - this.green.setBackgroundColor({x: 0, y: 1, z: 0}); - this.blue.setBackgroundColor({x: 0, y: 0, z: 1}); - + this.red.setBackgroundColor({ + x: 1, + y: 0, + z: 0 + }); + this.green.setBackgroundColor({ + x: 0, + y: 1, + z: 0 + }); + this.blue.setBackgroundColor({ + x: 0, + y: 0, + z: 1 + }); + this.red.onValueChanged = this.setterFromWidget; this.green.onValueChanged = this.setterFromWidget; this.blue.onValueChanged = this.setterFromWidget; this.visible = true; }; - - ColorBox.prototype.isClickableOverlayItem = function(item) { - return this.red.isClickableOverlayItem(item) - || this.green.isClickableOverlayItem(item) - || this.blue.isClickableOverlayItem(item); - }; - - ColorBox.prototype.onMousePressEvent = function(event, clickedOverlay) { - this.red.onMousePressEvent(event, clickedOverlay); - if (this.red.isMoving) { - return; - } - - this.green.onMousePressEvent(event, clickedOverlay); - if (this.green.isMoving) { - return; - } - - this.blue.onMousePressEvent(event, clickedOverlay); - }; - ColorBox.prototype.onMouseMoveEvent = function(event) { - this.red.onMouseMoveEvent(event); - this.green.onMouseMoveEvent(event); - this.blue.onMouseMoveEvent(event); - }; - + ColorBox.prototype.isClickableOverlayItem = function(item) { + return this.red.isClickableOverlayItem(item) || this.green.isClickableOverlayItem(item) || this.blue.isClickableOverlayItem(item); + }; + + ColorBox.prototype.onMousePressEvent = function(event, clickedOverlay) { + this.red.onMousePressEvent(event, clickedOverlay); + if (this.red.isMoving) { + return; + } + + this.green.onMousePressEvent(event, clickedOverlay); + if (this.green.isMoving) { + return; + } + + this.blue.onMousePressEvent(event, clickedOverlay); + }; + + ColorBox.prototype.onMouseMoveEvent = function(event) { + this.red.onMouseMoveEvent(event); + this.green.onMouseMoveEvent(event); + this.blue.onMouseMoveEvent(event); + }; + ColorBox.prototype.onMouseReleaseEvent = function(event) { - this.red.onMouseReleaseEvent(event); - this.green.onMouseReleaseEvent(event); - this.blue.onMouseReleaseEvent(event); - }; + this.red.onMouseReleaseEvent(event); + this.green.onMouseReleaseEvent(event); + this.blue.onMouseReleaseEvent(event); + }; ColorBox.prototype.updateWithKeys = function(direction) { this.red.updateWithKeys(direction); @@ -412,7 +482,7 @@ var CHECK_MARK_COLOR = { ColorBox.prototype.highlight = function() { this.red.highlight(); this.green.highlight(); - this.blue.highlight(); + this.blue.highlight(); this.highlighted = true; }; @@ -426,44 +496,60 @@ var CHECK_MARK_COLOR = { }; ColorBox.prototype.setterFromWidget = function(value) { - var color = this.getValue(); - this.onValueChanged(color); - this.updateRGBSliders(color); - }; + var color = this.getValue(); + this.onValueChanged(color); + this.updateRGBSliders(color); + }; ColorBox.prototype.onValueChanged = function(value) {}; - + ColorBox.prototype.updateRGBSliders = function(color) { - this.red.setThumbColor({x: color.x, y: 0, z: 0}); - this.green.setThumbColor({x: 0, y: color.y, z: 0}); - this.blue.setThumbColor({x: 0, y: 0, z: color.z}); - }; - - // Public members: + this.red.setThumbColor({ + x: color.x, + y: 0, + z: 0 + }); + this.green.setThumbColor({ + x: 0, + y: color.y, + z: 0 + }); + this.blue.setThumbColor({ + x: 0, + y: 0, + z: color.z + }); + }; + + // Public members: ColorBox.prototype.setValue = function(value) { - this.red.setValue(value.x); - this.green.setValue(value.y); - this.blue.setValue(value.z); - this.updateRGBSliders(value); - }; + this.red.setValue(value.x); + this.green.setValue(value.y); + this.blue.setValue(value.z); + this.updateRGBSliders(value); + }; ColorBox.prototype.getValue = function() { - var value = {x:this.red.getValue(), y:this.green.getValue(),z:this.blue.getValue()}; - return value; + var value = { + x: this.red.getValue(), + y: this.green.getValue(), + z: this.blue.getValue() }; + return value; + }; ColorBox.prototype.reset = function(resetValue) { - this.setValue(resetValue); - this.onValueChanged(resetValue); - }; + this.setValue(resetValue); + this.onValueChanged(resetValue); + }; + - ColorBox.prototype.getHeight = function() { - if(!this.visible) { + if (!this.visible) { return 0; } - return 1.5 * this.thumbSize; - }; + return 1.5 * this.thumbSize; + }; ColorBox.prototype.moveUp = function(newY) { this.red.moveUp(newY); @@ -490,121 +576,132 @@ var CHECK_MARK_COLOR = { this.blue.show(); this.visible = true; } - + ColorBox.prototype.destroy = function() { - this.red.destroy(); - this.green.destroy(); - this.blue.destroy(); - }; + this.red.destroy(); + this.green.destroy(); + this.blue.destroy(); + }; this.ColorBox = ColorBox; - + // The DirectionBox class - var DirectionBox = function(x,y,width,thumbSize) { + var DirectionBox = function(x, y, width, thumbSize) { var self = this; - + var slideHeight = thumbSize / 2; var sliderWidth = width; this.yaw = new Slider(x, y, width, slideHeight); this.pitch = new Slider(x, y + slideHeight, width, slideHeight); - - - this.yaw.setThumbColor({x: 1, y: 0, z: 0}); + + + this.yaw.setThumbColor({ + x: 1, + y: 0, + z: 0 + }); this.yaw.minValue = -180; this.yaw.maxValue = +180; - - this.pitch.setThumbColor({x: 0, y: 0, z: 1}); + + this.pitch.setThumbColor({ + x: 0, + y: 0, + z: 1 + }); this.pitch.minValue = -1; this.pitch.maxValue = +1; - + this.yaw.onValueChanged = this.setterFromWidget; this.pitch.onValueChanged = this.setterFromWidget; this.visible = true; }; - - DirectionBox.prototype.isClickableOverlayItem = function(item) { - return this.yaw.isClickableOverlayItem(item) - || this.pitch.isClickableOverlayItem(item); - }; - - DirectionBox.prototype.onMousePressEvent = function(event, clickedOverlay) { - this.yaw.onMousePressEvent(event, clickedOverlay); - if (this.yaw.isMoving) { - return; - } - this.pitch.onMousePressEvent(event, clickedOverlay); - }; - DirectionBox.prototype.onMouseMoveEvent = function(event) { - this.yaw.onMouseMoveEvent(event); - this.pitch.onMouseMoveEvent(event); - }; - + DirectionBox.prototype.isClickableOverlayItem = function(item) { + return this.yaw.isClickableOverlayItem(item) || this.pitch.isClickableOverlayItem(item); + }; + + DirectionBox.prototype.onMousePressEvent = function(event, clickedOverlay) { + this.yaw.onMousePressEvent(event, clickedOverlay); + if (this.yaw.isMoving) { + return; + } + this.pitch.onMousePressEvent(event, clickedOverlay); + }; + + DirectionBox.prototype.onMouseMoveEvent = function(event) { + this.yaw.onMouseMoveEvent(event); + this.pitch.onMouseMoveEvent(event); + }; + DirectionBox.prototype.onMouseReleaseEvent = function(event) { - this.yaw.onMouseReleaseEvent(event); - this.pitch.onMouseReleaseEvent(event); - }; + this.yaw.onMouseReleaseEvent(event); + this.pitch.onMouseReleaseEvent(event); + }; DirectionBox.prototype.updateWithKeys = function(direction) { this.yaw.updateWithKeys(direction); this.pitch.updateWithKeys(direction); - }; + }; DirectionBox.prototype.highlight = function() { this.pitch.highlight(); this.yaw.highlight(); - + this.highlighted = true; - }; + }; DirectionBox.prototype.unhighlight = function() { this.pitch.unhighlight(); this.yaw.unhighlight(); - + this.highlighted = false; - }; - + }; + DirectionBox.prototype.setterFromWidget = function(value) { - var yawPitch = this.getValue(); - this.onValueChanged(yawPitch); - }; + var yawPitch = this.getValue(); + this.onValueChanged(yawPitch); + }; DirectionBox.prototype.onValueChanged = function(value) {}; DirectionBox.prototype.setValue = function(direction) { - var flatXZ = Math.sqrt(direction.x * direction.x + direction.z * direction.z); - if (flatXZ > 0.0) { - var flatX = direction.x / flatXZ; - var flatZ = direction.z / flatXZ; - var yaw = Math.acos(flatX) * 180 / Math.PI; - if (flatZ < 0) { - yaw = -yaw; - } - this.yaw.setValue(yaw); + var flatXZ = Math.sqrt(direction.x * direction.x + direction.z * direction.z); + if (flatXZ > 0.0) { + var flatX = direction.x / flatXZ; + var flatZ = direction.z / flatXZ; + var yaw = Math.acos(flatX) * 180 / Math.PI; + if (flatZ < 0) { + yaw = -yaw; } - this.pitch.setValue(direction.y); - }; + this.yaw.setValue(yaw); + } + this.pitch.setValue(direction.y); + }; - DirectionBox.prototype.getValue = function() { - var dirZ = this.pitch.getValue(); - var yaw = this.yaw.getValue() * Math.PI / 180; - var cosY = Math.sqrt(1 - dirZ*dirZ); - var value = {x:cosY * Math.cos(yaw), y:dirZ, z: cosY * Math.sin(yaw)}; - return value; + DirectionBox.prototype.getValue = function() { + var dirZ = this.pitch.getValue(); + var yaw = this.yaw.getValue() * Math.PI / 180; + var cosY = Math.sqrt(1 - dirZ * dirZ); + var value = { + x: cosY * Math.cos(yaw), + y: dirZ, + z: cosY * Math.sin(yaw) }; - + return value; + }; + DirectionBox.prototype.reset = function(resetValue) { - this.setValue(resetValue); - this.onValueChanged(resetValue); - }; - + this.setValue(resetValue); + this.onValueChanged(resetValue); + }; + DirectionBox.prototype.getHeight = function() { - if(!this.visible) { + if (!this.visible) { return 0; } - return 1.5 * this.thumbSize; - }; + return 1.5 * this.thumbSize; + }; DirectionBox.prototype.moveUp = function(newY) { this.pitch.moveUp(newY); @@ -627,59 +724,73 @@ var CHECK_MARK_COLOR = { this.yaw.show(); this.visible = true; } - + DirectionBox.prototype.destroy = function() { - this.yaw.destroy(); - this.pitch.destroy(); - }; - + this.yaw.destroy(); + this.pitch.destroy(); + }; + this.DirectionBox = DirectionBox; - + var textFontSize = 12; - - var CollapsablePanelItem = function (name, x, y, textWidth, height) { + + var CollapsablePanelItem = function(name, x, y, textWidth, height) { this.name = name; this.height = height; this.y = y; this.isCollapsable = true; - + var topMargin = (height - 1.5 * textFontSize); - + this.thumb = Overlays.addOverlay("image", { - color: {red: 255, green: 255, blue: 255}, - imageURL: HIFI_PUBLIC_BUCKET + 'images/tools/min-max-toggle.svg', - x: x, - y: y, - width: rawHeight, - height: rawHeight, - alpha: 1.0, - visible: true - }); - + color: { + red: 255, + green: 255, + blue: 255 + }, + imageURL: HIFI_PUBLIC_BUCKET + 'images/tools/min-max-toggle.svg', + x: x, + y: y, + width: rawHeight, + height: rawHeight, + alpha: 1.0, + visible: true + }); + this.title = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: x + rawHeight * 1.5, - y: y, - width: textWidth, - height: height, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true, - text: " " + name, - font: {size: textFontSize}, - topMargin: topMargin - }); + backgroundColor: { + red: 255, + green: 255, + blue: 255 + }, + x: x + rawHeight * 1.5, + y: y, + width: textWidth, + height: height, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true, + text: " " + name, + font: { + size: textFontSize + }, + topMargin: topMargin + }); }; CollapsablePanelItem.prototype.destroy = function() { Overlays.deleteOverlay(this.title); Overlays.deleteOverlay(this.thumb); }; - - + + CollapsablePanelItem.prototype.hide = function() { - Overlays.editOverlay(this.title, {visible: false}); - Overlays.editOverlay(this.thumb, {visible: false}); + Overlays.editOverlay(this.title, { + visible: false + }); + Overlays.editOverlay(this.thumb, { + visible: false + }); if (this.widget != null) { this.widget.hide(); @@ -687,8 +798,12 @@ var CHECK_MARK_COLOR = { }; CollapsablePanelItem.prototype.show = function() { - Overlays.editOverlay(this.title, {visible: true}); - Overlays.editOverlay(this.thumb, {visible: true}); + Overlays.editOverlay(this.title, { + visible: true + }); + Overlays.editOverlay(this.thumb, { + visible: true + }); if (this.widget != null) { this.widget.show(); @@ -696,8 +811,12 @@ var CHECK_MARK_COLOR = { }; CollapsablePanelItem.prototype.moveUp = function(newY) { - Overlays.editOverlay(this.title, {y: newY}); - Overlays.editOverlay(this.thumb, {y: newY}); + Overlays.editOverlay(this.title, { + y: newY + }); + Overlays.editOverlay(this.thumb, { + y: newY + }); if (this.widget != null) { this.widget.moveUp(newY); @@ -705,74 +824,92 @@ var CHECK_MARK_COLOR = { } CollapsablePanelItem.prototype.moveDown = function() { - Overlays.editOverlay(this.title, {y: this.y}); - Overlays.editOverlay(this.thumb, {y: this.y}); + Overlays.editOverlay(this.title, { + y: this.y + }); + Overlays.editOverlay(this.thumb, { + y: this.y + }); if (this.widget != null) { this.widget.moveDown(); } } this.CollapsablePanelItem = CollapsablePanelItem; - - var PanelItem = function (name, setter, getter, displayer, x, y, textWidth, valueWidth, height) { + + var PanelItem = function(name, setter, getter, displayer, x, y, textWidth, valueWidth, height) { //print("creating panel item: " + name); this.isCollapsable = false; this.name = name; this.y = y; this.isCollapsed = false; - - this.displayer = typeof displayer !== 'undefined' ? displayer : function(value) { - if(value == true) { + + this.displayer = typeof displayer !== 'undefined' ? displayer : function(value) { + if (value == true) { return "On"; } else if (value == false) { return "Off"; } - return value.toFixed(2); + return value.toFixed(2); }; - + var topMargin = (height - 1.5 * textFontSize); this.title = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: x, - y: y, - width: textWidth, - height: height, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true, - text: " " + name, - font: {size: textFontSize}, - topMargin: topMargin - }); - + backgroundColor: { + red: 255, + green: 255, + blue: 255 + }, + x: x, + y: y, + width: textWidth, + height: height, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true, + text: " " + name, + font: { + size: textFontSize + }, + topMargin: topMargin + }); + this.value = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, - x: x + textWidth, - y: y, - width: valueWidth, - height: height, - alpha: 1.0, - backgroundAlpha: 0.5, - visible: true, - text: this.displayer(getter()), - font: {size: textFontSize}, - topMargin: topMargin - }); - + backgroundColor: { + red: 255, + green: 255, + blue: 255 + }, + x: x + textWidth, + y: y, + width: valueWidth, + height: height, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true, + text: this.displayer(getter()), + font: { + size: textFontSize + }, + topMargin: topMargin + }); + this.getter = getter; this.resetValue = getter(); - + this.setter = function(value) { - + setter(value); - Overlays.editOverlay(this.value, {text: this.displayer(getter())}); + Overlays.editOverlay(this.value, { + text: this.displayer(getter()) + }); if (this.widget) { this.widget.setValue(value); - } - + } + //print("successfully set value of widget to " + value); }; this.setterFromWidget = function(value) { @@ -782,16 +919,22 @@ var CHECK_MARK_COLOR = { if (this.widget) { this.widget.setValue(value); - } - Overlays.editOverlay(this.value, {text: this.displayer(value)}); - }; - + } + Overlays.editOverlay(this.value, { + text: this.displayer(value) + }); + }; + this.widget = null; }; PanelItem.prototype.hide = function() { - Overlays.editOverlay(this.title, {visible: false}); - Overlays.editOverlay(this.value, {visible: false}); + Overlays.editOverlay(this.title, { + visible: false + }); + Overlays.editOverlay(this.value, { + visible: false + }); if (this.widget != null) { this.widget.hide(); @@ -800,8 +943,12 @@ var CHECK_MARK_COLOR = { PanelItem.prototype.show = function() { - Overlays.editOverlay(this.title, {visible: true}); - Overlays.editOverlay(this.value, {visible: true}); + Overlays.editOverlay(this.title, { + visible: true + }); + Overlays.editOverlay(this.value, { + visible: true + }); if (this.widget != null) { this.widget.show(); @@ -811,8 +958,12 @@ var CHECK_MARK_COLOR = { PanelItem.prototype.moveUp = function(newY) { - Overlays.editOverlay(this.title, {y: newY}); - Overlays.editOverlay(this.value, {y: newY}); + Overlays.editOverlay(this.title, { + y: newY + }); + Overlays.editOverlay(this.value, { + y: newY + }); if (this.widget != null) { this.widget.moveUp(newY); @@ -822,8 +973,12 @@ var CHECK_MARK_COLOR = { PanelItem.prototype.moveDown = function() { - Overlays.editOverlay(this.title, {y: this.y}); - Overlays.editOverlay(this.value, {y: this.y}); + Overlays.editOverlay(this.title, { + y: this.y + }); + Overlays.editOverlay(this.value, { + y: this.y + }); if (this.widget != null) { this.widget.moveDown(); @@ -832,15 +987,15 @@ var CHECK_MARK_COLOR = { }; PanelItem.prototype.destroy = function() { - Overlays.deleteOverlay(this.title); - Overlays.deleteOverlay(this.value); + Overlays.deleteOverlay(this.title); + Overlays.deleteOverlay(this.value); - if (this.widget != null) { - this.widget.destroy(); - } - }; + if (this.widget != null) { + this.widget.destroy(); + } + }; this.PanelItem = PanelItem; - + var textWidth = 180; var valueWidth = 100; var widgetWidth = 300; @@ -848,7 +1003,7 @@ var CHECK_MARK_COLOR = { var rawYDelta = rawHeight * 1.5; var outerPanel = true; var widgets; - + var Panel = function(x, y) { @@ -856,50 +1011,53 @@ var CHECK_MARK_COLOR = { widgets = []; } outerPanel = false; - + this.x = x; this.y = y; - this.nextY = y; + this.nextY = y; print("creating panel at x: " + this.x + " y: " + this.y); - - this.widgetX = x + textWidth + valueWidth; - + + this.widgetX = x + textWidth + valueWidth; + this.items = new Array(); this.activeWidget = null; this.visible = true; this.indentation = 30; }; - + Panel.prototype.mouseMoveEvent = function(event) { if (this.activeWidget) { this.activeWidget.onMouseMoveEvent(event); } }; - + Panel.prototype.mousePressEvent = function(event) { // Make sure we quitted previous widget if (this.activeWidget) { this.activeWidget.onMouseReleaseEvent(event); } - this.activeWidget = null; - - var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + this.activeWidget = null; + + var clickedOverlay = Overlays.getOverlayAtPoint({ + x: event.x, + y: event.y + }); this.handleCollapse(clickedOverlay); - + // If the user clicked any of the slider background then... for (var i in this.items) { var item = this.items[i]; var widget = this.items[i].widget; - + if (widget.isClickableOverlayItem(clickedOverlay)) { this.activeWidget = widget; - this.activeWidget.onMousePressEvent(event, clickedOverlay); + this.activeWidget.onMousePressEvent(event, clickedOverlay); break; - } - } + } + } }; Panel.prototype.mouseReleaseEvent = function(event) { @@ -907,39 +1065,42 @@ var CHECK_MARK_COLOR = { this.activeWidget.onMouseReleaseEvent(event); } this.activeWidget = null; - }; - - // Reset panel item upon double-clicking + }; + + // Reset panel item upon double-clicking Panel.prototype.mouseDoublePressEvent = function(event) { - var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + var clickedOverlay = Overlays.getOverlayAtPoint({ + x: event.x, + y: event.y + }); this.handleReset(clickedOverlay); }; - - Panel.prototype.handleReset = function (clickedOverlay) { + + Panel.prototype.handleReset = function(clickedOverlay) { for (var i in this.items) { - - var item = this.items[i]; + + var item = this.items[i]; var widget = item.widget; - + if (item.isSubPanel && widget) { widget.handleReset(clickedOverlay); } - + if (clickedOverlay == item.title) { item.activeWidget = widget; item.activeWidget.reset(item.resetValue); break; - } + } } }; - Panel.prototype.handleCollapse = function (clickedOverlay) { + Panel.prototype.handleCollapse = function(clickedOverlay) { for (var i in this.items) { - - var item = this.items[i]; + + var item = this.items[i]; var widget = item.widget; - + if (item.isSubPanel && widget) { widget.handleCollapse(clickedOverlay); } @@ -948,20 +1109,20 @@ var CHECK_MARK_COLOR = { this.collapse(clickedOverlay); item.isCollapsed = true; break; - } else if (item.isCollapsed && item.isCollapsable && clickedOverlay == item.thumb) { + } else if (item.isCollapsed && item.isCollapsable && clickedOverlay == item.thumb) { this.expand(clickedOverlay); item.isCollapsed = false; } } }; - Panel.prototype.collapse = function (clickedOverlay) { + Panel.prototype.collapse = function(clickedOverlay) { var keys = Object.keys(this.items); - + for (var i = 0; i < keys.length; ++i) { var item = this.items[keys[i]]; - if(item.isCollapsable && clickedOverlay == item.thumb) { + if (item.isCollapsable && clickedOverlay == item.thumb) { var panel = item.widget; panel.hide(); break; @@ -969,40 +1130,40 @@ var CHECK_MARK_COLOR = { } // Now recalculate new heights of subsequent widgets - for(var j = i + 1; j < keys.length; ++j) { + for (var j = i + 1; j < keys.length; ++j) { this.items[keys[j]].moveUp(this.getCurrentY(keys[j])); } }; - Panel.prototype.expand = function (clickedOverlay) { + Panel.prototype.expand = function(clickedOverlay) { var keys = Object.keys(this.items); - + for (var i = 0; i < keys.length; ++i) { var item = this.items[keys[i]]; - if(item.isCollapsable && clickedOverlay == item.thumb) { + if (item.isCollapsable && clickedOverlay == item.thumb) { var panel = item.widget; panel.show(); break; } - } - // Now recalculate new heights of subsequent widgets - for(var j = i + 1; j < keys.length; ++j) { + } + // Now recalculate new heights of subsequent widgets + for (var j = i + 1; j < keys.length; ++j) { this.items[keys[j]].moveDown(); } }; - + Panel.prototype.onMousePressEvent = function(event, clickedOverlay) { for (var i in this.items) { var item = this.items[i]; - if(item.widget.isClickableOverlayItem(clickedOverlay)) { + if (item.widget.isClickableOverlayItem(clickedOverlay)) { item.activeWidget = item.widget; - item.activeWidget.onMousePressEvent(event,clickedOverlay); + item.activeWidget.onMousePressEvent(event, clickedOverlay); } } }; - + Panel.prototype.onMouseMoveEvent = function(event) { for (var i in this.items) { var item = this.items[i]; @@ -1011,7 +1172,7 @@ var CHECK_MARK_COLOR = { } } }; - + Panel.prototype.onMouseReleaseEvent = function(event, clickedOverlay) { for (var i in this.items) { var item = this.items[i]; @@ -1021,7 +1182,7 @@ var CHECK_MARK_COLOR = { item.activeWidget = null; } }; - + Panel.prototype.onMouseDoublePressEvent = function(event, clickedOverlay) { for (var i in this.items) { var item = this.items[i]; @@ -1035,13 +1196,13 @@ var CHECK_MARK_COLOR = { var tabIndex = 0; Panel.prototype.keyPressEvent = function(event) { - if(event.text == "TAB" && !event.isShifted) { + if (event.text == "TAB" && !event.isShifted) { tabView = true; - if(tabIndex < widgets.length) { - if(tabIndex > 0 && widgets[tabIndex - 1].highlighted) { + if (tabIndex < widgets.length) { + if (tabIndex > 0 && widgets[tabIndex - 1].highlighted) { // Unhighlight previous widget widgets[tabIndex - 1].unhighlight(); - } + } widgets[tabIndex].highlight(); tabIndex++; } else { @@ -1052,32 +1213,32 @@ var CHECK_MARK_COLOR = { tabIndex++; } } else if (tabView && event.isShifted) { - if(tabIndex > 0) { + if (tabIndex > 0) { tabIndex--; - if(tabIndex < widgets.length && widgets[tabIndex + 1].highlighted) { + if (tabIndex < widgets.length && widgets[tabIndex + 1].highlighted) { // Unhighlight previous widget widgets[tabIndex + 1].unhighlight(); - } + } widgets[tabIndex].highlight(); } else { widgets[tabIndex].unhighlight(); //Wrap around to end tabIndex = widgets.length - 1; - widgets[tabIndex].highlight(); + widgets[tabIndex].highlight(); } } else if (event.text == "LEFT") { - for(var i = 0; i < widgets.length; i++) { + for (var i = 0; i < widgets.length; i++) { // Find the highlighted widget, allow control with arrow keys - if(widgets[i].highlighted) { + if (widgets[i].highlighted) { var k = -1; widgets[i].updateWithKeys(k); break; } } } else if (event.text == "RIGHT") { - for(var i = 0; i < widgets.length; i++) { + for (var i = 0; i < widgets.length; i++) { // Find the highlighted widget, allow control with arrow keys - if(widgets[i].highlighted) { + if (widgets[i].highlighted) { var k = 1; widgets[i].updateWithKeys(k); break; @@ -1095,93 +1256,105 @@ var CHECK_MARK_COLOR = { slider.minValue = minValue; slider.maxValue = maxValue; widgets.push(slider); - + item.widget = slider; - item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; - item.setter(getValue()); + item.widget.onValueChanged = function(value) { + item.setterFromWidget(value); + }; + item.setter(getValue()); this.items[name] = item; }; - + Panel.prototype.newCheckbox = function(name, setValue, getValue, displayValue) { var display; if (displayValue == true) { - display = function() {return "On";}; + display = function() { + return "On"; + }; } else if (displayValue == false) { - display = function() {return "Off";}; + display = function() { + return "Off"; + }; } - + this.nextY = this.y + this.getHeight(); - + var item = new PanelItem(name, setValue, getValue, display, this.x, this.nextY, textWidth, valueWidth, rawHeight); - + var checkbox = new Checkbox(this.widgetX, this.nextY, widgetWidth, rawHeight); widgets.push(checkbox); - + item.widget = checkbox; - item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; - item.setter(getValue()); - this.items[name] = item; - - //print("created Item... checkbox=" + name); - }; - - Panel.prototype.newColorBox = function(name, setValue, getValue, displayValue) { - this.nextY = this.y + this.getHeight(); - - var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); - - var colorBox = new ColorBox(this.widgetX, this.nextY, widgetWidth, rawHeight); - widgets.push(colorBox); - - item.widget = colorBox; - item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; - item.setter(getValue()); + item.widget.onValueChanged = function(value) { + item.setterFromWidget(value); + }; + item.setter(getValue()); this.items[name] = item; - // print("created Item... colorBox=" + name); + //print("created Item... checkbox=" + name); }; - + + Panel.prototype.newColorBox = function(name, setValue, getValue, displayValue) { + this.nextY = this.y + this.getHeight(); + + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); + + var colorBox = new ColorBox(this.widgetX, this.nextY, widgetWidth, rawHeight); + widgets.push(colorBox); + + item.widget = colorBox; + item.widget.onValueChanged = function(value) { + item.setterFromWidget(value); + }; + item.setter(getValue()); + this.items[name] = item; + + // print("created Item... colorBox=" + name); + }; + Panel.prototype.newDirectionBox = function(name, setValue, getValue, displayValue) { this.nextY = this.y + this.getHeight(); - + var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight); var directionBox = new DirectionBox(this.widgetX, this.nextY, widgetWidth, rawHeight); widgets.push(directionBox); - + item.widget = directionBox; - item.widget.onValueChanged = function(value) { item.setterFromWidget(value); }; - item.setter(getValue()); + item.widget.onValueChanged = function(value) { + item.setterFromWidget(value); + }; + item.setter(getValue()); this.items[name] = item; - - // print("created Item... directionBox=" + name); + + // print("created Item... directionBox=" + name); }; - + Panel.prototype.newSubPanel = function(name) { - + this.nextY = this.y + this.getHeight(); - + var item = new CollapsablePanelItem(name, this.x, this.nextY, textWidth, rawHeight, panel); item.isSubPanel = true; - + this.nextY += 1.5 * item.height; - + var subPanel = new Panel(this.x + this.indentation, this.nextY); - + item.widget = subPanel; this.items[name] = item; return subPanel; - // print("created Item... subPanel=" + name); + // print("created Item... subPanel=" + name); }; - + Panel.prototype.onValueChanged = function(value) { for (var i in this.items) { this.items[i].widget.onValueChanged(value); } }; - - + + Panel.prototype.set = function(name, value) { var item = this.items[name]; if (item != null) { @@ -1189,7 +1362,7 @@ var CHECK_MARK_COLOR = { } return null; }; - + Panel.prototype.get = function(name) { var item = this.items[name]; if (item != null) { @@ -1197,7 +1370,7 @@ var CHECK_MARK_COLOR = { } return null; }; - + Panel.prototype.update = function(name) { var item = this.items[name]; if (item != null) { @@ -1205,7 +1378,7 @@ var CHECK_MARK_COLOR = { } return null; }; - + Panel.prototype.isClickableOverlayItem = function(item) { for (var i in this.items) { if (this.items[i].widget.isClickableOverlayItem(item)) { @@ -1214,30 +1387,30 @@ var CHECK_MARK_COLOR = { } return false; }; - + Panel.prototype.getHeight = function() { var height = 0; - + for (var i in this.items) { - height += this.items[i].widget.getHeight(); - if(this.items[i].isSubPanel && this.items[i].widget.visible) { - height += 1.5 * rawHeight; - } + height += this.items[i].widget.getHeight(); + if (this.items[i].isSubPanel && this.items[i].widget.visible) { + height += 1.5 * rawHeight; + } } return height; }; Panel.prototype.moveUp = function() { - for (var i in this.items) { + for (var i in this.items) { this.items[i].widget.moveUp(); - } + } }; Panel.prototype.moveDown = function() { for (var i in this.items) { this.items[i].widget.moveDown(); - } + } }; Panel.prototype.getCurrentY = function(key) { @@ -1247,34 +1420,34 @@ var CHECK_MARK_COLOR = { for (var i = 0; i < keys.indexOf(key); ++i) { var item = this.items[keys[i]]; - height += item.widget.getHeight(); - - if(item.isSubPanel) { + height += item.widget.getHeight(); + + if (item.isSubPanel) { height += 1.5 * rawHeight; - - } + + } } return this.y + height; }; - + Panel.prototype.hide = function() { for (var i in this.items) { - if(this.items[i].isSubPanel) { + if (this.items[i].isSubPanel) { this.items[i].widget.hide(); } this.items[i].hide(); - } + } this.visible = false; }; Panel.prototype.show = function() { for (var i in this.items) { - if(this.items[i].isSubPanel) { + if (this.items[i].isSubPanel) { this.items[i].widget.show(); } this.items[i].show(); - } + } this.visible = true; }; @@ -1282,21 +1455,29 @@ var CHECK_MARK_COLOR = { Panel.prototype.destroy = function() { for (var i in this.items) { - if(this.items[i].isSubPanel) { + if (this.items[i].isSubPanel) { this.items[i].widget.destroy(); } this.items[i].destroy(); - } + } }; this.Panel = Panel; })(); Script.scriptEnding.connect(function scriptEnding() { - Controller.releaseKeyEvents({text: "left"}); - Controller.releaseKeyEvents({key: "right"}); + Controller.releaseKeyEvents({ + text: "left" + }); + Controller.releaseKeyEvents({ + key: "right" + }); }); -Controller.captureKeyEvents({text: "left"}); -Controller.captureKeyEvents({text: "right"}); \ No newline at end of file +Controller.captureKeyEvents({ + text: "left" +}); +Controller.captureKeyEvents({ + text: "right" +}); \ No newline at end of file From ccb3d433afb69e6ce391c7d302092143515a96f1 Mon Sep 17 00:00:00 2001 From: bwent Date: Fri, 24 Jul 2015 09:43:49 -0700 Subject: [PATCH 53/58] Example script solarsystem.js with orbiting satellite game --- examples/example/games/satellite.js | 279 +++++++++++++ examples/example/games/solarsystem.js | 554 ++++++++++++++++++++++++++ examples/utilities/tools/vector.js | 197 +++++++++ 3 files changed, 1030 insertions(+) create mode 100644 examples/example/games/satellite.js create mode 100644 examples/example/games/solarsystem.js create mode 100644 examples/utilities/tools/vector.js diff --git a/examples/example/games/satellite.js b/examples/example/games/satellite.js new file mode 100644 index 0000000000..d2e4dd2a99 --- /dev/null +++ b/examples/example/games/satellite.js @@ -0,0 +1,279 @@ +// +// satellite.js +// games +// +// Created by Bridget Went 7/1/2015. +// Copyright 2015 High Fidelity, Inc. +// +// A game to bring a satellite model into orbit around an animated earth model . +// - Double click to create a new satellite +// - Click on the satellite, drag a vector arrow to specify initial velocity +// - Release mouse to launch the active satellite +// - Orbital movement is calculated using equations of gravitational physics +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +Script.include('../../utilities/tools/vector.js'); + +var URL = "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/"; + +SatelliteGame = function() { + var MAX_RANGE = 50.0; + var Y_AXIS = { + x: 0, + y: 1, + z: 0 + } + var LIFETIME = 6000; + + var v0; + var T = 4.0; + var M = 16000.0; + var m = M * 0.000000333; + var ERROR_THRESH = 20.0; + + // Create the spinning earth model + var EARTH_SIZE = 20.0; + var CLOUDS_OFFSET = 0.5; + var SPIN = 0.1; + var ZONE_DIM = 10.0; + var LIGHT_INTENSITY = 1.2; + + Earth = function(position, size) { + this.earth = Entities.addEntity({ + type: "Model", + shapeType: 'sphere', + modelURL: URL + "earth.fbx", + position: position, + dimensions: { + x: size, + y: size, + z: size + }, + rotation: Quat.angleAxis(180, {x: 1, y: 0, z: 0}), + angularVelocity: { x: 0.00, y: 0.5 * SPIN, z: 0.00 }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: 6000, + collisionsWillMove: false, + visible: true + }); + + this.clouds = Entities.addEntity({ + type: "Model", + shapeType: 'sphere', + modelURL: URL + "clouds.fbx?", + position: position, + dimensions: { + x: size + CLOUDS_OFFSET, + y: size + CLOUDS_OFFSET, + z: size + CLOUDS_OFFSET + }, + angularVelocity: { x: 0.00, y: SPIN, z: 0.00 }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: false, + visible: true + }); + + this.zone = Entities.addEntity({ + type: "Zone", + position: position, + dimensions: { + x: ZONE_DIM, + y: ZONE_DIM, + z: ZONE_DIM + }, + keyLightDirection: Vec3.normalize(Vec3.subtract(position, Camera.getPosition())), + keyLightIntensity: LIGHT_INTENSITY + }); + + this.cleanup = function() { + Entities.deleteEntity(this.clouds); + Entities.deleteEntity(this.earth); + Entities.deleteEntity(this.zone); + } + } + + // Create earth model + var center = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE, Quat.getFront(Camera.getOrientation()))); + var distance = Vec3.length(Vec3.subtract(center, Camera.getPosition())); + var earth = new Earth(center, EARTH_SIZE); + + var satellites = []; + var SATELLITE_SIZE = 2.0; + var launched = false; + var activeSatellite; + + Satellite = function(position, planetCenter) { + // The Satellite class + + this.launched = false; + this.startPosition = position; + this.readyToLaunch = false; + this.radius = Vec3.length(Vec3.subtract(position, planetCenter)); + + this.satellite = Entities.addEntity({ + type: "Model", + modelURL: "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/satellite/satellite.fbx", + position: this.startPosition, + dimensions: { + x: SATELLITE_SIZE, + y: SATELLITE_SIZE, + z: SATELLITE_SIZE + }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: false, + }); + + this.getProperties = function() { + return Entities.getEntityProperties(this.satellite); + } + + this.launch = function() { + var prop = Entities.getEntityProperties(this.satellite); + var between = Vec3.subtract(planetCenter, prop.position); + var radius = Vec3.length(between); + this.G = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (M * T * T); + + var v0 = Vec3.normalize(Vec3.cross(between, Y_AXIS)); + v0 = Vec3.multiply(Math.sqrt((this.G * M) / radius), v0); + v0 = Vec3.multiply(this.arrow.magnitude, v0); + v0 = Vec3.multiply(Vec3.length(v0), this.arrow.direction); + + Entities.editEntity(this.satellite, { velocity: v0 }); + this.launched = true; + }; + + + this.update = function(deltaTime) { + var prop = Entities.getEntityProperties(this.satellite); + var between = Vec3.subtract(prop.position, planetCenter); + var radius = Vec3.length(between); + var a = -(this.G * M) * Math.pow(radius, (-2.0)); + var speed = a * deltaTime; + var vel = Vec3.multiply(speed, Vec3.normalize(between)); + + var newVelocity = Vec3.sum(prop.velocity, vel); + var newPos = Vec3.sum(prop.position, Vec3.multiply(newVelocity, deltaTime)); + + Entities.editEntity(this.satellite, { + velocity: newVelocity, + position: newPos + }); + }; + } + + function mouseDoublePressEvent(event) { + var pickRay = Camera.computePickRay(event.x, event.y); + var addVector = Vec3.multiply(pickRay.direction, distance); + var point = Vec3.sum(Camera.getPosition(), addVector); + + // Create a new satellite + activeSatellite = new Satellite(point, center); + satellites.push(activeSatellite); + } + + function mousePressEvent(event) { + if (!activeSatellite) { + return; + } + // Reset label + if (activeSatellite.arrow) { + activeSatellite.arrow.deleteLabel(); + } + var statsPosition = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE * 0.5, Quat.getFront(Camera.getOrientation()))); + var pickRay = Camera.computePickRay(event.x, event.y) + var rayPickResult = Entities.findRayIntersection(pickRay, true); + if (rayPickResult.entityID === activeSatellite.satellite) { + // Create a draggable vector arrow at satellite position + activeSatellite.arrow = new VectorArrow(distance, true, "INITIAL VELOCITY", statsPosition); + activeSatellite.arrow.onMousePressEvent(event); + activeSatellite.arrow.isDragging = true; + } + } + + function mouseMoveEvent(event) { + if(!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { + return; + } + activeSatellite.arrow.onMouseMoveEvent(event); + } + + function mouseReleaseEvent(event) { + if(!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { + return; + } + activeSatellite.arrow.onMouseReleaseEvent(event); + activeSatellite.launch(); + activeSatellite.arrow.cleanup(); + } + + var counter = 0.0; + var TIME = 500; + + function update(deltaTime) { + if(!activeSatellite) { + return; + } + // Update all satellites + for (var i = 0; i < satellites.length; i++) { + if (!satellites[i].launched) { + return; + } + satellites[i].update(deltaTime); + } + + counter++; + if (counter % TIME == 0) { + var prop = activeSatellite.getProperties(); + var error = calcEnergyError(prop.position, Vec3.length(prop.velocity)); + if (Math.abs(error) <= ERROR_THRESH) { + activeSatellite.arrow.editLabel("Nice job! The satellite has reached a stable orbit."); + } else { + activeSatellite.arrow.editLabel("Try again! The satellite is in an unstable orbit."); + } + } + } + + this.endGame = function() { + print("ending game"); + for(var i = 0; i < satellites.length; i++) { + Entities.deleteEntitiy(satellites[i].satellite); + satellites[i].arrow.cleanup(); + } + earth.cleanup(); + } + + + function calcEnergyError(pos, vel) { + //Calculate total energy error for active satellite's orbital motion + var radius = activeSatellite.radius; + var G = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (M * T * T); + var v0 = Math.sqrt((G * M) / radius); + + var totalEnergy = 0.5 * M * Math.pow(v0, 2.0) - ((G * M * m) / radius); + var measuredEnergy = 0.5 * M * Math.pow(vel, 2.0) - ((G * M * m) / Vec3.length(Vec3.subtract(pos, center))); + var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100; + return error; + } + + Controller.mousePressEvent.connect(mousePressEvent); + Controller.mouseDoublePressEvent.connect(mouseDoublePressEvent); + Controller.mouseMoveEvent.connect(mouseMoveEvent); + Controller.mouseReleaseEvent.connect(mouseReleaseEvent); + Script.update.connect(update); + Script.scriptEnding.connect(this.endGame); + +} + + + diff --git a/examples/example/games/solarsystem.js b/examples/example/games/solarsystem.js new file mode 100644 index 0000000000..b651e551f0 --- /dev/null +++ b/examples/example/games/solarsystem.js @@ -0,0 +1,554 @@ +// +// solarsystem.js +// games +// +// Created by Bridget Went, 5/28/15. +// Copyright 2015 High Fidelity, Inc. +// +// The start to a project to build a virtual physics classroom to simulate the solar system, gravity, and orbital physics. +// A sun with oribiting planets is created in front of the user. UI elements allow for adjusting the period, gravity, trails, and energy recalculations. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +Script.include('../../utilities/tools/cookies.js'); +Script.include('satellite.js'); + +var BASE_URL = "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/planets/"; + +var NUM_PLANETS = 8; + +var trailsEnabled = true; +var energyConserved = true; +var planetView = false; +var earthView = false; +var satelliteGame; + +var PANEL_X = 850; +var PANEL_Y = 600; +var BUTTON_SIZE = 20; +var PADDING = 20; + +var DAMPING = 0.0; +var LIFETIME = 6000; +var ERROR_THRESH = 2.0; +var TIME_STEP = 70.0; + +var MAX_POINTS_PER_LINE = 5; +var LINE_DIM = 10; +var LINE_WIDTH = 3.0; +var line; +var planetLines = []; +var trails = []; + +var BOUNDS = 200; + + +// Alert user to move if they are too close to domain bounds +if (MyAvatar.position.x < BOUNDS || MyAvatar.position.x > TREE_SCALE - BOUNDS + || MyAvatar.position.y < BOUNDS || MyAvatar.position.y > TREE_SCALE - BOUNDS + || MyAvatar.position.z < BOUNDS || MyAvatar.position.z > TREE_SCALE - BOUNDS) { + Window.alert("Please move at least 200m away from domain bounds."); + return; +} + +// Save intiial avatar and camera position +var startingPosition = MyAvatar.position; +var startFrame = Window.location.href; + +// Place the sun +var MAX_RANGE = 80.0; +var SUN_SIZE = 8.0; +var center = Vec3.sum(startingPosition, Vec3.multiply(MAX_RANGE, Quat.getFront(Camera.getOrientation()))); + +var theSun = Entities.addEntity({ + type: "Model", + modelURL: BASE_URL + "sun.fbx", + position: center, + dimensions: { + x: SUN_SIZE, + y: SUN_SIZE, + z: SUN_SIZE + }, + angularDamping: DAMPING, + damping: DAMPING, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: false +}); + +var planets = []; +var planet_properties = []; + +// Reference values +var radius = 7.0; +var T_ref = 1.0; +var size = 1.0; +var M = 250.0; +var m = M * 0.000000333; +var G = (Math.pow(radius, 3.0) / Math.pow((T_ref / (2.0 * Math.PI)), 2.0)) / M; +var G_ref = G; + +// Adjust size and distance as number of planets increases +var DELTA_RADIUS = 1.8; +var DELTA_SIZE = 0.2; + +function initPlanets() { + for (var i = 0; i < NUM_PLANETS; ++i) { + var v0 = Math.sqrt((G * M) / radius); + var T = (2.0 * Math.PI) * Math.sqrt(Math.pow(radius, 3.0) / (G * M)); + + if (i == 0) { + var color = {red: 255, green: 255, blue: 255}; + } else if (i == 1) { + var color = {red: 255, green: 160, blue: 110}; + } else if (i == 2) { + var color = {red: 10, green: 150, blue: 160}; + } else if (i == 3) { + var color = {red: 180, green: 70, blue: 10}; + } else if (i == 4) { + var color = {red: 250, green: 140, blue: 0}; + } else if (i == 5) { + var color = {red: 235, green: 215, blue: 0}; + } else if (i == 6) { + var color = {red:135, green: 205, blue: 240}; + } else if (i == 7) { + var color = {red:30, green: 140, blue: 255}; + } + + var prop = { + radius: radius, + position: Vec3.sum(center, {x: radius, y: 0.0, z: 0.0}), + lineColor: color, + period: T, + dimensions: size, + velocity: Vec3.multiply(v0, Vec3.normalize({x: 0, y: -0.2, z: 0.9})) + }; + planet_properties.push(prop); + + planets.push(Entities.addEntity({ + type: "Model", + modelURL: BASE_URL + (i + 1) + ".fbx", + position: prop.position, + dimensions: { + x: prop.dimensions, + y: prop.dimensions, + z: prop.dimensions + }, + velocity: prop.velocity, + angularDamping: DAMPING, + damping: DAMPING, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: true, + })); + + radius *= DELTA_RADIUS; + size += DELTA_SIZE; + } +} + +// Initialize planets +initPlanets(); + + +var labels = []; +var labelLines = []; +var labelsShowing = false; +var LABEL_X = 8.0; +var LABEL_Y = 3.0; +var LABEL_Z = 1.0; +var LABEL_DIST = 8.0; +var TEXT_HEIGHT = 1.0; +var sunLabel; + +function showLabels() { + labelsShowing = true; + for (var i = 0; i < NUM_PLANETS; i++) { + var properties = planet_properties[i]; + var text; + if (i == 0) { + text = "Mercury"; + } else if (i == 1) { + text = "Venus"; + } else if (i == 2) { + text = "Earth"; + } else if (i == 3) { + text = "Mars"; + } else if (i == 4) { + text = "Jupiter"; + } else if (i == 5) { + text = "Saturn"; + } else if (i == 6) { + text = "Uranus"; + } else if (i == 7) { + text = "Neptune"; + } + + text = text + " Speed: " + Vec3.length(properties.velocity).toFixed(2); + + var labelPos = Vec3.sum(planet_properties[i].position, {x: 0.0, y: LABEL_DIST, z: LABEL_DIST}); + var linePos = planet_properties[i].position; + labelLines.push(Entities.addEntity( { + type: "Line", + position: linePos, + dimensions: {x: 20, y: 20, z: 20}, + lineWidth: 3.0, + color: {red: 255, green: 255, blue: 255}, + linePoints: [{x: 0, y: 0, z: 0}, computeLocalPoint(linePos, labelPos)] + })); + + labels.push(Entities.addEntity( { + type: "Text", + text: text, + lineHeight: TEXT_HEIGHT, + dimensions: {x: LABEL_X, y: LABEL_Y, z: LABEL_Z}, + position: labelPos, + backgroundColor: {red: 10, green: 10, blue: 10}, + textColor: {red: 255, green: 255, blue: 255}, + faceCamera: true + })); + } +} + +function hideLabels() { + labelsShowing = false; + Entities.deleteEntity(sunLabel); + + for (var i = 0; i < NUM_PLANETS; ++i) { + Entities.deleteEntity(labelLines[i]); + Entities.deleteEntity(labels[i]); + } + labels = []; + labelLines = []; +} + +var time = 0.0; +var elapsed; +var counter = 0; +var dt = 1.0 / TIME_STEP; + +function update(deltaTime) { + if (paused) { + return; + } + deltaTime = dt; + time++; + + for (var i = 0; i < NUM_PLANETS; ++i) { + var properties = planet_properties[i]; + var between = Vec3.subtract(properties.position, center); + var speed = getAcceleration(properties.radius) * deltaTime; + var vel = Vec3.multiply(speed, Vec3.normalize(between)); + + // Update velocity and position + properties.velocity = Vec3.sum(properties.velocity, vel); + properties.position = Vec3.sum(properties.position, Vec3.multiply(properties.velocity, deltaTime)); + Entities.editEntity(planets[i], { + velocity: properties.velocity, + position: properties.position + }); + + + // Create new or update current trail + if (trailsEnabled) { + var lineStack = planetLines[i]; + var point = properties.position; + var prop = Entities.getEntityProperties(lineStack[lineStack.length - 1]); + var linePos = prop.position; + + trails[i].push(computeLocalPoint(linePos, point)); + + Entities.editEntity(lineStack[lineStack.length - 1], { + linePoints: trails[i] + }); + if (trails[i].length === MAX_POINTS_PER_LINE) { + trails[i] = newLine(lineStack, point, properties.period, properties.lineColor); + } + } + + // Measure total energy every 10 updates, recalibrate velocity if necessary + if (energyConserved) { + if (counter % 10 === 0) { + var error = calcEnergyError(planets[i], properties.radius, properties.v0, properties.velocity, properties.position); + if (Math.abs(error) >= ERROR_THRESH) { + var speed = adjustVelocity(planets[i], properties.position); + properties.velocity = Vec3.multiply(speed, Vec3.normalize(properties.velocity)); + } + } + } + } + + counter++; + if (time % TIME_STEP == 0) { + elapsed++; + } +} + +function computeLocalPoint(linePos, worldPoint) { + var localPoint = Vec3.subtract(worldPoint, linePos); + return localPoint; +} + +function getAcceleration(radius) { + var acc = -(G * M) * Math.pow(radius, (-2.0)); + return acc; +} + +// Create a new trail +function resetTrails(planetIndex) { + elapsed = 0.0; + var properties = planet_properties[planetIndex]; + + var trail = []; + var lineStack = []; + + //add the first line to both the line entity stack and the trail + trails.push(newLine(lineStack, properties.position, properties.period, properties.lineColor)); + planetLines.push(lineStack); +} + +// Create a new line +function newLine(lineStack, point, period, color) { + if (elapsed < period) { + var line = Entities.addEntity({ + position: point, + type: "Line", + color: color, + dimensions: { + x: LINE_DIM, + y: LINE_DIM, + z: LINE_DIM + }, + lifetime: LIFETIME, + lineWidth: LINE_WIDTH + }); + lineStack.push(line); + } else { + // Begin overwriting first lines after one full revolution (one period) + var firstLine = lineStack.shift(); + Entities.editEntity(firstLine, { + position: point, + linePoints: [{x: 0.0, y: 0.0, z: 0.0}] + }); + lineStack.push(firstLine); + + } + var points = []; + points.push(computeLocalPoint(point, point)); + return points; +} + +// Measure energy error, recalculate velocity to return to initial net energy +var totalEnergy; +var measuredEnergy; +var measuredPE; + +function calcEnergyError(planet, radius, v0, v, pos) { + totalEnergy = 0.5 * M * Math.pow(v0, 2.0) - ((G * M * m) / radius); + measuredEnergy = 0.5 * M * Math.pow(v, 2.0) - ((G * M * m) / Vec3.length(Vec3.subtract(center, pos))); + var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100; + return error; +} +function adjustVelocity(planet, pos) { + var measuredPE = -(G * M * m) / Vec3.length(Vec3.subtract(center, pos)); + return Math.sqrt(2 * (totalEnergy - measuredPE) / M); +} + + +// Allow user to toggle pausing the model, switch to planet view +var pauseButton = Overlays.addOverlay("text", { + backgroundColor: { red: 200, green: 200, blue: 255 }, + text: "Pause", + x: PANEL_X, + y: PANEL_Y - 30, + width: 70, + height: 20, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true +}); + +var paused = false; + +function mousePressEvent(event) { + var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); + if(clickedOverlay == pauseButton) { + paused = !paused; + for (var i = 0; i < NUM_PLANETS; ++i) { + Entities.editEntity(planets[i], { velocity: {x: 0.0, y: 0.0, z: 0.0} }); + } + if (paused && !labelsShowing) { + Overlays.editOverlay(pauseButton, { text: "Paused", backgroundColor: {red: 255, green: 50, blue: 50} } ); + showLabels(); + } + if (paused == false && labelsShowing) { + Overlays.editOverlay(pauseButton, { text: "Pause", backgroundColor: {red: 200, green: 200, blue: 255}}); + hideLabels(); + } + planetView = false; + } +} + +function keyPressEvent(event) { + // Jump back to solar system view + if (event.text == "TAB" && planetView) { + if (earthView) { + satelliteGame.endGame(); + earthView = false; + } + MyAvatar.position = startingPosition; + } +} + +function mouseDoublePressEvent(event) { + if(earthView) { + return; + } + var pickRay = Camera.computePickRay(event.x, event.y) + var rayPickResult = Entities.findRayIntersection(pickRay, true); + + for (var i = 0; i < NUM_PLANETS; ++i) { + if (rayPickResult.entityID === labels[i]) { + planetView = true; + if (i == 2) { + MyAvatar.position = Vec3.sum(center, {x: 200, y: 200, z: 200}); + Camera.setPosition(Vec3.sum(center, {x: 200, y: 200, z: 200})); + earthView = true; + satelliteGame = new SatelliteGame(); + + } else { + MyAvatar.position = Vec3.sum({x: 0.0, y: 0.0, z: 3.0}, planet_properties[i].position); + Camera.lookAt(planet_properties[i].position); + } + break; + } + } +} + + + + +// Create UI panel +var panel = new Panel(PANEL_X, PANEL_Y); +var panelItems = []; + +var g_multiplier = 1.0; +panelItems.push(panel.newSlider("Adjust Gravitational Force: ", 0.1, 5.0, + function (value) { + g_multiplier = value; + G = G_ref * g_multiplier; + }, + + function () { + return g_multiplier; + }, + function (value) { + return value.toFixed(1) + "x"; + })); + +var period_multiplier = 1.0; +var last_alpha = period_multiplier; +panelItems.push(panel.newSlider("Adjust Orbital Period: ", 0.1, 3.0, + function (value) { + period_multiplier = value; + changePeriod(period_multiplier); + }, + function () { + return period_multiplier; + }, + function (value) { + return (value).toFixed(2) + "x"; + })); + +panelItems.push(panel.newCheckbox("Leave Trails: ", + function (value) { + trailsEnabled = value; + if (trailsEnabled) { + for (var i = 0; i < NUM_PLANETS; ++i) { + resetTrails(i); + } + //if trails are off and we've already created trails, remove existing trails + } else if (planetLines.length != 0) { + for (var i = 0; i < NUM_PLANETS; ++i) { + for (var j = 0; j < planetLines[i].length; ++j) { + Entities.deleteEntity(planetLines[i][j]); + } + planetLines[i] = []; + } + } + }, + function () { + return trailsEnabled; + }, + function (value) { + return value; + })); + +panelItems.push(panel.newCheckbox("Energy Error Calculations: ", + function (value) { + energyConserved = value; + }, + function () { + return energyConserved; + }, + function (value) { + return value; + })); + +// Update global G constant, period, poke velocity to new value +function changePeriod(alpha) { + var ratio = last_alpha / alpha; + G = Math.pow(ratio, 2.0) * G; + for (var i = 0; i < NUM_PLANETS; ++i) { + var properties = planet_properties[i]; + properties.period = ratio * properties.period; + properties.velocity = Vec3.multiply(ratio, properties.velocity); + + } + last_alpha = alpha; +} + + +// Clean up models, UI panels, lines, and button overlays +function scriptEnding() { + + satelliteGame.endGame(); + + Entities.deleteEntity(theSun); + for (var i = 0; i < NUM_PLANETS; ++i) { + Entities.deleteEntity(planets[i]); + } + Menu.removeMenu("Developer > Scene"); + panel.destroy(); + Overlays.deleteOverlay(pauseButton); + + var e = Entities.findEntities(MyAvatar.position, 16000); + for (i = 0; i < e.length; i++) { + var props = Entities.getEntityProperties(e[i]); + if (props.type === "Line" || props.type === "Text") { + Entities.deleteEntity(e[i]); + } + } +}; + + +Controller.mouseMoveEvent.connect(function panelMouseMoveEvent(event) { + return panel.mouseMoveEvent(event); +}); +Controller.mousePressEvent.connect(function panelMousePressEvent(event) { + return panel.mousePressEvent(event); +}); +Controller.mouseDoublePressEvent.connect(function panelMouseDoublePressEvent(event) { + return panel.mouseDoublePressEvent(event); +}); +Controller.mouseReleaseEvent.connect(function (event) { + return panel.mouseReleaseEvent(event); +}); +Controller.mousePressEvent.connect(mousePressEvent); +Controller.mouseDoublePressEvent.connect(mouseDoublePressEvent); +Controller.keyPressEvent.connect(keyPressEvent); + +Script.scriptEnding.connect(scriptEnding); +Script.update.connect(update); \ No newline at end of file diff --git a/examples/utilities/tools/vector.js b/examples/utilities/tools/vector.js new file mode 100644 index 0000000000..ab2e8cf200 --- /dev/null +++ b/examples/utilities/tools/vector.js @@ -0,0 +1,197 @@ +// +// vector.js +// examples +// +// Created by Bridget Went on 7/1/15. +// Copyright 2015 High Fidelity, Inc. +// +// A template for creating vector arrows using line entities. A VectorArrow object creates a +// draggable vector arrow where the user clicked at a specified distance from the viewer. +// The relative magnitude and direction of the vector may be displayed. +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +// + +var LINE_DIMENSIONS = 100; +var LIFETIME = 6000; +var RAD_TO_DEG = 180.0 / Math.PI; + +var LINE_WIDTH = 4; +var ARROW_WIDTH = 6; +var line, linePosition; +var arrow1, arrow2; + +var SCALE = 0.15; +var ANGLE = 150.0; + + +VectorArrow = function(distance, showStats, statsTitle, statsPosition) { + this.magnitude = 0; + this.direction = {x: 0, y: 0, z: 0}; + + this.showStats = showStats; + this.isDragging = false; + + this.newLine = function(position) { + linePosition = position; + var points = []; + + line = Entities.addEntity({ + position: linePosition, + type: "Line", + color: {red: 255, green: 255, blue: 255}, + dimensions: { + x: LINE_DIMENSIONS, + y: LINE_DIMENSIONS, + z: LINE_DIMENSIONS + }, + lineWidth: LINE_WIDTH, + lifetime: LIFETIME, + linePoints: [] + }); + + arrow1 = Entities.addEntity({ + position: {x: 0, y: 0, z: 0}, + type: "Line", + dimensions: { + x: LINE_DIMENSIONS, + y: LINE_DIMENSIONS, + z: LINE_DIMENSIONS + }, + color: {red: 255, green: 255, blue: 255}, + lineWidth: ARROW_WIDTH, + linePoints: [], + }); + + arrow2 = Entities.addEntity({ + position: {x: 0, y: 0, z: 0}, + type: "Line", + dimensions: { + x: LINE_DIMENSIONS, + y: LINE_DIMENSIONS, + z: LINE_DIMENSIONS + }, + color: {red: 255, green: 255, blue: 255}, + lineWidth: ARROW_WIDTH, + linePoints: [], + }); + + } + + + this.onMousePressEvent = function(event) { + + this.newLine(computeWorldPoint(event)); + + if (this.showStats) { + this.label = Entities.addEntity({ + type: "Text", + position: statsPosition, + dimensions: { + x: 4.0, + y: 1.5, + z: 0.1 + }, + lineHeight: 0.3, + faceCamera: true + }); + } + + this.isDragging = true; + + } + + + this.onMouseMoveEvent = function(event) { + + if (!this.isDragging) { + return; + } + + var worldPoint = computeWorldPoint(event); + var localPoint = computeLocalPoint(event, linePosition); + points = [{x: 0, y: 0, z: 0}, localPoint]; + Entities.editEntity(line, { linePoints: points }); + + var nextOffset = Vec3.multiply(SCALE, localPoint); + var normOffset = Vec3.normalize(localPoint); + var axis = Vec3.cross(normOffset, Quat.getFront(Camera.getOrientation()) ); + axis = Vec3.cross(axis, normOffset); + var rotate1 = Quat.angleAxis(ANGLE, axis); + var rotate2 = Quat.angleAxis(-ANGLE, axis); + + // Rotate arrow head to follow direction of the line + Entities.editEntity(arrow1, { + visible: true, + position: worldPoint, + linePoints: [{x: 0, y: 0, z: 0}, nextOffset], + rotation: rotate1 + }); + Entities.editEntity(arrow2, { + visible: true, + position: worldPoint, + linePoints: [{x: 0, y: 0, z: 0}, nextOffset], + rotation: rotate2 + }); + + this.magnitude = Vec3.length(localPoint) / 10.0; + this.direction = Vec3.normalize(Vec3.subtract(worldPoint, linePosition)); + + if (this.showStats) { + this.editLabel(statsTitle + " Magnitude " + this.magnitude.toFixed(2) + ", Direction: " + + this.direction.x.toFixed(2) + ", " + this.direction.y.toFixed(2) + ", " + this.direction.z.toFixed(2)); + } + } + + this.onMouseReleaseEvent = function() { + this.isDragging = false; + } + + this.cleanup = function() { + Entities.deleteEntity(line); + Entities.deleteEntity(arrow1); + Entities.deleteEntity(arrow2); + } + + this.deleteLabel = function() { + Entities.deleteEntity(this.label); + } + + this.editLabel = function(str) { + if(!this.showStats) { + return; + } + Entities.editEntity(this.label, { + text: str + }); + } + + function computeWorldPoint(event) { + var pickRay = Camera.computePickRay(event.x, event.y); + var addVector = Vec3.multiply(pickRay.direction, distance); + return Vec3.sum(Camera.getPosition(), addVector); + } + + function computeLocalPoint(event, linePosition) { + var localPoint = Vec3.subtract(computeWorldPoint(event), linePosition); + return localPoint; + } + + + +} + + + + + + + + + + + + From e0d6609a99b198f84a7a54445b2f9abb6465f047 Mon Sep 17 00:00:00 2001 From: bwent Date: Fri, 24 Jul 2015 10:18:33 -0700 Subject: [PATCH 54/58] resolve file path issue --- examples/example/games/satellite.js | 13 ++++++------- examples/example/{games => }/solarsystem.js | 12 +++++++++--- 2 files changed, 15 insertions(+), 10 deletions(-) rename examples/example/{games => }/solarsystem.js (96%) diff --git a/examples/example/games/satellite.js b/examples/example/games/satellite.js index d2e4dd2a99..e82285622b 100644 --- a/examples/example/games/satellite.js +++ b/examples/example/games/satellite.js @@ -15,7 +15,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include('../../utilities/tools/vector.js'); +Script.include('../utilities/tools/vector.js'); var URL = "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/"; @@ -38,8 +38,8 @@ SatelliteGame = function() { var EARTH_SIZE = 20.0; var CLOUDS_OFFSET = 0.5; var SPIN = 0.1; - var ZONE_DIM = 10.0; - var LIGHT_INTENSITY = 1.2; + var ZONE_DIM = 100.0; + var LIGHT_INTENSITY = 1.5; Earth = function(position, size) { this.earth = Entities.addEntity({ @@ -65,7 +65,7 @@ SatelliteGame = function() { this.clouds = Entities.addEntity({ type: "Model", shapeType: 'sphere', - modelURL: URL + "clouds.fbx?", + modelURL: URL + "clouds.fbx?i=2", position: position, dimensions: { x: size + CLOUDS_OFFSET, @@ -190,7 +190,7 @@ SatelliteGame = function() { if (activeSatellite.arrow) { activeSatellite.arrow.deleteLabel(); } - var statsPosition = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE * 0.5, Quat.getFront(Camera.getOrientation()))); + var statsPosition = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE * 0.4, Quat.getFront(Camera.getOrientation()))); var pickRay = Camera.computePickRay(event.x, event.y) var rayPickResult = Entities.findRayIntersection(pickRay, true); if (rayPickResult.entityID === activeSatellite.satellite) { @@ -245,9 +245,8 @@ SatelliteGame = function() { } this.endGame = function() { - print("ending game"); for(var i = 0; i < satellites.length; i++) { - Entities.deleteEntitiy(satellites[i].satellite); + Entities.deleteEntity(satellites[i].satellite); satellites[i].arrow.cleanup(); } earth.cleanup(); diff --git a/examples/example/games/solarsystem.js b/examples/example/solarsystem.js similarity index 96% rename from examples/example/games/solarsystem.js rename to examples/example/solarsystem.js index b651e551f0..09ba2eec8d 100644 --- a/examples/example/games/solarsystem.js +++ b/examples/example/solarsystem.js @@ -6,14 +6,20 @@ // Copyright 2015 High Fidelity, Inc. // // The start to a project to build a virtual physics classroom to simulate the solar system, gravity, and orbital physics. -// A sun with oribiting planets is created in front of the user. UI elements allow for adjusting the period, gravity, trails, and energy recalculations. +// - A sun with oribiting planets is created in front of the user +// - UI elements allow for adjusting the period, gravity, trails, and energy recalculations +// - Click "PAUSE" to pause the animation and show planet labels +// - In this mode, double-click a planet label to zoom in on that planet +// -Double-clicking on earth label initiates satellite orbiter game +// -Press "TAB" to toggle back to solar system view +// // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include('../../utilities/tools/cookies.js'); -Script.include('satellite.js'); +Script.include('../utilities/tools/cookies.js'); +Script.include('games/satellite.js'); var BASE_URL = "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/planets/"; From 5272a1d6e74a23b310b765ef51242a9ea81e0cc7 Mon Sep 17 00:00:00 2001 From: bwent Date: Mon, 27 Jul 2015 14:28:43 -0700 Subject: [PATCH 55/58] refactoring variables and constants, fix update loop to continue over unlaunched satellites --- examples/example/games/satellite.js | 212 +++++++++++++------------ examples/example/solarsystem.js | 229 ++++++++++++++++++++-------- examples/utilities/tools/vector.js | 31 ++-- 3 files changed, 290 insertions(+), 182 deletions(-) diff --git a/examples/example/games/satellite.js b/examples/example/games/satellite.js index e82285622b..3ddce96aa5 100644 --- a/examples/example/games/satellite.js +++ b/examples/example/games/satellite.js @@ -27,11 +27,6 @@ SatelliteGame = function() { z: 0 } var LIFETIME = 6000; - - var v0; - var T = 4.0; - var M = 16000.0; - var m = M * 0.000000333; var ERROR_THRESH = 20.0; // Create the spinning earth model @@ -43,42 +38,54 @@ SatelliteGame = function() { Earth = function(position, size) { this.earth = Entities.addEntity({ - type: "Model", - shapeType: 'sphere', - modelURL: URL + "earth.fbx", - position: position, - dimensions: { - x: size, - y: size, - z: size - }, - rotation: Quat.angleAxis(180, {x: 1, y: 0, z: 0}), - angularVelocity: { x: 0.00, y: 0.5 * SPIN, z: 0.00 }, - angularDamping: 0.0, - damping: 0.0, - ignoreCollisions: false, - lifetime: 6000, - collisionsWillMove: false, - visible: true + type: "Model", + shapeType: 'sphere', + modelURL: URL + "earth.fbx", + position: position, + dimensions: { + x: size, + y: size, + z: size + }, + rotation: Quat.angleAxis(180, { + x: 1, + y: 0, + z: 0 + }), + angularVelocity: { + x: 0.00, + y: 0.5 * SPIN, + z: 0.00 + }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: 6000, + collisionsWillMove: false, + visible: true }); this.clouds = Entities.addEntity({ - type: "Model", - shapeType: 'sphere', - modelURL: URL + "clouds.fbx?i=2", - position: position, - dimensions: { - x: size + CLOUDS_OFFSET, - y: size + CLOUDS_OFFSET, - z: size + CLOUDS_OFFSET - }, - angularVelocity: { x: 0.00, y: SPIN, z: 0.00 }, - angularDamping: 0.0, - damping: 0.0, - ignoreCollisions: false, - lifetime: LIFETIME, - collisionsWillMove: false, - visible: true + type: "Model", + shapeType: 'sphere', + modelURL: URL + "clouds.fbx?i=2", + position: position, + dimensions: { + x: size + CLOUDS_OFFSET, + y: size + CLOUDS_OFFSET, + z: size + CLOUDS_OFFSET + }, + angularVelocity: { + x: 0.00, + y: SPIN, + z: 0.00 + }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: false, + visible: true }); this.zone = Entities.addEntity({ @@ -93,11 +100,11 @@ SatelliteGame = function() { keyLightIntensity: LIGHT_INTENSITY }); - this.cleanup = function() { - Entities.deleteEntity(this.clouds); + this.cleanup = function() { + Entities.deleteEntity(this.clouds); Entities.deleteEntity(this.earth); Entities.deleteEntity(this.zone); - } + } } // Create earth model @@ -110,6 +117,10 @@ SatelliteGame = function() { var launched = false; var activeSatellite; + var PERIOD = 4.0; + var LARGE_BODY_MASS = 16000.0; + var SMALL_BODY_MASS = LARGE_BODY_MASS * 0.000000333; + Satellite = function(position, planetCenter) { // The Satellite class @@ -118,20 +129,20 @@ SatelliteGame = function() { this.readyToLaunch = false; this.radius = Vec3.length(Vec3.subtract(position, planetCenter)); - this.satellite = Entities.addEntity({ + this.satellite = Entities.addEntity({ type: "Model", - modelURL: "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/satellite/satellite.fbx", - position: this.startPosition, - dimensions: { - x: SATELLITE_SIZE, - y: SATELLITE_SIZE, - z: SATELLITE_SIZE - }, - angularDamping: 0.0, - damping: 0.0, - ignoreCollisions: false, - lifetime: LIFETIME, - collisionsWillMove: false, + modelURL: "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/satellite/satellite.fbx", + position: this.startPosition, + dimensions: { + x: SATELLITE_SIZE, + y: SATELLITE_SIZE, + z: SATELLITE_SIZE + }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: false, }); this.getProperties = function() { @@ -142,14 +153,16 @@ SatelliteGame = function() { var prop = Entities.getEntityProperties(this.satellite); var between = Vec3.subtract(planetCenter, prop.position); var radius = Vec3.length(between); - this.G = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (M * T * T); + this.gravity = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (LARGE_BODY_MASS * PERIOD * PERIOD); - var v0 = Vec3.normalize(Vec3.cross(between, Y_AXIS)); - v0 = Vec3.multiply(Math.sqrt((this.G * M) / radius), v0); - v0 = Vec3.multiply(this.arrow.magnitude, v0); - v0 = Vec3.multiply(Vec3.length(v0), this.arrow.direction); + var initialVelocity = Vec3.normalize(Vec3.cross(between, Y_AXIS)); + initialVelocity = Vec3.multiply(Math.sqrt((this.gravity * LARGE_BODY_MASS) / radius), initialVelocity); + initialVelocity = Vec3.multiply(this.arrow.magnitude, initialVelocity); + initialVelocity = Vec3.multiply(Vec3.length(initialVelocity), this.arrow.direction); - Entities.editEntity(this.satellite, { velocity: v0 }); + Entities.editEntity(this.satellite, { + velocity: initialVelocity + }); this.launched = true; }; @@ -158,12 +171,12 @@ SatelliteGame = function() { var prop = Entities.getEntityProperties(this.satellite); var between = Vec3.subtract(prop.position, planetCenter); var radius = Vec3.length(between); - var a = -(this.G * M) * Math.pow(radius, (-2.0)); - var speed = a * deltaTime; - var vel = Vec3.multiply(speed, Vec3.normalize(between)); + var acceleration = -(this.gravity * LARGE_BODY_MASS) * Math.pow(radius, (-2.0)); + var speed = acceleration * deltaTime; + var vel = Vec3.multiply(speed, Vec3.normalize(between)); - var newVelocity = Vec3.sum(prop.velocity, vel); - var newPos = Vec3.sum(prop.position, Vec3.multiply(newVelocity, deltaTime)); + var newVelocity = Vec3.sum(prop.velocity, vel); + var newPos = Vec3.sum(prop.position, Vec3.multiply(newVelocity, deltaTime)); Entities.editEntity(this.satellite, { velocity: newVelocity, @@ -173,11 +186,11 @@ SatelliteGame = function() { } function mouseDoublePressEvent(event) { - var pickRay = Camera.computePickRay(event.x, event.y); - var addVector = Vec3.multiply(pickRay.direction, distance); - var point = Vec3.sum(Camera.getPosition(), addVector); + var pickRay = Camera.computePickRay(event.x, event.y); + var addVector = Vec3.multiply(pickRay.direction, distance); + var point = Vec3.sum(Camera.getPosition(), addVector); - // Create a new satellite + // Create a new satellite activeSatellite = new Satellite(point, center); satellites.push(activeSatellite); } @@ -188,11 +201,11 @@ SatelliteGame = function() { } // Reset label if (activeSatellite.arrow) { - activeSatellite.arrow.deleteLabel(); - } + activeSatellite.arrow.deleteLabel(); + } var statsPosition = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE * 0.4, Quat.getFront(Camera.getOrientation()))); var pickRay = Camera.computePickRay(event.x, event.y) - var rayPickResult = Entities.findRayIntersection(pickRay, true); + var rayPickResult = Entities.findRayIntersection(pickRay, true); if (rayPickResult.entityID === activeSatellite.satellite) { // Create a draggable vector arrow at satellite position activeSatellite.arrow = new VectorArrow(distance, true, "INITIAL VELOCITY", statsPosition); @@ -202,50 +215,50 @@ SatelliteGame = function() { } function mouseMoveEvent(event) { - if(!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { + if (!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { return; } activeSatellite.arrow.onMouseMoveEvent(event); } function mouseReleaseEvent(event) { - if(!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { + if (!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { return; } activeSatellite.arrow.onMouseReleaseEvent(event); - activeSatellite.launch(); - activeSatellite.arrow.cleanup(); + activeSatellite.launch(); + activeSatellite.arrow.cleanup(); } var counter = 0.0; - var TIME = 500; + var CHECK_ENERGY_PERIOD = 500; function update(deltaTime) { - if(!activeSatellite) { + if (!activeSatellite) { return; } // Update all satellites for (var i = 0; i < satellites.length; i++) { if (!satellites[i].launched) { - return; + continue; } - satellites[i].update(deltaTime); + satellites[i].update(deltaTime); } - + counter++; - if (counter % TIME == 0) { + if (counter % CHECK_ENERGY_PERIOD == 0) { var prop = activeSatellite.getProperties(); - var error = calcEnergyError(prop.position, Vec3.length(prop.velocity)); - if (Math.abs(error) <= ERROR_THRESH) { - activeSatellite.arrow.editLabel("Nice job! The satellite has reached a stable orbit."); - } else { - activeSatellite.arrow.editLabel("Try again! The satellite is in an unstable orbit."); - } - } + var error = calcEnergyError(prop.position, Vec3.length(prop.velocity)); + if (Math.abs(error) <= ERROR_THRESH) { + activeSatellite.arrow.editLabel("Nice job! The satellite has reached a stable orbit."); + } else { + activeSatellite.arrow.editLabel("Try again! The satellite is in an unstable orbit."); + } + } } this.endGame = function() { - for(var i = 0; i < satellites.length; i++) { + for (var i = 0; i < satellites.length; i++) { Entities.deleteEntity(satellites[i].satellite); satellites[i].arrow.cleanup(); } @@ -256,13 +269,13 @@ SatelliteGame = function() { function calcEnergyError(pos, vel) { //Calculate total energy error for active satellite's orbital motion var radius = activeSatellite.radius; - var G = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (M * T * T); - var v0 = Math.sqrt((G * M) / radius); - - var totalEnergy = 0.5 * M * Math.pow(v0, 2.0) - ((G * M * m) / radius); - var measuredEnergy = 0.5 * M * Math.pow(vel, 2.0) - ((G * M * m) / Vec3.length(Vec3.subtract(pos, center))); - var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100; - return error; + var gravity = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (LARGE_BODY_MASS * PERIOD * PERIOD); + var initialVelocityCalculated = Math.sqrt((gravity * LARGE_BODY_MASS) / radius); + + var totalEnergy = 0.5 * LARGE_BODY_MASS * Math.pow(initialVelocityCalculated, 2.0) - ((gravity * LARGE_BODY_MASS * SMALL_BODY_MASS) / radius); + var measuredEnergy = 0.5 * LARGE_BODY_MASS * Math.pow(vel, 2.0) - ((gravity * LARGE_BODY_MASS * SMALL_BODY_MASS) / Vec3.length(Vec3.subtract(pos, center))); + var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100; + return error; } Controller.mousePressEvent.connect(mousePressEvent); @@ -272,7 +285,4 @@ SatelliteGame = function() { Script.update.connect(update); Script.scriptEnding.connect(this.endGame); -} - - - +} \ No newline at end of file diff --git a/examples/example/solarsystem.js b/examples/example/solarsystem.js index 09ba2eec8d..8d1f0c81e3 100644 --- a/examples/example/solarsystem.js +++ b/examples/example/solarsystem.js @@ -52,9 +52,7 @@ var BOUNDS = 200; // Alert user to move if they are too close to domain bounds -if (MyAvatar.position.x < BOUNDS || MyAvatar.position.x > TREE_SCALE - BOUNDS - || MyAvatar.position.y < BOUNDS || MyAvatar.position.y > TREE_SCALE - BOUNDS - || MyAvatar.position.z < BOUNDS || MyAvatar.position.z > TREE_SCALE - BOUNDS) { +if (MyAvatar.position.x < BOUNDS || MyAvatar.position.x > TREE_SCALE - BOUNDS || MyAvatar.position.y < BOUNDS || MyAvatar.position.y > TREE_SCALE - BOUNDS || MyAvatar.position.z < BOUNDS || MyAvatar.position.z > TREE_SCALE - BOUNDS) { Window.alert("Please move at least 200m away from domain bounds."); return; } @@ -106,30 +104,70 @@ function initPlanets() { var T = (2.0 * Math.PI) * Math.sqrt(Math.pow(radius, 3.0) / (G * M)); if (i == 0) { - var color = {red: 255, green: 255, blue: 255}; + var color = { + red: 255, + green: 255, + blue: 255 + }; } else if (i == 1) { - var color = {red: 255, green: 160, blue: 110}; + var color = { + red: 255, + green: 160, + blue: 110 + }; } else if (i == 2) { - var color = {red: 10, green: 150, blue: 160}; + var color = { + red: 10, + green: 150, + blue: 160 + }; } else if (i == 3) { - var color = {red: 180, green: 70, blue: 10}; + var color = { + red: 180, + green: 70, + blue: 10 + }; } else if (i == 4) { - var color = {red: 250, green: 140, blue: 0}; + var color = { + red: 250, + green: 140, + blue: 0 + }; } else if (i == 5) { - var color = {red: 235, green: 215, blue: 0}; + var color = { + red: 235, + green: 215, + blue: 0 + }; } else if (i == 6) { - var color = {red:135, green: 205, blue: 240}; + var color = { + red: 135, + green: 205, + blue: 240 + }; } else if (i == 7) { - var color = {red:30, green: 140, blue: 255}; + var color = { + red: 30, + green: 140, + blue: 255 + }; } var prop = { radius: radius, - position: Vec3.sum(center, {x: radius, y: 0.0, z: 0.0}), + position: Vec3.sum(center, { + x: radius, + y: 0.0, + z: 0.0 + }), lineColor: color, period: T, dimensions: size, - velocity: Vec3.multiply(v0, Vec3.normalize({x: 0, y: -0.2, z: 0.9})) + velocity: Vec3.multiply(v0, Vec3.normalize({ + x: 0, + y: -0.2, + z: 0.9 + })) }; planet_properties.push(prop); @@ -194,27 +232,55 @@ function showLabels() { text = text + " Speed: " + Vec3.length(properties.velocity).toFixed(2); - var labelPos = Vec3.sum(planet_properties[i].position, {x: 0.0, y: LABEL_DIST, z: LABEL_DIST}); + var labelPos = Vec3.sum(planet_properties[i].position, { + x: 0.0, + y: LABEL_DIST, + z: LABEL_DIST + }); var linePos = planet_properties[i].position; - labelLines.push(Entities.addEntity( { + labelLines.push(Entities.addEntity({ type: "Line", position: linePos, - dimensions: {x: 20, y: 20, z: 20}, + dimensions: { + x: 20, + y: 20, + z: 20 + }, lineWidth: 3.0, - color: {red: 255, green: 255, blue: 255}, - linePoints: [{x: 0, y: 0, z: 0}, computeLocalPoint(linePos, labelPos)] + color: { + red: 255, + green: 255, + blue: 255 + }, + linePoints: [{ + x: 0, + y: 0, + z: 0 + }, computeLocalPoint(linePos, labelPos)] })); - labels.push(Entities.addEntity( { + labels.push(Entities.addEntity({ type: "Text", text: text, lineHeight: TEXT_HEIGHT, - dimensions: {x: LABEL_X, y: LABEL_Y, z: LABEL_Z}, + dimensions: { + x: LABEL_X, + y: LABEL_Y, + z: LABEL_Z + }, position: labelPos, - backgroundColor: {red: 10, green: 10, blue: 10}, - textColor: {red: 255, green: 255, blue: 255}, + backgroundColor: { + red: 10, + green: 10, + blue: 10 + }, + textColor: { + red: 255, + green: 255, + blue: 255 + }, faceCamera: true - })); + })); } } @@ -255,7 +321,7 @@ function update(deltaTime) { velocity: properties.velocity, position: properties.position }); - + // Create new or update current trail if (trailsEnabled) { @@ -285,11 +351,11 @@ function update(deltaTime) { } } } - + counter++; if (time % TIME_STEP == 0) { elapsed++; - } + } } function computeLocalPoint(linePos, worldPoint) { @@ -306,7 +372,7 @@ function getAcceleration(radius) { function resetTrails(planetIndex) { elapsed = 0.0; var properties = planet_properties[planetIndex]; - + var trail = []; var lineStack = []; @@ -333,10 +399,14 @@ function newLine(lineStack, point, period, color) { lineStack.push(line); } else { // Begin overwriting first lines after one full revolution (one period) - var firstLine = lineStack.shift(); + var firstLine = lineStack.shift(); Entities.editEntity(firstLine, { position: point, - linePoints: [{x: 0.0, y: 0.0, z: 0.0}] + linePoints: [{ + x: 0.0, + y: 0.0, + z: 0.0 + }] }); lineStack.push(firstLine); @@ -357,6 +427,7 @@ function calcEnergyError(planet, radius, v0, v, pos) { var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100; return error; } + function adjustVelocity(planet, pos) { var measuredPE = -(G * M * m) / Vec3.length(Vec3.subtract(center, pos)); return Math.sqrt(2 * (totalEnergy - measuredPE) / M); @@ -365,7 +436,11 @@ function adjustVelocity(planet, pos) { // Allow user to toggle pausing the model, switch to planet view var pauseButton = Overlays.addOverlay("text", { - backgroundColor: { red: 200, green: 200, blue: 255 }, + backgroundColor: { + red: 200, + green: 200, + blue: 255 + }, text: "Pause", x: PANEL_X, y: PANEL_Y - 30, @@ -379,22 +454,45 @@ var pauseButton = Overlays.addOverlay("text", { var paused = false; function mousePressEvent(event) { - var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); - if(clickedOverlay == pauseButton) { + var clickedOverlay = Overlays.getOverlayAtPoint({ + x: event.x, + y: event.y + }); + if (clickedOverlay == pauseButton) { paused = !paused; for (var i = 0; i < NUM_PLANETS; ++i) { - Entities.editEntity(planets[i], { velocity: {x: 0.0, y: 0.0, z: 0.0} }); + Entities.editEntity(planets[i], { + velocity: { + x: 0.0, + y: 0.0, + z: 0.0 + } + }); } if (paused && !labelsShowing) { - Overlays.editOverlay(pauseButton, { text: "Paused", backgroundColor: {red: 255, green: 50, blue: 50} } ); + Overlays.editOverlay(pauseButton, { + text: "Paused", + backgroundColor: { + red: 255, + green: 50, + blue: 50 + } + }); showLabels(); } if (paused == false && labelsShowing) { - Overlays.editOverlay(pauseButton, { text: "Pause", backgroundColor: {red: 200, green: 200, blue: 255}}); + Overlays.editOverlay(pauseButton, { + text: "Pause", + backgroundColor: { + red: 200, + green: 200, + blue: 255 + } + }); hideLabels(); } planetView = false; - } + } } function keyPressEvent(event) { @@ -409,7 +507,7 @@ function keyPressEvent(event) { } function mouseDoublePressEvent(event) { - if(earthView) { + if (earthView) { return; } var pickRay = Camera.computePickRay(event.x, event.y) @@ -419,57 +517,68 @@ function mouseDoublePressEvent(event) { if (rayPickResult.entityID === labels[i]) { planetView = true; if (i == 2) { - MyAvatar.position = Vec3.sum(center, {x: 200, y: 200, z: 200}); - Camera.setPosition(Vec3.sum(center, {x: 200, y: 200, z: 200})); + MyAvatar.position = Vec3.sum(center, { + x: 200, + y: 200, + z: 200 + }); + Camera.setPosition(Vec3.sum(center, { + x: 200, + y: 200, + z: 200 + })); earthView = true; satelliteGame = new SatelliteGame(); - + } else { - MyAvatar.position = Vec3.sum({x: 0.0, y: 0.0, z: 3.0}, planet_properties[i].position); + MyAvatar.position = Vec3.sum({ + x: 0.0, + y: 0.0, + z: 3.0 + }, planet_properties[i].position); Camera.lookAt(planet_properties[i].position); } - break; - } - } + break; + } + } } - // Create UI panel var panel = new Panel(PANEL_X, PANEL_Y); var panelItems = []; var g_multiplier = 1.0; panelItems.push(panel.newSlider("Adjust Gravitational Force: ", 0.1, 5.0, - function (value) { + function(value) { g_multiplier = value; G = G_ref * g_multiplier; }, - function () { + function() { return g_multiplier; }, - function (value) { + function(value) { return value.toFixed(1) + "x"; })); var period_multiplier = 1.0; var last_alpha = period_multiplier; panelItems.push(panel.newSlider("Adjust Orbital Period: ", 0.1, 3.0, - function (value) { + function(value) { period_multiplier = value; changePeriod(period_multiplier); }, - function () { + function() { return period_multiplier; }, - function (value) { + function(value) { return (value).toFixed(2) + "x"; })); panelItems.push(panel.newCheckbox("Leave Trails: ", - function (value) { + function(value) { trailsEnabled = value; if (trailsEnabled) { for (var i = 0; i < NUM_PLANETS; ++i) { @@ -485,21 +594,21 @@ panelItems.push(panel.newCheckbox("Leave Trails: ", } } }, - function () { + function() { return trailsEnabled; }, - function (value) { + function(value) { return value; })); panelItems.push(panel.newCheckbox("Energy Error Calculations: ", - function (value) { + function(value) { energyConserved = value; }, - function () { + function() { return energyConserved; }, - function (value) { + function(value) { return value; })); @@ -519,7 +628,7 @@ function changePeriod(alpha) { // Clean up models, UI panels, lines, and button overlays function scriptEnding() { - + satelliteGame.endGame(); Entities.deleteEntity(theSun); @@ -536,7 +645,7 @@ function scriptEnding() { if (props.type === "Line" || props.type === "Text") { Entities.deleteEntity(e[i]); } - } + } }; @@ -549,7 +658,7 @@ Controller.mousePressEvent.connect(function panelMousePressEvent(event) { Controller.mouseDoublePressEvent.connect(function panelMouseDoublePressEvent(event) { return panel.mouseDoublePressEvent(event); }); -Controller.mouseReleaseEvent.connect(function (event) { +Controller.mouseReleaseEvent.connect(function(event) { return panel.mouseReleaseEvent(event); }); Controller.mousePressEvent.connect(mousePressEvent); diff --git a/examples/utilities/tools/vector.js b/examples/utilities/tools/vector.js index ab2e8cf200..0635b6cbc7 100644 --- a/examples/utilities/tools/vector.js +++ b/examples/utilities/tools/vector.js @@ -82,6 +82,13 @@ VectorArrow = function(distance, showStats, statsTitle, statsPosition) { } + var STATS_DIMENSIONS = { + x: 4.0, + y: 1.5, + z: 0.1 + }; + var TEXT_HEIGHT = 0.3; + this.onMousePressEvent = function(event) { this.newLine(computeWorldPoint(event)); @@ -90,12 +97,8 @@ VectorArrow = function(distance, showStats, statsTitle, statsPosition) { this.label = Entities.addEntity({ type: "Text", position: statsPosition, - dimensions: { - x: 4.0, - y: 1.5, - z: 0.1 - }, - lineHeight: 0.3, + dimensions: STATS_DIMENSIONS, + lineHeight: TEXT_HEIGHT, faceCamera: true }); } @@ -137,7 +140,7 @@ VectorArrow = function(distance, showStats, statsTitle, statsPosition) { rotation: rotate2 }); - this.magnitude = Vec3.length(localPoint) / 10.0; + this.magnitude = Vec3.length(localPoint) * 0.1; this.direction = Vec3.normalize(Vec3.subtract(worldPoint, linePosition)); if (this.showStats) { @@ -180,18 +183,4 @@ VectorArrow = function(distance, showStats, statsTitle, statsPosition) { return localPoint; } - - } - - - - - - - - - - - - From 1107742188a8cd878a65c2983f68d458648d0598 Mon Sep 17 00:00:00 2001 From: bwent Date: Tue, 28 Jul 2015 12:39:04 -0700 Subject: [PATCH 56/58] Clean up formatting for satellite.js --- examples/example/games/satellite.js | 468 ++++++++++++++-------------- 1 file changed, 234 insertions(+), 234 deletions(-) diff --git a/examples/example/games/satellite.js b/examples/example/games/satellite.js index 3ddce96aa5..f362c0c1e4 100644 --- a/examples/example/games/satellite.js +++ b/examples/example/games/satellite.js @@ -3,13 +3,13 @@ // games // // Created by Bridget Went 7/1/2015. -// Copyright 2015 High Fidelity, Inc. +// Copyright 2015 High Fidelity, Inc. // // A game to bring a satellite model into orbit around an animated earth model . -// - Double click to create a new satellite -// - Click on the satellite, drag a vector arrow to specify initial velocity -// - Release mouse to launch the active satellite -// - Orbital movement is calculated using equations of gravitational physics +// - Double click to create a new satellite +// - Click on the satellite, drag a vector arrow to specify initial velocity +// - Release mouse to launch the active satellite +// - Orbital movement is calculated using equations of gravitational physics // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -20,269 +20,269 @@ Script.include('../utilities/tools/vector.js'); var URL = "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/"; SatelliteGame = function() { - var MAX_RANGE = 50.0; - var Y_AXIS = { - x: 0, - y: 1, - z: 0 - } - var LIFETIME = 6000; - var ERROR_THRESH = 20.0; + var MAX_RANGE = 50.0; + var Y_AXIS = { + x: 0, + y: 1, + z: 0 + } + var LIFETIME = 6000; + var ERROR_THRESH = 20.0; - // Create the spinning earth model - var EARTH_SIZE = 20.0; - var CLOUDS_OFFSET = 0.5; - var SPIN = 0.1; - var ZONE_DIM = 100.0; - var LIGHT_INTENSITY = 1.5; + // Create the spinning earth model + var EARTH_SIZE = 20.0; + var CLOUDS_OFFSET = 0.5; + var SPIN = 0.1; + var ZONE_DIM = 100.0; + var LIGHT_INTENSITY = 1.5; - Earth = function(position, size) { - this.earth = Entities.addEntity({ - type: "Model", - shapeType: 'sphere', - modelURL: URL + "earth.fbx", - position: position, - dimensions: { - x: size, - y: size, - z: size - }, - rotation: Quat.angleAxis(180, { - x: 1, - y: 0, - z: 0 - }), - angularVelocity: { - x: 0.00, - y: 0.5 * SPIN, - z: 0.00 - }, - angularDamping: 0.0, - damping: 0.0, - ignoreCollisions: false, - lifetime: 6000, - collisionsWillMove: false, - visible: true - }); + Earth = function(position, size) { + this.earth = Entities.addEntity({ + type: "Model", + shapeType: 'sphere', + modelURL: URL + "earth.fbx", + position: position, + dimensions: { + x: size, + y: size, + z: size + }, + rotation: Quat.angleAxis(180, { + x: 1, + y: 0, + z: 0 + }), + angularVelocity: { + x: 0.00, + y: 0.5 * SPIN, + z: 0.00 + }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: 6000, + collisionsWillMove: false, + visible: true + }); - this.clouds = Entities.addEntity({ - type: "Model", - shapeType: 'sphere', - modelURL: URL + "clouds.fbx?i=2", - position: position, - dimensions: { - x: size + CLOUDS_OFFSET, - y: size + CLOUDS_OFFSET, - z: size + CLOUDS_OFFSET - }, - angularVelocity: { - x: 0.00, - y: SPIN, - z: 0.00 - }, - angularDamping: 0.0, - damping: 0.0, - ignoreCollisions: false, - lifetime: LIFETIME, - collisionsWillMove: false, - visible: true - }); + this.clouds = Entities.addEntity({ + type: "Model", + shapeType: 'sphere', + modelURL: URL + "clouds.fbx?i=2", + position: position, + dimensions: { + x: size + CLOUDS_OFFSET, + y: size + CLOUDS_OFFSET, + z: size + CLOUDS_OFFSET + }, + angularVelocity: { + x: 0.00, + y: SPIN, + z: 0.00 + }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: false, + visible: true + }); - this.zone = Entities.addEntity({ - type: "Zone", - position: position, - dimensions: { - x: ZONE_DIM, - y: ZONE_DIM, - z: ZONE_DIM - }, - keyLightDirection: Vec3.normalize(Vec3.subtract(position, Camera.getPosition())), - keyLightIntensity: LIGHT_INTENSITY - }); + this.zone = Entities.addEntity({ + type: "Zone", + position: position, + dimensions: { + x: ZONE_DIM, + y: ZONE_DIM, + z: ZONE_DIM + }, + keyLightDirection: Vec3.normalize(Vec3.subtract(position, Camera.getPosition())), + keyLightIntensity: LIGHT_INTENSITY + }); - this.cleanup = function() { - Entities.deleteEntity(this.clouds); - Entities.deleteEntity(this.earth); - Entities.deleteEntity(this.zone); - } - } + this.cleanup = function() { + Entities.deleteEntity(this.clouds); + Entities.deleteEntity(this.earth); + Entities.deleteEntity(this.zone); + } + } - // Create earth model - var center = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE, Quat.getFront(Camera.getOrientation()))); - var distance = Vec3.length(Vec3.subtract(center, Camera.getPosition())); - var earth = new Earth(center, EARTH_SIZE); + // Create earth model + var center = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE, Quat.getFront(Camera.getOrientation()))); + var distance = Vec3.length(Vec3.subtract(center, Camera.getPosition())); + var earth = new Earth(center, EARTH_SIZE); - var satellites = []; - var SATELLITE_SIZE = 2.0; - var launched = false; - var activeSatellite; + var satellites = []; + var SATELLITE_SIZE = 2.0; + var launched = false; + var activeSatellite; var PERIOD = 4.0; var LARGE_BODY_MASS = 16000.0; var SMALL_BODY_MASS = LARGE_BODY_MASS * 0.000000333; - Satellite = function(position, planetCenter) { - // The Satellite class + Satellite = function(position, planetCenter) { + // The Satellite class - this.launched = false; - this.startPosition = position; - this.readyToLaunch = false; - this.radius = Vec3.length(Vec3.subtract(position, planetCenter)); + this.launched = false; + this.startPosition = position; + this.readyToLaunch = false; + this.radius = Vec3.length(Vec3.subtract(position, planetCenter)); - this.satellite = Entities.addEntity({ - type: "Model", - modelURL: "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/satellite/satellite.fbx", - position: this.startPosition, - dimensions: { - x: SATELLITE_SIZE, - y: SATELLITE_SIZE, - z: SATELLITE_SIZE - }, - angularDamping: 0.0, - damping: 0.0, - ignoreCollisions: false, - lifetime: LIFETIME, - collisionsWillMove: false, - }); + this.satellite = Entities.addEntity({ + type: "Model", + modelURL: "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/satellite/satellite.fbx", + position: this.startPosition, + dimensions: { + x: SATELLITE_SIZE, + y: SATELLITE_SIZE, + z: SATELLITE_SIZE + }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: false, + }); - this.getProperties = function() { - return Entities.getEntityProperties(this.satellite); - } + this.getProperties = function() { + return Entities.getEntityProperties(this.satellite); + } - this.launch = function() { - var prop = Entities.getEntityProperties(this.satellite); - var between = Vec3.subtract(planetCenter, prop.position); - var radius = Vec3.length(between); - this.gravity = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (LARGE_BODY_MASS * PERIOD * PERIOD); + this.launch = function() { + var prop = Entities.getEntityProperties(this.satellite); + var between = Vec3.subtract(planetCenter, prop.position); + var radius = Vec3.length(between); + this.gravity = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (LARGE_BODY_MASS * PERIOD * PERIOD); - var initialVelocity = Vec3.normalize(Vec3.cross(between, Y_AXIS)); - initialVelocity = Vec3.multiply(Math.sqrt((this.gravity * LARGE_BODY_MASS) / radius), initialVelocity); - initialVelocity = Vec3.multiply(this.arrow.magnitude, initialVelocity); - initialVelocity = Vec3.multiply(Vec3.length(initialVelocity), this.arrow.direction); + var initialVelocity = Vec3.normalize(Vec3.cross(between, Y_AXIS)); + initialVelocity = Vec3.multiply(Math.sqrt((this.gravity * LARGE_BODY_MASS) / radius), initialVelocity); + initialVelocity = Vec3.multiply(this.arrow.magnitude, initialVelocity); + initialVelocity = Vec3.multiply(Vec3.length(initialVelocity), this.arrow.direction); - Entities.editEntity(this.satellite, { - velocity: initialVelocity - }); - this.launched = true; - }; + Entities.editEntity(this.satellite, { + velocity: initialVelocity + }); + this.launched = true; + }; - this.update = function(deltaTime) { - var prop = Entities.getEntityProperties(this.satellite); - var between = Vec3.subtract(prop.position, planetCenter); - var radius = Vec3.length(between); - var acceleration = -(this.gravity * LARGE_BODY_MASS) * Math.pow(radius, (-2.0)); - var speed = acceleration * deltaTime; - var vel = Vec3.multiply(speed, Vec3.normalize(between)); + this.update = function(deltaTime) { + var prop = Entities.getEntityProperties(this.satellite); + var between = Vec3.subtract(prop.position, planetCenter); + var radius = Vec3.length(between); + var acceleration = -(this.gravity * LARGE_BODY_MASS) * Math.pow(radius, (-2.0)); + var speed = acceleration * deltaTime; + var vel = Vec3.multiply(speed, Vec3.normalize(between)); - var newVelocity = Vec3.sum(prop.velocity, vel); - var newPos = Vec3.sum(prop.position, Vec3.multiply(newVelocity, deltaTime)); + var newVelocity = Vec3.sum(prop.velocity, vel); + var newPos = Vec3.sum(prop.position, Vec3.multiply(newVelocity, deltaTime)); - Entities.editEntity(this.satellite, { - velocity: newVelocity, - position: newPos - }); - }; - } + Entities.editEntity(this.satellite, { + velocity: newVelocity, + position: newPos + }); + }; + } - function mouseDoublePressEvent(event) { - var pickRay = Camera.computePickRay(event.x, event.y); - var addVector = Vec3.multiply(pickRay.direction, distance); - var point = Vec3.sum(Camera.getPosition(), addVector); + function mouseDoublePressEvent(event) { + var pickRay = Camera.computePickRay(event.x, event.y); + var addVector = Vec3.multiply(pickRay.direction, distance); + var point = Vec3.sum(Camera.getPosition(), addVector); - // Create a new satellite - activeSatellite = new Satellite(point, center); - satellites.push(activeSatellite); - } + // Create a new satellite + activeSatellite = new Satellite(point, center); + satellites.push(activeSatellite); + } - function mousePressEvent(event) { - if (!activeSatellite) { - return; - } - // Reset label - if (activeSatellite.arrow) { - activeSatellite.arrow.deleteLabel(); - } - var statsPosition = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE * 0.4, Quat.getFront(Camera.getOrientation()))); - var pickRay = Camera.computePickRay(event.x, event.y) - var rayPickResult = Entities.findRayIntersection(pickRay, true); - if (rayPickResult.entityID === activeSatellite.satellite) { - // Create a draggable vector arrow at satellite position - activeSatellite.arrow = new VectorArrow(distance, true, "INITIAL VELOCITY", statsPosition); - activeSatellite.arrow.onMousePressEvent(event); - activeSatellite.arrow.isDragging = true; - } - } + function mousePressEvent(event) { + if (!activeSatellite) { + return; + } + // Reset label + if (activeSatellite.arrow) { + activeSatellite.arrow.deleteLabel(); + } + var statsPosition = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE * 0.4, Quat.getFront(Camera.getOrientation()))); + var pickRay = Camera.computePickRay(event.x, event.y) + var rayPickResult = Entities.findRayIntersection(pickRay, true); + if (rayPickResult.entityID === activeSatellite.satellite) { + // Create a draggable vector arrow at satellite position + activeSatellite.arrow = new VectorArrow(distance, true, "INITIAL VELOCITY", statsPosition); + activeSatellite.arrow.onMousePressEvent(event); + activeSatellite.arrow.isDragging = true; + } + } - function mouseMoveEvent(event) { - if (!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { - return; - } - activeSatellite.arrow.onMouseMoveEvent(event); - } + function mouseMoveEvent(event) { + if (!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { + return; + } + activeSatellite.arrow.onMouseMoveEvent(event); + } - function mouseReleaseEvent(event) { - if (!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { - return; - } - activeSatellite.arrow.onMouseReleaseEvent(event); - activeSatellite.launch(); - activeSatellite.arrow.cleanup(); - } + function mouseReleaseEvent(event) { + if (!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { + return; + } + activeSatellite.arrow.onMouseReleaseEvent(event); + activeSatellite.launch(); + activeSatellite.arrow.cleanup(); + } - var counter = 0.0; - var CHECK_ENERGY_PERIOD = 500; + var counter = 0.0; + var CHECK_ENERGY_PERIOD = 500; - function update(deltaTime) { - if (!activeSatellite) { - return; - } - // Update all satellites - for (var i = 0; i < satellites.length; i++) { - if (!satellites[i].launched) { - continue; - } - satellites[i].update(deltaTime); - } + function update(deltaTime) { + if (!activeSatellite) { + return; + } + // Update all satellites + for (var i = 0; i < satellites.length; i++) { + if (!satellites[i].launched) { + continue; + } + satellites[i].update(deltaTime); + } - counter++; - if (counter % CHECK_ENERGY_PERIOD == 0) { - var prop = activeSatellite.getProperties(); - var error = calcEnergyError(prop.position, Vec3.length(prop.velocity)); - if (Math.abs(error) <= ERROR_THRESH) { - activeSatellite.arrow.editLabel("Nice job! The satellite has reached a stable orbit."); - } else { - activeSatellite.arrow.editLabel("Try again! The satellite is in an unstable orbit."); - } - } - } + counter++; + if (counter % CHECK_ENERGY_PERIOD == 0) { + var prop = activeSatellite.getProperties(); + var error = calcEnergyError(prop.position, Vec3.length(prop.velocity)); + if (Math.abs(error) <= ERROR_THRESH) { + activeSatellite.arrow.editLabel("Nice job! The satellite has reached a stable orbit."); + } else { + activeSatellite.arrow.editLabel("Try again! The satellite is in an unstable orbit."); + } + } + } - this.endGame = function() { - for (var i = 0; i < satellites.length; i++) { - Entities.deleteEntity(satellites[i].satellite); - satellites[i].arrow.cleanup(); - } - earth.cleanup(); - } + this.endGame = function() { + for (var i = 0; i < satellites.length; i++) { + Entities.deleteEntity(satellites[i].satellite); + satellites[i].arrow.cleanup(); + } + earth.cleanup(); + } - function calcEnergyError(pos, vel) { - //Calculate total energy error for active satellite's orbital motion - var radius = activeSatellite.radius; - var gravity = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (LARGE_BODY_MASS * PERIOD * PERIOD); - var initialVelocityCalculated = Math.sqrt((gravity * LARGE_BODY_MASS) / radius); + function calcEnergyError(pos, vel) { + //Calculate total energy error for active satellite's orbital motion + var radius = activeSatellite.radius; + var gravity = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (LARGE_BODY_MASS * PERIOD * PERIOD); + var initialVelocityCalculated = Math.sqrt((gravity * LARGE_BODY_MASS) / radius); - var totalEnergy = 0.5 * LARGE_BODY_MASS * Math.pow(initialVelocityCalculated, 2.0) - ((gravity * LARGE_BODY_MASS * SMALL_BODY_MASS) / radius); - var measuredEnergy = 0.5 * LARGE_BODY_MASS * Math.pow(vel, 2.0) - ((gravity * LARGE_BODY_MASS * SMALL_BODY_MASS) / Vec3.length(Vec3.subtract(pos, center))); - var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100; - return error; - } + var totalEnergy = 0.5 * LARGE_BODY_MASS * Math.pow(initialVelocityCalculated, 2.0) - ((gravity * LARGE_BODY_MASS * SMALL_BODY_MASS) / radius); + var measuredEnergy = 0.5 * LARGE_BODY_MASS * Math.pow(vel, 2.0) - ((gravity * LARGE_BODY_MASS * SMALL_BODY_MASS) / Vec3.length(Vec3.subtract(pos, center))); + var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100; + return error; + } - Controller.mousePressEvent.connect(mousePressEvent); - Controller.mouseDoublePressEvent.connect(mouseDoublePressEvent); - Controller.mouseMoveEvent.connect(mouseMoveEvent); - Controller.mouseReleaseEvent.connect(mouseReleaseEvent); - Script.update.connect(update); - Script.scriptEnding.connect(this.endGame); + Controller.mousePressEvent.connect(mousePressEvent); + Controller.mouseDoublePressEvent.connect(mouseDoublePressEvent); + Controller.mouseMoveEvent.connect(mouseMoveEvent); + Controller.mouseReleaseEvent.connect(mouseReleaseEvent); + Script.update.connect(update); + Script.scriptEnding.connect(this.endGame); } \ No newline at end of file From 044ea2ace56303e1a5101dc282db4c1459f561ce Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 28 Jul 2015 19:31:43 -0700 Subject: [PATCH 57/58] Changed mirror position to not be achored to the head. But instead it's anchored to the "default" eye position, which is where the eyes are in the model, before IK or animations occur. --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3f185af5a1..967880ca8d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3381,7 +3381,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi // This was removed in commit 71e59cfa88c6563749594e25494102fe01db38e9 but could be further // investigated in order to adapt the technique while fixing the head rendering issue, // but the complexity of the hack suggests that a better approach - _mirrorCamera.setPosition(_myAvatar->getHead()->getEyePosition() + + _mirrorCamera.setPosition(_myAvatar->getDefaultEyePosition() + _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_REARVIEW_DISTANCE * _myAvatar->getScale()); } _mirrorCamera.setProjection(glm::perspective(glm::radians(fov), aspect, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP)); From 7805cf4e481c07a78298c7774cb1792d55f06713 Mon Sep 17 00:00:00 2001 From: bwent Date: Wed, 29 Jul 2015 09:19:33 -0700 Subject: [PATCH 58/58] Format fixes, UI logos for collapse/expand toggle --- examples/utilities/tools/cookies.js | 35 ++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js index 24cda69ba2..751008fd99 100644 --- a/examples/utilities/tools/cookies.js +++ b/examples/utilities/tools/cookies.js @@ -12,7 +12,7 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; -var SCALE = 1000; +var SLIDER_RANGE_INCREMENT_SCALE = 1 / 1000; var THUMB_COLOR = { red: 150, green: 150, @@ -59,7 +59,6 @@ var CHECK_MARK_COLOR = { }); this.thumbSize = thumbSize; - this.thumbHalfSize = 0.5 * thumbSize; this.minThumbX = x + this.thumbHalfSize; @@ -128,7 +127,7 @@ var CHECK_MARK_COLOR = { Slider.prototype.updateWithKeys = function(direction) { this.range = this.maxThumbX - this.minThumbX; - this.thumbX += direction * (this.range / SCALE); + this.thumbX += direction * (this.range * SCALE); this.updateThumb(); this.onValueChanged(this.getValue()); }; @@ -211,6 +210,25 @@ var CHECK_MARK_COLOR = { }); }; + this.setThumbColor = function(color) { + Overlays.editOverlay(this.thumb, { + backgroundColor: { + red: color.x * 255, + green: color.y * 255, + blue: color.z * 255 + } + }); + }; + this.setBackgroundColor = function(color) { + Overlays.editOverlay(this.background, { + backgroundColor: { + red: color.x * 255, + green: color.y * 255, + blue: color.z * 255 + } + }); + }; + Slider.prototype.hide = function() { Overlays.editOverlay(this.background, { visible: false @@ -748,7 +766,7 @@ var CHECK_MARK_COLOR = { green: 255, blue: 255 }, - imageURL: HIFI_PUBLIC_BUCKET + 'images/tools/min-max-toggle.svg', + imageURL: HIFI_PUBLIC_BUCKET + 'images/tools/expand-ui.svg', x: x, y: y, width: rawHeight, @@ -778,6 +796,7 @@ var CHECK_MARK_COLOR = { }); }; + CollapsablePanelItem.prototype.destroy = function() { Overlays.deleteOverlay(this.title); Overlays.deleteOverlay(this.thumb); @@ -1044,6 +1063,7 @@ var CHECK_MARK_COLOR = { x: event.x, y: event.y }); + this.handleCollapse(clickedOverlay); // If the user clicked any of the slider background then... @@ -1106,10 +1126,15 @@ var CHECK_MARK_COLOR = { } if (!item.isCollapsed && item.isCollapsable && clickedOverlay == item.thumb) { + Overlays.editOverlay(item.thumb, { + imageURL: HIFI_PUBLIC_BUCKET + 'images/tools/expand-right.svg' + }); this.collapse(clickedOverlay); item.isCollapsed = true; - break; } else if (item.isCollapsed && item.isCollapsable && clickedOverlay == item.thumb) { + Overlays.editOverlay(item.thumb, { + imageURL: HIFI_PUBLIC_BUCKET + 'images/tools/expand-ui.svg' + }); this.expand(clickedOverlay); item.isCollapsed = false; }