From da6986f759860fa619a1d7b9a98ef0d8e60050aa Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 7 Jul 2015 21:06:12 +0200 Subject: [PATCH 01/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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/45] 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 0580c8477e1c3a89879176e21702765fe2e7eae0 Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Fri, 17 Jul 2015 16:42:03 -0700 Subject: [PATCH 13/45] 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 14/45] 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 48524b1c98999326b4b25ee782e16e107a851124 Mon Sep 17 00:00:00 2001 From: "Kevin M. Thomas" Date: Sun, 19 Jul 2015 18:22:58 -0400 Subject: [PATCH 15/45] 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 16/45] 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 17/45] 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 18/45] 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 19/45] 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 20/45] 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 21/45] 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 22/45] 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 23/45] 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 24/45] 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 216c499d1472abecc29968bd9f2ba6b0aa7be7ac Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Thu, 23 Jul 2015 18:53:43 -0700 Subject: [PATCH 25/45] 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 26/45] 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 27/45] 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 28/45] 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 29/45] 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 30/45] 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 31/45] 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 5cc0b45850fa489dc0439a2a1c40c4f5a3089bc8 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 15 Jul 2015 18:27:39 -0700 Subject: [PATCH 32/45] Improved ParticleEffectEntityItem rendering and updates * Created custom pipelines and shaders for untextured and textured particle rendering. * Created custom render payload for particles * Moved all particle updates into simulation rather then render. * Uses pendingChanges.updateItem lambda to update the playload with new data for rendering. * ParticleEffectEntityItem now updates its dimensions properly, based on emitter properties. * Bug fix for dt not accumulating properly, during gaps between updates. now we just update all the time. (super cheap tho, if there are no particles animating) --- examples/particles.js | 7 +- libraries/entities-renderer/CMakeLists.txt | 2 + .../RenderableParticleEffectEntityItem.cpp | 327 ++++++++++++++---- .../src/RenderableParticleEffectEntityItem.h | 25 +- .../src/textured_particle.slf | 20 ++ .../src/textured_particle.slv | 28 ++ .../src/untextured_particle.slf | 16 + .../src/untextured_particle.slv | 24 ++ .../entities/src/ParticleEffectEntityItem.cpp | 80 ++++- .../entities/src/ParticleEffectEntityItem.h | 14 +- 10 files changed, 457 insertions(+), 86 deletions(-) create mode 100644 libraries/entities-renderer/src/textured_particle.slf create mode 100644 libraries/entities-renderer/src/textured_particle.slv create mode 100644 libraries/entities-renderer/src/untextured_particle.slf create mode 100644 libraries/entities-renderer/src/untextured_particle.slv diff --git a/examples/particles.js b/examples/particles.js index c26458a9af..deb6228fff 100644 --- a/examples/particles.js +++ b/examples/particles.js @@ -44,6 +44,7 @@ emitStrength: emitStrength, emitDirection: emitDirection, color: color, + lifespan: 1.0, visible: true, locked: false }); @@ -67,13 +68,13 @@ var objs = []; function Init() { objs.push(new TestBox()); - objs.push(new TestFx({ red: 255, blue: 0, green: 0 }, + objs.push(new TestFx({ red: 255, green: 0, blue: 0 }, { x: 0.5, y: 1.0, z: 0.0 }, 100, 3, 1)); - objs.push(new TestFx({ red: 0, blue: 255, green: 0 }, + objs.push(new TestFx({ red: 0, green: 255, blue: 0 }, { x: 0, y: 1, z: 0 }, 1000, 5, 0.5)); - objs.push(new TestFx({ red: 0, blue: 0, green: 255 }, + objs.push(new TestFx({ red: 0, green: 0, blue: 255 }, { x: -0.5, y: 1, z: 0 }, 100, 3, 1)); } diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt index 810d5f5843..e9adf2b750 100644 --- a/libraries/entities-renderer/CMakeLists.txt +++ b/libraries/entities-renderer/CMakeLists.txt @@ -1,5 +1,7 @@ set(TARGET_NAME entities-renderer) +AUTOSCRIBE_SHADER_LIB(gpu model render) + # use setup_hifi_library macro to setup our project and link appropriate Qt modules setup_hifi_library(Widgets OpenGL Network Script) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 48ac83dfc2..738a150dc5 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -14,22 +14,141 @@ #include #include #include +#include #include "EntitiesRendererLogging.h" #include "RenderableParticleEffectEntityItem.h" +#include "untextured_particle_vert.h" +#include "untextured_particle_frag.h" +#include "textured_particle_vert.h" +#include "textured_particle_frag.h" + +class ParticlePayload { +public: + typedef render::Payload Payload; + typedef Payload::DataPointer Pointer; + typedef RenderableParticleEffectEntityItem::Vertex Vertex; + + ParticlePayload() : _vertexFormat(std::make_shared()), + _vertexBuffer(std::make_shared()), + _indexBuffer(std::make_shared()) { + _vertexFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element::VEC3F_XYZ, 0); + _vertexFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), offsetof(Vertex, uv)); + _vertexFormat->setAttribute(gpu::Stream::COLOR, 0, gpu::Element::COLOR_RGBA_32, offsetof(Vertex, rgba)); + } + + void setPipeline(gpu::PipelinePointer pipeline) { _pipeline = pipeline; } + const gpu::PipelinePointer& getPipeline() const { return _pipeline; } + + const Transform& getModelTransform() const { return _modelTransform; } + void setModelTransform(const Transform& modelTransform) { _modelTransform = modelTransform; } + + const AABox& getBound() const { return _bound; } + void setBound(AABox& bound) { _bound = bound; } + + gpu::BufferPointer getVertexBuffer() { return _vertexBuffer; } + const gpu::BufferPointer& getVertexBuffer() const { return _vertexBuffer; } + + gpu::BufferPointer getIndexBuffer() { return _indexBuffer; } + const gpu::BufferPointer& getIndexBuffer() const { return _indexBuffer; } + + void setTexture(gpu::TexturePointer texture) { _texture = texture; } + const gpu::TexturePointer& getTexture() const { return _texture; } + + bool getVisibleFlag() const { return _visibleFlag; } + void setVisibleFlag(bool visibleFlag) { _visibleFlag = visibleFlag; } + + void render(RenderArgs* args) const { + assert(_pipeline); + + gpu::Batch& batch = *args->_batch; + batch.setPipeline(_pipeline); + + if (_texture) { + batch.setResourceTexture(0, _texture); + } + + batch.setModelTransform(_modelTransform); + batch.setInputFormat(_vertexFormat); + batch.setInputBuffer(0, _vertexBuffer, 0, sizeof(Vertex)); + batch.setIndexBuffer(gpu::UINT16, _indexBuffer, 0); + + auto numIndices = _indexBuffer->getSize() / sizeof(uint16_t); + batch.drawIndexed(gpu::TRIANGLES, numIndices); + } + +protected: + Transform _modelTransform; + AABox _bound; + gpu::PipelinePointer _pipeline; + gpu::Stream::FormatPointer _vertexFormat; + gpu::BufferPointer _vertexBuffer; + gpu::BufferPointer _indexBuffer; + gpu::TexturePointer _texture; + bool _visibleFlag = true; +}; + +namespace render { + template <> + const ItemKey payloadGetKey(const ParticlePayload::Pointer& payload) { + if (payload->getVisibleFlag()) { + return ItemKey::Builder::transparentShape(); + } else { + return ItemKey::Builder().withInvisible().build(); + } + } + + template <> + const Item::Bound payloadGetBound(const ParticlePayload::Pointer& payload) { + return payload->getBound(); + } + + template <> + void payloadRender(const ParticlePayload::Pointer& payload, RenderArgs* args) { + payload->render(args); + } +} + +gpu::PipelinePointer RenderableParticleEffectEntityItem::_texturedPipeline; +gpu::PipelinePointer RenderableParticleEffectEntityItem::_untexturedPipeline; + EntityItemPointer RenderableParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { return std::make_shared(entityID, properties); } RenderableParticleEffectEntityItem::RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : ParticleEffectEntityItem(entityItemID, properties) { - _cacheID = DependencyManager::get()->allocateID(); + + // lazy creation of particle system pipeline + if (!_untexturedPipeline && !_texturedPipeline) { + createPipelines(); + } } -void RenderableParticleEffectEntityItem::render(RenderArgs* args) { - Q_ASSERT(getType() == EntityTypes::ParticleEffect); - PerformanceTimer perfTimer("RenderableParticleEffectEntityItem::render"); +bool RenderableParticleEffectEntityItem::addToScene(EntityItemPointer self, + render::ScenePointer scene, + render::PendingChanges& pendingChanges) { + + auto particlePayload = std::shared_ptr(new ParticlePayload()); + particlePayload->setPipeline(_untexturedPipeline); + _renderItemId = scene->allocateID(); + auto renderData = ParticlePayload::Pointer(particlePayload); + auto renderPayload = render::PayloadPointer(new ParticlePayload::Payload(renderData)); + pendingChanges.resetItem(_renderItemId, renderPayload); + _scene = scene; + return true; +} + +void RenderableParticleEffectEntityItem::removeFromScene(EntityItemPointer self, + render::ScenePointer scene, + render::PendingChanges& pendingChanges) { + pendingChanges.removeItem(_renderItemId); + _scene = nullptr; +}; + +void RenderableParticleEffectEntityItem::update(const quint64& now) { + ParticleEffectEntityItem::update(now); if (_texturesChangedFlag) { if (_textures.isEmpty()) { @@ -42,71 +161,151 @@ void RenderableParticleEffectEntityItem::render(RenderArgs* args) { _texturesChangedFlag = false; } - bool textured = _texture && _texture->isLoaded(); - updateQuads(args, textured); - - Q_ASSERT(args->_batch); - gpu::Batch& batch = *args->_batch; - if (textured) { - batch.setResourceTexture(0, _texture->getGPUTexture()); - } - batch.setModelTransform(getTransformToCenter()); - DependencyManager::get()->bindSimpleProgram(batch, textured); - DependencyManager::get()->renderVertices(batch, gpu::QUADS, _cacheID); -}; + updateRenderItem(); +} static glm::vec3 zSortAxis; static bool zSort(const glm::vec3& rhs, const glm::vec3& lhs) { return glm::dot(rhs, ::zSortAxis) > glm::dot(lhs, ::zSortAxis); } -void RenderableParticleEffectEntityItem::updateQuads(RenderArgs* args, bool textured) { - float particleRadius = getParticleRadius(); - glm::vec4 particleColor(toGlm(getXColor()), getLocalRenderAlpha()); - - glm::vec3 upOffset = args->_viewFrustum->getUp() * particleRadius; - glm::vec3 rightOffset = args->_viewFrustum->getRight() * particleRadius; - - QVector vertices; - QVector positions; - QVector textureCoords; - vertices.reserve(getLivingParticleCount() * VERTS_PER_PARTICLE); - - if (textured) { - textureCoords.reserve(getLivingParticleCount() * VERTS_PER_PARTICLE); - } - positions.reserve(getLivingParticleCount()); - - - for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) { - positions.append(_particlePositions[i]); - if (textured) { - textureCoords.append(glm::vec2(0, 1)); - textureCoords.append(glm::vec2(1, 1)); - textureCoords.append(glm::vec2(1, 0)); - textureCoords.append(glm::vec2(0, 0)); - } - } - - // sort particles back to front - ::zSortAxis = args->_viewFrustum->getDirection(); - qSort(positions.begin(), positions.end(), zSort); - - for (int i = 0; i < positions.size(); i++) { - glm::vec3 pos = (textured) ? positions[i] : _particlePositions[i]; - - // generate corners of quad aligned to face the camera. - vertices.append(pos + rightOffset + upOffset); - vertices.append(pos - rightOffset + upOffset); - vertices.append(pos - rightOffset - upOffset); - vertices.append(pos + rightOffset - upOffset); - - } - - if (textured) { - DependencyManager::get()->updateVertices(_cacheID, vertices, textureCoords, particleColor); - } else { - DependencyManager::get()->updateVertices(_cacheID, vertices, particleColor); - } +uint32_t toRGBA(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { + return ((uint32_t)r | (uint32_t)g << 8 | (uint32_t)b << 16 | (uint32_t)a << 24); } +void RenderableParticleEffectEntityItem::updateRenderItem() { + + if (!_scene) + return; + + float particleRadius = getParticleRadius(); + auto xcolor = getXColor(); + auto alpha = (uint8_t)(glm::clamp(getLocalRenderAlpha(), 0.0f, 1.0f) * 255.0f); + auto rgba = toRGBA(xcolor.red, xcolor.green, xcolor.blue, alpha); + + // make a copy of each particle position + std::vector positions; + positions.reserve(getLivingParticleCount()); + for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) { + positions.push_back(_particlePositions[i]); + } + + // sort particles back to front + // NOTE: this is view frustum might be one frame out of date. + auto frustum = AbstractViewStateInterface::instance()->getCurrentViewFrustum(); + ::zSortAxis = frustum->getDirection(); + qSort(positions.begin(), positions.end(), zSort); + + // allocate vertices + _vertices.clear(); + + // build vertices from particle positions + const glm::vec3 upOffset = frustum->getUp() * particleRadius; + const glm::vec3 rightOffset = frustum->getRight() * particleRadius; + for (auto&& pos : positions) { + // generate corners of quad aligned to face the camera. + _vertices.emplace_back(pos + rightOffset + upOffset, glm::vec2(1.0f, 1.0f), rgba); + _vertices.emplace_back(pos - rightOffset + upOffset, glm::vec2(0.0f, 1.0f), rgba); + _vertices.emplace_back(pos - rightOffset - upOffset, glm::vec2(0.0f, 0.0f), rgba); + _vertices.emplace_back(pos + rightOffset - upOffset, glm::vec2(1.0f, 0.0f), rgba); + } + + render::PendingChanges pendingChanges; + pendingChanges.updateItem(_renderItemId, [&](ParticlePayload& payload) { + + // update vertex buffer + auto vertexBuffer = payload.getVertexBuffer(); + size_t numBytes = sizeof(Vertex) * _vertices.size(); + vertexBuffer->resize(numBytes); + gpu::Byte* data = vertexBuffer->editData(); + memcpy(data, &(_vertices[0]), numBytes); + + // FIXME, don't update index buffer if num particles has not changed. + // update index buffer + auto indexBuffer = payload.getIndexBuffer(); + auto numQuads = (_vertices.size() / 4); + numBytes = sizeof(uint16_t) * numQuads * 6; + indexBuffer->resize(numBytes); + data = indexBuffer->editData(); + auto indexPtr = reinterpret_cast(data); + for (size_t i = 0; i < numQuads; ++i) { + indexPtr[i * 6 + 0] = i * 4 + 0; + indexPtr[i * 6 + 1] = i * 4 + 1; + indexPtr[i * 6 + 2] = i * 4 + 3; + indexPtr[i * 6 + 3] = i * 4 + 1; + indexPtr[i * 6 + 4] = i * 4 + 2; + indexPtr[i * 6 + 5] = i * 4 + 3; + } + + // update transform + glm::quat rot = _transform.getRotation(); + glm::vec3 pos = _transform.getTranslation(); + Transform t; + t.setRotation(rot); + t.setTranslation(pos); + payload.setModelTransform(t); + + // transform _particleMinBound and _particleMaxBound corners into world coords + glm::vec3 d = _particleMaxBound - _particleMinBound; + glm::vec3 corners[8] = { + pos + rot * (_particleMinBound + glm::vec3(0.0f, 0.0f, 0.0f)), + pos + rot * (_particleMinBound + glm::vec3(d.x, 0.0f, 0.0f)), + pos + rot * (_particleMinBound + glm::vec3(0.0f, d.y, 0.0f)), + pos + rot * (_particleMinBound + glm::vec3(d.x, d.y, 0.0f)), + pos + rot * (_particleMinBound + glm::vec3(0.0f, 0.0f, d.z)), + pos + rot * (_particleMinBound + glm::vec3(d.x, 0.0f, d.z)), + pos + rot * (_particleMinBound + glm::vec3(0.0f, d.y, d.z)), + pos + rot * (_particleMinBound + glm::vec3(d.x, d.y, d.z)) + }; + glm::vec3 min(FLT_MAX, FLT_MAX, FLT_MAX); + glm::vec3 max = -min; + for (int i = 0; i < 8; i++) { + min.x = std::min(min.x, corners[i].x); + min.y = std::min(min.y, corners[i].y); + min.z = std::min(min.z, corners[i].z); + max.x = std::max(max.x, corners[i].x); + max.y = std::max(max.y, corners[i].y); + max.z = std::max(max.z, corners[i].z); + } + AABox bound(min, max - min); + payload.setBound(bound); + + bool textured = _texture && _texture->isLoaded(); + if (textured) { + payload.setTexture(_texture->getGPUTexture()); + payload.setPipeline(_texturedPipeline); + } else { + payload.setTexture(nullptr); + payload.setPipeline(_untexturedPipeline); + } + }); + + _scene->enqueuePendingChanges(pendingChanges); +} + +void RenderableParticleEffectEntityItem::createPipelines() { + if (!_untexturedPipeline) { + auto state = std::make_shared(); + state->setCullMode(gpu::State::CULL_BACK); + state->setDepthTest(true, true, gpu::LESS_EQUAL); + state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, + gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, + gpu::State::BLEND_OP_ADD, gpu::State::ONE); + auto vertShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(untextured_particle_vert))); + auto fragShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(untextured_particle_frag))); + auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vertShader, fragShader)); + _untexturedPipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + } + if (!_texturedPipeline) { + auto state = std::make_shared(); + state->setCullMode(gpu::State::CULL_BACK); + state->setDepthTest(true, true, gpu::LESS_EQUAL); + state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, + gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, + gpu::State::BLEND_OP_ADD, gpu::State::ONE); + auto vertShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(textured_particle_vert))); + auto fragShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(textured_particle_frag))); + auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vertShader, fragShader)); + _texturedPipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + } +} diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h index 4ecea45ad0..9581c43ca5 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h @@ -16,20 +16,35 @@ #include "RenderableEntityItem.h" class RenderableParticleEffectEntityItem : public ParticleEffectEntityItem { +friend class ParticlePayload; public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); - virtual void render(RenderArgs* args); - void updateQuads(RenderArgs* args, bool textured); + virtual void update(const quint64& now) override; - SIMPLE_RENDERABLE(); + void updateRenderItem(); + + virtual bool addToScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges); + virtual void removeFromScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges); protected: + render::ItemID _renderItemId; - int _cacheID; - const int VERTS_PER_PARTICLE = 4; + struct Vertex { + Vertex(glm::vec3 xyzIn, glm::vec2 uvIn, uint32_t rgbaIn) : xyz(xyzIn), uv(uvIn), rgba(rgbaIn) {} + glm::vec3 xyz; + glm::vec2 uv; + uint32_t rgba; + }; + static void createPipelines(); + + std::vector _vertices; + static gpu::PipelinePointer _untexturedPipeline; + static gpu::PipelinePointer _texturedPipeline; + + render::ScenePointer _scene; NetworkTexturePointer _texture; }; diff --git a/libraries/entities-renderer/src/textured_particle.slf b/libraries/entities-renderer/src/textured_particle.slf new file mode 100644 index 0000000000..543aa643aa --- /dev/null +++ b/libraries/entities-renderer/src/textured_particle.slf @@ -0,0 +1,20 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// fragment shader +// +// 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 +// + +uniform sampler2D colorMap; + +varying vec4 varColor; +varying vec2 varTexCoord; + +void main(void) { + vec4 color = texture2D(colorMap, varTexCoord); + gl_FragColor = color * varColor; +} diff --git a/libraries/entities-renderer/src/textured_particle.slv b/libraries/entities-renderer/src/textured_particle.slv new file mode 100644 index 0000000000..7564feb1ce --- /dev/null +++ b/libraries/entities-renderer/src/textured_particle.slv @@ -0,0 +1,28 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// particle vertex shader +// +// 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 vec4 varColor; +varying vec2 varTexCoord; + +void main(void) { + // pass along the color & uvs to fragment shader + varColor = gl_Color; + varTexCoord = gl_MultiTexCoord0.xy; + + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToClipPos(cam, obj, gl_Vertex, gl_Position)$> +} diff --git a/libraries/entities-renderer/src/untextured_particle.slf b/libraries/entities-renderer/src/untextured_particle.slf new file mode 100644 index 0000000000..bb3ed77e3f --- /dev/null +++ b/libraries/entities-renderer/src/untextured_particle.slf @@ -0,0 +1,16 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// fragment shader +// +// 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 +// + +varying vec4 varColor; + +void main(void) { + gl_FragColor = varColor; +} diff --git a/libraries/entities-renderer/src/untextured_particle.slv b/libraries/entities-renderer/src/untextured_particle.slv new file mode 100644 index 0000000000..2975dab046 --- /dev/null +++ b/libraries/entities-renderer/src/untextured_particle.slv @@ -0,0 +1,24 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// particle vertex shader +// +// 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 vec4 varColor; + +void main(void) { + // pass along the diffuse color + varColor = gl_Color; + + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToClipPos(cam, obj, gl_Vertex, gl_Position)$> +} \ No newline at end of file diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 95effa2980..a687e2be7a 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -39,6 +39,7 @@ #include "EntityTree.h" #include "EntityTreeElement.h" #include "EntitiesLogging.h" +#include "EntityScriptingInterface.h" #include "ParticleEffectEntityItem.h" const xColor ParticleEffectEntityItem::DEFAULT_COLOR = { 255, 255, 255 }; @@ -92,6 +93,74 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte ParticleEffectEntityItem::~ParticleEffectEntityItem() { } +void ParticleEffectEntityItem::setDimensions(const glm::vec3& value) { + computeAndUpdateDimensions(); +} + +void ParticleEffectEntityItem::setLifespan(float lifespan) { + _lifespan = lifespan; + computeAndUpdateDimensions(); +} + +void ParticleEffectEntityItem::setEmitDirection(glm::vec3 emitDirection) { + _emitDirection = glm::normalize(emitDirection); + computeAndUpdateDimensions(); +} + +void ParticleEffectEntityItem::setEmitStrength(float emitStrength) { + _emitStrength = emitStrength; + computeAndUpdateDimensions(); +} + +void ParticleEffectEntityItem::setLocalGravity(float localGravity) { + _localGravity = localGravity; + computeAndUpdateDimensions(); +} + +void ParticleEffectEntityItem::setParticleRadius(float particleRadius) { + _particleRadius = particleRadius; + computeAndUpdateDimensions(); +} + +void ParticleEffectEntityItem::computeAndUpdateDimensions() { + + const float t = _lifespan * 1.1f; // add 10% extra time, to account for incremental timer accumulation error. + const float maxOffset = (0.5f * 0.25f * _emitStrength) + _particleRadius; + + // bounds for x and z is easy to compute because there is no at^2 term. + float xMax = (_emitDirection.x * _emitStrength + maxOffset) * t; + float xMin = (_emitDirection.x * _emitStrength - maxOffset) * t; + + float zMax = (_emitDirection.z * _emitStrength + maxOffset) * t; + float zMin = (_emitDirection.z * _emitStrength - maxOffset) * t; + + // yEnd is where the particle will end. + float a = _localGravity; + float atSquared = a * t * t; + float v = _emitDirection.y * _emitStrength + maxOffset; + float vt = v * t; + float yEnd = 0.5f * atSquared + vt; + + // yApex is where the particle is at it's apex. + float yApexT = (-v / a); + float yApex = 0.0f; + + // only set apex if it's within the lifespan of the particle. + if (yApexT >= 0.0f && yApexT <= t) { + yApex = -(v * v) / (2.0f * a); + } + + float yMax = std::max(yApex, yEnd); + float yMin = std::min(yApex, yEnd); + + // times 2 because dimensions are diameters not radii. + glm::vec3 dims(2.0f * std::max(fabs(xMin), fabs(xMax)), + 2.0f * std::max(fabs(yMin), fabs(yMax)), + 2.0f * std::max(fabs(zMin), fabs(zMax))); + + EntityItem::setDimensions(dims); +} + EntityItemProperties ParticleEffectEntityItem::getProperties() const { EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class @@ -245,7 +314,7 @@ bool ParticleEffectEntityItem::isAnimatingSomething() const { } bool ParticleEffectEntityItem::needsToCallUpdate() const { - return isAnimatingSomething() ? true : EntityItem::needsToCallUpdate(); + return true; } void ParticleEffectEntityItem::update(const quint64& now) { @@ -260,13 +329,6 @@ void ParticleEffectEntityItem::update(const quint64& now) { if (isAnimatingSomething()) { stepSimulation(deltaTime); - - // update the dimensions - glm::vec3 dims; - dims.x = glm::max(glm::abs(_particleMinBound.x), glm::abs(_particleMaxBound.x)) * 2.0f; - dims.y = glm::max(glm::abs(_particleMinBound.y), glm::abs(_particleMaxBound.y)) * 2.0f; - dims.z = glm::max(glm::abs(_particleMinBound.z), glm::abs(_particleMaxBound.z)) * 2.0f; - setDimensions(dims); } EntityItem::update(now); // let our base class handle it's updates... @@ -319,7 +381,7 @@ void ParticleEffectEntityItem::setAnimationSettings(const QString& value) { qCDebug(entities) << "ParticleEffectEntityItem::setAnimationSettings() calling setAnimationFrameIndex()..."; qCDebug(entities) << " settings:" << value; qCDebug(entities) << " settingsMap[frameIndex]:" << settingsMap["frameIndex"]; - qCDebug(entities" frameIndex: %20.5f", frameIndex); + qCDebug(entities, " frameIndex: %20.5f", frameIndex); } #endif diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 3136ab6c7c..994c609f0f 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -86,12 +86,14 @@ public: void setAnimationLastFrame(float lastFrame) { _animationLoop.setLastFrame(lastFrame); } float getAnimationLastFrame() const { return _animationLoop.getLastFrame(); } + virtual void setDimensions(const glm::vec3& value) override; + static const quint32 DEFAULT_MAX_PARTICLES; void setMaxParticles(quint32 maxParticles); quint32 getMaxParticles() const { return _maxParticles; } static const float DEFAULT_LIFESPAN; - void setLifespan(float lifespan) { _lifespan = lifespan; } + void setLifespan(float lifespan); float getLifespan() const { return _lifespan; } static const float DEFAULT_EMIT_RATE; @@ -99,21 +101,23 @@ public: float getEmitRate() const { return _emitRate; } static const glm::vec3 DEFAULT_EMIT_DIRECTION; - void setEmitDirection(glm::vec3 emitDirection) { _emitDirection = glm::normalize(emitDirection); } + void setEmitDirection(glm::vec3 emitDirection); const glm::vec3& getEmitDirection() const { return _emitDirection; } static const float DEFAULT_EMIT_STRENGTH; - void setEmitStrength(float emitStrength) { _emitStrength = emitStrength; } + void setEmitStrength(float emitStrength); float getEmitStrength() const { return _emitStrength; } static const float DEFAULT_LOCAL_GRAVITY; - void setLocalGravity(float localGravity) { _localGravity = localGravity; } + void setLocalGravity(float localGravity); float getLocalGravity() const { return _localGravity; } static const float DEFAULT_PARTICLE_RADIUS; - void setParticleRadius(float particleRadius) { _particleRadius = particleRadius; } + void setParticleRadius(float particleRadius); float getParticleRadius() const { return _particleRadius; } + void computeAndUpdateDimensions(); + bool getAnimationIsPlaying() const { return _animationLoop.isRunning(); } float getAnimationFrameIndex() const { return _animationLoop.getFrameIndex(); } float getAnimationFPS() const { return _animationLoop.getFPS(); } From d17ddae53787a3ad094f82f65fc5491c75774a4f Mon Sep 17 00:00:00 2001 From: "Kevin M. Thomas" Date: Mon, 27 Jul 2015 12:14:50 -0400 Subject: [PATCH 33/45] 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 5844b594dcfcdee259c9c67d50994cda801cb663 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 27 Jul 2015 09:27:16 -0700 Subject: [PATCH 34/45] Converted magic numbers to constants. --- .../RenderableParticleEffectEntityItem.cpp | 26 +++++++++++-------- .../entities/src/ParticleEffectEntityItem.cpp | 3 ++- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 738a150dc5..2b4626c2c3 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -175,8 +175,9 @@ uint32_t toRGBA(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { void RenderableParticleEffectEntityItem::updateRenderItem() { - if (!_scene) + if (!_scene) { return; + } float particleRadius = getParticleRadius(); auto xcolor = getXColor(); @@ -223,18 +224,20 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { // FIXME, don't update index buffer if num particles has not changed. // update index buffer auto indexBuffer = payload.getIndexBuffer(); - auto numQuads = (_vertices.size() / 4); - numBytes = sizeof(uint16_t) * numQuads * 6; + const size_t NUM_VERTS_PER_PARTICLE = 4; + const size_t NUM_INDICES_PER_PARTICLE = 6; + auto numQuads = (_vertices.size() / NUM_VERTS_PER_PARTICLE); + numBytes = sizeof(uint16_t) * numQuads * NUM_INDICES_PER_PARTICLE; indexBuffer->resize(numBytes); data = indexBuffer->editData(); auto indexPtr = reinterpret_cast(data); for (size_t i = 0; i < numQuads; ++i) { - indexPtr[i * 6 + 0] = i * 4 + 0; - indexPtr[i * 6 + 1] = i * 4 + 1; - indexPtr[i * 6 + 2] = i * 4 + 3; - indexPtr[i * 6 + 3] = i * 4 + 1; - indexPtr[i * 6 + 4] = i * 4 + 2; - indexPtr[i * 6 + 5] = i * 4 + 3; + indexPtr[i * NUM_INDICES_PER_PARTICLE + 0] = i * NUM_VERTS_PER_PARTICLE + 0; + indexPtr[i * NUM_INDICES_PER_PARTICLE + 1] = i * NUM_VERTS_PER_PARTICLE + 1; + indexPtr[i * NUM_INDICES_PER_PARTICLE + 2] = i * NUM_VERTS_PER_PARTICLE + 3; + indexPtr[i * NUM_INDICES_PER_PARTICLE + 3] = i * NUM_VERTS_PER_PARTICLE + 1; + indexPtr[i * NUM_INDICES_PER_PARTICLE + 4] = i * NUM_VERTS_PER_PARTICLE + 2; + indexPtr[i * NUM_INDICES_PER_PARTICLE + 5] = i * NUM_VERTS_PER_PARTICLE + 3; } // update transform @@ -247,7 +250,8 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { // transform _particleMinBound and _particleMaxBound corners into world coords glm::vec3 d = _particleMaxBound - _particleMinBound; - glm::vec3 corners[8] = { + const size_t NUM_BOX_CORNERS = 8; + glm::vec3 corners[NUM_BOX_CORNERS] = { pos + rot * (_particleMinBound + glm::vec3(0.0f, 0.0f, 0.0f)), pos + rot * (_particleMinBound + glm::vec3(d.x, 0.0f, 0.0f)), pos + rot * (_particleMinBound + glm::vec3(0.0f, d.y, 0.0f)), @@ -259,7 +263,7 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { }; glm::vec3 min(FLT_MAX, FLT_MAX, FLT_MAX); glm::vec3 max = -min; - for (int i = 0; i < 8; i++) { + for (size_t i = 0; i < NUM_BOX_CORNERS; i++) { min.x = std::min(min.x, corners[i].x); min.y = std::min(min.y, corners[i].y); min.z = std::min(min.z, corners[i].z); diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index a687e2be7a..71a5f87eb1 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -125,7 +125,8 @@ void ParticleEffectEntityItem::setParticleRadius(float particleRadius) { void ParticleEffectEntityItem::computeAndUpdateDimensions() { const float t = _lifespan * 1.1f; // add 10% extra time, to account for incremental timer accumulation error. - const float maxOffset = (0.5f * 0.25f * _emitStrength) + _particleRadius; + const float MAX_RANDOM_FACTOR = (0.5f * 0.25); + const float maxOffset = (MAX_RANDOM_FACTOR * _emitStrength) + _particleRadius; // bounds for x and z is easy to compute because there is no at^2 term. float xMax = (_emitDirection.x * _emitStrength + maxOffset) * t; From 604ef5dc71311982e25a90bb80eba499b46524c9 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 27 Jul 2015 09:28:56 -0700 Subject: [PATCH 35/45] Fixed float constant. --- libraries/entities/src/ParticleEffectEntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 71a5f87eb1..4dfc9dd436 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -125,7 +125,7 @@ void ParticleEffectEntityItem::setParticleRadius(float particleRadius) { void ParticleEffectEntityItem::computeAndUpdateDimensions() { const float t = _lifespan * 1.1f; // add 10% extra time, to account for incremental timer accumulation error. - const float MAX_RANDOM_FACTOR = (0.5f * 0.25); + const float MAX_RANDOM_FACTOR = (0.5f * 0.25f); const float maxOffset = (MAX_RANDOM_FACTOR * _emitStrength) + _particleRadius; // bounds for x and z is easy to compute because there is no at^2 term. From 9c57d1544fdc237fd4476972795e91050cdffa86 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Jul 2015 09:53:27 -0700 Subject: [PATCH 36/45] fix OctreeSceneStat unpacking in Application --- interface/src/Application.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fa2a82ecb4..c213d7629c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3596,19 +3596,13 @@ int Application::processOctreeStats(NLPacket& packet, SharedNodePointer sendingN int statsMessageLength = 0; const QUuid& nodeUUID = sendingNode->getUUID(); - OctreeSceneStats* octreeStats; - + // now that we know the node ID, let's add these stats to the stats for that node... _octreeSceneStatsLock.lockForWrite(); - auto it = _octreeServerSceneStats.find(nodeUUID); - if (it != _octreeServerSceneStats.end()) { - octreeStats = &it->second; - statsMessageLength = octreeStats->unpackFromPacket(packet); - } else { - OctreeSceneStats temp; - statsMessageLength = temp.unpackFromPacket(packet); - octreeStats = &temp; - } + + OctreeSceneStats* octreeStats = &_octreeServerSceneStats[nodeUUID]; + statsMessageLength = octreeStats->unpackFromPacket(packet); + _octreeSceneStatsLock.unlock(); VoxelPositionSize rootDetails; From 615218c77dc7c809a01da4265159805a81101da5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Jul 2015 09:58:58 -0700 Subject: [PATCH 37/45] use a ref in stats unpacking --- interface/src/Application.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c213d7629c..69c10fc0ee 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3600,13 +3600,13 @@ int Application::processOctreeStats(NLPacket& packet, SharedNodePointer sendingN // now that we know the node ID, let's add these stats to the stats for that node... _octreeSceneStatsLock.lockForWrite(); - OctreeSceneStats* octreeStats = &_octreeServerSceneStats[nodeUUID]; - statsMessageLength = octreeStats->unpackFromPacket(packet); + OctreeSceneStats& octreeStats = _octreeServerSceneStats[nodeUUID]; + statsMessageLength = octreeStats.unpackFromPacket(packet); _octreeSceneStatsLock.unlock(); VoxelPositionSize rootDetails; - voxelDetailsForCode(octreeStats->getJurisdictionRoot(), rootDetails); + voxelDetailsForCode(octreeStats.getJurisdictionRoot(), rootDetails); // see if this is the first we've heard of this node... NodeToJurisdictionMap* jurisdiction = NULL; @@ -3631,7 +3631,7 @@ int Application::processOctreeStats(NLPacket& packet, SharedNodePointer sendingN // but OctreeSceneStats thinks it's just returning a reference to its contents. So we need to make a copy of the // details from the OctreeSceneStats to construct the JurisdictionMap JurisdictionMap jurisdictionMap; - jurisdictionMap.copyContents(octreeStats->getJurisdictionRoot(), octreeStats->getJurisdictionEndNodes()); + jurisdictionMap.copyContents(octreeStats.getJurisdictionRoot(), octreeStats.getJurisdictionEndNodes()); jurisdiction->lockForWrite(); (*jurisdiction)[nodeUUID] = jurisdictionMap; jurisdiction->unlock(); From d3c6d8b3ccd528297de8f7e517499be4171105ef Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Jul 2015 10:06:34 -0700 Subject: [PATCH 38/45] move call to get VoxelPositionSize inside debug that uses it --- interface/src/Application.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 69c10fc0ee..bb564824b0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3605,9 +3605,6 @@ int Application::processOctreeStats(NLPacket& packet, SharedNodePointer sendingN _octreeSceneStatsLock.unlock(); - VoxelPositionSize rootDetails; - voxelDetailsForCode(octreeStats.getJurisdictionRoot(), rootDetails); - // see if this is the first we've heard of this node... NodeToJurisdictionMap* jurisdiction = NULL; QString serverType; @@ -3619,6 +3616,9 @@ int Application::processOctreeStats(NLPacket& packet, SharedNodePointer sendingN jurisdiction->lockForRead(); if (jurisdiction->find(nodeUUID) == jurisdiction->end()) { jurisdiction->unlock(); + + VoxelPositionSize rootDetails; + voxelDetailsForCode(octreeStats.getJurisdictionRoot(), rootDetails); qCDebug(interfaceapp, "stats from new %s server... [%f, %f, %f, %f]", qPrintable(serverType), From ceffbb6383fae7df2d722a24c39622c87169ee23 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 27 Jul 2015 11:41:53 -0700 Subject: [PATCH 39/45] Update edit.js to show an alert window when new objects would be out of bounds --- examples/edit.js | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 1af016958f..ec3106e585 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -329,7 +329,7 @@ var toolBar = (function () { Script.setTimeout(resize, RESIZE_INTERVAL); } else { - print("Can't add model: Model would be out of bounds."); + Window.alert("Can't add model: Model would be out of bounds."); } } @@ -374,7 +374,7 @@ var toolBar = (function () { }); } else { - print("Can't create box: Box would be out of bounds."); + Window.alert("Can't create box: Box would be out of bounds."); } return true; } @@ -390,7 +390,7 @@ var toolBar = (function () { color: { red: 255, green: 0, blue: 0 } }); } else { - print("Can't create sphere: Sphere would be out of bounds."); + Window.alert("Can't create sphere: Sphere would be out of bounds."); } return true; } @@ -413,7 +413,7 @@ var toolBar = (function () { cutoff: 180, // in degrees }); } else { - print("Can't create Light: Light would be out of bounds."); + Window.alert("Can't create Light: Light would be out of bounds."); } return true; } @@ -433,7 +433,7 @@ var toolBar = (function () { lineHeight: 0.06 }); } else { - print("Can't create box: Text would be out of bounds."); + Window.alert("Can't create box: Text would be out of bounds."); } return true; } @@ -449,7 +449,7 @@ var toolBar = (function () { sourceUrl: "https://highfidelity.com/", }); } else { - print("Can't create Web Entity: would be out of bounds."); + Window.alert("Can't create Web Entity: would be out of bounds."); } return true; } @@ -464,7 +464,7 @@ var toolBar = (function () { dimensions: { x: 10, y: 10, z: 10 }, }); } else { - print("Can't create box: Text would be out of bounds."); + Window.alert("Can't create box: Text would be out of bounds."); } return true; } @@ -482,7 +482,7 @@ var toolBar = (function () { voxelSurfaceStyle: 1 }); } else { - print("Can't create PolyVox: would be out of bounds."); + Window.alert("Can't create PolyVox: would be out of bounds."); } return true; } @@ -1068,13 +1068,16 @@ function importSVO(importURL) { if (Clipboard.getClipboardContentsLargestDimension() < VERY_LARGE) { position = getPositionToCreateEntity(); } - var pastedEntityIDs = Clipboard.pasteEntities(position); - - if (isActive) { - selectionManager.setSelections(pastedEntityIDs); - } + if (position.x > 0 && position.y > 0 && position.z > 0) { + var pastedEntityIDs = Clipboard.pasteEntities(position); + if (isActive) { + selectionManager.setSelections(pastedEntityIDs); + } Window.raiseMainWindow(); + } else { + Window.alert("Can't import objects: objects would be out of bounds."); + } } else { Window.alert("There was an error importing the entity file."); } From 92595583ec280e81a3e9a5783a696bfce2b17063 Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Mon, 27 Jul 2015 11:55:17 -0700 Subject: [PATCH 40/45] 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 1193b89918dba29ab25a0d5d14ee0d2c2b9b525f Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Mon, 27 Jul 2015 12:14:29 -0700 Subject: [PATCH 41/45] 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 42/45] 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 43/45] 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 44/45] 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 45/45] 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())); }